iwlwifi: move queue mapping out of transport
[deliverable/linux.git] / drivers / net / wireless / iwlwifi / iwl-agn.c
index f1226dbf789d796c7c366fe102f410eb32537f7f..c9079af61b1a23de1b1efea22a52f2c7502c64e0 100644 (file)
@@ -488,6 +488,93 @@ static void iwl_bg_tx_flush(struct work_struct *work)
        iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL);
 }
 
+/*
+ * queue/FIFO/AC mapping definitions
+ */
+
+#define IWL_TX_FIFO_BK         0       /* shared */
+#define IWL_TX_FIFO_BE         1
+#define IWL_TX_FIFO_VI         2       /* shared */
+#define IWL_TX_FIFO_VO         3
+#define IWL_TX_FIFO_BK_IPAN    IWL_TX_FIFO_BK
+#define IWL_TX_FIFO_BE_IPAN    4
+#define IWL_TX_FIFO_VI_IPAN    IWL_TX_FIFO_VI
+#define IWL_TX_FIFO_VO_IPAN    5
+/* re-uses the VO FIFO, uCode will properly flush/schedule */
+#define IWL_TX_FIFO_AUX                5
+#define IWL_TX_FIFO_UNUSED     -1
+
+#define IWLAGN_CMD_FIFO_NUM    7
+
+/*
+ * This queue number is required for proper operation
+ * because the ucode will stop/start the scheduler as
+ * required.
+ */
+#define IWL_IPAN_MCAST_QUEUE   8
+
+static const u8 iwlagn_default_queue_to_tx_fifo[] = {
+       IWL_TX_FIFO_VO,
+       IWL_TX_FIFO_VI,
+       IWL_TX_FIFO_BE,
+       IWL_TX_FIFO_BK,
+       IWLAGN_CMD_FIFO_NUM,
+};
+
+static const u8 iwlagn_ipan_queue_to_tx_fifo[] = {
+       IWL_TX_FIFO_VO,
+       IWL_TX_FIFO_VI,
+       IWL_TX_FIFO_BE,
+       IWL_TX_FIFO_BK,
+       IWL_TX_FIFO_BK_IPAN,
+       IWL_TX_FIFO_BE_IPAN,
+       IWL_TX_FIFO_VI_IPAN,
+       IWL_TX_FIFO_VO_IPAN,
+       IWL_TX_FIFO_BE_IPAN,
+       IWLAGN_CMD_FIFO_NUM,
+       IWL_TX_FIFO_AUX,
+};
+
+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,
+};
+
+static const u8 iwlagn_bss_queue_to_ac[] = {
+       IEEE80211_AC_VO,
+       IEEE80211_AC_VI,
+       IEEE80211_AC_BE,
+       IEEE80211_AC_BK,
+};
+
+static const u8 iwlagn_pan_queue_to_ac[] = {
+       IEEE80211_AC_VO,
+       IEEE80211_AC_VI,
+       IEEE80211_AC_BE,
+       IEEE80211_AC_BK,
+       IEEE80211_AC_BK,
+       IEEE80211_AC_BE,
+       IEEE80211_AC_VI,
+       IEEE80211_AC_VO,
+};
+
 static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
 {
        int i;
@@ -520,6 +607,10 @@ static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
        priv->contexts[IWL_RXON_CTX_BSS].ibss_devtype = RXON_DEV_TYPE_IBSS;
        priv->contexts[IWL_RXON_CTX_BSS].station_devtype = RXON_DEV_TYPE_ESS;
        priv->contexts[IWL_RXON_CTX_BSS].unused_devtype = RXON_DEV_TYPE_ESS;
+       memcpy(priv->contexts[IWL_RXON_CTX_BSS].ac_to_queue,
+              iwlagn_bss_ac_to_queue, sizeof(iwlagn_bss_ac_to_queue));
+       memcpy(priv->contexts[IWL_RXON_CTX_BSS].ac_to_fifo,
+              iwlagn_bss_ac_to_fifo, sizeof(iwlagn_bss_ac_to_fifo));
 
        priv->contexts[IWL_RXON_CTX_PAN].rxon_cmd = REPLY_WIPAN_RXON;
        priv->contexts[IWL_RXON_CTX_PAN].rxon_timing_cmd =
@@ -542,6 +633,11 @@ static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
        priv->contexts[IWL_RXON_CTX_PAN].ap_devtype = RXON_DEV_TYPE_CP;
        priv->contexts[IWL_RXON_CTX_PAN].station_devtype = RXON_DEV_TYPE_2STA;
        priv->contexts[IWL_RXON_CTX_PAN].unused_devtype = RXON_DEV_TYPE_P2P;
+       memcpy(priv->contexts[IWL_RXON_CTX_PAN].ac_to_queue,
+              iwlagn_pan_ac_to_queue, sizeof(iwlagn_pan_ac_to_queue));
+       memcpy(priv->contexts[IWL_RXON_CTX_PAN].ac_to_fifo,
+              iwlagn_pan_ac_to_fifo, sizeof(iwlagn_pan_ac_to_fifo));
+       priv->contexts[IWL_RXON_CTX_PAN].mcast_queue = IWL_IPAN_MCAST_QUEUE;
 
        BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
 }
