e1000网卡驱动分析

时间:2022-09-02 15:55:31

e1000网卡驱动分析


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楼

#else
e1000_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 void
e1000_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 int
e1000_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数组和对应分片的联系 设置DMA
e1000_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
  • 共有12篇贴子

发表回复

内 容: 本吧发贴,请先 登录 | 注册 
 Ctrl+Enter快捷发表 

#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 贴吧协议  意见反馈

e1000网卡驱动分析

     
  小游戏本周继续给力:
投篮高手           四方消砖块
e1000网卡驱动分析