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