沪东中华造船最新订单:broadcom网卡驱动 代码分析注释

来源:百度文库 编辑:偶看新闻 时间:2024/04/27 15:49:52
broadcom网卡驱动 代码分析注释 (2008-05-03 21:11:08) 标签:杂谈  分类:操作系统

 //注释者: zl

 //注释格式: //注释内容
 //blog: blog.sina.com.cn/foreveralbum
 //date:08.5.3
 //说明:对代码的几个关键函数进行了注释,包括初始化,收发包等

 //函数运行顺序:加载模块->b44_init()->b44_init_one()->register_netdev()
 //注册完后就可以调用驱动程序操作设备了
 

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//此驱动用到了ssb 代码在/driver/ssb
#include

#include
#include
#include


#include "b44.h"

#define DRV_MODULE_NAME  "b44"
#define PFX DRV_MODULE_NAME ": "
#define DRV_MODULE_VERSION "2.0"

#define B44_DEF_MSG_ENABLE   \
 (NETIF_MSG_DRV  | \
  NETIF_MSG_PROBE | \
  NETIF_MSG_LINK  | \
  NETIF_MSG_TIMER | \
  NETIF_MSG_IFDOWN | \
  NETIF_MSG_IFUP  | \
  NETIF_MSG_RX_ERR | \
  NETIF_MSG_TX_ERR)


#define B44_TX_TIMEOUT   (5 * HZ)


#define B44_MIN_MTU   60
#define B44_MAX_MTU   1500

#define B44_RX_RING_SIZE  512
#define B44_DEF_RX_RING_PENDING  200
#define B44_RX_RING_BYTES (sizeof(struct dma_desc) * \
     B44_RX_RING_SIZE)
#define B44_TX_RING_SIZE  512
#define B44_DEF_TX_RING_PENDING  (B44_TX_RING_SIZE - 1)
#define B44_TX_RING_BYTES (sizeof(struct dma_desc) * \
     B44_TX_RING_SIZE)

#define TX_RING_GAP(BP) \
 (B44_TX_RING_SIZE - (BP)->tx_pending)
#define TX_BUFFS_AVAIL(BP)      \
 (((BP)->tx_cons <= (BP)->tx_prod) ?    \
   (BP)->tx_cons + (BP)->tx_pending - (BP)->tx_prod :  \
   (BP)->tx_cons - (BP)->tx_prod - TX_RING_GAP(BP))
#define NEXT_TX(N)  (((N) + 1) & (B44_TX_RING_SIZE - 1))

#define RX_PKT_OFFSET  30
#define RX_PKT_BUF_SZ  (1536 + RX_PKT_OFFSET + 64)


#define B44_TX_WAKEUP_THRESH  (B44_TX_RING_SIZE / 4)


#define B44_PATTERN_BASE 0x400
#define B44_PATTERN_SIZE 0x80
#define B44_PMASK_BASE  0x600
#define B44_PMASK_SIZE  0x10
#define B44_MAX_PATTERNS 16
#define B44_ETHIPV6UDP_HLEN 62
#define B44_ETHIPV4UDP_HLEN 42

static char version[] __devinitdata =
 DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION "\n";

MODULE_AUTHOR("Felix Fietkau, Florian Schirmer, Pekka Pietikainen, David S. Miller");
MODULE_DESCRIPTION("Broadcom 44xx/47xx 10/100 PCI ethernet driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_MODULE_VERSION);

static int b44_debug = -1; 
module_param(b44_debug, int, 0);
MODULE_PARM_DESC(b44_debug, "B44 bitmapped debugging message enable value");


#ifdef CONFIG_B44_PCI
static const struct pci_device_id b44_pci_tbl[] = {
 { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401) },
 { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B0) },
 { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B1) },
 { 0 }
};
MODULE_DEVICE_TABLE(pci, b44_pci_tbl);

static struct pci_driver b44_pci_driver = {
 .name  = DRV_MODULE_NAME,
 .id_table = b44_pci_tbl,
};
#endif

//关于device_id:PCI设备都遵守PCI标准,这个部分所有的PCI设备都是一样的,每个PCI设备都有一段寄存器存储着配置空间,这一部分格式是一样的,
//比如第一个寄存器总是生产商号码,如Realtek就是10ec,而Intel则是另一个数字,这些都是商家像标准组织申请的,是肯定不同的。
//我就可以通过配置空间来辨别其生产商,设备号,不论你什么平台,x86也好,ppc也好,他们都是同一的标准格式
//这里b44_ssb_tbl就是用来匹配配置空间的如果b44_ssb_tbl和配置空间中的相同,就表明这个驱动程序就是用来驱动这个设备的
static const struct ssb_device_id b44_ssb_tbl[] = {
 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_ETHERNET, SSB_ANY_REV),
 SSB_DEVTABLE_END
};


