diff options
Diffstat (limited to 'drivers/net/wireless/mwl8k.c')
-rw-r--r-- | drivers/net/wireless/mwl8k.c | 2008 |
1 files changed, 1776 insertions, 232 deletions
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index f152a25be59f..aeac3cc4dbe4 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c | |||
@@ -29,6 +29,12 @@ | |||
29 | #define MWL8K_NAME KBUILD_MODNAME | 29 | #define MWL8K_NAME KBUILD_MODNAME |
30 | #define MWL8K_VERSION "0.12" | 30 | #define MWL8K_VERSION "0.12" |
31 | 31 | ||
32 | /* Module parameters */ | ||
33 | static unsigned ap_mode_default; | ||
34 | module_param(ap_mode_default, bool, 0); | ||
35 | MODULE_PARM_DESC(ap_mode_default, | ||
36 | "Set to 1 to make ap mode the default instead of sta mode"); | ||
37 | |||
32 | /* Register definitions */ | 38 | /* Register definitions */ |
33 | #define MWL8K_HIU_GEN_PTR 0x00000c10 | 39 | #define MWL8K_HIU_GEN_PTR 0x00000c10 |
34 | #define MWL8K_MODE_STA 0x0000005a | 40 | #define MWL8K_MODE_STA 0x0000005a |
@@ -57,6 +63,7 @@ | |||
57 | #define MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL 0x00000c38 | 63 | #define MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL 0x00000c38 |
58 | #define MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK 0x00000c3c | 64 | #define MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK 0x00000c3c |
59 | #define MWL8K_A2H_INT_DUMMY (1 << 20) | 65 | #define MWL8K_A2H_INT_DUMMY (1 << 20) |
66 | #define MWL8K_A2H_INT_BA_WATCHDOG (1 << 14) | ||
60 | #define MWL8K_A2H_INT_CHNL_SWITCHED (1 << 11) | 67 | #define MWL8K_A2H_INT_CHNL_SWITCHED (1 << 11) |
61 | #define MWL8K_A2H_INT_QUEUE_EMPTY (1 << 10) | 68 | #define MWL8K_A2H_INT_QUEUE_EMPTY (1 << 10) |
62 | #define MWL8K_A2H_INT_RADAR_DETECT (1 << 7) | 69 | #define MWL8K_A2H_INT_RADAR_DETECT (1 << 7) |
@@ -67,6 +74,14 @@ | |||
67 | #define MWL8K_A2H_INT_RX_READY (1 << 1) | 74 | #define MWL8K_A2H_INT_RX_READY (1 << 1) |
68 | #define MWL8K_A2H_INT_TX_DONE (1 << 0) | 75 | #define MWL8K_A2H_INT_TX_DONE (1 << 0) |
69 | 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 | |||
70 | #define MWL8K_A2H_EVENTS (MWL8K_A2H_INT_DUMMY | \ | 85 | #define MWL8K_A2H_EVENTS (MWL8K_A2H_INT_DUMMY | \ |
71 | MWL8K_A2H_INT_CHNL_SWITCHED | \ | 86 | MWL8K_A2H_INT_CHNL_SWITCHED | \ |
72 | MWL8K_A2H_INT_QUEUE_EMPTY | \ | 87 | MWL8K_A2H_INT_QUEUE_EMPTY | \ |
@@ -76,10 +91,14 @@ | |||
76 | MWL8K_A2H_INT_MAC_EVENT | \ | 91 | MWL8K_A2H_INT_MAC_EVENT | \ |
77 | MWL8K_A2H_INT_OPC_DONE | \ | 92 | MWL8K_A2H_INT_OPC_DONE | \ |
78 | MWL8K_A2H_INT_RX_READY | \ | 93 | MWL8K_A2H_INT_RX_READY | \ |
79 | MWL8K_A2H_INT_TX_DONE) | 94 | MWL8K_A2H_INT_TX_DONE | \ |
95 | MWL8K_A2H_INT_BA_WATCHDOG) | ||
80 | 96 | ||
81 | #define MWL8K_RX_QUEUES 1 | 97 | #define MWL8K_RX_QUEUES 1 |
82 | #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) | ||
83 | 102 | ||
84 | struct rxd_ops { | 103 | struct rxd_ops { |
85 | int rxd_size; | 104 | int rxd_size; |
@@ -92,8 +111,10 @@ struct rxd_ops { | |||
92 | struct mwl8k_device_info { | 111 | struct mwl8k_device_info { |
93 | char *part_name; | 112 | char *part_name; |
94 | char *helper_image; | 113 | char *helper_image; |
95 | char *fw_image; | 114 | char *fw_image_sta; |
115 | char *fw_image_ap; | ||
96 | struct rxd_ops *ap_rxd_ops; | 116 | struct rxd_ops *ap_rxd_ops; |
117 | u32 fw_api_ap; | ||
97 | }; | 118 | }; |
98 | 119 | ||
99 | struct mwl8k_rx_queue { | 120 | struct mwl8k_rx_queue { |
@@ -126,9 +147,25 @@ struct mwl8k_tx_queue { | |||
126 | struct sk_buff **skb; | 147 | struct sk_buff **skb; |
127 | }; | 148 | }; |
128 | 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 | |||
129 | struct mwl8k_priv { | 165 | struct mwl8k_priv { |
130 | struct ieee80211_hw *hw; | 166 | struct ieee80211_hw *hw; |
131 | struct pci_dev *pdev; | 167 | struct pci_dev *pdev; |
168 | int irq; | ||
132 | 169 | ||
133 | struct mwl8k_device_info *device_info; | 170 | struct mwl8k_device_info *device_info; |
134 | 171 | ||
@@ -136,8 +173,8 @@ struct mwl8k_priv { | |||
136 | void __iomem *regs; | 173 | void __iomem *regs; |
137 | 174 | ||
138 | /* firmware */ | 175 | /* firmware */ |
139 | struct firmware *fw_helper; | 176 | const struct firmware *fw_helper; |
140 | struct firmware *fw_ucode; | 177 | const struct firmware *fw_ucode; |
141 | 178 | ||
142 | /* hardware/firmware parameters */ | 179 | /* hardware/firmware parameters */ |
143 | bool ap_fw; | 180 | bool ap_fw; |
@@ -151,6 +188,12 @@ struct mwl8k_priv { | |||
151 | u32 ap_macids_supported; | 188 | u32 ap_macids_supported; |
152 | u32 sta_macids_supported; | 189 | u32 sta_macids_supported; |
153 | 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 | |||
154 | /* firmware access */ | 197 | /* firmware access */ |
155 | struct mutex fw_mutex; | 198 | struct mutex fw_mutex; |
156 | struct task_struct *fw_mutex_owner; | 199 | struct task_struct *fw_mutex_owner; |
@@ -182,7 +225,8 @@ struct mwl8k_priv { | |||
182 | int pending_tx_pkts; | 225 | int pending_tx_pkts; |
183 | 226 | ||
184 | struct mwl8k_rx_queue rxq[MWL8K_RX_QUEUES]; | 227 | struct mwl8k_rx_queue rxq[MWL8K_RX_QUEUES]; |
185 | 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]; | ||
186 | 230 | ||
187 | bool radio_on; | 231 | bool radio_on; |
188 | bool radio_short_preamble; | 232 | bool radio_short_preamble; |
@@ -210,8 +254,23 @@ struct mwl8k_priv { | |||
210 | 254 | ||
211 | /* Most recently reported noise in dBm */ | 255 | /* Most recently reported noise in dBm */ |
212 | s8 noise; | 256 | s8 noise; |
257 | |||
258 | /* | ||
259 | * preserve the queue configurations so they can be restored if/when | ||
260 | * the firmware image is swapped. | ||
261 | */ | ||
262 | struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_WMM_QUEUES]; | ||
263 | |||
264 | /* async firmware loading state */ | ||
265 | unsigned fw_state; | ||
266 | char *fw_pref; | ||
267 | char *fw_alt; | ||
268 | struct completion firmware_loading_complete; | ||
213 | }; | 269 | }; |
214 | 270 | ||
271 | #define MAX_WEP_KEY_LEN 13 | ||
272 | #define NUM_WEP_KEYS 4 | ||
273 | |||
215 | /* Per interface specific private data */ | 274 | /* Per interface specific private data */ |
216 | struct mwl8k_vif { | 275 | struct mwl8k_vif { |
217 | struct list_head list; | 276 | struct list_head list; |
@@ -222,12 +281,33 @@ struct mwl8k_vif { | |||
222 | 281 | ||
223 | /* Non AMPDU sequence number assigned by driver. */ | 282 | /* Non AMPDU sequence number assigned by driver. */ |
224 | u16 seqno; | 283 | u16 seqno; |
284 | |||
285 | /* Saved WEP keys */ | ||
286 | struct { | ||
287 | u8 enabled; | ||
288 | u8 key[sizeof(struct ieee80211_key_conf) + MAX_WEP_KEY_LEN]; | ||
289 | } wep_key_conf[NUM_WEP_KEYS]; | ||
290 | |||
291 | /* BSSID */ | ||
292 | u8 bssid[ETH_ALEN]; | ||
293 | |||
294 | /* A flag to indicate is HW crypto is enabled for this bssid */ | ||
295 | bool is_hw_crypto_enabled; | ||
225 | }; | 296 | }; |
226 | #define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv)) | 297 | #define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv)) |
298 | #define IEEE80211_KEY_CONF(_u8) ((struct ieee80211_key_conf *)(_u8)) | ||
299 | |||
300 | struct tx_traffic_info { | ||
301 | u32 start_time; | ||
302 | u32 pkts; | ||
303 | }; | ||
227 | 304 | ||
305 | #define MWL8K_MAX_TID 8 | ||
228 | struct mwl8k_sta { | 306 | struct mwl8k_sta { |
229 | /* Index into station database. Returned by UPDATE_STADB. */ | 307 | /* Index into station database. Returned by UPDATE_STADB. */ |
230 | u8 peer_id; | 308 | u8 peer_id; |
309 | u8 is_ampdu_allowed; | ||
310 | struct tx_traffic_info tx_stats[MWL8K_MAX_TID]; | ||
231 | }; | 311 | }; |
232 | #define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv)) | 312 | #define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv)) |
233 | 313 | ||
@@ -285,8 +365,9 @@ static const struct ieee80211_rate mwl8k_rates_50[] = { | |||
285 | }; | 365 | }; |
286 | 366 | ||
287 | /* Set or get info from Firmware */ | 367 | /* Set or get info from Firmware */ |
288 | #define MWL8K_CMD_SET 0x0001 | ||
289 | #define MWL8K_CMD_GET 0x0000 | 368 | #define MWL8K_CMD_GET 0x0000 |
369 | #define MWL8K_CMD_SET 0x0001 | ||
370 | #define MWL8K_CMD_SET_LIST 0x0002 | ||
290 | 371 | ||
291 | /* Firmware command codes */ | 372 | /* Firmware command codes */ |
292 | #define MWL8K_CMD_CODE_DNLD 0x0001 | 373 | #define MWL8K_CMD_CODE_DNLD 0x0001 |
@@ -296,6 +377,7 @@ static const struct ieee80211_rate mwl8k_rates_50[] = { | |||
296 | #define MWL8K_CMD_GET_STAT 0x0014 | 377 | #define MWL8K_CMD_GET_STAT 0x0014 |
297 | #define MWL8K_CMD_RADIO_CONTROL 0x001c | 378 | #define MWL8K_CMD_RADIO_CONTROL 0x001c |
298 | #define MWL8K_CMD_RF_TX_POWER 0x001e | 379 | #define MWL8K_CMD_RF_TX_POWER 0x001e |
380 | #define MWL8K_CMD_TX_POWER 0x001f | ||
299 | #define MWL8K_CMD_RF_ANTENNA 0x0020 | 381 | #define MWL8K_CMD_RF_ANTENNA 0x0020 |
300 | #define MWL8K_CMD_SET_BEACON 0x0100 /* per-vif */ | 382 | #define MWL8K_CMD_SET_BEACON 0x0100 /* per-vif */ |
301 | #define MWL8K_CMD_SET_PRE_SCAN 0x0107 | 383 | #define MWL8K_CMD_SET_PRE_SCAN 0x0107 |
@@ -313,9 +395,12 @@ static const struct ieee80211_rate mwl8k_rates_50[] = { | |||
313 | #define MWL8K_CMD_ENABLE_SNIFFER 0x0150 | 395 | #define MWL8K_CMD_ENABLE_SNIFFER 0x0150 |
314 | #define MWL8K_CMD_SET_MAC_ADDR 0x0202 /* per-vif */ | 396 | #define MWL8K_CMD_SET_MAC_ADDR 0x0202 /* per-vif */ |
315 | #define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 | 397 | #define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 |
398 | #define MWL8K_CMD_GET_WATCHDOG_BITMAP 0x0205 | ||
316 | #define MWL8K_CMD_BSS_START 0x1100 /* per-vif */ | 399 | #define MWL8K_CMD_BSS_START 0x1100 /* per-vif */ |
317 | #define MWL8K_CMD_SET_NEW_STN 0x1111 /* per-vif */ | 400 | #define MWL8K_CMD_SET_NEW_STN 0x1111 /* per-vif */ |
401 | #define MWL8K_CMD_UPDATE_ENCRYPTION 0x1122 /* per-vif */ | ||
318 | #define MWL8K_CMD_UPDATE_STADB 0x1123 | 402 | #define MWL8K_CMD_UPDATE_STADB 0x1123 |
403 | #define MWL8K_CMD_BASTREAM 0x1125 | ||
319 | 404 | ||
320 | 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) |
321 | { | 406 | { |
@@ -333,6 +418,7 @@ static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize) | |||
333 | MWL8K_CMDNAME(GET_STAT); | 418 | MWL8K_CMDNAME(GET_STAT); |
334 | MWL8K_CMDNAME(RADIO_CONTROL); | 419 | MWL8K_CMDNAME(RADIO_CONTROL); |
335 | MWL8K_CMDNAME(RF_TX_POWER); | 420 | MWL8K_CMDNAME(RF_TX_POWER); |
421 | MWL8K_CMDNAME(TX_POWER); | ||
336 | MWL8K_CMDNAME(RF_ANTENNA); | 422 | MWL8K_CMDNAME(RF_ANTENNA); |
337 | MWL8K_CMDNAME(SET_BEACON); | 423 | MWL8K_CMDNAME(SET_BEACON); |
338 | MWL8K_CMDNAME(SET_PRE_SCAN); | 424 | MWL8K_CMDNAME(SET_PRE_SCAN); |
@@ -352,7 +438,10 @@ static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize) | |||
352 | MWL8K_CMDNAME(SET_RATEADAPT_MODE); | 438 | MWL8K_CMDNAME(SET_RATEADAPT_MODE); |
353 | MWL8K_CMDNAME(BSS_START); | 439 | MWL8K_CMDNAME(BSS_START); |
354 | MWL8K_CMDNAME(SET_NEW_STN); | 440 | MWL8K_CMDNAME(SET_NEW_STN); |
441 | MWL8K_CMDNAME(UPDATE_ENCRYPTION); | ||
355 | MWL8K_CMDNAME(UPDATE_STADB); | 442 | MWL8K_CMDNAME(UPDATE_STADB); |
443 | MWL8K_CMDNAME(BASTREAM); | ||
444 | MWL8K_CMDNAME(GET_WATCHDOG_BITMAP); | ||
356 | default: | 445 | default: |
357 | snprintf(buf, bufsize, "0x%x", cmd); | 446 | snprintf(buf, bufsize, "0x%x", cmd); |
358 | } | 447 | } |
@@ -372,7 +461,7 @@ static void mwl8k_hw_reset(struct mwl8k_priv *priv) | |||
372 | } | 461 | } |
373 | 462 | ||
374 | /* Release fw image */ | 463 | /* Release fw image */ |
375 | static void mwl8k_release_fw(struct firmware **fw) | 464 | static void mwl8k_release_fw(const struct firmware **fw) |
376 | { | 465 | { |
377 | if (*fw == NULL) | 466 | if (*fw == NULL) |
378 | return; | 467 | return; |
@@ -386,37 +475,68 @@ static void mwl8k_release_firmware(struct mwl8k_priv *priv) | |||
386 | mwl8k_release_fw(&priv->fw_helper); | 475 | mwl8k_release_fw(&priv->fw_helper); |
387 | } | 476 | } |
388 | 477 | ||
478 | /* states for asynchronous f/w loading */ | ||
479 | static void mwl8k_fw_state_machine(const struct firmware *fw, void *context); | ||
480 | enum { | ||
481 | FW_STATE_INIT = 0, | ||
482 | FW_STATE_LOADING_PREF, | ||
483 | FW_STATE_LOADING_ALT, | ||
484 | FW_STATE_ERROR, | ||
485 | }; | ||
486 | |||
389 | /* Request fw image */ | 487 | /* Request fw image */ |
390 | static int mwl8k_request_fw(struct mwl8k_priv *priv, | 488 | static int mwl8k_request_fw(struct mwl8k_priv *priv, |
391 | const char *fname, struct firmware **fw) | 489 | const char *fname, const struct firmware **fw, |
490 | bool nowait) | ||
392 | { | 491 | { |
393 | /* release current image */ | 492 | /* release current image */ |
394 | if (*fw != NULL) | 493 | if (*fw != NULL) |
395 | mwl8k_release_fw(fw); | 494 | mwl8k_release_fw(fw); |
396 | 495 | ||
397 | return request_firmware((const struct firmware **)fw, | 496 | if (nowait) |
398 | fname, &priv->pdev->dev); | 497 | return request_firmware_nowait(THIS_MODULE, 1, fname, |
498 | &priv->pdev->dev, GFP_KERNEL, | ||
499 | priv, mwl8k_fw_state_machine); | ||
500 | else | ||
501 | return request_firmware(fw, fname, &priv->pdev->dev); | ||
399 | } | 502 | } |
400 | 503 | ||
401 | static int mwl8k_request_firmware(struct mwl8k_priv *priv) | 504 | static int mwl8k_request_firmware(struct mwl8k_priv *priv, char *fw_image, |
505 | bool nowait) | ||
402 | { | 506 | { |
403 | struct mwl8k_device_info *di = priv->device_info; | 507 | struct mwl8k_device_info *di = priv->device_info; |
404 | int rc; | 508 | int rc; |
405 | 509 | ||
406 | if (di->helper_image != NULL) { | 510 | if (di->helper_image != NULL) { |
407 | rc = mwl8k_request_fw(priv, di->helper_image, &priv->fw_helper); | 511 | if (nowait) |
408 | if (rc) { | 512 | rc = mwl8k_request_fw(priv, di->helper_image, |
409 | printk(KERN_ERR "%s: Error requesting helper " | 513 | &priv->fw_helper, true); |
410 | "firmware file %s\n", pci_name(priv->pdev), | 514 | else |
411 | di->helper_image); | 515 | rc = mwl8k_request_fw(priv, di->helper_image, |
516 | &priv->fw_helper, false); | ||
517 | if (rc) | ||
518 | printk(KERN_ERR "%s: Error requesting helper fw %s\n", | ||
519 | pci_name(priv->pdev), di->helper_image); | ||
520 | |||
521 | if (rc || nowait) | ||
412 | return rc; | 522 | return rc; |
413 | } | ||
414 | } | 523 | } |
415 | 524 | ||
416 | rc = mwl8k_request_fw(priv, di->fw_image, &priv->fw_ucode); | 525 | if (nowait) { |
526 | /* | ||
527 | * if we get here, no helper image is needed. Skip the | ||
528 | * FW_STATE_INIT state. | ||
529 | */ | ||
530 | priv->fw_state = FW_STATE_LOADING_PREF; | ||
531 | rc = mwl8k_request_fw(priv, fw_image, | ||
532 | &priv->fw_ucode, | ||
533 | true); | ||
534 | } else | ||
535 | rc = mwl8k_request_fw(priv, fw_image, | ||
536 | &priv->fw_ucode, false); | ||
417 | if (rc) { | 537 | if (rc) { |
418 | printk(KERN_ERR "%s: Error requesting firmware file %s\n", | 538 | printk(KERN_ERR "%s: Error requesting firmware file %s\n", |
419 | pci_name(priv->pdev), di->fw_image); | 539 | pci_name(priv->pdev), fw_image); |
420 | mwl8k_release_fw(&priv->fw_helper); | 540 | mwl8k_release_fw(&priv->fw_helper); |
421 | return rc; | 541 | return rc; |
422 | } | 542 | } |
@@ -577,12 +697,12 @@ static int mwl8k_feed_fw_image(struct mwl8k_priv *priv, | |||
577 | static int mwl8k_load_firmware(struct ieee80211_hw *hw) | 697 | static int mwl8k_load_firmware(struct ieee80211_hw *hw) |
578 | { | 698 | { |
579 | struct mwl8k_priv *priv = hw->priv; | 699 | struct mwl8k_priv *priv = hw->priv; |
580 | struct firmware *fw = priv->fw_ucode; | 700 | const struct firmware *fw = priv->fw_ucode; |
581 | int rc; | 701 | int rc; |
582 | int loops; | 702 | int loops; |
583 | 703 | ||
584 | if (!memcmp(fw->data, "\x01\x00\x00\x00", 4)) { | 704 | if (!memcmp(fw->data, "\x01\x00\x00\x00", 4)) { |
585 | struct firmware *helper = priv->fw_helper; | 705 | const struct firmware *helper = priv->fw_helper; |
586 | 706 | ||
587 | if (helper == NULL) { | 707 | if (helper == NULL) { |
588 | printk(KERN_ERR "%s: helper image needed but none " | 708 | printk(KERN_ERR "%s: helper image needed but none " |
@@ -596,7 +716,7 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw) | |||
596 | "helper image\n", pci_name(priv->pdev)); | 716 | "helper image\n", pci_name(priv->pdev)); |
597 | return rc; | 717 | return rc; |
598 | } | 718 | } |
599 | msleep(5); | 719 | msleep(20); |
600 | 720 | ||
601 | rc = mwl8k_feed_fw_image(priv, fw->data, fw->size); | 721 | rc = mwl8k_feed_fw_image(priv, fw->data, fw->size); |
602 | } else { | 722 | } else { |
@@ -661,10 +781,15 @@ static inline void mwl8k_remove_dma_header(struct sk_buff *skb, __le16 qos) | |||
661 | skb_pull(skb, sizeof(*tr) - hdrlen); | 781 | skb_pull(skb, sizeof(*tr) - hdrlen); |
662 | } | 782 | } |
663 | 783 | ||
664 | static inline void mwl8k_add_dma_header(struct sk_buff *skb) | 784 | #define REDUCED_TX_HEADROOM 8 |
785 | |||
786 | static void | ||
787 | mwl8k_add_dma_header(struct mwl8k_priv *priv, struct sk_buff *skb, | ||
788 | int head_pad, int tail_pad) | ||
665 | { | 789 | { |
666 | struct ieee80211_hdr *wh; | 790 | struct ieee80211_hdr *wh; |
667 | int hdrlen; | 791 | int hdrlen; |
792 | int reqd_hdrlen; | ||
668 | struct mwl8k_dma_data *tr; | 793 | struct mwl8k_dma_data *tr; |
669 | 794 | ||
670 | /* | 795 | /* |
@@ -676,11 +801,29 @@ static inline void mwl8k_add_dma_header(struct sk_buff *skb) | |||
676 | wh = (struct ieee80211_hdr *)skb->data; | 801 | wh = (struct ieee80211_hdr *)skb->data; |
677 | 802 | ||
678 | hdrlen = ieee80211_hdrlen(wh->frame_control); | 803 | hdrlen = ieee80211_hdrlen(wh->frame_control); |
679 | if (hdrlen != sizeof(*tr)) | 804 | |
680 | skb_push(skb, sizeof(*tr) - hdrlen); | 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; | ||
821 | |||
822 | if (hdrlen != reqd_hdrlen) | ||
823 | skb_push(skb, reqd_hdrlen - hdrlen); | ||
681 | 824 | ||
682 | if (ieee80211_is_data_qos(wh->frame_control)) | 825 | if (ieee80211_is_data_qos(wh->frame_control)) |
683 | hdrlen -= 2; | 826 | hdrlen -= IEEE80211_QOS_CTL_LEN; |
684 | 827 | ||
685 | tr = (struct mwl8k_dma_data *)skb->data; | 828 | tr = (struct mwl8k_dma_data *)skb->data; |
686 | if (wh != &tr->wh) | 829 | if (wh != &tr->wh) |
@@ -693,9 +836,53 @@ static inline void mwl8k_add_dma_header(struct sk_buff *skb) | |||
693 | * payload". That is, everything except for the 802.11 header. | 836 | * payload". That is, everything except for the 802.11 header. |
694 | * This includes all crypto material including the MIC. | 837 | * This includes all crypto material including the MIC. |
695 | */ | 838 | */ |
696 | tr->fwlen = cpu_to_le16(skb->len - sizeof(*tr)); | 839 | tr->fwlen = cpu_to_le16(skb->len - sizeof(*tr) + tail_pad); |
697 | } | 840 | } |
698 | 841 | ||
842 | static void mwl8k_encapsulate_tx_frame(struct mwl8k_priv *priv, | ||
843 | struct sk_buff *skb) | ||
844 | { | ||
845 | struct ieee80211_hdr *wh; | ||
846 | struct ieee80211_tx_info *tx_info; | ||
847 | struct ieee80211_key_conf *key_conf; | ||
848 | int data_pad; | ||
849 | int head_pad = 0; | ||
850 | |||
851 | wh = (struct ieee80211_hdr *)skb->data; | ||
852 | |||
853 | tx_info = IEEE80211_SKB_CB(skb); | ||
854 | |||
855 | key_conf = NULL; | ||
856 | if (ieee80211_is_data(wh->frame_control)) | ||
857 | key_conf = tx_info->control.hw_key; | ||
858 | |||
859 | /* | ||
860 | * Make sure the packet header is in the DMA header format (4-address | ||
861 | * without QoS), and add head & tail padding when HW crypto is enabled. | ||
862 | * | ||
863 | * We have the following trailer padding requirements: | ||
864 | * - WEP: 4 trailer bytes (ICV) | ||
865 | * - TKIP: 12 trailer bytes (8 MIC + 4 ICV) | ||
866 | * - CCMP: 8 trailer bytes (MIC) | ||
867 | */ | ||
868 | data_pad = 0; | ||
869 | if (key_conf != NULL) { | ||
870 | head_pad = key_conf->iv_len; | ||
871 | switch (key_conf->cipher) { | ||
872 | case WLAN_CIPHER_SUITE_WEP40: | ||
873 | case WLAN_CIPHER_SUITE_WEP104: | ||
874 | data_pad = 4; | ||
875 | break; | ||
876 | case WLAN_CIPHER_SUITE_TKIP: | ||
877 | data_pad = 12; | ||
878 | break; | ||
879 | case WLAN_CIPHER_SUITE_CCMP: | ||
880 | data_pad = 8; | ||
881 | break; | ||
882 | } | ||
883 | } | ||
884 | mwl8k_add_dma_header(priv, skb, head_pad, data_pad); | ||
885 | } | ||
699 | 886 | ||
700 | /* | 887 | /* |
701 | * Packet reception for 88w8366 AP firmware. | 888 | * Packet reception for 88w8366 AP firmware. |
@@ -724,6 +911,13 @@ struct mwl8k_rxd_8366_ap { | |||
724 | 911 | ||
725 | #define MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST 0x80 | 912 | #define MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST 0x80 |
726 | 913 | ||
914 | /* 8366 AP rx_status bits */ | ||
915 | #define MWL8K_8366_AP_RXSTAT_DECRYPT_ERR_MASK 0x80 | ||
916 | #define MWL8K_8366_AP_RXSTAT_GENERAL_DECRYPT_ERR 0xFF | ||
917 | #define MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_MIC_ERR 0x02 | ||
918 | #define MWL8K_8366_AP_RXSTAT_WEP_DECRYPT_ICV_ERR 0x04 | ||
919 | #define MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_ICV_ERR 0x08 | ||
920 | |||
727 | static void mwl8k_rxd_8366_ap_init(void *_rxd, dma_addr_t next_dma_addr) | 921 | static void mwl8k_rxd_8366_ap_init(void *_rxd, dma_addr_t next_dma_addr) |
728 | { | 922 | { |
729 | struct mwl8k_rxd_8366_ap *rxd = _rxd; | 923 | struct mwl8k_rxd_8366_ap *rxd = _rxd; |
@@ -780,10 +974,16 @@ mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status, | |||
780 | } else { | 974 | } else { |
781 | status->band = IEEE80211_BAND_2GHZ; | 975 | status->band = IEEE80211_BAND_2GHZ; |
782 | } | 976 | } |
783 | status->freq = ieee80211_channel_to_frequency(rxd->channel); | 977 | status->freq = ieee80211_channel_to_frequency(rxd->channel, |
978 | status->band); | ||
784 | 979 | ||
785 | *qos = rxd->qos_control; | 980 | *qos = rxd->qos_control; |
786 | 981 | ||
982 | if ((rxd->rx_status != MWL8K_8366_AP_RXSTAT_GENERAL_DECRYPT_ERR) && | ||
983 | (rxd->rx_status & MWL8K_8366_AP_RXSTAT_DECRYPT_ERR_MASK) && | ||
984 | (rxd->rx_status & MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_MIC_ERR)) | ||
985 | status->flag |= RX_FLAG_MMIC_ERROR; | ||
986 | |||
787 | return le16_to_cpu(rxd->pkt_len); | 987 | return le16_to_cpu(rxd->pkt_len); |
788 | } | 988 | } |
789 | 989 | ||
@@ -822,6 +1022,11 @@ struct mwl8k_rxd_sta { | |||
822 | #define MWL8K_STA_RATE_INFO_MCS_FORMAT 0x0001 | 1022 | #define MWL8K_STA_RATE_INFO_MCS_FORMAT 0x0001 |
823 | 1023 | ||
824 | #define MWL8K_STA_RX_CTRL_OWNED_BY_HOST 0x02 | 1024 | #define MWL8K_STA_RX_CTRL_OWNED_BY_HOST 0x02 |
1025 | #define MWL8K_STA_RX_CTRL_DECRYPT_ERROR 0x04 | ||
1026 | /* ICV=0 or MIC=1 */ | ||
1027 | #define MWL8K_STA_RX_CTRL_DEC_ERR_TYPE 0x08 | ||
1028 | /* Key is uploaded only in failure case */ | ||
1029 | #define MWL8K_STA_RX_CTRL_KEY_INDEX 0x30 | ||
825 | 1030 | ||
826 | static void mwl8k_rxd_sta_init(void *_rxd, dma_addr_t next_dma_addr) | 1031 | static void mwl8k_rxd_sta_init(void *_rxd, dma_addr_t next_dma_addr) |
827 | { | 1032 | { |
@@ -877,9 +1082,13 @@ mwl8k_rxd_sta_process(void *_rxd, struct ieee80211_rx_status *status, | |||
877 | } else { | 1082 | } else { |
878 | status->band = IEEE80211_BAND_2GHZ; | 1083 | status->band = IEEE80211_BAND_2GHZ; |
879 | } | 1084 | } |
880 | status->freq = ieee80211_channel_to_frequency(rxd->channel); | 1085 | status->freq = ieee80211_channel_to_frequency(rxd->channel, |
1086 | status->band); | ||
881 | 1087 | ||
882 | *qos = rxd->qos_control; | 1088 | *qos = rxd->qos_control; |
1089 | if ((rxd->rx_ctrl & MWL8K_STA_RX_CTRL_DECRYPT_ERROR) && | ||
1090 | (rxd->rx_ctrl & MWL8K_STA_RX_CTRL_DEC_ERR_TYPE)) | ||
1091 | status->flag |= RX_FLAG_MMIC_ERROR; | ||
883 | 1092 | ||
884 | return le16_to_cpu(rxd->pkt_len); | 1093 | return le16_to_cpu(rxd->pkt_len); |
885 | } | 1094 | } |
@@ -915,13 +1124,12 @@ static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index) | |||
915 | } | 1124 | } |
916 | memset(rxq->rxd, 0, size); | 1125 | memset(rxq->rxd, 0, size); |
917 | 1126 | ||
918 | rxq->buf = kmalloc(MWL8K_RX_DESCS * sizeof(*rxq->buf), GFP_KERNEL); | 1127 | rxq->buf = kcalloc(MWL8K_RX_DESCS, sizeof(*rxq->buf), GFP_KERNEL); |
919 | if (rxq->buf == NULL) { | 1128 | if (rxq->buf == NULL) { |
920 | wiphy_err(hw->wiphy, "failed to alloc RX skbuff list\n"); | 1129 | wiphy_err(hw->wiphy, "failed to alloc RX skbuff list\n"); |
921 | pci_free_consistent(priv->pdev, size, rxq->rxd, rxq->rxd_dma); | 1130 | pci_free_consistent(priv->pdev, size, rxq->rxd, rxq->rxd_dma); |
922 | return -ENOMEM; | 1131 | return -ENOMEM; |
923 | } | 1132 | } |
924 | memset(rxq->buf, 0, MWL8K_RX_DESCS * sizeof(*rxq->buf)); | ||
925 | 1133 | ||
926 | for (i = 0; i < MWL8K_RX_DESCS; i++) { | 1134 | for (i = 0; i < MWL8K_RX_DESCS; i++) { |
927 | int desc_size; | 1135 | int desc_size; |
@@ -986,6 +1194,9 @@ static void mwl8k_rxq_deinit(struct ieee80211_hw *hw, int index) | |||
986 | struct mwl8k_rx_queue *rxq = priv->rxq + index; | 1194 | struct mwl8k_rx_queue *rxq = priv->rxq + index; |
987 | int i; | 1195 | int i; |
988 | 1196 | ||
1197 | if (rxq->rxd == NULL) | ||
1198 | return; | ||
1199 | |||
989 | for (i = 0; i < MWL8K_RX_DESCS; i++) { | 1200 | for (i = 0; i < MWL8K_RX_DESCS; i++) { |
990 | if (rxq->buf[i].skb != NULL) { | 1201 | if (rxq->buf[i].skb != NULL) { |
991 | pci_unmap_single(priv->pdev, | 1202 | pci_unmap_single(priv->pdev, |
@@ -1038,9 +1249,25 @@ static inline void mwl8k_save_beacon(struct ieee80211_hw *hw, | |||
1038 | ieee80211_queue_work(hw, &priv->finalize_join_worker); | 1249 | ieee80211_queue_work(hw, &priv->finalize_join_worker); |
1039 | } | 1250 | } |
1040 | 1251 | ||
1252 | static inline struct mwl8k_vif *mwl8k_find_vif_bss(struct list_head *vif_list, | ||
1253 | u8 *bssid) | ||
1254 | { | ||
1255 | struct mwl8k_vif *mwl8k_vif; | ||
1256 | |||
1257 | list_for_each_entry(mwl8k_vif, | ||
1258 | vif_list, list) { | ||
1259 | if (memcmp(bssid, mwl8k_vif->bssid, | ||
1260 | ETH_ALEN) == 0) | ||
1261 | return mwl8k_vif; | ||
1262 | } | ||
1263 | |||
1264 | return NULL; | ||
1265 | } | ||
1266 | |||
1041 | static int rxq_process(struct ieee80211_hw *hw, int index, int limit) | 1267 | static int rxq_process(struct ieee80211_hw *hw, int index, int limit) |
1042 | { | 1268 | { |
1043 | struct mwl8k_priv *priv = hw->priv; | 1269 | struct mwl8k_priv *priv = hw->priv; |
1270 | struct mwl8k_vif *mwl8k_vif = NULL; | ||
1044 | struct mwl8k_rx_queue *rxq = priv->rxq + index; | 1271 | struct mwl8k_rx_queue *rxq = priv->rxq + index; |
1045 | int processed; | 1272 | int processed; |
1046 | 1273 | ||
@@ -1050,6 +1277,7 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit) | |||
1050 | void *rxd; | 1277 | void *rxd; |
1051 | int pkt_len; | 1278 | int pkt_len; |
1052 | struct ieee80211_rx_status status; | 1279 | struct ieee80211_rx_status status; |
1280 | struct ieee80211_hdr *wh; | ||
1053 | __le16 qos; | 1281 | __le16 qos; |
1054 | 1282 | ||
1055 | skb = rxq->buf[rxq->head].skb; | 1283 | skb = rxq->buf[rxq->head].skb; |
@@ -1076,8 +1304,7 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit) | |||
1076 | 1304 | ||
1077 | rxq->rxd_count--; | 1305 | rxq->rxd_count--; |
1078 | 1306 | ||
1079 | skb_put(skb, pkt_len); | 1307 | wh = &((struct mwl8k_dma_data *)skb->data)->wh; |
1080 | mwl8k_remove_dma_header(skb, qos); | ||
1081 | 1308 | ||
1082 | /* | 1309 | /* |
1083 | * Check for a pending join operation. Save a | 1310 | * Check for a pending join operation. Save a |
@@ -1087,6 +1314,46 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit) | |||
1087 | if (mwl8k_capture_bssid(priv, (void *)skb->data)) | 1314 | if (mwl8k_capture_bssid(priv, (void *)skb->data)) |
1088 | mwl8k_save_beacon(hw, skb); | 1315 | mwl8k_save_beacon(hw, skb); |
1089 | 1316 | ||
1317 | if (ieee80211_has_protected(wh->frame_control)) { | ||
1318 | |||
1319 | /* Check if hw crypto has been enabled for | ||
1320 | * this bss. If yes, set the status flags | ||
1321 | * accordingly | ||
1322 | */ | ||
1323 | mwl8k_vif = mwl8k_find_vif_bss(&priv->vif_list, | ||
1324 | wh->addr1); | ||
1325 | |||
1326 | if (mwl8k_vif != NULL && | ||
1327 | mwl8k_vif->is_hw_crypto_enabled == true) { | ||
1328 | /* | ||
1329 | * When MMIC ERROR is encountered | ||
1330 | * by the firmware, payload is | ||
1331 | * dropped and only 32 bytes of | ||
1332 | * mwl8k Firmware header is sent | ||
1333 | * to the host. | ||
1334 | * | ||
1335 | * We need to add four bytes of | ||
1336 | * key information. In it | ||
1337 | * MAC80211 expects keyidx set to | ||
1338 | * 0 for triggering Counter | ||
1339 | * Measure of MMIC failure. | ||
1340 | */ | ||
1341 | if (status.flag & RX_FLAG_MMIC_ERROR) { | ||
1342 | struct mwl8k_dma_data *tr; | ||
1343 | tr = (struct mwl8k_dma_data *)skb->data; | ||
1344 | memset((void *)&(tr->data), 0, 4); | ||
1345 | pkt_len += 4; | ||
1346 | } | ||
1347 | |||
1348 | if (!ieee80211_is_auth(wh->frame_control)) | ||
1349 | status.flag |= RX_FLAG_IV_STRIPPED | | ||
1350 | RX_FLAG_DECRYPTED | | ||
1351 | RX_FLAG_MMIC_STRIPPED; | ||
1352 | } | ||
1353 | } | ||
1354 | |||
1355 | skb_put(skb, pkt_len); | ||
1356 | mwl8k_remove_dma_header(skb, qos); | ||
1090 | memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); | 1357 | memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); |
1091 | ieee80211_rx_irqsafe(hw, skb); | 1358 | ieee80211_rx_irqsafe(hw, skb); |
1092 | 1359 | ||
@@ -1122,7 +1389,7 @@ struct mwl8k_tx_desc { | |||
1122 | __le16 pkt_len; | 1389 | __le16 pkt_len; |
1123 | __u8 dest_MAC_addr[ETH_ALEN]; | 1390 | __u8 dest_MAC_addr[ETH_ALEN]; |
1124 | __le32 next_txd_phys_addr; | 1391 | __le32 next_txd_phys_addr; |
1125 | __le32 reserved; | 1392 | __le32 timestamp; |
1126 | __le16 rate_info; | 1393 | __le16 rate_info; |
1127 | __u8 peer_id; | 1394 | __u8 peer_id; |
1128 | __u8 tx_frag_cnt; | 1395 | __u8 tx_frag_cnt; |
@@ -1150,13 +1417,12 @@ static int mwl8k_txq_init(struct ieee80211_hw *hw, int index) | |||
1150 | } | 1417 | } |
1151 | memset(txq->txd, 0, size); | 1418 | memset(txq->txd, 0, size); |
1152 | 1419 | ||
1153 | txq->skb = kmalloc(MWL8K_TX_DESCS * sizeof(*txq->skb), GFP_KERNEL); | 1420 | txq->skb = kcalloc(MWL8K_TX_DESCS, sizeof(*txq->skb), GFP_KERNEL); |
1154 | if (txq->skb == NULL) { | 1421 | if (txq->skb == NULL) { |
1155 | wiphy_err(hw->wiphy, "failed to alloc TX skbuff list\n"); | 1422 | wiphy_err(hw->wiphy, "failed to alloc TX skbuff list\n"); |
1156 | pci_free_consistent(priv->pdev, size, txq->txd, txq->txd_dma); | 1423 | pci_free_consistent(priv->pdev, size, txq->txd, txq->txd_dma); |
1157 | return -ENOMEM; | 1424 | return -ENOMEM; |
1158 | } | 1425 | } |
1159 | memset(txq->skb, 0, MWL8K_TX_DESCS * sizeof(*txq->skb)); | ||
1160 | 1426 | ||
1161 | for (i = 0; i < MWL8K_TX_DESCS; i++) { | 1427 | for (i = 0; i < MWL8K_TX_DESCS; i++) { |
1162 | struct mwl8k_tx_desc *tx_desc; | 1428 | struct mwl8k_tx_desc *tx_desc; |
@@ -1187,7 +1453,7 @@ static void mwl8k_dump_tx_rings(struct ieee80211_hw *hw) | |||
1187 | struct mwl8k_priv *priv = hw->priv; | 1453 | struct mwl8k_priv *priv = hw->priv; |
1188 | int i; | 1454 | int i; |
1189 | 1455 | ||
1190 | for (i = 0; i < MWL8K_TX_QUEUES; i++) { | 1456 | for (i = 0; i < mwl8k_tx_queues(priv); i++) { |
1191 | struct mwl8k_tx_queue *txq = priv->txq + i; | 1457 | struct mwl8k_tx_queue *txq = priv->txq + i; |
1192 | int fw_owned = 0; | 1458 | int fw_owned = 0; |
1193 | int drv_owned = 0; | 1459 | int drv_owned = 0; |
@@ -1256,9 +1522,8 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) | |||
1256 | 1522 | ||
1257 | if (timeout) { | 1523 | if (timeout) { |
1258 | WARN_ON(priv->pending_tx_pkts); | 1524 | WARN_ON(priv->pending_tx_pkts); |
1259 | if (retry) { | 1525 | if (retry) |
1260 | wiphy_notice(hw->wiphy, "tx rings drained\n"); | 1526 | wiphy_notice(hw->wiphy, "tx rings drained\n"); |
1261 | } | ||
1262 | break; | 1527 | break; |
1263 | } | 1528 | } |
1264 | 1529 | ||
@@ -1288,6 +1553,41 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) | |||
1288 | MWL8K_TXD_STATUS_OK_RETRY | \ | 1553 | MWL8K_TXD_STATUS_OK_RETRY | \ |
1289 | MWL8K_TXD_STATUS_OK_MORE_RETRY)) | 1554 | MWL8K_TXD_STATUS_OK_MORE_RETRY)) |
1290 | 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 | |||
1291 | static int | 1591 | static int |
1292 | 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) |
1293 | { | 1593 | { |
@@ -1304,6 +1604,10 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) | |||
1304 | struct sk_buff *skb; | 1604 | struct sk_buff *skb; |
1305 | struct ieee80211_tx_info *info; | 1605 | struct ieee80211_tx_info *info; |
1306 | 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; | ||
1307 | 1611 | ||
1308 | tx = txq->head; | 1612 | tx = txq->head; |
1309 | tx_desc = txq->txd + tx; | 1613 | tx_desc = txq->txd + tx; |
@@ -1332,12 +1636,41 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) | |||
1332 | 1636 | ||
1333 | mwl8k_remove_dma_header(skb, tx_desc->qos_control); | 1637 | mwl8k_remove_dma_header(skb, tx_desc->qos_control); |
1334 | 1638 | ||
1639 | wh = (struct ieee80211_hdr *) skb->data; | ||
1640 | |||
1335 | /* Mark descriptor as unused */ | 1641 | /* Mark descriptor as unused */ |
1336 | tx_desc->pkt_phys_addr = 0; | 1642 | tx_desc->pkt_phys_addr = 0; |
1337 | tx_desc->pkt_len = 0; | 1643 | tx_desc->pkt_len = 0; |
1338 | 1644 | ||
1339 | 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 | |||
1340 | ieee80211_tx_info_clear_status(info); | 1666 | ieee80211_tx_info_clear_status(info); |
1667 | |||
1668 | /* Rate control is happening in the firmware. | ||
1669 | * Ensure no tx rate is being reported. | ||
1670 | */ | ||
1671 | info->status.rates[0].idx = -1; | ||
1672 | info->status.rates[0].count = 1; | ||
1673 | |||
1341 | if (MWL8K_TXD_SUCCESS(status)) | 1674 | if (MWL8K_TXD_SUCCESS(status)) |
1342 | info->flags |= IEEE80211_TX_STAT_ACK; | 1675 | info->flags |= IEEE80211_TX_STAT_ACK; |
1343 | 1676 | ||
@@ -1346,9 +1679,6 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) | |||
1346 | processed++; | 1679 | processed++; |
1347 | } | 1680 | } |
1348 | 1681 | ||
1349 | if (processed && priv->radio_on && !mutex_is_locked(&priv->fw_mutex)) | ||
1350 | ieee80211_wake_queue(hw, index); | ||
1351 | |||
1352 | return processed; | 1682 | return processed; |
1353 | } | 1683 | } |
1354 | 1684 | ||
@@ -1358,6 +1688,9 @@ static void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index) | |||
1358 | struct mwl8k_priv *priv = hw->priv; | 1688 | struct mwl8k_priv *priv = hw->priv; |
1359 | struct mwl8k_tx_queue *txq = priv->txq + index; | 1689 | struct mwl8k_tx_queue *txq = priv->txq + index; |
1360 | 1690 | ||
1691 | if (txq->txd == NULL) | ||
1692 | return; | ||
1693 | |||
1361 | mwl8k_txq_reclaim(hw, index, INT_MAX, 1); | 1694 | mwl8k_txq_reclaim(hw, index, INT_MAX, 1); |
1362 | 1695 | ||
1363 | kfree(txq->skb); | 1696 | kfree(txq->skb); |
@@ -1369,12 +1702,116 @@ static void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index) | |||
1369 | txq->txd = NULL; | 1702 | txq->txd = NULL; |
1370 | } | 1703 | } |
1371 | 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 | |||
1372 | static int | 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 | |||
1808 | static void | ||
1373 | 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) |
1374 | { | 1810 | { |
1375 | struct mwl8k_priv *priv = hw->priv; | 1811 | struct mwl8k_priv *priv = hw->priv; |
1376 | struct ieee80211_tx_info *tx_info; | 1812 | struct ieee80211_tx_info *tx_info; |
1377 | struct mwl8k_vif *mwl8k_vif; | 1813 | struct mwl8k_vif *mwl8k_vif; |
1814 | struct ieee80211_sta *sta; | ||
1378 | struct ieee80211_hdr *wh; | 1815 | struct ieee80211_hdr *wh; |
1379 | struct mwl8k_tx_queue *txq; | 1816 | struct mwl8k_tx_queue *txq; |
1380 | struct mwl8k_tx_desc *tx; | 1817 | struct mwl8k_tx_desc *tx; |
@@ -1382,6 +1819,12 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1382 | u32 txstatus; | 1819 | u32 txstatus; |
1383 | u8 txdatarate; | 1820 | u8 txdatarate; |
1384 | 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; | ||
1385 | 1828 | ||
1386 | wh = (struct ieee80211_hdr *)skb->data; | 1829 | wh = (struct ieee80211_hdr *)skb->data; |
1387 | if (ieee80211_is_data_qos(wh->frame_control)) | 1830 | if (ieee80211_is_data_qos(wh->frame_control)) |
@@ -1389,10 +1832,18 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1389 | else | 1832 | else |
1390 | qos = 0; | 1833 | qos = 0; |
1391 | 1834 | ||
1392 | mwl8k_add_dma_header(skb); | 1835 | if (ieee80211_is_mgmt(wh->frame_control)) |
1836 | mgmtframe = true; | ||
1837 | |||
1838 | if (priv->ap_fw) | ||
1839 | mwl8k_encapsulate_tx_frame(priv, skb); | ||
1840 | else | ||
1841 | mwl8k_add_dma_header(priv, skb, 0, 0); | ||
1842 | |||
1393 | wh = &((struct mwl8k_dma_data *)skb->data)->wh; | 1843 | wh = &((struct mwl8k_dma_data *)skb->data)->wh; |
1394 | 1844 | ||
1395 | tx_info = IEEE80211_SKB_CB(skb); | 1845 | tx_info = IEEE80211_SKB_CB(skb); |
1846 | sta = tx_info->control.sta; | ||
1396 | mwl8k_vif = MWL8K_VIF(tx_info->control.vif); | 1847 | mwl8k_vif = MWL8K_VIF(tx_info->control.vif); |
1397 | 1848 | ||
1398 | if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { | 1849 | if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { |
@@ -1420,26 +1871,127 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1420 | qos |= MWL8K_QOS_ACK_POLICY_NORMAL; | 1871 | qos |= MWL8K_QOS_ACK_POLICY_NORMAL; |
1421 | } | 1872 | } |
1422 | 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 | |||
1423 | dma = pci_map_single(priv->pdev, skb->data, | 1948 | dma = pci_map_single(priv->pdev, skb->data, |
1424 | skb->len, PCI_DMA_TODEVICE); | 1949 | skb->len, PCI_DMA_TODEVICE); |
1425 | 1950 | ||
1426 | if (pci_dma_mapping_error(priv->pdev, dma)) { | 1951 | if (pci_dma_mapping_error(priv->pdev, dma)) { |
1427 | wiphy_debug(hw->wiphy, | 1952 | wiphy_debug(hw->wiphy, |
1428 | "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 | } | ||
1429 | dev_kfree_skb(skb); | 1959 | dev_kfree_skb(skb); |
1430 | return NETDEV_TX_OK; | 1960 | return; |
1431 | } | 1961 | } |
1432 | 1962 | ||
1433 | spin_lock_bh(&priv->tx_lock); | 1963 | spin_lock_bh(&priv->tx_lock); |
1434 | 1964 | ||
1435 | txq = priv->txq + index; | 1965 | txq = priv->txq + index; |
1436 | 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 | |||
1437 | BUG_ON(txq->skb[txq->tail] != NULL); | 1989 | BUG_ON(txq->skb[txq->tail] != NULL); |
1438 | txq->skb[txq->tail] = skb; | 1990 | txq->skb[txq->tail] = skb; |
1439 | 1991 | ||
1440 | tx = txq->txd + txq->tail; | 1992 | tx = txq->txd + txq->tail; |
1441 | tx->data_rate = txdatarate; | 1993 | tx->data_rate = txdatarate; |
1442 | tx->tx_priority = index; | 1994 | tx->tx_priority = txpriority; |
1443 | tx->qos_control = cpu_to_le16(qos); | 1995 | tx->qos_control = cpu_to_le16(qos); |
1444 | tx->pkt_phys_addr = cpu_to_le32(dma); | 1996 | tx->pkt_phys_addr = cpu_to_le32(dma); |
1445 | tx->pkt_len = cpu_to_le16(skb->len); | 1997 | tx->pkt_len = cpu_to_le16(skb->len); |
@@ -1448,6 +2000,11 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1448 | tx->peer_id = MWL8K_STA(tx_info->control.sta)->peer_id; | 2000 | tx->peer_id = MWL8K_STA(tx_info->control.sta)->peer_id; |
1449 | else | 2001 | else |
1450 | 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 | |||
1451 | wmb(); | 2008 | wmb(); |
1452 | tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); | 2009 | tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); |
1453 | 2010 | ||
@@ -1458,14 +2015,17 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1458 | if (txq->tail == MWL8K_TX_DESCS) | 2015 | if (txq->tail == MWL8K_TX_DESCS) |
1459 | txq->tail = 0; | 2016 | txq->tail = 0; |
1460 | 2017 | ||
1461 | if (txq->head == txq->tail) | ||
1462 | ieee80211_stop_queue(hw, index); | ||
1463 | |||
1464 | mwl8k_tx_start(priv); | 2018 | mwl8k_tx_start(priv); |
1465 | 2019 | ||
1466 | spin_unlock_bh(&priv->tx_lock); | 2020 | spin_unlock_bh(&priv->tx_lock); |
1467 | 2021 | ||
1468 | return NETDEV_TX_OK; | 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 | } | ||
1469 | } | 2029 | } |
1470 | 2030 | ||
1471 | 2031 | ||
@@ -1663,7 +2223,7 @@ struct mwl8k_cmd_get_hw_spec_sta { | |||
1663 | __u8 mcs_bitmap[16]; | 2223 | __u8 mcs_bitmap[16]; |
1664 | __le32 rx_queue_ptr; | 2224 | __le32 rx_queue_ptr; |
1665 | __le32 num_tx_queues; | 2225 | __le32 num_tx_queues; |
1666 | __le32 tx_queue_ptrs[MWL8K_TX_QUEUES]; | 2226 | __le32 tx_queue_ptrs[MWL8K_TX_WMM_QUEUES]; |
1667 | __le32 caps2; | 2227 | __le32 caps2; |
1668 | __le32 num_tx_desc_per_queue; | 2228 | __le32 num_tx_desc_per_queue; |
1669 | __le32 total_rxd; | 2229 | __le32 total_rxd; |
@@ -1769,8 +2329,8 @@ static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw) | |||
1769 | memset(cmd->perm_addr, 0xff, sizeof(cmd->perm_addr)); | 2329 | memset(cmd->perm_addr, 0xff, sizeof(cmd->perm_addr)); |
1770 | cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); | 2330 | cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); |
1771 | 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); |
1772 | cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES); | 2332 | cmd->num_tx_queues = cpu_to_le32(mwl8k_tx_queues(priv)); |
1773 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 2333 | for (i = 0; i < mwl8k_tx_queues(priv); i++) |
1774 | 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); |
1775 | 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); |
1776 | cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); | 2336 | cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); |
@@ -1811,13 +2371,18 @@ struct mwl8k_cmd_get_hw_spec_ap { | |||
1811 | __le32 wcbbase1; | 2371 | __le32 wcbbase1; |
1812 | __le32 wcbbase2; | 2372 | __le32 wcbbase2; |
1813 | __le32 wcbbase3; | 2373 | __le32 wcbbase3; |
2374 | __le32 fw_api_version; | ||
2375 | __le32 caps; | ||
2376 | __le32 num_of_ampdu_queues; | ||
2377 | __le32 wcbbase_ampdu[MWL8K_MAX_AMPDU_QUEUES]; | ||
1814 | } __packed; | 2378 | } __packed; |
1815 | 2379 | ||
1816 | 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) |
1817 | { | 2381 | { |
1818 | struct mwl8k_priv *priv = hw->priv; | 2382 | struct mwl8k_priv *priv = hw->priv; |
1819 | struct mwl8k_cmd_get_hw_spec_ap *cmd; | 2383 | struct mwl8k_cmd_get_hw_spec_ap *cmd; |
1820 | int rc; | 2384 | int rc, i; |
2385 | u32 api_version; | ||
1821 | 2386 | ||
1822 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | 2387 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); |
1823 | if (cmd == NULL) | 2388 | if (cmd == NULL) |
@@ -1834,33 +2399,48 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) | |||
1834 | if (!rc) { | 2399 | if (!rc) { |
1835 | int off; | 2400 | int off; |
1836 | 2401 | ||
2402 | api_version = le32_to_cpu(cmd->fw_api_version); | ||
2403 | if (priv->device_info->fw_api_ap != api_version) { | ||
2404 | printk(KERN_ERR "%s: Unsupported fw API version for %s." | ||
2405 | " Expected %d got %d.\n", MWL8K_NAME, | ||
2406 | priv->device_info->part_name, | ||
2407 | priv->device_info->fw_api_ap, | ||
2408 | api_version); | ||
2409 | rc = -EINVAL; | ||
2410 | goto done; | ||
2411 | } | ||
1837 | SET_IEEE80211_PERM_ADDR(hw, cmd->perm_addr); | 2412 | SET_IEEE80211_PERM_ADDR(hw, cmd->perm_addr); |
1838 | priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); | 2413 | priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); |
1839 | priv->fw_rev = le32_to_cpu(cmd->fw_rev); | 2414 | priv->fw_rev = le32_to_cpu(cmd->fw_rev); |
1840 | priv->hw_rev = cmd->hw_rev; | 2415 | priv->hw_rev = cmd->hw_rev; |
1841 | mwl8k_setup_2ghz_band(hw); | 2416 | mwl8k_set_caps(hw, le32_to_cpu(cmd->caps)); |
1842 | priv->ap_macids_supported = 0x000000ff; | 2417 | priv->ap_macids_supported = 0x000000ff; |
1843 | priv->sta_macids_supported = 0x00000000; | 2418 | priv->sta_macids_supported = 0x00000000; |
1844 | 2419 | priv->num_ampdu_queues = le32_to_cpu(cmd->num_of_ampdu_queues); | |
1845 | off = le32_to_cpu(cmd->wcbbase0) & 0xffff; | 2420 | if (priv->num_ampdu_queues > MWL8K_MAX_AMPDU_QUEUES) { |
1846 | iowrite32(priv->txq[0].txd_dma, priv->sram + off); | 2421 | wiphy_warn(hw->wiphy, "fw reported %d ampdu queues" |
1847 | 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 | } | ||
1848 | off = le32_to_cpu(cmd->rxwrptr) & 0xffff; | 2427 | off = le32_to_cpu(cmd->rxwrptr) & 0xffff; |
1849 | iowrite32(priv->rxq[0].rxd_dma, priv->sram + off); | 2428 | iowrite32(priv->rxq[0].rxd_dma, priv->sram + off); |
1850 | 2429 | ||
1851 | off = le32_to_cpu(cmd->rxrdptr) & 0xffff; | 2430 | off = le32_to_cpu(cmd->rxrdptr) & 0xffff; |
1852 | iowrite32(priv->rxq[0].rxd_dma, priv->sram + off); | 2431 | iowrite32(priv->rxq[0].rxd_dma, priv->sram + off); |
1853 | 2432 | ||
1854 | off = le32_to_cpu(cmd->wcbbase1) & 0xffff; | 2433 | priv->txq_offset[0] = le32_to_cpu(cmd->wcbbase0) & 0xffff; |
1855 | iowrite32(priv->txq[1].txd_dma, priv->sram + off); | 2434 | priv->txq_offset[1] = le32_to_cpu(cmd->wcbbase1) & 0xffff; |
1856 | 2435 | priv->txq_offset[2] = le32_to_cpu(cmd->wcbbase2) & 0xffff; | |
1857 | off = le32_to_cpu(cmd->wcbbase2) & 0xffff; | 2436 | priv->txq_offset[3] = le32_to_cpu(cmd->wcbbase3) & 0xffff; |
1858 | iowrite32(priv->txq[2].txd_dma, priv->sram + off); | ||
1859 | 2437 | ||
1860 | off = le32_to_cpu(cmd->wcbbase3) & 0xffff; | 2438 | for (i = 0; i < priv->num_ampdu_queues; i++) |
1861 | iowrite32(priv->txq[3].txd_dma, priv->sram + off); | 2439 | priv->txq_offset[i + MWL8K_TX_WMM_QUEUES] = |
2440 | le32_to_cpu(cmd->wcbbase_ampdu[i]) & 0xffff; | ||
1862 | } | 2441 | } |
1863 | 2442 | ||
2443 | done: | ||
1864 | kfree(cmd); | 2444 | kfree(cmd); |
1865 | return rc; | 2445 | return rc; |
1866 | } | 2446 | } |
@@ -1880,12 +2460,21 @@ struct mwl8k_cmd_set_hw_spec { | |||
1880 | __le32 caps; | 2460 | __le32 caps; |
1881 | __le32 rx_queue_ptr; | 2461 | __le32 rx_queue_ptr; |
1882 | __le32 num_tx_queues; | 2462 | __le32 num_tx_queues; |
1883 | __le32 tx_queue_ptrs[MWL8K_TX_QUEUES]; | 2463 | __le32 tx_queue_ptrs[MWL8K_MAX_TX_QUEUES]; |
1884 | __le32 flags; | 2464 | __le32 flags; |
1885 | __le32 num_tx_desc_per_queue; | 2465 | __le32 num_tx_desc_per_queue; |
1886 | __le32 total_rxd; | 2466 | __le32 total_rxd; |
1887 | } __packed; | 2467 | } __packed; |
1888 | 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 | ||
2477 | #define MWL8K_SET_HW_SPEC_FLAG_GENERATE_CCMP_HDR 0x00000200 | ||
1889 | #define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080 | 2478 | #define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080 |
1890 | #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP 0x00000020 | 2479 | #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP 0x00000020 |
1891 | #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON 0x00000010 | 2480 | #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON 0x00000010 |
@@ -1906,12 +2495,24 @@ static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) | |||
1906 | 2495 | ||
1907 | cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); | 2496 | cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); |
1908 | cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma); | 2497 | cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma); |
1909 | cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES); | 2498 | cmd->num_tx_queues = cpu_to_le32(mwl8k_tx_queues(priv)); |
1910 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 2499 | |
1911 | cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].txd_dma); | 2500 | /* |
2501 | * Mac80211 stack has Q0 as highest priority and Q3 as lowest in | ||
2502 | * that order. Firmware has Q3 as highest priority and Q0 as lowest | ||
2503 | * in that order. Map Q3 of mac80211 to Q0 of firmware so that the | ||
2504 | * priority is interpreted the right way in firmware. | ||
2505 | */ | ||
2506 | for (i = 0; i < mwl8k_tx_queues(priv); i++) { | ||
2507 | int j = mwl8k_tx_queues(priv) - 1 - i; | ||
2508 | cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[j].txd_dma); | ||
2509 | } | ||
2510 | |||
1912 | cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT | | 2511 | cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT | |
1913 | MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP | | 2512 | MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP | |
1914 | MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON); | 2513 | MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON | |
2514 | MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY | | ||
2515 | MWL8K_SET_HW_SPEC_FLAG_GENERATE_CCMP_HDR); | ||
1915 | cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); | 2516 | cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); |
1916 | cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); | 2517 | cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); |
1917 | 2518 | ||
@@ -2084,7 +2685,7 @@ mwl8k_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble) | |||
2084 | /* | 2685 | /* |
2085 | * CMD_RF_TX_POWER. | 2686 | * CMD_RF_TX_POWER. |
2086 | */ | 2687 | */ |
2087 | #define MWL8K_TX_POWER_LEVEL_TOTAL 8 | 2688 | #define MWL8K_RF_TX_POWER_LEVEL_TOTAL 8 |
2088 | 2689 | ||
2089 | struct mwl8k_cmd_rf_tx_power { | 2690 | struct mwl8k_cmd_rf_tx_power { |
2090 | struct mwl8k_cmd_pkt header; | 2691 | struct mwl8k_cmd_pkt header; |
@@ -2092,7 +2693,7 @@ struct mwl8k_cmd_rf_tx_power { | |||
2092 | __le16 support_level; | 2693 | __le16 support_level; |
2093 | __le16 current_level; | 2694 | __le16 current_level; |
2094 | __le16 reserved; | 2695 | __le16 reserved; |
2095 | __le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL]; | 2696 | __le16 power_level_list[MWL8K_RF_TX_POWER_LEVEL_TOTAL]; |
2096 | } __packed; | 2697 | } __packed; |
2097 | 2698 | ||
2098 | static int mwl8k_cmd_rf_tx_power(struct ieee80211_hw *hw, int dBm) | 2699 | static int mwl8k_cmd_rf_tx_power(struct ieee80211_hw *hw, int dBm) |
@@ -2116,6 +2717,65 @@ static int mwl8k_cmd_rf_tx_power(struct ieee80211_hw *hw, int dBm) | |||
2116 | } | 2717 | } |
2117 | 2718 | ||
2118 | /* | 2719 | /* |
2720 | * CMD_TX_POWER. | ||
2721 | */ | ||
2722 | #define MWL8K_TX_POWER_LEVEL_TOTAL 12 | ||
2723 | |||
2724 | struct mwl8k_cmd_tx_power { | ||
2725 | struct mwl8k_cmd_pkt header; | ||
2726 | __le16 action; | ||
2727 | __le16 band; | ||
2728 | __le16 channel; | ||
2729 | __le16 bw; | ||
2730 | __le16 sub_ch; | ||
2731 | __le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL]; | ||
2732 | } __packed; | ||
2733 | |||
2734 | static int mwl8k_cmd_tx_power(struct ieee80211_hw *hw, | ||
2735 | struct ieee80211_conf *conf, | ||
2736 | unsigned short pwr) | ||
2737 | { | ||
2738 | struct ieee80211_channel *channel = conf->channel; | ||
2739 | struct mwl8k_cmd_tx_power *cmd; | ||
2740 | int rc; | ||
2741 | int i; | ||
2742 | |||
2743 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
2744 | if (cmd == NULL) | ||
2745 | return -ENOMEM; | ||
2746 | |||
2747 | cmd->header.code = cpu_to_le16(MWL8K_CMD_TX_POWER); | ||
2748 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | ||
2749 | cmd->action = cpu_to_le16(MWL8K_CMD_SET_LIST); | ||
2750 | |||
2751 | if (channel->band == IEEE80211_BAND_2GHZ) | ||
2752 | cmd->band = cpu_to_le16(0x1); | ||
2753 | else if (channel->band == IEEE80211_BAND_5GHZ) | ||
2754 | cmd->band = cpu_to_le16(0x4); | ||
2755 | |||
2756 | cmd->channel = channel->hw_value; | ||
2757 | |||
2758 | if (conf->channel_type == NL80211_CHAN_NO_HT || | ||
2759 | conf->channel_type == NL80211_CHAN_HT20) { | ||
2760 | cmd->bw = cpu_to_le16(0x2); | ||
2761 | } else { | ||
2762 | cmd->bw = cpu_to_le16(0x4); | ||
2763 | if (conf->channel_type == NL80211_CHAN_HT40MINUS) | ||
2764 | cmd->sub_ch = cpu_to_le16(0x3); | ||
2765 | else if (conf->channel_type == NL80211_CHAN_HT40PLUS) | ||
2766 | cmd->sub_ch = cpu_to_le16(0x1); | ||
2767 | } | ||
2768 | |||
2769 | for (i = 0; i < MWL8K_TX_POWER_LEVEL_TOTAL; i++) | ||
2770 | cmd->power_level_list[i] = cpu_to_le16(pwr); | ||
2771 | |||
2772 | rc = mwl8k_post_cmd(hw, &cmd->header); | ||
2773 | kfree(cmd); | ||
2774 | |||
2775 | return rc; | ||
2776 | } | ||
2777 | |||
2778 | /* | ||
2119 | * CMD_RF_ANTENNA. | 2779 | * CMD_RF_ANTENNA. |
2120 | */ | 2780 | */ |
2121 | struct mwl8k_cmd_rf_antenna { | 2781 | struct mwl8k_cmd_rf_antenna { |
@@ -2836,6 +3496,65 @@ static int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode) | |||
2836 | } | 3496 | } |
2837 | 3497 | ||
2838 | /* | 3498 | /* |
3499 | * CMD_GET_WATCHDOG_BITMAP. | ||
3500 | */ | ||
3501 | struct mwl8k_cmd_get_watchdog_bitmap { | ||
3502 | struct mwl8k_cmd_pkt header; | ||
3503 | u8 bitmap; | ||
3504 | } __packed; | ||
3505 | |||
3506 | static int mwl8k_cmd_get_watchdog_bitmap(struct ieee80211_hw *hw, u8 *bitmap) | ||
3507 | { | ||
3508 | struct mwl8k_cmd_get_watchdog_bitmap *cmd; | ||
3509 | int rc; | ||
3510 | |||
3511 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
3512 | if (cmd == NULL) | ||
3513 | return -ENOMEM; | ||
3514 | |||
3515 | cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_WATCHDOG_BITMAP); | ||
3516 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | ||
3517 | |||
3518 | rc = mwl8k_post_cmd(hw, &cmd->header); | ||
3519 | if (!rc) | ||
3520 | *bitmap = cmd->bitmap; | ||
3521 | |||
3522 | kfree(cmd); | ||
3523 | |||
3524 | return rc; | ||
3525 | } | ||
3526 | |||
3527 | #define INVALID_BA 0xAA | ||
3528 | static void mwl8k_watchdog_ba_events(struct work_struct *work) | ||
3529 | { | ||
3530 | int rc; | ||
3531 | u8 bitmap = 0, stream_index; | ||
3532 | struct mwl8k_ampdu_stream *streams; | ||
3533 | struct mwl8k_priv *priv = | ||
3534 | container_of(work, struct mwl8k_priv, watchdog_ba_handle); | ||
3535 | |||
3536 | rc = mwl8k_cmd_get_watchdog_bitmap(priv->hw, &bitmap); | ||
3537 | if (rc) | ||
3538 | return; | ||
3539 | |||
3540 | if (bitmap == INVALID_BA) | ||
3541 | return; | ||
3542 | |||
3543 | /* the bitmap is the hw queue number. Map it to the ampdu queue. */ | ||
3544 | stream_index = bitmap - MWL8K_TX_WMM_QUEUES; | ||
3545 | |||
3546 | BUG_ON(stream_index >= priv->num_ampdu_queues); | ||
3547 | |||
3548 | streams = &priv->ampdu[stream_index]; | ||
3549 | |||
3550 | if (streams->state == AMPDU_STREAM_ACTIVE) | ||
3551 | ieee80211_stop_tx_ba_session(streams->sta, streams->tid); | ||
3552 | |||
3553 | return; | ||
3554 | } | ||
3555 | |||
3556 | |||
3557 | /* | ||
2839 | * CMD_BSS_START. | 3558 | * CMD_BSS_START. |
2840 | */ | 3559 | */ |
2841 | struct mwl8k_cmd_bss_start { | 3560 | struct mwl8k_cmd_bss_start { |
@@ -2864,6 +3583,152 @@ static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw, | |||
2864 | } | 3583 | } |
2865 | 3584 | ||
2866 | /* | 3585 | /* |
3586 | * CMD_BASTREAM. | ||
3587 | */ | ||
3588 | |||
3589 | /* | ||
3590 | * UPSTREAM is tx direction | ||
3591 | */ | ||
3592 | #define BASTREAM_FLAG_DIRECTION_UPSTREAM 0x00 | ||
3593 | #define BASTREAM_FLAG_IMMEDIATE_TYPE 0x01 | ||
3594 | |||
3595 | enum ba_stream_action_type { | ||
3596 | MWL8K_BA_CREATE, | ||
3597 | MWL8K_BA_UPDATE, | ||
3598 | MWL8K_BA_DESTROY, | ||
3599 | MWL8K_BA_FLUSH, | ||
3600 | MWL8K_BA_CHECK, | ||
3601 | }; | ||
3602 | |||
3603 | |||
3604 | struct mwl8k_create_ba_stream { | ||
3605 | __le32 flags; | ||
3606 | __le32 idle_thrs; | ||
3607 | __le32 bar_thrs; | ||
3608 | __le32 window_size; | ||
3609 | u8 peer_mac_addr[6]; | ||
3610 | u8 dialog_token; | ||
3611 | u8 tid; | ||
3612 | u8 queue_id; | ||
3613 | u8 param_info; | ||
3614 | __le32 ba_context; | ||
3615 | u8 reset_seq_no_flag; | ||
3616 | __le16 curr_seq_no; | ||
3617 | u8 sta_src_mac_addr[6]; | ||
3618 | } __packed; | ||
3619 | |||
3620 | struct mwl8k_destroy_ba_stream { | ||
3621 | __le32 flags; | ||
3622 | __le32 ba_context; | ||
3623 | } __packed; | ||
3624 | |||
3625 | struct mwl8k_cmd_bastream { | ||
3626 | struct mwl8k_cmd_pkt header; | ||
3627 | __le32 action; | ||
3628 | union { | ||
3629 | struct mwl8k_create_ba_stream create_params; | ||
3630 | struct mwl8k_destroy_ba_stream destroy_params; | ||
3631 | }; | ||
3632 | } __packed; | ||
3633 | |||
3634 | static int | ||
3635 | mwl8k_check_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream) | ||
3636 | { | ||
3637 | struct mwl8k_cmd_bastream *cmd; | ||
3638 | int rc; | ||
3639 | |||
3640 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
3641 | if (cmd == NULL) | ||
3642 | return -ENOMEM; | ||
3643 | |||
3644 | cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM); | ||
3645 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | ||
3646 | |||
3647 | cmd->action = cpu_to_le32(MWL8K_BA_CHECK); | ||
3648 | |||
3649 | cmd->create_params.queue_id = stream->idx; | ||
3650 | memcpy(&cmd->create_params.peer_mac_addr[0], stream->sta->addr, | ||
3651 | ETH_ALEN); | ||
3652 | cmd->create_params.tid = stream->tid; | ||
3653 | |||
3654 | cmd->create_params.flags = | ||
3655 | cpu_to_le32(BASTREAM_FLAG_IMMEDIATE_TYPE) | | ||
3656 | cpu_to_le32(BASTREAM_FLAG_DIRECTION_UPSTREAM); | ||
3657 | |||
3658 | rc = mwl8k_post_cmd(hw, &cmd->header); | ||
3659 | |||
3660 | kfree(cmd); | ||
3661 | |||
3662 | return rc; | ||
3663 | } | ||
3664 | |||
3665 | static int | ||
3666 | mwl8k_create_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream, | ||
3667 | u8 buf_size) | ||
3668 | { | ||
3669 | struct mwl8k_cmd_bastream *cmd; | ||
3670 | int rc; | ||
3671 | |||
3672 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
3673 | if (cmd == NULL) | ||
3674 | return -ENOMEM; | ||
3675 | |||
3676 | |||
3677 | cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM); | ||
3678 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | ||
3679 | |||
3680 | cmd->action = cpu_to_le32(MWL8K_BA_CREATE); | ||
3681 | |||
3682 | cmd->create_params.bar_thrs = cpu_to_le32((u32)buf_size); | ||
3683 | cmd->create_params.window_size = cpu_to_le32((u32)buf_size); | ||
3684 | cmd->create_params.queue_id = stream->idx; | ||
3685 | |||
3686 | memcpy(cmd->create_params.peer_mac_addr, stream->sta->addr, ETH_ALEN); | ||
3687 | cmd->create_params.tid = stream->tid; | ||
3688 | cmd->create_params.curr_seq_no = cpu_to_le16(0); | ||
3689 | cmd->create_params.reset_seq_no_flag = 1; | ||
3690 | |||
3691 | cmd->create_params.param_info = | ||
3692 | (stream->sta->ht_cap.ampdu_factor & | ||
3693 | IEEE80211_HT_AMPDU_PARM_FACTOR) | | ||
3694 | ((stream->sta->ht_cap.ampdu_density << 2) & | ||
3695 | IEEE80211_HT_AMPDU_PARM_DENSITY); | ||
3696 | |||
3697 | cmd->create_params.flags = | ||
3698 | cpu_to_le32(BASTREAM_FLAG_IMMEDIATE_TYPE | | ||
3699 | BASTREAM_FLAG_DIRECTION_UPSTREAM); | ||
3700 | |||
3701 | rc = mwl8k_post_cmd(hw, &cmd->header); | ||
3702 | |||
3703 | wiphy_debug(hw->wiphy, "Created a BA stream for %pM : tid %d\n", | ||
3704 | stream->sta->addr, stream->tid); | ||
3705 | kfree(cmd); | ||
3706 | |||
3707 | return rc; | ||
3708 | } | ||
3709 | |||
3710 | static void mwl8k_destroy_ba(struct ieee80211_hw *hw, | ||
3711 | struct mwl8k_ampdu_stream *stream) | ||
3712 | { | ||
3713 | struct mwl8k_cmd_bastream *cmd; | ||
3714 | |||
3715 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
3716 | if (cmd == NULL) | ||
3717 | return; | ||
3718 | |||
3719 | cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM); | ||
3720 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | ||
3721 | cmd->action = cpu_to_le32(MWL8K_BA_DESTROY); | ||
3722 | |||
3723 | cmd->destroy_params.ba_context = cpu_to_le32(stream->idx); | ||
3724 | mwl8k_post_cmd(hw, &cmd->header); | ||
3725 | |||
3726 | wiphy_debug(hw->wiphy, "Deleted BA stream index %d\n", stream->idx); | ||
3727 | |||
3728 | kfree(cmd); | ||
3729 | } | ||
3730 | |||
3731 | /* | ||
2867 | * CMD_SET_NEW_STN. | 3732 | * CMD_SET_NEW_STN. |
2868 | */ | 3733 | */ |
2869 | struct mwl8k_cmd_set_new_stn { | 3734 | struct mwl8k_cmd_set_new_stn { |
@@ -2973,6 +3838,273 @@ static int mwl8k_cmd_set_new_stn_del(struct ieee80211_hw *hw, | |||
2973 | } | 3838 | } |
2974 | 3839 | ||
2975 | /* | 3840 | /* |
3841 | * CMD_UPDATE_ENCRYPTION. | ||
3842 | */ | ||
3843 | |||
3844 | #define MAX_ENCR_KEY_LENGTH 16 | ||
3845 | #define MIC_KEY_LENGTH 8 | ||
3846 | |||
3847 | struct mwl8k_cmd_update_encryption { | ||
3848 | struct mwl8k_cmd_pkt header; | ||
3849 | |||
3850 | __le32 action; | ||
3851 | __le32 reserved; | ||
3852 | __u8 mac_addr[6]; | ||
3853 | __u8 encr_type; | ||
3854 | |||
3855 | } __packed; | ||
3856 | |||
3857 | struct mwl8k_cmd_set_key { | ||
3858 | struct mwl8k_cmd_pkt header; | ||
3859 | |||
3860 | __le32 action; | ||
3861 | __le32 reserved; | ||
3862 | __le16 length; | ||
3863 | __le16 key_type_id; | ||
3864 | __le32 key_info; | ||
3865 | __le32 key_id; | ||
3866 | __le16 key_len; | ||
3867 | __u8 key_material[MAX_ENCR_KEY_LENGTH]; | ||
3868 | __u8 tkip_tx_mic_key[MIC_KEY_LENGTH]; | ||
3869 | __u8 tkip_rx_mic_key[MIC_KEY_LENGTH]; | ||
3870 | __le16 tkip_rsc_low; | ||
3871 | __le32 tkip_rsc_high; | ||
3872 | __le16 tkip_tsc_low; | ||
3873 | __le32 tkip_tsc_high; | ||
3874 | __u8 mac_addr[6]; | ||
3875 | } __packed; | ||
3876 | |||
3877 | enum { | ||
3878 | MWL8K_ENCR_ENABLE, | ||
3879 | MWL8K_ENCR_SET_KEY, | ||
3880 | MWL8K_ENCR_REMOVE_KEY, | ||
3881 | MWL8K_ENCR_SET_GROUP_KEY, | ||
3882 | }; | ||
3883 | |||
3884 | #define MWL8K_UPDATE_ENCRYPTION_TYPE_WEP 0 | ||
3885 | #define MWL8K_UPDATE_ENCRYPTION_TYPE_DISABLE 1 | ||
3886 | #define MWL8K_UPDATE_ENCRYPTION_TYPE_TKIP 4 | ||
3887 | #define MWL8K_UPDATE_ENCRYPTION_TYPE_MIXED 7 | ||
3888 | #define MWL8K_UPDATE_ENCRYPTION_TYPE_AES 8 | ||
3889 | |||
3890 | enum { | ||
3891 | MWL8K_ALG_WEP, | ||
3892 | MWL8K_ALG_TKIP, | ||
3893 | MWL8K_ALG_CCMP, | ||
3894 | }; | ||
3895 | |||
3896 | #define MWL8K_KEY_FLAG_TXGROUPKEY 0x00000004 | ||
3897 | #define MWL8K_KEY_FLAG_PAIRWISE 0x00000008 | ||
3898 | #define MWL8K_KEY_FLAG_TSC_VALID 0x00000040 | ||
3899 | #define MWL8K_KEY_FLAG_WEP_TXKEY 0x01000000 | ||
3900 | #define MWL8K_KEY_FLAG_MICKEY_VALID 0x02000000 | ||
3901 | |||
3902 | static int mwl8k_cmd_update_encryption_enable(struct ieee80211_hw *hw, | ||
3903 | struct ieee80211_vif *vif, | ||
3904 | u8 *addr, | ||
3905 | u8 encr_type) | ||
3906 | { | ||
3907 | struct mwl8k_cmd_update_encryption *cmd; | ||
3908 | int rc; | ||
3909 | |||
3910 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
3911 | if (cmd == NULL) | ||
3912 | return -ENOMEM; | ||
3913 | |||
3914 | cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_ENCRYPTION); | ||
3915 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | ||
3916 | cmd->action = cpu_to_le32(MWL8K_ENCR_ENABLE); | ||
3917 | memcpy(cmd->mac_addr, addr, ETH_ALEN); | ||
3918 | cmd->encr_type = encr_type; | ||
3919 | |||
3920 | rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); | ||
3921 | kfree(cmd); | ||
3922 | |||
3923 | return rc; | ||
3924 | } | ||
3925 | |||
3926 | static int mwl8k_encryption_set_cmd_info(struct mwl8k_cmd_set_key *cmd, | ||
3927 | u8 *addr, | ||
3928 | struct ieee80211_key_conf *key) | ||
3929 | { | ||
3930 | cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_ENCRYPTION); | ||
3931 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | ||
3932 | cmd->length = cpu_to_le16(sizeof(*cmd) - | ||
3933 | offsetof(struct mwl8k_cmd_set_key, length)); | ||
3934 | cmd->key_id = cpu_to_le32(key->keyidx); | ||
3935 | cmd->key_len = cpu_to_le16(key->keylen); | ||
3936 | memcpy(cmd->mac_addr, addr, ETH_ALEN); | ||
3937 | |||
3938 | switch (key->cipher) { | ||
3939 | case WLAN_CIPHER_SUITE_WEP40: | ||
3940 | case WLAN_CIPHER_SUITE_WEP104: | ||
3941 | cmd->key_type_id = cpu_to_le16(MWL8K_ALG_WEP); | ||
3942 | if (key->keyidx == 0) | ||
3943 | cmd->key_info = cpu_to_le32(MWL8K_KEY_FLAG_WEP_TXKEY); | ||
3944 | |||
3945 | break; | ||
3946 | case WLAN_CIPHER_SUITE_TKIP: | ||
3947 | cmd->key_type_id = cpu_to_le16(MWL8K_ALG_TKIP); | ||
3948 | cmd->key_info = (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) | ||
3949 | ? cpu_to_le32(MWL8K_KEY_FLAG_PAIRWISE) | ||
3950 | : cpu_to_le32(MWL8K_KEY_FLAG_TXGROUPKEY); | ||
3951 | cmd->key_info |= cpu_to_le32(MWL8K_KEY_FLAG_MICKEY_VALID | ||
3952 | | MWL8K_KEY_FLAG_TSC_VALID); | ||
3953 | break; | ||
3954 | case WLAN_CIPHER_SUITE_CCMP: | ||
3955 | cmd->key_type_id = cpu_to_le16(MWL8K_ALG_CCMP); | ||
3956 | cmd->key_info = (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) | ||
3957 | ? cpu_to_le32(MWL8K_KEY_FLAG_PAIRWISE) | ||
3958 | : cpu_to_le32(MWL8K_KEY_FLAG_TXGROUPKEY); | ||
3959 | break; | ||
3960 | default: | ||
3961 | return -ENOTSUPP; | ||
3962 | } | ||
3963 | |||
3964 | return 0; | ||
3965 | } | ||
3966 | |||
3967 | static int mwl8k_cmd_encryption_set_key(struct ieee80211_hw *hw, | ||
3968 | struct ieee80211_vif *vif, | ||
3969 | u8 *addr, | ||
3970 | struct ieee80211_key_conf *key) | ||
3971 | { | ||
3972 | struct mwl8k_cmd_set_key *cmd; | ||
3973 | int rc; | ||
3974 | int keymlen; | ||
3975 | u32 action; | ||
3976 | u8 idx; | ||
3977 | struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); | ||
3978 | |||
3979 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
3980 | if (cmd == NULL) | ||
3981 | return -ENOMEM; | ||
3982 | |||
3983 | rc = mwl8k_encryption_set_cmd_info(cmd, addr, key); | ||
3984 | if (rc < 0) | ||
3985 | goto done; | ||
3986 | |||
3987 | idx = key->keyidx; | ||
3988 | |||
3989 | if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) | ||
3990 | action = MWL8K_ENCR_SET_KEY; | ||
3991 | else | ||
3992 | action = MWL8K_ENCR_SET_GROUP_KEY; | ||
3993 | |||
3994 | switch (key->cipher) { | ||
3995 | case WLAN_CIPHER_SUITE_WEP40: | ||
3996 | case WLAN_CIPHER_SUITE_WEP104: | ||
3997 | if (!mwl8k_vif->wep_key_conf[idx].enabled) { | ||
3998 | memcpy(mwl8k_vif->wep_key_conf[idx].key, key, | ||
3999 | sizeof(*key) + key->keylen); | ||
4000 | mwl8k_vif->wep_key_conf[idx].enabled = 1; | ||
4001 | } | ||
4002 | |||
4003 | keymlen = key->keylen; | ||
4004 | action = MWL8K_ENCR_SET_KEY; | ||
4005 | break; | ||
4006 | case WLAN_CIPHER_SUITE_TKIP: | ||
4007 | keymlen = MAX_ENCR_KEY_LENGTH + 2 * MIC_KEY_LENGTH; | ||
4008 | break; | ||
4009 | case WLAN_CIPHER_SUITE_CCMP: | ||
4010 | keymlen = key->keylen; | ||
4011 | break; | ||
4012 | default: | ||
4013 | rc = -ENOTSUPP; | ||
4014 | goto done; | ||
4015 | } | ||
4016 | |||
4017 | memcpy(cmd->key_material, key->key, keymlen); | ||
4018 | cmd->action = cpu_to_le32(action); | ||
4019 | |||
4020 | rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); | ||
4021 | done: | ||
4022 | kfree(cmd); | ||
4023 | |||
4024 | return rc; | ||
4025 | } | ||
4026 | |||
4027 | static int mwl8k_cmd_encryption_remove_key(struct ieee80211_hw *hw, | ||
4028 | struct ieee80211_vif *vif, | ||
4029 | u8 *addr, | ||
4030 | struct ieee80211_key_conf *key) | ||
4031 | { | ||
4032 | struct mwl8k_cmd_set_key *cmd; | ||
4033 | int rc; | ||
4034 | struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); | ||
4035 | |||
4036 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
4037 | if (cmd == NULL) | ||
4038 | return -ENOMEM; | ||
4039 | |||
4040 | rc = mwl8k_encryption_set_cmd_info(cmd, addr, key); | ||
4041 | if (rc < 0) | ||
4042 | goto done; | ||
4043 | |||
4044 | if (key->cipher == WLAN_CIPHER_SUITE_WEP40 || | ||
4045 | WLAN_CIPHER_SUITE_WEP104) | ||
4046 | mwl8k_vif->wep_key_conf[key->keyidx].enabled = 0; | ||
4047 | |||
4048 | cmd->action = cpu_to_le32(MWL8K_ENCR_REMOVE_KEY); | ||
4049 | |||
4050 | rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); | ||
4051 | done: | ||
4052 | kfree(cmd); | ||
4053 | |||
4054 | return rc; | ||
4055 | } | ||
4056 | |||
4057 | static int mwl8k_set_key(struct ieee80211_hw *hw, | ||
4058 | enum set_key_cmd cmd_param, | ||
4059 | struct ieee80211_vif *vif, | ||
4060 | struct ieee80211_sta *sta, | ||
4061 | struct ieee80211_key_conf *key) | ||
4062 | { | ||
4063 | int rc = 0; | ||
4064 | u8 encr_type; | ||
4065 | u8 *addr; | ||
4066 | struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); | ||
4067 | |||
4068 | if (vif->type == NL80211_IFTYPE_STATION) | ||
4069 | return -EOPNOTSUPP; | ||
4070 | |||
4071 | if (sta == NULL) | ||
4072 | addr = hw->wiphy->perm_addr; | ||
4073 | else | ||
4074 | addr = sta->addr; | ||
4075 | |||
4076 | if (cmd_param == SET_KEY) { | ||
4077 | rc = mwl8k_cmd_encryption_set_key(hw, vif, addr, key); | ||
4078 | if (rc) | ||
4079 | goto out; | ||
4080 | |||
4081 | if ((key->cipher == WLAN_CIPHER_SUITE_WEP40) | ||
4082 | || (key->cipher == WLAN_CIPHER_SUITE_WEP104)) | ||
4083 | encr_type = MWL8K_UPDATE_ENCRYPTION_TYPE_WEP; | ||
4084 | else | ||
4085 | encr_type = MWL8K_UPDATE_ENCRYPTION_TYPE_MIXED; | ||
4086 | |||
4087 | rc = mwl8k_cmd_update_encryption_enable(hw, vif, addr, | ||
4088 | encr_type); | ||
4089 | if (rc) | ||
4090 | goto out; | ||
4091 | |||
4092 | mwl8k_vif->is_hw_crypto_enabled = true; | ||
4093 | |||
4094 | } else { | ||
4095 | rc = mwl8k_cmd_encryption_remove_key(hw, vif, addr, key); | ||
4096 | |||
4097 | if (rc) | ||
4098 | goto out; | ||
4099 | |||
4100 | mwl8k_vif->is_hw_crypto_enabled = false; | ||
4101 | |||
4102 | } | ||
4103 | out: | ||
4104 | return rc; | ||
4105 | } | ||
4106 | |||
4107 | /* | ||
2976 | * CMD_UPDATE_STADB. | 4108 | * CMD_UPDATE_STADB. |
2977 | */ | 4109 | */ |
2978 | struct ewc_ht_info { | 4110 | struct ewc_ht_info { |
@@ -3116,6 +4248,11 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id) | |||
3116 | tasklet_schedule(&priv->poll_rx_task); | 4248 | tasklet_schedule(&priv->poll_rx_task); |
3117 | } | 4249 | } |
3118 | 4250 | ||
4251 | if (status & MWL8K_A2H_INT_BA_WATCHDOG) { | ||
4252 | status &= ~MWL8K_A2H_INT_BA_WATCHDOG; | ||
4253 | ieee80211_queue_work(hw, &priv->watchdog_ba_handle); | ||
4254 | } | ||
4255 | |||
3119 | if (status) | 4256 | if (status) |
3120 | iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); | 4257 | iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); |
3121 | 4258 | ||
@@ -3144,7 +4281,7 @@ static void mwl8k_tx_poll(unsigned long data) | |||
3144 | 4281 | ||
3145 | spin_lock_bh(&priv->tx_lock); | 4282 | spin_lock_bh(&priv->tx_lock); |
3146 | 4283 | ||
3147 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 4284 | for (i = 0; i < mwl8k_tx_queues(priv); i++) |
3148 | limit -= mwl8k_txq_reclaim(hw, i, limit, 0); | 4285 | limit -= mwl8k_txq_reclaim(hw, i, limit, 0); |
3149 | 4286 | ||
3150 | if (!priv->pending_tx_pkts && priv->tx_wait != NULL) { | 4287 | if (!priv->pending_tx_pkts && priv->tx_wait != NULL) { |
@@ -3184,22 +4321,19 @@ static void mwl8k_rx_poll(unsigned long data) | |||
3184 | /* | 4321 | /* |
3185 | * Core driver operations. | 4322 | * Core driver operations. |
3186 | */ | 4323 | */ |
3187 | static int mwl8k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | 4324 | static void mwl8k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) |
3188 | { | 4325 | { |
3189 | struct mwl8k_priv *priv = hw->priv; | 4326 | struct mwl8k_priv *priv = hw->priv; |
3190 | int index = skb_get_queue_mapping(skb); | 4327 | int index = skb_get_queue_mapping(skb); |
3191 | int rc; | ||
3192 | 4328 | ||
3193 | if (!priv->radio_on) { | 4329 | if (!priv->radio_on) { |
3194 | wiphy_debug(hw->wiphy, | 4330 | wiphy_debug(hw->wiphy, |
3195 | "dropped TX frame since radio disabled\n"); | 4331 | "dropped TX frame since radio disabled\n"); |
3196 | dev_kfree_skb(skb); | 4332 | dev_kfree_skb(skb); |
3197 | return NETDEV_TX_OK; | 4333 | return; |
3198 | } | 4334 | } |
3199 | 4335 | ||
3200 | rc = mwl8k_txq_xmit(hw, index, skb); | 4336 | mwl8k_txq_xmit(hw, index, skb); |
3201 | |||
3202 | return rc; | ||
3203 | } | 4337 | } |
3204 | 4338 | ||
3205 | static int mwl8k_start(struct ieee80211_hw *hw) | 4339 | static int mwl8k_start(struct ieee80211_hw *hw) |
@@ -3210,9 +4344,11 @@ static int mwl8k_start(struct ieee80211_hw *hw) | |||
3210 | rc = request_irq(priv->pdev->irq, mwl8k_interrupt, | 4344 | rc = request_irq(priv->pdev->irq, mwl8k_interrupt, |
3211 | IRQF_SHARED, MWL8K_NAME, hw); | 4345 | IRQF_SHARED, MWL8K_NAME, hw); |
3212 | if (rc) { | 4346 | if (rc) { |
4347 | priv->irq = -1; | ||
3213 | wiphy_err(hw->wiphy, "failed to register IRQ handler\n"); | 4348 | wiphy_err(hw->wiphy, "failed to register IRQ handler\n"); |
3214 | return -EIO; | 4349 | return -EIO; |
3215 | } | 4350 | } |
4351 | priv->irq = priv->pdev->irq; | ||
3216 | 4352 | ||
3217 | /* Enable TX reclaim and RX tasklets. */ | 4353 | /* Enable TX reclaim and RX tasklets. */ |
3218 | tasklet_enable(&priv->poll_tx_task); | 4354 | tasklet_enable(&priv->poll_tx_task); |
@@ -3220,6 +4356,8 @@ static int mwl8k_start(struct ieee80211_hw *hw) | |||
3220 | 4356 | ||
3221 | /* Enable interrupts */ | 4357 | /* Enable interrupts */ |
3222 | iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); | 4358 | iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); |
4359 | iowrite32(MWL8K_A2H_EVENTS, | ||
4360 | priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); | ||
3223 | 4361 | ||
3224 | rc = mwl8k_fw_lock(hw); | 4362 | rc = mwl8k_fw_lock(hw); |
3225 | if (!rc) { | 4363 | if (!rc) { |
@@ -3249,6 +4387,7 @@ static int mwl8k_start(struct ieee80211_hw *hw) | |||
3249 | if (rc) { | 4387 | if (rc) { |
3250 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); | 4388 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); |
3251 | free_irq(priv->pdev->irq, hw); | 4389 | free_irq(priv->pdev->irq, hw); |
4390 | priv->irq = -1; | ||
3252 | tasklet_disable(&priv->poll_tx_task); | 4391 | tasklet_disable(&priv->poll_tx_task); |
3253 | tasklet_disable(&priv->poll_rx_task); | 4392 | tasklet_disable(&priv->poll_rx_task); |
3254 | } | 4393 | } |
@@ -3267,10 +4406,14 @@ static void mwl8k_stop(struct ieee80211_hw *hw) | |||
3267 | 4406 | ||
3268 | /* Disable interrupts */ | 4407 | /* Disable interrupts */ |
3269 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); | 4408 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); |
3270 | free_irq(priv->pdev->irq, hw); | 4409 | if (priv->irq != -1) { |
4410 | free_irq(priv->pdev->irq, hw); | ||
4411 | priv->irq = -1; | ||
4412 | } | ||
3271 | 4413 | ||
3272 | /* Stop finalize join worker */ | 4414 | /* Stop finalize join worker */ |
3273 | cancel_work_sync(&priv->finalize_join_worker); | 4415 | cancel_work_sync(&priv->finalize_join_worker); |
4416 | cancel_work_sync(&priv->watchdog_ba_handle); | ||
3274 | if (priv->beacon_skb != NULL) | 4417 | if (priv->beacon_skb != NULL) |
3275 | dev_kfree_skb(priv->beacon_skb); | 4418 | dev_kfree_skb(priv->beacon_skb); |
3276 | 4419 | ||
@@ -3279,17 +4422,20 @@ static void mwl8k_stop(struct ieee80211_hw *hw) | |||
3279 | tasklet_disable(&priv->poll_rx_task); | 4422 | tasklet_disable(&priv->poll_rx_task); |
3280 | 4423 | ||
3281 | /* Return all skbs to mac80211 */ | 4424 | /* Return all skbs to mac80211 */ |
3282 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 4425 | for (i = 0; i < mwl8k_tx_queues(priv); i++) |
3283 | mwl8k_txq_reclaim(hw, i, INT_MAX, 1); | 4426 | mwl8k_txq_reclaim(hw, i, INT_MAX, 1); |
3284 | } | 4427 | } |
3285 | 4428 | ||
4429 | static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image); | ||
4430 | |||
3286 | static int mwl8k_add_interface(struct ieee80211_hw *hw, | 4431 | static int mwl8k_add_interface(struct ieee80211_hw *hw, |
3287 | struct ieee80211_vif *vif) | 4432 | struct ieee80211_vif *vif) |
3288 | { | 4433 | { |
3289 | struct mwl8k_priv *priv = hw->priv; | 4434 | struct mwl8k_priv *priv = hw->priv; |
3290 | struct mwl8k_vif *mwl8k_vif; | 4435 | struct mwl8k_vif *mwl8k_vif; |
3291 | u32 macids_supported; | 4436 | u32 macids_supported; |
3292 | int macid; | 4437 | int macid, rc; |
4438 | struct mwl8k_device_info *di; | ||
3293 | 4439 | ||
3294 | /* | 4440 | /* |
3295 | * Reject interface creation if sniffer mode is active, as | 4441 | * Reject interface creation if sniffer mode is active, as |
@@ -3302,12 +4448,28 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, | |||
3302 | return -EINVAL; | 4448 | return -EINVAL; |
3303 | } | 4449 | } |
3304 | 4450 | ||
3305 | 4451 | di = priv->device_info; | |
3306 | switch (vif->type) { | 4452 | switch (vif->type) { |
3307 | case NL80211_IFTYPE_AP: | 4453 | case NL80211_IFTYPE_AP: |
4454 | if (!priv->ap_fw && di->fw_image_ap) { | ||
4455 | /* we must load the ap fw to meet this request */ | ||
4456 | if (!list_empty(&priv->vif_list)) | ||
4457 | return -EBUSY; | ||
4458 | rc = mwl8k_reload_firmware(hw, di->fw_image_ap); | ||
4459 | if (rc) | ||
4460 | return rc; | ||
4461 | } | ||
3308 | macids_supported = priv->ap_macids_supported; | 4462 | macids_supported = priv->ap_macids_supported; |
3309 | break; | 4463 | break; |
3310 | case NL80211_IFTYPE_STATION: | 4464 | case NL80211_IFTYPE_STATION: |
4465 | if (priv->ap_fw && di->fw_image_sta) { | ||
4466 | /* we must load the sta fw to meet this request */ | ||
4467 | if (!list_empty(&priv->vif_list)) | ||
4468 | return -EBUSY; | ||
4469 | rc = mwl8k_reload_firmware(hw, di->fw_image_sta); | ||
4470 | if (rc) | ||
4471 | return rc; | ||
4472 | } | ||
3311 | macids_supported = priv->sta_macids_supported; | 4473 | macids_supported = priv->sta_macids_supported; |
3312 | break; | 4474 | break; |
3313 | default: | 4475 | default: |
@@ -3324,6 +4486,8 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, | |||
3324 | mwl8k_vif->vif = vif; | 4486 | mwl8k_vif->vif = vif; |
3325 | mwl8k_vif->macid = macid; | 4487 | mwl8k_vif->macid = macid; |
3326 | mwl8k_vif->seqno = 0; | 4488 | mwl8k_vif->seqno = 0; |
4489 | memcpy(mwl8k_vif->bssid, vif->addr, ETH_ALEN); | ||
4490 | mwl8k_vif->is_hw_crypto_enabled = false; | ||
3327 | 4491 | ||
3328 | /* Set the mac address. */ | 4492 | /* Set the mac address. */ |
3329 | mwl8k_cmd_set_mac_addr(hw, vif, vif->addr); | 4493 | mwl8k_cmd_set_mac_addr(hw, vif, vif->addr); |
@@ -3377,15 +4541,26 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) | |||
3377 | 4541 | ||
3378 | if (conf->power_level > 18) | 4542 | if (conf->power_level > 18) |
3379 | conf->power_level = 18; | 4543 | conf->power_level = 18; |
3380 | rc = mwl8k_cmd_rf_tx_power(hw, conf->power_level); | ||
3381 | if (rc) | ||
3382 | goto out; | ||
3383 | 4544 | ||
3384 | if (priv->ap_fw) { | 4545 | if (priv->ap_fw) { |
3385 | rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_RX, 0x7); | 4546 | |
3386 | if (!rc) | 4547 | if (conf->flags & IEEE80211_CONF_CHANGE_POWER) { |
3387 | rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_TX, 0x7); | 4548 | rc = mwl8k_cmd_tx_power(hw, conf, conf->power_level); |
4549 | if (rc) | ||
4550 | goto out; | ||
4551 | } | ||
4552 | |||
4553 | rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_RX, 0x3); | ||
4554 | if (rc) | ||
4555 | wiphy_warn(hw->wiphy, "failed to set # of RX antennas"); | ||
4556 | rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_TX, 0x7); | ||
4557 | if (rc) | ||
4558 | wiphy_warn(hw->wiphy, "failed to set # of TX antennas"); | ||
4559 | |||
3388 | } else { | 4560 | } else { |
4561 | rc = mwl8k_cmd_rf_tx_power(hw, conf->power_level); | ||
4562 | if (rc) | ||
4563 | goto out; | ||
3389 | rc = mwl8k_cmd_mimo_config(hw, 0x7, 0x7); | 4564 | rc = mwl8k_cmd_mimo_config(hw, 0x7, 0x7); |
3390 | } | 4565 | } |
3391 | 4566 | ||
@@ -3400,7 +4575,7 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
3400 | struct ieee80211_bss_conf *info, u32 changed) | 4575 | struct ieee80211_bss_conf *info, u32 changed) |
3401 | { | 4576 | { |
3402 | struct mwl8k_priv *priv = hw->priv; | 4577 | struct mwl8k_priv *priv = hw->priv; |
3403 | u32 ap_legacy_rates; | 4578 | u32 ap_legacy_rates = 0; |
3404 | u8 ap_mcs_rates[16]; | 4579 | u8 ap_mcs_rates[16]; |
3405 | int rc; | 4580 | int rc; |
3406 | 4581 | ||
@@ -3717,18 +4892,29 @@ static int mwl8k_sta_add(struct ieee80211_hw *hw, | |||
3717 | { | 4892 | { |
3718 | struct mwl8k_priv *priv = hw->priv; | 4893 | struct mwl8k_priv *priv = hw->priv; |
3719 | int ret; | 4894 | int ret; |
4895 | int i; | ||
4896 | struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); | ||
4897 | struct ieee80211_key_conf *key; | ||
3720 | 4898 | ||
3721 | if (!priv->ap_fw) { | 4899 | if (!priv->ap_fw) { |
3722 | ret = mwl8k_cmd_update_stadb_add(hw, vif, sta); | 4900 | ret = mwl8k_cmd_update_stadb_add(hw, vif, sta); |
3723 | if (ret >= 0) { | 4901 | if (ret >= 0) { |
3724 | MWL8K_STA(sta)->peer_id = ret; | 4902 | MWL8K_STA(sta)->peer_id = ret; |
3725 | return 0; | 4903 | if (sta->ht_cap.ht_supported) |
4904 | MWL8K_STA(sta)->is_ampdu_allowed = true; | ||
4905 | ret = 0; | ||
3726 | } | 4906 | } |
3727 | 4907 | ||
3728 | return ret; | 4908 | } else { |
4909 | ret = mwl8k_cmd_set_new_stn_add(hw, vif, sta); | ||
3729 | } | 4910 | } |
3730 | 4911 | ||
3731 | return mwl8k_cmd_set_new_stn_add(hw, vif, sta); | 4912 | for (i = 0; i < NUM_WEP_KEYS; i++) { |
4913 | key = IEEE80211_KEY_CONF(mwl8k_vif->wep_key_conf[i].key); | ||
4914 | if (mwl8k_vif->wep_key_conf[i].enabled) | ||
4915 | mwl8k_set_key(hw, SET_KEY, vif, sta, key); | ||
4916 | } | ||
4917 | return ret; | ||
3732 | } | 4918 | } |
3733 | 4919 | ||
3734 | static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, | 4920 | static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, |
@@ -3739,15 +4925,20 @@ static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, | |||
3739 | 4925 | ||
3740 | rc = mwl8k_fw_lock(hw); | 4926 | rc = mwl8k_fw_lock(hw); |
3741 | if (!rc) { | 4927 | if (!rc) { |
4928 | BUG_ON(queue > MWL8K_TX_WMM_QUEUES - 1); | ||
4929 | memcpy(&priv->wmm_params[queue], params, sizeof(*params)); | ||
4930 | |||
3742 | if (!priv->wmm_enabled) | 4931 | if (!priv->wmm_enabled) |
3743 | rc = mwl8k_cmd_set_wmm_mode(hw, 1); | 4932 | rc = mwl8k_cmd_set_wmm_mode(hw, 1); |
3744 | 4933 | ||
3745 | if (!rc) | 4934 | if (!rc) { |
3746 | rc = mwl8k_cmd_set_edca_params(hw, queue, | 4935 | int q = MWL8K_TX_WMM_QUEUES - 1 - queue; |
4936 | rc = mwl8k_cmd_set_edca_params(hw, q, | ||
3747 | params->cw_min, | 4937 | params->cw_min, |
3748 | params->cw_max, | 4938 | params->cw_max, |
3749 | params->aifs, | 4939 | params->aifs, |
3750 | params->txop); | 4940 | params->txop); |
4941 | } | ||
3751 | 4942 | ||
3752 | mwl8k_fw_unlock(hw); | 4943 | mwl8k_fw_unlock(hw); |
3753 | } | 4944 | } |
@@ -3777,20 +4968,118 @@ static int mwl8k_get_survey(struct ieee80211_hw *hw, int idx, | |||
3777 | return 0; | 4968 | return 0; |
3778 | } | 4969 | } |
3779 | 4970 | ||
4971 | #define MAX_AMPDU_ATTEMPTS 5 | ||
4972 | |||
3780 | static int | 4973 | static int |
3781 | mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 4974 | mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
3782 | enum ieee80211_ampdu_mlme_action action, | 4975 | enum ieee80211_ampdu_mlme_action action, |
3783 | struct ieee80211_sta *sta, u16 tid, u16 *ssn) | 4976 | struct ieee80211_sta *sta, u16 tid, u16 *ssn, |
4977 | u8 buf_size) | ||
3784 | { | 4978 | { |
4979 | |||
4980 | int i, rc = 0; | ||
4981 | struct mwl8k_priv *priv = hw->priv; | ||
4982 | struct mwl8k_ampdu_stream *stream; | ||
4983 | u8 *addr = sta->addr; | ||
4984 | |||
4985 | if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) | ||
4986 | return -ENOTSUPP; | ||
4987 | |||
4988 | spin_lock(&priv->stream_lock); | ||
4989 | stream = mwl8k_lookup_stream(hw, addr, tid); | ||
4990 | |||
3785 | switch (action) { | 4991 | switch (action) { |
3786 | case IEEE80211_AMPDU_RX_START: | 4992 | case IEEE80211_AMPDU_RX_START: |
3787 | case IEEE80211_AMPDU_RX_STOP: | 4993 | case IEEE80211_AMPDU_RX_STOP: |
3788 | if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) | 4994 | break; |
3789 | return -ENOTSUPP; | 4995 | case IEEE80211_AMPDU_TX_START: |
3790 | return 0; | 4996 | /* By the time we get here the hw queues may contain outgoing |
4997 | * packets for this RA/TID that are not part of this BA | ||
4998 | * session. The hw will assign sequence numbers to these | ||
4999 | * packets as they go out. So if we query the hw for its next | ||
5000 | * sequence number and use that for the SSN here, it may end up | ||
5001 | * being wrong, which will lead to sequence number mismatch at | ||
5002 | * the recipient. To avoid this, we reset the sequence number | ||
5003 | * to O for the first MPDU in this BA stream. | ||
5004 | */ | ||
5005 | *ssn = 0; | ||
5006 | if (stream == NULL) { | ||
5007 | /* This means that somebody outside this driver called | ||
5008 | * ieee80211_start_tx_ba_session. This is unexpected | ||
5009 | * because we do our own rate control. Just warn and | ||
5010 | * move on. | ||
5011 | */ | ||
5012 | wiphy_warn(hw->wiphy, "Unexpected call to %s. " | ||
5013 | "Proceeding anyway.\n", __func__); | ||
5014 | stream = mwl8k_add_stream(hw, sta, tid); | ||
5015 | } | ||
5016 | if (stream == NULL) { | ||
5017 | wiphy_debug(hw->wiphy, "no free AMPDU streams\n"); | ||
5018 | rc = -EBUSY; | ||
5019 | break; | ||
5020 | } | ||
5021 | stream->state = AMPDU_STREAM_IN_PROGRESS; | ||
5022 | |||
5023 | /* Release the lock before we do the time consuming stuff */ | ||
5024 | spin_unlock(&priv->stream_lock); | ||
5025 | for (i = 0; i < MAX_AMPDU_ATTEMPTS; i++) { | ||
5026 | rc = mwl8k_check_ba(hw, stream); | ||
5027 | |||
5028 | if (!rc) | ||
5029 | break; | ||
5030 | /* | ||
5031 | * HW queues take time to be flushed, give them | ||
5032 | * sufficient time | ||
5033 | */ | ||
5034 | |||
5035 | msleep(1000); | ||
5036 | } | ||
5037 | spin_lock(&priv->stream_lock); | ||
5038 | if (rc) { | ||
5039 | wiphy_err(hw->wiphy, "Stream for tid %d busy after %d" | ||
5040 | " attempts\n", tid, MAX_AMPDU_ATTEMPTS); | ||
5041 | mwl8k_remove_stream(hw, stream); | ||
5042 | rc = -EBUSY; | ||
5043 | break; | ||
5044 | } | ||
5045 | ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid); | ||
5046 | break; | ||
5047 | case IEEE80211_AMPDU_TX_STOP: | ||
5048 | if (stream == NULL) | ||
5049 | break; | ||
5050 | if (stream->state == AMPDU_STREAM_ACTIVE) { | ||
5051 | spin_unlock(&priv->stream_lock); | ||
5052 | mwl8k_destroy_ba(hw, stream); | ||
5053 | spin_lock(&priv->stream_lock); | ||
5054 | } | ||
5055 | mwl8k_remove_stream(hw, stream); | ||
5056 | ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid); | ||
5057 | break; | ||
5058 | case IEEE80211_AMPDU_TX_OPERATIONAL: | ||
5059 | BUG_ON(stream == NULL); | ||
5060 | BUG_ON(stream->state != AMPDU_STREAM_IN_PROGRESS); | ||
5061 | spin_unlock(&priv->stream_lock); | ||
5062 | rc = mwl8k_create_ba(hw, stream, buf_size); | ||
5063 | spin_lock(&priv->stream_lock); | ||
5064 | if (!rc) | ||
5065 | stream->state = AMPDU_STREAM_ACTIVE; | ||
5066 | else { | ||
5067 | spin_unlock(&priv->stream_lock); | ||
5068 | mwl8k_destroy_ba(hw, stream); | ||
5069 | spin_lock(&priv->stream_lock); | ||
5070 | wiphy_debug(hw->wiphy, | ||
5071 | "Failed adding stream for sta %pM tid %d\n", | ||
5072 | addr, tid); | ||
5073 | mwl8k_remove_stream(hw, stream); | ||
5074 | } | ||
5075 | break; | ||
5076 | |||
3791 | default: | 5077 | default: |
3792 | return -ENOTSUPP; | 5078 | rc = -ENOTSUPP; |
3793 | } | 5079 | } |
5080 | |||
5081 | spin_unlock(&priv->stream_lock); | ||
5082 | return rc; | ||
3794 | } | 5083 | } |
3795 | 5084 | ||
3796 | static const struct ieee80211_ops mwl8k_ops = { | 5085 | static const struct ieee80211_ops mwl8k_ops = { |
@@ -3803,6 +5092,7 @@ static const struct ieee80211_ops mwl8k_ops = { | |||
3803 | .bss_info_changed = mwl8k_bss_info_changed, | 5092 | .bss_info_changed = mwl8k_bss_info_changed, |
3804 | .prepare_multicast = mwl8k_prepare_multicast, | 5093 | .prepare_multicast = mwl8k_prepare_multicast, |
3805 | .configure_filter = mwl8k_configure_filter, | 5094 | .configure_filter = mwl8k_configure_filter, |
5095 | .set_key = mwl8k_set_key, | ||
3806 | .set_rts_threshold = mwl8k_set_rts_threshold, | 5096 | .set_rts_threshold = mwl8k_set_rts_threshold, |
3807 | .sta_add = mwl8k_sta_add, | 5097 | .sta_add = mwl8k_sta_add, |
3808 | .sta_remove = mwl8k_sta_remove, | 5098 | .sta_remove = mwl8k_sta_remove, |
@@ -3838,21 +5128,27 @@ enum { | |||
3838 | MWL8366, | 5128 | MWL8366, |
3839 | }; | 5129 | }; |
3840 | 5130 | ||
5131 | #define MWL8K_8366_AP_FW_API 2 | ||
5132 | #define _MWL8K_8366_AP_FW(api) "mwl8k/fmimage_8366_ap-" #api ".fw" | ||
5133 | #define MWL8K_8366_AP_FW(api) _MWL8K_8366_AP_FW(api) | ||
5134 | |||
3841 | static struct mwl8k_device_info mwl8k_info_tbl[] __devinitdata = { | 5135 | static struct mwl8k_device_info mwl8k_info_tbl[] __devinitdata = { |
3842 | [MWL8363] = { | 5136 | [MWL8363] = { |
3843 | .part_name = "88w8363", | 5137 | .part_name = "88w8363", |
3844 | .helper_image = "mwl8k/helper_8363.fw", | 5138 | .helper_image = "mwl8k/helper_8363.fw", |
3845 | .fw_image = "mwl8k/fmimage_8363.fw", | 5139 | .fw_image_sta = "mwl8k/fmimage_8363.fw", |
3846 | }, | 5140 | }, |
3847 | [MWL8687] = { | 5141 | [MWL8687] = { |
3848 | .part_name = "88w8687", | 5142 | .part_name = "88w8687", |
3849 | .helper_image = "mwl8k/helper_8687.fw", | 5143 | .helper_image = "mwl8k/helper_8687.fw", |
3850 | .fw_image = "mwl8k/fmimage_8687.fw", | 5144 | .fw_image_sta = "mwl8k/fmimage_8687.fw", |
3851 | }, | 5145 | }, |
3852 | [MWL8366] = { | 5146 | [MWL8366] = { |
3853 | .part_name = "88w8366", | 5147 | .part_name = "88w8366", |
3854 | .helper_image = "mwl8k/helper_8366.fw", | 5148 | .helper_image = "mwl8k/helper_8366.fw", |
3855 | .fw_image = "mwl8k/fmimage_8366.fw", | 5149 | .fw_image_sta = "mwl8k/fmimage_8366.fw", |
5150 | .fw_image_ap = MWL8K_8366_AP_FW(MWL8K_8366_AP_FW_API), | ||
5151 | .fw_api_ap = MWL8K_8366_AP_FW_API, | ||
3856 | .ap_rxd_ops = &rxd_8366_ap_ops, | 5152 | .ap_rxd_ops = &rxd_8366_ap_ops, |
3857 | }, | 5153 | }, |
3858 | }; | 5154 | }; |
@@ -3863,6 +5159,7 @@ MODULE_FIRMWARE("mwl8k/helper_8687.fw"); | |||
3863 | MODULE_FIRMWARE("mwl8k/fmimage_8687.fw"); | 5159 | MODULE_FIRMWARE("mwl8k/fmimage_8687.fw"); |
3864 | MODULE_FIRMWARE("mwl8k/helper_8366.fw"); | 5160 | MODULE_FIRMWARE("mwl8k/helper_8366.fw"); |
3865 | MODULE_FIRMWARE("mwl8k/fmimage_8366.fw"); | 5161 | MODULE_FIRMWARE("mwl8k/fmimage_8366.fw"); |
5162 | MODULE_FIRMWARE(MWL8K_8366_AP_FW(MWL8K_8366_AP_FW_API)); | ||
3866 | 5163 | ||
3867 | static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { | 5164 | static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { |
3868 | { PCI_VDEVICE(MARVELL, 0x2a0a), .driver_data = MWL8363, }, | 5165 | { PCI_VDEVICE(MARVELL, 0x2a0a), .driver_data = MWL8363, }, |
@@ -3876,94 +5173,150 @@ static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { | |||
3876 | }; | 5173 | }; |
3877 | MODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table); | 5174 | MODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table); |
3878 | 5175 | ||
3879 | static int __devinit mwl8k_probe(struct pci_dev *pdev, | 5176 | static int mwl8k_request_alt_fw(struct mwl8k_priv *priv) |
3880 | const struct pci_device_id *id) | ||
3881 | { | 5177 | { |
3882 | static int printed_version = 0; | ||
3883 | struct ieee80211_hw *hw; | ||
3884 | struct mwl8k_priv *priv; | ||
3885 | int rc; | 5178 | int rc; |
3886 | int i; | 5179 | printk(KERN_ERR "%s: Error requesting preferred fw %s.\n" |
3887 | 5180 | "Trying alternative firmware %s\n", pci_name(priv->pdev), | |
3888 | if (!printed_version) { | 5181 | priv->fw_pref, priv->fw_alt); |
3889 | printk(KERN_INFO "%s version %s\n", MWL8K_DESC, MWL8K_VERSION); | 5182 | rc = mwl8k_request_fw(priv, priv->fw_alt, &priv->fw_ucode, true); |
3890 | printed_version = 1; | ||
3891 | } | ||
3892 | |||
3893 | |||
3894 | rc = pci_enable_device(pdev); | ||
3895 | if (rc) { | 5183 | if (rc) { |
3896 | printk(KERN_ERR "%s: Cannot enable new PCI device\n", | 5184 | printk(KERN_ERR "%s: Error requesting alt fw %s\n", |
3897 | MWL8K_NAME); | 5185 | pci_name(priv->pdev), priv->fw_alt); |
3898 | return rc; | 5186 | return rc; |
3899 | } | 5187 | } |
5188 | return 0; | ||
5189 | } | ||
3900 | 5190 | ||
3901 | rc = pci_request_regions(pdev, MWL8K_NAME); | 5191 | static int mwl8k_firmware_load_success(struct mwl8k_priv *priv); |
3902 | if (rc) { | 5192 | static void mwl8k_fw_state_machine(const struct firmware *fw, void *context) |
3903 | printk(KERN_ERR "%s: Cannot obtain PCI resources\n", | 5193 | { |
3904 | MWL8K_NAME); | 5194 | struct mwl8k_priv *priv = context; |
3905 | goto err_disable_device; | 5195 | struct mwl8k_device_info *di = priv->device_info; |
3906 | } | 5196 | int rc; |
3907 | |||
3908 | pci_set_master(pdev); | ||
3909 | |||
3910 | |||
3911 | hw = ieee80211_alloc_hw(sizeof(*priv), &mwl8k_ops); | ||
3912 | if (hw == NULL) { | ||
3913 | printk(KERN_ERR "%s: ieee80211 alloc failed\n", MWL8K_NAME); | ||
3914 | rc = -ENOMEM; | ||
3915 | goto err_free_reg; | ||
3916 | } | ||
3917 | 5197 | ||
3918 | SET_IEEE80211_DEV(hw, &pdev->dev); | 5198 | switch (priv->fw_state) { |
3919 | pci_set_drvdata(pdev, hw); | 5199 | case FW_STATE_INIT: |
5200 | if (!fw) { | ||
5201 | printk(KERN_ERR "%s: Error requesting helper fw %s\n", | ||
5202 | pci_name(priv->pdev), di->helper_image); | ||
5203 | goto fail; | ||
5204 | } | ||
5205 | priv->fw_helper = fw; | ||
5206 | rc = mwl8k_request_fw(priv, priv->fw_pref, &priv->fw_ucode, | ||
5207 | true); | ||
5208 | if (rc && priv->fw_alt) { | ||
5209 | rc = mwl8k_request_alt_fw(priv); | ||
5210 | if (rc) | ||
5211 | goto fail; | ||
5212 | priv->fw_state = FW_STATE_LOADING_ALT; | ||
5213 | } else if (rc) | ||
5214 | goto fail; | ||
5215 | else | ||
5216 | priv->fw_state = FW_STATE_LOADING_PREF; | ||
5217 | break; | ||
3920 | 5218 | ||
3921 | priv = hw->priv; | 5219 | case FW_STATE_LOADING_PREF: |
3922 | priv->hw = hw; | 5220 | if (!fw) { |
3923 | priv->pdev = pdev; | 5221 | if (priv->fw_alt) { |
3924 | priv->device_info = &mwl8k_info_tbl[id->driver_data]; | 5222 | rc = mwl8k_request_alt_fw(priv); |
5223 | if (rc) | ||
5224 | goto fail; | ||
5225 | priv->fw_state = FW_STATE_LOADING_ALT; | ||
5226 | } else | ||
5227 | goto fail; | ||
5228 | } else { | ||
5229 | priv->fw_ucode = fw; | ||
5230 | rc = mwl8k_firmware_load_success(priv); | ||
5231 | if (rc) | ||
5232 | goto fail; | ||
5233 | else | ||
5234 | complete(&priv->firmware_loading_complete); | ||
5235 | } | ||
5236 | break; | ||
3925 | 5237 | ||
5238 | case FW_STATE_LOADING_ALT: | ||
5239 | if (!fw) { | ||
5240 | printk(KERN_ERR "%s: Error requesting alt fw %s\n", | ||
5241 | pci_name(priv->pdev), di->helper_image); | ||
5242 | goto fail; | ||
5243 | } | ||
5244 | priv->fw_ucode = fw; | ||
5245 | rc = mwl8k_firmware_load_success(priv); | ||
5246 | if (rc) | ||
5247 | goto fail; | ||
5248 | else | ||
5249 | complete(&priv->firmware_loading_complete); | ||
5250 | break; | ||
3926 | 5251 | ||
3927 | priv->sram = pci_iomap(pdev, 0, 0x10000); | 5252 | default: |
3928 | if (priv->sram == NULL) { | 5253 | printk(KERN_ERR "%s: Unexpected firmware loading state: %d\n", |
3929 | wiphy_err(hw->wiphy, "Cannot map device SRAM\n"); | 5254 | MWL8K_NAME, priv->fw_state); |
3930 | goto err_iounmap; | 5255 | BUG_ON(1); |
3931 | } | 5256 | } |
3932 | 5257 | ||
3933 | /* | 5258 | return; |
3934 | * If BAR0 is a 32 bit BAR, the register BAR will be BAR1. | ||
3935 | * If BAR0 is a 64 bit BAR, the register BAR will be BAR2. | ||
3936 | */ | ||
3937 | priv->regs = pci_iomap(pdev, 1, 0x10000); | ||
3938 | if (priv->regs == NULL) { | ||
3939 | priv->regs = pci_iomap(pdev, 2, 0x10000); | ||
3940 | if (priv->regs == NULL) { | ||
3941 | wiphy_err(hw->wiphy, "Cannot map device registers\n"); | ||
3942 | goto err_iounmap; | ||
3943 | } | ||
3944 | } | ||
3945 | 5259 | ||
5260 | fail: | ||
5261 | priv->fw_state = FW_STATE_ERROR; | ||
5262 | complete(&priv->firmware_loading_complete); | ||
5263 | device_release_driver(&priv->pdev->dev); | ||
5264 | mwl8k_release_firmware(priv); | ||
5265 | } | ||
5266 | |||
5267 | static int mwl8k_init_firmware(struct ieee80211_hw *hw, char *fw_image, | ||
5268 | bool nowait) | ||
5269 | { | ||
5270 | struct mwl8k_priv *priv = hw->priv; | ||
5271 | int rc; | ||
3946 | 5272 | ||
3947 | /* Reset firmware and hardware */ | 5273 | /* Reset firmware and hardware */ |
3948 | mwl8k_hw_reset(priv); | 5274 | mwl8k_hw_reset(priv); |
3949 | 5275 | ||
3950 | /* Ask userland hotplug daemon for the device firmware */ | 5276 | /* Ask userland hotplug daemon for the device firmware */ |
3951 | rc = mwl8k_request_firmware(priv); | 5277 | rc = mwl8k_request_firmware(priv, fw_image, nowait); |
3952 | if (rc) { | 5278 | if (rc) { |
3953 | wiphy_err(hw->wiphy, "Firmware files not found\n"); | 5279 | wiphy_err(hw->wiphy, "Firmware files not found\n"); |
3954 | goto err_stop_firmware; | 5280 | return rc; |
3955 | } | 5281 | } |
3956 | 5282 | ||
5283 | if (nowait) | ||
5284 | return rc; | ||
5285 | |||
3957 | /* Load firmware into hardware */ | 5286 | /* Load firmware into hardware */ |
3958 | rc = mwl8k_load_firmware(hw); | 5287 | rc = mwl8k_load_firmware(hw); |
3959 | if (rc) { | 5288 | if (rc) |
3960 | wiphy_err(hw->wiphy, "Cannot start firmware\n"); | 5289 | wiphy_err(hw->wiphy, "Cannot start firmware\n"); |
3961 | goto err_stop_firmware; | ||
3962 | } | ||
3963 | 5290 | ||
3964 | /* Reclaim memory once firmware is successfully loaded */ | 5291 | /* Reclaim memory once firmware is successfully loaded */ |
3965 | mwl8k_release_firmware(priv); | 5292 | mwl8k_release_firmware(priv); |
3966 | 5293 | ||
5294 | return rc; | ||
5295 | } | ||
5296 | |||
5297 | static int mwl8k_init_txqs(struct ieee80211_hw *hw) | ||
5298 | { | ||
5299 | struct mwl8k_priv *priv = hw->priv; | ||
5300 | int rc = 0; | ||
5301 | int i; | ||
5302 | |||
5303 | for (i = 0; i < mwl8k_tx_queues(priv); i++) { | ||
5304 | rc = mwl8k_txq_init(hw, i); | ||
5305 | if (rc) | ||
5306 | break; | ||
5307 | if (priv->ap_fw) | ||
5308 | iowrite32(priv->txq[i].txd_dma, | ||
5309 | priv->sram + priv->txq_offset[i]); | ||
5310 | } | ||
5311 | return rc; | ||
5312 | } | ||
5313 | |||
5314 | /* initialize hw after successfully loading a firmware image */ | ||
5315 | static int mwl8k_probe_hw(struct ieee80211_hw *hw) | ||
5316 | { | ||
5317 | struct mwl8k_priv *priv = hw->priv; | ||
5318 | int rc = 0; | ||
5319 | int i; | ||
3967 | 5320 | ||
3968 | if (priv->ap_fw) { | 5321 | if (priv->ap_fw) { |
3969 | priv->rxd_ops = priv->device_info->ap_rxd_ops; | 5322 | priv->rxd_ops = priv->device_info->ap_rxd_ops; |
@@ -3980,69 +5333,31 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, | |||
3980 | priv->wmm_enabled = false; | 5333 | priv->wmm_enabled = false; |
3981 | priv->pending_tx_pkts = 0; | 5334 | priv->pending_tx_pkts = 0; |
3982 | 5335 | ||
3983 | |||
3984 | /* | ||
3985 | * Extra headroom is the size of the required DMA header | ||
3986 | * minus the size of the smallest 802.11 frame (CTS frame). | ||
3987 | */ | ||
3988 | hw->extra_tx_headroom = | ||
3989 | sizeof(struct mwl8k_dma_data) - sizeof(struct ieee80211_cts); | ||
3990 | |||
3991 | hw->channel_change_time = 10; | ||
3992 | |||
3993 | hw->queues = MWL8K_TX_QUEUES; | ||
3994 | |||
3995 | /* Set rssi values to dBm */ | ||
3996 | hw->flags |= IEEE80211_HW_SIGNAL_DBM; | ||
3997 | hw->vif_data_size = sizeof(struct mwl8k_vif); | ||
3998 | hw->sta_data_size = sizeof(struct mwl8k_sta); | ||
3999 | |||
4000 | priv->macids_used = 0; | ||
4001 | INIT_LIST_HEAD(&priv->vif_list); | ||
4002 | |||
4003 | /* Set default radio state and preamble */ | ||
4004 | priv->radio_on = 0; | ||
4005 | priv->radio_short_preamble = 0; | ||
4006 | |||
4007 | /* Finalize join worker */ | ||
4008 | INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); | ||
4009 | |||
4010 | /* TX reclaim and RX tasklets. */ | ||
4011 | tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw); | ||
4012 | tasklet_disable(&priv->poll_tx_task); | ||
4013 | tasklet_init(&priv->poll_rx_task, mwl8k_rx_poll, (unsigned long)hw); | ||
4014 | tasklet_disable(&priv->poll_rx_task); | ||
4015 | |||
4016 | /* Power management cookie */ | ||
4017 | priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma); | ||
4018 | if (priv->cookie == NULL) | ||
4019 | goto err_stop_firmware; | ||
4020 | |||
4021 | rc = mwl8k_rxq_init(hw, 0); | 5336 | rc = mwl8k_rxq_init(hw, 0); |
4022 | if (rc) | 5337 | if (rc) |
4023 | goto err_free_cookie; | 5338 | goto err_stop_firmware; |
4024 | rxq_refill(hw, 0, INT_MAX); | 5339 | rxq_refill(hw, 0, INT_MAX); |
4025 | 5340 | ||
4026 | mutex_init(&priv->fw_mutex); | 5341 | /* For the sta firmware, we need to know the dma addresses of tx queues |
4027 | priv->fw_mutex_owner = NULL; | 5342 | * before sending MWL8K_CMD_GET_HW_SPEC. So we must initialize them |
4028 | priv->fw_mutex_depth = 0; | 5343 | * prior to issuing this command. But for the AP case, we learn the |
4029 | priv->hostcmd_wait = NULL; | 5344 | * total number of queues from the result CMD_GET_HW_SPEC, so for this |
4030 | 5345 | * case we must initialize the tx queues after. | |
4031 | spin_lock_init(&priv->tx_lock); | 5346 | */ |
4032 | 5347 | priv->num_ampdu_queues = 0; | |
4033 | priv->tx_wait = NULL; | 5348 | if (!priv->ap_fw) { |
4034 | 5349 | rc = mwl8k_init_txqs(hw); | |
4035 | for (i = 0; i < MWL8K_TX_QUEUES; i++) { | ||
4036 | rc = mwl8k_txq_init(hw, i); | ||
4037 | if (rc) | 5350 | if (rc) |
4038 | goto err_free_queues; | 5351 | goto err_free_queues; |
4039 | } | 5352 | } |
4040 | 5353 | ||
4041 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); | 5354 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); |
4042 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); | 5355 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); |
4043 | iowrite32(MWL8K_A2H_INT_TX_DONE | MWL8K_A2H_INT_RX_READY, | 5356 | iowrite32(MWL8K_A2H_INT_TX_DONE|MWL8K_A2H_INT_RX_READY| |
5357 | MWL8K_A2H_INT_BA_WATCHDOG, | ||
4044 | priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); | 5358 | priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); |
4045 | iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); | 5359 | iowrite32(MWL8K_A2H_INT_OPC_DONE, |
5360 | priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); | ||
4046 | 5361 | ||
4047 | rc = request_irq(priv->pdev->irq, mwl8k_interrupt, | 5362 | rc = request_irq(priv->pdev->irq, mwl8k_interrupt, |
4048 | IRQF_SHARED, MWL8K_NAME, hw); | 5363 | IRQF_SHARED, MWL8K_NAME, hw); |
@@ -4051,6 +5366,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, | |||
4051 | goto err_free_queues; | 5366 | goto err_free_queues; |
4052 | } | 5367 | } |
4053 | 5368 | ||
5369 | memset(priv->ampdu, 0, sizeof(priv->ampdu)); | ||
5370 | |||
4054 | /* | 5371 | /* |
4055 | * Temporarily enable interrupts. Initial firmware host | 5372 | * Temporarily enable interrupts. Initial firmware host |
4056 | * commands use interrupts and avoid polling. Disable | 5373 | * commands use interrupts and avoid polling. Disable |
@@ -4062,6 +5379,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, | |||
4062 | if (priv->ap_fw) { | 5379 | if (priv->ap_fw) { |
4063 | rc = mwl8k_cmd_get_hw_spec_ap(hw); | 5380 | rc = mwl8k_cmd_get_hw_spec_ap(hw); |
4064 | if (!rc) | 5381 | if (!rc) |
5382 | rc = mwl8k_init_txqs(hw); | ||
5383 | if (!rc) | ||
4065 | rc = mwl8k_cmd_set_hw_spec(hw); | 5384 | rc = mwl8k_cmd_set_hw_spec(hw); |
4066 | } else { | 5385 | } else { |
4067 | rc = mwl8k_cmd_get_hw_spec_sta(hw); | 5386 | rc = mwl8k_cmd_get_hw_spec_sta(hw); |
@@ -4071,13 +5390,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, | |||
4071 | goto err_free_irq; | 5390 | goto err_free_irq; |
4072 | } | 5391 | } |
4073 | 5392 | ||
4074 | hw->wiphy->interface_modes = 0; | ||
4075 | if (priv->ap_macids_supported) | ||
4076 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP); | ||
4077 | if (priv->sta_macids_supported) | ||
4078 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION); | ||
4079 | |||
4080 | |||
4081 | /* Turn radio off */ | 5393 | /* Turn radio off */ |
4082 | rc = mwl8k_cmd_radio_disable(hw); | 5394 | rc = mwl8k_cmd_radio_disable(hw); |
4083 | if (rc) { | 5395 | if (rc) { |
@@ -4096,12 +5408,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, | |||
4096 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); | 5408 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); |
4097 | free_irq(priv->pdev->irq, hw); | 5409 | free_irq(priv->pdev->irq, hw); |
4098 | 5410 | ||
4099 | rc = ieee80211_register_hw(hw); | ||
4100 | if (rc) { | ||
4101 | wiphy_err(hw->wiphy, "Cannot register device\n"); | ||
4102 | goto err_free_queues; | ||
4103 | } | ||
4104 | |||
4105 | wiphy_info(hw->wiphy, "%s v%d, %pm, %s firmware %u.%u.%u.%u\n", | 5411 | wiphy_info(hw->wiphy, "%s v%d, %pm, %s firmware %u.%u.%u.%u\n", |
4106 | priv->device_info->part_name, | 5412 | priv->device_info->part_name, |
4107 | priv->hw_rev, hw->wiphy->perm_addr, | 5413 | priv->hw_rev, hw->wiphy->perm_addr, |
@@ -4116,7 +5422,144 @@ err_free_irq: | |||
4116 | free_irq(priv->pdev->irq, hw); | 5422 | free_irq(priv->pdev->irq, hw); |
4117 | 5423 | ||
4118 | err_free_queues: | 5424 | err_free_queues: |
4119 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 5425 | for (i = 0; i < mwl8k_tx_queues(priv); i++) |
5426 | mwl8k_txq_deinit(hw, i); | ||
5427 | mwl8k_rxq_deinit(hw, 0); | ||
5428 | |||
5429 | err_stop_firmware: | ||
5430 | mwl8k_hw_reset(priv); | ||
5431 | |||
5432 | return rc; | ||
5433 | } | ||
5434 | |||
5435 | /* | ||
5436 | * invoke mwl8k_reload_firmware to change the firmware image after the device | ||
5437 | * has already been registered | ||
5438 | */ | ||
5439 | static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image) | ||
5440 | { | ||
5441 | int i, rc = 0; | ||
5442 | struct mwl8k_priv *priv = hw->priv; | ||
5443 | |||
5444 | mwl8k_stop(hw); | ||
5445 | mwl8k_rxq_deinit(hw, 0); | ||
5446 | |||
5447 | for (i = 0; i < mwl8k_tx_queues(priv); i++) | ||
5448 | mwl8k_txq_deinit(hw, i); | ||
5449 | |||
5450 | rc = mwl8k_init_firmware(hw, fw_image, false); | ||
5451 | if (rc) | ||
5452 | goto fail; | ||
5453 | |||
5454 | rc = mwl8k_probe_hw(hw); | ||
5455 | if (rc) | ||
5456 | goto fail; | ||
5457 | |||
5458 | rc = mwl8k_start(hw); | ||
5459 | if (rc) | ||
5460 | goto fail; | ||
5461 | |||
5462 | rc = mwl8k_config(hw, ~0); | ||
5463 | if (rc) | ||
5464 | goto fail; | ||
5465 | |||
5466 | for (i = 0; i < MWL8K_TX_WMM_QUEUES; i++) { | ||
5467 | rc = mwl8k_conf_tx(hw, i, &priv->wmm_params[i]); | ||
5468 | if (rc) | ||
5469 | goto fail; | ||
5470 | } | ||
5471 | |||
5472 | return rc; | ||
5473 | |||
5474 | fail: | ||
5475 | printk(KERN_WARNING "mwl8k: Failed to reload firmware image.\n"); | ||
5476 | return rc; | ||
5477 | } | ||
5478 | |||
5479 | static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) | ||
5480 | { | ||
5481 | struct ieee80211_hw *hw = priv->hw; | ||
5482 | int i, rc; | ||
5483 | |||
5484 | rc = mwl8k_load_firmware(hw); | ||
5485 | mwl8k_release_firmware(priv); | ||
5486 | if (rc) { | ||
5487 | wiphy_err(hw->wiphy, "Cannot start firmware\n"); | ||
5488 | return rc; | ||
5489 | } | ||
5490 | |||
5491 | /* | ||
5492 | * Extra headroom is the size of the required DMA header | ||
5493 | * minus the size of the smallest 802.11 frame (CTS frame). | ||
5494 | */ | ||
5495 | hw->extra_tx_headroom = | ||
5496 | sizeof(struct mwl8k_dma_data) - sizeof(struct ieee80211_cts); | ||
5497 | |||
5498 | hw->extra_tx_headroom -= priv->ap_fw ? REDUCED_TX_HEADROOM : 0; | ||
5499 | |||
5500 | hw->channel_change_time = 10; | ||
5501 | |||
5502 | hw->queues = MWL8K_TX_WMM_QUEUES; | ||
5503 | |||
5504 | /* Set rssi values to dBm */ | ||
5505 | hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_HAS_RATE_CONTROL; | ||
5506 | hw->vif_data_size = sizeof(struct mwl8k_vif); | ||
5507 | hw->sta_data_size = sizeof(struct mwl8k_sta); | ||
5508 | |||
5509 | priv->macids_used = 0; | ||
5510 | INIT_LIST_HEAD(&priv->vif_list); | ||
5511 | |||
5512 | /* Set default radio state and preamble */ | ||
5513 | priv->radio_on = 0; | ||
5514 | priv->radio_short_preamble = 0; | ||
5515 | |||
5516 | /* Finalize join worker */ | ||
5517 | INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); | ||
5518 | /* Handle watchdog ba events */ | ||
5519 | INIT_WORK(&priv->watchdog_ba_handle, mwl8k_watchdog_ba_events); | ||
5520 | |||
5521 | /* TX reclaim and RX tasklets. */ | ||
5522 | tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw); | ||
5523 | tasklet_disable(&priv->poll_tx_task); | ||
5524 | tasklet_init(&priv->poll_rx_task, mwl8k_rx_poll, (unsigned long)hw); | ||
5525 | tasklet_disable(&priv->poll_rx_task); | ||
5526 | |||
5527 | /* Power management cookie */ | ||
5528 | priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma); | ||
5529 | if (priv->cookie == NULL) | ||
5530 | return -ENOMEM; | ||
5531 | |||
5532 | mutex_init(&priv->fw_mutex); | ||
5533 | priv->fw_mutex_owner = NULL; | ||
5534 | priv->fw_mutex_depth = 0; | ||
5535 | priv->hostcmd_wait = NULL; | ||
5536 | |||
5537 | spin_lock_init(&priv->tx_lock); | ||
5538 | |||
5539 | spin_lock_init(&priv->stream_lock); | ||
5540 | |||
5541 | priv->tx_wait = NULL; | ||
5542 | |||
5543 | rc = mwl8k_probe_hw(hw); | ||
5544 | if (rc) | ||
5545 | goto err_free_cookie; | ||
5546 | |||
5547 | hw->wiphy->interface_modes = 0; | ||
5548 | if (priv->ap_macids_supported || priv->device_info->fw_image_ap) | ||
5549 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP); | ||
5550 | if (priv->sta_macids_supported || priv->device_info->fw_image_sta) | ||
5551 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION); | ||
5552 | |||
5553 | rc = ieee80211_register_hw(hw); | ||
5554 | if (rc) { | ||
5555 | wiphy_err(hw->wiphy, "Cannot register device\n"); | ||
5556 | goto err_unprobe_hw; | ||
5557 | } | ||
5558 | |||
5559 | return 0; | ||
5560 | |||
5561 | err_unprobe_hw: | ||
5562 | for (i = 0; i < mwl8k_tx_queues(priv); i++) | ||
4120 | mwl8k_txq_deinit(hw, i); | 5563 | mwl8k_txq_deinit(hw, i); |
4121 | mwl8k_rxq_deinit(hw, 0); | 5564 | mwl8k_rxq_deinit(hw, 0); |
4122 | 5565 | ||
@@ -4125,9 +5568,102 @@ err_free_cookie: | |||
4125 | pci_free_consistent(priv->pdev, 4, | 5568 | pci_free_consistent(priv->pdev, 4, |
4126 | priv->cookie, priv->cookie_dma); | 5569 | priv->cookie, priv->cookie_dma); |
4127 | 5570 | ||
5571 | return rc; | ||
5572 | } | ||
5573 | static int __devinit mwl8k_probe(struct pci_dev *pdev, | ||
5574 | const struct pci_device_id *id) | ||
5575 | { | ||
5576 | static int printed_version; | ||
5577 | struct ieee80211_hw *hw; | ||
5578 | struct mwl8k_priv *priv; | ||
5579 | struct mwl8k_device_info *di; | ||
5580 | int rc; | ||
5581 | |||
5582 | if (!printed_version) { | ||
5583 | printk(KERN_INFO "%s version %s\n", MWL8K_DESC, MWL8K_VERSION); | ||
5584 | printed_version = 1; | ||
5585 | } | ||
5586 | |||
5587 | |||
5588 | rc = pci_enable_device(pdev); | ||
5589 | if (rc) { | ||
5590 | printk(KERN_ERR "%s: Cannot enable new PCI device\n", | ||
5591 | MWL8K_NAME); | ||
5592 | return rc; | ||
5593 | } | ||
5594 | |||
5595 | rc = pci_request_regions(pdev, MWL8K_NAME); | ||
5596 | if (rc) { | ||
5597 | printk(KERN_ERR "%s: Cannot obtain PCI resources\n", | ||
5598 | MWL8K_NAME); | ||
5599 | goto err_disable_device; | ||
5600 | } | ||
5601 | |||
5602 | pci_set_master(pdev); | ||
5603 | |||
5604 | |||
5605 | hw = ieee80211_alloc_hw(sizeof(*priv), &mwl8k_ops); | ||
5606 | if (hw == NULL) { | ||
5607 | printk(KERN_ERR "%s: ieee80211 alloc failed\n", MWL8K_NAME); | ||
5608 | rc = -ENOMEM; | ||
5609 | goto err_free_reg; | ||
5610 | } | ||
5611 | |||
5612 | SET_IEEE80211_DEV(hw, &pdev->dev); | ||
5613 | pci_set_drvdata(pdev, hw); | ||
5614 | |||
5615 | priv = hw->priv; | ||
5616 | priv->hw = hw; | ||
5617 | priv->pdev = pdev; | ||
5618 | priv->device_info = &mwl8k_info_tbl[id->driver_data]; | ||
5619 | |||
5620 | |||
5621 | priv->sram = pci_iomap(pdev, 0, 0x10000); | ||
5622 | if (priv->sram == NULL) { | ||
5623 | wiphy_err(hw->wiphy, "Cannot map device SRAM\n"); | ||
5624 | goto err_iounmap; | ||
5625 | } | ||
5626 | |||
5627 | /* | ||
5628 | * If BAR0 is a 32 bit BAR, the register BAR will be BAR1. | ||
5629 | * If BAR0 is a 64 bit BAR, the register BAR will be BAR2. | ||
5630 | */ | ||
5631 | priv->regs = pci_iomap(pdev, 1, 0x10000); | ||
5632 | if (priv->regs == NULL) { | ||
5633 | priv->regs = pci_iomap(pdev, 2, 0x10000); | ||
5634 | if (priv->regs == NULL) { | ||
5635 | wiphy_err(hw->wiphy, "Cannot map device registers\n"); | ||
5636 | goto err_iounmap; | ||
5637 | } | ||
5638 | } | ||
5639 | |||
5640 | /* | ||
5641 | * Choose the initial fw image depending on user input. If a second | ||
5642 | * image is available, make it the alternative image that will be | ||
5643 | * loaded if the first one fails. | ||
5644 | */ | ||
5645 | init_completion(&priv->firmware_loading_complete); | ||
5646 | di = priv->device_info; | ||
5647 | if (ap_mode_default && di->fw_image_ap) { | ||
5648 | priv->fw_pref = di->fw_image_ap; | ||
5649 | priv->fw_alt = di->fw_image_sta; | ||
5650 | } else if (!ap_mode_default && di->fw_image_sta) { | ||
5651 | priv->fw_pref = di->fw_image_sta; | ||
5652 | priv->fw_alt = di->fw_image_ap; | ||
5653 | } else if (ap_mode_default && !di->fw_image_ap && di->fw_image_sta) { | ||
5654 | printk(KERN_WARNING "AP fw is unavailable. Using STA fw."); | ||
5655 | priv->fw_pref = di->fw_image_sta; | ||
5656 | } else if (!ap_mode_default && !di->fw_image_sta && di->fw_image_ap) { | ||
5657 | printk(KERN_WARNING "STA fw is unavailable. Using AP fw."); | ||
5658 | priv->fw_pref = di->fw_image_ap; | ||
5659 | } | ||
5660 | rc = mwl8k_init_firmware(hw, priv->fw_pref, true); | ||
5661 | if (rc) | ||
5662 | goto err_stop_firmware; | ||
5663 | return rc; | ||
5664 | |||
4128 | err_stop_firmware: | 5665 | err_stop_firmware: |
4129 | mwl8k_hw_reset(priv); | 5666 | mwl8k_hw_reset(priv); |
4130 | mwl8k_release_firmware(priv); | ||
4131 | 5667 | ||
4132 | err_iounmap: | 5668 | err_iounmap: |
4133 | if (priv->regs != NULL) | 5669 | if (priv->regs != NULL) |
@@ -4163,6 +5699,13 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev) | |||
4163 | return; | 5699 | return; |
4164 | priv = hw->priv; | 5700 | priv = hw->priv; |
4165 | 5701 | ||
5702 | wait_for_completion(&priv->firmware_loading_complete); | ||
5703 | |||
5704 | if (priv->fw_state == FW_STATE_ERROR) { | ||
5705 | mwl8k_hw_reset(priv); | ||
5706 | goto unmap; | ||
5707 | } | ||
5708 | |||
4166 | ieee80211_stop_queues(hw); | 5709 | ieee80211_stop_queues(hw); |
4167 | 5710 | ||
4168 | ieee80211_unregister_hw(hw); | 5711 | ieee80211_unregister_hw(hw); |
@@ -4175,16 +5718,17 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev) | |||
4175 | mwl8k_hw_reset(priv); | 5718 | mwl8k_hw_reset(priv); |
4176 | 5719 | ||
4177 | /* Return all skbs to mac80211 */ | 5720 | /* Return all skbs to mac80211 */ |
4178 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 5721 | for (i = 0; i < mwl8k_tx_queues(priv); i++) |
4179 | mwl8k_txq_reclaim(hw, i, INT_MAX, 1); | 5722 | mwl8k_txq_reclaim(hw, i, INT_MAX, 1); |
4180 | 5723 | ||
4181 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 5724 | for (i = 0; i < mwl8k_tx_queues(priv); i++) |
4182 | mwl8k_txq_deinit(hw, i); | 5725 | mwl8k_txq_deinit(hw, i); |
4183 | 5726 | ||
4184 | mwl8k_rxq_deinit(hw, 0); | 5727 | mwl8k_rxq_deinit(hw, 0); |
4185 | 5728 | ||
4186 | pci_free_consistent(priv->pdev, 4, priv->cookie, priv->cookie_dma); | 5729 | pci_free_consistent(priv->pdev, 4, priv->cookie, priv->cookie_dma); |
4187 | 5730 | ||
5731 | unmap: | ||
4188 | pci_iounmap(pdev, priv->regs); | 5732 | pci_iounmap(pdev, priv->regs); |
4189 | pci_iounmap(pdev, priv->sram); | 5733 | pci_iounmap(pdev, priv->sram); |
4190 | pci_set_drvdata(pdev, NULL); | 5734 | pci_set_drvdata(pdev, NULL); |