iwlagn: free the Tx cmd when a non empty Tx queue is freed
[deliverable/linux.git] / drivers / net / wireless / iwlwifi / iwl-agn.c
index 61437438c8439089731f862fbb6bc9c0668c86c9..1142d85ea8817c483fb43910e985834fbb6ecb13 100644 (file)
@@ -329,14 +329,14 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
                ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32));
 
        /* Make sure device is powered up for SRAM reads */
-       spin_lock_irqsave(&priv->reg_lock, reg_flags);
-       if (iwl_grab_nic_access(priv)) {
-               spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
+       spin_lock_irqsave(&bus(priv)->reg_lock, reg_flags);
+       if (iwl_grab_nic_access(bus(priv))) {
+               spin_unlock_irqrestore(&bus(priv)->reg_lock, reg_flags);
                return;
        }
 
        /* Set starting address; reads will auto-increment */
-       iwl_write32(priv, HBUS_TARG_MEM_RADDR, ptr);
+       iwl_write32(bus(priv), HBUS_TARG_MEM_RADDR, ptr);
        rmb();
 
        /*
@@ -344,20 +344,20 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
         * place event id # at far right for easier visual parsing.
         */
        for (i = 0; i < num_events; i++) {
-               ev = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
-               time = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
+               ev = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT);
+               time = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT);
                if (mode == 0) {
                        trace_iwlwifi_dev_ucode_cont_event(priv,
                                                        0, time, ev);
                } else {
-                       data = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
+                       data = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT);
                        trace_iwlwifi_dev_ucode_cont_event(priv,
                                                time, data, ev);
                }
        }
        /* Allow device to power down */
-       iwl_release_nic_access(priv);
-       spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
+       iwl_release_nic_access(bus(priv));
+       spin_unlock_irqrestore(&bus(priv)->reg_lock, reg_flags);
 }
 
 static void iwl_continuous_event_trace(struct iwl_priv *priv)
@@ -370,10 +370,12 @@ static void iwl_continuous_event_trace(struct iwl_priv *priv)
 
        base = priv->device_pointers.error_event_table;
        if (iwlagn_hw_valid_rtc_data_addr(base)) {
-               capacity = iwl_read_targ_mem(priv, base);
-               num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
-               mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
-               next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
+               capacity = iwl_read_targ_mem(bus(priv), base);
+               num_wraps = iwl_read_targ_mem(bus(priv),
+                                               base + (2 * sizeof(u32)));
+               mode = iwl_read_targ_mem(bus(priv), base + (1 * sizeof(u32)));
+               next_entry = iwl_read_targ_mem(bus(priv),
+                                               base + (3 * sizeof(u32)));
        } else
                return;
 
@@ -615,33 +617,15 @@ static int iwl_alloc_fw_desc(struct iwl_priv *priv, struct fw_desc *desc,
 
 static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
 {
-       static const u8 iwlagn_bss_ac_to_fifo[] = {
-               IWL_TX_FIFO_VO,
-               IWL_TX_FIFO_VI,
-               IWL_TX_FIFO_BE,
-               IWL_TX_FIFO_BK,
-       };
-       static const u8 iwlagn_bss_ac_to_queue[] = {
-               0, 1, 2, 3,
-       };
-       static const u8 iwlagn_pan_ac_to_fifo[] = {
-               IWL_TX_FIFO_VO_IPAN,
-               IWL_TX_FIFO_VI_IPAN,
-               IWL_TX_FIFO_BE_IPAN,
-               IWL_TX_FIFO_BK_IPAN,
-       };
-       static const u8 iwlagn_pan_ac_to_queue[] = {
-               7, 6, 5, 4,
-       };
        int i;
 
        /*
         * The default context is always valid,
         * the PAN context depends on uCode.
         */
-       priv->valid_contexts = BIT(IWL_RXON_CTX_BSS);
+       priv->shrd->valid_contexts = BIT(IWL_RXON_CTX_BSS);
        if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN)
-               priv->valid_contexts |= BIT(IWL_RXON_CTX_PAN);
+               priv->shrd->valid_contexts |= BIT(IWL_RXON_CTX_PAN);
 
        for (i = 0; i < NUM_IWL_RXON_CTX; i++)
                priv->contexts[i].ctxid = i;
@@ -654,8 +638,6 @@ static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
        priv->contexts[IWL_RXON_CTX_BSS].qos_cmd = REPLY_QOS_PARAM;
        priv->contexts[IWL_RXON_CTX_BSS].ap_sta_id = IWL_AP_ID;
        priv->contexts[IWL_RXON_CTX_BSS].wep_key_cmd = REPLY_WEPKEY;
-       priv->contexts[IWL_RXON_CTX_BSS].ac_to_fifo = iwlagn_bss_ac_to_fifo;
-       priv->contexts[IWL_RXON_CTX_BSS].ac_to_queue = iwlagn_bss_ac_to_queue;
        priv->contexts[IWL_RXON_CTX_BSS].exclusive_interface_modes =
                BIT(NL80211_IFTYPE_ADHOC);
        priv->contexts[IWL_RXON_CTX_BSS].interface_modes =
@@ -675,9 +657,6 @@ static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
        priv->contexts[IWL_RXON_CTX_PAN].wep_key_cmd = REPLY_WIPAN_WEPKEY;
        priv->contexts[IWL_RXON_CTX_PAN].bcast_sta_id = IWLAGN_PAN_BCAST_ID;
        priv->contexts[IWL_RXON_CTX_PAN].station_flags = STA_FLG_PAN_STATION;
-       priv->contexts[IWL_RXON_CTX_PAN].ac_to_fifo = iwlagn_pan_ac_to_fifo;
-       priv->contexts[IWL_RXON_CTX_PAN].ac_to_queue = iwlagn_pan_ac_to_queue;
-       priv->contexts[IWL_RXON_CTX_PAN].mcast_queue = IWL_IPAN_MCAST_QUEUE;
        priv->contexts[IWL_RXON_CTX_PAN].interface_modes =
                BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP);
 
