5a9c98b94b33a00d7af216fadd702ed022b568d0
[platform/kernel/linux-starfive.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 {
25         struct mlxsw_core *core;
26         u8 module_count;
27         struct mutex module_info_lock; /* Protects 'module_info'. */
28         struct mlxsw_env_module_info module_info[];
29 };
30
31 static int mlxsw_env_validate_cable_ident(struct mlxsw_core *core, int id,
32                                           bool *qsfp, bool *cmis)
33 {
34         char mcia_pl[MLXSW_REG_MCIA_LEN];
35         char *eeprom_tmp;
36         u8 ident;
37         int err;
38
39         mlxsw_reg_mcia_pack(mcia_pl, id, 0, MLXSW_REG_MCIA_PAGE0_LO_OFF, 0, 1,
40                             MLXSW_REG_MCIA_I2C_ADDR_LOW);
41         err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl);
42         if (err)
43                 return err;
44         eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl);
45         ident = eeprom_tmp[0];
46         *cmis = false;
47         switch (ident) {
48         case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP:
49                 *qsfp = false;
50                 break;
51         case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP:
52         case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS:
53         case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28:
54                 *qsfp = true;
55                 break;
56         case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_DD:
57                 *qsfp = true;
58                 *cmis = true;
59                 break;
60         default:
61                 return -EINVAL;
62         }
63
64         return 0;
65 }
66
67 static int
68 mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module,
69                               u16 offset, u16 size, void *data,
70                               bool qsfp, unsigned int *p_read_size)
71 {
72         char mcia_pl[MLXSW_REG_MCIA_LEN];
73         char *eeprom_tmp;
74         u16 i2c_addr;
75         u8 page = 0;
76         int status;
77         int err;
78
79         /* MCIA register accepts buffer size <= 48. Page of size 128 should be
80          * read by chunks of size 48, 48, 32. Align the size of the last chunk
81          * to avoid reading after the end of the page.
82          */
83         size = min_t(u16, size, MLXSW_REG_MCIA_EEPROM_SIZE);
84
85         if (offset < MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH &&
86             offset + size > MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH)
87                 /* Cross pages read, read until offset 256 in low page */
88                 size = MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH - offset;
89
90         i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_LOW;
91         if (offset >= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) {
92                 if (qsfp) {
93                         /* When reading upper pages 1, 2 and 3 the offset
94                          * starts at 128. Please refer to "QSFP+ Memory Map"
95                          * figure in SFF-8436 specification and to "CMIS Module
96                          * Memory Map" figure in CMIS specification for
97                          * graphical depiction.
98                          */
99                         page = MLXSW_REG_MCIA_PAGE_GET(offset);
100                         offset -= MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH * page;
101                         if (offset + size > MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH)
102                                 size = MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH - offset;
103                 } else {
104                         /* When reading upper pages 1, 2 and 3 the offset
105                          * starts at 0 and I2C high address is used. Please refer
106                          * refer to "Memory Organization" figure in SFF-8472
107                          * specification for graphical depiction.
108                          */
109                         i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_HIGH;
110                         offset -= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH;
111                 }
112         }
113
114         mlxsw_reg_mcia_pack(mcia_pl, module, 0, page, offset, size, i2c_addr);
115
116         err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl);
117         if (err)
118                 return err;
119
120         status = mlxsw_reg_mcia_status_get(mcia_pl);
121         if (status)
122                 return -EIO;
123
124         eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl);
125         memcpy(data, eeprom_tmp, size);
126         *p_read_size = size;
127
128         return 0;
129 }
130
131 int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module,
132                                          int off, int *temp)
133 {
134         unsigned int module_temp, module_crit, module_emerg;
135         union {
136                 u8 buf[MLXSW_REG_MCIA_TH_ITEM_SIZE];
137                 u16 temp;
138         } temp_thresh;
139         char mcia_pl[MLXSW_REG_MCIA_LEN] = {0};
140         char mtmp_pl[MLXSW_REG_MTMP_LEN];
141         char *eeprom_tmp;
142         bool qsfp, cmis;
143         int page;
144         int err;
145
146         mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTMP_MODULE_INDEX_MIN + module,
147                             false, false);
148         err = mlxsw_reg_query(core, MLXSW_REG(mtmp), mtmp_pl);
149         if (err)
150                 return err;
151         mlxsw_reg_mtmp_unpack(mtmp_pl, &module_temp, NULL, &module_crit,
152                               &module_emerg, NULL);
153         if (!module_temp) {
154                 *temp = 0;
155                 return 0;
156         }
157
158         /* Validate if threshold reading is available through MTMP register,
159          * otherwise fallback to read through MCIA.
160          */
161         if (module_emerg) {
162                 *temp = off == SFP_TEMP_HIGH_WARN ? module_crit : module_emerg;
163                 return 0;
164         }
165
166         /* Read Free Side Device Temperature Thresholds from page 03h
167          * (MSB at lower byte address).
168          * Bytes:
169          * 128-129 - Temp High Alarm (SFP_TEMP_HIGH_ALARM);
170          * 130-131 - Temp Low Alarm (SFP_TEMP_LOW_ALARM);
171          * 132-133 - Temp High Warning (SFP_TEMP_HIGH_WARN);
172          * 134-135 - Temp Low Warning (SFP_TEMP_LOW_WARN);
173          */
174
175         /* Validate module identifier value. */
176         err = mlxsw_env_validate_cable_ident(core, module, &qsfp, &cmis);
177         if (err)
178                 return err;
179
180         if (qsfp) {
181                 /* For QSFP/CMIS module-defined thresholds are located in page
182                  * 02h, otherwise in page 03h.
183                  */
184                 if (cmis)
185                         page = MLXSW_REG_MCIA_TH_PAGE_CMIS_NUM;
186                 else
187                         page = MLXSW_REG_MCIA_TH_PAGE_NUM;
188                 mlxsw_reg_mcia_pack(mcia_pl, module, 0, page,
189                                     MLXSW_REG_MCIA_TH_PAGE_OFF + off,
190                                     MLXSW_REG_MCIA_TH_ITEM_SIZE,
191                                     MLXSW_REG_MCIA_I2C_ADDR_LOW);
192         } else {
193                 mlxsw_reg_mcia_pack(mcia_pl, module, 0,
194                                     MLXSW_REG_MCIA_PAGE0_LO,
195                                     off, MLXSW_REG_MCIA_TH_ITEM_SIZE,
196                                     MLXSW_REG_MCIA_I2C_ADDR_HIGH);
197         }
198
199         err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl);
200         if (err)
201                 return err;
202
203         eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl);
204         memcpy(temp_thresh.buf, eeprom_tmp, MLXSW_REG_MCIA_TH_ITEM_SIZE);
205         *temp = temp_thresh.temp * 1000;
206
207         return 0;
208 }
209
210 int mlxsw_env_get_module_info(struct net_device *netdev,
211                               struct mlxsw_core *mlxsw_core, int module,
212                               struct ethtool_modinfo *modinfo)
213 {
214         u8 module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE];
215         u16 offset = MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE;
216         u8 module_rev_id, module_id, diag_mon;
217         unsigned int read_size;
218         int err;
219
220         err = mlxsw_env_query_module_eeprom(mlxsw_core, module, 0, offset,
221                                             module_info, false, &read_size);
222         if (err)
223                 return err;
224
225         if (read_size < offset)
226                 return -EIO;
227
228         module_rev_id = module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID];
229         module_id = module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID];
230
231         switch (module_id) {
232         case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP:
233                 modinfo->type       = ETH_MODULE_SFF_8436;
234                 modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN;
235                 break;
236         case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS:
237         case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28:
238                 if (module_id == MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28 ||
239                     module_rev_id >=
240                     MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID_8636) {
241                         modinfo->type       = ETH_MODULE_SFF_8636;
242                         modinfo->eeprom_len = ETH_MODULE_SFF_8636_MAX_LEN;
243                 } else {
244                         modinfo->type       = ETH_MODULE_SFF_8436;
245                         modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN;
246                 }
247                 break;
248         case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP:
249                 /* Verify if transceiver provides diagnostic monitoring page */
250                 err = mlxsw_env_query_module_eeprom(mlxsw_core, module,
251                                                     SFP_DIAGMON, 1, &diag_mon,
252                                                     false, &read_size);
253                 if (err)
254                         return err;
255
256                 if (read_size < 1)
257                         return -EIO;
258
259                 modinfo->type       = ETH_MODULE_SFF_8472;
260                 if (diag_mon)
261                         modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
262                 else
263                         modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN / 2;
264                 break;
265         case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_DD:
266                 /* Use SFF_8636 as base type. ethtool should recognize specific
267                  * type through the identifier value.
268                  */
269                 modinfo->type       = ETH_MODULE_SFF_8636;
270                 /* Verify if module EEPROM is a flat memory. In case of flat
271                  * memory only page 00h (0-255 bytes) can be read. Otherwise
272                  * upper pages 01h and 02h can also be read. Upper pages 10h
273                  * and 11h are currently not supported by the driver.
274                  */
275                 if (module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_TYPE_ID] &
276                     MLXSW_REG_MCIA_EEPROM_CMIS_FLAT_MEMORY)
277                         modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN;
278                 else
279                         modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
280                 break;
281         default:
282                 return -EINVAL;
283         }
284
285         return 0;
286 }
287 EXPORT_SYMBOL(mlxsw_env_get_module_info);
288
289 int mlxsw_env_get_module_eeprom(struct net_device *netdev,
290                                 struct mlxsw_core *mlxsw_core, int module,
291                                 struct ethtool_eeprom *ee, u8 *data)
292 {
293         int offset = ee->offset;
294         unsigned int read_size;
295         bool qsfp, cmis;
296         int i = 0;
297         int err;
298
299         if (!ee->len)
300                 return -EINVAL;
301
302         memset(data, 0, ee->len);
303         /* Validate module identifier value. */
304         err = mlxsw_env_validate_cable_ident(mlxsw_core, module, &qsfp, &cmis);
305         if (err)
306                 return err;
307
308         while (i < ee->len) {
309                 err = mlxsw_env_query_module_eeprom(mlxsw_core, module, offset,
310                                                     ee->len - i, data + i,
311                                                     qsfp, &read_size);
312                 if (err) {
313                         netdev_err(netdev, "Eeprom query failed\n");
314                         return err;
315                 }
316
317                 i += read_size;
318                 offset += read_size;
319         }
320
321         return 0;
322 }
323 EXPORT_SYMBOL(mlxsw_env_get_module_eeprom);
324
325 static int mlxsw_env_mcia_status_process(const char *mcia_pl,
326                                          struct netlink_ext_ack *extack)
327 {
328         u8 status = mlxsw_reg_mcia_status_get(mcia_pl);
329
330         switch (status) {
331         case MLXSW_REG_MCIA_STATUS_GOOD:
332                 return 0;
333         case MLXSW_REG_MCIA_STATUS_NO_EEPROM_MODULE:
334                 NL_SET_ERR_MSG_MOD(extack, "No response from module's EEPROM");
335                 return -EIO;
336         case MLXSW_REG_MCIA_STATUS_MODULE_NOT_SUPPORTED:
337                 NL_SET_ERR_MSG_MOD(extack, "Module type not supported by the device");
338                 return -EOPNOTSUPP;
339         case MLXSW_REG_MCIA_STATUS_MODULE_NOT_CONNECTED:
340                 NL_SET_ERR_MSG_MOD(extack, "No module present indication");
341                 return -EIO;
342         case MLXSW_REG_MCIA_STATUS_I2C_ERROR:
343                 NL_SET_ERR_MSG_MOD(extack, "Error occurred while trying to access module's EEPROM using I2C");
344                 return -EIO;
345         case MLXSW_REG_MCIA_STATUS_MODULE_DISABLED:
346                 NL_SET_ERR_MSG_MOD(extack, "Module is disabled");
347                 return -EIO;
348         default:
349                 NL_SET_ERR_MSG_MOD(extack, "Unknown error");
350                 return -EIO;
351         }
352 }
353
354 int
355 mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, u8 module,
356                                     const struct ethtool_module_eeprom *page,
357                                     struct netlink_ext_ack *extack)
358 {
359         u32 bytes_read = 0;
360         u16 device_addr;
361
362         /* Offset cannot be larger than 2 * ETH_MODULE_EEPROM_PAGE_LEN */
363         device_addr = page->offset;
364
365         while (bytes_read < page->length) {
366                 char mcia_pl[MLXSW_REG_MCIA_LEN];
367                 char *eeprom_tmp;
368                 u8 size;
369                 int err;
370
371                 size = min_t(u8, page->length - bytes_read,
372                              MLXSW_REG_MCIA_EEPROM_SIZE);
373
374                 mlxsw_reg_mcia_pack(mcia_pl, module, 0, page->page,
375                                     device_addr + bytes_read, size,
376                                     page->i2c_address);
377                 mlxsw_reg_mcia_bank_number_set(mcia_pl, page->bank);
378
379                 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl);
380                 if (err) {
381                         NL_SET_ERR_MSG_MOD(extack, "Failed to access module's EEPROM");
382                         return err;
383                 }
384
385                 err = mlxsw_env_mcia_status_process(mcia_pl, extack);
386                 if (err)
387                         return err;
388
389                 eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl);
390                 memcpy(page->data + bytes_read, eeprom_tmp, size);
391                 bytes_read += size;
392         }
393
394         return bytes_read;
395 }
396 EXPORT_SYMBOL(mlxsw_env_get_module_eeprom_by_page);
397
398 static int mlxsw_env_module_reset(struct mlxsw_core *mlxsw_core, u8 module)
399 {
400         char pmaos_pl[MLXSW_REG_PMAOS_LEN];
401
402         mlxsw_reg_pmaos_pack(pmaos_pl, module);
403         mlxsw_reg_pmaos_rst_set(pmaos_pl, true);
404
405         return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl);
406 }
407
408 int mlxsw_env_reset_module(struct net_device *netdev,
409                            struct mlxsw_core *mlxsw_core, u8 module, u32 *flags)
410 {
411         struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
412         u32 req = *flags;
413         int err;
414
415         if (!(req & ETH_RESET_PHY) &&
416             !(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT)))
417                 return 0;
418
419         if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
420                 return -EINVAL;
421
422         mutex_lock(&mlxsw_env->module_info_lock);
423
424         if (mlxsw_env->module_info[module].num_ports_up) {
425                 netdev_err(netdev, "Cannot reset module when ports using it are administratively up\n");
426                 err = -EINVAL;
427                 goto out;
428         }
429
430         if (mlxsw_env->module_info[module].num_ports_mapped > 1 &&
431             !(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT))) {
432                 netdev_err(netdev, "Cannot reset module without \"phy-shared\" flag when shared by multiple ports\n");
433                 err = -EINVAL;
434                 goto out;
435         }
436
437         err = mlxsw_env_module_reset(mlxsw_core, module);
438         if (err) {
439                 netdev_err(netdev, "Failed to reset module\n");
440                 goto out;
441         }
442
443         *flags &= ~(ETH_RESET_PHY | (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT));
444
445 out:
446         mutex_unlock(&mlxsw_env->module_info_lock);
447         return err;
448 }
449 EXPORT_SYMBOL(mlxsw_env_reset_module);
450
451 int
452 mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module,
453                                 struct ethtool_module_power_mode_params *params,
454                                 struct netlink_ext_ack *extack)
455 {
456         struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
457         char mcion_pl[MLXSW_REG_MCION_LEN];
458         u32 status_bits;
459         int err;
460
461         if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
462                 return -EINVAL;
463
464         mutex_lock(&mlxsw_env->module_info_lock);
465
466         params->policy = mlxsw_env->module_info[module].power_mode_policy;
467
468         mlxsw_reg_mcion_pack(mcion_pl, module);
469         err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcion), mcion_pl);
470         if (err) {
471                 NL_SET_ERR_MSG_MOD(extack, "Failed to retrieve module's power mode");
472                 goto out;
473         }
474
475         status_bits = mlxsw_reg_mcion_module_status_bits_get(mcion_pl);
476         if (!(status_bits & MLXSW_REG_MCION_MODULE_STATUS_BITS_PRESENT_MASK))
477                 goto out;
478
479         if (status_bits & MLXSW_REG_MCION_MODULE_STATUS_BITS_LOW_POWER_MASK)
480                 params->mode = ETHTOOL_MODULE_POWER_MODE_LOW;
481         else
482                 params->mode = ETHTOOL_MODULE_POWER_MODE_HIGH;
483
484 out:
485         mutex_unlock(&mlxsw_env->module_info_lock);
486         return err;
487 }
488 EXPORT_SYMBOL(mlxsw_env_get_module_power_mode);
489
490 static int mlxsw_env_module_enable_set(struct mlxsw_core *mlxsw_core,
491                                        u8 module, bool enable)
492 {
493         enum mlxsw_reg_pmaos_admin_status admin_status;
494         char pmaos_pl[MLXSW_REG_PMAOS_LEN];
495
496         mlxsw_reg_pmaos_pack(pmaos_pl, module);
497         admin_status = enable ? MLXSW_REG_PMAOS_ADMIN_STATUS_ENABLED :
498                                 MLXSW_REG_PMAOS_ADMIN_STATUS_DISABLED;
499         mlxsw_reg_pmaos_admin_status_set(pmaos_pl, admin_status);
500         mlxsw_reg_pmaos_ase_set(pmaos_pl, true);
501
502         return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl);
503 }
504
505 static int mlxsw_env_module_low_power_set(struct mlxsw_core *mlxsw_core,
506                                           u8 module, bool low_power)
507 {
508         u16 eeprom_override_mask, eeprom_override;
509         char pmmp_pl[MLXSW_REG_PMMP_LEN];
510
511         mlxsw_reg_pmmp_pack(pmmp_pl, module);
512         mlxsw_reg_pmmp_sticky_set(pmmp_pl, true);
513         /* Mask all the bits except low power mode. */
514         eeprom_override_mask = ~MLXSW_REG_PMMP_EEPROM_OVERRIDE_LOW_POWER_MASK;
515         mlxsw_reg_pmmp_eeprom_override_mask_set(pmmp_pl, eeprom_override_mask);
516         eeprom_override = low_power ? MLXSW_REG_PMMP_EEPROM_OVERRIDE_LOW_POWER_MASK :
517                                       0;
518         mlxsw_reg_pmmp_eeprom_override_set(pmmp_pl, eeprom_override);
519
520         return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmmp), pmmp_pl);
521 }
522
523 static int __mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core,
524                                              u8 module, bool low_power,
525                                              struct netlink_ext_ack *extack)
526 {
527         int err;
528
529         err = mlxsw_env_module_enable_set(mlxsw_core, module, false);
530         if (err) {
531                 NL_SET_ERR_MSG_MOD(extack, "Failed to disable module");
532                 return err;
533         }
534
535         err = mlxsw_env_module_low_power_set(mlxsw_core, module, low_power);
536         if (err) {
537                 NL_SET_ERR_MSG_MOD(extack, "Failed to set module's power mode");
538                 goto err_module_low_power_set;
539         }
540
541         err = mlxsw_env_module_enable_set(mlxsw_core, module, true);
542         if (err) {
543                 NL_SET_ERR_MSG_MOD(extack, "Failed to enable module");
544                 goto err_module_enable_set;
545         }
546
547         return 0;
548
549 err_module_enable_set:
550         mlxsw_env_module_low_power_set(mlxsw_core, module, !low_power);
551 err_module_low_power_set:
552         mlxsw_env_module_enable_set(mlxsw_core, module, true);
553         return err;
554 }
555
556 int
557 mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module,
558                                 enum ethtool_module_power_mode_policy policy,
559                                 struct netlink_ext_ack *extack)
560 {
561         struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
562         bool low_power;
563         int err = 0;
564
565         if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
566                 return -EINVAL;
567
568         if (policy != ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH &&
569             policy != ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO) {
570                 NL_SET_ERR_MSG_MOD(extack, "Unsupported power mode policy");
571                 return -EOPNOTSUPP;
572         }
573
574         mutex_lock(&mlxsw_env->module_info_lock);
575
576         if (mlxsw_env->module_info[module].power_mode_policy == policy)
577                 goto out;
578
579         /* If any ports are up, we are already in high power mode. */
580         if (mlxsw_env->module_info[module].num_ports_up)
581                 goto out_set_policy;
582
583         low_power = policy == ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO;
584         err = __mlxsw_env_set_module_power_mode(mlxsw_core, module, low_power,
585                                                 extack);
586         if (err)
587                 goto out;
588
589 out_set_policy:
590         mlxsw_env->module_info[module].power_mode_policy = policy;
591 out:
592         mutex_unlock(&mlxsw_env->module_info_lock);
593         return err;
594 }
595 EXPORT_SYMBOL(mlxsw_env_set_module_power_mode);
596
597 static int mlxsw_env_module_has_temp_sensor(struct mlxsw_core *mlxsw_core,
598                                             u8 module,
599                                             bool *p_has_temp_sensor)
600 {
601         char mtbr_pl[MLXSW_REG_MTBR_LEN];
602         u16 temp;
603         int err;
604
605         mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module,
606                             1);
607         err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mtbr), mtbr_pl);
608         if (err)
609                 return err;
610
611         mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL);
612
613         switch (temp) {
614         case MLXSW_REG_MTBR_BAD_SENS_INFO:
615         case MLXSW_REG_MTBR_NO_CONN:
616         case MLXSW_REG_MTBR_NO_TEMP_SENS:
617         case MLXSW_REG_MTBR_INDEX_NA:
618                 *p_has_temp_sensor = false;
619                 break;
620         default:
621                 *p_has_temp_sensor = temp ? true : false;
622         }
623         return 0;
624 }
625
626 static int mlxsw_env_temp_event_set(struct mlxsw_core *mlxsw_core,
627                                     u16 sensor_index, bool enable)
628 {
629         char mtmp_pl[MLXSW_REG_MTMP_LEN] = {0};
630         enum mlxsw_reg_mtmp_tee tee;
631         int err, threshold_hi;
632
633         mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, sensor_index);
634         err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mtmp), mtmp_pl);
635         if (err)
636                 return err;
637
638         if (enable) {
639                 err = mlxsw_env_module_temp_thresholds_get(mlxsw_core,
640                                                            sensor_index -
641                                                            MLXSW_REG_MTMP_MODULE_INDEX_MIN,
642                                                            SFP_TEMP_HIGH_WARN,
643                                                            &threshold_hi);
644                 /* In case it is not possible to query the module's threshold,
645                  * use the default value.
646                  */
647                 if (err)
648                         threshold_hi = MLXSW_REG_MTMP_THRESH_HI;
649                 else
650                         /* mlxsw_env_module_temp_thresholds_get() multiplies
651                          * Celsius degrees by 1000 whereas MTMP expects
652                          * temperature in 0.125 Celsius degrees units.
653                          * Convert threshold_hi to correct units.
654                          */
655                         threshold_hi = threshold_hi / 1000 * 8;
656
657                 mlxsw_reg_mtmp_temperature_threshold_hi_set(mtmp_pl, threshold_hi);
658                 mlxsw_reg_mtmp_temperature_threshold_lo_set(mtmp_pl, threshold_hi -
659                                                             MLXSW_REG_MTMP_HYSTERESIS_TEMP);
660         }
661         tee = enable ? MLXSW_REG_MTMP_TEE_GENERATE_EVENT : MLXSW_REG_MTMP_TEE_NO_EVENT;
662         mlxsw_reg_mtmp_tee_set(mtmp_pl, tee);
663         return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mtmp), mtmp_pl);
664 }
665
666 static int mlxsw_env_module_temp_event_enable(struct mlxsw_core *mlxsw_core)
667 {
668         int i, err, sensor_index;
669         bool has_temp_sensor;
670
671         for (i = 0; i < mlxsw_core_env(mlxsw_core)->module_count; i++) {
672                 err = mlxsw_env_module_has_temp_sensor(mlxsw_core, i,
673                                                        &has_temp_sensor);
674                 if (err)
675                         return err;
676
677                 if (!has_temp_sensor)
678                         continue;
679
680                 sensor_index = i + MLXSW_REG_MTMP_MODULE_INDEX_MIN;
681                 err = mlxsw_env_temp_event_set(mlxsw_core, sensor_index, true);
682                 if (err)
683                         return err;
684         }
685
686         return 0;
687 }
688
689 struct mlxsw_env_module_temp_warn_event {
690         struct mlxsw_env *mlxsw_env;
691         char mtwe_pl[MLXSW_REG_MTWE_LEN];
692         struct work_struct work;
693 };
694
695 static void mlxsw_env_mtwe_event_work(struct work_struct *work)
696 {
697         struct mlxsw_env_module_temp_warn_event *event;
698         struct mlxsw_env *mlxsw_env;
699         int i, sensor_warning;
700         bool is_overheat;
701
702         event = container_of(work, struct mlxsw_env_module_temp_warn_event,
703                              work);
704         mlxsw_env = event->mlxsw_env;
705
706         for (i = 0; i < mlxsw_env->module_count; i++) {
707                 /* 64-127 of sensor_index are mapped to the port modules
708                  * sequentially (module 0 is mapped to sensor_index 64,
709                  * module 1 to sensor_index 65 and so on)
710                  */
711                 sensor_warning =
712                         mlxsw_reg_mtwe_sensor_warning_get(event->mtwe_pl,
713                                                           i + MLXSW_REG_MTMP_MODULE_INDEX_MIN);
714                 mutex_lock(&mlxsw_env->module_info_lock);
715                 is_overheat =
716                         mlxsw_env->module_info[i].is_overheat;
717
718                 if ((is_overheat && sensor_warning) ||
719                     (!is_overheat && !sensor_warning)) {
720                         /* Current state is "warning" and MTWE still reports
721                          * warning OR current state in "no warning" and MTWE
722                          * does not report warning.
723                          */
724                         mutex_unlock(&mlxsw_env->module_info_lock);
725                         continue;
726                 } else if (is_overheat && !sensor_warning) {
727                         /* MTWE reports "no warning", turn is_overheat off.
728                          */
729                         mlxsw_env->module_info[i].is_overheat = false;
730                         mutex_unlock(&mlxsw_env->module_info_lock);
731                 } else {
732                         /* Current state is "no warning" and MTWE reports
733                          * "warning", increase the counter and turn is_overheat
734                          * on.
735                          */
736                         mlxsw_env->module_info[i].is_overheat = true;
737                         mlxsw_env->module_info[i].module_overheat_counter++;
738                         mutex_unlock(&mlxsw_env->module_info_lock);
739                 }
740         }
741
742         kfree(event);
743 }
744
745 static void
746 mlxsw_env_mtwe_listener_func(const struct mlxsw_reg_info *reg, char *mtwe_pl,
747                              void *priv)
748 {
749         struct mlxsw_env_module_temp_warn_event *event;
750         struct mlxsw_env *mlxsw_env = priv;
751
752         event = kmalloc(sizeof(*event), GFP_ATOMIC);
753         if (!event)
754                 return;
755
756         event->mlxsw_env = mlxsw_env;
757         memcpy(event->mtwe_pl, mtwe_pl, MLXSW_REG_MTWE_LEN);
758         INIT_WORK(&event->work, mlxsw_env_mtwe_event_work);
759         mlxsw_core_schedule_work(&event->work);
760 }
761
762 static const struct mlxsw_listener mlxsw_env_temp_warn_listener =
763         MLXSW_EVENTL(mlxsw_env_mtwe_listener_func, MTWE, MTWE);
764
765 static int mlxsw_env_temp_warn_event_register(struct mlxsw_core *mlxsw_core)
766 {
767         struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
768
769         if (!mlxsw_core_temp_warn_enabled(mlxsw_core))
770                 return 0;
771
772         return mlxsw_core_trap_register(mlxsw_core,
773                                         &mlxsw_env_temp_warn_listener,
774                                         mlxsw_env);
775 }
776
777 static void mlxsw_env_temp_warn_event_unregister(struct mlxsw_env *mlxsw_env)
778 {
779         if (!mlxsw_core_temp_warn_enabled(mlxsw_env->core))
780                 return;
781
782         mlxsw_core_trap_unregister(mlxsw_env->core,
783                                    &mlxsw_env_temp_warn_listener, mlxsw_env);
784 }
785
786 struct mlxsw_env_module_plug_unplug_event {
787         struct mlxsw_env *mlxsw_env;
788         u8 module;
789         struct work_struct work;
790 };
791
792 static void mlxsw_env_pmpe_event_work(struct work_struct *work)
793 {
794         struct mlxsw_env_module_plug_unplug_event *event;
795         struct mlxsw_env *mlxsw_env;
796         bool has_temp_sensor;
797         u16 sensor_index;
798         int err;
799
800         event = container_of(work, struct mlxsw_env_module_plug_unplug_event,
801                              work);
802         mlxsw_env = event->mlxsw_env;
803
804         mutex_lock(&mlxsw_env->module_info_lock);
805         mlxsw_env->module_info[event->module].is_overheat = false;
806         mutex_unlock(&mlxsw_env->module_info_lock);
807
808         err = mlxsw_env_module_has_temp_sensor(mlxsw_env->core, event->module,
809                                                &has_temp_sensor);
810         /* Do not disable events on modules without sensors or faulty sensors
811          * because FW returns errors.
812          */
813         if (err)
814                 goto out;
815
816         if (!has_temp_sensor)
817                 goto out;
818
819         sensor_index = event->module + MLXSW_REG_MTMP_MODULE_INDEX_MIN;
820         mlxsw_env_temp_event_set(mlxsw_env->core, sensor_index, true);
821
822 out:
823         kfree(event);
824 }
825
826 static void
827 mlxsw_env_pmpe_listener_func(const struct mlxsw_reg_info *reg, char *pmpe_pl,
828                              void *priv)
829 {
830         struct mlxsw_env_module_plug_unplug_event *event;
831         enum mlxsw_reg_pmpe_module_status module_status;
832         u8 module = mlxsw_reg_pmpe_module_get(pmpe_pl);
833         struct mlxsw_env *mlxsw_env = priv;
834
835         if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
836                 return;
837
838         module_status = mlxsw_reg_pmpe_module_status_get(pmpe_pl);
839         if (module_status != MLXSW_REG_PMPE_MODULE_STATUS_PLUGGED_ENABLED)
840                 return;
841
842         event = kmalloc(sizeof(*event), GFP_ATOMIC);
843         if (!event)
844                 return;
845
846         event->mlxsw_env = mlxsw_env;
847         event->module = module;
848         INIT_WORK(&event->work, mlxsw_env_pmpe_event_work);
849         mlxsw_core_schedule_work(&event->work);
850 }
851
852 static const struct mlxsw_listener mlxsw_env_module_plug_listener =
853         MLXSW_EVENTL(mlxsw_env_pmpe_listener_func, PMPE, PMPE);
854
855 static int
856 mlxsw_env_module_plug_event_register(struct mlxsw_core *mlxsw_core)
857 {
858         struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
859
860         if (!mlxsw_core_temp_warn_enabled(mlxsw_core))
861                 return 0;
862
863         return mlxsw_core_trap_register(mlxsw_core,
864                                         &mlxsw_env_module_plug_listener,
865                                         mlxsw_env);
866 }
867
868 static void
869 mlxsw_env_module_plug_event_unregister(struct mlxsw_env *mlxsw_env)
870 {
871         if (!mlxsw_core_temp_warn_enabled(mlxsw_env->core))
872                 return;
873
874         mlxsw_core_trap_unregister(mlxsw_env->core,
875                                    &mlxsw_env_module_plug_listener,
876                                    mlxsw_env);
877 }
878
879 static int
880 mlxsw_env_module_oper_state_event_enable(struct mlxsw_core *mlxsw_core)
881 {
882         int i, err;
883
884         for (i = 0; i < mlxsw_core_env(mlxsw_core)->module_count; i++) {
885                 char pmaos_pl[MLXSW_REG_PMAOS_LEN];
886
887                 mlxsw_reg_pmaos_pack(pmaos_pl, i);
888                 mlxsw_reg_pmaos_e_set(pmaos_pl,
889                                       MLXSW_REG_PMAOS_E_GENERATE_EVENT);
890                 mlxsw_reg_pmaos_ee_set(pmaos_pl, true);
891                 err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl);
892                 if (err)
893                         return err;
894         }
895         return 0;
896 }
897
898 int
899 mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 module,
900                                       u64 *p_counter)
901 {
902         struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
903
904         if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
905                 return -EINVAL;
906
907         mutex_lock(&mlxsw_env->module_info_lock);
908         *p_counter = mlxsw_env->module_info[module].module_overheat_counter;
909         mutex_unlock(&mlxsw_env->module_info_lock);
910
911         return 0;
912 }
913 EXPORT_SYMBOL(mlxsw_env_module_overheat_counter_get);
914
915 void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 module)
916 {
917         struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
918
919         if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
920                 return;
921
922         mutex_lock(&mlxsw_env->module_info_lock);
923         mlxsw_env->module_info[module].num_ports_mapped++;
924         mutex_unlock(&mlxsw_env->module_info_lock);
925 }
926 EXPORT_SYMBOL(mlxsw_env_module_port_map);
927
928 void mlxsw_env_module_port_unmap(struct mlxsw_core *mlxsw_core, u8 module)
929 {
930         struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
931
932         if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
933                 return;
934
935         mutex_lock(&mlxsw_env->module_info_lock);
936         mlxsw_env->module_info[module].num_ports_mapped--;
937         mutex_unlock(&mlxsw_env->module_info_lock);
938 }
939 EXPORT_SYMBOL(mlxsw_env_module_port_unmap);
940
941 int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 module)
942 {
943         struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
944         int err = 0;
945
946         if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
947                 return -EINVAL;
948
949         mutex_lock(&mlxsw_env->module_info_lock);
950
951         if (mlxsw_env->module_info[module].power_mode_policy !=
952             ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO)
953                 goto out_inc;
954
955         if (mlxsw_env->module_info[module].num_ports_up != 0)
956                 goto out_inc;
957
958         /* Transition to high power mode following first port using the module
959          * being put administratively up.
960          */
961         err = __mlxsw_env_set_module_power_mode(mlxsw_core, module, false,
962                                                 NULL);
963         if (err)
964                 goto out_unlock;
965
966 out_inc:
967         mlxsw_env->module_info[module].num_ports_up++;
968 out_unlock:
969         mutex_unlock(&mlxsw_env->module_info_lock);
970         return err;
971 }
972 EXPORT_SYMBOL(mlxsw_env_module_port_up);
973
974 void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 module)
975 {
976         struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
977
978         if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
979                 return;
980
981         mutex_lock(&mlxsw_env->module_info_lock);
982
983         mlxsw_env->module_info[module].num_ports_up--;
984
985         if (mlxsw_env->module_info[module].power_mode_policy !=
986             ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO)
987                 goto out_unlock;
988
989         if (mlxsw_env->module_info[module].num_ports_up != 0)
990                 goto out_unlock;
991
992         /* Transition to low power mode following last port using the module
993          * being put administratively down.
994          */
995         __mlxsw_env_set_module_power_mode(mlxsw_core, module, true, NULL);
996
997 out_unlock:
998         mutex_unlock(&mlxsw_env->module_info_lock);
999 }
1000 EXPORT_SYMBOL(mlxsw_env_module_port_down);
1001
1002 static int
1003 mlxsw_env_module_type_set(struct mlxsw_core *mlxsw_core)
1004 {
1005         struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
1006         int i;
1007
1008         for (i = 0; i < mlxsw_env->module_count; i++) {
1009                 char pmtm_pl[MLXSW_REG_PMTM_LEN];
1010                 int err;
1011
1012                 mlxsw_reg_pmtm_pack(pmtm_pl, 0, i);
1013                 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(pmtm), pmtm_pl);
1014                 if (err)
1015                         return err;
1016
1017                 mlxsw_env->module_info[i].type =
1018                         mlxsw_reg_pmtm_module_type_get(pmtm_pl);
1019         }
1020
1021         return 0;
1022 }
1023
1024 int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env)
1025 {
1026         char mgpir_pl[MLXSW_REG_MGPIR_LEN];
1027         struct mlxsw_env *env;
1028         u8 module_count;
1029         int i, err;
1030
1031         mlxsw_reg_mgpir_pack(mgpir_pl);
1032         err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mgpir), mgpir_pl);
1033         if (err)
1034                 return err;
1035
1036         mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, &module_count);
1037
1038         env = kzalloc(struct_size(env, module_info, module_count), GFP_KERNEL);
1039         if (!env)
1040                 return -ENOMEM;
1041
1042         /* Firmware defaults to high power mode policy where modules are
1043          * transitioned to high power mode following plug-in.
1044          */
1045         for (i = 0; i < module_count; i++)
1046                 env->module_info[i].power_mode_policy =
1047                         ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH;
1048
1049         mutex_init(&env->module_info_lock);
1050         env->core = mlxsw_core;
1051         env->module_count = module_count;
1052         *p_env = env;
1053
1054         err = mlxsw_env_temp_warn_event_register(mlxsw_core);
1055         if (err)
1056                 goto err_temp_warn_event_register;
1057
1058         err = mlxsw_env_module_plug_event_register(mlxsw_core);
1059         if (err)
1060                 goto err_module_plug_event_register;
1061
1062         err = mlxsw_env_module_oper_state_event_enable(mlxsw_core);
1063         if (err)
1064                 goto err_oper_state_event_enable;
1065
1066         err = mlxsw_env_module_temp_event_enable(mlxsw_core);
1067         if (err)
1068                 goto err_temp_event_enable;
1069
1070         err = mlxsw_env_module_type_set(mlxsw_core);
1071         if (err)
1072                 goto err_type_set;
1073
1074         return 0;
1075
1076 err_type_set:
1077 err_temp_event_enable:
1078 err_oper_state_event_enable:
1079         mlxsw_env_module_plug_event_unregister(env);
1080 err_module_plug_event_register:
1081         mlxsw_env_temp_warn_event_unregister(env);
1082 err_temp_warn_event_register:
1083         mutex_destroy(&env->module_info_lock);
1084         kfree(env);
1085         return err;
1086 }
1087
1088 void mlxsw_env_fini(struct mlxsw_env *env)
1089 {
1090         mlxsw_env_module_plug_event_unregister(env);
1091         /* Make sure there is no more event work scheduled. */
1092         mlxsw_core_flush_owq();
1093         mlxsw_env_temp_warn_event_unregister(env);
1094         mutex_destroy(&env->module_info_lock);
1095         kfree(env);
1096 }