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);