Commit 2a38de06 authored by David S. Miller's avatar David S. Miller

Merge branch 'mlxsw-line-card'

Ido Schimmel says:

====================
mlxsw: Introduce line card support for modular switch

Jiri says:

This patchset introduces support for modular switch systems and also
introduces mlxsw support for NVIDIA Mellanox SN4800 modular switch.
It contains 8 slots to accommodate line cards - replaceable PHY modules
which may contain gearboxes.
Currently supported line card:
16X 100GbE (QSFP28)
Other line cards that are going to be supported:
8X 200GbE (QSFP56)
4X 400GbE (QSFP-DD)
There may be other types of line cards added in the future.

To be consistent with the port split configuration (splitter cabels),
the line card entities are treated in the similar way. The nature of
a line card is not "a pluggable device", but "a pluggable PHY module".

A concept of "provisioning" is introduced. The user may "provision"
certain slot with a line card type. Driver then creates all instances
(devlink ports, netdevices, etc) related to this line card type. It does
not matter if the line card is plugged-in at the time. User is able to
configure netdevices, devlink ports, setup port splitters, etc. From the
perspective of the switch ASIC, all is present and can be configured.

The carrier of netdevices stays down if the line card is not plugged-in.
Once the line card is inserted and activated, the carrier of
the related netdevices is then reflecting the physical line state,
same as for an ordinary fixed port.

Once user does not want to use the line card related instances
anymore, he can "unprovision" the slot. Driver then removes the
instances.

Patches 1-4 are extending devlink driver API and UAPI in order to
register, show, dump, provision and activate the line card.
Patches 5-17 are implementing the introduced API in mlxsw.
The last patch adds a selftest for mlxsw line cards.

Example:
$ devlink port # No ports are listed
$ devlink lc
pci/0000:01:00.0:
  lc 1 state unprovisioned
    supported_types:
       16x100G
  lc 2 state unprovisioned
    supported_types:
       16x100G
  lc 3 state unprovisioned
    supported_types:
       16x100G
  lc 4 state unprovisioned
    supported_types:
       16x100G
  lc 5 state unprovisioned
    supported_types:
       16x100G
  lc 6 state unprovisioned
    supported_types:
       16x100G
  lc 7 state unprovisioned
    supported_types:
       16x100G
  lc 8 state unprovisioned
    supported_types:
       16x100G

Note that driver exposes list supported line card types. Currently
there is only one: "16x100G".

To provision the slot #8:

$ devlink lc set pci/0000:01:00.0 lc 8 type 16x100G
$ devlink lc show pci/0000:01:00.0 lc 8
pci/0000:01:00.0:
  lc 8 state active type 16x100G
    supported_types:
       16x100G
$ devlink port
pci/0000:01:00.0/0: type notset flavour cpu port 0 splittable false
pci/0000:01:00.0/53: type eth netdev enp1s0nl8p1 flavour physical lc 8 port 1 splittable true lanes 4
pci/0000:01:00.0/54: type eth netdev enp1s0nl8p2 flavour physical lc 8 port 2 splittable true lanes 4
pci/0000:01:00.0/55: type eth netdev enp1s0nl8p3 flavour physical lc 8 port 3 splittable true lanes 4
pci/0000:01:00.0/56: type eth netdev enp1s0nl8p4 flavour physical lc 8 port 4 splittable true lanes 4
pci/0000:01:00.0/57: type eth netdev enp1s0nl8p5 flavour physical lc 8 port 5 splittable true lanes 4
pci/0000:01:00.0/58: type eth netdev enp1s0nl8p6 flavour physical lc 8 port 6 splittable true lanes 4
pci/0000:01:00.0/59: type eth netdev enp1s0nl8p7 flavour physical lc 8 port 7 splittable true lanes 4
pci/0000:01:00.0/60: type eth netdev enp1s0nl8p8 flavour physical lc 8 port 8 splittable true lanes 4
pci/0000:01:00.0/61: type eth netdev enp1s0nl8p9 flavour physical lc 8 port 9 splittable true lanes 4
pci/0000:01:00.0/62: type eth netdev enp1s0nl8p10 flavour physical lc 8 port 10 splittable true lanes 4
pci/0000:01:00.0/63: type eth netdev enp1s0nl8p11 flavour physical lc 8 port 11 splittable true lanes 4
pci/0000:01:00.0/64: type eth netdev enp1s0nl8p12 flavour physical lc 8 port 12 splittable true lanes 4
pci/0000:01:00.0/125: type eth netdev enp1s0nl8p13 flavour physical lc 8 port 13 splittable true lanes 4
pci/0000:01:00.0/126: type eth netdev enp1s0nl8p14 flavour physical lc 8 port 14 splittable true lanes 4
pci/0000:01:00.0/127: type eth netdev enp1s0nl8p15 flavour physical lc 8 port 15 splittable true lanes 4
pci/0000:01:00.0/128: type eth netdev enp1s0nl8p16 flavour physical lc 8 port 16 splittable true lanes 4

