blob: 9f741686405310120db588cb73115057d09d1fed [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinen01c09162009-10-13 12:47:55 +030031#include <linux/inetdevice.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030032
33#include "wl1271.h"
34#include "wl12xx_80211.h"
35#include "wl1271_reg.h"
Teemu Paasikivi7b048c52010-02-18 13:25:55 +020036#include "wl1271_io.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030037#include "wl1271_event.h"
38#include "wl1271_tx.h"
39#include "wl1271_rx.h"
40#include "wl1271_ps.h"
41#include "wl1271_init.h"
42#include "wl1271_debugfs.h"
43#include "wl1271_cmd.h"
44#include "wl1271_boot.h"
Kalle Valoc8c90872010-02-18 13:25:53 +020045#include "wl1271_testmode.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030046
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020047#define WL1271_BOOT_RETRIES 3
48
Juuso Oikarinen8a080482009-10-13 12:47:44 +030049static struct conf_drv_settings default_conf = {
50 .sg = {
51 .per_threshold = 7500,
52 .max_scan_compensation_time = 120000,
53 .nfs_sample_interval = 400,
54 .load_ratio = 50,
55 .auto_ps_mode = 0,
56 .probe_req_compensation = 170,
57 .scan_window_compensation = 50,
58 .antenna_config = 0,
59 .beacon_miss_threshold = 60,
60 .rate_adaptation_threshold = CONF_HW_BIT_RATE_12MBPS,
61 .rate_adaptation_snr = 0
62 },
63 .rx = {
64 .rx_msdu_life_time = 512000,
65 .packet_detection_threshold = 0,
66 .ps_poll_timeout = 15,
67 .upsd_timeout = 15,
68 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +020069 .rx_cca_threshold = 0,
70 .irq_blk_threshold = 0xFFFF,
71 .irq_pkt_threshold = 0,
72 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +030073 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
74 },
75 .tx = {
76 .tx_energy_detection = 0,
77 .rc_conf = {
Juuso Oikarinenec078d92009-12-11 15:41:05 +020078 .enabled_rates = CONF_HW_BIT_RATE_1MBPS |
79 CONF_HW_BIT_RATE_2MBPS,
Juuso Oikarinen8a080482009-10-13 12:47:44 +030080 .short_retry_limit = 10,
81 .long_retry_limit = 10,
82 .aflags = 0
83 },
84 .ac_conf_count = 4,
85 .ac_conf = {
86 [0] = {
87 .ac = CONF_TX_AC_BE,
88 .cw_min = 15,
89 .cw_max = 63,
90 .aifsn = 3,
91 .tx_op_limit = 0,
92 },
93 [1] = {
94 .ac = CONF_TX_AC_BK,
95 .cw_min = 15,
96 .cw_max = 63,
97 .aifsn = 7,
98 .tx_op_limit = 0,
99 },
100 [2] = {
101 .ac = CONF_TX_AC_VI,
102 .cw_min = 15,
103 .cw_max = 63,
104 .aifsn = CONF_TX_AIFS_PIFS,
105 .tx_op_limit = 3008,
106 },
107 [3] = {
108 .ac = CONF_TX_AC_VO,
109 .cw_min = 15,
110 .cw_max = 63,
111 .aifsn = CONF_TX_AIFS_PIFS,
112 .tx_op_limit = 1504,
113 },
114 },
115 .tid_conf_count = 7,
116 .tid_conf = {
117 [0] = {
118 .queue_id = 0,
119 .channel_type = CONF_CHANNEL_TYPE_DCF,
120 .tsid = CONF_TX_AC_BE,
121 .ps_scheme = CONF_PS_SCHEME_LEGACY,
122 .ack_policy = CONF_ACK_POLICY_LEGACY,
123 .apsd_conf = {0, 0},
124 },
125 [1] = {
126 .queue_id = 1,
127 .channel_type = CONF_CHANNEL_TYPE_DCF,
128 .tsid = CONF_TX_AC_BE,
129 .ps_scheme = CONF_PS_SCHEME_LEGACY,
130 .ack_policy = CONF_ACK_POLICY_LEGACY,
131 .apsd_conf = {0, 0},
132 },
133 [2] = {
134 .queue_id = 2,
135 .channel_type = CONF_CHANNEL_TYPE_DCF,
136 .tsid = CONF_TX_AC_BE,
137 .ps_scheme = CONF_PS_SCHEME_LEGACY,
138 .ack_policy = CONF_ACK_POLICY_LEGACY,
139 .apsd_conf = {0, 0},
140 },
141 [3] = {
142 .queue_id = 3,
143 .channel_type = CONF_CHANNEL_TYPE_DCF,
144 .tsid = CONF_TX_AC_BE,
145 .ps_scheme = CONF_PS_SCHEME_LEGACY,
146 .ack_policy = CONF_ACK_POLICY_LEGACY,
147 .apsd_conf = {0, 0},
148 },
149 [4] = {
150 .queue_id = 4,
151 .channel_type = CONF_CHANNEL_TYPE_DCF,
152 .tsid = CONF_TX_AC_BE,
153 .ps_scheme = CONF_PS_SCHEME_LEGACY,
154 .ack_policy = CONF_ACK_POLICY_LEGACY,
155 .apsd_conf = {0, 0},
156 },
157 [5] = {
158 .queue_id = 5,
159 .channel_type = CONF_CHANNEL_TYPE_DCF,
160 .tsid = CONF_TX_AC_BE,
161 .ps_scheme = CONF_PS_SCHEME_LEGACY,
162 .ack_policy = CONF_ACK_POLICY_LEGACY,
163 .apsd_conf = {0, 0},
164 },
165 [6] = {
166 .queue_id = 6,
167 .channel_type = CONF_CHANNEL_TYPE_DCF,
168 .tsid = CONF_TX_AC_BE,
169 .ps_scheme = CONF_PS_SCHEME_LEGACY,
170 .ack_policy = CONF_ACK_POLICY_LEGACY,
171 .apsd_conf = {0, 0},
172 }
173 },
174 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200175 .tx_compl_timeout = 700,
176 .tx_compl_threshold = 4
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300177 },
178 .conn = {
179 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
180 .listen_interval = 0,
181 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
182 .bcn_filt_ie_count = 1,
183 .bcn_filt_ie = {
184 [0] = {
185 .ie = WLAN_EID_CHANNEL_SWITCH,
186 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
187 }
188 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200189 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300190 .bss_lose_timeout = 100,
191 .beacon_rx_timeout = 10000,
192 .broadcast_timeout = 20000,
193 .rx_broadcast_in_ps = 1,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200194 .ps_poll_threshold = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300195 .sig_trigger_count = 2,
196 .sig_trigger = {
197 [0] = {
198 .threshold = -75,
199 .pacing = 500,
200 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
201 .type = CONF_TRIG_EVENT_TYPE_EDGE,
202 .direction = CONF_TRIG_EVENT_DIR_LOW,
203 .hysteresis = 2,
204 .index = 0,
205 .enable = 1
206 },
207 [1] = {
208 .threshold = -75,
209 .pacing = 500,
210 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
211 .type = CONF_TRIG_EVENT_TYPE_EDGE,
212 .direction = CONF_TRIG_EVENT_DIR_HIGH,
213 .hysteresis = 2,
214 .index = 1,
215 .enable = 1
216 }
217 },
218 .sig_weights = {
219 .rssi_bcn_avg_weight = 10,
220 .rssi_pkt_avg_weight = 10,
221 .snr_bcn_avg_weight = 10,
222 .snr_pkt_avg_weight = 10
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300223 },
224 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200225 .bet_max_consecutive = 10,
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200226 .psm_entry_retries = 3
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300227 },
228 .init = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300229 .radioparam = {
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200230 .fem = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300231 }
Luciano Coelho6e92b412009-12-11 15:40:50 +0200232 },
233 .itrim = {
234 .enable = false,
235 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200236 },
237 .pm_config = {
238 .host_clk_settling_time = 5000,
239 .host_fast_wakeup_support = false
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300240 }
241};
242
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300243static LIST_HEAD(wl_list);
244
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300245static void wl1271_conf_init(struct wl1271 *wl)
246{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300247
248 /*
249 * This function applies the default configuration to the driver. This
250 * function is invoked upon driver load (spi probe.)
251 *
252 * The configuration is stored in a run-time structure in order to
253 * facilitate for run-time adjustment of any of the parameters. Making
254 * changes to the configuration structure will apply the new values on
255 * the next interface up (wl1271_op_start.)
256 */
257
258 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300259 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300260}
261
262
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300263static int wl1271_plt_init(struct wl1271 *wl)
264{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200265 struct conf_tx_ac_category *conf_ac;
266 struct conf_tx_tid *conf_tid;
267 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300268
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200269 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200270 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200271 return ret;
272
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200273 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200274 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200275 return ret;
276
Luciano Coelho12419cc2010-02-18 13:25:44 +0200277 ret = wl1271_init_templates_config(wl);
278 if (ret < 0)
279 return ret;
280
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300281 ret = wl1271_acx_init_mem_config(wl);
282 if (ret < 0)
283 return ret;
284
Luciano Coelho12419cc2010-02-18 13:25:44 +0200285 /* PHY layer config */
286 ret = wl1271_init_phy_config(wl);
287 if (ret < 0)
288 goto out_free_memmap;
289
290 ret = wl1271_acx_dco_itrim_params(wl);
291 if (ret < 0)
292 goto out_free_memmap;
293
294 /* Initialize connection monitoring thresholds */
295 ret = wl1271_acx_conn_monit_params(wl);
296 if (ret < 0)
297 goto out_free_memmap;
298
299 /* Bluetooth WLAN coexistence */
300 ret = wl1271_init_pta(wl);
301 if (ret < 0)
302 goto out_free_memmap;
303
304 /* Energy detection */
305 ret = wl1271_init_energy_detection(wl);
306 if (ret < 0)
307 goto out_free_memmap;
308
309 /* Default fragmentation threshold */
310 ret = wl1271_acx_frag_threshold(wl);
311 if (ret < 0)
312 goto out_free_memmap;
313
314 /* Default TID configuration */
315 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
316 conf_tid = &wl->conf.tx.tid_conf[i];
317 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
318 conf_tid->channel_type,
319 conf_tid->tsid,
320 conf_tid->ps_scheme,
321 conf_tid->ack_policy,
322 conf_tid->apsd_conf[0],
323 conf_tid->apsd_conf[1]);
324 if (ret < 0)
325 goto out_free_memmap;
326 }
327
328 /* Default AC configuration */
329 for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
330 conf_ac = &wl->conf.tx.ac_conf[i];
331 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
332 conf_ac->cw_max, conf_ac->aifsn,
333 conf_ac->tx_op_limit);
334 if (ret < 0)
335 goto out_free_memmap;
336 }
337
338 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200339 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300340 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200341 goto out_free_memmap;
342
343 /* Configure for CAM power saving (ie. always active) */
344 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
345 if (ret < 0)
346 goto out_free_memmap;
347
348 /* configure PM */
349 ret = wl1271_acx_pm_config(wl);
350 if (ret < 0)
351 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300352
353 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200354
355 out_free_memmap:
356 kfree(wl->target_mem_map);
357 wl->target_mem_map = NULL;
358
359 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300360}
361
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300362static void wl1271_power_off(struct wl1271 *wl)
363{
364 wl->set_power(false);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200365 clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300366}
367
368static void wl1271_power_on(struct wl1271 *wl)
369{
370 wl->set_power(true);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200371 set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300372}
373
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300374static void wl1271_fw_status(struct wl1271 *wl,
375 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300376{
377 u32 total = 0;
378 int i;
379
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200380 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300381
382 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
383 "drv_rx_counter = %d, tx_results_counter = %d)",
384 status->intr,
385 status->fw_rx_counter,
386 status->drv_rx_counter,
387 status->tx_results_counter);
388
389 /* update number of available TX blocks */
390 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300391 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
392 wl->tx_blocks_freed[i];
393
394 wl->tx_blocks_freed[i] =
395 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300396 wl->tx_blocks_available += cnt;
397 total += cnt;
398 }
399
400 /* if more blocks are available now, schedule some tx work */
401 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300402 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300403
404 /* update the host-chipset time offset */
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300405 wl->time_offset = jiffies_to_usecs(jiffies) -
406 le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300407}
408
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200409#define WL1271_IRQ_MAX_LOOPS 10
410
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300411static void wl1271_irq_work(struct work_struct *work)
412{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300413 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300414 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200415 int loopcount = WL1271_IRQ_MAX_LOOPS;
416 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300417 struct wl1271 *wl =
418 container_of(work, struct wl1271, irq_work);
419
420 mutex_lock(&wl->mutex);
421
422 wl1271_debug(DEBUG_IRQ, "IRQ work");
423
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200424 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300425 goto out;
426
427 ret = wl1271_ps_elp_wakeup(wl, true);
428 if (ret < 0)
429 goto out;
430
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200431 spin_lock_irqsave(&wl->wl_lock, flags);
432 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
433 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
434 spin_unlock_irqrestore(&wl->wl_lock, flags);
435 loopcount--;
436
437 wl1271_fw_status(wl, wl->fw_status);
438 intr = le32_to_cpu(wl->fw_status->intr);
439 if (!intr) {
440 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
441 continue;
442 }
443
444 intr &= WL1271_INTR_MASK;
445
446 if (intr & WL1271_ACX_INTR_DATA) {
447 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
448
449 /* check for tx results */
450 if (wl->fw_status->tx_results_counter !=
451 (wl->tx_results_count & 0xff))
452 wl1271_tx_complete(wl);
453
454 wl1271_rx(wl, wl->fw_status);
455 }
456
457 if (intr & WL1271_ACX_INTR_EVENT_A) {
458 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
459 wl1271_event_handle(wl, 0);
460 }
461
462 if (intr & WL1271_ACX_INTR_EVENT_B) {
463 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
464 wl1271_event_handle(wl, 1);
465 }
466
467 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
468 wl1271_debug(DEBUG_IRQ,
469 "WL1271_ACX_INTR_INIT_COMPLETE");
470
471 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
472 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
473
474 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300475 }
476
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200477 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
478 ieee80211_queue_work(wl->hw, &wl->irq_work);
479 else
480 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
481 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300482
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300483 wl1271_ps_elp_sleep(wl);
484
485out:
486 mutex_unlock(&wl->mutex);
487}
488
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300489static int wl1271_fetch_firmware(struct wl1271 *wl)
490{
491 const struct firmware *fw;
492 int ret;
493
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200494 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300495
496 if (ret < 0) {
497 wl1271_error("could not get firmware: %d", ret);
498 return ret;
499 }
500
501 if (fw->size % 4) {
502 wl1271_error("firmware size is not multiple of 32 bits: %zu",
503 fw->size);
504 ret = -EILSEQ;
505 goto out;
506 }
507
508 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300509 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300510
511 if (!wl->fw) {
512 wl1271_error("could not allocate memory for the firmware");
513 ret = -ENOMEM;
514 goto out;
515 }
516
517 memcpy(wl->fw, fw->data, wl->fw_len);
518
519 ret = 0;
520
521out:
522 release_firmware(fw);
523
524 return ret;
525}
526
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200527static int wl1271_update_mac_addr(struct wl1271 *wl)
528{
529 int ret = 0;
530 u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
531
532 /* get mac address from the NVS */
533 wl->mac_addr[0] = nvs_ptr[11];
534 wl->mac_addr[1] = nvs_ptr[10];
535 wl->mac_addr[2] = nvs_ptr[6];
536 wl->mac_addr[3] = nvs_ptr[5];
537 wl->mac_addr[4] = nvs_ptr[4];
538 wl->mac_addr[5] = nvs_ptr[3];
539
540 /* FIXME: if it is a zero-address, we should bail out. Now, instead,
541 we randomize an address */
542 if (is_zero_ether_addr(wl->mac_addr)) {
543 static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
544 memcpy(wl->mac_addr, nokia_oui, 3);
545 get_random_bytes(wl->mac_addr + 3, 3);
Juuso Oikarinene2e77b52010-02-18 13:25:46 +0200546
547 /* update this address to the NVS */
548 nvs_ptr[11] = wl->mac_addr[0];
549 nvs_ptr[10] = wl->mac_addr[1];
550 nvs_ptr[6] = wl->mac_addr[2];
551 nvs_ptr[5] = wl->mac_addr[3];
552 nvs_ptr[4] = wl->mac_addr[4];
553 nvs_ptr[3] = wl->mac_addr[5];
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200554 }
555
556 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
557
558 return ret;
559}
560
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300561static int wl1271_fetch_nvs(struct wl1271 *wl)
562{
563 const struct firmware *fw;
564 int ret;
565
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200566 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300567
568 if (ret < 0) {
569 wl1271_error("could not get nvs file: %d", ret);
570 return ret;
571 }
572
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200573 if (fw->size != sizeof(struct wl1271_nvs_file)) {
574 wl1271_error("nvs size is not as expected: %zu != %zu",
575 fw->size, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300576 ret = -EILSEQ;
577 goto out;
578 }
579
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200580 wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300581
582 if (!wl->nvs) {
583 wl1271_error("could not allocate memory for the nvs file");
584 ret = -ENOMEM;
585 goto out;
586 }
587
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200588 memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300589
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200590 ret = wl1271_update_mac_addr(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300591
592out:
593 release_firmware(fw);
594
595 return ret;
596}
597
598static void wl1271_fw_wakeup(struct wl1271 *wl)
599{
600 u32 elp_reg;
601
602 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300603 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300604}
605
606static int wl1271_setup(struct wl1271 *wl)
607{
608 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
609 if (!wl->fw_status)
610 return -ENOMEM;
611
612 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
613 if (!wl->tx_res_if) {
614 kfree(wl->fw_status);
615 return -ENOMEM;
616 }
617
618 INIT_WORK(&wl->irq_work, wl1271_irq_work);
619 INIT_WORK(&wl->tx_work, wl1271_tx_work);
620 return 0;
621}
622
623static int wl1271_chip_wakeup(struct wl1271 *wl)
624{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300625 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300626 int ret = 0;
627
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200628 msleep(WL1271_PRE_POWER_ON_SLEEP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300629 wl1271_power_on(wl);
630 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200631 wl1271_io_reset(wl);
632 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300633
634 /* We don't need a real memory partition here, because we only want
635 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300636 memset(&partition, 0, sizeof(partition));
637 partition.reg.start = REGISTERS_BASE;
638 partition.reg.size = REGISTERS_DOWN_SIZE;
639 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300640
641 /* ELP module wake up */
642 wl1271_fw_wakeup(wl);
643
644 /* whal_FwCtrl_BootSm() */
645
646 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200647 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300648
649 /* 1. check if chip id is valid */
650
651 switch (wl->chip.id) {
652 case CHIP_ID_1271_PG10:
653 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
654 wl->chip.id);
655
656 ret = wl1271_setup(wl);
657 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200658 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300659 break;
660 case CHIP_ID_1271_PG20:
661 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
662 wl->chip.id);
663
664 ret = wl1271_setup(wl);
665 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200666 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300667 break;
668 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200669 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300670 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200671 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300672 }
673
674 if (wl->fw == NULL) {
675 ret = wl1271_fetch_firmware(wl);
676 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200677 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300678 }
679
680 /* No NVS from netlink, try to get it from the filesystem */
681 if (wl->nvs == NULL) {
682 ret = wl1271_fetch_nvs(wl);
683 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200684 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300685 }
686
687out:
688 return ret;
689}
690
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300691int wl1271_plt_start(struct wl1271 *wl)
692{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200693 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300694 int ret;
695
696 mutex_lock(&wl->mutex);
697
698 wl1271_notice("power up");
699
700 if (wl->state != WL1271_STATE_OFF) {
701 wl1271_error("cannot go into PLT state because not "
702 "in off state: %d", wl->state);
703 ret = -EBUSY;
704 goto out;
705 }
706
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200707 while (retries) {
708 retries--;
709 ret = wl1271_chip_wakeup(wl);
710 if (ret < 0)
711 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300712
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200713 ret = wl1271_boot(wl);
714 if (ret < 0)
715 goto power_off;
716
717 ret = wl1271_plt_init(wl);
718 if (ret < 0)
719 goto irq_disable;
720
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200721 wl->state = WL1271_STATE_PLT;
722 wl1271_notice("firmware booted in PLT mode (%s)",
723 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300724 goto out;
725
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200726irq_disable:
727 wl1271_disable_interrupts(wl);
728 mutex_unlock(&wl->mutex);
729 /* Unlocking the mutex in the middle of handling is
730 inherently unsafe. In this case we deem it safe to do,
731 because we need to let any possibly pending IRQ out of
732 the system (and while we are WL1271_STATE_OFF the IRQ
733 work function will not do anything.) Also, any other
734 possible concurrent operations will fail due to the
735 current state, hence the wl1271 struct should be safe. */
736 cancel_work_sync(&wl->irq_work);
737 mutex_lock(&wl->mutex);
738power_off:
739 wl1271_power_off(wl);
740 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300741
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200742 wl1271_error("firmware boot in PLT mode failed despite %d retries",
743 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300744out:
745 mutex_unlock(&wl->mutex);
746
747 return ret;
748}
749
750int wl1271_plt_stop(struct wl1271 *wl)
751{
752 int ret = 0;
753
754 mutex_lock(&wl->mutex);
755
756 wl1271_notice("power down");
757
758 if (wl->state != WL1271_STATE_PLT) {
759 wl1271_error("cannot power down because not in PLT "
760 "state: %d", wl->state);
761 ret = -EBUSY;
762 goto out;
763 }
764
765 wl1271_disable_interrupts(wl);
766 wl1271_power_off(wl);
767
768 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300769 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300770
771out:
772 mutex_unlock(&wl->mutex);
773
774 return ret;
775}
776
777
778static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
779{
780 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200781 struct ieee80211_conf *conf = &hw->conf;
782 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
783 struct ieee80211_sta *sta = txinfo->control.sta;
784 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300785
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200786 /* peek into the rates configured in the STA entry */
787 spin_lock_irqsave(&wl->wl_lock, flags);
788 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
789 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
790 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
791 }
792 spin_unlock_irqrestore(&wl->wl_lock, flags);
793
794 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300795 skb_queue_tail(&wl->tx_queue, skb);
796
797 /*
798 * The chip specific setup must run before the first TX packet -
799 * before that, the tx_work will not be initialized!
800 */
801
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300802 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300803
804 /*
805 * The workqueue is slow to process the tx_queue and we need stop
806 * the queue here, otherwise the queue will get too long.
807 */
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200808 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
809 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300810
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200811 spin_lock_irqsave(&wl->wl_lock, flags);
812 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200813 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200814 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300815 }
816
817 return NETDEV_TX_OK;
818}
819
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300820static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
821 void *arg)
822{
823 struct net_device *dev;
824 struct wireless_dev *wdev;
825 struct wiphy *wiphy;
826 struct ieee80211_hw *hw;
827 struct wl1271 *wl;
828 struct wl1271 *wl_temp;
829 struct in_device *idev;
830 struct in_ifaddr *ifa = arg;
831 int ret = 0;
832
833 /* FIXME: this ugly function should probably be implemented in the
834 * mac80211, and here should only be a simple callback handling actual
835 * setting of the filters. Now we need to dig up references to
836 * various structures to gain access to what we need.
837 * Also, because of this, there is no "initial" setting of the filter
838 * in "op_start", because we don't want to dig up struct net_device
839 * there - the filter will be set upon first change of the interface
840 * IP address. */
841
842 dev = ifa->ifa_dev->dev;
843
844 wdev = dev->ieee80211_ptr;
845 if (wdev == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200846 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300847
848 wiphy = wdev->wiphy;
849 if (wiphy == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200850 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300851
852 hw = wiphy_priv(wiphy);
853 if (hw == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200854 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300855
856 /* Check that the interface is one supported by this driver. */
857 wl_temp = hw->priv;
858 list_for_each_entry(wl, &wl_list, list) {
859 if (wl == wl_temp)
860 break;
861 }
862 if (wl == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200863 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300864
865 /* Get the interface IP address for the device. "ifa" will become
866 NULL if:
867 - there is no IPV4 protocol address configured
868 - there are multiple (virtual) IPV4 addresses configured
869 When "ifa" is NULL, filtering will be disabled.
870 */
871 ifa = NULL;
872 idev = dev->ip_ptr;
873 if (idev)
874 ifa = idev->ifa_list;
875
876 if (ifa && ifa->ifa_next)
877 ifa = NULL;
878
879 mutex_lock(&wl->mutex);
880
881 if (wl->state == WL1271_STATE_OFF)
882 goto out;
883
884 ret = wl1271_ps_elp_wakeup(wl, false);
885 if (ret < 0)
886 goto out;
887 if (ifa)
888 ret = wl1271_acx_arp_ip_filter(wl, true,
889 (u8 *)&ifa->ifa_address,
890 ACX_IPV4_VERSION);
891 else
892 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
893 ACX_IPV4_VERSION);
894 wl1271_ps_elp_sleep(wl);
895
896out:
897 mutex_unlock(&wl->mutex);
898
Luciano Coelho17d72652009-11-23 23:22:15 +0200899 return NOTIFY_OK;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300900}
901
902static struct notifier_block wl1271_dev_notifier = {
903 .notifier_call = wl1271_dev_notify,
904};
905
906
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300907static int wl1271_op_start(struct ieee80211_hw *hw)
908{
909 struct wl1271 *wl = hw->priv;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200910 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300911 int ret = 0;
912
913 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
914
915 mutex_lock(&wl->mutex);
916
917 if (wl->state != WL1271_STATE_OFF) {
918 wl1271_error("cannot start because not in off state: %d",
919 wl->state);
920 ret = -EBUSY;
921 goto out;
922 }
923
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200924 while (retries) {
925 retries--;
926 ret = wl1271_chip_wakeup(wl);
927 if (ret < 0)
928 goto power_off;
929
930 ret = wl1271_boot(wl);
931 if (ret < 0)
932 goto power_off;
933
934 ret = wl1271_hw_init(wl);
935 if (ret < 0)
936 goto irq_disable;
937
938 wl->state = WL1271_STATE_ON;
939 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300940 goto out;
941
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200942irq_disable:
943 wl1271_disable_interrupts(wl);
944 mutex_unlock(&wl->mutex);
945 /* Unlocking the mutex in the middle of handling is
946 inherently unsafe. In this case we deem it safe to do,
947 because we need to let any possibly pending IRQ out of
948 the system (and while we are WL1271_STATE_OFF the IRQ
949 work function will not do anything.) Also, any other
950 possible concurrent operations will fail due to the
951 current state, hence the wl1271 struct should be safe. */
952 cancel_work_sync(&wl->irq_work);
953 mutex_lock(&wl->mutex);
954power_off:
955 wl1271_power_off(wl);
956 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300957
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200958 wl1271_error("firmware boot failed despite %d retries",
959 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300960out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300961 mutex_unlock(&wl->mutex);
962
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300963 if (!ret) {
964 list_add(&wl->list, &wl_list);
965 register_inetaddr_notifier(&wl1271_dev_notifier);
966 }
967
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300968 return ret;
969}
970
971static void wl1271_op_stop(struct ieee80211_hw *hw)
972{
973 struct wl1271 *wl = hw->priv;
974 int i;
975
976 wl1271_info("down");
977
978 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
979
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300980 unregister_inetaddr_notifier(&wl1271_dev_notifier);
981 list_del(&wl->list);
982
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300983 mutex_lock(&wl->mutex);
984
985 WARN_ON(wl->state != WL1271_STATE_ON);
986
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200987 if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300988 mutex_unlock(&wl->mutex);
989 ieee80211_scan_completed(wl->hw, true);
990 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300991 }
992
993 wl->state = WL1271_STATE_OFF;
994
995 wl1271_disable_interrupts(wl);
996
997 mutex_unlock(&wl->mutex);
998
999 cancel_work_sync(&wl->irq_work);
1000 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001001
1002 mutex_lock(&wl->mutex);
1003
1004 /* let's notify MAC80211 about the remaining pending TX frames */
1005 wl1271_tx_flush(wl);
1006 wl1271_power_off(wl);
1007
1008 memset(wl->bssid, 0, ETH_ALEN);
1009 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1010 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001011 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001012 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001013
1014 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001015 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001016 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1017 wl->tx_blocks_available = 0;
1018 wl->tx_results_count = 0;
1019 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001020 wl->tx_security_last_seq = 0;
1021 wl->tx_security_seq_16 = 0;
1022 wl->tx_security_seq_32 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001023 wl->time_offset = 0;
1024 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001025 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1026 wl->sta_rate_set = 0;
1027 wl->flags = 0;
Luciano Coelhod6e19d132009-10-12 15:08:43 +03001028
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001029 for (i = 0; i < NUM_TX_QUEUES; i++)
1030 wl->tx_blocks_freed[i] = 0;
1031
1032 wl1271_debugfs_reset(wl);
1033 mutex_unlock(&wl->mutex);
1034}
1035
1036static int wl1271_op_add_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +01001037 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001038{
1039 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001040 int ret = 0;
1041
John W. Linvillee5539bc2009-08-18 10:50:34 -04001042 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Johannes Berg1ed32e42009-12-23 13:15:45 +01001043 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001044
1045 mutex_lock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001046 if (wl->vif) {
1047 ret = -EBUSY;
1048 goto out;
1049 }
1050
Johannes Berg1ed32e42009-12-23 13:15:45 +01001051 wl->vif = vif;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001052
Johannes Berg1ed32e42009-12-23 13:15:45 +01001053 switch (vif->type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001054 case NL80211_IFTYPE_STATION:
1055 wl->bss_type = BSS_TYPE_STA_BSS;
1056 break;
1057 case NL80211_IFTYPE_ADHOC:
1058 wl->bss_type = BSS_TYPE_IBSS;
1059 break;
1060 default:
1061 ret = -EOPNOTSUPP;
1062 goto out;
1063 }
1064
1065 /* FIXME: what if conf->mac_addr changes? */
1066
1067out:
1068 mutex_unlock(&wl->mutex);
1069 return ret;
1070}
1071
1072static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +01001073 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001074{
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001075 struct wl1271 *wl = hw->priv;
1076
1077 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001078 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001079 wl->vif = NULL;
1080 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001081}
1082
1083#if 0
1084static int wl1271_op_config_interface(struct ieee80211_hw *hw,
1085 struct ieee80211_vif *vif,
1086 struct ieee80211_if_conf *conf)
1087{
1088 struct wl1271 *wl = hw->priv;
1089 struct sk_buff *beacon;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001090 int ret;
1091
David S. Miller32646902009-09-17 10:18:30 -07001092 wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM",
1093 conf->bssid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001094 wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid,
1095 conf->ssid_len);
1096
1097 mutex_lock(&wl->mutex);
1098
1099 ret = wl1271_ps_elp_wakeup(wl, false);
1100 if (ret < 0)
1101 goto out;
1102
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001103 if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
1104 wl1271_debug(DEBUG_MAC80211, "bssid changed");
1105
1106 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
1107
Juuso Oikarinen15305492010-02-22 08:38:32 +02001108 ret = wl1271_cmd_join(wl, wl->bss_type);
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001109 if (ret < 0)
1110 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001111
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001112 ret = wl1271_cmd_build_null_data(wl);
1113 if (ret < 0)
1114 goto out_sleep;
1115 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001116
1117 wl->ssid_len = conf->ssid_len;
1118 if (wl->ssid_len)
1119 memcpy(wl->ssid, conf->ssid, wl->ssid_len);
1120
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001121 if (conf->changed & IEEE80211_IFCC_BEACON) {
1122 beacon = ieee80211_beacon_get(hw, vif);
1123 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1124 beacon->data, beacon->len);
1125
1126 if (ret < 0) {
1127 dev_kfree_skb(beacon);
1128 goto out_sleep;
1129 }
1130
1131 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE,
1132 beacon->data, beacon->len);
1133
1134 dev_kfree_skb(beacon);
1135
1136 if (ret < 0)
1137 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001138 }
1139
1140out_sleep:
1141 wl1271_ps_elp_sleep(wl);
1142
1143out:
1144 mutex_unlock(&wl->mutex);
1145
1146 return ret;
1147}
1148#endif
1149
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001150static int wl1271_join_channel(struct wl1271 *wl, int channel)
1151{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001152 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001153 /* we need to use a dummy BSSID for now */
1154 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1155 0xad, 0xbe, 0xef };
1156
1157 /* disable mac filter, so we hear everything */
1158 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1159
1160 wl->channel = channel;
1161 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1162
Juuso Oikarinen15305492010-02-22 08:38:32 +02001163 /* the dummy join is performed always with STATION BSS type to allow
1164 also ad-hoc mode to listen to the surroundings without sending any
1165 beacons yet. */
1166 ret = wl1271_cmd_join(wl, BSS_TYPE_STA_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001167 if (ret < 0)
1168 goto out;
1169
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001170 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001171
1172out:
1173 return ret;
1174}
1175
1176static int wl1271_unjoin_channel(struct wl1271 *wl)
1177{
1178 int ret;
1179
1180 /* to stop listening to a channel, we disconnect */
1181 ret = wl1271_cmd_disconnect(wl);
1182 if (ret < 0)
1183 goto out;
1184
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001185 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001186 wl->channel = 0;
1187 memset(wl->bssid, 0, ETH_ALEN);
1188 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1189
1190out:
1191 return ret;
1192}
1193
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001194static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1195{
1196 struct wl1271 *wl = hw->priv;
1197 struct ieee80211_conf *conf = &hw->conf;
1198 int channel, ret = 0;
1199
1200 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1201
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001202 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001203 channel,
1204 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001205 conf->power_level,
1206 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001207
1208 mutex_lock(&wl->mutex);
1209
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001210 wl->band = conf->channel->band;
1211
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001212 ret = wl1271_ps_elp_wakeup(wl, false);
1213 if (ret < 0)
1214 goto out;
1215
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001216 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001217 if (conf->flags & IEEE80211_CONF_IDLE &&
1218 test_bit(WL1271_FLAG_JOINED, &wl->flags))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001219 wl1271_unjoin_channel(wl);
Juuso Oikarinen8f648c02009-12-11 15:41:10 +02001220 else if (!(conf->flags & IEEE80211_CONF_IDLE))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001221 wl1271_join_channel(wl, channel);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001222
1223 if (conf->flags & IEEE80211_CONF_IDLE) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001224 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1225 wl->sta_rate_set = 0;
1226 wl1271_acx_rate_policies(wl);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001227 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001228 }
1229
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001230 /* if the channel changes while joined, join again */
Juuso Oikarinenddb01a52010-02-18 13:25:37 +02001231 if (channel != wl->channel &&
1232 test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1233 wl->channel = channel;
1234 /* FIXME: maybe use CMD_CHANNEL_SWITCH for this? */
Juuso Oikarinen15305492010-02-22 08:38:32 +02001235 ret = wl1271_cmd_join(wl, wl->bss_type);
Juuso Oikarinenddb01a52010-02-18 13:25:37 +02001236 if (ret < 0)
1237 wl1271_warning("cmd join to update channel failed %d",
1238 ret);
1239 } else
1240 wl->channel = channel;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001241
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001242 if (conf->flags & IEEE80211_CONF_PS &&
1243 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1244 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001245
1246 /*
1247 * We enter PSM only if we're already associated.
1248 * If we're not, we'll enter it when joining an SSID,
1249 * through the bss_info_changed() hook.
1250 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001251 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001252 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001253 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1254 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001255 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001256 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001257 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001258 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001259
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001260 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001261
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001262 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001263 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1264 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001265 }
1266
1267 if (conf->power_level != wl->power_level) {
1268 ret = wl1271_acx_tx_power(wl, conf->power_level);
1269 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001270 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001271
1272 wl->power_level = conf->power_level;
1273 }
1274
1275out_sleep:
1276 wl1271_ps_elp_sleep(wl);
1277
1278out:
1279 mutex_unlock(&wl->mutex);
1280
1281 return ret;
1282}
1283
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001284struct wl1271_filter_params {
1285 bool enabled;
1286 int mc_list_length;
1287 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1288};
1289
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001290static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1291 struct dev_addr_list *mc_list)
1292{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001293 struct wl1271_filter_params *fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001294 int i;
1295
Juuso Oikarinen74441132009-10-13 12:47:53 +03001296 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001297 if (!fp) {
1298 wl1271_error("Out of memory setting filters.");
1299 return 0;
1300 }
1301
1302 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001303 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001304 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1305 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001306 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001307 }
1308
1309 fp->mc_list_length = 0;
1310 for (i = 0; i < mc_count; i++) {
1311 if (mc_list->da_addrlen == ETH_ALEN) {
1312 memcpy(fp->mc_list[fp->mc_list_length],
1313 mc_list->da_addr, ETH_ALEN);
1314 fp->mc_list_length++;
1315 } else
1316 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001317 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001318 }
1319
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001320 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001321}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001322
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001323#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1324 FIF_ALLMULTI | \
1325 FIF_FCSFAIL | \
1326 FIF_BCN_PRBRESP_PROMISC | \
1327 FIF_CONTROL | \
1328 FIF_OTHER_BSS)
1329
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001330static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1331 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001332 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001333{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001334 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001335 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001336 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001337
1338 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1339
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001340 mutex_lock(&wl->mutex);
1341
1342 if (wl->state == WL1271_STATE_OFF)
1343 goto out;
1344
1345 ret = wl1271_ps_elp_wakeup(wl, false);
1346 if (ret < 0)
1347 goto out;
1348
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001349 *total &= WL1271_SUPPORTED_FILTERS;
1350 changed &= WL1271_SUPPORTED_FILTERS;
1351
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001352 if (*total & FIF_ALLMULTI)
1353 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1354 else if (fp)
1355 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1356 fp->mc_list,
1357 fp->mc_list_length);
1358 if (ret < 0)
1359 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001360
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001361 kfree(fp);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001362
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001363 /* FIXME: We still need to set our filters properly */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001364
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001365 /* determine, whether supported filter values have changed */
1366 if (changed == 0)
1367 goto out_sleep;
1368
1369 /* apply configured filters */
1370 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1371 if (ret < 0)
1372 goto out_sleep;
1373
1374out_sleep:
1375 wl1271_ps_elp_sleep(wl);
1376
1377out:
1378 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001379}
1380
1381static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1382 struct ieee80211_vif *vif,
1383 struct ieee80211_sta *sta,
1384 struct ieee80211_key_conf *key_conf)
1385{
1386 struct wl1271 *wl = hw->priv;
1387 const u8 *addr;
1388 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001389 u32 tx_seq_32 = 0;
1390 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001391 u8 key_type;
1392
1393 static const u8 bcast_addr[ETH_ALEN] =
1394 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1395
1396 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1397
1398 addr = sta ? sta->addr : bcast_addr;
1399
1400 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1401 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1402 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1403 key_conf->alg, key_conf->keyidx,
1404 key_conf->keylen, key_conf->flags);
1405 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1406
1407 if (is_zero_ether_addr(addr)) {
1408 /* We dont support TX only encryption */
1409 ret = -EOPNOTSUPP;
1410 goto out;
1411 }
1412
1413 mutex_lock(&wl->mutex);
1414
1415 ret = wl1271_ps_elp_wakeup(wl, false);
1416 if (ret < 0)
1417 goto out_unlock;
1418
1419 switch (key_conf->alg) {
1420 case ALG_WEP:
1421 key_type = KEY_WEP;
1422
1423 key_conf->hw_key_idx = key_conf->keyidx;
1424 break;
1425 case ALG_TKIP:
1426 key_type = KEY_TKIP;
1427
1428 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001429 tx_seq_32 = wl->tx_security_seq_32;
1430 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001431 break;
1432 case ALG_CCMP:
1433 key_type = KEY_AES;
1434
1435 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001436 tx_seq_32 = wl->tx_security_seq_32;
1437 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001438 break;
1439 default:
1440 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1441
1442 ret = -EOPNOTSUPP;
1443 goto out_sleep;
1444 }
1445
1446 switch (cmd) {
1447 case SET_KEY:
1448 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1449 key_conf->keyidx, key_type,
1450 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001451 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001452 if (ret < 0) {
1453 wl1271_error("Could not add or replace key");
1454 goto out_sleep;
1455 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001456
1457 /* the default WEP key needs to be configured at least once */
1458 if (key_type == KEY_WEP) {
1459 ret = wl1271_cmd_set_default_wep_key(wl,
1460 wl->default_key);
1461 if (ret < 0)
1462 goto out_sleep;
1463 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001464 break;
1465
1466 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001467 /* The wl1271 does not allow to remove unicast keys - they
1468 will be cleared automatically on next CMD_JOIN. Ignore the
1469 request silently, as we dont want the mac80211 to emit
1470 an error message. */
1471 if (!is_broadcast_ether_addr(addr))
1472 break;
1473
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001474 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1475 key_conf->keyidx, key_type,
1476 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001477 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001478 if (ret < 0) {
1479 wl1271_error("Could not remove key");
1480 goto out_sleep;
1481 }
1482 break;
1483
1484 default:
1485 wl1271_error("Unsupported key cmd 0x%x", cmd);
1486 ret = -EOPNOTSUPP;
1487 goto out_sleep;
1488
1489 break;
1490 }
1491
1492out_sleep:
1493 wl1271_ps_elp_sleep(wl);
1494
1495out_unlock:
1496 mutex_unlock(&wl->mutex);
1497
1498out:
1499 return ret;
1500}
1501
1502static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1503 struct cfg80211_scan_request *req)
1504{
1505 struct wl1271 *wl = hw->priv;
1506 int ret;
1507 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001508 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001509
1510 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1511
1512 if (req->n_ssids) {
1513 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001514 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001515 }
1516
1517 mutex_lock(&wl->mutex);
1518
1519 ret = wl1271_ps_elp_wakeup(wl, false);
1520 if (ret < 0)
1521 goto out;
1522
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001523 if (wl1271_11a_enabled())
1524 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1525 WL1271_SCAN_BAND_DUAL, 3);
1526 else
1527 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1528 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001529
1530 wl1271_ps_elp_sleep(wl);
1531
1532out:
1533 mutex_unlock(&wl->mutex);
1534
1535 return ret;
1536}
1537
1538static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1539{
1540 struct wl1271 *wl = hw->priv;
1541 int ret;
1542
1543 mutex_lock(&wl->mutex);
1544
1545 ret = wl1271_ps_elp_wakeup(wl, false);
1546 if (ret < 0)
1547 goto out;
1548
1549 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1550 if (ret < 0)
1551 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1552
1553 wl1271_ps_elp_sleep(wl);
1554
1555out:
1556 mutex_unlock(&wl->mutex);
1557
1558 return ret;
1559}
1560
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001561static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1562{
1563 u8 *ptr = beacon->data +
1564 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1565
1566 /* find the location of the ssid in the beacon */
1567 while (ptr < beacon->data + beacon->len) {
1568 if (ptr[0] == WLAN_EID_SSID) {
1569 wl->ssid_len = ptr[1];
1570 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1571 return;
1572 }
1573 ptr += ptr[1];
1574 }
1575 wl1271_error("ad-hoc beacon template has no SSID!\n");
1576}
1577
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001578static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1579 struct ieee80211_vif *vif,
1580 struct ieee80211_bss_conf *bss_conf,
1581 u32 changed)
1582{
1583 enum wl1271_cmd_ps_mode mode;
1584 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001585 bool do_join = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001586 int ret;
1587
1588 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1589
1590 mutex_lock(&wl->mutex);
1591
1592 ret = wl1271_ps_elp_wakeup(wl, false);
1593 if (ret < 0)
1594 goto out;
1595
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001596 if (wl->bss_type == BSS_TYPE_IBSS) {
1597 /* FIXME: This implements rudimentary ad-hoc support -
1598 proper templates are on the wish list and notification
1599 on when they change. This patch will update the templates
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001600 on every call to this function. */
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001601 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1602
1603 if (beacon) {
1604 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001605
1606 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001607 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1608 beacon->data,
1609 beacon->len);
1610
1611 if (ret < 0) {
1612 dev_kfree_skb(beacon);
1613 goto out_sleep;
1614 }
1615
1616 hdr = (struct ieee80211_hdr *) beacon->data;
1617 hdr->frame_control = cpu_to_le16(
1618 IEEE80211_FTYPE_MGMT |
1619 IEEE80211_STYPE_PROBE_RESP);
1620
1621 ret = wl1271_cmd_template_set(wl,
1622 CMD_TEMPL_PROBE_RESPONSE,
1623 beacon->data,
1624 beacon->len);
1625 dev_kfree_skb(beacon);
1626 if (ret < 0)
1627 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001628
1629 /* Need to update the SSID (for filtering etc) */
1630 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001631 }
1632 }
1633
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001634 if ((changed & BSS_CHANGED_BSSID) &&
1635 /*
1636 * Now we know the correct bssid, so we send a new join command
1637 * and enable the BSSID filter
1638 */
1639 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
1640 wl->rx_config |= CFG_BSSID_FILTER_EN;
1641 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
1642 ret = wl1271_cmd_build_null_data(wl);
1643 if (ret < 0) {
1644 wl1271_warning("cmd buld null data failed %d",
1645 ret);
1646 goto out_sleep;
1647 }
1648
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001649 /* Need to update the BSSID (for filtering etc) */
1650 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001651 }
1652
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001653 if (changed & BSS_CHANGED_ASSOC) {
1654 if (bss_conf->assoc) {
1655 wl->aid = bss_conf->aid;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001656 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001657
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001658 /*
1659 * with wl1271, we don't need to update the
1660 * beacon_int and dtim_period, because the firmware
1661 * updates it by itself when the first beacon is
1662 * received after a join.
1663 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001664 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1665 if (ret < 0)
1666 goto out_sleep;
1667
1668 ret = wl1271_acx_aid(wl, wl->aid);
1669 if (ret < 0)
1670 goto out_sleep;
1671
1672 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001673 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1674 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001675 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001676 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001677 if (ret < 0)
1678 goto out_sleep;
1679 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001680 } else {
1681 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001682 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001683 wl->aid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001684 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001685
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001686 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001687
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001688 if (changed & BSS_CHANGED_ERP_SLOT) {
1689 if (bss_conf->use_short_slot)
1690 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1691 else
1692 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1693 if (ret < 0) {
1694 wl1271_warning("Set slot time failed %d", ret);
1695 goto out_sleep;
1696 }
1697 }
1698
1699 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1700 if (bss_conf->use_short_preamble)
1701 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1702 else
1703 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1704 }
1705
1706 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1707 if (bss_conf->use_cts_prot)
1708 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1709 else
1710 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1711 if (ret < 0) {
1712 wl1271_warning("Set ctsprotect failed %d", ret);
1713 goto out_sleep;
1714 }
1715 }
1716
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001717 if (do_join) {
Juuso Oikarinen15305492010-02-22 08:38:32 +02001718 ret = wl1271_cmd_join(wl, wl->bss_type);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001719 if (ret < 0) {
1720 wl1271_warning("cmd join failed %d", ret);
1721 goto out_sleep;
1722 }
1723 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1724 }
1725
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001726out_sleep:
1727 wl1271_ps_elp_sleep(wl);
1728
1729out:
1730 mutex_unlock(&wl->mutex);
1731}
1732
Kalle Valoc6999d82010-02-18 13:25:41 +02001733static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1734 const struct ieee80211_tx_queue_params *params)
1735{
1736 struct wl1271 *wl = hw->priv;
1737 int ret;
1738
1739 mutex_lock(&wl->mutex);
1740
1741 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1742
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001743 ret = wl1271_ps_elp_wakeup(wl, false);
1744 if (ret < 0)
1745 goto out;
1746
Kalle Valoc6999d82010-02-18 13:25:41 +02001747 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1748 params->cw_min, params->cw_max,
1749 params->aifs, params->txop);
1750 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001751 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001752
1753 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1754 CONF_CHANNEL_TYPE_EDCF,
1755 wl1271_tx_get_queue(queue),
1756 CONF_PS_SCHEME_LEGACY_PSPOLL,
1757 CONF_ACK_POLICY_LEGACY, 0, 0);
1758 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001759 goto out_sleep;
1760
1761out_sleep:
1762 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001763
1764out:
1765 mutex_unlock(&wl->mutex);
1766
1767 return ret;
1768}
1769
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001770
1771/* can't be const, mac80211 writes to this */
1772static struct ieee80211_rate wl1271_rates[] = {
1773 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001774 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1775 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001776 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001777 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1778 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001779 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1780 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001781 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1782 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001783 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1784 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001785 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1786 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001787 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1788 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001789 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1790 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001791 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001792 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1793 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001794 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001795 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1796 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001797 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001798 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1799 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001800 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001801 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1802 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001803 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001804 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1805 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001806 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001807 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1808 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001809 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001810 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1811 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001812};
1813
1814/* can't be const, mac80211 writes to this */
1815static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001816 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1817 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1818 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1819 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1820 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1821 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1822 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1823 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1824 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1825 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1826 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1827 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1828 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001829};
1830
1831/* can't be const, mac80211 writes to this */
1832static struct ieee80211_supported_band wl1271_band_2ghz = {
1833 .channels = wl1271_channels,
1834 .n_channels = ARRAY_SIZE(wl1271_channels),
1835 .bitrates = wl1271_rates,
1836 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1837};
1838
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001839/* 5 GHz data rates for WL1273 */
1840static struct ieee80211_rate wl1271_rates_5ghz[] = {
1841 { .bitrate = 60,
1842 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1843 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
1844 { .bitrate = 90,
1845 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1846 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
1847 { .bitrate = 120,
1848 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1849 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
1850 { .bitrate = 180,
1851 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1852 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
1853 { .bitrate = 240,
1854 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1855 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
1856 { .bitrate = 360,
1857 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1858 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
1859 { .bitrate = 480,
1860 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1861 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
1862 { .bitrate = 540,
1863 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1864 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
1865};
1866
1867/* 5 GHz band channels for WL1273 */
1868static struct ieee80211_channel wl1271_channels_5ghz[] = {
1869 { .hw_value = 183, .center_freq = 4915},
1870 { .hw_value = 184, .center_freq = 4920},
1871 { .hw_value = 185, .center_freq = 4925},
1872 { .hw_value = 187, .center_freq = 4935},
1873 { .hw_value = 188, .center_freq = 4940},
1874 { .hw_value = 189, .center_freq = 4945},
1875 { .hw_value = 192, .center_freq = 4960},
1876 { .hw_value = 196, .center_freq = 4980},
1877 { .hw_value = 7, .center_freq = 5035},
1878 { .hw_value = 8, .center_freq = 5040},
1879 { .hw_value = 9, .center_freq = 5045},
1880 { .hw_value = 11, .center_freq = 5055},
1881 { .hw_value = 12, .center_freq = 5060},
1882 { .hw_value = 16, .center_freq = 5080},
1883 { .hw_value = 34, .center_freq = 5170},
1884 { .hw_value = 36, .center_freq = 5180},
1885 { .hw_value = 38, .center_freq = 5190},
1886 { .hw_value = 40, .center_freq = 5200},
1887 { .hw_value = 42, .center_freq = 5210},
1888 { .hw_value = 44, .center_freq = 5220},
1889 { .hw_value = 46, .center_freq = 5230},
1890 { .hw_value = 48, .center_freq = 5240},
1891 { .hw_value = 52, .center_freq = 5260},
1892 { .hw_value = 56, .center_freq = 5280},
1893 { .hw_value = 60, .center_freq = 5300},
1894 { .hw_value = 64, .center_freq = 5320},
1895 { .hw_value = 100, .center_freq = 5500},
1896 { .hw_value = 104, .center_freq = 5520},
1897 { .hw_value = 108, .center_freq = 5540},
1898 { .hw_value = 112, .center_freq = 5560},
1899 { .hw_value = 116, .center_freq = 5580},
1900 { .hw_value = 120, .center_freq = 5600},
1901 { .hw_value = 124, .center_freq = 5620},
1902 { .hw_value = 128, .center_freq = 5640},
1903 { .hw_value = 132, .center_freq = 5660},
1904 { .hw_value = 136, .center_freq = 5680},
1905 { .hw_value = 140, .center_freq = 5700},
1906 { .hw_value = 149, .center_freq = 5745},
1907 { .hw_value = 153, .center_freq = 5765},
1908 { .hw_value = 157, .center_freq = 5785},
1909 { .hw_value = 161, .center_freq = 5805},
1910 { .hw_value = 165, .center_freq = 5825},
1911};
1912
1913
1914static struct ieee80211_supported_band wl1271_band_5ghz = {
1915 .channels = wl1271_channels_5ghz,
1916 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
1917 .bitrates = wl1271_rates_5ghz,
1918 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
1919};
1920
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001921static const struct ieee80211_ops wl1271_ops = {
1922 .start = wl1271_op_start,
1923 .stop = wl1271_op_stop,
1924 .add_interface = wl1271_op_add_interface,
1925 .remove_interface = wl1271_op_remove_interface,
1926 .config = wl1271_op_config,
1927/* .config_interface = wl1271_op_config_interface, */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001928 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001929 .configure_filter = wl1271_op_configure_filter,
1930 .tx = wl1271_op_tx,
1931 .set_key = wl1271_op_set_key,
1932 .hw_scan = wl1271_op_hw_scan,
1933 .bss_info_changed = wl1271_op_bss_info_changed,
1934 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02001935 .conf_tx = wl1271_op_conf_tx,
Kalle Valoc8c90872010-02-18 13:25:53 +02001936 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001937};
1938
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02001939int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001940{
1941 int ret;
1942
1943 if (wl->mac80211_registered)
1944 return 0;
1945
1946 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
1947
1948 ret = ieee80211_register_hw(wl->hw);
1949 if (ret < 0) {
1950 wl1271_error("unable to register mac80211 hw: %d", ret);
1951 return ret;
1952 }
1953
1954 wl->mac80211_registered = true;
1955
1956 wl1271_notice("loaded");
1957
1958 return 0;
1959}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02001960EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001961
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02001962int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001963{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03001964 /* The tx descriptor buffer and the TKIP space. */
1965 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
1966 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001967
1968 /* unit us */
1969 /* FIXME: find a proper value */
1970 wl->hw->channel_change_time = 10000;
1971
1972 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03001973 IEEE80211_HW_NOISE_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02001974 IEEE80211_HW_BEACON_FILTER |
1975 IEEE80211_HW_SUPPORTS_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001976
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001977 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
1978 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001979 wl->hw->wiphy->max_scan_ssids = 1;
1980 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
1981
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001982 if (wl1271_11a_enabled())
1983 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
1984
Teemu Paasikivi8197b712010-02-22 08:38:23 +02001985 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001986
1987 return 0;
1988}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02001989EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001990
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001991#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02001992
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02001993struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001994{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001995 struct ieee80211_hw *hw;
1996 struct wl1271 *wl;
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02001997 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001998
1999 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2000 if (!hw) {
2001 wl1271_error("could not alloc ieee80211_hw");
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002002 return ERR_PTR(-ENOMEM);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002003 }
2004
2005 wl = hw->priv;
2006 memset(wl, 0, sizeof(*wl));
2007
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002008 INIT_LIST_HEAD(&wl->list);
2009
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002010 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002011
2012 skb_queue_head_init(&wl->tx_queue);
2013
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002014 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002015 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002016 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002017 wl->rx_counter = 0;
2018 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2019 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002020 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002021 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002022 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002023 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2024 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002025 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002026 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002027 wl->flags = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002028
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002029 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002030 wl->tx_frames[i] = NULL;
2031
2032 spin_lock_init(&wl->wl_lock);
2033
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002034 wl->state = WL1271_STATE_OFF;
2035 mutex_init(&wl->mutex);
2036
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002037 /* Apply default driver configuration. */
2038 wl1271_conf_init(wl);
2039
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002040 wl1271_debugfs_init(wl);
2041
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002042 return hw;
2043}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002044EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002045
2046int wl1271_free_hw(struct wl1271 *wl)
2047{
2048 ieee80211_unregister_hw(wl->hw);
2049
2050 wl1271_debugfs_exit(wl);
2051
2052 kfree(wl->target_mem_map);
2053 vfree(wl->fw);
2054 wl->fw = NULL;
2055 kfree(wl->nvs);
2056 wl->nvs = NULL;
2057
2058 kfree(wl->fw_status);
2059 kfree(wl->tx_res_if);
2060
2061 ieee80211_free_hw(wl->hw);
2062
2063 return 0;
2064}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002065EXPORT_SYMBOL_GPL(wl1271_free_hw);
2066
2067MODULE_LICENSE("GPL");
2068MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2069MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");