iwlagn: move PCI power related functions to the PCI layer
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / iwlwifi / iwl-core.c
index 46d69657407c6acae8d330c051ae868c723beafa..360df33585ee507251c9589fb7ae5cc3298e52b0 100644 (file)
 #include "iwl-power.h"
 #include "iwl-sta.h"
 #include "iwl-helpers.h"
-
-
-/*
- * set bt_coex_active to true, uCode will do kill/defer
- * every time the priority line is asserted (BT is sending signals on the
- * priority line in the PCIx).
- * set bt_coex_active to false, uCode will ignore the BT activity and
- * perform the normal operation
- *
- * User might experience transmit issue on some platform due to WiFi/BT
- * co-exist problem. The possible behaviors are:
- *   Able to scan and finding all the available AP
- *   Not able to associate with any AP
- * On those platforms, WiFi communication can be restored by set
- * "bt_coex_active" module parameter to "false"
- *
- * default: bt_coex_active = true (BT_COEX_ENABLE)
- */
-bool bt_coex_active = true;
-module_param(bt_coex_active, bool, S_IRUGO);
-MODULE_PARM_DESC(bt_coex_active, "enable wifi/bluetooth co-exist");
+#include "iwl-agn.h"
 
 u32 iwl_debug_level;
 
@@ -94,7 +74,7 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
                max_bit_rate = MAX_BIT_RATE_40_MHZ;
        }
 
-       if (priv->cfg->mod_params->amsdu_size_8K)
+       if (iwlagn_mod_params.amsdu_size_8K)
                ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
 
        ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
@@ -135,6 +115,7 @@ int iwlcore_init_geos(struct iwl_priv *priv)
        struct ieee80211_channel *geo_ch;
        struct ieee80211_rate *rates;
        int i = 0;
+       s8 max_tx_power = IWLAGN_TX_POWER_TARGET_POWER_MIN;
 
        if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates ||
            priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) {
@@ -162,7 +143,7 @@ int iwlcore_init_geos(struct iwl_priv *priv)
        sband->bitrates = &rates[IWL_FIRST_OFDM_RATE];
        sband->n_bitrates = IWL_RATE_COUNT_LEGACY - IWL_FIRST_OFDM_RATE;
 
-       if (priv->cfg->sku & IWL_SKU_N)
+       if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE)
                iwlcore_init_ht_hw_capab(priv, &sband->ht_cap,
                                         IEEE80211_BAND_5GHZ);
 
@@ -172,7 +153,7 @@ int iwlcore_init_geos(struct iwl_priv *priv)
        sband->bitrates = rates;
        sband->n_bitrates = IWL_RATE_COUNT_LEGACY;
 
-       if (priv->cfg->sku & IWL_SKU_N)
+       if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE)
                iwlcore_init_ht_hw_capab(priv, &sband->ht_cap,
                                         IEEE80211_BAND_2GHZ);
 
@@ -208,8 +189,8 @@ int iwlcore_init_geos(struct iwl_priv *priv)
 
                        geo_ch->flags |= ch->ht40_extension_channel;
 
-                       if (ch->max_power_avg > priv->tx_power_device_lmt)
-                               priv->tx_power_device_lmt = ch->max_power_avg;
+                       if (ch->max_power_avg > max_tx_power)
+                               max_tx_power = ch->max_power_avg;
                } else {
                        geo_ch->flags |= IEEE80211_CHAN_DISABLED;
                }
@@ -222,13 +203,17 @@ int iwlcore_init_geos(struct iwl_priv *priv)
                                 geo_ch->flags);
        }
 
+       priv->tx_power_device_lmt = max_tx_power;
+       priv->tx_power_user_lmt = max_tx_power;
+       priv->tx_power_next = max_tx_power;
+
        if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) &&