@@ -869,6 +965,7 @@ void iwlagn_prepare_restart(struct iwl_priv *priv)
        u8 bt_load;
        u8 bt_status;
        bool bt_is_sco;
+       int i;
 
        lockdep_assert_held(&priv->mutex);
 
@@ -898,6 +995,15 @@ void iwlagn_prepare_restart(struct iwl_priv *priv)
        priv->bt_traffic_load = bt_load;
        priv->bt_status = bt_status;
        priv->bt_is_sco = bt_is_sco;
+
+       /* reset all queues */
+       for (i = 0; i < IEEE80211_NUM_ACS; i++)
+               atomic_set(&priv->ac_stop_count[i], 0);
+
+       for (i = IWLAGN_FIRST_AMPDU_QUEUE; i < IWL_MAX_HW_QUEUES; i++)
+               priv->queue_to_ac[i] = IWL_INVALID_AC;
+
+       memset(priv->agg_q_alloc, 0, sizeof(priv->agg_q_alloc));
 }
 
 static void iwl_bg_restart(struct work_struct *data)
@@ -1130,8 +1236,6 @@ static void iwl_set_hw_params(struct iwl_priv *priv)
        if (iwlagn_mod_params.disable_11n & IWL_DISABLE_HT_ALL)
                hw_params(priv).sku &= ~EEPROM_SKU_CAP_11N_ENABLE;
 
-       hw_params(priv).num_ampdu_queues =
-               cfg(priv)->base_params->num_of_ampdu_queues;
        hw_params(priv).wd_timeout = cfg(priv)->base_params->wd_timeout;
 
        /* Device-specific setup */
@@ -1178,7 +1282,6 @@ static void iwl_debug_config(struct iwl_priv *priv)
 static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
                                                 const struct iwl_fw *fw)
 {
-       int err = 0;
        struct iwl_priv *priv;
        struct ieee80211_hw *hw;
        struct iwl_op_mode *op_mode;
@@ -1193,6 +1296,9 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
                STATISTICS_NOTIFICATION,
                REPLY_TX,
        };
+       const u8 *q_to_ac;
+       int n_q_to_ac;
+       int i;
 
        /************************
         * 1. Allocating HW data
@@ -1201,7 +1307,6 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
        if (!hw) {
                pr_err("%s: Cannot allocate network device\n",
                                cfg(trans)->name);
-               err = -ENOMEM;
                goto out;
        }
 
@@ -1230,9 +1335,19 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
        if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN) {
                priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN;
                trans_cfg.cmd_queue = IWL_IPAN_CMD_QUEUE_NUM;
+               trans_cfg.queue_to_fifo = iwlagn_ipan_queue_to_tx_fifo;
+               trans_cfg.n_queue_to_fifo =
+                       ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo);
+               q_to_ac = iwlagn_pan_queue_to_ac;
+               n_q_to_ac = ARRAY_SIZE(iwlagn_pan_queue_to_ac);
        } else {
                priv->sta_key_max_num = STA_KEY_MAX_NUM;
                trans_cfg.cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
+               trans_cfg.queue_to_fifo = iwlagn_default_queue_to_tx_fifo;
+               trans_cfg.n_queue_to_fifo =
+                       ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo);
+               q_to_ac = iwlagn_bss_queue_to_ac;
+               n_q_to_ac = ARRAY_SIZE(iwlagn_bss_queue_to_ac);
        }
 
        /* Configure transport layer */
@@ -1273,26 +1388,24 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
        IWL_INFO(priv, "Detected %s, REV=0x%X\n",
                cfg(priv)->name, trans(priv)->hw_rev);
 
-       err = iwl_trans_start_hw(trans(priv));
-       if (err)
+       if (iwl_trans_start_hw(trans(priv)))
                goto out_free_traffic_mem;
 
        /*****************
         * 3. Read EEPROM
         *****************/
