]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
Merge remote-tracking branch 'wireless-next/master'
[karo-tx-linux.git] / drivers / net / ethernet / qlogic / qlcnic / qlcnic_83xx_init.c
index 345d987aede491b8d5daf0e1e268b0ed8a9f2a51..e2cd48417041c1e749058d89f235a02822eaf159 100644 (file)
@@ -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->dcb);
        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,11 @@ 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 owner;
+       u32 val;
 
        /* Perform NIC configuration based ready state entry actions */
        if (ahw->idc.state_entry(adapter))
@@ -825,7 +831,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,14 +844,20 @@ 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);
+               }  else {
+                       owner = qlcnic_83xx_idc_find_reset_owner_id(adapter);
+                       if (ahw->pci_func == owner)
+                               qlcnic_dump_fw(adapter);
                }
                return -EIO;
        }
 
        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 +895,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);
 
@@ -1050,6 +1063,12 @@ void qlcnic_83xx_idc_poll_dev_state(struct work_struct *work)
        adapter->ahw->idc.prev_state = adapter->ahw->idc.curr_state;
        qlcnic_83xx_periodic_tasks(adapter);
 
+       /* Do not reschedule if firmaware is in hanged state and auto
+        * recovery is disabled
+        */
+       if ((adapter->flags & QLCNIC_FW_HANG) && !qlcnic_auto_fw_reset)
+               return;
+
        /* Re-schedule the function */
        if (test_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status))
                qlcnic_schedule_work(adapter, qlcnic_83xx_idc_poll_dev_state,
@@ -1080,7 +1099,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 +1209,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 +1278,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 +1312,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 +1964,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 +2014,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 +2033,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 +2060,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 +2138,83 @@ 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;
+       struct qlcnic_dcb *dcb;
+       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);
 
-       /* Initilaize 83xx mailbox spinlock */
-       spin_lock_init(&ahw->mbx_lock);
+       err = qlcnic_83xx_get_fw_info(adapter);
+       if (err)
+               goto detach_mbx;
+
+       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 +2222,92 @@ 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;
+
+       dcb = adapter->dcb;
+
+       if (dcb && qlcnic_dcb_attach(dcb))
+               qlcnic_clear_dcb_ops(dcb);
 
        /* 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);
 }