1楼 基于2.6.19.7内核源码 要对收发过程进行分析 |
|
|
2楼 重要数据结构:/* Receive Descriptor 接收描述符*/ struct e1000_rx_desc { uint64_t buffer_addr; /* Address of the descriptor's data buffer */ uint16_t length; /* Length of data DMAed into data buffer */ uint16_t csum; /* Packet checksum */ uint8_t status; /* Descriptor status */ uint8_t errors; /* Descriptor Errors */ uint16_t special; }; /* Transmit Descriptor 发送描述符*/ struct e1000_tx_desc { uint64_t buffer_addr; /* Address of the descriptor's data buffer */ union { uint32_t data; struct { uint16_t length; /* Data buffer length */ uint8_t cso; /* Checksum offset */ uint8_t cmd; /* Descriptor control */ } flags; } lower; union { uint32_t data; struct { uint8_t status; /* Descriptor status */ uint8_t css; /* Checksum start */ uint16_t special; } fields; } upper; }; /* wrapper around a pointer to a socket buffer, * so a DMA handle can be stored along with the buffer */ struct e1000_buffer { struct sk_buff *skb; dma_addr_t dma; unsigned long time_stamp; uint16_t length; uint16_t next_to_watch; }; struct e1000_tx_ring { /* pointer to the descriptor ring memory */ void *desc; /* physical address of the descriptor ring */ dma_addr_t dma; /* length of descriptor ring in bytes */ unsigned int size; /* number of descriptors in the ring */ unsigned int count; /* next descriptor to associate a buffer with */ unsigned int next_to_use; /* next descriptor to check for DD status bit */ unsigned int next_to_clean; /* array of buffer information structs */ struct e1000_buffer *buffer_info; spinlock_t tx_lock; uint16_t tdh; uint16_t tdt; boolean_t last_tx_tso; }; struct e1000_rx_ring { /* pointer to the descriptor ring memory */ void *desc; /* physical address of the descriptor ring */ dma_addr_t dma; /* length of descriptor ring in bytes */ unsigned int size; /* number of descriptors in the ring */ unsigned int count; /* next descriptor to associate a buffer with */ unsigned int next_to_use; /* next descriptor to check for DD status bit */ unsigned int next_to_clean; /* array of buffer information structs */ struct e1000_buffer *buffer_info; /* arrays of page information for packet split */ struct e1000_ps_page *ps_page; struct e1000_ps_page_dma *ps_page_dma; /* cpu for rx queue */ int cpu; uint16_t rdh; uint16_t rdt; }; |
|
|
3楼 函数:(1130) static int __devinit e1000_sw_init(struct e1000_adapter *adapter) /*在probe中被调用(821) 负责初始化网卡私有域的数据结构 对我们重要的是设定缓冲长度 接受和发送队列的个数(通常是1)创建接收发送的环队列 以及工作在NAPI时每个队列的轮询函数以及初始权值*/ (1718)int e1000_setup_all_rx_resources(struct e1000_adapter *adapter) //e1000_open中被调用(1288) 封装了e1000_setup_rx_resources(1612) (1612)static int e1000_setup_rx_resources(struct e1000_adapter *adapter,struct e1000_rx_ring *rxdr) //被e1000_setup_all_rx_resources封装 用于分配接收描述符 { struct pci_dev *pdev = adapter->pdev; int size, desc_len; size = sizeof(struct e1000_buffer) * rxdr->count;//这个结构体的主要功能是指向报文缓存并保存其物理地址 rxdr->buffer_info = vmalloc(size); if (!rxdr->buffer_info) { DPRINTK(PROBE, ERR, "Unable to allocate memory for the receive descriptor ring/n"); return -ENOMEM; } memset(rxdr->buffer_info, 0, size); size = sizeof(struct e1000_ps_page) * rxdr->count;//这玩意我的82540用不上 无视 rxdr->ps_page = kmalloc(size, GFP_KERNEL); if (!rxdr->ps_page) { vfree(rxdr->buffer_info); DPRINTK(PROBE, ERR, "Unable to allocate memory for the receive descriptor ring/n"); return -ENOMEM; } memset(rxdr->ps_page, 0, size); size = sizeof(struct e1000_ps_page_dma) * rxdr->count;//一样无视 rxdr->ps_page_dma = kmalloc(size, GFP_KERNEL); if (!rxdr->ps_page_dma) { vfree(rxdr->buffer_info); kfree(rxdr->ps_page); DPRINTK(PROBE, ERR, "Unable to allocate memory for the receive descriptor ring/n"); return -ENOMEM; } memset(rxdr->ps_page_dma, 0, size); if (adapter->hw.mac_type <= e1000_82547_rev_2) desc_len = sizeof(struct e1000_rx_desc);//获得接收描述符长度 else desc_len = sizeof(union e1000_rx_desc_packet_split); /* Round up to nearest 4K */ rxdr->size = rxdr->count * desc_len;//计算总描述符长度 E1000_ROUNDUP(rxdr->size, 4096); rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);//为描述符缓存建立一致性DMA映射 分配内存并返回内核逻辑地址以及物理地址 if (!rxdr->desc) { DPRINTK(PROBE, ERR, "Unable to allocate memory for the receive descriptor ring/n"); setup_rx_desc_die: vfree(rxdr->buffer_info); kfree(rxdr->ps_page); kfree(rxdr->ps_page_dma); return -ENOMEM; } //。。省去边界判断 memset(rxdr->desc, 0, rxdr->size); rxdr->next_to_clean = 0; rxdr->next_to_use = 0; return 0; } |
|
|
4楼 (2271)static void e1000_set_multi(struct net_device *netdev)//e1000_up中被调用(461)用于设置网卡的广播模式和混杂模式 {struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; struct dev_mc_list *mc_ptr; uint32_t rctl; uint32_t hash_value; int i, rar_entries = E1000_RAR_ENTRIES; int mta_reg_count = (hw->mac_type == e1000_ich8lan) ? E1000_NUM_MTA_REGISTERS_ICH8LAN : E1000_NUM_MTA_REGISTERS; if (adapter->hw.mac_type == e1000_ich8lan) rar_entries = E1000_RAR_ENTRIES_ICH8LAN; /* reserve RAR[14] for LAA over-write work-around */ if (adapter->hw.mac_type == e1000_82571) rar_entries--; /* Check for Promiscuous and All Multicast modes */ rctl = E1000_READ_REG(hw, RCTL);//读寄存器 if (netdev->flags & IFF_PROMISC) { //如果是混杂模式 则开启单播广播混杂模式 对零拷贝这里非常重要 否则只能收到给自己的数据包 rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); } else if (netdev->flags & IFF_ALLMULTI) { rctl |= E1000_RCTL_MPE; rctl &= ~E1000_RCTL_UPE; } else { rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE); } E1000_WRITE_REG(hw, RCTL, rctl);//回写寄存器 //ok 目标达到 可以无视剩下的代码 } (1745)static void e1000_setup_rctl(struct e1000_adapter *adapter) //e1000_up中被调用(466) 负责设置RCTL接收控制寄存器 { uint32_t rctl, rfctl; uint32_t psrctl = 0; #ifndef CONFIG_E1000_DISABLE_PACKET_SPLIT uint32_t pages = 0; #endif rctl = E1000_READ_REG(&adapter->hw, RCTL);//读取接收控制寄存器 rctl &= ~(3 << E1000_RCTL_MO_SHIFT);//清空寄存器并将12,13位设为1 rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | (adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT);//开始设置rctl:允许收包 允许广播 禁止loopback 设定描述符门限为1/2 if (adapter->hw.tbi_compatibility_on == 1) rctl |= E1000_RCTL_SBP; //允许存坏包 else rctl &= ~E1000_RCTL_SBP;//不许 if (adapter->netdev->mtu <= ETH_DATA_LEN) rctl &= ~E1000_RCTL_LPE;//最大载荷如果小于预定的以太网最大报文长度 不允许存超过1522的包 else rctl |= E1000_RCTL_LPE;//否则允许 /* Setup buffer sizes */ rctl &= ~E1000_RCTL_SZ_4096; rctl |= E1000_RCTL_BSEX;//这里先将报文缓存值设为保留 switch (adapter->rx_buffer_len) { case E1000_RXBUFFER_256: rctl |= E1000_RCTL_SZ_256; rctl &= ~E1000_RCTL_BSEX; break; case E1000_RXBUFFER_512: rctl |= E1000_RCTL_SZ_512; rctl &= ~E1000_RCTL_BSEX; break; case E1000_RXBUFFER_1024: rctl |= E1000_RCTL_SZ_1024; rctl &= ~E1000_RCTL_BSEX; break; case E1000_RXBUFFER_2048: default: //再在此处将缓存设为2048B rctl |= E1000_RCTL_SZ_2048; rctl &= ~E1000_RCTL_BSEX; break; case E1000_RXBUFFER_4096: rctl |= E1000_RCTL_SZ_4096; break; case E1000_RXBUFFER_8192: rctl |= E1000_RCTL_SZ_8192; break; case E1000_RXBUFFER_16384: rctl |= E1000_RCTL_SZ_16384; break; } //以下代码与packet split有关 82540不支持 含泪删去。。。 E1000_WRITE_REG(&adapter->hw, RCTL, rctl); } |
|
|
5楼 (1859)static void e1000_configure_rx(struct e1000_adapter *adapter)//主要用于设置时间以及接收寄存器//e1000_up中被调用(467) { uint64_t rdba; struct e1000_hw *hw = &adapter->hw; uint32_t rdlen, rctl, rxcsum, ctrl_ext; if (adapter->rx_ps_pages) {//是否支持packet split技术 我用的82540em不支持 故跳到else /* this is a 32 byte descriptor */ rdlen = adapter->rx_ring[0].count * sizeof(union e1000_rx_desc_packet_split); adapter->clean_rx = e1000_clean_rx_irq_ps; adapter->alloc_rx_buf = e1000_alloc_rx_buffers_ps; } else { rdlen = adapter->rx_ring[0].count * sizeof(struct e1000_rx_desc); //计算接收描述符缓冲区大小 adapter->clean_rx = e1000_clean_rx_irq; //赋值给函数指针 clean_rx指向一个函数 此函数将已完成传输的数据包上交内核栈 adapter->alloc_rx_buf = e1000_alloc_rx_buffers;//同上 指向的函数负责回收已用的接收缓存 } /* disable receives while setting up the descriptors */ //写接收控制寄存器 暂时停止接收 rctl = E1000_READ_REG(hw, RCTL); E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN); /* set the Receive Delay Timer Register */ E1000_WRITE_REG(hw, RDTR, adapter->rx_int_delay); //设置RDTR寄存器 有关RDTR详见intel 8254X 开发者手册 if (hw->mac_type >= e1000_82540) { //设置RADV寄存器 有关RADV具体详见开发者手册 E1000_WRITE_REG(hw, RADV, adapter->rx_abs_int_delay); if (adapter->itr > 1) E1000_WRITE_REG(hw, ITR, 1000000000 / (adapter->itr * 256)); } //。。省掉对其他芯片的设置。。。 /* Setup the HW Rx Head and Tail Descriptor Pointers and * the Base and Length of the Rx Descriptor Ring */ //与接收描述符环有关的有4个寄存器:RDBA存放描述符缓冲的首地址 做为基地址 供64位 包括各32位的高低地址 //RDLEN:为缓冲区分配的总空间的大小 RDH和RDT是头尾指针 存放相对基址的偏移量 RDH的值由硬件增加 表示指向下一次DMA将用的描述符 //RDT由软件增加 表示下一次要处理并送交协议栈的有关描述符 switch (adapter->num_rx_queues) { //分别取相应值并写寄存器 case 1: default: rdba = adapter->rx_ring[0].dma; //向寄存器设置接收描述符物理首地址 E1000_WRITE_REG(hw, RDLEN, rdlen);//设置大小 E1000_WRITE_REG(hw, RDBAH, (rdba >> 32)); //基址的高32位 E1000_WRITE_REG(hw, RDBAL, (rdba & 0x00000000ffffffffULL));//基址低32位 E1000_WRITE_REG(hw, RDT, 0);//初试偏移量均为0 E1000_WRITE_REG(hw, RDH, 0); adapter->rx_ring[0].rdh = ((hw->mac_type >= e1000_82543) ? E1000_RDH : E1000_82542_RDH); adapter->rx_ring[0].rdt = ((hw->mac_type >= e1000_82543) ? E1000_RDT : E1000_82542_RDT); break; //E1000_RDH E1000_RDT为映射过的寄存器的偏移量 将其保存在结构体中 } /* Enable 82543 Receive Checksum Offload for TCP and UDP */ if (hw->mac_type >= e1000_82543) { //根据定义的eum值 82540是大于82543的 在此开启硬件的校验和功能 rxcsum = E1000_READ_REG(hw, RXCSUM); if (adapter->rx_csum == TRUE) { rxcsum |= E1000_RXCSUM_TUOFL; /* Enable 82571 IPv4 payload checksum for UDP fragments * Must be used in conjunction with packet-split. */ if ((hw->mac_type >= e1000_82571) && //eum值不大于82571 也不具有packet split技术 跳至else (adapter->rx_ps_pages)) { rxcsum |= E1000_RXCSUM_IPPCSE; |
|
|
6楼 }} else { rxcsum &= ~E1000_RXCSUM_TUOFL; /* don't need to clear IPPCSE as it defaults to 0 */ } E1000_WRITE_REG(hw, RXCSUM, rxcsum); //写校验和寄存器 } /* Enable Receives */ E1000_WRITE_REG(hw, RCTL, rctl); //写RCTL寄存器 重新开启接收功能 } /** * e1000_alloc_rx_buffers - Replace used receive buffers; legacy & extended * @adapter: address of board private structure **/ //初始化收包缓存或重分配缓存时调用 (4079)static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,struct e1000_rx_ring *rx_ring,int cleaned_count) { struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; struct e1000_rx_desc *rx_desc; struct e1000_buffer *buffer_info; struct sk_buff *skb; unsigned int i; unsigned int bufsz = adapter->rx_buffer_len + NET_IP_ALIGN; i = rx_ring->next_to_use; buffer_info = &rx_ring->buffer_info[i]; while (cleaned_count--) { skb = buffer_info->skb;//对于小包的情况 用过的skb会遗留在buffer里面( 见e1000_clean_rx_irq中对小包的处理) 则进行一些处理 if (skb) { skb_trim(skb, 0); goto map_skb; } skb = netdev_alloc_skb(netdev, bufsz); //分配了一个skb if (unlikely(!skb)) { /* Better luck next round */ adapter->alloc_rx_buff_failed++; break; } //。省略边界判断。。。 /* Make buffer alignment 2 beyond a 16 byte boundary * this will result in a 16 byte aligned IP header after * the 14 byte MAC header is removed */ skb_reserve(skb, NET_IP_ALIGN); buffer_info->skb = skb; //对缓冲描述符赋值 buffer_info->length = adapter->rx_buffer_len; map_skb: buffer_info->dma = pci_map_single(pdev,//为刚分配的skb建立流式DMA映射 并返回物理地址 skb->data, adapter->rx_buffer_len, PCI_DMA_FROMDEVICE); //。省去边界判断。。。 rx_desc = E1000_RX_DESC(*rx_ring, i); rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);//将物理地址存在对应的描述符中 if (unlikely(++i == rx_ring->count)) //i循环向后 i = 0; buffer_info = &rx_ring->buffer_info[i];//指向下一个单位 } if (likely(rx_ring->next_to_use != i)) { rx_ring->next_to_use = i;//标记next_to_use指向下一个要处理(分配或回收)的偏移量 if (unlikely(i-- == 0)) i = (rx_ring->count - 1); /* Force memory writes to complete before letting h/w * know there are new descriptors to fetch. (Only * applicable for weak-ordered memory model archs, * such as IA-64). */ wmb(); writel(i, adapter->hw.hw_addr + rx_ring->rdt);//因为已经有新缓存被分配 所以给rdt赋新值 } } |
|
|
7楼 (453)int e1000_up(struct e1000_adapter *adapter)//在e1000_open中调用(1297) 负责一些初始化设置{ struct net_device *netdev = adapter->netdev; int i; /* hardware has been reset, we need to reload some things */ e1000_set_multi(netdev); //设置多播混杂模式 e1000_restore_vlan(adapter); e1000_configure_tx(adapter); e1000_setup_rctl(adapter);//设置接收控制寄存器 e1000_configure_rx(adapter);//接收设置 /* call E1000_DESC_UNUSED which always leaves * at least 1 descriptor unused to make sure * next_to_use != next_to_clean */ for (i = 0; i < adapter->num_rx_queues; i++) { //根据接收描述符设置报文缓冲 struct e1000_rx_ring *ring = &adapter->rx_ring[i]; adapter->alloc_rx_buf(adapter, ring, E1000_DESC_UNUSED(ring)); } //#define E1000_DESC_UNUSED(R) / //((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + / //(R)->next_to_clean - (R)->next_to_use - 1) adapter->tx_queue_len = netdev->tx_queue_len; #ifdef CONFIG_E1000_NAPI //如果要使用 NAPI 在此开启 netif_poll_enable(netdev); #endif e1000_irq_enable(adapter); //开启中断 clear_bit(__E1000_DOWN, &adapter->flags); mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); return 0; } (1271)static int e1000_open(struct net_device *netdev) //ifup时被调用 初始化接收发送,中断,时间。 { struct e1000_adapter *adapter = netdev_priv(netdev); int err; /* disallow open during test */ if (test_bit(__E1000_TESTING, &adapter->flags)) return -EBUSY; /* allocate transmit descriptors */ if ((err = e1000_setup_all_tx_resources(adapter))) goto err_setup_tx; /* allocate receive descriptors */ if ((err = e1000_setup_all_rx_resources(adapter)))//包裹函数 用于分配接收描述符 goto err_setup_rx; err = e1000_request_irq(adapter); //分配中断号 if (err) goto err_req_irq; e1000_power_up_phy(adapter); if ((err = e1000_up(adapter))) //一些初始化设置 goto err_up; adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; if ((adapter->hw.mng_cookie.status & E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) { e1000_update_mng_vlan(adapter); } /* If AMT is enabled, let the firmware know that the network * interface is now open */ if (adapter->hw.mac_type == e1000_82573 && e1000_check_mng_mode(&adapter->hw)) e1000_get_hw_control(adapter); return E1000_SUCCESS; err_up: e1000_power_down_phy(adapter); e1000_free_irq(adapter); err_req_irq: e1000_free_all_rx_resources(adapter); err_setup_rx: e1000_free_all_tx_resources(adapter); err_setup_tx: e1000_reset(adapter); return err; } |
|
|
8楼 static irqreturn_t e1000_intr(int irq, void *data)//e1000的ISR{ struct net_device *netdev = data; struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; uint32_t rctl, icr = E1000_READ_REG(hw, ICR); #ifndef CONFIG_E1000_NAPI int i; #else /* Interrupt Auto-Mask...upon reading ICR, * interrupts are masked. No need for the * IMC write, but it does mean we should * account for it ASAP. */ if (likely(hw->mac_type >= e1000_82571)) atomic_inc(&adapter->irq_sem); #endif if (unlikely(!icr)) {//由于存在共享中断线的可能 要看是否是本网卡的中断 #ifdef CONFIG_E1000_NAPI if (hw->mac_type >= e1000_82571) e1000_irq_enable(adapter); #endif return IRQ_NONE; /* Not our interrupt */ } if (unlikely(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC))) {//处理类似乱序或者网卡被down掉的情况 hw->get_link_status = 1; /* 80003ES2LAN workaround-- * For packet buffer work-around on link down event; * disable receives here in the ISR and * reset adapter in watchdog */ if (netif_carrier_ok(netdev) && (adapter->hw.mac_type == e1000_80003es2lan)) { /* disable receives */ rctl = E1000_READ_REG(hw, RCTL); E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN); } /* guard against interrupt when we're going down */ if (!test_bit(__E1000_DOWN, &adapter->flags)) mod_timer(&adapter->watchdog_timer, jiffies + 1); } #ifdef CONFIG_E1000_NAPI if (unlikely(hw->mac_type < e1000_82571)) { atomic_inc(&adapter->irq_sem); E1000_WRITE_REG(hw, IMC, ~0);//关中断 E1000_WRITE_FLUSH(hw); } if (likely(netif_rx_schedule_prep(netdev))) __netif_rx_schedule(netdev);//如果定义了NAPI 软中断调度开始处理已收到的数据包 else e1000_irq_enable(adapter); #else /* Writing IMC and IMS is needed for 82547. * Due to Hub Link bus being occupied, an interrupt * de-assertion message is not able to be sent. * When an interrupt assertion message is generated later, * two messages are re-ordered and sent out. * That causes APIC to think 82547 is in de-assertion * state, while 82547 is in assertion state, resulting * in dead lock. Writing IMC forces 82547 into * de-assertion state. */ if (hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2) { atomic_inc(&adapter->irq_sem); E1000_WRITE_REG(hw, IMC, ~0); } for (i = 0; i < E1000_MAX_INTR; i++) //如果是非NAPI的情况 就有限次的处理收包和发包 if (unlikely(!adapter->clean_rx(adapter, adapter->rx_ring) & !e1000_clean_tx_irq(adapter, adapter->tx_ring))) break; if (hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2) e1000_irq_enable(adapter); #endif return IRQ_HANDLED; } /** * e1000_clean_rx_irq - Send received data up the network stack; legacy * @adapter: board private structure **/ static boolean_t //用于将接收到的报文送至协议栈 如果是NAPI方式则在轮询中被调用 #ifdef CONFIG_E1000_NAPI e1000_clean_rx_irq(struct e1000_adapter *adapter, struct e1000_rx_ring *rx_ring, int *work_done, int work_to_do) |
|
|
9楼 #elsee1000_clean_rx_irq(struct e1000_adapter *adapter, struct e1000_rx_ring *rx_ring) #endif { struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; struct e1000_rx_desc *rx_desc, *next_rxd; struct e1000_buffer *buffer_info, *next_buffer; unsigned long flags; uint32_t length; uint8_t last_byte; unsigned int i; int cleaned_count = 0; boolean_t cleaned = FALSE; i = rx_ring->next_to_clean;//找到现在要处理的偏移量 rx_desc = E1000_RX_DESC(*rx_ring, i);//根据偏移量找到接收描述符 buffer_info = &rx_ring->buffer_info[i];//以及缓冲描述符 while (rx_desc->status & E1000_RXD_STAT_DD) {//如果当前包已经完成传输 struct sk_buff *skb; u8 status; #ifdef CONFIG_E1000_NAPI//对于napi而言 加上这次工作量 if (*work_done >= work_to_do) break; (*work_done)++; #endif status = rx_desc->status; skb = buffer_info->skb; buffer_info->skb = NULL;//把buffer null掉 表示这个报文要交到协议栈了 prefetch(skb->data - NET_IP_ALIGN); if (++i == rx_ring->count) i = 0; next_rxd = E1000_RX_DESC(*rx_ring, i);//指向下个报文描述符 prefetch(next_rxd); next_buffer = &rx_ring->buffer_info[i];//和报文缓存 cleaned = TRUE; cleaned_count++; pci_unmap_single(pdev, buffer_info->dma, buffer_info->length, PCI_DMA_FROMDEVICE);//因为传输完成解除对报文的流式映射 length = le16_to_cpu(rx_desc->length);// if (unlikely(!(status & E1000_RXD_STAT_EOP))) { /* All receives must fit into a single buffer */ E1000_DBG("%s: Receive packet consumed multiple" " buffers/n", netdev->name); /* recycle */ buffer_info->skb = skb; goto next_desc; } if (unlikely(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK)) { last_byte = *(skb->data + length - 1); if (TBI_ACCEPT(&adapter->hw, status, rx_desc->errors, length, last_byte)) { spin_lock_irqsave(&adapter->stats_lock, flags); e1000_tbi_adjust_stats(&adapter->hw, &adapter->stats, length, skb->data); spin_unlock_irqrestore(&adapter->stats_lock, flags); length--; } else { /* recycle */ buffer_info->skb = skb; goto next_desc; } } /* adjust length to remove Ethernet CRC, this must be * done after the TBI_ACCEPT workaround above */ length -= 4; /* code added for copybreak, this should improve * performance for small packets with large amounts * of reassembly being done in the stack */ #define E1000_CB_LENGTH 256//在这里有个对小包的特殊情况 如果包长度小于预定长度 则分配个报文长度的skb送至协议栈 原有skb保留可供以后使用 if (length < E1000_CB_LENGTH) { struct sk_buff *new_skb = netdev_alloc_skb(netdev, length + NET_IP_ALIGN); if (new_skb) { skb_reserve(new_skb, NET_IP_ALIGN); memcpy(new_skb->data - NET_IP_ALIGN, skb->data - NET_IP_ALIGN, length + NET_IP_ALIGN); /* save the skb in buffer_info as good */ buffer_info->skb = skb; skb = new_skb; skb_put(skb, length); } } else skb_put(skb, length); /* end copybreak code */ /* Receive Checksum Offload */ e1000_rx_checksum(adapter, (uint32_t)(status) | ((uint32_t)(rx_desc->errors) << 24), le16_to_cpu(rx_desc->csum), skb); skb->protocol = eth_type_trans(skb, netdev); #ifdef CONFIG_E1000_NAPI if (unlikely(adapter->vlgrp && (status & E1000_RXD_STAT_VP))) { vlan_hwaccel_receive_skb(skb, adapter->vlgrp, le16_to_cpu(rx_desc->special) & E1000_RXD_SPC_VLAN_MASK); } else { netif_receive_skb(skb);//以napi方式将包送至协议栈 } #else /* CONFIG_E1000_NAPI */ if (unlikely(adapter->vlgrp && (status & E1000_RXD_STAT_VP))) { vlan_hwaccel_rx(skb, adapter->vlgrp, le16_to_cpu(rx_desc->special) & E1000_RXD_SPC_VLAN_MASK); } else { netif_rx(skb);//如果是非napi方式 用此方法 } #endif /* CONFIG_E1000_NAPI */ netdev->last_rx = jiffies; next_desc: rx_desc->status = 0;//处理完这个描述符所指向的数据后 请空这个描述符的状态位 /* return some buffers to hardware, one at a time is too slow */ if (unlikely(cleaned_count >= E1000_RX_BUFFER_WRITE)) {//每次处理的buffer累计到一定数量的时候就返回些空buffer以免一次处理全部 adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count); cleaned_count = 0; } /* use prefetched values */ rx_desc = next_rxd; buffer_info = next_buffer; } rx_ring->next_to_clean = i; cleaned_count = E1000_DESC_UNUSED(rx_ring);//结尾时再检查一次 if (cleaned_count) adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count); return cleaned; } |
|
|
10楼 static voide1000_tx_queue(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, int tx_flags, int count)//根据buffer数组设置发送描述符并写寄存器进行发送 { struct e1000_tx_desc *tx_desc = NULL; struct e1000_buffer *buffer_info; uint32_t txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS; unsigned int i; if (likely(tx_flags & E1000_TX_FLAGS_TSO)) {//根据TSO标志设置描述符 txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D | E1000_TXD_CMD_TSE; txd_upper |= E1000_TXD_POPTS_TXSM << 8; if (likely(tx_flags & E1000_TX_FLAGS_IPV4)) txd_upper |= E1000_TXD_POPTS_IXSM << 8; } if (likely(tx_flags & E1000_TX_FLAGS_CSUM)) {//更具校验和标志设置描述符 txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; txd_upper |= E1000_TXD_POPTS_TXSM << 8; } if (unlikely(tx_flags & E1000_TX_FLAGS_VLAN)) {//根据VLAN标志设置描述符 txd_lower |= E1000_TXD_CMD_VLE; txd_upper |= (tx_flags & E1000_TX_FLAGS_VLAN_MASK); } i = tx_ring->next_to_use;//找到下个可用的发送描述符 while (count--) { buffer_info = &tx_ring->buffer_info[i];//找到对应buffer tx_desc = E1000_TX_DESC(*tx_ring, i);//找到对应描述符 tx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);//在描述符中记录DMA所用的物理地址 tx_desc->lower.data = cpu_to_le32(txd_lower | buffer_info->length); tx_desc->upper.data = cpu_to_le32(txd_upper);//分别设置描述符的高32位和低32位 if (unlikely(++i == tx_ring->count)) i = 0; } tx_desc->lower.data |= cpu_to_le32(adapter->txd_cmd);//额外的为eop描述符设定位 /*adapter->txd_cmd = E1000_TXD_CMD_IDE | E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS;*/ /* Force memory writes to complete before letting h/w * know there are new descriptors to fetch. (Only * applicable for weak-ordered memory model archs, * such as IA-64). */ wmb(); tx_ring->next_to_use = i; writel(i, adapter->hw.hw_addr + tx_ring->tdt);//将新的可用号做为rdt写入寄存器 在此前位置的包将被网卡做发送处理 } |
|
|
18楼 static inte1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)//网卡的发送函数 省去TSO的部分 { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_tx_ring *tx_ring; unsigned int first, max_per_txd = E1000_MAX_DATA_PER_TXD; unsigned int max_txd_pwr = E1000_MAX_TXD_PWR; unsigned int tx_flags = 0; unsigned int len = skb->len; unsigned long flags; unsigned int nr_frags = 0; unsigned int mss = 0; int count = 0; int tso; unsigned int f; len -= skb->data_len; /* This goes back to the question of how to logically map a tx queue * to a flow. Right now, performance is impacted slightly negatively * if using multiple tx queues. If the stack breaks away from a * single qdisc implementation, we can look at this again. */ tx_ring = adapter->tx_ring; if (unlikely(skb->len <= 0)) { dev_kfree_skb_any(skb); return NETDEV_TX_OK; } /* 82571 and newer doesn't need the workaround that limited descriptor * length to 4kB */ if (adapter->hw.mac_type >= e1000_82571) max_per_txd = 8192; if (skb->ip_summed == CHECKSUM_PARTIAL) count++; count += TXD_USE_COUNT(len, max_txd_pwr);//加上第一个数据分段所要使用的描述符数 if (adapter->pcix_82544) count++; /* work-around for errata 10 and it applies to all controllers * in PCI-X mode, so add one more descriptor to the count */ if (unlikely((adapter->hw.bus_type == e1000_bus_type_pcix) && (len > 2015))) count++; nr_frags = skb_shinfo(skb)->nr_frags; for (f = 0; f < nr_frags; f++) count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size, max_txd_pwr);//加上剩余分段所要使用的描述符数 if (adapter->pcix_82544) count += nr_frags; if (adapter->hw.tx_pkt_filtering && (adapter->hw.mac_type == e1000_82573)) e1000_transfer_dhcp_info(adapter, skb); local_irq_save(flags); if (!spin_trylock(&tx_ring->tx_lock)) { /* Collision - tell upper layer to requeue */ local_irq_restore(flags); return NETDEV_TX_LOCKED; } /* need: count + 2 desc gap to keep tail from touching * head, otherwise try next time */ if (unlikely(e1000_maybe_stop_tx(netdev, tx_ring, count + 2))) {//看看是否有足够的空闲描述符够使用 spin_unlock_irqrestore(&tx_ring->tx_lock, flags); return NETDEV_TX_BUSY; } if (unlikely(adapter->hw.mac_type == e1000_82547)) { if (unlikely(e1000_82547_fifo_workaround(adapter, skb))) { netif_stop_queue(netdev); mod_timer(&adapter->tx_fifo_stall_timer, jiffies + 1); spin_unlock_irqrestore(&tx_ring->tx_lock, flags); return NETDEV_TX_BUSY; } } if (unlikely(adapter->vlgrp && vlan_tx_tag_present(skb))) {//根据vlan选项设置标志位 tx_flags |= E1000_TX_FLAGS_VLAN; tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT); } first = tx_ring->next_to_use;//找到第一个可用的序号 tso = e1000_tso(adapter, tx_ring, skb); if (tso < 0) { dev_kfree_skb_any(skb); spin_unlock_irqrestore(&tx_ring->tx_lock, flags); return NETDEV_TX_OK; } if (likely(tso)) {//根据TSO选项设置标志位 tx_ring->last_tx_tso = 1; tx_flags |= E1000_TX_FLAGS_TSO; } else if (likely(e1000_tx_csum(adapter, tx_ring, skb))) tx_flags |= E1000_TX_FLAGS_CSUM;//根据校验和选项设置标志位 /* Old method was to assume IPv4 packet by default if TSO was enabled. * 82571 hardware supports TSO capabilities for IPv6 as well... * no longer assume, we must. */ if (likely(skb->protocol == htons(ETH_P_IP))) tx_flags |= E1000_TX_FLAGS_IPV4;//根据协议选项设置标志位 e1000_tx_queue(adapter, tx_ring, tx_flags, e1000_tx_map(adapter, tx_ring, skb, first, max_per_txd, nr_frags, mss));//将要发送的包加入发送队列 netdev->trans_start = jiffies; /* Make sure there is space in the ring for the next send. */ e1000_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 2); spin_unlock_irqrestore(&tx_ring->tx_lock, flags); return NETDEV_TX_OK; } |
|
|
21楼 tatic int //为一个skb建立buffer数组和对应分片的联系 设置DMAe1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, struct sk_buff *skb, unsigned int first, unsigned int max_per_txd, unsigned int nr_frags, unsigned int mss)//省去与TSO有关的部分 见链接: http://hi.baidu.com/duanius/blog/item/92300af792abf624730eec77.html |
|
|
发表回复
#ft { clear: both; line-height: 20px; text-align: center; padding-bottom: 50px; }#ft, #ft * { color: rgb(119, 119, 204); font-size: 12px; font-family: Arial; white-space: nowrap; }#ft .c { color: rgb(119, 119, 204); font-family: arial; }#ft a.c { color: rgb(119, 119, 204); }#ft a.c:visited { color: rgb(119, 119, 204); }
©2011 Baidu 贴吧协议 意见反馈小游戏本周继续给力: 投篮高手 四方消砖块 |
||