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[];
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
mlxsw_env_module_reset(struct mlxsw_core * mlxsw_core,u8 slot_index,u8 module)516 static int mlxsw_env_module_reset(struct mlxsw_core *mlxsw_core, u8 slot_index,
517 u8 module)
518 {
519 char pmaos_pl[MLXSW_REG_PMAOS_LEN];
520
521 mlxsw_reg_pmaos_pack(pmaos_pl, slot_index, module);
522 mlxsw_reg_pmaos_rst_set(pmaos_pl, true);
523
524 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl);
525 }
526
mlxsw_env_reset_module(struct net_device * netdev,struct mlxsw_core * mlxsw_core,u8 slot_index,u8 module,u32 * flags)527 int mlxsw_env_reset_module(struct net_device *netdev,
528 struct mlxsw_core *mlxsw_core, u8 slot_index,
529 u8 module, u32 *flags)
530 {
531 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
532 struct mlxsw_env_module_info *module_info;
533 u32 req = *flags;
534 int err;
535
536 if (!(req & ETH_RESET_PHY) &&
537 !(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT)))
538 return 0;
539
540 if (!mlxsw_env_linecard_is_active(mlxsw_env, slot_index)) {
541 netdev_err(netdev, "Cannot reset module on an inactive line card\n");
542 return -EIO;
543 }
544
545 mutex_lock(&mlxsw_env->line_cards_lock);
546
547 err = __mlxsw_env_validate_module_type(mlxsw_core, slot_index, module);
548 if (err) {
549 netdev_err(netdev, "Reset module is not supported on port module type\n");
550 goto out;
551 }
552
553 module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
554 if (module_info->num_ports_up) {
555 netdev_err(netdev, "Cannot reset module when ports using it are administratively up\n");
556 err = -EINVAL;
557 goto out;
558 }
559
560 if (module_info->num_ports_mapped > 1 &&
561 !(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT))) {
562 netdev_err(netdev, "Cannot reset module without \"phy-shared\" flag when shared by multiple ports\n");
563 err = -EINVAL;
564 goto out;
565 }
566
567 err = mlxsw_env_module_reset(mlxsw_core, slot_index, module);
568 if (err) {
569 netdev_err(netdev, "Failed to reset module\n");
570 goto out;
571 }
572
573 *flags &= ~(ETH_RESET_PHY | (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT));
574
575 out:
576 mutex_unlock(&mlxsw_env->line_cards_lock);
577 return err;
578 }
579 EXPORT_SYMBOL(mlxsw_env_reset_module);
580
581 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)582 mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index,
583 u8 module,
584 struct ethtool_module_power_mode_params *params,
585 struct netlink_ext_ack *extack)
586 {
587 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
588 struct mlxsw_env_module_info *module_info;
589 char mcion_pl[MLXSW_REG_MCION_LEN];
590 u32 status_bits;
591 int err = 0;
592
593 mutex_lock(&mlxsw_env->line_cards_lock);
594
595 err = __mlxsw_env_validate_module_type(mlxsw_core, slot_index, module);
596 if (err) {
597 NL_SET_ERR_MSG_MOD(extack, "Power mode is not supported on port module type");
598 goto out;
599 }
600
601 module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
602 params->policy = module_info->power_mode_policy;
603
604 /* Avoid accessing an inactive line card, as it will result in an error. */
605 if (!__mlxsw_env_linecard_is_active(mlxsw_env, slot_index))
606 goto out;
607
608 mlxsw_reg_mcion_pack(mcion_pl, slot_index, module);
609 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcion), mcion_pl);
610 if (err) {
611 NL_SET_ERR_MSG_MOD(extack, "Failed to retrieve module's power mode");
612 goto out;
613 }
614
615 status_bits = mlxsw_reg_mcion_module_status_bits_get(mcion_pl);
616 if (!(status_bits & MLXSW_REG_MCION_MODULE_STATUS_BITS_PRESENT_MASK))
617 goto out;
618
619 if (status_bits & MLXSW_REG_MCION_MODULE_STATUS_BITS_LOW_POWER_MASK)
620 params->mode = ETHTOOL_MODULE_POWER_MODE_LOW;
621 else
622 params->mode = ETHTOOL_MODULE_POWER_MODE_HIGH;
623
624 out:
625 mutex_unlock(&mlxsw_env->line_cards_lock);
626 return err;
627 }
628 EXPORT_SYMBOL(mlxsw_env_get_module_power_mode);
629
mlxsw_env_module_enable_set(struct mlxsw_core * mlxsw_core,u8 slot_index,u8 module,bool enable)630 static int mlxsw_env_module_enable_set(struct mlxsw_core *mlxsw_core,
631 u8 slot_index, u8 module, bool enable)
632 {
633 enum mlxsw_reg_pmaos_admin_status admin_status;
634 char pmaos_pl[MLXSW_REG_PMAOS_LEN];
635
636 mlxsw_reg_pmaos_pack(pmaos_pl, slot_index, module);
637 admin_status = enable ? MLXSW_REG_PMAOS_ADMIN_STATUS_ENABLED :
638 MLXSW_REG_PMAOS_ADMIN_STATUS_DISABLED;
639 mlxsw_reg_pmaos_admin_status_set(pmaos_pl, admin_status);
640 mlxsw_reg_pmaos_ase_set(pmaos_pl, true);
641
642 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl);
643 }
644
mlxsw_env_module_low_power_set(struct mlxsw_core * mlxsw_core,u8 slot_index,u8 module,bool low_power)645 static int mlxsw_env_module_low_power_set(struct mlxsw_core *mlxsw_core,
646 u8 slot_index, u8 module,
647 bool low_power)
648 {
649 u16 eeprom_override_mask, eeprom_override;
650 char pmmp_pl[MLXSW_REG_PMMP_LEN];
651
652 mlxsw_reg_pmmp_pack(pmmp_pl, slot_index, module);
653 mlxsw_reg_pmmp_sticky_set(pmmp_pl, true);
654 /* Mask all the bits except low power mode. */
655 eeprom_override_mask = ~MLXSW_REG_PMMP_EEPROM_OVERRIDE_LOW_POWER_MASK;
656 mlxsw_reg_pmmp_eeprom_override_mask_set(pmmp_pl, eeprom_override_mask);
657 eeprom_override = low_power ? MLXSW_REG_PMMP_EEPROM_OVERRIDE_LOW_POWER_MASK :
658 0;
659 mlxsw_reg_pmmp_eeprom_override_set(pmmp_pl, eeprom_override);
660
661 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmmp), pmmp_pl);
662 }
663
__mlxsw_env_set_module_power_mode(struct mlxsw_core * mlxsw_core,u8 slot_index,u8 module,bool low_power,struct netlink_ext_ack * extack)664 static int __mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core,
665 u8 slot_index, u8 module,
666 bool low_power,
667 struct netlink_ext_ack *extack)
668 {
669 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
670 int err;
671
672 /* Avoid accessing an inactive line card, as it will result in an error.
673 * Cached configuration will be applied by mlxsw_env_got_active() when
674 * line card becomes active.
675 */
676 if (!__mlxsw_env_linecard_is_active(mlxsw_env, slot_index))
677 return 0;
678
679 err = mlxsw_env_module_enable_set(mlxsw_core, slot_index, module, false);
680 if (err) {
681 NL_SET_ERR_MSG_MOD(extack, "Failed to disable module");
682 return err;
683 }
684
685 err = mlxsw_env_module_low_power_set(mlxsw_core, slot_index, module,
686 low_power);
687 if (err) {
688 NL_SET_ERR_MSG_MOD(extack, "Failed to set module's power mode");
689 goto err_module_low_power_set;
690 }
691
692 err = mlxsw_env_module_enable_set(mlxsw_core, slot_index, module, true);
693 if (err) {
694 NL_SET_ERR_MSG_MOD(extack, "Failed to enable module");
695 goto err_module_enable_set;
696 }
697
698 return 0;
699
700 err_module_enable_set:
701 mlxsw_env_module_low_power_set(mlxsw_core, slot_index, module,
702 !low_power);
703 err_module_low_power_set:
704 mlxsw_env_module_enable_set(mlxsw_core, slot_index, module, true);
705 return err;
706 }
707
708 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)709 mlxsw_env_set_module_power_mode_apply(struct mlxsw_core *mlxsw_core,
710 u8 slot_index, u8 module,
711 enum ethtool_module_power_mode_policy policy,
712 struct netlink_ext_ack *extack)
713 {
714 struct mlxsw_env_module_info *module_info;
715 bool low_power;
716 int err = 0;
717
718 err = __mlxsw_env_validate_module_type(mlxsw_core, slot_index, module);
719 if (err) {
720 NL_SET_ERR_MSG_MOD(extack,
721 "Power mode set is not supported on port module type");
722 goto out;
723 }
724
725 module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
726 if (module_info->power_mode_policy == policy)
727 goto out;
728
729 /* If any ports are up, we are already in high power mode. */
730 if (module_info->num_ports_up)
731 goto out_set_policy;
732
733 low_power = policy == ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO;
734 err = __mlxsw_env_set_module_power_mode(mlxsw_core, slot_index, module,
735 low_power, extack);
736 if (err)
737 goto out;
738
739 out_set_policy:
740 module_info->power_mode_policy = policy;
741 out:
742 return err;
743 }
744
745 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)746 mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index,
747 u8 module,
748 enum ethtool_module_power_mode_policy policy,
749 struct netlink_ext_ack *extack)
750 {
751 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
752 int err;
753
754 if (policy != ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH &&
755 policy != ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO) {
756 NL_SET_ERR_MSG_MOD(extack, "Unsupported power mode policy");
757 return -EOPNOTSUPP;
758 }
759
760 mutex_lock(&mlxsw_env->line_cards_lock);
761 err = mlxsw_env_set_module_power_mode_apply(mlxsw_core, slot_index,
762 module, policy, extack);
763 mutex_unlock(&mlxsw_env->line_cards_lock);
764
765 return err;
766 }
767 EXPORT_SYMBOL(mlxsw_env_set_module_power_mode);
768
mlxsw_env_module_has_temp_sensor(struct mlxsw_core * mlxsw_core,u8 slot_index,u8 module,bool * p_has_temp_sensor)769 static int mlxsw_env_module_has_temp_sensor(struct mlxsw_core *mlxsw_core,
770 u8 slot_index, u8 module,
771 bool *p_has_temp_sensor)
772 {
773 char mtbr_pl[MLXSW_REG_MTBR_LEN];
774 u16 temp;
775 int err;
776
777 mlxsw_reg_mtbr_pack(mtbr_pl, slot_index,
778 MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, 1);
779 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mtbr), mtbr_pl);
780 if (err)
781 return err;
782
783 mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL);
784
785 switch (temp) {
786 case MLXSW_REG_MTBR_BAD_SENS_INFO:
787 case MLXSW_REG_MTBR_NO_CONN:
788 case MLXSW_REG_MTBR_NO_TEMP_SENS:
789 case MLXSW_REG_MTBR_INDEX_NA:
790 *p_has_temp_sensor = false;
791 break;
792 default:
793 *p_has_temp_sensor = temp ? true : false;
794 }
795 return 0;
796 }
797
798 static int
mlxsw_env_temp_event_set(struct mlxsw_core * mlxsw_core,u8 slot_index,u16 sensor_index,bool enable)799 mlxsw_env_temp_event_set(struct mlxsw_core *mlxsw_core, u8 slot_index,
800 u16 sensor_index, bool enable)
801 {
802 char mtmp_pl[MLXSW_REG_MTMP_LEN] = {0};
803 enum mlxsw_reg_mtmp_tee tee;
804 int err, threshold_hi;
805
806 mlxsw_reg_mtmp_slot_index_set(mtmp_pl, slot_index);
807 mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, sensor_index);
808 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mtmp), mtmp_pl);
809 if (err)
810 return err;
811
812 if (enable) {
813 err = mlxsw_env_module_temp_thresholds_get(mlxsw_core,
814 slot_index,
815 sensor_index -
816 MLXSW_REG_MTMP_MODULE_INDEX_MIN,
817 SFP_TEMP_HIGH_WARN,
818 &threshold_hi);
819 /* In case it is not possible to query the module's threshold,
820 * use the default value.
821 */
822 if (err)
823 threshold_hi = MLXSW_REG_MTMP_THRESH_HI;
824 else
825 /* mlxsw_env_module_temp_thresholds_get() multiplies
826 * Celsius degrees by 1000 whereas MTMP expects
827 * temperature in 0.125 Celsius degrees units.
828 * Convert threshold_hi to correct units.
829 */
830 threshold_hi = threshold_hi / 1000 * 8;
831
832 mlxsw_reg_mtmp_temperature_threshold_hi_set(mtmp_pl, threshold_hi);
833 mlxsw_reg_mtmp_temperature_threshold_lo_set(mtmp_pl, threshold_hi -
834 MLXSW_REG_MTMP_HYSTERESIS_TEMP);
835 }
836 tee = enable ? MLXSW_REG_MTMP_TEE_GENERATE_EVENT : MLXSW_REG_MTMP_TEE_NO_EVENT;
837 mlxsw_reg_mtmp_tee_set(mtmp_pl, tee);
838 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mtmp), mtmp_pl);
839 }
840
mlxsw_env_module_temp_event_enable(struct mlxsw_core * mlxsw_core,u8 slot_index)841 static int mlxsw_env_module_temp_event_enable(struct mlxsw_core *mlxsw_core,
842 u8 slot_index)
843 {
844 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
845 int i, err, sensor_index;
846 bool has_temp_sensor;
847
848 for (i = 0; i < mlxsw_env->line_cards[slot_index]->module_count; i++) {
849 err = mlxsw_env_module_has_temp_sensor(mlxsw_core, slot_index,
850 i, &has_temp_sensor);
851 if (err)
852 return err;
853
854 if (!has_temp_sensor)
855 continue;
856
857 sensor_index = i + MLXSW_REG_MTMP_MODULE_INDEX_MIN;
858 err = mlxsw_env_temp_event_set(mlxsw_core, slot_index,
859 sensor_index, true);
860 if (err)
861 return err;
862 }
863
864 return 0;
865 }
866
867 struct mlxsw_env_module_temp_warn_event {
868 struct mlxsw_env *mlxsw_env;
869 char mtwe_pl[MLXSW_REG_MTWE_LEN];
870 struct work_struct work;
871 };
872
mlxsw_env_mtwe_event_work(struct work_struct * work)873 static void mlxsw_env_mtwe_event_work(struct work_struct *work)
874 {
875 struct mlxsw_env_module_temp_warn_event *event;
876 struct mlxsw_env_module_info *module_info;
877 struct mlxsw_env *mlxsw_env;
878 int i, sensor_warning;
879 bool is_overheat;
880
881 event = container_of(work, struct mlxsw_env_module_temp_warn_event,
882 work);
883 mlxsw_env = event->mlxsw_env;
884
885 for (i = 0; i < mlxsw_env->max_module_count; i++) {
886 /* 64-127 of sensor_index are mapped to the port modules
887 * sequentially (module 0 is mapped to sensor_index 64,
888 * module 1 to sensor_index 65 and so on)
889 */
890 sensor_warning =
891 mlxsw_reg_mtwe_sensor_warning_get(event->mtwe_pl,
892 i + MLXSW_REG_MTMP_MODULE_INDEX_MIN);
893 mutex_lock(&mlxsw_env->line_cards_lock);
894 /* MTWE only supports main board. */
895 module_info = mlxsw_env_module_info_get(mlxsw_env->core, 0, i);
896 is_overheat = module_info->is_overheat;
897
898 if ((is_overheat && sensor_warning) ||
899 (!is_overheat && !sensor_warning)) {
900 /* Current state is "warning" and MTWE still reports
901 * warning OR current state in "no warning" and MTWE
902 * does not report warning.
903 */
904 mutex_unlock(&mlxsw_env->line_cards_lock);
905 continue;
906 } else if (is_overheat && !sensor_warning) {
907 /* MTWE reports "no warning", turn is_overheat off.
908 */
909 module_info->is_overheat = false;
910 mutex_unlock(&mlxsw_env->line_cards_lock);
911 } else {
912 /* Current state is "no warning" and MTWE reports
913 * "warning", increase the counter and turn is_overheat
914 * on.
915 */
916 module_info->is_overheat = true;
917 module_info->module_overheat_counter++;
918 mutex_unlock(&mlxsw_env->line_cards_lock);
919 }
920 }
921
922 kfree(event);
923 }
924
925 static void
mlxsw_env_mtwe_listener_func(const struct mlxsw_reg_info * reg,char * mtwe_pl,void * priv)926 mlxsw_env_mtwe_listener_func(const struct mlxsw_reg_info *reg, char *mtwe_pl,
927 void *priv)
928 {
929 struct mlxsw_env_module_temp_warn_event *event;
930 struct mlxsw_env *mlxsw_env = priv;
931
932 event = kmalloc(sizeof(*event), GFP_ATOMIC);
933 if (!event)
934 return;
935
936 event->mlxsw_env = mlxsw_env;
937 memcpy(event->mtwe_pl, mtwe_pl, MLXSW_REG_MTWE_LEN);
938 INIT_WORK(&event->work, mlxsw_env_mtwe_event_work);
939 mlxsw_core_schedule_work(&event->work);
940 }
941
942 static const struct mlxsw_listener mlxsw_env_temp_warn_listener =
943 MLXSW_CORE_EVENTL(mlxsw_env_mtwe_listener_func, MTWE);
944
mlxsw_env_temp_warn_event_register(struct mlxsw_core * mlxsw_core)945 static int mlxsw_env_temp_warn_event_register(struct mlxsw_core *mlxsw_core)
946 {
947 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
948
949 return mlxsw_core_trap_register(mlxsw_core,
950 &mlxsw_env_temp_warn_listener,
951 mlxsw_env);
952 }
953
mlxsw_env_temp_warn_event_unregister(struct mlxsw_env * mlxsw_env)954 static void mlxsw_env_temp_warn_event_unregister(struct mlxsw_env *mlxsw_env)
955 {
956 mlxsw_core_trap_unregister(mlxsw_env->core,
957 &mlxsw_env_temp_warn_listener, mlxsw_env);
958 }
959
960 struct mlxsw_env_module_plug_unplug_event {
961 struct mlxsw_env *mlxsw_env;
962 u8 slot_index;
963 u8 module;
964 struct work_struct work;
965 };
966
mlxsw_env_pmpe_event_work(struct work_struct * work)967 static void mlxsw_env_pmpe_event_work(struct work_struct *work)
968 {
969 struct mlxsw_env_module_plug_unplug_event *event;
970 struct mlxsw_env_module_info *module_info;
971 struct mlxsw_env *mlxsw_env;
972 bool has_temp_sensor;
973 u16 sensor_index;
974 int err;
975
976 event = container_of(work, struct mlxsw_env_module_plug_unplug_event,
977 work);
978 mlxsw_env = event->mlxsw_env;
979
980 mutex_lock(&mlxsw_env->line_cards_lock);
981 module_info = mlxsw_env_module_info_get(mlxsw_env->core,
982 event->slot_index,
983 event->module);
984 module_info->is_overheat = false;
985 mutex_unlock(&mlxsw_env->line_cards_lock);
986
987 err = mlxsw_env_module_has_temp_sensor(mlxsw_env->core,
988 event->slot_index,
989 event->module,
990 &has_temp_sensor);
991 /* Do not disable events on modules without sensors or faulty sensors
992 * because FW returns errors.
993 */
994 if (err)
995 goto out;
996
997 if (!has_temp_sensor)
998 goto out;
999
1000 sensor_index = event->module + MLXSW_REG_MTMP_MODULE_INDEX_MIN;
1001 mlxsw_env_temp_event_set(mlxsw_env->core, event->slot_index,
1002 sensor_index, true);
1003
1004 out:
1005 kfree(event);
1006 }
1007
1008 static void
mlxsw_env_pmpe_listener_func(const struct mlxsw_reg_info * reg,char * pmpe_pl,void * priv)1009 mlxsw_env_pmpe_listener_func(const struct mlxsw_reg_info *reg, char *pmpe_pl,
1010 void *priv)
1011 {
1012 u8 slot_index = mlxsw_reg_pmpe_slot_index_get(pmpe_pl);
1013 struct mlxsw_env_module_plug_unplug_event *event;
1014 enum mlxsw_reg_pmpe_module_status module_status;
1015 u8 module = mlxsw_reg_pmpe_module_get(pmpe_pl);
1016 struct mlxsw_env *mlxsw_env = priv;
1017
1018 if (WARN_ON_ONCE(module >= mlxsw_env->max_module_count ||
1019 slot_index >= mlxsw_env->num_of_slots))
1020 return;
1021
1022 module_status = mlxsw_reg_pmpe_module_status_get(pmpe_pl);
1023 if (module_status != MLXSW_REG_PMPE_MODULE_STATUS_PLUGGED_ENABLED)
1024 return;
1025
1026 event = kmalloc(sizeof(*event), GFP_ATOMIC);
1027 if (!event)
1028 return;
1029
1030 event->mlxsw_env = mlxsw_env;
1031 event->slot_index = slot_index;
1032 event->module = module;
1033 INIT_WORK(&event->work, mlxsw_env_pmpe_event_work);
1034 mlxsw_core_schedule_work(&event->work);
1035 }
1036
1037 static const struct mlxsw_listener mlxsw_env_module_plug_listener =
1038 MLXSW_CORE_EVENTL(mlxsw_env_pmpe_listener_func, PMPE);
1039
1040 static int
mlxsw_env_module_plug_event_register(struct mlxsw_core * mlxsw_core)1041 mlxsw_env_module_plug_event_register(struct mlxsw_core *mlxsw_core)
1042 {
1043 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
1044
1045 return mlxsw_core_trap_register(mlxsw_core,
1046 &mlxsw_env_module_plug_listener,
1047 mlxsw_env);
1048 }
1049
1050 static void
mlxsw_env_module_plug_event_unregister(struct mlxsw_env * mlxsw_env)1051 mlxsw_env_module_plug_event_unregister(struct mlxsw_env *mlxsw_env)
1052 {
1053 mlxsw_core_trap_unregister(mlxsw_env->core,
1054 &mlxsw_env_module_plug_listener,
1055 mlxsw_env);
1056 }
1057
1058 static int
mlxsw_env_module_oper_state_event_enable(struct mlxsw_core * mlxsw_core,u8 slot_index)1059 mlxsw_env_module_oper_state_event_enable(struct mlxsw_core *mlxsw_core,
1060 u8 slot_index)
1061 {
1062 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
1063 int i, err;
1064
1065 for (i = 0; i < mlxsw_env->line_cards[slot_index]->module_count; i++) {
1066 char pmaos_pl[MLXSW_REG_PMAOS_LEN];
1067
1068 mlxsw_reg_pmaos_pack(pmaos_pl, slot_index, i);
1069 mlxsw_reg_pmaos_e_set(pmaos_pl,
1070 MLXSW_REG_PMAOS_E_GENERATE_EVENT);
1071 mlxsw_reg_pmaos_ee_set(pmaos_pl, true);
1072 err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl);
1073 if (err)
1074 return err;
1075 }
1076 return 0;
1077 }
1078
1079 int
mlxsw_env_module_overheat_counter_get(struct mlxsw_core * mlxsw_core,u8 slot_index,u8 module,u64 * p_counter)1080 mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 slot_index,
1081 u8 module, u64 *p_counter)
1082 {
1083 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
1084 struct mlxsw_env_module_info *module_info;
1085
1086 mutex_lock(&mlxsw_env->line_cards_lock);
1087 module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
1088 *p_counter = module_info->module_overheat_counter;
1089 mutex_unlock(&mlxsw_env->line_cards_lock);
1090
1091 return 0;
1092 }
1093 EXPORT_SYMBOL(mlxsw_env_module_overheat_counter_get);
1094
mlxsw_env_module_port_map(struct mlxsw_core * mlxsw_core,u8 slot_index,u8 module)1095 void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 slot_index,
1096 u8 module)
1097 {
1098 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
1099 struct mlxsw_env_module_info *module_info;
1100
1101 mutex_lock(&mlxsw_env->line_cards_lock);
1102 module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
1103 module_info->num_ports_mapped++;
1104 mutex_unlock(&mlxsw_env->line_cards_lock);
1105 }
1106 EXPORT_SYMBOL(mlxsw_env_module_port_map);
1107
mlxsw_env_module_port_unmap(struct mlxsw_core * mlxsw_core,u8 slot_index,u8 module)1108 void mlxsw_env_module_port_unmap(struct mlxsw_core *mlxsw_core, u8 slot_index,
1109 u8 module)
1110 {
1111 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
1112 struct mlxsw_env_module_info *module_info;
1113
1114 mutex_lock(&mlxsw_env->line_cards_lock);
1115 module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
1116 module_info->num_ports_mapped--;
1117 mutex_unlock(&mlxsw_env->line_cards_lock);
1118 }
1119 EXPORT_SYMBOL(mlxsw_env_module_port_unmap);
1120
mlxsw_env_module_port_up(struct mlxsw_core * mlxsw_core,u8 slot_index,u8 module)1121 int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 slot_index,
1122 u8 module)
1123 {
1124 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
1125 struct mlxsw_env_module_info *module_info;
1126 int err = 0;
1127
1128 mutex_lock(&mlxsw_env->line_cards_lock);
1129
1130 module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
1131 if (module_info->power_mode_policy !=
1132 ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO)
1133 goto out_inc;
1134
1135 if (module_info->num_ports_up != 0)
1136 goto out_inc;
1137
1138 /* Transition to high power mode following first port using the module
1139 * being put administratively up.
1140 */
1141 err = __mlxsw_env_set_module_power_mode(mlxsw_core, slot_index, module,
1142 false, NULL);
1143 if (err)
1144 goto out_unlock;
1145
1146 out_inc:
1147 module_info->num_ports_up++;
1148 out_unlock:
1149 mutex_unlock(&mlxsw_env->line_cards_lock);
1150 return err;
1151 }
1152 EXPORT_SYMBOL(mlxsw_env_module_port_up);
1153
mlxsw_env_module_port_down(struct mlxsw_core * mlxsw_core,u8 slot_index,u8 module)1154 void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 slot_index,
1155 u8 module)
1156 {
1157 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
1158 struct mlxsw_env_module_info *module_info;
1159
1160 mutex_lock(&mlxsw_env->line_cards_lock);
1161
1162 module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
1163 module_info->num_ports_up--;
1164
1165 if (module_info->power_mode_policy !=
1166 ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO)
1167 goto out_unlock;
1168
1169 if (module_info->num_ports_up != 0)
1170 goto out_unlock;
1171
1172 /* Transition to low power mode following last port using the module
1173 * being put administratively down.
1174 */
1175 __mlxsw_env_set_module_power_mode(mlxsw_core, slot_index, module, true,
1176 NULL);
1177
1178 out_unlock:
1179 mutex_unlock(&mlxsw_env->line_cards_lock);
1180 }
1181 EXPORT_SYMBOL(mlxsw_env_module_port_down);
1182
mlxsw_env_line_cards_alloc(struct mlxsw_env * env)1183 static int mlxsw_env_line_cards_alloc(struct mlxsw_env *env)
1184 {
1185 struct mlxsw_env_module_info *module_info;
1186 int i, j;
1187
1188 for (i = 0; i < env->num_of_slots; i++) {
1189 env->line_cards[i] = kzalloc(struct_size(env->line_cards[i],
1190 module_info,
1191 env->max_module_count),
1192 GFP_KERNEL);
1193 if (!env->line_cards[i])
1194 goto kzalloc_err;
1195
1196 /* Firmware defaults to high power mode policy where modules
1197 * are transitioned to high power mode following plug-in.
1198 */
1199 for (j = 0; j < env->max_module_count; j++) {
1200 module_info = &env->line_cards[i]->module_info[j];
1201 module_info->power_mode_policy =
1202 ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH;
1203 }
1204 }
1205
1206 return 0;
1207
1208 kzalloc_err:
1209 for (i--; i >= 0; i--)
1210 kfree(env->line_cards[i]);
1211 return -ENOMEM;
1212 }
1213
mlxsw_env_line_cards_free(struct mlxsw_env * env)1214 static void mlxsw_env_line_cards_free(struct mlxsw_env *env)
1215 {
1216 int i = env->num_of_slots;
1217
1218 for (i--; i >= 0; i--)
1219 kfree(env->line_cards[i]);
1220 }
1221
1222 static int
mlxsw_env_module_event_enable(struct mlxsw_env * mlxsw_env,u8 slot_index)1223 mlxsw_env_module_event_enable(struct mlxsw_env *mlxsw_env, u8 slot_index)
1224 {
1225 int err;
1226
1227 err = mlxsw_env_module_oper_state_event_enable(mlxsw_env->core,
1228 slot_index);
1229 if (err)
1230 return err;
1231
1232 err = mlxsw_env_module_temp_event_enable(mlxsw_env->core, slot_index);
1233 if (err)
1234 return err;
1235
1236 return 0;
1237 }
1238
1239 static void
mlxsw_env_module_event_disable(struct mlxsw_env * mlxsw_env,u8 slot_index)1240 mlxsw_env_module_event_disable(struct mlxsw_env *mlxsw_env, u8 slot_index)
1241 {
1242 }
1243
1244 static int
mlxsw_env_module_type_set(struct mlxsw_core * mlxsw_core,u8 slot_index)1245 mlxsw_env_module_type_set(struct mlxsw_core *mlxsw_core, u8 slot_index)
1246 {
1247 struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
1248 int i;
1249
1250 for (i = 0; i < mlxsw_env->line_cards[slot_index]->module_count; i++) {
1251 struct mlxsw_env_module_info *module_info;
1252 char pmtm_pl[MLXSW_REG_PMTM_LEN];
1253 int err;
1254
1255 mlxsw_reg_pmtm_pack(pmtm_pl, slot_index, i);
1256 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(pmtm), pmtm_pl);
1257 if (err)
1258 return err;
1259
1260 module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index,
1261 i);
1262 module_info->type = mlxsw_reg_pmtm_module_type_get(pmtm_pl);
1263 }
1264
1265 return 0;
1266 }
1267
1268 static void
mlxsw_env_linecard_modules_power_mode_apply(struct mlxsw_core * mlxsw_core,struct mlxsw_env * env,u8 slot_index)1269 mlxsw_env_linecard_modules_power_mode_apply(struct mlxsw_core *mlxsw_core,
1270 struct mlxsw_env *env,
1271 u8 slot_index)
1272 {
1273 int i;
1274
1275 for (i = 0; i < env->line_cards[slot_index]->module_count; i++) {
1276 enum ethtool_module_power_mode_policy policy;
1277 struct mlxsw_env_module_info *module_info;
1278 struct netlink_ext_ack extack;
1279 int err;
1280
1281 module_info = &env->line_cards[slot_index]->module_info[i];
1282 policy = module_info->power_mode_policy;
1283 err = mlxsw_env_set_module_power_mode_apply(mlxsw_core,
1284 slot_index, i,
1285 policy, &extack);
1286 if (err)
1287 dev_err(env->bus_info->dev, "%s\n", extack._msg);
1288 }
1289 }
1290
1291 static void
mlxsw_env_got_active(struct mlxsw_core * mlxsw_core,u8 slot_index,void * priv)1292 mlxsw_env_got_active(struct mlxsw_core *mlxsw_core, u8 slot_index, void *priv)
1293 {
1294 struct mlxsw_env *mlxsw_env = priv;
1295 char mgpir_pl[MLXSW_REG_MGPIR_LEN];
1296 int err;
1297
1298 mutex_lock(&mlxsw_env->line_cards_lock);
1299 if (__mlxsw_env_linecard_is_active(mlxsw_env, slot_index))
1300 goto out_unlock;
1301
1302 mlxsw_reg_mgpir_pack(mgpir_pl, slot_index);
1303 err = mlxsw_reg_query(mlxsw_env->core, MLXSW_REG(mgpir), mgpir_pl);
1304 if (err)
1305 goto out_unlock;
1306
1307 mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL,
1308 &mlxsw_env->line_cards[slot_index]->module_count,
1309 NULL);
1310
1311 err = mlxsw_env_module_event_enable(mlxsw_env, slot_index);
1312 if (err) {
1313 dev_err(mlxsw_env->bus_info->dev, "Failed to enable port module events for line card in slot %d\n",
1314 slot_index);
1315 goto err_mlxsw_env_module_event_enable;
1316 }
1317 err = mlxsw_env_module_type_set(mlxsw_env->core, slot_index);
1318 if (err) {
1319 dev_err(mlxsw_env->bus_info->dev, "Failed to set modules' type for line card in slot %d\n",
1320 slot_index);
1321 goto err_type_set;
1322 }
1323
1324 mlxsw_env->line_cards[slot_index]->active = true;
1325 /* Apply power mode policy. */
1326 mlxsw_env_linecard_modules_power_mode_apply(mlxsw_core, mlxsw_env,
1327 slot_index);
1328 mutex_unlock(&mlxsw_env->line_cards_lock);
1329
1330 return;
1331
1332 err_type_set:
1333 mlxsw_env_module_event_disable(mlxsw_env, slot_index);
1334 err_mlxsw_env_module_event_enable:
1335 out_unlock:
1336 mutex_unlock(&mlxsw_env->line_cards_lock);
1337 }
1338
1339 static void
mlxsw_env_got_inactive(struct mlxsw_core * mlxsw_core,u8 slot_index,void * priv)1340 mlxsw_env_got_inactive(struct mlxsw_core *mlxsw_core, u8 slot_index,
1341 void *priv)
1342 {
1343 struct mlxsw_env *mlxsw_env = priv;
1344
1345 mutex_lock(&mlxsw_env->line_cards_lock);
1346 if (!__mlxsw_env_linecard_is_active(mlxsw_env, slot_index))
1347 goto out_unlock;
1348 mlxsw_env->line_cards[slot_index]->active = false;
1349 mlxsw_env_module_event_disable(mlxsw_env, slot_index);
1350 mlxsw_env->line_cards[slot_index]->module_count = 0;
1351 out_unlock:
1352 mutex_unlock(&mlxsw_env->line_cards_lock);
1353 }
1354
1355 static struct mlxsw_linecards_event_ops mlxsw_env_event_ops = {
1356 .got_active = mlxsw_env_got_active,
1357 .got_inactive = mlxsw_env_got_inactive,
1358 };
1359
mlxsw_env_max_module_eeprom_len_query(struct mlxsw_env * mlxsw_env)1360 static int mlxsw_env_max_module_eeprom_len_query(struct mlxsw_env *mlxsw_env)
1361 {
1362 char mcam_pl[MLXSW_REG_MCAM_LEN];
1363 bool mcia_128b_supported;
1364 int err;
1365
1366 mlxsw_reg_mcam_pack(mcam_pl,
1367 MLXSW_REG_MCAM_FEATURE_GROUP_ENHANCED_FEATURES);
1368 err = mlxsw_reg_query(mlxsw_env->core, MLXSW_REG(mcam), mcam_pl);
1369 if (err)
1370 return err;
1371
1372 mlxsw_reg_mcam_unpack(mcam_pl, MLXSW_REG_MCAM_MCIA_128B,
1373 &mcia_128b_supported);
1374
1375 mlxsw_env->max_eeprom_len = mcia_128b_supported ? 128 : 48;
1376
1377 return 0;
1378 }
1379
mlxsw_env_init(struct mlxsw_core * mlxsw_core,const struct mlxsw_bus_info * bus_info,struct mlxsw_env ** p_env)1380 int mlxsw_env_init(struct mlxsw_core *mlxsw_core,
1381 const struct mlxsw_bus_info *bus_info,
1382 struct mlxsw_env **p_env)
1383 {
1384 u8 module_count, num_of_slots, max_module_count;
1385 char mgpir_pl[MLXSW_REG_MGPIR_LEN];
1386 struct mlxsw_env *env;
1387 int err;
1388
1389 mlxsw_reg_mgpir_pack(mgpir_pl, 0);
1390 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mgpir), mgpir_pl);
1391 if (err)
1392 return err;
1393
1394 mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, &module_count,
1395 &num_of_slots);
1396 /* If the system is modular, get the maximum number of modules per-slot.
1397 * Otherwise, get the maximum number of modules on the main board.
1398 */
1399 max_module_count = num_of_slots ?
1400 mlxsw_reg_mgpir_max_modules_per_slot_get(mgpir_pl) :
1401 module_count;
1402
1403 env = kzalloc(struct_size(env, line_cards, num_of_slots + 1),
1404 GFP_KERNEL);
1405 if (!env)
1406 return -ENOMEM;
1407
1408 env->core = mlxsw_core;
1409 env->bus_info = bus_info;
1410 env->num_of_slots = num_of_slots + 1;
1411 env->max_module_count = max_module_count;
1412 err = mlxsw_env_line_cards_alloc(env);
1413 if (err)
1414 goto err_mlxsw_env_line_cards_alloc;
1415
1416 mutex_init(&env->line_cards_lock);
1417 *p_env = env;
1418
1419 err = mlxsw_linecards_event_ops_register(env->core,
1420 &mlxsw_env_event_ops, env);
1421 if (err)
1422 goto err_linecards_event_ops_register;
1423
1424 err = mlxsw_env_temp_warn_event_register(mlxsw_core);
1425 if (err)
1426 goto err_temp_warn_event_register;
1427
1428 err = mlxsw_env_module_plug_event_register(mlxsw_core);
1429 if (err)
1430 goto err_module_plug_event_register;
1431
1432 /* Set 'module_count' only for main board. Actual count for line card
1433 * is to be set after line card is activated.
1434 */
1435 env->line_cards[0]->module_count = num_of_slots ? 0 : module_count;
1436 /* Enable events only for main board. Line card events are to be
1437 * configured only after line card is activated. Before that, access to
1438 * modules on line cards is not allowed.
1439 */
1440 err = mlxsw_env_module_event_enable(env, 0);
1441 if (err)
1442 goto err_mlxsw_env_module_event_enable;
1443
1444 err = mlxsw_env_module_type_set(mlxsw_core, 0);
1445 if (err)
1446 goto err_type_set;
1447
1448 err = mlxsw_env_max_module_eeprom_len_query(env);
1449 if (err)
1450 goto err_eeprom_len_query;
1451
1452 env->line_cards[0]->active = true;
1453
1454 return 0;
1455
1456 err_eeprom_len_query:
1457 err_type_set:
1458 mlxsw_env_module_event_disable(env, 0);
1459 err_mlxsw_env_module_event_enable:
1460 mlxsw_env_module_plug_event_unregister(env);
1461 err_module_plug_event_register:
1462 mlxsw_env_temp_warn_event_unregister(env);
1463 err_temp_warn_event_register:
1464 mlxsw_linecards_event_ops_unregister(env->core,
1465 &mlxsw_env_event_ops, env);
1466 err_linecards_event_ops_register:
1467 mutex_destroy(&env->line_cards_lock);
1468 mlxsw_env_line_cards_free(env);
1469 err_mlxsw_env_line_cards_alloc:
1470 kfree(env);
1471 return err;
1472 }
1473
mlxsw_env_fini(struct mlxsw_env * env)1474 void mlxsw_env_fini(struct mlxsw_env *env)
1475 {
1476 env->line_cards[0]->active = false;
1477 mlxsw_env_module_event_disable(env, 0);
1478 mlxsw_env_module_plug_event_unregister(env);
1479 /* Make sure there is no more event work scheduled. */
1480 mlxsw_core_flush_owq();
1481 mlxsw_env_temp_warn_event_unregister(env);
1482 mlxsw_linecards_event_ops_unregister(env->core,
1483 &mlxsw_env_event_ops, env);
1484 mutex_destroy(&env->line_cards_lock);
1485 mlxsw_env_line_cards_free(env);
1486 kfree(env);
1487 }
1488