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 	enum mlxsw_reg_pmtm_module_type type;
22 };
23 
24 struct mlxsw_env_line_card {
25 	u8 module_count;
26 	bool active;
27 	struct mlxsw_env_module_info module_info[];
28 };
29 
30 struct 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 
__mlxsw_env_linecard_is_active(struct mlxsw_env * mlxsw_env,u8 slot_index)39 static 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 
mlxsw_env_linecard_is_active(struct mlxsw_env * mlxsw_env,u8 slot_index)45 static 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 
57 static struct
mlxsw_env_module_info_get(struct mlxsw_core * mlxsw_core,u8 slot_index,u8 module)58 mlxsw_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 
__mlxsw_env_validate_module_type(struct mlxsw_core * core,u8 slot_index,u8 module)66 static 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 
mlxsw_env_validate_module_type(struct mlxsw_core * core,u8 slot_index,u8 module)88 static 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 
101 static int
mlxsw_env_validate_cable_ident(struct mlxsw_core * core,u8 slot_index,int id,bool * qsfp,bool * cmis)102 mlxsw_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 
144 static int
mlxsw_env_query_module_eeprom(struct mlxsw_core * mlxsw_core,u8 slot_index,int module,u16 offset,u16 size,void * data,bool qsfp,unsigned int * p_read_size)145 mlxsw_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 
209 int
mlxsw_env_module_temp_thresholds_get(struct mlxsw_core * core,u8 slot_index,int module,int off,int * temp)210 mlxsw_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 
mlxsw_env_get_module_info(struct net_device * netdev,struct mlxsw_core * mlxsw_core,u8 slot_index,int module,struct ethtool_modinfo * modinfo)291 int 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 }
384 EXPORT_SYMBOL(mlxsw_env_get_module_info);
385 
mlxsw_env_get_module_eeprom(struct net_device * netdev,struct mlxsw_core * mlxsw_core,u8 slot_index,int module,struct ethtool_eeprom * ee,u8 * data)386 int 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 }
429 EXPORT_SYMBOL(mlxsw_env_get_module_eeprom);
430 
mlxsw_env_mcia_status_process(const char * mcia_pl,struct netlink_ext_ack * extack)431 static 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 
460 int
mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core * mlxsw_core,u8 slot_index,u8 module,const struct ethtool_module_eeprom * page,struct netlink_ext_ack * extack)461 mlxsw_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 }
516 EXPORT_SYMBOL(mlxsw_env_get_module_eeprom_by_page);
517 
mlxsw_env_module_reset(struct mlxsw_core * mlxsw_core,u8 slot_index,u8 module)518 static 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 
mlxsw_env_reset_module(struct net_device * netdev,struct mlxsw_core * mlxsw_core,u8 slot_index,u8 module,u32 * flags)529 int 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 
577 out:
578 	mutex_unlock(&mlxsw_env->line_cards_lock);
579 	return err;
580 }
581 EXPORT_SYMBOL(mlxsw_env_reset_module);
582 
583 int
mlxsw_env_get_module_power_mode(struct mlxsw_core * mlxsw_core,u8 slot_index,u8 module,struct ethtool_module_power_mode_params * params,struct netlink_ext_ack * extack)584 mlxsw_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 
626 out:
627 	mutex_unlock(&mlxsw_env->line_cards_lock);
628 	return err;
629 }
630 EXPORT_SYMBOL(mlxsw_env_get_module_power_mode);
631 
mlxsw_env_module_enable_set(struct mlxsw_core * mlxsw_core,u8 slot_index,u8 module,bool enable)632 static 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 
mlxsw_env_module_low_power_set(struct mlxsw_core * mlxsw_core,u8 slot_index,u8 module,bool low_power)647 static 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 
__mlxsw_env_set_module_power_mode(struct mlxsw_core * mlxsw_core,u8 slot_index,u8 module,bool low_power,struct netlink_ext_ack * extack)666 static 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 
702 err_module_enable_set:
703 	mlxsw_env_module_low_power_set(mlxsw_core, slot_index, module,
704 				       !low_power);
705 err_module_low_power_set:
706 	mlxsw_env_module_enable_set(mlxsw_core, slot_index, module, true);
707 	return err;
708 }
709 
710 static int
mlxsw_env_set_module_power_mode_apply(struct mlxsw_core * mlxsw_core,u8 slot_index,u8 module,enum ethtool_module_power_mode_policy policy,struct netlink_ext_ack * extack)711 mlxsw_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 
741 out_set_policy:
742 	module_info->power_mode_policy = policy;
743 out:
744 	return err;
745 }
746 
747 int
mlxsw_env_set_module_power_mode(struct mlxsw_core * mlxsw_core,u8 slot_index,u8 module,enum ethtool_module_power_mode_policy policy,struct netlink_ext_ack * extack)748 mlxsw_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 }
769 EXPORT_SYMBOL(mlxsw_env_set_module_power_mode);
770 
mlxsw_env_module_has_temp_sensor(struct mlxsw_core * mlxsw_core,u8 slot_index,u8 module,bool * p_has_temp_sensor)771 static 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 
800 static int
mlxsw_env_temp_event_set(struct mlxsw_core * mlxsw_core,u8 slot_index,u16 sensor_index,bool enable)801 mlxsw_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 
mlxsw_env_module_temp_event_enable(struct mlxsw_core * mlxsw_core,u8 slot_index)843 static 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 
869 struct 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 
mlxsw_env_mtwe_event_work(struct work_struct * work)875 static 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 
927 static void
mlxsw_env_mtwe_listener_func(const struct mlxsw_reg_info * reg,char * mtwe_pl,void * priv)928 mlxsw_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 
944 static const struct mlxsw_listener mlxsw_env_temp_warn_listener =
945 	MLXSW_CORE_EVENTL(mlxsw_env_mtwe_listener_func, MTWE);
946 
mlxsw_env_temp_warn_event_register(struct mlxsw_core * mlxsw_core)947 static 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 
mlxsw_env_temp_warn_event_unregister(struct mlxsw_env * mlxsw_env)956 static 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 
962 struct 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 
mlxsw_env_pmpe_event_work(struct work_struct * work)969 static 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 
1006 out:
1007 	kfree(event);
1008 }
1009 
1010 static void
mlxsw_env_pmpe_listener_func(const struct mlxsw_reg_info * reg,char * pmpe_pl,void * priv)1011 mlxsw_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 
1039 static const struct mlxsw_listener mlxsw_env_module_plug_listener =
1040 	MLXSW_CORE_EVENTL(mlxsw_env_pmpe_listener_func, PMPE);
1041 
1042 static int
mlxsw_env_module_plug_event_register(struct mlxsw_core * mlxsw_core)1043 mlxsw_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 
1052 static void
mlxsw_env_module_plug_event_unregister(struct mlxsw_env * mlxsw_env)1053 mlxsw_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 
1060 static int
mlxsw_env_module_oper_state_event_enable(struct mlxsw_core * mlxsw_core,u8 slot_index)1061 mlxsw_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 
1081 int
mlxsw_env_module_overheat_counter_get(struct mlxsw_core * mlxsw_core,u8 slot_index,u8 module,u64 * p_counter)1082 mlxsw_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 }
1095 EXPORT_SYMBOL(mlxsw_env_module_overheat_counter_get);
1096 
mlxsw_env_module_port_map(struct mlxsw_core * mlxsw_core,u8 slot_index,u8 module)1097 void 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 }
1108 EXPORT_SYMBOL(mlxsw_env_module_port_map);
1109 
mlxsw_env_module_port_unmap(struct mlxsw_core * mlxsw_core,u8 slot_index,u8 module)1110 void 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 }
1121 EXPORT_SYMBOL(mlxsw_env_module_port_unmap);
1122 
mlxsw_env_module_port_up(struct mlxsw_core * mlxsw_core,u8 slot_index,u8 module)1123 int 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 
1148 out_inc:
1149 	module_info->num_ports_up++;
1150 out_unlock:
1151 	mutex_unlock(&mlxsw_env->line_cards_lock);
1152 	return err;
1153 }
1154 EXPORT_SYMBOL(mlxsw_env_module_port_up);
1155 
mlxsw_env_module_port_down(struct mlxsw_core * mlxsw_core,u8 slot_index,u8 module)1156 void 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 
1180 out_unlock:
1181 	mutex_unlock(&mlxsw_env->line_cards_lock);
1182 }
1183 EXPORT_SYMBOL(mlxsw_env_module_port_down);
1184 
mlxsw_env_line_cards_alloc(struct mlxsw_env * env)1185 static 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 
1210 kzalloc_err:
1211 	for (i--; i >= 0; i--)
1212 		kfree(env->line_cards[i]);
1213 	return -ENOMEM;
1214 }
1215 
mlxsw_env_line_cards_free(struct mlxsw_env * env)1216 static 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 
1224 static int
mlxsw_env_module_event_enable(struct mlxsw_env * mlxsw_env,u8 slot_index)1225 mlxsw_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 
1241 static void
mlxsw_env_module_event_disable(struct mlxsw_env * mlxsw_env,u8 slot_index)1242 mlxsw_env_module_event_disable(struct mlxsw_env *mlxsw_env, u8 slot_index)
1243 {
1244 }
1245 
1246 static int
mlxsw_env_module_type_set(struct mlxsw_core * mlxsw_core,u8 slot_index)1247 mlxsw_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 
1270 static void
mlxsw_env_linecard_modules_power_mode_apply(struct mlxsw_core * mlxsw_core,struct mlxsw_env * env,u8 slot_index)1271 mlxsw_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 
1293 static void
mlxsw_env_got_active(struct mlxsw_core * mlxsw_core,u8 slot_index,void * priv)1294 mlxsw_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 
1334 err_type_set:
1335 	mlxsw_env_module_event_disable(mlxsw_env, slot_index);
1336 err_mlxsw_env_module_event_enable:
1337 out_unlock:
1338 	mutex_unlock(&mlxsw_env->line_cards_lock);
1339 }
1340 
1341 static void
mlxsw_env_got_inactive(struct mlxsw_core * mlxsw_core,u8 slot_index,void * priv)1342 mlxsw_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;
1353 out_unlock:
1354 	mutex_unlock(&mlxsw_env->line_cards_lock);
1355 }
1356 
1357 static 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 
mlxsw_env_init(struct mlxsw_core * mlxsw_core,const struct mlxsw_bus_info * bus_info,struct mlxsw_env ** p_env)1362 int 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 
1434 err_type_set:
1435 	mlxsw_env_module_event_disable(env, 0);
1436 err_mlxsw_env_module_event_enable:
1437 	mlxsw_env_module_plug_event_unregister(env);
1438 err_module_plug_event_register:
1439 	mlxsw_env_temp_warn_event_unregister(env);
1440 err_temp_warn_event_register:
1441 	mlxsw_linecards_event_ops_unregister(env->core,
1442 					     &mlxsw_env_event_ops, env);
1443 err_linecards_event_ops_register:
1444 	mutex_destroy(&env->line_cards_lock);
1445 	mlxsw_env_line_cards_free(env);
1446 err_mlxsw_env_line_cards_alloc:
1447 	kfree(env);
1448 	return err;
1449 }
1450 
mlxsw_env_fini(struct mlxsw_env * env)1451 void 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 }
1465