-            priv->cfg->sku & IWL_SKU_A) {
+            priv->cfg->sku & EEPROM_SKU_CAP_BAND_52GHZ) {
                IWL_INFO(priv, "Incorrectly detected BG card as ABG. "
                        "Please send your PCI ID 0x%04X:0x%04X to maintainer.\n",
                           priv->pci_dev->device,
                           priv->pci_dev->subsystem_device);
-               priv->cfg->sku &= ~IWL_SKU_A;
+               priv->cfg->sku &= ~EEPROM_SKU_CAP_BAND_52GHZ;
        }
 
        IWL_INFO(priv, "Tunable channels: %d 802.11bg, %d 802.11a channels\n",
@@ -410,72 +395,72 @@ void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
 int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 {
        struct iwl_rxon_cmd *rxon = &ctx->staging;
-       bool error = false;
+       u32 errors = 0;
 
        if (rxon->flags & RXON_FLG_BAND_24G_MSK) {
                if (rxon->flags & RXON_FLG_TGJ_NARROW_BAND_MSK) {
                        IWL_WARN(priv, "check 2.4G: wrong narrow\n");
-                       error = true;
+                       errors |= BIT(0);
                }
                if (rxon->flags & RXON_FLG_RADAR_DETECT_MSK) {
                        IWL_WARN(priv, "check 2.4G: wrong radar\n");
-                       error = true;
+                       errors |= BIT(1);
                }
        } else {
                if (!(rxon->flags & RXON_FLG_SHORT_SLOT_MSK)) {
                        IWL_WARN(priv, "check 5.2G: not short slot!\n");
-                       error = true;
+                       errors |= BIT(2);
                }
                if (rxon->flags & RXON_FLG_CCK_MSK) {
                        IWL_WARN(priv, "check 5.2G: CCK!\n");
-                       error = true;
+                       errors |= BIT(3);
                }
        }
        if ((rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1) {
                IWL_WARN(priv, "mac/bssid mcast!\n");
-               error = true;
+               errors |= BIT(4);
        }
 
        /* make sure basic rates 6Mbps and 1Mbps are supported */
        if ((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0 &&
            (rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0) {
                IWL_WARN(priv, "neither 1 nor 6 are basic\n");
-               error = true;
+               errors |= BIT(5);
        }
 
        if (le16_to_cpu(rxon->assoc_id) > 2007) {
                IWL_WARN(priv, "aid > 2007\n");
-               error = true;
+               errors |= BIT(6);
        }
 
        if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK))
                        == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) {
                IWL_WARN(priv, "CCK and short slot\n");
-               error = true;
+               errors |= BIT(7);
        }
 
        if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK))
                        == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) {
                IWL_WARN(priv, "CCK and auto detect");
-               error = true;
+               errors |= BIT(8);
        }
 
        if ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK |
                            RXON_FLG_TGG_PROTECT_MSK)) ==
                            RXON_FLG_TGG_PROTECT_MSK) {
                IWL_WARN(priv, "TGg but no auto-detect\n");
-               error = true;
+               errors |= BIT(9);
        }
 
-       if (error)
-               IWL_WARN(priv, "Tuning to channel %d\n",
-                           le16_to_cpu(rxon->channel));
-
-       if (error) {
-               IWL_ERR(priv, "Invalid RXON\n");
-               return -EINVAL;
+       if (rxon->channel == 0) {
+               IWL_WARN(priv, "zero channel is invalid\n");
+               errors |= BIT(10);
        }
-       return 0;
+
+       WARN(errors, "Invalid RXON (%#x), channel %d",
+            errors, le16_to_cpu(rxon->channel));
+
+       return errors ? -EINVAL : 0;
 }
 
 /**
@@ -837,12 +822,8 @@ void iwl_chswitch_done(struct iwl_priv *priv, bool is_success)
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
-       if (priv->switch_rxon.switch_in_progress) {
+       if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
                ieee80211_chswitch_done(ctx->vif, is_success);
-               mutex_lock(&priv->mutex);
-               priv->switch_rxon.switch_in_progress = false;
-               mutex_unlock(&priv->mutex);
-       }
 }
 
 #ifdef CONFIG_IWLWIFI_DEBUG
@@ -921,7 +902,7 @@ void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
        }
 
        if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
-               if (priv->cfg->mod_params->restart_fw) {
+               if (iwlagn_mod_params.restart_fw) {
                        IWL_DEBUG(priv, IWL_DL_FW_ERRORS,
                                  "Restarting adapter due to uCode error.\n");
                        queue_work(priv->workqueue, &priv->restart);
@@ -990,6 +971,8 @@ void iwl_apm_stop(struct iwl_priv *priv)
 {
        IWL_DEBUG_INFO(priv, "Stop card, put in low power state\n");
 
+       clear_bit(STATUS_DEVICE_ENABLED, &priv->status);
+
        /* Stop device's DMA activity */
        iwl_apm_stop_master(priv);
 
@@ -1014,8 +997,6 @@ void iwl_apm_stop(struct iwl_priv *priv)
 int iwl_apm_init(struct iwl_priv *priv)
 {
        int ret = 0;
-       u16 lctl;
-
        IWL_DEBUG_INFO(priv, "Init card's basic functions\n");
 
        /*
@@ -1044,27 +1025,7 @@ int iwl_apm_init(struct iwl_priv *priv)
        iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
                                    CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);
 
-       /*
-        * HW bug W/A for instability in PCIe bus L0->L0S->L1 transition.
-        * Check if BIOS (or OS) enabled L1-ASPM on this device.
-        * If so (likely), disable L0S, so device moves directly L0->L1;
-        *    costs negligible amount of power savings.
-        * If not (unlikely), enable L0S, so there is at least some
-        *    power savings, even without L1.
-        */
-       lctl = iwl_pcie_link_ctl(priv);
-       if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) ==
-                               PCI_CFG_LINK_CTRL_VAL_L1_EN) {
-               /* L1-ASPM enabled; disable(!) L0S  */
-               iwl_set_bit(priv, CSR_GIO_REG,
-                               CSR_GIO_REG_VAL_L0S_ENABLED);
-               IWL_DEBUG_POWER(priv, "L1 Enabled; Disabling L0S\n");
-       } else {
-               /* L1-ASPM disabled; enable(!) L0S */
-               iwl_clear_bit(priv, CSR_GIO_REG,
-                               CSR_GIO_REG_VAL_L0S_ENABLED);
-               IWL_DEBUG_POWER(priv, "L1 Disabled; Enabling L0S\n");
-       }
+       priv->bus.ops->apm_config(&priv->bus);
 
        /* Configure analog phase-lock-loop before activating to D0A */
        if (priv->cfg->base_params->pll_cfg_val)
