最近在看网络驱动时,发现这个函数:

 

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

 


 

12-06 23:15