iwlwifi: 802.11n add support to 8K A-MSDU Rx frames
authorRon Rindjunsky <ron.rindjunsky@intel.com>
Mon, 26 Nov 2007 14:14:42 +0000 (16:14 +0200)
committerDavid S. Miller <davem@davemloft.net>
Mon, 28 Jan 2008 23:05:46 +0000 (15:05 -0800)
This patch give the iwlwifi the ability to support A-MSDU up to 8K

Please notice - in order to work in 8K A-MSDU ucode support is needed,
version 4.44.1.19 (soon to be published). 4K A-MSDU works in current ucode
version as well.

Signed-off-by: Ron Rindjunsky <ron.rindjunsky@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/iwlwifi/iwl-3945-hw.h
drivers/net/wireless/iwlwifi/iwl-3945.c
drivers/net/wireless/iwlwifi/iwl-3945.h
drivers/net/wireless/iwlwifi/iwl-4965-hw.h
drivers/net/wireless/iwlwifi/iwl-4965.c
drivers/net/wireless/iwlwifi/iwl-4965.h
drivers/net/wireless/iwlwifi/iwl4965-base.c

index ec619533fcd98d10bacdbada5aeda0ce3cc5cdf7..2c955a6070f96805991e7181add0e59a5568d8de 100644 (file)
@@ -646,9 +646,6 @@ struct iwl3945_eeprom {
 #define RX_FREE_BUFFERS 64
 #define RX_LOW_WATERMARK 8
 
-/* Size of one Rx buffer in host DRAM */
-#define IWL_RX_BUF_SIZE 3000
-
 /* Sizes and addresses for instruction and data memory (SRAM) in
  * 3945's embedded processor.  Driver access is via HBUS_TARG_MEM_* regs. */
 #define RTC_INST_LOWER_BOUND                   (0x000000)
index 1b81545b94eadd94ec6e4fc595f883524ebb3416..7d15b33b9dcdddef5d43f2ec8599195f66a550b5 100644 (file)
@@ -2229,7 +2229,8 @@ int iwl3945_hw_set_hw_setting(struct iwl3945_priv *priv)
        }
 
        priv->hw_setting.ac_queue_count = AC_NUM;
-       priv->hw_setting.rx_buffer_size = IWL_RX_BUF_SIZE;
+       priv->hw_setting.rx_buf_size = IWL_RX_BUF_SIZE;
+       priv->hw_setting.max_pkt_size = 2342;
        priv->hw_setting.tx_cmd_len = sizeof(struct iwl3945_tx_cmd);
        priv->hw_setting.max_rxq_size = RX_QUEUE_SIZE;
        priv->hw_setting.max_rxq_log = RX_QUEUE_SIZE_LOG;
index 263b0b71c0c3c743748e8a320c1f49eacac2e0b7..709203a419862808b5fee98352a3252ad84e8694 100644 (file)
@@ -75,6 +75,7 @@ enum iwl3945_antenna {
  * else RTS for data/management frames where MPDU is larger
  *   than RTS value.
  */
+#define IWL_RX_BUF_SIZE           3000U
 #define DEFAULT_RTS_THRESHOLD     2347U
 #define MIN_RTS_THRESHOLD         0U
 #define MAX_RTS_THRESHOLD         2347U
@@ -452,6 +453,30 @@ union iwl3945_ht_rate_supp {
        };
 };
 
