Commit 59a49d96 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'mlxsw-expose-number-of-physical-ports'

Ido Schimmel says:

====================
mlxsw: Expose number of physical ports

The switch ASIC has a limited capacity of physical ports that it can
support. While each system is brought up with a different number of
ports, this number can be increased via splitting up to the ASIC's
limit.

Expose physical ports as a devlink resource so that user space will have
visibility into the maximum number of ports that can be supported and
the current occupancy. With this resource it is possible, for example,
to write generic (i.e., not platform dependent) tests for port
splitting.

Patch #1 adds the new resource and patch #2 adds a selftest.

v2:
* Add the physical ports resource as a generic devlink resource so that
  it could be re-used by other device drivers
====================

Link: https://lore.kernel.org/r/20210121131024.2656154-1-idosch@idosch.orgSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 35187642 5154b1b8
...@@ -23,6 +23,20 @@ current size and related sub resources. To access a sub resource, you ...@@ -23,6 +23,20 @@ current size and related sub resources. To access a sub resource, you
specify the path of the resource. For example ``/IPv4/fib`` is the id for specify the path of the resource. For example ``/IPv4/fib`` is the id for
the ``fib`` sub-resource under the ``IPv4`` resource. the ``fib`` sub-resource under the ``IPv4`` resource.
Generic Resources
=================
Generic resources are used to describe resources that can be shared by multiple
device drivers and their description must be added to the following table:
.. list-table:: List of Generic Resources
:widths: 10 90
* - Name
- Description
* - ``physical_ports``
- A limited capacity of physical ports that the switch ASIC can support
example usage example usage
------------- -------------
......
...@@ -84,6 +84,7 @@ struct mlxsw_core { ...@@ -84,6 +84,7 @@ struct mlxsw_core {
struct mlxsw_thermal *thermal; struct mlxsw_thermal *thermal;
struct mlxsw_core_port *ports; struct mlxsw_core_port *ports;
unsigned int max_ports; unsigned int max_ports;
atomic_t active_ports_count;
bool fw_flash_in_progress; bool fw_flash_in_progress;
struct { struct {
struct devlink_health_reporter *fw_fatal; struct devlink_health_reporter *fw_fatal;
...@@ -96,8 +97,36 @@ struct mlxsw_core { ...@@ -96,8 +97,36 @@ struct mlxsw_core {
#define MLXSW_PORT_MAX_PORTS_DEFAULT 0x40 #define MLXSW_PORT_MAX_PORTS_DEFAULT 0x40
static int mlxsw_ports_init(struct mlxsw_core *mlxsw_core) static u64 mlxsw_ports_occ_get(void *priv)
{ {
struct mlxsw_core *mlxsw_core = priv;
return atomic_read(&mlxsw_core->active_ports_count);
}
static int mlxsw_core_resources_ports_register(struct mlxsw_core *mlxsw_core)
{
struct devlink *devlink = priv_to_devlink(mlxsw_core);
struct devlink_resource_size_params ports_num_params;
u32 max_ports;
max_ports = mlxsw_core->max_ports - 1;
devlink_resource_size_params_init(&ports_num_params, max_ports,
max_ports, 1,
DEVLINK_RESOURCE_UNIT_ENTRY);
return devlink_resource_register(devlink,
DEVLINK_RESOURCE_GENERIC_NAME_PORTS,
max_ports, MLXSW_CORE_RESOURCE_PORTS,
DEVLINK_RESOURCE_ID_PARENT_TOP,
&ports_num_params);
}
static int mlxsw_ports_init(struct mlxsw_core *mlxsw_core, bool reload)
{
struct devlink *devlink = priv_to_devlink(mlxsw_core);
int err;
/* Switch ports are numbered from 1 to queried value */ /* Switch ports are numbered from 1 to queried value */
if (MLXSW_CORE_RES_VALID(mlxsw_core, MAX_SYSTEM_PORT)) if (MLXSW_CORE_RES_VALID(mlxsw_core, MAX_SYSTEM_PORT))
mlxsw_core->max_ports = MLXSW_CORE_RES_GET(mlxsw_core, mlxsw_core->max_ports = MLXSW_CORE_RES_GET(mlxsw_core,
...@@ -110,11 +139,30 @@ static int mlxsw_ports_init(struct mlxsw_core *mlxsw_core) ...@@ -110,11 +139,30 @@ static int mlxsw_ports_init(struct mlxsw_core *mlxsw_core)
if (!mlxsw_core->ports) if (!mlxsw_core->ports)
return -ENOMEM; return -ENOMEM;
if (!reload) {
err = mlxsw_core_resources_ports_register(mlxsw_core);
if (err)
goto err_resources_ports_register;
}
atomic_set(&mlxsw_core->active_ports_count, 0);
devlink_resource_occ_get_register(devlink, MLXSW_CORE_RESOURCE_PORTS,
mlxsw_ports_occ_get, mlxsw_core);
return 0; return 0;
err_resources_ports_register:
kfree(mlxsw_core->ports);
return err;
} }
static void mlxsw_ports_fini(struct mlxsw_core *mlxsw_core) static void mlxsw_ports_fini(struct mlxsw_core *mlxsw_core, bool reload)
{ {
struct devlink *devlink = priv_to_devlink(mlxsw_core);
devlink_resource_occ_get_unregister(devlink, MLXSW_CORE_RESOURCE_PORTS);
if (!reload)
devlink_resources_unregister(priv_to_devlink(mlxsw_core), NULL);
kfree(mlxsw_core->ports); kfree(mlxsw_core->ports);
} }
...@@ -1897,7 +1945,7 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, ...@@ -1897,7 +1945,7 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
goto err_register_resources; goto err_register_resources;
} }
err = mlxsw_ports_init(mlxsw_core); err = mlxsw_ports_init(mlxsw_core, reload);
if (err) if (err)
goto err_ports_init; goto err_ports_init;
...@@ -1986,7 +2034,7 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, ...@@ -1986,7 +2034,7 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
err_emad_init: err_emad_init:
kfree(mlxsw_core->lag.mapping); kfree(mlxsw_core->lag.mapping);
err_alloc_lag_mapping: err_alloc_lag_mapping:
mlxsw_ports_fini(mlxsw_core); mlxsw_ports_fini(mlxsw_core, reload);
err_ports_init: err_ports_init:
if (!reload) if (!reload)
devlink_resources_unregister(devlink, NULL); devlink_resources_unregister(devlink, NULL);
...@@ -2056,7 +2104,7 @@ void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core, ...@@ -2056,7 +2104,7 @@ void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core,
devlink_unregister(devlink); devlink_unregister(devlink);
mlxsw_emad_fini(mlxsw_core); mlxsw_emad_fini(mlxsw_core);
kfree(mlxsw_core->lag.mapping); kfree(mlxsw_core->lag.mapping);
mlxsw_ports_fini(mlxsw_core); mlxsw_ports_fini(mlxsw_core, reload);
if (!reload) if (!reload)
devlink_resources_unregister(devlink, NULL); devlink_resources_unregister(devlink, NULL);
mlxsw_core->bus->fini(mlxsw_core->bus_priv); mlxsw_core->bus->fini(mlxsw_core->bus_priv);
...@@ -2755,16 +2803,25 @@ int mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u8 local_port, ...@@ -2755,16 +2803,25 @@ int mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u8 local_port,
const unsigned char *switch_id, const unsigned char *switch_id,
unsigned char switch_id_len) unsigned char switch_id_len)
{ {
return __mlxsw_core_port_init(mlxsw_core, local_port, int err;
DEVLINK_PORT_FLAVOUR_PHYSICAL,
port_number, split, split_port_subnumber, err = __mlxsw_core_port_init(mlxsw_core, local_port,
splittable, lanes, DEVLINK_PORT_FLAVOUR_PHYSICAL,
switch_id, switch_id_len); port_number, split, split_port_subnumber,
splittable, lanes,
switch_id, switch_id_len);
if (err)
return err;
atomic_inc(&mlxsw_core->active_ports_count);
return 0;
} }
EXPORT_SYMBOL(mlxsw_core_port_init); EXPORT_SYMBOL(mlxsw_core_port_init);
void mlxsw_core_port_fini(struct mlxsw_core *mlxsw_core, u8 local_port) void mlxsw_core_port_fini(struct mlxsw_core *mlxsw_core, u8 local_port)
{ {
atomic_dec(&mlxsw_core->active_ports_count);
__mlxsw_core_port_fini(mlxsw_core, local_port); __mlxsw_core_port_fini(mlxsw_core, local_port);
} }
EXPORT_SYMBOL(mlxsw_core_port_fini); EXPORT_SYMBOL(mlxsw_core_port_fini);
......
...@@ -19,6 +19,11 @@ ...@@ -19,6 +19,11 @@
#include "cmd.h" #include "cmd.h"
#include "resources.h" #include "resources.h"
enum mlxsw_core_resource_id {
MLXSW_CORE_RESOURCE_PORTS = 1,
MLXSW_CORE_RESOURCE_MAX,
};
struct mlxsw_core; struct mlxsw_core;
struct mlxsw_core_port; struct mlxsw_core_port;
struct mlxsw_driver; struct mlxsw_driver;
......
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
#define MLXSW_SP_RESOURCE_NAME_COUNTERS_RIF "rif" #define MLXSW_SP_RESOURCE_NAME_COUNTERS_RIF "rif"
enum mlxsw_sp_resource_id { enum mlxsw_sp_resource_id {
MLXSW_SP_RESOURCE_KVD = 1, MLXSW_SP_RESOURCE_KVD = MLXSW_CORE_RESOURCE_MAX,
MLXSW_SP_RESOURCE_KVD_LINEAR, MLXSW_SP_RESOURCE_KVD_LINEAR,
MLXSW_SP_RESOURCE_KVD_HASH_SINGLE, MLXSW_SP_RESOURCE_KVD_HASH_SINGLE,
MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE, MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE,
......
...@@ -380,6 +380,8 @@ struct devlink_resource { ...@@ -380,6 +380,8 @@ struct devlink_resource {
#define DEVLINK_RESOURCE_ID_PARENT_TOP 0 #define DEVLINK_RESOURCE_ID_PARENT_TOP 0
#define DEVLINK_RESOURCE_GENERIC_NAME_PORTS "physical_ports"
#define __DEVLINK_PARAM_MAX_STRING_VALUE 32 #define __DEVLINK_PARAM_MAX_STRING_VALUE 32
enum devlink_param_type { enum devlink_param_type {
DEVLINK_PARAM_TYPE_U8, DEVLINK_PARAM_TYPE_U8,
......
...@@ -8617,6 +8617,10 @@ EXPORT_SYMBOL_GPL(devlink_dpipe_table_unregister); ...@@ -8617,6 +8617,10 @@ EXPORT_SYMBOL_GPL(devlink_dpipe_table_unregister);
* @resource_id: resource's id * @resource_id: resource's id
* @parent_resource_id: resource's parent id * @parent_resource_id: resource's parent id
* @size_params: size parameters * @size_params: size parameters
*
* Generic resources should reuse the same names across drivers.
* Please see the generic resources list at:
* Documentation/networking/devlink/devlink-resource.rst
*/ */
int devlink_resource_register(struct devlink *devlink, int devlink_resource_register(struct devlink *devlink,
const char *resource_name, const char *resource_name,
......
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# Test for physical ports resource. The test splits each splittable port
# to its width and checks that eventually the number of physical ports equals
# the maximum number of physical ports.
PORT_NUM_NETIFS=0
port_setup_prepare()
{
:
}
port_cleanup()
{
pre_cleanup
for port in "${unsplit[@]}"; do
devlink port unsplit $port
check_err $? "Did not unsplit $netdev"
done
}
split_all_ports()
{
local should_fail=$1; shift
local -a unsplit
# Loop over the splittable netdevs and create tuples of netdev along
# with its width. For example:
# '$netdev1 $count1 $netdev2 $count2...', when:
# $netdev1-2 are splittable netdevs in the device, and
# $count1-2 are the netdevs width respectively.
while read netdev count <<<$(
devlink -j port show |
jq -r '.[][] | select(.splittable==true) | "\(.netdev) \(.lanes)"'
)
[[ ! -z $netdev ]]
do
devlink port split $netdev count $count
check_err $? "Did not split $netdev into $count"
unsplit+=( "${netdev}s0" )
done
}
port_test()
{
local max_ports=$1; shift
local should_fail=$1; shift
split_all_ports $should_fail
occ=$(devlink -j resource show $DEVLINK_DEV \
| jq '.[][][] | select(.name=="physical_ports") |.["occ"]')
[[ $occ -eq $max_ports ]]
if [[ $should_fail -eq 0 ]]; then
check_err $? "Mismatch ports number: Expected $max_ports, got $occ."
else
check_err_fail $should_fail $? "Reached more ports than expected"
fi
}
# SPDX-License-Identifier: GPL-2.0
source ../port_scale.sh
port_get_target()
{
local should_fail=$1
local target
target=$(devlink_resource_size_get physical_ports)
if ((! should_fail)); then
echo $target
else
echo $((target + 1))
fi
}
...@@ -28,7 +28,7 @@ cleanup() ...@@ -28,7 +28,7 @@ cleanup()
trap cleanup EXIT trap cleanup EXIT
ALL_TESTS="router tc_flower mirror_gre tc_police" ALL_TESTS="router tc_flower mirror_gre tc_police port"
for current_test in ${TESTS:-$ALL_TESTS}; do for current_test in ${TESTS:-$ALL_TESTS}; do
source ${current_test}_scale.sh source ${current_test}_scale.sh
......
# SPDX-License-Identifier: GPL-2.0
source ../port_scale.sh
port_get_target()
{
local should_fail=$1
local target
target=$(devlink_resource_size_get physical_ports)
if ((! should_fail)); then
echo $target
else
echo $((target + 1))
fi
}
...@@ -22,7 +22,7 @@ cleanup() ...@@ -22,7 +22,7 @@ cleanup()
devlink_sp_read_kvd_defaults devlink_sp_read_kvd_defaults
trap cleanup EXIT trap cleanup EXIT
ALL_TESTS="router tc_flower mirror_gre tc_police" ALL_TESTS="router tc_flower mirror_gre tc_police port"
for current_test in ${TESTS:-$ALL_TESTS}; do for current_test in ${TESTS:-$ALL_TESTS}; do
source ${current_test}_scale.sh source ${current_test}_scale.sh
......
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