diff options
Diffstat (limited to 'drivers/net/wireless/mwl8k.c')
-rw-r--r-- | drivers/net/wireless/mwl8k.c | 1265 |
1 files changed, 909 insertions, 356 deletions
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 746532ebe5a8..0cb5ecc822a8 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
15 | #include <linux/sched.h> | ||
15 | #include <linux/spinlock.h> | 16 | #include <linux/spinlock.h> |
16 | #include <linux/list.h> | 17 | #include <linux/list.h> |
17 | #include <linux/pci.h> | 18 | #include <linux/pci.h> |
@@ -27,18 +28,6 @@ | |||
27 | #define MWL8K_NAME KBUILD_MODNAME | 28 | #define MWL8K_NAME KBUILD_MODNAME |
28 | #define MWL8K_VERSION "0.10" | 29 | #define MWL8K_VERSION "0.10" |
29 | 30 | ||
30 | MODULE_DESCRIPTION(MWL8K_DESC); | ||
31 | MODULE_VERSION(MWL8K_VERSION); | ||
32 | MODULE_AUTHOR("Lennert Buytenhek <buytenh@marvell.com>"); | ||
33 | MODULE_LICENSE("GPL"); | ||
34 | |||
35 | static DEFINE_PCI_DEVICE_TABLE(mwl8k_table) = { | ||
36 | { PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = 8687, }, | ||
37 | { PCI_VDEVICE(MARVELL, 0x2a30), .driver_data = 8687, }, | ||
38 | { } | ||
39 | }; | ||
40 | MODULE_DEVICE_TABLE(pci, mwl8k_table); | ||
41 | |||
42 | /* Register definitions */ | 31 | /* Register definitions */ |
43 | #define MWL8K_HIU_GEN_PTR 0x00000c10 | 32 | #define MWL8K_HIU_GEN_PTR 0x00000c10 |
44 | #define MWL8K_MODE_STA 0x0000005a | 33 | #define MWL8K_MODE_STA 0x0000005a |
@@ -88,72 +77,89 @@ MODULE_DEVICE_TABLE(pci, mwl8k_table); | |||
88 | MWL8K_A2H_INT_RX_READY | \ | 77 | MWL8K_A2H_INT_RX_READY | \ |
89 | MWL8K_A2H_INT_TX_DONE) | 78 | MWL8K_A2H_INT_TX_DONE) |
90 | 79 | ||
91 | /* WME stream classes */ | ||
92 | #define WME_AC_BE 0 /* best effort */ | ||
93 | #define WME_AC_BK 1 /* background */ | ||
94 | #define WME_AC_VI 2 /* video */ | ||
95 | #define WME_AC_VO 3 /* voice */ | ||
96 | |||
97 | #define MWL8K_RX_QUEUES 1 | 80 | #define MWL8K_RX_QUEUES 1 |
98 | #define MWL8K_TX_QUEUES 4 | 81 | #define MWL8K_TX_QUEUES 4 |
99 | 82 | ||
83 | struct rxd_ops { | ||
84 | int rxd_size; | ||
85 | void (*rxd_init)(void *rxd, dma_addr_t next_dma_addr); | ||
86 | void (*rxd_refill)(void *rxd, dma_addr_t addr, int len); | ||
87 | int (*rxd_process)(void *rxd, struct ieee80211_rx_status *status); | ||
88 | }; | ||
89 | |||
90 | struct mwl8k_device_info { | ||
91 | char *part_name; | ||
92 | char *helper_image; | ||
93 | char *fw_image; | ||
94 | struct rxd_ops *rxd_ops; | ||
95 | u16 modes; | ||
96 | }; | ||
97 | |||
100 | struct mwl8k_rx_queue { | 98 | struct mwl8k_rx_queue { |
101 | int rx_desc_count; | 99 | int rxd_count; |
102 | 100 | ||
103 | /* hw receives here */ | 101 | /* hw receives here */ |
104 | int rx_head; | 102 | int head; |
105 | 103 | ||
106 | /* refill descs here */ | 104 | /* refill descs here */ |
107 | int rx_tail; | 105 | int tail; |
108 | 106 | ||
109 | struct mwl8k_rx_desc *rx_desc_area; | 107 | void *rxd; |
110 | dma_addr_t rx_desc_dma; | 108 | dma_addr_t rxd_dma; |
111 | struct sk_buff **rx_skb; | 109 | struct { |
110 | struct sk_buff *skb; | ||
111 | DECLARE_PCI_UNMAP_ADDR(dma) | ||
112 | } *buf; | ||
112 | }; | 113 | }; |
113 | 114 | ||
114 | struct mwl8k_tx_queue { | 115 | struct mwl8k_tx_queue { |
115 | /* hw transmits here */ | 116 | /* hw transmits here */ |
116 | int tx_head; | 117 | int head; |
117 | 118 | ||
118 | /* sw appends here */ | 119 | /* sw appends here */ |
119 | int tx_tail; | 120 | int tail; |
120 | 121 | ||
121 | struct ieee80211_tx_queue_stats tx_stats; | 122 | struct ieee80211_tx_queue_stats stats; |
122 | struct mwl8k_tx_desc *tx_desc_area; | 123 | struct mwl8k_tx_desc *txd; |
123 | dma_addr_t tx_desc_dma; | 124 | dma_addr_t txd_dma; |
124 | struct sk_buff **tx_skb; | 125 | struct sk_buff **skb; |
125 | }; | 126 | }; |
126 | 127 | ||
127 | /* Pointers to the firmware data and meta information about it. */ | 128 | /* Pointers to the firmware data and meta information about it. */ |
128 | struct mwl8k_firmware { | 129 | struct mwl8k_firmware { |
129 | /* Microcode */ | ||
130 | struct firmware *ucode; | ||
131 | |||
132 | /* Boot helper code */ | 130 | /* Boot helper code */ |
133 | struct firmware *helper; | 131 | struct firmware *helper; |
132 | |||
133 | /* Microcode */ | ||
134 | struct firmware *ucode; | ||
134 | }; | 135 | }; |
135 | 136 | ||
136 | struct mwl8k_priv { | 137 | struct mwl8k_priv { |
138 | void __iomem *sram; | ||
137 | void __iomem *regs; | 139 | void __iomem *regs; |
138 | struct ieee80211_hw *hw; | 140 | struct ieee80211_hw *hw; |
139 | 141 | ||
140 | struct pci_dev *pdev; | 142 | struct pci_dev *pdev; |
141 | u8 name[16]; | 143 | |
144 | struct mwl8k_device_info *device_info; | ||
145 | bool ap_fw; | ||
146 | struct rxd_ops *rxd_ops; | ||
142 | 147 | ||
143 | /* firmware files and meta data */ | 148 | /* firmware files and meta data */ |
144 | struct mwl8k_firmware fw; | 149 | struct mwl8k_firmware fw; |
145 | u32 part_num; | ||
146 | 150 | ||
147 | /* firmware access */ | 151 | /* firmware access */ |
148 | struct mutex fw_mutex; | 152 | struct mutex fw_mutex; |
149 | struct task_struct *fw_mutex_owner; | 153 | struct task_struct *fw_mutex_owner; |
150 | int fw_mutex_depth; | 154 | int fw_mutex_depth; |
151 | struct completion *tx_wait; | ||
152 | struct completion *hostcmd_wait; | 155 | struct completion *hostcmd_wait; |
153 | 156 | ||
154 | /* lock held over TX and TX reap */ | 157 | /* lock held over TX and TX reap */ |
155 | spinlock_t tx_lock; | 158 | spinlock_t tx_lock; |
156 | 159 | ||
160 | /* TX quiesce completion, protected by fw_mutex and tx_lock */ | ||
161 | struct completion *tx_wait; | ||
162 | |||
157 | struct ieee80211_vif *vif; | 163 | struct ieee80211_vif *vif; |
158 | 164 | ||
159 | struct ieee80211_channel *current_channel; | 165 | struct ieee80211_channel *current_channel; |
@@ -178,10 +184,11 @@ struct mwl8k_priv { | |||
178 | /* PHY parameters */ | 184 | /* PHY parameters */ |
179 | struct ieee80211_supported_band band; | 185 | struct ieee80211_supported_band band; |
180 | struct ieee80211_channel channels[14]; | 186 | struct ieee80211_channel channels[14]; |
181 | struct ieee80211_rate rates[12]; | 187 | struct ieee80211_rate rates[13]; |
182 | 188 | ||
183 | bool radio_on; | 189 | bool radio_on; |
184 | bool radio_short_preamble; | 190 | bool radio_short_preamble; |
191 | bool sniffer_enabled; | ||
185 | bool wmm_enabled; | 192 | bool wmm_enabled; |
186 | 193 | ||
187 | /* XXX need to convert this to handle multiple interfaces */ | 194 | /* XXX need to convert this to handle multiple interfaces */ |
@@ -199,9 +206,6 @@ struct mwl8k_priv { | |||
199 | 206 | ||
200 | /* Tasklet to reclaim TX descriptors and buffers after tx */ | 207 | /* Tasklet to reclaim TX descriptors and buffers after tx */ |
201 | struct tasklet_struct tx_reclaim_task; | 208 | struct tasklet_struct tx_reclaim_task; |
202 | |||
203 | /* Work thread to serialize configuration requests */ | ||
204 | struct workqueue_struct *config_wq; | ||
205 | }; | 209 | }; |
206 | 210 | ||
207 | /* Per interface specific private data */ | 211 | /* Per interface specific private data */ |
@@ -220,7 +224,7 @@ struct mwl8k_vif { | |||
220 | * Subset of supported legacy rates. | 224 | * Subset of supported legacy rates. |
221 | * Intersection of AP and STA supported rates. | 225 | * Intersection of AP and STA supported rates. |
222 | */ | 226 | */ |
223 | struct ieee80211_rate legacy_rates[12]; | 227 | struct ieee80211_rate legacy_rates[13]; |
224 | 228 | ||
225 | /* number of supported legacy rates */ | 229 | /* number of supported legacy rates */ |
226 | u8 legacy_nrates; | 230 | u8 legacy_nrates; |
@@ -252,9 +256,10 @@ static const struct ieee80211_rate mwl8k_rates[] = { | |||
252 | { .bitrate = 10, .hw_value = 2, }, | 256 | { .bitrate = 10, .hw_value = 2, }, |
253 | { .bitrate = 20, .hw_value = 4, }, | 257 | { .bitrate = 20, .hw_value = 4, }, |
254 | { .bitrate = 55, .hw_value = 11, }, | 258 | { .bitrate = 55, .hw_value = 11, }, |
259 | { .bitrate = 110, .hw_value = 22, }, | ||
260 | { .bitrate = 220, .hw_value = 44, }, | ||
255 | { .bitrate = 60, .hw_value = 12, }, | 261 | { .bitrate = 60, .hw_value = 12, }, |
256 | { .bitrate = 90, .hw_value = 18, }, | 262 | { .bitrate = 90, .hw_value = 18, }, |
257 | { .bitrate = 110, .hw_value = 22, }, | ||
258 | { .bitrate = 120, .hw_value = 24, }, | 263 | { .bitrate = 120, .hw_value = 24, }, |
259 | { .bitrate = 180, .hw_value = 36, }, | 264 | { .bitrate = 180, .hw_value = 36, }, |
260 | { .bitrate = 240, .hw_value = 48, }, | 265 | { .bitrate = 240, .hw_value = 48, }, |
@@ -270,10 +275,12 @@ static const struct ieee80211_rate mwl8k_rates[] = { | |||
270 | /* Firmware command codes */ | 275 | /* Firmware command codes */ |
271 | #define MWL8K_CMD_CODE_DNLD 0x0001 | 276 | #define MWL8K_CMD_CODE_DNLD 0x0001 |
272 | #define MWL8K_CMD_GET_HW_SPEC 0x0003 | 277 | #define MWL8K_CMD_GET_HW_SPEC 0x0003 |
278 | #define MWL8K_CMD_SET_HW_SPEC 0x0004 | ||
273 | #define MWL8K_CMD_MAC_MULTICAST_ADR 0x0010 | 279 | #define MWL8K_CMD_MAC_MULTICAST_ADR 0x0010 |
274 | #define MWL8K_CMD_GET_STAT 0x0014 | 280 | #define MWL8K_CMD_GET_STAT 0x0014 |
275 | #define MWL8K_CMD_RADIO_CONTROL 0x001c | 281 | #define MWL8K_CMD_RADIO_CONTROL 0x001c |
276 | #define MWL8K_CMD_RF_TX_POWER 0x001e | 282 | #define MWL8K_CMD_RF_TX_POWER 0x001e |
283 | #define MWL8K_CMD_RF_ANTENNA 0x0020 | ||
277 | #define MWL8K_CMD_SET_PRE_SCAN 0x0107 | 284 | #define MWL8K_CMD_SET_PRE_SCAN 0x0107 |
278 | #define MWL8K_CMD_SET_POST_SCAN 0x0108 | 285 | #define MWL8K_CMD_SET_POST_SCAN 0x0108 |
279 | #define MWL8K_CMD_SET_RF_CHANNEL 0x010a | 286 | #define MWL8K_CMD_SET_RF_CHANNEL 0x010a |
@@ -287,6 +294,7 @@ static const struct ieee80211_rate mwl8k_rates[] = { | |||
287 | #define MWL8K_CMD_MIMO_CONFIG 0x0125 | 294 | #define MWL8K_CMD_MIMO_CONFIG 0x0125 |
288 | #define MWL8K_CMD_USE_FIXED_RATE 0x0126 | 295 | #define MWL8K_CMD_USE_FIXED_RATE 0x0126 |
289 | #define MWL8K_CMD_ENABLE_SNIFFER 0x0150 | 296 | #define MWL8K_CMD_ENABLE_SNIFFER 0x0150 |
297 | #define MWL8K_CMD_SET_MAC_ADDR 0x0202 | ||
290 | #define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 | 298 | #define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 |
291 | #define MWL8K_CMD_UPDATE_STADB 0x1123 | 299 | #define MWL8K_CMD_UPDATE_STADB 0x1123 |
292 | 300 | ||
@@ -299,10 +307,12 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize) | |||
299 | switch (cmd & ~0x8000) { | 307 | switch (cmd & ~0x8000) { |
300 | MWL8K_CMDNAME(CODE_DNLD); | 308 | MWL8K_CMDNAME(CODE_DNLD); |
301 | MWL8K_CMDNAME(GET_HW_SPEC); | 309 | MWL8K_CMDNAME(GET_HW_SPEC); |
310 | MWL8K_CMDNAME(SET_HW_SPEC); | ||
302 | MWL8K_CMDNAME(MAC_MULTICAST_ADR); | 311 | MWL8K_CMDNAME(MAC_MULTICAST_ADR); |
303 | MWL8K_CMDNAME(GET_STAT); | 312 | MWL8K_CMDNAME(GET_STAT); |
304 | MWL8K_CMDNAME(RADIO_CONTROL); | 313 | MWL8K_CMDNAME(RADIO_CONTROL); |
305 | MWL8K_CMDNAME(RF_TX_POWER); | 314 | MWL8K_CMDNAME(RF_TX_POWER); |
315 | MWL8K_CMDNAME(RF_ANTENNA); | ||
306 | MWL8K_CMDNAME(SET_PRE_SCAN); | 316 | MWL8K_CMDNAME(SET_PRE_SCAN); |
307 | MWL8K_CMDNAME(SET_POST_SCAN); | 317 | MWL8K_CMDNAME(SET_POST_SCAN); |
308 | MWL8K_CMDNAME(SET_RF_CHANNEL); | 318 | MWL8K_CMDNAME(SET_RF_CHANNEL); |
@@ -316,6 +326,7 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize) | |||
316 | MWL8K_CMDNAME(MIMO_CONFIG); | 326 | MWL8K_CMDNAME(MIMO_CONFIG); |
317 | MWL8K_CMDNAME(USE_FIXED_RATE); | 327 | MWL8K_CMDNAME(USE_FIXED_RATE); |
318 | MWL8K_CMDNAME(ENABLE_SNIFFER); | 328 | MWL8K_CMDNAME(ENABLE_SNIFFER); |
329 | MWL8K_CMDNAME(SET_MAC_ADDR); | ||
319 | MWL8K_CMDNAME(SET_RATEADAPT_MODE); | 330 | MWL8K_CMDNAME(SET_RATEADAPT_MODE); |
320 | MWL8K_CMDNAME(UPDATE_STADB); | 331 | MWL8K_CMDNAME(UPDATE_STADB); |
321 | default: | 332 | default: |
@@ -353,41 +364,35 @@ static void mwl8k_release_firmware(struct mwl8k_priv *priv) | |||
353 | 364 | ||
354 | /* Request fw image */ | 365 | /* Request fw image */ |
355 | static int mwl8k_request_fw(struct mwl8k_priv *priv, | 366 | static int mwl8k_request_fw(struct mwl8k_priv *priv, |
356 | const char *fname, struct firmware **fw) | 367 | const char *fname, struct firmware **fw) |
357 | { | 368 | { |
358 | /* release current image */ | 369 | /* release current image */ |
359 | if (*fw != NULL) | 370 | if (*fw != NULL) |
360 | mwl8k_release_fw(fw); | 371 | mwl8k_release_fw(fw); |
361 | 372 | ||
362 | return request_firmware((const struct firmware **)fw, | 373 | return request_firmware((const struct firmware **)fw, |
363 | fname, &priv->pdev->dev); | 374 | fname, &priv->pdev->dev); |
364 | } | 375 | } |
365 | 376 | ||
366 | static int mwl8k_request_firmware(struct mwl8k_priv *priv, u32 part_num) | 377 | static int mwl8k_request_firmware(struct mwl8k_priv *priv) |
367 | { | 378 | { |
368 | u8 filename[64]; | 379 | struct mwl8k_device_info *di = priv->device_info; |
369 | int rc; | 380 | int rc; |
370 | 381 | ||
371 | priv->part_num = part_num; | 382 | if (di->helper_image != NULL) { |
372 | 383 | rc = mwl8k_request_fw(priv, di->helper_image, &priv->fw.helper); | |
373 | snprintf(filename, sizeof(filename), | 384 | if (rc) { |
374 | "mwl8k/helper_%u.fw", priv->part_num); | 385 | printk(KERN_ERR "%s: Error requesting helper " |
375 | 386 | "firmware file %s\n", pci_name(priv->pdev), | |
376 | rc = mwl8k_request_fw(priv, filename, &priv->fw.helper); | 387 | di->helper_image); |
377 | if (rc) { | 388 | return rc; |
378 | printk(KERN_ERR | 389 | } |
379 | "%s Error requesting helper firmware file %s\n", | ||
380 | pci_name(priv->pdev), filename); | ||
381 | return rc; | ||
382 | } | 390 | } |
383 | 391 | ||
384 | snprintf(filename, sizeof(filename), | 392 | rc = mwl8k_request_fw(priv, di->fw_image, &priv->fw.ucode); |
385 | "mwl8k/fmimage_%u.fw", priv->part_num); | ||
386 | |||
387 | rc = mwl8k_request_fw(priv, filename, &priv->fw.ucode); | ||
388 | if (rc) { | 393 | if (rc) { |
389 | printk(KERN_ERR "%s Error requesting firmware file %s\n", | 394 | printk(KERN_ERR "%s: Error requesting firmware file %s\n", |
390 | pci_name(priv->pdev), filename); | 395 | pci_name(priv->pdev), di->fw_image); |
391 | mwl8k_release_fw(&priv->fw.helper); | 396 | mwl8k_release_fw(&priv->fw.helper); |
392 | return rc; | 397 | return rc; |
393 | } | 398 | } |
@@ -395,6 +400,9 @@ static int mwl8k_request_firmware(struct mwl8k_priv *priv, u32 part_num) | |||
395 | return 0; | 400 | return 0; |
396 | } | 401 | } |
397 | 402 | ||
403 | MODULE_FIRMWARE("mwl8k/helper_8687.fw"); | ||
404 | MODULE_FIRMWARE("mwl8k/fmimage_8687.fw"); | ||
405 | |||
398 | struct mwl8k_cmd_pkt { | 406 | struct mwl8k_cmd_pkt { |
399 | __le16 code; | 407 | __le16 code; |
400 | __le16 length; | 408 | __le16 length; |
@@ -434,6 +442,7 @@ mwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length) | |||
434 | break; | 442 | break; |
435 | } | 443 | } |
436 | 444 | ||
445 | cond_resched(); | ||
437 | udelay(1); | 446 | udelay(1); |
438 | } while (--loops); | 447 | } while (--loops); |
439 | 448 | ||
@@ -542,43 +551,62 @@ static int mwl8k_feed_fw_image(struct mwl8k_priv *priv, | |||
542 | return rc; | 551 | return rc; |
543 | } | 552 | } |
544 | 553 | ||
545 | static int mwl8k_load_firmware(struct mwl8k_priv *priv) | 554 | static int mwl8k_load_firmware(struct ieee80211_hw *hw) |
546 | { | 555 | { |
547 | int loops, rc; | 556 | struct mwl8k_priv *priv = hw->priv; |
557 | struct firmware *fw = priv->fw.ucode; | ||
558 | struct mwl8k_device_info *di = priv->device_info; | ||
559 | int rc; | ||
560 | int loops; | ||
548 | 561 | ||
549 | const u8 *ucode = priv->fw.ucode->data; | 562 | if (!memcmp(fw->data, "\x01\x00\x00\x00", 4)) { |
550 | size_t ucode_len = priv->fw.ucode->size; | 563 | struct firmware *helper = priv->fw.helper; |
551 | const u8 *helper = priv->fw.helper->data; | ||
552 | size_t helper_len = priv->fw.helper->size; | ||
553 | 564 | ||
554 | if (!memcmp(ucode, "\x01\x00\x00\x00", 4)) { | 565 | if (helper == NULL) { |
555 | rc = mwl8k_load_fw_image(priv, helper, helper_len); | 566 | printk(KERN_ERR "%s: helper image needed but none " |
567 | "given\n", pci_name(priv->pdev)); | ||
568 | return -EINVAL; | ||
569 | } | ||
570 | |||
571 | rc = mwl8k_load_fw_image(priv, helper->data, helper->size); | ||
556 | if (rc) { | 572 | if (rc) { |
557 | printk(KERN_ERR "%s: unable to load firmware " | 573 | printk(KERN_ERR "%s: unable to load firmware " |
558 | "helper image\n", pci_name(priv->pdev)); | 574 | "helper image\n", pci_name(priv->pdev)); |
559 | return rc; | 575 | return rc; |
560 | } | 576 | } |
561 | msleep(1); | 577 | msleep(1); |
562 | 578 | ||
563 | rc = mwl8k_feed_fw_image(priv, ucode, ucode_len); | 579 | rc = mwl8k_feed_fw_image(priv, fw->data, fw->size); |
564 | } else { | 580 | } else { |
565 | rc = mwl8k_load_fw_image(priv, ucode, ucode_len); | 581 | rc = mwl8k_load_fw_image(priv, fw->data, fw->size); |
566 | } | 582 | } |
567 | 583 | ||
568 | if (rc) { | 584 | if (rc) { |
569 | printk(KERN_ERR "%s: unable to load firmware data\n", | 585 | printk(KERN_ERR "%s: unable to load firmware image\n", |
570 | pci_name(priv->pdev)); | 586 | pci_name(priv->pdev)); |
571 | return rc; | 587 | return rc; |
572 | } | 588 | } |
573 | 589 | ||
574 | iowrite32(MWL8K_MODE_STA, priv->regs + MWL8K_HIU_GEN_PTR); | 590 | if (di->modes & BIT(NL80211_IFTYPE_AP)) |
591 | iowrite32(MWL8K_MODE_AP, priv->regs + MWL8K_HIU_GEN_PTR); | ||
592 | else | ||
593 | iowrite32(MWL8K_MODE_STA, priv->regs + MWL8K_HIU_GEN_PTR); | ||
575 | msleep(1); | 594 | msleep(1); |
576 | 595 | ||
577 | loops = 200000; | 596 | loops = 200000; |
578 | do { | 597 | do { |
579 | if (ioread32(priv->regs + MWL8K_HIU_INT_CODE) | 598 | u32 ready_code; |
580 | == MWL8K_FWSTA_READY) | 599 | |
600 | ready_code = ioread32(priv->regs + MWL8K_HIU_INT_CODE); | ||
601 | if (ready_code == MWL8K_FWAP_READY) { | ||
602 | priv->ap_fw = 1; | ||
603 | break; | ||
604 | } else if (ready_code == MWL8K_FWSTA_READY) { | ||
605 | priv->ap_fw = 0; | ||
581 | break; | 606 | break; |
607 | } | ||
608 | |||
609 | cond_resched(); | ||
582 | udelay(1); | 610 | udelay(1); |
583 | } while (--loops); | 611 | } while (--loops); |
584 | 612 | ||
@@ -605,7 +633,7 @@ struct ewc_ht_info { | |||
605 | /* Peer Entry flags - used to define the type of the peer node */ | 633 | /* Peer Entry flags - used to define the type of the peer node */ |
606 | #define MWL8K_PEER_TYPE_ACCESSPOINT 2 | 634 | #define MWL8K_PEER_TYPE_ACCESSPOINT 2 |
607 | 635 | ||
608 | #define MWL8K_IEEE_LEGACY_DATA_RATES 12 | 636 | #define MWL8K_IEEE_LEGACY_DATA_RATES 13 |
609 | #define MWL8K_MCS_BITMAP_SIZE 16 | 637 | #define MWL8K_MCS_BITMAP_SIZE 16 |
610 | 638 | ||
611 | struct peer_capability_info { | 639 | struct peer_capability_info { |
@@ -731,16 +759,96 @@ static inline void mwl8k_add_dma_header(struct sk_buff *skb) | |||
731 | 759 | ||
732 | 760 | ||
733 | /* | 761 | /* |
734 | * Packet reception. | 762 | * Packet reception for 88w8366. |
735 | */ | 763 | */ |
736 | #define MWL8K_RX_CTRL_OWNED_BY_HOST 0x02 | 764 | struct mwl8k_rxd_8366 { |
765 | __le16 pkt_len; | ||
766 | __u8 sq2; | ||
767 | __u8 rate; | ||
768 | __le32 pkt_phys_addr; | ||
769 | __le32 next_rxd_phys_addr; | ||
770 | __le16 qos_control; | ||
771 | __le16 htsig2; | ||
772 | __le32 hw_rssi_info; | ||
773 | __le32 hw_noise_floor_info; | ||
774 | __u8 noise_floor; | ||
775 | __u8 pad0[3]; | ||
776 | __u8 rssi; | ||
777 | __u8 rx_status; | ||
778 | __u8 channel; | ||
779 | __u8 rx_ctrl; | ||
780 | } __attribute__((packed)); | ||
781 | |||
782 | #define MWL8K_8366_RX_CTRL_OWNED_BY_HOST 0x80 | ||
783 | |||
784 | static void mwl8k_rxd_8366_init(void *_rxd, dma_addr_t next_dma_addr) | ||
785 | { | ||
786 | struct mwl8k_rxd_8366 *rxd = _rxd; | ||
787 | |||
788 | rxd->next_rxd_phys_addr = cpu_to_le32(next_dma_addr); | ||
789 | rxd->rx_ctrl = MWL8K_8366_RX_CTRL_OWNED_BY_HOST; | ||
790 | } | ||
791 | |||
792 | static void mwl8k_rxd_8366_refill(void *_rxd, dma_addr_t addr, int len) | ||
793 | { | ||
794 | struct mwl8k_rxd_8366 *rxd = _rxd; | ||
795 | |||
796 | rxd->pkt_len = cpu_to_le16(len); | ||
797 | rxd->pkt_phys_addr = cpu_to_le32(addr); | ||
798 | wmb(); | ||
799 | rxd->rx_ctrl = 0; | ||
800 | } | ||
801 | |||
802 | static int | ||
803 | mwl8k_rxd_8366_process(void *_rxd, struct ieee80211_rx_status *status) | ||
804 | { | ||
805 | struct mwl8k_rxd_8366 *rxd = _rxd; | ||
806 | |||
807 | if (!(rxd->rx_ctrl & MWL8K_8366_RX_CTRL_OWNED_BY_HOST)) | ||
808 | return -1; | ||
809 | rmb(); | ||
810 | |||
811 | memset(status, 0, sizeof(*status)); | ||
812 | |||
813 | status->signal = -rxd->rssi; | ||
814 | status->noise = -rxd->noise_floor; | ||
737 | 815 | ||
738 | struct mwl8k_rx_desc { | 816 | if (rxd->rate & 0x80) { |
817 | status->flag |= RX_FLAG_HT; | ||
818 | status->rate_idx = rxd->rate & 0x7f; | ||
819 | } else { | ||
820 | int i; | ||
821 | |||
822 | for (i = 0; i < ARRAY_SIZE(mwl8k_rates); i++) { | ||
823 | if (mwl8k_rates[i].hw_value == rxd->rate) { | ||
824 | status->rate_idx = i; | ||
825 | break; | ||
826 | } | ||
827 | } | ||
828 | } | ||
829 | |||
830 | status->band = IEEE80211_BAND_2GHZ; | ||
831 | status->freq = ieee80211_channel_to_frequency(rxd->channel); | ||
832 | |||
833 | return le16_to_cpu(rxd->pkt_len); | ||
834 | } | ||
835 | |||
836 | static struct rxd_ops rxd_8366_ops = { | ||
837 | .rxd_size = sizeof(struct mwl8k_rxd_8366), | ||
838 | .rxd_init = mwl8k_rxd_8366_init, | ||
839 | .rxd_refill = mwl8k_rxd_8366_refill, | ||
840 | .rxd_process = mwl8k_rxd_8366_process, | ||
841 | }; | ||
842 | |||
843 | /* | ||
844 | * Packet reception for 88w8687. | ||
845 | */ | ||
846 | struct mwl8k_rxd_8687 { | ||
739 | __le16 pkt_len; | 847 | __le16 pkt_len; |
740 | __u8 link_quality; | 848 | __u8 link_quality; |
741 | __u8 noise_level; | 849 | __u8 noise_level; |
742 | __le32 pkt_phys_addr; | 850 | __le32 pkt_phys_addr; |
743 | __le32 next_rx_desc_phys_addr; | 851 | __le32 next_rxd_phys_addr; |
744 | __le16 qos_control; | 852 | __le16 qos_control; |
745 | __le16 rate_info; | 853 | __le16 rate_info; |
746 | __le32 pad0[4]; | 854 | __le32 pad0[4]; |
@@ -752,6 +860,76 @@ struct mwl8k_rx_desc { | |||
752 | __u8 pad2[2]; | 860 | __u8 pad2[2]; |
753 | } __attribute__((packed)); | 861 | } __attribute__((packed)); |
754 | 862 | ||
863 | #define MWL8K_8687_RATE_INFO_SHORTPRE 0x8000 | ||
864 | #define MWL8K_8687_RATE_INFO_ANTSELECT(x) (((x) >> 11) & 0x3) | ||
865 | #define MWL8K_8687_RATE_INFO_RATEID(x) (((x) >> 3) & 0x3f) | ||
866 | #define MWL8K_8687_RATE_INFO_40MHZ 0x0004 | ||
867 | #define MWL8K_8687_RATE_INFO_SHORTGI 0x0002 | ||
868 | #define MWL8K_8687_RATE_INFO_MCS_FORMAT 0x0001 | ||
869 | |||
870 | #define MWL8K_8687_RX_CTRL_OWNED_BY_HOST 0x02 | ||
871 | |||
872 | static void mwl8k_rxd_8687_init(void *_rxd, dma_addr_t next_dma_addr) | ||
873 | { | ||
874 | struct mwl8k_rxd_8687 *rxd = _rxd; | ||
875 | |||
876 | rxd->next_rxd_phys_addr = cpu_to_le32(next_dma_addr); | ||
877 | rxd->rx_ctrl = MWL8K_8687_RX_CTRL_OWNED_BY_HOST; | ||
878 | } | ||
879 | |||
880 | static void mwl8k_rxd_8687_refill(void *_rxd, dma_addr_t addr, int len) | ||
881 | { | ||
882 | struct mwl8k_rxd_8687 *rxd = _rxd; | ||
883 | |||
884 | rxd->pkt_len = cpu_to_le16(len); | ||
885 | rxd->pkt_phys_addr = cpu_to_le32(addr); | ||
886 | wmb(); | ||
887 | rxd->rx_ctrl = 0; | ||
888 | } | ||
889 | |||
890 | static int | ||
891 | mwl8k_rxd_8687_process(void *_rxd, struct ieee80211_rx_status *status) | ||
892 | { | ||
893 | struct mwl8k_rxd_8687 *rxd = _rxd; | ||
894 | u16 rate_info; | ||
895 | |||
896 | if (!(rxd->rx_ctrl & MWL8K_8687_RX_CTRL_OWNED_BY_HOST)) | ||
897 | return -1; | ||
898 | rmb(); | ||
899 | |||
900 | rate_info = le16_to_cpu(rxd->rate_info); | ||
901 | |||
902 | memset(status, 0, sizeof(*status)); | ||
903 | |||
904 | status->signal = -rxd->rssi; | ||
905 | status->noise = -rxd->noise_level; | ||
906 | status->qual = rxd->link_quality; | ||
907 | status->antenna = MWL8K_8687_RATE_INFO_ANTSELECT(rate_info); | ||
908 | status->rate_idx = MWL8K_8687_RATE_INFO_RATEID(rate_info); | ||
909 | |||
910 | if (rate_info & MWL8K_8687_RATE_INFO_SHORTPRE) | ||
911 | status->flag |= RX_FLAG_SHORTPRE; | ||
912 | if (rate_info & MWL8K_8687_RATE_INFO_40MHZ) | ||
913 | status->flag |= RX_FLAG_40MHZ; | ||
914 | if (rate_info & MWL8K_8687_RATE_INFO_SHORTGI) | ||
915 | status->flag |= RX_FLAG_SHORT_GI; | ||
916 | if (rate_info & MWL8K_8687_RATE_INFO_MCS_FORMAT) | ||
917 | status->flag |= RX_FLAG_HT; | ||
918 | |||
919 | status->band = IEEE80211_BAND_2GHZ; | ||
920 | status->freq = ieee80211_channel_to_frequency(rxd->channel); | ||
921 | |||
922 | return le16_to_cpu(rxd->pkt_len); | ||
923 | } | ||
924 | |||
925 | static struct rxd_ops rxd_8687_ops = { | ||
926 | .rxd_size = sizeof(struct mwl8k_rxd_8687), | ||
927 | .rxd_init = mwl8k_rxd_8687_init, | ||
928 | .rxd_refill = mwl8k_rxd_8687_refill, | ||
929 | .rxd_process = mwl8k_rxd_8687_process, | ||
930 | }; | ||
931 | |||
932 | |||
755 | #define MWL8K_RX_DESCS 256 | 933 | #define MWL8K_RX_DESCS 256 |
756 | #define MWL8K_RX_MAXSZ 3800 | 934 | #define MWL8K_RX_MAXSZ 3800 |
757 | 935 | ||
@@ -762,43 +940,44 @@ static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index) | |||
762 | int size; | 940 | int size; |
763 | int i; | 941 | int i; |
764 | 942 | ||
765 | rxq->rx_desc_count = 0; | 943 | rxq->rxd_count = 0; |
766 | rxq->rx_head = 0; | 944 | rxq->head = 0; |
767 | rxq->rx_tail = 0; | 945 | rxq->tail = 0; |
768 | 946 | ||
769 | size = MWL8K_RX_DESCS * sizeof(struct mwl8k_rx_desc); | 947 | size = MWL8K_RX_DESCS * priv->rxd_ops->rxd_size; |
770 | 948 | ||
771 | rxq->rx_desc_area = | 949 | rxq->rxd = pci_alloc_consistent(priv->pdev, size, &rxq->rxd_dma); |
772 | pci_alloc_consistent(priv->pdev, size, &rxq->rx_desc_dma); | 950 | if (rxq->rxd == NULL) { |
773 | if (rxq->rx_desc_area == NULL) { | ||
774 | printk(KERN_ERR "%s: failed to alloc RX descriptors\n", | 951 | printk(KERN_ERR "%s: failed to alloc RX descriptors\n", |
775 | priv->name); | 952 | wiphy_name(hw->wiphy)); |
776 | return -ENOMEM; | 953 | return -ENOMEM; |
777 | } | 954 | } |
778 | memset(rxq->rx_desc_area, 0, size); | 955 | memset(rxq->rxd, 0, size); |
779 | 956 | ||
780 | rxq->rx_skb = kmalloc(MWL8K_RX_DESCS * | 957 | rxq->buf = kmalloc(MWL8K_RX_DESCS * sizeof(*rxq->buf), GFP_KERNEL); |
781 | sizeof(*rxq->rx_skb), GFP_KERNEL); | 958 | if (rxq->buf == NULL) { |
782 | if (rxq->rx_skb == NULL) { | ||
783 | printk(KERN_ERR "%s: failed to alloc RX skbuff list\n", | 959 | printk(KERN_ERR "%s: failed to alloc RX skbuff list\n", |
784 | priv->name); | 960 | wiphy_name(hw->wiphy)); |
785 | pci_free_consistent(priv->pdev, size, | 961 | pci_free_consistent(priv->pdev, size, rxq->rxd, rxq->rxd_dma); |
786 | rxq->rx_desc_area, rxq->rx_desc_dma); | ||
787 | return -ENOMEM; | 962 | return -ENOMEM; |
788 | } | 963 | } |
789 | memset(rxq->rx_skb, 0, MWL8K_RX_DESCS * sizeof(*rxq->rx_skb)); | 964 | memset(rxq->buf, 0, MWL8K_RX_DESCS * sizeof(*rxq->buf)); |
790 | 965 | ||
791 | for (i = 0; i < MWL8K_RX_DESCS; i++) { | 966 | for (i = 0; i < MWL8K_RX_DESCS; i++) { |
792 | struct mwl8k_rx_desc *rx_desc; | 967 | int desc_size; |
968 | void *rxd; | ||
793 | int nexti; | 969 | int nexti; |
970 | dma_addr_t next_dma_addr; | ||
794 | 971 | ||
795 | rx_desc = rxq->rx_desc_area + i; | 972 | desc_size = priv->rxd_ops->rxd_size; |
796 | nexti = (i + 1) % MWL8K_RX_DESCS; | 973 | rxd = rxq->rxd + (i * priv->rxd_ops->rxd_size); |
797 | 974 | ||
798 | rx_desc->next_rx_desc_phys_addr = | 975 | nexti = i + 1; |
799 | cpu_to_le32(rxq->rx_desc_dma | 976 | if (nexti == MWL8K_RX_DESCS) |
800 | + nexti * sizeof(*rx_desc)); | 977 | nexti = 0; |
801 | rx_desc->rx_ctrl = MWL8K_RX_CTRL_OWNED_BY_HOST; | 978 | next_dma_addr = rxq->rxd_dma + (nexti * desc_size); |
979 | |||
980 | priv->rxd_ops->rxd_init(rxd, next_dma_addr); | ||
802 | } | 981 | } |
803 | 982 | ||
804 | return 0; | 983 | return 0; |
@@ -811,27 +990,28 @@ static int rxq_refill(struct ieee80211_hw *hw, int index, int limit) | |||
811 | int refilled; | 990 | int refilled; |
812 | 991 | ||
813 | refilled = 0; | 992 | refilled = 0; |
814 | while (rxq->rx_desc_count < MWL8K_RX_DESCS && limit--) { | 993 | while (rxq->rxd_count < MWL8K_RX_DESCS && limit--) { |
815 | struct sk_buff *skb; | 994 | struct sk_buff *skb; |
995 | dma_addr_t addr; | ||
816 | int rx; | 996 | int rx; |
997 | void *rxd; | ||
817 | 998 | ||
818 | skb = dev_alloc_skb(MWL8K_RX_MAXSZ); | 999 | skb = dev_alloc_skb(MWL8K_RX_MAXSZ); |
819 | if (skb == NULL) | 1000 | if (skb == NULL) |
820 | break; | 1001 | break; |
821 | 1002 | ||
822 | rxq->rx_desc_count++; | 1003 | addr = pci_map_single(priv->pdev, skb->data, |
823 | 1004 | MWL8K_RX_MAXSZ, DMA_FROM_DEVICE); | |
824 | rx = rxq->rx_tail; | ||
825 | rxq->rx_tail = (rx + 1) % MWL8K_RX_DESCS; | ||
826 | 1005 | ||
827 | rxq->rx_desc_area[rx].pkt_phys_addr = | 1006 | rxq->rxd_count++; |
828 | cpu_to_le32(pci_map_single(priv->pdev, skb->data, | 1007 | rx = rxq->tail++; |
829 | MWL8K_RX_MAXSZ, DMA_FROM_DEVICE)); | 1008 | if (rxq->tail == MWL8K_RX_DESCS) |
1009 | rxq->tail = 0; | ||
1010 | rxq->buf[rx].skb = skb; | ||
1011 | pci_unmap_addr_set(&rxq->buf[rx], dma, addr); | ||
830 | 1012 | ||
831 | rxq->rx_desc_area[rx].pkt_len = cpu_to_le16(MWL8K_RX_MAXSZ); | 1013 | rxd = rxq->rxd + (rx * priv->rxd_ops->rxd_size); |
832 | rxq->rx_skb[rx] = skb; | 1014 | priv->rxd_ops->rxd_refill(rxd, addr, MWL8K_RX_MAXSZ); |
833 | wmb(); | ||
834 | rxq->rx_desc_area[rx].rx_ctrl = 0; | ||
835 | 1015 | ||
836 | refilled++; | 1016 | refilled++; |
837 | } | 1017 | } |
@@ -847,24 +1027,24 @@ static void mwl8k_rxq_deinit(struct ieee80211_hw *hw, int index) | |||
847 | int i; | 1027 | int i; |
848 | 1028 | ||
849 | for (i = 0; i < MWL8K_RX_DESCS; i++) { | 1029 | for (i = 0; i < MWL8K_RX_DESCS; i++) { |
850 | if (rxq->rx_skb[i] != NULL) { | 1030 | if (rxq->buf[i].skb != NULL) { |
851 | unsigned long addr; | 1031 | pci_unmap_single(priv->pdev, |
852 | 1032 | pci_unmap_addr(&rxq->buf[i], dma), | |
853 | addr = le32_to_cpu(rxq->rx_desc_area[i].pkt_phys_addr); | 1033 | MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE); |
854 | pci_unmap_single(priv->pdev, addr, MWL8K_RX_MAXSZ, | 1034 | pci_unmap_addr_set(&rxq->buf[i], dma, 0); |
855 | PCI_DMA_FROMDEVICE); | 1035 | |
856 | kfree_skb(rxq->rx_skb[i]); | 1036 | kfree_skb(rxq->buf[i].skb); |
857 | rxq->rx_skb[i] = NULL; | 1037 | rxq->buf[i].skb = NULL; |
858 | } | 1038 | } |
859 | } | 1039 | } |
860 | 1040 | ||
861 | kfree(rxq->rx_skb); | 1041 | kfree(rxq->buf); |
862 | rxq->rx_skb = NULL; | 1042 | rxq->buf = NULL; |
863 | 1043 | ||
864 | pci_free_consistent(priv->pdev, | 1044 | pci_free_consistent(priv->pdev, |
865 | MWL8K_RX_DESCS * sizeof(struct mwl8k_rx_desc), | 1045 | MWL8K_RX_DESCS * priv->rxd_ops->rxd_size, |
866 | rxq->rx_desc_area, rxq->rx_desc_dma); | 1046 | rxq->rxd, rxq->rxd_dma); |
867 | rxq->rx_desc_area = NULL; | 1047 | rxq->rxd = NULL; |
868 | } | 1048 | } |
869 | 1049 | ||
870 | 1050 | ||
@@ -880,9 +1060,11 @@ mwl8k_capture_bssid(struct mwl8k_priv *priv, struct ieee80211_hdr *wh) | |||
880 | !compare_ether_addr(wh->addr3, priv->capture_bssid); | 1060 | !compare_ether_addr(wh->addr3, priv->capture_bssid); |
881 | } | 1061 | } |
882 | 1062 | ||
883 | static inline void mwl8k_save_beacon(struct mwl8k_priv *priv, | 1063 | static inline void mwl8k_save_beacon(struct ieee80211_hw *hw, |
884 | struct sk_buff *skb) | 1064 | struct sk_buff *skb) |
885 | { | 1065 | { |
1066 | struct mwl8k_priv *priv = hw->priv; | ||
1067 | |||
886 | priv->capture_beacon = false; | 1068 | priv->capture_beacon = false; |
887 | memset(priv->capture_bssid, 0, ETH_ALEN); | 1069 | memset(priv->capture_bssid, 0, ETH_ALEN); |
888 | 1070 | ||
@@ -893,8 +1075,7 @@ static inline void mwl8k_save_beacon(struct mwl8k_priv *priv, | |||
893 | */ | 1075 | */ |
894 | priv->beacon_skb = skb_copy(skb, GFP_ATOMIC); | 1076 | priv->beacon_skb = skb_copy(skb, GFP_ATOMIC); |
895 | if (priv->beacon_skb != NULL) | 1077 | if (priv->beacon_skb != NULL) |
896 | queue_work(priv->config_wq, | 1078 | ieee80211_queue_work(hw, &priv->finalize_join_worker); |
897 | &priv->finalize_join_worker); | ||
898 | } | 1079 | } |
899 | 1080 | ||
900 | static int rxq_process(struct ieee80211_hw *hw, int index, int limit) | 1081 | static int rxq_process(struct ieee80211_hw *hw, int index, int limit) |
@@ -904,53 +1085,46 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit) | |||
904 | int processed; | 1085 | int processed; |
905 | 1086 | ||
906 | processed = 0; | 1087 | processed = 0; |
907 | while (rxq->rx_desc_count && limit--) { | 1088 | while (rxq->rxd_count && limit--) { |
908 | struct mwl8k_rx_desc *rx_desc; | ||
909 | struct sk_buff *skb; | 1089 | struct sk_buff *skb; |
1090 | void *rxd; | ||
1091 | int pkt_len; | ||
910 | struct ieee80211_rx_status status; | 1092 | struct ieee80211_rx_status status; |
911 | unsigned long addr; | ||
912 | struct ieee80211_hdr *wh; | ||
913 | 1093 | ||
914 | rx_desc = rxq->rx_desc_area + rxq->rx_head; | 1094 | skb = rxq->buf[rxq->head].skb; |
915 | if (!(rx_desc->rx_ctrl & MWL8K_RX_CTRL_OWNED_BY_HOST)) | 1095 | if (skb == NULL) |
916 | break; | 1096 | break; |
917 | rmb(); | ||
918 | 1097 | ||
919 | skb = rxq->rx_skb[rxq->rx_head]; | 1098 | rxd = rxq->rxd + (rxq->head * priv->rxd_ops->rxd_size); |
920 | if (skb == NULL) | 1099 | |
1100 | pkt_len = priv->rxd_ops->rxd_process(rxd, &status); | ||
1101 | if (pkt_len < 0) | ||
921 | break; | 1102 | break; |
922 | rxq->rx_skb[rxq->rx_head] = NULL; | ||
923 | 1103 | ||
924 | rxq->rx_head = (rxq->rx_head + 1) % MWL8K_RX_DESCS; | 1104 | rxq->buf[rxq->head].skb = NULL; |
925 | rxq->rx_desc_count--; | ||
926 | 1105 | ||
927 | addr = le32_to_cpu(rx_desc->pkt_phys_addr); | 1106 | pci_unmap_single(priv->pdev, |
928 | pci_unmap_single(priv->pdev, addr, | 1107 | pci_unmap_addr(&rxq->buf[rxq->head], dma), |
929 | MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE); | 1108 | MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE); |
1109 | pci_unmap_addr_set(&rxq->buf[rxq->head], dma, 0); | ||
930 | 1110 | ||
931 | skb_put(skb, le16_to_cpu(rx_desc->pkt_len)); | 1111 | rxq->head++; |
932 | mwl8k_remove_dma_header(skb); | 1112 | if (rxq->head == MWL8K_RX_DESCS) |
1113 | rxq->head = 0; | ||
1114 | |||
1115 | rxq->rxd_count--; | ||
933 | 1116 | ||
934 | wh = (struct ieee80211_hdr *)skb->data; | 1117 | skb_put(skb, pkt_len); |
1118 | mwl8k_remove_dma_header(skb); | ||
935 | 1119 | ||
936 | /* | 1120 | /* |
937 | * Check for pending join operation. save a copy of | 1121 | * Check for a pending join operation. Save a |
938 | * the beacon and schedule a tasklet to send finalize | 1122 | * copy of the beacon and schedule a tasklet to |
939 | * join command to the firmware. | 1123 | * send a FINALIZE_JOIN command to the firmware. |
940 | */ | 1124 | */ |
941 | if (mwl8k_capture_bssid(priv, wh)) | 1125 | if (mwl8k_capture_bssid(priv, (void *)skb->data)) |
942 | mwl8k_save_beacon(priv, skb); | 1126 | mwl8k_save_beacon(hw, skb); |
943 | 1127 | ||
944 | memset(&status, 0, sizeof(status)); | ||
945 | status.mactime = 0; | ||
946 | status.signal = -rx_desc->rssi; | ||
947 | status.noise = -rx_desc->noise_level; | ||
948 | status.qual = rx_desc->link_quality; | ||
949 | status.antenna = 1; | ||
950 | status.rate_idx = 1; | ||
951 | status.flag = 0; | ||
952 | status.band = IEEE80211_BAND_2GHZ; | ||
953 | status.freq = ieee80211_channel_to_frequency(rx_desc->channel); | ||
954 | memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); | 1128 | memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); |
955 | ieee80211_rx_irqsafe(hw, skb); | 1129 | ieee80211_rx_irqsafe(hw, skb); |
956 | 1130 | ||
@@ -965,24 +1139,10 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit) | |||
965 | * Packet transmission. | 1139 | * Packet transmission. |
966 | */ | 1140 | */ |
967 | 1141 | ||
968 | /* Transmit queue assignment. */ | ||
969 | enum { | ||
970 | MWL8K_WME_AC_BK = 0, /* background access */ | ||
971 | MWL8K_WME_AC_BE = 1, /* best effort access */ | ||
972 | MWL8K_WME_AC_VI = 2, /* video access */ | ||
973 | MWL8K_WME_AC_VO = 3, /* voice access */ | ||
974 | }; | ||
975 | |||
976 | /* Transmit packet ACK policy */ | 1142 | /* Transmit packet ACK policy */ |
977 | #define MWL8K_TXD_ACK_POLICY_NORMAL 0 | 1143 | #define MWL8K_TXD_ACK_POLICY_NORMAL 0 |
978 | #define MWL8K_TXD_ACK_POLICY_BLOCKACK 3 | 1144 | #define MWL8K_TXD_ACK_POLICY_BLOCKACK 3 |
979 | 1145 | ||
980 | #define GET_TXQ(_ac) (\ | ||
981 | ((_ac) == WME_AC_VO) ? MWL8K_WME_AC_VO : \ | ||
982 | ((_ac) == WME_AC_VI) ? MWL8K_WME_AC_VI : \ | ||
983 | ((_ac) == WME_AC_BK) ? MWL8K_WME_AC_BK : \ | ||
984 | MWL8K_WME_AC_BE) | ||
985 | |||
986 | #define MWL8K_TXD_STATUS_OK 0x00000001 | 1146 | #define MWL8K_TXD_STATUS_OK 0x00000001 |
987 | #define MWL8K_TXD_STATUS_OK_RETRY 0x00000002 | 1147 | #define MWL8K_TXD_STATUS_OK_RETRY 0x00000002 |
988 | #define MWL8K_TXD_STATUS_OK_MORE_RETRY 0x00000004 | 1148 | #define MWL8K_TXD_STATUS_OK_MORE_RETRY 0x00000004 |
@@ -997,7 +1157,7 @@ struct mwl8k_tx_desc { | |||
997 | __le32 pkt_phys_addr; | 1157 | __le32 pkt_phys_addr; |
998 | __le16 pkt_len; | 1158 | __le16 pkt_len; |
999 | __u8 dest_MAC_addr[ETH_ALEN]; | 1159 | __u8 dest_MAC_addr[ETH_ALEN]; |
1000 | __le32 next_tx_desc_phys_addr; | 1160 | __le32 next_txd_phys_addr; |
1001 | __le32 reserved; | 1161 | __le32 reserved; |
1002 | __le16 rate_info; | 1162 | __le16 rate_info; |
1003 | __u8 peer_id; | 1163 | __u8 peer_id; |
@@ -1013,44 +1173,40 @@ static int mwl8k_txq_init(struct ieee80211_hw *hw, int index) | |||
1013 | int size; | 1173 | int size; |
1014 | int i; | 1174 | int i; |
1015 | 1175 | ||
1016 | memset(&txq->tx_stats, 0, sizeof(struct ieee80211_tx_queue_stats)); | 1176 | memset(&txq->stats, 0, sizeof(struct ieee80211_tx_queue_stats)); |
1017 | txq->tx_stats.limit = MWL8K_TX_DESCS; | 1177 | txq->stats.limit = MWL8K_TX_DESCS; |
1018 | txq->tx_head = 0; | 1178 | txq->head = 0; |
1019 | txq->tx_tail = 0; | 1179 | txq->tail = 0; |
1020 | 1180 | ||
1021 | size = MWL8K_TX_DESCS * sizeof(struct mwl8k_tx_desc); | 1181 | size = MWL8K_TX_DESCS * sizeof(struct mwl8k_tx_desc); |
1022 | 1182 | ||
1023 | txq->tx_desc_area = | 1183 | txq->txd = pci_alloc_consistent(priv->pdev, size, &txq->txd_dma); |
1024 | pci_alloc_consistent(priv->pdev, size, &txq->tx_desc_dma); | 1184 | if (txq->txd == NULL) { |
1025 | if (txq->tx_desc_area == NULL) { | ||
1026 | printk(KERN_ERR "%s: failed to alloc TX descriptors\n", | 1185 | printk(KERN_ERR "%s: failed to alloc TX descriptors\n", |
1027 | priv->name); | 1186 | wiphy_name(hw->wiphy)); |
1028 | return -ENOMEM; | 1187 | return -ENOMEM; |
1029 | } | 1188 | } |
1030 | memset(txq->tx_desc_area, 0, size); | 1189 | memset(txq->txd, 0, size); |
1031 | 1190 | ||
1032 | txq->tx_skb = kmalloc(MWL8K_TX_DESCS * sizeof(*txq->tx_skb), | 1191 | txq->skb = kmalloc(MWL8K_TX_DESCS * sizeof(*txq->skb), GFP_KERNEL); |
1033 | GFP_KERNEL); | 1192 | if (txq->skb == NULL) { |
1034 | if (txq->tx_skb == NULL) { | ||
1035 | printk(KERN_ERR "%s: failed to alloc TX skbuff list\n", | 1193 | printk(KERN_ERR "%s: failed to alloc TX skbuff list\n", |
1036 | priv->name); | 1194 | wiphy_name(hw->wiphy)); |
1037 | pci_free_consistent(priv->pdev, size, | 1195 | pci_free_consistent(priv->pdev, size, txq->txd, txq->txd_dma); |
1038 | txq->tx_desc_area, txq->tx_desc_dma); | ||
1039 | return -ENOMEM; | 1196 | return -ENOMEM; |
1040 | } | 1197 | } |
1041 | memset(txq->tx_skb, 0, MWL8K_TX_DESCS * sizeof(*txq->tx_skb)); | 1198 | memset(txq->skb, 0, MWL8K_TX_DESCS * sizeof(*txq->skb)); |
1042 | 1199 | ||
1043 | for (i = 0; i < MWL8K_TX_DESCS; i++) { | 1200 | for (i = 0; i < MWL8K_TX_DESCS; i++) { |
1044 | struct mwl8k_tx_desc *tx_desc; | 1201 | struct mwl8k_tx_desc *tx_desc; |
1045 | int nexti; | 1202 | int nexti; |
1046 | 1203 | ||
1047 | tx_desc = txq->tx_desc_area + i; | 1204 | tx_desc = txq->txd + i; |
1048 | nexti = (i + 1) % MWL8K_TX_DESCS; | 1205 | nexti = (i + 1) % MWL8K_TX_DESCS; |
1049 | 1206 | ||
1050 | tx_desc->status = 0; | 1207 | tx_desc->status = 0; |
1051 | tx_desc->next_tx_desc_phys_addr = | 1208 | tx_desc->next_txd_phys_addr = |
1052 | cpu_to_le32(txq->tx_desc_dma + | 1209 | cpu_to_le32(txq->txd_dma + nexti * sizeof(*tx_desc)); |
1053 | nexti * sizeof(*tx_desc)); | ||
1054 | } | 1210 | } |
1055 | 1211 | ||
1056 | return 0; | 1212 | return 0; |
@@ -1065,11 +1221,6 @@ static inline void mwl8k_tx_start(struct mwl8k_priv *priv) | |||
1065 | ioread32(priv->regs + MWL8K_HIU_INT_CODE); | 1221 | ioread32(priv->regs + MWL8K_HIU_INT_CODE); |
1066 | } | 1222 | } |
1067 | 1223 | ||
1068 | static inline int mwl8k_txq_busy(struct mwl8k_priv *priv) | ||
1069 | { | ||
1070 | return priv->pending_tx_pkts; | ||
1071 | } | ||
1072 | |||
1073 | struct mwl8k_txq_info { | 1224 | struct mwl8k_txq_info { |
1074 | u32 fw_owned; | 1225 | u32 fw_owned; |
1075 | u32 drv_owned; | 1226 | u32 drv_owned; |
@@ -1089,14 +1240,13 @@ static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv, | |||
1089 | 1240 | ||
1090 | memset(txinfo, 0, MWL8K_TX_QUEUES * sizeof(struct mwl8k_txq_info)); | 1241 | memset(txinfo, 0, MWL8K_TX_QUEUES * sizeof(struct mwl8k_txq_info)); |
1091 | 1242 | ||
1092 | spin_lock_bh(&priv->tx_lock); | ||
1093 | for (count = 0; count < MWL8K_TX_QUEUES; count++) { | 1243 | for (count = 0; count < MWL8K_TX_QUEUES; count++) { |
1094 | txq = priv->txq + count; | 1244 | txq = priv->txq + count; |
1095 | txinfo[count].len = txq->tx_stats.len; | 1245 | txinfo[count].len = txq->stats.len; |
1096 | txinfo[count].head = txq->tx_head; | 1246 | txinfo[count].head = txq->head; |
1097 | txinfo[count].tail = txq->tx_tail; | 1247 | txinfo[count].tail = txq->tail; |
1098 | for (desc = 0; desc < MWL8K_TX_DESCS; desc++) { | 1248 | for (desc = 0; desc < MWL8K_TX_DESCS; desc++) { |
1099 | tx_desc = txq->tx_desc_area + desc; | 1249 | tx_desc = txq->txd + desc; |
1100 | status = le32_to_cpu(tx_desc->status); | 1250 | status = le32_to_cpu(tx_desc->status); |
1101 | 1251 | ||
1102 | if (status & MWL8K_TXD_STATUS_FW_OWNED) | 1252 | if (status & MWL8K_TXD_STATUS_FW_OWNED) |
@@ -1108,30 +1258,26 @@ static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv, | |||
1108 | txinfo[count].unused++; | 1258 | txinfo[count].unused++; |
1109 | } | 1259 | } |
1110 | } | 1260 | } |
1111 | spin_unlock_bh(&priv->tx_lock); | ||
1112 | 1261 | ||
1113 | return ndescs; | 1262 | return ndescs; |
1114 | } | 1263 | } |
1115 | 1264 | ||
1116 | /* | 1265 | /* |
1117 | * Must be called with hw->fw_mutex held and tx queues stopped. | 1266 | * Must be called with priv->fw_mutex held and tx queues stopped. |
1118 | */ | 1267 | */ |
1119 | static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) | 1268 | static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) |
1120 | { | 1269 | { |
1121 | struct mwl8k_priv *priv = hw->priv; | 1270 | struct mwl8k_priv *priv = hw->priv; |
1122 | DECLARE_COMPLETION_ONSTACK(cmd_wait); | 1271 | DECLARE_COMPLETION_ONSTACK(tx_wait); |
1123 | u32 count; | 1272 | u32 count; |
1124 | unsigned long timeout; | 1273 | unsigned long timeout; |
1125 | 1274 | ||
1126 | might_sleep(); | 1275 | might_sleep(); |
1127 | 1276 | ||
1128 | spin_lock_bh(&priv->tx_lock); | 1277 | spin_lock_bh(&priv->tx_lock); |
1129 | count = mwl8k_txq_busy(priv); | 1278 | count = priv->pending_tx_pkts; |
1130 | if (count) { | 1279 | if (count) |
1131 | priv->tx_wait = &cmd_wait; | 1280 | priv->tx_wait = &tx_wait; |
1132 | if (priv->radio_on) | ||
1133 | mwl8k_tx_start(priv); | ||
1134 | } | ||
1135 | spin_unlock_bh(&priv->tx_lock); | 1281 | spin_unlock_bh(&priv->tx_lock); |
1136 | 1282 | ||
1137 | if (count) { | 1283 | if (count) { |
@@ -1139,23 +1285,23 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) | |||
1139 | int index; | 1285 | int index; |
1140 | int newcount; | 1286 | int newcount; |
1141 | 1287 | ||
1142 | timeout = wait_for_completion_timeout(&cmd_wait, | 1288 | timeout = wait_for_completion_timeout(&tx_wait, |
1143 | msecs_to_jiffies(5000)); | 1289 | msecs_to_jiffies(5000)); |
1144 | if (timeout) | 1290 | if (timeout) |
1145 | return 0; | 1291 | return 0; |
1146 | 1292 | ||
1147 | spin_lock_bh(&priv->tx_lock); | 1293 | spin_lock_bh(&priv->tx_lock); |
1148 | priv->tx_wait = NULL; | 1294 | priv->tx_wait = NULL; |
1149 | newcount = mwl8k_txq_busy(priv); | 1295 | newcount = priv->pending_tx_pkts; |
1296 | mwl8k_scan_tx_ring(priv, txinfo); | ||
1150 | spin_unlock_bh(&priv->tx_lock); | 1297 | spin_unlock_bh(&priv->tx_lock); |
1151 | 1298 | ||
1152 | printk(KERN_ERR "%s(%u) TIMEDOUT:5000ms Pend:%u-->%u\n", | 1299 | printk(KERN_ERR "%s(%u) TIMEDOUT:5000ms Pend:%u-->%u\n", |
1153 | __func__, __LINE__, count, newcount); | 1300 | __func__, __LINE__, count, newcount); |
1154 | 1301 | ||
1155 | mwl8k_scan_tx_ring(priv, txinfo); | ||
1156 | for (index = 0; index < MWL8K_TX_QUEUES; index++) | 1302 | for (index = 0; index < MWL8K_TX_QUEUES; index++) |
1157 | printk(KERN_ERR | 1303 | printk(KERN_ERR "TXQ:%u L:%u H:%u T:%u FW:%u " |
1158 | "TXQ:%u L:%u H:%u T:%u FW:%u DRV:%u U:%u\n", | 1304 | "DRV:%u U:%u\n", |
1159 | index, | 1305 | index, |
1160 | txinfo[index].len, | 1306 | txinfo[index].len, |
1161 | txinfo[index].head, | 1307 | txinfo[index].head, |
@@ -1181,7 +1327,7 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) | |||
1181 | struct mwl8k_tx_queue *txq = priv->txq + index; | 1327 | struct mwl8k_tx_queue *txq = priv->txq + index; |
1182 | int wake = 0; | 1328 | int wake = 0; |
1183 | 1329 | ||
1184 | while (txq->tx_stats.len > 0) { | 1330 | while (txq->stats.len > 0) { |
1185 | int tx; | 1331 | int tx; |
1186 | struct mwl8k_tx_desc *tx_desc; | 1332 | struct mwl8k_tx_desc *tx_desc; |
1187 | unsigned long addr; | 1333 | unsigned long addr; |
@@ -1190,8 +1336,8 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) | |||
1190 | struct ieee80211_tx_info *info; | 1336 | struct ieee80211_tx_info *info; |
1191 | u32 status; | 1337 | u32 status; |
1192 | 1338 | ||
1193 | tx = txq->tx_head; | 1339 | tx = txq->head; |
1194 | tx_desc = txq->tx_desc_area + tx; | 1340 | tx_desc = txq->txd + tx; |
1195 | 1341 | ||
1196 | status = le32_to_cpu(tx_desc->status); | 1342 | status = le32_to_cpu(tx_desc->status); |
1197 | 1343 | ||
@@ -1202,15 +1348,15 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) | |||
1202 | ~cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED); | 1348 | ~cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED); |
1203 | } | 1349 | } |
1204 | 1350 | ||
1205 | txq->tx_head = (tx + 1) % MWL8K_TX_DESCS; | 1351 | txq->head = (tx + 1) % MWL8K_TX_DESCS; |
1206 | BUG_ON(txq->tx_stats.len == 0); | 1352 | BUG_ON(txq->stats.len == 0); |
1207 | txq->tx_stats.len--; | 1353 | txq->stats.len--; |
1208 | priv->pending_tx_pkts--; | 1354 | priv->pending_tx_pkts--; |
1209 | 1355 | ||
1210 | addr = le32_to_cpu(tx_desc->pkt_phys_addr); | 1356 | addr = le32_to_cpu(tx_desc->pkt_phys_addr); |
1211 | size = le16_to_cpu(tx_desc->pkt_len); | 1357 | size = le16_to_cpu(tx_desc->pkt_len); |
1212 | skb = txq->tx_skb[tx]; | 1358 | skb = txq->skb[tx]; |
1213 | txq->tx_skb[tx] = NULL; | 1359 | txq->skb[tx] = NULL; |
1214 | 1360 | ||
1215 | BUG_ON(skb == NULL); | 1361 | BUG_ON(skb == NULL); |
1216 | pci_unmap_single(priv->pdev, addr, size, PCI_DMA_TODEVICE); | 1362 | pci_unmap_single(priv->pdev, addr, size, PCI_DMA_TODEVICE); |
@@ -1243,13 +1389,13 @@ static void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index) | |||
1243 | 1389 | ||
1244 | mwl8k_txq_reclaim(hw, index, 1); | 1390 | mwl8k_txq_reclaim(hw, index, 1); |
1245 | 1391 | ||
1246 | kfree(txq->tx_skb); | 1392 | kfree(txq->skb); |
1247 | txq->tx_skb = NULL; | 1393 | txq->skb = NULL; |
1248 | 1394 | ||
1249 | pci_free_consistent(priv->pdev, | 1395 | pci_free_consistent(priv->pdev, |
1250 | MWL8K_TX_DESCS * sizeof(struct mwl8k_tx_desc), | 1396 | MWL8K_TX_DESCS * sizeof(struct mwl8k_tx_desc), |
1251 | txq->tx_desc_area, txq->tx_desc_dma); | 1397 | txq->txd, txq->txd_dma); |
1252 | txq->tx_desc_area = NULL; | 1398 | txq->txd = NULL; |
1253 | } | 1399 | } |
1254 | 1400 | ||
1255 | static int | 1401 | static int |
@@ -1317,7 +1463,7 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1317 | 1463 | ||
1318 | if (pci_dma_mapping_error(priv->pdev, dma)) { | 1464 | if (pci_dma_mapping_error(priv->pdev, dma)) { |
1319 | printk(KERN_DEBUG "%s: failed to dma map skb, " | 1465 | printk(KERN_DEBUG "%s: failed to dma map skb, " |
1320 | "dropping TX frame.\n", priv->name); | 1466 | "dropping TX frame.\n", wiphy_name(hw->wiphy)); |
1321 | dev_kfree_skb(skb); | 1467 | dev_kfree_skb(skb); |
1322 | return NETDEV_TX_OK; | 1468 | return NETDEV_TX_OK; |
1323 | } | 1469 | } |
@@ -1326,10 +1472,10 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1326 | 1472 | ||
1327 | txq = priv->txq + index; | 1473 | txq = priv->txq + index; |
1328 | 1474 | ||
1329 | BUG_ON(txq->tx_skb[txq->tx_tail] != NULL); | 1475 | BUG_ON(txq->skb[txq->tail] != NULL); |
1330 | txq->tx_skb[txq->tx_tail] = skb; | 1476 | txq->skb[txq->tail] = skb; |
1331 | 1477 | ||
1332 | tx = txq->tx_desc_area + txq->tx_tail; | 1478 | tx = txq->txd + txq->tail; |
1333 | tx->data_rate = txdatarate; | 1479 | tx->data_rate = txdatarate; |
1334 | tx->tx_priority = index; | 1480 | tx->tx_priority = index; |
1335 | tx->qos_control = cpu_to_le16(qos); | 1481 | tx->qos_control = cpu_to_le16(qos); |
@@ -1340,15 +1486,15 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1340 | wmb(); | 1486 | wmb(); |
1341 | tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); | 1487 | tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); |
1342 | 1488 | ||
1343 | txq->tx_stats.count++; | 1489 | txq->stats.count++; |
1344 | txq->tx_stats.len++; | 1490 | txq->stats.len++; |
1345 | priv->pending_tx_pkts++; | 1491 | priv->pending_tx_pkts++; |
1346 | 1492 | ||
1347 | txq->tx_tail++; | 1493 | txq->tail++; |
1348 | if (txq->tx_tail == MWL8K_TX_DESCS) | 1494 | if (txq->tail == MWL8K_TX_DESCS) |
1349 | txq->tx_tail = 0; | 1495 | txq->tail = 0; |
1350 | 1496 | ||
1351 | if (txq->tx_head == txq->tx_tail) | 1497 | if (txq->head == txq->tail) |
1352 | ieee80211_stop_queue(hw, index); | 1498 | ieee80211_stop_queue(hw, index); |
1353 | 1499 | ||
1354 | mwl8k_tx_start(priv); | 1500 | mwl8k_tx_start(priv); |
@@ -1431,7 +1577,7 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) | |||
1431 | unsigned long timeout = 0; | 1577 | unsigned long timeout = 0; |
1432 | u8 buf[32]; | 1578 | u8 buf[32]; |
1433 | 1579 | ||
1434 | cmd->result = 0xFFFF; | 1580 | cmd->result = 0xffff; |
1435 | dma_size = le16_to_cpu(cmd->length); | 1581 | dma_size = le16_to_cpu(cmd->length); |
1436 | dma_addr = pci_map_single(priv->pdev, cmd, dma_size, | 1582 | dma_addr = pci_map_single(priv->pdev, cmd, dma_size, |
1437 | PCI_DMA_BIDIRECTIONAL); | 1583 | PCI_DMA_BIDIRECTIONAL); |
@@ -1464,7 +1610,7 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) | |||
1464 | 1610 | ||
1465 | if (!timeout) { | 1611 | if (!timeout) { |
1466 | printk(KERN_ERR "%s: Command %s timeout after %u ms\n", | 1612 | printk(KERN_ERR "%s: Command %s timeout after %u ms\n", |
1467 | priv->name, | 1613 | wiphy_name(hw->wiphy), |
1468 | mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), | 1614 | mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), |
1469 | MWL8K_CMD_TIMEOUT_MS); | 1615 | MWL8K_CMD_TIMEOUT_MS); |
1470 | rc = -ETIMEDOUT; | 1616 | rc = -ETIMEDOUT; |
@@ -1472,7 +1618,7 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) | |||
1472 | rc = cmd->result ? -EINVAL : 0; | 1618 | rc = cmd->result ? -EINVAL : 0; |
1473 | if (rc) | 1619 | if (rc) |
1474 | printk(KERN_ERR "%s: Command %s error 0x%x\n", | 1620 | printk(KERN_ERR "%s: Command %s error 0x%x\n", |
1475 | priv->name, | 1621 | wiphy_name(hw->wiphy), |
1476 | mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), | 1622 | mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), |
1477 | le16_to_cpu(cmd->result)); | 1623 | le16_to_cpu(cmd->result)); |
1478 | } | 1624 | } |
@@ -1481,9 +1627,9 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) | |||
1481 | } | 1627 | } |
1482 | 1628 | ||
1483 | /* | 1629 | /* |
1484 | * GET_HW_SPEC. | 1630 | * CMD_GET_HW_SPEC (STA version). |
1485 | */ | 1631 | */ |
1486 | struct mwl8k_cmd_get_hw_spec { | 1632 | struct mwl8k_cmd_get_hw_spec_sta { |
1487 | struct mwl8k_cmd_pkt header; | 1633 | struct mwl8k_cmd_pkt header; |
1488 | __u8 hw_rev; | 1634 | __u8 hw_rev; |
1489 | __u8 host_interface; | 1635 | __u8 host_interface; |
@@ -1499,13 +1645,13 @@ struct mwl8k_cmd_get_hw_spec { | |||
1499 | __le32 tx_queue_ptrs[MWL8K_TX_QUEUES]; | 1645 | __le32 tx_queue_ptrs[MWL8K_TX_QUEUES]; |
1500 | __le32 caps2; | 1646 | __le32 caps2; |
1501 | __le32 num_tx_desc_per_queue; | 1647 | __le32 num_tx_desc_per_queue; |
1502 | __le32 total_rx_desc; | 1648 | __le32 total_rxd; |
1503 | } __attribute__((packed)); | 1649 | } __attribute__((packed)); |
1504 | 1650 | ||
1505 | static int mwl8k_cmd_get_hw_spec(struct ieee80211_hw *hw) | 1651 | static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw) |
1506 | { | 1652 | { |
1507 | struct mwl8k_priv *priv = hw->priv; | 1653 | struct mwl8k_priv *priv = hw->priv; |
1508 | struct mwl8k_cmd_get_hw_spec *cmd; | 1654 | struct mwl8k_cmd_get_hw_spec_sta *cmd; |
1509 | int rc; | 1655 | int rc; |
1510 | int i; | 1656 | int i; |
1511 | 1657 | ||
@@ -1518,12 +1664,12 @@ static int mwl8k_cmd_get_hw_spec(struct ieee80211_hw *hw) | |||
1518 | 1664 | ||
1519 | memset(cmd->perm_addr, 0xff, sizeof(cmd->perm_addr)); | 1665 | memset(cmd->perm_addr, 0xff, sizeof(cmd->perm_addr)); |
1520 | cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); | 1666 | cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); |
1521 | cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rx_desc_dma); | 1667 | cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma); |
1522 | cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES); | 1668 | cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES); |
1523 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 1669 | for (i = 0; i < MWL8K_TX_QUEUES; i++) |
1524 | cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].tx_desc_dma); | 1670 | cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].txd_dma); |
1525 | cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); | 1671 | cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); |
1526 | cmd->total_rx_desc = cpu_to_le32(MWL8K_RX_DESCS); | 1672 | cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); |
1527 | 1673 | ||
1528 | rc = mwl8k_post_cmd(hw, &cmd->header); | 1674 | rc = mwl8k_post_cmd(hw, &cmd->header); |
1529 | 1675 | ||
@@ -1539,6 +1685,129 @@ static int mwl8k_cmd_get_hw_spec(struct ieee80211_hw *hw) | |||
1539 | } | 1685 | } |
1540 | 1686 | ||
1541 | /* | 1687 | /* |
1688 | * CMD_GET_HW_SPEC (AP version). | ||
1689 | */ | ||
1690 | struct mwl8k_cmd_get_hw_spec_ap { | ||
1691 | struct mwl8k_cmd_pkt header; | ||
1692 | __u8 hw_rev; | ||
1693 | __u8 host_interface; | ||
1694 | __le16 num_wcb; | ||
1695 | __le16 num_mcaddrs; | ||
1696 | __u8 perm_addr[ETH_ALEN]; | ||
1697 | __le16 region_code; | ||
1698 | __le16 num_antenna; | ||
1699 | __le32 fw_rev; | ||
1700 | __le32 wcbbase0; | ||
1701 | __le32 rxwrptr; | ||
1702 | __le32 rxrdptr; | ||
1703 | __le32 ps_cookie; | ||
1704 | __le32 wcbbase1; | ||
1705 | __le32 wcbbase2; | ||
1706 | __le32 wcbbase3; | ||
1707 | } __attribute__((packed)); | ||
1708 | |||
1709 | static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) | ||
1710 | { | ||
1711 | struct mwl8k_priv *priv = hw->priv; | ||
1712 | struct mwl8k_cmd_get_hw_spec_ap *cmd; | ||
1713 | int rc; | ||
1714 | |||
1715 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
1716 | if (cmd == NULL) | ||
1717 | return -ENOMEM; | ||
1718 | |||
1719 | cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_HW_SPEC); | ||
1720 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | ||
1721 | |||
1722 | memset(cmd->perm_addr, 0xff, sizeof(cmd->perm_addr)); | ||
1723 | cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); | ||
1724 | |||
1725 | rc = mwl8k_post_cmd(hw, &cmd->header); | ||
1726 | |||
1727 | if (!rc) { | ||
1728 | int off; | ||
1729 | |||
1730 | SET_IEEE80211_PERM_ADDR(hw, cmd->perm_addr); | ||
1731 | priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); | ||
1732 | priv->fw_rev = le32_to_cpu(cmd->fw_rev); | ||
1733 | priv->hw_rev = cmd->hw_rev; | ||
1734 | |||
1735 | off = le32_to_cpu(cmd->wcbbase0) & 0xffff; | ||
1736 | iowrite32(cpu_to_le32(priv->txq[0].txd_dma), priv->sram + off); | ||
1737 | |||
1738 | off = le32_to_cpu(cmd->rxwrptr) & 0xffff; | ||
1739 | iowrite32(cpu_to_le32(priv->rxq[0].rxd_dma), priv->sram + off); | ||
1740 | |||
1741 | off = le32_to_cpu(cmd->rxrdptr) & 0xffff; | ||
1742 | iowrite32(cpu_to_le32(priv->rxq[0].rxd_dma), priv->sram + off); | ||
1743 | |||
1744 | off = le32_to_cpu(cmd->wcbbase1) & 0xffff; | ||
1745 | iowrite32(cpu_to_le32(priv->txq[1].txd_dma), priv->sram + off); | ||
1746 | |||
1747 | off = le32_to_cpu(cmd->wcbbase2) & 0xffff; | ||
1748 | iowrite32(cpu_to_le32(priv->txq[2].txd_dma), priv->sram + off); | ||
1749 | |||
1750 | off = le32_to_cpu(cmd->wcbbase3) & 0xffff; | ||
1751 | iowrite32(cpu_to_le32(priv->txq[3].txd_dma), priv->sram + off); | ||
1752 | } | ||
1753 | |||
1754 | kfree(cmd); | ||
1755 | return rc; | ||
1756 | } | ||
1757 | |||
1758 | /* | ||
1759 | * CMD_SET_HW_SPEC. | ||
1760 | */ | ||
1761 | struct mwl8k_cmd_set_hw_spec { | ||
1762 | struct mwl8k_cmd_pkt header; | ||
1763 | __u8 hw_rev; | ||
1764 | __u8 host_interface; | ||
1765 | __le16 num_mcaddrs; | ||
1766 | __u8 perm_addr[ETH_ALEN]; | ||
1767 | __le16 region_code; | ||
1768 | __le32 fw_rev; | ||
1769 | __le32 ps_cookie; | ||
1770 | __le32 caps; | ||
1771 | __le32 rx_queue_ptr; | ||
1772 | __le32 num_tx_queues; | ||
1773 | __le32 tx_queue_ptrs[MWL8K_TX_QUEUES]; | ||
1774 | __le32 flags; | ||
1775 | __le32 num_tx_desc_per_queue; | ||
1776 | __le32 total_rxd; | ||
1777 | } __attribute__((packed)); | ||
1778 | |||
1779 | #define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080 | ||
1780 | |||
1781 | static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) | ||
1782 | { | ||
1783 | struct mwl8k_priv *priv = hw->priv; | ||
1784 | struct mwl8k_cmd_set_hw_spec *cmd; | ||
1785 | int rc; | ||
1786 | int i; | ||
1787 | |||
1788 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
1789 | if (cmd == NULL) | ||
1790 | return -ENOMEM; | ||
1791 | |||
1792 | cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_HW_SPEC); | ||
1793 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | ||
1794 | |||
1795 | cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); | ||
1796 | cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma); | ||
1797 | cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES); | ||
1798 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | ||
1799 | cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].txd_dma); | ||
1800 | cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT); | ||
1801 | cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); | ||
1802 | cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); | ||
1803 | |||
1804 | rc = mwl8k_post_cmd(hw, &cmd->header); | ||
1805 | kfree(cmd); | ||
1806 | |||
1807 | return rc; | ||
1808 | } | ||
1809 | |||
1810 | /* | ||
1542 | * CMD_MAC_MULTICAST_ADR. | 1811 | * CMD_MAC_MULTICAST_ADR. |
1543 | */ | 1812 | */ |
1544 | struct mwl8k_cmd_mac_multicast_adr { | 1813 | struct mwl8k_cmd_mac_multicast_adr { |
@@ -1548,19 +1817,23 @@ struct mwl8k_cmd_mac_multicast_adr { | |||
1548 | __u8 addr[0][ETH_ALEN]; | 1817 | __u8 addr[0][ETH_ALEN]; |
1549 | }; | 1818 | }; |
1550 | 1819 | ||
1551 | #define MWL8K_ENABLE_RX_MULTICAST 0x000F | 1820 | #define MWL8K_ENABLE_RX_DIRECTED 0x0001 |
1821 | #define MWL8K_ENABLE_RX_MULTICAST 0x0002 | ||
1822 | #define MWL8K_ENABLE_RX_ALL_MULTICAST 0x0004 | ||
1823 | #define MWL8K_ENABLE_RX_BROADCAST 0x0008 | ||
1552 | 1824 | ||
1553 | static struct mwl8k_cmd_pkt * | 1825 | static struct mwl8k_cmd_pkt * |
1554 | __mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, | 1826 | __mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, int allmulti, |
1555 | int mc_count, struct dev_addr_list *mclist) | 1827 | int mc_count, struct dev_addr_list *mclist) |
1556 | { | 1828 | { |
1557 | struct mwl8k_priv *priv = hw->priv; | 1829 | struct mwl8k_priv *priv = hw->priv; |
1558 | struct mwl8k_cmd_mac_multicast_adr *cmd; | 1830 | struct mwl8k_cmd_mac_multicast_adr *cmd; |
1559 | int size; | 1831 | int size; |
1560 | int i; | ||
1561 | 1832 | ||
1562 | if (mc_count > priv->num_mcaddrs) | 1833 | if (allmulti || mc_count > priv->num_mcaddrs) { |
1563 | mc_count = priv->num_mcaddrs; | 1834 | allmulti = 1; |
1835 | mc_count = 0; | ||
1836 | } | ||
1564 | 1837 | ||
1565 | size = sizeof(*cmd) + mc_count * ETH_ALEN; | 1838 | size = sizeof(*cmd) + mc_count * ETH_ALEN; |
1566 | 1839 | ||
@@ -1570,16 +1843,24 @@ __mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, | |||
1570 | 1843 | ||
1571 | cmd->header.code = cpu_to_le16(MWL8K_CMD_MAC_MULTICAST_ADR); | 1844 | cmd->header.code = cpu_to_le16(MWL8K_CMD_MAC_MULTICAST_ADR); |
1572 | cmd->header.length = cpu_to_le16(size); | 1845 | cmd->header.length = cpu_to_le16(size); |
1573 | cmd->action = cpu_to_le16(MWL8K_ENABLE_RX_MULTICAST); | 1846 | cmd->action = cpu_to_le16(MWL8K_ENABLE_RX_DIRECTED | |
1574 | cmd->numaddr = cpu_to_le16(mc_count); | 1847 | MWL8K_ENABLE_RX_BROADCAST); |
1575 | 1848 | ||
1576 | for (i = 0; i < mc_count && mclist; i++) { | 1849 | if (allmulti) { |
1577 | if (mclist->da_addrlen != ETH_ALEN) { | 1850 | cmd->action |= cpu_to_le16(MWL8K_ENABLE_RX_ALL_MULTICAST); |
1578 | kfree(cmd); | 1851 | } else if (mc_count) { |
1579 | return NULL; | 1852 | int i; |
1853 | |||
1854 | cmd->action |= cpu_to_le16(MWL8K_ENABLE_RX_MULTICAST); | ||
1855 | cmd->numaddr = cpu_to_le16(mc_count); | ||
1856 | for (i = 0; i < mc_count && mclist; i++) { | ||
1857 | if (mclist->da_addrlen != ETH_ALEN) { | ||
1858 | kfree(cmd); | ||
1859 | return NULL; | ||
1860 | } | ||
1861 | memcpy(cmd->addr[i], mclist->da_addr, ETH_ALEN); | ||
1862 | mclist = mclist->next; | ||
1580 | } | 1863 | } |
1581 | memcpy(cmd->addr[i], mclist->da_addr, ETH_ALEN); | ||
1582 | mclist = mclist->next; | ||
1583 | } | 1864 | } |
1584 | 1865 | ||
1585 | return &cmd->header; | 1866 | return &cmd->header; |
@@ -1590,7 +1871,6 @@ __mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, | |||
1590 | */ | 1871 | */ |
1591 | struct mwl8k_cmd_802_11_get_stat { | 1872 | struct mwl8k_cmd_802_11_get_stat { |
1592 | struct mwl8k_cmd_pkt header; | 1873 | struct mwl8k_cmd_pkt header; |
1593 | __le16 action; | ||
1594 | __le32 stats[64]; | 1874 | __le32 stats[64]; |
1595 | } __attribute__((packed)); | 1875 | } __attribute__((packed)); |
1596 | 1876 | ||
@@ -1611,7 +1891,6 @@ static int mwl8k_cmd_802_11_get_stat(struct ieee80211_hw *hw, | |||
1611 | 1891 | ||
1612 | cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_STAT); | 1892 | cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_STAT); |
1613 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | 1893 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); |
1614 | cmd->action = cpu_to_le16(MWL8K_CMD_GET); | ||
1615 | 1894 | ||
1616 | rc = mwl8k_post_cmd(hw, &cmd->header); | 1895 | rc = mwl8k_post_cmd(hw, &cmd->header); |
1617 | if (!rc) { | 1896 | if (!rc) { |
@@ -1727,6 +2006,39 @@ static int mwl8k_cmd_802_11_rf_tx_power(struct ieee80211_hw *hw, int dBm) | |||
1727 | } | 2006 | } |
1728 | 2007 | ||
1729 | /* | 2008 | /* |
2009 | * CMD_RF_ANTENNA. | ||
2010 | */ | ||
2011 | struct mwl8k_cmd_rf_antenna { | ||
2012 | struct mwl8k_cmd_pkt header; | ||
2013 | __le16 antenna; | ||
2014 | __le16 mode; | ||
2015 | } __attribute__((packed)); | ||
2016 | |||
2017 | #define MWL8K_RF_ANTENNA_RX 1 | ||
2018 | #define MWL8K_RF_ANTENNA_TX 2 | ||
2019 | |||
2020 | static int | ||
2021 | mwl8k_cmd_rf_antenna(struct ieee80211_hw *hw, int antenna, int mask) | ||
2022 | { | ||
2023 | struct mwl8k_cmd_rf_antenna *cmd; | ||
2024 | int rc; | ||
2025 | |||
2026 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
2027 | if (cmd == NULL) | ||
2028 | return -ENOMEM; | ||
2029 | |||
2030 | cmd->header.code = cpu_to_le16(MWL8K_CMD_RF_ANTENNA); | ||
2031 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | ||
2032 | cmd->antenna = cpu_to_le16(antenna); | ||
2033 | cmd->mode = cpu_to_le16(mask); | ||
2034 | |||
2035 | rc = mwl8k_post_cmd(hw, &cmd->header); | ||
2036 | kfree(cmd); | ||
2037 | |||
2038 | return rc; | ||
2039 | } | ||
2040 | |||
2041 | /* | ||
1730 | * CMD_SET_PRE_SCAN. | 2042 | * CMD_SET_PRE_SCAN. |
1731 | */ | 2043 | */ |
1732 | struct mwl8k_cmd_set_pre_scan { | 2044 | struct mwl8k_cmd_set_pre_scan { |
@@ -1904,6 +2216,46 @@ static int mwl8k_enable_sniffer(struct ieee80211_hw *hw, bool enable) | |||
1904 | } | 2216 | } |
1905 | 2217 | ||
1906 | /* | 2218 | /* |
2219 | * CMD_SET_MAC_ADDR. | ||
2220 | */ | ||
2221 | struct mwl8k_cmd_set_mac_addr { | ||
2222 | struct mwl8k_cmd_pkt header; | ||
2223 | union { | ||
2224 | struct { | ||
2225 | __le16 mac_type; | ||
2226 | __u8 mac_addr[ETH_ALEN]; | ||
2227 | } mbss; | ||
2228 | __u8 mac_addr[ETH_ALEN]; | ||
2229 | }; | ||
2230 | } __attribute__((packed)); | ||
2231 | |||
2232 | static int mwl8k_set_mac_addr(struct ieee80211_hw *hw, u8 *mac) | ||
2233 | { | ||
2234 | struct mwl8k_priv *priv = hw->priv; | ||
2235 | struct mwl8k_cmd_set_mac_addr *cmd; | ||
2236 | int rc; | ||
2237 | |||
2238 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
2239 | if (cmd == NULL) | ||
2240 | return -ENOMEM; | ||
2241 | |||
2242 | cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_MAC_ADDR); | ||
2243 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | ||
2244 | if (priv->ap_fw) { | ||
2245 | cmd->mbss.mac_type = 0; | ||
2246 | memcpy(cmd->mbss.mac_addr, mac, ETH_ALEN); | ||
2247 | } else { | ||
2248 | memcpy(cmd->mac_addr, mac, ETH_ALEN); | ||
2249 | } | ||
2250 | |||
2251 | rc = mwl8k_post_cmd(hw, &cmd->header); | ||
2252 | kfree(cmd); | ||
2253 | |||
2254 | return rc; | ||
2255 | } | ||
2256 | |||
2257 | |||
2258 | /* | ||
1907 | * CMD_SET_RATEADAPT_MODE. | 2259 | * CMD_SET_RATEADAPT_MODE. |
1908 | */ | 2260 | */ |
1909 | struct mwl8k_cmd_set_rate_adapt_mode { | 2261 | struct mwl8k_cmd_set_rate_adapt_mode { |
@@ -2005,17 +2357,34 @@ struct mwl8k_cmd_set_edca_params { | |||
2005 | /* TX opportunity in units of 32 us */ | 2357 | /* TX opportunity in units of 32 us */ |
2006 | __le16 txop; | 2358 | __le16 txop; |
2007 | 2359 | ||
2008 | /* Log exponent of max contention period: 0...15*/ | 2360 | union { |
2009 | __u8 log_cw_max; | 2361 | struct { |
2362 | /* Log exponent of max contention period: 0...15 */ | ||
2363 | __le32 log_cw_max; | ||
2364 | |||
2365 | /* Log exponent of min contention period: 0...15 */ | ||
2366 | __le32 log_cw_min; | ||
2367 | |||
2368 | /* Adaptive interframe spacing in units of 32us */ | ||
2369 | __u8 aifs; | ||
2370 | |||
2371 | /* TX queue to configure */ | ||
2372 | __u8 txq; | ||
2373 | } ap; | ||
2374 | struct { | ||
2375 | /* Log exponent of max contention period: 0...15 */ | ||
2376 | __u8 log_cw_max; | ||
2010 | 2377 | ||
2011 | /* Log exponent of min contention period: 0...15 */ | 2378 | /* Log exponent of min contention period: 0...15 */ |
2012 | __u8 log_cw_min; | 2379 | __u8 log_cw_min; |
2013 | 2380 | ||
2014 | /* Adaptive interframe spacing in units of 32us */ | 2381 | /* Adaptive interframe spacing in units of 32us */ |
2015 | __u8 aifs; | 2382 | __u8 aifs; |
2016 | 2383 | ||
2017 | /* TX queue to configure */ | 2384 | /* TX queue to configure */ |
2018 | __u8 txq; | 2385 | __u8 txq; |
2386 | } sta; | ||
2387 | }; | ||
2019 | } __attribute__((packed)); | 2388 | } __attribute__((packed)); |
2020 | 2389 | ||
2021 | #define MWL8K_SET_EDCA_CW 0x01 | 2390 | #define MWL8K_SET_EDCA_CW 0x01 |
@@ -2031,6 +2400,7 @@ mwl8k_set_edca_params(struct ieee80211_hw *hw, __u8 qnum, | |||
2031 | __u16 cw_min, __u16 cw_max, | 2400 | __u16 cw_min, __u16 cw_max, |
2032 | __u8 aifs, __u16 txop) | 2401 | __u8 aifs, __u16 txop) |
2033 | { | 2402 | { |
2403 | struct mwl8k_priv *priv = hw->priv; | ||
2034 | struct mwl8k_cmd_set_edca_params *cmd; | 2404 | struct mwl8k_cmd_set_edca_params *cmd; |
2035 | int rc; | 2405 | int rc; |
2036 | 2406 | ||
@@ -2038,14 +2408,27 @@ mwl8k_set_edca_params(struct ieee80211_hw *hw, __u8 qnum, | |||
2038 | if (cmd == NULL) | 2408 | if (cmd == NULL) |
2039 | return -ENOMEM; | 2409 | return -ENOMEM; |
2040 | 2410 | ||
2411 | /* | ||
2412 | * Queues 0 (BE) and 1 (BK) are swapped in hardware for | ||
2413 | * this call. | ||
2414 | */ | ||
2415 | qnum ^= !(qnum >> 1); | ||
2416 | |||
2041 | cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_EDCA_PARAMS); | 2417 | cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_EDCA_PARAMS); |
2042 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | 2418 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); |
2043 | cmd->action = cpu_to_le16(MWL8K_SET_EDCA_ALL); | 2419 | cmd->action = cpu_to_le16(MWL8K_SET_EDCA_ALL); |
2044 | cmd->txop = cpu_to_le16(txop); | 2420 | cmd->txop = cpu_to_le16(txop); |
2045 | cmd->log_cw_max = (u8)ilog2(cw_max + 1); | 2421 | if (priv->ap_fw) { |
2046 | cmd->log_cw_min = (u8)ilog2(cw_min + 1); | 2422 | cmd->ap.log_cw_max = cpu_to_le32(ilog2(cw_max + 1)); |
2047 | cmd->aifs = aifs; | 2423 | cmd->ap.log_cw_min = cpu_to_le32(ilog2(cw_min + 1)); |
2048 | cmd->txq = qnum; | 2424 | cmd->ap.aifs = aifs; |
2425 | cmd->ap.txq = qnum; | ||
2426 | } else { | ||
2427 | cmd->sta.log_cw_max = (u8)ilog2(cw_max + 1); | ||
2428 | cmd->sta.log_cw_min = (u8)ilog2(cw_min + 1); | ||
2429 | cmd->sta.aifs = aifs; | ||
2430 | cmd->sta.txq = qnum; | ||
2431 | } | ||
2049 | 2432 | ||
2050 | rc = mwl8k_post_cmd(hw, &cmd->header); | 2433 | rc = mwl8k_post_cmd(hw, &cmd->header); |
2051 | kfree(cmd); | 2434 | kfree(cmd); |
@@ -2093,8 +2476,8 @@ static int mwl8k_finalize_join(struct ieee80211_hw *hw, void *frame, | |||
2093 | /* XXX TBD Might just have to abort and return an error */ | 2476 | /* XXX TBD Might just have to abort and return an error */ |
2094 | if (payload_len > MWL8K_FJ_BEACON_MAXLEN) | 2477 | if (payload_len > MWL8K_FJ_BEACON_MAXLEN) |
2095 | printk(KERN_ERR "%s(): WARNING: Incomplete beacon " | 2478 | printk(KERN_ERR "%s(): WARNING: Incomplete beacon " |
2096 | "sent to firmware. Sz=%u MAX=%u\n", __func__, | 2479 | "sent to firmware. Sz=%u MAX=%u\n", __func__, |
2097 | payload_len, MWL8K_FJ_BEACON_MAXLEN); | 2480 | payload_len, MWL8K_FJ_BEACON_MAXLEN); |
2098 | 2481 | ||
2099 | if (payload_len > MWL8K_FJ_BEACON_MAXLEN) | 2482 | if (payload_len > MWL8K_FJ_BEACON_MAXLEN) |
2100 | payload_len = MWL8K_FJ_BEACON_MAXLEN; | 2483 | payload_len = MWL8K_FJ_BEACON_MAXLEN; |
@@ -2341,9 +2724,10 @@ static int mwl8k_cmd_use_fixed_rate(struct ieee80211_hw *hw, | |||
2341 | cmd->rate_type = cpu_to_le32(rate_type); | 2724 | cmd->rate_type = cpu_to_le32(rate_type); |
2342 | 2725 | ||
2343 | if (rate_table != NULL) { | 2726 | if (rate_table != NULL) { |
2344 | /* Copy over each field manually so | 2727 | /* |
2345 | * that bitflipping can be done | 2728 | * Copy over each field manually so that endian |
2346 | */ | 2729 | * conversion can be done. |
2730 | */ | ||
2347 | cmd->rate_table.allow_rate_drop = | 2731 | cmd->rate_table.allow_rate_drop = |
2348 | cpu_to_le32(rate_table->allow_rate_drop); | 2732 | cpu_to_le32(rate_table->allow_rate_drop); |
2349 | cmd->rate_table.num_rates = | 2733 | cmd->rate_table.num_rates = |
@@ -2399,7 +2783,7 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id) | |||
2399 | 2783 | ||
2400 | if (status & MWL8K_A2H_INT_QUEUE_EMPTY) { | 2784 | if (status & MWL8K_A2H_INT_QUEUE_EMPTY) { |
2401 | if (!mutex_is_locked(&priv->fw_mutex) && | 2785 | if (!mutex_is_locked(&priv->fw_mutex) && |
2402 | priv->radio_on && mwl8k_txq_busy(priv)) | 2786 | priv->radio_on && priv->pending_tx_pkts) |
2403 | mwl8k_tx_start(priv); | 2787 | mwl8k_tx_start(priv); |
2404 | } | 2788 | } |
2405 | 2789 | ||
@@ -2418,7 +2802,7 @@ static int mwl8k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
2418 | 2802 | ||
2419 | if (priv->current_channel == NULL) { | 2803 | if (priv->current_channel == NULL) { |
2420 | printk(KERN_DEBUG "%s: dropped TX frame since radio " | 2804 | printk(KERN_DEBUG "%s: dropped TX frame since radio " |
2421 | "disabled\n", priv->name); | 2805 | "disabled\n", wiphy_name(hw->wiphy)); |
2422 | dev_kfree_skb(skb); | 2806 | dev_kfree_skb(skb); |
2423 | return NETDEV_TX_OK; | 2807 | return NETDEV_TX_OK; |
2424 | } | 2808 | } |
@@ -2433,11 +2817,11 @@ static int mwl8k_start(struct ieee80211_hw *hw) | |||
2433 | struct mwl8k_priv *priv = hw->priv; | 2817 | struct mwl8k_priv *priv = hw->priv; |
2434 | int rc; | 2818 | int rc; |
2435 | 2819 | ||
2436 | rc = request_irq(priv->pdev->irq, &mwl8k_interrupt, | 2820 | rc = request_irq(priv->pdev->irq, mwl8k_interrupt, |
2437 | IRQF_SHARED, MWL8K_NAME, hw); | 2821 | IRQF_SHARED, MWL8K_NAME, hw); |
2438 | if (rc) { | 2822 | if (rc) { |
2439 | printk(KERN_ERR "%s: failed to register IRQ handler\n", | 2823 | printk(KERN_ERR "%s: failed to register IRQ handler\n", |
2440 | priv->name); | 2824 | wiphy_name(hw->wiphy)); |
2441 | return -EIO; | 2825 | return -EIO; |
2442 | } | 2826 | } |
2443 | 2827 | ||
@@ -2451,12 +2835,17 @@ static int mwl8k_start(struct ieee80211_hw *hw) | |||
2451 | if (!rc) { | 2835 | if (!rc) { |
2452 | rc = mwl8k_cmd_802_11_radio_enable(hw); | 2836 | rc = mwl8k_cmd_802_11_radio_enable(hw); |
2453 | 2837 | ||
2454 | if (!rc) | 2838 | if (!priv->ap_fw) { |
2455 | rc = mwl8k_cmd_set_pre_scan(hw); | 2839 | if (!rc) |
2840 | rc = mwl8k_enable_sniffer(hw, 0); | ||
2456 | 2841 | ||
2457 | if (!rc) | 2842 | if (!rc) |
2458 | rc = mwl8k_cmd_set_post_scan(hw, | 2843 | rc = mwl8k_cmd_set_pre_scan(hw); |
2459 | "\x00\x00\x00\x00\x00\x00"); | 2844 | |
2845 | if (!rc) | ||
2846 | rc = mwl8k_cmd_set_post_scan(hw, | ||
2847 | "\x00\x00\x00\x00\x00\x00"); | ||
2848 | } | ||
2460 | 2849 | ||
2461 | if (!rc) | 2850 | if (!rc) |
2462 | rc = mwl8k_cmd_setrateadaptmode(hw, 0); | 2851 | rc = mwl8k_cmd_setrateadaptmode(hw, 0); |
@@ -2464,9 +2853,6 @@ static int mwl8k_start(struct ieee80211_hw *hw) | |||
2464 | if (!rc) | 2853 | if (!rc) |
2465 | rc = mwl8k_set_wmm(hw, 0); | 2854 | rc = mwl8k_set_wmm(hw, 0); |
2466 | 2855 | ||
2467 | if (!rc) | ||
2468 | rc = mwl8k_enable_sniffer(hw, 0); | ||
2469 | |||
2470 | mwl8k_fw_unlock(hw); | 2856 | mwl8k_fw_unlock(hw); |
2471 | } | 2857 | } |
2472 | 2858 | ||
@@ -2500,9 +2886,6 @@ static void mwl8k_stop(struct ieee80211_hw *hw) | |||
2500 | /* Stop tx reclaim tasklet */ | 2886 | /* Stop tx reclaim tasklet */ |
2501 | tasklet_disable(&priv->tx_reclaim_task); | 2887 | tasklet_disable(&priv->tx_reclaim_task); |
2502 | 2888 | ||
2503 | /* Stop config thread */ | ||
2504 | flush_workqueue(priv->config_wq); | ||
2505 | |||
2506 | /* Return all skbs to mac80211 */ | 2889 | /* Return all skbs to mac80211 */ |
2507 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 2890 | for (i = 0; i < MWL8K_TX_QUEUES; i++) |
2508 | mwl8k_txq_reclaim(hw, i, 1); | 2891 | mwl8k_txq_reclaim(hw, i, 1); |
@@ -2526,11 +2909,24 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, | |||
2526 | if (conf->type != NL80211_IFTYPE_STATION) | 2909 | if (conf->type != NL80211_IFTYPE_STATION) |
2527 | return -EINVAL; | 2910 | return -EINVAL; |
2528 | 2911 | ||
2912 | /* | ||
2913 | * Reject interface creation if sniffer mode is active, as | ||
2914 | * STA operation is mutually exclusive with hardware sniffer | ||
2915 | * mode. | ||
2916 | */ | ||
2917 | if (priv->sniffer_enabled) { | ||
2918 | printk(KERN_INFO "%s: unable to create STA " | ||
2919 | "interface due to sniffer mode being enabled\n", | ||
2920 | wiphy_name(hw->wiphy)); | ||
2921 | return -EINVAL; | ||
2922 | } | ||
2923 | |||
2529 | /* Clean out driver private area */ | 2924 | /* Clean out driver private area */ |
2530 | mwl8k_vif = MWL8K_VIF(conf->vif); | 2925 | mwl8k_vif = MWL8K_VIF(conf->vif); |
2531 | memset(mwl8k_vif, 0, sizeof(*mwl8k_vif)); | 2926 | memset(mwl8k_vif, 0, sizeof(*mwl8k_vif)); |
2532 | 2927 | ||
2533 | /* Save the mac address */ | 2928 | /* Set and save the mac address */ |
2929 | mwl8k_set_mac_addr(hw, conf->mac_addr); | ||
2534 | memcpy(mwl8k_vif->mac_addr, conf->mac_addr, ETH_ALEN); | 2930 | memcpy(mwl8k_vif->mac_addr, conf->mac_addr, ETH_ALEN); |
2535 | 2931 | ||
2536 | /* Back pointer to parent config block */ | 2932 | /* Back pointer to parent config block */ |
@@ -2558,6 +2954,8 @@ static void mwl8k_remove_interface(struct ieee80211_hw *hw, | |||
2558 | if (priv->vif == NULL) | 2954 | if (priv->vif == NULL) |
2559 | return; | 2955 | return; |
2560 | 2956 | ||
2957 | mwl8k_set_mac_addr(hw, "\x00\x00\x00\x00\x00\x00"); | ||
2958 | |||
2561 | priv->vif = NULL; | 2959 | priv->vif = NULL; |
2562 | } | 2960 | } |
2563 | 2961 | ||
@@ -2593,8 +2991,13 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) | |||
2593 | if (rc) | 2991 | if (rc) |
2594 | goto out; | 2992 | goto out; |
2595 | 2993 | ||
2596 | if (mwl8k_cmd_mimo_config(hw, 0x7, 0x7)) | 2994 | if (priv->ap_fw) { |
2597 | rc = -EINVAL; | 2995 | rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_RX, 0x7); |
2996 | if (!rc) | ||
2997 | rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_TX, 0x7); | ||
2998 | } else { | ||
2999 | rc = mwl8k_cmd_mimo_config(hw, 0x7, 0x7); | ||
3000 | } | ||
2598 | 3001 | ||
2599 | out: | 3002 | out: |
2600 | mwl8k_fw_unlock(hw); | 3003 | mwl8k_fw_unlock(hw); |
@@ -2681,32 +3084,108 @@ static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw, | |||
2681 | { | 3084 | { |
2682 | struct mwl8k_cmd_pkt *cmd; | 3085 | struct mwl8k_cmd_pkt *cmd; |
2683 | 3086 | ||
2684 | cmd = __mwl8k_cmd_mac_multicast_adr(hw, mc_count, mclist); | 3087 | /* |
3088 | * Synthesize and return a command packet that programs the | ||
3089 | * hardware multicast address filter. At this point we don't | ||
3090 | * know whether FIF_ALLMULTI is being requested, but if it is, | ||
3091 | * we'll end up throwing this packet away and creating a new | ||
3092 | * one in mwl8k_configure_filter(). | ||
3093 | */ | ||
3094 | cmd = __mwl8k_cmd_mac_multicast_adr(hw, 0, mc_count, mclist); | ||
2685 | 3095 | ||
2686 | return (unsigned long)cmd; | 3096 | return (unsigned long)cmd; |
2687 | } | 3097 | } |
2688 | 3098 | ||
3099 | static int | ||
3100 | mwl8k_configure_filter_sniffer(struct ieee80211_hw *hw, | ||
3101 | unsigned int changed_flags, | ||
3102 | unsigned int *total_flags) | ||
3103 | { | ||
3104 | struct mwl8k_priv *priv = hw->priv; | ||
3105 | |||
3106 | /* | ||
3107 | * Hardware sniffer mode is mutually exclusive with STA | ||
3108 | * operation, so refuse to enable sniffer mode if a STA | ||
3109 | * interface is active. | ||
3110 | */ | ||
3111 | if (priv->vif != NULL) { | ||
3112 | if (net_ratelimit()) | ||
3113 | printk(KERN_INFO "%s: not enabling sniffer " | ||
3114 | "mode because STA interface is active\n", | ||
3115 | wiphy_name(hw->wiphy)); | ||
3116 | return 0; | ||
3117 | } | ||
3118 | |||
3119 | if (!priv->sniffer_enabled) { | ||
3120 | if (mwl8k_enable_sniffer(hw, 1)) | ||
3121 | return 0; | ||
3122 | priv->sniffer_enabled = true; | ||
3123 | } | ||
3124 | |||
3125 | *total_flags &= FIF_PROMISC_IN_BSS | FIF_ALLMULTI | | ||
3126 | FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL | | ||
3127 | FIF_OTHER_BSS; | ||
3128 | |||
3129 | return 1; | ||
3130 | } | ||
3131 | |||
2689 | static void mwl8k_configure_filter(struct ieee80211_hw *hw, | 3132 | static void mwl8k_configure_filter(struct ieee80211_hw *hw, |
2690 | unsigned int changed_flags, | 3133 | unsigned int changed_flags, |
2691 | unsigned int *total_flags, | 3134 | unsigned int *total_flags, |
2692 | u64 multicast) | 3135 | u64 multicast) |
2693 | { | 3136 | { |
2694 | struct mwl8k_priv *priv = hw->priv; | 3137 | struct mwl8k_priv *priv = hw->priv; |
2695 | struct mwl8k_cmd_pkt *multicast_adr_cmd; | 3138 | struct mwl8k_cmd_pkt *cmd = (void *)(unsigned long)multicast; |
3139 | |||
3140 | /* | ||
3141 | * AP firmware doesn't allow fine-grained control over | ||
3142 | * the receive filter. | ||
3143 | */ | ||
3144 | if (priv->ap_fw) { | ||
3145 | *total_flags &= FIF_ALLMULTI | FIF_BCN_PRBRESP_PROMISC; | ||
3146 | kfree(cmd); | ||
3147 | return; | ||
3148 | } | ||
3149 | |||
3150 | /* | ||
3151 | * Enable hardware sniffer mode if FIF_CONTROL or | ||
3152 | * FIF_OTHER_BSS is requested. | ||
3153 | */ | ||
3154 | if (*total_flags & (FIF_CONTROL | FIF_OTHER_BSS) && | ||
3155 | mwl8k_configure_filter_sniffer(hw, changed_flags, total_flags)) { | ||
3156 | kfree(cmd); | ||
3157 | return; | ||
3158 | } | ||
2696 | 3159 | ||
2697 | /* Clear unsupported feature flags */ | 3160 | /* Clear unsupported feature flags */ |
2698 | *total_flags &= FIF_BCN_PRBRESP_PROMISC; | 3161 | *total_flags &= FIF_ALLMULTI | FIF_BCN_PRBRESP_PROMISC; |
2699 | 3162 | ||
2700 | if (mwl8k_fw_lock(hw)) | 3163 | if (mwl8k_fw_lock(hw)) |
2701 | return; | 3164 | return; |
2702 | 3165 | ||
3166 | if (priv->sniffer_enabled) { | ||
3167 | mwl8k_enable_sniffer(hw, 0); | ||
3168 | priv->sniffer_enabled = false; | ||
3169 | } | ||
3170 | |||
2703 | if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { | 3171 | if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { |
2704 | if (*total_flags & FIF_BCN_PRBRESP_PROMISC) | 3172 | if (*total_flags & FIF_BCN_PRBRESP_PROMISC) { |
3173 | /* | ||
3174 | * Disable the BSS filter. | ||
3175 | */ | ||
2705 | mwl8k_cmd_set_pre_scan(hw); | 3176 | mwl8k_cmd_set_pre_scan(hw); |
2706 | else { | 3177 | } else { |
2707 | u8 *bssid; | 3178 | u8 *bssid; |
2708 | 3179 | ||
2709 | bssid = "\x00\x00\x00\x00\x00\x00"; | 3180 | /* |
3181 | * Enable the BSS filter. | ||
3182 | * | ||
3183 | * If there is an active STA interface, use that | ||
3184 | * interface's BSSID, otherwise use a dummy one | ||
3185 | * (where the OUI part needs to be nonzero for | ||
3186 | * the BSSID to be accepted by POST_SCAN). | ||
3187 | */ | ||
3188 | bssid = "\x01\x00\x00\x00\x00\x00"; | ||
2710 | if (priv->vif != NULL) | 3189 | if (priv->vif != NULL) |
2711 | bssid = MWL8K_VIF(priv->vif)->bssid; | 3190 | bssid = MWL8K_VIF(priv->vif)->bssid; |
2712 | 3191 | ||
@@ -2714,10 +3193,20 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, | |||
2714 | } | 3193 | } |
2715 | } | 3194 | } |
2716 | 3195 | ||
2717 | multicast_adr_cmd = (void *)(unsigned long)multicast; | 3196 | /* |
2718 | if (multicast_adr_cmd != NULL) { | 3197 | * If FIF_ALLMULTI is being requested, throw away the command |
2719 | mwl8k_post_cmd(hw, multicast_adr_cmd); | 3198 | * packet that ->prepare_multicast() built and replace it with |
2720 | kfree(multicast_adr_cmd); | 3199 | * a command packet that enables reception of all multicast |
3200 | * packets. | ||
3201 | */ | ||
3202 | if (*total_flags & FIF_ALLMULTI) { | ||
3203 | kfree(cmd); | ||
3204 | cmd = __mwl8k_cmd_mac_multicast_adr(hw, 1, 0, NULL); | ||
3205 | } | ||
3206 | |||
3207 | if (cmd != NULL) { | ||
3208 | mwl8k_post_cmd(hw, cmd); | ||
3209 | kfree(cmd); | ||
2721 | } | 3210 | } |
2722 | 3211 | ||
2723 | mwl8k_fw_unlock(hw); | 3212 | mwl8k_fw_unlock(hw); |
@@ -2762,7 +3251,7 @@ static int mwl8k_get_tx_stats(struct ieee80211_hw *hw, | |||
2762 | spin_lock_bh(&priv->tx_lock); | 3251 | spin_lock_bh(&priv->tx_lock); |
2763 | for (index = 0; index < MWL8K_TX_QUEUES; index++) { | 3252 | for (index = 0; index < MWL8K_TX_QUEUES; index++) { |
2764 | txq = priv->txq + index; | 3253 | txq = priv->txq + index; |
2765 | memcpy(&stats[index], &txq->tx_stats, | 3254 | memcpy(&stats[index], &txq->stats, |
2766 | sizeof(struct ieee80211_tx_queue_stats)); | 3255 | sizeof(struct ieee80211_tx_queue_stats)); |
2767 | } | 3256 | } |
2768 | spin_unlock_bh(&priv->tx_lock); | 3257 | spin_unlock_bh(&priv->tx_lock); |
@@ -2802,7 +3291,7 @@ static void mwl8k_tx_reclaim_handler(unsigned long data) | |||
2802 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 3291 | for (i = 0; i < MWL8K_TX_QUEUES; i++) |
2803 | mwl8k_txq_reclaim(hw, i, 0); | 3292 | mwl8k_txq_reclaim(hw, i, 0); |
2804 | 3293 | ||
2805 | if (priv->tx_wait != NULL && mwl8k_txq_busy(priv) == 0) { | 3294 | if (priv->tx_wait != NULL && !priv->pending_tx_pkts) { |
2806 | complete(priv->tx_wait); | 3295 | complete(priv->tx_wait); |
2807 | priv->tx_wait = NULL; | 3296 | priv->tx_wait = NULL; |
2808 | } | 3297 | } |
@@ -2822,6 +3311,36 @@ static void mwl8k_finalize_join_worker(struct work_struct *work) | |||
2822 | priv->beacon_skb = NULL; | 3311 | priv->beacon_skb = NULL; |
2823 | } | 3312 | } |
2824 | 3313 | ||
3314 | enum { | ||
3315 | MWL8687 = 0, | ||
3316 | MWL8366, | ||
3317 | }; | ||
3318 | |||
3319 | static struct mwl8k_device_info mwl8k_info_tbl[] __devinitdata = { | ||
3320 | { | ||
3321 | .part_name = "88w8687", | ||
3322 | .helper_image = "mwl8k/helper_8687.fw", | ||
3323 | .fw_image = "mwl8k/fmimage_8687.fw", | ||
3324 | .rxd_ops = &rxd_8687_ops, | ||
3325 | .modes = BIT(NL80211_IFTYPE_STATION), | ||
3326 | }, | ||
3327 | { | ||
3328 | .part_name = "88w8366", | ||
3329 | .helper_image = "mwl8k/helper_8366.fw", | ||
3330 | .fw_image = "mwl8k/fmimage_8366.fw", | ||
3331 | .rxd_ops = &rxd_8366_ops, | ||
3332 | .modes = 0, | ||
3333 | }, | ||
3334 | }; | ||
3335 | |||
3336 | static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { | ||
3337 | { PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = MWL8687, }, | ||
3338 | { PCI_VDEVICE(MARVELL, 0x2a30), .driver_data = MWL8687, }, | ||
3339 | { PCI_VDEVICE(MARVELL, 0x2a40), .driver_data = MWL8366, }, | ||
3340 | { }, | ||
3341 | }; | ||
3342 | MODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table); | ||
3343 | |||
2825 | static int __devinit mwl8k_probe(struct pci_dev *pdev, | 3344 | static int __devinit mwl8k_probe(struct pci_dev *pdev, |
2826 | const struct pci_device_id *id) | 3345 | const struct pci_device_id *id) |
2827 | { | 3346 | { |
@@ -2862,17 +3381,34 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, | |||
2862 | priv = hw->priv; | 3381 | priv = hw->priv; |
2863 | priv->hw = hw; | 3382 | priv->hw = hw; |
2864 | priv->pdev = pdev; | 3383 | priv->pdev = pdev; |
3384 | priv->device_info = &mwl8k_info_tbl[id->driver_data]; | ||
3385 | priv->rxd_ops = priv->device_info->rxd_ops; | ||
3386 | priv->sniffer_enabled = false; | ||
2865 | priv->wmm_enabled = false; | 3387 | priv->wmm_enabled = false; |
2866 | priv->pending_tx_pkts = 0; | 3388 | priv->pending_tx_pkts = 0; |
2867 | strncpy(priv->name, MWL8K_NAME, sizeof(priv->name)); | ||
2868 | 3389 | ||
2869 | SET_IEEE80211_DEV(hw, &pdev->dev); | 3390 | SET_IEEE80211_DEV(hw, &pdev->dev); |
2870 | pci_set_drvdata(pdev, hw); | 3391 | pci_set_drvdata(pdev, hw); |
2871 | 3392 | ||
3393 | priv->sram = pci_iomap(pdev, 0, 0x10000); | ||
3394 | if (priv->sram == NULL) { | ||
3395 | printk(KERN_ERR "%s: Cannot map device SRAM\n", | ||
3396 | wiphy_name(hw->wiphy)); | ||
3397 | goto err_iounmap; | ||
3398 | } | ||
3399 | |||
3400 | /* | ||
3401 | * If BAR0 is a 32 bit BAR, the register BAR will be BAR1. | ||
3402 | * If BAR0 is a 64 bit BAR, the register BAR will be BAR2. | ||
3403 | */ | ||
2872 | priv->regs = pci_iomap(pdev, 1, 0x10000); | 3404 | priv->regs = pci_iomap(pdev, 1, 0x10000); |
2873 | if (priv->regs == NULL) { | 3405 | if (priv->regs == NULL) { |
2874 | printk(KERN_ERR "%s: Cannot map device memory\n", priv->name); | 3406 | priv->regs = pci_iomap(pdev, 2, 0x10000); |
2875 | goto err_iounmap; | 3407 | if (priv->regs == NULL) { |
3408 | printk(KERN_ERR "%s: Cannot map device registers\n", | ||
3409 | wiphy_name(hw->wiphy)); | ||
3410 | goto err_iounmap; | ||
3411 | } | ||
2876 | } | 3412 | } |
2877 | 3413 | ||
2878 | memcpy(priv->channels, mwl8k_channels, sizeof(mwl8k_channels)); | 3414 | memcpy(priv->channels, mwl8k_channels, sizeof(mwl8k_channels)); |
@@ -2897,7 +3433,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, | |||
2897 | 3433 | ||
2898 | hw->queues = MWL8K_TX_QUEUES; | 3434 | hw->queues = MWL8K_TX_QUEUES; |
2899 | 3435 | ||
2900 | hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); | 3436 | hw->wiphy->interface_modes = priv->device_info->modes; |
2901 | 3437 | ||
2902 | /* Set rssi and noise values to dBm */ | 3438 | /* Set rssi and noise values to dBm */ |
2903 | hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; | 3439 | hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; |
@@ -2916,11 +3452,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, | |||
2916 | mwl8k_tx_reclaim_handler, (unsigned long)hw); | 3452 | mwl8k_tx_reclaim_handler, (unsigned long)hw); |
2917 | tasklet_disable(&priv->tx_reclaim_task); | 3453 | tasklet_disable(&priv->tx_reclaim_task); |
2918 | 3454 | ||
2919 | /* Config workthread */ | ||
2920 | priv->config_wq = create_singlethread_workqueue("mwl8k_config"); | ||
2921 | if (priv->config_wq == NULL) | ||
2922 | goto err_iounmap; | ||
2923 | |||
2924 | /* Power management cookie */ | 3455 | /* Power management cookie */ |
2925 | priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma); | 3456 | priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma); |
2926 | if (priv->cookie == NULL) | 3457 | if (priv->cookie == NULL) |
@@ -2934,11 +3465,12 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, | |||
2934 | mutex_init(&priv->fw_mutex); | 3465 | mutex_init(&priv->fw_mutex); |
2935 | priv->fw_mutex_owner = NULL; | 3466 | priv->fw_mutex_owner = NULL; |
2936 | priv->fw_mutex_depth = 0; | 3467 | priv->fw_mutex_depth = 0; |
2937 | priv->tx_wait = NULL; | ||
2938 | priv->hostcmd_wait = NULL; | 3468 | priv->hostcmd_wait = NULL; |
2939 | 3469 | ||
2940 | spin_lock_init(&priv->tx_lock); | 3470 | spin_lock_init(&priv->tx_lock); |
2941 | 3471 | ||
3472 | priv->tx_wait = NULL; | ||
3473 | |||
2942 | for (i = 0; i < MWL8K_TX_QUEUES; i++) { | 3474 | for (i = 0; i < MWL8K_TX_QUEUES; i++) { |
2943 | rc = mwl8k_txq_init(hw, i); | 3475 | rc = mwl8k_txq_init(hw, i); |
2944 | if (rc) | 3476 | if (rc) |
@@ -2950,11 +3482,11 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, | |||
2950 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); | 3482 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); |
2951 | iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); | 3483 | iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); |
2952 | 3484 | ||
2953 | rc = request_irq(priv->pdev->irq, &mwl8k_interrupt, | 3485 | rc = request_irq(priv->pdev->irq, mwl8k_interrupt, |
2954 | IRQF_SHARED, MWL8K_NAME, hw); | 3486 | IRQF_SHARED, MWL8K_NAME, hw); |
2955 | if (rc) { | 3487 | if (rc) { |
2956 | printk(KERN_ERR "%s: failed to register IRQ handler\n", | 3488 | printk(KERN_ERR "%s: failed to register IRQ handler\n", |
2957 | priv->name); | 3489 | wiphy_name(hw->wiphy)); |
2958 | goto err_free_queues; | 3490 | goto err_free_queues; |
2959 | } | 3491 | } |
2960 | 3492 | ||
@@ -2962,16 +3494,18 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, | |||
2962 | mwl8k_hw_reset(priv); | 3494 | mwl8k_hw_reset(priv); |
2963 | 3495 | ||
2964 | /* Ask userland hotplug daemon for the device firmware */ | 3496 | /* Ask userland hotplug daemon for the device firmware */ |
2965 | rc = mwl8k_request_firmware(priv, (u32)id->driver_data); | 3497 | rc = mwl8k_request_firmware(priv); |
2966 | if (rc) { | 3498 | if (rc) { |
2967 | printk(KERN_ERR "%s: Firmware files not found\n", priv->name); | 3499 | printk(KERN_ERR "%s: Firmware files not found\n", |
3500 | wiphy_name(hw->wiphy)); | ||
2968 | goto err_free_irq; | 3501 | goto err_free_irq; |
2969 | } | 3502 | } |
2970 | 3503 | ||
2971 | /* Load firmware into hardware */ | 3504 | /* Load firmware into hardware */ |
2972 | rc = mwl8k_load_firmware(priv); | 3505 | rc = mwl8k_load_firmware(hw); |
2973 | if (rc) { | 3506 | if (rc) { |
2974 | printk(KERN_ERR "%s: Cannot start firmware\n", priv->name); | 3507 | printk(KERN_ERR "%s: Cannot start firmware\n", |
3508 | wiphy_name(hw->wiphy)); | ||
2975 | goto err_stop_firmware; | 3509 | goto err_stop_firmware; |
2976 | } | 3510 | } |
2977 | 3511 | ||
@@ -2986,16 +3520,31 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, | |||
2986 | iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); | 3520 | iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); |
2987 | 3521 | ||
2988 | /* Get config data, mac addrs etc */ | 3522 | /* Get config data, mac addrs etc */ |
2989 | rc = mwl8k_cmd_get_hw_spec(hw); | 3523 | if (priv->ap_fw) { |
3524 | rc = mwl8k_cmd_get_hw_spec_ap(hw); | ||
3525 | if (!rc) | ||
3526 | rc = mwl8k_cmd_set_hw_spec(hw); | ||
3527 | } else { | ||
3528 | rc = mwl8k_cmd_get_hw_spec_sta(hw); | ||
3529 | } | ||
2990 | if (rc) { | 3530 | if (rc) { |
2991 | printk(KERN_ERR "%s: Cannot initialise firmware\n", priv->name); | 3531 | printk(KERN_ERR "%s: Cannot initialise firmware\n", |
3532 | wiphy_name(hw->wiphy)); | ||
2992 | goto err_stop_firmware; | 3533 | goto err_stop_firmware; |
2993 | } | 3534 | } |
2994 | 3535 | ||
2995 | /* Turn radio off */ | 3536 | /* Turn radio off */ |
2996 | rc = mwl8k_cmd_802_11_radio_disable(hw); | 3537 | rc = mwl8k_cmd_802_11_radio_disable(hw); |
2997 | if (rc) { | 3538 | if (rc) { |
2998 | printk(KERN_ERR "%s: Cannot disable\n", priv->name); | 3539 | printk(KERN_ERR "%s: Cannot disable\n", wiphy_name(hw->wiphy)); |
3540 | goto err_stop_firmware; | ||
3541 | } | ||
3542 | |||
3543 | /* Clear MAC address */ | ||
3544 | rc = mwl8k_set_mac_addr(hw, "\x00\x00\x00\x00\x00\x00"); | ||
3545 | if (rc) { | ||
3546 | printk(KERN_ERR "%s: Cannot clear MAC address\n", | ||
3547 | wiphy_name(hw->wiphy)); | ||
2999 | goto err_stop_firmware; | 3548 | goto err_stop_firmware; |
3000 | } | 3549 | } |
3001 | 3550 | ||
@@ -3005,13 +3554,15 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, | |||
3005 | 3554 | ||
3006 | rc = ieee80211_register_hw(hw); | 3555 | rc = ieee80211_register_hw(hw); |
3007 | if (rc) { | 3556 | if (rc) { |
3008 | printk(KERN_ERR "%s: Cannot register device\n", priv->name); | 3557 | printk(KERN_ERR "%s: Cannot register device\n", |
3558 | wiphy_name(hw->wiphy)); | ||
3009 | goto err_stop_firmware; | 3559 | goto err_stop_firmware; |
3010 | } | 3560 | } |
3011 | 3561 | ||
3012 | printk(KERN_INFO "%s: 88w%u v%d, %pM, firmware version %u.%u.%u.%u\n", | 3562 | printk(KERN_INFO "%s: %s v%d, %pM, %s firmware %u.%u.%u.%u\n", |
3013 | wiphy_name(hw->wiphy), priv->part_num, priv->hw_rev, | 3563 | wiphy_name(hw->wiphy), priv->device_info->part_name, |
3014 | hw->wiphy->perm_addr, | 3564 | priv->hw_rev, hw->wiphy->perm_addr, |
3565 | priv->ap_fw ? "AP" : "STA", | ||
3015 | (priv->fw_rev >> 24) & 0xff, (priv->fw_rev >> 16) & 0xff, | 3566 | (priv->fw_rev >> 24) & 0xff, (priv->fw_rev >> 16) & 0xff, |
3016 | (priv->fw_rev >> 8) & 0xff, priv->fw_rev & 0xff); | 3567 | (priv->fw_rev >> 8) & 0xff, priv->fw_rev & 0xff); |
3017 | 3568 | ||
@@ -3038,8 +3589,8 @@ err_iounmap: | |||
3038 | if (priv->regs != NULL) | 3589 | if (priv->regs != NULL) |
3039 | pci_iounmap(pdev, priv->regs); | 3590 | pci_iounmap(pdev, priv->regs); |
3040 | 3591 | ||
3041 | if (priv->config_wq != NULL) | 3592 | if (priv->sram != NULL) |
3042 | destroy_workqueue(priv->config_wq); | 3593 | pci_iounmap(pdev, priv->sram); |
3043 | 3594 | ||
3044 | pci_set_drvdata(pdev, NULL); | 3595 | pci_set_drvdata(pdev, NULL); |
3045 | ieee80211_free_hw(hw); | 3596 | ieee80211_free_hw(hw); |
@@ -3073,9 +3624,6 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev) | |||
3073 | /* Remove tx reclaim tasklet */ | 3624 | /* Remove tx reclaim tasklet */ |
3074 | tasklet_kill(&priv->tx_reclaim_task); | 3625 | tasklet_kill(&priv->tx_reclaim_task); |
3075 | 3626 | ||
3076 | /* Stop config thread */ | ||
3077 | destroy_workqueue(priv->config_wq); | ||
3078 | |||
3079 | /* Stop hardware */ | 3627 | /* Stop hardware */ |
3080 | mwl8k_hw_reset(priv); | 3628 | mwl8k_hw_reset(priv); |
3081 | 3629 | ||
@@ -3088,10 +3636,10 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev) | |||
3088 | 3636 | ||
3089 | mwl8k_rxq_deinit(hw, 0); | 3637 | mwl8k_rxq_deinit(hw, 0); |
3090 | 3638 | ||
3091 | pci_free_consistent(priv->pdev, 4, | 3639 | pci_free_consistent(priv->pdev, 4, priv->cookie, priv->cookie_dma); |
3092 | priv->cookie, priv->cookie_dma); | ||
3093 | 3640 | ||
3094 | pci_iounmap(pdev, priv->regs); | 3641 | pci_iounmap(pdev, priv->regs); |
3642 | pci_iounmap(pdev, priv->sram); | ||
3095 | pci_set_drvdata(pdev, NULL); | 3643 | pci_set_drvdata(pdev, NULL); |
3096 | ieee80211_free_hw(hw); | 3644 | ieee80211_free_hw(hw); |
3097 | pci_release_regions(pdev); | 3645 | pci_release_regions(pdev); |
@@ -3100,7 +3648,7 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev) | |||
3100 | 3648 | ||
3101 | static struct pci_driver mwl8k_driver = { | 3649 | static struct pci_driver mwl8k_driver = { |
3102 | .name = MWL8K_NAME, | 3650 | .name = MWL8K_NAME, |
3103 | .id_table = mwl8k_table, | 3651 | .id_table = mwl8k_pci_id_table, |
3104 | .probe = mwl8k_probe, | 3652 | .probe = mwl8k_probe, |
3105 | .remove = __devexit_p(mwl8k_remove), | 3653 | .remove = __devexit_p(mwl8k_remove), |
3106 | .shutdown = __devexit_p(mwl8k_shutdown), | 3654 | .shutdown = __devexit_p(mwl8k_shutdown), |
@@ -3118,3 +3666,8 @@ static void __exit mwl8k_exit(void) | |||
3118 | 3666 | ||
3119 | module_init(mwl8k_init); | 3667 | module_init(mwl8k_init); |
3120 | module_exit(mwl8k_exit); | 3668 | module_exit(mwl8k_exit); |
3669 | |||
3670 | MODULE_DESCRIPTION(MWL8K_DESC); | ||
3671 | MODULE_VERSION(MWL8K_VERSION); | ||
3672 | MODULE_AUTHOR("Lennert Buytenhek <buytenh@marvell.com>"); | ||
3673 | MODULE_LICENSE("GPL"); | ||