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