blob: a40434b5572b4cb3468a6bef4ca41f875717e62d [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 Buytenheka66098d2009-03-10 10:13:33 +01001616static int mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw,
1617 int mc_count,
1618 struct dev_addr_list *mclist)
1619{
1620 struct mwl8k_cmd_mac_multicast_adr *cmd;
1621 int index = 0;
1622 int rc;
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02001623 int size = sizeof(*cmd) + mc_count * ETH_ALEN;
1624
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001625 cmd = kzalloc(size, GFP_KERNEL);
1626 if (cmd == NULL)
1627 return -ENOMEM;
1628
1629 cmd->header.code = cpu_to_le16(MWL8K_CMD_MAC_MULTICAST_ADR);
1630 cmd->header.length = cpu_to_le16(size);
1631 cmd->action = cpu_to_le16(MWL8K_ENABLE_RX_MULTICAST);
1632 cmd->numaddr = cpu_to_le16(mc_count);
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02001633
1634 while (index < mc_count && mclist) {
Lennert Buytenhekd89173f2009-07-16 09:54:27 +02001635 if (mclist->da_addrlen != ETH_ALEN) {
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001636 rc = -EINVAL;
1637 goto mwl8k_cmd_mac_multicast_adr_exit;
1638 }
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02001639 memcpy(cmd->addr[index++], mclist->da_addr, ETH_ALEN);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001640 mclist = mclist->next;
1641 }
1642
1643 rc = mwl8k_post_cmd(hw, &cmd->header);
1644
1645mwl8k_cmd_mac_multicast_adr_exit:
1646 kfree(cmd);
1647 return rc;
1648}
1649
1650/*
1651 * CMD_802_11_GET_STAT.
1652 */
1653struct mwl8k_cmd_802_11_get_stat {
1654 struct mwl8k_cmd_pkt header;
1655 __le16 action;
1656 __le32 stats[64];
1657} __attribute__((packed));
1658
1659#define MWL8K_STAT_ACK_FAILURE 9
1660#define MWL8K_STAT_RTS_FAILURE 12
1661#define MWL8K_STAT_FCS_ERROR 24
1662#define MWL8K_STAT_RTS_SUCCESS 11
1663
1664static int mwl8k_cmd_802_11_get_stat(struct ieee80211_hw *hw,
1665 struct ieee80211_low_level_stats *stats)
1666{
1667 struct mwl8k_cmd_802_11_get_stat *cmd;
1668 int rc;
1669
1670 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1671 if (cmd == NULL)
1672 return -ENOMEM;
1673
1674 cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_STAT);
1675 cmd->header.length = cpu_to_le16(sizeof(*cmd));
1676 cmd->action = cpu_to_le16(MWL8K_CMD_GET);
1677
1678 rc = mwl8k_post_cmd(hw, &cmd->header);
1679 if (!rc) {
1680 stats->dot11ACKFailureCount =
1681 le32_to_cpu(cmd->stats[MWL8K_STAT_ACK_FAILURE]);
1682 stats->dot11RTSFailureCount =
1683 le32_to_cpu(cmd->stats[MWL8K_STAT_RTS_FAILURE]);
1684 stats->dot11FCSErrorCount =
1685 le32_to_cpu(cmd->stats[MWL8K_STAT_FCS_ERROR]);
1686 stats->dot11RTSSuccessCount =
1687 le32_to_cpu(cmd->stats[MWL8K_STAT_RTS_SUCCESS]);
1688 }
1689 kfree(cmd);
1690
1691 return rc;
1692}
1693
1694/*
1695 * CMD_802_11_RADIO_CONTROL.
1696 */
1697struct mwl8k_cmd_802_11_radio_control {
1698 struct mwl8k_cmd_pkt header;
1699 __le16 action;
1700 __le16 control;
1701 __le16 radio_on;
1702} __attribute__((packed));
1703
Lennert Buytenhekc46563b2009-07-16 12:14:58 +02001704static int
1705mwl8k_cmd_802_11_radio_control(struct ieee80211_hw *hw, bool enable, bool force)
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001706{
1707 struct mwl8k_priv *priv = hw->priv;
1708 struct mwl8k_cmd_802_11_radio_control *cmd;
1709 int rc;
1710
Lennert Buytenhekc46563b2009-07-16 12:14:58 +02001711 if (enable == priv->radio_on && !force)
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001712 return 0;
1713
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001714 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1715 if (cmd == NULL)
1716 return -ENOMEM;
1717
1718 cmd->header.code = cpu_to_le16(MWL8K_CMD_RADIO_CONTROL);
1719 cmd->header.length = cpu_to_le16(sizeof(*cmd));
1720 cmd->action = cpu_to_le16(MWL8K_CMD_SET);
Lennert Buytenhek68ce3882009-07-16 12:26:57 +02001721 cmd->control = cpu_to_le16(priv->radio_short_preamble ? 3 : 1);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001722 cmd->radio_on = cpu_to_le16(enable ? 0x0001 : 0x0000);
1723
1724 rc = mwl8k_post_cmd(hw, &cmd->header);
1725 kfree(cmd);
1726
1727 if (!rc)
Lennert Buytenhekc46563b2009-07-16 12:14:58 +02001728 priv->radio_on = enable;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001729
1730 return rc;
1731}
1732
Lennert Buytenhekc46563b2009-07-16 12:14:58 +02001733static int mwl8k_cmd_802_11_radio_disable(struct ieee80211_hw *hw)
1734{
1735 return mwl8k_cmd_802_11_radio_control(hw, 0, 0);
1736}
1737
1738static int mwl8k_cmd_802_11_radio_enable(struct ieee80211_hw *hw)
1739{
1740 return mwl8k_cmd_802_11_radio_control(hw, 1, 0);
1741}
1742
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001743static int
1744mwl8k_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble)
1745{
1746 struct mwl8k_priv *priv;
1747
1748 if (hw == NULL || hw->priv == NULL)
1749 return -EINVAL;
1750 priv = hw->priv;
1751
Lennert Buytenhek68ce3882009-07-16 12:26:57 +02001752 priv->radio_short_preamble = short_preamble;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001753
Lennert Buytenhekc46563b2009-07-16 12:14:58 +02001754 return mwl8k_cmd_802_11_radio_control(hw, 1, 1);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001755}
1756
1757/*
1758 * CMD_802_11_RF_TX_POWER.
1759 */
1760#define MWL8K_TX_POWER_LEVEL_TOTAL 8
1761
1762struct mwl8k_cmd_802_11_rf_tx_power {
1763 struct mwl8k_cmd_pkt header;
1764 __le16 action;
1765 __le16 support_level;
1766 __le16 current_level;
1767 __le16 reserved;
1768 __le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL];
1769} __attribute__((packed));
1770
1771static int mwl8k_cmd_802_11_rf_tx_power(struct ieee80211_hw *hw, int dBm)
1772{
1773 struct mwl8k_cmd_802_11_rf_tx_power *cmd;
1774 int rc;
1775
1776 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1777 if (cmd == NULL)
1778 return -ENOMEM;
1779
1780 cmd->header.code = cpu_to_le16(MWL8K_CMD_RF_TX_POWER);
1781 cmd->header.length = cpu_to_le16(sizeof(*cmd));
1782 cmd->action = cpu_to_le16(MWL8K_CMD_SET);
1783 cmd->support_level = cpu_to_le16(dBm);
1784
1785 rc = mwl8k_post_cmd(hw, &cmd->header);
1786 kfree(cmd);
1787
1788 return rc;
1789}
1790
1791/*
1792 * CMD_SET_PRE_SCAN.
1793 */
1794struct mwl8k_cmd_set_pre_scan {
1795 struct mwl8k_cmd_pkt header;
1796} __attribute__((packed));
1797
1798static int mwl8k_cmd_set_pre_scan(struct ieee80211_hw *hw)
1799{
1800 struct mwl8k_cmd_set_pre_scan *cmd;
1801 int rc;
1802
1803 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1804 if (cmd == NULL)
1805 return -ENOMEM;
1806
1807 cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_PRE_SCAN);
1808 cmd->header.length = cpu_to_le16(sizeof(*cmd));
1809
1810 rc = mwl8k_post_cmd(hw, &cmd->header);
1811 kfree(cmd);
1812
1813 return rc;
1814}
1815
1816/*
1817 * CMD_SET_POST_SCAN.
1818 */
1819struct mwl8k_cmd_set_post_scan {
1820 struct mwl8k_cmd_pkt header;
1821 __le32 isibss;
Lennert Buytenhekd89173f2009-07-16 09:54:27 +02001822 __u8 bssid[ETH_ALEN];
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001823} __attribute__((packed));
1824
1825static int
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02001826mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, __u8 *mac)
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001827{
1828 struct mwl8k_cmd_set_post_scan *cmd;
1829 int rc;
1830
1831 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1832 if (cmd == NULL)
1833 return -ENOMEM;
1834
1835 cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_POST_SCAN);
1836 cmd->header.length = cpu_to_le16(sizeof(*cmd));
1837 cmd->isibss = 0;
Lennert Buytenhekd89173f2009-07-16 09:54:27 +02001838 memcpy(cmd->bssid, mac, ETH_ALEN);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001839
1840 rc = mwl8k_post_cmd(hw, &cmd->header);
1841 kfree(cmd);
1842
1843 return rc;
1844}
1845
1846/*
1847 * CMD_SET_RF_CHANNEL.
1848 */
1849struct mwl8k_cmd_set_rf_channel {
1850 struct mwl8k_cmd_pkt header;
1851 __le16 action;
1852 __u8 current_channel;
1853 __le32 channel_flags;
1854} __attribute__((packed));
1855
1856static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw,
1857 struct ieee80211_channel *channel)
1858{
1859 struct mwl8k_cmd_set_rf_channel *cmd;
1860 int rc;
1861
1862 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1863 if (cmd == NULL)
1864 return -ENOMEM;
1865
1866 cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RF_CHANNEL);
1867 cmd->header.length = cpu_to_le16(sizeof(*cmd));
1868 cmd->action = cpu_to_le16(MWL8K_CMD_SET);
1869 cmd->current_channel = channel->hw_value;
1870 if (channel->band == IEEE80211_BAND_2GHZ)
1871 cmd->channel_flags = cpu_to_le32(0x00000081);
1872 else
1873 cmd->channel_flags = cpu_to_le32(0x00000000);
1874
1875 rc = mwl8k_post_cmd(hw, &cmd->header);
1876 kfree(cmd);
1877
1878 return rc;
1879}
1880
1881/*
1882 * CMD_SET_SLOT.
1883 */
1884struct mwl8k_cmd_set_slot {
1885 struct mwl8k_cmd_pkt header;
1886 __le16 action;
1887 __u8 short_slot;
1888} __attribute__((packed));
1889
Lennert Buytenhek5539bb52009-07-16 16:06:53 +02001890static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, bool short_slot_time)
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001891{
1892 struct mwl8k_cmd_set_slot *cmd;
1893 int rc;
1894
1895 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1896 if (cmd == NULL)
1897 return -ENOMEM;
1898
1899 cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_SLOT);
1900 cmd->header.length = cpu_to_le16(sizeof(*cmd));
1901 cmd->action = cpu_to_le16(MWL8K_CMD_SET);
Lennert Buytenhek5539bb52009-07-16 16:06:53 +02001902 cmd->short_slot = short_slot_time;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001903
1904 rc = mwl8k_post_cmd(hw, &cmd->header);
1905 kfree(cmd);
1906
1907 return rc;
1908}
1909
1910/*
1911 * CMD_MIMO_CONFIG.
1912 */
1913struct mwl8k_cmd_mimo_config {
1914 struct mwl8k_cmd_pkt header;
1915 __le32 action;
1916 __u8 rx_antenna_map;
1917 __u8 tx_antenna_map;
1918} __attribute__((packed));
1919
1920static int mwl8k_cmd_mimo_config(struct ieee80211_hw *hw, __u8 rx, __u8 tx)
1921{
1922 struct mwl8k_cmd_mimo_config *cmd;
1923 int rc;
1924
1925 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1926 if (cmd == NULL)
1927 return -ENOMEM;
1928
1929 cmd->header.code = cpu_to_le16(MWL8K_CMD_MIMO_CONFIG);
1930 cmd->header.length = cpu_to_le16(sizeof(*cmd));
1931 cmd->action = cpu_to_le32((u32)MWL8K_CMD_SET);
1932 cmd->rx_antenna_map = rx;
1933 cmd->tx_antenna_map = tx;
1934
1935 rc = mwl8k_post_cmd(hw, &cmd->header);
1936 kfree(cmd);
1937
1938 return rc;
1939}
1940
1941/*
1942 * CMD_ENABLE_SNIFFER.
1943 */
1944struct mwl8k_cmd_enable_sniffer {
1945 struct mwl8k_cmd_pkt header;
1946 __le32 action;
1947} __attribute__((packed));
1948
1949static int mwl8k_enable_sniffer(struct ieee80211_hw *hw, bool enable)
1950{
1951 struct mwl8k_cmd_enable_sniffer *cmd;
1952 int rc;
1953
1954 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1955 if (cmd == NULL)
1956 return -ENOMEM;
1957
1958 cmd->header.code = cpu_to_le16(MWL8K_CMD_ENABLE_SNIFFER);
1959 cmd->header.length = cpu_to_le16(sizeof(*cmd));
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02001960 cmd->action = cpu_to_le32(!!enable);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001961
1962 rc = mwl8k_post_cmd(hw, &cmd->header);
1963 kfree(cmd);
1964
1965 return rc;
1966}
1967
1968/*
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02001969 * CMD_SET_RATEADAPT_MODE.
Lennert Buytenheka66098d2009-03-10 10:13:33 +01001970 */
1971struct mwl8k_cmd_set_rate_adapt_mode {
1972 struct mwl8k_cmd_pkt header;
1973 __le16 action;
1974 __le16 mode;
1975} __attribute__((packed));
1976
1977static int mwl8k_cmd_setrateadaptmode(struct ieee80211_hw *hw, __u16 mode)
1978{
1979 struct mwl8k_cmd_set_rate_adapt_mode *cmd;
1980 int rc;
1981
1982 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1983 if (cmd == NULL)
1984 return -ENOMEM;
1985
1986 cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATEADAPT_MODE);
1987 cmd->header.length = cpu_to_le16(sizeof(*cmd));
1988 cmd->action = cpu_to_le16(MWL8K_CMD_SET);
1989 cmd->mode = cpu_to_le16(mode);
1990
1991 rc = mwl8k_post_cmd(hw, &cmd->header);
1992 kfree(cmd);
1993
1994 return rc;
1995}
1996
1997/*
1998 * CMD_SET_WMM_MODE.
1999 */
2000struct mwl8k_cmd_set_wmm {
2001 struct mwl8k_cmd_pkt header;
2002 __le16 action;
2003} __attribute__((packed));
2004
2005static int mwl8k_set_wmm(struct ieee80211_hw *hw, bool enable)
2006{
2007 struct mwl8k_priv *priv = hw->priv;
2008 struct mwl8k_cmd_set_wmm *cmd;
2009 int rc;
2010
2011 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
2012 if (cmd == NULL)
2013 return -ENOMEM;
2014
2015 cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_WMM_MODE);
2016 cmd->header.length = cpu_to_le16(sizeof(*cmd));
Lennert Buytenhek0439b1f2009-07-16 12:34:02 +02002017 cmd->action = cpu_to_le16(!!enable);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002018
2019 rc = mwl8k_post_cmd(hw, &cmd->header);
2020 kfree(cmd);
2021
2022 if (!rc)
Lennert Buytenhek0439b1f2009-07-16 12:34:02 +02002023 priv->wmm_enabled = enable;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002024
2025 return rc;
2026}
2027
2028/*
2029 * CMD_SET_RTS_THRESHOLD.
2030 */
2031struct mwl8k_cmd_rts_threshold {
2032 struct mwl8k_cmd_pkt header;
2033 __le16 action;
2034 __le16 threshold;
2035} __attribute__((packed));
2036
2037static int mwl8k_rts_threshold(struct ieee80211_hw *hw,
2038 u16 action, u16 *threshold)
2039{
2040 struct mwl8k_cmd_rts_threshold *cmd;
2041 int rc;
2042
2043 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
2044 if (cmd == NULL)
2045 return -ENOMEM;
2046
2047 cmd->header.code = cpu_to_le16(MWL8K_CMD_RTS_THRESHOLD);
2048 cmd->header.length = cpu_to_le16(sizeof(*cmd));
2049 cmd->action = cpu_to_le16(action);
2050 cmd->threshold = cpu_to_le16(*threshold);
2051
2052 rc = mwl8k_post_cmd(hw, &cmd->header);
2053 kfree(cmd);
2054
2055 return rc;
2056}
2057
2058/*
2059 * CMD_SET_EDCA_PARAMS.
2060 */
2061struct mwl8k_cmd_set_edca_params {
2062 struct mwl8k_cmd_pkt header;
2063
2064 /* See MWL8K_SET_EDCA_XXX below */
2065 __le16 action;
2066
2067 /* TX opportunity in units of 32 us */
2068 __le16 txop;
2069
2070 /* Log exponent of max contention period: 0...15*/
2071 __u8 log_cw_max;
2072
2073 /* Log exponent of min contention period: 0...15 */
2074 __u8 log_cw_min;
2075
2076 /* Adaptive interframe spacing in units of 32us */
2077 __u8 aifs;
2078
2079 /* TX queue to configure */
2080 __u8 txq;
2081} __attribute__((packed));
2082
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002083#define MWL8K_SET_EDCA_CW 0x01
2084#define MWL8K_SET_EDCA_TXOP 0x02
2085#define MWL8K_SET_EDCA_AIFS 0x04
2086
2087#define MWL8K_SET_EDCA_ALL (MWL8K_SET_EDCA_CW | \
2088 MWL8K_SET_EDCA_TXOP | \
2089 MWL8K_SET_EDCA_AIFS)
2090
2091static int
2092mwl8k_set_edca_params(struct ieee80211_hw *hw, __u8 qnum,
2093 __u16 cw_min, __u16 cw_max,
2094 __u8 aifs, __u16 txop)
2095{
2096 struct mwl8k_cmd_set_edca_params *cmd;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002097 int rc;
2098
2099 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
2100 if (cmd == NULL)
2101 return -ENOMEM;
2102
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002103 cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_EDCA_PARAMS);
2104 cmd->header.length = cpu_to_le16(sizeof(*cmd));
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002105 cmd->action = cpu_to_le16(MWL8K_SET_EDCA_ALL);
2106 cmd->txop = cpu_to_le16(txop);
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02002107 cmd->log_cw_max = (u8)ilog2(cw_max + 1);
2108 cmd->log_cw_min = (u8)ilog2(cw_min + 1);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002109 cmd->aifs = aifs;
2110 cmd->txq = qnum;
2111
2112 rc = mwl8k_post_cmd(hw, &cmd->header);
2113 kfree(cmd);
2114
2115 return rc;
2116}
2117
2118/*
2119 * CMD_FINALIZE_JOIN.
2120 */
2121
2122/* FJ beacon buffer size is compiled into the firmware. */
2123#define MWL8K_FJ_BEACON_MAXLEN 128
2124
2125struct mwl8k_cmd_finalize_join {
2126 struct mwl8k_cmd_pkt header;
2127 __le32 sleep_interval; /* Number of beacon periods to sleep */
2128 __u8 beacon_data[MWL8K_FJ_BEACON_MAXLEN];
2129} __attribute__((packed));
2130
2131static int mwl8k_finalize_join(struct ieee80211_hw *hw, void *frame,
2132 __u16 framelen, __u16 dtim)
2133{
2134 struct mwl8k_cmd_finalize_join *cmd;
2135 struct ieee80211_mgmt *payload = frame;
2136 u16 hdrlen;
2137 u32 payload_len;
2138 int rc;
2139
2140 if (frame == NULL)
2141 return -EINVAL;
2142
2143 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
2144 if (cmd == NULL)
2145 return -ENOMEM;
2146
2147 cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_FINALIZE_JOIN);
2148 cmd->header.length = cpu_to_le16(sizeof(*cmd));
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02002149 cmd->sleep_interval = cpu_to_le32(dtim ? dtim : 1);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002150
2151 hdrlen = ieee80211_hdrlen(payload->frame_control);
2152
2153 payload_len = framelen > hdrlen ? framelen - hdrlen : 0;
2154
2155 /* XXX TBD Might just have to abort and return an error */
2156 if (payload_len > MWL8K_FJ_BEACON_MAXLEN)
2157 printk(KERN_ERR "%s(): WARNING: Incomplete beacon "
2158 "sent to firmware. Sz=%u MAX=%u\n", __func__,
2159 payload_len, MWL8K_FJ_BEACON_MAXLEN);
2160
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02002161 if (payload_len > MWL8K_FJ_BEACON_MAXLEN)
2162 payload_len = MWL8K_FJ_BEACON_MAXLEN;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002163
2164 if (payload && payload_len)
2165 memcpy(cmd->beacon_data, &payload->u.beacon, payload_len);
2166
2167 rc = mwl8k_post_cmd(hw, &cmd->header);
2168 kfree(cmd);
2169 return rc;
2170}
2171
2172/*
2173 * CMD_UPDATE_STADB.
2174 */
2175struct mwl8k_cmd_update_sta_db {
2176 struct mwl8k_cmd_pkt header;
2177
2178 /* See STADB_ACTION_TYPE */
2179 __le32 action;
2180
2181 /* Peer MAC address */
Lennert Buytenhekd89173f2009-07-16 09:54:27 +02002182 __u8 peer_addr[ETH_ALEN];
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002183
2184 __le32 reserved;
2185
2186 /* Peer info - valid during add/update. */
2187 struct peer_capability_info peer_info;
2188} __attribute__((packed));
2189
2190static int mwl8k_cmd_update_sta_db(struct ieee80211_hw *hw,
2191 struct ieee80211_vif *vif, __u32 action)
2192{
2193 struct mwl8k_vif *mv_vif = MWL8K_VIF(vif);
2194 struct ieee80211_bss_conf *info = &mv_vif->bss_info;
2195 struct mwl8k_cmd_update_sta_db *cmd;
2196 struct peer_capability_info *peer_info;
2197 struct ieee80211_rate *bitrates = mv_vif->legacy_rates;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002198 int rc;
2199 __u8 count, *rates;
2200
2201 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
2202 if (cmd == NULL)
2203 return -ENOMEM;
2204
2205 cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB);
2206 cmd->header.length = cpu_to_le16(sizeof(*cmd));
2207
2208 cmd->action = cpu_to_le32(action);
2209 peer_info = &cmd->peer_info;
Lennert Buytenhekd89173f2009-07-16 09:54:27 +02002210 memcpy(cmd->peer_addr, mv_vif->bssid, ETH_ALEN);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002211
2212 switch (action) {
2213 case MWL8K_STA_DB_ADD_ENTRY:
2214 case MWL8K_STA_DB_MODIFY_ENTRY:
2215 /* Build peer_info block */
2216 peer_info->peer_type = MWL8K_PEER_TYPE_ACCESSPOINT;
2217 peer_info->basic_caps = cpu_to_le16(info->assoc_capability);
2218 peer_info->interop = 1;
2219 peer_info->amsdu_enabled = 0;
2220
2221 rates = peer_info->legacy_rates;
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02002222 for (count = 0; count < mv_vif->legacy_nrates; count++)
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002223 rates[count] = bitrates[count].hw_value;
2224
2225 rc = mwl8k_post_cmd(hw, &cmd->header);
2226 if (rc == 0)
2227 mv_vif->peer_id = peer_info->station_id;
2228
2229 break;
2230
2231 case MWL8K_STA_DB_DEL_ENTRY:
2232 case MWL8K_STA_DB_FLUSH:
2233 default:
2234 rc = mwl8k_post_cmd(hw, &cmd->header);
2235 if (rc == 0)
2236 mv_vif->peer_id = 0;
2237 break;
2238 }
2239 kfree(cmd);
2240
2241 return rc;
2242}
2243
2244/*
2245 * CMD_SET_AID.
2246 */
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002247#define MWL8K_RATE_INDEX_MAX_ARRAY 14
2248
2249#define MWL8K_FRAME_PROT_DISABLED 0x00
2250#define MWL8K_FRAME_PROT_11G 0x07
2251#define MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY 0x02
2252#define MWL8K_FRAME_PROT_11N_HT_ALL 0x06
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002253
2254struct mwl8k_cmd_update_set_aid {
2255 struct mwl8k_cmd_pkt header;
2256 __le16 aid;
2257
2258 /* AP's MAC address (BSSID) */
Lennert Buytenhekd89173f2009-07-16 09:54:27 +02002259 __u8 bssid[ETH_ALEN];
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002260 __le16 protection_mode;
2261 __u8 supp_rates[MWL8K_RATE_INDEX_MAX_ARRAY];
2262} __attribute__((packed));
2263
2264static int mwl8k_cmd_set_aid(struct ieee80211_hw *hw,
2265 struct ieee80211_vif *vif)
2266{
2267 struct mwl8k_vif *mv_vif = MWL8K_VIF(vif);
2268 struct ieee80211_bss_conf *info = &mv_vif->bss_info;
2269 struct mwl8k_cmd_update_set_aid *cmd;
2270 struct ieee80211_rate *bitrates = mv_vif->legacy_rates;
2271 int count;
2272 u16 prot_mode;
2273 int rc;
2274
2275 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
2276 if (cmd == NULL)
2277 return -ENOMEM;
2278
2279 cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_AID);
2280 cmd->header.length = cpu_to_le16(sizeof(*cmd));
2281 cmd->aid = cpu_to_le16(info->aid);
2282
Lennert Buytenhekd89173f2009-07-16 09:54:27 +02002283 memcpy(cmd->bssid, mv_vif->bssid, ETH_ALEN);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002284
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002285 if (info->use_cts_prot) {
2286 prot_mode = MWL8K_FRAME_PROT_11G;
2287 } else {
Johannes Berg9ed6bcc2009-05-08 20:47:39 +02002288 switch (info->ht_operation_mode &
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002289 IEEE80211_HT_OP_MODE_PROTECTION) {
2290 case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
2291 prot_mode = MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY;
2292 break;
2293 case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
2294 prot_mode = MWL8K_FRAME_PROT_11N_HT_ALL;
2295 break;
2296 default:
2297 prot_mode = MWL8K_FRAME_PROT_DISABLED;
2298 break;
2299 }
2300 }
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002301 cmd->protection_mode = cpu_to_le16(prot_mode);
2302
2303 for (count = 0; count < mv_vif->legacy_nrates; count++)
2304 cmd->supp_rates[count] = bitrates[count].hw_value;
2305
2306 rc = mwl8k_post_cmd(hw, &cmd->header);
2307 kfree(cmd);
2308
2309 return rc;
2310}
2311
2312/*
2313 * CMD_SET_RATE.
2314 */
2315struct mwl8k_cmd_update_rateset {
2316 struct mwl8k_cmd_pkt header;
2317 __u8 legacy_rates[MWL8K_RATE_INDEX_MAX_ARRAY];
2318
2319 /* Bitmap for supported MCS codes. */
2320 __u8 mcs_set[MWL8K_IEEE_LEGACY_DATA_RATES];
2321 __u8 reserved[MWL8K_IEEE_LEGACY_DATA_RATES];
2322} __attribute__((packed));
2323
2324static int mwl8k_update_rateset(struct ieee80211_hw *hw,
2325 struct ieee80211_vif *vif)
2326{
2327 struct mwl8k_vif *mv_vif = MWL8K_VIF(vif);
2328 struct mwl8k_cmd_update_rateset *cmd;
2329 struct ieee80211_rate *bitrates = mv_vif->legacy_rates;
2330 int count;
2331 int rc;
2332
2333 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
2334 if (cmd == NULL)
2335 return -ENOMEM;
2336
2337 cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATE);
2338 cmd->header.length = cpu_to_le16(sizeof(*cmd));
2339
2340 for (count = 0; count < mv_vif->legacy_nrates; count++)
2341 cmd->legacy_rates[count] = bitrates[count].hw_value;
2342
2343 rc = mwl8k_post_cmd(hw, &cmd->header);
2344 kfree(cmd);
2345
2346 return rc;
2347}
2348
2349/*
2350 * CMD_USE_FIXED_RATE.
2351 */
2352#define MWL8K_RATE_TABLE_SIZE 8
2353#define MWL8K_UCAST_RATE 0
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002354#define MWL8K_USE_AUTO_RATE 0x0002
2355
2356struct mwl8k_rate_entry {
2357 /* Set to 1 if HT rate, 0 if legacy. */
2358 __le32 is_ht_rate;
2359
2360 /* Set to 1 to use retry_count field. */
2361 __le32 enable_retry;
2362
2363 /* Specified legacy rate or MCS. */
2364 __le32 rate;
2365
2366 /* Number of allowed retries. */
2367 __le32 retry_count;
2368} __attribute__((packed));
2369
2370struct mwl8k_rate_table {
2371 /* 1 to allow specified rate and below */
2372 __le32 allow_rate_drop;
2373 __le32 num_rates;
2374 struct mwl8k_rate_entry rate_entry[MWL8K_RATE_TABLE_SIZE];
2375} __attribute__((packed));
2376
2377struct mwl8k_cmd_use_fixed_rate {
2378 struct mwl8k_cmd_pkt header;
2379 __le32 action;
2380 struct mwl8k_rate_table rate_table;
2381
2382 /* Unicast, Broadcast or Multicast */
2383 __le32 rate_type;
2384 __le32 reserved1;
2385 __le32 reserved2;
2386} __attribute__((packed));
2387
2388static int mwl8k_cmd_use_fixed_rate(struct ieee80211_hw *hw,
2389 u32 action, u32 rate_type, struct mwl8k_rate_table *rate_table)
2390{
2391 struct mwl8k_cmd_use_fixed_rate *cmd;
2392 int count;
2393 int rc;
2394
2395 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
2396 if (cmd == NULL)
2397 return -ENOMEM;
2398
2399 cmd->header.code = cpu_to_le16(MWL8K_CMD_USE_FIXED_RATE);
2400 cmd->header.length = cpu_to_le16(sizeof(*cmd));
2401
2402 cmd->action = cpu_to_le32(action);
2403 cmd->rate_type = cpu_to_le32(rate_type);
2404
2405 if (rate_table != NULL) {
2406 /* Copy over each field manually so
2407 * that bitflipping can be done
2408 */
2409 cmd->rate_table.allow_rate_drop =
2410 cpu_to_le32(rate_table->allow_rate_drop);
2411 cmd->rate_table.num_rates =
2412 cpu_to_le32(rate_table->num_rates);
2413
2414 for (count = 0; count < rate_table->num_rates; count++) {
2415 struct mwl8k_rate_entry *dst =
2416 &cmd->rate_table.rate_entry[count];
2417 struct mwl8k_rate_entry *src =
2418 &rate_table->rate_entry[count];
2419
2420 dst->is_ht_rate = cpu_to_le32(src->is_ht_rate);
2421 dst->enable_retry = cpu_to_le32(src->enable_retry);
2422 dst->rate = cpu_to_le32(src->rate);
2423 dst->retry_count = cpu_to_le32(src->retry_count);
2424 }
2425 }
2426
2427 rc = mwl8k_post_cmd(hw, &cmd->header);
2428 kfree(cmd);
2429
2430 return rc;
2431}
2432
2433
2434/*
2435 * Interrupt handling.
2436 */
2437static irqreturn_t mwl8k_interrupt(int irq, void *dev_id)
2438{
2439 struct ieee80211_hw *hw = dev_id;
2440 struct mwl8k_priv *priv = hw->priv;
2441 u32 status;
2442
2443 status = ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
2444 iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
2445
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002446 if (!status)
2447 return IRQ_NONE;
2448
2449 if (status & MWL8K_A2H_INT_TX_DONE)
2450 tasklet_schedule(&priv->tx_reclaim_task);
2451
2452 if (status & MWL8K_A2H_INT_RX_READY) {
2453 while (rxq_process(hw, 0, 1))
2454 rxq_refill(hw, 0, 1);
2455 }
2456
2457 if (status & MWL8K_A2H_INT_OPC_DONE) {
2458 if (priv->hostcmd_wait != NULL) {
2459 complete(priv->hostcmd_wait);
2460 priv->hostcmd_wait = NULL;
2461 }
2462 }
2463
2464 if (status & MWL8K_A2H_INT_QUEUE_EMPTY) {
2465 if (!priv->inconfig &&
Lennert Buytenhekc46563b2009-07-16 12:14:58 +02002466 priv->radio_on &&
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002467 mwl8k_txq_busy(priv))
2468 mwl8k_tx_start(priv);
2469 }
2470
2471 return IRQ_HANDLED;
2472}
2473
2474
2475/*
2476 * Core driver operations.
2477 */
2478static int mwl8k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
2479{
2480 struct mwl8k_priv *priv = hw->priv;
2481 int index = skb_get_queue_mapping(skb);
2482 int rc;
2483
2484 if (priv->current_channel == NULL) {
2485 printk(KERN_DEBUG "%s: dropped TX frame since radio "
2486 "disabled\n", priv->name);
2487 dev_kfree_skb(skb);
2488 return NETDEV_TX_OK;
2489 }
2490
2491 rc = mwl8k_txq_xmit(hw, index, skb);
2492
2493 return rc;
2494}
2495
2496struct mwl8k_work_struct {
2497 /* Initialized by mwl8k_queue_work(). */
2498 struct work_struct wt;
2499
2500 /* Required field passed in to mwl8k_queue_work(). */
2501 struct ieee80211_hw *hw;
2502
2503 /* Required field passed in to mwl8k_queue_work(). */
2504 int (*wfunc)(struct work_struct *w);
2505
2506 /* Initialized by mwl8k_queue_work(). */
2507 struct completion *cmd_wait;
2508
2509 /* Result code. */
2510 int rc;
2511
2512 /*
2513 * Optional field. Refer to explanation of MWL8K_WQ_XXX_XXX
2514 * flags for explanation. Defaults to MWL8K_WQ_DEFAULT_OPTIONS.
2515 */
2516 u32 options;
2517
2518 /* Optional field. Defaults to MWL8K_CONFIG_TIMEOUT_MS. */
2519 unsigned long timeout_ms;
2520
2521 /* Optional field. Defaults to MWL8K_WQ_TXWAIT_ATTEMPTS. */
2522 u32 txwait_attempts;
2523
2524 /* Optional field. Defaults to MWL8K_TXWAIT_MS. */
2525 u32 tx_timeout_ms;
2526 u32 step;
2527};
2528
2529/* Flags controlling behavior of config queue requests */
2530
2531/* Caller spins while waiting for completion. */
2532#define MWL8K_WQ_SPIN 0x00000001
2533
2534/* Wait for TX queues to empty before proceeding with configuration. */
2535#define MWL8K_WQ_TX_WAIT_EMPTY 0x00000002
2536
2537/* Queue request and return immediately. */
2538#define MWL8K_WQ_POST_REQUEST 0x00000004
2539
2540/*
2541 * Caller sleeps and waits for task complete notification.
2542 * Do not use in atomic context.
2543 */
2544#define MWL8K_WQ_SLEEP 0x00000008
2545
2546/* Free work struct when task is done. */
2547#define MWL8K_WQ_FREE_WORKSTRUCT 0x00000010
2548
2549/*
2550 * Config request is queued and returns to caller imediately. Use
2551 * this in atomic context. Work struct is freed by mwl8k_queue_work()
2552 * when this flag is set.
2553 */
2554#define MWL8K_WQ_QUEUE_ONLY (MWL8K_WQ_POST_REQUEST | \
2555 MWL8K_WQ_FREE_WORKSTRUCT)
2556
2557/* Default work queue behavior is to sleep and wait for tx completion. */
2558#define MWL8K_WQ_DEFAULT_OPTIONS (MWL8K_WQ_SLEEP | MWL8K_WQ_TX_WAIT_EMPTY)
2559
2560/*
2561 * Default config request timeout. Add adjustments to make sure the
2562 * config thread waits long enough for both tx wait and cmd wait before
2563 * timing out.
2564 */
2565
2566/* Time to wait for all TXQs to drain. TX Doorbell is pressed each time. */
2567#define MWL8K_TXWAIT_TIMEOUT_MS 1000
2568
2569/* Default number of TX wait attempts. */
2570#define MWL8K_WQ_TXWAIT_ATTEMPTS 4
2571
2572/* Total time to wait for TXQ to drain. */
2573#define MWL8K_TXWAIT_MS (MWL8K_TXWAIT_TIMEOUT_MS * \
2574 MWL8K_WQ_TXWAIT_ATTEMPTS)
2575
2576/* Scheduling slop. */
2577#define MWL8K_OS_SCHEDULE_OVERHEAD_MS 200
2578
2579#define MWL8K_CONFIG_TIMEOUT_MS (MWL8K_CMD_TIMEOUT_MS + \
2580 MWL8K_TXWAIT_MS + \
2581 MWL8K_OS_SCHEDULE_OVERHEAD_MS)
2582
2583static void mwl8k_config_thread(struct work_struct *wt)
2584{
2585 struct mwl8k_work_struct *worker = (struct mwl8k_work_struct *)wt;
2586 struct ieee80211_hw *hw = worker->hw;
2587 struct mwl8k_priv *priv = hw->priv;
2588 int rc = 0;
2589
2590 spin_lock_irq(&priv->tx_lock);
2591 priv->inconfig = true;
2592 spin_unlock_irq(&priv->tx_lock);
2593
2594 ieee80211_stop_queues(hw);
2595
2596 /*
2597 * Wait for host queues to drain before doing PHY
2598 * reconfiguration. This avoids interrupting any in-flight
2599 * DMA transfers to the hardware.
2600 */
2601 if (worker->options & MWL8K_WQ_TX_WAIT_EMPTY) {
2602 u32 timeout;
2603 u32 time_remaining;
2604 u32 iter;
2605 u32 tx_wait_attempts = worker->txwait_attempts;
2606
2607 time_remaining = worker->tx_timeout_ms;
2608 if (!tx_wait_attempts)
2609 tx_wait_attempts = 1;
2610
2611 timeout = worker->tx_timeout_ms/tx_wait_attempts;
2612 if (!timeout)
2613 timeout = 1;
2614
2615 iter = tx_wait_attempts;
2616 do {
2617 int wait_time;
2618
2619 if (time_remaining > timeout) {
2620 time_remaining -= timeout;
2621 wait_time = timeout;
2622 } else
2623 wait_time = time_remaining;
2624
2625 if (!wait_time)
2626 wait_time = 1;
2627
2628 rc = mwl8k_tx_wait_empty(hw, wait_time);
2629 if (rc)
2630 printk(KERN_ERR "%s() txwait timeout=%ums "
2631 "Retry:%u/%u\n", __func__, timeout,
2632 tx_wait_attempts - iter + 1,
2633 tx_wait_attempts);
2634
2635 } while (rc && --iter);
2636
2637 rc = iter ? 0 : -ETIMEDOUT;
2638 }
2639 if (!rc)
2640 rc = worker->wfunc(wt);
2641
2642 spin_lock_irq(&priv->tx_lock);
2643 priv->inconfig = false;
Lennert Buytenhekc46563b2009-07-16 12:14:58 +02002644 if (priv->pending_tx_pkts && priv->radio_on)
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002645 mwl8k_tx_start(priv);
2646 spin_unlock_irq(&priv->tx_lock);
2647 ieee80211_wake_queues(hw);
2648
2649 worker->rc = rc;
2650 if (worker->options & MWL8K_WQ_SLEEP)
2651 complete(worker->cmd_wait);
2652
2653 if (worker->options & MWL8K_WQ_FREE_WORKSTRUCT)
2654 kfree(wt);
2655}
2656
2657static int mwl8k_queue_work(struct ieee80211_hw *hw,
2658 struct mwl8k_work_struct *worker,
2659 struct workqueue_struct *wqueue,
2660 int (*wfunc)(struct work_struct *w))
2661{
2662 unsigned long timeout = 0;
2663 int rc = 0;
2664
2665 DECLARE_COMPLETION_ONSTACK(cmd_wait);
2666
2667 if (!worker->timeout_ms)
2668 worker->timeout_ms = MWL8K_CONFIG_TIMEOUT_MS;
2669
2670 if (!worker->options)
2671 worker->options = MWL8K_WQ_DEFAULT_OPTIONS;
2672
2673 if (!worker->txwait_attempts)
2674 worker->txwait_attempts = MWL8K_WQ_TXWAIT_ATTEMPTS;
2675
2676 if (!worker->tx_timeout_ms)
2677 worker->tx_timeout_ms = MWL8K_TXWAIT_MS;
2678
2679 worker->hw = hw;
2680 worker->cmd_wait = &cmd_wait;
2681 worker->rc = 1;
2682 worker->wfunc = wfunc;
2683
2684 INIT_WORK(&worker->wt, mwl8k_config_thread);
2685 queue_work(wqueue, &worker->wt);
2686
2687 if (worker->options & MWL8K_WQ_POST_REQUEST) {
2688 rc = 0;
2689 } else {
2690 if (worker->options & MWL8K_WQ_SPIN) {
2691 timeout = worker->timeout_ms;
2692 while (timeout && (worker->rc > 0)) {
2693 mdelay(1);
2694 timeout--;
2695 }
2696 } else if (worker->options & MWL8K_WQ_SLEEP)
2697 timeout = wait_for_completion_timeout(&cmd_wait,
2698 msecs_to_jiffies(worker->timeout_ms));
2699
2700 if (timeout)
2701 rc = worker->rc;
2702 else {
2703 cancel_work_sync(&worker->wt);
2704 rc = -ETIMEDOUT;
2705 }
2706 }
2707
2708 return rc;
2709}
2710
2711struct mwl8k_start_worker {
2712 struct mwl8k_work_struct header;
2713};
2714
2715static int mwl8k_start_wt(struct work_struct *wt)
2716{
2717 struct mwl8k_start_worker *worker = (struct mwl8k_start_worker *)wt;
2718 struct ieee80211_hw *hw = worker->header.hw;
2719 struct mwl8k_priv *priv = hw->priv;
2720 int rc = 0;
2721
2722 if (priv->vif != NULL) {
2723 rc = -EIO;
2724 goto mwl8k_start_exit;
2725 }
2726
2727 /* Turn on radio */
Lennert Buytenhekc46563b2009-07-16 12:14:58 +02002728 if (mwl8k_cmd_802_11_radio_enable(hw)) {
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002729 rc = -EIO;
2730 goto mwl8k_start_exit;
2731 }
2732
2733 /* Purge TX/RX HW queues */
2734 if (mwl8k_cmd_set_pre_scan(hw)) {
2735 rc = -EIO;
2736 goto mwl8k_start_exit;
2737 }
2738
2739 if (mwl8k_cmd_set_post_scan(hw, "\x00\x00\x00\x00\x00\x00")) {
2740 rc = -EIO;
2741 goto mwl8k_start_exit;
2742 }
2743
2744 /* Enable firmware rate adaptation */
2745 if (mwl8k_cmd_setrateadaptmode(hw, 0)) {
2746 rc = -EIO;
2747 goto mwl8k_start_exit;
2748 }
2749
2750 /* Disable WMM. WMM gets enabled when stack sends WMM parms */
Lennert Buytenhek0439b1f2009-07-16 12:34:02 +02002751 if (mwl8k_set_wmm(hw, 0)) {
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002752 rc = -EIO;
2753 goto mwl8k_start_exit;
2754 }
2755
2756 /* Disable sniffer mode */
2757 if (mwl8k_enable_sniffer(hw, 0))
2758 rc = -EIO;
2759
2760mwl8k_start_exit:
2761 return rc;
2762}
2763
2764static int mwl8k_start(struct ieee80211_hw *hw)
2765{
2766 struct mwl8k_start_worker *worker;
2767 struct mwl8k_priv *priv = hw->priv;
2768 int rc;
2769
2770 /* Enable tx reclaim tasklet */
2771 tasklet_enable(&priv->tx_reclaim_task);
2772
2773 rc = request_irq(priv->pdev->irq, &mwl8k_interrupt,
2774 IRQF_SHARED, MWL8K_NAME, hw);
2775 if (rc) {
2776 printk(KERN_ERR "%s: failed to register IRQ handler\n",
2777 priv->name);
2778 rc = -EIO;
2779 goto mwl8k_start_disable_tasklet;
2780 }
2781
2782 /* Enable interrupts */
Lennert Buytenhekc23b5a62009-07-16 13:49:55 +02002783 iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002784
2785 worker = kzalloc(sizeof(*worker), GFP_KERNEL);
2786 if (worker == NULL) {
2787 rc = -ENOMEM;
2788 goto mwl8k_start_disable_irq;
2789 }
2790
2791 rc = mwl8k_queue_work(hw, &worker->header,
2792 priv->config_wq, mwl8k_start_wt);
2793 kfree(worker);
2794 if (!rc)
2795 return rc;
2796
2797 if (rc == -ETIMEDOUT)
2798 printk(KERN_ERR "%s() timed out\n", __func__);
2799
2800 rc = -EIO;
2801
2802mwl8k_start_disable_irq:
2803 spin_lock_irq(&priv->tx_lock);
2804 iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
2805 spin_unlock_irq(&priv->tx_lock);
2806 free_irq(priv->pdev->irq, hw);
2807
2808mwl8k_start_disable_tasklet:
2809 tasklet_disable(&priv->tx_reclaim_task);
2810
2811 return rc;
2812}
2813
2814struct mwl8k_stop_worker {
2815 struct mwl8k_work_struct header;
2816};
2817
2818static int mwl8k_stop_wt(struct work_struct *wt)
2819{
2820 struct mwl8k_stop_worker *worker = (struct mwl8k_stop_worker *)wt;
2821 struct ieee80211_hw *hw = worker->header.hw;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002822
Lennert Buytenhekc46563b2009-07-16 12:14:58 +02002823 return mwl8k_cmd_802_11_radio_disable(hw);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002824}
2825
2826static void mwl8k_stop(struct ieee80211_hw *hw)
2827{
2828 int rc;
2829 struct mwl8k_stop_worker *worker;
2830 struct mwl8k_priv *priv = hw->priv;
2831 int i;
2832
2833 if (priv->vif != NULL)
2834 return;
2835
2836 ieee80211_stop_queues(hw);
2837
2838 worker = kzalloc(sizeof(*worker), GFP_KERNEL);
2839 if (worker == NULL)
2840 return;
2841
2842 rc = mwl8k_queue_work(hw, &worker->header,
2843 priv->config_wq, mwl8k_stop_wt);
2844 kfree(worker);
2845 if (rc == -ETIMEDOUT)
2846 printk(KERN_ERR "%s() timed out\n", __func__);
2847
2848 /* Disable interrupts */
2849 spin_lock_irq(&priv->tx_lock);
2850 iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
2851 spin_unlock_irq(&priv->tx_lock);
2852 free_irq(priv->pdev->irq, hw);
2853
2854 /* Stop finalize join worker */
2855 cancel_work_sync(&priv->finalize_join_worker);
2856 if (priv->beacon_skb != NULL)
2857 dev_kfree_skb(priv->beacon_skb);
2858
2859 /* Stop tx reclaim tasklet */
2860 tasklet_disable(&priv->tx_reclaim_task);
2861
2862 /* Stop config thread */
2863 flush_workqueue(priv->config_wq);
2864
2865 /* Return all skbs to mac80211 */
2866 for (i = 0; i < MWL8K_TX_QUEUES; i++)
2867 mwl8k_txq_reclaim(hw, i, 1);
2868}
2869
2870static int mwl8k_add_interface(struct ieee80211_hw *hw,
2871 struct ieee80211_if_init_conf *conf)
2872{
2873 struct mwl8k_priv *priv = hw->priv;
2874 struct mwl8k_vif *mwl8k_vif;
2875
2876 /*
2877 * We only support one active interface at a time.
2878 */
2879 if (priv->vif != NULL)
2880 return -EBUSY;
2881
2882 /*
2883 * We only support managed interfaces for now.
2884 */
2885 if (conf->type != NL80211_IFTYPE_STATION &&
2886 conf->type != NL80211_IFTYPE_MONITOR)
2887 return -EINVAL;
2888
2889 /* Clean out driver private area */
2890 mwl8k_vif = MWL8K_VIF(conf->vif);
2891 memset(mwl8k_vif, 0, sizeof(*mwl8k_vif));
2892
2893 /* Save the mac address */
Lennert Buytenhekd89173f2009-07-16 09:54:27 +02002894 memcpy(mwl8k_vif->mac_addr, conf->mac_addr, ETH_ALEN);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002895
2896 /* Back pointer to parent config block */
2897 mwl8k_vif->priv = priv;
2898
2899 /* Setup initial PHY parameters */
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02002900 memcpy(mwl8k_vif->legacy_rates,
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002901 priv->rates, sizeof(mwl8k_vif->legacy_rates));
2902 mwl8k_vif->legacy_nrates = ARRAY_SIZE(priv->rates);
2903
2904 /* Set Initial sequence number to zero */
2905 mwl8k_vif->seqno = 0;
2906
2907 priv->vif = conf->vif;
2908 priv->current_channel = NULL;
2909
2910 return 0;
2911}
2912
2913static void mwl8k_remove_interface(struct ieee80211_hw *hw,
2914 struct ieee80211_if_init_conf *conf)
2915{
2916 struct mwl8k_priv *priv = hw->priv;
2917
2918 if (priv->vif == NULL)
2919 return;
2920
2921 priv->vif = NULL;
2922}
2923
2924struct mwl8k_config_worker {
2925 struct mwl8k_work_struct header;
2926 u32 changed;
2927};
2928
2929static int mwl8k_config_wt(struct work_struct *wt)
2930{
2931 struct mwl8k_config_worker *worker =
2932 (struct mwl8k_config_worker *)wt;
2933 struct ieee80211_hw *hw = worker->header.hw;
2934 struct ieee80211_conf *conf = &hw->conf;
2935 struct mwl8k_priv *priv = hw->priv;
2936 int rc = 0;
2937
Lennert Buytenhekc46563b2009-07-16 12:14:58 +02002938 if (mwl8k_cmd_802_11_radio_enable(hw)) {
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002939 rc = -EINVAL;
2940 goto mwl8k_config_exit;
2941 }
2942
2943 priv->current_channel = conf->channel;
2944
2945 if (mwl8k_cmd_set_rf_channel(hw, conf->channel)) {
2946 rc = -EINVAL;
2947 goto mwl8k_config_exit;
2948 }
2949
2950 if (conf->power_level > 18)
2951 conf->power_level = 18;
2952 if (mwl8k_cmd_802_11_rf_tx_power(hw, conf->power_level)) {
2953 rc = -EINVAL;
2954 goto mwl8k_config_exit;
2955 }
2956
2957 if (mwl8k_cmd_mimo_config(hw, 0x7, 0x7))
2958 rc = -EINVAL;
2959
2960mwl8k_config_exit:
2961 return rc;
2962}
2963
2964static int mwl8k_config(struct ieee80211_hw *hw, u32 changed)
2965{
2966 int rc = 0;
2967 struct mwl8k_config_worker *worker;
2968 struct mwl8k_priv *priv = hw->priv;
2969
2970 worker = kzalloc(sizeof(*worker), GFP_KERNEL);
2971 if (worker == NULL)
2972 return -ENOMEM;
2973
2974 worker->changed = changed;
2975 rc = mwl8k_queue_work(hw, &worker->header,
2976 priv->config_wq, mwl8k_config_wt);
2977 if (rc == -ETIMEDOUT) {
2978 printk(KERN_ERR "%s() timed out.\n", __func__);
2979 rc = -EINVAL;
2980 }
2981
2982 kfree(worker);
2983
2984 /*
2985 * mac80211 will crash on anything other than -EINVAL on
2986 * error. Looks like wireless extensions which calls mac80211
2987 * may be the actual culprit...
2988 */
2989 return rc ? -EINVAL : 0;
2990}
2991
Lennert Buytenheka66098d2009-03-10 10:13:33 +01002992struct mwl8k_bss_info_changed_worker {
2993 struct mwl8k_work_struct header;
2994 struct ieee80211_vif *vif;
2995 struct ieee80211_bss_conf *info;
2996 u32 changed;
2997};
2998
2999static int mwl8k_bss_info_changed_wt(struct work_struct *wt)
3000{
3001 struct mwl8k_bss_info_changed_worker *worker =
3002 (struct mwl8k_bss_info_changed_worker *)wt;
3003 struct ieee80211_hw *hw = worker->header.hw;
3004 struct ieee80211_vif *vif = worker->vif;
3005 struct ieee80211_bss_conf *info = worker->info;
3006 u32 changed;
3007 int rc;
3008
3009 struct mwl8k_priv *priv = hw->priv;
3010 struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif);
3011
3012 changed = worker->changed;
3013 priv->capture_beacon = false;
3014
3015 if (info->assoc) {
3016 memcpy(&mwl8k_vif->bss_info, info,
3017 sizeof(struct ieee80211_bss_conf));
3018
3019 /* Install rates */
3020 if (mwl8k_update_rateset(hw, vif))
3021 goto mwl8k_bss_info_changed_exit;
3022
3023 /* Turn on rate adaptation */
3024 if (mwl8k_cmd_use_fixed_rate(hw, MWL8K_USE_AUTO_RATE,
3025 MWL8K_UCAST_RATE, NULL))
3026 goto mwl8k_bss_info_changed_exit;
3027
3028 /* Set radio preamble */
Lennert Buytenhek68ce3882009-07-16 12:26:57 +02003029 if (mwl8k_set_radio_preamble(hw, info->use_short_preamble))
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003030 goto mwl8k_bss_info_changed_exit;
3031
3032 /* Set slot time */
Lennert Buytenhek5539bb52009-07-16 16:06:53 +02003033 if (mwl8k_cmd_set_slot(hw, info->use_short_slot))
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003034 goto mwl8k_bss_info_changed_exit;
3035
3036 /* Update peer rate info */
3037 if (mwl8k_cmd_update_sta_db(hw, vif,
3038 MWL8K_STA_DB_MODIFY_ENTRY))
3039 goto mwl8k_bss_info_changed_exit;
3040
3041 /* Set AID */
3042 if (mwl8k_cmd_set_aid(hw, vif))
3043 goto mwl8k_bss_info_changed_exit;
3044
3045 /*
3046 * Finalize the join. Tell rx handler to process
3047 * next beacon from our BSSID.
3048 */
Lennert Buytenhekd89173f2009-07-16 09:54:27 +02003049 memcpy(priv->capture_bssid, mwl8k_vif->bssid, ETH_ALEN);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003050 priv->capture_beacon = true;
3051 } else {
3052 mwl8k_cmd_update_sta_db(hw, vif, MWL8K_STA_DB_DEL_ENTRY);
3053 memset(&mwl8k_vif->bss_info, 0,
3054 sizeof(struct ieee80211_bss_conf));
Lennert Buytenhekd89173f2009-07-16 09:54:27 +02003055 memset(mwl8k_vif->bssid, 0, ETH_ALEN);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003056 }
3057
3058mwl8k_bss_info_changed_exit:
3059 rc = 0;
3060 return rc;
3061}
3062
3063static void mwl8k_bss_info_changed(struct ieee80211_hw *hw,
3064 struct ieee80211_vif *vif,
3065 struct ieee80211_bss_conf *info,
3066 u32 changed)
3067{
3068 struct mwl8k_bss_info_changed_worker *worker;
3069 struct mwl8k_priv *priv = hw->priv;
Johannes Berg2d0ddec2009-04-23 16:13:26 +02003070 struct mwl8k_vif *mv_vif = MWL8K_VIF(vif);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003071 int rc;
3072
Johannes Berg2d0ddec2009-04-23 16:13:26 +02003073 if (changed & BSS_CHANGED_BSSID)
Lennert Buytenhekd89173f2009-07-16 09:54:27 +02003074 memcpy(mv_vif->bssid, info->bssid, ETH_ALEN);
Johannes Berg2d0ddec2009-04-23 16:13:26 +02003075
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003076 if ((changed & BSS_CHANGED_ASSOC) == 0)
3077 return;
3078
3079 worker = kzalloc(sizeof(*worker), GFP_KERNEL);
3080 if (worker == NULL)
3081 return;
3082
3083 worker->vif = vif;
3084 worker->info = info;
3085 worker->changed = changed;
3086 rc = mwl8k_queue_work(hw, &worker->header,
3087 priv->config_wq,
3088 mwl8k_bss_info_changed_wt);
3089 kfree(worker);
3090 if (rc == -ETIMEDOUT)
3091 printk(KERN_ERR "%s() timed out\n", __func__);
3092}
3093
3094struct mwl8k_configure_filter_worker {
3095 struct mwl8k_work_struct header;
3096 unsigned int changed_flags;
3097 unsigned int *total_flags;
3098 int mc_count;
3099 struct dev_addr_list *mclist;
3100};
3101
3102#define MWL8K_SUPPORTED_IF_FLAGS FIF_BCN_PRBRESP_PROMISC
3103
3104static int mwl8k_configure_filter_wt(struct work_struct *wt)
3105{
3106 struct mwl8k_configure_filter_worker *worker =
3107 (struct mwl8k_configure_filter_worker *)wt;
3108
3109 struct ieee80211_hw *hw = worker->header.hw;
3110 unsigned int changed_flags = worker->changed_flags;
3111 unsigned int *total_flags = worker->total_flags;
3112 int mc_count = worker->mc_count;
3113 struct dev_addr_list *mclist = worker->mclist;
3114
3115 struct mwl8k_priv *priv = hw->priv;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003116 int rc = 0;
3117
3118 if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
3119 if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
3120 rc = mwl8k_cmd_set_pre_scan(hw);
3121 else {
Lennert Buytenheka94cc972009-08-03 21:58:57 +02003122 u8 *bssid;
3123
3124 bssid = "\x00\x00\x00\x00\x00\x00";
3125 if (priv->vif != NULL)
3126 bssid = MWL8K_VIF(priv->vif)->bssid;
3127
3128 rc = mwl8k_cmd_set_post_scan(hw, bssid);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003129 }
3130 }
3131
3132 if (rc)
3133 goto mwl8k_configure_filter_exit;
3134 if (mc_count) {
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02003135 if (mc_count > priv->num_mcaddrs)
3136 mc_count = priv->num_mcaddrs;
3137
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003138 rc = mwl8k_cmd_mac_multicast_adr(hw, mc_count, mclist);
3139 if (rc)
3140 printk(KERN_ERR
3141 "%s()Error setting multicast addresses\n",
3142 __func__);
3143 }
3144
3145mwl8k_configure_filter_exit:
3146 return rc;
3147}
3148
Johannes Berg3ac64be2009-08-17 16:16:53 +02003149static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw,
3150 int mc_count, struct dev_addr_list *mclist)
3151{
3152 struct mwl8k_configure_filter_worker *worker;
3153
3154 worker = kzalloc(sizeof(*worker), GFP_ATOMIC);
3155
3156 if (!worker)
3157 return 0;
3158
3159 /*
3160 * XXX: This is _HORRIBLY_ broken!!
3161 *
3162 * No locking, the mclist pointer might be invalid as soon as this
3163 * function returns, something in the list might be invalidated
3164 * once we get to the worker, etc...
3165 */
3166 worker->mc_count = mc_count;
3167 worker->mclist = mclist;
3168
3169 return (u64)worker;
3170}
3171
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003172static void mwl8k_configure_filter(struct ieee80211_hw *hw,
3173 unsigned int changed_flags,
3174 unsigned int *total_flags,
Johannes Berg3ac64be2009-08-17 16:16:53 +02003175 u64 multicast)
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003176{
3177
Johannes Berg3ac64be2009-08-17 16:16:53 +02003178 struct mwl8k_configure_filter_worker *worker = (void *)multicast;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003179 struct mwl8k_priv *priv = hw->priv;
3180
3181 /* Clear unsupported feature flags */
3182 *total_flags &= MWL8K_SUPPORTED_IF_FLAGS;
3183
Johannes Berg3ac64be2009-08-17 16:16:53 +02003184 if (!(changed_flags & MWL8K_SUPPORTED_IF_FLAGS))
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003185 return;
3186
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003187 if (worker == NULL)
3188 return;
3189
3190 worker->header.options = MWL8K_WQ_QUEUE_ONLY | MWL8K_WQ_TX_WAIT_EMPTY;
3191 worker->changed_flags = changed_flags;
3192 worker->total_flags = total_flags;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003193
3194 mwl8k_queue_work(hw, &worker->header, priv->config_wq,
3195 mwl8k_configure_filter_wt);
3196}
3197
3198struct mwl8k_set_rts_threshold_worker {
3199 struct mwl8k_work_struct header;
3200 u32 value;
3201};
3202
3203static int mwl8k_set_rts_threshold_wt(struct work_struct *wt)
3204{
3205 struct mwl8k_set_rts_threshold_worker *worker =
3206 (struct mwl8k_set_rts_threshold_worker *)wt;
3207
3208 struct ieee80211_hw *hw = worker->header.hw;
3209 u16 threshold = (u16)(worker->value);
3210 int rc;
3211
3212 rc = mwl8k_rts_threshold(hw, MWL8K_CMD_SET, &threshold);
3213
3214 return rc;
3215}
3216
3217static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3218{
3219 int rc;
3220 struct mwl8k_set_rts_threshold_worker *worker;
3221 struct mwl8k_priv *priv = hw->priv;
3222
3223 worker = kzalloc(sizeof(*worker), GFP_KERNEL);
3224 if (worker == NULL)
3225 return -ENOMEM;
3226
3227 worker->value = value;
3228
3229 rc = mwl8k_queue_work(hw, &worker->header,
3230 priv->config_wq,
3231 mwl8k_set_rts_threshold_wt);
3232 kfree(worker);
3233
3234 if (rc == -ETIMEDOUT) {
3235 printk(KERN_ERR "%s() timed out\n", __func__);
3236 rc = -EINVAL;
3237 }
3238
3239 return rc;
3240}
3241
3242struct mwl8k_conf_tx_worker {
3243 struct mwl8k_work_struct header;
3244 u16 queue;
3245 const struct ieee80211_tx_queue_params *params;
3246};
3247
3248static int mwl8k_conf_tx_wt(struct work_struct *wt)
3249{
3250 struct mwl8k_conf_tx_worker *worker =
3251 (struct mwl8k_conf_tx_worker *)wt;
3252
3253 struct ieee80211_hw *hw = worker->header.hw;
3254 u16 queue = worker->queue;
3255 const struct ieee80211_tx_queue_params *params = worker->params;
3256
3257 struct mwl8k_priv *priv = hw->priv;
3258 int rc = 0;
3259
Lennert Buytenhek0439b1f2009-07-16 12:34:02 +02003260 if (!priv->wmm_enabled) {
3261 if (mwl8k_set_wmm(hw, 1)) {
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003262 rc = -EINVAL;
3263 goto mwl8k_conf_tx_exit;
Lennert Buytenhek0439b1f2009-07-16 12:34:02 +02003264 }
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003265 }
3266
3267 if (mwl8k_set_edca_params(hw, GET_TXQ(queue), params->cw_min,
3268 params->cw_max, params->aifs, params->txop))
3269 rc = -EINVAL;
3270mwl8k_conf_tx_exit:
3271 return rc;
3272}
3273
3274static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue,
3275 const struct ieee80211_tx_queue_params *params)
3276{
3277 int rc;
3278 struct mwl8k_conf_tx_worker *worker;
3279 struct mwl8k_priv *priv = hw->priv;
3280
3281 worker = kzalloc(sizeof(*worker), GFP_KERNEL);
3282 if (worker == NULL)
3283 return -ENOMEM;
3284
3285 worker->queue = queue;
3286 worker->params = params;
3287 rc = mwl8k_queue_work(hw, &worker->header,
3288 priv->config_wq, mwl8k_conf_tx_wt);
3289 kfree(worker);
3290 if (rc == -ETIMEDOUT) {
3291 printk(KERN_ERR "%s() timed out\n", __func__);
3292 rc = -EINVAL;
3293 }
3294 return rc;
3295}
3296
3297static int mwl8k_get_tx_stats(struct ieee80211_hw *hw,
3298 struct ieee80211_tx_queue_stats *stats)
3299{
3300 struct mwl8k_priv *priv = hw->priv;
3301 struct mwl8k_tx_queue *txq;
3302 int index;
3303
3304 spin_lock_bh(&priv->tx_lock);
3305 for (index = 0; index < MWL8K_TX_QUEUES; index++) {
3306 txq = priv->txq + index;
3307 memcpy(&stats[index], &txq->tx_stats,
3308 sizeof(struct ieee80211_tx_queue_stats));
3309 }
3310 spin_unlock_bh(&priv->tx_lock);
3311 return 0;
3312}
3313
3314struct mwl8k_get_stats_worker {
3315 struct mwl8k_work_struct header;
3316 struct ieee80211_low_level_stats *stats;
3317};
3318
3319static int mwl8k_get_stats_wt(struct work_struct *wt)
3320{
3321 struct mwl8k_get_stats_worker *worker =
3322 (struct mwl8k_get_stats_worker *)wt;
3323
3324 return mwl8k_cmd_802_11_get_stat(worker->header.hw, worker->stats);
3325}
3326
3327static int mwl8k_get_stats(struct ieee80211_hw *hw,
3328 struct ieee80211_low_level_stats *stats)
3329{
3330 int rc;
3331 struct mwl8k_get_stats_worker *worker;
3332 struct mwl8k_priv *priv = hw->priv;
3333
3334 worker = kzalloc(sizeof(*worker), GFP_KERNEL);
3335 if (worker == NULL)
3336 return -ENOMEM;
3337
3338 worker->stats = stats;
3339 rc = mwl8k_queue_work(hw, &worker->header,
3340 priv->config_wq, mwl8k_get_stats_wt);
3341
3342 kfree(worker);
3343 if (rc == -ETIMEDOUT) {
3344 printk(KERN_ERR "%s() timed out\n", __func__);
3345 rc = -EINVAL;
3346 }
3347
3348 return rc;
3349}
3350
3351static const struct ieee80211_ops mwl8k_ops = {
3352 .tx = mwl8k_tx,
3353 .start = mwl8k_start,
3354 .stop = mwl8k_stop,
3355 .add_interface = mwl8k_add_interface,
3356 .remove_interface = mwl8k_remove_interface,
3357 .config = mwl8k_config,
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003358 .bss_info_changed = mwl8k_bss_info_changed,
Johannes Berg3ac64be2009-08-17 16:16:53 +02003359 .prepare_multicast = mwl8k_prepare_multicast,
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003360 .configure_filter = mwl8k_configure_filter,
3361 .set_rts_threshold = mwl8k_set_rts_threshold,
3362 .conf_tx = mwl8k_conf_tx,
3363 .get_tx_stats = mwl8k_get_tx_stats,
3364 .get_stats = mwl8k_get_stats,
3365};
3366
3367static void mwl8k_tx_reclaim_handler(unsigned long data)
3368{
3369 int i;
3370 struct ieee80211_hw *hw = (struct ieee80211_hw *) data;
3371 struct mwl8k_priv *priv = hw->priv;
3372
3373 spin_lock_bh(&priv->tx_lock);
3374 for (i = 0; i < MWL8K_TX_QUEUES; i++)
3375 mwl8k_txq_reclaim(hw, i, 0);
3376
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02003377 if (priv->tx_wait != NULL && mwl8k_txq_busy(priv) == 0) {
3378 complete(priv->tx_wait);
3379 priv->tx_wait = NULL;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003380 }
3381 spin_unlock_bh(&priv->tx_lock);
3382}
3383
3384static void mwl8k_finalize_join_worker(struct work_struct *work)
3385{
3386 struct mwl8k_priv *priv =
3387 container_of(work, struct mwl8k_priv, finalize_join_worker);
3388 struct sk_buff *skb = priv->beacon_skb;
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02003389 u8 dtim = MWL8K_VIF(priv->vif)->bss_info.dtim_period;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003390
3391 mwl8k_finalize_join(priv->hw, skb->data, skb->len, dtim);
3392 dev_kfree_skb(skb);
3393
3394 priv->beacon_skb = NULL;
3395}
3396
3397static int __devinit mwl8k_probe(struct pci_dev *pdev,
3398 const struct pci_device_id *id)
3399{
3400 struct ieee80211_hw *hw;
3401 struct mwl8k_priv *priv;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003402 int rc;
3403 int i;
3404 u8 *fw;
3405
3406 rc = pci_enable_device(pdev);
3407 if (rc) {
3408 printk(KERN_ERR "%s: Cannot enable new PCI device\n",
3409 MWL8K_NAME);
3410 return rc;
3411 }
3412
3413 rc = pci_request_regions(pdev, MWL8K_NAME);
3414 if (rc) {
3415 printk(KERN_ERR "%s: Cannot obtain PCI resources\n",
3416 MWL8K_NAME);
3417 return rc;
3418 }
3419
3420 pci_set_master(pdev);
3421
3422 hw = ieee80211_alloc_hw(sizeof(*priv), &mwl8k_ops);
3423 if (hw == NULL) {
3424 printk(KERN_ERR "%s: ieee80211 alloc failed\n", MWL8K_NAME);
3425 rc = -ENOMEM;
3426 goto err_free_reg;
3427 }
3428
3429 priv = hw->priv;
3430 priv->hw = hw;
3431 priv->pdev = pdev;
3432 priv->hostcmd_wait = NULL;
3433 priv->tx_wait = NULL;
3434 priv->inconfig = false;
Lennert Buytenhek0439b1f2009-07-16 12:34:02 +02003435 priv->wmm_enabled = false;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003436 priv->pending_tx_pkts = 0;
3437 strncpy(priv->name, MWL8K_NAME, sizeof(priv->name));
3438
3439 spin_lock_init(&priv->fw_lock);
3440
3441 SET_IEEE80211_DEV(hw, &pdev->dev);
3442 pci_set_drvdata(pdev, hw);
3443
3444 priv->regs = pci_iomap(pdev, 1, 0x10000);
3445 if (priv->regs == NULL) {
3446 printk(KERN_ERR "%s: Cannot map device memory\n", priv->name);
3447 goto err_iounmap;
3448 }
3449
3450 memcpy(priv->channels, mwl8k_channels, sizeof(mwl8k_channels));
3451 priv->band.band = IEEE80211_BAND_2GHZ;
3452 priv->band.channels = priv->channels;
3453 priv->band.n_channels = ARRAY_SIZE(mwl8k_channels);
3454 priv->band.bitrates = priv->rates;
3455 priv->band.n_bitrates = ARRAY_SIZE(mwl8k_rates);
3456 hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
3457
3458 BUILD_BUG_ON(sizeof(priv->rates) != sizeof(mwl8k_rates));
3459 memcpy(priv->rates, mwl8k_rates, sizeof(mwl8k_rates));
3460
3461 /*
3462 * Extra headroom is the size of the required DMA header
3463 * minus the size of the smallest 802.11 frame (CTS frame).
3464 */
3465 hw->extra_tx_headroom =
3466 sizeof(struct mwl8k_dma_data) - sizeof(struct ieee80211_cts);
3467
3468 hw->channel_change_time = 10;
3469
3470 hw->queues = MWL8K_TX_QUEUES;
3471
3472 hw->wiphy->interface_modes =
3473 BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_MONITOR);
3474
3475 /* Set rssi and noise values to dBm */
Lennert Buytenhekce9e2e12009-07-16 14:00:45 +02003476 hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003477 hw->vif_data_size = sizeof(struct mwl8k_vif);
3478 priv->vif = NULL;
3479
3480 /* Set default radio state and preamble */
Lennert Buytenhekc46563b2009-07-16 12:14:58 +02003481 priv->radio_on = 0;
Lennert Buytenhek68ce3882009-07-16 12:26:57 +02003482 priv->radio_short_preamble = 0;
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003483
3484 /* Finalize join worker */
3485 INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker);
3486
3487 /* TX reclaim tasklet */
3488 tasklet_init(&priv->tx_reclaim_task,
3489 mwl8k_tx_reclaim_handler, (unsigned long)hw);
3490 tasklet_disable(&priv->tx_reclaim_task);
3491
3492 /* Config workthread */
3493 priv->config_wq = create_singlethread_workqueue("mwl8k_config");
3494 if (priv->config_wq == NULL)
3495 goto err_iounmap;
3496
3497 /* Power management cookie */
3498 priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma);
3499 if (priv->cookie == NULL)
3500 goto err_iounmap;
3501
3502 rc = mwl8k_rxq_init(hw, 0);
3503 if (rc)
3504 goto err_iounmap;
3505 rxq_refill(hw, 0, INT_MAX);
3506
3507 spin_lock_init(&priv->tx_lock);
3508
3509 for (i = 0; i < MWL8K_TX_QUEUES; i++) {
3510 rc = mwl8k_txq_init(hw, i);
3511 if (rc)
3512 goto err_free_queues;
3513 }
3514
3515 iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
Lennert Buytenhekc23b5a62009-07-16 13:49:55 +02003516 iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003517 iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL);
3518 iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
3519
3520 rc = request_irq(priv->pdev->irq, &mwl8k_interrupt,
3521 IRQF_SHARED, MWL8K_NAME, hw);
3522 if (rc) {
3523 printk(KERN_ERR "%s: failed to register IRQ handler\n",
3524 priv->name);
3525 goto err_free_queues;
3526 }
3527
3528 /* Reset firmware and hardware */
3529 mwl8k_hw_reset(priv);
3530
3531 /* Ask userland hotplug daemon for the device firmware */
3532 rc = mwl8k_request_firmware(priv, (u32)id->driver_data);
3533 if (rc) {
3534 printk(KERN_ERR "%s: Firmware files not found\n", priv->name);
3535 goto err_free_irq;
3536 }
3537
3538 /* Load firmware into hardware */
3539 rc = mwl8k_load_firmware(priv);
3540 if (rc) {
3541 printk(KERN_ERR "%s: Cannot start firmware\n", priv->name);
3542 goto err_stop_firmware;
3543 }
3544
3545 /* Reclaim memory once firmware is successfully loaded */
3546 mwl8k_release_firmware(priv);
3547
3548 /*
3549 * Temporarily enable interrupts. Initial firmware host
3550 * commands use interrupts and avoids polling. Disable
3551 * interrupts when done.
3552 */
Lennert Buytenhekc23b5a62009-07-16 13:49:55 +02003553 iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003554
3555 /* Get config data, mac addrs etc */
3556 rc = mwl8k_cmd_get_hw_spec(hw);
3557 if (rc) {
3558 printk(KERN_ERR "%s: Cannot initialise firmware\n", priv->name);
3559 goto err_stop_firmware;
3560 }
3561
3562 /* Turn radio off */
Lennert Buytenhekc46563b2009-07-16 12:14:58 +02003563 rc = mwl8k_cmd_802_11_radio_disable(hw);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003564 if (rc) {
3565 printk(KERN_ERR "%s: Cannot disable\n", priv->name);
3566 goto err_stop_firmware;
3567 }
3568
3569 /* Disable interrupts */
3570 spin_lock_irq(&priv->tx_lock);
3571 iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
3572 spin_unlock_irq(&priv->tx_lock);
3573 free_irq(priv->pdev->irq, hw);
3574
3575 rc = ieee80211_register_hw(hw);
3576 if (rc) {
3577 printk(KERN_ERR "%s: Cannot register device\n", priv->name);
3578 goto err_stop_firmware;
3579 }
3580
3581 fw = (u8 *)&priv->fw_rev;
3582 printk(KERN_INFO "%s: 88W%u %s\n", priv->name, priv->part_num,
3583 MWL8K_DESC);
3584 printk(KERN_INFO "%s: Driver Ver:%s Firmware Ver:%u.%u.%u.%u\n",
3585 priv->name, MWL8K_VERSION, fw[3], fw[2], fw[1], fw[0]);
Johannes Berge91d8332009-07-15 17:21:41 +02003586 printk(KERN_INFO "%s: MAC Address: %pM\n", priv->name,
3587 hw->wiphy->perm_addr);
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003588
3589 return 0;
3590
3591err_stop_firmware:
3592 mwl8k_hw_reset(priv);
3593 mwl8k_release_firmware(priv);
3594
3595err_free_irq:
3596 spin_lock_irq(&priv->tx_lock);
3597 iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
3598 spin_unlock_irq(&priv->tx_lock);
3599 free_irq(priv->pdev->irq, hw);
3600
3601err_free_queues:
3602 for (i = 0; i < MWL8K_TX_QUEUES; i++)
3603 mwl8k_txq_deinit(hw, i);
3604 mwl8k_rxq_deinit(hw, 0);
3605
3606err_iounmap:
3607 if (priv->cookie != NULL)
3608 pci_free_consistent(priv->pdev, 4,
3609 priv->cookie, priv->cookie_dma);
3610
3611 if (priv->regs != NULL)
3612 pci_iounmap(pdev, priv->regs);
3613
3614 if (priv->config_wq != NULL)
3615 destroy_workqueue(priv->config_wq);
3616
3617 pci_set_drvdata(pdev, NULL);
3618 ieee80211_free_hw(hw);
3619
3620err_free_reg:
3621 pci_release_regions(pdev);
3622 pci_disable_device(pdev);
3623
3624 return rc;
3625}
3626
Joerg Albert230f7af2009-04-18 02:10:45 +02003627static void __devexit mwl8k_shutdown(struct pci_dev *pdev)
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003628{
3629 printk(KERN_ERR "===>%s(%u)\n", __func__, __LINE__);
3630}
3631
Joerg Albert230f7af2009-04-18 02:10:45 +02003632static void __devexit mwl8k_remove(struct pci_dev *pdev)
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003633{
3634 struct ieee80211_hw *hw = pci_get_drvdata(pdev);
3635 struct mwl8k_priv *priv;
3636 int i;
3637
3638 if (hw == NULL)
3639 return;
3640 priv = hw->priv;
3641
3642 ieee80211_stop_queues(hw);
3643
Lennert Buytenhek60aa5692009-08-03 21:59:09 +02003644 ieee80211_unregister_hw(hw);
3645
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003646 /* Remove tx reclaim tasklet */
3647 tasklet_kill(&priv->tx_reclaim_task);
3648
3649 /* Stop config thread */
3650 destroy_workqueue(priv->config_wq);
3651
3652 /* Stop hardware */
3653 mwl8k_hw_reset(priv);
3654
3655 /* Return all skbs to mac80211 */
3656 for (i = 0; i < MWL8K_TX_QUEUES; i++)
3657 mwl8k_txq_reclaim(hw, i, 1);
3658
Lennert Buytenheka66098d2009-03-10 10:13:33 +01003659 for (i = 0; i < MWL8K_TX_QUEUES; i++)
3660 mwl8k_txq_deinit(hw, i);
3661
3662 mwl8k_rxq_deinit(hw, 0);
3663
3664 pci_free_consistent(priv->pdev, 4,
3665 priv->cookie, priv->cookie_dma);
3666
3667 pci_iounmap(pdev, priv->regs);
3668 pci_set_drvdata(pdev, NULL);
3669 ieee80211_free_hw(hw);
3670 pci_release_regions(pdev);
3671 pci_disable_device(pdev);
3672}
3673
3674static struct pci_driver mwl8k_driver = {
3675 .name = MWL8K_NAME,
3676 .id_table = mwl8k_table,
3677 .probe = mwl8k_probe,
3678 .remove = __devexit_p(mwl8k_remove),
3679 .shutdown = __devexit_p(mwl8k_shutdown),
3680};
3681
3682static int __init mwl8k_init(void)
3683{
3684 return pci_register_driver(&mwl8k_driver);
3685}
3686
3687static void __exit mwl8k_exit(void)
3688{
3689 pci_unregister_driver(&mwl8k_driver);
3690}
3691
3692module_init(mwl8k_init);
3693module_exit(mwl8k_exit);