linux 網路裝置驅動之alloc_etherdev
阿新 • • 發佈:2018-12-21
最近在看網路驅動時,發現這個函式:
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; }