。。。。。。。

//超时函数
static void b44_tx_timeout(struct net_device *dev)
{
 struct b44 *bp = netdev_priv(dev);

 printk(KERN_ERR PFX "%s: transmit timed out, resetting\n",
        dev->name);

 spin_lock_irq(&bp->lock);

 b44_halt(bp); //终止网卡
 b44_init_rings(bp);
 b44_init_hw(bp, B44_FULL_RESET);

 spin_unlock_irq(&bp->lock);

 b44_enable_ints(bp);

 netif_wake_queue(dev); //唤醒网卡等待队列
}

 

。。。。。。。。。。。

//打开设备函数
//这个函数一般是用来注册所有系统资源包括IO端口,IRQ DMA等
static int b44_open(struct net_device *dev)
{
 struct b44 *bp = netdev_priv(dev); //获得网卡私有数据地址
 int err;

 err = b44_alloc_consistent(bp, GFP_KERNEL);
 if (err)
  goto out;

 napi_enable(&bp->napi); //napi是采用轮询的方式接受数据包见设备驱动p518

 b44_init_rings(bp);
 b44_init_hw(bp, B44_FULL_RESET); //做硬件初始化

 b44_check_phy(bp);

 err = request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev); //注册中断
 if (unlikely(err < 0)) {
  napi_disable(&bp->napi);
  b44_chip_reset(bp, B44_CHIP_RESET_PARTIAL);
  b44_free_rings(bp);
  b44_free_consistent(bp);
  goto out;
 }

 init_timer(&bp->timer);
 bp->timer.expires = jiffies + HZ;
 bp->timer.data = (unsigned long) bp;
 bp->timer.function = b44_timer;
 add_timer(&bp->timer);

 b44_enable_ints(bp);
 netif_start_queue(dev);
out:
 return err;
}

。。。。。。。。。。。。。。。


