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;
 
 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)");
 
 
        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;
 
        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
  *
  * @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
 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;
 
        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 |
 
        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
  *
  *     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)
        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;
 
        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);
 
 
  * @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
        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;
 
        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);
         * 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
         */
 
                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;