cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

core_env.c (41607B)


      1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
      2/* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
      3
      4#include <linux/kernel.h>
      5#include <linux/err.h>
      6#include <linux/ethtool.h>
      7#include <linux/sfp.h>
      8#include <linux/mutex.h>
      9
     10#include "core.h"
     11#include "core_env.h"
     12#include "item.h"
     13#include "reg.h"
     14
     15struct mlxsw_env_module_info {
     16	u64 module_overheat_counter;
     17	bool is_overheat;
     18	int num_ports_mapped;
     19	int num_ports_up;
     20	enum ethtool_module_power_mode_policy power_mode_policy;
     21	enum mlxsw_reg_pmtm_module_type type;
     22};
     23
     24struct mlxsw_env_line_card {
     25	u8 module_count;
     26	bool active;
     27	struct mlxsw_env_module_info module_info[];
     28};
     29
     30struct mlxsw_env {
     31	struct mlxsw_core *core;
     32	const struct mlxsw_bus_info *bus_info;
     33	u8 max_module_count; /* Maximum number of modules per-slot. */
     34	u8 num_of_slots; /* Including the main board. */
     35	struct mutex line_cards_lock; /* Protects line cards. */
     36	struct mlxsw_env_line_card *line_cards[];
     37};
     38
     39static bool __mlxsw_env_linecard_is_active(struct mlxsw_env *mlxsw_env,
     40					   u8 slot_index)
     41{
     42	return mlxsw_env->line_cards[slot_index]->active;
     43}
     44
     45static bool mlxsw_env_linecard_is_active(struct mlxsw_env *mlxsw_env,
     46					 u8 slot_index)
     47{
     48	bool active;
     49
     50	mutex_lock(&mlxsw_env->line_cards_lock);
     51	active = __mlxsw_env_linecard_is_active(mlxsw_env, slot_index);
     52	mutex_unlock(&mlxsw_env->line_cards_lock);
     53
     54	return active;
     55}
     56
     57static struct
     58mlxsw_env_module_info *mlxsw_env_module_info_get(struct mlxsw_core *mlxsw_core,
     59						 u8 slot_index, u8 module)
     60{
     61	struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
     62
     63	return &mlxsw_env->line_cards[slot_index]->module_info[module];
     64}
     65
     66static int __mlxsw_env_validate_module_type(struct mlxsw_core *core,
     67					    u8 slot_index, u8 module)
     68{
     69	struct mlxsw_env *mlxsw_env = mlxsw_core_env(core);
     70	struct mlxsw_env_module_info *module_info;
     71	int err;
     72
     73	if (!__mlxsw_env_linecard_is_active(mlxsw_env, slot_index))
     74		return 0;
     75
     76	module_info = mlxsw_env_module_info_get(core, slot_index, module);
     77	switch (module_info->type) {
     78	case MLXSW_REG_PMTM_MODULE_TYPE_TWISTED_PAIR:
     79		err = -EINVAL;
     80		break;
     81	default:
     82		err = 0;
     83	}
     84
     85	return err;
     86}
     87
     88static int mlxsw_env_validate_module_type(struct mlxsw_core *core,
     89					  u8 slot_index, u8 module)
     90{
     91	struct mlxsw_env *mlxsw_env = mlxsw_core_env(core);
     92	int err;
     93
     94	mutex_lock(&mlxsw_env->line_cards_lock);
     95	err = __mlxsw_env_validate_module_type(core, slot_index, module);
     96	mutex_unlock(&mlxsw_env->line_cards_lock);
     97
     98	return err;
     99}
    100
    101static int
    102mlxsw_env_validate_cable_ident(struct mlxsw_core *core, u8 slot_index, int id,
    103			       bool *qsfp, bool *cmis)
    104{
    105	char mcia_pl[MLXSW_REG_MCIA_LEN];
    106	char *eeprom_tmp;
    107	u8 ident;
    108	int err;
    109
    110	err = mlxsw_env_validate_module_type(core, slot_index, id);
    111	if (err)
    112		return err;
    113
    114	mlxsw_reg_mcia_pack(mcia_pl, slot_index, id, 0,
    115			    MLXSW_REG_MCIA_PAGE0_LO_OFF, 0, 1,
    116			    MLXSW_REG_MCIA_I2C_ADDR_LOW);
    117	err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl);
    118	if (err)
    119		return err;
    120	eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl);
    121	ident = eeprom_tmp[0];
    122	*cmis = false;
    123	switch (ident) {
    124	case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP:
    125		*qsfp = false;
    126		break;
    127	case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP:
    128	case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS:
    129	case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28:
    130		*qsfp = true;
    131		break;
    132	case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_DD:
    133	case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_OSFP:
    134		*qsfp = true;
    135		*cmis = true;
    136		break;
    137	default:
    138		return -EINVAL;
    139	}
    140
    141	return 0;
    142}
    143
    144static int
    145mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, u8 slot_index,
    146			      int module, u16 offset, u16 size, void *data,
    147			      bool qsfp, unsigned int *p_read_size)
    148{
    149	char mcia_pl[MLXSW_REG_MCIA_LEN];
    150	char *eeprom_tmp;
    151	u16 i2c_addr;
    152	u8 page = 0;
    153	int status;
    154	int err;
    155
    156	/* MCIA register accepts buffer size <= 48. Page of size 128 should be
    157	 * read by chunks of size 48, 48, 32. Align the size of the last chunk
    158	 * to avoid reading after the end of the page.
    159	 */
    160	size = min_t(u16, size, MLXSW_REG_MCIA_EEPROM_SIZE);
    161
    162	if (offset < MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH &&
    163	    offset + size > MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH)
    164		/* Cross pages read, read until offset 256 in low page */
    165		size = MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH - offset;
    166
    167	i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_LOW;
    168	if (offset >= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) {
    169		if (qsfp) {
    170			/* When reading upper pages 1, 2 and 3 the offset
    171			 * starts at 128. Please refer to "QSFP+ Memory Map"
    172			 * figure in SFF-8436 specification and to "CMIS Module
    173			 * Memory Map" figure in CMIS specification for
    174			 * graphical depiction.
    175			 */
    176			page = MLXSW_REG_MCIA_PAGE_GET(offset);
    177			offset -= MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH * page;
    178			if (offset + size > MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH)
    179				size = MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH - offset;
    180		} else {
    181			/* When reading upper pages 1, 2 and 3 the offset
    182			 * starts at 0 and I2C high address is used. Please refer
    183			 * refer to "Memory Organization" figure in SFF-8472
    184			 * specification for graphical depiction.
    185			 */
    186			i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_HIGH;
    187			offset -= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH;
    188		}
    189	}
    190
    191	mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, 0, page, offset, size,
    192			    i2c_addr);
    193
    194	err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl);
    195	if (err)
    196		return err;
    197
    198	status = mlxsw_reg_mcia_status_get(mcia_pl);
    199	if (status)
    200		return -EIO;
    201
    202	eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl);
    203	memcpy(data, eeprom_tmp, size);
    204	*p_read_size = size;
    205
    206	return 0;
    207}
    208
    209int
    210mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, u8 slot_index,
    211				     int module, int off, int *temp)
    212{
    213	unsigned int module_temp, module_crit, module_emerg;
    214	union {
    215		u8 buf[MLXSW_REG_MCIA_TH_ITEM_SIZE];
    216		u16 temp;
    217	} temp_thresh;
    218	char mcia_pl[MLXSW_REG_MCIA_LEN] = {0};
    219	char mtmp_pl[MLXSW_REG_MTMP_LEN];
    220	char *eeprom_tmp;
    221	bool qsfp, cmis;
    222	int page;
    223	int err;
    224
    225	mlxsw_reg_mtmp_pack(mtmp_pl, slot_index,
    226			    MLXSW_REG_MTMP_MODULE_INDEX_MIN + module, false,
    227			    false);
    228	err = mlxsw_reg_query(core, MLXSW_REG(mtmp), mtmp_pl);
    229	if (err)
    230		return err;
    231	mlxsw_reg_mtmp_unpack(mtmp_pl, &module_temp, NULL, &module_crit,
    232			      &module_emerg, NULL);
    233	if (!module_temp) {
    234		*temp = 0;
    235		return 0;
    236	}
    237
    238	/* Validate if threshold reading is available through MTMP register,
    239	 * otherwise fallback to read through MCIA.
    240	 */
    241	if (module_emerg) {
    242		*temp = off == SFP_TEMP_HIGH_WARN ? module_crit : module_emerg;
    243		return 0;
    244	}
    245
    246	/* Read Free Side Device Temperature Thresholds from page 03h
    247	 * (MSB at lower byte address).
    248	 * Bytes:
    249	 * 128-129 - Temp High Alarm (SFP_TEMP_HIGH_ALARM);
    250	 * 130-131 - Temp Low Alarm (SFP_TEMP_LOW_ALARM);
    251	 * 132-133 - Temp High Warning (SFP_TEMP_HIGH_WARN);
    252	 * 134-135 - Temp Low Warning (SFP_TEMP_LOW_WARN);
    253	 */
    254
    255	/* Validate module identifier value. */
    256	err = mlxsw_env_validate_cable_ident(core, slot_index, module, &qsfp,
    257					     &cmis);
    258	if (err)
    259		return err;
    260
    261	if (qsfp) {
    262		/* For QSFP/CMIS module-defined thresholds are located in page
    263		 * 02h, otherwise in page 03h.
    264		 */
    265		if (cmis)
    266			page = MLXSW_REG_MCIA_TH_PAGE_CMIS_NUM;
    267		else
    268			page = MLXSW_REG_MCIA_TH_PAGE_NUM;
    269		mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, 0, page,
    270				    MLXSW_REG_MCIA_TH_PAGE_OFF + off,
    271				    MLXSW_REG_MCIA_TH_ITEM_SIZE,
    272				    MLXSW_REG_MCIA_I2C_ADDR_LOW);
    273	} else {
    274		mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, 0,
    275				    MLXSW_REG_MCIA_PAGE0_LO,
    276				    off, MLXSW_REG_MCIA_TH_ITEM_SIZE,
    277				    MLXSW_REG_MCIA_I2C_ADDR_HIGH);
    278	}
    279
    280	err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl);
    281	if (err)
    282		return err;
    283
    284	eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl);
    285	memcpy(temp_thresh.buf, eeprom_tmp, MLXSW_REG_MCIA_TH_ITEM_SIZE);
    286	*temp = temp_thresh.temp * 1000;
    287
    288	return 0;
    289}
    290
    291int mlxsw_env_get_module_info(struct net_device *netdev,
    292			      struct mlxsw_core *mlxsw_core, u8 slot_index,
    293			      int module, struct ethtool_modinfo *modinfo)
    294{
    295	struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
    296	u8 module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE];
    297	u16 offset = MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE;
    298	u8 module_rev_id, module_id, diag_mon;
    299	unsigned int read_size;
    300	int err;
    301
    302	if (!mlxsw_env_linecard_is_active(mlxsw_env, slot_index)) {
    303		netdev_err(netdev, "Cannot read EEPROM of module on an inactive line card\n");
    304		return -EIO;
    305	}
    306
    307	err = mlxsw_env_validate_module_type(mlxsw_core, slot_index, module);
    308	if (err) {
    309		netdev_err(netdev,
    310			   "EEPROM is not equipped on port module type");
    311		return err;
    312	}
    313
    314	err = mlxsw_env_query_module_eeprom(mlxsw_core, slot_index, module, 0,
    315					    offset, module_info, false,
    316					    &read_size);
    317	if (err)
    318		return err;
    319
    320	if (read_size < offset)
    321		return -EIO;
    322
    323	module_rev_id = module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID];
    324	module_id = module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID];
    325
    326	switch (module_id) {
    327	case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP:
    328		modinfo->type       = ETH_MODULE_SFF_8436;
    329		modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN;
    330		break;
    331	case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS:
    332	case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28:
    333		if (module_id == MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28 ||
    334		    module_rev_id >=
    335		    MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID_8636) {
    336			modinfo->type       = ETH_MODULE_SFF_8636;
    337			modinfo->eeprom_len = ETH_MODULE_SFF_8636_MAX_LEN;
    338		} else {
    339			modinfo->type       = ETH_MODULE_SFF_8436;
    340			modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN;
    341		}
    342		break;
    343	case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP:
    344		/* Verify if transceiver provides diagnostic monitoring page */
    345		err = mlxsw_env_query_module_eeprom(mlxsw_core, slot_index,
    346						    module, SFP_DIAGMON, 1,
    347						    &diag_mon, false,
    348						    &read_size);
    349		if (err)
    350			return err;
    351
    352		if (read_size < 1)
    353			return -EIO;
    354
    355		modinfo->type       = ETH_MODULE_SFF_8472;
    356		if (diag_mon)
    357			modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
    358		else
    359			modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN / 2;
    360		break;
    361	case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_DD:
    362	case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_OSFP:
    363		/* Use SFF_8636 as base type. ethtool should recognize specific
    364		 * type through the identifier value.
    365		 */
    366		modinfo->type       = ETH_MODULE_SFF_8636;
    367		/* Verify if module EEPROM is a flat memory. In case of flat
    368		 * memory only page 00h (0-255 bytes) can be read. Otherwise
    369		 * upper pages 01h and 02h can also be read. Upper pages 10h
    370		 * and 11h are currently not supported by the driver.
    371		 */
    372		if (module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_TYPE_ID] &
    373		    MLXSW_REG_MCIA_EEPROM_CMIS_FLAT_MEMORY)
    374			modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN;
    375		else
    376			modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
    377		break;
    378	default:
    379		return -EINVAL;
    380	}
    381
    382	return 0;
    383}
    384EXPORT_SYMBOL(mlxsw_env_get_module_info);
    385
    386int mlxsw_env_get_module_eeprom(struct net_device *netdev,
    387				struct mlxsw_core *mlxsw_core, u8 slot_index,
    388				int module, struct ethtool_eeprom *ee,
    389				u8 *data)
    390{
    391	struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
    392	int offset = ee->offset;
    393	unsigned int read_size;
    394	bool qsfp, cmis;
    395	int i = 0;
    396	int err;
    397
    398	if (!ee->len)
    399		return -EINVAL;
    400
    401	if (!mlxsw_env_linecard_is_active(mlxsw_env, slot_index)) {
    402		netdev_err(netdev, "Cannot read EEPROM of module on an inactive line card\n");
    403		return -EIO;
    404	}
    405
    406	memset(data, 0, ee->len);
    407	/* Validate module identifier value. */
    408	err = mlxsw_env_validate_cable_ident(mlxsw_core, slot_index, module,
    409					     &qsfp, &cmis);
    410	if (err)
    411		return err;
    412
    413	while (i < ee->len) {
    414		err = mlxsw_env_query_module_eeprom(mlxsw_core, slot_index,
    415						    module, offset,
    416						    ee->len - i, data + i,
    417						    qsfp, &read_size);
    418		if (err) {
    419			netdev_err(netdev, "Eeprom query failed\n");
    420			return err;
    421		}
    422
    423		i += read_size;
    424		offset += read_size;
    425	}
    426
    427	return 0;
    428}
    429EXPORT_SYMBOL(mlxsw_env_get_module_eeprom);
    430
    431static int mlxsw_env_mcia_status_process(const char *mcia_pl,
    432					 struct netlink_ext_ack *extack)
    433{
    434	u8 status = mlxsw_reg_mcia_status_get(mcia_pl);
    435
    436	switch (status) {
    437	case MLXSW_REG_MCIA_STATUS_GOOD:
    438		return 0;
    439	case MLXSW_REG_MCIA_STATUS_NO_EEPROM_MODULE:
    440		NL_SET_ERR_MSG_MOD(extack, "No response from module's EEPROM");
    441		return -EIO;
    442	case MLXSW_REG_MCIA_STATUS_MODULE_NOT_SUPPORTED:
    443		NL_SET_ERR_MSG_MOD(extack, "Module type not supported by the device");
    444		return -EOPNOTSUPP;
    445	case MLXSW_REG_MCIA_STATUS_MODULE_NOT_CONNECTED:
    446		NL_SET_ERR_MSG_MOD(extack, "No module present indication");
    447		return -EIO;
    448	case MLXSW_REG_MCIA_STATUS_I2C_ERROR:
    449		NL_SET_ERR_MSG_MOD(extack, "Error occurred while trying to access module's EEPROM using I2C");
    450		return -EIO;
    451	case MLXSW_REG_MCIA_STATUS_MODULE_DISABLED:
    452		NL_SET_ERR_MSG_MOD(extack, "Module is disabled");
    453		return -EIO;
    454	default:
    455		NL_SET_ERR_MSG_MOD(extack, "Unknown error");
    456		return -EIO;
    457	}
    458}
    459
    460int
    461mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core,
    462				    u8 slot_index, u8 module,
    463				    const struct ethtool_module_eeprom *page,
    464				    struct netlink_ext_ack *extack)
    465{
    466	struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
    467	u32 bytes_read = 0;
    468	u16 device_addr;
    469	int err;
    470
    471	if (!mlxsw_env_linecard_is_active(mlxsw_env, slot_index)) {
    472		NL_SET_ERR_MSG_MOD(extack,
    473				   "Cannot read EEPROM of module on an inactive line card");
    474		return -EIO;
    475	}
    476
    477	err = mlxsw_env_validate_module_type(mlxsw_core, slot_index, module);
    478	if (err) {
    479		NL_SET_ERR_MSG_MOD(extack, "EEPROM is not equipped on port module type");
    480		return err;
    481	}
    482
    483	/* Offset cannot be larger than 2 * ETH_MODULE_EEPROM_PAGE_LEN */
    484	device_addr = page->offset;
    485
    486	while (bytes_read < page->length) {
    487		char mcia_pl[MLXSW_REG_MCIA_LEN];
    488		char *eeprom_tmp;
    489		u8 size;
    490
    491		size = min_t(u8, page->length - bytes_read,
    492			     MLXSW_REG_MCIA_EEPROM_SIZE);
    493
    494		mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, 0, page->page,
    495				    device_addr + bytes_read, size,
    496				    page->i2c_address);
    497		mlxsw_reg_mcia_bank_number_set(mcia_pl, page->bank);
    498
    499		err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl);
    500		if (err) {
    501			NL_SET_ERR_MSG_MOD(extack, "Failed to access module's EEPROM");
    502			return err;
    503		}
    504
    505		err = mlxsw_env_mcia_status_process(mcia_pl, extack);
    506		if (err)
    507			return err;
    508
    509		eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl);
    510		memcpy(page->data + bytes_read, eeprom_tmp, size);
    511		bytes_read += size;
    512	}
    513
    514	return bytes_read;
    515}
    516EXPORT_SYMBOL(mlxsw_env_get_module_eeprom_by_page);
    517
    518static int mlxsw_env_module_reset(struct mlxsw_core *mlxsw_core, u8 slot_index,
    519				  u8 module)
    520{
    521	char pmaos_pl[MLXSW_REG_PMAOS_LEN];
    522
    523	mlxsw_reg_pmaos_pack(pmaos_pl, slot_index, module);
    524	mlxsw_reg_pmaos_rst_set(pmaos_pl, true);
    525
    526	return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl);
    527}
    528
    529int mlxsw_env_reset_module(struct net_device *netdev,
    530			   struct mlxsw_core *mlxsw_core, u8 slot_index,
    531			   u8 module, u32 *flags)
    532{
    533	struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
    534	struct mlxsw_env_module_info *module_info;
    535	u32 req = *flags;
    536	int err;
    537
    538	if (!(req & ETH_RESET_PHY) &&
    539	    !(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT)))
    540		return 0;
    541
    542	if (!mlxsw_env_linecard_is_active(mlxsw_env, slot_index)) {
    543		netdev_err(netdev, "Cannot reset module on an inactive line card\n");
    544		return -EIO;
    545	}
    546
    547	mutex_lock(&mlxsw_env->line_cards_lock);
    548
    549	err = __mlxsw_env_validate_module_type(mlxsw_core, slot_index, module);
    550	if (err) {
    551		netdev_err(netdev, "Reset module is not supported on port module type\n");
    552		goto out;
    553	}
    554
    555	module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
    556	if (module_info->num_ports_up) {
    557		netdev_err(netdev, "Cannot reset module when ports using it are administratively up\n");
    558		err = -EINVAL;
    559		goto out;
    560	}
    561
    562	if (module_info->num_ports_mapped > 1 &&
    563	    !(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT))) {
    564		netdev_err(netdev, "Cannot reset module without \"phy-shared\" flag when shared by multiple ports\n");
    565		err = -EINVAL;
    566		goto out;
    567	}
    568
    569	err = mlxsw_env_module_reset(mlxsw_core, slot_index, module);
    570	if (err) {
    571		netdev_err(netdev, "Failed to reset module\n");
    572		goto out;
    573	}
    574
    575	*flags &= ~(ETH_RESET_PHY | (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT));
    576
    577out:
    578	mutex_unlock(&mlxsw_env->line_cards_lock);
    579	return err;
    580}
    581EXPORT_SYMBOL(mlxsw_env_reset_module);
    582
    583int
    584mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index,
    585				u8 module,
    586				struct ethtool_module_power_mode_params *params,
    587				struct netlink_ext_ack *extack)
    588{
    589	struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
    590	struct mlxsw_env_module_info *module_info;
    591	char mcion_pl[MLXSW_REG_MCION_LEN];
    592	u32 status_bits;
    593	int err = 0;
    594
    595	mutex_lock(&mlxsw_env->line_cards_lock);
    596
    597	err = __mlxsw_env_validate_module_type(mlxsw_core, slot_index, module);
    598	if (err) {
    599		NL_SET_ERR_MSG_MOD(extack, "Power mode is not supported on port module type");
    600		goto out;
    601	}
    602
    603	module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
    604	params->policy = module_info->power_mode_policy;
    605
    606	/* Avoid accessing an inactive line card, as it will result in an error. */
    607	if (!__mlxsw_env_linecard_is_active(mlxsw_env, slot_index))
    608		goto out;
    609
    610	mlxsw_reg_mcion_pack(mcion_pl, slot_index, module);
    611	err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcion), mcion_pl);
    612	if (err) {
    613		NL_SET_ERR_MSG_MOD(extack, "Failed to retrieve module's power mode");
    614		goto out;
    615	}
    616
    617	status_bits = mlxsw_reg_mcion_module_status_bits_get(mcion_pl);
    618	if (!(status_bits & MLXSW_REG_MCION_MODULE_STATUS_BITS_PRESENT_MASK))
    619		goto out;
    620
    621	if (status_bits & MLXSW_REG_MCION_MODULE_STATUS_BITS_LOW_POWER_MASK)
    622		params->mode = ETHTOOL_MODULE_POWER_MODE_LOW;
    623	else
    624		params->mode = ETHTOOL_MODULE_POWER_MODE_HIGH;
    625
    626out:
    627	mutex_unlock(&mlxsw_env->line_cards_lock);
    628	return err;
    629}
    630EXPORT_SYMBOL(mlxsw_env_get_module_power_mode);
    631
    632static int mlxsw_env_module_enable_set(struct mlxsw_core *mlxsw_core,
    633				       u8 slot_index, u8 module, bool enable)
    634{
    635	enum mlxsw_reg_pmaos_admin_status admin_status;
    636	char pmaos_pl[MLXSW_REG_PMAOS_LEN];
    637
    638	mlxsw_reg_pmaos_pack(pmaos_pl, slot_index, module);
    639	admin_status = enable ? MLXSW_REG_PMAOS_ADMIN_STATUS_ENABLED :
    640				MLXSW_REG_PMAOS_ADMIN_STATUS_DISABLED;
    641	mlxsw_reg_pmaos_admin_status_set(pmaos_pl, admin_status);
    642	mlxsw_reg_pmaos_ase_set(pmaos_pl, true);
    643
    644	return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl);
    645}
    646
    647static int mlxsw_env_module_low_power_set(struct mlxsw_core *mlxsw_core,
    648					  u8 slot_index, u8 module,
    649					  bool low_power)
    650{
    651	u16 eeprom_override_mask, eeprom_override;
    652	char pmmp_pl[MLXSW_REG_PMMP_LEN];
    653
    654	mlxsw_reg_pmmp_pack(pmmp_pl, slot_index, module);
    655	mlxsw_reg_pmmp_sticky_set(pmmp_pl, true);
    656	/* Mask all the bits except low power mode. */
    657	eeprom_override_mask = ~MLXSW_REG_PMMP_EEPROM_OVERRIDE_LOW_POWER_MASK;
    658	mlxsw_reg_pmmp_eeprom_override_mask_set(pmmp_pl, eeprom_override_mask);
    659	eeprom_override = low_power ? MLXSW_REG_PMMP_EEPROM_OVERRIDE_LOW_POWER_MASK :
    660				      0;
    661	mlxsw_reg_pmmp_eeprom_override_set(pmmp_pl, eeprom_override);
    662
    663	return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmmp), pmmp_pl);
    664}
    665
    666static int __mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core,
    667					     u8 slot_index, u8 module,
    668					     bool low_power,
    669					     struct netlink_ext_ack *extack)
    670{
    671	struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
    672	int err;
    673
    674	/* Avoid accessing an inactive line card, as it will result in an error.
    675	 * Cached configuration will be applied by mlxsw_env_got_active() when
    676	 * line card becomes active.
    677	 */
    678	if (!__mlxsw_env_linecard_is_active(mlxsw_env, slot_index))
    679		return 0;
    680
    681	err = mlxsw_env_module_enable_set(mlxsw_core, slot_index, module, false);
    682	if (err) {
    683		NL_SET_ERR_MSG_MOD(extack, "Failed to disable module");
    684		return err;
    685	}
    686
    687	err = mlxsw_env_module_low_power_set(mlxsw_core, slot_index, module,
    688					     low_power);
    689	if (err) {
    690		NL_SET_ERR_MSG_MOD(extack, "Failed to set module's power mode");
    691		goto err_module_low_power_set;
    692	}
    693
    694	err = mlxsw_env_module_enable_set(mlxsw_core, slot_index, module, true);
    695	if (err) {
    696		NL_SET_ERR_MSG_MOD(extack, "Failed to enable module");
    697		goto err_module_enable_set;
    698	}
    699
    700	return 0;
    701
    702err_module_enable_set:
    703	mlxsw_env_module_low_power_set(mlxsw_core, slot_index, module,
    704				       !low_power);
    705err_module_low_power_set:
    706	mlxsw_env_module_enable_set(mlxsw_core, slot_index, module, true);
    707	return err;
    708}
    709
    710static int
    711mlxsw_env_set_module_power_mode_apply(struct mlxsw_core *mlxsw_core,
    712				      u8 slot_index, u8 module,
    713				      enum ethtool_module_power_mode_policy policy,
    714				      struct netlink_ext_ack *extack)
    715{
    716	struct mlxsw_env_module_info *module_info;
    717	bool low_power;
    718	int err = 0;
    719
    720	err = __mlxsw_env_validate_module_type(mlxsw_core, slot_index, module);
    721	if (err) {
    722		NL_SET_ERR_MSG_MOD(extack,
    723				   "Power mode set is not supported on port module type");
    724		goto out;
    725	}
    726
    727	module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
    728	if (module_info->power_mode_policy == policy)
    729		goto out;
    730
    731	/* If any ports are up, we are already in high power mode. */
    732	if (module_info->num_ports_up)
    733		goto out_set_policy;
    734
    735	low_power = policy == ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO;
    736	err = __mlxsw_env_set_module_power_mode(mlxsw_core, slot_index, module,
    737						low_power, extack);
    738	if (err)
    739		goto out;
    740
    741out_set_policy:
    742	module_info->power_mode_policy = policy;
    743out:
    744	return err;
    745}
    746
    747int
    748mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index,
    749				u8 module,
    750				enum ethtool_module_power_mode_policy policy,
    751				struct netlink_ext_ack *extack)
    752{
    753	struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
    754	int err;
    755
    756	if (policy != ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH &&
    757	    policy != ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO) {
    758		NL_SET_ERR_MSG_MOD(extack, "Unsupported power mode policy");
    759		return -EOPNOTSUPP;
    760	}
    761
    762	mutex_lock(&mlxsw_env->line_cards_lock);
    763	err = mlxsw_env_set_module_power_mode_apply(mlxsw_core, slot_index,
    764						    module, policy, extack);
    765	mutex_unlock(&mlxsw_env->line_cards_lock);
    766
    767	return err;
    768}
    769EXPORT_SYMBOL(mlxsw_env_set_module_power_mode);
    770
    771static int mlxsw_env_module_has_temp_sensor(struct mlxsw_core *mlxsw_core,
    772					    u8 slot_index, u8 module,
    773					    bool *p_has_temp_sensor)
    774{
    775	char mtbr_pl[MLXSW_REG_MTBR_LEN];
    776	u16 temp;
    777	int err;
    778
    779	mlxsw_reg_mtbr_pack(mtbr_pl, slot_index,
    780			    MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, 1);
    781	err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mtbr), mtbr_pl);
    782	if (err)
    783		return err;
    784
    785	mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL);
    786
    787	switch (temp) {
    788	case MLXSW_REG_MTBR_BAD_SENS_INFO:
    789	case MLXSW_REG_MTBR_NO_CONN:
    790	case MLXSW_REG_MTBR_NO_TEMP_SENS:
    791	case MLXSW_REG_MTBR_INDEX_NA:
    792		*p_has_temp_sensor = false;
    793		break;
    794	default:
    795		*p_has_temp_sensor = temp ? true : false;
    796	}
    797	return 0;
    798}
    799
    800static int
    801mlxsw_env_temp_event_set(struct mlxsw_core *mlxsw_core, u8 slot_index,
    802			 u16 sensor_index, bool enable)
    803{
    804	char mtmp_pl[MLXSW_REG_MTMP_LEN] = {0};
    805	enum mlxsw_reg_mtmp_tee tee;
    806	int err, threshold_hi;
    807
    808	mlxsw_reg_mtmp_slot_index_set(mtmp_pl, slot_index);
    809	mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, sensor_index);
    810	err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mtmp), mtmp_pl);
    811	if (err)
    812		return err;
    813
    814	if (enable) {
    815		err = mlxsw_env_module_temp_thresholds_get(mlxsw_core,
    816							   slot_index,
    817							   sensor_index -
    818							   MLXSW_REG_MTMP_MODULE_INDEX_MIN,
    819							   SFP_TEMP_HIGH_WARN,
    820							   &threshold_hi);
    821		/* In case it is not possible to query the module's threshold,
    822		 * use the default value.
    823		 */
    824		if (err)
    825			threshold_hi = MLXSW_REG_MTMP_THRESH_HI;
    826		else
    827			/* mlxsw_env_module_temp_thresholds_get() multiplies
    828			 * Celsius degrees by 1000 whereas MTMP expects
    829			 * temperature in 0.125 Celsius degrees units.
    830			 * Convert threshold_hi to correct units.
    831			 */
    832			threshold_hi = threshold_hi / 1000 * 8;
    833
    834		mlxsw_reg_mtmp_temperature_threshold_hi_set(mtmp_pl, threshold_hi);
    835		mlxsw_reg_mtmp_temperature_threshold_lo_set(mtmp_pl, threshold_hi -
    836							    MLXSW_REG_MTMP_HYSTERESIS_TEMP);
    837	}
    838	tee = enable ? MLXSW_REG_MTMP_TEE_GENERATE_EVENT : MLXSW_REG_MTMP_TEE_NO_EVENT;
    839	mlxsw_reg_mtmp_tee_set(mtmp_pl, tee);
    840	return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mtmp), mtmp_pl);
    841}
    842
    843static int mlxsw_env_module_temp_event_enable(struct mlxsw_core *mlxsw_core,
    844					      u8 slot_index)
    845{
    846	struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
    847	int i, err, sensor_index;
    848	bool has_temp_sensor;
    849
    850	for (i = 0; i < mlxsw_env->line_cards[slot_index]->module_count; i++) {
    851		err = mlxsw_env_module_has_temp_sensor(mlxsw_core, slot_index,
    852						       i, &has_temp_sensor);
    853		if (err)
    854			return err;
    855
    856		if (!has_temp_sensor)
    857			continue;
    858
    859		sensor_index = i + MLXSW_REG_MTMP_MODULE_INDEX_MIN;
    860		err = mlxsw_env_temp_event_set(mlxsw_core, slot_index,
    861					       sensor_index, true);
    862		if (err)
    863			return err;
    864	}
    865
    866	return 0;
    867}
    868
    869struct mlxsw_env_module_temp_warn_event {
    870	struct mlxsw_env *mlxsw_env;
    871	char mtwe_pl[MLXSW_REG_MTWE_LEN];
    872	struct work_struct work;
    873};
    874
    875static void mlxsw_env_mtwe_event_work(struct work_struct *work)
    876{
    877	struct mlxsw_env_module_temp_warn_event *event;
    878	struct mlxsw_env_module_info *module_info;
    879	struct mlxsw_env *mlxsw_env;
    880	int i, sensor_warning;
    881	bool is_overheat;
    882
    883	event = container_of(work, struct mlxsw_env_module_temp_warn_event,
    884			     work);
    885	mlxsw_env = event->mlxsw_env;
    886
    887	for (i = 0; i < mlxsw_env->max_module_count; i++) {
    888		/* 64-127 of sensor_index are mapped to the port modules
    889		 * sequentially (module 0 is mapped to sensor_index 64,
    890		 * module 1 to sensor_index 65 and so on)
    891		 */
    892		sensor_warning =
    893			mlxsw_reg_mtwe_sensor_warning_get(event->mtwe_pl,
    894							  i + MLXSW_REG_MTMP_MODULE_INDEX_MIN);
    895		mutex_lock(&mlxsw_env->line_cards_lock);
    896		/* MTWE only supports main board. */
    897		module_info = mlxsw_env_module_info_get(mlxsw_env->core, 0, i);
    898		is_overheat = module_info->is_overheat;
    899
    900		if ((is_overheat && sensor_warning) ||
    901		    (!is_overheat && !sensor_warning)) {
    902			/* Current state is "warning" and MTWE still reports
    903			 * warning OR current state in "no warning" and MTWE
    904			 * does not report warning.
    905			 */
    906			mutex_unlock(&mlxsw_env->line_cards_lock);
    907			continue;
    908		} else if (is_overheat && !sensor_warning) {
    909			/* MTWE reports "no warning", turn is_overheat off.
    910			 */
    911			module_info->is_overheat = false;
    912			mutex_unlock(&mlxsw_env->line_cards_lock);
    913		} else {
    914			/* Current state is "no warning" and MTWE reports
    915			 * "warning", increase the counter and turn is_overheat
    916			 * on.
    917			 */
    918			module_info->is_overheat = true;
    919			module_info->module_overheat_counter++;
    920			mutex_unlock(&mlxsw_env->line_cards_lock);
    921		}
    922	}
    923
    924	kfree(event);
    925}
    926
    927static void
    928mlxsw_env_mtwe_listener_func(const struct mlxsw_reg_info *reg, char *mtwe_pl,
    929			     void *priv)
    930{
    931	struct mlxsw_env_module_temp_warn_event *event;
    932	struct mlxsw_env *mlxsw_env = priv;
    933
    934	event = kmalloc(sizeof(*event), GFP_ATOMIC);
    935	if (!event)
    936		return;
    937
    938	event->mlxsw_env = mlxsw_env;
    939	memcpy(event->mtwe_pl, mtwe_pl, MLXSW_REG_MTWE_LEN);
    940	INIT_WORK(&event->work, mlxsw_env_mtwe_event_work);
    941	mlxsw_core_schedule_work(&event->work);
    942}
    943
    944static const struct mlxsw_listener mlxsw_env_temp_warn_listener =
    945	MLXSW_CORE_EVENTL(mlxsw_env_mtwe_listener_func, MTWE);
    946
    947static int mlxsw_env_temp_warn_event_register(struct mlxsw_core *mlxsw_core)
    948{
    949	struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
    950
    951	return mlxsw_core_trap_register(mlxsw_core,
    952					&mlxsw_env_temp_warn_listener,
    953					mlxsw_env);
    954}
    955
    956static void mlxsw_env_temp_warn_event_unregister(struct mlxsw_env *mlxsw_env)
    957{
    958	mlxsw_core_trap_unregister(mlxsw_env->core,
    959				   &mlxsw_env_temp_warn_listener, mlxsw_env);
    960}
    961
    962struct mlxsw_env_module_plug_unplug_event {
    963	struct mlxsw_env *mlxsw_env;
    964	u8 slot_index;
    965	u8 module;
    966	struct work_struct work;
    967};
    968
    969static void mlxsw_env_pmpe_event_work(struct work_struct *work)
    970{
    971	struct mlxsw_env_module_plug_unplug_event *event;
    972	struct mlxsw_env_module_info *module_info;
    973	struct mlxsw_env *mlxsw_env;
    974	bool has_temp_sensor;
    975	u16 sensor_index;
    976	int err;
    977
    978	event = container_of(work, struct mlxsw_env_module_plug_unplug_event,
    979			     work);
    980	mlxsw_env = event->mlxsw_env;
    981
    982	mutex_lock(&mlxsw_env->line_cards_lock);
    983	module_info = mlxsw_env_module_info_get(mlxsw_env->core,
    984						event->slot_index,
    985						event->module);
    986	module_info->is_overheat = false;
    987	mutex_unlock(&mlxsw_env->line_cards_lock);
    988
    989	err = mlxsw_env_module_has_temp_sensor(mlxsw_env->core,
    990					       event->slot_index,
    991					       event->module,
    992					       &has_temp_sensor);
    993	/* Do not disable events on modules without sensors or faulty sensors
    994	 * because FW returns errors.
    995	 */
    996	if (err)
    997		goto out;
    998
    999	if (!has_temp_sensor)
   1000		goto out;
   1001
   1002	sensor_index = event->module + MLXSW_REG_MTMP_MODULE_INDEX_MIN;
   1003	mlxsw_env_temp_event_set(mlxsw_env->core, event->slot_index,
   1004				 sensor_index, true);
   1005
   1006out:
   1007	kfree(event);
   1008}
   1009
   1010static void
   1011mlxsw_env_pmpe_listener_func(const struct mlxsw_reg_info *reg, char *pmpe_pl,
   1012			     void *priv)
   1013{
   1014	u8 slot_index = mlxsw_reg_pmpe_slot_index_get(pmpe_pl);
   1015	struct mlxsw_env_module_plug_unplug_event *event;
   1016	enum mlxsw_reg_pmpe_module_status module_status;
   1017	u8 module = mlxsw_reg_pmpe_module_get(pmpe_pl);
   1018	struct mlxsw_env *mlxsw_env = priv;
   1019
   1020	if (WARN_ON_ONCE(module >= mlxsw_env->max_module_count ||
   1021			 slot_index >= mlxsw_env->num_of_slots))
   1022		return;
   1023
   1024	module_status = mlxsw_reg_pmpe_module_status_get(pmpe_pl);
   1025	if (module_status != MLXSW_REG_PMPE_MODULE_STATUS_PLUGGED_ENABLED)
   1026		return;
   1027
   1028	event = kmalloc(sizeof(*event), GFP_ATOMIC);
   1029	if (!event)
   1030		return;
   1031
   1032	event->mlxsw_env = mlxsw_env;
   1033	event->slot_index = slot_index;
   1034	event->module = module;
   1035	INIT_WORK(&event->work, mlxsw_env_pmpe_event_work);
   1036	mlxsw_core_schedule_work(&event->work);
   1037}
   1038
   1039static const struct mlxsw_listener mlxsw_env_module_plug_listener =
   1040	MLXSW_CORE_EVENTL(mlxsw_env_pmpe_listener_func, PMPE);
   1041
   1042static int
   1043mlxsw_env_module_plug_event_register(struct mlxsw_core *mlxsw_core)
   1044{
   1045	struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
   1046
   1047	return mlxsw_core_trap_register(mlxsw_core,
   1048					&mlxsw_env_module_plug_listener,
   1049					mlxsw_env);
   1050}
   1051
   1052static void
   1053mlxsw_env_module_plug_event_unregister(struct mlxsw_env *mlxsw_env)
   1054{
   1055	mlxsw_core_trap_unregister(mlxsw_env->core,
   1056				   &mlxsw_env_module_plug_listener,
   1057				   mlxsw_env);
   1058}
   1059
   1060static int
   1061mlxsw_env_module_oper_state_event_enable(struct mlxsw_core *mlxsw_core,
   1062					 u8 slot_index)
   1063{
   1064	struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
   1065	int i, err;
   1066
   1067	for (i = 0; i < mlxsw_env->line_cards[slot_index]->module_count; i++) {
   1068		char pmaos_pl[MLXSW_REG_PMAOS_LEN];
   1069
   1070		mlxsw_reg_pmaos_pack(pmaos_pl, slot_index, i);
   1071		mlxsw_reg_pmaos_e_set(pmaos_pl,
   1072				      MLXSW_REG_PMAOS_E_GENERATE_EVENT);
   1073		mlxsw_reg_pmaos_ee_set(pmaos_pl, true);
   1074		err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl);
   1075		if (err)
   1076			return err;
   1077	}
   1078	return 0;
   1079}
   1080
   1081int
   1082mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 slot_index,
   1083				      u8 module, u64 *p_counter)
   1084{
   1085	struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
   1086	struct mlxsw_env_module_info *module_info;
   1087
   1088	mutex_lock(&mlxsw_env->line_cards_lock);
   1089	module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
   1090	*p_counter = module_info->module_overheat_counter;
   1091	mutex_unlock(&mlxsw_env->line_cards_lock);
   1092
   1093	return 0;
   1094}
   1095EXPORT_SYMBOL(mlxsw_env_module_overheat_counter_get);
   1096
   1097void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 slot_index,
   1098			       u8 module)
   1099{
   1100	struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
   1101	struct mlxsw_env_module_info *module_info;
   1102
   1103	mutex_lock(&mlxsw_env->line_cards_lock);
   1104	module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
   1105	module_info->num_ports_mapped++;
   1106	mutex_unlock(&mlxsw_env->line_cards_lock);
   1107}
   1108EXPORT_SYMBOL(mlxsw_env_module_port_map);
   1109
   1110void mlxsw_env_module_port_unmap(struct mlxsw_core *mlxsw_core, u8 slot_index,
   1111				 u8 module)
   1112{
   1113	struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
   1114	struct mlxsw_env_module_info *module_info;
   1115
   1116	mutex_lock(&mlxsw_env->line_cards_lock);
   1117	module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
   1118	module_info->num_ports_mapped--;
   1119	mutex_unlock(&mlxsw_env->line_cards_lock);
   1120}
   1121EXPORT_SYMBOL(mlxsw_env_module_port_unmap);
   1122
   1123int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 slot_index,
   1124			     u8 module)
   1125{
   1126	struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
   1127	struct mlxsw_env_module_info *module_info;
   1128	int err = 0;
   1129
   1130	mutex_lock(&mlxsw_env->line_cards_lock);
   1131
   1132	module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
   1133	if (module_info->power_mode_policy !=
   1134	    ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO)
   1135		goto out_inc;
   1136
   1137	if (module_info->num_ports_up != 0)
   1138		goto out_inc;
   1139
   1140	/* Transition to high power mode following first port using the module
   1141	 * being put administratively up.
   1142	 */
   1143	err = __mlxsw_env_set_module_power_mode(mlxsw_core, slot_index, module,
   1144						false, NULL);
   1145	if (err)
   1146		goto out_unlock;
   1147
   1148out_inc:
   1149	module_info->num_ports_up++;
   1150out_unlock:
   1151	mutex_unlock(&mlxsw_env->line_cards_lock);
   1152	return err;
   1153}
   1154EXPORT_SYMBOL(mlxsw_env_module_port_up);
   1155
   1156void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 slot_index,
   1157				u8 module)
   1158{
   1159	struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
   1160	struct mlxsw_env_module_info *module_info;
   1161
   1162	mutex_lock(&mlxsw_env->line_cards_lock);
   1163
   1164	module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
   1165	module_info->num_ports_up--;
   1166
   1167	if (module_info->power_mode_policy !=
   1168	    ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO)
   1169		goto out_unlock;
   1170
   1171	if (module_info->num_ports_up != 0)
   1172		goto out_unlock;
   1173
   1174	/* Transition to low power mode following last port using the module
   1175	 * being put administratively down.
   1176	 */
   1177	__mlxsw_env_set_module_power_mode(mlxsw_core, slot_index, module, true,
   1178					  NULL);
   1179
   1180out_unlock:
   1181	mutex_unlock(&mlxsw_env->line_cards_lock);
   1182}
   1183EXPORT_SYMBOL(mlxsw_env_module_port_down);
   1184
   1185static int mlxsw_env_line_cards_alloc(struct mlxsw_env *env)
   1186{
   1187	struct mlxsw_env_module_info *module_info;
   1188	int i, j;
   1189
   1190	for (i = 0; i < env->num_of_slots; i++) {
   1191		env->line_cards[i] = kzalloc(struct_size(env->line_cards[i],
   1192							 module_info,
   1193							 env->max_module_count),
   1194							 GFP_KERNEL);
   1195		if (!env->line_cards[i])
   1196			goto kzalloc_err;
   1197
   1198		/* Firmware defaults to high power mode policy where modules
   1199		 * are transitioned to high power mode following plug-in.
   1200		 */
   1201		for (j = 0; j < env->max_module_count; j++) {
   1202			module_info = &env->line_cards[i]->module_info[j];
   1203			module_info->power_mode_policy =
   1204					ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH;
   1205		}
   1206	}
   1207
   1208	return 0;
   1209
   1210kzalloc_err:
   1211	for (i--; i >= 0; i--)
   1212		kfree(env->line_cards[i]);
   1213	return -ENOMEM;
   1214}
   1215
   1216static void mlxsw_env_line_cards_free(struct mlxsw_env *env)
   1217{
   1218	int i = env->num_of_slots;
   1219
   1220	for (i--; i >= 0; i--)
   1221		kfree(env->line_cards[i]);
   1222}
   1223
   1224static int
   1225mlxsw_env_module_event_enable(struct mlxsw_env *mlxsw_env, u8 slot_index)
   1226{
   1227	int err;
   1228
   1229	err = mlxsw_env_module_oper_state_event_enable(mlxsw_env->core,
   1230						       slot_index);
   1231	if (err)
   1232		return err;
   1233
   1234	err = mlxsw_env_module_temp_event_enable(mlxsw_env->core, slot_index);
   1235	if (err)
   1236		return err;
   1237
   1238	return 0;
   1239}
   1240
   1241static void
   1242mlxsw_env_module_event_disable(struct mlxsw_env *mlxsw_env, u8 slot_index)
   1243{
   1244}
   1245
   1246static int
   1247mlxsw_env_module_type_set(struct mlxsw_core *mlxsw_core, u8 slot_index)
   1248{
   1249	struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
   1250	int i;
   1251
   1252	for (i = 0; i < mlxsw_env->line_cards[slot_index]->module_count; i++) {
   1253		struct mlxsw_env_module_info *module_info;
   1254		char pmtm_pl[MLXSW_REG_PMTM_LEN];
   1255		int err;
   1256
   1257		mlxsw_reg_pmtm_pack(pmtm_pl, slot_index, i);
   1258		err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(pmtm), pmtm_pl);
   1259		if (err)
   1260			return err;
   1261
   1262		module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index,
   1263							i);
   1264		module_info->type = mlxsw_reg_pmtm_module_type_get(pmtm_pl);
   1265	}
   1266
   1267	return 0;
   1268}
   1269
   1270static void
   1271mlxsw_env_linecard_modules_power_mode_apply(struct mlxsw_core *mlxsw_core,
   1272					    struct mlxsw_env *env,
   1273					    u8 slot_index)
   1274{
   1275	int i;
   1276
   1277	for (i = 0; i < env->line_cards[slot_index]->module_count; i++) {
   1278		enum ethtool_module_power_mode_policy policy;
   1279		struct mlxsw_env_module_info *module_info;
   1280		struct netlink_ext_ack extack;
   1281		int err;
   1282
   1283		module_info = &env->line_cards[slot_index]->module_info[i];
   1284		policy = module_info->power_mode_policy;
   1285		err = mlxsw_env_set_module_power_mode_apply(mlxsw_core,
   1286							    slot_index, i,
   1287							    policy, &extack);
   1288		if (err)
   1289			dev_err(env->bus_info->dev, "%s\n", extack._msg);
   1290	}
   1291}
   1292
   1293static void
   1294mlxsw_env_got_active(struct mlxsw_core *mlxsw_core, u8 slot_index, void *priv)
   1295{
   1296	struct mlxsw_env *mlxsw_env = priv;
   1297	char mgpir_pl[MLXSW_REG_MGPIR_LEN];
   1298	int err;
   1299
   1300	mutex_lock(&mlxsw_env->line_cards_lock);
   1301	if (__mlxsw_env_linecard_is_active(mlxsw_env, slot_index))
   1302		goto out_unlock;
   1303
   1304	mlxsw_reg_mgpir_pack(mgpir_pl, slot_index);
   1305	err = mlxsw_reg_query(mlxsw_env->core, MLXSW_REG(mgpir), mgpir_pl);
   1306	if (err)
   1307		goto out_unlock;
   1308
   1309	mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL,
   1310			       &mlxsw_env->line_cards[slot_index]->module_count,
   1311			       NULL);
   1312
   1313	err = mlxsw_env_module_event_enable(mlxsw_env, slot_index);
   1314	if (err) {
   1315		dev_err(mlxsw_env->bus_info->dev, "Failed to enable port module events for line card in slot %d\n",
   1316			slot_index);
   1317		goto err_mlxsw_env_module_event_enable;
   1318	}
   1319	err = mlxsw_env_module_type_set(mlxsw_env->core, slot_index);
   1320	if (err) {
   1321		dev_err(mlxsw_env->bus_info->dev, "Failed to set modules' type for line card in slot %d\n",
   1322			slot_index);
   1323		goto err_type_set;
   1324	}
   1325
   1326	mlxsw_env->line_cards[slot_index]->active = true;
   1327	/* Apply power mode policy. */
   1328	mlxsw_env_linecard_modules_power_mode_apply(mlxsw_core, mlxsw_env,
   1329						    slot_index);
   1330	mutex_unlock(&mlxsw_env->line_cards_lock);
   1331
   1332	return;
   1333
   1334err_type_set:
   1335	mlxsw_env_module_event_disable(mlxsw_env, slot_index);
   1336err_mlxsw_env_module_event_enable:
   1337out_unlock:
   1338	mutex_unlock(&mlxsw_env->line_cards_lock);
   1339}
   1340
   1341static void
   1342mlxsw_env_got_inactive(struct mlxsw_core *mlxsw_core, u8 slot_index,
   1343		       void *priv)
   1344{
   1345	struct mlxsw_env *mlxsw_env = priv;
   1346
   1347	mutex_lock(&mlxsw_env->line_cards_lock);
   1348	if (!__mlxsw_env_linecard_is_active(mlxsw_env, slot_index))
   1349		goto out_unlock;
   1350	mlxsw_env->line_cards[slot_index]->active = false;
   1351	mlxsw_env_module_event_disable(mlxsw_env, slot_index);
   1352	mlxsw_env->line_cards[slot_index]->module_count = 0;
   1353out_unlock:
   1354	mutex_unlock(&mlxsw_env->line_cards_lock);
   1355}
   1356
   1357static struct mlxsw_linecards_event_ops mlxsw_env_event_ops = {
   1358	.got_active = mlxsw_env_got_active,
   1359	.got_inactive = mlxsw_env_got_inactive,
   1360};
   1361
   1362int mlxsw_env_init(struct mlxsw_core *mlxsw_core,
   1363		   const struct mlxsw_bus_info *bus_info,
   1364		   struct mlxsw_env **p_env)
   1365{
   1366	u8 module_count, num_of_slots, max_module_count;
   1367	char mgpir_pl[MLXSW_REG_MGPIR_LEN];
   1368	struct mlxsw_env *env;
   1369	int err;
   1370
   1371	mlxsw_reg_mgpir_pack(mgpir_pl, 0);
   1372	err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mgpir), mgpir_pl);
   1373	if (err)
   1374		return err;
   1375
   1376	mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, &module_count,
   1377			       &num_of_slots);
   1378	/* If the system is modular, get the maximum number of modules per-slot.
   1379	 * Otherwise, get the maximum number of modules on the main board.
   1380	 */
   1381	max_module_count = num_of_slots ?
   1382			   mlxsw_reg_mgpir_max_modules_per_slot_get(mgpir_pl) :
   1383			   module_count;
   1384
   1385	env = kzalloc(struct_size(env, line_cards, num_of_slots + 1),
   1386		      GFP_KERNEL);
   1387	if (!env)
   1388		return -ENOMEM;
   1389
   1390	env->core = mlxsw_core;
   1391	env->bus_info = bus_info;
   1392	env->num_of_slots = num_of_slots + 1;
   1393	env->max_module_count = max_module_count;
   1394	err = mlxsw_env_line_cards_alloc(env);
   1395	if (err)
   1396		goto err_mlxsw_env_line_cards_alloc;
   1397
   1398	mutex_init(&env->line_cards_lock);
   1399	*p_env = env;
   1400
   1401	err = mlxsw_linecards_event_ops_register(env->core,
   1402						 &mlxsw_env_event_ops, env);
   1403	if (err)
   1404		goto err_linecards_event_ops_register;
   1405
   1406	err = mlxsw_env_temp_warn_event_register(mlxsw_core);
   1407	if (err)
   1408		goto err_temp_warn_event_register;
   1409
   1410	err = mlxsw_env_module_plug_event_register(mlxsw_core);
   1411	if (err)
   1412		goto err_module_plug_event_register;
   1413
   1414	/* Set 'module_count' only for main board. Actual count for line card
   1415	 * is to be set after line card is activated.
   1416	 */
   1417	env->line_cards[0]->module_count = num_of_slots ? 0 : module_count;
   1418	/* Enable events only for main board. Line card events are to be
   1419	 * configured only after line card is activated. Before that, access to
   1420	 * modules on line cards is not allowed.
   1421	 */
   1422	err = mlxsw_env_module_event_enable(env, 0);
   1423	if (err)
   1424		goto err_mlxsw_env_module_event_enable;
   1425
   1426	err = mlxsw_env_module_type_set(mlxsw_core, 0);
   1427	if (err)
   1428		goto err_type_set;
   1429
   1430	env->line_cards[0]->active = true;
   1431
   1432	return 0;
   1433
   1434err_type_set:
   1435	mlxsw_env_module_event_disable(env, 0);
   1436err_mlxsw_env_module_event_enable:
   1437	mlxsw_env_module_plug_event_unregister(env);
   1438err_module_plug_event_register:
   1439	mlxsw_env_temp_warn_event_unregister(env);
   1440err_temp_warn_event_register:
   1441	mlxsw_linecards_event_ops_unregister(env->core,
   1442					     &mlxsw_env_event_ops, env);
   1443err_linecards_event_ops_register:
   1444	mutex_destroy(&env->line_cards_lock);
   1445	mlxsw_env_line_cards_free(env);
   1446err_mlxsw_env_line_cards_alloc:
   1447	kfree(env);
   1448	return err;
   1449}
   1450
   1451void mlxsw_env_fini(struct mlxsw_env *env)
   1452{
   1453	env->line_cards[0]->active = false;
   1454	mlxsw_env_module_event_disable(env, 0);
   1455	mlxsw_env_module_plug_event_unregister(env);
   1456	/* Make sure there is no more event work scheduled. */
   1457	mlxsw_core_flush_owq();
   1458	mlxsw_env_temp_warn_event_unregister(env);
   1459	mlxsw_linecards_event_ops_unregister(env->core,
   1460					     &mlxsw_env_event_ops, env);
   1461	mutex_destroy(&env->line_cards_lock);
   1462	mlxsw_env_line_cards_free(env);
   1463	kfree(env);
   1464}