Skip to content

Commit

Permalink
Merge branch 'devlink-expose-instance-locking-and-simplify-port-split…
Browse files Browse the repository at this point in the history
…ting'

Jakub Kicinski says:

====================
devlink: expose instance locking and simplify port splitting

This series puts the devlink ports fully under the devlink instance
lock's protection. As discussed in the past it implements my preferred
solution of exposing the instance lock to the drivers. This way drivers
which want to support port splitting can lock the devlink instance
themselves on the probe path, and we can take that lock in the core
on the split/unsplit paths.

nfp and mlxsw are converted, with slightly deeper changes done in
nfp since I'm more familiar with that driver.

Now that the devlink port is protected we can pass a pointer to
the drivers, instead of passing a port index and forcing the drivers
to do their own lookups. Both nfp and mlxsw can container_of() to
their own structures.
====================

Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Jakub Kicinski <[email protected]>
  • Loading branch information
kuba-moo committed Mar 16, 2022
2 parents 49045b9 + 706217c commit b135152
Show file tree
Hide file tree
Showing 16 changed files with 208 additions and 171 deletions.
16 changes: 16 additions & 0 deletions Documentation/networking/devlink/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@ Linux Devlink Documentation
devlink is an API to expose device information and resources not directly
related to any device class, such as chip-wide/switch-ASIC-wide configuration.

Locking
-------

Driver facing APIs are currently transitioning to allow more explicit
locking. Drivers can use the existing ``devlink_*`` set of APIs, or
new APIs prefixed by ``devl_*``. The older APIs handle all the locking
in devlink core, but don't allow registration of most sub-objects once
the main devlink object is itself registered. The newer ``devl_*`` APIs assume
the devlink instance lock is already held. Drivers can take the instance
lock by calling ``devl_lock()``. It is also held in most of the callbacks.
Eventually all callbacks will be invoked under the devlink instance lock,
refer to the use of the ``DEVLINK_NL_FLAG_NO_LOCK`` flag in devlink core
to find out which callbacks are not converted, yet.

Drivers are encouraged to use the devlink instance lock for their own needs.

Interface documentation
-----------------------

Expand Down
36 changes: 16 additions & 20 deletions drivers/net/ethernet/mellanox/mlxsw/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1217,36 +1217,37 @@ static void mlxsw_core_fw_params_unregister(struct mlxsw_core *mlxsw_core)
ARRAY_SIZE(mlxsw_core_fw_devlink_params));
}

static void *__dl_port(struct devlink_port *devlink_port)
{
return container_of(devlink_port, struct mlxsw_core_port, devlink_port);
}

static int mlxsw_devlink_port_split(struct devlink *devlink,
unsigned int port_index,
struct devlink_port *port,
unsigned int count,
struct netlink_ext_ack *extack)
{
struct mlxsw_core_port *mlxsw_core_port = __dl_port(port);
struct mlxsw_core *mlxsw_core = devlink_priv(devlink);

if (port_index >= mlxsw_core->max_ports) {
NL_SET_ERR_MSG_MOD(extack, "Port index exceeds maximum number of ports");
return -EINVAL;
}
if (!mlxsw_core->driver->port_split)
return -EOPNOTSUPP;
return mlxsw_core->driver->port_split(mlxsw_core, port_index, count,
extack);
return mlxsw_core->driver->port_split(mlxsw_core,
mlxsw_core_port->local_port,
count, extack);
}

static int mlxsw_devlink_port_unsplit(struct devlink *devlink,
unsigned int port_index,
struct devlink_port *port,
struct netlink_ext_ack *extack)
{
struct mlxsw_core_port *mlxsw_core_port = __dl_port(port);
struct mlxsw_core *mlxsw_core = devlink_priv(devlink);

if (port_index >= mlxsw_core->max_ports) {
NL_SET_ERR_MSG_MOD(extack, "Port index exceeds maximum number of ports");
return -EINVAL;
}
if (!mlxsw_core->driver->port_unsplit)
return -EOPNOTSUPP;
return mlxsw_core->driver->port_unsplit(mlxsw_core, port_index,
return mlxsw_core->driver->port_unsplit(mlxsw_core,
mlxsw_core_port->local_port,
extack);
}

Expand Down Expand Up @@ -1280,11 +1281,6 @@ mlxsw_devlink_sb_pool_set(struct devlink *devlink,
extack);
}

static void *__dl_port(struct devlink_port *devlink_port)
{
return container_of(devlink_port, struct mlxsw_core_port, devlink_port);
}