@@ -1316,7 +1295,7 @@ static void iwl_rf_kill_ct_config(struct iwl_priv *priv)
        int ret = 0;
 
        spin_lock_irqsave(&priv->shrd->lock, flags);
-       iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+       iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_CLR,
                    CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
        spin_unlock_irqrestore(&priv->shrd->lock, flags);
        priv->thermal_throttle.ct_kill_toggle = false;
@@ -1540,9 +1519,11 @@ static void __iwl_down(struct iwl_priv *priv)
        if (!exit_pending)
                clear_bit(STATUS_EXIT_PENDING, &priv->shrd->status);
 
-       if (priv->mac80211_registered)
+       if (priv->shrd->mac80211_registered)
                ieee80211_stop_queues(priv->hw);
 
+       iwl_trans_stop_device(trans(priv));
+
        /* Clear out all status bits but a few that are stable across reset */
        priv->shrd->status &=
                        test_bit(STATUS_RF_KILL_HW, &priv->shrd->status) <<
@@ -1554,8 +1535,6 @@ static void __iwl_down(struct iwl_priv *priv)
                        test_bit(STATUS_EXIT_PENDING, &priv->shrd->status) <<
                                STATUS_EXIT_PENDING;
 
-       iwl_trans_stop_device(trans(priv));
-
        dev_kfree_skb(priv->beacon_skb);
        priv->beacon_skb = NULL;
 }
@@ -1884,7 +1863,7 @@ static int iwl_mac_setup_register(struct iwl_priv *priv,
                IWL_ERR(priv, "Failed to register hw (error %d)\n", ret);
                return ret;
        }
-       priv->mac80211_registered = 1;
+       priv->shrd->mac80211_registered = 1;
 
        return 0;
 }
@@ -1934,7 +1913,7 @@ static void iwlagn_mac_stop(struct ieee80211_hw *hw)
 
        /* User space software may expect getting rfkill changes
         * even if interface is down */
-       iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+       iwl_write32(bus(priv), CSR_INT, 0xFFFFFFFF);
        iwl_enable_rfkill_int(priv);
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -2201,7 +2180,7 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
         * since the uCode will add 0x10 before using the value.
         */
        for (i = 0; i < 8; i++) {
-               seq = priv->stations[IWL_AP_ID].tid[i].seq_number;
+               seq = priv->shrd->tid_data[IWL_AP_ID][i].seq_number;
                seq -= 0x10;
                wakeup_filter_cmd.qos_seq[i] = cpu_to_le16(seq);
        }
@@ -2329,7 +2308,7 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
        device_set_wakeup_enable(priv->bus->dev, true);
 
        /* Now let the ucode operate on its own */
-       iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
+       iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_SET,
                          CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
 
        goto out;
@@ -2355,19 +2334,19 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
 
        mutex_lock(&priv->shrd->mutex);
 
-       iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+       iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_CLR,
                          CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
 
        base = priv->device_pointers.error_event_table;
        if (iwlagn_hw_valid_rtc_data_addr(base)) {
-               spin_lock_irqsave(&priv->reg_lock, flags);
-               ret = iwl_grab_nic_access_silent(priv);
+               spin_lock_irqsave(&bus(priv)->reg_lock, flags);
+               ret = iwl_grab_nic_access_silent(bus(priv));
                if (ret == 0) {
-                       iwl_write32(priv, HBUS_TARG_MEM_RADDR, base);
-                       status = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
-                       iwl_release_nic_access(priv);
+                       iwl_write32(bus(priv), HBUS_TARG_MEM_RADDR, base);
+                       status = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT);
+                       iwl_release_nic_access(bus(priv));
                }
