1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
4 #include <linux/kernel.h>
13 static int mlxsw_env_validate_cable_ident(struct mlxsw_core
*core
, int id
,
16 char eeprom_tmp
[MLXSW_REG_MCIA_EEPROM_SIZE
];
17 char mcia_pl
[MLXSW_REG_MCIA_LEN
];
21 mlxsw_reg_mcia_pack(mcia_pl
, id
, 0, MLXSW_REG_MCIA_PAGE0_LO_OFF
, 0, 1,
22 MLXSW_REG_MCIA_I2C_ADDR_LOW
);
23 err
= mlxsw_reg_query(core
, MLXSW_REG(mcia
), mcia_pl
);
26 mlxsw_reg_mcia_eeprom_memcpy_from(mcia_pl
, eeprom_tmp
);
27 ident
= eeprom_tmp
[0];
29 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP
:
32 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP
: /* fall-through */
33 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS
: /* fall-through */
34 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28
: /* fall-through */
35 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_DD
:
46 mlxsw_env_query_module_eeprom(struct mlxsw_core
*mlxsw_core
, int module
,
47 u16 offset
, u16 size
, void *data
,
48 unsigned int *p_read_size
)
50 char eeprom_tmp
[MLXSW_REG_MCIA_EEPROM_SIZE
];
51 char mcia_pl
[MLXSW_REG_MCIA_LEN
];
57 size
= min_t(u16
, size
, MLXSW_REG_MCIA_EEPROM_SIZE
);
59 if (offset
< MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH
&&
60 offset
+ size
> MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH
)
61 /* Cross pages read, read until offset 256 in low page */
62 size
= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH
- offset
;
64 i2c_addr
= MLXSW_REG_MCIA_I2C_ADDR_LOW
;
65 if (offset
>= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH
) {
66 page
= MLXSW_REG_MCIA_PAGE_GET(offset
);
67 offset
-= MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH
* page
;
68 /* When reading upper pages 1, 2 and 3 the offset starts at
69 * 128. Please refer to "QSFP+ Memory Map" figure in SFF-8436
70 * specification for graphical depiction.
71 * MCIA register accepts buffer size <= 48. Page of size 128
72 * should be read by chunks of size 48, 48, 32. Align the size
73 * of the last chunk to avoid reading after the end of the
76 if (offset
+ size
> MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH
)
77 size
= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH
- offset
;
80 mlxsw_reg_mcia_pack(mcia_pl
, module
, 0, page
, offset
, size
, i2c_addr
);
82 err
= mlxsw_reg_query(mlxsw_core
, MLXSW_REG(mcia
), mcia_pl
);
86 status
= mlxsw_reg_mcia_status_get(mcia_pl
);
90 mlxsw_reg_mcia_eeprom_memcpy_from(mcia_pl
, eeprom_tmp
);
91 memcpy(data
, eeprom_tmp
, size
);
97 int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core
*core
, int module
,
100 char eeprom_tmp
[MLXSW_REG_MCIA_EEPROM_SIZE
];
102 u8 buf
[MLXSW_REG_MCIA_TH_ITEM_SIZE
];
105 char mcia_pl
[MLXSW_REG_MCIA_LEN
] = {0};
106 char mtmp_pl
[MLXSW_REG_MTMP_LEN
];
107 unsigned int module_temp
;
111 mlxsw_reg_mtmp_pack(mtmp_pl
, MLXSW_REG_MTMP_MODULE_INDEX_MIN
+ module
,
113 err
= mlxsw_reg_query(core
, MLXSW_REG(mtmp
), mtmp_pl
);
116 mlxsw_reg_mtmp_unpack(mtmp_pl
, &module_temp
, NULL
, NULL
);
122 /* Read Free Side Device Temperature Thresholds from page 03h
123 * (MSB at lower byte address).
125 * 128-129 - Temp High Alarm (SFP_TEMP_HIGH_ALARM);
126 * 130-131 - Temp Low Alarm (SFP_TEMP_LOW_ALARM);
127 * 132-133 - Temp High Warning (SFP_TEMP_HIGH_WARN);
128 * 134-135 - Temp Low Warning (SFP_TEMP_LOW_WARN);
131 /* Validate module identifier value. */
132 err
= mlxsw_env_validate_cable_ident(core
, module
, &qsfp
);
137 mlxsw_reg_mcia_pack(mcia_pl
, module
, 0,
138 MLXSW_REG_MCIA_TH_PAGE_NUM
,
139 MLXSW_REG_MCIA_TH_PAGE_OFF
+ off
,
140 MLXSW_REG_MCIA_TH_ITEM_SIZE
,
141 MLXSW_REG_MCIA_I2C_ADDR_LOW
);
143 mlxsw_reg_mcia_pack(mcia_pl
, module
, 0,
144 MLXSW_REG_MCIA_PAGE0_LO
,
145 off
, MLXSW_REG_MCIA_TH_ITEM_SIZE
,
146 MLXSW_REG_MCIA_I2C_ADDR_HIGH
);
148 err
= mlxsw_reg_query(core
, MLXSW_REG(mcia
), mcia_pl
);
152 mlxsw_reg_mcia_eeprom_memcpy_from(mcia_pl
, eeprom_tmp
);
153 memcpy(temp_thresh
.buf
, eeprom_tmp
, MLXSW_REG_MCIA_TH_ITEM_SIZE
);
154 *temp
= temp_thresh
.temp
* 1000;
159 int mlxsw_env_get_module_info(struct mlxsw_core
*mlxsw_core
, int module
,
160 struct ethtool_modinfo
*modinfo
)
162 u8 module_info
[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE
];
163 u16 offset
= MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE
;
164 u8 module_rev_id
, module_id
, diag_mon
;
165 unsigned int read_size
;
168 err
= mlxsw_env_query_module_eeprom(mlxsw_core
, module
, 0, offset
,
169 module_info
, &read_size
);
173 if (read_size
< offset
)
176 module_rev_id
= module_info
[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID
];
177 module_id
= module_info
[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID
];
180 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP
:
181 modinfo
->type
= ETH_MODULE_SFF_8436
;
182 modinfo
->eeprom_len
= ETH_MODULE_SFF_8436_MAX_LEN
;
184 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS
: /* fall-through */
185 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28
:
186 if (module_id
== MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28
||
188 MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID_8636
) {
189 modinfo
->type
= ETH_MODULE_SFF_8636
;
190 modinfo
->eeprom_len
= ETH_MODULE_SFF_8636_MAX_LEN
;
192 modinfo
->type
= ETH_MODULE_SFF_8436
;
193 modinfo
->eeprom_len
= ETH_MODULE_SFF_8436_MAX_LEN
;
196 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP
:
197 /* Verify if transceiver provides diagnostic monitoring page */
198 err
= mlxsw_env_query_module_eeprom(mlxsw_core
, module
,
199 SFP_DIAGMON
, 1, &diag_mon
,
207 modinfo
->type
= ETH_MODULE_SFF_8472
;
209 modinfo
->eeprom_len
= ETH_MODULE_SFF_8472_LEN
;
211 modinfo
->eeprom_len
= ETH_MODULE_SFF_8472_LEN
/ 2;
219 EXPORT_SYMBOL(mlxsw_env_get_module_info
);
221 int mlxsw_env_get_module_eeprom(struct net_device
*netdev
,
222 struct mlxsw_core
*mlxsw_core
, int module
,
223 struct ethtool_eeprom
*ee
, u8
*data
)
225 int offset
= ee
->offset
;
226 unsigned int read_size
;
233 memset(data
, 0, ee
->len
);
235 while (i
< ee
->len
) {
236 err
= mlxsw_env_query_module_eeprom(mlxsw_core
, module
, offset
,
237 ee
->len
- i
, data
+ i
,
240 netdev_err(netdev
, "Eeprom query failed\n");
250 EXPORT_SYMBOL(mlxsw_env_get_module_eeprom
);