devlink: Allow control devlink ops behavior through feature mask
authorLeon Romanovsky <leonro@nvidia.com>
Tue, 12 Oct 2021 13:15:24 +0000 (16:15 +0300)
committerJakub Kicinski <kuba@kernel.org>
Tue, 12 Oct 2021 23:29:17 +0000 (16:29 -0700)
Introduce new devlink call to set feature mask to control devlink
behavior during device initialization phase after devlink_alloc()
is already called.

This allows us to set reload ops based on device property which
is not known at the beginning of driver initialization.

For the sake of simplicity, this API lacks any type of locking and
needs to be called before devlink_register() to make sure that no
parallel access to the ops is possible at this stage.

Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c
drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_devlink.c
drivers/net/ethernet/mellanox/mlx4/main.c
drivers/net/ethernet/mellanox/mlx5/core/devlink.c
drivers/net/ethernet/mellanox/mlxsw/core.c
drivers/net/netdevsim/dev.c
include/net/devlink.h
net/core/devlink.c

index 59b0ae7d59e018748941672b4052c415a7ebdb52..438fe62fea4db693ed4545d0186b8e7b278eea0b 100644 (file)
@@ -119,6 +119,7 @@ int hclge_devlink_init(struct hclge_dev *hdev)
        priv->hdev = hdev;
        hdev->devlink = devlink;
 
+       devlink_set_features(devlink, DEVLINK_F_RELOAD);
        devlink_register(devlink);
        devlink_reload_enable(devlink);
        return 0;
index d60cc9426f7019ae68b376a2c364be447bc17d9f..519f4108422ee56b940a6bdf68e6d19d5010c646 100644 (file)
@@ -121,6 +121,7 @@ int hclgevf_devlink_init(struct hclgevf_dev *hdev)
        priv->hdev = hdev;
        hdev->devlink = devlink;
 
+       devlink_set_features(devlink, DEVLINK_F_RELOAD);
        devlink_register(devlink);
        devlink_reload_enable(devlink);
        return 0;
index 9541f3a920c8c291ce0d698aafbe30f738a190f5..05e850a40b36ae7ba1ae113b490e1daa33bf0018 100644 (file)
@@ -4025,6 +4025,7 @@ static int mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
                goto err_params_unregister;
 
        pci_save_state(pdev);
+       devlink_set_features(devlink, DEVLINK_F_RELOAD);
        devlink_register(devlink);
        devlink_reload_enable(devlink);
        return 0;
index b9a6cea03951b9ea65b2042f3f1e55c6a4965f0e..fa98b7b9599006ec6b789ccef698e4998044be3e 100644 (file)
@@ -813,6 +813,7 @@ int mlx5_devlink_register(struct devlink *devlink)
        if (err)
                goto traps_reg_err;
 
+       devlink_set_features(devlink, DEVLINK_F_RELOAD);
        return 0;
 
 traps_reg_err:
index 9e831e8b607a4677cd32d89861911e45aa2ede9f..0f1567149a542b098c1d04097eecdda9f952be1d 100644 (file)
@@ -2008,6 +2008,7 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
        }
 
        if (!reload) {
+               devlink_set_features(devlink, DEVLINK_F_RELOAD);
                devlink_register(devlink);
                devlink_reload_enable(devlink);
        }
index cb6645012a30961f4915908e6926265d96fcce2d..520c019dbad59866ae63d8d5f4ff8b74d5d2717b 100644 (file)
@@ -1511,6 +1511,7 @@ int nsim_dev_probe(struct nsim_bus_dev *nsim_bus_dev)
                goto err_psample_exit;
 
        nsim_dev->esw_mode = DEVLINK_ESWITCH_MODE_LEGACY;
+       devlink_set_features(devlink, DEVLINK_F_RELOAD);
        devlink_register(devlink);
        devlink_reload_enable(devlink);
        return 0;
index 7f44ad14e5edf814ae619443c331c5a4065463d3..287f18b8829372e05098f3b6e32455c4d97e70cc 100644 (file)
@@ -1186,6 +1186,11 @@ enum devlink_trap_group_generic_id {
                .min_burst = _min_burst,                                      \
        }
 
+enum {
+       /* device supports reload operations */
+       DEVLINK_F_RELOAD = 1UL << 0,
+};
+
 struct devlink_ops {
        /**
         * @supported_flash_update_params:
@@ -1503,6 +1508,7 @@ static inline struct devlink *devlink_alloc(const struct devlink_ops *ops,
 {
        return devlink_alloc_ns(ops, priv_size, &init_net, dev);
 }
+void devlink_set_features(struct devlink *devlink, u64 features);
 void devlink_register(struct devlink *devlink);
 void devlink_unregister(struct devlink *devlink);
 void devlink_reload_enable(struct devlink *devlink);
index 276e1e421eb4e94098dd60b5c2b005ea6f5f331b..1931caa0ce1e724dddc813d5507d4d738341695e 100644 (file)
@@ -54,6 +54,7 @@ struct devlink {
        struct list_head trap_group_list;
        struct list_head trap_policer_list;
        const struct devlink_ops *ops;
+       u64 features;
        struct xarray snapshot_ids;
        struct devlink_dev_stats stats;
        struct device *dev;
@@ -4032,7 +4033,7 @@ static int devlink_reload(struct devlink *devlink, struct net *dest_net,
        struct net *curr_net;
        int err;
 
-       if (!devlink->reload_enabled)
+       if (!devlink->reload_enabled || !(devlink->features & DEVLINK_F_RELOAD))
                return -EOPNOTSUPP;
 
        memcpy(remote_reload_stats, devlink->stats.remote_reload_stats,
@@ -8985,6 +8986,25 @@ static bool devlink_reload_actions_valid(const struct devlink_ops *ops)
        return true;
 }
 
+/**
+ *     devlink_set_features - Set devlink supported features
+ *
+ *     @devlink: devlink
+ *     @features: devlink support features
+ *
+ *     This interface allows us to set reload ops separatelly from
+ *     the devlink_alloc.
+ */
+void devlink_set_features(struct devlink *devlink, u64 features)
+{
+       ASSERT_DEVLINK_NOT_REGISTERED(devlink);
+
+       WARN_ON(features & DEVLINK_F_RELOAD &&
+               !devlink_reload_supported(devlink->ops));
+       devlink->features = features;
+}
+EXPORT_SYMBOL_GPL(devlink_set_features);
+
 /**
  *     devlink_alloc_ns - Allocate new devlink instance resources
  *     in specific namespace
@@ -9155,7 +9175,7 @@ void devlink_unregister(struct devlink *devlink)
        wait_for_completion(&devlink->comp);
 
        mutex_lock(&devlink_mutex);
-       WARN_ON(devlink_reload_supported(devlink->ops) &&
+       WARN_ON(devlink->features & DEVLINK_F_RELOAD &&
                devlink->reload_enabled);
        devlink_notify_unregister(devlink);
        xa_clear_mark(&devlinks, devlink->index, DEVLINK_REGISTERED);