Blame view

net/devres.c 2.2 KB
cb8a14b20   Bartosz Golaszewski   net: move devres ...
1
2
3
4
5
6
7
8
  // SPDX-License-Identifier: GPL-2.0-or-later
  /*
   * This file contains all networking devres helpers.
   */
  
  #include <linux/device.h>
  #include <linux/etherdevice.h>
  #include <linux/netdevice.h>
f75063abc   Bartosz Golaszewski   net: devres: defi...
9
10
11
12
13
  struct net_device_devres {
  	struct net_device *ndev;
  };
  
  static void devm_free_netdev(struct device *dev, void *this)
cb8a14b20   Bartosz Golaszewski   net: move devres ...
14
  {
f75063abc   Bartosz Golaszewski   net: devres: defi...
15
16
17
  	struct net_device_devres *res = this;
  
  	free_netdev(res->ndev);
cb8a14b20   Bartosz Golaszewski   net: move devres ...
18
19
20
21
22
  }
  
  struct net_device *devm_alloc_etherdev_mqs(struct device *dev, int sizeof_priv,
  					   unsigned int txqs, unsigned int rxqs)
  {
f75063abc   Bartosz Golaszewski   net: devres: defi...
23
  	struct net_device_devres *dr;
cb8a14b20   Bartosz Golaszewski   net: move devres ...
24
25
26
27
  
  	dr = devres_alloc(devm_free_netdev, sizeof(*dr), GFP_KERNEL);
  	if (!dr)
  		return NULL;
f75063abc   Bartosz Golaszewski   net: devres: defi...
28
29
  	dr->ndev = alloc_etherdev_mqs(sizeof_priv, txqs, rxqs);
  	if (!dr->ndev) {
cb8a14b20   Bartosz Golaszewski   net: move devres ...
30
31
32
  		devres_free(dr);
  		return NULL;
  	}
cb8a14b20   Bartosz Golaszewski   net: move devres ...
33
  	devres_add(dev, dr);
f75063abc   Bartosz Golaszewski   net: devres: defi...
34
  	return dr->ndev;
cb8a14b20   Bartosz Golaszewski   net: move devres ...
35
36
  }
  EXPORT_SYMBOL(devm_alloc_etherdev_mqs);
cd16627fc   Bartosz Golaszewski   net: devres: prov...
37

fe189519e   Bartosz Golaszewski   net: devres: rena...
38
  static void devm_unregister_netdev(struct device *dev, void *this)
cd16627fc   Bartosz Golaszewski   net: devres: prov...
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
  {
  	struct net_device_devres *res = this;
  
  	unregister_netdev(res->ndev);
  }
  
  static int netdev_devres_match(struct device *dev, void *this, void *match_data)
  {
  	struct net_device_devres *res = this;
  	struct net_device *ndev = match_data;
  
  	return ndev == res->ndev;
  }
  
  /**
   *	devm_register_netdev - resource managed variant of register_netdev()
   *	@dev: managing device for this netdev - usually the parent device
   *	@ndev: device to register
   *
   *	This is a devres variant of register_netdev() for which the unregister
   *	function will be call automatically when the managing device is
   *	detached. Note: the net_device used must also be resource managed by
   *	the same struct device.
   */
  int devm_register_netdev(struct device *dev, struct net_device *ndev)
  {
  	struct net_device_devres *dr;
  	int ret;
  
  	/* struct net_device must itself be managed. For now a managed netdev
  	 * can only be allocated by devm_alloc_etherdev_mqs() so the check is
  	 * straightforward.
  	 */
  	if (WARN_ON(!devres_find(dev, devm_free_netdev,
  				 netdev_devres_match, ndev)))
  		return -EINVAL;
fe189519e   Bartosz Golaszewski   net: devres: rena...
75
  	dr = devres_alloc(devm_unregister_netdev, sizeof(*dr), GFP_KERNEL);
cd16627fc   Bartosz Golaszewski   net: devres: prov...
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
  	if (!dr)
  		return -ENOMEM;
  
  	ret = register_netdev(ndev);
  	if (ret) {
  		devres_free(dr);
  		return ret;
  	}
  
  	dr->ndev = ndev;
  	devres_add(ndev->dev.parent, dr);
  
  	return 0;
  }
  EXPORT_SYMBOL(devm_register_netdev);