1cb8a14b2SBartosz Golaszewski // SPDX-License-Identifier: GPL-2.0-or-later
2cb8a14b2SBartosz Golaszewski /*
3cb8a14b2SBartosz Golaszewski * This file contains all networking devres helpers.
4cb8a14b2SBartosz Golaszewski */
5cb8a14b2SBartosz Golaszewski
6cb8a14b2SBartosz Golaszewski #include <linux/device.h>
7cb8a14b2SBartosz Golaszewski #include <linux/etherdevice.h>
8cb8a14b2SBartosz Golaszewski #include <linux/netdevice.h>
9cb8a14b2SBartosz Golaszewski
10f75063abSBartosz Golaszewski struct net_device_devres {
11f75063abSBartosz Golaszewski struct net_device *ndev;
12f75063abSBartosz Golaszewski };
13f75063abSBartosz Golaszewski
devm_free_netdev(struct device * dev,void * this)14f75063abSBartosz Golaszewski static void devm_free_netdev(struct device *dev, void *this)
15cb8a14b2SBartosz Golaszewski {
16f75063abSBartosz Golaszewski struct net_device_devres *res = this;
17f75063abSBartosz Golaszewski
18f75063abSBartosz Golaszewski free_netdev(res->ndev);
19cb8a14b2SBartosz Golaszewski }
20cb8a14b2SBartosz Golaszewski
devm_alloc_etherdev_mqs(struct device * dev,int sizeof_priv,unsigned int txqs,unsigned int rxqs)21cb8a14b2SBartosz Golaszewski struct net_device *devm_alloc_etherdev_mqs(struct device *dev, int sizeof_priv,
22cb8a14b2SBartosz Golaszewski unsigned int txqs, unsigned int rxqs)
23cb8a14b2SBartosz Golaszewski {
24f75063abSBartosz Golaszewski struct net_device_devres *dr;
25cb8a14b2SBartosz Golaszewski
26cb8a14b2SBartosz Golaszewski dr = devres_alloc(devm_free_netdev, sizeof(*dr), GFP_KERNEL);
27cb8a14b2SBartosz Golaszewski if (!dr)
28cb8a14b2SBartosz Golaszewski return NULL;
29cb8a14b2SBartosz Golaszewski
30f75063abSBartosz Golaszewski dr->ndev = alloc_etherdev_mqs(sizeof_priv, txqs, rxqs);
31f75063abSBartosz Golaszewski if (!dr->ndev) {
32cb8a14b2SBartosz Golaszewski devres_free(dr);
33cb8a14b2SBartosz Golaszewski return NULL;
34cb8a14b2SBartosz Golaszewski }
35cb8a14b2SBartosz Golaszewski
36cb8a14b2SBartosz Golaszewski devres_add(dev, dr);
37cb8a14b2SBartosz Golaszewski
38f75063abSBartosz Golaszewski return dr->ndev;
39cb8a14b2SBartosz Golaszewski }
40cb8a14b2SBartosz Golaszewski EXPORT_SYMBOL(devm_alloc_etherdev_mqs);
41cd16627fSBartosz Golaszewski
devm_unregister_netdev(struct device * dev,void * this)42fe189519SBartosz Golaszewski static void devm_unregister_netdev(struct device *dev, void *this)
43cd16627fSBartosz Golaszewski {
44cd16627fSBartosz Golaszewski struct net_device_devres *res = this;
45cd16627fSBartosz Golaszewski
46cd16627fSBartosz Golaszewski unregister_netdev(res->ndev);
47cd16627fSBartosz Golaszewski }
48cd16627fSBartosz Golaszewski
netdev_devres_match(struct device * dev,void * this,void * match_data)49cd16627fSBartosz Golaszewski static int netdev_devres_match(struct device *dev, void *this, void *match_data)
50cd16627fSBartosz Golaszewski {
51cd16627fSBartosz Golaszewski struct net_device_devres *res = this;
52cd16627fSBartosz Golaszewski struct net_device *ndev = match_data;
53cd16627fSBartosz Golaszewski
54cd16627fSBartosz Golaszewski return ndev == res->ndev;
55cd16627fSBartosz Golaszewski }
56cd16627fSBartosz Golaszewski
57cd16627fSBartosz Golaszewski /**
58cd16627fSBartosz Golaszewski * devm_register_netdev - resource managed variant of register_netdev()
59cd16627fSBartosz Golaszewski * @dev: managing device for this netdev - usually the parent device
60cd16627fSBartosz Golaszewski * @ndev: device to register
61cd16627fSBartosz Golaszewski *
62cd16627fSBartosz Golaszewski * This is a devres variant of register_netdev() for which the unregister
63*51a1ebc3Sgushengxian * function will be called automatically when the managing device is
64cd16627fSBartosz Golaszewski * detached. Note: the net_device used must also be resource managed by
65cd16627fSBartosz Golaszewski * the same struct device.
66cd16627fSBartosz Golaszewski */
devm_register_netdev(struct device * dev,struct net_device * ndev)67cd16627fSBartosz Golaszewski int devm_register_netdev(struct device *dev, struct net_device *ndev)
68cd16627fSBartosz Golaszewski {
69cd16627fSBartosz Golaszewski struct net_device_devres *dr;
70cd16627fSBartosz Golaszewski int ret;
71cd16627fSBartosz Golaszewski
72cd16627fSBartosz Golaszewski /* struct net_device must itself be managed. For now a managed netdev
73cd16627fSBartosz Golaszewski * can only be allocated by devm_alloc_etherdev_mqs() so the check is
74cd16627fSBartosz Golaszewski * straightforward.
75cd16627fSBartosz Golaszewski */
76cd16627fSBartosz Golaszewski if (WARN_ON(!devres_find(dev, devm_free_netdev,
77cd16627fSBartosz Golaszewski netdev_devres_match, ndev)))
78cd16627fSBartosz Golaszewski return -EINVAL;
79cd16627fSBartosz Golaszewski
80fe189519SBartosz Golaszewski dr = devres_alloc(devm_unregister_netdev, sizeof(*dr), GFP_KERNEL);
81cd16627fSBartosz Golaszewski if (!dr)
82cd16627fSBartosz Golaszewski return -ENOMEM;
83cd16627fSBartosz Golaszewski
84cd16627fSBartosz Golaszewski ret = register_netdev(ndev);
85cd16627fSBartosz Golaszewski if (ret) {
86cd16627fSBartosz Golaszewski devres_free(dr);
87cd16627fSBartosz Golaszewski return ret;
88cd16627fSBartosz Golaszewski }
89cd16627fSBartosz Golaszewski
90cd16627fSBartosz Golaszewski dr->ndev = ndev;
91cd16627fSBartosz Golaszewski devres_add(ndev->dev.parent, dr);
92cd16627fSBartosz Golaszewski
93cd16627fSBartosz Golaszewski return 0;
94cd16627fSBartosz Golaszewski }
95cd16627fSBartosz Golaszewski EXPORT_SYMBOL(devm_register_netdev);
96