-               spin_unlock_irqrestore(&priv->reg_lock, flags);
+               spin_unlock_irqrestore(&bus(priv)->reg_lock, flags);
 
 #ifdef CONFIG_IWLWIFI_DEBUGFS
                if (ret == 0) {
@@ -2378,7 +2357,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
 
                        if (priv->wowlan_sram)
                                _iwl_read_targ_mem_words(
-                                       priv, 0x800000, priv->wowlan_sram,
+                                       bus(priv), 0x800000, priv->wowlan_sram,
                                        priv->ucode_wowlan.data.len / 4);
                }
 #endif
@@ -2532,6 +2511,7 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
        struct iwl_priv *priv = hw->priv;
        int ret = -EINVAL;
        struct iwl_station_priv *sta_priv = (void *) sta->drv_priv;
+       struct iwl_rxon_context *ctx =  iwl_rxon_ctx_from_vif(vif);
 
        IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n",
                     sta->addr, tid);
@@ -2585,8 +2565,8 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
        case IEEE80211_AMPDU_TX_OPERATIONAL:
                buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF);
 
-               iwl_trans_txq_agg_setup(trans(priv), iwl_sta_id(sta), tid,
-                               buf_size);
+               iwl_trans_tx_agg_setup(trans(priv), ctx->ctxid, iwl_sta_id(sta),
+                               tid, buf_size);
 
                /*
                 * If the limit is 0, then it wasn't initialised yet,
@@ -2853,7 +2833,7 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
                }
        }
        IWL_DEBUG_MAC80211(priv, "wait transmit/flush all frames\n");
-       iwlagn_wait_tx_queue_empty(priv);
+       iwl_trans_wait_tx_queue_empty(trans(priv));
 done:
        mutex_unlock(&priv->shrd->mutex);
        IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -2900,7 +2880,7 @@ static int iwl_mac_remain_on_channel(struct ieee80211_hw *hw,
        struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
        int err = 0;
 
-       if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
+       if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
                return -EOPNOTSUPP;
 
        if (!(ctx->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)))
@@ -2965,7 +2945,7 @@ static int iwl_mac_cancel_remain_on_channel(struct ieee80211_hw *hw)
 {
        struct iwl_priv *priv = hw->priv;
 
-       if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
+       if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
                return -EOPNOTSUPP;
 
        mutex_lock(&priv->shrd->mutex);
@@ -2976,6 +2956,72 @@ static int iwl_mac_cancel_remain_on_channel(struct ieee80211_hw *hw)
        return 0;
 }
 
+static int iwl_mac_tx_sync(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                          const u8 *bssid, enum ieee80211_tx_sync_type type)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       struct iwl_rxon_context *ctx = vif_priv->ctx;
+       int ret;
+       u8 sta_id;
+
+       mutex_lock(&priv->shrd->mutex);
+
+       if (iwl_is_associated_ctx(ctx)) {
+               ret = 0;
+               goto out;
+       }
+
+       if (ctx->preauth_bssid || test_bit(STATUS_SCAN_HW, &priv->shrd->status)) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       ret = iwl_add_station_common(priv, ctx, bssid, true, NULL, &sta_id);
+       if (ret)
+               goto out;
+
+       if (WARN_ON(sta_id != ctx->ap_sta_id)) {
+               ret = -EIO;
+               goto out_remove_sta;
+       }
+
+       memcpy(ctx->bssid, bssid, ETH_ALEN);
+       ctx->preauth_bssid = true;
+
+       ret = iwlagn_commit_rxon(priv, ctx);
+
+       if (ret == 0)
+               goto out;
+
+ out_remove_sta:
+       iwl_remove_station(priv, sta_id, bssid);
+ out:
+       mutex_unlock(&priv->shrd->mutex);
+       return ret;
+}
+
+static void iwl_mac_finish_tx_sync(struct ieee80211_hw *hw,
+                                  struct ieee80211_vif *vif,
+                                  const u8 *bssid,
+                                  enum ieee80211_tx_sync_type type)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       struct iwl_rxon_context *ctx = vif_priv->ctx;
+
+       mutex_lock(&priv->shrd->mutex);
+
+       if (iwl_is_associated_ctx(ctx))
+               goto out;
+
+       iwl_remove_station(priv, ctx->ap_sta_id, bssid);
+       ctx->preauth_bssid = false;
+       /* no need to commit */
+ out:
+       mutex_unlock(&priv->shrd->mutex);
+}
+
 /*****************************************************************************
  *
  * driver setup and teardown
@@ -2986,7 +3032,7 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
 {
        priv->shrd->workqueue = create_singlethread_workqueue(DRV_NAME);
 
-       init_waitqueue_head(&priv->wait_command_queue);
+       init_waitqueue_head(&priv->shrd->wait_command_queue);
 
        INIT_WORK(&priv->restart, iwl_bg_restart);
        INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
@@ -3121,6 +3167,8 @@ static void iwl_uninit_drv(struct iwl_priv *priv)
        iwl_calib_free_results(priv);
        iwl_free_geos(priv);
        iwl_free_channel_map(priv);
+       if (priv->tx_cmd_pool)
+               kmem_cache_destroy(priv->tx_cmd_pool);
        kfree(priv->scan_cmd);
        kfree(priv->beacon_cmd);
 #ifdef CONFIG_IWLWIFI_DEBUGFS
@@ -3182,13 +3230,19 @@ struct ieee80211_ops iwlagn_hw_ops = {
        .rssi_callback = iwl_mac_rssi_callback,
        CFG80211_TESTMODE_CMD(iwl_testmode_cmd)
        CFG80211_TESTMODE_DUMP(iwl_testmode_dump)
+       .tx_sync = iwl_mac_tx_sync,
+       .finish_tx_sync = iwl_mac_finish_tx_sync,
 };
 
 static u32 iwl_hw_detect(struct iwl_priv *priv)
 {
-       return iwl_read32(priv, CSR_HW_REV);
+       return iwl_read32(bus(priv), CSR_HW_REV);
 }
 
+/* Size of one Rx buffer in host DRAM */
+#define IWL_RX_BUF_SIZE_4K (4 * 1024)
+#define IWL_RX_BUF_SIZE_8K (8 * 1024)
+
 static int iwl_set_hw_params(struct iwl_priv *priv)
 {
        if (iwlagn_mod_params.amsdu_size_8K)
@@ -3201,6 +3255,13 @@ static int iwl_set_hw_params(struct iwl_priv *priv)
        if (iwlagn_mod_params.disable_11n)
                priv->cfg->sku &= ~EEPROM_SKU_CAP_11N_ENABLE;
 
+       hw_params(priv).num_ampdu_queues =
+               priv->cfg->base_params->num_of_ampdu_queues;
+       hw_params(priv).shadow_reg_enable =
+               priv->cfg->base_params->shadow_reg_enable;
+       hw_params(priv).sku = priv->cfg->sku;
+       hw_params(priv).wd_timeout = priv->cfg->base_params->wd_timeout;
+
        /* Device-specific setup */
        return priv->cfg->lib->set_hw_params(priv);
 }
