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

Merge branch 'mlxsw-next'

Ido Schimmel says:

====================
mlxsw: spectrum: Adjustments to port split and label port

Jiri says:

This patchset includes patches that prepare the driver to support modular
systems.

PLLP register is introduced to get front panel port label which is no
longer equivalent to "module + 1" for modular systems, where the
numbering is per line card.

So far for all systems all front panel ports had same format and could
be split to the same number of subports. This is no longer true for
modular systems, where every line card can have different types of front
panel ports.

The PMTDB register is introduced to easily query FW for split
capabilities of particular front panel port. It is generic for use in
modular and non-modular systems.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 13bb8429 cd92d79d
......@@ -2944,44 +2944,6 @@ bool mlxsw_core_is_initialized(const struct mlxsw_core *mlxsw_core)
return mlxsw_core->is_initialized;
}
int mlxsw_core_module_max_width(struct mlxsw_core *mlxsw_core, u8 module)
{
enum mlxsw_reg_pmtm_module_type module_type;
char pmtm_pl[MLXSW_REG_PMTM_LEN];
int err;
mlxsw_reg_pmtm_pack(pmtm_pl, module);
err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(pmtm), pmtm_pl);
if (err)
return err;
mlxsw_reg_pmtm_unpack(pmtm_pl, &module_type);
/* Here we need to get the module width according to the module type. */
switch (module_type) {
case MLXSW_REG_PMTM_MODULE_TYPE_C2C8X:
case MLXSW_REG_PMTM_MODULE_TYPE_QSFP_DD:
case MLXSW_REG_PMTM_MODULE_TYPE_OSFP:
return 8;
case MLXSW_REG_PMTM_MODULE_TYPE_C2C4X:
case MLXSW_REG_PMTM_MODULE_TYPE_BP_4X:
case MLXSW_REG_PMTM_MODULE_TYPE_QSFP:
return 4;
case MLXSW_REG_PMTM_MODULE_TYPE_C2C2X:
case MLXSW_REG_PMTM_MODULE_TYPE_BP_2X:
case MLXSW_REG_PMTM_MODULE_TYPE_SFP_DD:
case MLXSW_REG_PMTM_MODULE_TYPE_DSFP:
return 2;
case MLXSW_REG_PMTM_MODULE_TYPE_C2C1X:
case MLXSW_REG_PMTM_MODULE_TYPE_BP_1X:
case MLXSW_REG_PMTM_MODULE_TYPE_SFP:
return 1;
default:
return -EINVAL;
}
}
EXPORT_SYMBOL(mlxsw_core_module_max_width);
static void mlxsw_core_buf_dump_dbg(struct mlxsw_core *mlxsw_core,
const char *buf, size_t size)
{
......
......@@ -250,7 +250,6 @@ mlxsw_core_port_devlink_port_get(struct mlxsw_core *mlxsw_core,
bool mlxsw_core_port_is_xm(const struct mlxsw_core *mlxsw_core, u8 local_port);
struct mlxsw_env *mlxsw_core_env(const struct mlxsw_core *mlxsw_core);
bool mlxsw_core_is_initialized(const struct mlxsw_core *mlxsw_core);
int mlxsw_core_module_max_width(struct mlxsw_core *mlxsw_core, u8 module);
int mlxsw_core_schedule_dw(struct delayed_work *dwork, unsigned long delay);
bool mlxsw_core_schedule_work(struct work_struct *work);
......
......@@ -5766,6 +5766,69 @@ static inline void mlxsw_reg_pplr_pack(char *payload, u8 local_port,
MLXSW_REG_PPLR_LB_TYPE_BIT_PHY_LOCAL : 0);
}
/* PMTDB - Port Module To local DataBase Register
* ----------------------------------------------
* The PMTDB register allows to query the possible module<->local port
* mapping than can be used in PMLP. It does not represent the actual/current
* mapping of the local to module. Actual mapping is only defined by PMLP.
*/
#define MLXSW_REG_PMTDB_ID 0x501A
#define MLXSW_REG_PMTDB_LEN 0x40
MLXSW_REG_DEFINE(pmtdb, MLXSW_REG_PMTDB_ID, MLXSW_REG_PMTDB_LEN);
/* reg_pmtdb_slot_index
* Slot index (0: Main board).
* Access: Index
*/
MLXSW_ITEM32(reg, pmtdb, slot_index, 0x00, 24, 4);
/* reg_pmtdb_module
* Module number.
* Access: Index
*/
MLXSW_ITEM32(reg, pmtdb, module, 0x00, 16, 8);
/* reg_pmtdb_ports_width
* Port's width
* Access: Index
*/
MLXSW_ITEM32(reg, pmtdb, ports_width, 0x00, 12, 4);
/* reg_pmtdb_num_ports
* Number of ports in a single module (split/breakout)
* Access: Index
*/
MLXSW_ITEM32(reg, pmtdb, num_ports, 0x00, 8, 4);
enum mlxsw_reg_pmtdb_status {
MLXSW_REG_PMTDB_STATUS_SUCCESS,
};
/* reg_pmtdb_status
* Status
* Access: RO
*/
MLXSW_ITEM32(reg, pmtdb, status, 0x00, 0, 4);
/* reg_pmtdb_port_num
* The local_port value which can be assigned to the module.
* In case of more than one port, port<x> represent the /<x> port of
* the module.
* Access: RO
*/
MLXSW_ITEM16_INDEXED(reg, pmtdb, port_num, 0x04, 0, 8, 0x02, 0x00, false);
static inline void mlxsw_reg_pmtdb_pack(char *payload, u8 slot_index, u8 module,
u8 ports_width, u8 num_ports)
{
MLXSW_REG_ZERO(pmtdb, payload);
mlxsw_reg_pmtdb_slot_index_set(payload, slot_index);
mlxsw_reg_pmtdb_module_set(payload, module);
mlxsw_reg_pmtdb_ports_width_set(payload, ports_width);
mlxsw_reg_pmtdb_num_ports_set(payload, num_ports);
}
/* PMPE - Port Module Plug/Unplug Event Register
* ---------------------------------------------
* This register reports any operational status change of a module.
......@@ -5860,67 +5923,51 @@ static inline void mlxsw_reg_pddr_pack(char *payload, u8 local_port,
mlxsw_reg_pddr_page_select_set(payload, page_select);
}
/* PMTM - Port Module Type Mapping Register
* ----------------------------------------
* The PMTM allows query or configuration of module types.
/* PLLP - Port Local port to Label Port mapping Register
* -----------------------------------------------------
* The PLLP register returns the mapping from Local Port into Label Port.
*/
#define MLXSW_REG_PMTM_ID 0x5067
#define MLXSW_REG_PMTM_LEN 0x10
#define MLXSW_REG_PLLP_ID 0x504A
#define MLXSW_REG_PLLP_LEN 0x10
MLXSW_REG_DEFINE(pmtm, MLXSW_REG_PMTM_ID, MLXSW_REG_PMTM_LEN);
MLXSW_REG_DEFINE(pllp, MLXSW_REG_PLLP_ID, MLXSW_REG_PLLP_LEN);
/* reg_pmtm_module
* Module number.
/* reg_pllp_local_port
* Local port number.
* Access: Index
*/
MLXSW_ITEM32(reg, pmtm, module, 0x00, 16, 8);
MLXSW_ITEM32(reg, pllp, local_port, 0x00, 16, 8);
enum mlxsw_reg_pmtm_module_type {
/* Backplane with 4 lanes */
MLXSW_REG_PMTM_MODULE_TYPE_BP_4X,
/* QSFP */
MLXSW_REG_PMTM_MODULE_TYPE_QSFP,
/* SFP */
MLXSW_REG_PMTM_MODULE_TYPE_SFP,
/* Backplane with single lane */
MLXSW_REG_PMTM_MODULE_TYPE_BP_1X = 4,
/* Backplane with two lane */
MLXSW_REG_PMTM_MODULE_TYPE_BP_2X = 8,
/* Chip2Chip4x */
MLXSW_REG_PMTM_MODULE_TYPE_C2C4X = 10,
/* Chip2Chip2x */
MLXSW_REG_PMTM_MODULE_TYPE_C2C2X,
/* Chip2Chip1x */
MLXSW_REG_PMTM_MODULE_TYPE_C2C1X,
/* QSFP-DD */
MLXSW_REG_PMTM_MODULE_TYPE_QSFP_DD = 14,
/* OSFP */
MLXSW_REG_PMTM_MODULE_TYPE_OSFP,
/* SFP-DD */
MLXSW_REG_PMTM_MODULE_TYPE_SFP_DD,
/* DSFP */
MLXSW_REG_PMTM_MODULE_TYPE_DSFP,
/* Chip2Chip8x */
MLXSW_REG_PMTM_MODULE_TYPE_C2C8X,
};
/* reg_pllp_label_port
* Front panel label of the port.
* Access: RO
*/
MLXSW_ITEM32(reg, pllp, label_port, 0x00, 0, 8);
/* reg_pmtm_module_type
* Module type.
* Access: RW
/* reg_pllp_split_num
* Label split mapping for local_port.
* Access: RO
*/
MLXSW_ITEM32(reg, pmtm, module_type, 0x04, 0, 4);
MLXSW_ITEM32(reg, pllp, split_num, 0x04, 0, 4);
static inline void mlxsw_reg_pmtm_pack(char *payload, u8 module)
/* reg_pllp_slot_index
* Slot index (0: Main board).
* Access: RO
*/
MLXSW_ITEM32(reg, pllp, slot_index, 0x08, 0, 4);
static inline void mlxsw_reg_pllp_pack(char *payload, u8 local_port)
{
MLXSW_REG_ZERO(pmtm, payload);
mlxsw_reg_pmtm_module_set(payload, module);
MLXSW_REG_ZERO(pllp, payload);
mlxsw_reg_pllp_local_port_set(payload, local_port);
}
static inline void
mlxsw_reg_pmtm_unpack(char *payload,
enum mlxsw_reg_pmtm_module_type *module_type)
static inline void mlxsw_reg_pllp_unpack(char *payload, u8 *label_port,
u8 *split_num, u8 *slot_index)
{
*module_type = mlxsw_reg_pmtm_module_type_get(payload);
*label_port = mlxsw_reg_pllp_label_port_get(payload);
*split_num = mlxsw_reg_pllp_split_num_get(payload);
*slot_index = mlxsw_reg_pllp_slot_index_get(payload);
}
/* HTGT - Host Trap Group Table
......@@ -12200,9 +12247,10 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = {
MLXSW_REG(pspa),
MLXSW_REG(pmaos),
MLXSW_REG(pplr),
MLXSW_REG(pmtdb),
MLXSW_REG(pmpe),
MLXSW_REG(pddr),
MLXSW_REG(pmtm),
MLXSW_REG(pllp),
MLXSW_REG(htgt),
MLXSW_REG(hpkt),
MLXSW_REG(rgcr),
......
......@@ -25,9 +25,6 @@ enum mlxsw_res_id {
MLXSW_RES_ID_MAX_SYSTEM_PORT,
MLXSW_RES_ID_MAX_LAG,
MLXSW_RES_ID_MAX_LAG_MEMBERS,
MLXSW_RES_ID_LOCAL_PORTS_IN_1X,
MLXSW_RES_ID_LOCAL_PORTS_IN_2X,
MLXSW_RES_ID_LOCAL_PORTS_IN_4X,
MLXSW_RES_ID_GUARANTEED_SHARED_BUFFER,
MLXSW_RES_ID_CELL_SIZE,
MLXSW_RES_ID_MAX_HEADROOM_SIZE,
......@@ -84,9 +81,6 @@ static u16 mlxsw_res_ids[] = {
[MLXSW_RES_ID_MAX_SYSTEM_PORT] = 0x2502,
[MLXSW_RES_ID_MAX_LAG] = 0x2520,
[MLXSW_RES_ID_MAX_LAG_MEMBERS] = 0x2521,
[MLXSW_RES_ID_LOCAL_PORTS_IN_1X] = 0x2610,
[MLXSW_RES_ID_LOCAL_PORTS_IN_2X] = 0x2611,
[MLXSW_RES_ID_LOCAL_PORTS_IN_4X] = 0x2612,
[MLXSW_RES_ID_GUARANTEED_SHARED_BUFFER] = 0x2805, /* Bytes */
[MLXSW_RES_ID_CELL_SIZE] = 0x2803, /* Bytes */
[MLXSW_RES_ID_MAX_HEADROOM_SIZE] = 0x2811, /* Bytes */
......
......@@ -47,7 +47,7 @@
#define MLXSW_SP1_FWREV_MAJOR 13
#define MLXSW_SP1_FWREV_MINOR 2008
#define MLXSW_SP1_FWREV_SUBMINOR 2406
#define MLXSW_SP1_FWREV_SUBMINOR 3326
#define MLXSW_SP1_FWREV_CAN_RESET_MINOR 1702
static const struct mlxsw_fw_rev mlxsw_sp1_fw_rev = {
......@@ -64,7 +64,7 @@ static const struct mlxsw_fw_rev mlxsw_sp1_fw_rev = {
#define MLXSW_SP2_FWREV_MAJOR 29
#define MLXSW_SP2_FWREV_MINOR 2008
#define MLXSW_SP2_FWREV_SUBMINOR 2406
#define MLXSW_SP2_FWREV_SUBMINOR 3326
static const struct mlxsw_fw_rev mlxsw_sp2_fw_rev = {
.major = MLXSW_SP2_FWREV_MAJOR,
......@@ -79,7 +79,7 @@ static const struct mlxsw_fw_rev mlxsw_sp2_fw_rev = {
#define MLXSW_SP3_FWREV_MAJOR 30
#define MLXSW_SP3_FWREV_MINOR 2008
#define MLXSW_SP3_FWREV_SUBMINOR 2406
#define MLXSW_SP3_FWREV_SUBMINOR 3326
static const struct mlxsw_fw_rev mlxsw_sp3_fw_rev = {
.major = MLXSW_SP3_FWREV_MAJOR,
......@@ -351,12 +351,12 @@ static int mlxsw_sp_port_mtu_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 mtu)
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmtu), pmtu_pl);
}
static int mlxsw_sp_port_swid_set(struct mlxsw_sp_port *mlxsw_sp_port, u8 swid)
static int mlxsw_sp_port_swid_set(struct mlxsw_sp *mlxsw_sp,
u8 local_port, u8 swid)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
char pspa_pl[MLXSW_REG_PSPA_LEN];
mlxsw_reg_pspa_pack(pspa_pl, swid, mlxsw_sp_port->local_port);
mlxsw_reg_pspa_pack(pspa_pl, swid, local_port);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pspa), pspa_pl);
}
......@@ -529,18 +529,19 @@ mlxsw_sp_port_module_info_get(struct mlxsw_sp *mlxsw_sp, u8 local_port,
port_mapping->module = module;
port_mapping->width = width;
port_mapping->module_width = width;
port_mapping->lane = mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, 0);
return 0;
}
static int mlxsw_sp_port_module_map(struct mlxsw_sp_port *mlxsw_sp_port)
static int
mlxsw_sp_port_module_map(struct mlxsw_sp *mlxsw_sp, u8 local_port,
const struct mlxsw_sp_port_mapping *port_mapping)
{
struct mlxsw_sp_port_mapping *port_mapping = &mlxsw_sp_port->mapping;
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
char pmlp_pl[MLXSW_REG_PMLP_LEN];
int i;
mlxsw_reg_pmlp_pack(pmlp_pl, mlxsw_sp_port->local_port);
mlxsw_reg_pmlp_pack(pmlp_pl, local_port);
mlxsw_reg_pmlp_width_set(pmlp_pl, port_mapping->width);
for (i = 0; i < port_mapping->width; i++) {
mlxsw_reg_pmlp_module_set(pmlp_pl, i, port_mapping->module);
......@@ -550,12 +551,11 @@ static int mlxsw_sp_port_module_map(struct mlxsw_sp_port *mlxsw_sp_port)
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl);
}
static int mlxsw_sp_port_module_unmap(struct mlxsw_sp_port *mlxsw_sp_port)
static int mlxsw_sp_port_module_unmap(struct mlxsw_sp *mlxsw_sp, u8 local_port)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
char pmlp_pl[MLXSW_REG_PMLP_LEN];
mlxsw_reg_pmlp_pack(pmlp_pl, mlxsw_sp_port->local_port);
mlxsw_reg_pmlp_pack(pmlp_pl, local_port);
mlxsw_reg_pmlp_width_set(pmlp_pl, 0);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl);
}
......@@ -1442,29 +1442,68 @@ mlxsw_sp_port_vlan_classification_set(struct mlxsw_sp_port *mlxsw_sp_port,
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvc), spvc_pl);
}
static int mlxsw_sp_port_label_info_get(struct mlxsw_sp *mlxsw_sp,
u8 local_port, u8 *port_number,
u8 *split_port_subnumber,
u8 *slot_index)
{
char pllp_pl[MLXSW_REG_PLLP_LEN];
int err;
mlxsw_reg_pllp_pack(pllp_pl, local_port);
err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(pllp), pllp_pl);
if (err)
return err;
mlxsw_reg_pllp_unpack(pllp_pl, port_number,
split_port_subnumber, slot_index);
return 0;
}
static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
u8 split_base_local_port,
bool split,
struct mlxsw_sp_port_mapping *port_mapping)
{
struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
bool split = !!split_base_local_port;
struct mlxsw_sp_port *mlxsw_sp_port;
u32 lanes = port_mapping->width;
u8 split_port_subnumber;
struct net_device *dev;
u8 port_number;
u8 slot_index;
bool splittable;
int err;
err = mlxsw_sp_port_module_map(mlxsw_sp, local_port, port_mapping);
if (err) {
dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to map module\n",
local_port);
return err;
}
err = mlxsw_sp_port_swid_set(mlxsw_sp, local_port, 0);
if (err) {
dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set SWID\n",
local_port);
goto err_port_swid_set;
}
err = mlxsw_sp_port_label_info_get(mlxsw_sp, local_port, &port_number,
&split_port_subnumber, &slot_index);
if (err) {
dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to get port label information\n",
local_port);
goto err_port_label_info_get;
}
splittable = lanes > 1 && !split;
err = mlxsw_core_port_init(mlxsw_sp->core, local_port,
port_mapping->module + 1, split,
port_mapping->lane / lanes,
splittable, lanes,
mlxsw_sp->base_mac,
port_number, split, split_port_subnumber,
splittable, lanes, mlxsw_sp->base_mac,
sizeof(mlxsw_sp->base_mac));
if (err) {
dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to init core port\n",
local_port);
return err;
goto err_core_port_init;
}
dev = alloc_etherdev(sizeof(struct mlxsw_sp_port));
......@@ -1480,7 +1519,6 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
mlxsw_sp_port->local_port = local_port;
mlxsw_sp_port->pvid = MLXSW_SP_DEFAULT_VID;
mlxsw_sp_port->split = split;
mlxsw_sp_port->split_base_local_port = split_base_local_port;
mlxsw_sp_port->mapping = *port_mapping;
mlxsw_sp_port->link.autoneg = 1;
INIT_LIST_HEAD(&mlxsw_sp_port->vlans_list);
......@@ -1498,20 +1536,6 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
dev->netdev_ops = &mlxsw_sp_port_netdev_ops;
dev->ethtool_ops = &mlxsw_sp_port_ethtool_ops;
err = mlxsw_sp_port_module_map(mlxsw_sp_port);
if (err) {
dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to map module\n",
mlxsw_sp_port->local_port);
goto err_port_module_map;
}
err = mlxsw_sp_port_swid_set(mlxsw_sp_port, 0);
if (err) {
dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set SWID\n",
mlxsw_sp_port->local_port);
goto err_port_swid_set;
}
err = mlxsw_sp_port_dev_addr_init(mlxsw_sp_port);
if (err) {
dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unable to init port mac address\n",
......@@ -1712,15 +1736,17 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
err_port_speed_by_width_set:
err_port_system_port_mapping_set:
err_dev_addr_init:
mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT);
err_port_swid_set:
mlxsw_sp_port_module_unmap(mlxsw_sp_port);
err_port_module_map:
free_percpu(mlxsw_sp_port->pcpu_stats);
err_alloc_stats:
free_netdev(dev);
err_alloc_etherdev:
mlxsw_core_port_fini(mlxsw_sp->core, local_port);
err_core_port_init:
err_port_label_info_get:
mlxsw_sp_port_swid_set(mlxsw_sp, local_port,
MLXSW_PORT_SWID_DISABLED_PORT);
err_port_swid_set:
mlxsw_sp_port_module_unmap(mlxsw_sp, local_port);
return err;
}
......@@ -1742,12 +1768,13 @@ static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port)
mlxsw_sp_port_dcb_fini(mlxsw_sp_port);
mlxsw_sp_port_tc_mc_mode_set(mlxsw_sp_port, false);
mlxsw_sp_port_buffers_fini(mlxsw_sp_port);
mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT);
mlxsw_sp_port_module_unmap(mlxsw_sp_port);
free_percpu(mlxsw_sp_port->pcpu_stats);
WARN_ON_ONCE(!list_empty(&mlxsw_sp_port->vlans_list));
free_netdev(mlxsw_sp_port->dev);
mlxsw_core_port_fini(mlxsw_sp->core, local_port);
mlxsw_sp_port_swid_set(mlxsw_sp, local_port,
MLXSW_PORT_SWID_DISABLED_PORT);
mlxsw_sp_port_module_unmap(mlxsw_sp, local_port);
}
static int mlxsw_sp_cpu_port_create(struct mlxsw_sp *mlxsw_sp)
......@@ -1789,8 +1816,15 @@ static void mlxsw_sp_cpu_port_remove(struct mlxsw_sp *mlxsw_sp)
kfree(mlxsw_sp_port);
}
static bool mlxsw_sp_local_port_valid(u8 local_port)
{
return local_port != MLXSW_PORT_CPU_PORT;
}
static bool mlxsw_sp_port_created(struct mlxsw_sp *mlxsw_sp, u8 local_port)
{
if (!mlxsw_sp_local_port_valid(local_port))
return false;
return mlxsw_sp->ports[local_port] != NULL;
}
......@@ -1827,7 +1861,7 @@ static int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp)
port_mapping = mlxsw_sp->port_mapping[i];
if (!port_mapping)
continue;
err = mlxsw_sp_port_create(mlxsw_sp, i, 0, port_mapping);
err = mlxsw_sp_port_create(mlxsw_sp, i, false, port_mapping);
if (err)
goto err_port_create;
}
......@@ -1894,17 +1928,10 @@ static void mlxsw_sp_port_module_info_fini(struct mlxsw_sp *mlxsw_sp)
kfree(mlxsw_sp->port_mapping);
}
static u8 mlxsw_sp_cluster_base_port_get(u8 local_port, unsigned int max_width)
{
u8 offset = (local_port - 1) % max_width;
return local_port - offset;
}
static int
mlxsw_sp_port_split_create(struct mlxsw_sp *mlxsw_sp, u8 base_port,
mlxsw_sp_port_split_create(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_port_mapping *port_mapping,
unsigned int count, u8 offset)
unsigned int count, const char *pmtdb_pl)
{
struct mlxsw_sp_port_mapping split_port_mapping;
int err, i;
......@@ -1912,8 +1939,13 @@ mlxsw_sp_port_split_create(struct mlxsw_sp *mlxsw_sp, u8 base_port,
split_port_mapping = *port_mapping;
split_port_mapping.width /= count;
for (i = 0; i < count; i++) {
err = mlxsw_sp_port_create(mlxsw_sp, base_port + i * offset,
base_port, &split_port_mapping);
u8 s_local_port = mlxsw_reg_pmtdb_port_num_get(pmtdb_pl, i);
if (!mlxsw_sp_local_port_valid(s_local_port))
continue;
err = mlxsw_sp_port_create(mlxsw_sp, s_local_port,
true, &split_port_mapping);
if (err)
goto err_port_create;
split_port_mapping.lane += split_port_mapping.width;
......@@ -1922,49 +1954,34 @@ mlxsw_sp_port_split_create(struct mlxsw_sp *mlxsw_sp, u8 base_port,
return 0;
err_port_create:
for (i--; i >= 0; i--)
if (mlxsw_sp_port_created(mlxsw_sp, base_port + i * offset))
mlxsw_sp_port_remove(mlxsw_sp, base_port + i * offset);
for (i--; i >= 0; i--) {
u8 s_local_port = mlxsw_reg_pmtdb_port_num_get(pmtdb_pl, i);
if (mlxsw_sp_port_created(mlxsw_sp, s_local_port))
mlxsw_sp_port_remove(mlxsw_sp, s_local_port);
}
return err;
}
static void mlxsw_sp_port_unsplit_create(struct mlxsw_sp *mlxsw_sp,
u8 base_port,
unsigned int count, u8 offset)
unsigned int count,
const char *pmtdb_pl)
{
struct mlxsw_sp_port_mapping *port_mapping;
int i;
/* Go over original unsplit ports in the gap and recreate them. */
for (i = 0; i < count * offset; i++) {
port_mapping = mlxsw_sp->port_mapping[base_port + i];
if (!port_mapping)
for (i = 0; i < count; i++) {
u8 local_port = mlxsw_reg_pmtdb_port_num_get(pmtdb_pl, i);
port_mapping = mlxsw_sp->port_mapping[local_port];
if (!port_mapping || !mlxsw_sp_local_port_valid(local_port))
continue;
mlxsw_sp_port_create(mlxsw_sp, base_port + i, 0, port_mapping);
mlxsw_sp_port_create(mlxsw_sp, local_port,
false, port_mapping);
}
}
static int mlxsw_sp_local_ports_offset(struct mlxsw_core *mlxsw_core,
unsigned int count,
unsigned int max_width)
{
enum mlxsw_res_id local_ports_in_x_res_id;
int split_width = max_width / count;
if (split_width == 1)
local_ports_in_x_res_id = MLXSW_RES_ID_LOCAL_PORTS_IN_1X;
else if (split_width == 2)
local_ports_in_x_res_id = MLXSW_RES_ID_LOCAL_PORTS_IN_2X;
else if (split_width == 4)
local_ports_in_x_res_id = MLXSW_RES_ID_LOCAL_PORTS_IN_4X;
else
return -EINVAL;
if (!mlxsw_core_res_valid(mlxsw_core, local_ports_in_x_res_id))
return -EINVAL;
return mlxsw_core_res_get(mlxsw_core, local_ports_in_x_res_id);
}
static struct mlxsw_sp_port *
mlxsw_sp_port_get_by_local_port(struct mlxsw_sp *mlxsw_sp, u8 local_port)
{
......@@ -1980,9 +1997,8 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port,
struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
struct mlxsw_sp_port_mapping port_mapping;
struct mlxsw_sp_port *mlxsw_sp_port;
int max_width;
u8 base_port;
int offset;
enum mlxsw_reg_pmtdb_status status;
char pmtdb_pl[MLXSW_REG_PMTDB_LEN];
int i;
int err;
......@@ -1994,57 +2010,37 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port,
return -EINVAL;
}
max_width = mlxsw_core_module_max_width(mlxsw_core,
mlxsw_sp_port->mapping.module);
if (max_width < 0) {
netdev_err(mlxsw_sp_port->dev, "Cannot get max width of port module\n");
NL_SET_ERR_MSG_MOD(extack, "Cannot get max width of port module");
return max_width;
}
/* Split port with non-max cannot be split. */
if (mlxsw_sp_port->mapping.width != max_width) {
netdev_err(mlxsw_sp_port->dev, "Port cannot be split\n");
NL_SET_ERR_MSG_MOD(extack, "Port cannot be split");
if (mlxsw_sp_port->split) {
NL_SET_ERR_MSG_MOD(extack, "Port is already split");
return -EINVAL;
}
offset = mlxsw_sp_local_ports_offset(mlxsw_core, count, max_width);
if (offset < 0) {
netdev_err(mlxsw_sp_port->dev, "Cannot obtain local port offset\n");
NL_SET_ERR_MSG_MOD(extack, "Cannot obtain local port offset");
return -EINVAL;
mlxsw_reg_pmtdb_pack(pmtdb_pl, 0, mlxsw_sp_port->mapping.module,
mlxsw_sp_port->mapping.module_width / count,
count);
err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(pmtdb), pmtdb_pl);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Failed to query split info");
return err;
}
/* Only in case max split is being done, the local port and
* base port may differ.
*/
base_port = count == max_width ?
mlxsw_sp_cluster_base_port_get(local_port, max_width) :
local_port;
for (i = 0; i < count * offset; i++) {
/* Expect base port to exist and also the one in the middle in
* case of maximal split count.
*/
if (i == 0 || (count == max_width && i == count / 2))
continue;
if (mlxsw_sp_port_created(mlxsw_sp, base_port + i)) {
netdev_err(mlxsw_sp_port->dev, "Invalid split configuration\n");
NL_SET_ERR_MSG_MOD(extack, "Invalid split configuration");
status = mlxsw_reg_pmtdb_status_get(pmtdb_pl);
if (status != MLXSW_REG_PMTDB_STATUS_SUCCESS) {
NL_SET_ERR_MSG_MOD(extack, "Unsupported split configuration");
return -EINVAL;
}
}
port_mapping = mlxsw_sp_port->mapping;
for (i = 0; i < count; i++)
if (mlxsw_sp_port_created(mlxsw_sp, base_port + i * offset))
mlxsw_sp_port_remove(mlxsw_sp, base_port + i * offset);
for (i = 0; i < count; i++) {
u8 s_local_port = mlxsw_reg_pmtdb_port_num_get(pmtdb_pl, i);
if (mlxsw_sp_port_created(mlxsw_sp, s_local_port))
mlxsw_sp_port_remove(mlxsw_sp, s_local_port);
}
err = mlxsw_sp_port_split_create(mlxsw_sp, base_port, &port_mapping,
count, offset);
err = mlxsw_sp_port_split_create(mlxsw_sp, &port_mapping,
count, pmtdb_pl);
if (err) {
dev_err(mlxsw_sp->bus_info->dev, "Failed to create split ports\n");
goto err_port_split_create;
......@@ -2053,7 +2049,7 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port,
return 0;
err_port_split_create:
mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count, offset);
mlxsw_sp_port_unsplit_create(mlxsw_sp, count, pmtdb_pl);
return err;
}
......@@ -2062,11 +2058,10 @@ static int mlxsw_sp_port_unsplit(struct mlxsw_core *mlxsw_core, u8 local_port,
{
struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
struct mlxsw_sp_port *mlxsw_sp_port;
char pmtdb_pl[MLXSW_REG_PMTDB_LEN];
unsigned int count;
int max_width;
u8 base_port;
int offset;
int i;
int err;
mlxsw_sp_port = mlxsw_sp_port_get_by_local_port(mlxsw_sp, local_port);
if (!mlxsw_sp_port) {
......@@ -2077,35 +2072,30 @@ static int mlxsw_sp_port_unsplit(struct mlxsw_core *mlxsw_core, u8 local_port,
}
if (!mlxsw_sp_port->split) {
netdev_err(mlxsw_sp_port->dev, "Port was not split\n");
NL_SET_ERR_MSG_MOD(extack, "Port was not split");
return -EINVAL;
}
max_width = mlxsw_core_module_max_width(mlxsw_core,
mlxsw_sp_port->mapping.module);
if (max_width < 0) {
netdev_err(mlxsw_sp_port->dev, "Cannot get max width of port module\n");
NL_SET_ERR_MSG_MOD(extack, "Cannot get max width of port module");
return max_width;
}
count = max_width / mlxsw_sp_port->mapping.width;
count = mlxsw_sp_port->mapping.module_width /
mlxsw_sp_port->mapping.width;
offset = mlxsw_sp_local_ports_offset(mlxsw_core, count, max_width);
if (WARN_ON(offset < 0)) {
netdev_err(mlxsw_sp_port->dev, "Cannot obtain local port offset\n");
NL_SET_ERR_MSG_MOD(extack, "Cannot obtain local port offset");
return -EINVAL;
mlxsw_reg_pmtdb_pack(pmtdb_pl, 0, mlxsw_sp_port->mapping.module,
mlxsw_sp_port->mapping.module_width / count,
count);
err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(pmtdb), pmtdb_pl);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Failed to query split info");
return err;
}
base_port = mlxsw_sp_port->split_base_local_port;
for (i = 0; i < count; i++) {
u8 s_local_port = mlxsw_reg_pmtdb_port_num_get(pmtdb_pl, i);
for (i = 0; i < count; i++)
if (mlxsw_sp_port_created(mlxsw_sp, base_port + i * offset))
mlxsw_sp_port_remove(mlxsw_sp, base_port + i * offset);
if (mlxsw_sp_port_created(mlxsw_sp, s_local_port))
mlxsw_sp_port_remove(mlxsw_sp, s_local_port);
}
mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count, offset);
mlxsw_sp_port_unsplit_create(mlxsw_sp, count, pmtdb_pl);
return 0;
}
......
......@@ -144,7 +144,8 @@ struct mlxsw_sp_mall_entry;
struct mlxsw_sp_port_mapping {
u8 module;
u8 width;
u8 width; /* Number of lanes used by the port */
u8 module_width; /* Number of lanes in the module (static) */
u8 lane;
};
......@@ -345,7 +346,6 @@ struct mlxsw_sp_port {
u16 egr_types;
struct mlxsw_sp_ptp_port_stats stats;
} ptp;
u8 split_base_local_port;
int max_mtu;
u32 max_speed;
struct mlxsw_sp_hdroom *hdroom;
......
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