iwlwifi: add support for 12K Receive Buffers
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Tue, 10 Nov 2015 09:57:41 +0000 (11:57 +0200)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Thu, 26 Nov 2015 14:38:48 +0000 (16:38 +0200)
802.11ac allows A-MSDU that can be up to 12KB long. Since
an entire A-MSDU needs to fit into one single Receive
Buffer (RB), add support for big RBs.
Since this adds lots of pressure to the memory manager and
significantly increase the true_size of the RX buffers,
don't enable this by default.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
drivers/net/wireless/intel/iwlwifi/dvm/main.c
drivers/net/wireless/intel/iwlwifi/iwl-drv.c
drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c
drivers/net/wireless/intel/iwlwifi/iwl-modparams.h
drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/intel/iwlwifi/iwl-trans.h
drivers/net/wireless/intel/iwlwifi/mvm/ops.c
drivers/net/wireless/intel/iwlwifi/pcie/internal.h
drivers/net/wireless/intel/iwlwifi/pcie/rx.c
drivers/net/wireless/intel/iwlwifi/pcie/trans.c

index e7616f0..41f3aa1 100644 (file)
@@ -1227,7 +1227,21 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
        trans_cfg.op_mode = op_mode;
        trans_cfg.no_reclaim_cmds = no_reclaim_cmds;
        trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds);
-       trans_cfg.rx_buf_size_8k = iwlwifi_mod_params.amsdu_size_8K;
+
+       switch (iwlwifi_mod_params.amsdu_size) {
+       case IWL_AMSDU_4K:
+               trans_cfg.rx_buf_size = IWL_AMSDU_4K;
+               break;
+       case IWL_AMSDU_8K:
+               trans_cfg.rx_buf_size = IWL_AMSDU_8K;
+               break;
+       case IWL_AMSDU_12K:
+       default:
+               trans_cfg.rx_buf_size = IWL_AMSDU_4K;
+               pr_err("Unsupported amsdu_size: %d\n",
+                      iwlwifi_mod_params.amsdu_size);
+       }
+
        trans_cfg.cmd_q_wdg_timeout = IWL_WATCHDOG_DISABLED;
 
        trans_cfg.command_names = iwl_dvm_cmd_strings;
index 463cadf..48f090a 100644 (file)
@@ -1637,9 +1637,9 @@ MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
 module_param_named(11n_disable, iwlwifi_mod_params.disable_11n, uint, S_IRUGO);
 MODULE_PARM_DESC(11n_disable,
        "disable 11n functionality, bitmap: 1: full, 2: disable agg TX, 4: disable agg RX, 8 enable agg TX");
