Merge branch 'mlxsw-RJ45'

Ido Schimmel says:

====================
mlxsw: Add RJ45 ports support

We are in the process of qualifying a new system that has RJ45 ports as
opposed to the transceiver modules (e.g., SFP, QSFP) present on all
existing systems.

This patchset adds support for these ports in mlxsw by adding a couple of
missing BaseT link modes and rejecting ethtool operations that are
specific to transceiver modules.

Patchset overview:

Patches #1-#3 are cleanups and preparations.

Patch #4 adds support for two new link modes.

Patches #5-#6 query and cache the port module's type (e.g., QSFP, RJ45)
during initialization.

Patches #7-#9 forbid ethtool operations that are invalid on RJ45 ports.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2022-01-26 11:15:42 +00:00
commit 3cade91d0e
5 changed files with 179 additions and 27 deletions

View File

@ -18,6 +18,7 @@ struct mlxsw_env_module_info {
int num_ports_mapped;
int num_ports_up;
enum ethtool_module_power_mode_policy power_mode_policy;
enum mlxsw_reg_pmtm_module_type type;
};
struct mlxsw_env {
@ -27,14 +28,47 @@ struct mlxsw_env {
struct mlxsw_env_module_info module_info[];
};
static int mlxsw_env_validate_cable_ident(struct mlxsw_core *core, int id,
bool *qsfp, bool *cmis)
static int __mlxsw_env_validate_module_type(struct mlxsw_core *core, u8 module)
{
struct mlxsw_env *mlxsw_env = mlxsw_core_env(core);
int err;
switch (mlxsw_env->module_info[module].type) {
case MLXSW_REG_PMTM_MODULE_TYPE_TWISTED_PAIR:
err = -EINVAL;
break;
default:
err = 0;
}
return err;
}
static int mlxsw_env_validate_module_type(struct mlxsw_core *core, u8 module)
{
struct mlxsw_env *mlxsw_env = mlxsw_core_env(core);
int err;
mutex_lock(&mlxsw_env->module_info_lock);
err = __mlxsw_env_validate_module_type(core, module);
mutex_unlock(&mlxsw_env->module_info_lock);
return err;
}
static int
mlxsw_env_validate_cable_ident(struct mlxsw_core *core, int id, bool *qsfp,
bool *cmis)
{
char mcia_pl[MLXSW_REG_MCIA_LEN];
char *eeprom_tmp;
u8 ident;
int err;
err = mlxsw_env_validate_module_type(core, id);
if (err)
return err;
mlxsw_reg_mcia_pack(mcia_pl, id, 0, MLXSW_REG_MCIA_PAGE0_LO_OFF, 0, 1,
MLXSW_REG_MCIA_I2C_ADDR_LOW);
err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl);
@ -206,7 +240,8 @@ int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module,
return 0;
}
int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module,
int mlxsw_env_get_module_info(struct net_device *netdev,
struct mlxsw_core *mlxsw_core, int module,
struct ethtool_modinfo *modinfo)
{
u8 module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE];
@ -215,6 +250,13 @@ int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module,
unsigned int read_size;
int err;
err = mlxsw_env_validate_module_type(mlxsw_core, module);
if (err) {
netdev_err(netdev,
"EEPROM is not equipped on port module type");
return err;
}
err = mlxsw_env_query_module_eeprom(mlxsw_core, module, 0, offset,
module_info, false, &read_size);
if (err)
@ -356,6 +398,13 @@ mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, u8 module,
{
u32 bytes_read = 0;
u16 device_addr;
int err;
err = mlxsw_env_validate_module_type(mlxsw_core, module);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "EEPROM is not equipped on port module type");
return err;
}
/* Offset cannot be larger than 2 * ETH_MODULE_EEPROM_PAGE_LEN */
device_addr = page->offset;
@ -364,7 +413,6 @@ mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, u8 module,
char mcia_pl[MLXSW_REG_MCIA_LEN];
char *eeprom_tmp;
u8 size;
int err;
size = min_t(u8, page->length - bytes_read,
MLXSW_REG_MCIA_EEPROM_SIZE);
@ -419,6 +467,12 @@ int mlxsw_env_reset_module(struct net_device *netdev,
mutex_lock(&mlxsw_env->module_info_lock);
err = __mlxsw_env_validate_module_type(mlxsw_core, module);
if (err) {
netdev_err(netdev, "Reset module is not supported on port module type\n");
goto out;
}
if (mlxsw_env->module_info[module].num_ports_up) {
netdev_err(netdev, "Cannot reset module when ports using it are administratively up\n");
err = -EINVAL;
@ -461,6 +515,12 @@ mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module,
mutex_lock(&mlxsw_env->module_info_lock);
err = __mlxsw_env_validate_module_type(mlxsw_core, module);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Power mode is not supported on port module type");
goto out;
}
params->policy = mlxsw_env->module_info[module].power_mode_policy;
mlxsw_reg_mcion_pack(mcion_pl, module);
@ -571,6 +631,13 @@ mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module,
mutex_lock(&mlxsw_env->module_info_lock);
err = __mlxsw_env_validate_module_type(mlxsw_core, module);
if (err) {
NL_SET_ERR_MSG_MOD(extack,
"Power mode set is not supported on port module type");
goto out;
}
if (mlxsw_env->module_info[module].power_mode_policy == policy)
goto out;
@ -661,13 +728,12 @@ static int mlxsw_env_temp_event_set(struct mlxsw_core *mlxsw_core,
return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mtmp), mtmp_pl);
}
static int mlxsw_env_module_temp_event_enable(struct mlxsw_core *mlxsw_core,
u8 module_count)
static int mlxsw_env_module_temp_event_enable(struct mlxsw_core *mlxsw_core)
{
int i, err, sensor_index;
bool has_temp_sensor;
for (i = 0; i < module_count; i++) {
for (i = 0; i < mlxsw_core_env(mlxsw_core)->module_count; i++) {
err = mlxsw_env_module_has_temp_sensor(mlxsw_core, i,
&has_temp_sensor);
if (err)
@ -876,12 +942,11 @@ mlxsw_env_module_plug_event_unregister(struct mlxsw_env *mlxsw_env)
}
static int
mlxsw_env_module_oper_state_event_enable(struct mlxsw_core *mlxsw_core,
u8 module_count)
mlxsw_env_module_oper_state_event_enable(struct mlxsw_core *mlxsw_core)
{
int i, err;
for (i = 0; i < module_count; i++) {
for (i = 0; i < mlxsw_core_env(mlxsw_core)->module_count; i++) {
char pmaos_pl[MLXSW_REG_PMAOS_LEN];
mlxsw_reg_pmaos_pack(pmaos_pl, i);
@ -999,6 +1064,28 @@ out_unlock:
}
EXPORT_SYMBOL(mlxsw_env_module_port_down);
static int
mlxsw_env_module_type_set(struct mlxsw_core *mlxsw_core)
{
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
int i;
for (i = 0; i < mlxsw_env->module_count; i++) {
char pmtm_pl[MLXSW_REG_PMTM_LEN];
int err;
mlxsw_reg_pmtm_pack(pmtm_pl, 0, i);
err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(pmtm), pmtm_pl);
if (err)
return err;
mlxsw_env->module_info[i].type =
mlxsw_reg_pmtm_module_type_get(pmtm_pl);
}
return 0;
}
int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env)
{
char mgpir_pl[MLXSW_REG_MGPIR_LEN];
@ -1037,17 +1124,21 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env)
if (err)
goto err_module_plug_event_register;
err = mlxsw_env_module_oper_state_event_enable(mlxsw_core,
env->module_count);
err = mlxsw_env_module_oper_state_event_enable(mlxsw_core);
if (err)
goto err_oper_state_event_enable;
err = mlxsw_env_module_temp_event_enable(mlxsw_core, env->module_count);
err = mlxsw_env_module_temp_event_enable(mlxsw_core);
if (err)
goto err_temp_event_enable;
err = mlxsw_env_module_type_set(mlxsw_core);
if (err)
goto err_type_set;
return 0;
err_type_set:
err_temp_event_enable:
err_oper_state_event_enable:
mlxsw_env_module_plug_event_unregister(env);

View File

@ -12,7 +12,8 @@ struct ethtool_eeprom;
int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module,
int off, int *temp);
int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module,
int mlxsw_env_get_module_info(struct net_device *netdev,
struct mlxsw_core *mlxsw_core, int module,
struct ethtool_modinfo *modinfo);
int mlxsw_env_get_module_eeprom(struct net_device *netdev,

View File

@ -110,7 +110,8 @@ static int mlxsw_m_get_module_info(struct net_device *netdev,
struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
return mlxsw_env_get_module_info(core, mlxsw_m_port->module, modinfo);
return mlxsw_env_get_module_info(netdev, core, mlxsw_m_port->module,
modinfo);
}
static int

View File

@ -4482,6 +4482,8 @@ MLXSW_ITEM32(reg, ptys, ext_eth_proto_cap, 0x08, 0, 32);
#define MLXSW_REG_PTYS_ETH_SPEED_100GBASE_SR4 BIT(21)
#define MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4 BIT(22)
#define MLXSW_REG_PTYS_ETH_SPEED_100GBASE_LR4_ER4 BIT(23)
#define MLXSW_REG_PTYS_ETH_SPEED_100BASE_T BIT(24)
#define MLXSW_REG_PTYS_ETH_SPEED_1000BASE_T BIT(25)
#define MLXSW_REG_PTYS_ETH_SPEED_25GBASE_CR BIT(27)
#define MLXSW_REG_PTYS_ETH_SPEED_25GBASE_KR BIT(28)
#define MLXSW_REG_PTYS_ETH_SPEED_25GBASE_SR BIT(29)
@ -6062,6 +6064,58 @@ static inline void mlxsw_reg_pllp_unpack(char *payload, u8 *label_port,
*slot_index = mlxsw_reg_pllp_slot_index_get(payload);
}
/* PMTM - Port Module Type Mapping Register
* ----------------------------------------
* The PMTM register allows query or configuration of module types.
* The register can only be set when the module is disabled by PMAOS register
*/
#define MLXSW_REG_PMTM_ID 0x5067
#define MLXSW_REG_PMTM_LEN 0x10
MLXSW_REG_DEFINE(pmtm, MLXSW_REG_PMTM_ID, MLXSW_REG_PMTM_LEN);
/* reg_pmtm_slot_index
* Slot index.
* Access: Index
*/
MLXSW_ITEM32(reg, pmtm, slot_index, 0x00, 24, 4);
/* reg_pmtm_module
* Module number.
* Access: Index
*/
MLXSW_ITEM32(reg, pmtm, module, 0x00, 16, 8);
enum mlxsw_reg_pmtm_module_type {
MLXSW_REG_PMTM_MODULE_TYPE_BACKPLANE_4_LANES = 0,
MLXSW_REG_PMTM_MODULE_TYPE_QSFP = 1,
MLXSW_REG_PMTM_MODULE_TYPE_SFP = 2,
MLXSW_REG_PMTM_MODULE_TYPE_BACKPLANE_SINGLE_LANE = 4,
MLXSW_REG_PMTM_MODULE_TYPE_BACKPLANE_2_LANES = 8,
MLXSW_REG_PMTM_MODULE_TYPE_CHIP2CHIP4X = 10,
MLXSW_REG_PMTM_MODULE_TYPE_CHIP2CHIP2X = 11,
MLXSW_REG_PMTM_MODULE_TYPE_CHIP2CHIP1X = 12,
MLXSW_REG_PMTM_MODULE_TYPE_QSFP_DD = 14,
MLXSW_REG_PMTM_MODULE_TYPE_OSFP = 15,
MLXSW_REG_PMTM_MODULE_TYPE_SFP_DD = 16,
MLXSW_REG_PMTM_MODULE_TYPE_DSFP = 17,
MLXSW_REG_PMTM_MODULE_TYPE_CHIP2CHIP8X = 18,
MLXSW_REG_PMTM_MODULE_TYPE_TWISTED_PAIR = 19,
};
/* reg_pmtm_module_type
* Module type.
* Access: RW
*/
MLXSW_ITEM32(reg, pmtm, module_type, 0x04, 0, 5);
static inline void mlxsw_reg_pmtm_pack(char *payload, u8 slot_index, u8 module)
{
MLXSW_REG_ZERO(pmtm, payload);
mlxsw_reg_pmtm_slot_index_set(payload, slot_index);
mlxsw_reg_pmtm_module_set(payload, module);
}
/* HTGT - Host Trap Group Table
* ----------------------------
* Configures the properties for forwarding to CPU.
@ -12568,6 +12622,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = {
MLXSW_REG(pddr),
MLXSW_REG(pmmp),
MLXSW_REG(pllp),
MLXSW_REG(pmtm),
MLXSW_REG(htgt),
MLXSW_REG(hpkt),
MLXSW_REG(rgcr),

View File

@ -1034,13 +1034,10 @@ 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;
int err;
err = mlxsw_env_get_module_info(mlxsw_sp->core,
mlxsw_sp_port->mapping.module,
modinfo);
return err;
return mlxsw_env_get_module_info(netdev, mlxsw_sp->core,
mlxsw_sp_port->mapping.module,
modinfo);
}
static int mlxsw_sp_get_module_eeprom(struct net_device *netdev,
@ -1048,13 +1045,10 @@ 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;
int err;
err = mlxsw_env_get_module_eeprom(netdev, mlxsw_sp->core,
mlxsw_sp_port->mapping.module, ee,
data);
return err;
return mlxsw_env_get_module_eeprom(netdev, mlxsw_sp->core,
mlxsw_sp_port->mapping.module, ee,
data);
}
static int
@ -1272,12 +1266,22 @@ struct mlxsw_sp1_port_link_mode {
};
static const struct mlxsw_sp1_port_link_mode mlxsw_sp1_port_link_mode[] = {
{
.mask = MLXSW_REG_PTYS_ETH_SPEED_100BASE_T,
.mask_ethtool = ETHTOOL_LINK_MODE_100baseT_Full_BIT,
.speed = SPEED_100,
},
{
.mask = MLXSW_REG_PTYS_ETH_SPEED_SGMII |
MLXSW_REG_PTYS_ETH_SPEED_1000BASE_KX,
.mask_ethtool = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
.speed = SPEED_1000,
},
{
.mask = MLXSW_REG_PTYS_ETH_SPEED_1000BASE_T,
.mask_ethtool = ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
.speed = SPEED_1000,
},
{
.mask = MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CX4 |
MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KX4,