@@ -3250,6 +3311,7 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
        priv->shrd = &priv->_shrd;
        priv->shrd->bus = bus;
        priv->shrd->priv = priv;
+       priv->shrd->hw = hw;
        bus_set_drv_data(priv->bus, priv->shrd);
 
        priv->shrd->trans = trans_ops->alloc(priv->shrd);
@@ -3282,7 +3344,7 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
        /* these spin locks will be used in apm_ops.init and EEPROM access
         * we should init now
         */
-       spin_lock_init(&priv->reg_lock);
+       spin_lock_init(&bus(priv)->reg_lock);
        spin_lock_init(&priv->shrd->lock);
 
        /*
@@ -3290,7 +3352,7 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
         * strange state ... like being left stranded by a primary kernel
         * and this is now the kdump kernel trying to start up
         */
-       iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
+       iwl_write32(bus(priv), CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
 
        /***********************
         * 3. Read REV register
@@ -3371,7 +3433,8 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
        iwl_enable_rfkill_int(priv);
 
        /* If platform's RF_KILL switch is NOT set to KILL */
-       if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
+       if (iwl_read32(bus(priv),
+                       CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
                clear_bit(STATUS_RF_KILL_HW, &priv->shrd->status);
        else
                set_bit(STATUS_RF_KILL_HW, &priv->shrd->status);
@@ -3424,25 +3487,18 @@ void __devexit iwl_remove(struct iwl_priv * priv)
        iwl_testmode_cleanup(priv);
        iwl_leds_exit(priv);
 
-       if (priv->mac80211_registered) {
+       if (priv->shrd->mac80211_registered) {
                ieee80211_unregister_hw(priv->hw);
-               priv->mac80211_registered = 0;
+               priv->shrd->mac80211_registered = 0;
        }
 
-       /* Reset to low power before unloading driver. */
-       iwl_apm_stop(priv);
-
        iwl_tt_exit(priv);
 
-       /* make sure we flush any pending irq or
-        * tasklet for the driver */
-       iwl_trans_disable_sync_irq(trans(priv));
+       /*This will stop the queues, move the device to low power state */
+       iwl_trans_stop_device(trans(priv));
 
        iwl_dealloc_ucode(priv);
 
-       iwl_trans_rx_free(trans(priv));
-       iwl_trans_tx_free(trans(priv));
-
        iwl_eeprom_free(priv);
 
        /*netif_stop_queue(dev); */
This page took 0.033932 seconds and 5 git commands to generate.