-module_param_named(amsdu_size_8K, iwlwifi_mod_params.amsdu_size_8K,
+module_param_named(amsdu_size, iwlwifi_mod_params.amsdu_size,
                   int, S_IRUGO);
-MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size (default 0)");
+MODULE_PARM_DESC(amsdu_size, "amsdu size 0:4K 1:8K 2:12K (default 0)");
 module_param_named(fw_restart, iwlwifi_mod_params.restart_fw, bool, S_IRUGO);
 MODULE_PARM_DESC(fw_restart, "restart firmware in case of error (default true)");
 
index acc3d18..a19c458 100644 (file)
@@ -766,7 +766,7 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
        if (cfg->ht_params->ldpc)
                ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING;
 
-       if (iwlwifi_mod_params.amsdu_size_8K)
+       if (iwlwifi_mod_params.amsdu_size >= IWL_AMSDU_8K)
                ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
 
        ht_info->ampdu_factor = cfg->max_ht_ampdu_exponent;
index ac2b90d..3436c00 100644 (file)
@@ -86,6 +86,12 @@ enum iwl_disable_11n {
        IWL_ENABLE_HT_TXAGG      = BIT(3),
 };
 
+enum iwl_amsdu_size {
+       IWL_AMSDU_4K = 0,
+       IWL_AMSDU_8K = 1,
+       IWL_AMSDU_12K = 2,
+};
+
 /**
  * struct iwl_mod_params
  *
@@ -94,7 +100,7 @@ enum iwl_disable_11n {
  * @sw_crypto: using hardware encryption, default = 0
  * @disable_11n: disable 11n capabilities, default = 0,
  *     use IWL_[DIS,EN]ABLE_HT_* constants
- * @amsdu_size_8K: enable 8K amsdu size, default = 0
+ * @amsdu_size: enable 8K amsdu size, default = 4K. enum iwl_amsdu_size.
  * @restart_fw: restart firmware, default = 1
  * @bt_coex_active: enable bt coex, default = true
  * @led_mode: system default, default = 0
@@ -109,7 +115,7 @@ enum iwl_disable_11n {
 struct iwl_mod_params {
        int sw_crypto;
        unsigned int disable_11n;
-       int amsdu_size_8K;
+       int amsdu_size;
        bool restart_fw;
        bool bt_coex_active;
        int led_mode;
index 3b8e85e..60b7fce 100644 (file)
@@ -379,8 +379,19 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
        else
                vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN;
 
-       if (iwlwifi_mod_params.amsdu_size_8K)
+       switch (iwlwifi_mod_params.amsdu_size) {
+       case IWL_AMSDU_4K:
+               vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895;
+               break;
+       case IWL_AMSDU_8K:
                vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991;
+               break;
+       case IWL_AMSDU_12K:
+               vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
+               break;
+       default:
+               break;
+       }
 
        vht_cap->vht_mcs.rx_mcs_map =
                cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 |
index 6f76525..607f4f7 100644 (file)
@@ -423,6 +423,22 @@ enum iwl_trans_status {
        STATUS_TRANS_DEAD,
 };
 
+static inline int
+iwl_trans_get_rb_size_order(enum iwl_amsdu_size rb_size)
+{
+       switch (rb_size) {
+       case IWL_AMSDU_4K:
+               return get_order(4 * 1024);
+       case IWL_AMSDU_8K:
+               return get_order(8 * 1024);
+       case IWL_AMSDU_12K:
+               return get_order(12 * 1024);
+       default:
+               WARN_ON(1);
+               return -1;
+       }
+}
+
 /**
  * struct iwl_trans_config - transport configuration
  *
@@ -436,7 +452,7 @@ enum iwl_trans_status {
  *     list of such notifications to filter. Max length is
  *     %MAX_NO_RECLAIM_CMDS.
  * @n_no_reclaim_cmds: # of commands in list
- * @rx_buf_size_8k: 8 kB RX buffer size needed for A-MSDUs,
+ * @rx_buf_size: RX buffer size needed for A-MSDUs
  *     if unset 4k will be the RX buffer size
  * @bc_table_dword: set to true if the BC table expects the byte count to be
  *     in DWORD (as opposed to bytes)
@@ -456,7 +472,7 @@ struct iwl_trans_config {
        const u8 *no_reclaim_cmds;
        unsigned int n_no_reclaim_cmds;
 
-       bool rx_buf_size_8k;
+       enum iwl_amsdu_size rx_buf_size;
        bool bc_table_dword;
        bool scd_set_active;
        bool wide_cmd_header;
index 13c97f6..1646cdd 100644 (file)
@@ -485,7 +485,21 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
        trans_cfg.op_mode = op_mode;
        trans_cfg.no_reclaim_cmds = no_reclaim_cmds;
        trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds);
-       trans_cfg.rx_buf_size_8k = iwlwifi_mod_params.amsdu_size_8K;
+       switch (iwlwifi_mod_params.amsdu_size) {
+       case IWL_AMSDU_4K:
+               trans_cfg.rx_buf_size = IWL_AMSDU_4K;
+               break;
+       case IWL_AMSDU_8K:
+               trans_cfg.rx_buf_size = IWL_AMSDU_8K;
+               break;
+       case IWL_AMSDU_12K:
+               trans_cfg.rx_buf_size = IWL_AMSDU_12K;
+               break;
+       default:
+               pr_err("%s: Unsupported amsdu_size: %d\n", KBUILD_MODNAME,
+                      iwlwifi_mod_params.amsdu_size);
+               trans_cfg.rx_buf_size = IWL_AMSDU_4K;
+       }
        trans_cfg.wide_cmd_header = fw_has_api(&mvm->fw->ucode_capa,
                                               IWL_UCODE_TLV_API_WIDE_CMD_HDR);
 
index feb2f7e..bf8cb59 100644 (file)
@@ -302,7 +302,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx)
  * @ucode_write_complete: indicates that the ucode has been copied.
  * @ucode_write_waitq: wait queue for uCode load
  * @cmd_queue - command queue number
- * @rx_buf_size_8k: 8 kB RX buffer size
+ * @rx_buf_size: Rx buffer size
  * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes)
  * @scd_set_active: should the transport configure the SCD for HCMD queue
  * @wide_cmd_header: true when ucode supports wide command header format
@@ -356,7 +356,7 @@ struct iwl_trans_pcie {
        u8 n_no_reclaim_cmds;
        u8 no_reclaim_cmds[MAX_NO_RECLAIM_CMDS];
 
-       bool rx_buf_size_8k;
+       enum iwl_amsdu_size rx_buf_size;
        bool bc_table_dword;
        bool scd_set_active;
        bool wide_cmd_header;
index e06591f..b837b34 100644 (file)
@@ -602,10 +602,20 @@ static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq)
        u32 rb_size;
        const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */
 
-       if (trans_pcie->rx_buf_size_8k)
+       switch (trans_pcie->rx_buf_size) {
+       case IWL_AMSDU_4K:
+               rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K;
+               break;
+       case IWL_AMSDU_8K:
                rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
-       else
+               break;
+       case IWL_AMSDU_12K:
+               rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_12K;
+               break;
+       default:
+               WARN_ON(1);
                rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K;
+       }
 
        /* Stop Rx DMA */
        iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
@@ -629,7 +639,7 @@ static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq)
         * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set because of HW bug in
         *      the credit mechanism in 5000 HW RX FIFO
         * Direct rx interrupts to hosts
-        * Rx buffer size 4 or 8k
+        * Rx buffer size 4 or 8k or 12k
         * RB timeout 0x10
         * 256 RBDs
         */
index 9028345..889227c 100644 (file)
@@ -1435,11 +1435,9 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,
                memcpy(trans_pcie->no_reclaim_cmds, trans_cfg->no_reclaim_cmds,
                       trans_pcie->n_no_reclaim_cmds * sizeof(u8));
 
-       trans_pcie->rx_buf_size_8k = trans_cfg->rx_buf_size_8k;
-       if (trans_pcie->rx_buf_size_8k)
-               trans_pcie->rx_page_order = get_order(8 * 1024);
-       else
-               trans_pcie->rx_page_order = get_order(4 * 1024);
+       trans_pcie->rx_buf_size = trans_cfg->rx_buf_size;
+       trans_pcie->rx_page_order =
+               iwl_trans_get_rb_size_order(trans_pcie->rx_buf_size);
 
        trans_pcie->wide_cmd_header = trans_cfg->wide_cmd_header;
        trans_pcie->command_names = trans_cfg->command_names;