Commit e03f0dfb authored by David S. Miller's avatar David S. Miller

Merge branch 'devlink-instances-relationships'

Jiri Pirko says:

====================
expose devlink instances relationships

From: Jiri Pirko <jiri@nvidia.com>

Currently, the user can instantiate new SF using "devlink port add"
command. That creates an E-switch representor devlink port.

When user activates this SF, there is an auxiliary device created and
probed for it which leads to SF devlink instance creation.

There is 1:1 relationship between E-switch representor devlink port and
the SF auxiliary device devlink instance.

Also, for example in mlx5, one devlink instance is created for
PCI device and one is created for an auxiliary device that represents
the uplink port. The relation between these is invisible to the user.

Patches #1-#3 and #5 are small preparations.

Patch #4 adds netnsid attribute for nested devlink if that in a
different namespace.

Patch #5 is the main one in this set, introduces the relationship
tracking infrastructure later on used to track SFs, linecards and
devlink instance relationships with nested devlink instances.

Expose the relation to the user by introducing new netlink attribute
DEVLINK_PORT_FN_ATTR_DEVLINK which contains the devlink instance related
to devlink port function. This is done by patch #8.
Patch #9 implements this in mlx5 driver.

Patch #10 converts the linecard nested devlink handling to the newly
introduced rel infrastructure.

Patch #11 benefits from the rel infra and introduces possiblitily to
have relation between devlink instances.
Patch #12 implements this in mlx5 driver.

Examples:
$ devlink dev
pci/0000:08:00.0: nested_devlink auxiliary/mlx5_core.eth.0
pci/0000:08:00.1: nested_devlink auxiliary/mlx5_core.eth.1
auxiliary/mlx5_core.eth.1
auxiliary/mlx5_core.eth.0

$ devlink port add pci/0000:08:00.0 flavour pcisf pfnum 0 sfnum 106
pci/0000:08:00.0/32768: type eth netdev eth4 flavour pcisf controller 0 pfnum 0 sfnum 106 splittable false
  function:
    hw_addr 00:00:00:00:00:00 state inactive opstate detached roce enable
$ devlink port function set pci/0000:08:00.0/32768 state active
$ devlink port show pci/0000:08:00.0/32768
pci/0000:08:00.0/32768: type eth netdev eth4 flavour pcisf controller 0 pfnum 0 sfnum 106 splittable false
  function:
    hw_addr 00:00:00:00:00:00 state active opstate attached roce enable nested_devlink auxiliary/mlx5_core.sf.2

$ devlink port show pci/0000:08:00.0/32768
pci/0000:08:00.0/32768: type eth netdev eth4 flavour pcisf controller 0 pfnum 0 sfnum 106 splittable false
  function:
    hw_addr 00:00:00:00:00:00 state active opstate attached roce enable nested_devlink auxiliary/mlx5_core.sf.2 nested_devlink_netns ns1
