xref: /openbmc/linux/net/devres.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
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