最近在看网络驱动时,发现这个函数:
struct net_device *netdev;
netdev = alloc_etherdev(sizeof(synopGMACPciNetworkAdapter));
顺着这个函数进行追踪:
#define alloc_etherdev(sizeof_priv) alloc_etherdev_mq(sizeof_priv, 1)
#define alloc_etherdev_mq(sizeof_priv, count) alloc_etherdev_mqs(sizeof_priv, count, count)
由上面两个宏可以看出,alloc_etherdev最后调用的函数是alloc_etherdev_mqs函数,且传递的参数为:
sizeof_priv:synopGMACPciNetworkAdapter结构体大小。因为net_device可以由驱动程序扩展私有空间,此参数表示扩展的私有空间大小。是网络设备驱动程序私有数据块的大小,在alloc_netdev_mqs函数中,将和net_device数据结构一起分配,但是sizeof_priv也可以设置为0,不需要私有数据块,或者自己分配私有数据块内存。如果和net_device数据结构一起分配驱动程序的私有数据块,则其私有数据块的内存地址通过函数net_dec_priv获取。
count:发送队列的个数
count:接收队列的个数
所以最终是调用到函数数alloc_etherdev_mqs时,传递的参数是:sizeof(synopGMACPciNetworkAdapter) 1 1
函数实现如下:
struct net_device *alloc_etherdev_mqs(int sizeof_priv, unsigned int txqs,
unsigned int rxqs)
{
return alloc_netdev_mqs(sizeof_priv, "eth%d", ether_setup, txqs, rxqs);
}
该函数是封装的alloc_netdev_mqs函数,传递的参数为:
struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
void (*setup)(struct net_device *),
unsigned int txqs, unsigned int rxqs)
{
struct net_device *dev;
size_t alloc_size;
struct net_device *p;
BUG_ON(strlen(name) >= sizeof(dev->name)); //net_device数据结构中设备名称的最大长度是16个字节
/*将net_device数据结构的大小按32字节对齐后,和sizeof_priv私有数据大小相加,产生分配的总内存字节大小*/
alloc_size = sizeof(struct net_device);
if (sizeof_priv) {
/* ensure 32-byte alignment of private area */
alloc_size = ALIGN(alloc_size, NETDEV_ALIGN);
alloc_size += sizeof_priv;
}
/*在这里增加31个字节,是为后面将分配后net_device数据结构的地址调整到32字节边界对齐,预留空间*/
/* ensure 32-byte alignment of whole construct */
alloc_size += NETDEV_ALIGN - 1;
p = kzalloc(alloc_size, GFP_KERNEL); //分配内存
if (!p) {
printk(KERN_ERR "alloc_netdev: Unable to allocate device.\n");
return NULL;
}
/*将net_device数据结构的地址对齐到32字节边界,并记录下调整后的地址和实际分配的地址之间的长度,便于释放空间时使用分配的实际起始地址*/
dev = PTR_ALIGN(p, NETDEV_ALIGN);
dev->padded = (char *)dev - (char *)p;
/*分配一个per_cpu变量,记录该结构的引用计数*/
dev->pcpu_refcnt = alloc_percpu(int);
if (!dev->pcpu_refcnt)
goto free_p;
/*初始化设备的硬件地址列表,并分配一个硬件地址成员*/
if (dev_addr_init(dev))
goto free_pcpu;
/*初始化多播和单播硬件地址列表*/
dev_mc_init(dev);
dev_uc_init(dev);
/*设置设备的网络空间*/
dev_net_set(dev, &init_net);
dev->gso_max_size = GSO_MAX_SIZE;
INIT_LIST_HEAD(&dev->ethtool_ntuple_list.list);
dev->ethtool_ntuple_list.count = 0;
INIT_LIST_HEAD(&dev->napi_list);
INIT_LIST_HEAD(&dev->unreg_list);
INIT_LIST_HEAD(&dev->link_watch_list);
dev->priv_flags = IFF_XMIT_DST_RELEASE;
/*调用setup函数,初始化net_device结构中与设备类型密切相关的成员*/
setup(dev);
/*分配接收队列和发送队列*/
dev->num_tx_queues = txqs;
dev->real_num_tx_queues = txqs;
if (netif_alloc_netdev_queues(dev))
goto free_all;
#ifdef CONFIG_RPS
dev->num_rx_queues = rxqs;
dev->real_num_rx_queues = rxqs;
if (netif_alloc_rx_queues(dev))
goto free_all;
#endif
/*设置网络设备名称*/
strcpy(dev->name, name);
dev->group = INIT_NETDEV_GROUP;
return dev;
free_all:
free_netdev(dev);
return NULL;
free_pcpu:
free_percpu(dev->pcpu_refcnt);
kfree(dev->_tx);
#ifdef CONFIG_RPS
kfree(dev->_rx);
#endif
free_p:
kfree(p);
return NULL;
}