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
Last revision Both sides next revision
alloc_netdev_etherdev [2018/08/28 07:07]
rpjday [The variations]
alloc_netdev_etherdev [2018/08/28 07:58]
rpjday [alloc_etherdev(),alloc_etherdev_mq()]
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 ''​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 ====+ 
 +===== 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>​ 
 + 
 +Not a lot of drivers call this routine directly given that you can call more convenient wrappers (see below). 
 + 
 +===== Wrappers/​variations ===== 
 + 
 +==== alloc_netdev()/​alloc_netdev_mq() ==== 
 + 
 +From ''​include/​linux/​netdevice.h'':​ 
 + 
 +<​code>​
  
 #define alloc_netdev(sizeof_priv,​ name, name_assign_type,​ setup) \ #define alloc_netdev(sizeof_priv,​ name, name_assign_type,​ setup) \
Line 35: Line 93:
  count)  count)
 </​code>​ </​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 42: 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.txt · Last modified: 2018/08/28 08:00 by rpjday