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