Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: hns3: adds support for reading module eeprom info

This patch adds support for reading the optical module eeprom
info via "ethtool -m".

Signed-off-by: Yonglong Liu <liuyonglong@huawei.com>
Signed-off-by: Huazhong Tan <tanhuazhong@huawei.com>
Acked-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Yonglong Liu and committed by
David S. Miller
cb10228d c76c2230

+196
+4
drivers/net/ethernet/hisilicon/hns3/hnae3.h
··· 374 374 * Set the max tx rate of specified vf. 375 375 * set_vf_mac 376 376 * Configure the default MAC for specified VF 377 + * get_module_eeprom 378 + * Get the optical module eeprom info. 377 379 */ 378 380 struct hnae3_ae_ops { 379 381 int (*init_ae_dev)(struct hnae3_ae_dev *ae_dev); ··· 550 548 int (*set_vf_rate)(struct hnae3_handle *handle, int vf, 551 549 int min_tx_rate, int max_tx_rate, bool force); 552 550 int (*set_vf_mac)(struct hnae3_handle *handle, int vf, u8 *p); 551 + int (*get_module_eeprom)(struct hnae3_handle *handle, u32 offset, 552 + u32 len, u8 *data); 553 553 }; 554 554 555 555 struct hnae3_dcb_ops {
+75
drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
··· 4 4 #include <linux/etherdevice.h> 5 5 #include <linux/string.h> 6 6 #include <linux/phy.h> 7 + #include <linux/sfp.h> 7 8 8 9 #include "hns3_enet.h" 9 10 10 11 struct hns3_stats { 11 12 char stats_string[ETH_GSTRING_LEN]; 12 13 int stats_offset; 14 + }; 15 + 16 + struct hns3_sfp_type { 17 + u8 type; 18 + u8 ext_type; 13 19 }; 14 20 15 21 /* tqp related stats */ ··· 1392 1386 return ops->set_fec(handle, fec_mode); 1393 1387 } 1394 1388 1389 + static int hns3_get_module_info(struct net_device *netdev, 1390 + struct ethtool_modinfo *modinfo) 1391 + { 1392 + #define HNS3_SFF_8636_V1_3 0x03 1393 + 1394 + struct hnae3_handle *handle = hns3_get_handle(netdev); 1395 + const struct hnae3_ae_ops *ops = handle->ae_algo->ops; 1396 + struct hns3_sfp_type sfp_type; 1397 + int ret; 1398 + 1399 + if (handle->pdev->revision == 0x20 || !ops->get_module_eeprom) 1400 + return -EOPNOTSUPP; 1401 + 1402 + memset(&sfp_type, 0, sizeof(sfp_type)); 1403 + ret = ops->get_module_eeprom(handle, 0, sizeof(sfp_type) / sizeof(u8), 1404 + (u8 *)&sfp_type); 1405 + if (ret) 1406 + return ret; 1407 + 1408 + switch (sfp_type.type) { 1409 + case SFF8024_ID_SFP: 1410 + modinfo->type = ETH_MODULE_SFF_8472; 1411 + modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; 1412 + break; 1413 + case SFF8024_ID_QSFP_8438: 1414 + modinfo->type = ETH_MODULE_SFF_8436; 1415 + modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN; 1416 + break; 1417 + case SFF8024_ID_QSFP_8436_8636: 1418 + if (sfp_type.ext_type < HNS3_SFF_8636_V1_3) { 1419 + modinfo->type = ETH_MODULE_SFF_8436; 1420 + modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN; 1421 + } else { 1422 + modinfo->type = ETH_MODULE_SFF_8636; 1423 + modinfo->eeprom_len = ETH_MODULE_SFF_8636_MAX_LEN; 1424 + } 1425 + break; 1426 + case SFF8024_ID_QSFP28_8636: 1427 + modinfo->type = ETH_MODULE_SFF_8636; 1428 + modinfo->eeprom_len = ETH_MODULE_SFF_8636_MAX_LEN; 1429 + break; 1430 + default: 1431 + netdev_err(netdev, "Optical module unknown: %#x\n", 1432 + sfp_type.type); 1433 + return -EINVAL; 1434 + } 1435 + 1436 + return 0; 1437 + } 1438 + 1439 + static int hns3_get_module_eeprom(struct net_device *netdev, 1440 + struct ethtool_eeprom *ee, u8 *data) 1441 + { 1442 + struct hnae3_handle *handle = hns3_get_handle(netdev); 1443 + const struct hnae3_ae_ops *ops = handle->ae_algo->ops; 1444 + 1445 + if (handle->pdev->revision == 0x20 || !ops->get_module_eeprom) 1446 + return -EOPNOTSUPP; 1447 + 1448 + if (!ee->len) 1449 + return -EINVAL; 1450 + 1451 + memset(data, 0, ee->len); 1452 + 1453 + return ops->get_module_eeprom(handle, ee->offset, ee->len, data); 1454 + } 1455 + 1395 1456 #define HNS3_ETHTOOL_COALESCE (ETHTOOL_COALESCE_USECS | \ 1396 1457 ETHTOOL_COALESCE_USE_ADAPTIVE | \ 1397 1458 ETHTOOL_COALESCE_RX_USECS_HIGH | \ ··· 1522 1449 .set_msglevel = hns3_set_msglevel, 1523 1450 .get_fecparam = hns3_get_fecparam, 1524 1451 .set_fecparam = hns3_set_fecparam, 1452 + .get_module_info = hns3_get_module_info, 1453 + .get_module_eeprom = hns3_get_module_eeprom, 1525 1454 }; 1526 1455 1527 1456 void hns3_ethtool_set_ops(struct net_device *netdev)
+15
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
··· 270 270 HCLGE_OPC_M7_COMPAT_CFG = 0x701A, 271 271 272 272 /* SFP command */ 273 + HCLGE_OPC_GET_SFP_EEPROM = 0x7100, 274 + HCLGE_OPC_GET_SFP_EXIST = 0x7101, 273 275 HCLGE_OPC_GET_SFP_INFO = 0x7104, 274 276 275 277 /* Error INT commands */ ··· 1054 1052 struct hclge_firmware_compat_cmd { 1055 1053 __le32 compat; 1056 1054 u8 rsv[20]; 1055 + }; 1056 + 1057 + #define HCLGE_SFP_INFO_CMD_NUM 6 1058 + #define HCLGE_SFP_INFO_BD0_LEN 20 1059 + #define HCLGE_SFP_INFO_BDX_LEN 24 1060 + #define HCLGE_SFP_INFO_MAX_LEN \ 1061 + (HCLGE_SFP_INFO_BD0_LEN + \ 1062 + (HCLGE_SFP_INFO_CMD_NUM - 1) * HCLGE_SFP_INFO_BDX_LEN) 1063 + 1064 + struct hclge_sfp_info_bd0_cmd { 1065 + __le16 offset; 1066 + __le16 read_len; 1067 + u8 data[HCLGE_SFP_INFO_BD0_LEN]; 1057 1068 }; 1058 1069 1059 1070 int hclge_cmd_init(struct hclge_dev *hdev);
+102
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
··· 11119 11119 } 11120 11120 } 11121 11121 11122 + static bool hclge_module_existed(struct hclge_dev *hdev) 11123 + { 11124 + struct hclge_desc desc; 11125 + u32 existed; 11126 + int ret; 11127 + 11128 + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_GET_SFP_EXIST, true); 11129 + ret = hclge_cmd_send(&hdev->hw, &desc, 1); 11130 + if (ret) { 11131 + dev_err(&hdev->pdev->dev, 11132 + "failed to get SFP exist state, ret = %d\n", ret); 11133 + return false; 11134 + } 11135 + 11136 + existed = le32_to_cpu(desc.data[0]); 11137 + 11138 + return existed != 0; 11139 + } 11140 + 11141 + /* need 6 bds(total 140 bytes) in one reading 11142 + * return the number of bytes actually read, 0 means read failed. 11143 + */ 11144 + static u16 hclge_get_sfp_eeprom_info(struct hclge_dev *hdev, u32 offset, 11145 + u32 len, u8 *data) 11146 + { 11147 + struct hclge_desc desc[HCLGE_SFP_INFO_CMD_NUM]; 11148 + struct hclge_sfp_info_bd0_cmd *sfp_info_bd0; 11149 + u16 read_len; 11150 + u16 copy_len; 11151 + int ret; 11152 + int i; 11153 + 11154 + /* setup all 6 bds to read module eeprom info. */ 11155 + for (i = 0; i < HCLGE_SFP_INFO_CMD_NUM; i++) { 11156 + hclge_cmd_setup_basic_desc(&desc[i], HCLGE_OPC_GET_SFP_EEPROM, 11157 + true); 11158 + 11159 + /* bd0~bd4 need next flag */ 11160 + if (i < HCLGE_SFP_INFO_CMD_NUM - 1) 11161 + desc[i].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT); 11162 + } 11163 + 11164 + /* setup bd0, this bd contains offset and read length. */ 11165 + sfp_info_bd0 = (struct hclge_sfp_info_bd0_cmd *)desc[0].data; 11166 + sfp_info_bd0->offset = cpu_to_le16((u16)offset); 11167 + read_len = min_t(u16, len, HCLGE_SFP_INFO_MAX_LEN); 11168 + sfp_info_bd0->read_len = cpu_to_le16(read_len); 11169 + 11170 + ret = hclge_cmd_send(&hdev->hw, desc, i); 11171 + if (ret) { 11172 + dev_err(&hdev->pdev->dev, 11173 + "failed to get SFP eeprom info, ret = %d\n", ret); 11174 + return 0; 11175 + } 11176 + 11177 + /* copy sfp info from bd0 to out buffer. */ 11178 + copy_len = min_t(u16, len, HCLGE_SFP_INFO_BD0_LEN); 11179 + memcpy(data, sfp_info_bd0->data, copy_len); 11180 + read_len = copy_len; 11181 + 11182 + /* copy sfp info from bd1~bd5 to out buffer if needed. */ 11183 + for (i = 1; i < HCLGE_SFP_INFO_CMD_NUM; i++) { 11184 + if (read_len >= len) 11185 + return read_len; 11186 + 11187 + copy_len = min_t(u16, len - read_len, HCLGE_SFP_INFO_BDX_LEN); 11188 + memcpy(data + read_len, desc[i].data, copy_len); 11189 + read_len += copy_len; 11190 + } 11191 + 11192 + return read_len; 11193 + } 11194 + 11195 + static int hclge_get_module_eeprom(struct hnae3_handle *handle, u32 offset, 11196 + u32 len, u8 *data) 11197 + { 11198 + struct hclge_vport *vport = hclge_get_vport(handle); 11199 + struct hclge_dev *hdev = vport->back; 11200 + u32 read_len = 0; 11201 + u16 data_len; 11202 + 11203 + if (hdev->hw.mac.media_type != HNAE3_MEDIA_TYPE_FIBER) 11204 + return -EOPNOTSUPP; 11205 + 11206 + if (!hclge_module_existed(hdev)) 11207 + return -ENXIO; 11208 + 11209 + while (read_len < len) { 11210 + data_len = hclge_get_sfp_eeprom_info(hdev, 11211 + offset + read_len, 11212 + len - read_len, 11213 + data + read_len); 11214 + if (!data_len) 11215 + return -EIO; 11216 + 11217 + read_len += data_len; 11218 + } 11219 + 11220 + return 0; 11221 + } 11222 + 11122 11223 static const struct hnae3_ae_ops hclge_ops = { 11123 11224 .init_ae_dev = hclge_init_ae_dev, 11124 11225 .uninit_ae_dev = hclge_uninit_ae_dev, ··· 11312 11211 .set_vf_trust = hclge_set_vf_trust, 11313 11212 .set_vf_rate = hclge_set_vf_rate, 11314 11213 .set_vf_mac = hclge_set_vf_mac, 11214 + .get_module_eeprom = hclge_get_module_eeprom, 11315 11215 }; 11316 11216 11317 11217 static struct hnae3_ae_algo ae_algo = {