Linux内核--网络栈实现分析(十一)--驱动程序层(下)

发表于:2013-1-07 10:21

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:闫明    来源:51Testing软件测试网采编

  注:标题中的”(上)“,”(下)“表示分析过程基于数据包的传递方向:”(上)“表示分析是从底层向上分析、”(下)“表示分析是从上向下分析。

  在博文Linux内核--网络栈实现分析(三)--驱动程序层(链路层)(上)中对网络设备结构,网络设备初始化等函数有了初步认识,并列出了设备的发送和接收函数。

  设备接口层会调用函数设备驱动层ei_start_xmit()函数发送数据,这里没有详细分析。

static int ei_start_xmit(struct sk_buff *skb, struct device *dev)
{
    int e8390_base = dev->base_addr;
    struct ei_device *ei_local = (struct ei_device *) dev->priv;//取出网卡设备的私有数据,和具体的网卡型号有关,在ethdev_init()函数中已经分配空间
    int length, send_length;
    unsigned long flags;
   
/*
 *  We normally shouldn't be called if dev->tbusy is set, but the
 *  existing code does anyway. If it has been too long since the
 *  last Tx, we assume the board has died and kick it.
 */
 
    if (dev->tbusy) { /* Do timeouts, just like the 8003 driver. */
  ........................................
  ........................................
    }
   
    /* Sending a NULL skb means some higher layer thinks we've missed an
       tx-done interrupt. Caution: dev_tint() handles the cli()/sti()
       itself. */
    if (skb == NULL) {//该条件似乎不会发生,这用于处理内核中的BUG
  dev_tint(dev);//发送设备中的所有缓存的数据包
  return 0;
    }
   
    length = skb->len;
    if (skb->len <= 0)
  return 0;

    save_flags(flags);
    cli();

    /* Block a timer-based transmit from overlapping. */
    if ((set_bit(0, (void*)&dev->tbusy) != 0) || ei_local->irqlock) {
 printk("%s: Tx access conflict. irq=%d lock=%d tx1=%d tx2=%d last=%d\n",
  dev->name, dev->interrupt, ei_local->irqlock, ei_local->tx1,
  ei_local->tx2, ei_local->lasttx);
 restore_flags(flags);
 return 1;
    }

    /* Mask interrupts from the ethercard. */
    outb(0x00, e8390_base + EN0_IMR);
    ei_local->irqlock = 1;
    restore_flags(flags);

    send_length = ETH_ZLEN < length ? length : ETH_ZLEN;

    if (ei_local->pingpong) {
  int output_page;
  if (ei_local->tx1 == 0) {
   output_page = ei_local->tx_start_page;
   ei_local->tx1 = send_length;
   if (ei_debug  &&  ei_local->tx2 > 0)
    printk("%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n",
        dev->name, ei_local->tx2, ei_local->lasttx,
        ei_local->txing);
  } else if (ei_local->tx2 == 0) {
   output_page = ei_local->tx_start_page + 6;
   ei_local->tx2 = send_length;
   if (ei_debug  &&  ei_local->tx1 > 0)
    printk("%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n",
        dev->name, ei_local->tx1, ei_local->lasttx,
        ei_local->txing);
  } else { /* We should never get here. */
   if (ei_debug)
    printk("%s: No Tx buffers free. irq=%d tx1=%d tx2=%d last=%d\n",
     dev->name, dev->interrupt, ei_local->tx1,
     ei_local->tx2, ei_local->lasttx);
   ei_local->irqlock = 0;
   dev->tbusy = 1;
   outb_p(ENISR_ALL, e8390_base + EN0_IMR);
   return 1;
  }
  ei_block_output(dev, length, skb->data, output_page);
  if (! ei_local->txing) {
   ei_local->txing = 1;
   NS8390_trigger_send(dev, send_length, output_page);
   dev->trans_start = jiffies;
   if (output_page == ei_local->tx_start_page)
    ei_local->tx1 = -1, ei_local->lasttx = -1;
   else
    ei_local->tx2 = -1, ei_local->lasttx = -2;
  } else
   ei_local->txqueue++;

  dev->tbusy = (ei_local->tx1  &&  ei_local->tx2);
    } else {  /* No pingpong, just a single Tx buffer. */
  ei_block_output(dev, length, skb->data, ei_local->tx_start_page);
  ei_local->txing = 1;
  NS8390_trigger_send(dev, send_length, ei_local->tx_start_page);
  dev->trans_start = jiffies;
  dev->tbusy = 1;
    }
   
    /* Turn 8390 interrupts back on. */
    ei_local->irqlock = 0;
    outb_p(ENISR_ALL, e8390_base + EN0_IMR);

    dev_kfree_skb (skb, FREE_WRITE);
   
    return 0;

21/212>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号