From: Chiqijun chiqijun@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@huawei.com Reviewed-by: Luoshaokai luoshaokai@huawei.com Signed-off-by: Yang Yingliang yangyingliang@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,
From: Chiqijun chiqijun@huawei.com
driver inclusion category: feature bugzilla: 4472
-----------------------------------------------------------------------
Added support for trust mode on VFs. This allows the VM to change the MAC address of the VF on the host at run time.
Signed-off-by: Chiqijun chiqijun@huawei.com Reviewed-by: Luoshaokai luoshaokai@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/net/ethernet/huawei/hinic/hinic_main.c | 8 ++++ drivers/net/ethernet/huawei/hinic/hinic_nic.h | 1 + drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.c | 45 ++++++++++++++++++++-- drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.h | 5 +++ drivers/net/ethernet/huawei/hinic/hinic_sriov.c | 31 +++++++++++++++ drivers/net/ethernet/huawei/hinic/hinic_sriov.h | 4 ++ drivers/net/ethernet/huawei/hinic/ossl_knl_linux.h | 2 + 7 files changed, 93 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_main.c b/drivers/net/ethernet/huawei/hinic/hinic_main.c index 83af4a8..910fed9 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_main.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_main.c @@ -2127,6 +2127,14 @@ static void hinic_nic_set_rx_mode(struct net_device *netdev) #ifdef HAVE_VF_SPOOFCHK_CONFIGURE .ndo_set_vf_spoofchk = hinic_ndo_set_vf_spoofchk, #endif +#ifdef HAVE_NDO_SET_VF_TRUST +#ifdef HAVE_RHEL7_NET_DEVICE_OPS_EXT + .extended.ndo_set_vf_trust = hinic_ndo_set_vf_trust, +#else + .ndo_set_vf_trust = hinic_ndo_set_vf_trust, +#endif /* HAVE_RHEL7_NET_DEVICE_OPS_EXT */ +#endif /* HAVE_NDO_SET_VF_TRUST */ + .ndo_get_vf_config = hinic_ndo_get_vf_config, #endif
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_nic.h b/drivers/net/ethernet/huawei/hinic/hinic_nic.h index 5b5b094..f2fb937 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_nic.h +++ b/drivers/net/ethernet/huawei/hinic/hinic_nic.h @@ -64,6 +64,7 @@ struct vf_data_storage { bool link_forced; bool link_up; /* only valid if VF link is forced */ bool spoofchk; + bool trust; };
struct hinic_nic_cfg { diff --git a/drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.c b/drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.c index 6ddae36..f9e16ec 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.c @@ -2432,7 +2432,8 @@ static int hinic_set_vf_mac_msg_handler(struct hinic_nic_io *nic_io, u16 vf, struct hinic_port_mac_set *mac_out = buf_out; int err;
- if (vf_info->pf_set_mac && is_valid_ether_addr(mac_in->mac)) { + if (vf_info->pf_set_mac && !(vf_info->trust) && + is_valid_ether_addr(mac_in->mac)) { nic_warn(nic_io->hwdev->dev_hdl, "PF has already set VF %d MAC address\n", HW_VF_ID_TO_OS(vf)); mac_out->status = HINIC_PF_SET_VF_ALREADY; @@ -2462,7 +2463,8 @@ static int hinic_del_vf_mac_msg_handler(struct hinic_nic_io *nic_io, u16 vf, struct hinic_port_mac_set *mac_out = buf_out; int err;
- if (vf_info->pf_set_mac && is_valid_ether_addr(mac_in->mac) && + if (vf_info->pf_set_mac && !(vf_info->trust) && + is_valid_ether_addr(mac_in->mac) && !memcmp(vf_info->vf_mac_addr, mac_in->mac, ETH_ALEN)) { nic_warn(nic_io->hwdev->dev_hdl, "PF has already set VF mac.\n"); mac_out->status = HINIC_PF_SET_VF_ALREADY; @@ -2497,7 +2499,7 @@ static int hinic_update_vf_mac_msg_handler(struct hinic_nic_io *nic_io, u16 vf, return -EINVAL; }
- if (vf_info->pf_set_mac) { + if (vf_info->pf_set_mac && !(vf_info->trust)) { nic_warn(nic_io->hwdev->dev_hdl, "PF has already set VF mac.\n"); mac_out->status = HINIC_PF_SET_VF_ALREADY; *out_size = sizeof(*mac_out); @@ -3026,6 +3028,10 @@ void hinic_get_vf_config(void *hwdev, u16 vf_id, struct ifla_vf_info *ivi) ivi->spoofchk = vfinfo->spoofchk; #endif
+#ifdef HAVE_NDO_SET_VF_TRUST + ivi->trusted = vfinfo->trust; +#endif + #ifdef HAVE_NDO_SET_VF_MIN_MAX_TX_RATE ivi->max_tx_rate = vfinfo->max_rate; ivi->min_tx_rate = vfinfo->min_rate; @@ -3063,6 +3069,11 @@ void hinic_clear_vf_infos(void *hwdev, u16 vf_id) if (vf_infos->spoofchk) hinic_set_vf_spoofchk(hwdev, vf_id, false);
+#ifdef HAVE_NDO_SET_VF_TRUST + if (vf_infos->trust) + hinic_set_vf_trust(hwdev, vf_id, false); +#endif + memset(vf_infos, 0, sizeof(*vf_infos)); /* set vf_infos to default */ hinic_init_vf_infos(hw_dev->nic_io, HW_VF_ID_TO_OS(vf_id)); @@ -3181,6 +3192,24 @@ int hinic_set_vf_spoofchk(void *hwdev, u16 vf_id, bool spoofchk) return err; }
+#ifdef HAVE_NDO_SET_VF_TRUST +int hinic_set_vf_trust(void *hwdev, u16 vf_id, bool trust) +{ + struct hinic_hwdev *hw_dev = hwdev; + struct hinic_nic_io *nic_io = NULL; + struct vf_data_storage *vf_infos = NULL; + + if (!hwdev) + return -EINVAL; + + nic_io = hw_dev->nic_io; + vf_infos = nic_io->vf_infos; + vf_infos[HW_VF_ID_TO_OS(vf_id)].trust = trust; + + return 0; +} +#endif + bool hinic_vf_info_spoofchk(void *hwdev, int vf_id) { struct hinic_nic_io *nic_io = ((struct hinic_hwdev *)hwdev)->nic_io; @@ -3189,6 +3218,16 @@ bool hinic_vf_info_spoofchk(void *hwdev, int vf_id) return spoofchk; }
+#ifdef HAVE_NDO_SET_VF_TRUST +bool hinic_vf_info_trust(void *hwdev, int vf_id) +{ + struct hinic_nic_io *nic_io = ((struct hinic_hwdev *)hwdev)->nic_io; + bool trust = nic_io->vf_infos[HW_VF_ID_TO_OS(vf_id)].trust; + + return trust; +} +#endif + static int hinic_set_vf_rate_limit(void *hwdev, u16 vf_id, u32 tx_rate) { struct hinic_hwdev *hw_dev = hwdev; diff --git a/drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.h b/drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.h index eb060fb..427d469 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.h +++ b/drivers/net/ethernet/huawei/hinic/hinic_nic_cfg.h @@ -578,6 +578,11 @@ int hinic_get_rss_type(void *hwdev, u32 tmpl_idx,
bool hinic_vf_info_spoofchk(void *hwdev, int vf_id);
+#ifdef HAVE_NDO_SET_VF_TRUST +int hinic_set_vf_trust(void *hwdev, u16 vf_id, bool trust); +bool hinic_vf_info_trust(void *hwdev, int vf_id); +#endif + int hinic_set_vf_tx_rate(void *hwdev, u16 vf_id, u32 max_rate, u32 min_rate);
int hinic_init_vf_hw(void *hwdev, u16 start_vf_id, u16 end_vf_id); diff --git a/drivers/net/ethernet/huawei/hinic/hinic_sriov.c b/drivers/net/ethernet/huawei/hinic/hinic_sriov.c index 0ec12d9..37d0116 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_sriov.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_sriov.c @@ -356,6 +356,37 @@ int hinic_ndo_set_vf_spoofchk(struct net_device *netdev, int vf, bool setting) } #endif
+#ifdef HAVE_NDO_SET_VF_TRUST +int hinic_ndo_set_vf_trust(struct net_device *netdev, int vf, bool setting) +{ + struct hinic_nic_dev *adapter = netdev_priv(netdev); + struct hinic_sriov_info *sriov_info; + int err = 0; + bool cur_trust; + + sriov_info = hinic_get_sriov_info_by_pcidev(adapter->pdev); + if (vf >= sriov_info->num_vfs) + return -EINVAL; + + cur_trust = hinic_vf_info_trust(sriov_info->hwdev, + OS_VF_ID_TO_HW(vf)); + /* same request, so just return success */ + if ((setting && cur_trust) || (!setting && !cur_trust)) + return 0; + + err = hinic_set_vf_trust(sriov_info->hwdev, + OS_VF_ID_TO_HW(vf), setting); + if (!err) + nicif_info(adapter, drv, netdev, "Set VF %d trusted %s succeed\n", + vf, setting ? "on" : "off"); + else + nicif_err(adapter, drv, netdev, "Failed set VF %d trusted %s\n", + vf, setting ? "on" : "off"); + + return err; +} +#endif + int hinic_ndo_get_vf_config(struct net_device *netdev, int vf, struct ifla_vf_info *ivi) { diff --git a/drivers/net/ethernet/huawei/hinic/hinic_sriov.h b/drivers/net/ethernet/huawei/hinic/hinic_sriov.h index 6dc60d9..a1188fd 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_sriov.h +++ b/drivers/net/ethernet/huawei/hinic/hinic_sriov.h @@ -59,6 +59,10 @@ int hinic_ndo_get_vf_config(struct net_device *netdev, int vf, int hinic_ndo_set_vf_spoofchk(struct net_device *netdev, int vf, bool setting); #endif
+#ifdef HAVE_NDO_SET_VF_TRUST +int hinic_ndo_set_vf_trust(struct net_device *netdev, int vf, bool setting); +#endif + int hinic_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link);
#ifdef HAVE_NDO_SET_VF_MIN_MAX_TX_RATE diff --git a/drivers/net/ethernet/huawei/hinic/ossl_knl_linux.h b/drivers/net/ethernet/huawei/hinic/ossl_knl_linux.h index 8cdcb1d..f99e1db 100644 --- a/drivers/net/ethernet/huawei/hinic/ossl_knl_linux.h +++ b/drivers/net/ethernet/huawei/hinic/ossl_knl_linux.h @@ -265,6 +265,8 @@ enum ethtool_link_mode_bit_indices { #define HAVE_SKB_L4_RXHASH #endif
+#define HAVE_NDO_SET_VF_TRUST + /*****************************************************************************/ #define HAVE_ETHTOOL_GRXFHINDIR_SIZE #define HAVE_INT_NDO_VLAN_RX_ADD_VID
From: Liu Yanshi liuyanshi@huawei.com
driver inclusion category: bugfix bugzilla: NA CVE: NA
hisi_pcie_cae add judgement abount chip type and modifies some variables name.
Signed-off-by: Liu Yanshi liuyanshi@huawei.com Reviewed-by: Zhu Xiongxiong zhuxiongxiong@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- .../controller/hisi-pcie-customer/hisi_pcie_cae.c | 58 +++++++++++++++------- 1 file changed, 39 insertions(+), 19 deletions(-)
diff --git a/drivers/pci/controller/hisi-pcie-customer/hisi_pcie_cae.c b/drivers/pci/controller/hisi-pcie-customer/hisi_pcie_cae.c index 6229a54..fb7dbca 100644 --- a/drivers/pci/controller/hisi-pcie-customer/hisi_pcie_cae.c +++ b/drivers/pci/controller/hisi-pcie-customer/hisi_pcie_cae.c @@ -7,6 +7,7 @@ #include <linux/device.h> #include <linux/module.h> #include <linux/io.h> +#include <linux/pci.h>
#define CHIP_OFFSET 0x200000000000UL #define APB_SUBCTRL_BASE 0x148070000UL @@ -23,7 +24,8 @@ #define TYPE_SHIFT 4 #define BIT_SHIFT_8 8 #define PCIE_CMD_GET_CHIPNUMS 0x01 - +#define HI1620_PCI_VENDOR_ID 0x19e5 +#define HI1620_PCI_DEVICE_ID 0xa120 #define DEVICE_NAME "pcie_reg_dev"
enum chip_type_t { @@ -55,7 +57,7 @@ static int pcie_reg_mmap(struct file *filep, struct vm_area_struct *vma) u64 phy_addr;
if (chip_id >= current_chip_nums) { - pr_info("[PCIe Base] input chip_id %u is invalid\n", chip_id); + pr_err("pcie_cae input chip_id %u is invalid\n", chip_id); return -EINVAL; }
@@ -64,26 +66,26 @@ static int pcie_reg_mmap(struct file *filep, struct vm_area_struct *vma) case MMAP_TYPE_APB: phy_addr = APB_SUBCTRL_BASE + CHIP_OFFSET * chip_id; if (size > PCIE_REG_SIZE) { - pr_info("[PCIe Base] mmap_type_apb map size is invalid\n"); + pr_err("pcie_cae mmap_type_apb map size is invalid\n"); return -EINVAL; } break; case MMAP_TYPE_NVME: phy_addr = NVME_BAR_BASE + CHIP_OFFSET * chip_id; if (size > NVME_BAR_SIZE) { - pr_info("[PCIe Base] mmap_type_nvme map size is invalid\n"); + pr_err("pcie_cae mmap_type_nvme map size is invalid\n"); return -EINVAL; } break; case MMAP_TYPE_VIRTIO: phy_addr = VIRTIO_BAR_BASE + CHIP_OFFSET * chip_id; if (size > VIRTIO_BAR_SIZE) { - pr_info("[PCIe Base] mmap_type_virtio map size is invalid\n"); + pr_err("pcie_cae mmap_type_virtio map size is invalid\n"); return -EINVAL; } break; default: - pr_info("[PCIe Base] input addr type %u is invalid\n", type); + pr_err("pcie_cae input addr type %u is invalid\n", type); return -EINVAL; } vma->vm_pgoff = phy_addr >> PAGE_SHIFT; @@ -95,7 +97,7 @@ static int pcie_reg_mmap(struct file *filep, struct vm_area_struct *vma) vma->vm_pgoff, size, vma->vm_page_prot)) { - pr_info("[PCIe Base] map pcie reg zone failed\n"); + pr_err("pcie_cae map pcie reg zone failed\n"); return -EAGAIN; }
@@ -125,10 +127,28 @@ static int pcie_open(struct inode *inode, struct file *f) { void __iomem *addr_base; u32 val; + struct pci_dev *dev; + int type; + + dev = pci_get_device(HI1620_PCI_VENDOR_ID, HI1620_PCI_DEVICE_ID, NULL); + if (!dev) { + pr_err("pcie_cae can only work at Hi1620 series chip\n"); + return -EINVAL; + } + + type = pci_pcie_type(dev); + pr_info("pcie_cae detect chip PCIe Vendor ID:0x%x, Device ID:0x%x\n", + dev->vendor, dev->device); + pci_dev_put(dev); + + if (type != PCI_EXP_TYPE_ROOT_PORT) { + pr_err("pcie_cae can not support this chip\n"); + return -EINVAL; + }
addr_base = ioremap_nocache(SYSCTRL_SC_ECO_RSV1, CHIP_INFO_REG_SIZE); if (!addr_base) { - pr_info("[PCIe Base] map chip_info_reg zone failed\n"); + pr_err("pcie_cae map chip_info_reg zone failed\n"); return -EPERM; }
@@ -136,7 +156,6 @@ static int pcie_open(struct inode *inode, struct file *f) current_chip_nums = pcie_get_chipnums(val);
iounmap(addr_base); - addr_base = NULL;
return 0; } @@ -154,27 +173,28 @@ static long pcie_reg_ioctl(struct file *pfile, unsigned int cmd, switch (cmd) { case PCIE_CMD_GET_CHIPNUMS: if ((void *)arg == NULL) { - pr_info("[PCIe Base] invalid arg address\n"); + pr_err("pcie_cae invalid arg address\n"); ret = -EINVAL; break; }
if (copy_to_user((void *)arg, (void *)¤t_chip_nums, sizeof(int))) { - pr_info("[PCIe Base] copy chip_nums to usr failed\n"); + pr_err("pcie_cae copy chip_nums to usr failed\n"); ret = -EINVAL; } break;
default: - pr_info("[PCIe Base] invalid pcie ioctl cmd:%u\n", cmd); + pr_err("pcie_cae invalid pcie ioctl cmd:%u\n", cmd); + ret = -EINVAL; break; }
return ret; }
-static const struct file_operations pcie_dfx_fops = { +static const struct file_operations pcie_cae_fops = { .owner = THIS_MODULE, .open = pcie_open, .release = pcie_release, @@ -183,25 +203,25 @@ static long pcie_reg_ioctl(struct file *pfile, unsigned int cmd, .unlocked_ioctl = pcie_reg_ioctl, };
-static struct miscdevice pcie_dfx_misc = { +static struct miscdevice pcie_cae_misc = { .minor = MISC_DYNAMIC_MINOR, - .fops = &pcie_dfx_fops, + .fops = &pcie_cae_fops, .name = DEVICE_NAME, };
static int __init misc_dev_init(void) { - return misc_register(&pcie_dfx_misc); + return misc_register(&pcie_cae_misc); }
static void __exit misc_dev_exit(void) { - (void)misc_deregister(&pcie_dfx_misc); + (void)misc_deregister(&pcie_cae_misc); }
module_init(misc_dev_init); module_exit(misc_dev_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Huawei Technology Company"); -MODULE_DESCRIPTION("PCIe DFX TOOL"); -MODULE_VERSION("V1.1"); +MODULE_DESCRIPTION("PCIe CAE Driver"); +MODULE_VERSION("V1.2");