To uprovision the slot #8:

$ devlink lc set pci/0000:01:00.0 lc 8 notype
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 843f7740 e1fad951
.. SPDX-License-Identifier: GPL-2.0
=================
Devlink Line card
=================
Background
==========
The ``devlink-linecard`` mechanism is targeted for manipulation of
line cards that serve as a detachable PHY modules for modular switch
system. Following operations are provided:
* Get a list of supported line card types.
* Provision of a slot with specific line card type.
* Get and monitor of line card state and its change.
Line card according to the type may contain one or more gearboxes
to mux the lanes with certain speed to multiple ports with lanes
of different speed. Line card ensures N:M mapping between
the switch ASIC modules and physical front panel ports.
Overview
========
Each line card devlink object is created by device driver,
according to the physical line card slots available on the device.
Similar to splitter cable, where the device might have no way
of detection of the splitter cable geometry, the device
might not have a way to detect line card type. For that devices,
concept of provisioning is introduced. It allows the user to:
* Provision a line card slot with certain line card type
- Device driver would instruct the ASIC to prepare all
resources accordingly. The device driver would
create all instances, namely devlink port and netdevices
that reside on the line card, according to the line card type
* Manipulate of line card entities even without line card
being physically connected or powered-up
* Setup splitter cable on line card ports
- As on the ordinary ports, user may provision a splitter
cable of a certain type, without the need to
be physically connected to the port
* Configure devlink ports and netdevices
Netdevice carrier is decided as follows:
* Line card is not inserted or powered-down
- The carrier is always down
* Line card is inserted and powered up
- The carrier is decided as for ordinary port netdevice
Line card state
===============
The ``devlink-linecard`` mechanism supports the following line card states:
* ``unprovisioned``: Line card is not provisioned on the slot.
* ``unprovisioning``: Line card slot is currently being unprovisioned.
* ``provisioning``: Line card slot is currently in a process of being provisioned
with a line card type.
* ``provisioning_failed``: Provisioning was not successful.
* ``provisioned``: Line card slot is provisioned with a type.
* ``active``: Line card is powered-up and active.
The following diagram provides a general overview of ``devlink-linecard``
state transitions::
+-------------------------+
| |
+----------------------------------> unprovisioned |
| | |
| +--------|-------^--------+
| | |
| | |
| +--------v-------|--------+
| | |
| | provisioning |
| | |
| +------------|------------+
| |
| +-----------------------------+
| | |
| +------------v------------+ +------------v------------+ +-------------------------+
| | | | ----> |
+----- provisioning_failed | | provisioned | | active |
| | | | <---- |
| +------------^------------+ +------------|------------+ +-------------------------+
| | |
| | |
| | +------------v------------+
| | | |
| | | unprovisioning |
| | | |
| | +------------|------------+
| | |
| +-----------------------------+
| |
+-----------------------------------------------+
Example usage
=============
.. code:: shell
$ devlink lc show [ DEV [ lc LC_INDEX ] ]
$ devlink lc set DEV lc LC_INDEX [ { type LC_TYPE | notype } ]
# Show current line card configuration and status for all slots:
$ devlink lc
# Set slot 8 to be provisioned with type "16x100G":
$ devlink lc set pci/0000:01:00.0 lc 8 type 16x100G
# Set slot 8 to be unprovisioned:
$ devlink lc set pci/0000:01:00.0 lc 8 notype
......@@ -39,6 +39,7 @@ general.
devlink-resource
devlink-reload
devlink-trap
devlink-linecard
Driver-specific documentation
-----------------------------
......
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_MLXSW_CORE) += mlxsw_core.o
mlxsw_core-objs := core.o core_acl_flex_keys.o \
core_acl_flex_actions.o core_env.o
core_acl_flex_actions.o core_env.o \
core_linecards.o
mlxsw_core-$(CONFIG_MLXSW_CORE_HWMON) += core_hwmon.o
mlxsw_core-$(CONFIG_MLXSW_CORE_THERMAL) += core_thermal.o
obj-$(CONFIG_MLXSW_PCI) += mlxsw_pci.o
......
......@@ -48,6 +48,7 @@ struct mlxsw_core_port {
struct devlink_port devlink_port;
void *port_driver_priv;
u16 local_port;
struct mlxsw_linecard *linecard;
};
void *mlxsw_core_port_driver_priv(struct mlxsw_core_port *mlxsw_core_port)
......@@ -82,6 +83,7 @@ struct mlxsw_core {
struct mlxsw_res res;
struct mlxsw_hwmon *hwmon;
struct mlxsw_thermal *thermal;
struct mlxsw_linecards *linecards;
struct mlxsw_core_port *ports;
unsigned int max_ports;
atomic_t active_ports_count;
......@@ -94,6 +96,17 @@ struct mlxsw_core {
/* driver_priv has to be always the last item */
};
struct mlxsw_linecards *mlxsw_core_linecards(struct mlxsw_core *mlxsw_core)
{
return mlxsw_core->linecards;
}
void mlxsw_core_linecards_set(struct mlxsw_core *mlxsw_core,
struct mlxsw_linecards *linecards)
{
mlxsw_core->linecards = linecards;
}
#define MLXSW_PORT_MAX_PORTS_DEFAULT 0x40
static u64 mlxsw_ports_occ_get(void *priv)
......@@ -2145,6 +2158,10 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
if (err)
goto err_fw_rev_validate;
err = mlxsw_linecards_init(mlxsw_core, mlxsw_bus_info);
if (err)
goto err_linecards_init;
err = mlxsw_core_health_init(mlxsw_core);
if (err)
goto err_health_init;
......@@ -2183,6 +2200,8 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
err_hwmon_init:
mlxsw_core_health_fini(mlxsw_core);
err_health_init:
mlxsw_linecards_fini(mlxsw_core);
err_linecards_init:
err_fw_rev_validate:
if (!reload)
mlxsw_core_params_unregister(mlxsw_core);
......@@ -2255,6 +2274,7 @@ void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core,
mlxsw_thermal_fini(mlxsw_core->thermal);
mlxsw_hwmon_fini(mlxsw_core->hwmon);
mlxsw_core_health_fini(mlxsw_core);
mlxsw_linecards_fini(mlxsw_core);
if (!reload)
mlxsw_core_params_unregister(mlxsw_core);
mlxsw_emad_fini(mlxsw_core);
......@@ -2956,7 +2976,7 @@ EXPORT_SYMBOL(mlxsw_core_res_get);
static int __mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u16 local_port,
enum devlink_port_flavour flavour,
u32 port_number, bool split,
u8 slot_index, u32 port_number, bool split,
u32 split_port_subnumber,
bool splittable, u32 lanes,
const unsigned char *switch_id,
......@@ -2979,6 +2999,15 @@ 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);
if (slot_index) {
struct mlxsw_linecard *linecard;
linecard = mlxsw_linecard_get(mlxsw_core->linecards,
slot_index);
mlxsw_core_port->linecard = linecard;
devlink_port_linecard_set(devlink_port,
linecard->devlink_linecard);
}
err = devl_port_register(devlink, devlink_port, local_port);
if (err)
memset(mlxsw_core_port, 0, sizeof(*mlxsw_core_port));
......@@ -2996,7 +3025,7 @@ static void __mlxsw_core_port_fini(struct mlxsw_core *mlxsw_core, u16 local_port
}
int mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u16 local_port,
u32 port_number, bool split,
u8 slot_index, u32 port_number, bool split,
u32 split_port_subnumber,
bool splittable, u32 lanes,
const unsigned char *switch_id,
......@@ -3005,7 +3034,7 @@ int mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u16 local_port,
int err;
err = __mlxsw_core_port_init(mlxsw_core, local_port,
DEVLINK_PORT_FLAVOUR_PHYSICAL,
DEVLINK_PORT_FLAVOUR_PHYSICAL, slot_index,
port_number, split, split_port_subnumber,
splittable, lanes,
switch_id, switch_id_len);
......@@ -3036,7 +3065,7 @@ int mlxsw_core_cpu_port_init(struct mlxsw_core *mlxsw_core,
err = __mlxsw_core_port_init(mlxsw_core, MLXSW_PORT_CPU_PORT,
DEVLINK_PORT_FLAVOUR_CPU,
0, false, 0, false, 0,
0, 0, false, 0, false, 0,
switch_id, switch_id_len);
if (err)
return err;
......@@ -3112,6 +3141,16 @@ mlxsw_core_port_devlink_port_get(struct mlxsw_core *mlxsw_core,
}
EXPORT_SYMBOL(mlxsw_core_port_devlink_port_get);
struct mlxsw_linecard *
mlxsw_core_port_linecard_get(struct mlxsw_core *mlxsw_core,
u16 local_port)
{
struct mlxsw_core_port *mlxsw_core_port =
&mlxsw_core->ports[local_port];
return mlxsw_core_port->linecard;
}
bool mlxsw_core_port_is_xm(const struct mlxsw_core *mlxsw_core, u16 local_port)
{
const struct mlxsw_bus_info *bus_info = mlxsw_core->bus_info;
......@@ -3124,6 +3163,15 @@ bool mlxsw_core_port_is_xm(const struct mlxsw_core *mlxsw_core, u16 local_port)
}
EXPORT_SYMBOL(mlxsw_core_port_is_xm);
void mlxsw_core_ports_remove_selected(struct mlxsw_core *mlxsw_core,
bool (*selector)(void *priv, u16 local_port),
void *priv)
{
if (WARN_ON_ONCE(!mlxsw_core->driver->ports_remove_selected))
return;
mlxsw_core->driver->ports_remove_selected(mlxsw_core, selector, priv);
}
struct mlxsw_env *mlxsw_core_env(const struct mlxsw_core *mlxsw_core)
{
return mlxsw_core->env;
......
......@@ -35,6 +35,11 @@ unsigned int mlxsw_core_max_ports(const struct mlxsw_core *mlxsw_core);
void *mlxsw_core_driver_priv(struct mlxsw_core *mlxsw_core);
struct mlxsw_linecards *mlxsw_core_linecards(struct mlxsw_core *mlxsw_core);
void mlxsw_core_linecards_set(struct mlxsw_core *mlxsw_core,
struct mlxsw_linecards *linecard);
bool
mlxsw_core_fw_rev_minor_subminor_validate(const struct mlxsw_fw_rev *rev,
const struct mlxsw_fw_rev *req_rev);
......@@ -231,7 +236,8 @@ void mlxsw_core_lag_mapping_clear(struct mlxsw_core *mlxsw_core,
void *mlxsw_core_port_driver_priv(struct mlxsw_core_port *mlxsw_core_port);
int mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u16 local_port,
u32 port_number, bool split, u32 split_port_subnumber,
u8 slot_index, u32 port_number, bool split,
u32 split_port_subnumber,
bool splittable, u32 lanes,
const unsigned char *switch_id,
unsigned char switch_id_len);
......@@ -252,7 +258,14 @@ enum devlink_port_type mlxsw_core_port_type_get(struct mlxsw_core *mlxsw_core,
struct devlink_port *
mlxsw_core_port_devlink_port_get(struct mlxsw_core *mlxsw_core,
u16 local_port);
struct mlxsw_linecard *
mlxsw_core_port_linecard_get(struct mlxsw_core *mlxsw_core,
u16 local_port);
bool mlxsw_core_port_is_xm(const struct mlxsw_core *mlxsw_core, u16 local_port);
void mlxsw_core_ports_remove_selected(struct mlxsw_core *mlxsw_core,
bool (*selector)(void *priv,
u16 local_port),
void *priv);
struct mlxsw_env *mlxsw_core_env(const struct mlxsw_core *mlxsw_core);
int mlxsw_core_schedule_dw(struct delayed_work *dwork, unsigned long delay);
......@@ -326,6 +339,10 @@ struct mlxsw_driver {
unsigned int count, struct netlink_ext_ack *extack);
int (*port_unsplit)(struct mlxsw_core *mlxsw_core, u16 local_port,
struct netlink_ext_ack *extack);
void (*ports_remove_selected)(struct mlxsw_core *mlxsw_core,
bool (*selector)(void *priv,
u16 local_port),
void *priv);
int (*sb_pool_get)(struct mlxsw_core *mlxsw_core,
unsigned int sb_index, u16 pool_index,
struct devlink_sb_pool_info *pool_info);
......@@ -543,4 +560,47 @@ static inline struct mlxsw_skb_cb *mlxsw_skb_cb(struct sk_buff *skb)
return (struct mlxsw_skb_cb *) skb->cb;
}
struct mlxsw_linecards;
enum mlxsw_linecard_status_event_type {
MLXSW_LINECARD_STATUS_EVENT_TYPE_PROVISION,
MLXSW_LINECARD_STATUS_EVENT_TYPE_UNPROVISION,
};
struct mlxsw_linecard {
u8 slot_index;
struct mlxsw_linecards *linecards;
struct devlink_linecard *devlink_linecard;
struct mutex lock; /* Locks accesses to the linecard structure */
char name[MLXSW_REG_MDDQ_SLOT_ASCII_NAME_LEN];
char mbct_pl[MLXSW_REG_MBCT_LEN]; /* Too big for stack */
enum mlxsw_linecard_status_event_type status_event_type_to;
struct delayed_work status_event_to_dw;
u8 provisioned:1,
ready:1,
active:1;
u16 hw_revision;
u16 ini_version;
};
struct mlxsw_linecard_types_info;
struct mlxsw_linecards {
struct mlxsw_core *mlxsw_core;
const struct mlxsw_bus_info *bus_info;
u8 count;
struct mlxsw_linecard_types_info *types_info;
struct mlxsw_linecard linecards[];
};
static inline struct mlxsw_linecard *
mlxsw_linecard_get(struct mlxsw_linecards *linecards, u8 slot_index)
{
return &linecards->linecards[slot_index - 1];
}
int mlxsw_linecards_init(struct mlxsw_core *mlxsw_core,
const struct mlxsw_bus_info *bus_info);
void mlxsw_linecards_fini(struct mlxsw_core *mlxsw_core);
#endif
This diff is collapsed.
......@@ -223,7 +223,7 @@ mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u16 local_port, u8 module)
struct net_device *dev;
int err;
err = mlxsw_core_port_init(mlxsw_m->core, local_port,
err = mlxsw_core_port_init(mlxsw_m->core, local_port, 0,
module + 1, false, 0, false,
0, mlxsw_m->base_mac,
sizeof(mlxsw_m->base_mac));
......@@ -328,6 +328,7 @@ static void mlxsw_m_port_module_unmap(struct mlxsw_m *mlxsw_m, u8 module)
static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m)
{
unsigned int max_ports = mlxsw_core_max_ports(mlxsw_m->core);
struct devlink *devlink = priv_to_devlink(mlxsw_m->core);
u8 last_module = max_ports;
int i;
int err;
......@@ -356,6 +357,7 @@ static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m)
}
/* Create port objects for each valid entry */
devl_lock(devlink);
for (i = 0; i < mlxsw_m->max_ports; i++) {
if (mlxsw_m->module_to_port[i] > 0 &&
!mlxsw_core_port_is_xm(mlxsw_m->core, i)) {
......@@ -366,6 +368,7 @@ static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m)
goto err_module_to_port_create;
}
}
devl_unlock(devlink);
return 0;
......@@ -375,6 +378,7 @@ static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m)
mlxsw_m_port_remove(mlxsw_m,
mlxsw_m->module_to_port[i]);
}
devl_unlock(devlink);
i = max_ports;
err_module_to_port_map:
for (i--; i > 0; i--)
......@@ -387,8 +391,10 @@ static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m)
static void mlxsw_m_ports_remove(struct mlxsw_m *mlxsw_m)
{
struct devlink *devlink = priv_to_devlink(mlxsw_m->core);
int i;
devl_lock(devlink);
for (i = 0; i < mlxsw_m->max_ports; i++) {
if (mlxsw_m->module_to_port[i] > 0) {
mlxsw_m_port_remove(mlxsw_m,
......@@ -396,6 +402,7 @@ static void mlxsw_m_ports_remove(struct mlxsw_m *mlxsw_m)
mlxsw_m_port_module_unmap(mlxsw_m, i);
}
}
devl_unlock(devlink);
kfree(mlxsw_m->module_to_port);
kfree(mlxsw_m->ports);
......@@ -424,7 +431,6 @@ 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;
......@@ -440,9 +446,7 @@ 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;
......@@ -454,11 +458,8 @@ 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;
......
This diff is collapsed.
......@@ -145,11 +145,18 @@ struct mlxsw_sp_mall_entry;
struct mlxsw_sp_port_mapping {
u8 module;
u8 slot_index;
u8 width; /* Number of lanes used by the port */
u8 module_width; /* Number of lanes in the module (static) */
u8 lane;
};
struct mlxsw_sp_port_mapping_events {
struct list_head queue;
spinlock_t queue_lock; /* protects queue */
struct work_struct work;
};
struct mlxsw_sp_parsing {
refcount_t parsing_depth_ref;
u16 parsing_depth;
......@@ -164,7 +171,8 @@ struct mlxsw_sp {
unsigned char base_mac[ETH_ALEN];
const unsigned char *mac_mask;
struct mlxsw_sp_upper *lags;
struct mlxsw_sp_port_mapping **port_mapping;
struct mlxsw_sp_port_mapping *port_mapping;
struct mlxsw_sp_port_mapping_events port_mapping_events;
struct rhashtable sample_trigger_ht;
struct mlxsw_sp_sb *sb;
struct mlxsw_sp_bridge *bridge;
......
......@@ -568,14 +568,14 @@ struct mlxsw_sp_port_stats {
static u64
mlxsw_sp_port_get_transceiver_overheat_stats(struct mlxsw_sp_port *mlxsw_sp_port)
{
struct mlxsw_sp_port_mapping port_mapping = mlxsw_sp_port->mapping;
struct mlxsw_core *mlxsw_core = mlxsw_sp_port->mlxsw_sp->core;
u8 slot_index = mlxsw_sp_port->mapping.slot_index;
u8 module = mlxsw_sp_port->mapping.module;
u64 stats;
int err;
err = mlxsw_env_module_overheat_counter_get(mlxsw_core, 0,
port_mapping.module,
&stats);
err = mlxsw_env_module_overheat_counter_get(mlxsw_core, slot_index,
module, &stats);
if (err)
return mlxsw_sp_port->module_overheat_initial_val;
......@@ -1035,7 +1035,8 @@ static int mlxsw_sp_get_module_info(struct net_device *netdev,
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(netdev);
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
return mlxsw_env_get_module_info(netdev, mlxsw_sp->core, 0,
return mlxsw_env_get_module_info(netdev, mlxsw_sp->core,
mlxsw_sp_port->mapping.slot_index,
mlxsw_sp_port->mapping.module,
modinfo);
}
......@@ -1045,10 +1046,11 @@ static int mlxsw_sp_get_module_eeprom(struct net_device *netdev,
{
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(netdev);
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
u8 slot_index = mlxsw_sp_port->mapping.slot_index;
u8 module = mlxsw_sp_port->mapping.module;
return mlxsw_env_get_module_eeprom(netdev, mlxsw_sp->core, 0,
mlxsw_sp_port->mapping.module, ee,
data);
return mlxsw_env_get_module_eeprom(netdev, mlxsw_sp->core, slot_index,
module, ee, data);
}
static int
......@@ -1058,10 +1060,11 @@ mlxsw_sp_get_module_eeprom_by_page(struct net_device *dev,
{
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
u8 slot_index = mlxsw_sp_port->mapping.slot_index;
u8 module = mlxsw_sp_port->mapping.module;
return mlxsw_env_get_module_eeprom_by_page(mlxsw_sp->core, 0, module,
page, extack);
return mlxsw_env_get_module_eeprom_by_page(mlxsw_sp->core, slot_index,
module, page, extack);
}
static int
......@@ -1202,9 +1205,11 @@ static int mlxsw_sp_reset(struct net_device *dev, u32 *flags)
{
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
u8 slot_index = mlxsw_sp_port->mapping.slot_index;
u8 module = mlxsw_sp_port->mapping.module;
return mlxsw_env_reset_module(dev, mlxsw_sp->core, 0, module, flags);
return mlxsw_env_reset_module(dev, mlxsw_sp->core, slot_index,
module, flags);
}
static int
......@@ -1214,10 +1219,11 @@ mlxsw_sp_get_module_power_mode(struct net_device *dev,
{
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
u8 slot_index = mlxsw_sp_port->mapping.slot_index;
u8 module = mlxsw_sp_port->mapping.module;
return mlxsw_env_get_module_power_mode(mlxsw_sp->core, 0, module,
params, extack);
return mlxsw_env_get_module_power_mode(mlxsw_sp->core, slot_index,
module, params, extack);
}
static int
......@@ -1227,10 +1233,11 @@ mlxsw_sp_set_module_power_mode(struct net_device *dev,
{
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
u8 slot_index = mlxsw_sp_port->mapping.slot_index;
u8 module = mlxsw_sp_port->mapping.module;
return mlxsw_env_set_module_power_mode(mlxsw_sp->core, 0, module,
params->policy, extack);
return mlxsw_env_set_module_power_mode(mlxsw_sp->core, slot_index,
module, params->policy, extack);
}
const struct ethtool_ops mlxsw_sp_port_ethtool_ops = {
......
......@@ -133,6 +133,12 @@ enum mlxsw_event_trap_id {
MLXSW_TRAP_ID_PTP_ING_FIFO = 0x2D,
/* PTP Egress FIFO has a new entry */
MLXSW_TRAP_ID_PTP_EGR_FIFO = 0x2E,
/* Downstream Device Status Change */
MLXSW_TRAP_ID_DSDSC = 0x321,
/* Binary Code Transfer Operation Executed Event */
MLXSW_TRAP_ID_BCTOE = 0x322,
/* Port mapping change */
MLXSW_TRAP_ID_PMLPE = 0x32E,
};
#endif /* _MLXSW_TRAP_H */
......@@ -22,6 +22,7 @@
#include <linux/firmware.h>
struct devlink;
struct devlink_linecard;
struct devlink_port_phys_attrs {
u32 port_number; /* Same value as "split group".
......@@ -135,6 +136,7 @@ struct devlink_port {
struct mutex reporters_lock; /* Protects reporter_list */
struct devlink_rate *devlink_rate;
struct devlink_linecard *linecard;
};
struct devlink_port_new_attrs {
......@@ -148,6 +150,40 @@ struct devlink_port_new_attrs {
sfnum_valid:1;
};
/**
* struct devlink_linecard_ops - Linecard operations
* @provision: callback to provision the linecard slot with certain
* type of linecard. As a result of this operation,
* driver is expected to eventually (could be after
* the function call returns) call one of:
* devlink_linecard_provision_set()
* devlink_linecard_provision_fail()
* @unprovision: callback to unprovision the linecard slot. As a result
* of this operation, driver is expected to eventually
* (could be after the function call returns) call
* devlink_linecard_provision_clear()
* devlink_linecard_provision_fail()
* @same_provision: callback to ask the driver if linecard is already
* provisioned in the same way user asks this linecard to be
* provisioned.
* @types_count: callback to get number of supported types
* @types_get: callback to get next type in list
*/
struct devlink_linecard_ops {
int (*provision)(struct devlink_linecard *linecard, void *priv,
const char *type, const void *type_priv,
struct netlink_ext_ack *extack);
int (*unprovision)(struct devlink_linecard *linecard, void *priv,
struct netlink_ext_ack *extack);
bool (*same_provision)(struct devlink_linecard *linecard, void *priv,
const char *type, const void *type_priv);
unsigned int (*types_count)(struct devlink_linecard *linecard,
void *priv);
void (*types_get)(struct devlink_linecard *linecard,
void *priv, unsigned int index, const char **type,
const void **type_priv);
};
struct devlink_sb_pool_info {
enum devlink_sb_pool_type pool_type;
u32 size;
......@@ -1536,6 +1572,18 @@ void devlink_port_attrs_pci_sf_set(struct devlink_port *devlink_port,
int devlink_rate_leaf_create(struct devlink_port *port, void *priv);
void devlink_rate_leaf_destroy(struct devlink_port *devlink_port);
void devlink_rate_nodes_destroy(struct devlink *devlink);
void devlink_port_linecard_set(struct devlink_port *devlink_port,
struct devlink_linecard *linecard);
struct devlink_linecard *
devlink_linecard_create(struct devlink *devlink, unsigned int linecard_index,
const struct devlink_linecard_ops *ops, void *priv);
void devlink_linecard_destroy(struct devlink_linecard *linecard);
void devlink_linecard_provision_set(struct devlink_linecard *linecard,
const char *type);
void devlink_linecard_provision_clear(struct devlink_linecard *linecard);
void devlink_linecard_provision_fail(struct devlink_linecard *linecard);
void devlink_linecard_activate(struct devlink_linecard *linecard);
void devlink_linecard_deactivate(struct devlink_linecard *linecard);
int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
u32 size, u16 ingress_pools_count,
u16 egress_pools_count, u16 ingress_tc_count,
......
......@@ -131,6 +131,11 @@ enum devlink_command {
DEVLINK_CMD_RATE_NEW,
DEVLINK_CMD_RATE_DEL,
DEVLINK_CMD_LINECARD_GET, /* can dump */
DEVLINK_CMD_LINECARD_SET,
DEVLINK_CMD_LINECARD_NEW,
DEVLINK_CMD_LINECARD_DEL,
/* add new commands above here */
__DEVLINK_CMD_MAX,
DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1
......@@ -338,6 +343,19 @@ enum devlink_reload_limit {
#define DEVLINK_RELOAD_LIMITS_VALID_MASK (_BITUL(__DEVLINK_RELOAD_LIMIT_MAX) - 1)
enum devlink_linecard_state {
DEVLINK_LINECARD_STATE_UNSPEC,
DEVLINK_LINECARD_STATE_UNPROVISIONED,
DEVLINK_LINECARD_STATE_UNPROVISIONING,
DEVLINK_LINECARD_STATE_PROVISIONING,
DEVLINK_LINECARD_STATE_PROVISIONING_FAILED,
DEVLINK_LINECARD_STATE_PROVISIONED,
DEVLINK_LINECARD_STATE_ACTIVE,
__DEVLINK_LINECARD_STATE_MAX,
DEVLINK_LINECARD_STATE_MAX = __DEVLINK_LINECARD_STATE_MAX - 1
};
enum devlink_attr {
/* don't change the order or add anything between, this is ABI! */
DEVLINK_ATTR_UNSPEC,
......@@ -553,6 +571,11 @@ enum devlink_attr {
DEVLINK_ATTR_REGION_MAX_SNAPSHOTS, /* u32 */
DEVLINK_ATTR_LINECARD_INDEX, /* u32 */
DEVLINK_ATTR_LINECARD_STATE, /* u8 */
DEVLINK_ATTR_LINECARD_TYPE, /* string */
DEVLINK_ATTR_LINECARD_SUPPORTED_TYPES, /* nested */
/* add new attributes above here, update the policy in devlink.c */
__DEVLINK_ATTR_MAX,
......
This diff is collapsed.
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# In addition to the common variables, user might use:
# LC_SLOT - If not set, all probed line cards are going to be tested,
# with an exception of the "activation_16x100G_test".
# It set, only the selected line card is going to be used
# for tests, including "activation_16x100G_test".
lib_dir=$(dirname $0)/../../../net/forwarding
ALL_TESTS="
unprovision_test
provision_test
activation_16x100G_test
"
NUM_NETIFS=0
source $lib_dir/lib.sh
source $lib_dir/devlink_lib.sh
until_lc_state_is()
{
local state=$1; shift
local current=$("$@")
echo "$current"
[ "$current" == "$state" ]
}
until_lc_state_is_not()
{
! until_lc_state_is "$@"
}
lc_state_get()
{
local lc=$1
devlink lc show $DEVLINK_DEV lc $lc -j | jq -e -r ".[][][].state"
}
lc_wait_until_state_changes()
{
local lc=$1
local state=$2
local timeout=$3 # ms
busywait "$timeout" until_lc_state_is_not "$state" lc_state_get "$lc"
}
lc_wait_until_state_becomes()
{
local lc=$1
local state=$2
local timeout=$3 # ms
busywait "$timeout" until_lc_state_is "$state" lc_state_get "$lc"
}
until_lc_port_count_is()
{
local port_count=$1; shift
local current=$("$@")
echo "$current"
[ $current == $port_count ]
}
lc_port_count_get()
{
local lc=$1
devlink port -j | jq -e -r ".[][] | select(.lc==$lc) | .port" | wc -l
}
lc_wait_until_port_count_is()
{
local lc=$1
local port_count=$2
local timeout=$3 # ms
busywait "$timeout" until_lc_port_count_is "$port_count" lc_port_count_get "$lc"
}
PROV_UNPROV_TIMEOUT=8000 # ms
POST_PROV_ACT_TIMEOUT=2000 # ms
PROV_PORTS_INSTANTIATION_TIMEOUT=15000 # ms
unprovision_one()
{
local lc=$1
local state
state=$(lc_state_get $lc)
check_err $? "Failed to get state of linecard $lc"
if [[ "$state" == "unprovisioned" ]]; then
return
fi
log_info "Unprovisioning linecard $lc"
devlink lc set $DEVLINK_DEV lc $lc notype
check_err $? "Failed to trigger linecard $lc unprovisioning"
state=$(lc_wait_until_state_changes $lc "unprovisioning" \
$PROV_UNPROV_TIMEOUT)
check_err $? "Failed to unprovision linecard $lc (timeout)"
[ "$state" == "unprovisioned" ]
check_err $? "Failed to unprovision linecard $lc (state=$state)"
}
provision_one()
{
local lc=$1
local type=$2
local state
log_info "Provisioning linecard $lc"
devlink lc set $DEVLINK_DEV lc $lc type $type
check_err $? "Failed trigger linecard $lc provisioning"
state=$(lc_wait_until_state_changes $lc "provisioning" \
$PROV_UNPROV_TIMEOUT)
check_err $? "Failed to provision linecard $lc (timeout)"
[ "$state" == "provisioned" ] || [ "$state" == "active" ]
check_err $? "Failed to provision linecard $lc (state=$state)"
provisioned_type=$(devlink lc show $DEVLINK_DEV lc $lc -j | jq -e -r ".[][][].type")
[ "$provisioned_type" == "$type" ]
check_err $? "Wrong provision type returned for linecard $lc (got \"$provisioned_type\", expected \"$type\")"
# Wait for possible activation to make sure the state
# won't change after return from this function.
state=$(lc_wait_until_state_becomes $lc "active" \
$POST_PROV_ACT_TIMEOUT)
}
unprovision_test()
{
RET=0
local lc
lc=$LC_SLOT
unprovision_one $lc
log_test "Unprovision"
}
LC_16X100G_TYPE="16x100G"
LC_16X100G_PORT_COUNT=16
supported_types_check()
{
local lc=$1
local supported_types_count
local type_index
local lc_16x100_found=false
supported_types_count=$(devlink lc show $DEVLINK_DEV lc $lc -j | \
jq -e -r ".[][][].supported_types | length")
[ $supported_types_count != 0 ]
check_err $? "No supported types found for linecard $lc"
for (( type_index=0; type_index<$supported_types_count; type_index++ ))
do
type=$(devlink lc show $DEVLINK_DEV lc $lc -j | \
jq -e -r ".[][][].supported_types[$type_index]")
if [[ "$type" == "$LC_16X100G_TYPE" ]]; then
lc_16x100_found=true
break
fi
done
[ $lc_16x100_found = true ]
check_err $? "16X100G not found between supported types of linecard $lc"
}
ports_check()
{
local lc=$1
local expected_port_count=$2
local port_count
port_count=$(lc_wait_until_port_count_is $lc $expected_port_count \
$PROV_PORTS_INSTANTIATION_TIMEOUT)
[ $port_count != 0 ]
check_err $? "No port associated with linecard $lc"
[ $port_count == $expected_port_count ]
check_err $? "Unexpected port count linecard $lc (got $port_count, expected $expected_port_count)"
}
provision_test()
{
RET=0
local lc
local type
local state
lc=$LC_SLOT
supported_types_check $lc
state=$(lc_state_get $lc)
check_err $? "Failed to get state of linecard $lc"
if [[ "$state" != "unprovisioned" ]]; then
unprovision_one $lc
fi
provision_one $lc $LC_16X100G_TYPE
ports_check $lc $LC_16X100G_PORT_COUNT
log_test "Provision"
}
ACTIVATION_TIMEOUT=20000 # ms
interface_check()
{
ip link set $h1 up
ip link set $h2 up
ifaces_upped=true
setup_wait
}
activation_16x100G_test()
{
RET=0
local lc
local type
local state
lc=$LC_SLOT
type=$LC_16X100G_TYPE
unprovision_one $lc
provision_one $lc $type
state=$(lc_wait_until_state_becomes $lc "active" \
$ACTIVATION_TIMEOUT)
check_err $? "Failed to get linecard $lc activated (timeout)"
interface_check
log_test "Activation 16x100G"
}
setup_prepare()
{
local lc_num=$(devlink lc show -j | jq -e -r ".[][\"$DEVLINK_DEV\"] |length")
if [[ $? -ne 0 ]] || [[ $lc_num -eq 0 ]]; then
echo "SKIP: No linecard support found"
exit $ksft_skip
fi
if [ -z "$LC_SLOT" ]; then
echo "SKIP: \"LC_SLOT\" variable not provided"
exit $ksft_skip
fi
# Interfaces are not present during the script start,
# that's why we define NUM_NETIFS here so dummy
# implicit veth pairs are not created.
NUM_NETIFS=2
h1=${NETIFS[p1]}
h2=${NETIFS[p2]}
ifaces_upped=false
}
cleanup()
{
if [ "$ifaces_upped" = true ] ; then
ip link set $h1 down
ip link set $h2 down
fi
}
trap cleanup EXIT
setup_prepare
tests_run
exit $EXIT_STATUS
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