hc
2024-08-12 0517ab8c70e05fc5877c0c6dae1a5f42a16dcf88
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// 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>
 
struct net_device_devres {
   struct net_device *ndev;
};
 
static void devm_free_netdev(struct device *dev, void *this)
{
   struct net_device_devres *res = this;
 
   free_netdev(res->ndev);
}
 
struct net_device *devm_alloc_etherdev_mqs(struct device *dev, int sizeof_priv,
                      unsigned int txqs, unsigned int rxqs)
{
   struct net_device_devres *dr;
 
   dr = devres_alloc(devm_free_netdev, sizeof(*dr), GFP_KERNEL);
   if (!dr)
       return NULL;
 
   dr->ndev = alloc_etherdev_mqs(sizeof_priv, txqs, rxqs);
   if (!dr->ndev) {
       devres_free(dr);
       return NULL;
   }
 
   devres_add(dev, dr);
 
   return dr->ndev;
}
EXPORT_SYMBOL(devm_alloc_etherdev_mqs);
 
static void devm_unregister_netdev(struct device *dev, void *this)
{
   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;
 
   dr = devres_alloc(devm_unregister_netdev, sizeof(*dr), GFP_KERNEL);
   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);