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 | 292 |
1 files changed, 205 insertions, 87 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index 345d987..f09e787 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c @@ -399,6 +399,7 @@ static void qlcnic_83xx_idc_detach_driver(struct qlcnic_adapter *adapter) struct net_device *netdev = adapter->netdev; netif_device_detach(netdev); + qlcnic_83xx_detach_mailbox_work(adapter); /* Disable mailbox interrupt */ qlcnic_83xx_disable_mbx_intr(adapter); @@ -610,6 +611,9 @@ int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *adapter) { int err; + 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); @@ -617,7 +621,7 @@ int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *adapter) if (err) return err; - qlcnic_83xx_enable_mbx_intrpt(adapter); + qlcnic_83xx_enable_mbx_interrupt(adapter); if (qlcnic_83xx_configure_opmode(adapter)) { qlcnic_83xx_idc_enter_failed_state(adapter, 1); @@ -631,6 +635,8 @@ 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_83xx_idc_attach_driver(adapter); return 0; @@ -641,7 +647,6 @@ static void qlcnic_83xx_idc_update_idc_params(struct qlcnic_adapter *adapter) struct qlcnic_hardware_context *ahw = adapter->ahw; qlcnic_83xx_idc_update_drv_presence_reg(adapter, 1, 1); - set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status); qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1); set_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status); @@ -792,7 +797,6 @@ static int qlcnic_83xx_idc_init_state(struct qlcnic_adapter *adapter) ret = qlcnic_83xx_idc_restart_hw(adapter, 1); } else { ret = qlcnic_83xx_idc_check_timeout(adapter, timeout); - return ret; } return ret; @@ -811,9 +815,10 @@ static int qlcnic_83xx_idc_init_state(struct qlcnic_adapter *adapter) **/ static int qlcnic_83xx_idc_ready_state(struct qlcnic_adapter *adapter) { - u32 val; struct qlcnic_hardware_context *ahw = adapter->ahw; + struct qlcnic_mailbox *mbx = ahw->mailbox; int ret = 0; + u32 val; /* Perform NIC configuration based ready state entry actions */ if (ahw->idc.state_entry(adapter)) @@ -825,7 +830,7 @@ static int qlcnic_83xx_idc_ready_state(struct qlcnic_adapter *adapter) dev_err(&adapter->pdev->dev, "Error: device temperature %d above limits\n", adapter->ahw->temp); - clear_bit(QLC_83XX_MBX_READY, &ahw->idc.status); + clear_bit(QLC_83XX_MBX_READY, &mbx->status); set_bit(__QLCNIC_RESETTING, &adapter->state); qlcnic_83xx_idc_detach_driver(adapter); qlcnic_83xx_idc_enter_failed_state(adapter, 1); @@ -838,7 +843,7 @@ static int qlcnic_83xx_idc_ready_state(struct qlcnic_adapter *adapter) if (ret) { adapter->flags |= QLCNIC_FW_HANG; if (!(val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY)) { - clear_bit(QLC_83XX_MBX_READY, &ahw->idc.status); + clear_bit(QLC_83XX_MBX_READY, &mbx->status); set_bit(__QLCNIC_RESETTING, &adapter->state); qlcnic_83xx_idc_enter_need_reset_state(adapter, 1); } @@ -846,6 +851,8 @@ static int qlcnic_83xx_idc_ready_state(struct qlcnic_adapter *adapter) } if ((val & QLC_83XX_IDC_GRACEFULL_RESET) || ahw->idc.collect_dump) { + clear_bit(QLC_83XX_MBX_READY, &mbx->status); + /* Move to need reset state and prepare for reset */ qlcnic_83xx_idc_enter_need_reset_state(adapter, 1); return ret; @@ -883,12 +890,13 @@ static int qlcnic_83xx_idc_ready_state(struct qlcnic_adapter *adapter) **/ static int qlcnic_83xx_idc_need_reset_state(struct qlcnic_adapter *adapter) { + struct qlcnic_mailbox *mbx = adapter->ahw->mailbox; int ret = 0; if (adapter->ahw->idc.prev_state != QLC_83XX_IDC_DEV_NEED_RESET) { qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1); set_bit(__QLCNIC_RESETTING, &adapter->state); - clear_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status); + clear_bit(QLC_83XX_MBX_READY, &mbx->status); if (adapter->ahw->nic_mode == QLC_83XX_VIRTUAL_NIC_MODE) qlcnic_83xx_disable_vnic_mode(adapter, 1); @@ -1080,7 +1088,6 @@ static void qlcnic_83xx_setup_idc_parameters(struct qlcnic_adapter *adapter) adapter->ahw->idc.name = (char **)qlc_83xx_idc_states; clear_bit(__QLCNIC_RESETTING, &adapter->state); - set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status); set_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status); /* Check if reset recovery is disabled */ @@ -1191,6 +1198,9 @@ void qlcnic_83xx_idc_request_reset(struct qlcnic_adapter *adapter, u32 key) { u32 val; + if (qlcnic_sriov_vf_check(adapter)) + return; + if (qlcnic_83xx_lock_driver(adapter)) { dev_err(&adapter->pdev->dev, "%s:failed, please retry\n", __func__); @@ -1257,31 +1267,33 @@ static int qlcnic_83xx_copy_bootloader(struct qlcnic_adapter *adapter) static int qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter) { + struct qlc_83xx_fw_info *fw_info = adapter->ahw->fw_info; + const struct firmware *fw = fw_info->fw; u32 dest, *p_cache; - u64 addr; + int i, ret = -EIO; u8 data[16]; size_t size; - int i, ret = -EIO; + u64 addr; dest = QLCRDX(adapter->ahw, QLCNIC_FW_IMAGE_ADDR); - size = (adapter->ahw->fw_info.fw->size & ~0xF); - p_cache = (u32 *)adapter->ahw->fw_info.fw->data; + size = (fw->size & ~0xF); + p_cache = (u32 *)fw->data; addr = (u64)dest; ret = qlcnic_83xx_ms_mem_write128(adapter, addr, (u32 *)p_cache, size / 16); if (ret) { dev_err(&adapter->pdev->dev, "MS memory write failed\n"); - release_firmware(adapter->ahw->fw_info.fw); - adapter->ahw->fw_info.fw = NULL; + release_firmware(fw); + fw_info->fw = NULL; return -EIO; } /* alignment check */ - if (adapter->ahw->fw_info.fw->size & 0xF) { + if (fw->size & 0xF) { addr = dest + size; - for (i = 0; i < (adapter->ahw->fw_info.fw->size & 0xF); i++) - data[i] = adapter->ahw->fw_info.fw->data[size + i]; + for (i = 0; i < (fw->size & 0xF); i++) + data[i] = fw->data[size + i]; for (; i < 16; i++) data[i] = 0; ret = qlcnic_83xx_ms_mem_write128(adapter, addr, @@ -1289,13 +1301,13 @@ static int qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter) if (ret) { dev_err(&adapter->pdev->dev, "MS memory write failed\n"); - release_firmware(adapter->ahw->fw_info.fw); - adapter->ahw->fw_info.fw = NULL; + release_firmware(fw); + fw_info->fw = NULL; return -EIO; } } - release_firmware(adapter->ahw->fw_info.fw); - adapter->ahw->fw_info.fw = NULL; + release_firmware(fw); + fw_info->fw = NULL; return 0; } @@ -1941,10 +1953,11 @@ static void qlcnic_83xx_init_hw(struct qlcnic_adapter *p_dev) static int qlcnic_83xx_load_fw_image_from_host(struct qlcnic_adapter *adapter) { + struct qlc_83xx_fw_info *fw_info = adapter->ahw->fw_info; int err = -EIO; - if (request_firmware(&adapter->ahw->fw_info.fw, - QLC_83XX_FW_FILE_NAME, &(adapter->pdev->dev))) { + if (request_firmware(&fw_info->fw, fw_info->fw_file_name, + &(adapter->pdev->dev))) { dev_err(&adapter->pdev->dev, "No file FW image, loading flash FW image.\n"); QLC_SHARED_REG_WR32(adapter, QLCNIC_FW_IMG_VALID, @@ -1990,36 +2003,6 @@ static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter) return 0; } -/** -* qlcnic_83xx_config_default_opmode -* -* @adapter: adapter structure -* -* Configure default driver operating mode -* -* Returns: Error code or Success(0) -* */ -int qlcnic_83xx_config_default_opmode(struct qlcnic_adapter *adapter) -{ - u32 op_mode; - struct qlcnic_hardware_context *ahw = adapter->ahw; - - qlcnic_get_func_no(adapter); - op_mode = QLCRDX(ahw, QLC_83XX_DRV_OP_MODE); - - if (test_bit(__QLCNIC_SRIOV_CAPABLE, &adapter->state)) - op_mode = QLC_83XX_DEFAULT_OPMODE; - - if (op_mode == QLC_83XX_DEFAULT_OPMODE) { - adapter->nic_ops->init_driver = qlcnic_83xx_init_default_driver; - ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry; - } else { - return -EIO; - } - - return 0; -} - int qlcnic_83xx_get_nic_configuration(struct qlcnic_adapter *adapter) { int err; @@ -2039,26 +2022,26 @@ int qlcnic_83xx_get_nic_configuration(struct qlcnic_adapter *adapter) ahw->max_mac_filters = nic_info.max_mac_filters; ahw->max_mtu = nic_info.max_mtu; - /* VNIC mode is detected by BIT_23 in capabilities. This bit is also - * set in case device is SRIOV capable. VNIC and SRIOV are mutually - * exclusive. So in case of sriov capable device load driver in - * default mode + /* eSwitch capability indicates vNIC mode. + * vNIC and SRIOV are mutually exclusive operational modes. + * If SR-IOV capability is detected, SR-IOV physical function + * will get initialized in default mode. + * SR-IOV virtual function initialization follows a + * different code path and opmode. + * SRIOV mode has precedence over vNIC mode. */ - if (test_bit(__QLCNIC_SRIOV_CAPABLE, &adapter->state)) { - ahw->nic_mode = QLC_83XX_DEFAULT_MODE; - return ahw->nic_mode; - } + if (test_bit(__QLCNIC_SRIOV_CAPABLE, &adapter->state)) + return QLC_83XX_DEFAULT_OPMODE; - if (ahw->capabilities & BIT_23) - ahw->nic_mode = QLC_83XX_VIRTUAL_NIC_MODE; - else - ahw->nic_mode = QLC_83XX_DEFAULT_MODE; + if (ahw->capabilities & QLC_83XX_ESWITCH_CAPABILITY) + return QLC_83XX_VIRTUAL_NIC_MODE; - return ahw->nic_mode; + return QLC_83XX_DEFAULT_OPMODE; } int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter) { + struct qlcnic_hardware_context *ahw = adapter->ahw; int ret; ret = qlcnic_83xx_get_nic_configuration(adapter); @@ -2066,11 +2049,16 @@ int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter) return -EIO; if (ret == QLC_83XX_VIRTUAL_NIC_MODE) { + ahw->nic_mode = QLC_83XX_VIRTUAL_NIC_MODE; if (qlcnic_83xx_config_vnic_opmode(adapter)) return -EIO; - } else if (ret == QLC_83XX_DEFAULT_MODE) { - if (qlcnic_83xx_config_default_opmode(adapter)) - return -EIO; + + } else if (ret == QLC_83XX_DEFAULT_OPMODE) { + ahw->nic_mode = QLC_83XX_DEFAULT_MODE; + adapter->nic_ops->init_driver = qlcnic_83xx_init_default_driver; + ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry; + } else { + return -EIO; } return 0; @@ -2139,20 +2127,82 @@ static void qlcnic_83xx_clear_function_resources(struct qlcnic_adapter *adapter) } } +static int qlcnic_83xx_get_fw_info(struct qlcnic_adapter *adapter) +{ + struct qlcnic_hardware_context *ahw = adapter->ahw; + struct pci_dev *pdev = adapter->pdev; + struct qlc_83xx_fw_info *fw_info; + int err = 0; + + ahw->fw_info = kzalloc(sizeof(*fw_info), GFP_KERNEL); + if (!ahw->fw_info) { + err = -ENOMEM; + } else { + fw_info = ahw->fw_info; + switch (pdev->device) { + case PCI_DEVICE_ID_QLOGIC_QLE834X: + strncpy(fw_info->fw_file_name, QLC_83XX_FW_FILE_NAME, + QLC_FW_FILE_NAME_LEN); + break; + case PCI_DEVICE_ID_QLOGIC_QLE844X: + strncpy(fw_info->fw_file_name, QLC_84XX_FW_FILE_NAME, + QLC_FW_FILE_NAME_LEN); + break; + default: + dev_err(&pdev->dev, "%s: Invalid device id\n", + __func__); + err = -EINVAL; + break; + } + } + + return err; +} + + int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac) { struct qlcnic_hardware_context *ahw = adapter->ahw; + int err = 0; - if (qlcnic_sriov_vf_check(adapter)) - return qlcnic_sriov_vf_init(adapter, pci_using_dac); + ahw->msix_supported = !!qlcnic_use_msi_x; + err = qlcnic_83xx_init_mailbox_work(adapter); + if (err) + goto exit; - if (qlcnic_83xx_check_hw_status(adapter)) - return -EIO; + if (qlcnic_sriov_vf_check(adapter)) { + err = qlcnic_sriov_vf_init(adapter, pci_using_dac); + if (err) + goto detach_mbx; + else + return err; + } + + 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; - /* Initilaize 83xx mailbox spinlock */ - spin_lock_init(&ahw->mbx_lock); + err = qlcnic_83xx_idc_init(adapter); + if (err) + goto clear_fw_info; + + err = qlcnic_setup_intr(adapter, 0, 0); + if (err) { + dev_err(&adapter->pdev->dev, "Failed to setup interrupt\n"); + goto disable_intr; + } + + err = qlcnic_83xx_setup_mbx_intr(adapter); + if (err) + goto disable_mbx_intr; - set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status); qlcnic_83xx_clear_function_resources(adapter); INIT_DELAYED_WORK(&adapter->idc_aen_work, qlcnic_83xx_idc_aen_work); @@ -2160,22 +2210,90 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac) /* register for NIC IDC AEN Events */ qlcnic_83xx_register_nic_idc_func(adapter, 1); - if (!qlcnic_83xx_read_flash_descriptor_table(adapter)) - qlcnic_83xx_read_flash_mfg_id(adapter); - - if (qlcnic_83xx_idc_init(adapter)) - return -EIO; - /* Configure default, SR-IOV or Virtual NIC mode of operation */ - if (qlcnic_83xx_configure_opmode(adapter)) - return -EIO; + err = qlcnic_83xx_configure_opmode(adapter); + if (err) + goto disable_mbx_intr; /* Perform operating mode specific initialization */ - if (adapter->nic_ops->init_driver(adapter)) - return -EIO; + 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; + +disable_mbx_intr: + qlcnic_83xx_free_mbx_intr(adapter); + +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); +exit: + return err; +} + +void qlcnic_83xx_aer_stop_poll_work(struct qlcnic_adapter *adapter) +{ + struct qlcnic_hardware_context *ahw = adapter->ahw; + struct qlc_83xx_idc *idc = &ahw->idc; + + clear_bit(QLC_83XX_MBX_READY, &idc->status); + cancel_delayed_work_sync(&adapter->fw_work); + + if (ahw->nic_mode == QLC_83XX_VIRTUAL_NIC_MODE) + qlcnic_83xx_disable_vnic_mode(adapter, 1); + + qlcnic_83xx_idc_detach_driver(adapter); + qlcnic_83xx_register_nic_idc_func(adapter, 0); + + cancel_delayed_work_sync(&adapter->idc_aen_work); +} + +int qlcnic_83xx_aer_reset(struct qlcnic_adapter *adapter) +{ + struct qlcnic_hardware_context *ahw = adapter->ahw; + struct qlc_83xx_idc *idc = &ahw->idc; + int ret = 0; + u32 owner; + + /* Mark the previous IDC state as NEED_RESET so + * that state_entry() will perform the reattachment + * and bringup the device + */ + idc->prev_state = QLC_83XX_IDC_DEV_NEED_RESET; + owner = qlcnic_83xx_idc_find_reset_owner_id(adapter); + if (ahw->pci_func == owner) { + ret = qlcnic_83xx_restart_hw(adapter); + if (ret < 0) + return ret; + qlcnic_83xx_idc_clear_registers(adapter, 0); + } + + ret = idc->state_entry(adapter); + return ret; +} + +void qlcnic_83xx_aer_start_poll_work(struct qlcnic_adapter *adapter) +{ + struct qlcnic_hardware_context *ahw = adapter->ahw; + struct qlc_83xx_idc *idc = &ahw->idc; + u32 owner; + + idc->prev_state = QLC_83XX_IDC_DEV_READY; + owner = qlcnic_83xx_idc_find_reset_owner_id(adapter); + if (ahw->pci_func == owner) + qlcnic_83xx_idc_enter_ready_state(adapter, 0); - return adapter->ahw->idc.err_code; + qlcnic_schedule_work(adapter, qlcnic_83xx_idc_poll_dev_state, 0); } |