diff options
Diffstat (limited to 'drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c')
| -rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c | 245 |
1 files changed, 197 insertions, 48 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index f09e787af0b..f33559b7252 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c @@ -39,6 +39,9 @@ static int qlcnic_83xx_init_default_driver(struct qlcnic_adapter *adapter); static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev); static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter); +static int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev); +static int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *); +static void qlcnic_83xx_stop_hw(struct qlcnic_adapter *); /* Template header */ struct qlc_83xx_reset_hdr { @@ -380,7 +383,7 @@ static int qlcnic_83xx_idc_tx_soft_reset(struct qlcnic_adapter *adapter) qlcnic_up(adapter, netdev); netif_device_attach(netdev); clear_bit(__QLCNIC_RESETTING, &adapter->state); - dev_err(&adapter->pdev->dev, "%s:\n", __func__); + netdev_info(adapter->netdev, "%s: soft reset complete.\n", __func__); return 0; } @@ -614,8 +617,7 @@ int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *adapter) qlcnic_83xx_reinit_mbx_work(adapter->ahw->mailbox); qlcnic_83xx_enable_mbx_interrupt(adapter); - /* register for NIC IDC AEN Events */ - qlcnic_83xx_register_nic_idc_func(adapter, 1); + qlcnic_83xx_initialize_nic(adapter, 1); err = qlcnic_sriov_pf_reinit(adapter); if (err) @@ -636,7 +638,7 @@ int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *adapter) if (adapter->portnum == 0) qlcnic_set_drv_version(adapter); - qlcnic_dcb_get_info(adapter); + qlcnic_dcb_get_info(adapter->dcb); qlcnic_83xx_idc_attach_driver(adapter); return 0; @@ -740,6 +742,7 @@ static int qlcnic_83xx_idc_unknown_state(struct qlcnic_adapter *adapter) adapter->ahw->idc.err_code = -EIO; dev_err(&adapter->pdev->dev, "%s: Device in unknown state\n", __func__); + clear_bit(__QLCNIC_RESETTING, &adapter->state); return 0; } @@ -846,6 +849,10 @@ static int qlcnic_83xx_idc_ready_state(struct qlcnic_adapter *adapter) clear_bit(QLC_83XX_MBX_READY, &mbx->status); set_bit(__QLCNIC_RESETTING, &adapter->state); qlcnic_83xx_idc_enter_need_reset_state(adapter, 1); + } else { + netdev_info(adapter->netdev, "%s: Auto firmware recovery is disabled\n", + __func__); + qlcnic_83xx_idc_enter_failed_state(adapter, 1); } return -EIO; } @@ -897,7 +904,7 @@ static int qlcnic_83xx_idc_need_reset_state(struct qlcnic_adapter *adapter) qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1); set_bit(__QLCNIC_RESETTING, &adapter->state); clear_bit(QLC_83XX_MBX_READY, &mbx->status); - if (adapter->ahw->nic_mode == QLC_83XX_VIRTUAL_NIC_MODE) + if (adapter->ahw->nic_mode == QLCNIC_VNIC_MODE) qlcnic_83xx_disable_vnic_mode(adapter, 1); if (qlcnic_check_diag_status(adapter)) { @@ -943,13 +950,26 @@ static int qlcnic_83xx_idc_need_quiesce_state(struct qlcnic_adapter *adapter) return 0; } -static int qlcnic_83xx_idc_failed_state(struct qlcnic_adapter *adapter) +static void qlcnic_83xx_idc_failed_state(struct qlcnic_adapter *adapter) { - dev_err(&adapter->pdev->dev, "%s: please restart!!\n", __func__); + struct qlcnic_hardware_context *ahw = adapter->ahw; + u32 val, owner; + + val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL); + if (val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY) { + owner = qlcnic_83xx_idc_find_reset_owner_id(adapter); + if (ahw->pci_func == owner) { + qlcnic_83xx_stop_hw(adapter); + qlcnic_dump_fw(adapter); + } + } + + netdev_warn(adapter->netdev, "%s: Reboot will be required to recover the adapter!!\n", + __func__); clear_bit(__QLCNIC_RESETTING, &adapter->state); - adapter->ahw->idc.err_code = -EIO; + ahw->idc.err_code = -EIO; - return 0; + return; } static int qlcnic_83xx_idc_quiesce_state(struct qlcnic_adapter *adapter) @@ -1000,10 +1020,99 @@ static int qlcnic_83xx_idc_check_state_validity(struct qlcnic_adapter *adapter, return 0; } +#ifdef CONFIG_QLCNIC_VXLAN +#define QLC_83XX_ENCAP_TYPE_VXLAN BIT_1 +#define QLC_83XX_MATCH_ENCAP_ID BIT_2 +#define QLC_83XX_SET_VXLAN_UDP_DPORT BIT_3 +#define QLC_83XX_VXLAN_UDP_DPORT(PORT) ((PORT & 0xffff) << 16) + +#define QLCNIC_ENABLE_INGRESS_ENCAP_PARSING 1 +#define QLCNIC_DISABLE_INGRESS_ENCAP_PARSING 0 + +static int qlcnic_set_vxlan_port(struct qlcnic_adapter *adapter) +{ + u16 port = adapter->ahw->vxlan_port; + struct qlcnic_cmd_args cmd; + int ret = 0; + + memset(&cmd, 0, sizeof(cmd)); + + ret = qlcnic_alloc_mbx_args(&cmd, adapter, + QLCNIC_CMD_INIT_NIC_FUNC); + if (ret) + return ret; + + cmd.req.arg[1] = QLC_83XX_MULTI_TENANCY_INFO; + cmd.req.arg[2] = QLC_83XX_ENCAP_TYPE_VXLAN | + QLC_83XX_SET_VXLAN_UDP_DPORT | + QLC_83XX_VXLAN_UDP_DPORT(port); + + ret = qlcnic_issue_cmd(adapter, &cmd); + if (ret) + netdev_err(adapter->netdev, + "Failed to set VXLAN port %d in adapter\n", + port); + + qlcnic_free_mbx_args(&cmd); + + return ret; +} + +static int qlcnic_set_vxlan_parsing(struct qlcnic_adapter *adapter, + bool state) +{ + u16 vxlan_port = adapter->ahw->vxlan_port; + struct qlcnic_cmd_args cmd; + int ret = 0; + + memset(&cmd, 0, sizeof(cmd)); + + ret = qlcnic_alloc_mbx_args(&cmd, adapter, + QLCNIC_CMD_SET_INGRESS_ENCAP); + if (ret) + return ret; + + cmd.req.arg[1] = state ? QLCNIC_ENABLE_INGRESS_ENCAP_PARSING : + QLCNIC_DISABLE_INGRESS_ENCAP_PARSING; + + ret = qlcnic_issue_cmd(adapter, &cmd); + if (ret) + netdev_err(adapter->netdev, + "Failed to %s VXLAN parsing for port %d\n", + state ? "enable" : "disable", vxlan_port); + else + netdev_info(adapter->netdev, + "%s VXLAN parsing for port %d\n", + state ? "Enabled" : "Disabled", vxlan_port); + + qlcnic_free_mbx_args(&cmd); + + return ret; +} +#endif + static void qlcnic_83xx_periodic_tasks(struct qlcnic_adapter *adapter) { if (adapter->fhash.fnum) qlcnic_prune_lb_filters(adapter); + +#ifdef CONFIG_QLCNIC_VXLAN + if (adapter->flags & QLCNIC_ADD_VXLAN_PORT) { + if (qlcnic_set_vxlan_port(adapter)) + return; + + if (qlcnic_set_vxlan_parsing(adapter, true)) + return; + + adapter->flags &= ~QLCNIC_ADD_VXLAN_PORT; + } else if (adapter->flags & QLCNIC_DEL_VXLAN_PORT) { + if (qlcnic_set_vxlan_parsing(adapter, false)) + return; + + adapter->ahw->vxlan_port = 0; + adapter->flags &= ~QLCNIC_DEL_VXLAN_PORT; + } +#endif } /** @@ -1208,10 +1317,10 @@ void qlcnic_83xx_idc_request_reset(struct qlcnic_adapter *adapter, u32 key) } val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL); - if ((val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY) || - !qlcnic_auto_fw_reset) { - dev_err(&adapter->pdev->dev, - "%s:failed, device in non reset mode\n", __func__); + if (val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY) { + netdev_info(adapter->netdev, "%s: Auto firmware recovery is disabled\n", + __func__); + qlcnic_83xx_idc_enter_failed_state(adapter, 0); qlcnic_83xx_unlock_driver(adapter); return; } @@ -1243,24 +1352,24 @@ static int qlcnic_83xx_copy_bootloader(struct qlcnic_adapter *adapter) if (size & 0xF) size = (size + 16) & ~0xF; - p_cache = kzalloc(size, GFP_KERNEL); + p_cache = vzalloc(size); if (p_cache == NULL) return -ENOMEM; ret = qlcnic_83xx_lockless_flash_read32(adapter, src, p_cache, size / sizeof(u32)); if (ret) { - kfree(p_cache); + vfree(p_cache); return ret; } /* 16 byte write to MS memory */ - ret = qlcnic_83xx_ms_mem_write128(adapter, dest, (u32 *)p_cache, - size / 16); + ret = qlcnic_ms_mem_write128(adapter, dest, (u32 *)p_cache, + size / 16); if (ret) { - kfree(p_cache); + vfree(p_cache); return ret; } - kfree(p_cache); + vfree(p_cache); return ret; } @@ -1280,8 +1389,8 @@ static int qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter) p_cache = (u32 *)fw->data; addr = (u64)dest; - ret = qlcnic_83xx_ms_mem_write128(adapter, addr, - (u32 *)p_cache, size / 16); + ret = qlcnic_ms_mem_write128(adapter, addr, + p_cache, size / 16); if (ret) { dev_err(&adapter->pdev->dev, "MS memory write failed\n"); release_firmware(fw); @@ -1296,8 +1405,8 @@ static int qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter) data[i] = fw->data[size + i]; for (; i < 16; i++) data[i] = 0; - ret = qlcnic_83xx_ms_mem_write128(adapter, addr, - (u32 *)data, 1); + ret = qlcnic_ms_mem_write128(adapter, addr, + (u32 *)data, 1); if (ret) { dev_err(&adapter->pdev->dev, "MS memory write failed\n"); @@ -1511,7 +1620,7 @@ static int qlcnic_83xx_check_cmd_peg_status(struct qlcnic_adapter *p_dev) return -EIO; } -int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev) +static int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev) { int err; @@ -1584,7 +1693,7 @@ static int qlcnic_83xx_reset_template_checksum(struct qlcnic_adapter *p_dev) } } -int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *p_dev) +static int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *p_dev) { struct qlcnic_hardware_context *ahw = p_dev->ahw; u32 addr, count, prev_ver, curr_ver; @@ -1983,6 +2092,14 @@ static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter) val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL); if (!(val & QLC_83XX_IDC_GRACEFULL_RESET)) qlcnic_dump_fw(adapter); + + if (val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY) { + netdev_info(adapter->netdev, "%s: Auto firmware recovery is disabled\n", + __func__); + qlcnic_83xx_idc_enter_failed_state(adapter, 1); + return err; + } + qlcnic_83xx_init_hw(adapter); if (qlcnic_83xx_copy_bootloader(adapter)) @@ -2003,7 +2120,7 @@ static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter) return 0; } -int qlcnic_83xx_get_nic_configuration(struct qlcnic_adapter *adapter) +static int qlcnic_83xx_get_nic_configuration(struct qlcnic_adapter *adapter) { int err; struct qlcnic_info nic_info; @@ -2034,7 +2151,7 @@ int qlcnic_83xx_get_nic_configuration(struct qlcnic_adapter *adapter) return QLC_83XX_DEFAULT_OPMODE; if (ahw->capabilities & QLC_83XX_ESWITCH_CAPABILITY) - return QLC_83XX_VIRTUAL_NIC_MODE; + return QLCNIC_VNIC_MODE; return QLC_83XX_DEFAULT_OPMODE; } @@ -2042,25 +2159,36 @@ int qlcnic_83xx_get_nic_configuration(struct qlcnic_adapter *adapter) int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter) { struct qlcnic_hardware_context *ahw = adapter->ahw; + u16 max_sds_rings, max_tx_rings; int ret; ret = qlcnic_83xx_get_nic_configuration(adapter); if (ret == -EIO) return -EIO; - if (ret == QLC_83XX_VIRTUAL_NIC_MODE) { - ahw->nic_mode = QLC_83XX_VIRTUAL_NIC_MODE; + if (ret == QLCNIC_VNIC_MODE) { + ahw->nic_mode = QLCNIC_VNIC_MODE; + if (qlcnic_83xx_config_vnic_opmode(adapter)) return -EIO; + max_sds_rings = QLCNIC_MAX_VNIC_SDS_RINGS; + max_tx_rings = QLCNIC_MAX_VNIC_TX_RINGS; } else if (ret == QLC_83XX_DEFAULT_OPMODE) { - ahw->nic_mode = QLC_83XX_DEFAULT_MODE; + ahw->nic_mode = QLCNIC_DEFAULT_MODE; adapter->nic_ops->init_driver = qlcnic_83xx_init_default_driver; ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry; + max_sds_rings = QLCNIC_MAX_SDS_RINGS; + max_tx_rings = QLCNIC_MAX_TX_RINGS; } else { + dev_err(&adapter->pdev->dev, "%s: Invalid opmode %d\n", + __func__, ret); return -EIO; } + adapter->max_sds_rings = min(ahw->max_rx_ques, max_sds_rings); + adapter->max_tx_rings = min(ahw->max_tx_ques, max_tx_rings); + return 0; } @@ -2159,13 +2287,34 @@ static int qlcnic_83xx_get_fw_info(struct qlcnic_adapter *adapter) return err; } +static void qlcnic_83xx_init_rings(struct qlcnic_adapter *adapter) +{ + u8 rx_cnt = QLCNIC_DEF_SDS_RINGS; + u8 tx_cnt = QLCNIC_DEF_TX_RINGS; + + adapter->max_tx_rings = QLCNIC_MAX_TX_RINGS; + adapter->max_sds_rings = QLCNIC_MAX_SDS_RINGS; + + if (!adapter->ahw->msix_supported) { + rx_cnt = QLCNIC_SINGLE_RING; + tx_cnt = QLCNIC_SINGLE_RING; + } + + /* compute and set drv sds rings */ + qlcnic_set_tx_ring_count(adapter, tx_cnt); + qlcnic_set_sds_ring_count(adapter, rx_cnt); +} int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac) { struct qlcnic_hardware_context *ahw = adapter->ahw; int err = 0; + adapter->rx_mac_learn = false; ahw->msix_supported = !!qlcnic_use_msi_x; + + qlcnic_83xx_init_rings(adapter); + err = qlcnic_83xx_init_mailbox_work(adapter); if (err) goto exit; @@ -2178,51 +2327,53 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac) return err; } + if (qlcnic_83xx_read_flash_descriptor_table(adapter) || + qlcnic_83xx_read_flash_mfg_id(adapter)) { + dev_err(&adapter->pdev->dev, "Failed reading flash mfg id\n"); + err = -ENOTRECOVERABLE; + goto detach_mbx; + } + err = qlcnic_83xx_check_hw_status(adapter); if (err) goto detach_mbx; - if (!qlcnic_83xx_read_flash_descriptor_table(adapter)) - qlcnic_83xx_read_flash_mfg_id(adapter); - err = qlcnic_83xx_get_fw_info(adapter); if (err) goto detach_mbx; err = qlcnic_83xx_idc_init(adapter); if (err) - goto clear_fw_info; + goto detach_mbx; - err = qlcnic_setup_intr(adapter, 0, 0); + err = qlcnic_setup_intr(adapter); if (err) { dev_err(&adapter->pdev->dev, "Failed to setup interrupt\n"); goto disable_intr; } + INIT_DELAYED_WORK(&adapter->idc_aen_work, qlcnic_83xx_idc_aen_work); + err = qlcnic_83xx_setup_mbx_intr(adapter); if (err) goto disable_mbx_intr; qlcnic_83xx_clear_function_resources(adapter); - - INIT_DELAYED_WORK(&adapter->idc_aen_work, qlcnic_83xx_idc_aen_work); - - /* register for NIC IDC AEN Events */ - qlcnic_83xx_register_nic_idc_func(adapter, 1); + qlcnic_dcb_enable(adapter->dcb); + qlcnic_83xx_initialize_nic(adapter, 1); + qlcnic_dcb_get_info(adapter->dcb); /* Configure default, SR-IOV or Virtual NIC mode of operation */ err = qlcnic_83xx_configure_opmode(adapter); if (err) goto disable_mbx_intr; + /* Perform operating mode specific initialization */ err = adapter->nic_ops->init_driver(adapter); if (err) goto disable_mbx_intr; - if (adapter->dcb && qlcnic_dcb_attach(adapter)) - qlcnic_clear_dcb_ops(adapter); - /* Periodically monitor device status */ qlcnic_83xx_idc_poll_dev_state(&adapter->fw_work.work); return 0; @@ -2233,12 +2384,10 @@ disable_mbx_intr: disable_intr: qlcnic_teardown_intr(adapter); -clear_fw_info: - kfree(ahw->fw_info); - detach_mbx: qlcnic_83xx_detach_mailbox_work(adapter); qlcnic_83xx_free_mailbox(ahw->mailbox); + ahw->mailbox = NULL; exit: return err; } @@ -2251,11 +2400,11 @@ void qlcnic_83xx_aer_stop_poll_work(struct qlcnic_adapter *adapter) clear_bit(QLC_83XX_MBX_READY, &idc->status); cancel_delayed_work_sync(&adapter->fw_work); - if (ahw->nic_mode == QLC_83XX_VIRTUAL_NIC_MODE) + if (ahw->nic_mode == QLCNIC_VNIC_MODE) qlcnic_83xx_disable_vnic_mode(adapter, 1); qlcnic_83xx_idc_detach_driver(adapter); - qlcnic_83xx_register_nic_idc_func(adapter, 0); + qlcnic_83xx_initialize_nic(adapter, 0); cancel_delayed_work_sync(&adapter->idc_aen_work); } |