static int mlxsw_devlink_port_type_set(struct devlink_port *devlink_port,
enum devlink_port_type port_type)
{
Expand Down Expand Up @@ -2983,7 +2979,7 @@ static int __mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u16 local_port,
attrs.switch_id.id_len = switch_id_len;
mlxsw_core_port->local_port = local_port;
devlink_port_attrs_set(devlink_port, &attrs);
err = devlink_port_register(devlink, devlink_port, local_port);
err = devl_port_register(devlink, devlink_port, local_port);
if (err)
memset(mlxsw_core_port, 0, sizeof(*mlxsw_core_port));
return err;
Expand All @@ -2995,7 +2991,7 @@ static void __mlxsw_core_port_fini(struct mlxsw_core *mlxsw_core, u16 local_port
&mlxsw_core->ports[local_port];
struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port;

devlink_port_unregister(devlink_port);
devl_port_unregister(devlink_port);
memset(mlxsw_core_port, 0, sizeof(*mlxsw_core_port));
}

Expand Down
6 changes: 6 additions & 0 deletions drivers/net/ethernet/mellanox/mlxsw/minimal.c
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@ static int mlxsw_m_init(struct mlxsw_core *mlxsw_core,
struct netlink_ext_ack *extack)
{
struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core);
struct devlink *devlink = priv_to_devlink(mlxsw_core);
int err;

mlxsw_m->core = mlxsw_core;
Expand All @@ -437,7 +438,9 @@ static int mlxsw_m_init(struct mlxsw_core *mlxsw_core,
return err;
}

devl_lock(devlink);
err = mlxsw_m_ports_create(mlxsw_m);
devl_unlock(devlink);
if (err) {
dev_err(mlxsw_m->bus_info->dev, "Failed to create ports\n");
return err;
Expand All @@ -449,8 +452,11 @@ static int mlxsw_m_init(struct mlxsw_core *mlxsw_core,
static void mlxsw_m_fini(struct mlxsw_core *mlxsw_core)
{
struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core);
struct devlink *devlink = priv_to_devlink(mlxsw_core);

devl_lock(devlink);
mlxsw_m_ports_remove(mlxsw_m);
devl_unlock(devlink);
}

static const struct mlxsw_config_profile mlxsw_m_config_profile;
Expand Down
7 changes: 7 additions & 0 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum.c
Original file line number Diff line number Diff line change
Expand Up @@ -2818,6 +2818,7 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
struct netlink_ext_ack *extack)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
struct devlink *devlink = priv_to_devlink(mlxsw_core);
int err;

mlxsw_sp->core = mlxsw_core;
Expand Down Expand Up @@ -2978,7 +2979,9 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
goto err_sample_trigger_init;
}