-       err = iwl_eeprom_init(trans(priv), trans(priv)->hw_rev);
-       /* Reset chip to save power until we load uCode during "up". */
-       iwl_trans_stop_hw(trans(priv));
-       if (err) {
+       /* Read the EEPROM */
+       if (iwl_eeprom_init(trans(priv), trans(priv)->hw_rev)) {
                IWL_ERR(priv, "Unable to init EEPROM\n");
                goto out_free_traffic_mem;
        }
-       err = iwl_eeprom_check_version(priv);
-       if (err)
+       /* Reset chip to save power until we load uCode during "up". */
+       iwl_trans_stop_hw(trans(priv));
+
+       if (iwl_eeprom_check_version(priv))
                goto out_free_eeprom;
 
-       err = iwl_eeprom_init_hw_params(priv);
-       if (err)
+       if (iwl_eeprom_init_hw_params(priv))
                goto out_free_eeprom;
 
        /* extract MAC Address */
@@ -1323,6 +1436,11 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
                ucode_flags &= ~IWL_UCODE_TLV_FLAGS_P2P;
                priv->sta_key_max_num = STA_KEY_MAX_NUM;
                trans_cfg.cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
+               trans_cfg.queue_to_fifo = iwlagn_default_queue_to_tx_fifo;
+               trans_cfg.n_queue_to_fifo =
+                       ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo);
+               q_to_ac = iwlagn_bss_queue_to_ac;
+               n_q_to_ac = ARRAY_SIZE(iwlagn_bss_queue_to_ac);
 
                /* Configure transport layer again*/
                iwl_trans_configure(trans(priv), &trans_cfg);
@@ -1331,10 +1449,22 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
        /*******************
         * 5. Setup priv
         *******************/
+       for (i = 0; i < IEEE80211_NUM_ACS; i++)
+               atomic_set(&priv->ac_stop_count[i], 0);
+
+       for (i = 0; i < IWL_MAX_HW_QUEUES; i++) {
+               if (i < n_q_to_ac)
+                       priv->queue_to_ac[i] = q_to_ac[i];
+               else
+                       priv->queue_to_ac[i] = IWL_INVALID_AC;
+       }
 
-       err = iwl_init_drv(priv);
-       if (err)
+       WARN_ON(trans_cfg.queue_to_fifo[trans_cfg.cmd_queue] !=
+                                               IWLAGN_CMD_FIFO_NUM);
+
+       if (iwl_init_drv(priv))
                goto out_free_eeprom;
+
        /* At this point both hw and priv are initialized. */
 
        /********************
@@ -1367,15 +1497,12 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
         *
         * 7. Setup and register with mac80211 and debugfs
         **************************************************/
-       err = iwlagn_mac_setup_register(priv, &fw->ucode_capa);
-       if (err)
+       if (iwlagn_mac_setup_register(priv, &fw->ucode_capa))
                goto out_destroy_workqueue;
 
-       err = iwl_dbgfs_register(priv, DRV_NAME);
-       if (err)
+       if (iwl_dbgfs_register(priv, DRV_NAME))
                IWL_ERR(priv,
-                       "failed to create debugfs files. Ignoring error: %d\n",
-                       err);
+                       "failed to create debugfs files. Ignoring error\n");
 
        return op_mode;
 
@@ -1446,17 +1573,39 @@ static void iwl_nic_config(struct iwl_op_mode *op_mode)
        cfg(priv)->lib->nic_config(priv);
 }
 
-static void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, u8 ac)
+static void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, int queue)
 {
        struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+       int ac = priv->queue_to_ac[queue];
+
+       if (WARN_ON_ONCE(ac == IWL_INVALID_AC))
+               return;
+
+       if (atomic_inc_return(&priv->ac_stop_count[ac]) > 1) {
+               IWL_DEBUG_TX_QUEUES(priv,
+                       "queue %d (AC %d) already stopped\n",
+                       queue, ac);
+               return;
+       }
 
        set_bit(ac, &priv->transport_queue_stop);
        ieee80211_stop_queue(priv->hw, ac);
 }
 
-static void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, u8 ac)
+static void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, int queue)
 {
        struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+       int ac = priv->queue_to_ac[queue];
+
+       if (WARN_ON_ONCE(ac == IWL_INVALID_AC))
+               return;
+
+       if (atomic_dec_return(&priv->ac_stop_count[ac]) > 0) {
+               IWL_DEBUG_TX_QUEUES(priv,
+                       "queue %d (AC %d) already awake\n",
+                       queue, ac);
+               return;
+       }
 
        clear_bit(ac, &priv->transport_queue_stop);
 
This page took 0.027822 seconds and 5 git commands to generate.