+#ifdef CONFIG_IWL3945_HT
+#define CFG_HT_RX_AMPDU_FACTOR_DEF  (0x3)
+#define CFG_HT_MPDU_DENSITY_2USEC   (0x5)
+#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_2USEC
+
+struct sta_ht_info {
+       u8 is_ht;
+       u16 rx_mimo_ps_mode;
+       u16 tx_mimo_ps_mode;
+       u16 control_channel;
+       u8 max_amsdu_size;
+       u8 ampdu_factor;
+       u8 mpdu_density;
+       u8 operating_mode;
+       u8 supported_chan_width;
+       u8 extension_chan_offset;
+       u8 is_green_field;
+       u8 sgf;
+       u8 supp_rates[16];
+       u8 tx_chan_width;
+       u8 chan_width_cap;
+};
+#endif                         /*CONFIG_IWL3945_HT */
+
 #ifdef CONFIG_IWL3945_QOS
 
 union iwl3945_qos_capabity {
@@ -535,7 +560,8 @@ struct iwl3945_ibss_seq {
  * @ac_queue_count: # Tx queues for EDCA Access Categories (AC)
  * @tx_cmd_len: Size of Tx command (but not including frame itself)
  * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2)
- * @rx_buffer_size:
+ * @rx_buf_size:
+ * @max_pkt_size:
  * @max_rxq_log: Log-base-2 of max_rxq_size
  * @max_stations:
  * @bcast_sta_id:
@@ -547,7 +573,8 @@ struct iwl3945_driver_hw_info {
        u16 ac_queue_count;
        u16 tx_cmd_len;
        u16 max_rxq_size;
-       u32 rx_buffer_size;
+       u32 rx_buf_size;
+       u32 max_pkt_size;
        u16 max_rxq_log;
        u8  max_stations;
        u8  bcast_sta_id;
index d5d418e61923e118a5b15d71f029de7102854cf2..7e7d6e497e0fe2616fe1772630723e7ddeaddd55 100644 (file)
@@ -609,7 +609,8 @@ struct iwl4965_eeprom {
 #define RX_LOW_WATERMARK 8
 
 /* Size of one Rx buffer in host DRAM */
-#define IWL_RX_BUF_SIZE (4 * 1024)
+#define IWL_RX_BUF_SIZE_4K (4 * 1024)
+#define IWL_RX_BUF_SIZE_8K (8 * 1024)
 
 /* Sizes and addresses for instruction and data memory (SRAM) in
  * 4965's embedded processor.  Driver access is via HBUS_TARG_MEM_* regs. */
@@ -1457,13 +1458,17 @@ enum {
 #define FH_RCSR_CHNL0_RX_CONFIG_DMA_CHNL_EN_MASK  (0xC0000000) /* bits 30-31 */
 
 #define FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT  (20)
-#define FH_RCSR_RX_CONFIG_RB_SIZE_BITSHIFT     (16)
+#define FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_BITSHIFT        (4)
+#define RX_RB_TIMEOUT  (0x10)
 
 #define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_VAL         (0x00000000)
 #define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_EOF_VAL     (0x40000000)
 #define FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL        (0x80000000)
 
-#define IWL_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K    (0x00000000)
+#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K    (0x00000000)
+#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K    (0x00010000)
+#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_12K   (0x00020000)
+#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_16K   (0x00030000)
 
 #define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL       (0x00000000)
 #define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL     (0x00001000)
index 55d61000e34240225ce4b944944fb101c304b5ba..f65fd6e5fecce1980a8aae3f55b023eec7f1ec90 100644 (file)
@@ -226,6 +226,7 @@ static int iwl4965_rx_init(struct iwl4965_priv *priv, struct iwl4965_rx_queue *r
 {
        int rc;
        unsigned long flags;
+       unsigned int rb_size;
 
        spin_lock_irqsave(&priv->lock, flags);
        rc = iwl4965_grab_nic_access(priv);
@@ -234,6 +235,11 @@ static int iwl4965_rx_init(struct iwl4965_priv *priv, struct iwl4965_rx_queue *r
                return rc;
        }
 
+       if (iwl4965_param_amsdu_size_8K)
+               rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
+       else
+               rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K;
+
        /* Stop Rx DMA */
        iwl4965_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
 
@@ -253,7 +259,7 @@ static int iwl4965_rx_init(struct iwl4965_priv *priv, struct iwl4965_rx_queue *r
        iwl4965_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG,
                             FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
                             FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
-                            IWL_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K |
+                            rb_size |
                             /*0x10 << 4 | */
                             (RX_QUEUE_SIZE_LOG <<
                              FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT));
@@ -1771,7 +1777,11 @@ int iwl4965_hw_set_hw_setting(struct iwl4965_priv *priv)
        priv->hw_setting.tx_cmd_len = sizeof(struct iwl4965_tx_cmd);
        priv->hw_setting.max_rxq_size = RX_QUEUE_SIZE;
        priv->hw_setting.max_rxq_log = RX_QUEUE_SIZE_LOG;
-
+       if (iwl4965_param_amsdu_size_8K)
+               priv->hw_setting.rx_buf_size = IWL_RX_BUF_SIZE_8K;
+       else
+               priv->hw_setting.rx_buf_size = IWL_RX_BUF_SIZE_4K;
+       priv->hw_setting.max_pkt_size = priv->hw_setting.rx_buf_size - 256;
        priv->hw_setting.max_stations = IWL4965_STATION_COUNT;
        priv->hw_setting.bcast_sta_id = IWL4965_BROADCAST_ID;
        return 0;
@@ -3619,7 +3629,7 @@ static void iwl4965_handle_data_packet(struct iwl4965_priv *priv, int is_data,
                rx_start->byte_count = amsdu->byte_count;
                rx_end = (__le32 *) (((u8 *) hdr) + len);
        }
-       if (len > IWL_RX_BUF_SIZE || len < 16) {
+       if (len > priv->hw_setting.max_pkt_size || len < 16) {
                IWL_WARNING("byte count out of range [16,4K]"
                               " : %d\n", len);
                return;
@@ -3785,6 +3795,10 @@ void iwl4965_init_ht_hw_capab(struct ieee80211_ht_info *ht_info, int mode)
        ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20;
        ht_info->cap |= (u16)(IEEE80211_HT_CAP_MIMO_PS &
                             (IWL_MIMO_PS_NONE << 2));
+       if (iwl4965_param_amsdu_size_8K) {
+               printk(KERN_DEBUG "iwl4965 in A-MSDU 8K support mode\n");
+               ht_info->cap |= (u16)IEEE80211_HT_CAP_MAX_AMSDU;
+       }
 
        ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
        ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF;
index 50209e6cdd0c8b58ec9043b9242d02ed2308d07b..5a410e284b95fe632adce2811bd3a0fcf8ae84a2 100644 (file)
@@ -60,6 +60,7 @@ extern struct pci_device_id iwl4965_hw_card_ids[];
 /* Module parameters accessible from iwl-*.c */
 extern int iwl4965_param_hwcrypto;
 extern int iwl4965_param_queues_num;
+extern int iwl4965_param_amsdu_size_8K;
 
 enum iwl4965_antenna {
        IWL_ANTENNA_DIVERSITY,
@@ -506,7 +507,6 @@ union iwl4965_ht_rate_supp {
 
 #ifdef CONFIG_IWL4965_HT
 #define CFG_HT_RX_AMPDU_FACTOR_DEF  (0x3)
-#define HT_IE_MAX_AMSDU_SIZE_4K     (0)
 #define CFG_HT_MPDU_DENSITY_2USEC   (0x5)
 #define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_2USEC
 
@@ -618,7 +618,8 @@ struct iwl4965_driver_hw_info {
        u16 ac_queue_count;
        u16 tx_cmd_len;
        u16 max_rxq_size;
-       u32 rx_buffer_size;
+       u32 rx_buf_size;
+       u32 max_pkt_size;
        u16 max_rxq_log;
        u8  max_stations;
        u8  bcast_sta_id;
index 9f89f596283ccb17c98b80b7b25687a2a965d094..3a9f14d8f26ae284e244f998070294cfd1b45a09 100644 (file)
@@ -70,6 +70,7 @@ static int iwl4965_param_antenna;  /* def: 0 = both antennas (use diversity) */
 int iwl4965_param_hwcrypto;        /* def: using software encryption */
 static int iwl4965_param_qos_enable = 1; /* def: 1 = use quality of service */
 int iwl4965_param_queues_num = IWL_MAX_NUM_QUEUES; /* def: 16 Tx queues */
+int iwl4965_param_amsdu_size_8K;   /* def: enable 8K amsdu size */
 
 /*
  * module name, copyright, version, etc.
@@ -3263,7 +3264,7 @@ void iwl4965_handle_data_packet_monitor(struct iwl4965_priv *priv,
        __le16 phy_flags_hw = cpu_to_le16(phy_flags);
 
        /* We received data from the HW, so stop the watchdog */
-       if (len > IWL_RX_BUF_SIZE - sizeof(*iwl4965_rt)) {
+       if (len > priv->hw_setting.rx_buf_size - sizeof(*iwl4965_rt)) {
                IWL_DEBUG_DROP("Dropping too large packet in monitor\n");
                return;
        }
@@ -4506,7 +4507,8 @@ static void iwl4965_rx_allocate(struct iwl4965_priv *priv)
 
                /* Alloc a new receive buffer */
                rxb->skb =
-                   alloc_skb(IWL_RX_BUF_SIZE, __GFP_NOWARN | GFP_ATOMIC);
+                   alloc_skb(priv->hw_setting.rx_buf_size,
+                               __GFP_NOWARN | GFP_ATOMIC);
                if (!rxb->skb) {
                        if (net_ratelimit())
                                printk(KERN_CRIT DRV_NAME
@@ -4522,7 +4524,7 @@ static void iwl4965_rx_allocate(struct iwl4965_priv *priv)
                /* Get physical address of RB/SKB */
                rxb->dma_addr =
                    pci_map_single(priv->pci_dev, rxb->skb->data,
-                                  IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+                          priv->hw_setting.rx_buf_size, PCI_DMA_FROMDEVICE);
                list_add_tail(&rxb->list, &rxq->rx_free);
                rxq->free_count++;
        }
@@ -4565,7 +4567,8 @@ static void iwl4965_rx_queue_free(struct iwl4965_priv *priv, struct iwl4965_rx_q
                if (rxq->pool[i].skb != NULL) {
                        pci_unmap_single(priv->pci_dev,
                                         rxq->pool[i].dma_addr,
-                                        IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+                                        priv->hw_setting.rx_buf_size,
+                                        PCI_DMA_FROMDEVICE);
                        dev_kfree_skb(rxq->pool[i].skb);
                }
        }
@@ -4616,7 +4619,8 @@ void iwl4965_rx_queue_reset(struct iwl4965_priv *priv, struct iwl4965_rx_queue *
                if (rxq->pool[i].skb != NULL) {
                        pci_unmap_single(priv->pci_dev,
                                         rxq->pool[i].dma_addr,
-                                        IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+                                        priv->hw_setting.rx_buf_size,
+                                        PCI_DMA_FROMDEVICE);
                        priv->alloc_rxb_skb--;
                        dev_kfree_skb(rxq->pool[i].skb);
                        rxq->pool[i].skb = NULL;
@@ -4750,7 +4754,7 @@ static void iwl4965_rx_handle(struct iwl4965_priv *priv)
                rxq->queue[i] = NULL;
 
                pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
-                                           IWL_RX_BUF_SIZE,
+                                           priv->hw_setting.rx_buf_size,
                                            PCI_DMA_FROMDEVICE);
                pkt = (struct iwl4965_rx_packet *)rxb->skb->data;
 
@@ -4803,7 +4807,8 @@ static void iwl4965_rx_handle(struct iwl4965_priv *priv)
                }
 
                pci_unmap_single(priv->pci_dev, rxb->dma_addr,
-                                IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+                                priv->hw_setting.rx_buf_size,
+                                PCI_DMA_FROMDEVICE);
                spin_lock_irqsave(&rxq->lock, flags);
                list_add_tail(&rxb->list, &priv->rxq.rx_used);
                spin_unlock_irqrestore(&rxq->lock, flags);
@@ -9523,6 +9528,8 @@ MODULE_PARM_DESC(queues_num, "number of hw queues.");
 /* QoS */
 module_param_named(qos_enable, iwl4965_param_qos_enable, int, 0444);
 MODULE_PARM_DESC(qos_enable, "enable all QoS functionality");
+module_param_named(amsdu_size_8K, iwl4965_param_amsdu_size_8K, int, 0444);
+MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size");
 
 module_exit(iwl4965_exit);
 module_init(iwl4965_init);