blob: a961b698c69124c2d2e56bee72cff4d76032b2fb [file] [log] [blame]
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001/*
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02002 * drivers/net/wireless/mwl8k.c
3 * Driver for Marvell TOPDOG 802.11 Wireless cards
Lennert Buytenheka66098d2009-03-10 10:13:33 +01004 *
5 * Copyright (C) 2008 Marvell Semiconductor Inc.
6 *
7 * This file is licensed under the terms of the GNU General Public
8 * License version 2. This program is licensed "as is" without any
9 * warranty of any kind, whether express or implied.
10 */
11
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/spinlock.h>
16#include <linux/list.h>
17#include <linux/pci.h>
18#include <linux/delay.h>
19#include <linux/completion.h>
20#include <linux/etherdevice.h>
21#include <net/mac80211.h>
22#include <linux/moduleparam.h>
23#include <linux/firmware.h>
24#include <linux/workqueue.h>
25
26#define MWL8K_DESC "Marvell TOPDOG(R) 802.11 Wireless Network Driver"
27#define MWL8K_NAME KBUILD_MODNAME
28#define MWL8K_VERSION "0.9.1"
29
30MODULE_DESCRIPTION(MWL8K_DESC);
31MODULE_VERSION(MWL8K_VERSION);
32MODULE_AUTHOR("Lennert Buytenhek <buytenh@marvell.com>");
33MODULE_LICENSE("GPL");
34
35static DEFINE_PCI_DEVICE_TABLE(mwl8k_table) = {
36 { PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = 8687, },
37 { PCI_VDEVICE(MARVELL, 0x2a30), .driver_data = 8687, },
38 { }
39};
40MODULE_DEVICE_TABLE(pci, mwl8k_table);
41
Lennert Buytenheka66098d2009-03-10 10:13:33 +010042/* Register definitions */
43#define MWL8K_HIU_GEN_PTR 0x00000c10
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +020044#define MWL8K_MODE_STA 0x0000005a
45#define MWL8K_MODE_AP 0x000000a5
Lennert Buytenheka66098d2009-03-10 10:13:33 +010046#define MWL8K_HIU_INT_CODE 0x00000c14
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +020047#define MWL8K_FWSTA_READY 0xf0f1f2f4
48#define MWL8K_FWAP_READY 0xf1f2f4a5
49#define MWL8K_INT_CODE_CMD_FINISHED 0x00000005
Lennert Buytenheka66098d2009-03-10 10:13:33 +010050#define MWL8K_HIU_SCRATCH 0x00000c40
51
52/* Host->device communications */
53#define MWL8K_HIU_H2A_INTERRUPT_EVENTS 0x00000c18
54#define MWL8K_HIU_H2A_INTERRUPT_STATUS 0x00000c1c
55#define MWL8K_HIU_H2A_INTERRUPT_MASK 0x00000c20
56#define MWL8K_HIU_H2A_INTERRUPT_CLEAR_SEL 0x00000c24
57#define MWL8K_HIU_H2A_INTERRUPT_STATUS_MASK 0x00000c28
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +020058#define MWL8K_H2A_INT_DUMMY (1 << 20)
59#define MWL8K_H2A_INT_RESET (1 << 15)
60#define MWL8K_H2A_INT_DOORBELL (1 << 1)
61#define MWL8K_H2A_INT_PPA_READY (1 << 0)
Lennert Buytenheka66098d2009-03-10 10:13:33 +010062
63/* Device->host communications */
64#define MWL8K_HIU_A2H_INTERRUPT_EVENTS 0x00000c2c
65#define MWL8K_HIU_A2H_INTERRUPT_STATUS 0x00000c30
66#define MWL8K_HIU_A2H_INTERRUPT_MASK 0x00000c34
67#define MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL 0x00000c38
68#define MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK 0x00000c3c
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +020069#define MWL8K_A2H_INT_DUMMY (1 << 20)
70#define MWL8K_A2H_INT_CHNL_SWITCHED (1 << 11)
71#define MWL8K_A2H_INT_QUEUE_EMPTY (1 << 10)
72#define MWL8K_A2H_INT_RADAR_DETECT (1 << 7)
73#define MWL8K_A2H_INT_RADIO_ON (1 << 6)
74#define MWL8K_A2H_INT_RADIO_OFF (1 << 5)
75#define MWL8K_A2H_INT_MAC_EVENT (1 << 3)
76#define MWL8K_A2H_INT_OPC_DONE (1 << 2)
77#define MWL8K_A2H_INT_RX_READY (1 << 1)
78#define MWL8K_A2H_INT_TX_DONE (1 << 0)
Lennert Buytenheka66098d2009-03-10 10:13:33 +010079
80#define MWL8K_A2H_EVENTS (MWL8K_A2H_INT_DUMMY | \
81 MWL8K_A2H_INT_CHNL_SWITCHED | \
82 MWL8K_A2H_INT_QUEUE_EMPTY | \
83 MWL8K_A2H_INT_RADAR_DETECT | \
84 MWL8K_A2H_INT_RADIO_ON | \
85 MWL8K_A2H_INT_RADIO_OFF | \
86 MWL8K_A2H_INT_MAC_EVENT | \
87 MWL8K_A2H_INT_OPC_DONE | \
88 MWL8K_A2H_INT_RX_READY | \
89 MWL8K_A2H_INT_TX_DONE)
90
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
98#define MWL8K_TX_QUEUES 4
99
100struct mwl8k_rx_queue {
101 int rx_desc_count;
102
103 /* hw receives here */
104 int rx_head;
105
106 /* refill descs here */
107 int rx_tail;
108
109 struct mwl8k_rx_desc *rx_desc_area;
110 dma_addr_t rx_desc_dma;
111 struct sk_buff **rx_skb;
112};
113
114struct mwl8k_skb {
115 /*
116 * The DMA engine requires a modification to the payload.
117 * If the skbuff is shared/cloned, it needs to be unshared.
118 * This method is used to ensure the stack always gets back
119 * the skbuff it sent for transmission.
120 */
121 struct sk_buff *clone;
122 struct sk_buff *skb;
123};
124
125struct mwl8k_tx_queue {
126 /* hw transmits here */
127 int tx_head;
128
129 /* sw appends here */
130 int tx_tail;
131
132 struct ieee80211_tx_queue_stats tx_stats;
133 struct mwl8k_tx_desc *tx_desc_area;
134 dma_addr_t tx_desc_dma;
135 struct mwl8k_skb *tx_skb;
136};
137
138/* Pointers to the firmware data and meta information about it. */
139struct mwl8k_firmware {
140 /* Microcode */
141 struct firmware *ucode;
142
143 /* Boot helper code */
144 struct firmware *helper;
145};
146
147struct mwl8k_priv {
148 void __iomem *regs;
149 struct ieee80211_hw *hw;
150
151 struct pci_dev *pdev;
152 u8 name[16];
153 /* firmware access lock */
154 spinlock_t fw_lock;
155
156 /* firmware files and meta data */
157 struct mwl8k_firmware fw;
158 u32 part_num;
159
160 /* lock held over TX and TX reap */
161 spinlock_t tx_lock;
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100162
163 struct ieee80211_vif *vif;
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100164
165 struct ieee80211_channel *current_channel;
166
167 /* power management status cookie from firmware */
168 u32 *cookie;
169 dma_addr_t cookie_dma;
170
171 u16 num_mcaddrs;
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100172 u8 hw_rev;
173 __le32 fw_rev;
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100174
175 /*
176 * Running count of TX packets in flight, to avoid
177 * iterating over the transmit rings each time.
178 */
179 int pending_tx_pkts;
180
181 struct mwl8k_rx_queue rxq[MWL8K_RX_QUEUES];
182 struct mwl8k_tx_queue txq[MWL8K_TX_QUEUES];
183
184 /* PHY parameters */
185 struct ieee80211_supported_band band;
186 struct ieee80211_channel channels[14];
187 struct ieee80211_rate rates[12];
188
Lennert Buytenhekc46563b2009-07-16 12:14:58 +0200189 bool radio_on;
Lennert Buytenhek68ce3882009-07-16 12:26:57 +0200190 bool radio_short_preamble;
Lennert Buytenhek0439b1f2009-07-16 12:34:02 +0200191 bool wmm_enabled;
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100192
193 /* Set if PHY config is in progress */
194 bool inconfig;
195
196 /* XXX need to convert this to handle multiple interfaces */
197 bool capture_beacon;
Lennert Buytenhekd89173f2009-07-16 09:54:27 +0200198 u8 capture_bssid[ETH_ALEN];
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100199 struct sk_buff *beacon_skb;
200
201 /*
202 * This FJ worker has to be global as it is scheduled from the
203 * RX handler. At this point we don't know which interface it
204 * belongs to until the list of bssids waiting to complete join
205 * is checked.
206 */
207 struct work_struct finalize_join_worker;
208
209 /* Tasklet to reclaim TX descriptors and buffers after tx */
210 struct tasklet_struct tx_reclaim_task;
211
212 /* Work thread to serialize configuration requests */
213 struct workqueue_struct *config_wq;
214 struct completion *hostcmd_wait;
215 struct completion *tx_wait;
216};
217
218/* Per interface specific private data */
219struct mwl8k_vif {
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100220 /* backpointer to parent config block */
221 struct mwl8k_priv *priv;
222
223 /* BSS config of AP or IBSS from mac80211*/
224 struct ieee80211_bss_conf bss_info;
225
226 /* BSSID of AP or IBSS */
Lennert Buytenhekd89173f2009-07-16 09:54:27 +0200227 u8 bssid[ETH_ALEN];
228 u8 mac_addr[ETH_ALEN];
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100229
230 /*
231 * Subset of supported legacy rates.
232 * Intersection of AP and STA supported rates.
233 */
234 struct ieee80211_rate legacy_rates[12];
235
236 /* number of supported legacy rates */
237 u8 legacy_nrates;
238
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100239 /* Index into station database.Returned by update_sta_db call */
240 u8 peer_id;
241
242 /* Non AMPDU sequence number assigned by driver */
243 u16 seqno;
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100244};
245
Lennert Buytenheka94cc972009-08-03 21:58:57 +0200246#define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv))
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100247
248static const struct ieee80211_channel mwl8k_channels[] = {
249 { .center_freq = 2412, .hw_value = 1, },
250 { .center_freq = 2417, .hw_value = 2, },
251 { .center_freq = 2422, .hw_value = 3, },
252 { .center_freq = 2427, .hw_value = 4, },
253 { .center_freq = 2432, .hw_value = 5, },
254 { .center_freq = 2437, .hw_value = 6, },
255 { .center_freq = 2442, .hw_value = 7, },
256 { .center_freq = 2447, .hw_value = 8, },
257 { .center_freq = 2452, .hw_value = 9, },
258 { .center_freq = 2457, .hw_value = 10, },
259 { .center_freq = 2462, .hw_value = 11, },
260};
261
262static const struct ieee80211_rate mwl8k_rates[] = {
263 { .bitrate = 10, .hw_value = 2, },
264 { .bitrate = 20, .hw_value = 4, },
265 { .bitrate = 55, .hw_value = 11, },
266 { .bitrate = 60, .hw_value = 12, },
267 { .bitrate = 90, .hw_value = 18, },
268 { .bitrate = 110, .hw_value = 22, },
269 { .bitrate = 120, .hw_value = 24, },
270 { .bitrate = 180, .hw_value = 36, },
271 { .bitrate = 240, .hw_value = 48, },
272 { .bitrate = 360, .hw_value = 72, },
273 { .bitrate = 480, .hw_value = 96, },
274 { .bitrate = 540, .hw_value = 108, },
275};
276
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100277/* Set or get info from Firmware */
278#define MWL8K_CMD_SET 0x0001
279#define MWL8K_CMD_GET 0x0000
280
281/* Firmware command codes */
282#define MWL8K_CMD_CODE_DNLD 0x0001
283#define MWL8K_CMD_GET_HW_SPEC 0x0003
284#define MWL8K_CMD_MAC_MULTICAST_ADR 0x0010
285#define MWL8K_CMD_GET_STAT 0x0014
Lennert Buytenhekff45fc62009-07-16 11:50:36 +0200286#define MWL8K_CMD_RADIO_CONTROL 0x001c
287#define MWL8K_CMD_RF_TX_POWER 0x001e
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100288#define MWL8K_CMD_SET_PRE_SCAN 0x0107
289#define MWL8K_CMD_SET_POST_SCAN 0x0108
Lennert Buytenhekff45fc62009-07-16 11:50:36 +0200290#define MWL8K_CMD_SET_RF_CHANNEL 0x010a
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100291#define MWL8K_CMD_SET_AID 0x010d
292#define MWL8K_CMD_SET_RATE 0x0110
Lennert Buytenhekff45fc62009-07-16 11:50:36 +0200293#define MWL8K_CMD_SET_FINALIZE_JOIN 0x0111
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100294#define MWL8K_CMD_RTS_THRESHOLD 0x0113
Lennert Buytenhekff45fc62009-07-16 11:50:36 +0200295#define MWL8K_CMD_SET_SLOT 0x0114
296#define MWL8K_CMD_SET_EDCA_PARAMS 0x0115
297#define MWL8K_CMD_SET_WMM_MODE 0x0123
298#define MWL8K_CMD_MIMO_CONFIG 0x0125
299#define MWL8K_CMD_USE_FIXED_RATE 0x0126
300#define MWL8K_CMD_ENABLE_SNIFFER 0x0150
301#define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203
302#define MWL8K_CMD_UPDATE_STADB 0x1123
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100303
304static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize)
305{
306#define MWL8K_CMDNAME(x) case MWL8K_CMD_##x: do {\
307 snprintf(buf, bufsize, "%s", #x);\
308 return buf;\
309 } while (0)
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +0200310 switch (cmd & ~0x8000) {
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100311 MWL8K_CMDNAME(CODE_DNLD);
312 MWL8K_CMDNAME(GET_HW_SPEC);
313 MWL8K_CMDNAME(MAC_MULTICAST_ADR);
314 MWL8K_CMDNAME(GET_STAT);
315 MWL8K_CMDNAME(RADIO_CONTROL);
316 MWL8K_CMDNAME(RF_TX_POWER);
317 MWL8K_CMDNAME(SET_PRE_SCAN);
318 MWL8K_CMDNAME(SET_POST_SCAN);
319 MWL8K_CMDNAME(SET_RF_CHANNEL);
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100320 MWL8K_CMDNAME(SET_AID);
321 MWL8K_CMDNAME(SET_RATE);
Lennert Buytenhekff45fc62009-07-16 11:50:36 +0200322 MWL8K_CMDNAME(SET_FINALIZE_JOIN);
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100323 MWL8K_CMDNAME(RTS_THRESHOLD);
Lennert Buytenhekff45fc62009-07-16 11:50:36 +0200324 MWL8K_CMDNAME(SET_SLOT);
325 MWL8K_CMDNAME(SET_EDCA_PARAMS);
326 MWL8K_CMDNAME(SET_WMM_MODE);
327 MWL8K_CMDNAME(MIMO_CONFIG);
328 MWL8K_CMDNAME(USE_FIXED_RATE);
329 MWL8K_CMDNAME(ENABLE_SNIFFER);
330 MWL8K_CMDNAME(SET_RATEADAPT_MODE);
331 MWL8K_CMDNAME(UPDATE_STADB);
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100332 default:
333 snprintf(buf, bufsize, "0x%x", cmd);
334 }
335#undef MWL8K_CMDNAME
336
337 return buf;
338}
339
340/* Hardware and firmware reset */
341static void mwl8k_hw_reset(struct mwl8k_priv *priv)
342{
343 iowrite32(MWL8K_H2A_INT_RESET,
344 priv->regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS);
345 iowrite32(MWL8K_H2A_INT_RESET,
346 priv->regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS);
347 msleep(20);
348}
349
350/* Release fw image */
351static void mwl8k_release_fw(struct firmware **fw)
352{
353 if (*fw == NULL)
354 return;
355 release_firmware(*fw);
356 *fw = NULL;
357}
358
359static void mwl8k_release_firmware(struct mwl8k_priv *priv)
360{
361 mwl8k_release_fw(&priv->fw.ucode);
362 mwl8k_release_fw(&priv->fw.helper);
363}
364
365/* Request fw image */
366static int mwl8k_request_fw(struct mwl8k_priv *priv,
367 const char *fname, struct firmware **fw)
368{
369 /* release current image */
370 if (*fw != NULL)
371 mwl8k_release_fw(fw);
372
373 return request_firmware((const struct firmware **)fw,
374 fname, &priv->pdev->dev);
375}
376
377static int mwl8k_request_firmware(struct mwl8k_priv *priv, u32 part_num)
378{
379 u8 filename[64];
380 int rc;
381
382 priv->part_num = part_num;
383
384 snprintf(filename, sizeof(filename),
385 "mwl8k/helper_%u.fw", priv->part_num);
386
387 rc = mwl8k_request_fw(priv, filename, &priv->fw.helper);
388 if (rc) {
389 printk(KERN_ERR
390 "%s Error requesting helper firmware file %s\n",
391 pci_name(priv->pdev), filename);
392 return rc;
393 }
394
395 snprintf(filename, sizeof(filename),
396 "mwl8k/fmimage_%u.fw", priv->part_num);
397
398 rc = mwl8k_request_fw(priv, filename, &priv->fw.ucode);
399 if (rc) {
400 printk(KERN_ERR "%s Error requesting firmware file %s\n",
401 pci_name(priv->pdev), filename);
402 mwl8k_release_fw(&priv->fw.helper);
403 return rc;
404 }
405
406 return 0;
407}
408
409struct mwl8k_cmd_pkt {
410 __le16 code;
411 __le16 length;
412 __le16 seq_num;
413 __le16 result;
414 char payload[0];
415} __attribute__((packed));
416
417/*
418 * Firmware loading.
419 */
420static int
421mwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length)
422{
423 void __iomem *regs = priv->regs;
424 dma_addr_t dma_addr;
425 int rc;
426 int loops;
427
428 dma_addr = pci_map_single(priv->pdev, data, length, PCI_DMA_TODEVICE);
429 if (pci_dma_mapping_error(priv->pdev, dma_addr))
430 return -ENOMEM;
431
432 iowrite32(dma_addr, regs + MWL8K_HIU_GEN_PTR);
433 iowrite32(0, regs + MWL8K_HIU_INT_CODE);
434 iowrite32(MWL8K_H2A_INT_DOORBELL,
435 regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS);
436 iowrite32(MWL8K_H2A_INT_DUMMY,
437 regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS);
438
439 rc = -ETIMEDOUT;
440 loops = 1000;
441 do {
442 u32 int_code;
443
444 int_code = ioread32(regs + MWL8K_HIU_INT_CODE);
445 if (int_code == MWL8K_INT_CODE_CMD_FINISHED) {
446 iowrite32(0, regs + MWL8K_HIU_INT_CODE);
447 rc = 0;
448 break;
449 }
450
451 udelay(1);
452 } while (--loops);
453
454 pci_unmap_single(priv->pdev, dma_addr, length, PCI_DMA_TODEVICE);
455
456 /*
457 * Clear 'command done' interrupt bit.
458 */
459 loops = 1000;
460 do {
461 u32 status;
462
463 status = ioread32(priv->regs +
464 MWL8K_HIU_A2H_INTERRUPT_STATUS);
465 if (status & MWL8K_A2H_INT_OPC_DONE) {
466 iowrite32(~MWL8K_A2H_INT_OPC_DONE,
467 priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
468 ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
469 break;
470 }
471
472 udelay(1);
473 } while (--loops);
474
475 return rc;
476}
477
478static int mwl8k_load_fw_image(struct mwl8k_priv *priv,
479 const u8 *data, size_t length)
480{
481 struct mwl8k_cmd_pkt *cmd;
482 int done;
483 int rc = 0;
484
485 cmd = kmalloc(sizeof(*cmd) + 256, GFP_KERNEL);
486 if (cmd == NULL)
487 return -ENOMEM;
488
489 cmd->code = cpu_to_le16(MWL8K_CMD_CODE_DNLD);
490 cmd->seq_num = 0;
491 cmd->result = 0;
492
493 done = 0;
494 while (length) {
495 int block_size = length > 256 ? 256 : length;
496
497 memcpy(cmd->payload, data + done, block_size);
498 cmd->length = cpu_to_le16(block_size);
499
500 rc = mwl8k_send_fw_load_cmd(priv, cmd,
501 sizeof(*cmd) + block_size);
502 if (rc)
503 break;
504
505 done += block_size;
506 length -= block_size;
507 }
508
509 if (!rc) {
510 cmd->length = 0;
511 rc = mwl8k_send_fw_load_cmd(priv, cmd, sizeof(*cmd));
512 }
513
514 kfree(cmd);
515
516 return rc;
517}
518
519static int mwl8k_feed_fw_image(struct mwl8k_priv *priv,
520 const u8 *data, size_t length)
521{
522 unsigned char *buffer;
523 int may_continue, rc = 0;
524 u32 done, prev_block_size;
525
526 buffer = kmalloc(1024, GFP_KERNEL);
527 if (buffer == NULL)
528 return -ENOMEM;
529
530 done = 0;
531 prev_block_size = 0;
532 may_continue = 1000;
533 while (may_continue > 0) {
534 u32 block_size;
535
536 block_size = ioread32(priv->regs + MWL8K_HIU_SCRATCH);
537 if (block_size & 1) {
538 block_size &= ~1;
539 may_continue--;
540 } else {
541 done += prev_block_size;
542 length -= prev_block_size;
543 }
544
545 if (block_size > 1024 || block_size > length) {
546 rc = -EOVERFLOW;
547 break;
548 }
549
550 if (length == 0) {
551 rc = 0;
552 break;
553 }
554
555 if (block_size == 0) {
556 rc = -EPROTO;
557 may_continue--;
558 udelay(1);
559 continue;
560 }
561
562 prev_block_size = block_size;
563 memcpy(buffer, data + done, block_size);
564
565 rc = mwl8k_send_fw_load_cmd(priv, buffer, block_size);
566 if (rc)
567 break;
568 }
569
570 if (!rc && length != 0)
571 rc = -EREMOTEIO;
572
573 kfree(buffer);
574
575 return rc;
576}
577
578static int mwl8k_load_firmware(struct mwl8k_priv *priv)
579{
580 int loops, rc;
581
582 const u8 *ucode = priv->fw.ucode->data;
583 size_t ucode_len = priv->fw.ucode->size;
584 const u8 *helper = priv->fw.helper->data;
585 size_t helper_len = priv->fw.helper->size;
586
587 if (!memcmp(ucode, "\x01\x00\x00\x00", 4)) {
588 rc = mwl8k_load_fw_image(priv, helper, helper_len);
589 if (rc) {
590 printk(KERN_ERR "%s: unable to load firmware "
591 "helper image\n", pci_name(priv->pdev));
592 return rc;
593 }
594 msleep(1);
595
596 rc = mwl8k_feed_fw_image(priv, ucode, ucode_len);
597 } else {
598 rc = mwl8k_load_fw_image(priv, ucode, ucode_len);
599 }
600
601 if (rc) {
602 printk(KERN_ERR "%s: unable to load firmware data\n",
603 pci_name(priv->pdev));
604 return rc;
605 }
606
607 iowrite32(MWL8K_MODE_STA, priv->regs + MWL8K_HIU_GEN_PTR);
608 msleep(1);
609
610 loops = 200000;
611 do {
612 if (ioread32(priv->regs + MWL8K_HIU_INT_CODE)
613 == MWL8K_FWSTA_READY)
614 break;
615 udelay(1);
616 } while (--loops);
617
618 return loops ? 0 : -ETIMEDOUT;
619}
620
621
622/*
623 * Defines shared between transmission and reception.
624 */
625/* HT control fields for firmware */
626struct ewc_ht_info {
627 __le16 control1;
628 __le16 control2;
629 __le16 control3;
630} __attribute__((packed));
631
632/* Firmware Station database operations */
633#define MWL8K_STA_DB_ADD_ENTRY 0
634#define MWL8K_STA_DB_MODIFY_ENTRY 1
635#define MWL8K_STA_DB_DEL_ENTRY 2
636#define MWL8K_STA_DB_FLUSH 3
637
638/* Peer Entry flags - used to define the type of the peer node */
639#define MWL8K_PEER_TYPE_ACCESSPOINT 2
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100640
641#define MWL8K_IEEE_LEGACY_DATA_RATES 12
642#define MWL8K_MCS_BITMAP_SIZE 16
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100643
644struct peer_capability_info {
645 /* Peer type - AP vs. STA. */
646 __u8 peer_type;
647
648 /* Basic 802.11 capabilities from assoc resp. */
649 __le16 basic_caps;
650
651 /* Set if peer supports 802.11n high throughput (HT). */
652 __u8 ht_support;
653
654 /* Valid if HT is supported. */
655 __le16 ht_caps;
656 __u8 extended_ht_caps;
657 struct ewc_ht_info ewc_info;
658
659 /* Legacy rate table. Intersection of our rates and peer rates. */
660 __u8 legacy_rates[MWL8K_IEEE_LEGACY_DATA_RATES];
661
662 /* HT rate table. Intersection of our rates and peer rates. */
663 __u8 ht_rates[MWL8K_MCS_BITMAP_SIZE];
Lennert Buytenhekc23b5a62009-07-16 13:49:55 +0200664 __u8 pad[16];
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100665
666 /* If set, interoperability mode, no proprietary extensions. */
667 __u8 interop;
668 __u8 pad2;
669 __u8 station_id;
670 __le16 amsdu_enabled;
671} __attribute__((packed));
672
673/* Inline functions to manipulate QoS field in data descriptor. */
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100674static inline u16 mwl8k_qos_setbit_eosp(u16 qos)
675{
676 u16 val_mask = 1 << 4;
677
678 /* End of Service Period Bit 4 */
679 return qos | val_mask;
680}
681
682static inline u16 mwl8k_qos_setbit_ack(u16 qos, u8 ack_policy)
683{
684 u16 val_mask = 0x3;
685 u8 shift = 5;
686 u16 qos_mask = ~(val_mask << shift);
687
688 /* Ack Policy Bit 5-6 */
689 return (qos & qos_mask) | ((ack_policy & val_mask) << shift);
690}
691
692static inline u16 mwl8k_qos_setbit_amsdu(u16 qos)
693{
694 u16 val_mask = 1 << 7;
695
696 /* AMSDU present Bit 7 */
697 return qos | val_mask;
698}
699
700static inline u16 mwl8k_qos_setbit_qlen(u16 qos, u8 len)
701{
702 u16 val_mask = 0xff;
703 u8 shift = 8;
704 u16 qos_mask = ~(val_mask << shift);
705
706 /* Queue Length Bits 8-15 */
707 return (qos & qos_mask) | ((len & val_mask) << shift);
708}
709
710/* DMA header used by firmware and hardware. */
711struct mwl8k_dma_data {
712 __le16 fwlen;
713 struct ieee80211_hdr wh;
714} __attribute__((packed));
715
716/* Routines to add/remove DMA header from skb. */
717static inline int mwl8k_remove_dma_header(struct sk_buff *skb)
718{
719 struct mwl8k_dma_data *tr = (struct mwl8k_dma_data *)(skb->data);
720 void *dst, *src = &tr->wh;
721 __le16 fc = tr->wh.frame_control;
722 int hdrlen = ieee80211_hdrlen(fc);
723 u16 space = sizeof(struct mwl8k_dma_data) - hdrlen;
724
725 dst = (void *)tr + space;
726 if (dst != src) {
727 memmove(dst, src, hdrlen);
728 skb_pull(skb, space);
729 }
730
731 return 0;
732}
733
734static inline struct sk_buff *mwl8k_add_dma_header(struct sk_buff *skb)
735{
736 struct ieee80211_hdr *wh;
737 u32 hdrlen, pktlen;
738 struct mwl8k_dma_data *tr;
739
740 wh = (struct ieee80211_hdr *)skb->data;
741 hdrlen = ieee80211_hdrlen(wh->frame_control);
742 pktlen = skb->len;
743
744 /*
745 * Copy up/down the 802.11 header; the firmware requires
746 * we present a 2-byte payload length followed by a
747 * 4-address header (w/o QoS), followed (optionally) by
748 * any WEP/ExtIV header (but only filled in for CCMP).
749 */
750 if (hdrlen != sizeof(struct mwl8k_dma_data))
751 skb_push(skb, sizeof(struct mwl8k_dma_data) - hdrlen);
752
753 tr = (struct mwl8k_dma_data *)skb->data;
754 if (wh != &tr->wh)
755 memmove(&tr->wh, wh, hdrlen);
756
757 /* Clear addr4 */
Lennert Buytenhekd89173f2009-07-16 09:54:27 +0200758 memset(tr->wh.addr4, 0, ETH_ALEN);
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100759
760 /*
761 * Firmware length is the length of the fully formed "802.11
762 * payload". That is, everything except for the 802.11 header.
763 * This includes all crypto material including the MIC.
764 */
765 tr->fwlen = cpu_to_le16(pktlen - hdrlen);
766
767 return skb;
768}
769
770
771/*
772 * Packet reception.
773 */
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100774#define MWL8K_RX_CTRL_OWNED_BY_HOST 0x02
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100775
776struct mwl8k_rx_desc {
777 __le16 pkt_len;
778 __u8 link_quality;
779 __u8 noise_level;
780 __le32 pkt_phys_addr;
781 __le32 next_rx_desc_phys_addr;
782 __le16 qos_control;
783 __le16 rate_info;
784 __le32 pad0[4];
785 __u8 rssi;
786 __u8 channel;
787 __le16 pad1;
788 __u8 rx_ctrl;
789 __u8 rx_status;
790 __u8 pad2[2];
791} __attribute__((packed));
792
793#define MWL8K_RX_DESCS 256
794#define MWL8K_RX_MAXSZ 3800
795
796static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index)
797{
798 struct mwl8k_priv *priv = hw->priv;
799 struct mwl8k_rx_queue *rxq = priv->rxq + index;
800 int size;
801 int i;
802
803 rxq->rx_desc_count = 0;
804 rxq->rx_head = 0;
805 rxq->rx_tail = 0;
806
807 size = MWL8K_RX_DESCS * sizeof(struct mwl8k_rx_desc);
808
809 rxq->rx_desc_area =
810 pci_alloc_consistent(priv->pdev, size, &rxq->rx_desc_dma);
811 if (rxq->rx_desc_area == NULL) {
812 printk(KERN_ERR "%s: failed to alloc RX descriptors\n",
813 priv->name);
814 return -ENOMEM;
815 }
816 memset(rxq->rx_desc_area, 0, size);
817
818 rxq->rx_skb = kmalloc(MWL8K_RX_DESCS *
819 sizeof(*rxq->rx_skb), GFP_KERNEL);
820 if (rxq->rx_skb == NULL) {
821 printk(KERN_ERR "%s: failed to alloc RX skbuff list\n",
822 priv->name);
823 pci_free_consistent(priv->pdev, size,
824 rxq->rx_desc_area, rxq->rx_desc_dma);
825 return -ENOMEM;
826 }
827 memset(rxq->rx_skb, 0, MWL8K_RX_DESCS * sizeof(*rxq->rx_skb));
828
829 for (i = 0; i < MWL8K_RX_DESCS; i++) {
830 struct mwl8k_rx_desc *rx_desc;
831 int nexti;
832
833 rx_desc = rxq->rx_desc_area + i;
834 nexti = (i + 1) % MWL8K_RX_DESCS;
835
836 rx_desc->next_rx_desc_phys_addr =
837 cpu_to_le32(rxq->rx_desc_dma
838 + nexti * sizeof(*rx_desc));
Rami Rosenc491bf12009-04-21 16:22:01 +0300839 rx_desc->rx_ctrl = MWL8K_RX_CTRL_OWNED_BY_HOST;
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100840 }
841
842 return 0;
843}
844
845static int rxq_refill(struct ieee80211_hw *hw, int index, int limit)
846{
847 struct mwl8k_priv *priv = hw->priv;
848 struct mwl8k_rx_queue *rxq = priv->rxq + index;
849 int refilled;
850
851 refilled = 0;
852 while (rxq->rx_desc_count < MWL8K_RX_DESCS && limit--) {
853 struct sk_buff *skb;
854 int rx;
855
856 skb = dev_alloc_skb(MWL8K_RX_MAXSZ);
857 if (skb == NULL)
858 break;
859
860 rxq->rx_desc_count++;
861
862 rx = rxq->rx_tail;
863 rxq->rx_tail = (rx + 1) % MWL8K_RX_DESCS;
864
865 rxq->rx_desc_area[rx].pkt_phys_addr =
866 cpu_to_le32(pci_map_single(priv->pdev, skb->data,
867 MWL8K_RX_MAXSZ, DMA_FROM_DEVICE));
868
869 rxq->rx_desc_area[rx].pkt_len = cpu_to_le16(MWL8K_RX_MAXSZ);
870 rxq->rx_skb[rx] = skb;
871 wmb();
872 rxq->rx_desc_area[rx].rx_ctrl = 0;
873
874 refilled++;
875 }
876
877 return refilled;
878}
879
880/* Must be called only when the card's reception is completely halted */
881static void mwl8k_rxq_deinit(struct ieee80211_hw *hw, int index)
882{
883 struct mwl8k_priv *priv = hw->priv;
884 struct mwl8k_rx_queue *rxq = priv->rxq + index;
885 int i;
886
887 for (i = 0; i < MWL8K_RX_DESCS; i++) {
888 if (rxq->rx_skb[i] != NULL) {
889 unsigned long addr;
890
891 addr = le32_to_cpu(rxq->rx_desc_area[i].pkt_phys_addr);
892 pci_unmap_single(priv->pdev, addr, MWL8K_RX_MAXSZ,
893 PCI_DMA_FROMDEVICE);
894 kfree_skb(rxq->rx_skb[i]);
895 rxq->rx_skb[i] = NULL;
896 }
897 }
898
899 kfree(rxq->rx_skb);
900 rxq->rx_skb = NULL;
901
902 pci_free_consistent(priv->pdev,
903 MWL8K_RX_DESCS * sizeof(struct mwl8k_rx_desc),
904 rxq->rx_desc_area, rxq->rx_desc_dma);
905 rxq->rx_desc_area = NULL;
906}
907
908
909/*
910 * Scan a list of BSSIDs to process for finalize join.
911 * Allows for extension to process multiple BSSIDs.
912 */
913static inline int
914mwl8k_capture_bssid(struct mwl8k_priv *priv, struct ieee80211_hdr *wh)
915{
916 return priv->capture_beacon &&
917 ieee80211_is_beacon(wh->frame_control) &&
918 !compare_ether_addr(wh->addr3, priv->capture_bssid);
919}
920
921static inline void mwl8k_save_beacon(struct mwl8k_priv *priv,
922 struct sk_buff *skb)
923{
924 priv->capture_beacon = false;
Lennert Buytenhekd89173f2009-07-16 09:54:27 +0200925 memset(priv->capture_bssid, 0, ETH_ALEN);
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100926
927 /*
928 * Use GFP_ATOMIC as rxq_process is called from
929 * the primary interrupt handler, memory allocation call
930 * must not sleep.
931 */
932 priv->beacon_skb = skb_copy(skb, GFP_ATOMIC);
933 if (priv->beacon_skb != NULL)
934 queue_work(priv->config_wq,
935 &priv->finalize_join_worker);
936}
937
938static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
939{
940 struct mwl8k_priv *priv = hw->priv;
941 struct mwl8k_rx_queue *rxq = priv->rxq + index;
942 int processed;
943
944 processed = 0;
945 while (rxq->rx_desc_count && limit--) {
946 struct mwl8k_rx_desc *rx_desc;
947 struct sk_buff *skb;
948 struct ieee80211_rx_status status;
949 unsigned long addr;
950 struct ieee80211_hdr *wh;
951
952 rx_desc = rxq->rx_desc_area + rxq->rx_head;
953 if (!(rx_desc->rx_ctrl & MWL8K_RX_CTRL_OWNED_BY_HOST))
954 break;
955 rmb();
956
957 skb = rxq->rx_skb[rxq->rx_head];
Lennert Buytenhekd25f9f12009-08-03 21:58:26 +0200958 if (skb == NULL)
959 break;
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100960 rxq->rx_skb[rxq->rx_head] = NULL;
961
962 rxq->rx_head = (rxq->rx_head + 1) % MWL8K_RX_DESCS;
963 rxq->rx_desc_count--;
964
965 addr = le32_to_cpu(rx_desc->pkt_phys_addr);
966 pci_unmap_single(priv->pdev, addr,
967 MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE);
968
969 skb_put(skb, le16_to_cpu(rx_desc->pkt_len));
970 if (mwl8k_remove_dma_header(skb)) {
971 dev_kfree_skb(skb);
972 continue;
973 }
974
975 wh = (struct ieee80211_hdr *)skb->data;
976
977 /*
978 * Check for pending join operation. save a copy of
979 * the beacon and schedule a tasklet to send finalize
980 * join command to the firmware.
981 */
982 if (mwl8k_capture_bssid(priv, wh))
983 mwl8k_save_beacon(priv, skb);
984
985 memset(&status, 0, sizeof(status));
986 status.mactime = 0;
987 status.signal = -rx_desc->rssi;
988 status.noise = -rx_desc->noise_level;
989 status.qual = rx_desc->link_quality;
990 status.antenna = 1;
991 status.rate_idx = 1;
992 status.flag = 0;
993 status.band = IEEE80211_BAND_2GHZ;
994 status.freq = ieee80211_channel_to_frequency(rx_desc->channel);
Johannes Bergf1d58c22009-06-17 13:13:00 +0200995 memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
996 ieee80211_rx_irqsafe(hw, skb);
Lennert Buytenheka66098d2009-03-10 10:13:33 +0100997
998 processed++;
999 }
1000
1001 return processed;
1002}
1003
1004
1005/*
1006 * Packet transmission.
1007 */
1008
1009/* Transmit queue assignment. */
1010enum {
1011 MWL8K_WME_AC_BK = 0, /* background access */
1012 MWL8K_WME_AC_BE = 1, /* best effort access */
1013 MWL8K_WME_AC_VI = 2, /* video access */
1014 MWL8K_WME_AC_VO = 3, /* voice access */
1015};
1016
1017/* Transmit packet ACK policy */
1018#define MWL8K_TXD_ACK_POLICY_NORMAL 0
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001019#define MWL8K_TXD_ACK_POLICY_BLOCKACK 3
1020
1021#define GET_TXQ(_ac) (\
1022 ((_ac) == WME_AC_VO) ? MWL8K_WME_AC_VO : \
1023 ((_ac) == WME_AC_VI) ? MWL8K_WME_AC_VI : \
1024 ((_ac) == WME_AC_BK) ? MWL8K_WME_AC_BK : \
1025 MWL8K_WME_AC_BE)
1026
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001027#define MWL8K_TXD_STATUS_OK 0x00000001
1028#define MWL8K_TXD_STATUS_OK_RETRY 0x00000002
1029#define MWL8K_TXD_STATUS_OK_MORE_RETRY 0x00000004
1030#define MWL8K_TXD_STATUS_MULTICAST_TX 0x00000008
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001031#define MWL8K_TXD_STATUS_FW_OWNED 0x80000000
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001032
1033struct mwl8k_tx_desc {
1034 __le32 status;
1035 __u8 data_rate;
1036 __u8 tx_priority;
1037 __le16 qos_control;
1038 __le32 pkt_phys_addr;
1039 __le16 pkt_len;
Lennert Buytenhekd89173f2009-07-16 09:54:27 +02001040 __u8 dest_MAC_addr[ETH_ALEN];
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001041 __le32 next_tx_desc_phys_addr;
1042 __le32 reserved;
1043 __le16 rate_info;
1044 __u8 peer_id;
1045 __u8 tx_frag_cnt;
1046} __attribute__((packed));
1047
1048#define MWL8K_TX_DESCS 128
1049
1050static int mwl8k_txq_init(struct ieee80211_hw *hw, int index)
1051{
1052 struct mwl8k_priv *priv = hw->priv;
1053 struct mwl8k_tx_queue *txq = priv->txq + index;
1054 int size;
1055 int i;
1056
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02001057 memset(&txq->tx_stats, 0, sizeof(struct ieee80211_tx_queue_stats));
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001058 txq->tx_stats.limit = MWL8K_TX_DESCS;
1059 txq->tx_head = 0;
1060 txq->tx_tail = 0;
1061
1062 size = MWL8K_TX_DESCS * sizeof(struct mwl8k_tx_desc);
1063
1064 txq->tx_desc_area =
1065 pci_alloc_consistent(priv->pdev, size, &txq->tx_desc_dma);
1066 if (txq->tx_desc_area == NULL) {
1067 printk(KERN_ERR "%s: failed to alloc TX descriptors\n",
1068 priv->name);
1069 return -ENOMEM;
1070 }
1071 memset(txq->tx_desc_area, 0, size);
1072
1073 txq->tx_skb = kmalloc(MWL8K_TX_DESCS * sizeof(*txq->tx_skb),
1074 GFP_KERNEL);
1075 if (txq->tx_skb == NULL) {
1076 printk(KERN_ERR "%s: failed to alloc TX skbuff list\n",
1077 priv->name);
1078 pci_free_consistent(priv->pdev, size,
1079 txq->tx_desc_area, txq->tx_desc_dma);
1080 return -ENOMEM;
1081 }
1082 memset(txq->tx_skb, 0, MWL8K_TX_DESCS * sizeof(*txq->tx_skb));
1083
1084 for (i = 0; i < MWL8K_TX_DESCS; i++) {
1085 struct mwl8k_tx_desc *tx_desc;
1086 int nexti;
1087
1088 tx_desc = txq->tx_desc_area + i;
1089 nexti = (i + 1) % MWL8K_TX_DESCS;
1090
1091 tx_desc->status = 0;
1092 tx_desc->next_tx_desc_phys_addr =
1093 cpu_to_le32(txq->tx_desc_dma +
1094 nexti * sizeof(*tx_desc));
1095 }
1096
1097 return 0;
1098}
1099
1100static inline void mwl8k_tx_start(struct mwl8k_priv *priv)
1101{
1102 iowrite32(MWL8K_H2A_INT_PPA_READY,
1103 priv->regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS);
1104 iowrite32(MWL8K_H2A_INT_DUMMY,
1105 priv->regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS);
1106 ioread32(priv->regs + MWL8K_HIU_INT_CODE);
1107}
1108
1109static inline int mwl8k_txq_busy(struct mwl8k_priv *priv)
1110{
1111 return priv->pending_tx_pkts;
1112}
1113
1114struct mwl8k_txq_info {
1115 u32 fw_owned;
1116 u32 drv_owned;
1117 u32 unused;
1118 u32 len;
1119 u32 head;
1120 u32 tail;
1121};
1122
1123static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv,
1124 struct mwl8k_txq_info txinfo[],
1125 u32 num_queues)
1126{
1127 int count, desc, status;
1128 struct mwl8k_tx_queue *txq;
1129 struct mwl8k_tx_desc *tx_desc;
1130 int ndescs = 0;
1131
1132 memset(txinfo, 0, num_queues * sizeof(struct mwl8k_txq_info));
1133 spin_lock_bh(&priv->tx_lock);
1134 for (count = 0; count < num_queues; count++) {
1135 txq = priv->txq + count;
1136 txinfo[count].len = txq->tx_stats.len;
1137 txinfo[count].head = txq->tx_head;
1138 txinfo[count].tail = txq->tx_tail;
1139 for (desc = 0; desc < MWL8K_TX_DESCS; desc++) {
1140 tx_desc = txq->tx_desc_area + desc;
1141 status = le32_to_cpu(tx_desc->status);
1142
1143 if (status & MWL8K_TXD_STATUS_FW_OWNED)
1144 txinfo[count].fw_owned++;
1145 else
1146 txinfo[count].drv_owned++;
1147
1148 if (tx_desc->pkt_len == 0)
1149 txinfo[count].unused++;
1150 }
1151 }
1152 spin_unlock_bh(&priv->tx_lock);
1153
1154 return ndescs;
1155}
1156
1157static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms)
1158{
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001159 struct mwl8k_priv *priv = hw->priv;
1160 DECLARE_COMPLETION_ONSTACK(cmd_wait);
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02001161 u32 count;
1162 unsigned long timeout;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001163
1164 might_sleep();
1165
1166 if (priv->tx_wait != NULL)
1167 printk(KERN_ERR "WARNING Previous TXWaitEmpty instance\n");
1168
1169 spin_lock_bh(&priv->tx_lock);
1170 count = mwl8k_txq_busy(priv);
1171 if (count) {
1172 priv->tx_wait = &cmd_wait;
Lennert Buytenhekc46563b2009-07-16 12:14:58 +02001173 if (priv->radio_on)
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001174 mwl8k_tx_start(priv);
1175 }
1176 spin_unlock_bh(&priv->tx_lock);
1177
1178 if (count) {
1179 struct mwl8k_txq_info txinfo[4];
1180 int index;
1181 int newcount;
1182
1183 timeout = wait_for_completion_timeout(&cmd_wait,
1184 msecs_to_jiffies(delay_ms));
1185 if (timeout)
1186 return 0;
1187
1188 spin_lock_bh(&priv->tx_lock);
1189 priv->tx_wait = NULL;
1190 newcount = mwl8k_txq_busy(priv);
1191 spin_unlock_bh(&priv->tx_lock);
1192
1193 printk(KERN_ERR "%s(%u) TIMEDOUT:%ums Pend:%u-->%u\n",
1194 __func__, __LINE__, delay_ms, count, newcount);
1195
1196 mwl8k_scan_tx_ring(priv, txinfo, 4);
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02001197 for (index = 0; index < 4; index++)
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001198 printk(KERN_ERR
1199 "TXQ:%u L:%u H:%u T:%u FW:%u DRV:%u U:%u\n",
1200 index,
1201 txinfo[index].len,
1202 txinfo[index].head,
1203 txinfo[index].tail,
1204 txinfo[index].fw_owned,
1205 txinfo[index].drv_owned,
1206 txinfo[index].unused);
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02001207
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001208 return -ETIMEDOUT;
1209 }
1210
1211 return 0;
1212}
1213
Lennert Buytenhekc23b5a62009-07-16 13:49:55 +02001214#define MWL8K_TXD_SUCCESS(status) \
1215 ((status) & (MWL8K_TXD_STATUS_OK | \
1216 MWL8K_TXD_STATUS_OK_RETRY | \
1217 MWL8K_TXD_STATUS_OK_MORE_RETRY))
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001218
1219static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force)
1220{
1221 struct mwl8k_priv *priv = hw->priv;
1222 struct mwl8k_tx_queue *txq = priv->txq + index;
1223 int wake = 0;
1224
1225 while (txq->tx_stats.len > 0) {
1226 int tx;
1227 int rc;
1228 struct mwl8k_tx_desc *tx_desc;
1229 unsigned long addr;
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02001230 int size;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001231 struct sk_buff *skb;
1232 struct ieee80211_tx_info *info;
1233 u32 status;
1234
1235 rc = 0;
1236 tx = txq->tx_head;
1237 tx_desc = txq->tx_desc_area + tx;
1238
1239 status = le32_to_cpu(tx_desc->status);
1240
1241 if (status & MWL8K_TXD_STATUS_FW_OWNED) {
1242 if (!force)
1243 break;
1244 tx_desc->status &=
1245 ~cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED);
1246 }
1247
1248 txq->tx_head = (tx + 1) % MWL8K_TX_DESCS;
1249 BUG_ON(txq->tx_stats.len == 0);
1250 txq->tx_stats.len--;
1251 priv->pending_tx_pkts--;
1252
1253 addr = le32_to_cpu(tx_desc->pkt_phys_addr);
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02001254 size = le16_to_cpu(tx_desc->pkt_len);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001255 skb = txq->tx_skb[tx].skb;
1256 txq->tx_skb[tx].skb = NULL;
1257
1258 BUG_ON(skb == NULL);
1259 pci_unmap_single(priv->pdev, addr, size, PCI_DMA_TODEVICE);
1260
1261 rc = mwl8k_remove_dma_header(skb);
1262
1263 /* Mark descriptor as unused */
1264 tx_desc->pkt_phys_addr = 0;
1265 tx_desc->pkt_len = 0;
1266
1267 if (txq->tx_skb[tx].clone) {
1268 /* Replace with original skb
1269 * before returning to stack
1270 * as buffer has been cloned
1271 */
1272 dev_kfree_skb(skb);
1273 skb = txq->tx_skb[tx].clone;
1274 txq->tx_skb[tx].clone = NULL;
1275 }
1276
1277 if (rc) {
1278 /* Something has gone wrong here.
1279 * Failed to remove DMA header.
1280 * Print error message and drop packet.
1281 */
1282 printk(KERN_ERR "%s: Error removing DMA header from "
1283 "tx skb 0x%p.\n", priv->name, skb);
1284
1285 dev_kfree_skb(skb);
1286 continue;
1287 }
1288
1289 info = IEEE80211_SKB_CB(skb);
1290 ieee80211_tx_info_clear_status(info);
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02001291 if (MWL8K_TXD_SUCCESS(status))
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001292 info->flags |= IEEE80211_TX_STAT_ACK;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001293
1294 ieee80211_tx_status_irqsafe(hw, skb);
1295
Lennert Buytenhekc46563b2009-07-16 12:14:58 +02001296 wake = !priv->inconfig && priv->radio_on;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001297 }
1298
1299 if (wake)
1300 ieee80211_wake_queue(hw, index);
1301}
1302
1303/* must be called only when the card's transmit is completely halted */
1304static void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index)
1305{
1306 struct mwl8k_priv *priv = hw->priv;
1307 struct mwl8k_tx_queue *txq = priv->txq + index;
1308
1309 mwl8k_txq_reclaim(hw, index, 1);
1310
1311 kfree(txq->tx_skb);
1312 txq->tx_skb = NULL;
1313
1314 pci_free_consistent(priv->pdev,
1315 MWL8K_TX_DESCS * sizeof(struct mwl8k_tx_desc),
1316 txq->tx_desc_area, txq->tx_desc_dma);
1317 txq->tx_desc_area = NULL;
1318}
1319
1320static int
1321mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
1322{
1323 struct mwl8k_priv *priv = hw->priv;
1324 struct ieee80211_tx_info *tx_info;
1325 struct ieee80211_hdr *wh;
1326 struct mwl8k_tx_queue *txq;
1327 struct mwl8k_tx_desc *tx;
1328 struct mwl8k_dma_data *tr;
1329 struct mwl8k_vif *mwl8k_vif;
1330 struct sk_buff *org_skb = skb;
1331 dma_addr_t dma;
1332 u16 qos = 0;
1333 bool qosframe = false, ampduframe = false;
1334 bool mcframe = false, eapolframe = false;
1335 bool amsduframe = false;
1336 __le16 fc;
1337
1338 txq = priv->txq + index;
1339 tx = txq->tx_desc_area + txq->tx_tail;
1340
1341 BUG_ON(txq->tx_skb[txq->tx_tail].skb != NULL);
1342
1343 /*
1344 * Append HW DMA header to start of packet. Drop packet if
1345 * there is not enough space or a failure to unshare/unclone
1346 * the skb.
1347 */
1348 skb = mwl8k_add_dma_header(skb);
1349
1350 if (skb == NULL) {
1351 printk(KERN_DEBUG "%s: failed to prepend HW DMA "
1352 "header, dropping TX frame.\n", priv->name);
1353 dev_kfree_skb(org_skb);
1354 return NETDEV_TX_OK;
1355 }
1356
1357 tx_info = IEEE80211_SKB_CB(skb);
1358 mwl8k_vif = MWL8K_VIF(tx_info->control.vif);
1359 tr = (struct mwl8k_dma_data *)skb->data;
1360 wh = &tr->wh;
1361 fc = wh->frame_control;
1362 qosframe = ieee80211_is_data_qos(fc);
1363 mcframe = is_multicast_ether_addr(wh->addr1);
1364 ampduframe = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
1365
1366 if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
1367 u16 seqno = mwl8k_vif->seqno;
1368 wh->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
1369 wh->seq_ctrl |= cpu_to_le16(seqno << 4);
1370 mwl8k_vif->seqno = seqno++ % 4096;
1371 }
1372
1373 if (qosframe)
1374 qos = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(wh)));
1375
1376 dma = pci_map_single(priv->pdev, skb->data,
1377 skb->len, PCI_DMA_TODEVICE);
1378
1379 if (pci_dma_mapping_error(priv->pdev, dma)) {
1380 printk(KERN_DEBUG "%s: failed to dma map skb, "
1381 "dropping TX frame.\n", priv->name);
1382
1383 if (org_skb != NULL)
1384 dev_kfree_skb(org_skb);
1385 if (skb != NULL)
1386 dev_kfree_skb(skb);
1387 return NETDEV_TX_OK;
1388 }
1389
1390 /* Set desc header, cpu bit order. */
1391 tx->status = 0;
1392 tx->data_rate = 0;
1393 tx->tx_priority = index;
1394 tx->qos_control = 0;
1395 tx->rate_info = 0;
1396 tx->peer_id = mwl8k_vif->peer_id;
1397
1398 amsduframe = !!(qos & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT);
1399
1400 /* Setup firmware control bit fields for each frame type. */
1401 if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) {
1402 tx->data_rate = 0;
1403 qos = mwl8k_qos_setbit_eosp(qos);
1404 /* Set Queue size to unspecified */
1405 qos = mwl8k_qos_setbit_qlen(qos, 0xff);
1406 } else if (ieee80211_is_data(fc)) {
1407 tx->data_rate = 1;
1408 if (mcframe)
1409 tx->status |= MWL8K_TXD_STATUS_MULTICAST_TX;
1410
1411 /*
1412 * Tell firmware to not send EAPOL pkts in an
1413 * aggregate. Verify against mac80211 tx path. If
1414 * stack turns off AMPDU for an EAPOL frame this
1415 * check will be removed.
1416 */
1417 if (eapolframe) {
1418 qos = mwl8k_qos_setbit_ack(qos,
1419 MWL8K_TXD_ACK_POLICY_NORMAL);
1420 } else {
1421 /* Send pkt in an aggregate if AMPDU frame. */
1422 if (ampduframe)
1423 qos = mwl8k_qos_setbit_ack(qos,
1424 MWL8K_TXD_ACK_POLICY_BLOCKACK);
1425 else
1426 qos = mwl8k_qos_setbit_ack(qos,
1427 MWL8K_TXD_ACK_POLICY_NORMAL);
1428
1429 if (amsduframe)
1430 qos = mwl8k_qos_setbit_amsdu(qos);
1431 }
1432 }
1433
1434 /* Convert to little endian */
1435 tx->qos_control = cpu_to_le16(qos);
1436 tx->status = cpu_to_le32(tx->status);
1437 tx->pkt_phys_addr = cpu_to_le32(dma);
1438 tx->pkt_len = cpu_to_le16(skb->len);
1439
1440 txq->tx_skb[txq->tx_tail].skb = skb;
1441 txq->tx_skb[txq->tx_tail].clone =
1442 skb == org_skb ? NULL : org_skb;
1443
1444 spin_lock_bh(&priv->tx_lock);
1445
1446 tx->status = cpu_to_le32(MWL8K_TXD_STATUS_OK |
1447 MWL8K_TXD_STATUS_FW_OWNED);
1448 wmb();
1449 txq->tx_stats.len++;
1450 priv->pending_tx_pkts++;
1451 txq->tx_stats.count++;
1452 txq->tx_tail++;
1453
1454 if (txq->tx_tail == MWL8K_TX_DESCS)
1455 txq->tx_tail = 0;
1456 if (txq->tx_head == txq->tx_tail)
1457 ieee80211_stop_queue(hw, index);
1458
1459 if (priv->inconfig) {
1460 /*
1461 * Silently queue packet when we are in the middle of
1462 * a config cycle. Notify firmware only if we are
1463 * waiting for TXQs to empty. If a packet is sent
1464 * before .config() is complete, perhaps it is better
1465 * to drop the packet, as the channel is being changed
1466 * and the packet will end up on the wrong channel.
1467 */
1468 printk(KERN_ERR "%s(): WARNING TX activity while "
1469 "in config\n", __func__);
1470
1471 if (priv->tx_wait != NULL)
1472 mwl8k_tx_start(priv);
1473 } else
1474 mwl8k_tx_start(priv);
1475
1476 spin_unlock_bh(&priv->tx_lock);
1477
1478 return NETDEV_TX_OK;
1479}
1480
1481
1482/*
1483 * Command processing.
1484 */
1485
1486/* Timeout firmware commands after 2000ms */
1487#define MWL8K_CMD_TIMEOUT_MS 2000
1488
1489static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd)
1490{
1491 DECLARE_COMPLETION_ONSTACK(cmd_wait);
1492 struct mwl8k_priv *priv = hw->priv;
1493 void __iomem *regs = priv->regs;
1494 dma_addr_t dma_addr;
1495 unsigned int dma_size;
1496 int rc;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001497 unsigned long timeout = 0;
1498 u8 buf[32];
1499
1500 cmd->result = 0xFFFF;
1501 dma_size = le16_to_cpu(cmd->length);
1502 dma_addr = pci_map_single(priv->pdev, cmd, dma_size,
1503 PCI_DMA_BIDIRECTIONAL);
1504 if (pci_dma_mapping_error(priv->pdev, dma_addr))
1505 return -ENOMEM;
1506
1507 if (priv->hostcmd_wait != NULL)
1508 printk(KERN_ERR "WARNING host command in progress\n");
1509
1510 spin_lock_irq(&priv->fw_lock);
1511 priv->hostcmd_wait = &cmd_wait;
1512 iowrite32(dma_addr, regs + MWL8K_HIU_GEN_PTR);
1513 iowrite32(MWL8K_H2A_INT_DOORBELL,
1514 regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS);
1515 iowrite32(MWL8K_H2A_INT_DUMMY,
1516 regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS);
1517 spin_unlock_irq(&priv->fw_lock);
1518
1519 timeout = wait_for_completion_timeout(&cmd_wait,
1520 msecs_to_jiffies(MWL8K_CMD_TIMEOUT_MS));
1521
Lennert Buytenhek37055bd2009-08-03 21:58:47 +02001522 pci_unmap_single(priv->pdev, dma_addr, dma_size,
1523 PCI_DMA_BIDIRECTIONAL);
1524
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001525 if (!timeout) {
1526 spin_lock_irq(&priv->fw_lock);
1527 priv->hostcmd_wait = NULL;
1528 spin_unlock_irq(&priv->fw_lock);
1529 printk(KERN_ERR "%s: Command %s timeout after %u ms\n",
1530 priv->name,
1531 mwl8k_cmd_name(cmd->code, buf, sizeof(buf)),
1532 MWL8K_CMD_TIMEOUT_MS);
1533 rc = -ETIMEDOUT;
1534 } else {
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02001535 rc = cmd->result ? -EINVAL : 0;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001536 if (rc)
1537 printk(KERN_ERR "%s: Command %s error 0x%x\n",
1538 priv->name,
1539 mwl8k_cmd_name(cmd->code, buf, sizeof(buf)),
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02001540 cmd->result);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001541 }
1542
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001543 return rc;
1544}
1545
1546/*
1547 * GET_HW_SPEC.
1548 */
1549struct mwl8k_cmd_get_hw_spec {
1550 struct mwl8k_cmd_pkt header;
1551 __u8 hw_rev;
1552 __u8 host_interface;
1553 __le16 num_mcaddrs;
Lennert Buytenhekd89173f2009-07-16 09:54:27 +02001554 __u8 perm_addr[ETH_ALEN];
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001555 __le16 region_code;
1556 __le32 fw_rev;
1557 __le32 ps_cookie;
1558 __le32 caps;
1559 __u8 mcs_bitmap[16];
1560 __le32 rx_queue_ptr;
1561 __le32 num_tx_queues;
1562 __le32 tx_queue_ptrs[MWL8K_TX_QUEUES];
1563 __le32 caps2;
1564 __le32 num_tx_desc_per_queue;
1565 __le32 total_rx_desc;
1566} __attribute__((packed));
1567
1568static int mwl8k_cmd_get_hw_spec(struct ieee80211_hw *hw)
1569{
1570 struct mwl8k_priv *priv = hw->priv;
1571 struct mwl8k_cmd_get_hw_spec *cmd;
1572 int rc;
1573 int i;
1574
1575 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1576 if (cmd == NULL)
1577 return -ENOMEM;
1578
1579 cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_HW_SPEC);
1580 cmd->header.length = cpu_to_le16(sizeof(*cmd));
1581
1582 memset(cmd->perm_addr, 0xff, sizeof(cmd->perm_addr));
1583 cmd->ps_cookie = cpu_to_le32(priv->cookie_dma);
1584 cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rx_desc_dma);
Lennert Buytenhek4ff64322009-08-03 21:58:39 +02001585 cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001586 for (i = 0; i < MWL8K_TX_QUEUES; i++)
1587 cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].tx_desc_dma);
Lennert Buytenhek4ff64322009-08-03 21:58:39 +02001588 cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS);
1589 cmd->total_rx_desc = cpu_to_le32(MWL8K_RX_DESCS);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001590
1591 rc = mwl8k_post_cmd(hw, &cmd->header);
1592
1593 if (!rc) {
1594 SET_IEEE80211_PERM_ADDR(hw, cmd->perm_addr);
1595 priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs);
Lennert Buytenhek4ff64322009-08-03 21:58:39 +02001596 priv->fw_rev = le32_to_cpu(cmd->fw_rev);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001597 priv->hw_rev = cmd->hw_rev;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001598 }
1599
1600 kfree(cmd);
1601 return rc;
1602}
1603
1604/*
1605 * CMD_MAC_MULTICAST_ADR.
1606 */
1607struct mwl8k_cmd_mac_multicast_adr {
1608 struct mwl8k_cmd_pkt header;
1609 __le16 action;
1610 __le16 numaddr;
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02001611 __u8 addr[0][ETH_ALEN];
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001612};
1613
1614#define MWL8K_ENABLE_RX_MULTICAST 0x000F
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02001615
Lennert Buytenheke81cd2d2009-08-18 03:55:42 +02001616static struct mwl8k_cmd_pkt *
1617__mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw,
1618 int mc_count, struct dev_addr_list *mclist)
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001619{
Lennert Buytenheke81cd2d2009-08-18 03:55:42 +02001620 struct mwl8k_priv *priv = hw->priv;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001621 struct mwl8k_cmd_mac_multicast_adr *cmd;
Lennert Buytenheke81cd2d2009-08-18 03:55:42 +02001622 int size;
1623 int i;
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02001624
Lennert Buytenheke81cd2d2009-08-18 03:55:42 +02001625 if (mc_count > priv->num_mcaddrs)
1626 mc_count = priv->num_mcaddrs;
1627
1628 size = sizeof(*cmd) + mc_count * ETH_ALEN;
1629
1630 cmd = kzalloc(size, GFP_ATOMIC);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001631 if (cmd == NULL)
Lennert Buytenheke81cd2d2009-08-18 03:55:42 +02001632 return NULL;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001633
1634 cmd->header.code = cpu_to_le16(MWL8K_CMD_MAC_MULTICAST_ADR);
1635 cmd->header.length = cpu_to_le16(size);
1636 cmd->action = cpu_to_le16(MWL8K_ENABLE_RX_MULTICAST);
1637 cmd->numaddr = cpu_to_le16(mc_count);
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02001638
Lennert Buytenheke81cd2d2009-08-18 03:55:42 +02001639 for (i = 0; i < mc_count && mclist; i++) {
Lennert Buytenhekd89173f2009-07-16 09:54:27 +02001640 if (mclist->da_addrlen != ETH_ALEN) {
Lennert Buytenheke81cd2d2009-08-18 03:55:42 +02001641 kfree(cmd);
1642 return NULL;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001643 }
Lennert Buytenheke81cd2d2009-08-18 03:55:42 +02001644 memcpy(cmd->addr[i], mclist->da_addr, ETH_ALEN);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001645 mclist = mclist->next;
1646 }
1647
Lennert Buytenheke81cd2d2009-08-18 03:55:42 +02001648 return &cmd->header;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001649}
1650
1651/*
1652 * CMD_802_11_GET_STAT.
1653 */
1654struct mwl8k_cmd_802_11_get_stat {
1655 struct mwl8k_cmd_pkt header;
1656 __le16 action;
1657 __le32 stats[64];
1658} __attribute__((packed));
1659
1660#define MWL8K_STAT_ACK_FAILURE 9
1661#define MWL8K_STAT_RTS_FAILURE 12
1662#define MWL8K_STAT_FCS_ERROR 24
1663#define MWL8K_STAT_RTS_SUCCESS 11
1664
1665static int mwl8k_cmd_802_11_get_stat(struct ieee80211_hw *hw,
1666 struct ieee80211_low_level_stats *stats)
1667{
1668 struct mwl8k_cmd_802_11_get_stat *cmd;
1669 int rc;
1670
1671 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1672 if (cmd == NULL)
1673 return -ENOMEM;
1674
1675 cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_STAT);
1676 cmd->header.length = cpu_to_le16(sizeof(*cmd));
1677 cmd->action = cpu_to_le16(MWL8K_CMD_GET);
1678
1679 rc = mwl8k_post_cmd(hw, &cmd->header);
1680 if (!rc) {
1681 stats->dot11ACKFailureCount =
1682 le32_to_cpu(cmd->stats[MWL8K_STAT_ACK_FAILURE]);
1683 stats->dot11RTSFailureCount =
1684 le32_to_cpu(cmd->stats[MWL8K_STAT_RTS_FAILURE]);
1685 stats->dot11FCSErrorCount =
1686 le32_to_cpu(cmd->stats[MWL8K_STAT_FCS_ERROR]);
1687 stats->dot11RTSSuccessCount =
1688 le32_to_cpu(cmd->stats[MWL8K_STAT_RTS_SUCCESS]);
1689 }
1690 kfree(cmd);
1691
1692 return rc;
1693}
1694
1695/*
1696 * CMD_802_11_RADIO_CONTROL.
1697 */
1698struct mwl8k_cmd_802_11_radio_control {
1699 struct mwl8k_cmd_pkt header;
1700 __le16 action;
1701 __le16 control;
1702 __le16 radio_on;
1703} __attribute__((packed));
1704
Lennert Buytenhekc46563b2009-07-16 12:14:58 +02001705static int
1706mwl8k_cmd_802_11_radio_control(struct ieee80211_hw *hw, bool enable, bool force)
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001707{
1708 struct mwl8k_priv *priv = hw->priv;
1709 struct mwl8k_cmd_802_11_radio_control *cmd;
1710 int rc;
1711
Lennert Buytenhekc46563b2009-07-16 12:14:58 +02001712 if (enable == priv->radio_on && !force)
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001713 return 0;
1714
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001715 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1716 if (cmd == NULL)
1717 return -ENOMEM;
1718
1719 cmd->header.code = cpu_to_le16(MWL8K_CMD_RADIO_CONTROL);
1720 cmd->header.length = cpu_to_le16(sizeof(*cmd));
1721 cmd->action = cpu_to_le16(MWL8K_CMD_SET);
Lennert Buytenhek68ce3882009-07-16 12:26:57 +02001722 cmd->control = cpu_to_le16(priv->radio_short_preamble ? 3 : 1);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001723 cmd->radio_on = cpu_to_le16(enable ? 0x0001 : 0x0000);
1724
1725 rc = mwl8k_post_cmd(hw, &cmd->header);
1726 kfree(cmd);
1727
1728 if (!rc)
Lennert Buytenhekc46563b2009-07-16 12:14:58 +02001729 priv->radio_on = enable;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001730
1731 return rc;
1732}
1733
Lennert Buytenhekc46563b2009-07-16 12:14:58 +02001734static int mwl8k_cmd_802_11_radio_disable(struct ieee80211_hw *hw)
1735{
1736 return mwl8k_cmd_802_11_radio_control(hw, 0, 0);
1737}
1738
1739static int mwl8k_cmd_802_11_radio_enable(struct ieee80211_hw *hw)
1740{
1741 return mwl8k_cmd_802_11_radio_control(hw, 1, 0);
1742}
1743
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001744static int
1745mwl8k_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble)
1746{
1747 struct mwl8k_priv *priv;
1748
1749 if (hw == NULL || hw->priv == NULL)
1750 return -EINVAL;
1751 priv = hw->priv;
1752
Lennert Buytenhek68ce3882009-07-16 12:26:57 +02001753 priv->radio_short_preamble = short_preamble;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001754
Lennert Buytenhekc46563b2009-07-16 12:14:58 +02001755 return mwl8k_cmd_802_11_radio_control(hw, 1, 1);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001756}
1757
1758/*
1759 * CMD_802_11_RF_TX_POWER.
1760 */
1761#define MWL8K_TX_POWER_LEVEL_TOTAL 8
1762
1763struct mwl8k_cmd_802_11_rf_tx_power {
1764 struct mwl8k_cmd_pkt header;
1765 __le16 action;
1766 __le16 support_level;
1767 __le16 current_level;
1768 __le16 reserved;
1769 __le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL];
1770} __attribute__((packed));
1771
1772static int mwl8k_cmd_802_11_rf_tx_power(struct ieee80211_hw *hw, int dBm)
1773{
1774 struct mwl8k_cmd_802_11_rf_tx_power *cmd;
1775 int rc;
1776
1777 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1778 if (cmd == NULL)
1779 return -ENOMEM;
1780
1781 cmd->header.code = cpu_to_le16(MWL8K_CMD_RF_TX_POWER);
1782 cmd->header.length = cpu_to_le16(sizeof(*cmd));
1783 cmd->action = cpu_to_le16(MWL8K_CMD_SET);
1784 cmd->support_level = cpu_to_le16(dBm);
1785
1786 rc = mwl8k_post_cmd(hw, &cmd->header);
1787 kfree(cmd);
1788
1789 return rc;
1790}
1791
1792/*
1793 * CMD_SET_PRE_SCAN.
1794 */
1795struct mwl8k_cmd_set_pre_scan {
1796 struct mwl8k_cmd_pkt header;
1797} __attribute__((packed));
1798
1799static int mwl8k_cmd_set_pre_scan(struct ieee80211_hw *hw)
1800{
1801 struct mwl8k_cmd_set_pre_scan *cmd;
1802 int rc;
1803
1804 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1805 if (cmd == NULL)
1806 return -ENOMEM;
1807
1808 cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_PRE_SCAN);
1809 cmd->header.length = cpu_to_le16(sizeof(*cmd));
1810
1811 rc = mwl8k_post_cmd(hw, &cmd->header);
1812 kfree(cmd);
1813
1814 return rc;
1815}
1816
1817/*
1818 * CMD_SET_POST_SCAN.
1819 */
1820struct mwl8k_cmd_set_post_scan {
1821 struct mwl8k_cmd_pkt header;
1822 __le32 isibss;
Lennert Buytenhekd89173f2009-07-16 09:54:27 +02001823 __u8 bssid[ETH_ALEN];
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001824} __attribute__((packed));
1825
1826static int
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02001827mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, __u8 *mac)
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001828{
1829 struct mwl8k_cmd_set_post_scan *cmd;
1830 int rc;
1831
1832 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1833 if (cmd == NULL)
1834 return -ENOMEM;
1835
1836 cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_POST_SCAN);
1837 cmd->header.length = cpu_to_le16(sizeof(*cmd));
1838 cmd->isibss = 0;
Lennert Buytenhekd89173f2009-07-16 09:54:27 +02001839 memcpy(cmd->bssid, mac, ETH_ALEN);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001840
1841 rc = mwl8k_post_cmd(hw, &cmd->header);
1842 kfree(cmd);
1843
1844 return rc;
1845}
1846
1847/*
1848 * CMD_SET_RF_CHANNEL.
1849 */
1850struct mwl8k_cmd_set_rf_channel {
1851 struct mwl8k_cmd_pkt header;
1852 __le16 action;
1853 __u8 current_channel;
1854 __le32 channel_flags;
1855} __attribute__((packed));
1856
1857static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw,
1858 struct ieee80211_channel *channel)
1859{
1860 struct mwl8k_cmd_set_rf_channel *cmd;
1861 int rc;
1862
1863 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1864 if (cmd == NULL)
1865 return -ENOMEM;
1866
1867 cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RF_CHANNEL);
1868 cmd->header.length = cpu_to_le16(sizeof(*cmd));
1869 cmd->action = cpu_to_le16(MWL8K_CMD_SET);
1870 cmd->current_channel = channel->hw_value;
1871 if (channel->band == IEEE80211_BAND_2GHZ)
1872 cmd->channel_flags = cpu_to_le32(0x00000081);
1873 else
1874 cmd->channel_flags = cpu_to_le32(0x00000000);
1875
1876 rc = mwl8k_post_cmd(hw, &cmd->header);
1877 kfree(cmd);
1878
1879 return rc;
1880}
1881
1882/*
1883 * CMD_SET_SLOT.
1884 */
1885struct mwl8k_cmd_set_slot {
1886 struct mwl8k_cmd_pkt header;
1887 __le16 action;
1888 __u8 short_slot;
1889} __attribute__((packed));
1890
Lennert Buytenhek5539bb52009-07-16 16:06:53 +02001891static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, bool short_slot_time)
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001892{
1893 struct mwl8k_cmd_set_slot *cmd;
1894 int rc;
1895
1896 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1897 if (cmd == NULL)
1898 return -ENOMEM;
1899
1900 cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_SLOT);
1901 cmd->header.length = cpu_to_le16(sizeof(*cmd));
1902 cmd->action = cpu_to_le16(MWL8K_CMD_SET);
Lennert Buytenhek5539bb52009-07-16 16:06:53 +02001903 cmd->short_slot = short_slot_time;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001904
1905 rc = mwl8k_post_cmd(hw, &cmd->header);
1906 kfree(cmd);
1907
1908 return rc;
1909}
1910
1911/*
1912 * CMD_MIMO_CONFIG.
1913 */
1914struct mwl8k_cmd_mimo_config {
1915 struct mwl8k_cmd_pkt header;
1916 __le32 action;
1917 __u8 rx_antenna_map;
1918 __u8 tx_antenna_map;
1919} __attribute__((packed));
1920
1921static int mwl8k_cmd_mimo_config(struct ieee80211_hw *hw, __u8 rx, __u8 tx)
1922{
1923 struct mwl8k_cmd_mimo_config *cmd;
1924 int rc;
1925
1926 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1927 if (cmd == NULL)
1928 return -ENOMEM;
1929
1930 cmd->header.code = cpu_to_le16(MWL8K_CMD_MIMO_CONFIG);
1931 cmd->header.length = cpu_to_le16(sizeof(*cmd));
1932 cmd->action = cpu_to_le32((u32)MWL8K_CMD_SET);
1933 cmd->rx_antenna_map = rx;
1934 cmd->tx_antenna_map = tx;
1935
1936 rc = mwl8k_post_cmd(hw, &cmd->header);
1937 kfree(cmd);
1938
1939 return rc;
1940}
1941
1942/*
1943 * CMD_ENABLE_SNIFFER.
1944 */
1945struct mwl8k_cmd_enable_sniffer {
1946 struct mwl8k_cmd_pkt header;
1947 __le32 action;
1948} __attribute__((packed));
1949
1950static int mwl8k_enable_sniffer(struct ieee80211_hw *hw, bool enable)
1951{
1952 struct mwl8k_cmd_enable_sniffer *cmd;
1953 int rc;
1954
1955 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1956 if (cmd == NULL)
1957 return -ENOMEM;
1958
1959 cmd->header.code = cpu_to_le16(MWL8K_CMD_ENABLE_SNIFFER);
1960 cmd->header.length = cpu_to_le16(sizeof(*cmd));
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02001961 cmd->action = cpu_to_le32(!!enable);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001962
1963 rc = mwl8k_post_cmd(hw, &cmd->header);
1964 kfree(cmd);
1965
1966 return rc;
1967}
1968
1969/*
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02001970 * CMD_SET_RATEADAPT_MODE.
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001971 */
1972struct mwl8k_cmd_set_rate_adapt_mode {
1973 struct mwl8k_cmd_pkt header;
1974 __le16 action;
1975 __le16 mode;
1976} __attribute__((packed));
1977
1978static int mwl8k_cmd_setrateadaptmode(struct ieee80211_hw *hw, __u16 mode)
1979{
1980 struct mwl8k_cmd_set_rate_adapt_mode *cmd;
1981 int rc;
1982
1983 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1984 if (cmd == NULL)
1985 return -ENOMEM;
1986
1987 cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATEADAPT_MODE);
1988 cmd->header.length = cpu_to_le16(sizeof(*cmd));
1989 cmd->action = cpu_to_le16(MWL8K_CMD_SET);
1990 cmd->mode = cpu_to_le16(mode);
1991
1992 rc = mwl8k_post_cmd(hw, &cmd->header);
1993 kfree(cmd);
1994
1995 return rc;
1996}
1997
1998/*
1999 * CMD_SET_WMM_MODE.
2000 */
2001struct mwl8k_cmd_set_wmm {
2002 struct mwl8k_cmd_pkt header;
2003 __le16 action;
2004} __attribute__((packed));
2005
2006static int mwl8k_set_wmm(struct ieee80211_hw *hw, bool enable)
2007{
2008 struct mwl8k_priv *priv = hw->priv;
2009 struct mwl8k_cmd_set_wmm *cmd;
2010 int rc;
2011
2012 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
2013 if (cmd == NULL)
2014 return -ENOMEM;
2015
2016 cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_WMM_MODE);
2017 cmd->header.length = cpu_to_le16(sizeof(*cmd));
Lennert Buytenhek0439b1f2009-07-16 12:34:02 +02002018 cmd->action = cpu_to_le16(!!enable);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002019
2020 rc = mwl8k_post_cmd(hw, &cmd->header);
2021 kfree(cmd);
2022
2023 if (!rc)
Lennert Buytenhek0439b1f2009-07-16 12:34:02 +02002024 priv->wmm_enabled = enable;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002025
2026 return rc;
2027}
2028
2029/*
2030 * CMD_SET_RTS_THRESHOLD.
2031 */
2032struct mwl8k_cmd_rts_threshold {
2033 struct mwl8k_cmd_pkt header;
2034 __le16 action;
2035 __le16 threshold;
2036} __attribute__((packed));
2037
2038static int mwl8k_rts_threshold(struct ieee80211_hw *hw,
2039 u16 action, u16 *threshold)
2040{
2041 struct mwl8k_cmd_rts_threshold *cmd;
2042 int rc;
2043
2044 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
2045 if (cmd == NULL)
2046 return -ENOMEM;
2047
2048 cmd->header.code = cpu_to_le16(MWL8K_CMD_RTS_THRESHOLD);
2049 cmd->header.length = cpu_to_le16(sizeof(*cmd));
2050 cmd->action = cpu_to_le16(action);
2051 cmd->threshold = cpu_to_le16(*threshold);
2052
2053 rc = mwl8k_post_cmd(hw, &cmd->header);
2054 kfree(cmd);
2055
2056 return rc;
2057}
2058
2059/*
2060 * CMD_SET_EDCA_PARAMS.
2061 */
2062struct mwl8k_cmd_set_edca_params {
2063 struct mwl8k_cmd_pkt header;
2064
2065 /* See MWL8K_SET_EDCA_XXX below */
2066 __le16 action;
2067
2068 /* TX opportunity in units of 32 us */
2069 __le16 txop;
2070
2071 /* Log exponent of max contention period: 0...15*/
2072 __u8 log_cw_max;
2073
2074 /* Log exponent of min contention period: 0...15 */
2075 __u8 log_cw_min;
2076
2077 /* Adaptive interframe spacing in units of 32us */
2078 __u8 aifs;
2079
2080 /* TX queue to configure */
2081 __u8 txq;
2082} __attribute__((packed));
2083
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002084#define MWL8K_SET_EDCA_CW 0x01
2085#define MWL8K_SET_EDCA_TXOP 0x02
2086#define MWL8K_SET_EDCA_AIFS 0x04
2087
2088#define MWL8K_SET_EDCA_ALL (MWL8K_SET_EDCA_CW | \
2089 MWL8K_SET_EDCA_TXOP | \
2090 MWL8K_SET_EDCA_AIFS)
2091
2092static int
2093mwl8k_set_edca_params(struct ieee80211_hw *hw, __u8 qnum,
2094 __u16 cw_min, __u16 cw_max,
2095 __u8 aifs, __u16 txop)
2096{
2097 struct mwl8k_cmd_set_edca_params *cmd;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002098 int rc;
2099
2100 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
2101 if (cmd == NULL)
2102 return -ENOMEM;
2103
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002104 cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_EDCA_PARAMS);
2105 cmd->header.length = cpu_to_le16(sizeof(*cmd));
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002106 cmd->action = cpu_to_le16(MWL8K_SET_EDCA_ALL);
2107 cmd->txop = cpu_to_le16(txop);
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02002108 cmd->log_cw_max = (u8)ilog2(cw_max + 1);
2109 cmd->log_cw_min = (u8)ilog2(cw_min + 1);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002110 cmd->aifs = aifs;
2111 cmd->txq = qnum;
2112
2113 rc = mwl8k_post_cmd(hw, &cmd->header);
2114 kfree(cmd);
2115
2116 return rc;
2117}
2118
2119/*
2120 * CMD_FINALIZE_JOIN.
2121 */
2122
2123/* FJ beacon buffer size is compiled into the firmware. */
2124#define MWL8K_FJ_BEACON_MAXLEN 128
2125
2126struct mwl8k_cmd_finalize_join {
2127 struct mwl8k_cmd_pkt header;
2128 __le32 sleep_interval; /* Number of beacon periods to sleep */
2129 __u8 beacon_data[MWL8K_FJ_BEACON_MAXLEN];
2130} __attribute__((packed));
2131
2132static int mwl8k_finalize_join(struct ieee80211_hw *hw, void *frame,
2133 __u16 framelen, __u16 dtim)
2134{
2135 struct mwl8k_cmd_finalize_join *cmd;
2136 struct ieee80211_mgmt *payload = frame;
2137 u16 hdrlen;
2138 u32 payload_len;
2139 int rc;
2140
2141 if (frame == NULL)
2142 return -EINVAL;
2143
2144 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
2145 if (cmd == NULL)
2146 return -ENOMEM;
2147
2148 cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_FINALIZE_JOIN);
2149 cmd->header.length = cpu_to_le16(sizeof(*cmd));
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02002150 cmd->sleep_interval = cpu_to_le32(dtim ? dtim : 1);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002151
2152 hdrlen = ieee80211_hdrlen(payload->frame_control);
2153
2154 payload_len = framelen > hdrlen ? framelen - hdrlen : 0;
2155
2156 /* XXX TBD Might just have to abort and return an error */
2157 if (payload_len > MWL8K_FJ_BEACON_MAXLEN)
2158 printk(KERN_ERR "%s(): WARNING: Incomplete beacon "
2159 "sent to firmware. Sz=%u MAX=%u\n", __func__,
2160 payload_len, MWL8K_FJ_BEACON_MAXLEN);
2161
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02002162 if (payload_len > MWL8K_FJ_BEACON_MAXLEN)
2163 payload_len = MWL8K_FJ_BEACON_MAXLEN;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002164
2165 if (payload && payload_len)
2166 memcpy(cmd->beacon_data, &payload->u.beacon, payload_len);
2167
2168 rc = mwl8k_post_cmd(hw, &cmd->header);
2169 kfree(cmd);
2170 return rc;
2171}
2172
2173/*
2174 * CMD_UPDATE_STADB.
2175 */
2176struct mwl8k_cmd_update_sta_db {
2177 struct mwl8k_cmd_pkt header;
2178
2179 /* See STADB_ACTION_TYPE */
2180 __le32 action;
2181
2182 /* Peer MAC address */
Lennert Buytenhekd89173f2009-07-16 09:54:27 +02002183 __u8 peer_addr[ETH_ALEN];
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002184
2185 __le32 reserved;
2186
2187 /* Peer info - valid during add/update. */
2188 struct peer_capability_info peer_info;
2189} __attribute__((packed));
2190
2191static int mwl8k_cmd_update_sta_db(struct ieee80211_hw *hw,
2192 struct ieee80211_vif *vif, __u32 action)
2193{
2194 struct mwl8k_vif *mv_vif = MWL8K_VIF(vif);
2195 struct ieee80211_bss_conf *info = &mv_vif->bss_info;
2196 struct mwl8k_cmd_update_sta_db *cmd;
2197 struct peer_capability_info *peer_info;
2198 struct ieee80211_rate *bitrates = mv_vif->legacy_rates;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002199 int rc;
2200 __u8 count, *rates;
2201
2202 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
2203 if (cmd == NULL)
2204 return -ENOMEM;
2205
2206 cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB);
2207 cmd->header.length = cpu_to_le16(sizeof(*cmd));
2208
2209 cmd->action = cpu_to_le32(action);
2210 peer_info = &cmd->peer_info;
Lennert Buytenhekd89173f2009-07-16 09:54:27 +02002211 memcpy(cmd->peer_addr, mv_vif->bssid, ETH_ALEN);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002212
2213 switch (action) {
2214 case MWL8K_STA_DB_ADD_ENTRY:
2215 case MWL8K_STA_DB_MODIFY_ENTRY:
2216 /* Build peer_info block */
2217 peer_info->peer_type = MWL8K_PEER_TYPE_ACCESSPOINT;
2218 peer_info->basic_caps = cpu_to_le16(info->assoc_capability);
2219 peer_info->interop = 1;
2220 peer_info->amsdu_enabled = 0;
2221
2222 rates = peer_info->legacy_rates;
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02002223 for (count = 0; count < mv_vif->legacy_nrates; count++)
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002224 rates[count] = bitrates[count].hw_value;
2225
2226 rc = mwl8k_post_cmd(hw, &cmd->header);
2227 if (rc == 0)
2228 mv_vif->peer_id = peer_info->station_id;
2229
2230 break;
2231
2232 case MWL8K_STA_DB_DEL_ENTRY:
2233 case MWL8K_STA_DB_FLUSH:
2234 default:
2235 rc = mwl8k_post_cmd(hw, &cmd->header);
2236 if (rc == 0)
2237 mv_vif->peer_id = 0;
2238 break;
2239 }
2240 kfree(cmd);
2241
2242 return rc;
2243}
2244
2245/*
2246 * CMD_SET_AID.
2247 */
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002248#define MWL8K_RATE_INDEX_MAX_ARRAY 14
2249
2250#define MWL8K_FRAME_PROT_DISABLED 0x00
2251#define MWL8K_FRAME_PROT_11G 0x07
2252#define MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY 0x02
2253#define MWL8K_FRAME_PROT_11N_HT_ALL 0x06
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002254
2255struct mwl8k_cmd_update_set_aid {
2256 struct mwl8k_cmd_pkt header;
2257 __le16 aid;
2258
2259 /* AP's MAC address (BSSID) */
Lennert Buytenhekd89173f2009-07-16 09:54:27 +02002260 __u8 bssid[ETH_ALEN];
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002261 __le16 protection_mode;
2262 __u8 supp_rates[MWL8K_RATE_INDEX_MAX_ARRAY];
2263} __attribute__((packed));
2264
2265static int mwl8k_cmd_set_aid(struct ieee80211_hw *hw,
2266 struct ieee80211_vif *vif)
2267{
2268 struct mwl8k_vif *mv_vif = MWL8K_VIF(vif);
2269 struct ieee80211_bss_conf *info = &mv_vif->bss_info;
2270 struct mwl8k_cmd_update_set_aid *cmd;
2271 struct ieee80211_rate *bitrates = mv_vif->legacy_rates;
2272 int count;
2273 u16 prot_mode;
2274 int rc;
2275
2276 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
2277 if (cmd == NULL)
2278 return -ENOMEM;
2279
2280 cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_AID);
2281 cmd->header.length = cpu_to_le16(sizeof(*cmd));
2282 cmd->aid = cpu_to_le16(info->aid);
2283
Lennert Buytenhekd89173f2009-07-16 09:54:27 +02002284 memcpy(cmd->bssid, mv_vif->bssid, ETH_ALEN);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002285
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002286 if (info->use_cts_prot) {
2287 prot_mode = MWL8K_FRAME_PROT_11G;
2288 } else {
Johannes Berg9ed6bcc2009-05-08 20:47:39 +02002289 switch (info->ht_operation_mode &
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002290 IEEE80211_HT_OP_MODE_PROTECTION) {
2291 case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
2292 prot_mode = MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY;
2293 break;
2294 case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
2295 prot_mode = MWL8K_FRAME_PROT_11N_HT_ALL;
2296 break;
2297 default:
2298 prot_mode = MWL8K_FRAME_PROT_DISABLED;
2299 break;
2300 }
2301 }
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002302 cmd->protection_mode = cpu_to_le16(prot_mode);
2303
2304 for (count = 0; count < mv_vif->legacy_nrates; count++)
2305 cmd->supp_rates[count] = bitrates[count].hw_value;
2306
2307 rc = mwl8k_post_cmd(hw, &cmd->header);
2308 kfree(cmd);
2309
2310 return rc;
2311}
2312
2313/*
2314 * CMD_SET_RATE.
2315 */
2316struct mwl8k_cmd_update_rateset {
2317 struct mwl8k_cmd_pkt header;
2318 __u8 legacy_rates[MWL8K_RATE_INDEX_MAX_ARRAY];
2319
2320 /* Bitmap for supported MCS codes. */
2321 __u8 mcs_set[MWL8K_IEEE_LEGACY_DATA_RATES];
2322 __u8 reserved[MWL8K_IEEE_LEGACY_DATA_RATES];
2323} __attribute__((packed));
2324
2325static int mwl8k_update_rateset(struct ieee80211_hw *hw,
2326 struct ieee80211_vif *vif)
2327{
2328 struct mwl8k_vif *mv_vif = MWL8K_VIF(vif);
2329 struct mwl8k_cmd_update_rateset *cmd;
2330 struct ieee80211_rate *bitrates = mv_vif->legacy_rates;
2331 int count;
2332 int rc;
2333
2334 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
2335 if (cmd == NULL)
2336 return -ENOMEM;
2337
2338 cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATE);
2339 cmd->header.length = cpu_to_le16(sizeof(*cmd));
2340
2341 for (count = 0; count < mv_vif->legacy_nrates; count++)
2342 cmd->legacy_rates[count] = bitrates[count].hw_value;
2343
2344 rc = mwl8k_post_cmd(hw, &cmd->header);
2345 kfree(cmd);
2346
2347 return rc;
2348}
2349
2350/*
2351 * CMD_USE_FIXED_RATE.
2352 */
2353#define MWL8K_RATE_TABLE_SIZE 8
2354#define MWL8K_UCAST_RATE 0
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002355#define MWL8K_USE_AUTO_RATE 0x0002
2356
2357struct mwl8k_rate_entry {
2358 /* Set to 1 if HT rate, 0 if legacy. */
2359 __le32 is_ht_rate;
2360
2361 /* Set to 1 to use retry_count field. */
2362 __le32 enable_retry;
2363
2364 /* Specified legacy rate or MCS. */
2365 __le32 rate;
2366
2367 /* Number of allowed retries. */
2368 __le32 retry_count;
2369} __attribute__((packed));
2370
2371struct mwl8k_rate_table {
2372 /* 1 to allow specified rate and below */
2373 __le32 allow_rate_drop;
2374 __le32 num_rates;
2375 struct mwl8k_rate_entry rate_entry[MWL8K_RATE_TABLE_SIZE];
2376} __attribute__((packed));
2377
2378struct mwl8k_cmd_use_fixed_rate {
2379 struct mwl8k_cmd_pkt header;
2380 __le32 action;
2381 struct mwl8k_rate_table rate_table;
2382
2383 /* Unicast, Broadcast or Multicast */
2384 __le32 rate_type;
2385 __le32 reserved1;
2386 __le32 reserved2;
2387} __attribute__((packed));
2388
2389static int mwl8k_cmd_use_fixed_rate(struct ieee80211_hw *hw,
2390 u32 action, u32 rate_type, struct mwl8k_rate_table *rate_table)
2391{
2392 struct mwl8k_cmd_use_fixed_rate *cmd;
2393 int count;
2394 int rc;
2395
2396 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
2397 if (cmd == NULL)
2398 return -ENOMEM;
2399
2400 cmd->header.code = cpu_to_le16(MWL8K_CMD_USE_FIXED_RATE);
2401 cmd->header.length = cpu_to_le16(sizeof(*cmd));
2402
2403 cmd->action = cpu_to_le32(action);
2404 cmd->rate_type = cpu_to_le32(rate_type);
2405
2406 if (rate_table != NULL) {
2407 /* Copy over each field manually so
2408 * that bitflipping can be done
2409 */
2410 cmd->rate_table.allow_rate_drop =
2411 cpu_to_le32(rate_table->allow_rate_drop);
2412 cmd->rate_table.num_rates =
2413 cpu_to_le32(rate_table->num_rates);
2414
2415 for (count = 0; count < rate_table->num_rates; count++) {
2416 struct mwl8k_rate_entry *dst =
2417 &cmd->rate_table.rate_entry[count];
2418 struct mwl8k_rate_entry *src =
2419 &rate_table->rate_entry[count];
2420
2421 dst->is_ht_rate = cpu_to_le32(src->is_ht_rate);
2422 dst->enable_retry = cpu_to_le32(src->enable_retry);
2423 dst->rate = cpu_to_le32(src->rate);
2424 dst->retry_count = cpu_to_le32(src->retry_count);
2425 }
2426 }
2427
2428 rc = mwl8k_post_cmd(hw, &cmd->header);
2429 kfree(cmd);
2430
2431 return rc;
2432}
2433
2434
2435/*
2436 * Interrupt handling.
2437 */
2438static irqreturn_t mwl8k_interrupt(int irq, void *dev_id)
2439{
2440 struct ieee80211_hw *hw = dev_id;
2441 struct mwl8k_priv *priv = hw->priv;
2442 u32 status;
2443
2444 status = ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
2445 iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
2446
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002447 if (!status)
2448 return IRQ_NONE;
2449
2450 if (status & MWL8K_A2H_INT_TX_DONE)
2451 tasklet_schedule(&priv->tx_reclaim_task);
2452
2453 if (status & MWL8K_A2H_INT_RX_READY) {
2454 while (rxq_process(hw, 0, 1))
2455 rxq_refill(hw, 0, 1);
2456 }
2457
2458 if (status & MWL8K_A2H_INT_OPC_DONE) {
2459 if (priv->hostcmd_wait != NULL) {
2460 complete(priv->hostcmd_wait);
2461 priv->hostcmd_wait = NULL;
2462 }
2463 }
2464
2465 if (status & MWL8K_A2H_INT_QUEUE_EMPTY) {
2466 if (!priv->inconfig &&
Lennert Buytenhekc46563b2009-07-16 12:14:58 +02002467 priv->radio_on &&
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002468 mwl8k_txq_busy(priv))
2469 mwl8k_tx_start(priv);
2470 }
2471
2472 return IRQ_HANDLED;
2473}
2474
2475
2476/*
2477 * Core driver operations.
2478 */
2479static int mwl8k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
2480{
2481 struct mwl8k_priv *priv = hw->priv;
2482 int index = skb_get_queue_mapping(skb);
2483 int rc;
2484
2485 if (priv->current_channel == NULL) {
2486 printk(KERN_DEBUG "%s: dropped TX frame since radio "
2487 "disabled\n", priv->name);
2488 dev_kfree_skb(skb);
2489 return NETDEV_TX_OK;
2490 }
2491
2492 rc = mwl8k_txq_xmit(hw, index, skb);
2493
2494 return rc;
2495}
2496
2497struct mwl8k_work_struct {
2498 /* Initialized by mwl8k_queue_work(). */
2499 struct work_struct wt;
2500
2501 /* Required field passed in to mwl8k_queue_work(). */
2502 struct ieee80211_hw *hw;
2503
2504 /* Required field passed in to mwl8k_queue_work(). */
2505 int (*wfunc)(struct work_struct *w);
2506
2507 /* Initialized by mwl8k_queue_work(). */
2508 struct completion *cmd_wait;
2509
2510 /* Result code. */
2511 int rc;
2512
2513 /*
2514 * Optional field. Refer to explanation of MWL8K_WQ_XXX_XXX
2515 * flags for explanation. Defaults to MWL8K_WQ_DEFAULT_OPTIONS.
2516 */
2517 u32 options;
2518
2519 /* Optional field. Defaults to MWL8K_CONFIG_TIMEOUT_MS. */
2520 unsigned long timeout_ms;
2521
2522 /* Optional field. Defaults to MWL8K_WQ_TXWAIT_ATTEMPTS. */
2523 u32 txwait_attempts;
2524
2525 /* Optional field. Defaults to MWL8K_TXWAIT_MS. */
2526 u32 tx_timeout_ms;
2527 u32 step;
2528};
2529
2530/* Flags controlling behavior of config queue requests */
2531
2532/* Caller spins while waiting for completion. */
2533#define MWL8K_WQ_SPIN 0x00000001
2534
2535/* Wait for TX queues to empty before proceeding with configuration. */
2536#define MWL8K_WQ_TX_WAIT_EMPTY 0x00000002
2537
2538/* Queue request and return immediately. */
2539#define MWL8K_WQ_POST_REQUEST 0x00000004
2540
2541/*
2542 * Caller sleeps and waits for task complete notification.
2543 * Do not use in atomic context.
2544 */
2545#define MWL8K_WQ_SLEEP 0x00000008
2546
2547/* Free work struct when task is done. */
2548#define MWL8K_WQ_FREE_WORKSTRUCT 0x00000010
2549
2550/*
2551 * Config request is queued and returns to caller imediately. Use
2552 * this in atomic context. Work struct is freed by mwl8k_queue_work()
2553 * when this flag is set.
2554 */
2555#define MWL8K_WQ_QUEUE_ONLY (MWL8K_WQ_POST_REQUEST | \
2556 MWL8K_WQ_FREE_WORKSTRUCT)
2557
2558/* Default work queue behavior is to sleep and wait for tx completion. */
2559#define MWL8K_WQ_DEFAULT_OPTIONS (MWL8K_WQ_SLEEP | MWL8K_WQ_TX_WAIT_EMPTY)
2560
2561/*
2562 * Default config request timeout. Add adjustments to make sure the
2563 * config thread waits long enough for both tx wait and cmd wait before
2564 * timing out.
2565 */
2566
2567/* Time to wait for all TXQs to drain. TX Doorbell is pressed each time. */
2568#define MWL8K_TXWAIT_TIMEOUT_MS 1000
2569
2570/* Default number of TX wait attempts. */
2571#define MWL8K_WQ_TXWAIT_ATTEMPTS 4
2572
2573/* Total time to wait for TXQ to drain. */
2574#define MWL8K_TXWAIT_MS (MWL8K_TXWAIT_TIMEOUT_MS * \
2575 MWL8K_WQ_TXWAIT_ATTEMPTS)
2576
2577/* Scheduling slop. */
2578#define MWL8K_OS_SCHEDULE_OVERHEAD_MS 200
2579
2580#define MWL8K_CONFIG_TIMEOUT_MS (MWL8K_CMD_TIMEOUT_MS + \
2581 MWL8K_TXWAIT_MS + \
2582 MWL8K_OS_SCHEDULE_OVERHEAD_MS)
2583
2584static void mwl8k_config_thread(struct work_struct *wt)
2585{
2586 struct mwl8k_work_struct *worker = (struct mwl8k_work_struct *)wt;
2587 struct ieee80211_hw *hw = worker->hw;
2588 struct mwl8k_priv *priv = hw->priv;
2589 int rc = 0;
2590
2591 spin_lock_irq(&priv->tx_lock);
2592 priv->inconfig = true;
2593 spin_unlock_irq(&priv->tx_lock);
2594
2595 ieee80211_stop_queues(hw);
2596
2597 /*
2598 * Wait for host queues to drain before doing PHY
2599 * reconfiguration. This avoids interrupting any in-flight
2600 * DMA transfers to the hardware.
2601 */
2602 if (worker->options & MWL8K_WQ_TX_WAIT_EMPTY) {
2603 u32 timeout;
2604 u32 time_remaining;
2605 u32 iter;
2606 u32 tx_wait_attempts = worker->txwait_attempts;
2607
2608 time_remaining = worker->tx_timeout_ms;
2609 if (!tx_wait_attempts)
2610 tx_wait_attempts = 1;
2611
2612 timeout = worker->tx_timeout_ms/tx_wait_attempts;
2613 if (!timeout)
2614 timeout = 1;
2615
2616 iter = tx_wait_attempts;
2617 do {
2618 int wait_time;
2619
2620 if (time_remaining > timeout) {
2621 time_remaining -= timeout;
2622 wait_time = timeout;
2623 } else
2624 wait_time = time_remaining;
2625
2626 if (!wait_time)
2627 wait_time = 1;
2628
2629 rc = mwl8k_tx_wait_empty(hw, wait_time);
2630 if (rc)
2631 printk(KERN_ERR "%s() txwait timeout=%ums "
2632 "Retry:%u/%u\n", __func__, timeout,
2633 tx_wait_attempts - iter + 1,
2634 tx_wait_attempts);
2635
2636 } while (rc && --iter);
2637
2638 rc = iter ? 0 : -ETIMEDOUT;
2639 }
2640 if (!rc)
2641 rc = worker->wfunc(wt);
2642
2643 spin_lock_irq(&priv->tx_lock);
2644 priv->inconfig = false;
Lennert Buytenhekc46563b2009-07-16 12:14:58 +02002645 if (priv->pending_tx_pkts && priv->radio_on)
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002646 mwl8k_tx_start(priv);
2647 spin_unlock_irq(&priv->tx_lock);
2648 ieee80211_wake_queues(hw);
2649
2650 worker->rc = rc;
2651 if (worker->options & MWL8K_WQ_SLEEP)
2652 complete(worker->cmd_wait);
2653
2654 if (worker->options & MWL8K_WQ_FREE_WORKSTRUCT)
2655 kfree(wt);
2656}
2657
2658static int mwl8k_queue_work(struct ieee80211_hw *hw,
2659 struct mwl8k_work_struct *worker,
2660 struct workqueue_struct *wqueue,
2661 int (*wfunc)(struct work_struct *w))
2662{
2663 unsigned long timeout = 0;
2664 int rc = 0;
2665
2666 DECLARE_COMPLETION_ONSTACK(cmd_wait);
2667
2668 if (!worker->timeout_ms)
2669 worker->timeout_ms = MWL8K_CONFIG_TIMEOUT_MS;
2670
2671 if (!worker->options)
2672 worker->options = MWL8K_WQ_DEFAULT_OPTIONS;
2673
2674 if (!worker->txwait_attempts)
2675 worker->txwait_attempts = MWL8K_WQ_TXWAIT_ATTEMPTS;
2676
2677 if (!worker->tx_timeout_ms)
2678 worker->tx_timeout_ms = MWL8K_TXWAIT_MS;
2679
2680 worker->hw = hw;
2681 worker->cmd_wait = &cmd_wait;
2682 worker->rc = 1;
2683 worker->wfunc = wfunc;
2684
2685 INIT_WORK(&worker->wt, mwl8k_config_thread);
2686 queue_work(wqueue, &worker->wt);
2687
2688 if (worker->options & MWL8K_WQ_POST_REQUEST) {
2689 rc = 0;
2690 } else {
2691 if (worker->options & MWL8K_WQ_SPIN) {
2692 timeout = worker->timeout_ms;
2693 while (timeout && (worker->rc > 0)) {
2694 mdelay(1);
2695 timeout--;
2696 }
2697 } else if (worker->options & MWL8K_WQ_SLEEP)
2698 timeout = wait_for_completion_timeout(&cmd_wait,
2699 msecs_to_jiffies(worker->timeout_ms));
2700
2701 if (timeout)
2702 rc = worker->rc;
2703 else {
2704 cancel_work_sync(&worker->wt);
2705 rc = -ETIMEDOUT;
2706 }
2707 }
2708
2709 return rc;
2710}
2711
2712struct mwl8k_start_worker {
2713 struct mwl8k_work_struct header;
2714};
2715
2716static int mwl8k_start_wt(struct work_struct *wt)
2717{
2718 struct mwl8k_start_worker *worker = (struct mwl8k_start_worker *)wt;
2719 struct ieee80211_hw *hw = worker->header.hw;
2720 struct mwl8k_priv *priv = hw->priv;
2721 int rc = 0;
2722
2723 if (priv->vif != NULL) {
2724 rc = -EIO;
2725 goto mwl8k_start_exit;
2726 }
2727
2728 /* Turn on radio */
Lennert Buytenhekc46563b2009-07-16 12:14:58 +02002729 if (mwl8k_cmd_802_11_radio_enable(hw)) {
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002730 rc = -EIO;
2731 goto mwl8k_start_exit;
2732 }
2733
2734 /* Purge TX/RX HW queues */
2735 if (mwl8k_cmd_set_pre_scan(hw)) {
2736 rc = -EIO;
2737 goto mwl8k_start_exit;
2738 }
2739
2740 if (mwl8k_cmd_set_post_scan(hw, "\x00\x00\x00\x00\x00\x00")) {
2741 rc = -EIO;
2742 goto mwl8k_start_exit;
2743 }
2744
2745 /* Enable firmware rate adaptation */
2746 if (mwl8k_cmd_setrateadaptmode(hw, 0)) {
2747 rc = -EIO;
2748 goto mwl8k_start_exit;
2749 }
2750
2751 /* Disable WMM. WMM gets enabled when stack sends WMM parms */
Lennert Buytenhek0439b1f2009-07-16 12:34:02 +02002752 if (mwl8k_set_wmm(hw, 0)) {
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002753 rc = -EIO;
2754 goto mwl8k_start_exit;
2755 }
2756
2757 /* Disable sniffer mode */
2758 if (mwl8k_enable_sniffer(hw, 0))
2759 rc = -EIO;
2760
2761mwl8k_start_exit:
2762 return rc;
2763}
2764
2765static int mwl8k_start(struct ieee80211_hw *hw)
2766{
2767 struct mwl8k_start_worker *worker;
2768 struct mwl8k_priv *priv = hw->priv;
2769 int rc;
2770
2771 /* Enable tx reclaim tasklet */
2772 tasklet_enable(&priv->tx_reclaim_task);
2773
2774 rc = request_irq(priv->pdev->irq, &mwl8k_interrupt,
2775 IRQF_SHARED, MWL8K_NAME, hw);
2776 if (rc) {
2777 printk(KERN_ERR "%s: failed to register IRQ handler\n",
2778 priv->name);
2779 rc = -EIO;
2780 goto mwl8k_start_disable_tasklet;
2781 }
2782
2783 /* Enable interrupts */
Lennert Buytenhekc23b5a62009-07-16 13:49:55 +02002784 iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002785
2786 worker = kzalloc(sizeof(*worker), GFP_KERNEL);
2787 if (worker == NULL) {
2788 rc = -ENOMEM;
2789 goto mwl8k_start_disable_irq;
2790 }
2791
2792 rc = mwl8k_queue_work(hw, &worker->header,
2793 priv->config_wq, mwl8k_start_wt);
2794 kfree(worker);
2795 if (!rc)
2796 return rc;
2797
2798 if (rc == -ETIMEDOUT)
2799 printk(KERN_ERR "%s() timed out\n", __func__);
2800
2801 rc = -EIO;
2802
2803mwl8k_start_disable_irq:
2804 spin_lock_irq(&priv->tx_lock);
2805 iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
2806 spin_unlock_irq(&priv->tx_lock);
2807 free_irq(priv->pdev->irq, hw);
2808
2809mwl8k_start_disable_tasklet:
2810 tasklet_disable(&priv->tx_reclaim_task);
2811
2812 return rc;
2813}
2814
2815struct mwl8k_stop_worker {
2816 struct mwl8k_work_struct header;
2817};
2818
2819static int mwl8k_stop_wt(struct work_struct *wt)
2820{
2821 struct mwl8k_stop_worker *worker = (struct mwl8k_stop_worker *)wt;
2822 struct ieee80211_hw *hw = worker->header.hw;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002823
Lennert Buytenhekc46563b2009-07-16 12:14:58 +02002824 return mwl8k_cmd_802_11_radio_disable(hw);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002825}
2826
2827static void mwl8k_stop(struct ieee80211_hw *hw)
2828{
2829 int rc;
2830 struct mwl8k_stop_worker *worker;
2831 struct mwl8k_priv *priv = hw->priv;
2832 int i;
2833
2834 if (priv->vif != NULL)
2835 return;
2836
2837 ieee80211_stop_queues(hw);
2838
2839 worker = kzalloc(sizeof(*worker), GFP_KERNEL);
2840 if (worker == NULL)
2841 return;
2842
2843 rc = mwl8k_queue_work(hw, &worker->header,
2844 priv->config_wq, mwl8k_stop_wt);
2845 kfree(worker);
2846 if (rc == -ETIMEDOUT)
2847 printk(KERN_ERR "%s() timed out\n", __func__);
2848
2849 /* Disable interrupts */
2850 spin_lock_irq(&priv->tx_lock);
2851 iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
2852 spin_unlock_irq(&priv->tx_lock);
2853 free_irq(priv->pdev->irq, hw);
2854
2855 /* Stop finalize join worker */
2856 cancel_work_sync(&priv->finalize_join_worker);
2857 if (priv->beacon_skb != NULL)
2858 dev_kfree_skb(priv->beacon_skb);
2859
2860 /* Stop tx reclaim tasklet */
2861 tasklet_disable(&priv->tx_reclaim_task);
2862
2863 /* Stop config thread */
2864 flush_workqueue(priv->config_wq);
2865
2866 /* Return all skbs to mac80211 */
2867 for (i = 0; i < MWL8K_TX_QUEUES; i++)
2868 mwl8k_txq_reclaim(hw, i, 1);
2869}
2870
2871static int mwl8k_add_interface(struct ieee80211_hw *hw,
2872 struct ieee80211_if_init_conf *conf)
2873{
2874 struct mwl8k_priv *priv = hw->priv;
2875 struct mwl8k_vif *mwl8k_vif;
2876
2877 /*
2878 * We only support one active interface at a time.
2879 */
2880 if (priv->vif != NULL)
2881 return -EBUSY;
2882
2883 /*
2884 * We only support managed interfaces for now.
2885 */
2886 if (conf->type != NL80211_IFTYPE_STATION &&
2887 conf->type != NL80211_IFTYPE_MONITOR)
2888 return -EINVAL;
2889
2890 /* Clean out driver private area */
2891 mwl8k_vif = MWL8K_VIF(conf->vif);
2892 memset(mwl8k_vif, 0, sizeof(*mwl8k_vif));
2893
2894 /* Save the mac address */
Lennert Buytenhekd89173f2009-07-16 09:54:27 +02002895 memcpy(mwl8k_vif->mac_addr, conf->mac_addr, ETH_ALEN);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002896
2897 /* Back pointer to parent config block */
2898 mwl8k_vif->priv = priv;
2899
2900 /* Setup initial PHY parameters */
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02002901 memcpy(mwl8k_vif->legacy_rates,
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002902 priv->rates, sizeof(mwl8k_vif->legacy_rates));
2903 mwl8k_vif->legacy_nrates = ARRAY_SIZE(priv->rates);
2904
2905 /* Set Initial sequence number to zero */
2906 mwl8k_vif->seqno = 0;
2907
2908 priv->vif = conf->vif;
2909 priv->current_channel = NULL;
2910
2911 return 0;
2912}
2913
2914static void mwl8k_remove_interface(struct ieee80211_hw *hw,
2915 struct ieee80211_if_init_conf *conf)
2916{
2917 struct mwl8k_priv *priv = hw->priv;
2918
2919 if (priv->vif == NULL)
2920 return;
2921
2922 priv->vif = NULL;
2923}
2924
2925struct mwl8k_config_worker {
2926 struct mwl8k_work_struct header;
2927 u32 changed;
2928};
2929
2930static int mwl8k_config_wt(struct work_struct *wt)
2931{
2932 struct mwl8k_config_worker *worker =
2933 (struct mwl8k_config_worker *)wt;
2934 struct ieee80211_hw *hw = worker->header.hw;
2935 struct ieee80211_conf *conf = &hw->conf;
2936 struct mwl8k_priv *priv = hw->priv;
2937 int rc = 0;
2938
Lennert Buytenhekc46563b2009-07-16 12:14:58 +02002939 if (mwl8k_cmd_802_11_radio_enable(hw)) {
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002940 rc = -EINVAL;
2941 goto mwl8k_config_exit;
2942 }
2943
2944 priv->current_channel = conf->channel;
2945
2946 if (mwl8k_cmd_set_rf_channel(hw, conf->channel)) {
2947 rc = -EINVAL;
2948 goto mwl8k_config_exit;
2949 }
2950
2951 if (conf->power_level > 18)
2952 conf->power_level = 18;
2953 if (mwl8k_cmd_802_11_rf_tx_power(hw, conf->power_level)) {
2954 rc = -EINVAL;
2955 goto mwl8k_config_exit;
2956 }
2957
2958 if (mwl8k_cmd_mimo_config(hw, 0x7, 0x7))
2959 rc = -EINVAL;
2960
2961mwl8k_config_exit:
2962 return rc;
2963}
2964
2965static int mwl8k_config(struct ieee80211_hw *hw, u32 changed)
2966{
2967 int rc = 0;
2968 struct mwl8k_config_worker *worker;
2969 struct mwl8k_priv *priv = hw->priv;
2970
2971 worker = kzalloc(sizeof(*worker), GFP_KERNEL);
2972 if (worker == NULL)
2973 return -ENOMEM;
2974
2975 worker->changed = changed;
2976 rc = mwl8k_queue_work(hw, &worker->header,
2977 priv->config_wq, mwl8k_config_wt);
2978 if (rc == -ETIMEDOUT) {
2979 printk(KERN_ERR "%s() timed out.\n", __func__);
2980 rc = -EINVAL;
2981 }
2982
2983 kfree(worker);
2984
2985 /*
2986 * mac80211 will crash on anything other than -EINVAL on
2987 * error. Looks like wireless extensions which calls mac80211
2988 * may be the actual culprit...
2989 */
2990 return rc ? -EINVAL : 0;
2991}
2992
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002993struct mwl8k_bss_info_changed_worker {
2994 struct mwl8k_work_struct header;
2995 struct ieee80211_vif *vif;
2996 struct ieee80211_bss_conf *info;
2997 u32 changed;
2998};
2999
3000static int mwl8k_bss_info_changed_wt(struct work_struct *wt)
3001{
3002 struct mwl8k_bss_info_changed_worker *worker =
3003 (struct mwl8k_bss_info_changed_worker *)wt;
3004 struct ieee80211_hw *hw = worker->header.hw;
3005 struct ieee80211_vif *vif = worker->vif;
3006 struct ieee80211_bss_conf *info = worker->info;
3007 u32 changed;
3008 int rc;
3009
3010 struct mwl8k_priv *priv = hw->priv;
3011 struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif);
3012
3013 changed = worker->changed;
3014 priv->capture_beacon = false;
3015
3016 if (info->assoc) {
3017 memcpy(&mwl8k_vif->bss_info, info,
3018 sizeof(struct ieee80211_bss_conf));
3019
3020 /* Install rates */
3021 if (mwl8k_update_rateset(hw, vif))
3022 goto mwl8k_bss_info_changed_exit;
3023
3024 /* Turn on rate adaptation */
3025 if (mwl8k_cmd_use_fixed_rate(hw, MWL8K_USE_AUTO_RATE,
3026 MWL8K_UCAST_RATE, NULL))
3027 goto mwl8k_bss_info_changed_exit;
3028
3029 /* Set radio preamble */
Lennert Buytenhek68ce3882009-07-16 12:26:57 +02003030 if (mwl8k_set_radio_preamble(hw, info->use_short_preamble))
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003031 goto mwl8k_bss_info_changed_exit;
3032
3033 /* Set slot time */
Lennert Buytenhek5539bb52009-07-16 16:06:53 +02003034 if (mwl8k_cmd_set_slot(hw, info->use_short_slot))
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003035 goto mwl8k_bss_info_changed_exit;
3036
3037 /* Update peer rate info */
3038 if (mwl8k_cmd_update_sta_db(hw, vif,
3039 MWL8K_STA_DB_MODIFY_ENTRY))
3040 goto mwl8k_bss_info_changed_exit;
3041
3042 /* Set AID */
3043 if (mwl8k_cmd_set_aid(hw, vif))
3044 goto mwl8k_bss_info_changed_exit;
3045
3046 /*
3047 * Finalize the join. Tell rx handler to process
3048 * next beacon from our BSSID.
3049 */
Lennert Buytenhekd89173f2009-07-16 09:54:27 +02003050 memcpy(priv->capture_bssid, mwl8k_vif->bssid, ETH_ALEN);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003051 priv->capture_beacon = true;
3052 } else {
3053 mwl8k_cmd_update_sta_db(hw, vif, MWL8K_STA_DB_DEL_ENTRY);
3054 memset(&mwl8k_vif->bss_info, 0,
3055 sizeof(struct ieee80211_bss_conf));
Lennert Buytenhekd89173f2009-07-16 09:54:27 +02003056 memset(mwl8k_vif->bssid, 0, ETH_ALEN);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003057 }
3058
3059mwl8k_bss_info_changed_exit:
3060 rc = 0;
3061 return rc;
3062}
3063
3064static void mwl8k_bss_info_changed(struct ieee80211_hw *hw,
3065 struct ieee80211_vif *vif,
3066 struct ieee80211_bss_conf *info,
3067 u32 changed)
3068{
3069 struct mwl8k_bss_info_changed_worker *worker;
3070 struct mwl8k_priv *priv = hw->priv;
Johannes Berg2d0ddec2009-04-23 16:13:26 +02003071 struct mwl8k_vif *mv_vif = MWL8K_VIF(vif);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003072 int rc;
3073
Johannes Berg2d0ddec2009-04-23 16:13:26 +02003074 if (changed & BSS_CHANGED_BSSID)
Lennert Buytenhekd89173f2009-07-16 09:54:27 +02003075 memcpy(mv_vif->bssid, info->bssid, ETH_ALEN);
Johannes Berg2d0ddec2009-04-23 16:13:26 +02003076
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003077 if ((changed & BSS_CHANGED_ASSOC) == 0)
3078 return;
3079
3080 worker = kzalloc(sizeof(*worker), GFP_KERNEL);
3081 if (worker == NULL)
3082 return;
3083
3084 worker->vif = vif;
3085 worker->info = info;
3086 worker->changed = changed;
3087 rc = mwl8k_queue_work(hw, &worker->header,
3088 priv->config_wq,
3089 mwl8k_bss_info_changed_wt);
3090 kfree(worker);
3091 if (rc == -ETIMEDOUT)
3092 printk(KERN_ERR "%s() timed out\n", __func__);
3093}
3094
Lennert Buytenheke81cd2d2009-08-18 03:55:42 +02003095static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw,
3096 int mc_count, struct dev_addr_list *mclist)
3097{
3098 struct mwl8k_cmd_pkt *cmd;
3099
3100 cmd = __mwl8k_cmd_mac_multicast_adr(hw, mc_count, mclist);
3101
3102 return (unsigned long)cmd;
3103}
3104
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003105struct mwl8k_configure_filter_worker {
3106 struct mwl8k_work_struct header;
3107 unsigned int changed_flags;
Lennert Buytenheke81cd2d2009-08-18 03:55:42 +02003108 unsigned int total_flags;
3109 struct mwl8k_cmd_pkt *multicast_adr_cmd;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003110};
3111
3112#define MWL8K_SUPPORTED_IF_FLAGS FIF_BCN_PRBRESP_PROMISC
3113
3114static int mwl8k_configure_filter_wt(struct work_struct *wt)
3115{
3116 struct mwl8k_configure_filter_worker *worker =
3117 (struct mwl8k_configure_filter_worker *)wt;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003118 struct ieee80211_hw *hw = worker->header.hw;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003119 struct mwl8k_priv *priv = hw->priv;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003120 int rc = 0;
3121
Lennert Buytenheke81cd2d2009-08-18 03:55:42 +02003122 if (worker->changed_flags & FIF_BCN_PRBRESP_PROMISC) {
3123 if (worker->total_flags & FIF_BCN_PRBRESP_PROMISC)
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003124 rc = mwl8k_cmd_set_pre_scan(hw);
3125 else {
Lennert Buytenheka94cc972009-08-03 21:58:57 +02003126 u8 *bssid;
3127
3128 bssid = "\x00\x00\x00\x00\x00\x00";
3129 if (priv->vif != NULL)
3130 bssid = MWL8K_VIF(priv->vif)->bssid;
3131
3132 rc = mwl8k_cmd_set_post_scan(hw, bssid);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003133 }
3134 }
3135
Lennert Buytenheke81cd2d2009-08-18 03:55:42 +02003136 if (!rc && worker->multicast_adr_cmd != NULL)
3137 rc = mwl8k_post_cmd(hw, worker->multicast_adr_cmd);
3138 kfree(worker->multicast_adr_cmd);
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02003139
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003140 return rc;
3141}
3142
3143static void mwl8k_configure_filter(struct ieee80211_hw *hw,
3144 unsigned int changed_flags,
3145 unsigned int *total_flags,
Johannes Berg3ac64be2009-08-17 16:16:53 +02003146 u64 multicast)
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003147{
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003148 struct mwl8k_priv *priv = hw->priv;
Lennert Buytenheke81cd2d2009-08-18 03:55:42 +02003149 struct mwl8k_configure_filter_worker *worker;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003150
3151 /* Clear unsupported feature flags */
3152 *total_flags &= MWL8K_SUPPORTED_IF_FLAGS;
3153
Johannes Berg3ac64be2009-08-17 16:16:53 +02003154 if (!(changed_flags & MWL8K_SUPPORTED_IF_FLAGS))
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003155 return;
3156
Lennert Buytenheke81cd2d2009-08-18 03:55:42 +02003157 worker = kzalloc(sizeof(*worker), GFP_ATOMIC);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003158 if (worker == NULL)
3159 return;
3160
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003161 worker->changed_flags = changed_flags;
Lennert Buytenheke81cd2d2009-08-18 03:55:42 +02003162 worker->total_flags = *total_flags;
3163 worker->multicast_adr_cmd = (void *)(unsigned long)multicast;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003164
3165 mwl8k_queue_work(hw, &worker->header, priv->config_wq,
3166 mwl8k_configure_filter_wt);
3167}
3168
3169struct mwl8k_set_rts_threshold_worker {
3170 struct mwl8k_work_struct header;
3171 u32 value;
3172};
3173
3174static int mwl8k_set_rts_threshold_wt(struct work_struct *wt)
3175{
3176 struct mwl8k_set_rts_threshold_worker *worker =
3177 (struct mwl8k_set_rts_threshold_worker *)wt;
3178
3179 struct ieee80211_hw *hw = worker->header.hw;
3180 u16 threshold = (u16)(worker->value);
3181 int rc;
3182
3183 rc = mwl8k_rts_threshold(hw, MWL8K_CMD_SET, &threshold);
3184
3185 return rc;
3186}
3187
3188static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3189{
3190 int rc;
3191 struct mwl8k_set_rts_threshold_worker *worker;
3192 struct mwl8k_priv *priv = hw->priv;
3193
3194 worker = kzalloc(sizeof(*worker), GFP_KERNEL);
3195 if (worker == NULL)
3196 return -ENOMEM;
3197
3198 worker->value = value;
3199
3200 rc = mwl8k_queue_work(hw, &worker->header,
3201 priv->config_wq,
3202 mwl8k_set_rts_threshold_wt);
3203 kfree(worker);
3204
3205 if (rc == -ETIMEDOUT) {
3206 printk(KERN_ERR "%s() timed out\n", __func__);
3207 rc = -EINVAL;
3208 }
3209
3210 return rc;
3211}
3212
3213struct mwl8k_conf_tx_worker {
3214 struct mwl8k_work_struct header;
3215 u16 queue;
3216 const struct ieee80211_tx_queue_params *params;
3217};
3218
3219static int mwl8k_conf_tx_wt(struct work_struct *wt)
3220{
3221 struct mwl8k_conf_tx_worker *worker =
3222 (struct mwl8k_conf_tx_worker *)wt;
3223
3224 struct ieee80211_hw *hw = worker->header.hw;
3225 u16 queue = worker->queue;
3226 const struct ieee80211_tx_queue_params *params = worker->params;
3227
3228 struct mwl8k_priv *priv = hw->priv;
3229 int rc = 0;
3230
Lennert Buytenhek0439b1f2009-07-16 12:34:02 +02003231 if (!priv->wmm_enabled) {
3232 if (mwl8k_set_wmm(hw, 1)) {
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003233 rc = -EINVAL;
3234 goto mwl8k_conf_tx_exit;
Lennert Buytenhek0439b1f2009-07-16 12:34:02 +02003235 }
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003236 }
3237
3238 if (mwl8k_set_edca_params(hw, GET_TXQ(queue), params->cw_min,
3239 params->cw_max, params->aifs, params->txop))
3240 rc = -EINVAL;
3241mwl8k_conf_tx_exit:
3242 return rc;
3243}
3244
3245static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue,
3246 const struct ieee80211_tx_queue_params *params)
3247{
3248 int rc;
3249 struct mwl8k_conf_tx_worker *worker;
3250 struct mwl8k_priv *priv = hw->priv;
3251
3252 worker = kzalloc(sizeof(*worker), GFP_KERNEL);
3253 if (worker == NULL)
3254 return -ENOMEM;
3255
3256 worker->queue = queue;
3257 worker->params = params;
3258 rc = mwl8k_queue_work(hw, &worker->header,
3259 priv->config_wq, mwl8k_conf_tx_wt);
3260 kfree(worker);
3261 if (rc == -ETIMEDOUT) {
3262 printk(KERN_ERR "%s() timed out\n", __func__);
3263 rc = -EINVAL;
3264 }
3265 return rc;
3266}
3267
3268static int mwl8k_get_tx_stats(struct ieee80211_hw *hw,
3269 struct ieee80211_tx_queue_stats *stats)
3270{
3271 struct mwl8k_priv *priv = hw->priv;
3272 struct mwl8k_tx_queue *txq;
3273 int index;
3274
3275 spin_lock_bh(&priv->tx_lock);
3276 for (index = 0; index < MWL8K_TX_QUEUES; index++) {
3277 txq = priv->txq + index;
3278 memcpy(&stats[index], &txq->tx_stats,
3279 sizeof(struct ieee80211_tx_queue_stats));
3280 }
3281 spin_unlock_bh(&priv->tx_lock);
3282 return 0;
3283}
3284
3285struct mwl8k_get_stats_worker {
3286 struct mwl8k_work_struct header;
3287 struct ieee80211_low_level_stats *stats;
3288};
3289
3290static int mwl8k_get_stats_wt(struct work_struct *wt)
3291{
3292 struct mwl8k_get_stats_worker *worker =
3293 (struct mwl8k_get_stats_worker *)wt;
3294
3295 return mwl8k_cmd_802_11_get_stat(worker->header.hw, worker->stats);
3296}
3297
3298static int mwl8k_get_stats(struct ieee80211_hw *hw,
3299 struct ieee80211_low_level_stats *stats)
3300{
3301 int rc;
3302 struct mwl8k_get_stats_worker *worker;
3303 struct mwl8k_priv *priv = hw->priv;
3304
3305 worker = kzalloc(sizeof(*worker), GFP_KERNEL);
3306 if (worker == NULL)
3307 return -ENOMEM;
3308
3309 worker->stats = stats;
3310 rc = mwl8k_queue_work(hw, &worker->header,
3311 priv->config_wq, mwl8k_get_stats_wt);
3312
3313 kfree(worker);
3314 if (rc == -ETIMEDOUT) {
3315 printk(KERN_ERR "%s() timed out\n", __func__);
3316 rc = -EINVAL;
3317 }
3318
3319 return rc;
3320}
3321
3322static const struct ieee80211_ops mwl8k_ops = {
3323 .tx = mwl8k_tx,
3324 .start = mwl8k_start,
3325 .stop = mwl8k_stop,
3326 .add_interface = mwl8k_add_interface,
3327 .remove_interface = mwl8k_remove_interface,
3328 .config = mwl8k_config,
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003329 .bss_info_changed = mwl8k_bss_info_changed,
Johannes Berg3ac64be2009-08-17 16:16:53 +02003330 .prepare_multicast = mwl8k_prepare_multicast,
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003331 .configure_filter = mwl8k_configure_filter,
3332 .set_rts_threshold = mwl8k_set_rts_threshold,
3333 .conf_tx = mwl8k_conf_tx,
3334 .get_tx_stats = mwl8k_get_tx_stats,
3335 .get_stats = mwl8k_get_stats,
3336};
3337
3338static void mwl8k_tx_reclaim_handler(unsigned long data)
3339{
3340 int i;
3341 struct ieee80211_hw *hw = (struct ieee80211_hw *) data;
3342 struct mwl8k_priv *priv = hw->priv;
3343
3344 spin_lock_bh(&priv->tx_lock);
3345 for (i = 0; i < MWL8K_TX_QUEUES; i++)
3346 mwl8k_txq_reclaim(hw, i, 0);
3347
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02003348 if (priv->tx_wait != NULL && mwl8k_txq_busy(priv) == 0) {
3349 complete(priv->tx_wait);
3350 priv->tx_wait = NULL;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003351 }
3352 spin_unlock_bh(&priv->tx_lock);
3353}
3354
3355static void mwl8k_finalize_join_worker(struct work_struct *work)
3356{
3357 struct mwl8k_priv *priv =
3358 container_of(work, struct mwl8k_priv, finalize_join_worker);
3359 struct sk_buff *skb = priv->beacon_skb;
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02003360 u8 dtim = MWL8K_VIF(priv->vif)->bss_info.dtim_period;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003361
3362 mwl8k_finalize_join(priv->hw, skb->data, skb->len, dtim);
3363 dev_kfree_skb(skb);
3364
3365 priv->beacon_skb = NULL;
3366}
3367
3368static int __devinit mwl8k_probe(struct pci_dev *pdev,
3369 const struct pci_device_id *id)
3370{
3371 struct ieee80211_hw *hw;
3372 struct mwl8k_priv *priv;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003373 int rc;
3374 int i;
3375 u8 *fw;
3376
3377 rc = pci_enable_device(pdev);
3378 if (rc) {
3379 printk(KERN_ERR "%s: Cannot enable new PCI device\n",
3380 MWL8K_NAME);
3381 return rc;
3382 }
3383
3384 rc = pci_request_regions(pdev, MWL8K_NAME);
3385 if (rc) {
3386 printk(KERN_ERR "%s: Cannot obtain PCI resources\n",
3387 MWL8K_NAME);
3388 return rc;
3389 }
3390
3391 pci_set_master(pdev);
3392
3393 hw = ieee80211_alloc_hw(sizeof(*priv), &mwl8k_ops);
3394 if (hw == NULL) {
3395 printk(KERN_ERR "%s: ieee80211 alloc failed\n", MWL8K_NAME);
3396 rc = -ENOMEM;
3397 goto err_free_reg;
3398 }
3399
3400 priv = hw->priv;
3401 priv->hw = hw;
3402 priv->pdev = pdev;
3403 priv->hostcmd_wait = NULL;
3404 priv->tx_wait = NULL;
3405 priv->inconfig = false;
Lennert Buytenhek0439b1f2009-07-16 12:34:02 +02003406 priv->wmm_enabled = false;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003407 priv->pending_tx_pkts = 0;
3408 strncpy(priv->name, MWL8K_NAME, sizeof(priv->name));
3409
3410 spin_lock_init(&priv->fw_lock);
3411
3412 SET_IEEE80211_DEV(hw, &pdev->dev);
3413 pci_set_drvdata(pdev, hw);
3414
3415 priv->regs = pci_iomap(pdev, 1, 0x10000);
3416 if (priv->regs == NULL) {
3417 printk(KERN_ERR "%s: Cannot map device memory\n", priv->name);
3418 goto err_iounmap;
3419 }
3420
3421 memcpy(priv->channels, mwl8k_channels, sizeof(mwl8k_channels));
3422 priv->band.band = IEEE80211_BAND_2GHZ;
3423 priv->band.channels = priv->channels;
3424 priv->band.n_channels = ARRAY_SIZE(mwl8k_channels);
3425 priv->band.bitrates = priv->rates;
3426 priv->band.n_bitrates = ARRAY_SIZE(mwl8k_rates);
3427 hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
3428
3429 BUILD_BUG_ON(sizeof(priv->rates) != sizeof(mwl8k_rates));
3430 memcpy(priv->rates, mwl8k_rates, sizeof(mwl8k_rates));
3431
3432 /*
3433 * Extra headroom is the size of the required DMA header
3434 * minus the size of the smallest 802.11 frame (CTS frame).
3435 */
3436 hw->extra_tx_headroom =
3437 sizeof(struct mwl8k_dma_data) - sizeof(struct ieee80211_cts);
3438
3439 hw->channel_change_time = 10;
3440
3441 hw->queues = MWL8K_TX_QUEUES;
3442
3443 hw->wiphy->interface_modes =
3444 BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_MONITOR);
3445
3446 /* Set rssi and noise values to dBm */
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02003447 hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003448 hw->vif_data_size = sizeof(struct mwl8k_vif);
3449 priv->vif = NULL;
3450
3451 /* Set default radio state and preamble */
Lennert Buytenhekc46563b2009-07-16 12:14:58 +02003452 priv->radio_on = 0;
Lennert Buytenhek68ce3882009-07-16 12:26:57 +02003453 priv->radio_short_preamble = 0;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003454
3455 /* Finalize join worker */
3456 INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker);
3457
3458 /* TX reclaim tasklet */
3459 tasklet_init(&priv->tx_reclaim_task,
3460 mwl8k_tx_reclaim_handler, (unsigned long)hw);
3461 tasklet_disable(&priv->tx_reclaim_task);
3462
3463 /* Config workthread */
3464 priv->config_wq = create_singlethread_workqueue("mwl8k_config");
3465 if (priv->config_wq == NULL)
3466 goto err_iounmap;
3467
3468 /* Power management cookie */
3469 priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma);
3470 if (priv->cookie == NULL)
3471 goto err_iounmap;
3472
3473 rc = mwl8k_rxq_init(hw, 0);
3474 if (rc)
3475 goto err_iounmap;
3476 rxq_refill(hw, 0, INT_MAX);
3477
3478 spin_lock_init(&priv->tx_lock);
3479
3480 for (i = 0; i < MWL8K_TX_QUEUES; i++) {
3481 rc = mwl8k_txq_init(hw, i);
3482 if (rc)
3483 goto err_free_queues;
3484 }
3485
3486 iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
Lennert Buytenhekc23b5a62009-07-16 13:49:55 +02003487 iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003488 iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL);
3489 iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
3490
3491 rc = request_irq(priv->pdev->irq, &mwl8k_interrupt,
3492 IRQF_SHARED, MWL8K_NAME, hw);
3493 if (rc) {
3494 printk(KERN_ERR "%s: failed to register IRQ handler\n",
3495 priv->name);
3496 goto err_free_queues;
3497 }
3498
3499 /* Reset firmware and hardware */
3500 mwl8k_hw_reset(priv);
3501
3502 /* Ask userland hotplug daemon for the device firmware */
3503 rc = mwl8k_request_firmware(priv, (u32)id->driver_data);
3504 if (rc) {
3505 printk(KERN_ERR "%s: Firmware files not found\n", priv->name);
3506 goto err_free_irq;
3507 }
3508
3509 /* Load firmware into hardware */
3510 rc = mwl8k_load_firmware(priv);
3511 if (rc) {
3512 printk(KERN_ERR "%s: Cannot start firmware\n", priv->name);
3513 goto err_stop_firmware;
3514 }
3515
3516 /* Reclaim memory once firmware is successfully loaded */
3517 mwl8k_release_firmware(priv);
3518
3519 /*
3520 * Temporarily enable interrupts. Initial firmware host
3521 * commands use interrupts and avoids polling. Disable
3522 * interrupts when done.
3523 */
Lennert Buytenhekc23b5a62009-07-16 13:49:55 +02003524 iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003525
3526 /* Get config data, mac addrs etc */
3527 rc = mwl8k_cmd_get_hw_spec(hw);
3528 if (rc) {
3529 printk(KERN_ERR "%s: Cannot initialise firmware\n", priv->name);
3530 goto err_stop_firmware;
3531 }
3532
3533 /* Turn radio off */
Lennert Buytenhekc46563b2009-07-16 12:14:58 +02003534 rc = mwl8k_cmd_802_11_radio_disable(hw);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003535 if (rc) {
3536 printk(KERN_ERR "%s: Cannot disable\n", priv->name);
3537 goto err_stop_firmware;
3538 }
3539
3540 /* Disable interrupts */
3541 spin_lock_irq(&priv->tx_lock);
3542 iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
3543 spin_unlock_irq(&priv->tx_lock);
3544 free_irq(priv->pdev->irq, hw);
3545
3546 rc = ieee80211_register_hw(hw);
3547 if (rc) {
3548 printk(KERN_ERR "%s: Cannot register device\n", priv->name);
3549 goto err_stop_firmware;
3550 }
3551
3552 fw = (u8 *)&priv->fw_rev;
3553 printk(KERN_INFO "%s: 88W%u %s\n", priv->name, priv->part_num,
3554 MWL8K_DESC);
3555 printk(KERN_INFO "%s: Driver Ver:%s Firmware Ver:%u.%u.%u.%u\n",
3556 priv->name, MWL8K_VERSION, fw[3], fw[2], fw[1], fw[0]);
Johannes Berge91d8332009-07-15 17:21:41 +02003557 printk(KERN_INFO "%s: MAC Address: %pM\n", priv->name,
3558 hw->wiphy->perm_addr);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003559
3560 return 0;
3561
3562err_stop_firmware:
3563 mwl8k_hw_reset(priv);
3564 mwl8k_release_firmware(priv);
3565
3566err_free_irq:
3567 spin_lock_irq(&priv->tx_lock);
3568 iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
3569 spin_unlock_irq(&priv->tx_lock);
3570 free_irq(priv->pdev->irq, hw);
3571
3572err_free_queues:
3573 for (i = 0; i < MWL8K_TX_QUEUES; i++)
3574 mwl8k_txq_deinit(hw, i);
3575 mwl8k_rxq_deinit(hw, 0);
3576
3577err_iounmap:
3578 if (priv->cookie != NULL)
3579 pci_free_consistent(priv->pdev, 4,
3580 priv->cookie, priv->cookie_dma);
3581
3582 if (priv->regs != NULL)
3583 pci_iounmap(pdev, priv->regs);
3584
3585 if (priv->config_wq != NULL)
3586 destroy_workqueue(priv->config_wq);
3587
3588 pci_set_drvdata(pdev, NULL);
3589 ieee80211_free_hw(hw);
3590
3591err_free_reg:
3592 pci_release_regions(pdev);
3593 pci_disable_device(pdev);
3594
3595 return rc;
3596}
3597
Joerg Albert230f7af2009-04-18 02:10:45 +02003598static void __devexit mwl8k_shutdown(struct pci_dev *pdev)
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003599{
3600 printk(KERN_ERR "===>%s(%u)\n", __func__, __LINE__);
3601}
3602
Joerg Albert230f7af2009-04-18 02:10:45 +02003603static void __devexit mwl8k_remove(struct pci_dev *pdev)
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003604{
3605 struct ieee80211_hw *hw = pci_get_drvdata(pdev);
3606 struct mwl8k_priv *priv;
3607 int i;
3608
3609 if (hw == NULL)
3610 return;
3611 priv = hw->priv;
3612
3613 ieee80211_stop_queues(hw);
3614
Lennert Buytenhek60aa5692009-08-03 21:59:09 +02003615 ieee80211_unregister_hw(hw);
3616
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003617 /* Remove tx reclaim tasklet */
3618 tasklet_kill(&priv->tx_reclaim_task);
3619
3620 /* Stop config thread */
3621 destroy_workqueue(priv->config_wq);
3622
3623 /* Stop hardware */
3624 mwl8k_hw_reset(priv);
3625
3626 /* Return all skbs to mac80211 */
3627 for (i = 0; i < MWL8K_TX_QUEUES; i++)
3628 mwl8k_txq_reclaim(hw, i, 1);
3629
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003630 for (i = 0; i < MWL8K_TX_QUEUES; i++)
3631 mwl8k_txq_deinit(hw, i);
3632
3633 mwl8k_rxq_deinit(hw, 0);
3634
3635 pci_free_consistent(priv->pdev, 4,
3636 priv->cookie, priv->cookie_dma);
3637
3638 pci_iounmap(pdev, priv->regs);
3639 pci_set_drvdata(pdev, NULL);
3640 ieee80211_free_hw(hw);
3641 pci_release_regions(pdev);
3642 pci_disable_device(pdev);
3643}
3644
3645static struct pci_driver mwl8k_driver = {
3646 .name = MWL8K_NAME,
3647 .id_table = mwl8k_table,
3648 .probe = mwl8k_probe,
3649 .remove = __devexit_p(mwl8k_remove),
3650 .shutdown = __devexit_p(mwl8k_shutdown),
3651};
3652
3653static int __init mwl8k_init(void)
3654{
3655 return pci_register_driver(&mwl8k_driver);
3656}
3657
3658static void __exit mwl8k_exit(void)
3659{
3660 pci_unregister_driver(&mwl8k_driver);
3661}
3662
3663module_init(mwl8k_init);
3664module_exit(mwl8k_exit);