Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[linux-2.6-block.git] / drivers / net / wireless / intel / iwlwifi / pcie / trans.c
index b796952da644ca0a32ad4bf1cf5851b984fdcf88..58591ca051fd3c23f410d8d369f2c1a3a3150816 100644 (file)
@@ -1022,82 +1022,6 @@ static int iwl_pcie_load_given_ucode_8000(struct iwl_trans *trans,
                                               &first_ucode_section);
 }
 
-static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
-                                  const struct fw_img *fw, bool run_in_rfkill)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       bool hw_rfkill;
-       int ret;
-
-       mutex_lock(&trans_pcie->mutex);
-
-       /* Someone called stop_device, don't try to start_fw */
-       if (trans_pcie->is_down) {
-               IWL_WARN(trans,
-                        "Can't start_fw since the HW hasn't been started\n");
-               ret = EIO;
-               goto out;
-       }
-
-       /* This may fail if AMT took ownership of the device */
-       if (iwl_pcie_prepare_card_hw(trans)) {
-               IWL_WARN(trans, "Exit HW not ready\n");
-               ret = -EIO;
-               goto out;
-       }
-
-       iwl_enable_rfkill_int(trans);
-
-       /* If platform's RF_KILL switch is NOT set to KILL */
-       hw_rfkill = iwl_is_rfkill_set(trans);
-       if (hw_rfkill)
-               set_bit(STATUS_RFKILL, &trans->status);
-       else
-               clear_bit(STATUS_RFKILL, &trans->status);
-       iwl_trans_pcie_rf_kill(trans, hw_rfkill);
-       if (hw_rfkill && !run_in_rfkill) {
-               ret = -ERFKILL;
-               goto out;
-       }
-
-       iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
-
-       ret = iwl_pcie_nic_init(trans);
-       if (ret) {
-               IWL_ERR(trans, "Unable to init nic\n");
-               goto out;
-       }
-
-       /* make sure rfkill handshake bits are cleared */
-       iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-       iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR,
-                   CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
-
-       /* clear (again), then enable host interrupts */
-       iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
-       iwl_enable_interrupts(trans);
-
-       /* really make sure rfkill handshake bits are cleared */
-       iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-       iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-
-       /* Load the given image to the HW */
-       if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
-               ret = iwl_pcie_load_given_ucode_8000(trans, fw);
-       else
-               ret = iwl_pcie_load_given_ucode(trans, fw);
-
-out:
-       mutex_unlock(&trans_pcie->mutex);
-       return ret;
-}
-
-static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr)
-{
-       iwl_pcie_reset_ict(trans);
-       iwl_pcie_tx_start(trans, scd_addr);
-}
-
 static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
@@ -1128,7 +1052,8 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
         * already dead.
         */
        if (test_and_clear_bit(STATUS_DEVICE_ENABLED, &trans->status)) {
-               IWL_DEBUG_INFO(trans, "DEVICE_ENABLED bit was set and is now cleared\n");
+               IWL_DEBUG_INFO(trans,
+                              "DEVICE_ENABLED bit was set and is now cleared\n");
                iwl_pcie_tx_stop(trans);
                iwl_pcie_rx_stop(trans);
 
@@ -1162,7 +1087,6 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
        iwl_disable_interrupts(trans);
        spin_unlock(&trans_pcie->irq_lock);
 
-
        /* clear all status bits */
        clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
        clear_bit(STATUS_INT_ENABLED, &trans->status);
@@ -1195,10 +1119,116 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
        if (hw_rfkill != was_hw_rfkill)
                iwl_trans_pcie_rf_kill(trans, hw_rfkill);
 
-       /* re-take ownership to prevent other users from stealing the deivce */
+       /* re-take ownership to prevent other users from stealing the device */
        iwl_pcie_prepare_card_hw(trans);
 }
 
+static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
+                                  const struct fw_img *fw, bool run_in_rfkill)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       bool hw_rfkill;
+       int ret;
+
+       /* This may fail if AMT took ownership of the device */
+       if (iwl_pcie_prepare_card_hw(trans)) {
+               IWL_WARN(trans, "Exit HW not ready\n");
+               ret = -EIO;
+               goto out;
+       }
+
+       iwl_enable_rfkill_int(trans);
+
+       iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
+
+       /*
+        * We enabled the RF-Kill interrupt and the handler may very
+        * well be running. Disable the interrupts to make sure no other
+        * interrupt can be fired.
+        */
+       iwl_disable_interrupts(trans);
+
+       /* Make sure it finished running */
+       synchronize_irq(trans_pcie->pci_dev->irq);
+
+       mutex_lock(&trans_pcie->mutex);
+
+       /* If platform's RF_KILL switch is NOT set to KILL */
+       hw_rfkill = iwl_is_rfkill_set(trans);
+       if (hw_rfkill)
+               set_bit(STATUS_RFKILL, &trans->status);
+       else
+               clear_bit(STATUS_RFKILL, &trans->status);
+       iwl_trans_pcie_rf_kill(trans, hw_rfkill);
+       if (hw_rfkill && !run_in_rfkill) {
+               ret = -ERFKILL;
+               goto out;
+       }
+
+       /* Someone called stop_device, don't try to start_fw */
+       if (trans_pcie->is_down) {
+               IWL_WARN(trans,
+                        "Can't start_fw since the HW hasn't been started\n");
+               ret = -EIO;
+               goto out;
+       }
+
+       /* make sure rfkill handshake bits are cleared */
+       iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+       iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR,
+                   CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+
+       /* clear (again), then enable host interrupts */
+       iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
+
+       ret = iwl_pcie_nic_init(trans);
+       if (ret) {
+               IWL_ERR(trans, "Unable to init nic\n");
+               goto out;
+       }
+
+       /*
+        * Now, we load the firmware and don't want to be interrupted, even
+        * by the RF-Kill interrupt (hence mask all the interrupt besides the
+        * FH_TX interrupt which is needed to load the firmware). If the
+        * RF-Kill switch is toggled, we will find out after having loaded
+        * the firmware and return the proper value to the caller.
+        */
+       iwl_enable_fw_load_int(trans);
+
+       /* really make sure rfkill handshake bits are cleared */
+       iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+       iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+
+       /* Load the given image to the HW */
+       if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
+               ret = iwl_pcie_load_given_ucode_8000(trans, fw);
+       else
+               ret = iwl_pcie_load_given_ucode(trans, fw);
+       iwl_enable_interrupts(trans);
+
+       /* re-check RF-Kill state since we may have missed the interrupt */
+       hw_rfkill = iwl_is_rfkill_set(trans);
+       if (hw_rfkill)
+               set_bit(STATUS_RFKILL, &trans->status);
+       else
+               clear_bit(STATUS_RFKILL, &trans->status);
+
+       iwl_trans_pcie_rf_kill(trans, hw_rfkill);
+       if (hw_rfkill && !run_in_rfkill)
+               ret = -ERFKILL;
+
+out:
+       mutex_unlock(&trans_pcie->mutex);
+       return ret;
+}
+
+static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr)
+{
+       iwl_pcie_reset_ict(trans);
+       iwl_pcie_tx_start(trans, scd_addr);
+}
+
 static void iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);