From: Chiqijun <chiqijun(a)huawei.com>
driver inclusion
category: feature
bugzilla: 4472
-----------------------------------------------------------------------
Obtaining optical module information is time-consuming. If the user
frequently acquires, it will affect the firmware to process other
commands. To prevent such events, the firmware will actively report
the optical module information to the driver when it is idle. Obtained
from the driver cache information. When the user obtains through the
command, directly obtain from the information saved by the driver.
Signed-off-by: Chiqijun <chiqijun(a)huawei.com>
Reviewed-by: Luoshaokai <luoshaokai(a)huawei.com>
Signed-off-by: Yang Yingliang <yangyingliang(a)huawei.com>
---
drivers/net/ethernet/huawei/hinic/hinic_ethtool.c | 77 ++++++++++
drivers/net/ethernet/huawei/hinic/hinic_hw.h | 54 +++++++
drivers/net/ethernet/huawei/hinic/hinic_hwdev.c | 168 +++++++++++++++++++++
drivers/net/ethernet/huawei/hinic/hinic_lld.c | 2 +
.../ethernet/huawei/hinic/hinic_mgmt_interface.h | 12 ++
drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.c | 139 ++++++++++++++++-
drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.h | 2 +
drivers/net/ethernet/huawei/hinic/hinic_nic_io.c | 11 +-
drivers/net/ethernet/huawei/hinic/hinic_port_cmd.h | 3 +
9 files changed, 465 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c b/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c
index f321365..78d32ea 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 int hinic_set_rxfh_indir(struct net_device *netdev, const u32 *indir)
#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 int hinic_set_rxfh_indir(struct net_device *netdev, const u32 *indir)
.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 e489a00..d4becb6 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 101b671..172be6c 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 @@ struct hinic_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 e8e446a..3bf47ac 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 13bc351..3c3be6e 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 @@ struct hinic_set_link_follow {
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 07858be..6ddae36 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 395f6d8..eb060fb 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 8d13105..1cb4e26 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 8730565..46464b1f 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,
--
1.8.3