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