//此函数初始话和注册net_device结构体
static int __devinit b44_init_one(struct ssb_device *sdev,
      const struct ssb_device_id *ent)
{
 static int b44_version_printed = 0;
 struct net_device *dev; //net_device指针
 struct b44 *bp; //网卡信息结构指针是net_device结构体的一员,就是linux设备驱动里讲的那个priv结构体
     //它代表着不同网卡的私有数据,比如Intel的网卡和Realtek的网卡在内核中都是以net_device来代表。
     //但是他们是有区别的,比如Intel和Realtek实现同一功能的方法不一样,这些都是靠着priv来体现。
     //所以这里把拿出来同net_device相提并论。分配内存时,net_device中除了priv以外的成员都是固定的,
     //而priv的大小是可以任意的,所以分配时要把priv的大小传过去。
     //priv在net_device结构体里是void *priv; void类型指针所以可以指向任何类型的priv结构体
 int err;
 DECLARE_MAC_BUF(mac);

 instance++;

 if (b44_version_printed++ == 0)
  printk(KERN_INFO "%s", version);

 //分配net_device结构体空间,参数是priv的大小
 //这个函数是alloc_netdev的封装,不但分配空间在做些必须的初始化
 dev = alloc_etherdev(sizeof(*bp));
 if (!dev) {
  dev_err(sdev->dev, "Etherdev alloc failed, aborting.\n");
  err = -ENOMEM;
  goto out;
 }

 SET_NETDEV_DEV(dev, sdev->dev);

 
 dev->features |= 0;

 bp = netdev_priv(dev);
 bp->sdev = sdev;
 bp->dev = dev;

 bp->msg_enable = netif_msg_init(b44_debug, B44_DEF_MSG_ENABLE);

 spin_lock_init(&bp->lock);

 bp->rx_pending = B44_DEF_RX_RING_PENDING;
 bp->tx_pending = B44_DEF_TX_RING_PENDING;

 //一下是给一些函数指针赋值具体可以看设备驱动一书
 dev->open = b44_open;
 dev->stop = b44_close;
 dev->hard_start_xmit = b44_start_xmit;
 dev->get_stats = b44_get_stats;
 dev->set_multicast_list = b44_set_rx_mode;
 dev->set_mac_address = b44_set_mac_addr;
 dev->do_ioctl = b44_ioctl;
 dev->tx_timeout = b44_tx_timeout;
 netif_napi_add(dev, &bp->napi, b44_poll, 64);
 dev->watchdog_timeo = B44_TX_TIMEOUT;
#ifdef CONFIG_NET_POLL_CONTROLLER
 dev->poll_controller = b44_poll_controller;
#endif
 dev->change_mtu = b44_change_mtu;
 dev->irq = sdev->irq;
 SET_ETHTOOL_OPS(dev, &b44_ethtool_ops);

 netif_carrier_off(dev);

 err = ssb_bus_powerup(sdev->bus, 0);
 if (err) {
  dev_err(sdev->dev,
   "Failed to powerup the bus\n");
  goto err_out_free_dev;
 }
 err = ssb_dma_set_mask(sdev, DMA_30BIT_MASK);
 if (err) {
  dev_err(sdev->dev,
   "Required 30BIT DMA mask unsupported by the system.\n");
  goto err_out_powerdown;
 }
 err = b44_get_invariants(bp);
 if (err) {
  dev_err(sdev->dev,
   "Problem fetching invariants of chip, aborting.\n");
  goto err_out_powerdown;
 }

 bp->mii_if.dev = dev;
 bp->mii_if.mdio_read = b44_mii_read;
 bp->mii_if.mdio_write = b44_mii_write;
 bp->mii_if.phy_id = bp->phy_addr;
 bp->mii_if.phy_id_mask = 0x1f;
 bp->mii_if.reg_num_mask = 0x1f;

 
 bp->flags |= (B44_FLAG_ADV_10HALF | B44_FLAG_ADV_10FULL |
        B44_FLAG_ADV_100HALF | B44_FLAG_ADV_100FULL);

 
 bp->flags |= B44_FLAG_PAUSE_AUTO;

 //注册net_device结构体
 err = register_netdev(dev);
 if (err) {
  dev_err(sdev->dev, "Cannot register net device, aborting.\n");
  goto err_out_powerdown;
 }

 ssb_set_drvdata(sdev, dev);

 
 b44_chip_reset(bp, B44_CHIP_RESET_FULL);

 printk(KERN_INFO "%s: Broadcom 44xx/47xx 10/100BaseT Ethernet %s\n",
        dev->name, print_mac(mac, dev->dev_addr));

 return 0;

err_out_powerdown:
 ssb_bus_may_powerdown(sdev->bus);

err_out_free_dev:
 free_netdev(dev);

out:
 return err;
}

static void __devexit b44_remove_one(struct ssb_device *sdev)
{
 struct net_device *dev = ssb_get_drvdata(sdev);

 unregister_netdev(dev);
 ssb_bus_may_powerdown(sdev->bus);
 free_netdev(dev);
 ssb_pcihost_set_power_state(sdev, PCI_D3hot);
 ssb_set_drvdata(sdev, NULL);
}


static struct ssb_driver b44_ssb_driver = {
 .name  = DRV_MODULE_NAME, //模块名字
 .id_table = b44_ssb_tbl, //模块id表
 .probe  = b44_init_one, //探针 用来初始化 注册 netdev结构
 .remove  = __devexit_p(b44_remove_one),
 .suspend = b44_suspend,
 .resume  = b44_resume,
};
//register pci
static inline int b44_pci_init(void)
{
 int err = 0;
#ifdef CONFIG_B44_PCI
 err = ssb_pcihost_register(&b44_pci_driver);
#endif
 return err;
}
//unregister pci
static inline void b44_pci_exit(void)
{
#ifdef CONFIG_B44_PCI
 ssb_pcihost_unregister(&b44_pci_driver);
#endif
}

//初始化函数,用来注册pci设备和ssb驱动
static int __init b44_init(void)
{
 //这里是dma的一些设置,设备驱动一书中有介绍,我本人也还没看
 unsigned int dma_desc_align_size = dma_get_cache_alignment();
 int err;

 
 dma_desc_align_mask = ~(dma_desc_align_size - 1);
 dma_desc_sync_size = max_t(unsigned int, dma_desc_align_size, sizeof(struct dma_desc));

 err = b44_pci_init();
 if (err)
  return err;
 err = ssb_driver_register(&b44_ssb_driver);
 if (err)
  b44_pci_exit();
 return err;
}

static void __exit b44_cleanup(void)
{
 ssb_driver_unregister(&b44_ssb_driver);
 b44_pci_exit();
}

//设置模块加载时的初始化函数
module_init(b44_init);
//设置模块卸载时运行的函数
module_exit(b44_cleanup);