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