diff options
Diffstat (limited to 'drivers/net/wireless/mwl8k.c')
-rw-r--r-- | drivers/net/wireless/mwl8k.c | 875 |
1 files changed, 798 insertions, 77 deletions
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index c1ceb4b23971..32261189bcef 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c | |||
@@ -63,6 +63,7 @@ MODULE_PARM_DESC(ap_mode_default, | |||
63 | #define MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL 0x00000c38 | 63 | #define MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL 0x00000c38 |
64 | #define MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK 0x00000c3c | 64 | #define MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK 0x00000c3c |
65 | #define MWL8K_A2H_INT_DUMMY (1 << 20) | 65 | #define MWL8K_A2H_INT_DUMMY (1 << 20) |
66 | #define MWL8K_A2H_INT_BA_WATCHDOG (1 << 14) | ||
66 | #define MWL8K_A2H_INT_CHNL_SWITCHED (1 << 11) | 67 | #define MWL8K_A2H_INT_CHNL_SWITCHED (1 << 11) |
67 | #define MWL8K_A2H_INT_QUEUE_EMPTY (1 << 10) | 68 | #define MWL8K_A2H_INT_QUEUE_EMPTY (1 << 10) |
68 | #define MWL8K_A2H_INT_RADAR_DETECT (1 << 7) | 69 | #define MWL8K_A2H_INT_RADAR_DETECT (1 << 7) |
@@ -73,6 +74,14 @@ MODULE_PARM_DESC(ap_mode_default, | |||
73 | #define MWL8K_A2H_INT_RX_READY (1 << 1) | 74 | #define MWL8K_A2H_INT_RX_READY (1 << 1) |
74 | #define MWL8K_A2H_INT_TX_DONE (1 << 0) | 75 | #define MWL8K_A2H_INT_TX_DONE (1 << 0) |
75 | 76 | ||
77 | /* HW micro second timer register | ||
78 | * located at offset 0xA600. This | ||
79 | * will be used to timestamp tx | ||
80 | * packets. | ||
81 | */ | ||
82 | |||
83 | #define MWL8K_HW_TIMER_REGISTER 0x0000a600 | ||
84 | |||
76 | #define MWL8K_A2H_EVENTS (MWL8K_A2H_INT_DUMMY | \ | 85 | #define MWL8K_A2H_EVENTS (MWL8K_A2H_INT_DUMMY | \ |
77 | MWL8K_A2H_INT_CHNL_SWITCHED | \ | 86 | MWL8K_A2H_INT_CHNL_SWITCHED | \ |
78 | MWL8K_A2H_INT_QUEUE_EMPTY | \ | 87 | MWL8K_A2H_INT_QUEUE_EMPTY | \ |
@@ -82,10 +91,14 @@ MODULE_PARM_DESC(ap_mode_default, | |||
82 | MWL8K_A2H_INT_MAC_EVENT | \ | 91 | MWL8K_A2H_INT_MAC_EVENT | \ |
83 | MWL8K_A2H_INT_OPC_DONE | \ | 92 | MWL8K_A2H_INT_OPC_DONE | \ |
84 | MWL8K_A2H_INT_RX_READY | \ | 93 | MWL8K_A2H_INT_RX_READY | \ |
85 | MWL8K_A2H_INT_TX_DONE) | 94 | MWL8K_A2H_INT_TX_DONE | \ |
95 | MWL8K_A2H_INT_BA_WATCHDOG) | ||
86 | 96 | ||
87 | #define MWL8K_RX_QUEUES 1 | 97 | #define MWL8K_RX_QUEUES 1 |
88 | #define MWL8K_TX_QUEUES 4 | 98 | #define MWL8K_TX_WMM_QUEUES 4 |
99 | #define MWL8K_MAX_AMPDU_QUEUES 8 | ||
100 | #define MWL8K_MAX_TX_QUEUES (MWL8K_TX_WMM_QUEUES + MWL8K_MAX_AMPDU_QUEUES) | ||
101 | #define mwl8k_tx_queues(priv) (MWL8K_TX_WMM_QUEUES + (priv)->num_ampdu_queues) | ||
89 | 102 | ||
90 | struct rxd_ops { | 103 | struct rxd_ops { |
91 | int rxd_size; | 104 | int rxd_size; |
@@ -134,6 +147,21 @@ struct mwl8k_tx_queue { | |||
134 | struct sk_buff **skb; | 147 | struct sk_buff **skb; |
135 | }; | 148 | }; |
136 | 149 | ||
150 | enum { | ||
151 | AMPDU_NO_STREAM, | ||
152 | AMPDU_STREAM_NEW, | ||
153 | AMPDU_STREAM_IN_PROGRESS, | ||
154 | AMPDU_STREAM_ACTIVE, | ||
155 | }; | ||
156 | |||
157 | struct mwl8k_ampdu_stream { | ||
158 | struct ieee80211_sta *sta; | ||
159 | u8 tid; | ||
160 | u8 state; | ||
161 | u8 idx; | ||
162 | u8 txq_idx; /* index of this stream in priv->txq */ | ||
163 | }; | ||
164 | |||
137 | struct mwl8k_priv { | 165 | struct mwl8k_priv { |
138 | struct ieee80211_hw *hw; | 166 | struct ieee80211_hw *hw; |
139 | struct pci_dev *pdev; | 167 | struct pci_dev *pdev; |
@@ -160,6 +188,12 @@ struct mwl8k_priv { | |||
160 | u32 ap_macids_supported; | 188 | u32 ap_macids_supported; |
161 | u32 sta_macids_supported; | 189 | u32 sta_macids_supported; |
162 | 190 | ||
191 | /* Ampdu stream information */ | ||
192 | u8 num_ampdu_queues; | ||
193 | spinlock_t stream_lock; | ||
194 | struct mwl8k_ampdu_stream ampdu[MWL8K_MAX_AMPDU_QUEUES]; | ||
195 | struct work_struct watchdog_ba_handle; | ||
196 | |||
163 | /* firmware access */ | 197 | /* firmware access */ |
164 | struct mutex fw_mutex; | 198 | struct mutex fw_mutex; |
165 | struct task_struct *fw_mutex_owner; | 199 | struct task_struct *fw_mutex_owner; |
@@ -191,7 +225,8 @@ struct mwl8k_priv { | |||
191 | int pending_tx_pkts; | 225 | int pending_tx_pkts; |
192 | 226 | ||
193 | struct mwl8k_rx_queue rxq[MWL8K_RX_QUEUES]; | 227 | struct mwl8k_rx_queue rxq[MWL8K_RX_QUEUES]; |
194 | struct mwl8k_tx_queue txq[MWL8K_TX_QUEUES]; | 228 | struct mwl8k_tx_queue txq[MWL8K_MAX_TX_QUEUES]; |
229 | u32 txq_offset[MWL8K_MAX_TX_QUEUES]; | ||
195 | 230 | ||
196 | bool radio_on; | 231 | bool radio_on; |
197 | bool radio_short_preamble; | 232 | bool radio_short_preamble; |
@@ -224,7 +259,7 @@ struct mwl8k_priv { | |||
224 | * preserve the queue configurations so they can be restored if/when | 259 | * preserve the queue configurations so they can be restored if/when |
225 | * the firmware image is swapped. | 260 | * the firmware image is swapped. |
226 | */ | 261 | */ |
227 | struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_QUEUES]; | 262 | struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_WMM_QUEUES]; |
228 | 263 | ||
229 | /* async firmware loading state */ | 264 | /* async firmware loading state */ |
230 | unsigned fw_state; | 265 | unsigned fw_state; |
@@ -262,9 +297,17 @@ struct mwl8k_vif { | |||
262 | #define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv)) | 297 | #define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv)) |
263 | #define IEEE80211_KEY_CONF(_u8) ((struct ieee80211_key_conf *)(_u8)) | 298 | #define IEEE80211_KEY_CONF(_u8) ((struct ieee80211_key_conf *)(_u8)) |
264 | 299 | ||
300 | struct tx_traffic_info { | ||
301 | u32 start_time; | ||
302 | u32 pkts; | ||
303 | }; | ||
304 | |||
305 | #define MWL8K_MAX_TID 8 | ||
265 | struct mwl8k_sta { | 306 | struct mwl8k_sta { |
266 | /* Index into station database. Returned by UPDATE_STADB. */ | 307 | /* Index into station database. Returned by UPDATE_STADB. */ |
267 | u8 peer_id; | 308 | u8 peer_id; |
309 | u8 is_ampdu_allowed; | ||
310 | struct tx_traffic_info tx_stats[MWL8K_MAX_TID]; | ||
268 | }; | 311 | }; |
269 | #define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv)) | 312 | #define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv)) |
270 | 313 | ||
@@ -352,10 +395,12 @@ static const struct ieee80211_rate mwl8k_rates_50[] = { | |||
352 | #define MWL8K_CMD_ENABLE_SNIFFER 0x0150 | 395 | #define MWL8K_CMD_ENABLE_SNIFFER 0x0150 |
353 | #define MWL8K_CMD_SET_MAC_ADDR 0x0202 /* per-vif */ | 396 | #define MWL8K_CMD_SET_MAC_ADDR 0x0202 /* per-vif */ |
354 | #define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 | 397 | #define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 |
398 | #define MWL8K_CMD_GET_WATCHDOG_BITMAP 0x0205 | ||
355 | #define MWL8K_CMD_BSS_START 0x1100 /* per-vif */ | 399 | #define MWL8K_CMD_BSS_START 0x1100 /* per-vif */ |
356 | #define MWL8K_CMD_SET_NEW_STN 0x1111 /* per-vif */ | 400 | #define MWL8K_CMD_SET_NEW_STN 0x1111 /* per-vif */ |
357 | #define MWL8K_CMD_UPDATE_ENCRYPTION 0x1122 /* per-vif */ | 401 | #define MWL8K_CMD_UPDATE_ENCRYPTION 0x1122 /* per-vif */ |
358 | #define MWL8K_CMD_UPDATE_STADB 0x1123 | 402 | #define MWL8K_CMD_UPDATE_STADB 0x1123 |
403 | #define MWL8K_CMD_BASTREAM 0x1125 | ||
359 | 404 | ||
360 | static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize) | 405 | static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize) |
361 | { | 406 | { |
@@ -395,6 +440,8 @@ static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize) | |||
395 | MWL8K_CMDNAME(SET_NEW_STN); | 440 | MWL8K_CMDNAME(SET_NEW_STN); |
396 | MWL8K_CMDNAME(UPDATE_ENCRYPTION); | 441 | MWL8K_CMDNAME(UPDATE_ENCRYPTION); |
397 | MWL8K_CMDNAME(UPDATE_STADB); | 442 | MWL8K_CMDNAME(UPDATE_STADB); |
443 | MWL8K_CMDNAME(BASTREAM); | ||
444 | MWL8K_CMDNAME(GET_WATCHDOG_BITMAP); | ||
398 | default: | 445 | default: |
399 | snprintf(buf, bufsize, "0x%x", cmd); | 446 | snprintf(buf, bufsize, "0x%x", cmd); |
400 | } | 447 | } |
@@ -669,7 +716,7 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw) | |||
669 | "helper image\n", pci_name(priv->pdev)); | 716 | "helper image\n", pci_name(priv->pdev)); |
670 | return rc; | 717 | return rc; |
671 | } | 718 | } |
672 | msleep(5); | 719 | msleep(20); |
673 | 720 | ||
674 | rc = mwl8k_feed_fw_image(priv, fw->data, fw->size); | 721 | rc = mwl8k_feed_fw_image(priv, fw->data, fw->size); |
675 | } else { | 722 | } else { |
@@ -734,8 +781,11 @@ static inline void mwl8k_remove_dma_header(struct sk_buff *skb, __le16 qos) | |||
734 | skb_pull(skb, sizeof(*tr) - hdrlen); | 781 | skb_pull(skb, sizeof(*tr) - hdrlen); |
735 | } | 782 | } |
736 | 783 | ||
784 | #define REDUCED_TX_HEADROOM 8 | ||
785 | |||
737 | static void | 786 | static void |
738 | mwl8k_add_dma_header(struct sk_buff *skb, int tail_pad) | 787 | mwl8k_add_dma_header(struct mwl8k_priv *priv, struct sk_buff *skb, |
788 | int head_pad, int tail_pad) | ||
739 | { | 789 | { |
740 | struct ieee80211_hdr *wh; | 790 | struct ieee80211_hdr *wh; |
741 | int hdrlen; | 791 | int hdrlen; |
@@ -751,7 +801,23 @@ mwl8k_add_dma_header(struct sk_buff *skb, int tail_pad) | |||
751 | wh = (struct ieee80211_hdr *)skb->data; | 801 | wh = (struct ieee80211_hdr *)skb->data; |
752 | 802 | ||
753 | hdrlen = ieee80211_hdrlen(wh->frame_control); | 803 | hdrlen = ieee80211_hdrlen(wh->frame_control); |
754 | reqd_hdrlen = sizeof(*tr); | 804 | |
805 | /* | ||
806 | * Check if skb_resize is required because of | ||
807 | * tx_headroom adjustment. | ||
808 | */ | ||
809 | if (priv->ap_fw && (hdrlen < (sizeof(struct ieee80211_cts) | ||
810 | + REDUCED_TX_HEADROOM))) { | ||
811 | if (pskb_expand_head(skb, REDUCED_TX_HEADROOM, 0, GFP_ATOMIC)) { | ||
812 | |||
813 | wiphy_err(priv->hw->wiphy, | ||
814 | "Failed to reallocate TX buffer\n"); | ||
815 | return; | ||
816 | } | ||
817 | skb->truesize += REDUCED_TX_HEADROOM; | ||
818 | } | ||
819 | |||
820 | reqd_hdrlen = sizeof(*tr) + head_pad; | ||
755 | 821 | ||
756 | if (hdrlen != reqd_hdrlen) | 822 | if (hdrlen != reqd_hdrlen) |
757 | skb_push(skb, reqd_hdrlen - hdrlen); | 823 | skb_push(skb, reqd_hdrlen - hdrlen); |
@@ -773,12 +839,14 @@ mwl8k_add_dma_header(struct sk_buff *skb, int tail_pad) | |||
773 | tr->fwlen = cpu_to_le16(skb->len - sizeof(*tr) + tail_pad); | 839 | tr->fwlen = cpu_to_le16(skb->len - sizeof(*tr) + tail_pad); |
774 | } | 840 | } |
775 | 841 | ||
776 | static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb) | 842 | static void mwl8k_encapsulate_tx_frame(struct mwl8k_priv *priv, |
843 | struct sk_buff *skb) | ||
777 | { | 844 | { |
778 | struct ieee80211_hdr *wh; | 845 | struct ieee80211_hdr *wh; |
779 | struct ieee80211_tx_info *tx_info; | 846 | struct ieee80211_tx_info *tx_info; |
780 | struct ieee80211_key_conf *key_conf; | 847 | struct ieee80211_key_conf *key_conf; |
781 | int data_pad; | 848 | int data_pad; |
849 | int head_pad = 0; | ||
782 | 850 | ||
783 | wh = (struct ieee80211_hdr *)skb->data; | 851 | wh = (struct ieee80211_hdr *)skb->data; |
784 | 852 | ||
@@ -790,9 +858,7 @@ static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb) | |||
790 | 858 | ||
791 | /* | 859 | /* |
792 | * Make sure the packet header is in the DMA header format (4-address | 860 | * Make sure the packet header is in the DMA header format (4-address |
793 | * without QoS), the necessary crypto padding between the header and the | 861 | * without QoS), and add head & tail padding when HW crypto is enabled. |
794 | * payload has already been provided by mac80211, but it doesn't add tail | ||
795 | * padding when HW crypto is enabled. | ||
796 | * | 862 | * |
797 | * We have the following trailer padding requirements: | 863 | * We have the following trailer padding requirements: |
798 | * - WEP: 4 trailer bytes (ICV) | 864 | * - WEP: 4 trailer bytes (ICV) |
@@ -801,6 +867,7 @@ static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb) | |||
801 | */ | 867 | */ |
802 | data_pad = 0; | 868 | data_pad = 0; |
803 | if (key_conf != NULL) { | 869 | if (key_conf != NULL) { |
870 | head_pad = key_conf->iv_len; | ||
804 | switch (key_conf->cipher) { | 871 | switch (key_conf->cipher) { |
805 | case WLAN_CIPHER_SUITE_WEP40: | 872 | case WLAN_CIPHER_SUITE_WEP40: |
806 | case WLAN_CIPHER_SUITE_WEP104: | 873 | case WLAN_CIPHER_SUITE_WEP104: |
@@ -814,7 +881,7 @@ static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb) | |||
814 | break; | 881 | break; |
815 | } | 882 | } |
816 | } | 883 | } |
817 | mwl8k_add_dma_header(skb, data_pad); | 884 | mwl8k_add_dma_header(priv, skb, head_pad, data_pad); |
818 | } | 885 | } |
819 | 886 | ||
820 | /* | 887 | /* |
@@ -1127,6 +1194,9 @@ static void mwl8k_rxq_deinit(struct ieee80211_hw *hw, int index) | |||
1127 | struct mwl8k_rx_queue *rxq = priv->rxq + index; | 1194 | struct mwl8k_rx_queue *rxq = priv->rxq + index; |
1128 | int i; | 1195 | int i; |
1129 | 1196 | ||
1197 | if (rxq->rxd == NULL) | ||
1198 | return; | ||
1199 | |||
1130 | for (i = 0; i < MWL8K_RX_DESCS; i++) { | 1200 | for (i = 0; i < MWL8K_RX_DESCS; i++) { |
1131 | if (rxq->buf[i].skb != NULL) { | 1201 | if (rxq->buf[i].skb != NULL) { |
1132 | pci_unmap_single(priv->pdev, | 1202 | pci_unmap_single(priv->pdev, |
@@ -1319,7 +1389,7 @@ struct mwl8k_tx_desc { | |||
1319 | __le16 pkt_len; | 1389 | __le16 pkt_len; |
1320 | __u8 dest_MAC_addr[ETH_ALEN]; | 1390 | __u8 dest_MAC_addr[ETH_ALEN]; |
1321 | __le32 next_txd_phys_addr; | 1391 | __le32 next_txd_phys_addr; |
1322 | __le32 reserved; | 1392 | __le32 timestamp; |
1323 | __le16 rate_info; | 1393 | __le16 rate_info; |
1324 | __u8 peer_id; | 1394 | __u8 peer_id; |
1325 | __u8 tx_frag_cnt; | 1395 | __u8 tx_frag_cnt; |
@@ -1383,7 +1453,7 @@ static void mwl8k_dump_tx_rings(struct ieee80211_hw *hw) | |||
1383 | struct mwl8k_priv *priv = hw->priv; | 1453 | struct mwl8k_priv *priv = hw->priv; |
1384 | int i; | 1454 | int i; |
1385 | 1455 | ||
1386 | for (i = 0; i < MWL8K_TX_QUEUES; i++) { | 1456 | for (i = 0; i < mwl8k_tx_queues(priv); i++) { |
1387 | struct mwl8k_tx_queue *txq = priv->txq + i; | 1457 | struct mwl8k_tx_queue *txq = priv->txq + i; |
1388 | int fw_owned = 0; | 1458 | int fw_owned = 0; |
1389 | int drv_owned = 0; | 1459 | int drv_owned = 0; |
@@ -1452,9 +1522,8 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) | |||
1452 | 1522 | ||
1453 | if (timeout) { | 1523 | if (timeout) { |
1454 | WARN_ON(priv->pending_tx_pkts); | 1524 | WARN_ON(priv->pending_tx_pkts); |
1455 | if (retry) { | 1525 | if (retry) |
1456 | wiphy_notice(hw->wiphy, "tx rings drained\n"); | 1526 | wiphy_notice(hw->wiphy, "tx rings drained\n"); |
1457 | } | ||
1458 | break; | 1527 | break; |
1459 | } | 1528 | } |
1460 | 1529 | ||
@@ -1484,6 +1553,41 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) | |||
1484 | MWL8K_TXD_STATUS_OK_RETRY | \ | 1553 | MWL8K_TXD_STATUS_OK_RETRY | \ |
1485 | MWL8K_TXD_STATUS_OK_MORE_RETRY)) | 1554 | MWL8K_TXD_STATUS_OK_MORE_RETRY)) |
1486 | 1555 | ||
1556 | static int mwl8k_tid_queue_mapping(u8 tid) | ||
1557 | { | ||
1558 | BUG_ON(tid > 7); | ||
1559 | |||
1560 | switch (tid) { | ||
1561 | case 0: | ||
1562 | case 3: | ||
1563 | return IEEE80211_AC_BE; | ||
1564 | break; | ||
1565 | case 1: | ||
1566 | case 2: | ||
1567 | return IEEE80211_AC_BK; | ||
1568 | break; | ||
1569 | case 4: | ||
1570 | case 5: | ||
1571 | return IEEE80211_AC_VI; | ||
1572 | break; | ||
1573 | case 6: | ||
1574 | case 7: | ||
1575 | return IEEE80211_AC_VO; | ||
1576 | break; | ||
1577 | default: | ||
1578 | return -1; | ||
1579 | break; | ||
1580 | } | ||
1581 | } | ||
1582 | |||
1583 | /* The firmware will fill in the rate information | ||
1584 | * for each packet that gets queued in the hardware | ||
1585 | * and these macros will interpret that info. | ||
1586 | */ | ||
1587 | |||
1588 | #define RI_FORMAT(a) (a & 0x0001) | ||
1589 | #define RI_RATE_ID_MCS(a) ((a & 0x01f8) >> 3) | ||
1590 | |||
1487 | static int | 1591 | static int |
1488 | mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) | 1592 | mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) |
1489 | { | 1593 | { |
@@ -1500,6 +1604,10 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) | |||
1500 | struct sk_buff *skb; | 1604 | struct sk_buff *skb; |
1501 | struct ieee80211_tx_info *info; | 1605 | struct ieee80211_tx_info *info; |
1502 | u32 status; | 1606 | u32 status; |
1607 | struct ieee80211_sta *sta; | ||
1608 | struct mwl8k_sta *sta_info = NULL; | ||
1609 | u16 rate_info; | ||
1610 | struct ieee80211_hdr *wh; | ||
1503 | 1611 | ||
1504 | tx = txq->head; | 1612 | tx = txq->head; |
1505 | tx_desc = txq->txd + tx; | 1613 | tx_desc = txq->txd + tx; |
@@ -1528,18 +1636,40 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) | |||
1528 | 1636 | ||
1529 | mwl8k_remove_dma_header(skb, tx_desc->qos_control); | 1637 | mwl8k_remove_dma_header(skb, tx_desc->qos_control); |
1530 | 1638 | ||
1639 | wh = (struct ieee80211_hdr *) skb->data; | ||
1640 | |||
1531 | /* Mark descriptor as unused */ | 1641 | /* Mark descriptor as unused */ |
1532 | tx_desc->pkt_phys_addr = 0; | 1642 | tx_desc->pkt_phys_addr = 0; |
1533 | tx_desc->pkt_len = 0; | 1643 | tx_desc->pkt_len = 0; |
1534 | 1644 | ||
1535 | info = IEEE80211_SKB_CB(skb); | 1645 | info = IEEE80211_SKB_CB(skb); |
1646 | if (ieee80211_is_data(wh->frame_control)) { | ||
1647 | sta = info->control.sta; | ||
1648 | if (sta) { | ||
1649 | sta_info = MWL8K_STA(sta); | ||
1650 | BUG_ON(sta_info == NULL); | ||
1651 | rate_info = le16_to_cpu(tx_desc->rate_info); | ||
1652 | /* If rate is < 6.5 Mpbs for an ht station | ||
1653 | * do not form an ampdu. If the station is a | ||
1654 | * legacy station (format = 0), do not form an | ||
1655 | * ampdu | ||
1656 | */ | ||
1657 | if (RI_RATE_ID_MCS(rate_info) < 1 || | ||
1658 | RI_FORMAT(rate_info) == 0) { | ||
1659 | sta_info->is_ampdu_allowed = false; | ||
1660 | } else { | ||
1661 | sta_info->is_ampdu_allowed = true; | ||
1662 | } | ||
1663 | } | ||
1664 | } | ||
1665 | |||
1536 | ieee80211_tx_info_clear_status(info); | 1666 | ieee80211_tx_info_clear_status(info); |
1537 | 1667 | ||
1538 | /* Rate control is happening in the firmware. | 1668 | /* Rate control is happening in the firmware. |
1539 | * Ensure no tx rate is being reported. | 1669 | * Ensure no tx rate is being reported. |
1540 | */ | 1670 | */ |
1541 | info->status.rates[0].idx = -1; | 1671 | info->status.rates[0].idx = -1; |
1542 | info->status.rates[0].count = 1; | 1672 | info->status.rates[0].count = 1; |
1543 | 1673 | ||
1544 | if (MWL8K_TXD_SUCCESS(status)) | 1674 | if (MWL8K_TXD_SUCCESS(status)) |
1545 | info->flags |= IEEE80211_TX_STAT_ACK; | 1675 | info->flags |= IEEE80211_TX_STAT_ACK; |
@@ -1549,9 +1679,6 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) | |||
1549 | processed++; | 1679 | processed++; |
1550 | } | 1680 | } |
1551 | 1681 | ||
1552 | if (processed && priv->radio_on && !mutex_is_locked(&priv->fw_mutex)) | ||
1553 | ieee80211_wake_queue(hw, index); | ||
1554 | |||
1555 | return processed; | 1682 | return processed; |
1556 | } | 1683 | } |
1557 | 1684 | ||
@@ -1561,6 +1688,9 @@ static void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index) | |||
1561 | struct mwl8k_priv *priv = hw->priv; | 1688 | struct mwl8k_priv *priv = hw->priv; |
1562 | struct mwl8k_tx_queue *txq = priv->txq + index; | 1689 | struct mwl8k_tx_queue *txq = priv->txq + index; |
1563 | 1690 | ||
1691 | if (txq->txd == NULL) | ||
1692 | return; | ||
1693 | |||
1564 | mwl8k_txq_reclaim(hw, index, INT_MAX, 1); | 1694 | mwl8k_txq_reclaim(hw, index, INT_MAX, 1); |
1565 | 1695 | ||
1566 | kfree(txq->skb); | 1696 | kfree(txq->skb); |
@@ -1572,12 +1702,116 @@ static void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index) | |||
1572 | txq->txd = NULL; | 1702 | txq->txd = NULL; |
1573 | } | 1703 | } |
1574 | 1704 | ||
1705 | /* caller must hold priv->stream_lock when calling the stream functions */ | ||
1706 | static struct mwl8k_ampdu_stream * | ||
1707 | mwl8k_add_stream(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u8 tid) | ||
1708 | { | ||
1709 | struct mwl8k_ampdu_stream *stream; | ||
1710 | struct mwl8k_priv *priv = hw->priv; | ||
1711 | int i; | ||
1712 | |||
1713 | for (i = 0; i < priv->num_ampdu_queues; i++) { | ||
1714 | stream = &priv->ampdu[i]; | ||
1715 | if (stream->state == AMPDU_NO_STREAM) { | ||
1716 | stream->sta = sta; | ||
1717 | stream->state = AMPDU_STREAM_NEW; | ||
1718 | stream->tid = tid; | ||
1719 | stream->idx = i; | ||
1720 | stream->txq_idx = MWL8K_TX_WMM_QUEUES + i; | ||
1721 | wiphy_debug(hw->wiphy, "Added a new stream for %pM %d", | ||
1722 | sta->addr, tid); | ||
1723 | return stream; | ||
1724 | } | ||
1725 | } | ||
1726 | return NULL; | ||
1727 | } | ||
1728 | |||
1729 | static int | ||
1730 | mwl8k_start_stream(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream) | ||
1731 | { | ||
1732 | int ret; | ||
1733 | |||
1734 | /* if the stream has already been started, don't start it again */ | ||
1735 | if (stream->state != AMPDU_STREAM_NEW) | ||
1736 | return 0; | ||
1737 | ret = ieee80211_start_tx_ba_session(stream->sta, stream->tid, 0); | ||
1738 | if (ret) | ||
1739 | wiphy_debug(hw->wiphy, "Failed to start stream for %pM %d: " | ||
1740 | "%d\n", stream->sta->addr, stream->tid, ret); | ||
1741 | else | ||
1742 | wiphy_debug(hw->wiphy, "Started stream for %pM %d\n", | ||
1743 | stream->sta->addr, stream->tid); | ||
1744 | return ret; | ||
1745 | } | ||
1746 | |||
1747 | static void | ||
1748 | mwl8k_remove_stream(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream) | ||
1749 | { | ||
1750 | wiphy_debug(hw->wiphy, "Remove stream for %pM %d\n", stream->sta->addr, | ||
1751 | stream->tid); | ||
1752 | memset(stream, 0, sizeof(*stream)); | ||
1753 | } | ||
1754 | |||
1755 | static struct mwl8k_ampdu_stream * | ||
1756 | mwl8k_lookup_stream(struct ieee80211_hw *hw, u8 *addr, u8 tid) | ||
1757 | { | ||
1758 | struct mwl8k_priv *priv = hw->priv; | ||
1759 | int i; | ||
1760 | |||
1761 | for (i = 0 ; i < priv->num_ampdu_queues; i++) { | ||
1762 | struct mwl8k_ampdu_stream *stream; | ||
1763 | stream = &priv->ampdu[i]; | ||
1764 | if (stream->state == AMPDU_NO_STREAM) | ||
1765 | continue; | ||
1766 | if (!memcmp(stream->sta->addr, addr, ETH_ALEN) && | ||
1767 | stream->tid == tid) | ||
1768 | return stream; | ||
1769 | } | ||
1770 | return NULL; | ||
1771 | } | ||
1772 | |||
1773 | #define MWL8K_AMPDU_PACKET_THRESHOLD 64 | ||
1774 | static inline bool mwl8k_ampdu_allowed(struct ieee80211_sta *sta, u8 tid) | ||
1775 | { | ||
1776 | struct mwl8k_sta *sta_info = MWL8K_STA(sta); | ||
1777 | struct tx_traffic_info *tx_stats; | ||
1778 | |||
1779 | BUG_ON(tid >= MWL8K_MAX_TID); | ||
1780 | tx_stats = &sta_info->tx_stats[tid]; | ||
1781 | |||
1782 | return sta_info->is_ampdu_allowed && | ||
1783 | tx_stats->pkts > MWL8K_AMPDU_PACKET_THRESHOLD; | ||
1784 | } | ||
1785 | |||
1786 | static inline void mwl8k_tx_count_packet(struct ieee80211_sta *sta, u8 tid) | ||
1787 | { | ||
1788 | struct mwl8k_sta *sta_info = MWL8K_STA(sta); | ||
1789 | struct tx_traffic_info *tx_stats; | ||
1790 | |||
1791 | BUG_ON(tid >= MWL8K_MAX_TID); | ||
1792 | tx_stats = &sta_info->tx_stats[tid]; | ||
1793 | |||
1794 | if (tx_stats->start_time == 0) | ||
1795 | tx_stats->start_time = jiffies; | ||
1796 | |||
1797 | /* reset the packet count after each second elapses. If the number of | ||
1798 | * packets ever exceeds the ampdu_min_traffic threshold, we will allow | ||
1799 | * an ampdu stream to be started. | ||
1800 | */ | ||
1801 | if (jiffies - tx_stats->start_time > HZ) { | ||
1802 | tx_stats->pkts = 0; | ||
1803 | tx_stats->start_time = 0; | ||
1804 | } else | ||
1805 | tx_stats->pkts++; | ||
1806 | } | ||
1807 | |||
1575 | static void | 1808 | static void |
1576 | mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | 1809 | mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) |
1577 | { | 1810 | { |
1578 | struct mwl8k_priv *priv = hw->priv; | 1811 | struct mwl8k_priv *priv = hw->priv; |
1579 | struct ieee80211_tx_info *tx_info; | 1812 | struct ieee80211_tx_info *tx_info; |
1580 | struct mwl8k_vif *mwl8k_vif; | 1813 | struct mwl8k_vif *mwl8k_vif; |
1814 | struct ieee80211_sta *sta; | ||
1581 | struct ieee80211_hdr *wh; | 1815 | struct ieee80211_hdr *wh; |
1582 | struct mwl8k_tx_queue *txq; | 1816 | struct mwl8k_tx_queue *txq; |
1583 | struct mwl8k_tx_desc *tx; | 1817 | struct mwl8k_tx_desc *tx; |
@@ -1585,6 +1819,12 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1585 | u32 txstatus; | 1819 | u32 txstatus; |
1586 | u8 txdatarate; | 1820 | u8 txdatarate; |
1587 | u16 qos; | 1821 | u16 qos; |
1822 | int txpriority; | ||
1823 | u8 tid = 0; | ||
1824 | struct mwl8k_ampdu_stream *stream = NULL; | ||
1825 | bool start_ba_session = false; | ||
1826 | bool mgmtframe = false; | ||
1827 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; | ||
1588 | 1828 | ||
1589 | wh = (struct ieee80211_hdr *)skb->data; | 1829 | wh = (struct ieee80211_hdr *)skb->data; |
1590 | if (ieee80211_is_data_qos(wh->frame_control)) | 1830 | if (ieee80211_is_data_qos(wh->frame_control)) |
@@ -1592,14 +1832,18 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1592 | else | 1832 | else |
1593 | qos = 0; | 1833 | qos = 0; |
1594 | 1834 | ||
1835 | if (ieee80211_is_mgmt(wh->frame_control)) | ||
1836 | mgmtframe = true; | ||
1837 | |||
1595 | if (priv->ap_fw) | 1838 | if (priv->ap_fw) |
1596 | mwl8k_encapsulate_tx_frame(skb); | 1839 | mwl8k_encapsulate_tx_frame(priv, skb); |
1597 | else | 1840 | else |
1598 | mwl8k_add_dma_header(skb, 0); | 1841 | mwl8k_add_dma_header(priv, skb, 0, 0); |
1599 | 1842 | ||
1600 | wh = &((struct mwl8k_dma_data *)skb->data)->wh; | 1843 | wh = &((struct mwl8k_dma_data *)skb->data)->wh; |
1601 | 1844 | ||
1602 | tx_info = IEEE80211_SKB_CB(skb); | 1845 | tx_info = IEEE80211_SKB_CB(skb); |
1846 | sta = tx_info->control.sta; | ||
1603 | mwl8k_vif = MWL8K_VIF(tx_info->control.vif); | 1847 | mwl8k_vif = MWL8K_VIF(tx_info->control.vif); |
1604 | 1848 | ||
1605 | if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { | 1849 | if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { |
@@ -1627,12 +1871,91 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1627 | qos |= MWL8K_QOS_ACK_POLICY_NORMAL; | 1871 | qos |= MWL8K_QOS_ACK_POLICY_NORMAL; |
1628 | } | 1872 | } |
1629 | 1873 | ||
1874 | /* Queue ADDBA request in the respective data queue. While setting up | ||
1875 | * the ampdu stream, mac80211 queues further packets for that | ||
1876 | * particular ra/tid pair. However, packets piled up in the hardware | ||
1877 | * for that ra/tid pair will still go out. ADDBA request and the | ||
1878 | * related data packets going out from different queues asynchronously | ||
1879 | * will cause a shift in the receiver window which might result in | ||
1880 | * ampdu packets getting dropped at the receiver after the stream has | ||
1881 | * been setup. | ||
1882 | */ | ||
1883 | if (unlikely(ieee80211_is_action(wh->frame_control) && | ||
1884 | mgmt->u.action.category == WLAN_CATEGORY_BACK && | ||
1885 | mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ && | ||
1886 | priv->ap_fw)) { | ||
1887 | u16 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); | ||
1888 | tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; | ||
1889 | index = mwl8k_tid_queue_mapping(tid); | ||
1890 | } | ||
1891 | |||
1892 | txpriority = index; | ||
1893 | |||
1894 | if (ieee80211_is_data_qos(wh->frame_control) && | ||
1895 | skb->protocol != cpu_to_be16(ETH_P_PAE) && | ||
1896 | sta->ht_cap.ht_supported && priv->ap_fw) { | ||
1897 | tid = qos & 0xf; | ||
1898 | mwl8k_tx_count_packet(sta, tid); | ||
1899 | spin_lock(&priv->stream_lock); | ||
1900 | stream = mwl8k_lookup_stream(hw, sta->addr, tid); | ||
1901 | if (stream != NULL) { | ||
1902 | if (stream->state == AMPDU_STREAM_ACTIVE) { | ||
1903 | txpriority = stream->txq_idx; | ||
1904 | index = stream->txq_idx; | ||
1905 | } else if (stream->state == AMPDU_STREAM_NEW) { | ||
1906 | /* We get here if the driver sends us packets | ||
1907 | * after we've initiated a stream, but before | ||
1908 | * our ampdu_action routine has been called | ||
1909 | * with IEEE80211_AMPDU_TX_START to get the SSN | ||
1910 | * for the ADDBA request. So this packet can | ||
1911 | * go out with no risk of sequence number | ||
1912 | * mismatch. No special handling is required. | ||
1913 | */ | ||
1914 | } else { | ||
1915 | /* Drop packets that would go out after the | ||
1916 | * ADDBA request was sent but before the ADDBA | ||
1917 | * response is received. If we don't do this, | ||
1918 | * the recipient would probably receive it | ||
1919 | * after the ADDBA request with SSN 0. This | ||
1920 | * will cause the recipient's BA receive window | ||
1921 | * to shift, which would cause the subsequent | ||
1922 | * packets in the BA stream to be discarded. | ||
1923 | * mac80211 queues our packets for us in this | ||
1924 | * case, so this is really just a safety check. | ||
1925 | */ | ||
1926 | wiphy_warn(hw->wiphy, | ||
1927 | "Cannot send packet while ADDBA " | ||
1928 | "dialog is underway.\n"); | ||
1929 | spin_unlock(&priv->stream_lock); | ||
1930 | dev_kfree_skb(skb); | ||
1931 | return; | ||
1932 | } | ||
1933 | } else { | ||
1934 | /* Defer calling mwl8k_start_stream so that the current | ||
1935 | * skb can go out before the ADDBA request. This | ||
1936 | * prevents sequence number mismatch at the recepient | ||
1937 | * as described above. | ||
1938 | */ | ||
1939 | if (mwl8k_ampdu_allowed(sta, tid)) { | ||
1940 | stream = mwl8k_add_stream(hw, sta, tid); | ||
1941 | if (stream != NULL) | ||
1942 | start_ba_session = true; | ||
1943 | } | ||
1944 | } | ||
1945 | spin_unlock(&priv->stream_lock); | ||
1946 | } | ||
1947 | |||
1630 | dma = pci_map_single(priv->pdev, skb->data, | 1948 | dma = pci_map_single(priv->pdev, skb->data, |
1631 | skb->len, PCI_DMA_TODEVICE); | 1949 | skb->len, PCI_DMA_TODEVICE); |
1632 | 1950 | ||
1633 | if (pci_dma_mapping_error(priv->pdev, dma)) { | 1951 | if (pci_dma_mapping_error(priv->pdev, dma)) { |
1634 | wiphy_debug(hw->wiphy, | 1952 | wiphy_debug(hw->wiphy, |
1635 | "failed to dma map skb, dropping TX frame.\n"); | 1953 | "failed to dma map skb, dropping TX frame.\n"); |
1954 | if (start_ba_session) { | ||
1955 | spin_lock(&priv->stream_lock); | ||
1956 | mwl8k_remove_stream(hw, stream); | ||
1957 | spin_unlock(&priv->stream_lock); | ||
1958 | } | ||
1636 | dev_kfree_skb(skb); | 1959 | dev_kfree_skb(skb); |
1637 | return; | 1960 | return; |
1638 | } | 1961 | } |
@@ -1641,12 +1964,34 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1641 | 1964 | ||
1642 | txq = priv->txq + index; | 1965 | txq = priv->txq + index; |
1643 | 1966 | ||
1967 | /* Mgmt frames that go out frequently are probe | ||
1968 | * responses. Other mgmt frames got out relatively | ||
1969 | * infrequently. Hence reserve 2 buffers so that | ||
1970 | * other mgmt frames do not get dropped due to an | ||
1971 | * already queued probe response in one of the | ||
1972 | * reserved buffers. | ||
1973 | */ | ||
1974 | |||
1975 | if (txq->len >= MWL8K_TX_DESCS - 2) { | ||
1976 | if (mgmtframe == false || | ||
1977 | txq->len == MWL8K_TX_DESCS) { | ||
1978 | if (start_ba_session) { | ||
1979 | spin_lock(&priv->stream_lock); | ||
1980 | mwl8k_remove_stream(hw, stream); | ||
1981 | spin_unlock(&priv->stream_lock); | ||
1982 | } | ||
1983 | spin_unlock_bh(&priv->tx_lock); | ||
1984 | dev_kfree_skb(skb); | ||
1985 | return; | ||
1986 | } | ||
1987 | } | ||
1988 | |||
1644 | BUG_ON(txq->skb[txq->tail] != NULL); | 1989 | BUG_ON(txq->skb[txq->tail] != NULL); |
1645 | txq->skb[txq->tail] = skb; | 1990 | txq->skb[txq->tail] = skb; |
1646 | 1991 | ||
1647 | tx = txq->txd + txq->tail; | 1992 | tx = txq->txd + txq->tail; |
1648 | tx->data_rate = txdatarate; | 1993 | tx->data_rate = txdatarate; |
1649 | tx->tx_priority = index; | 1994 | tx->tx_priority = txpriority; |
1650 | tx->qos_control = cpu_to_le16(qos); | 1995 | tx->qos_control = cpu_to_le16(qos); |
1651 | tx->pkt_phys_addr = cpu_to_le32(dma); | 1996 | tx->pkt_phys_addr = cpu_to_le32(dma); |
1652 | tx->pkt_len = cpu_to_le16(skb->len); | 1997 | tx->pkt_len = cpu_to_le16(skb->len); |
@@ -1655,6 +2000,11 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1655 | tx->peer_id = MWL8K_STA(tx_info->control.sta)->peer_id; | 2000 | tx->peer_id = MWL8K_STA(tx_info->control.sta)->peer_id; |
1656 | else | 2001 | else |
1657 | tx->peer_id = 0; | 2002 | tx->peer_id = 0; |
2003 | |||
2004 | if (priv->ap_fw) | ||
2005 | tx->timestamp = cpu_to_le32(ioread32(priv->regs + | ||
2006 | MWL8K_HW_TIMER_REGISTER)); | ||
2007 | |||
1658 | wmb(); | 2008 | wmb(); |
1659 | tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); | 2009 | tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); |
1660 | 2010 | ||
@@ -1665,12 +2015,17 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1665 | if (txq->tail == MWL8K_TX_DESCS) | 2015 | if (txq->tail == MWL8K_TX_DESCS) |
1666 | txq->tail = 0; | 2016 | txq->tail = 0; |
1667 | 2017 | ||
1668 | if (txq->head == txq->tail) | ||
1669 | ieee80211_stop_queue(hw, index); | ||
1670 | |||
1671 | mwl8k_tx_start(priv); | 2018 | mwl8k_tx_start(priv); |
1672 | 2019 | ||
1673 | spin_unlock_bh(&priv->tx_lock); | 2020 | spin_unlock_bh(&priv->tx_lock); |
2021 | |||
2022 | /* Initiate the ampdu session here */ | ||
2023 | if (start_ba_session) { | ||
2024 | spin_lock(&priv->stream_lock); | ||
2025 | if (mwl8k_start_stream(hw, stream)) | ||
2026 | mwl8k_remove_stream(hw, stream); | ||
2027 | spin_unlock(&priv->stream_lock); | ||
2028 | } | ||
1674 | } | 2029 | } |
1675 | 2030 | ||
1676 | 2031 | ||
@@ -1868,7 +2223,7 @@ struct mwl8k_cmd_get_hw_spec_sta { | |||
1868 | __u8 mcs_bitmap[16]; | 2223 | __u8 mcs_bitmap[16]; |
1869 | __le32 rx_queue_ptr; | 2224 | __le32 rx_queue_ptr; |
1870 | __le32 num_tx_queues; | 2225 | __le32 num_tx_queues; |
1871 | __le32 tx_queue_ptrs[MWL8K_TX_QUEUES]; | 2226 | __le32 tx_queue_ptrs[MWL8K_TX_WMM_QUEUES]; |
1872 | __le32 caps2; | 2227 | __le32 caps2; |
1873 | __le32 num_tx_desc_per_queue; | 2228 | __le32 num_tx_desc_per_queue; |
1874 | __le32 total_rxd; | 2229 | __le32 total_rxd; |
@@ -1974,8 +2329,8 @@ static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw) | |||
1974 | memset(cmd->perm_addr, 0xff, sizeof(cmd->perm_addr)); | 2329 | memset(cmd->perm_addr, 0xff, sizeof(cmd->perm_addr)); |
1975 | cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); | 2330 | cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); |
1976 | cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma); | 2331 | cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma); |
1977 | cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES); | 2332 | cmd->num_tx_queues = cpu_to_le32(mwl8k_tx_queues(priv)); |
1978 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 2333 | for (i = 0; i < mwl8k_tx_queues(priv); i++) |
1979 | cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].txd_dma); | 2334 | cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].txd_dma); |
1980 | cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); | 2335 | cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); |
1981 | cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); | 2336 | cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); |
@@ -2017,13 +2372,16 @@ struct mwl8k_cmd_get_hw_spec_ap { | |||
2017 | __le32 wcbbase2; | 2372 | __le32 wcbbase2; |
2018 | __le32 wcbbase3; | 2373 | __le32 wcbbase3; |
2019 | __le32 fw_api_version; | 2374 | __le32 fw_api_version; |
2375 | __le32 caps; | ||
2376 | __le32 num_of_ampdu_queues; | ||
2377 | __le32 wcbbase_ampdu[MWL8K_MAX_AMPDU_QUEUES]; | ||
2020 | } __packed; | 2378 | } __packed; |
2021 | 2379 | ||
2022 | static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) | 2380 | static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) |
2023 | { | 2381 | { |
2024 | struct mwl8k_priv *priv = hw->priv; | 2382 | struct mwl8k_priv *priv = hw->priv; |
2025 | struct mwl8k_cmd_get_hw_spec_ap *cmd; | 2383 | struct mwl8k_cmd_get_hw_spec_ap *cmd; |
2026 | int rc; | 2384 | int rc, i; |
2027 | u32 api_version; | 2385 | u32 api_version; |
2028 | 2386 | ||
2029 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | 2387 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); |
@@ -2055,27 +2413,31 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) | |||
2055 | priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); | 2413 | priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); |
2056 | priv->fw_rev = le32_to_cpu(cmd->fw_rev); | 2414 | priv->fw_rev = le32_to_cpu(cmd->fw_rev); |
2057 | priv->hw_rev = cmd->hw_rev; | 2415 | priv->hw_rev = cmd->hw_rev; |
2058 | mwl8k_setup_2ghz_band(hw); | 2416 | mwl8k_set_caps(hw, le32_to_cpu(cmd->caps)); |
2059 | priv->ap_macids_supported = 0x000000ff; | 2417 | priv->ap_macids_supported = 0x000000ff; |
2060 | priv->sta_macids_supported = 0x00000000; | 2418 | priv->sta_macids_supported = 0x00000000; |
2061 | 2419 | priv->num_ampdu_queues = le32_to_cpu(cmd->num_of_ampdu_queues); | |
2062 | off = le32_to_cpu(cmd->wcbbase0) & 0xffff; | 2420 | if (priv->num_ampdu_queues > MWL8K_MAX_AMPDU_QUEUES) { |
2063 | iowrite32(priv->txq[0].txd_dma, priv->sram + off); | 2421 | wiphy_warn(hw->wiphy, "fw reported %d ampdu queues" |
2064 | 2422 | " but we only support %d.\n", | |
2423 | priv->num_ampdu_queues, | ||
2424 | MWL8K_MAX_AMPDU_QUEUES); | ||
2425 | priv->num_ampdu_queues = MWL8K_MAX_AMPDU_QUEUES; | ||
2426 | } | ||
2065 | off = le32_to_cpu(cmd->rxwrptr) & 0xffff; | 2427 | off = le32_to_cpu(cmd->rxwrptr) & 0xffff; |
2066 | iowrite32(priv->rxq[0].rxd_dma, priv->sram + off); | 2428 | iowrite32(priv->rxq[0].rxd_dma, priv->sram + off); |
2067 | 2429 | ||
2068 | off = le32_to_cpu(cmd->rxrdptr) & 0xffff; | 2430 | off = le32_to_cpu(cmd->rxrdptr) & 0xffff; |
2069 | iowrite32(priv->rxq[0].rxd_dma, priv->sram + off); | 2431 | iowrite32(priv->rxq[0].rxd_dma, priv->sram + off); |
2070 | 2432 | ||
2071 | off = le32_to_cpu(cmd->wcbbase1) & 0xffff; | 2433 | priv->txq_offset[0] = le32_to_cpu(cmd->wcbbase0) & 0xffff; |
2072 | iowrite32(priv->txq[1].txd_dma, priv->sram + off); | 2434 | priv->txq_offset[1] = le32_to_cpu(cmd->wcbbase1) & 0xffff; |
2435 | priv->txq_offset[2] = le32_to_cpu(cmd->wcbbase2) & 0xffff; | ||
2436 | priv->txq_offset[3] = le32_to_cpu(cmd->wcbbase3) & 0xffff; | ||
2073 | 2437 | ||
2074 | off = le32_to_cpu(cmd->wcbbase2) & 0xffff; | 2438 | for (i = 0; i < priv->num_ampdu_queues; i++) |
2075 | iowrite32(priv->txq[2].txd_dma, priv->sram + off); | 2439 | priv->txq_offset[i + MWL8K_TX_WMM_QUEUES] = |
2076 | 2440 | le32_to_cpu(cmd->wcbbase_ampdu[i]) & 0xffff; | |
2077 | off = le32_to_cpu(cmd->wcbbase3) & 0xffff; | ||
2078 | iowrite32(priv->txq[3].txd_dma, priv->sram + off); | ||
2079 | } | 2441 | } |
2080 | 2442 | ||
2081 | done: | 2443 | done: |
@@ -2098,12 +2460,20 @@ struct mwl8k_cmd_set_hw_spec { | |||
2098 | __le32 caps; | 2460 | __le32 caps; |
2099 | __le32 rx_queue_ptr; | 2461 | __le32 rx_queue_ptr; |
2100 | __le32 num_tx_queues; | 2462 | __le32 num_tx_queues; |
2101 | __le32 tx_queue_ptrs[MWL8K_TX_QUEUES]; | 2463 | __le32 tx_queue_ptrs[MWL8K_MAX_TX_QUEUES]; |
2102 | __le32 flags; | 2464 | __le32 flags; |
2103 | __le32 num_tx_desc_per_queue; | 2465 | __le32 num_tx_desc_per_queue; |
2104 | __le32 total_rxd; | 2466 | __le32 total_rxd; |
2105 | } __packed; | 2467 | } __packed; |
2106 | 2468 | ||
2469 | /* If enabled, MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY will cause | ||
2470 | * packets to expire 500 ms after the timestamp in the tx descriptor. That is, | ||
2471 | * the packets that are queued for more than 500ms, will be dropped in the | ||
2472 | * hardware. This helps minimizing the issues caused due to head-of-line | ||
2473 | * blocking where a slow client can hog the bandwidth and affect traffic to a | ||
2474 | * faster client. | ||
2475 | */ | ||
2476 | #define MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY 0x00000400 | ||
2107 | #define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080 | 2477 | #define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080 |
2108 | #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP 0x00000020 | 2478 | #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP 0x00000020 |
2109 | #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON 0x00000010 | 2479 | #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON 0x00000010 |
@@ -2124,7 +2494,7 @@ static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) | |||
2124 | 2494 | ||
2125 | cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); | 2495 | cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); |
2126 | cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma); | 2496 | cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma); |
2127 | cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES); | 2497 | cmd->num_tx_queues = cpu_to_le32(mwl8k_tx_queues(priv)); |
2128 | 2498 | ||
2129 | /* | 2499 | /* |
2130 | * Mac80211 stack has Q0 as highest priority and Q3 as lowest in | 2500 | * Mac80211 stack has Q0 as highest priority and Q3 as lowest in |
@@ -2132,14 +2502,15 @@ static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) | |||
2132 | * in that order. Map Q3 of mac80211 to Q0 of firmware so that the | 2502 | * in that order. Map Q3 of mac80211 to Q0 of firmware so that the |
2133 | * priority is interpreted the right way in firmware. | 2503 | * priority is interpreted the right way in firmware. |
2134 | */ | 2504 | */ |
2135 | for (i = 0; i < MWL8K_TX_QUEUES; i++) { | 2505 | for (i = 0; i < mwl8k_tx_queues(priv); i++) { |
2136 | int j = MWL8K_TX_QUEUES - 1 - i; | 2506 | int j = mwl8k_tx_queues(priv) - 1 - i; |
2137 | cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[j].txd_dma); | 2507 | cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[j].txd_dma); |
2138 | } | 2508 | } |
2139 | 2509 | ||
2140 | cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT | | 2510 | cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT | |
2141 | MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP | | 2511 | MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP | |
2142 | MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON); | 2512 | MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON | |
2513 | MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY); | ||
2143 | cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); | 2514 | cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); |
2144 | cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); | 2515 | cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); |
2145 | 2516 | ||
@@ -2356,7 +2727,7 @@ struct mwl8k_cmd_tx_power { | |||
2356 | __le16 bw; | 2727 | __le16 bw; |
2357 | __le16 sub_ch; | 2728 | __le16 sub_ch; |
2358 | __le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL]; | 2729 | __le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL]; |
2359 | } __attribute__((packed)); | 2730 | } __packed; |
2360 | 2731 | ||
2361 | static int mwl8k_cmd_tx_power(struct ieee80211_hw *hw, | 2732 | static int mwl8k_cmd_tx_power(struct ieee80211_hw *hw, |
2362 | struct ieee80211_conf *conf, | 2733 | struct ieee80211_conf *conf, |
@@ -3123,6 +3494,65 @@ static int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode) | |||
3123 | } | 3494 | } |
3124 | 3495 | ||
3125 | /* | 3496 | /* |
3497 | * CMD_GET_WATCHDOG_BITMAP. | ||
3498 | */ | ||
3499 | struct mwl8k_cmd_get_watchdog_bitmap { | ||
3500 | struct mwl8k_cmd_pkt header; | ||
3501 | u8 bitmap; | ||
3502 | } __packed; | ||
3503 | |||
3504 | static int mwl8k_cmd_get_watchdog_bitmap(struct ieee80211_hw *hw, u8 *bitmap) | ||
3505 | { | ||
3506 | struct mwl8k_cmd_get_watchdog_bitmap *cmd; | ||
3507 | int rc; | ||
3508 | |||
3509 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
3510 | if (cmd == NULL) | ||
3511 | return -ENOMEM; | ||
3512 | |||
3513 | cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_WATCHDOG_BITMAP); | ||
3514 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | ||
3515 | |||
3516 | rc = mwl8k_post_cmd(hw, &cmd->header); | ||
3517 | if (!rc) | ||
3518 | *bitmap = cmd->bitmap; | ||
3519 | |||
3520 | kfree(cmd); | ||
3521 | |||
3522 | return rc; | ||
3523 | } | ||
3524 | |||
3525 | #define INVALID_BA 0xAA | ||
3526 | static void mwl8k_watchdog_ba_events(struct work_struct *work) | ||
3527 | { | ||
3528 | int rc; | ||
3529 | u8 bitmap = 0, stream_index; | ||
3530 | struct mwl8k_ampdu_stream *streams; | ||
3531 | struct mwl8k_priv *priv = | ||
3532 | container_of(work, struct mwl8k_priv, watchdog_ba_handle); | ||
3533 | |||
3534 | rc = mwl8k_cmd_get_watchdog_bitmap(priv->hw, &bitmap); | ||
3535 | if (rc) | ||
3536 | return; | ||
3537 | |||
3538 | if (bitmap == INVALID_BA) | ||
3539 | return; | ||
3540 | |||
3541 | /* the bitmap is the hw queue number. Map it to the ampdu queue. */ | ||
3542 | stream_index = bitmap - MWL8K_TX_WMM_QUEUES; | ||
3543 | |||
3544 | BUG_ON(stream_index >= priv->num_ampdu_queues); | ||
3545 | |||
3546 | streams = &priv->ampdu[stream_index]; | ||
3547 | |||
3548 | if (streams->state == AMPDU_STREAM_ACTIVE) | ||
3549 | ieee80211_stop_tx_ba_session(streams->sta, streams->tid); | ||
3550 | |||
3551 | return; | ||
3552 | } | ||
3553 | |||
3554 | |||
3555 | /* | ||
3126 | * CMD_BSS_START. | 3556 | * CMD_BSS_START. |
3127 | */ | 3557 | */ |
3128 | struct mwl8k_cmd_bss_start { | 3558 | struct mwl8k_cmd_bss_start { |
@@ -3151,6 +3581,152 @@ static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw, | |||
3151 | } | 3581 | } |
3152 | 3582 | ||
3153 | /* | 3583 | /* |
3584 | * CMD_BASTREAM. | ||
3585 | */ | ||
3586 | |||
3587 | /* | ||
3588 | * UPSTREAM is tx direction | ||
3589 | */ | ||
3590 | #define BASTREAM_FLAG_DIRECTION_UPSTREAM 0x00 | ||
3591 | #define BASTREAM_FLAG_IMMEDIATE_TYPE 0x01 | ||
3592 | |||
3593 | enum ba_stream_action_type { | ||
3594 | MWL8K_BA_CREATE, | ||
3595 | MWL8K_BA_UPDATE, | ||
3596 | MWL8K_BA_DESTROY, | ||
3597 | MWL8K_BA_FLUSH, | ||
3598 | MWL8K_BA_CHECK, | ||
3599 | }; | ||
3600 | |||
3601 | |||
3602 | struct mwl8k_create_ba_stream { | ||
3603 | __le32 flags; | ||
3604 | __le32 idle_thrs; | ||
3605 | __le32 bar_thrs; | ||
3606 | __le32 window_size; | ||
3607 | u8 peer_mac_addr[6]; | ||
3608 | u8 dialog_token; | ||
3609 | u8 tid; | ||
3610 | u8 queue_id; | ||
3611 | u8 param_info; | ||
3612 | __le32 ba_context; | ||
3613 | u8 reset_seq_no_flag; | ||
3614 | __le16 curr_seq_no; | ||
3615 | u8 sta_src_mac_addr[6]; | ||
3616 | } __packed; | ||
3617 | |||
3618 | struct mwl8k_destroy_ba_stream { | ||
3619 | __le32 flags; | ||
3620 | __le32 ba_context; | ||
3621 | } __packed; | ||
3622 | |||
3623 | struct mwl8k_cmd_bastream { | ||
3624 | struct mwl8k_cmd_pkt header; | ||
3625 | __le32 action; | ||
3626 | union { | ||
3627 | struct mwl8k_create_ba_stream create_params; | ||
3628 | struct mwl8k_destroy_ba_stream destroy_params; | ||
3629 | }; | ||
3630 | } __packed; | ||
3631 | |||
3632 | static int | ||
3633 | mwl8k_check_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream) | ||
3634 | { | ||
3635 | struct mwl8k_cmd_bastream *cmd; | ||
3636 | int rc; | ||
3637 | |||
3638 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
3639 | if (cmd == NULL) | ||
3640 | return -ENOMEM; | ||
3641 | |||
3642 | cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM); | ||
3643 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | ||
3644 | |||
3645 | cmd->action = cpu_to_le32(MWL8K_BA_CHECK); | ||
3646 | |||
3647 | cmd->create_params.queue_id = stream->idx; | ||
3648 | memcpy(&cmd->create_params.peer_mac_addr[0], stream->sta->addr, | ||
3649 | ETH_ALEN); | ||
3650 | cmd->create_params.tid = stream->tid; | ||
3651 | |||
3652 | cmd->create_params.flags = | ||
3653 | cpu_to_le32(BASTREAM_FLAG_IMMEDIATE_TYPE) | | ||
3654 | cpu_to_le32(BASTREAM_FLAG_DIRECTION_UPSTREAM); | ||
3655 | |||
3656 | rc = mwl8k_post_cmd(hw, &cmd->header); | ||
3657 | |||
3658 | kfree(cmd); | ||
3659 | |||
3660 | return rc; | ||
3661 | } | ||
3662 | |||
3663 | static int | ||
3664 | mwl8k_create_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream, | ||
3665 | u8 buf_size) | ||
3666 | { | ||
3667 | struct mwl8k_cmd_bastream *cmd; | ||
3668 | int rc; | ||
3669 | |||
3670 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
3671 | if (cmd == NULL) | ||
3672 | return -ENOMEM; | ||
3673 | |||
3674 | |||
3675 | cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM); | ||
3676 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | ||
3677 | |||
3678 | cmd->action = cpu_to_le32(MWL8K_BA_CREATE); | ||
3679 | |||
3680 | cmd->create_params.bar_thrs = cpu_to_le32((u32)buf_size); | ||
3681 | cmd->create_params.window_size = cpu_to_le32((u32)buf_size); | ||
3682 | cmd->create_params.queue_id = stream->idx; | ||
3683 | |||
3684 | memcpy(cmd->create_params.peer_mac_addr, stream->sta->addr, ETH_ALEN); | ||
3685 | cmd->create_params.tid = stream->tid; | ||
3686 | cmd->create_params.curr_seq_no = cpu_to_le16(0); | ||
3687 | cmd->create_params.reset_seq_no_flag = 1; | ||
3688 | |||
3689 | cmd->create_params.param_info = | ||
3690 | (stream->sta->ht_cap.ampdu_factor & | ||
3691 | IEEE80211_HT_AMPDU_PARM_FACTOR) | | ||
3692 | ((stream->sta->ht_cap.ampdu_density << 2) & | ||
3693 | IEEE80211_HT_AMPDU_PARM_DENSITY); | ||
3694 | |||
3695 | cmd->create_params.flags = | ||
3696 | cpu_to_le32(BASTREAM_FLAG_IMMEDIATE_TYPE | | ||
3697 | BASTREAM_FLAG_DIRECTION_UPSTREAM); | ||
3698 | |||
3699 | rc = mwl8k_post_cmd(hw, &cmd->header); | ||
3700 | |||
3701 | wiphy_debug(hw->wiphy, "Created a BA stream for %pM : tid %d\n", | ||
3702 | stream->sta->addr, stream->tid); | ||
3703 | kfree(cmd); | ||
3704 | |||
3705 | return rc; | ||
3706 | } | ||
3707 | |||
3708 | static void mwl8k_destroy_ba(struct ieee80211_hw *hw, | ||
3709 | struct mwl8k_ampdu_stream *stream) | ||
3710 | { | ||
3711 | struct mwl8k_cmd_bastream *cmd; | ||
3712 | |||
3713 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
3714 | if (cmd == NULL) | ||
3715 | return; | ||
3716 | |||
3717 | cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM); | ||
3718 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | ||
3719 | cmd->action = cpu_to_le32(MWL8K_BA_DESTROY); | ||
3720 | |||
3721 | cmd->destroy_params.ba_context = cpu_to_le32(stream->idx); | ||
3722 | mwl8k_post_cmd(hw, &cmd->header); | ||
3723 | |||
3724 | wiphy_debug(hw->wiphy, "Deleted BA stream index %d\n", stream->idx); | ||
3725 | |||
3726 | kfree(cmd); | ||
3727 | } | ||
3728 | |||
3729 | /* | ||
3154 | * CMD_SET_NEW_STN. | 3730 | * CMD_SET_NEW_STN. |
3155 | */ | 3731 | */ |
3156 | struct mwl8k_cmd_set_new_stn { | 3732 | struct mwl8k_cmd_set_new_stn { |
@@ -3274,7 +3850,7 @@ struct mwl8k_cmd_update_encryption { | |||
3274 | __u8 mac_addr[6]; | 3850 | __u8 mac_addr[6]; |
3275 | __u8 encr_type; | 3851 | __u8 encr_type; |
3276 | 3852 | ||
3277 | } __attribute__((packed)); | 3853 | } __packed; |
3278 | 3854 | ||
3279 | struct mwl8k_cmd_set_key { | 3855 | struct mwl8k_cmd_set_key { |
3280 | struct mwl8k_cmd_pkt header; | 3856 | struct mwl8k_cmd_pkt header; |
@@ -3294,7 +3870,7 @@ struct mwl8k_cmd_set_key { | |||
3294 | __le16 tkip_tsc_low; | 3870 | __le16 tkip_tsc_low; |
3295 | __le32 tkip_tsc_high; | 3871 | __le32 tkip_tsc_high; |
3296 | __u8 mac_addr[6]; | 3872 | __u8 mac_addr[6]; |
3297 | } __attribute__((packed)); | 3873 | } __packed; |
3298 | 3874 | ||
3299 | enum { | 3875 | enum { |
3300 | MWL8K_ENCR_ENABLE, | 3876 | MWL8K_ENCR_ENABLE, |
@@ -3422,7 +3998,7 @@ static int mwl8k_cmd_encryption_set_key(struct ieee80211_hw *hw, | |||
3422 | mwl8k_vif->wep_key_conf[idx].enabled = 1; | 3998 | mwl8k_vif->wep_key_conf[idx].enabled = 1; |
3423 | } | 3999 | } |
3424 | 4000 | ||
3425 | keymlen = 0; | 4001 | keymlen = key->keylen; |
3426 | action = MWL8K_ENCR_SET_KEY; | 4002 | action = MWL8K_ENCR_SET_KEY; |
3427 | break; | 4003 | break; |
3428 | case WLAN_CIPHER_SUITE_TKIP: | 4004 | case WLAN_CIPHER_SUITE_TKIP: |
@@ -3496,7 +4072,6 @@ static int mwl8k_set_key(struct ieee80211_hw *hw, | |||
3496 | addr = sta->addr; | 4072 | addr = sta->addr; |
3497 | 4073 | ||
3498 | if (cmd_param == SET_KEY) { | 4074 | if (cmd_param == SET_KEY) { |
3499 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | ||
3500 | rc = mwl8k_cmd_encryption_set_key(hw, vif, addr, key); | 4075 | rc = mwl8k_cmd_encryption_set_key(hw, vif, addr, key); |
3501 | if (rc) | 4076 | if (rc) |
3502 | goto out; | 4077 | goto out; |
@@ -3671,6 +4246,11 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id) | |||
3671 | tasklet_schedule(&priv->poll_rx_task); | 4246 | tasklet_schedule(&priv->poll_rx_task); |
3672 | } | 4247 | } |
3673 | 4248 | ||
4249 | if (status & MWL8K_A2H_INT_BA_WATCHDOG) { | ||
4250 | status &= ~MWL8K_A2H_INT_BA_WATCHDOG; | ||
4251 | ieee80211_queue_work(hw, &priv->watchdog_ba_handle); | ||
4252 | } | ||
4253 | |||
3674 | if (status) | 4254 | if (status) |
3675 | iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); | 4255 | iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); |
3676 | 4256 | ||
@@ -3699,7 +4279,7 @@ static void mwl8k_tx_poll(unsigned long data) | |||
3699 | 4279 | ||
3700 | spin_lock_bh(&priv->tx_lock); | 4280 | spin_lock_bh(&priv->tx_lock); |
3701 | 4281 | ||
3702 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 4282 | for (i = 0; i < mwl8k_tx_queues(priv); i++) |
3703 | limit -= mwl8k_txq_reclaim(hw, i, limit, 0); | 4283 | limit -= mwl8k_txq_reclaim(hw, i, limit, 0); |
3704 | 4284 | ||
3705 | if (!priv->pending_tx_pkts && priv->tx_wait != NULL) { | 4285 | if (!priv->pending_tx_pkts && priv->tx_wait != NULL) { |
@@ -3774,6 +4354,8 @@ static int mwl8k_start(struct ieee80211_hw *hw) | |||
3774 | 4354 | ||
3775 | /* Enable interrupts */ | 4355 | /* Enable interrupts */ |
3776 | iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); | 4356 | iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); |
4357 | iowrite32(MWL8K_A2H_EVENTS, | ||
4358 | priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); | ||
3777 | 4359 | ||
3778 | rc = mwl8k_fw_lock(hw); | 4360 | rc = mwl8k_fw_lock(hw); |
3779 | if (!rc) { | 4361 | if (!rc) { |
@@ -3829,6 +4411,7 @@ static void mwl8k_stop(struct ieee80211_hw *hw) | |||
3829 | 4411 | ||
3830 | /* Stop finalize join worker */ | 4412 | /* Stop finalize join worker */ |
3831 | cancel_work_sync(&priv->finalize_join_worker); | 4413 | cancel_work_sync(&priv->finalize_join_worker); |
4414 | cancel_work_sync(&priv->watchdog_ba_handle); | ||
3832 | if (priv->beacon_skb != NULL) | 4415 | if (priv->beacon_skb != NULL) |
3833 | dev_kfree_skb(priv->beacon_skb); | 4416 | dev_kfree_skb(priv->beacon_skb); |
3834 | 4417 | ||
@@ -3837,7 +4420,7 @@ static void mwl8k_stop(struct ieee80211_hw *hw) | |||
3837 | tasklet_disable(&priv->poll_rx_task); | 4420 | tasklet_disable(&priv->poll_rx_task); |
3838 | 4421 | ||
3839 | /* Return all skbs to mac80211 */ | 4422 | /* Return all skbs to mac80211 */ |
3840 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 4423 | for (i = 0; i < mwl8k_tx_queues(priv); i++) |
3841 | mwl8k_txq_reclaim(hw, i, INT_MAX, 1); | 4424 | mwl8k_txq_reclaim(hw, i, INT_MAX, 1); |
3842 | } | 4425 | } |
3843 | 4426 | ||
@@ -3958,9 +4541,12 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) | |||
3958 | conf->power_level = 18; | 4541 | conf->power_level = 18; |
3959 | 4542 | ||
3960 | if (priv->ap_fw) { | 4543 | if (priv->ap_fw) { |
3961 | rc = mwl8k_cmd_tx_power(hw, conf, conf->power_level); | 4544 | |
3962 | if (rc) | 4545 | if (conf->flags & IEEE80211_CONF_CHANGE_POWER) { |
3963 | goto out; | 4546 | rc = mwl8k_cmd_tx_power(hw, conf, conf->power_level); |
4547 | if (rc) | ||
4548 | goto out; | ||
4549 | } | ||
3964 | 4550 | ||
3965 | rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_RX, 0x3); | 4551 | rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_RX, 0x3); |
3966 | if (rc) | 4552 | if (rc) |
@@ -3987,7 +4573,7 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
3987 | struct ieee80211_bss_conf *info, u32 changed) | 4573 | struct ieee80211_bss_conf *info, u32 changed) |
3988 | { | 4574 | { |
3989 | struct mwl8k_priv *priv = hw->priv; | 4575 | struct mwl8k_priv *priv = hw->priv; |
3990 | u32 ap_legacy_rates; | 4576 | u32 ap_legacy_rates = 0; |
3991 | u8 ap_mcs_rates[16]; | 4577 | u8 ap_mcs_rates[16]; |
3992 | int rc; | 4578 | int rc; |
3993 | 4579 | ||
@@ -4312,6 +4898,8 @@ static int mwl8k_sta_add(struct ieee80211_hw *hw, | |||
4312 | ret = mwl8k_cmd_update_stadb_add(hw, vif, sta); | 4898 | ret = mwl8k_cmd_update_stadb_add(hw, vif, sta); |
4313 | if (ret >= 0) { | 4899 | if (ret >= 0) { |
4314 | MWL8K_STA(sta)->peer_id = ret; | 4900 | MWL8K_STA(sta)->peer_id = ret; |
4901 | if (sta->ht_cap.ht_supported) | ||
4902 | MWL8K_STA(sta)->is_ampdu_allowed = true; | ||
4315 | ret = 0; | 4903 | ret = 0; |
4316 | } | 4904 | } |
4317 | 4905 | ||
@@ -4335,14 +4923,14 @@ static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, | |||
4335 | 4923 | ||
4336 | rc = mwl8k_fw_lock(hw); | 4924 | rc = mwl8k_fw_lock(hw); |
4337 | if (!rc) { | 4925 | if (!rc) { |
4338 | BUG_ON(queue > MWL8K_TX_QUEUES - 1); | 4926 | BUG_ON(queue > MWL8K_TX_WMM_QUEUES - 1); |
4339 | memcpy(&priv->wmm_params[queue], params, sizeof(*params)); | 4927 | memcpy(&priv->wmm_params[queue], params, sizeof(*params)); |
4340 | 4928 | ||
4341 | if (!priv->wmm_enabled) | 4929 | if (!priv->wmm_enabled) |
4342 | rc = mwl8k_cmd_set_wmm_mode(hw, 1); | 4930 | rc = mwl8k_cmd_set_wmm_mode(hw, 1); |
4343 | 4931 | ||
4344 | if (!rc) { | 4932 | if (!rc) { |
4345 | int q = MWL8K_TX_QUEUES - 1 - queue; | 4933 | int q = MWL8K_TX_WMM_QUEUES - 1 - queue; |
4346 | rc = mwl8k_cmd_set_edca_params(hw, q, | 4934 | rc = mwl8k_cmd_set_edca_params(hw, q, |
4347 | params->cw_min, | 4935 | params->cw_min, |
4348 | params->cw_max, | 4936 | params->cw_max, |
@@ -4378,21 +4966,118 @@ static int mwl8k_get_survey(struct ieee80211_hw *hw, int idx, | |||
4378 | return 0; | 4966 | return 0; |
4379 | } | 4967 | } |
4380 | 4968 | ||
4969 | #define MAX_AMPDU_ATTEMPTS 5 | ||
4970 | |||
4381 | static int | 4971 | static int |
4382 | mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 4972 | mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
4383 | enum ieee80211_ampdu_mlme_action action, | 4973 | enum ieee80211_ampdu_mlme_action action, |
4384 | struct ieee80211_sta *sta, u16 tid, u16 *ssn, | 4974 | struct ieee80211_sta *sta, u16 tid, u16 *ssn, |
4385 | u8 buf_size) | 4975 | u8 buf_size) |
4386 | { | 4976 | { |
4977 | |||
4978 | int i, rc = 0; | ||
4979 | struct mwl8k_priv *priv = hw->priv; | ||
4980 | struct mwl8k_ampdu_stream *stream; | ||
4981 | u8 *addr = sta->addr; | ||
4982 | |||
4983 | if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) | ||
4984 | return -ENOTSUPP; | ||
4985 | |||
4986 | spin_lock(&priv->stream_lock); | ||
4987 | stream = mwl8k_lookup_stream(hw, addr, tid); | ||
4988 | |||
4387 | switch (action) { | 4989 | switch (action) { |
4388 | case IEEE80211_AMPDU_RX_START: | 4990 | case IEEE80211_AMPDU_RX_START: |
4389 | case IEEE80211_AMPDU_RX_STOP: | 4991 | case IEEE80211_AMPDU_RX_STOP: |
4390 | if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) | 4992 | break; |
4391 | return -ENOTSUPP; | 4993 | case IEEE80211_AMPDU_TX_START: |
4392 | return 0; | 4994 | /* By the time we get here the hw queues may contain outgoing |
4995 | * packets for this RA/TID that are not part of this BA | ||
4996 | * session. The hw will assign sequence numbers to these | ||
4997 | * packets as they go out. So if we query the hw for its next | ||
4998 | * sequence number and use that for the SSN here, it may end up | ||
4999 | * being wrong, which will lead to sequence number mismatch at | ||
5000 | * the recipient. To avoid this, we reset the sequence number | ||
5001 | * to O for the first MPDU in this BA stream. | ||
5002 | */ | ||
5003 | *ssn = 0; | ||
5004 | if (stream == NULL) { | ||
5005 | /* This means that somebody outside this driver called | ||
5006 | * ieee80211_start_tx_ba_session. This is unexpected | ||
5007 | * because we do our own rate control. Just warn and | ||
5008 | * move on. | ||
5009 | */ | ||
5010 | wiphy_warn(hw->wiphy, "Unexpected call to %s. " | ||
5011 | "Proceeding anyway.\n", __func__); | ||
5012 | stream = mwl8k_add_stream(hw, sta, tid); | ||
5013 | } | ||
5014 | if (stream == NULL) { | ||
5015 | wiphy_debug(hw->wiphy, "no free AMPDU streams\n"); | ||
5016 | rc = -EBUSY; | ||
5017 | break; | ||
5018 | } | ||
5019 | stream->state = AMPDU_STREAM_IN_PROGRESS; | ||
5020 | |||
5021 | /* Release the lock before we do the time consuming stuff */ | ||
5022 | spin_unlock(&priv->stream_lock); | ||
5023 | for (i = 0; i < MAX_AMPDU_ATTEMPTS; i++) { | ||
5024 | rc = mwl8k_check_ba(hw, stream); | ||
5025 | |||
5026 | if (!rc) | ||
5027 | break; | ||
5028 | /* | ||
5029 | * HW queues take time to be flushed, give them | ||
5030 | * sufficient time | ||
5031 | */ | ||
5032 | |||
5033 | msleep(1000); | ||
5034 | } | ||
5035 | spin_lock(&priv->stream_lock); | ||
5036 | if (rc) { | ||
5037 | wiphy_err(hw->wiphy, "Stream for tid %d busy after %d" | ||
5038 | " attempts\n", tid, MAX_AMPDU_ATTEMPTS); | ||
5039 | mwl8k_remove_stream(hw, stream); | ||
5040 | rc = -EBUSY; | ||
5041 | break; | ||
5042 | } | ||
5043 | ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid); | ||
5044 | break; | ||
5045 | case IEEE80211_AMPDU_TX_STOP: | ||
5046 | if (stream == NULL) | ||
5047 | break; | ||
5048 | if (stream->state == AMPDU_STREAM_ACTIVE) { | ||
5049 | spin_unlock(&priv->stream_lock); | ||
5050 | mwl8k_destroy_ba(hw, stream); | ||
5051 | spin_lock(&priv->stream_lock); | ||
5052 | } | ||
5053 | mwl8k_remove_stream(hw, stream); | ||
5054 | ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid); | ||
5055 | break; | ||
5056 | case IEEE80211_AMPDU_TX_OPERATIONAL: | ||
5057 | BUG_ON(stream == NULL); | ||
5058 | BUG_ON(stream->state != AMPDU_STREAM_IN_PROGRESS); | ||
5059 | spin_unlock(&priv->stream_lock); | ||
5060 | rc = mwl8k_create_ba(hw, stream, buf_size); | ||
5061 | spin_lock(&priv->stream_lock); | ||
5062 | if (!rc) | ||
5063 | stream->state = AMPDU_STREAM_ACTIVE; | ||
5064 | else { | ||
5065 | spin_unlock(&priv->stream_lock); | ||
5066 | mwl8k_destroy_ba(hw, stream); | ||
5067 | spin_lock(&priv->stream_lock); | ||
5068 | wiphy_debug(hw->wiphy, | ||
5069 | "Failed adding stream for sta %pM tid %d\n", | ||
5070 | addr, tid); | ||
5071 | mwl8k_remove_stream(hw, stream); | ||
5072 | } | ||
5073 | break; | ||
5074 | |||
4393 | default: | 5075 | default: |
4394 | return -ENOTSUPP; | 5076 | rc = -ENOTSUPP; |
4395 | } | 5077 | } |
5078 | |||
5079 | spin_unlock(&priv->stream_lock); | ||
5080 | return rc; | ||
4396 | } | 5081 | } |
4397 | 5082 | ||
4398 | static const struct ieee80211_ops mwl8k_ops = { | 5083 | static const struct ieee80211_ops mwl8k_ops = { |
@@ -4441,7 +5126,7 @@ enum { | |||
4441 | MWL8366, | 5126 | MWL8366, |
4442 | }; | 5127 | }; |
4443 | 5128 | ||
4444 | #define MWL8K_8366_AP_FW_API 1 | 5129 | #define MWL8K_8366_AP_FW_API 2 |
4445 | #define _MWL8K_8366_AP_FW(api) "mwl8k/fmimage_8366_ap-" #api ".fw" | 5130 | #define _MWL8K_8366_AP_FW(api) "mwl8k/fmimage_8366_ap-" #api ".fw" |
4446 | #define MWL8K_8366_AP_FW(api) _MWL8K_8366_AP_FW(api) | 5131 | #define MWL8K_8366_AP_FW(api) _MWL8K_8366_AP_FW(api) |
4447 | 5132 | ||
@@ -4607,6 +5292,23 @@ static int mwl8k_init_firmware(struct ieee80211_hw *hw, char *fw_image, | |||
4607 | return rc; | 5292 | return rc; |
4608 | } | 5293 | } |
4609 | 5294 | ||
5295 | static int mwl8k_init_txqs(struct ieee80211_hw *hw) | ||
5296 | { | ||
5297 | struct mwl8k_priv *priv = hw->priv; | ||
5298 | int rc = 0; | ||
5299 | int i; | ||
5300 | |||
5301 | for (i = 0; i < mwl8k_tx_queues(priv); i++) { | ||
5302 | rc = mwl8k_txq_init(hw, i); | ||
5303 | if (rc) | ||
5304 | break; | ||
5305 | if (priv->ap_fw) | ||
5306 | iowrite32(priv->txq[i].txd_dma, | ||
5307 | priv->sram + priv->txq_offset[i]); | ||
5308 | } | ||
5309 | return rc; | ||
5310 | } | ||
5311 | |||
4610 | /* initialize hw after successfully loading a firmware image */ | 5312 | /* initialize hw after successfully loading a firmware image */ |
4611 | static int mwl8k_probe_hw(struct ieee80211_hw *hw) | 5313 | static int mwl8k_probe_hw(struct ieee80211_hw *hw) |
4612 | { | 5314 | { |
@@ -4634,17 +5336,26 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw) | |||
4634 | goto err_stop_firmware; | 5336 | goto err_stop_firmware; |
4635 | rxq_refill(hw, 0, INT_MAX); | 5337 | rxq_refill(hw, 0, INT_MAX); |
4636 | 5338 | ||
4637 | for (i = 0; i < MWL8K_TX_QUEUES; i++) { | 5339 | /* For the sta firmware, we need to know the dma addresses of tx queues |
4638 | rc = mwl8k_txq_init(hw, i); | 5340 | * before sending MWL8K_CMD_GET_HW_SPEC. So we must initialize them |
5341 | * prior to issuing this command. But for the AP case, we learn the | ||
5342 | * total number of queues from the result CMD_GET_HW_SPEC, so for this | ||
5343 | * case we must initialize the tx queues after. | ||
5344 | */ | ||
5345 | priv->num_ampdu_queues = 0; | ||
5346 | if (!priv->ap_fw) { | ||
5347 | rc = mwl8k_init_txqs(hw); | ||
4639 | if (rc) | 5348 | if (rc) |
4640 | goto err_free_queues; | 5349 | goto err_free_queues; |
4641 | } | 5350 | } |
4642 | 5351 | ||
4643 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); | 5352 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); |
4644 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); | 5353 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); |
4645 | iowrite32(MWL8K_A2H_INT_TX_DONE | MWL8K_A2H_INT_RX_READY, | 5354 | iowrite32(MWL8K_A2H_INT_TX_DONE|MWL8K_A2H_INT_RX_READY| |
5355 | MWL8K_A2H_INT_BA_WATCHDOG, | ||
4646 | priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); | 5356 | priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); |
4647 | iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); | 5357 | iowrite32(MWL8K_A2H_INT_OPC_DONE, |
5358 | priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); | ||
4648 | 5359 | ||
4649 | rc = request_irq(priv->pdev->irq, mwl8k_interrupt, | 5360 | rc = request_irq(priv->pdev->irq, mwl8k_interrupt, |
4650 | IRQF_SHARED, MWL8K_NAME, hw); | 5361 | IRQF_SHARED, MWL8K_NAME, hw); |
@@ -4653,6 +5364,8 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw) | |||
4653 | goto err_free_queues; | 5364 | goto err_free_queues; |
4654 | } | 5365 | } |
4655 | 5366 | ||
5367 | memset(priv->ampdu, 0, sizeof(priv->ampdu)); | ||
5368 | |||
4656 | /* | 5369 | /* |
4657 | * Temporarily enable interrupts. Initial firmware host | 5370 | * Temporarily enable interrupts. Initial firmware host |
4658 | * commands use interrupts and avoid polling. Disable | 5371 | * commands use interrupts and avoid polling. Disable |
@@ -4664,6 +5377,8 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw) | |||
4664 | if (priv->ap_fw) { | 5377 | if (priv->ap_fw) { |
4665 | rc = mwl8k_cmd_get_hw_spec_ap(hw); | 5378 | rc = mwl8k_cmd_get_hw_spec_ap(hw); |
4666 | if (!rc) | 5379 | if (!rc) |
5380 | rc = mwl8k_init_txqs(hw); | ||
5381 | if (!rc) | ||
4667 | rc = mwl8k_cmd_set_hw_spec(hw); | 5382 | rc = mwl8k_cmd_set_hw_spec(hw); |
4668 | } else { | 5383 | } else { |
4669 | rc = mwl8k_cmd_get_hw_spec_sta(hw); | 5384 | rc = mwl8k_cmd_get_hw_spec_sta(hw); |
@@ -4705,7 +5420,7 @@ err_free_irq: | |||
4705 | free_irq(priv->pdev->irq, hw); | 5420 | free_irq(priv->pdev->irq, hw); |
4706 | 5421 | ||
4707 | err_free_queues: | 5422 | err_free_queues: |
4708 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 5423 | for (i = 0; i < mwl8k_tx_queues(priv); i++) |
4709 | mwl8k_txq_deinit(hw, i); | 5424 | mwl8k_txq_deinit(hw, i); |
4710 | mwl8k_rxq_deinit(hw, 0); | 5425 | mwl8k_rxq_deinit(hw, 0); |
4711 | 5426 | ||
@@ -4727,7 +5442,7 @@ static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image) | |||
4727 | mwl8k_stop(hw); | 5442 | mwl8k_stop(hw); |
4728 | mwl8k_rxq_deinit(hw, 0); | 5443 | mwl8k_rxq_deinit(hw, 0); |
4729 | 5444 | ||
4730 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 5445 | for (i = 0; i < mwl8k_tx_queues(priv); i++) |
4731 | mwl8k_txq_deinit(hw, i); | 5446 | mwl8k_txq_deinit(hw, i); |
4732 | 5447 | ||
4733 | rc = mwl8k_init_firmware(hw, fw_image, false); | 5448 | rc = mwl8k_init_firmware(hw, fw_image, false); |
@@ -4746,7 +5461,7 @@ static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image) | |||
4746 | if (rc) | 5461 | if (rc) |
4747 | goto fail; | 5462 | goto fail; |
4748 | 5463 | ||
4749 | for (i = 0; i < MWL8K_TX_QUEUES; i++) { | 5464 | for (i = 0; i < MWL8K_TX_WMM_QUEUES; i++) { |
4750 | rc = mwl8k_conf_tx(hw, i, &priv->wmm_params[i]); | 5465 | rc = mwl8k_conf_tx(hw, i, &priv->wmm_params[i]); |
4751 | if (rc) | 5466 | if (rc) |
4752 | goto fail; | 5467 | goto fail; |
@@ -4778,9 +5493,11 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) | |||
4778 | hw->extra_tx_headroom = | 5493 | hw->extra_tx_headroom = |
4779 | sizeof(struct mwl8k_dma_data) - sizeof(struct ieee80211_cts); | 5494 | sizeof(struct mwl8k_dma_data) - sizeof(struct ieee80211_cts); |
4780 | 5495 | ||
5496 | hw->extra_tx_headroom -= priv->ap_fw ? REDUCED_TX_HEADROOM : 0; | ||
5497 | |||
4781 | hw->channel_change_time = 10; | 5498 | hw->channel_change_time = 10; |
4782 | 5499 | ||
4783 | hw->queues = MWL8K_TX_QUEUES; | 5500 | hw->queues = MWL8K_TX_WMM_QUEUES; |
4784 | 5501 | ||
4785 | /* Set rssi values to dBm */ | 5502 | /* Set rssi values to dBm */ |
4786 | hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_HAS_RATE_CONTROL; | 5503 | hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_HAS_RATE_CONTROL; |
@@ -4796,6 +5513,8 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) | |||
4796 | 5513 | ||
4797 | /* Finalize join worker */ | 5514 | /* Finalize join worker */ |
4798 | INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); | 5515 | INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); |
5516 | /* Handle watchdog ba events */ | ||
5517 | INIT_WORK(&priv->watchdog_ba_handle, mwl8k_watchdog_ba_events); | ||
4799 | 5518 | ||
4800 | /* TX reclaim and RX tasklets. */ | 5519 | /* TX reclaim and RX tasklets. */ |
4801 | tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw); | 5520 | tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw); |
@@ -4815,6 +5534,8 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) | |||
4815 | 5534 | ||
4816 | spin_lock_init(&priv->tx_lock); | 5535 | spin_lock_init(&priv->tx_lock); |
4817 | 5536 | ||
5537 | spin_lock_init(&priv->stream_lock); | ||
5538 | |||
4818 | priv->tx_wait = NULL; | 5539 | priv->tx_wait = NULL; |
4819 | 5540 | ||
4820 | rc = mwl8k_probe_hw(hw); | 5541 | rc = mwl8k_probe_hw(hw); |
@@ -4836,7 +5557,7 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) | |||
4836 | return 0; | 5557 | return 0; |
4837 | 5558 | ||
4838 | err_unprobe_hw: | 5559 | err_unprobe_hw: |
4839 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 5560 | for (i = 0; i < mwl8k_tx_queues(priv); i++) |
4840 | mwl8k_txq_deinit(hw, i); | 5561 | mwl8k_txq_deinit(hw, i); |
4841 | mwl8k_rxq_deinit(hw, 0); | 5562 | mwl8k_rxq_deinit(hw, 0); |
4842 | 5563 | ||
@@ -4995,10 +5716,10 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev) | |||
4995 | mwl8k_hw_reset(priv); | 5716 | mwl8k_hw_reset(priv); |
4996 | 5717 | ||
4997 | /* Return all skbs to mac80211 */ | 5718 | /* Return all skbs to mac80211 */ |
4998 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 5719 | for (i = 0; i < mwl8k_tx_queues(priv); i++) |
4999 | mwl8k_txq_reclaim(hw, i, INT_MAX, 1); | 5720 | mwl8k_txq_reclaim(hw, i, INT_MAX, 1); |
5000 | 5721 | ||
5001 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 5722 | for (i = 0; i < mwl8k_tx_queues(priv); i++) |
5002 | mwl8k_txq_deinit(hw, i); | 5723 | mwl8k_txq_deinit(hw, i); |
5003 | 5724 | ||
5004 | mwl8k_rxq_deinit(hw, 0); | 5725 | mwl8k_rxq_deinit(hw, 0); |