diff --git a/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c b/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c index f321365fc997b2ae03a4944e7cb1367e61c4f1ca..78d32ea5cc88c53bd2f6a98f0d928364b6f3e38e 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c @@ -2039,6 +2039,74 @@ static void hinic_diag_test(struct net_device *netdev, hinic_lp_test(netdev, eth_test, data, 0); } +#ifdef ETHTOOL_GMODULEEEPROM +static int hinic_get_module_info(struct net_device *netdev, + struct ethtool_modinfo *modinfo) +{ + struct hinic_nic_dev *nic_dev = netdev_priv(netdev); + u8 sfp_type; + u8 sfp_type_ext; + int err; + + err = hinic_get_sfp_type(nic_dev->hwdev, &sfp_type, &sfp_type_ext); + if (err) + return err; + + switch (sfp_type) { + case MODULE_TYPE_SFP: + modinfo->type = ETH_MODULE_SFF_8472; + modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; + break; + case MODULE_TYPE_QSFP: + modinfo->type = ETH_MODULE_SFF_8436; + modinfo->eeprom_len = STD_SFP_INFO_MAX_SIZE; + break; + case MODULE_TYPE_QSFP_PLUS: + if (sfp_type_ext >= 0x3) { + modinfo->type = ETH_MODULE_SFF_8636; + modinfo->eeprom_len = STD_SFP_INFO_MAX_SIZE; + + } else { + modinfo->type = ETH_MODULE_SFF_8436; + modinfo->eeprom_len = STD_SFP_INFO_MAX_SIZE; + } + break; + case MODULE_TYPE_QSFP28: + modinfo->type = ETH_MODULE_SFF_8636; + modinfo->eeprom_len = STD_SFP_INFO_MAX_SIZE; + break; + default: + nicif_warn(nic_dev, drv, netdev, + "Optical module unknown: 0x%x\n", sfp_type); + return -EINVAL; + } + + return 0; +} + +static int hinic_get_module_eeprom(struct net_device *netdev, + struct ethtool_eeprom *ee, u8 *data) +{ + struct hinic_nic_dev *nic_dev = netdev_priv(netdev); + u8 sfp_data[STD_SFP_INFO_MAX_SIZE]; + u16 len; + int err; + + if (!ee->len || ((ee->len + ee->offset) > STD_SFP_INFO_MAX_SIZE)) + return -EINVAL; + + memset(data, 0, ee->len); + + err = hinic_get_sfp_eeprom(nic_dev->hwdev, sfp_data, &len); + if (err) + return err; + + memcpy(data, sfp_data + ee->offset, ee->len); + + return 0; +} +#endif /* ETHTOOL_GMODULEEEPROM */ + static int set_l4_rss_hash_ops(struct ethtool_rxnfc *cmd, struct nic_rss_type *rss_type) { @@ -2532,6 +2600,10 @@ static const struct ethtool_ops hinic_ethtool_ops = { #ifndef HAVE_RHEL6_ETHTOOL_OPS_EXT_STRUCT .get_channels = hinic_get_channels, .set_channels = hinic_set_channels, +#ifdef ETHTOOL_GMODULEEEPROM + .get_module_info = hinic_get_module_info, + .get_module_eeprom = hinic_get_module_eeprom, +#endif #ifndef NOT_HAVE_GET_RXFH_INDIR_SIZE .get_rxfh_indir_size = hinic_get_rxfh_indir_size, #endif @@ -2552,6 +2624,11 @@ static const struct ethtool_ops_ext hinic_ethtool_ops_ext = { .set_phys_id = hinic_set_phys_id, .get_channels = hinic_get_channels, .set_channels = hinic_set_channels, +#ifdef ETHTOOL_GMODULEEEPROM + .get_module_info = hinic_get_module_info, + .get_module_eeprom = hinic_get_module_eeprom, +#endif + #ifndef NOT_HAVE_GET_RXFH_INDIR_SIZE .get_rxfh_indir_size = hinic_get_rxfh_indir_size, #endif diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw.h b/drivers/net/ethernet/huawei/hinic/hinic_hw.h index e489a00cab2cfed4d8c6ae6b3c4e5f351f53086d..d4becb6287590fe1085dfe368aa34b51e18d921f 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_hw.h +++ b/drivers/net/ethernet/huawei/hinic/hinic_hw.h @@ -264,6 +264,56 @@ struct hinic_init_para { #define INIT_SUCCESS 1 #define MAX_DRV_BUF_SIZE 4096 +struct hinic_cmd_get_light_module_abs { + u8 status; + u8 version; + u8 rsvd0[6]; + + u8 port_id; + u8 abs_status; /* 0:present, 1:absent */ + u8 rsv[2]; +}; + +#define MODULE_TYPE_SFP 0x3 +#define MODULE_TYPE_QSFP28 0x11 +#define MODULE_TYPE_QSFP 0x0C +#define MODULE_TYPE_QSFP_PLUS 0x0D + +#define SFP_INFO_MAX_SIZE 512 +struct hinic_cmd_get_sfp_qsfp_info { + u8 status; + u8 version; + u8 rsvd0[6]; + + u8 port_id; + u8 wire_type; + u16 out_len; + u8 sfp_qsfp_info[SFP_INFO_MAX_SIZE]; +}; + +#define STD_SFP_INFO_MAX_SIZE 640 +struct hinic_cmd_get_std_sfp_info { + u8 status; + u8 version; + u8 rsvd0[6]; + + u8 port_id; + u8 wire_type; + u16 eeprom_len; + u32 rsvd; + u8 sfp_info[STD_SFP_INFO_MAX_SIZE]; +}; + +#define HINIC_MAX_PORT_ID 4 + +struct hinic_port_routine_cmd { + int up_send_sfp_info; + int up_send_sfp_abs; + + struct hinic_cmd_get_sfp_qsfp_info sfp_info; + struct hinic_cmd_get_light_module_abs abs; +}; + struct card_node { struct list_head node; struct list_head func_list; @@ -282,6 +332,10 @@ struct card_node { bool disable_vf_load[HINIC_MAX_PF_NUM]; u32 vf_mbx_old_rand_id[MAX_FUNCTION_NUM]; u32 vf_mbx_rand_id[MAX_FUNCTION_NUM]; + struct hinic_port_routine_cmd rt_cmd[HINIC_MAX_PORT_ID]; + + /* mutex used for copy sfp info */ + struct mutex sfp_mutex; }; enum hinic_hwdev_init_state { diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hwdev.c b/drivers/net/ethernet/huawei/hinic/hinic_hwdev.c index 101b671db4250b2191b46c44561cb7bd86f8f63c..172be6c9a1d9ffc0bc43b57a0f0ccc9542f60542 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_hwdev.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_hwdev.c @@ -59,6 +59,8 @@ #define HINIC_OK_FLAG_FAILED 1 +#define HINIC_GET_SFP_INFO_REAL_TIME 0x1 + #define HINIC_GLB_SO_RO_CFG_SHIFT 0x0 #define HINIC_GLB_SO_RO_CFG_MASK 0x1 #define HINIC_DISABLE_ORDER 0 @@ -913,6 +915,80 @@ int hinic_pf_msg_to_mgmt_sync(void *hwdev, enum hinic_mod_type mod, u8 cmd, return err; } +static bool is_sfp_info_cmd_cached(struct hinic_hwdev *hwdev, + enum hinic_mod_type mod, u8 cmd, + void *buf_in, u16 in_size, + void *buf_out, u16 *out_size) +{ + struct hinic_cmd_get_sfp_qsfp_info *sfp_info = NULL; + struct hinic_port_routine_cmd *rt_cmd = NULL; + struct card_node *chip_node = hwdev->chip_node; + + sfp_info = buf_in; + if (sfp_info->port_id >= HINIC_MAX_PORT_ID || + *out_size < sizeof(*sfp_info)) + return false; + + if (sfp_info->version == HINIC_GET_SFP_INFO_REAL_TIME) + return false; + + rt_cmd = &chip_node->rt_cmd[sfp_info->port_id]; + mutex_lock(&chip_node->sfp_mutex); + memcpy(buf_out, &rt_cmd->sfp_info, sizeof(*sfp_info)); + mutex_unlock(&chip_node->sfp_mutex); + + return true; +} + +static bool is_sfp_abs_cmd_cached(struct hinic_hwdev *hwdev, + enum hinic_mod_type mod, u8 cmd, + void *buf_in, u16 in_size, + void *buf_out, u16 *out_size) +{ + struct hinic_cmd_get_light_module_abs *abs = NULL; + struct hinic_port_routine_cmd *rt_cmd = NULL; + struct card_node *chip_node = hwdev->chip_node; + + abs = buf_in; + if (abs->port_id >= HINIC_MAX_PORT_ID || + *out_size < sizeof(*abs)) + return false; + + if (abs->version == HINIC_GET_SFP_INFO_REAL_TIME) + return false; + + rt_cmd = &chip_node->rt_cmd[abs->port_id]; + mutex_lock(&chip_node->sfp_mutex); + memcpy(buf_out, &rt_cmd->abs, sizeof(*abs)); + mutex_unlock(&chip_node->sfp_mutex); + + return true; +} + +static bool driver_processed_cmd(struct hinic_hwdev *hwdev, + enum hinic_mod_type mod, u8 cmd, + void *buf_in, u16 in_size, + void *buf_out, u16 *out_size) +{ + struct card_node *chip_node = hwdev->chip_node; + + if (mod == HINIC_MOD_L2NIC) { + if (cmd == HINIC_PORT_CMD_GET_SFP_INFO && + chip_node->rt_cmd->up_send_sfp_info) { + return is_sfp_info_cmd_cached(hwdev, mod, cmd, buf_in, + in_size, buf_out, + out_size); + } else if (cmd == HINIC_PORT_CMD_GET_SFP_ABS && + chip_node->rt_cmd->up_send_sfp_abs) { + return is_sfp_abs_cmd_cached(hwdev, mod, cmd, buf_in, + in_size, buf_out, + out_size); + } + } + + return false; +} + int hinic_msg_to_mgmt_sync(void *hwdev, enum hinic_mod_type mod, u8 cmd, void *buf_in, u16 in_size, void *buf_out, u16 *out_size, u32 timeout) @@ -949,6 +1025,10 @@ int hinic_msg_to_mgmt_sync(void *hwdev, enum hinic_mod_type mod, u8 cmd, err = __func_send_mbox(hwdev, mod, cmd, buf_in, in_size, buf_out, out_size, timeout); } else { + if (driver_processed_cmd(hwdev, mod, cmd, buf_in, in_size, + buf_out, out_size)) + return 0; + do { if (!hinic_get_mgmt_channel_status(hwdev) || !hinic_get_chip_present_flag(hwdev)) @@ -3202,6 +3282,8 @@ enum hinic_event_cmd { HINIC_EVENT_MGMT_PCIE_DFX, HINIC_EVENT_MCTP_HOST_INFO, HINIC_EVENT_MGMT_HEARTBEAT_EHD, + HINIC_EVENT_SFP_INFO_REPORT, + HINIC_EVENT_SFP_ABS_REPORT, HINIC_EVENT_MAX_TYPE, }; @@ -3284,6 +3366,16 @@ static struct hinic_event_convert __event_convert[] = { .cmd = HINIC_MGMT_CMD_HEARTBEAT_EVENT, .event = HINIC_EVENT_MGMT_HEARTBEAT_EHD, }, + { + .mod = HINIC_MOD_L2NIC, + .cmd = HINIC_PORT_CMD_GET_SFP_INFO, + .event = HINIC_EVENT_SFP_INFO_REPORT, + }, + { + .mod = HINIC_MOD_L2NIC, + .cmd = HINIC_PORT_CMD_GET_SFP_ABS, + .event = HINIC_EVENT_SFP_ABS_REPORT, + }, }; static enum hinic_event_cmd __get_event_type(u8 mod, u8 cmd) @@ -3587,12 +3679,22 @@ static void module_status_event(struct hinic_hwdev *hwdev, struct hinic_cable_plug_event *plug_event; struct hinic_link_err_event *link_err; struct hinic_event_info event_info = {0}; + struct hinic_port_routine_cmd *rt_cmd; + struct card_node *chip_node = hwdev->chip_node; event_info.type = HINIC_EVENT_PORT_MODULE_EVENT; if (cmd == HINIC_EVENT_CABLE_PLUG) { plug_event = buf_in; + if (plug_event->port_id < HINIC_MAX_PORT_ID) { + rt_cmd = &chip_node->rt_cmd[plug_event->port_id]; + mutex_lock(&chip_node->sfp_mutex); + rt_cmd->up_send_sfp_abs = false; + rt_cmd->up_send_sfp_info = false; + mutex_unlock(&chip_node->sfp_mutex); + } + event_info.module_event.type = plug_event->plugged ? HINIC_PORT_MODULE_CABLE_PLUGGED : HINIC_PORT_MODULE_CABLE_UNPLUGGED; @@ -3733,6 +3835,64 @@ static void mgmt_watchdog_timeout_event_handler(struct hinic_hwdev *hwdev, queue_work(hwdev->workq, &hwdev->fault_work); } +static void port_sfp_info_event(struct hinic_hwdev *hwdev, void *buf_in, + u16 in_size, void *buf_out, u16 *out_size) +{ + struct hinic_cmd_get_sfp_qsfp_info *sfp_info = buf_in; + struct hinic_port_routine_cmd *rt_cmd; + struct card_node *chip_node = hwdev->chip_node; + + if (in_size != sizeof(*sfp_info)) { + sdk_err(hwdev->dev_hdl, "Invalid sfp info cmd, length: %d, should be %ld\n", + in_size, sizeof(*sfp_info)); + return; + } + + if (sfp_info->port_id >= HINIC_MAX_PORT_ID) { + sdk_err(hwdev->dev_hdl, "Invalid sfp port id: %d, max port is %d\n", + sfp_info->port_id, HINIC_MAX_PORT_ID - 1); + return; + } + + if (!chip_node->rt_cmd) + return; + + rt_cmd = &chip_node->rt_cmd[sfp_info->port_id]; + mutex_lock(&chip_node->sfp_mutex); + memcpy(&rt_cmd->sfp_info, sfp_info, sizeof(rt_cmd->sfp_info)); + rt_cmd->up_send_sfp_info = true; + mutex_unlock(&chip_node->sfp_mutex); +} + +static void port_sfp_abs_event(struct hinic_hwdev *hwdev, void *buf_in, + u16 in_size, void *buf_out, u16 *out_size) +{ + struct hinic_cmd_get_light_module_abs *sfp_abs = buf_in; + struct hinic_port_routine_cmd *rt_cmd; + struct card_node *chip_node = hwdev->chip_node; + + if (in_size != sizeof(*sfp_abs)) { + sdk_err(hwdev->dev_hdl, "Invalid sfp absent cmd, length: %d, should be %ld\n", + in_size, sizeof(*sfp_abs)); + return; + } + + if (sfp_abs->port_id >= HINIC_MAX_PORT_ID) { + sdk_err(hwdev->dev_hdl, "Invalid sfp port id: %d, max port is %d\n", + sfp_abs->port_id, HINIC_MAX_PORT_ID - 1); + return; + } + + if (!chip_node->rt_cmd) + return; + + rt_cmd = &chip_node->rt_cmd[sfp_abs->port_id]; + mutex_lock(&chip_node->sfp_mutex); + memcpy(&rt_cmd->abs, sfp_abs, sizeof(rt_cmd->abs)); + rt_cmd->up_send_sfp_abs = true; + mutex_unlock(&chip_node->sfp_mutex); +} + static void mgmt_reset_event_handler(struct hinic_hwdev *hwdev) { sdk_info(hwdev->dev_hdl, "Mgmt is reset\n"); @@ -4241,6 +4401,14 @@ static void _event_handler(struct hinic_hwdev *hwdev, enum hinic_event_cmd cmd, buf_out, out_size); break; + case HINIC_EVENT_SFP_INFO_REPORT: + port_sfp_info_event(hwdev, buf_in, in_size, buf_out, out_size); + break; + + case HINIC_EVENT_SFP_ABS_REPORT: + port_sfp_abs_event(hwdev, buf_in, in_size, buf_out, out_size); + break; + default: sdk_warn(hwdev->dev_hdl, "Unsupported event %d to process\n", cmd); diff --git a/drivers/net/ethernet/huawei/hinic/hinic_lld.c b/drivers/net/ethernet/huawei/hinic/hinic_lld.c index e8e446a245fec86f86564983b18882ab6e9ecf1c..3bf47accd9d3ebfe6c7838a430cd622b65d3dc6b 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_lld.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_lld.c @@ -1990,6 +1990,8 @@ static int alloc_chip_node(struct hinic_pcidev *pci_adapter) INIT_LIST_HEAD(&chip_node->func_list); pci_adapter->chip_node = chip_node; + mutex_init(&chip_node->sfp_mutex); + return 0; alloc_dbgtool_attr_file_err: diff --git a/drivers/net/ethernet/huawei/hinic/hinic_mgmt_interface.h b/drivers/net/ethernet/huawei/hinic/hinic_mgmt_interface.h index 13bc351a090237183820d9b9d5b59d9088c97da7..3c3be6e6fa8dced8d9821dbbd74986890d8faaec 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_mgmt_interface.h +++ b/drivers/net/ethernet/huawei/hinic/hinic_mgmt_interface.h @@ -680,6 +680,16 @@ struct hinic_capture_info { u32 data_vlan; }; +struct hinic_port_rt_cmd { + u8 status; + u8 version; + u8 rsvd0[6]; + + u8 pf_id; + u8 enable; + u8 rsvd1[6]; +}; + struct hinic_vf_dcb_state { u8 status; u8 version; @@ -737,6 +747,8 @@ void hinic_vf_func_free(struct hinic_hwdev *hwdev); void hinic_unregister_vf_msg_handler(void *hwdev, u16 vf_id); +int hinic_set_port_routine_cmd_report(void *hwdev, bool enable); + int hinic_refresh_nic_cfg(void *hwdev, struct nic_port_info *port_info); int hinic_save_dcb_state(struct hinic_hwdev *hwdev, diff --git a/drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.c b/drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.c index 07858be0404ceabf1da8143fff2e32fb800f29d2..6ddae363b4a0a057392d5494b59af976c51771de 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.c @@ -35,7 +35,6 @@ #include "hinic_nic.h" #include "hinic_mgmt_interface.h" #include "hinic_hwif.h" -#include "hinic_eqs.h" static unsigned char set_vf_link_state; module_param(set_vf_link_state, byte, 0444); @@ -3571,6 +3570,35 @@ int hinic_set_super_cqe_state(void *hwdev, bool enable) return 0; } +int hinic_set_port_routine_cmd_report(void *hwdev, bool enable) +{ + struct hinic_port_rt_cmd rt_cmd = { 0 }; + struct hinic_hwdev *dev = hwdev; + u16 out_size = sizeof(rt_cmd); + int err; + + if (!hwdev) + return -EINVAL; + + rt_cmd.pf_id = (u8)hinic_global_func_id(hwdev); + rt_cmd.enable = enable; + + err = l2nic_msg_to_mgmt_sync(hwdev, + HINIC_PORT_CMD_SET_PORT_REPORT, + &rt_cmd, sizeof(rt_cmd), &rt_cmd, + &out_size); + if (rt_cmd.status == HINIC_MGMT_CMD_UNSUPPORTED) { + nic_info(dev->dev_hdl, "Current firmware doesn't support to set port routine command report\n"); + } else if (rt_cmd.status || err || !out_size) { + nic_err(dev->dev_hdl, + "Failed to set port routine command report, err: %d, status: 0x%x, out size: 0x%x\n", + err, rt_cmd.status, out_size); + return -EFAULT; + } + + return 0; +} + int hinic_set_func_capture_en(void *hwdev, u16 func_id, bool cap_en) { struct hinic_hwdev *dev = hwdev; @@ -3889,3 +3917,112 @@ int hinic_disable_tx_promisc(void *hwdev) } return 0; } + +static bool hinic_if_sfp_absent(void *hwdev) +{ + struct card_node *chip_node = ((struct hinic_hwdev *)hwdev)->chip_node; + struct hinic_port_routine_cmd *rt_cmd; + struct hinic_cmd_get_light_module_abs sfp_abs = {0}; + u8 port_id = hinic_physical_port_id(hwdev); + u16 out_size = sizeof(sfp_abs); + int err; + bool sfp_abs_valid; + bool sfp_abs_status; + + rt_cmd = &chip_node->rt_cmd[port_id]; + mutex_lock(&chip_node->sfp_mutex); + sfp_abs_valid = rt_cmd->up_send_sfp_abs; + sfp_abs_status = (bool)rt_cmd->abs.abs_status; + if (sfp_abs_valid) { + mutex_unlock(&chip_node->sfp_mutex); + return sfp_abs_status; + } + mutex_unlock(&chip_node->sfp_mutex); + + sfp_abs.port_id = port_id; + err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_GET_SFP_ABS, + &sfp_abs, sizeof(sfp_abs), &sfp_abs, + &out_size); + if (sfp_abs.status || err || !out_size) { + nic_err(((struct hinic_hwdev *)hwdev)->dev_hdl, + "Failed to get port%d sfp absent status, err: %d, status: 0x%x, out size: 0x%x\n", + port_id, err, sfp_abs.status, out_size); + return true; + } + + return ((sfp_abs.abs_status == 0) ? false : true); +} + +int hinic_get_sfp_eeprom(void *hwdev, u8 *data, u16 *len) +{ + struct hinic_cmd_get_std_sfp_info sfp_info = {0}; + u8 port_id; + u16 out_size = sizeof(sfp_info); + int err; + + if (!hwdev || !data || !len) + return -EINVAL; + + port_id = hinic_physical_port_id(hwdev); + if (port_id >= HINIC_MAX_PORT_ID) + return -EINVAL; + + if (hinic_if_sfp_absent(hwdev)) + return -ENXIO; + + sfp_info.port_id = port_id; + err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_GET_STD_SFP_INFO, + &sfp_info, sizeof(sfp_info), &sfp_info, + &out_size); + if (sfp_info.status || err || !out_size) { + nic_err(((struct hinic_hwdev *)hwdev)->dev_hdl, + "Failed to get port%d sfp eeprom information, err: %d, status: 0x%x, out size: 0x%x\n", + port_id, err, sfp_info.status, out_size); + return -EIO; + } + + *len = min_t(u16, sfp_info.eeprom_len, STD_SFP_INFO_MAX_SIZE); + memcpy(data, sfp_info.sfp_info, STD_SFP_INFO_MAX_SIZE); + + return 0; +} + +int hinic_get_sfp_type(void *hwdev, u8 *data0, u8 *data1) +{ + struct card_node *chip_node = NULL; + struct hinic_port_routine_cmd *rt_cmd; + u8 sfp_data[STD_SFP_INFO_MAX_SIZE]; + u16 len; + u8 port_id; + int err; + + if (!hwdev || !data0 || !data1) + return -EINVAL; + + port_id = hinic_physical_port_id(hwdev); + if (port_id >= HINIC_MAX_PORT_ID) + return -EINVAL; + + if (hinic_if_sfp_absent(hwdev)) + return -ENXIO; + + chip_node = ((struct hinic_hwdev *)hwdev)->chip_node; + rt_cmd = &chip_node->rt_cmd[port_id]; + mutex_lock(&chip_node->sfp_mutex); + if (rt_cmd->up_send_sfp_info) { + *data0 = rt_cmd->sfp_info.sfp_qsfp_info[0]; + *data1 = rt_cmd->sfp_info.sfp_qsfp_info[1]; + mutex_unlock(&chip_node->sfp_mutex); + return 0; + } + mutex_unlock(&chip_node->sfp_mutex); + + err = hinic_get_sfp_eeprom(hwdev, sfp_data, &len); + if (err) + return err; + + *data0 = sfp_data[0]; + *data1 = sfp_data[1]; + + return 0; +} diff --git a/drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.h b/drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.h index 395f6d8f29efede7d9d3e47bf2f71dc588df6a4d..eb060fba46275151a0e9209a32db9c03647c0b8c 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.h +++ b/drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.h @@ -620,5 +620,7 @@ int hinic_add_hw_rqfilter(void *hwdev, struct hinic_rq_filter_info *filter_info); int hinic_del_hw_rqfilter(void *hwdev, struct hinic_rq_filter_info *filter_info); +int hinic_get_sfp_eeprom(void *hwdev, u8 *data, u16 *len); +int hinic_get_sfp_type(void *hwdev, u8 *data0, u8 *data1); #endif diff --git a/drivers/net/ethernet/huawei/hinic/hinic_nic_io.c b/drivers/net/ethernet/huawei/hinic/hinic_nic_io.c index 8d131054786b2fc550badab0975e747b70349840..1cb4e2657db5cde5f5cda5151e492c802616df79 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_nic_io.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_nic_io.c @@ -829,13 +829,20 @@ int hinic_init_nic_hwdev(void *hwdev, u16 rx_buff_len) } } } - return 0; + + /* VFs don't set port routine command report */ + if (hinic_func_type(dev) != TYPE_VF) + /* Inform mgmt to send sfp's information to driver */ + err = hinic_set_port_routine_cmd_report(hwdev, true); + + return err; } EXPORT_SYMBOL(hinic_init_nic_hwdev); void hinic_free_nic_hwdev(void *hwdev) { - /* nothing to do for now */ + if (hinic_func_type(hwdev) != TYPE_VF) + hinic_set_port_routine_cmd_report(hwdev, false); } EXPORT_SYMBOL(hinic_free_nic_hwdev); diff --git a/drivers/net/ethernet/huawei/hinic/hinic_port_cmd.h b/drivers/net/ethernet/huawei/hinic/hinic_port_cmd.h index 87305658ab2721f80f298fc5b105bfac92ab8694..46464b1fe20c4bd5db2b04f03398e6da29876108 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_port_cmd.h +++ b/drivers/net/ethernet/huawei/hinic/hinic_port_cmd.h @@ -146,6 +146,8 @@ enum hinic_port_cmd { HINIC_PORT_CMD_SET_PORT_LINK_STATUS = 0x76, HINIC_PORT_CMD_SET_CGE_PAUSE_TIME_CFG = 0x77, + HINIC_PORT_CMD_SET_PORT_REPORT = 0x7B, + HINIC_PORT_CMD_LINK_STATUS_REPORT = 0xa0, HINIC_PORT_CMD_SET_LOSSLESS_ETH = 0xa3, @@ -200,6 +202,7 @@ enum hinic_port_cmd { HINIC_PORT_CMD_SET_LINK_FOLLOW = 0xF8, HINIC_PORT_CMD_SET_VF_MAX_MIN_RATE = 0xF9, HINIC_PORT_CMD_SET_RXQ_LRO_ADPT = 0xFA, + HINIC_PORT_CMD_GET_SFP_ABS = 0xFB, HINIC_PORT_CMD_Q_FILTER = 0xFC, HINIC_PORT_CMD_TCAM_FILTER = 0xFE, HINIC_PORT_CMD_SET_VLAN_FILTER = 0xFF,