====================
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1e73cfe8 6c75258c
...@@ -138,7 +138,6 @@ static int mlx5_devlink_reload_down(struct devlink *devlink, bool netns_change, ...@@ -138,7 +138,6 @@ static int mlx5_devlink_reload_down(struct devlink *devlink, bool netns_change,
{ {
struct mlx5_core_dev *dev = devlink_priv(devlink); struct mlx5_core_dev *dev = devlink_priv(devlink);
struct pci_dev *pdev = dev->pdev; struct pci_dev *pdev = dev->pdev;
bool sf_dev_allocated;
int ret = 0; int ret = 0;
if (mlx5_dev_is_lightweight(dev)) { if (mlx5_dev_is_lightweight(dev)) {
...@@ -148,16 +147,6 @@ static int mlx5_devlink_reload_down(struct devlink *devlink, bool netns_change, ...@@ -148,16 +147,6 @@ static int mlx5_devlink_reload_down(struct devlink *devlink, bool netns_change,
return 0; return 0;
} }
sf_dev_allocated = mlx5_sf_dev_allocated(dev);
if (sf_dev_allocated) {
/* Reload results in deleting SF device which further results in
* unregistering devlink instance while holding devlink_mutext.
* Hence, do not support reload.
*/
NL_SET_ERR_MSG_MOD(extack, "reload is unsupported when SFs are allocated");
return -EOPNOTSUPP;
}
if (mlx5_lag_is_active(dev)) { if (mlx5_lag_is_active(dev)) {
NL_SET_ERR_MSG_MOD(extack, "reload is unsupported in Lag mode"); NL_SET_ERR_MSG_MOD(extack, "reload is unsupported in Lag mode");
return -EOPNOTSUPP; return -EOPNOTSUPP;
......
...@@ -12,11 +12,19 @@ struct mlx5e_dev *mlx5e_create_devlink(struct device *dev, ...@@ -12,11 +12,19 @@ struct mlx5e_dev *mlx5e_create_devlink(struct device *dev,
{ {
struct mlx5e_dev *mlx5e_dev; struct mlx5e_dev *mlx5e_dev;
struct devlink *devlink; struct devlink *devlink;
int err;
devlink = devlink_alloc_ns(&mlx5e_devlink_ops, sizeof(*mlx5e_dev), devlink = devlink_alloc_ns(&mlx5e_devlink_ops, sizeof(*mlx5e_dev),
devlink_net(priv_to_devlink(mdev)), dev); devlink_net(priv_to_devlink(mdev)), dev);
if (!devlink) if (!devlink)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
err = devl_nested_devlink_set(priv_to_devlink(mdev), devlink);
if (err) {
devlink_free(devlink);
return ERR_PTR(err);
}
devlink_register(devlink); devlink_register(devlink);
return devlink_priv(devlink); return devlink_priv(devlink);
} }
......
...@@ -1405,9 +1405,9 @@ static int mlx5_load(struct mlx5_core_dev *dev) ...@@ -1405,9 +1405,9 @@ static int mlx5_load(struct mlx5_core_dev *dev)
static void mlx5_unload(struct mlx5_core_dev *dev) static void mlx5_unload(struct mlx5_core_dev *dev)
{ {
mlx5_eswitch_disable(dev->priv.eswitch);
mlx5_devlink_traps_unregister(priv_to_devlink(dev)); mlx5_devlink_traps_unregister(priv_to_devlink(dev));
mlx5_sf_dev_table_destroy(dev); mlx5_sf_dev_table_destroy(dev);
mlx5_eswitch_disable(dev->priv.eswitch);
mlx5_sriov_detach(dev); mlx5_sriov_detach(dev);
mlx5_lag_remove_mdev(dev); mlx5_lag_remove_mdev(dev);
mlx5_ec_cleanup(dev); mlx5_ec_cleanup(dev);
......
...@@ -19,6 +19,12 @@ struct mlx5_sf_dev { ...@@ -19,6 +19,12 @@ struct mlx5_sf_dev {
u16 fn_id; u16 fn_id;
}; };
struct mlx5_sf_peer_devlink_event_ctx {
u16 fn_id;
struct devlink *devlink;
int err;
};
void mlx5_sf_dev_table_create(struct mlx5_core_dev *dev); void mlx5_sf_dev_table_create(struct mlx5_core_dev *dev);
void mlx5_sf_dev_table_destroy(struct mlx5_core_dev *dev); void mlx5_sf_dev_table_destroy(struct mlx5_core_dev *dev);
......
...@@ -8,6 +8,20 @@ ...@@ -8,6 +8,20 @@
#include "dev.h" #include "dev.h"
#include "devlink.h" #include "devlink.h"
static int mlx5_core_peer_devlink_set(struct mlx5_sf_dev *sf_dev, struct devlink *devlink)
{
struct mlx5_sf_peer_devlink_event_ctx event_ctx = {
.fn_id = sf_dev->fn_id,
.devlink = devlink,
};
int ret;
ret = mlx5_blocking_notifier_call_chain(sf_dev->parent_mdev,
MLX5_DRIVER_EVENT_SF_PEER_DEVLINK,
&event_ctx);
return ret == NOTIFY_OK ? event_ctx.err : 0;
}
static int mlx5_sf_dev_probe(struct auxiliary_device *adev, const struct auxiliary_device_id *id) static int mlx5_sf_dev_probe(struct auxiliary_device *adev, const struct auxiliary_device_id *id)
{ {
struct mlx5_sf_dev *sf_dev = container_of(adev, struct mlx5_sf_dev, adev); struct mlx5_sf_dev *sf_dev = container_of(adev, struct mlx5_sf_dev, adev);
...@@ -54,9 +68,21 @@ static int mlx5_sf_dev_probe(struct auxiliary_device *adev, const struct auxilia ...@@ -54,9 +68,21 @@ static int mlx5_sf_dev_probe(struct auxiliary_device *adev, const struct auxilia
mlx5_core_warn(mdev, "mlx5_init_one err=%d\n", err); mlx5_core_warn(mdev, "mlx5_init_one err=%d\n", err);
goto init_one_err; goto init_one_err;
} }
err = mlx5_core_peer_devlink_set(sf_dev, devlink);
if (err) {
mlx5_core_warn(mdev, "mlx5_core_peer_devlink_set err=%d\n", err);
goto peer_devlink_set_err;
}
devlink_register(devlink); devlink_register(devlink);
return 0; return 0;
peer_devlink_set_err:
if (mlx5_dev_is_lightweight(sf_dev->mdev))
mlx5_uninit_one_light(sf_dev->mdev);
else
mlx5_uninit_one(sf_dev->mdev);
init_one_err: init_one_err:
iounmap(mdev->iseg); iounmap(mdev->iseg);
remap_err: remap_err:
......
...@@ -28,6 +28,7 @@ struct mlx5_sf_table { ...@@ -28,6 +28,7 @@ struct mlx5_sf_table {
struct mutex sf_state_lock; /* Serializes sf state among user cmds & vhca event handler. */ struct mutex sf_state_lock; /* Serializes sf state among user cmds & vhca event handler. */
struct notifier_block esw_nb; struct notifier_block esw_nb;
struct notifier_block vhca_nb; struct notifier_block vhca_nb;
struct notifier_block mdev_nb;
}; };
static struct mlx5_sf * static struct mlx5_sf *
...@@ -511,6 +512,35 @@ static int mlx5_sf_esw_event(struct notifier_block *nb, unsigned long event, voi ...@@ -511,6 +512,35 @@ static int mlx5_sf_esw_event(struct notifier_block *nb, unsigned long event, voi
return 0; return 0;
} }
static int mlx5_sf_mdev_event(struct notifier_block *nb, unsigned long event, void *data)
{
struct mlx5_sf_table *table = container_of(nb, struct mlx5_sf_table, mdev_nb);
struct mlx5_sf_peer_devlink_event_ctx *event_ctx = data;
int ret = NOTIFY_DONE;
struct mlx5_sf *sf;
if (event != MLX5_DRIVER_EVENT_SF_PEER_DEVLINK)
return NOTIFY_DONE;
table = mlx5_sf_table_try_get(table->dev);
if (!table)
return NOTIFY_DONE;
mutex_lock(&table->sf_state_lock);
sf = mlx5_sf_lookup_by_function_id(table, event_ctx->fn_id);
if (!sf)
goto out;
event_ctx->err = devl_port_fn_devlink_set(&sf->dl_port.dl_port,
event_ctx->devlink);
ret = NOTIFY_OK;
out:
mutex_unlock(&table->sf_state_lock);
mlx5_sf_table_put(table);
return ret;
}
static bool mlx5_sf_table_supported(const struct mlx5_core_dev *dev) static bool mlx5_sf_table_supported(const struct mlx5_core_dev *dev)
{ {
return dev->priv.eswitch && MLX5_ESWITCH_MANAGER(dev) && return dev->priv.eswitch && MLX5_ESWITCH_MANAGER(dev) &&
...@@ -544,6 +574,9 @@ int mlx5_sf_table_init(struct mlx5_core_dev *dev) ...@@ -544,6 +574,9 @@ int mlx5_sf_table_init(struct mlx5_core_dev *dev)
if (err) if (err)
goto vhca_err; goto vhca_err;
table->mdev_nb.notifier_call = mlx5_sf_mdev_event;
mlx5_blocking_notifier_register(dev, &table->mdev_nb);
return 0; return 0;
vhca_err: vhca_err:
...@@ -562,6 +595,7 @@ void mlx5_sf_table_cleanup(struct mlx5_core_dev *dev) ...@@ -562,6 +595,7 @@ void mlx5_sf_table_cleanup(struct mlx5_core_dev *dev)
if (!table) if (!table)
return; return;
mlx5_blocking_notifier_unregister(dev, &table->mdev_nb);
mlx5_vhca_event_notifier_unregister(table->dev, &table->vhca_nb); mlx5_vhca_event_notifier_unregister(table->dev, &table->vhca_nb);
mlx5_esw_event_notifier_unregister(dev->priv.eswitch, &table->esw_nb); mlx5_esw_event_notifier_unregister(dev->priv.eswitch, &table->esw_nb);
WARN_ON(refcount_read(&table->refcount)); WARN_ON(refcount_read(&table->refcount));
......
...@@ -132,6 +132,7 @@ static int mlxsw_linecard_bdev_probe(struct auxiliary_device *adev, ...@@ -132,6 +132,7 @@ static int mlxsw_linecard_bdev_probe(struct auxiliary_device *adev,
struct mlxsw_linecard *linecard = linecard_bdev->linecard; struct mlxsw_linecard *linecard = linecard_bdev->linecard;
struct mlxsw_linecard_dev *linecard_dev; struct mlxsw_linecard_dev *linecard_dev;
struct devlink *devlink; struct devlink *devlink;
int err;
devlink = devlink_alloc(&mlxsw_linecard_dev_devlink_ops, devlink = devlink_alloc(&mlxsw_linecard_dev_devlink_ops,
sizeof(*linecard_dev), &adev->dev); sizeof(*linecard_dev), &adev->dev);
...@@ -141,8 +142,12 @@ static int mlxsw_linecard_bdev_probe(struct auxiliary_device *adev, ...@@ -141,8 +142,12 @@ static int mlxsw_linecard_bdev_probe(struct auxiliary_device *adev,
linecard_dev->linecard = linecard_bdev->linecard; linecard_dev->linecard = linecard_bdev->linecard;
linecard_bdev->linecard_dev = linecard_dev; linecard_bdev->linecard_dev = linecard_dev;
err = devlink_linecard_nested_dl_set(linecard->devlink_linecard, devlink);
if (err) {
devlink_free(devlink);
return err;
}
devlink_register(devlink); devlink_register(devlink);
devlink_linecard_nested_dl_set(linecard->devlink_linecard, devlink);
return 0; return 0;
} }
...@@ -151,9 +156,7 @@ static void mlxsw_linecard_bdev_remove(struct auxiliary_device *adev) ...@@ -151,9 +156,7 @@ static void mlxsw_linecard_bdev_remove(struct auxiliary_device *adev)
struct mlxsw_linecard_bdev *linecard_bdev = struct mlxsw_linecard_bdev *linecard_bdev =
container_of(adev, struct mlxsw_linecard_bdev, adev); container_of(adev, struct mlxsw_linecard_bdev, adev);
struct devlink *devlink = priv_to_devlink(linecard_bdev->linecard_dev); struct devlink *devlink = priv_to_devlink(linecard_bdev->linecard_dev);
struct mlxsw_linecard *linecard = linecard_bdev->linecard;
devlink_linecard_nested_dl_set(linecard->devlink_linecard, NULL);
devlink_unregister(devlink); devlink_unregister(devlink);
devlink_free(devlink); devlink_free(devlink);
} }
......
...@@ -366,6 +366,7 @@ enum mlx5_driver_event { ...@@ -366,6 +366,7 @@ enum mlx5_driver_event {
MLX5_DRIVER_EVENT_UPLINK_NETDEV, MLX5_DRIVER_EVENT_UPLINK_NETDEV,
MLX5_DRIVER_EVENT_MACSEC_SA_ADDED, MLX5_DRIVER_EVENT_MACSEC_SA_ADDED,
MLX5_DRIVER_EVENT_MACSEC_SA_DELETED, MLX5_DRIVER_EVENT_MACSEC_SA_DELETED,
MLX5_DRIVER_EVENT_SF_PEER_DEVLINK,
}; };
enum { enum {
......
...@@ -150,6 +150,7 @@ struct devlink_port { ...@@ -150,6 +150,7 @@ struct devlink_port {
struct devlink_rate *devlink_rate; struct devlink_rate *devlink_rate;
struct devlink_linecard *linecard; struct devlink_linecard *linecard;
u32 rel_index;
}; };
struct devlink_port_new_attrs { struct devlink_port_new_attrs {
...@@ -1697,6 +1698,8 @@ void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port, u32 contro ...@@ -1697,6 +1698,8 @@ void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port, u32 contro
void devlink_port_attrs_pci_sf_set(struct devlink_port *devlink_port, void devlink_port_attrs_pci_sf_set(struct devlink_port *devlink_port,
u32 controller, u16 pf, u32 sf, u32 controller, u16 pf, u32 sf,
bool external); bool external);
int devl_port_fn_devlink_set(struct devlink_port *devlink_port,
struct devlink *fn_devlink);
struct devlink_rate * struct devlink_rate *
devl_rate_node_create(struct devlink *devlink, void *priv, char *node_name, devl_rate_node_create(struct devlink *devlink, void *priv, char *node_name,
struct devlink_rate *parent); struct devlink_rate *parent);
...@@ -1717,8 +1720,8 @@ void devlink_linecard_provision_clear(struct devlink_linecard *linecard); ...@@ -1717,8 +1720,8 @@ void devlink_linecard_provision_clear(struct devlink_linecard *linecard);
void devlink_linecard_provision_fail(struct devlink_linecard *linecard); void devlink_linecard_provision_fail(struct devlink_linecard *linecard);
void devlink_linecard_activate(struct devlink_linecard *linecard); void devlink_linecard_activate(struct devlink_linecard *linecard);
void devlink_linecard_deactivate(struct devlink_linecard *linecard); void devlink_linecard_deactivate(struct devlink_linecard *linecard);
void devlink_linecard_nested_dl_set(struct devlink_linecard *linecard, int devlink_linecard_nested_dl_set(struct devlink_linecard *linecard,
struct devlink *nested_devlink); struct devlink *nested_devlink);
int devl_sb_register(struct devlink *devlink, unsigned int sb_index, int devl_sb_register(struct devlink *devlink, unsigned int sb_index,
u32 size, u16 ingress_pools_count, u32 size, u16 ingress_pools_count,
u16 egress_pools_count, u16 ingress_tc_count, u16 egress_pools_count, u16 ingress_tc_count,
...@@ -1918,6 +1921,8 @@ devlink_health_reporter_state_update(struct devlink_health_reporter *reporter, ...@@ -1918,6 +1921,8 @@ devlink_health_reporter_state_update(struct devlink_health_reporter *reporter,
void void
devlink_health_reporter_recovery_done(struct devlink_health_reporter *reporter); devlink_health_reporter_recovery_done(struct devlink_health_reporter *reporter);
int devl_nested_devlink_set(struct devlink *devlink,
struct devlink *nested_devlink);
bool devlink_is_reload_failed(const struct devlink *devlink); bool devlink_is_reload_failed(const struct devlink *devlink);
void devlink_remote_reload_actions_performed(struct devlink *devlink, void devlink_remote_reload_actions_performed(struct devlink *devlink,
enum devlink_reload_limit limit, enum devlink_reload_limit limit,
......
...@@ -680,6 +680,7 @@ enum devlink_port_function_attr { ...@@ -680,6 +680,7 @@ enum devlink_port_function_attr {
DEVLINK_PORT_FN_ATTR_STATE, /* u8 */ DEVLINK_PORT_FN_ATTR_STATE, /* u8 */
DEVLINK_PORT_FN_ATTR_OPSTATE, /* u8 */ DEVLINK_PORT_FN_ATTR_OPSTATE, /* u8 */
DEVLINK_PORT_FN_ATTR_CAPS, /* bitfield32 */ DEVLINK_PORT_FN_ATTR_CAPS, /* bitfield32 */
DEVLINK_PORT_FN_ATTR_DEVLINK, /* nested */
__DEVLINK_PORT_FUNCTION_ATTR_MAX, __DEVLINK_PORT_FUNCTION_ATTR_MAX,
DEVLINK_PORT_FUNCTION_ATTR_MAX = __DEVLINK_PORT_FUNCTION_ATTR_MAX - 1 DEVLINK_PORT_FUNCTION_ATTR_MAX = __DEVLINK_PORT_FUNCTION_ATTR_MAX - 1
......
...@@ -16,6 +16,219 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_trap_report); ...@@ -16,6 +16,219 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_trap_report);
DEFINE_XARRAY_FLAGS(devlinks, XA_FLAGS_ALLOC); DEFINE_XARRAY_FLAGS(devlinks, XA_FLAGS_ALLOC);
static struct devlink *devlinks_xa_get(unsigned long index)
{
struct devlink *devlink;
rcu_read_lock();
devlink = xa_find(&devlinks, &index, index, DEVLINK_REGISTERED);
if (!devlink || !devlink_try_get(devlink))
devlink = NULL;
rcu_read_unlock();
return devlink;
}
/* devlink_rels xarray contains 1:1 relationships between
* devlink object and related nested devlink instance.
* The xarray index is used to get the nested object from
* the nested-in object code.
*/
static DEFINE_XARRAY_FLAGS(devlink_rels, XA_FLAGS_ALLOC1);
#define DEVLINK_REL_IN_USE XA_MARK_0
struct devlink_rel {
u32 index;
refcount_t refcount;
u32 devlink_index;
struct {
u32 devlink_index;
u32 obj_index;
devlink_rel_notify_cb_t *notify_cb;
devlink_rel_cleanup_cb_t *cleanup_cb;
struct work_struct notify_work;
} nested_in;
};
static void devlink_rel_free(struct devlink_rel *rel)
{
xa_erase(&devlink_rels, rel->index);
kfree(rel);
}
static void __devlink_rel_get(struct devlink_rel *rel)
{
refcount_inc(&rel->refcount);
}
static void __devlink_rel_put(struct devlink_rel *rel)
{
if (refcount_dec_and_test(&rel->refcount))
devlink_rel_free(rel);
}
static void devlink_rel_nested_in_notify_work(struct work_struct *work)
{
struct devlink_rel *rel = container_of(work, struct devlink_rel,
nested_in.notify_work);
struct devlink *devlink;
devlink = devlinks_xa_get(rel->nested_in.devlink_index);
if (!devlink)
goto rel_put;
if (!devl_trylock(devlink)) {
devlink_put(devlink);
goto reschedule_work;
}
if (!devl_is_registered(devlink)) {
devl_unlock(devlink);
devlink_put(devlink);
goto rel_put;
}
if (!xa_get_mark(&devlink_rels, rel->index, DEVLINK_REL_IN_USE))
rel->nested_in.cleanup_cb(devlink, rel->nested_in.obj_index, rel->index);
rel->nested_in.notify_cb(devlink, rel->nested_in.obj_index);
devl_unlock(devlink);
devlink_put(devlink);
rel_put:
__devlink_rel_put(rel);
return;
reschedule_work:
schedule_work(&rel->nested_in.notify_work);
}
static void devlink_rel_nested_in_notify_work_schedule(struct devlink_rel *rel)
{
__devlink_rel_get(rel);
schedule_work(&rel->nested_in.notify_work);
}
static struct devlink_rel *devlink_rel_alloc(void)
{
struct devlink_rel *rel;
static u32 next;
int err;
rel = kzalloc(sizeof(*rel), GFP_KERNEL);
if (!rel)
return ERR_PTR(-ENOMEM);
err = xa_alloc_cyclic(&devlink_rels, &rel->index, rel,
xa_limit_32b, &next, GFP_KERNEL);
if (err) {
kfree(rel);
return ERR_PTR(err);
}
refcount_set(&rel->refcount, 1);
INIT_WORK(&rel->nested_in.notify_work,
&devlink_rel_nested_in_notify_work);
return rel;
}
static void devlink_rel_put(struct devlink *devlink)
{
struct devlink_rel *rel = devlink->rel;
if (!rel)
return;
xa_clear_mark(&devlink_rels, rel->index, DEVLINK_REL_IN_USE);
devlink_rel_nested_in_notify_work_schedule(rel);
__devlink_rel_put(rel);
devlink->rel = NULL;
}
void devlink_rel_nested_in_clear(u32 rel_index)
{
xa_clear_mark(&devlink_rels, rel_index, DEVLINK_REL_IN_USE);
}
int devlink_rel_nested_in_add(u32 *rel_index, u32 devlink_index,
u32 obj_index, devlink_rel_notify_cb_t *notify_cb,
devlink_rel_cleanup_cb_t *cleanup_cb,
struct devlink *devlink)
{
struct devlink_rel *rel = devlink_rel_alloc();
ASSERT_DEVLINK_NOT_REGISTERED(devlink);
if (IS_ERR(rel))
return PTR_ERR(rel);
rel->devlink_index = devlink->index;
rel->nested_in.devlink_index = devlink_index;
rel->nested_in.obj_index = obj_index;
rel->nested_in.notify_cb = notify_cb;
rel->nested_in.cleanup_cb = cleanup_cb;
*rel_index = rel->index;
xa_set_mark(&devlink_rels, rel->index, DEVLINK_REL_IN_USE);
devlink->rel = rel;
return 0;
}
void devlink_rel_nested_in_notify(struct devlink *devlink)
{
struct devlink_rel *rel = devlink->rel;
if (!rel)
return;
devlink_rel_nested_in_notify_work_schedule(rel);
}
static struct devlink_rel *devlink_rel_find(unsigned long rel_index)
{
return xa_find(&devlink_rels, &rel_index, rel_index,
DEVLINK_REL_IN_USE);
}
static struct devlink *devlink_rel_devlink_get_lock(u32 rel_index)
{
struct devlink *devlink;
struct devlink_rel *rel;
u32 devlink_index;
if (!rel_index)
return NULL;
xa_lock(&devlink_rels);
rel = devlink_rel_find(rel_index);
if (rel)
devlink_index = rel->devlink_index;
xa_unlock(&devlink_rels);
if (!rel)
return NULL;
devlink = devlinks_xa_get(devlink_index);
if (!devlink)
return NULL;
devl_lock(devlink);
if (!devl_is_registered(devlink)) {
devl_unlock(devlink);
devlink_put(devlink);
return NULL;
}
return devlink;
}
int devlink_rel_devlink_handle_put(struct sk_buff *msg, struct devlink *devlink,
u32 rel_index, int attrtype,
bool *msg_updated)
{
struct net *net = devlink_net(devlink);
struct devlink *rel_devlink;
int err;
rel_devlink = devlink_rel_devlink_get_lock(rel_index);
if (!rel_devlink)
return 0;
err = devlink_nl_put_nested_handle(msg, net, rel_devlink, attrtype);
devl_unlock(rel_devlink);
devlink_put(rel_devlink);
if (!err && msg_updated)
*msg_updated = true;
return err;
}
void *devlink_priv(struct devlink *devlink) void *devlink_priv(struct devlink *devlink)
{ {
return &devlink->priv; return &devlink->priv;
...@@ -142,6 +355,7 @@ int devl_register(struct devlink *devlink) ...@@ -142,6 +355,7 @@ int devl_register(struct devlink *devlink)
xa_set_mark(&devlinks, devlink->index, DEVLINK_REGISTERED); xa_set_mark(&devlinks, devlink->index, DEVLINK_REGISTERED);
devlink_notify_register(devlink); devlink_notify_register(devlink);
devlink_rel_nested_in_notify(devlink);
return 0; return 0;
} }
...@@ -166,6 +380,7 @@ void devl_unregister(struct devlink *devlink) ...@@ -166,6 +380,7 @@ void devl_unregister(struct devlink *devlink)
devlink_notify_unregister(devlink); devlink_notify_unregister(devlink);
xa_clear_mark(&devlinks, devlink->index, DEVLINK_REGISTERED); xa_clear_mark(&devlinks, devlink->index, DEVLINK_REGISTERED);
devlink_rel_put(devlink);
} }
EXPORT_SYMBOL_GPL(devl_unregister); EXPORT_SYMBOL_GPL(devl_unregister);
...@@ -215,6 +430,7 @@ struct devlink *devlink_alloc_ns(const struct devlink_ops *ops, ...@@ -215,6 +430,7 @@ struct devlink *devlink_alloc_ns(const struct devlink_ops *ops,
xa_init_flags(&devlink->ports, XA_FLAGS_ALLOC); xa_init_flags(&devlink->ports, XA_FLAGS_ALLOC);
xa_init_flags(&devlink->params, XA_FLAGS_ALLOC); xa_init_flags(&devlink->params, XA_FLAGS_ALLOC);
xa_init_flags(&devlink->snapshot_ids, XA_FLAGS_ALLOC); xa_init_flags(&devlink->snapshot_ids, XA_FLAGS_ALLOC);
xa_init_flags(&devlink->nested_rels, XA_FLAGS_ALLOC);
write_pnet(&devlink->_net, net); write_pnet(&devlink->_net, net);
INIT_LIST_HEAD(&devlink->rate_list); INIT_LIST_HEAD(&devlink->rate_list);
INIT_LIST_HEAD(&devlink->linecard_list); INIT_LIST_HEAD(&devlink->linecard_list);
...@@ -261,6 +477,7 @@ void devlink_free(struct devlink *devlink) ...@@ -261,6 +477,7 @@ void devlink_free(struct devlink *devlink)
WARN_ON(!list_empty(&devlink->linecard_list)); WARN_ON(!list_empty(&devlink->linecard_list));
WARN_ON(!xa_empty(&devlink->ports)); WARN_ON(!xa_empty(&devlink->ports));
xa_destroy(&devlink->nested_rels);
xa_destroy(&devlink->snapshot_ids); xa_destroy(&devlink->snapshot_ids);
xa_destroy(&devlink->params); xa_destroy(&devlink->params);
xa_destroy(&devlink->ports); xa_destroy(&devlink->ports);
......
...@@ -138,6 +138,23 @@ devlink_reload_stats_put(struct sk_buff *msg, struct devlink *devlink, bool is_r ...@@ -138,6 +138,23 @@ devlink_reload_stats_put(struct sk_buff *msg, struct devlink *devlink, bool is_r
return -EMSGSIZE; return -EMSGSIZE;
} }
static int devlink_nl_nested_fill(struct sk_buff *msg, struct devlink *devlink)
{
unsigned long rel_index;
void *unused;
int err;
xa_for_each(&devlink->nested_rels, rel_index, unused) {
err = devlink_rel_devlink_handle_put(msg, devlink,
rel_index,
DEVLINK_ATTR_NESTED_DEVLINK,
NULL);
if (err)
return err;
}
return 0;
}
static int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink, static int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink,
enum devlink_command cmd, u32 portid, enum devlink_command cmd, u32 portid,
u32 seq, int flags) u32 seq, int flags)
...@@ -164,6 +181,10 @@ static int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink, ...@@ -164,6 +181,10 @@ static int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink,
goto dev_stats_nest_cancel; goto dev_stats_nest_cancel;
nla_nest_end(msg, dev_stats); nla_nest_end(msg, dev_stats);
if (devlink_nl_nested_fill(msg, devlink))
goto nla_put_failure;
genlmsg_end(msg, hdr); genlmsg_end(msg, hdr);
return 0; return 0;
...@@ -230,6 +251,34 @@ int devlink_nl_get_dumpit(struct sk_buff *msg, struct netlink_callback *cb) ...@@ -230,6 +251,34 @@ int devlink_nl_get_dumpit(struct sk_buff *msg, struct netlink_callback *cb)
return devlink_nl_dumpit(msg, cb, devlink_nl_get_dump_one); return devlink_nl_dumpit(msg, cb, devlink_nl_get_dump_one);
} }
static void devlink_rel_notify_cb(struct devlink *devlink, u32 obj_index)
{
devlink_notify(devlink, DEVLINK_CMD_NEW);
}
static void devlink_rel_cleanup_cb(struct devlink *devlink, u32 obj_index,
u32 rel_index)
{
xa_erase(&devlink->nested_rels, rel_index);
}
int devl_nested_devlink_set(struct devlink *devlink,
struct devlink *nested_devlink)
{
u32 rel_index;
int err;
err = devlink_rel_nested_in_add(&rel_index, devlink->index, 0,
devlink_rel_notify_cb,
devlink_rel_cleanup_cb,
nested_devlink);
if (err)
return err;
return xa_insert(&devlink->nested_rels, rel_index,
xa_mk_value(0), GFP_KERNEL);
}
EXPORT_SYMBOL_GPL(devl_nested_devlink_set);
void devlink_notify_register(struct devlink *devlink) void devlink_notify_register(struct devlink *devlink)
{ {
devlink_notify(devlink, DEVLINK_CMD_NEW); devlink_notify(devlink, DEVLINK_CMD_NEW);
...@@ -372,6 +421,7 @@ static void devlink_reload_netns_change(struct devlink *devlink, ...@@ -372,6 +421,7 @@ static void devlink_reload_netns_change(struct devlink *devlink,
devlink_notify_unregister(devlink); devlink_notify_unregister(devlink);
write_pnet(&devlink->_net, dest_net); write_pnet(&devlink->_net, dest_net);
devlink_notify_register(devlink); devlink_notify_register(devlink);
devlink_rel_nested_in_notify(devlink);
} }
int devlink_reload(struct devlink *devlink, struct net *dest_net, int devlink_reload(struct devlink *devlink, struct net *dest_net,
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
#include "netlink_gen.h" #include "netlink_gen.h"
struct devlink_rel;
#define DEVLINK_REGISTERED XA_MARK_1 #define DEVLINK_REGISTERED XA_MARK_1
#define DEVLINK_RELOAD_STATS_ARRAY_SIZE \ #define DEVLINK_RELOAD_STATS_ARRAY_SIZE \
...@@ -55,6 +57,8 @@ struct devlink { ...@@ -55,6 +57,8 @@ struct devlink {
u8 reload_failed:1; u8 reload_failed:1;
refcount_t refcount; refcount_t refcount;
struct rcu_work rwork; struct rcu_work rwork;
struct devlink_rel *rel;
struct xarray nested_rels;
char priv[] __aligned(NETDEV_ALIGN); char priv[] __aligned(NETDEV_ALIGN);
}; };
...@@ -92,6 +96,20 @@ static inline bool devl_is_registered(struct devlink *devlink) ...@@ -92,6 +96,20 @@ static inline bool devl_is_registered(struct devlink *devlink)
return xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED); return xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED);
} }
typedef void devlink_rel_notify_cb_t(struct devlink *devlink, u32 obj_index);
typedef void devlink_rel_cleanup_cb_t(struct devlink *devlink, u32 obj_index,
u32 rel_index);
void devlink_rel_nested_in_clear(u32 rel_index);
int devlink_rel_nested_in_add(u32 *rel_index, u32 devlink_index,
u32 obj_index, devlink_rel_notify_cb_t *notify_cb,
devlink_rel_cleanup_cb_t *cleanup_cb,
struct devlink *devlink);
void devlink_rel_nested_in_notify(struct devlink *devlink);
int devlink_rel_devlink_handle_put(struct sk_buff *msg, struct devlink *devlink,
u32 rel_index, int attrtype,
bool *msg_updated);
/* Netlink */ /* Netlink */
#define DEVLINK_NL_FLAG_NEED_PORT BIT(0) #define DEVLINK_NL_FLAG_NEED_PORT BIT(0)
#define DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT BIT(1) #define DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT BIT(1)
...@@ -145,6 +163,8 @@ devlink_nl_put_handle(struct sk_buff *msg, struct devlink *devlink) ...@@ -145,6 +163,8 @@ devlink_nl_put_handle(struct sk_buff *msg, struct devlink *devlink)
return 0; return 0;
} }
int devlink_nl_put_nested_handle(struct sk_buff *msg, struct net *net,
struct devlink *devlink, int attrtype);
int devlink_nl_msg_reply_and_new(struct sk_buff **msg, struct genl_info *info); int devlink_nl_msg_reply_and_new(struct sk_buff **msg, struct genl_info *info);
/* Notify */ /* Notify */
...@@ -206,19 +226,7 @@ int devlink_rate_nodes_check(struct devlink *devlink, u16 mode, ...@@ -206,19 +226,7 @@ int devlink_rate_nodes_check(struct devlink *devlink, u16 mode,
struct netlink_ext_ack *extack); struct netlink_ext_ack *extack);
/* Linecards */ /* Linecards */
struct devlink_linecard { unsigned int devlink_linecard_index(struct devlink_linecard *linecard);
struct list_head list;
struct devlink *devlink;
unsigned int index;
const struct devlink_linecard_ops *ops;
void *priv;
enum devlink_linecard_state state;
struct mutex state_lock; /* Protects state */
const char *type;
struct devlink_linecard_type *types;
unsigned int types_count;
struct devlink *nested_devlink;
};
/* Devlink nl cmds */ /* Devlink nl cmds */
int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info); int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info);
......
...@@ -6,6 +6,25 @@ ...@@ -6,6 +6,25 @@
#include "devl_internal.h" #include "devl_internal.h"
struct devlink_linecard {
struct list_head list;
struct devlink *devlink;
unsigned int index;
const struct devlink_linecard_ops *ops;
void *priv;
enum devlink_linecard_state state;
struct mutex state_lock; /* Protects state */
const char *type;
struct devlink_linecard_type *types;
unsigned int types_count;
u32 rel_index;
};
unsigned int devlink_linecard_index(struct devlink_linecard *linecard)
{
return linecard->index;
}
static struct devlink_linecard * static struct devlink_linecard *
devlink_linecard_get_by_index(struct devlink *devlink, devlink_linecard_get_by_index(struct devlink *devlink,
unsigned int linecard_index) unsigned int linecard_index)
...@@ -46,24 +65,6 @@ devlink_linecard_get_from_info(struct devlink *devlink, struct genl_info *info) ...@@ -46,24 +65,6 @@ devlink_linecard_get_from_info(struct devlink *devlink, struct genl_info *info)
return devlink_linecard_get_from_attrs(devlink, info->attrs); return devlink_linecard_get_from_attrs(devlink, info->attrs);
} }
static int devlink_nl_put_nested_handle(struct sk_buff *msg, struct devlink *devlink)
{
struct nlattr *nested_attr;
nested_attr = nla_nest_start(msg, DEVLINK_ATTR_NESTED_DEVLINK);
if (!nested_attr)
return -EMSGSIZE;
if (devlink_nl_put_handle(msg, devlink))
goto nla_put_failure;
nla_nest_end(msg, nested_attr);
return 0;
nla_put_failure:
nla_nest_cancel(msg, nested_attr);
return -EMSGSIZE;
}
struct devlink_linecard_type { struct devlink_linecard_type {
const char *type; const char *type;
const void *priv; const void *priv;
...@@ -111,8 +112,10 @@ static int devlink_nl_linecard_fill(struct sk_buff *msg, ...@@ -111,8 +112,10 @@ static int devlink_nl_linecard_fill(struct sk_buff *msg,
nla_nest_end(msg, attr); nla_nest_end(msg, attr);
} }
if (linecard->nested_devlink && if (devlink_rel_devlink_handle_put(msg, devlink,
devlink_nl_put_nested_handle(msg, linecard->nested_devlink)) linecard->rel_index,
DEVLINK_ATTR_NESTED_DEVLINK,
NULL))
goto nla_put_failure; goto nla_put_failure;
genlmsg_end(msg, hdr); genlmsg_end(msg, hdr);
...@@ -521,7 +524,6 @@ EXPORT_SYMBOL_GPL(devlink_linecard_provision_set); ...@@ -521,7 +524,6 @@ EXPORT_SYMBOL_GPL(devlink_linecard_provision_set);
void devlink_linecard_provision_clear(struct devlink_linecard *linecard) void devlink_linecard_provision_clear(struct devlink_linecard *linecard)
{ {
mutex_lock(&linecard->state_lock); mutex_lock(&linecard->state_lock);
WARN_ON(linecard->nested_devlink);
linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED; linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
linecard->type = NULL; linecard->type = NULL;
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
...@@ -540,7 +542,6 @@ EXPORT_SYMBOL_GPL(devlink_linecard_provision_clear); ...@@ -540,7 +542,6 @@ EXPORT_SYMBOL_GPL(devlink_linecard_provision_clear);
void devlink_linecard_provision_fail(struct devlink_linecard *linecard) void devlink_linecard_provision_fail(struct devlink_linecard *linecard)
{ {
mutex_lock(&linecard->state_lock); mutex_lock(&linecard->state_lock);
WARN_ON(linecard->nested_devlink);
linecard->state = DEVLINK_LINECARD_STATE_PROVISIONING_FAILED; linecard->state = DEVLINK_LINECARD_STATE_PROVISIONING_FAILED;
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
mutex_unlock(&linecard->state_lock); mutex_unlock(&linecard->state_lock);
...@@ -588,6 +589,27 @@ void devlink_linecard_deactivate(struct devlink_linecard *linecard) ...@@ -588,6 +589,27 @@ void devlink_linecard_deactivate(struct devlink_linecard *linecard)
} }
EXPORT_SYMBOL_GPL(devlink_linecard_deactivate); EXPORT_SYMBOL_GPL(devlink_linecard_deactivate);
static void devlink_linecard_rel_notify_cb(struct devlink *devlink,
u32 linecard_index)
{
struct devlink_linecard *linecard;
linecard = devlink_linecard_get_by_index(devlink, linecard_index);
if (!linecard)
return;
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
}
static void devlink_linecard_rel_cleanup_cb(struct devlink *devlink,
u32 linecard_index, u32 rel_index)
{
struct devlink_linecard *linecard;
linecard = devlink_linecard_get_by_index(devlink, linecard_index);
if (linecard && linecard->rel_index == rel_index)
linecard->rel_index = 0;
}
/** /**
* devlink_linecard_nested_dl_set - Attach/detach nested devlink * devlink_linecard_nested_dl_set - Attach/detach nested devlink
* instance to linecard. * instance to linecard.
...@@ -595,12 +617,14 @@ EXPORT_SYMBOL_GPL(devlink_linecard_deactivate); ...@@ -595,12 +617,14 @@ EXPORT_SYMBOL_GPL(devlink_linecard_deactivate);
* @linecard: devlink linecard * @linecard: devlink linecard
* @nested_devlink: devlink instance to attach or NULL to detach * @nested_devlink: devlink instance to attach or NULL to detach
*/ */
void devlink_linecard_nested_dl_set(struct devlink_linecard *linecard, int devlink_linecard_nested_dl_set(struct devlink_linecard *linecard,
struct devlink *nested_devlink) struct devlink *nested_devlink)
{ {
mutex_lock(&linecard->state_lock); return devlink_rel_nested_in_add(&linecard->rel_index,
linecard->nested_devlink = nested_devlink; linecard->devlink->index,
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); linecard->index,
mutex_unlock(&linecard->state_lock); devlink_linecard_rel_notify_cb,
devlink_linecard_rel_cleanup_cb,
nested_devlink);
} }
EXPORT_SYMBOL_GPL(devlink_linecard_nested_dl_set); EXPORT_SYMBOL_GPL(devlink_linecard_nested_dl_set);
...@@ -82,6 +82,32 @@ static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = { ...@@ -82,6 +82,32 @@ static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
[DEVLINK_ATTR_REGION_DIRECT] = { .type = NLA_FLAG }, [DEVLINK_ATTR_REGION_DIRECT] = { .type = NLA_FLAG },
}; };
int devlink_nl_put_nested_handle(struct sk_buff *msg, struct net *net,
struct devlink *devlink, int attrtype)
{
struct nlattr *nested_attr;
nested_attr = nla_nest_start(msg, attrtype);
if (!nested_attr)
return -EMSGSIZE;
if (devlink_nl_put_handle(msg, devlink))
goto nla_put_failure;
if (!net_eq(net, devlink_net(devlink))) {
int id = peernet2id_alloc(net, devlink_net(devlink),
GFP_KERNEL);
if (nla_put_s32(msg, DEVLINK_ATTR_NETNS_ID, id))
return -EMSGSIZE;
}
nla_nest_end(msg, nested_attr);
return 0;
nla_put_failure:
nla_nest_cancel(msg, nested_attr);
return -EMSGSIZE;
}
int devlink_nl_msg_reply_and_new(struct sk_buff **msg, struct genl_info *info) int devlink_nl_msg_reply_and_new(struct sk_buff **msg, struct genl_info *info)
{ {
int err; int err;
......
...@@ -428,6 +428,13 @@ devlink_nl_port_function_attrs_put(struct sk_buff *msg, struct devlink_port *por ...@@ -428,6 +428,13 @@ devlink_nl_port_function_attrs_put(struct sk_buff *msg, struct devlink_port *por
if (err) if (err)
goto out; goto out;
err = devlink_port_fn_state_fill(port, msg, extack, &msg_updated); err = devlink_port_fn_state_fill(port, msg, extack, &msg_updated);
if (err)
goto out;
err = devlink_rel_devlink_handle_put(msg, port->devlink,
port->rel_index,
DEVLINK_PORT_FN_ATTR_DEVLINK,
&msg_updated);
out: out:
if (err || !msg_updated) if (err || !msg_updated)
nla_nest_cancel(msg, function_attr); nla_nest_cancel(msg, function_attr);
...@@ -483,7 +490,7 @@ static int devlink_nl_port_fill(struct sk_buff *msg, ...@@ -483,7 +490,7 @@ static int devlink_nl_port_fill(struct sk_buff *msg,
goto nla_put_failure; goto nla_put_failure;
if (devlink_port->linecard && if (devlink_port->linecard &&
nla_put_u32(msg, DEVLINK_ATTR_LINECARD_INDEX, nla_put_u32(msg, DEVLINK_ATTR_LINECARD_INDEX,
devlink_port->linecard->index)) devlink_linecard_index(devlink_port->linecard)))
goto nla_put_failure; goto nla_put_failure;
genlmsg_end(msg, hdr); genlmsg_end(msg, hdr);
...@@ -1392,6 +1399,50 @@ void devlink_port_attrs_pci_sf_set(struct devlink_port *devlink_port, u32 contro ...@@ -1392,6 +1399,50 @@ void devlink_port_attrs_pci_sf_set(struct devlink_port *devlink_port, u32 contro
} }
EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_sf_set); EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_sf_set);
static void devlink_port_rel_notify_cb(struct devlink *devlink, u32 port_index)
{
struct devlink_port *devlink_port;
devlink_port = devlink_port_get_by_index(devlink, port_index);
if (!devlink_port)
return;
devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
}
static void devlink_port_rel_cleanup_cb(struct devlink *devlink, u32 port_index,
u32 rel_index)
{
struct devlink_port *devlink_port;
devlink_port = devlink_port_get_by_index(devlink, port_index);
if (devlink_port && devlink_port->rel_index == rel_index)
devlink_port->rel_index = 0;
}
/**
* devl_port_fn_devlink_set - Attach peer devlink
* instance to port function.
* @devlink_port: devlink port
* @fn_devlink: devlink instance to attach
*/
int devl_port_fn_devlink_set(struct devlink_port *devlink_port,
struct devlink *fn_devlink)
{
ASSERT_DEVLINK_PORT_REGISTERED(devlink_port);
if (WARN_ON(devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_PCI_SF ||
devlink_port->attrs.pci_sf.external))
return -EINVAL;
return devlink_rel_nested_in_add(&devlink_port->rel_index,
devlink_port->devlink->index,
devlink_port->index,
devlink_port_rel_notify_cb,
devlink_port_rel_cleanup_cb,
fn_devlink);
}
EXPORT_SYMBOL_GPL(devl_port_fn_devlink_set);
/** /**
* devlink_port_linecard_set - Link port with a linecard * devlink_port_linecard_set - Link port with a linecard
* *
...@@ -1420,7 +1471,7 @@ static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port, ...@@ -1420,7 +1471,7 @@ static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
case DEVLINK_PORT_FLAVOUR_PHYSICAL: case DEVLINK_PORT_FLAVOUR_PHYSICAL:
if (devlink_port->linecard) if (devlink_port->linecard)
n = snprintf(name, len, "l%u", n = snprintf(name, len, "l%u",
devlink_port->linecard->index); devlink_linecard_index(devlink_port->linecard));
if (n < len) if (n < len)
n += snprintf(name + n, len - n, "p%u", n += snprintf(name + n, len - n, "p%u",
attrs->phys.port_number); attrs->phys.port_number);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment