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 
15 struct 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 };
22 
23 struct mlxsw_env {
24 	struct mlxsw_core *core;
25 	u8 module_count;
26 	struct mutex module_info_lock; /* Protects 'module_info'. */
27 	struct mlxsw_env_module_info module_info[];
28 };
29 
30 static int mlxsw_env_validate_cable_ident(struct mlxsw_core *core, int id,
31 					  bool *qsfp, bool *cmis)
32 {
33 	char mcia_pl[MLXSW_REG_MCIA_LEN];
34 	char *eeprom_tmp;
35 	u8 ident;
36 	int err;
37 
38 	mlxsw_reg_mcia_pack(mcia_pl, id, 0, MLXSW_REG_MCIA_PAGE0_LO_OFF, 0, 1,
39 			    MLXSW_REG_MCIA_I2C_ADDR_LOW);
40 	err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl);
41 	if (err)
42 		return err;
43 	eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl);
44 	ident = eeprom_tmp[0];
45 	*cmis = false;
46 	switch (ident) {
47 	case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP:
48 		*qsfp = false;
49 		break;
50 	case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP:
51 	case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS:
52 	case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28:
53 		*qsfp = true;
54 		break;
55 	case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_DD:
56 		*qsfp = true;
57 		*cmis = true;
58 		break;
59 	default:
60 		return -EINVAL;
61 	}
62 
63 	return 0;
64 }
65 
66 static int
67 mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module,
68 			      u16 offset, u16 size, void *data,
69 			      bool qsfp, unsigned int *p_read_size)
70 {
71 	char mcia_pl[MLXSW_REG_MCIA_LEN];
72 	char *eeprom_tmp;
73 	u16 i2c_addr;
74 	u8 page = 0;
75 	int status;
76 	int err;
77 
78 	/* MCIA register accepts buffer size <= 48. Page of size 128 should be
79 	 * read by chunks of size 48, 48, 32. Align the size of the last chunk
80 	 * to avoid reading after the end of the page.
81 	 */
82 	size = min_t(u16, size, MLXSW_REG_MCIA_EEPROM_SIZE);
83 
84 	if (offset < MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH &&
85 	    offset + size > MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH)
86 		/* Cross pages read, read until offset 256 in low page */
87 		size = MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH - offset;
88 
89 	i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_LOW;
90 	if (offset >= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) {
91 		if (qsfp) {
92 			/* When reading upper pages 1, 2 and 3 the offset
93 			 * starts at 128. Please refer to "QSFP+ Memory Map"
94 			 * figure in SFF-8436 specification and to "CMIS Module
95 			 * Memory Map" figure in CMIS specification for
96 			 * graphical depiction.
97 			 */
98 			page = MLXSW_REG_MCIA_PAGE_GET(offset);
99 			offset -= MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH * page;
100 			if (offset + size > MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH)
101 				size = MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH - offset;
102 		} else {
103 			/* When reading upper pages 1, 2 and 3 the offset
104 			 * starts at 0 and I2C high address is used. Please refer
105 			 * refer to "Memory Organization" figure in SFF-8472
106 			 * specification for graphical depiction.
107 			 */
108 			i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_HIGH;
109 			offset -= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH;
110 		}
111 	}
112 
113 	mlxsw_reg_mcia_pack(mcia_pl, module, 0, page, offset, size, i2c_addr);
114 
115 	err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl);
116 	if (err)
117 		return err;
118 
119 	status = mlxsw_reg_mcia_status_get(mcia_pl);
120 	if (status)
121 		return -EIO;
122 
123 	eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl);
124 	memcpy(data, eeprom_tmp, size);
125 	*p_read_size = size;
126 
127 	return 0;
128 }
129 
130 int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module,
131 					 int off, int *temp)
132 {
133 	unsigned int module_temp, module_crit, module_emerg;
134 	union {
135 		u8 buf[MLXSW_REG_MCIA_TH_ITEM_SIZE];
136 		u16 temp;
137 	} temp_thresh;
138 	char mcia_pl[MLXSW_REG_MCIA_LEN] = {0};
139 	char mtmp_pl[MLXSW_REG_MTMP_LEN];
140 	char *eeprom_tmp;
141 	bool qsfp, cmis;
142 	int page;
143 	int err;
144 
145 	mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTMP_MODULE_INDEX_MIN + module,
146 			    false, false);
147 	err = mlxsw_reg_query(core, MLXSW_REG(mtmp), mtmp_pl);
148 	if (err)
149 		return err;
150 	mlxsw_reg_mtmp_unpack(mtmp_pl, &module_temp, NULL, &module_crit,
151 			      &module_emerg, NULL);
152 	if (!module_temp) {
153 		*temp = 0;
154 		return 0;
155 	}
156 
157 	/* Validate if threshold reading is available through MTMP register,
158 	 * otherwise fallback to read through MCIA.
159 	 */
160 	if (module_emerg) {
161 		*temp = off == SFP_TEMP_HIGH_WARN ? module_crit : module_emerg;
162 		return 0;
163 	}
164 
165 	/* Read Free Side Device Temperature Thresholds from page 03h
166 	 * (MSB at lower byte address).
167 	 * Bytes:
168 	 * 128-129 - Temp High Alarm (SFP_TEMP_HIGH_ALARM);
169 	 * 130-131 - Temp Low Alarm (SFP_TEMP_LOW_ALARM);
170 	 * 132-133 - Temp High Warning (SFP_TEMP_HIGH_WARN);
171 	 * 134-135 - Temp Low Warning (SFP_TEMP_LOW_WARN);
172 	 */
173 
174 	/* Validate module identifier value. */
175 	err = mlxsw_env_validate_cable_ident(core, module, &qsfp, &cmis);
176 	if (err)
177 		return err;
178 
179 	if (qsfp) {
180 		/* For QSFP/CMIS module-defined thresholds are located in page
181 		 * 02h, otherwise in page 03h.
182 		 */
183 		if (cmis)
184 			page = MLXSW_REG_MCIA_TH_PAGE_CMIS_NUM;
185 		else
186 			page = MLXSW_REG_MCIA_TH_PAGE_NUM;
187 		mlxsw_reg_mcia_pack(mcia_pl, module, 0, page,
188 				    MLXSW_REG_MCIA_TH_PAGE_OFF + off,
189 				    MLXSW_REG_MCIA_TH_ITEM_SIZE,
190 				    MLXSW_REG_MCIA_I2C_ADDR_LOW);
191 	} else {
192 		mlxsw_reg_mcia_pack(mcia_pl, module, 0,
193 				    MLXSW_REG_MCIA_PAGE0_LO,
194 				    off, MLXSW_REG_MCIA_TH_ITEM_SIZE,
195 				    MLXSW_REG_MCIA_I2C_ADDR_HIGH);
196 	}
197 
198 	err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl);
199 	if (err)
200 		return err;
201 
202 	eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl);
203 	memcpy(temp_thresh.buf, eeprom_tmp, MLXSW_REG_MCIA_TH_ITEM_SIZE);
204 	*temp = temp_thresh.temp * 1000;
205 
206 	return 0;
207 }
208 
209 int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module,
210 			      struct ethtool_modinfo *modinfo)
211 {
212 	u8 module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE];
213 	u16 offset = MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE;
214 	u8 module_rev_id, module_id, diag_mon;
215 	unsigned int read_size;
216 	int err;
217 
218 	err = mlxsw_env_query_module_eeprom(mlxsw_core, module, 0, offset,
219 					    module_info, false, &read_size);
220 	if (err)
221 		return err;
222 
223 	if (read_size < offset)
224 		return -EIO;
225 
226 	module_rev_id = module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID];
227 	module_id = module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID];
228 
229 	switch (module_id) {
230 	case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP:
231 		modinfo->type       = ETH_MODULE_SFF_8436;
232 		modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN;
233 		break;
234 	case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS:
235 	case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28:
236 		if (module_id == MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28 ||
237 		    module_rev_id >=
238 		    MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID_8636) {
239 			modinfo->type       = ETH_MODULE_SFF_8636;
240 			modinfo->eeprom_len = ETH_MODULE_SFF_8636_MAX_LEN;
241 		} else {
242 			modinfo->type       = ETH_MODULE_SFF_8436;
243 			modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN;
244 		}
245 		break;
246 	case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP:
247 		/* Verify if transceiver provides diagnostic monitoring page */
248 		err = mlxsw_env_query_module_eeprom(mlxsw_core, module,
249 						    SFP_DIAGMON, 1, &diag_mon,
250 						    false, &read_size);
251 		if (err)
252 			return err;
253 
254 		if (read_size < 1)
255 			return -EIO;
256 
257 		modinfo->type       = ETH_MODULE_SFF_8472;
258 		if (diag_mon)
259 			modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
260 		else
261 			modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN / 2;
262 		break;
263 	case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_DD:
264 		/* Use SFF_8636 as base type. ethtool should recognize specific
265 		 * type through the identifier value.
266 		 */
267 		modinfo->type       = ETH_MODULE_SFF_8636;
268 		/* Verify if module EEPROM is a flat memory. In case of flat
269 		 * memory only page 00h (0-255 bytes) can be read. Otherwise
270 		 * upper pages 01h and 02h can also be read. Upper pages 10h
271 		 * and 11h are currently not supported by the driver.
272 		 */
273 		if (module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_TYPE_ID] &
274 		    MLXSW_REG_MCIA_EEPROM_CMIS_FLAT_MEMORY)
275 			modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN;
276 		else
277 			modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
278 		break;
279 	default:
280 		return -EINVAL;
281 	}
282 
283 	return 0;
284 }
285 EXPORT_SYMBOL(mlxsw_env_get_module_info);
286 
287 int mlxsw_env_get_module_eeprom(struct net_device *netdev,
288 				struct mlxsw_core *mlxsw_core, int module,
289 				struct ethtool_eeprom *ee, u8 *data)
290 {
291 	int offset = ee->offset;
292 	unsigned int read_size;
293 	bool qsfp, cmis;
294 	int i = 0;
295 	int err;
296 
297 	if (!ee->len)
298 		return -EINVAL;
299 
300 	memset(data, 0, ee->len);
301 	/* Validate module identifier value. */
302 	err = mlxsw_env_validate_cable_ident(mlxsw_core, module, &qsfp, &cmis);
303 	if (err)
304 		return err;
305 
306 	while (i < ee->len) {
307 		err = mlxsw_env_query_module_eeprom(mlxsw_core, module, offset,
308 						    ee->len - i, data + i,
309 						    qsfp, &read_size);
310 		if (err) {
311 			netdev_err(netdev, "Eeprom query failed\n");
312 			return err;
313 		}
314 
315 		i += read_size;
316 		offset += read_size;
317 	}
318 
319 	return 0;
320 }
321 EXPORT_SYMBOL(mlxsw_env_get_module_eeprom);
322 
323 static int mlxsw_env_mcia_status_process(const char *mcia_pl,
324 					 struct netlink_ext_ack *extack)
325 {
326 	u8 status = mlxsw_reg_mcia_status_get(mcia_pl);
327 
328 	switch (status) {
329 	case MLXSW_REG_MCIA_STATUS_GOOD:
330 		return 0;
331 	case MLXSW_REG_MCIA_STATUS_NO_EEPROM_MODULE:
332 		NL_SET_ERR_MSG_MOD(extack, "No response from module's EEPROM");
333 		return -EIO;
334 	case MLXSW_REG_MCIA_STATUS_MODULE_NOT_SUPPORTED:
335 		NL_SET_ERR_MSG_MOD(extack, "Module type not supported by the device");
336 		return -EOPNOTSUPP;
337 	case MLXSW_REG_MCIA_STATUS_MODULE_NOT_CONNECTED:
338 		NL_SET_ERR_MSG_MOD(extack, "No module present indication");
339 		return -EIO;
340 	case MLXSW_REG_MCIA_STATUS_I2C_ERROR:
341 		NL_SET_ERR_MSG_MOD(extack, "Error occurred while trying to access module's EEPROM using I2C");
342 		return -EIO;
343 	case MLXSW_REG_MCIA_STATUS_MODULE_DISABLED:
344 		NL_SET_ERR_MSG_MOD(extack, "Module is disabled");
345 		return -EIO;
346 	default:
347 		NL_SET_ERR_MSG_MOD(extack, "Unknown error");
348 		return -EIO;
349 	}
350 }
351 
352 int
353 mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, u8 module,
354 				    const struct ethtool_module_eeprom *page,
355 				    struct netlink_ext_ack *extack)
356 {
357 	u32 bytes_read = 0;
358 	u16 device_addr;
359 
360 	/* Offset cannot be larger than 2 * ETH_MODULE_EEPROM_PAGE_LEN */
361 	device_addr = page->offset;
362 
363 	while (bytes_read < page->length) {
364 		char mcia_pl[MLXSW_REG_MCIA_LEN];
365 		char *eeprom_tmp;
366 		u8 size;
367 		int err;
368 
369 		size = min_t(u8, page->length - bytes_read,
370 			     MLXSW_REG_MCIA_EEPROM_SIZE);
371 
372 		mlxsw_reg_mcia_pack(mcia_pl, module, 0, page->page,
373 				    device_addr + bytes_read, size,
374 				    page->i2c_address);
375 		mlxsw_reg_mcia_bank_number_set(mcia_pl, page->bank);
376 
377 		err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl);
378 		if (err) {
379 			NL_SET_ERR_MSG_MOD(extack, "Failed to access module's EEPROM");
380 			return err;
381 		}
382 
383 		err = mlxsw_env_mcia_status_process(mcia_pl, extack);
384 		if (err)
385 			return err;
386 
387 		eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl);
388 		memcpy(page->data + bytes_read, eeprom_tmp, size);
389 		bytes_read += size;
390 	}
391 
392 	return bytes_read;
393 }
394 EXPORT_SYMBOL(mlxsw_env_get_module_eeprom_by_page);
395 
396 static int mlxsw_env_module_reset(struct mlxsw_core *mlxsw_core, u8 module)
397 {
398 	char pmaos_pl[MLXSW_REG_PMAOS_LEN];
399 
400 	mlxsw_reg_pmaos_pack(pmaos_pl, module);
401 	mlxsw_reg_pmaos_rst_set(pmaos_pl, true);
402 
403 	return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl);
404 }
405 
406 int mlxsw_env_reset_module(struct net_device *netdev,
407 			   struct mlxsw_core *mlxsw_core, u8 module, u32 *flags)
408 {
409 	struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
410 	u32 req = *flags;
411 	int err;
412 
413 	if (!(req & ETH_RESET_PHY) &&
414 	    !(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT)))
415 		return 0;
416 
417 	if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
418 		return -EINVAL;
419 
420 	mutex_lock(&mlxsw_env->module_info_lock);
421 
422 	if (mlxsw_env->module_info[module].num_ports_up) {
423 		netdev_err(netdev, "Cannot reset module when ports using it are administratively up\n");
424 		err = -EINVAL;
425 		goto out;
426 	}
427 
428 	if (mlxsw_env->module_info[module].num_ports_mapped > 1 &&
429 	    !(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT))) {
430 		netdev_err(netdev, "Cannot reset module without \"phy-shared\" flag when shared by multiple ports\n");
431 		err = -EINVAL;
432 		goto out;
433 	}
434 
435 	err = mlxsw_env_module_reset(mlxsw_core, module);
436 	if (err) {
437 		netdev_err(netdev, "Failed to reset module\n");
438 		goto out;
439 	}
440 
441 	*flags &= ~(ETH_RESET_PHY | (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT));
442 
443 out:
444 	mutex_unlock(&mlxsw_env->module_info_lock);
445 	return err;
446 }
447 EXPORT_SYMBOL(mlxsw_env_reset_module);
448 
449 int
450 mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module,
451 				struct ethtool_module_power_mode_params *params,
452 				struct netlink_ext_ack *extack)
453 {
454 	struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
455 	char mcion_pl[MLXSW_REG_MCION_LEN];
456 	u32 status_bits;
457 	int err;
458 
459 	if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
460 		return -EINVAL;
461 
462 	mutex_lock(&mlxsw_env->module_info_lock);
463 
464 	params->policy = mlxsw_env->module_info[module].power_mode_policy;
465 
466 	mlxsw_reg_mcion_pack(mcion_pl, module);
467 	err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcion), mcion_pl);
468 	if (err) {
469 		NL_SET_ERR_MSG_MOD(extack, "Failed to retrieve module's power mode");
470 		goto out;
471 	}
472 
473 	status_bits = mlxsw_reg_mcion_module_status_bits_get(mcion_pl);
474 	if (!(status_bits & MLXSW_REG_MCION_MODULE_STATUS_BITS_PRESENT_MASK))
475 		goto out;
476 
477 	if (status_bits & MLXSW_REG_MCION_MODULE_STATUS_BITS_LOW_POWER_MASK)
478 		params->mode = ETHTOOL_MODULE_POWER_MODE_LOW;
479 	else
480 		params->mode = ETHTOOL_MODULE_POWER_MODE_HIGH;
481 
482 out:
483 	mutex_unlock(&mlxsw_env->module_info_lock);
484 	return err;
485 }
486 EXPORT_SYMBOL(mlxsw_env_get_module_power_mode);
487 
488 static int mlxsw_env_module_enable_set(struct mlxsw_core *mlxsw_core,
489 				       u8 module, bool enable)
490 {
491 	enum mlxsw_reg_pmaos_admin_status admin_status;
492 	char pmaos_pl[MLXSW_REG_PMAOS_LEN];
493 
494 	mlxsw_reg_pmaos_pack(pmaos_pl, module);
495 	admin_status = enable ? MLXSW_REG_PMAOS_ADMIN_STATUS_ENABLED :
496 				MLXSW_REG_PMAOS_ADMIN_STATUS_DISABLED;
497 	mlxsw_reg_pmaos_admin_status_set(pmaos_pl, admin_status);
498 	mlxsw_reg_pmaos_ase_set(pmaos_pl, true);
499 
500 	return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl);
501 }
502 
503 static int mlxsw_env_module_low_power_set(struct mlxsw_core *mlxsw_core,
504 					  u8 module, bool low_power)
505 {
506 	u16 eeprom_override_mask, eeprom_override;
507 	char pmmp_pl[MLXSW_REG_PMMP_LEN];
508 
509 	mlxsw_reg_pmmp_pack(pmmp_pl, module);
510 	mlxsw_reg_pmmp_sticky_set(pmmp_pl, true);
511 	/* Mask all the bits except low power mode. */
512 	eeprom_override_mask = ~MLXSW_REG_PMMP_EEPROM_OVERRIDE_LOW_POWER_MASK;
513 	mlxsw_reg_pmmp_eeprom_override_mask_set(pmmp_pl, eeprom_override_mask);
514 	eeprom_override = low_power ? MLXSW_REG_PMMP_EEPROM_OVERRIDE_LOW_POWER_MASK :
515 				      0;
516 	mlxsw_reg_pmmp_eeprom_override_set(pmmp_pl, eeprom_override);
517 
518 	return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmmp), pmmp_pl);
519 }
520 
521 static int __mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core,
522 					     u8 module, bool low_power,
523 					     struct netlink_ext_ack *extack)
524 {
525 	int err;
526 
527 	err = mlxsw_env_module_enable_set(mlxsw_core, module, false);
528 	if (err) {
529 		NL_SET_ERR_MSG_MOD(extack, "Failed to disable module");
530 		return err;
531 	}
532 
533 	err = mlxsw_env_module_low_power_set(mlxsw_core, module, low_power);
534 	if (err) {
535 		NL_SET_ERR_MSG_MOD(extack, "Failed to set module's power mode");
536 		goto err_module_low_power_set;
537 	}
538 
539 	err = mlxsw_env_module_enable_set(mlxsw_core, module, true);
540 	if (err) {
541 		NL_SET_ERR_MSG_MOD(extack, "Failed to enable module");
542 		goto err_module_enable_set;
543 	}
544 
545 	return 0;
546 
547 err_module_enable_set:
548 	mlxsw_env_module_low_power_set(mlxsw_core, module, !low_power);
549 err_module_low_power_set:
550 	mlxsw_env_module_enable_set(mlxsw_core, module, true);
551 	return err;
552 }
553 
554 int
555 mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module,
556 				enum ethtool_module_power_mode_policy policy,
557 				struct netlink_ext_ack *extack)
558 {
559 	struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
560 	bool low_power;
561 	int err = 0;
562 
563 	if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
564 		return -EINVAL;
565 
566 	if (policy != ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH &&
567 	    policy != ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO) {
568 		NL_SET_ERR_MSG_MOD(extack, "Unsupported power mode policy");
569 		return -EOPNOTSUPP;
570 	}
571 
572 	mutex_lock(&mlxsw_env->module_info_lock);
573 
574 	if (mlxsw_env->module_info[module].power_mode_policy == policy)
575 		goto out;
576 
577 	/* If any ports are up, we are already in high power mode. */
578 	if (mlxsw_env->module_info[module].num_ports_up)
579 		goto out_set_policy;
580 
581 	low_power = policy == ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO;
582 	err = __mlxsw_env_set_module_power_mode(mlxsw_core, module, low_power,
583 						extack);
584 	if (err)
585 		goto out;
586 
587 out_set_policy:
588 	mlxsw_env->module_info[module].power_mode_policy = policy;
589 out:
590 	mutex_unlock(&mlxsw_env->module_info_lock);
591 	return err;
592 }
593 EXPORT_SYMBOL(mlxsw_env_set_module_power_mode);
594 
595 static int mlxsw_env_module_has_temp_sensor(struct mlxsw_core *mlxsw_core,
596 					    u8 module,
597 					    bool *p_has_temp_sensor)
598 {
599 	char mtbr_pl[MLXSW_REG_MTBR_LEN];
600 	u16 temp;
601 	int err;
602 
603 	mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module,
604 			    1);
605 	err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mtbr), mtbr_pl);
606 	if (err)
607 		return err;
608 
609 	mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL);
610 
611 	switch (temp) {
612 	case MLXSW_REG_MTBR_BAD_SENS_INFO:
613 	case MLXSW_REG_MTBR_NO_CONN:
614 	case MLXSW_REG_MTBR_NO_TEMP_SENS:
615 	case MLXSW_REG_MTBR_INDEX_NA:
616 		*p_has_temp_sensor = false;
617 		break;
618 	default:
619 		*p_has_temp_sensor = temp ? true : false;
620 	}
621 	return 0;
622 }
623 
624 static int mlxsw_env_temp_event_set(struct mlxsw_core *mlxsw_core,
625 				    u16 sensor_index, bool enable)
626 {
627 	char mtmp_pl[MLXSW_REG_MTMP_LEN] = {0};
628 	enum mlxsw_reg_mtmp_tee tee;
629 	int err, threshold_hi;
630 
631 	mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, sensor_index);
632 	err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mtmp), mtmp_pl);
633 	if (err)
634 		return err;
635 
636 	if (enable) {
637 		err = mlxsw_env_module_temp_thresholds_get(mlxsw_core,
638 							   sensor_index -
639 							   MLXSW_REG_MTMP_MODULE_INDEX_MIN,
640 							   SFP_TEMP_HIGH_WARN,
641 							   &threshold_hi);
642 		/* In case it is not possible to query the module's threshold,
643 		 * use the default value.
644 		 */
645 		if (err)
646 			threshold_hi = MLXSW_REG_MTMP_THRESH_HI;
647 		else
648 			/* mlxsw_env_module_temp_thresholds_get() multiplies
649 			 * Celsius degrees by 1000 whereas MTMP expects
650 			 * temperature in 0.125 Celsius degrees units.
651 			 * Convert threshold_hi to correct units.
652 			 */
653 			threshold_hi = threshold_hi / 1000 * 8;
654 
655 		mlxsw_reg_mtmp_temperature_threshold_hi_set(mtmp_pl, threshold_hi);
656 		mlxsw_reg_mtmp_temperature_threshold_lo_set(mtmp_pl, threshold_hi -
657 							    MLXSW_REG_MTMP_HYSTERESIS_TEMP);
658 	}
659 	tee = enable ? MLXSW_REG_MTMP_TEE_GENERATE_EVENT : MLXSW_REG_MTMP_TEE_NO_EVENT;
660 	mlxsw_reg_mtmp_tee_set(mtmp_pl, tee);
661 	return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mtmp), mtmp_pl);
662 }
663 
664 static int mlxsw_env_module_temp_event_enable(struct mlxsw_core *mlxsw_core,
665 					      u8 module_count)
666 {
667 	int i, err, sensor_index;
668 	bool has_temp_sensor;
669 
670 	for (i = 0; i < module_count; i++) {
671 		err = mlxsw_env_module_has_temp_sensor(mlxsw_core, i,
672 						       &has_temp_sensor);
673 		if (err)
674 			return err;
675 
676 		if (!has_temp_sensor)
677 			continue;
678 
679 		sensor_index = i + MLXSW_REG_MTMP_MODULE_INDEX_MIN;
680 		err = mlxsw_env_temp_event_set(mlxsw_core, sensor_index, true);
681 		if (err)
682 			return err;
683 	}
684 
685 	return 0;
686 }
687 
688 struct mlxsw_env_module_temp_warn_event {
689 	struct mlxsw_env *mlxsw_env;
690 	char mtwe_pl[MLXSW_REG_MTWE_LEN];
691 	struct work_struct work;
692 };
693 
694 static void mlxsw_env_mtwe_event_work(struct work_struct *work)
695 {
696 	struct mlxsw_env_module_temp_warn_event *event;
697 	struct mlxsw_env *mlxsw_env;
698 	int i, sensor_warning;
699 	bool is_overheat;
700 
701 	event = container_of(work, struct mlxsw_env_module_temp_warn_event,
702 			     work);
703 	mlxsw_env = event->mlxsw_env;
704 
705 	for (i = 0; i < mlxsw_env->module_count; i++) {
706 		/* 64-127 of sensor_index are mapped to the port modules
707 		 * sequentially (module 0 is mapped to sensor_index 64,
708 		 * module 1 to sensor_index 65 and so on)
709 		 */
710 		sensor_warning =
711 			mlxsw_reg_mtwe_sensor_warning_get(event->mtwe_pl,
712 							  i + MLXSW_REG_MTMP_MODULE_INDEX_MIN);
713 		mutex_lock(&mlxsw_env->module_info_lock);
714 		is_overheat =
715 			mlxsw_env->module_info[i].is_overheat;
716 
717 		if ((is_overheat && sensor_warning) ||
718 		    (!is_overheat && !sensor_warning)) {
719 			/* Current state is "warning" and MTWE still reports
720 			 * warning OR current state in "no warning" and MTWE
721 			 * does not report warning.
722 			 */
723 			mutex_unlock(&mlxsw_env->module_info_lock);
724 			continue;
725 		} else if (is_overheat && !sensor_warning) {
726 			/* MTWE reports "no warning", turn is_overheat off.
727 			 */
728 			mlxsw_env->module_info[i].is_overheat = false;
729 			mutex_unlock(&mlxsw_env->module_info_lock);
730 		} else {
731 			/* Current state is "no warning" and MTWE reports
732 			 * "warning", increase the counter and turn is_overheat
733 			 * on.
734 			 */
735 			mlxsw_env->module_info[i].is_overheat = true;
736 			mlxsw_env->module_info[i].module_overheat_counter++;
737 			mutex_unlock(&mlxsw_env->module_info_lock);
738 		}
739 	}
740 
741 	kfree(event);
742 }
743 
744 static void
745 mlxsw_env_mtwe_listener_func(const struct mlxsw_reg_info *reg, char *mtwe_pl,
746 			     void *priv)
747 {
748 	struct mlxsw_env_module_temp_warn_event *event;
749 	struct mlxsw_env *mlxsw_env = priv;
750 
751 	event = kmalloc(sizeof(*event), GFP_ATOMIC);
752 	if (!event)
753 		return;
754 
755 	event->mlxsw_env = mlxsw_env;
756 	memcpy(event->mtwe_pl, mtwe_pl, MLXSW_REG_MTWE_LEN);
757 	INIT_WORK(&event->work, mlxsw_env_mtwe_event_work);
758 	mlxsw_core_schedule_work(&event->work);
759 }
760 
761 static const struct mlxsw_listener mlxsw_env_temp_warn_listener =
762 	MLXSW_EVENTL(mlxsw_env_mtwe_listener_func, MTWE, MTWE);
763 
764 static int mlxsw_env_temp_warn_event_register(struct mlxsw_core *mlxsw_core)
765 {
766 	struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
767 
768 	if (!mlxsw_core_temp_warn_enabled(mlxsw_core))
769 		return 0;
770 
771 	return mlxsw_core_trap_register(mlxsw_core,
772 					&mlxsw_env_temp_warn_listener,
773 					mlxsw_env);
774 }
775 
776 static void mlxsw_env_temp_warn_event_unregister(struct mlxsw_env *mlxsw_env)
777 {
778 	if (!mlxsw_core_temp_warn_enabled(mlxsw_env->core))
779 		return;
780 
781 	mlxsw_core_trap_unregister(mlxsw_env->core,
782 				   &mlxsw_env_temp_warn_listener, mlxsw_env);
783 }
784 
785 struct mlxsw_env_module_plug_unplug_event {
786 	struct mlxsw_env *mlxsw_env;
787 	u8 module;
788 	struct work_struct work;
789 };
790 
791 static void mlxsw_env_pmpe_event_work(struct work_struct *work)
792 {
793 	struct mlxsw_env_module_plug_unplug_event *event;
794 	struct mlxsw_env *mlxsw_env;
795 	bool has_temp_sensor;
796 	u16 sensor_index;
797 	int err;
798 
799 	event = container_of(work, struct mlxsw_env_module_plug_unplug_event,
800 			     work);
801 	mlxsw_env = event->mlxsw_env;
802 
803 	mutex_lock(&mlxsw_env->module_info_lock);
804 	mlxsw_env->module_info[event->module].is_overheat = false;
805 	mutex_unlock(&mlxsw_env->module_info_lock);
806 
807 	err = mlxsw_env_module_has_temp_sensor(mlxsw_env->core, event->module,
808 					       &has_temp_sensor);
809 	/* Do not disable events on modules without sensors or faulty sensors
810 	 * because FW returns errors.
811 	 */
812 	if (err)
813 		goto out;
814 
815 	if (!has_temp_sensor)
816 		goto out;
817 
818 	sensor_index = event->module + MLXSW_REG_MTMP_MODULE_INDEX_MIN;
819 	mlxsw_env_temp_event_set(mlxsw_env->core, sensor_index, true);
820 
821 out:
822 	kfree(event);
823 }
824 
825 static void
826 mlxsw_env_pmpe_listener_func(const struct mlxsw_reg_info *reg, char *pmpe_pl,
827 			     void *priv)
828 {
829 	struct mlxsw_env_module_plug_unplug_event *event;
830 	enum mlxsw_reg_pmpe_module_status module_status;
831 	u8 module = mlxsw_reg_pmpe_module_get(pmpe_pl);
832 	struct mlxsw_env *mlxsw_env = priv;
833 
834 	if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
835 		return;
836 
837 	module_status = mlxsw_reg_pmpe_module_status_get(pmpe_pl);
838 	if (module_status != MLXSW_REG_PMPE_MODULE_STATUS_PLUGGED_ENABLED)
839 		return;
840 
841 	event = kmalloc(sizeof(*event), GFP_ATOMIC);
842 	if (!event)
843 		return;
844 
845 	event->mlxsw_env = mlxsw_env;
846 	event->module = module;
847 	INIT_WORK(&event->work, mlxsw_env_pmpe_event_work);
848 	mlxsw_core_schedule_work(&event->work);
849 }
850 
851 static const struct mlxsw_listener mlxsw_env_module_plug_listener =
852 	MLXSW_EVENTL(mlxsw_env_pmpe_listener_func, PMPE, PMPE);
853 
854 static int
855 mlxsw_env_module_plug_event_register(struct mlxsw_core *mlxsw_core)
856 {
857 	struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
858 
859 	if (!mlxsw_core_temp_warn_enabled(mlxsw_core))
860 		return 0;
861 
862 	return mlxsw_core_trap_register(mlxsw_core,
863 					&mlxsw_env_module_plug_listener,
864 					mlxsw_env);
865 }
866 
867 static void
868 mlxsw_env_module_plug_event_unregister(struct mlxsw_env *mlxsw_env)
869 {
870 	if (!mlxsw_core_temp_warn_enabled(mlxsw_env->core))
871 		return;
872 
873 	mlxsw_core_trap_unregister(mlxsw_env->core,
874 				   &mlxsw_env_module_plug_listener,
875 				   mlxsw_env);
876 }
877 
878 static int
879 mlxsw_env_module_oper_state_event_enable(struct mlxsw_core *mlxsw_core,
880 					 u8 module_count)
881 {
882 	int i, err;
883 
884 	for (i = 0; i < module_count; i++) {
885 		char pmaos_pl[MLXSW_REG_PMAOS_LEN];
886 
887 		mlxsw_reg_pmaos_pack(pmaos_pl, i);
888 		mlxsw_reg_pmaos_e_set(pmaos_pl,
889 				      MLXSW_REG_PMAOS_E_GENERATE_EVENT);
890 		mlxsw_reg_pmaos_ee_set(pmaos_pl, true);
891 		err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl);
892 		if (err)
893 			return err;
894 	}
895 	return 0;
896 }
897 
898 int
899 mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 module,
900 				      u64 *p_counter)
901 {
902 	struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
903 
904 	if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
905 		return -EINVAL;
906 
907 	mutex_lock(&mlxsw_env->module_info_lock);
908 	*p_counter = mlxsw_env->module_info[module].module_overheat_counter;
909 	mutex_unlock(&mlxsw_env->module_info_lock);
910 
911 	return 0;
912 }
913 EXPORT_SYMBOL(mlxsw_env_module_overheat_counter_get);
914 
915 void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 module)
916 {
917 	struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
918 
919 	if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
920 		return;
921 
922 	mutex_lock(&mlxsw_env->module_info_lock);
923 	mlxsw_env->module_info[module].num_ports_mapped++;
924 	mutex_unlock(&mlxsw_env->module_info_lock);
925 }
926 EXPORT_SYMBOL(mlxsw_env_module_port_map);
927 
928 void mlxsw_env_module_port_unmap(struct mlxsw_core *mlxsw_core, u8 module)
929 {
930 	struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
931 
932 	if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
933 		return;
934 
935 	mutex_lock(&mlxsw_env->module_info_lock);
936 	mlxsw_env->module_info[module].num_ports_mapped--;
937 	mutex_unlock(&mlxsw_env->module_info_lock);
938 }
939 EXPORT_SYMBOL(mlxsw_env_module_port_unmap);
940 
941 int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 module)
942 {
943 	struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
944 	int err = 0;
945 
946 	if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
947 		return -EINVAL;
948 
949 	mutex_lock(&mlxsw_env->module_info_lock);
950 
951 	if (mlxsw_env->module_info[module].power_mode_policy !=
952 	    ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO)
953 		goto out_inc;
954 
955 	if (mlxsw_env->module_info[module].num_ports_up != 0)
956 		goto out_inc;
957 
958 	/* Transition to high power mode following first port using the module
959 	 * being put administratively up.
960 	 */
961 	err = __mlxsw_env_set_module_power_mode(mlxsw_core, module, false,
962 						NULL);
963 	if (err)
964 		goto out_unlock;
965 
966 out_inc:
967 	mlxsw_env->module_info[module].num_ports_up++;
968 out_unlock:
969 	mutex_unlock(&mlxsw_env->module_info_lock);
970 	return err;
971 }
972 EXPORT_SYMBOL(mlxsw_env_module_port_up);
973 
974 void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 module)
975 {
976 	struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
977 
978 	if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
979 		return;
980 
981 	mutex_lock(&mlxsw_env->module_info_lock);
982 
983 	mlxsw_env->module_info[module].num_ports_up--;
984 
985 	if (mlxsw_env->module_info[module].power_mode_policy !=
986 	    ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO)
987 		goto out_unlock;
988 
989 	if (mlxsw_env->module_info[module].num_ports_up != 0)
990 		goto out_unlock;
991 
992 	/* Transition to low power mode following last port using the module
993 	 * being put administratively down.
994 	 */
995 	__mlxsw_env_set_module_power_mode(mlxsw_core, module, true, NULL);
996 
997 out_unlock:
998 	mutex_unlock(&mlxsw_env->module_info_lock);
999 }
1000 EXPORT_SYMBOL(mlxsw_env_module_port_down);
1001 
1002 int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env)
1003 {
1004 	char mgpir_pl[MLXSW_REG_MGPIR_LEN];
1005 	struct mlxsw_env *env;
1006 	u8 module_count;
1007 	int i, err;
1008 
1009 	mlxsw_reg_mgpir_pack(mgpir_pl);
1010 	err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mgpir), mgpir_pl);
1011 	if (err)
1012 		return err;
1013 
1014 	mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, &module_count);
1015 
1016 	env = kzalloc(struct_size(env, module_info, module_count), GFP_KERNEL);
1017 	if (!env)
1018 		return -ENOMEM;
1019 
1020 	/* Firmware defaults to high power mode policy where modules are
1021 	 * transitioned to high power mode following plug-in.
1022 	 */
1023 	for (i = 0; i < module_count; i++)
1024 		env->module_info[i].power_mode_policy =
1025 			ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH;
1026 
1027 	mutex_init(&env->module_info_lock);
1028 	env->core = mlxsw_core;
1029 	env->module_count = module_count;
1030 	*p_env = env;
1031 
1032 	err = mlxsw_env_temp_warn_event_register(mlxsw_core);
1033 	if (err)
1034 		goto err_temp_warn_event_register;
1035 
1036 	err = mlxsw_env_module_plug_event_register(mlxsw_core);
1037 	if (err)
1038 		goto err_module_plug_event_register;
1039 
1040 	err = mlxsw_env_module_oper_state_event_enable(mlxsw_core,
1041 						       env->module_count);
1042 	if (err)
1043 		goto err_oper_state_event_enable;
1044 
1045 	err = mlxsw_env_module_temp_event_enable(mlxsw_core, env->module_count);
1046 	if (err)
1047 		goto err_temp_event_enable;
1048 
1049 	return 0;
1050 
1051 err_temp_event_enable:
1052 err_oper_state_event_enable:
1053 	mlxsw_env_module_plug_event_unregister(env);
1054 err_module_plug_event_register:
1055 	mlxsw_env_temp_warn_event_unregister(env);
1056 err_temp_warn_event_register:
1057 	mutex_destroy(&env->module_info_lock);
1058 	kfree(env);
1059 	return err;
1060 }
1061 
1062 void mlxsw_env_fini(struct mlxsw_env *env)
1063 {
1064 	mlxsw_env_module_plug_event_unregister(env);
1065 	/* Make sure there is no more event work scheduled. */
1066 	mlxsw_core_flush_owq();
1067 	mlxsw_env_temp_warn_event_unregister(env);
1068 	mutex_destroy(&env->module_info_lock);
1069 	kfree(env);
1070 }
1071