]> Pileus Git - ~andy/linux/blobdiff - drivers/net/wireless/iwlwifi/iwl-core.c
iwlagn: fix tx power initialization
[~andy/linux] / drivers / net / wireless / iwlwifi / iwl-core.c
index 6c30fa652e277a8bcb753ecd9eabbf811fb680b9..af72fd51ea74261f197d76c274d6de37c052b695 100644 (file)
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -67,30 +67,6 @@ u32 iwl_debug_level;
 
 const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
 
-
-/* This function both allocates and initializes hw and priv. */
-struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg)
-{
-       struct iwl_priv *priv;
-       /* mac80211 allocates memory for this device instance, including
-        *   space for this driver's private structure */
-       struct ieee80211_hw *hw;
-
-       hw = ieee80211_alloc_hw(sizeof(struct iwl_priv),
-                               cfg->ops->ieee80211_ops);
-       if (hw == NULL) {
-               pr_err("%s: Can not allocate network device\n",
-                      cfg->name);
-               goto out;
-       }
-
-       priv = hw->priv;
-       priv->hw = hw;
-
-out:
-       return hw;
-}
-
 #define MAX_BIT_RATE_40_MHZ 150 /* Mbps */
 #define MAX_BIT_RATE_20_MHZ 72 /* Mbps */
 static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
@@ -159,6 +135,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) {
@@ -232,8 +209,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;
                }
@@ -246,6 +223,10 @@ 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) {
                IWL_INFO(priv, "Incorrectly detected BG card as ABG. "
@@ -890,10 +871,21 @@ void iwl_print_rx_config_cmd(struct iwl_priv *priv,
        IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
 }
 #endif
-/**
- * iwl_irq_handle_error - called for HW or SW error interrupt from card
- */
-void iwl_irq_handle_error(struct iwl_priv *priv)
+
+static void iwlagn_abort_notification_waits(struct iwl_priv *priv)
+{
+       unsigned long flags;
+       struct iwl_notification_wait *wait_entry;
+
+       spin_lock_irqsave(&priv->_agn.notif_wait_lock, flags);
+       list_for_each_entry(wait_entry, &priv->_agn.notif_waits, list)
+               wait_entry->aborted = true;
+       spin_unlock_irqrestore(&priv->_agn.notif_wait_lock, flags);
+
+       wake_up_all(&priv->_agn.notif_waitq);
+}
+
+void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
 {
        unsigned int reload_msec;
        unsigned long reload_jiffies;
@@ -904,18 +896,64 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
        /* Cancel currently queued command. */
        clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
 
+       iwlagn_abort_notification_waits(priv);
+
+       /* Keep the restart process from trying to send host
+        * commands by clearing the ready bit */
+       clear_bit(STATUS_READY, &priv->status);
+
+       wake_up_interruptible(&priv->wait_command_queue);
+
+       if (!ondemand) {
+               /*
+                * If firmware keep reloading, then it indicate something
+                * serious wrong and firmware having problem to recover
+                * from it. Instead of keep trying which will fill the syslog
+                * and hang the system, let's just stop it
+                */
+               reload_jiffies = jiffies;
+               reload_msec = jiffies_to_msecs((long) reload_jiffies -
+                                       (long) priv->reload_jiffies);
+               priv->reload_jiffies = reload_jiffies;
+               if (reload_msec <= IWL_MIN_RELOAD_DURATION) {
+                       priv->reload_count++;
+                       if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) {
+                               IWL_ERR(priv, "BUG_ON, Stop restarting\n");
+                               return;
+                       }
+               } else
+                       priv->reload_count = 0;
+       }
+
+       if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+               if (priv->cfg->mod_params->restart_fw) {
+                       IWL_DEBUG(priv, IWL_DL_FW_ERRORS,
+                                 "Restarting adapter due to uCode error.\n");
+                       queue_work(priv->workqueue, &priv->restart);
+               } else
+                       IWL_DEBUG(priv, IWL_DL_FW_ERRORS,
+                                 "Detected FW error, but not restarting\n");
+       }
+}
+
+/**
+ * iwl_irq_handle_error - called for HW or SW error interrupt from card
+ */
+void iwl_irq_handle_error(struct iwl_priv *priv)
+{
        /* W/A for WiFi/WiMAX coex and WiMAX own the RF */
        if (priv->cfg->internal_wimax_coex &&
            (!(iwl_read_prph(priv, APMG_CLK_CTRL_REG) &
                        APMS_CLK_VAL_MRB_FUNC_MODE) ||
             (iwl_read_prph(priv, APMG_PS_CTRL_REG) &
                        APMG_PS_CTRL_VAL_RESET_REQ))) {
-               wake_up_interruptible(&priv->wait_command_queue);
                /*
-                *Keep the restart process from trying to send host
-                * commands by clearing the INIT status bit
+                * Keep the restart process from trying to send host
+                * commands by clearing the ready bit.
                 */
                clear_bit(STATUS_READY, &priv->status);
+               clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+               wake_up_interruptible(&priv->wait_command_queue);
                IWL_ERR(priv, "RF is used by WiMAX\n");
                return;
        }
@@ -923,50 +961,17 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
        IWL_ERR(priv, "Loaded firmware version: %s\n",
                priv->hw->wiphy->fw_version);
 
-       priv->cfg->ops->lib->dump_nic_error_log(priv);
-       if (priv->cfg->ops->lib->dump_csr)
-               priv->cfg->ops->lib->dump_csr(priv);
-       if (priv->cfg->ops->lib->dump_fh)
-               priv->cfg->ops->lib->dump_fh(priv, NULL, false);
-       priv->cfg->ops->lib->dump_nic_event_log(priv, false, NULL, false);
+       iwl_dump_nic_error_log(priv);
+       iwl_dump_csr(priv);
+       iwl_dump_fh(priv, NULL, false);
+       iwl_dump_nic_event_log(priv, false, NULL, false);
 #ifdef CONFIG_IWLWIFI_DEBUG
        if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS)
                iwl_print_rx_config_cmd(priv,
                                        &priv->contexts[IWL_RXON_CTX_BSS]);
 #endif
 