devl_lock(devlink);
err = mlxsw_sp_ports_create(mlxsw_sp);
devl_unlock(devlink);
if (err) {
dev_err(mlxsw_sp->bus_info->dev, "Failed to create ports\n");
goto err_ports_create;
Expand Down Expand Up @@ -3159,8 +3162,12 @@ static int mlxsw_sp4_init(struct mlxsw_core *mlxsw_core,
static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
struct devlink *devlink = priv_to_devlink(mlxsw_core);

devl_lock(devlink);
mlxsw_sp_ports_remove(mlxsw_sp);
devl_unlock(devlink);

rhashtable_destroy(&mlxsw_sp->sample_trigger_ht);
mlxsw_sp_port_module_info_fini(mlxsw_sp);
mlxsw_sp_dpipe_fini(mlxsw_sp);
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/ethernet/netronome/nfp/flower/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ nfp_flower_reprs_reify(struct nfp_app *app, enum nfp_repr_type type,
int i, err, count = 0;

reprs = rcu_dereference_protected(app->reprs[type],
lockdep_is_held(&app->pf->lock));
nfp_app_is_locked(app));
if (!reprs)
return 0;

Expand Down Expand Up @@ -295,7 +295,7 @@ nfp_flower_wait_repr_reify(struct nfp_app *app, atomic_t *replies, int tot_repl)
if (!tot_repl)
return 0;

lockdep_assert_held(&app->pf->lock);
assert_nfp_app_locked(app);
if (!wait_event_timeout(priv->reify_wait_queue,
atomic_read(replies) >= tot_repl,
NFP_FL_REPLY_TIMEOUT)) {
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/ethernet/netronome/nfp/nfp_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ struct nfp_reprs *
nfp_reprs_get_locked(struct nfp_app *app, enum nfp_repr_type type)
{
return rcu_dereference_protected(app->reprs[type],
lockdep_is_held(&app->pf->lock));
nfp_app_is_locked(app));
}

struct nfp_reprs *
Expand Down
12 changes: 11 additions & 1 deletion drivers/net/ethernet/netronome/nfp/nfp_app.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ extern const struct nfp_app_type app_abm;
* @bpf: BPF ndo offload-related calls
* @xdp_offload: offload an XDP program
* @eswitch_mode_get: get SR-IOV eswitch mode
* @eswitch_mode_set: set SR-IOV eswitch mode (under pf->lock)
* @eswitch_mode_set: set SR-IOV eswitch mode
* @sriov_enable: app-specific sriov initialisation
* @sriov_disable: app-specific sriov clean-up
* @dev_get: get representor or internal port representing netdev
Expand Down Expand Up @@ -174,6 +174,16 @@ struct nfp_app {
void *priv;
};

static inline void assert_nfp_app_locked(struct nfp_app *app)
{
devl_assert_locked(priv_to_devlink(app->pf));
}

static inline bool nfp_app_is_locked(struct nfp_app *app)
{
return devl_lock_is_held(priv_to_devlink(app->pf));
}

void nfp_check_rhashtable_empty(void *ptr, void *arg);
bool __nfp_ctrl_tx(struct nfp_net *nn, struct sk_buff *skb);
bool nfp_ctrl_tx(struct nfp_net *nn, struct sk_buff *skb);
Expand Down
55 changes: 19 additions & 36 deletions drivers/net/ethernet/netronome/nfp/nfp_devlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,11 @@ nfp_devlink_fill_eth_port(struct nfp_port *port,
}

static int
nfp_devlink_fill_eth_port_from_id(struct nfp_pf *pf, unsigned int port_index,
nfp_devlink_fill_eth_port_from_id(struct nfp_pf *pf,
struct devlink_port *dl_port,
struct nfp_eth_table_port *copy)
{
struct nfp_port *port;

port = nfp_port_from_id(pf, NFP_PORT_PHYS_PORT, port_index);
struct nfp_port *port = container_of(dl_port, struct nfp_port, dl_port);

return nfp_devlink_fill_eth_port(port, copy);
}
Expand Down Expand Up @@ -62,71 +61,55 @@ nfp_devlink_set_lanes(struct nfp_pf *pf, unsigned int idx, unsigned int lanes)
}

static int
nfp_devlink_port_split(struct devlink *devlink, unsigned int port_index,
nfp_devlink_port_split(struct devlink *devlink, struct devlink_port *port,
unsigned int count, struct netlink_ext_ack *extack)
{
struct nfp_pf *pf = devlink_priv(devlink);
struct nfp_eth_table_port eth_port;
unsigned int lanes;
int ret;

mutex_lock(&pf->lock);

rtnl_lock();
ret = nfp_devlink_fill_eth_port_from_id(pf, port_index, &eth_port);
ret = nfp_devlink_fill_eth_port_from_id(pf, port, &eth_port);
rtnl_unlock();
if (ret)
goto out;
return ret;

if (eth_port.port_lanes % count) {
ret = -EINVAL;
goto out;
}
if (eth_port.port_lanes % count)
return -EINVAL;

/* Special case the 100G CXP -> 2x40G split */
lanes = eth_port.port_lanes / count;
if (eth_port.lanes == 10 && count == 2)
lanes = 8 / count;

ret = nfp_devlink_set_lanes(pf, eth_port.index, lanes);
out:
mutex_unlock(&pf->lock);

return ret;
return nfp_devlink_set_lanes(pf, eth_port.index, lanes);
}

static int
nfp_devlink_port_unsplit(struct devlink *devlink, unsigned int port_index,
nfp_devlink_port_unsplit(struct devlink *devlink, struct devlink_port *port,
struct netlink_ext_ack *extack)
{
struct nfp_pf *pf = devlink_priv(devlink);
struct nfp_eth_table_port eth_port;
unsigned int lanes;
int ret;

mutex_lock(&pf->lock);

rtnl_lock();
ret = nfp_devlink_fill_eth_port_from_id(pf, port_index, &eth_port);
ret = nfp_devlink_fill_eth_port_from_id(pf, port, &eth_port);
rtnl_unlock();
if (ret)
goto out;
return ret;

if (!eth_port.is_split) {
ret = -EINVAL;
goto out;
}
if (!eth_port.is_split)
return -EINVAL;

/* Special case the 100G CXP -> 2x40G unsplit */
lanes = eth_port.port_lanes;
if (eth_port.port_lanes == 8)
lanes = 10;

ret = nfp_devlink_set_lanes(pf, eth_port.index, lanes);
out:
mutex_unlock(&pf->lock);

return ret;
return nfp_devlink_set_lanes(pf, eth_port.index, lanes);
}

static int
Expand Down Expand Up @@ -163,9 +146,9 @@ static int nfp_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
struct nfp_pf *pf = devlink_priv(devlink);
int ret;

mutex_lock(&pf->lock);
devl_lock(devlink);
ret = nfp_app_eswitch_mode_set(pf->app, mode);
mutex_unlock(&pf->lock);
devl_unlock(devlink);

return ret;
}
Expand Down Expand Up @@ -375,12 +358,12 @@ int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port)

devlink = priv_to_devlink(app->pf);

return devlink_port_register(devlink, &port->dl_port, port->eth_id);
return devl_port_register(devlink, &port->dl_port, port->eth_id);
}

void nfp_devlink_port_unregister(struct nfp_port *port)
{
devlink_port_unregister(&port->dl_port);
devl_port_unregister(&port->dl_port);
}

void nfp_devlink_port_type_eth_set(struct nfp_port *port)
Expand Down
Loading

0 comments on commit b135152

Please sign in to comment.