iwlwifi: add support for 12K Receive Buffers

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>
This commit is contained in:
Emmanuel Grumbach 2015-11-10 11:57:41 +02:00
parent 7d1620451d
commit 6c4fbcbc1c
10 changed files with 90 additions and 21 deletions

View 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.op_mode = op_mode;
trans_cfg.no_reclaim_cmds = no_reclaim_cmds; trans_cfg.no_reclaim_cmds = no_reclaim_cmds;
trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(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.cmd_q_wdg_timeout = IWL_WATCHDOG_DISABLED;
trans_cfg.command_names = iwl_dvm_cmd_strings; trans_cfg.command_names = iwl_dvm_cmd_strings;

View 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_param_named(11n_disable, iwlwifi_mod_params.disable_11n, uint, S_IRUGO);
MODULE_PARM_DESC(11n_disable, MODULE_PARM_DESC(11n_disable,
"disable 11n functionality, bitmap: 1: full, 2: disable agg TX, 4: disable agg RX, 8 enable agg TX"); "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); 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_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)"); MODULE_PARM_DESC(fw_restart, "restart firmware in case of error (default true)");

View File

@ -766,7 +766,7 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
if (cfg->ht_params->ldpc) if (cfg->ht_params->ldpc)
ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; 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->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
ht_info->ampdu_factor = cfg->max_ht_ampdu_exponent; ht_info->ampdu_factor = cfg->max_ht_ampdu_exponent;

View File

@ -86,6 +86,12 @@ enum iwl_disable_11n {
IWL_ENABLE_HT_TXAGG = BIT(3), 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 * struct iwl_mod_params
* *
@ -94,7 +100,7 @@ enum iwl_disable_11n {
* @sw_crypto: using hardware encryption, default = 0 * @sw_crypto: using hardware encryption, default = 0
* @disable_11n: disable 11n capabilities, default = 0, * @disable_11n: disable 11n capabilities, default = 0,
* use IWL_[DIS,EN]ABLE_HT_* constants * 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 * @restart_fw: restart firmware, default = 1
* @bt_coex_active: enable bt coex, default = true * @bt_coex_active: enable bt coex, default = true
* @led_mode: system default, default = 0 * @led_mode: system default, default = 0
@ -109,7 +115,7 @@ enum iwl_disable_11n {
struct iwl_mod_params { struct iwl_mod_params {
int sw_crypto; int sw_crypto;
unsigned int disable_11n; unsigned int disable_11n;
int amsdu_size_8K; int amsdu_size;
bool restart_fw; bool restart_fw;
bool bt_coex_active; bool bt_coex_active;
int led_mode; int led_mode;

View File

@ -379,8 +379,19 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
else else
vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN; 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; 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 = vht_cap->vht_mcs.rx_mcs_map =
cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 |

View File

@ -423,6 +423,22 @@ enum iwl_trans_status {
STATUS_TRANS_DEAD, 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 * struct iwl_trans_config - transport configuration
* *
@ -436,7 +452,7 @@ enum iwl_trans_status {
* list of such notifications to filter. Max length is * list of such notifications to filter. Max length is
* %MAX_NO_RECLAIM_CMDS. * %MAX_NO_RECLAIM_CMDS.
* @n_no_reclaim_cmds: # of commands in list * @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 * 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 * @bc_table_dword: set to true if the BC table expects the byte count to be
* in DWORD (as opposed to bytes) * in DWORD (as opposed to bytes)
@ -456,7 +472,7 @@ struct iwl_trans_config {
const u8 *no_reclaim_cmds; const u8 *no_reclaim_cmds;
unsigned int n_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 bc_table_dword;
bool scd_set_active; bool scd_set_active;
bool wide_cmd_header; bool wide_cmd_header;

View 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.op_mode = op_mode;
trans_cfg.no_reclaim_cmds = no_reclaim_cmds; trans_cfg.no_reclaim_cmds = no_reclaim_cmds;
trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(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, trans_cfg.wide_cmd_header = fw_has_api(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_API_WIDE_CMD_HDR); IWL_UCODE_TLV_API_WIDE_CMD_HDR);

View 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_complete: indicates that the ucode has been copied.
* @ucode_write_waitq: wait queue for uCode load * @ucode_write_waitq: wait queue for uCode load
* @cmd_queue - command queue number * @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) * @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 * @scd_set_active: should the transport configure the SCD for HCMD queue
* @wide_cmd_header: true when ucode supports wide command header format * @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 n_no_reclaim_cmds;
u8 no_reclaim_cmds[MAX_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 bc_table_dword;
bool scd_set_active; bool scd_set_active;
bool wide_cmd_header; bool wide_cmd_header;

View File

@ -602,10 +602,20 @@ static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq)
u32 rb_size; u32 rb_size;
const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */ const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */
if (trans_pcie->rx_buf_size_8k) switch (trans_pcie->rx_buf_size) {
rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K; case IWL_AMSDU_4K:
else
rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_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;
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 */ /* Stop Rx DMA */
iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); 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 * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set because of HW bug in
* the credit mechanism in 5000 HW RX FIFO * the credit mechanism in 5000 HW RX FIFO
* Direct rx interrupts to hosts * Direct rx interrupts to hosts
* Rx buffer size 4 or 8k * Rx buffer size 4 or 8k or 12k
* RB timeout 0x10 * RB timeout 0x10
* 256 RBDs * 256 RBDs
*/ */

View 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, memcpy(trans_pcie->no_reclaim_cmds, trans_cfg->no_reclaim_cmds,
trans_pcie->n_no_reclaim_cmds * sizeof(u8)); trans_pcie->n_no_reclaim_cmds * sizeof(u8));
trans_pcie->rx_buf_size_8k = trans_cfg->rx_buf_size_8k; trans_pcie->rx_buf_size = trans_cfg->rx_buf_size;
if (trans_pcie->rx_buf_size_8k) trans_pcie->rx_page_order =
trans_pcie->rx_page_order = get_order(8 * 1024); iwl_trans_get_rb_size_order(trans_pcie->rx_buf_size);
else
trans_pcie->rx_page_order = get_order(4 * 1024);
trans_pcie->wide_cmd_header = trans_cfg->wide_cmd_header; trans_pcie->wide_cmd_header = trans_cfg->wide_cmd_header;
trans_pcie->command_names = trans_cfg->command_names; trans_pcie->command_names = trans_cfg->command_names;