-       wake_up_interruptible(&priv->wait_command_queue);
-
-       /* Keep the restart process from trying to send host
-        * commands by clearing the INIT status bit */
-       clear_bit(STATUS_READY, &priv->status);
-
-       /*
-        * If firmware keep reloading, then it indicate something
-        * serious wrong and firmware having problem to recover
-        * from it. Instead of keep trying which will fill the syslog
-        * and hang the system, let's just stop it
-        */
-       reload_jiffies = jiffies;
-       reload_msec = jiffies_to_msecs((long) reload_jiffies -
-                               (long) priv->reload_jiffies);
-       priv->reload_jiffies = reload_jiffies;
-       if (reload_msec <= IWL_MIN_RELOAD_DURATION) {
-               priv->reload_count++;
-               if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) {
-                       IWL_ERR(priv, "BUG_ON, Stop restarting\n");
-                       return;
-               }
-       } else
-               priv->reload_count = 0;
-
-       if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
-               IWL_DEBUG(priv, IWL_DL_FW_ERRORS,
-                         "Restarting adapter due to uCode error.\n");
-
-               if (priv->cfg->mod_params->restart_fw)
-                       queue_work(priv->workqueue, &priv->restart);
-       }
+       iwlagn_fw_error(priv, false);
 }
 
 static int iwl_apm_stop_master(struct iwl_priv *priv)
@@ -1040,7 +1045,6 @@ int iwl_apm_init(struct iwl_priv *priv)
        /*
         * Enable HAP INTA (interrupt from management bus) to
         * wake device's PCI Express link L1a -> L0s
-        * NOTE:  This is no-op for 3945 (non-existant bit)
         */
        iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
                                    CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);
@@ -1053,20 +1057,18 @@ int iwl_apm_init(struct iwl_priv *priv)
         * If not (unlikely), enable L0S, so there is at least some
         *    power savings, even without L1.
         */
-       if (priv->cfg->base_params->set_l0s) {
-               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");
-               }
+       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");
        }
 
        /* Configure analog phase-lock-loop before activating to D0A */
@@ -1094,21 +1096,13 @@ int iwl_apm_init(struct iwl_priv *priv)
        }
 
        /*
-        * Enable DMA and BSM (if used) clocks, wait for them to stabilize.
-        * BSM (Boostrap State Machine) is only in 3945 and 4965;
-        * later devices (i.e. 5000 and later) have non-volatile SRAM,
-        * and don't need BSM to restore data after power-saving sleep.
+        * Enable DMA clock and wait for it to stabilize.
         *
         * Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" bits
         * do not disable clocks.  This preserves any hardware bits already
         * set by default in "CLK_CTRL_REG" after reset.
         */
-       if (priv->cfg->base_params->use_bsm)
-               iwl_write_prph(priv, APMG_CLK_EN_REG,
-                       APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT);
-       else
-               iwl_write_prph(priv, APMG_CLK_EN_REG,
-                       APMG_CLK_VAL_DMA_CLK_RQT);
+       iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT);
        udelay(20);
 
        /* Disable L1-Active */
@@ -1430,7 +1424,6 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw,
 
        iwl_teardown_interface(priv, vif, false);
 
-       memset(priv->bssid, 0, ETH_ALEN);
        mutex_unlock(&priv->mutex);
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -1756,15 +1749,7 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external)
                        break;
                }
                IWL_ERR(priv, "On demand firmware reload\n");
-               /* Set the FW error flag -- cleared on iwl_down */
-               set_bit(STATUS_FW_ERROR, &priv->status);
-               wake_up_interruptible(&priv->wait_command_queue);
-               /*
-                * Keep the restart process from trying to send host
-                * commands by clearing the INIT status bit
-                */
-               clear_bit(STATUS_READY, &priv->status);
-               queue_work(priv->workqueue, &priv->restart);
+               iwlagn_fw_error(priv, true);
                break;
        }
        return 0;
@@ -1783,6 +1768,15 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 
        mutex_lock(&priv->mutex);
 
+       if (!ctx->vif || !iwl_is_ready_rf(priv)) {
+               /*
+                * Huh? But wait ... this can maybe happen when
+                * we're in the middle of a firmware restart!
+                */
+               err = -EBUSY;
+               goto out;
+       }
+
        interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes;
 
        if (!(interface_modes & BIT(newtype))) {
@@ -1810,6 +1804,7 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        /* success */
        iwl_teardown_interface(priv, vif, true);
        vif->type = newtype;
+       vif->p2p = newp2p;
        err = iwl_setup_interface(priv, ctx);
        WARN_ON(err);
        /*