@@ -1104,6 +1065,8 @@ int iwl_apm_init(struct iwl_priv *priv)
        iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
                          APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
 
+       set_bit(STATUS_DEVICE_ENABLED, &priv->status);
+
 out:
        return ret;
 }
@@ -1121,9 +1084,6 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
        if (priv->tx_power_user_lmt == tx_power && !force)
                return 0;
 
-       if (!priv->cfg->ops->lib->send_tx_power)
-               return -EOPNOTSUPP;
-
        if (tx_power < IWLAGN_TX_POWER_TARGET_POWER_MIN) {
                IWL_WARN(priv,
                         "Requested user TXPOWER %d below lower limit %d.\n",
@@ -1157,7 +1117,7 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
        prev_tx_power = priv->tx_power_user_lmt;
        priv->tx_power_user_lmt = tx_power;
 
-       ret = priv->cfg->ops->lib->send_tx_power(priv);
+       ret = iwlagn_send_tx_power(priv);
 
        /* if fail to set tx_power, restore the orig. tx power */
        if (ret) {
@@ -1176,7 +1136,7 @@ void iwl_send_bt_config(struct iwl_priv *priv)
                .kill_cts_mask = 0,
        };
 
-       if (!bt_coex_active)
+       if (!iwlagn_mod_params.bt_coex_active)
                bt_cmd.flags = BT_COEX_DISABLE;
        else
                bt_cmd.flags = BT_COEX_ENABLE;
@@ -1272,7 +1232,7 @@ static int iwl_set_mode(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
        if (priv->cfg->ops->hcmd->set_rxon_chain)
                priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
 
-       return iwlcore_commit_rxon(priv, ctx);
+       return iwlagn_commit_rxon(priv, ctx);
 }
 
 static int iwl_setup_interface(struct iwl_priv *priv,
@@ -1738,7 +1698,7 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external)
                 * detect failure), then fw_restart module parameter
                 * need to be check before performing firmware reload
                 */
-               if (!external && !priv->cfg->mod_params->restart_fw) {
+               if (!external && !iwlagn_mod_params.restart_fw) {
                        IWL_DEBUG_INFO(priv, "Cancel firmware reload based on "
                                       "module parameter setting\n");
                        break;
@@ -1755,6 +1715,7 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 {
        struct iwl_priv *priv = hw->priv;
        struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+       struct iwl_rxon_context *bss_ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        struct iwl_rxon_context *tmp;
        u32 interface_modes;
        int err;
@@ -1779,6 +1740,19 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                goto out;
        }
 
+       /*
+        * Refuse a change that should be done by moving from the PAN
+        * context to the BSS context instead, if the BSS context is
+        * available and can support the new interface type.
+        */
+       if (ctx->ctxid == IWL_RXON_CTX_PAN && !bss_ctx->vif &&
+           (bss_ctx->interface_modes & BIT(newtype) ||
+            bss_ctx->exclusive_interface_modes & BIT(newtype))) {
+               BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
+               err = -EBUSY;
+               goto out;
+       }
+
        if (ctx->exclusive_interface_modes & BIT(newtype)) {
                for_each_context(priv, tmp) {
                        if (ctx == tmp)
@@ -1952,11 +1926,8 @@ __le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base,
 
 #ifdef CONFIG_PM
 
-int iwl_pci_suspend(struct device *device)
+int iwl_suspend(struct iwl_priv *priv)
 {
-       struct pci_dev *pdev = to_pci_dev(device);
-       struct iwl_priv *priv = pci_get_drvdata(pdev);
-
        /*
         * This function is called when system goes into suspend state
         * mac80211 will call iwl_mac_stop() from the mac80211 suspend function
@@ -1969,18 +1940,10 @@ int iwl_pci_suspend(struct device *device)
        return 0;
 }
 
-int iwl_pci_resume(struct device *device)
+int iwl_resume(struct iwl_priv *priv)
 {
-       struct pci_dev *pdev = to_pci_dev(device);
-       struct iwl_priv *priv = pci_get_drvdata(pdev);
        bool hw_rfkill = false;
 
-       /*
-        * We disable the RETRY_TIMEOUT register (0x41) to keep
-        * PCI Tx retries from interfering with C3 CPU state.
-        */
-       pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00);
-
        iwl_enable_interrupts(priv);
 
        if (!(iwl_read32(priv, CSR_GP_CNTRL) &
@@ -1997,13 +1960,4 @@ int iwl_pci_resume(struct device *device)
        return 0;
 }
 
-const struct dev_pm_ops iwl_pm_ops = {
-       .suspend = iwl_pci_suspend,
-       .resume = iwl_pci_resume,
-       .freeze = iwl_pci_suspend,
-       .thaw = iwl_pci_resume,
-       .poweroff = iwl_pci_suspend,
-       .restore = iwl_pci_resume,
-};
-
 #endif /* CONFIG_PM */