User Tools

Site Tools


alloc_netdev_etherdev

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
alloc_netdev_etherdev [2018/08/28 07:11]
rpjday [alloc_netdev_mqs]
alloc_netdev_etherdev [2018/08/28 08:00] (current)
rpjday [netdev private data]
Line 5: Line 5:
 ===== netdev private data ===== ===== netdev private data =====
  
-From ''​netdevice.h'',​ private data is stored (aligned) after the end of the structure:+From ''​include/​linux/​netdevice.h'', ​optional ​private data is stored (aligned) after the end of the structure:
  
 <​code>​ <​code>​
Line 18: Line 18:
 </​code>​ </​code>​
  
-===== The variations ​of allocating net devices =====+Explanation ​of ''​NETDEV_ALIGN''​ [[https://​stackoverflow.com/​questions/​31459565/​memory-alignment-in-the-alloc-netdev-mqs|here]].
  
-==== alloc_netdev_mqs ==== 
  
-The base allocation routine from ''​net/​core/​dev.c'':​+===== alloc_netdev_mqs ===== 
 + 
 +The base allocation routine from ''​net/​core/​dev.c'' ​for allocating a //single// device:
  
 <​code>​ <​code>​
 +
 +/**
 + * alloc_netdev_mqs - allocate network device
 + * @sizeof_priv:​ size of private data to allocate space for
 + * @name: device name format string
 + * @name_assign_type:​ origin of device name
 + * @setup: callback to initialize device
 + * @txqs: the number of TX subqueues to allocate
 + * @rxqs: the number of RX subqueues to allocate
 + *
 + * Allocates a struct net_device with private data area for driver use
 + * and performs basic initialization. ​ Also allocates subqueue structs
 + * for each queue on the device.
 + */
 struct net_device *alloc_netdev_mqs(int sizeof_priv,​ const char *name, struct net_device *alloc_netdev_mqs(int sizeof_priv,​ const char *name,
-     ​unsigned char name_assign_type,​ + unsigned char name_assign_type,​ 
-     ​void (*setup)(struct net_device *), + void (*setup)(struct net_device *), 
-     ​unsigned int txqs, unsigned int rxqs);+ unsigned int txqs, unsigned int rxqs) 
 +
 + struct net_device *dev; 
 + unsigned int alloc_size;​ 
 + struct net_device *p; 
 + 
 + BUG_ON(strlen(name) >= sizeof(dev->​name));​ 
 + 
 + if (txqs < 1) { 
 + pr_err("​alloc_netdev:​ Unable to allocate device with zero queues\n"​);​ 
 + return NULL; 
 +
 + 
 + if (rxqs < 1) { 
 + pr_err("​alloc_netdev:​ Unable to allocate device with zero RX queues\n"​);​ 
 + return NULL; 
 +
 + 
 + 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;​ 
 +
 + /* ensure 32-byte alignment of whole construct */ 
 + alloc_size += NETDEV_ALIGN - 1; 
 + 
 + p = kvzalloc(alloc_size,​ GFP_KERNEL | __GFP_RETRY_MAYFAIL);​ 
 + if (!p) 
 + return NULL; 
 +        ... snip ...
 </​code>​ </​code>​
  
 +Not a lot of drivers call this routine directly given that you can call more convenient wrappers (see below).
  
-==== More ====+===== Wrappers/​variations ​===== 
 + 
 +==== alloc_netdev()/​alloc_netdev_mq() ==== 
 + 
 +From ''​include/​linux/​netdevice.h'':​ 
 + 
 +<​code>​ 
 + 
 +#define alloc_netdev(sizeof_priv,​ name, name_assign_type,​ setup) \ 
 + alloc_netdev_mqs(sizeof_priv,​ name, name_assign_type,​ setup, 1, 1) 
 + 
 +#define alloc_netdev_mq(sizeof_priv,​ name, name_assign_type,​ setup, count) \ 
 + alloc_netdev_mqs(sizeof_priv,​ name, name_assign_type,​ setup, count, \ 
 + count) 
 +</​code>​ 
 + 
 +==== alloc_etherdev(),​alloc_etherdev_mq(),​alloc_etherdev_mqs() ==== 
 + 
 +From ''​include/​linux/​etherdevice.h'':​ 
 + 
 +<​code>​ 
 +struct net_device *alloc_etherdev_mqs(int sizeof_priv,​ unsigned int txqs, 
 +     unsigned int rxqs); 
 +#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) 
 +</​code>​ 
 + 
 +From ''​net/​ethernet/​net.c'':​
  
 <​code>​ <​code>​
Line 40: Line 113:
  return alloc_netdev_mqs(sizeof_priv,​ "​eth%d",​ NET_NAME_UNKNOWN,​  return alloc_netdev_mqs(sizeof_priv,​ "​eth%d",​ NET_NAME_UNKNOWN,​
  ether_setup,​ txqs, rxqs);  ether_setup,​ txqs, rxqs);
 +}
 +</​code>​
 +
 +==== devm_alloc_etherdev*() ====
 +
 +From ''​include/​linux/​etherdevice.h'':​
 +
 +<​code>​
 +struct net_device *devm_alloc_etherdev_mqs(struct device *dev, int sizeof_priv,​
 +    ​unsigned int txqs,
 +    ​unsigned int rxqs);
 +#define devm_alloc_etherdev(dev,​ sizeof_priv) devm_alloc_etherdev_mqs(dev,​ sizeof_priv,​ 1, 1)
 +</​code>​
 +
 +From ''​net/​ethernet/​net.c'':​
 +
 +<​code>​
 +struct net_device *devm_alloc_etherdev_mqs(struct device *dev, int sizeof_priv,​
 +    ​unsigned int txqs, unsigned int rxqs)
 +{
 + struct net_device **dr;
 + struct net_device *netdev;
 +
 + dr = devres_alloc(devm_free_netdev,​ sizeof(*dr),​ GFP_KERNEL);​
 + if (!dr)
 + return NULL;
 +
 + netdev = alloc_etherdev_mqs(sizeof_priv,​ txqs, rxqs);
 + if (!netdev) {
 + devres_free(dr);​
 + return NULL;
 + }
 +
 + *dr = netdev;
 + devres_add(dev,​ dr);
 +
 + return netdev;
 } }
 </​code>​ </​code>​
alloc_netdev_etherdev.1535440273.txt.gz · Last modified: 2018/08/28 07:11 by rpjday