blob: 0a4ff7b02f5999d3169a7f6e9e79f3979f7e60cc [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 Coelho12419cce2010-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 Coelho12419cce2010-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 Coelho12419cce2010-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 Coelho12419cce2010-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 Coelho12419cce2010-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{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200377 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300378 u32 total = 0;
379 int i;
380
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200381 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300382
383 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
384 "drv_rx_counter = %d, tx_results_counter = %d)",
385 status->intr,
386 status->fw_rx_counter,
387 status->drv_rx_counter,
388 status->tx_results_counter);
389
390 /* update number of available TX blocks */
391 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300392 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
393 wl->tx_blocks_freed[i];
394
395 wl->tx_blocks_freed[i] =
396 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300397 wl->tx_blocks_available += cnt;
398 total += cnt;
399 }
400
401 /* if more blocks are available now, schedule some tx work */
402 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300403 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300404
405 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200406 getnstimeofday(&ts);
407 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
408 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300409}
410
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200411#define WL1271_IRQ_MAX_LOOPS 10
412
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300413static void wl1271_irq_work(struct work_struct *work)
414{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300415 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300416 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200417 int loopcount = WL1271_IRQ_MAX_LOOPS;
418 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300419 struct wl1271 *wl =
420 container_of(work, struct wl1271, irq_work);
421
422 mutex_lock(&wl->mutex);
423
424 wl1271_debug(DEBUG_IRQ, "IRQ work");
425
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200426 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300427 goto out;
428
429 ret = wl1271_ps_elp_wakeup(wl, true);
430 if (ret < 0)
431 goto out;
432
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200433 spin_lock_irqsave(&wl->wl_lock, flags);
434 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
435 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
436 spin_unlock_irqrestore(&wl->wl_lock, flags);
437 loopcount--;
438
439 wl1271_fw_status(wl, wl->fw_status);
440 intr = le32_to_cpu(wl->fw_status->intr);
441 if (!intr) {
442 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
443 continue;
444 }
445
446 intr &= WL1271_INTR_MASK;
447
448 if (intr & WL1271_ACX_INTR_DATA) {
449 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
450
451 /* check for tx results */
452 if (wl->fw_status->tx_results_counter !=
453 (wl->tx_results_count & 0xff))
454 wl1271_tx_complete(wl);
455
456 wl1271_rx(wl, wl->fw_status);
457 }
458
459 if (intr & WL1271_ACX_INTR_EVENT_A) {
460 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
461 wl1271_event_handle(wl, 0);
462 }
463
464 if (intr & WL1271_ACX_INTR_EVENT_B) {
465 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
466 wl1271_event_handle(wl, 1);
467 }
468
469 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
470 wl1271_debug(DEBUG_IRQ,
471 "WL1271_ACX_INTR_INIT_COMPLETE");
472
473 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
474 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
475
476 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300477 }
478
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200479 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
480 ieee80211_queue_work(wl->hw, &wl->irq_work);
481 else
482 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
483 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300484
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300485 wl1271_ps_elp_sleep(wl);
486
487out:
488 mutex_unlock(&wl->mutex);
489}
490
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300491static int wl1271_fetch_firmware(struct wl1271 *wl)
492{
493 const struct firmware *fw;
494 int ret;
495
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200496 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300497
498 if (ret < 0) {
499 wl1271_error("could not get firmware: %d", ret);
500 return ret;
501 }
502
503 if (fw->size % 4) {
504 wl1271_error("firmware size is not multiple of 32 bits: %zu",
505 fw->size);
506 ret = -EILSEQ;
507 goto out;
508 }
509
510 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300511 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300512
513 if (!wl->fw) {
514 wl1271_error("could not allocate memory for the firmware");
515 ret = -ENOMEM;
516 goto out;
517 }
518
519 memcpy(wl->fw, fw->data, wl->fw_len);
520
521 ret = 0;
522
523out:
524 release_firmware(fw);
525
526 return ret;
527}
528
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200529static int wl1271_update_mac_addr(struct wl1271 *wl)
530{
531 int ret = 0;
532 u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
533
534 /* get mac address from the NVS */
535 wl->mac_addr[0] = nvs_ptr[11];
536 wl->mac_addr[1] = nvs_ptr[10];
537 wl->mac_addr[2] = nvs_ptr[6];
538 wl->mac_addr[3] = nvs_ptr[5];
539 wl->mac_addr[4] = nvs_ptr[4];
540 wl->mac_addr[5] = nvs_ptr[3];
541
542 /* FIXME: if it is a zero-address, we should bail out. Now, instead,
543 we randomize an address */
544 if (is_zero_ether_addr(wl->mac_addr)) {
545 static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
546 memcpy(wl->mac_addr, nokia_oui, 3);
547 get_random_bytes(wl->mac_addr + 3, 3);
Juuso Oikarinene2e77b52010-02-18 13:25:46 +0200548
549 /* update this address to the NVS */
550 nvs_ptr[11] = wl->mac_addr[0];
551 nvs_ptr[10] = wl->mac_addr[1];
552 nvs_ptr[6] = wl->mac_addr[2];
553 nvs_ptr[5] = wl->mac_addr[3];
554 nvs_ptr[4] = wl->mac_addr[4];
555 nvs_ptr[3] = wl->mac_addr[5];
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200556 }
557
558 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
559
560 return ret;
561}
562
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300563static int wl1271_fetch_nvs(struct wl1271 *wl)
564{
565 const struct firmware *fw;
566 int ret;
567
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200568 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300569
570 if (ret < 0) {
571 wl1271_error("could not get nvs file: %d", ret);
572 return ret;
573 }
574
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200575 if (fw->size != sizeof(struct wl1271_nvs_file)) {
576 wl1271_error("nvs size is not as expected: %zu != %zu",
577 fw->size, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300578 ret = -EILSEQ;
579 goto out;
580 }
581
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200582 wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300583
584 if (!wl->nvs) {
585 wl1271_error("could not allocate memory for the nvs file");
586 ret = -ENOMEM;
587 goto out;
588 }
589
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200590 memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300591
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200592 ret = wl1271_update_mac_addr(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300593
594out:
595 release_firmware(fw);
596
597 return ret;
598}
599
600static void wl1271_fw_wakeup(struct wl1271 *wl)
601{
602 u32 elp_reg;
603
604 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300605 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300606}
607
608static int wl1271_setup(struct wl1271 *wl)
609{
610 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
611 if (!wl->fw_status)
612 return -ENOMEM;
613
614 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
615 if (!wl->tx_res_if) {
616 kfree(wl->fw_status);
617 return -ENOMEM;
618 }
619
620 INIT_WORK(&wl->irq_work, wl1271_irq_work);
621 INIT_WORK(&wl->tx_work, wl1271_tx_work);
622 return 0;
623}
624
625static int wl1271_chip_wakeup(struct wl1271 *wl)
626{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300627 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300628 int ret = 0;
629
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200630 msleep(WL1271_PRE_POWER_ON_SLEEP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300631 wl1271_power_on(wl);
632 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200633 wl1271_io_reset(wl);
634 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300635
636 /* We don't need a real memory partition here, because we only want
637 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300638 memset(&partition, 0, sizeof(partition));
639 partition.reg.start = REGISTERS_BASE;
640 partition.reg.size = REGISTERS_DOWN_SIZE;
641 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300642
643 /* ELP module wake up */
644 wl1271_fw_wakeup(wl);
645
646 /* whal_FwCtrl_BootSm() */
647
648 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200649 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300650
651 /* 1. check if chip id is valid */
652
653 switch (wl->chip.id) {
654 case CHIP_ID_1271_PG10:
655 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
656 wl->chip.id);
657
658 ret = wl1271_setup(wl);
659 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200660 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300661 break;
662 case CHIP_ID_1271_PG20:
663 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
664 wl->chip.id);
665
666 ret = wl1271_setup(wl);
667 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200668 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300669 break;
670 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200671 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300672 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200673 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300674 }
675
676 if (wl->fw == NULL) {
677 ret = wl1271_fetch_firmware(wl);
678 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200679 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300680 }
681
682 /* No NVS from netlink, try to get it from the filesystem */
683 if (wl->nvs == NULL) {
684 ret = wl1271_fetch_nvs(wl);
685 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200686 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300687 }
688
689out:
690 return ret;
691}
692
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300693int wl1271_plt_start(struct wl1271 *wl)
694{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200695 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300696 int ret;
697
698 mutex_lock(&wl->mutex);
699
700 wl1271_notice("power up");
701
702 if (wl->state != WL1271_STATE_OFF) {
703 wl1271_error("cannot go into PLT state because not "
704 "in off state: %d", wl->state);
705 ret = -EBUSY;
706 goto out;
707 }
708
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200709 while (retries) {
710 retries--;
711 ret = wl1271_chip_wakeup(wl);
712 if (ret < 0)
713 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300714
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200715 ret = wl1271_boot(wl);
716 if (ret < 0)
717 goto power_off;
718
719 ret = wl1271_plt_init(wl);
720 if (ret < 0)
721 goto irq_disable;
722
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200723 wl->state = WL1271_STATE_PLT;
724 wl1271_notice("firmware booted in PLT mode (%s)",
725 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300726 goto out;
727
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200728irq_disable:
729 wl1271_disable_interrupts(wl);
730 mutex_unlock(&wl->mutex);
731 /* Unlocking the mutex in the middle of handling is
732 inherently unsafe. In this case we deem it safe to do,
733 because we need to let any possibly pending IRQ out of
734 the system (and while we are WL1271_STATE_OFF the IRQ
735 work function will not do anything.) Also, any other
736 possible concurrent operations will fail due to the
737 current state, hence the wl1271 struct should be safe. */
738 cancel_work_sync(&wl->irq_work);
739 mutex_lock(&wl->mutex);
740power_off:
741 wl1271_power_off(wl);
742 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300743
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200744 wl1271_error("firmware boot in PLT mode failed despite %d retries",
745 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300746out:
747 mutex_unlock(&wl->mutex);
748
749 return ret;
750}
751
752int wl1271_plt_stop(struct wl1271 *wl)
753{
754 int ret = 0;
755
756 mutex_lock(&wl->mutex);
757
758 wl1271_notice("power down");
759
760 if (wl->state != WL1271_STATE_PLT) {
761 wl1271_error("cannot power down because not in PLT "
762 "state: %d", wl->state);
763 ret = -EBUSY;
764 goto out;
765 }
766
767 wl1271_disable_interrupts(wl);
768 wl1271_power_off(wl);
769
770 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300771 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300772
773out:
774 mutex_unlock(&wl->mutex);
775
776 return ret;
777}
778
779
780static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
781{
782 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200783 struct ieee80211_conf *conf = &hw->conf;
784 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
785 struct ieee80211_sta *sta = txinfo->control.sta;
786 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300787
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200788 /* peek into the rates configured in the STA entry */
789 spin_lock_irqsave(&wl->wl_lock, flags);
790 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
791 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
792 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
793 }
794 spin_unlock_irqrestore(&wl->wl_lock, flags);
795
796 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300797 skb_queue_tail(&wl->tx_queue, skb);
798
799 /*
800 * The chip specific setup must run before the first TX packet -
801 * before that, the tx_work will not be initialized!
802 */
803
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300804 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300805
806 /*
807 * The workqueue is slow to process the tx_queue and we need stop
808 * the queue here, otherwise the queue will get too long.
809 */
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200810 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
811 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300812
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200813 spin_lock_irqsave(&wl->wl_lock, flags);
814 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200815 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200816 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300817 }
818
819 return NETDEV_TX_OK;
820}
821
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300822static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
823 void *arg)
824{
825 struct net_device *dev;
826 struct wireless_dev *wdev;
827 struct wiphy *wiphy;
828 struct ieee80211_hw *hw;
829 struct wl1271 *wl;
830 struct wl1271 *wl_temp;
831 struct in_device *idev;
832 struct in_ifaddr *ifa = arg;
833 int ret = 0;
834
835 /* FIXME: this ugly function should probably be implemented in the
836 * mac80211, and here should only be a simple callback handling actual
837 * setting of the filters. Now we need to dig up references to
838 * various structures to gain access to what we need.
839 * Also, because of this, there is no "initial" setting of the filter
840 * in "op_start", because we don't want to dig up struct net_device
841 * there - the filter will be set upon first change of the interface
842 * IP address. */
843
844 dev = ifa->ifa_dev->dev;
845
846 wdev = dev->ieee80211_ptr;
847 if (wdev == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200848 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300849
850 wiphy = wdev->wiphy;
851 if (wiphy == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200852 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300853
854 hw = wiphy_priv(wiphy);
855 if (hw == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200856 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300857
858 /* Check that the interface is one supported by this driver. */
859 wl_temp = hw->priv;
860 list_for_each_entry(wl, &wl_list, list) {
861 if (wl == wl_temp)
862 break;
863 }
864 if (wl == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200865 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300866
867 /* Get the interface IP address for the device. "ifa" will become
868 NULL if:
869 - there is no IPV4 protocol address configured
870 - there are multiple (virtual) IPV4 addresses configured
871 When "ifa" is NULL, filtering will be disabled.
872 */
873 ifa = NULL;
874 idev = dev->ip_ptr;
875 if (idev)
876 ifa = idev->ifa_list;
877
878 if (ifa && ifa->ifa_next)
879 ifa = NULL;
880
881 mutex_lock(&wl->mutex);
882
883 if (wl->state == WL1271_STATE_OFF)
884 goto out;
885
886 ret = wl1271_ps_elp_wakeup(wl, false);
887 if (ret < 0)
888 goto out;
889 if (ifa)
890 ret = wl1271_acx_arp_ip_filter(wl, true,
891 (u8 *)&ifa->ifa_address,
892 ACX_IPV4_VERSION);
893 else
894 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
895 ACX_IPV4_VERSION);
896 wl1271_ps_elp_sleep(wl);
897
898out:
899 mutex_unlock(&wl->mutex);
900
Luciano Coelho17d72652009-11-23 23:22:15 +0200901 return NOTIFY_OK;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300902}
903
904static struct notifier_block wl1271_dev_notifier = {
905 .notifier_call = wl1271_dev_notify,
906};
907
908
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300909static int wl1271_op_start(struct ieee80211_hw *hw)
910{
911 struct wl1271 *wl = hw->priv;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200912 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300913 int ret = 0;
914
915 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
916
917 mutex_lock(&wl->mutex);
918
919 if (wl->state != WL1271_STATE_OFF) {
920 wl1271_error("cannot start because not in off state: %d",
921 wl->state);
922 ret = -EBUSY;
923 goto out;
924 }
925
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200926 while (retries) {
927 retries--;
928 ret = wl1271_chip_wakeup(wl);
929 if (ret < 0)
930 goto power_off;
931
932 ret = wl1271_boot(wl);
933 if (ret < 0)
934 goto power_off;
935
936 ret = wl1271_hw_init(wl);
937 if (ret < 0)
938 goto irq_disable;
939
940 wl->state = WL1271_STATE_ON;
941 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300942 goto out;
943
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200944irq_disable:
945 wl1271_disable_interrupts(wl);
946 mutex_unlock(&wl->mutex);
947 /* Unlocking the mutex in the middle of handling is
948 inherently unsafe. In this case we deem it safe to do,
949 because we need to let any possibly pending IRQ out of
950 the system (and while we are WL1271_STATE_OFF the IRQ
951 work function will not do anything.) Also, any other
952 possible concurrent operations will fail due to the
953 current state, hence the wl1271 struct should be safe. */
954 cancel_work_sync(&wl->irq_work);
955 mutex_lock(&wl->mutex);
956power_off:
957 wl1271_power_off(wl);
958 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300959
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200960 wl1271_error("firmware boot failed despite %d retries",
961 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300962out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300963 mutex_unlock(&wl->mutex);
964
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300965 if (!ret) {
966 list_add(&wl->list, &wl_list);
967 register_inetaddr_notifier(&wl1271_dev_notifier);
968 }
969
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300970 return ret;
971}
972
973static void wl1271_op_stop(struct ieee80211_hw *hw)
974{
975 struct wl1271 *wl = hw->priv;
976 int i;
977
978 wl1271_info("down");
979
980 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
981
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300982 unregister_inetaddr_notifier(&wl1271_dev_notifier);
983 list_del(&wl->list);
984
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300985 mutex_lock(&wl->mutex);
986
987 WARN_ON(wl->state != WL1271_STATE_ON);
988
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200989 if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300990 mutex_unlock(&wl->mutex);
991 ieee80211_scan_completed(wl->hw, true);
992 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300993 }
994
995 wl->state = WL1271_STATE_OFF;
996
997 wl1271_disable_interrupts(wl);
998
999 mutex_unlock(&wl->mutex);
1000
1001 cancel_work_sync(&wl->irq_work);
1002 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001003
1004 mutex_lock(&wl->mutex);
1005
1006 /* let's notify MAC80211 about the remaining pending TX frames */
1007 wl1271_tx_flush(wl);
1008 wl1271_power_off(wl);
1009
1010 memset(wl->bssid, 0, ETH_ALEN);
1011 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1012 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001013 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001014 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001015
1016 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001017 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001018 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1019 wl->tx_blocks_available = 0;
1020 wl->tx_results_count = 0;
1021 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001022 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001023 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001024 wl->time_offset = 0;
1025 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001026 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1027 wl->sta_rate_set = 0;
1028 wl->flags = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001029
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001030 for (i = 0; i < NUM_TX_QUEUES; i++)
1031 wl->tx_blocks_freed[i] = 0;
1032
1033 wl1271_debugfs_reset(wl);
1034 mutex_unlock(&wl->mutex);
1035}
1036
1037static int wl1271_op_add_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +01001038 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001039{
1040 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001041 int ret = 0;
1042
John W. Linvillee5539bc2009-08-18 10:50:34 -04001043 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Johannes Berg1ed32e42009-12-23 13:15:45 +01001044 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001045
1046 mutex_lock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001047 if (wl->vif) {
1048 ret = -EBUSY;
1049 goto out;
1050 }
1051
Johannes Berg1ed32e42009-12-23 13:15:45 +01001052 wl->vif = vif;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001053
Johannes Berg1ed32e42009-12-23 13:15:45 +01001054 switch (vif->type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001055 case NL80211_IFTYPE_STATION:
1056 wl->bss_type = BSS_TYPE_STA_BSS;
1057 break;
1058 case NL80211_IFTYPE_ADHOC:
1059 wl->bss_type = BSS_TYPE_IBSS;
1060 break;
1061 default:
1062 ret = -EOPNOTSUPP;
1063 goto out;
1064 }
1065
1066 /* FIXME: what if conf->mac_addr changes? */
1067
1068out:
1069 mutex_unlock(&wl->mutex);
1070 return ret;
1071}
1072
1073static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +01001074 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001075{
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001076 struct wl1271 *wl = hw->priv;
1077
1078 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001079 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001080 wl->vif = NULL;
1081 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001082}
1083
1084#if 0
1085static int wl1271_op_config_interface(struct ieee80211_hw *hw,
1086 struct ieee80211_vif *vif,
1087 struct ieee80211_if_conf *conf)
1088{
1089 struct wl1271 *wl = hw->priv;
1090 struct sk_buff *beacon;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001091 int ret;
1092
David S. Miller32646902009-09-17 10:18:30 -07001093 wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM",
1094 conf->bssid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001095 wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid,
1096 conf->ssid_len);
1097
1098 mutex_lock(&wl->mutex);
1099
1100 ret = wl1271_ps_elp_wakeup(wl, false);
1101 if (ret < 0)
1102 goto out;
1103
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001104 if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
1105 wl1271_debug(DEBUG_MAC80211, "bssid changed");
1106
1107 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
1108
Juuso Oikarinen15305492010-02-22 08:38:32 +02001109 ret = wl1271_cmd_join(wl, wl->bss_type);
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001110 if (ret < 0)
1111 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001112
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001113 ret = wl1271_cmd_build_null_data(wl);
1114 if (ret < 0)
1115 goto out_sleep;
1116 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001117
1118 wl->ssid_len = conf->ssid_len;
1119 if (wl->ssid_len)
1120 memcpy(wl->ssid, conf->ssid, wl->ssid_len);
1121
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001122 if (conf->changed & IEEE80211_IFCC_BEACON) {
1123 beacon = ieee80211_beacon_get(hw, vif);
1124 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1125 beacon->data, beacon->len);
1126
1127 if (ret < 0) {
1128 dev_kfree_skb(beacon);
1129 goto out_sleep;
1130 }
1131
1132 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE,
1133 beacon->data, beacon->len);
1134
1135 dev_kfree_skb(beacon);
1136
1137 if (ret < 0)
1138 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001139 }
1140
1141out_sleep:
1142 wl1271_ps_elp_sleep(wl);
1143
1144out:
1145 mutex_unlock(&wl->mutex);
1146
1147 return ret;
1148}
1149#endif
1150
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001151static int wl1271_join_channel(struct wl1271 *wl, int channel)
1152{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001153 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001154 /* we need to use a dummy BSSID for now */
1155 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1156 0xad, 0xbe, 0xef };
1157
1158 /* disable mac filter, so we hear everything */
1159 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1160
1161 wl->channel = channel;
1162 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1163
Juuso Oikarinen15305492010-02-22 08:38:32 +02001164 /* the dummy join is performed always with STATION BSS type to allow
1165 also ad-hoc mode to listen to the surroundings without sending any
1166 beacons yet. */
1167 ret = wl1271_cmd_join(wl, BSS_TYPE_STA_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001168 if (ret < 0)
1169 goto out;
1170
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001171 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001172
1173out:
1174 return ret;
1175}
1176
1177static int wl1271_unjoin_channel(struct wl1271 *wl)
1178{
1179 int ret;
1180
1181 /* to stop listening to a channel, we disconnect */
1182 ret = wl1271_cmd_disconnect(wl);
1183 if (ret < 0)
1184 goto out;
1185
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001186 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001187 wl->channel = 0;
1188 memset(wl->bssid, 0, ETH_ALEN);
1189 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1190
1191out:
1192 return ret;
1193}
1194
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001195static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1196{
1197 struct wl1271 *wl = hw->priv;
1198 struct ieee80211_conf *conf = &hw->conf;
1199 int channel, ret = 0;
1200
1201 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1202
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001203 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001204 channel,
1205 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001206 conf->power_level,
1207 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001208
1209 mutex_lock(&wl->mutex);
1210
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001211 wl->band = conf->channel->band;
1212
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001213 ret = wl1271_ps_elp_wakeup(wl, false);
1214 if (ret < 0)
1215 goto out;
1216
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001217 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001218 if (conf->flags & IEEE80211_CONF_IDLE &&
1219 test_bit(WL1271_FLAG_JOINED, &wl->flags))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001220 wl1271_unjoin_channel(wl);
Juuso Oikarinen8f648c02009-12-11 15:41:10 +02001221 else if (!(conf->flags & IEEE80211_CONF_IDLE))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001222 wl1271_join_channel(wl, channel);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001223
1224 if (conf->flags & IEEE80211_CONF_IDLE) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001225 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1226 wl->sta_rate_set = 0;
1227 wl1271_acx_rate_policies(wl);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001228 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001229 }
1230
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001231 /* if the channel changes while joined, join again */
Juuso Oikarinenddb01a52010-02-18 13:25:37 +02001232 if (channel != wl->channel &&
1233 test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1234 wl->channel = channel;
1235 /* FIXME: maybe use CMD_CHANNEL_SWITCH for this? */
Juuso Oikarinen15305492010-02-22 08:38:32 +02001236 ret = wl1271_cmd_join(wl, wl->bss_type);
Juuso Oikarinenddb01a52010-02-18 13:25:37 +02001237 if (ret < 0)
1238 wl1271_warning("cmd join to update channel failed %d",
1239 ret);
1240 } else
1241 wl->channel = channel;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001242
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001243 if (conf->flags & IEEE80211_CONF_PS &&
1244 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1245 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001246
1247 /*
1248 * We enter PSM only if we're already associated.
1249 * If we're not, we'll enter it when joining an SSID,
1250 * through the bss_info_changed() hook.
1251 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001252 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001253 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001254 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1255 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001256 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001257 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001258 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001259 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001260
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001261 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001262
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001263 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001264 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1265 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001266 }
1267
1268 if (conf->power_level != wl->power_level) {
1269 ret = wl1271_acx_tx_power(wl, conf->power_level);
1270 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001271 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001272
1273 wl->power_level = conf->power_level;
1274 }
1275
1276out_sleep:
1277 wl1271_ps_elp_sleep(wl);
1278
1279out:
1280 mutex_unlock(&wl->mutex);
1281
1282 return ret;
1283}
1284
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001285struct wl1271_filter_params {
1286 bool enabled;
1287 int mc_list_length;
1288 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1289};
1290
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001291static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1292 struct dev_addr_list *mc_list)
1293{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001294 struct wl1271_filter_params *fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001295 int i;
1296
Juuso Oikarinen74441132009-10-13 12:47:53 +03001297 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001298 if (!fp) {
1299 wl1271_error("Out of memory setting filters.");
1300 return 0;
1301 }
1302
1303 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001304 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001305 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1306 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001307 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001308 }
1309
1310 fp->mc_list_length = 0;
1311 for (i = 0; i < mc_count; i++) {
1312 if (mc_list->da_addrlen == ETH_ALEN) {
1313 memcpy(fp->mc_list[fp->mc_list_length],
1314 mc_list->da_addr, ETH_ALEN);
1315 fp->mc_list_length++;
1316 } else
1317 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001318 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001319 }
1320
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001321 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001322}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001323
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001324#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1325 FIF_ALLMULTI | \
1326 FIF_FCSFAIL | \
1327 FIF_BCN_PRBRESP_PROMISC | \
1328 FIF_CONTROL | \
1329 FIF_OTHER_BSS)
1330
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001331static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1332 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001333 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001334{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001335 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001336 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001337 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001338
1339 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1340
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001341 mutex_lock(&wl->mutex);
1342
1343 if (wl->state == WL1271_STATE_OFF)
1344 goto out;
1345
1346 ret = wl1271_ps_elp_wakeup(wl, false);
1347 if (ret < 0)
1348 goto out;
1349
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001350 *total &= WL1271_SUPPORTED_FILTERS;
1351 changed &= WL1271_SUPPORTED_FILTERS;
1352
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001353 if (*total & FIF_ALLMULTI)
1354 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1355 else if (fp)
1356 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1357 fp->mc_list,
1358 fp->mc_list_length);
1359 if (ret < 0)
1360 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001361
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001362 kfree(fp);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001363
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001364 /* FIXME: We still need to set our filters properly */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001365
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001366 /* determine, whether supported filter values have changed */
1367 if (changed == 0)
1368 goto out_sleep;
1369
1370 /* apply configured filters */
1371 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1372 if (ret < 0)
1373 goto out_sleep;
1374
1375out_sleep:
1376 wl1271_ps_elp_sleep(wl);
1377
1378out:
1379 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001380}
1381
1382static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1383 struct ieee80211_vif *vif,
1384 struct ieee80211_sta *sta,
1385 struct ieee80211_key_conf *key_conf)
1386{
1387 struct wl1271 *wl = hw->priv;
1388 const u8 *addr;
1389 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001390 u32 tx_seq_32 = 0;
1391 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001392 u8 key_type;
1393
1394 static const u8 bcast_addr[ETH_ALEN] =
1395 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1396
1397 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1398
1399 addr = sta ? sta->addr : bcast_addr;
1400
1401 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1402 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1403 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1404 key_conf->alg, key_conf->keyidx,
1405 key_conf->keylen, key_conf->flags);
1406 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1407
1408 if (is_zero_ether_addr(addr)) {
1409 /* We dont support TX only encryption */
1410 ret = -EOPNOTSUPP;
1411 goto out;
1412 }
1413
1414 mutex_lock(&wl->mutex);
1415
1416 ret = wl1271_ps_elp_wakeup(wl, false);
1417 if (ret < 0)
1418 goto out_unlock;
1419
1420 switch (key_conf->alg) {
1421 case ALG_WEP:
1422 key_type = KEY_WEP;
1423
1424 key_conf->hw_key_idx = key_conf->keyidx;
1425 break;
1426 case ALG_TKIP:
1427 key_type = KEY_TKIP;
1428
1429 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001430 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1431 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001432 break;
1433 case ALG_CCMP:
1434 key_type = KEY_AES;
1435
1436 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001437 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1438 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001439 break;
1440 default:
1441 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1442
1443 ret = -EOPNOTSUPP;
1444 goto out_sleep;
1445 }
1446
1447 switch (cmd) {
1448 case SET_KEY:
1449 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1450 key_conf->keyidx, key_type,
1451 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001452 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001453 if (ret < 0) {
1454 wl1271_error("Could not add or replace key");
1455 goto out_sleep;
1456 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001457
1458 /* the default WEP key needs to be configured at least once */
1459 if (key_type == KEY_WEP) {
1460 ret = wl1271_cmd_set_default_wep_key(wl,
1461 wl->default_key);
1462 if (ret < 0)
1463 goto out_sleep;
1464 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001465 break;
1466
1467 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001468 /* The wl1271 does not allow to remove unicast keys - they
1469 will be cleared automatically on next CMD_JOIN. Ignore the
1470 request silently, as we dont want the mac80211 to emit
1471 an error message. */
1472 if (!is_broadcast_ether_addr(addr))
1473 break;
1474
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001475 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1476 key_conf->keyidx, key_type,
1477 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001478 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001479 if (ret < 0) {
1480 wl1271_error("Could not remove key");
1481 goto out_sleep;
1482 }
1483 break;
1484
1485 default:
1486 wl1271_error("Unsupported key cmd 0x%x", cmd);
1487 ret = -EOPNOTSUPP;
1488 goto out_sleep;
1489
1490 break;
1491 }
1492
1493out_sleep:
1494 wl1271_ps_elp_sleep(wl);
1495
1496out_unlock:
1497 mutex_unlock(&wl->mutex);
1498
1499out:
1500 return ret;
1501}
1502
1503static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1504 struct cfg80211_scan_request *req)
1505{
1506 struct wl1271 *wl = hw->priv;
1507 int ret;
1508 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001509 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001510
1511 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1512
1513 if (req->n_ssids) {
1514 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001515 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001516 }
1517
1518 mutex_lock(&wl->mutex);
1519
1520 ret = wl1271_ps_elp_wakeup(wl, false);
1521 if (ret < 0)
1522 goto out;
1523
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001524 if (wl1271_11a_enabled())
1525 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1526 WL1271_SCAN_BAND_DUAL, 3);
1527 else
1528 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1529 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001530
1531 wl1271_ps_elp_sleep(wl);
1532
1533out:
1534 mutex_unlock(&wl->mutex);
1535
1536 return ret;
1537}
1538
1539static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1540{
1541 struct wl1271 *wl = hw->priv;
1542 int ret;
1543
1544 mutex_lock(&wl->mutex);
1545
1546 ret = wl1271_ps_elp_wakeup(wl, false);
1547 if (ret < 0)
1548 goto out;
1549
1550 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1551 if (ret < 0)
1552 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1553
1554 wl1271_ps_elp_sleep(wl);
1555
1556out:
1557 mutex_unlock(&wl->mutex);
1558
1559 return ret;
1560}
1561
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001562static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1563{
1564 u8 *ptr = beacon->data +
1565 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1566
1567 /* find the location of the ssid in the beacon */
1568 while (ptr < beacon->data + beacon->len) {
1569 if (ptr[0] == WLAN_EID_SSID) {
1570 wl->ssid_len = ptr[1];
1571 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1572 return;
1573 }
1574 ptr += ptr[1];
1575 }
1576 wl1271_error("ad-hoc beacon template has no SSID!\n");
1577}
1578
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001579static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1580 struct ieee80211_vif *vif,
1581 struct ieee80211_bss_conf *bss_conf,
1582 u32 changed)
1583{
1584 enum wl1271_cmd_ps_mode mode;
1585 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001586 bool do_join = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001587 int ret;
1588
1589 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1590
1591 mutex_lock(&wl->mutex);
1592
1593 ret = wl1271_ps_elp_wakeup(wl, false);
1594 if (ret < 0)
1595 goto out;
1596
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001597 if (wl->bss_type == BSS_TYPE_IBSS) {
1598 /* FIXME: This implements rudimentary ad-hoc support -
1599 proper templates are on the wish list and notification
1600 on when they change. This patch will update the templates
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001601 on every call to this function. */
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001602 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1603
1604 if (beacon) {
1605 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001606
1607 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001608 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1609 beacon->data,
1610 beacon->len);
1611
1612 if (ret < 0) {
1613 dev_kfree_skb(beacon);
1614 goto out_sleep;
1615 }
1616
1617 hdr = (struct ieee80211_hdr *) beacon->data;
1618 hdr->frame_control = cpu_to_le16(
1619 IEEE80211_FTYPE_MGMT |
1620 IEEE80211_STYPE_PROBE_RESP);
1621
1622 ret = wl1271_cmd_template_set(wl,
1623 CMD_TEMPL_PROBE_RESPONSE,
1624 beacon->data,
1625 beacon->len);
1626 dev_kfree_skb(beacon);
1627 if (ret < 0)
1628 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001629
1630 /* Need to update the SSID (for filtering etc) */
1631 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001632 }
1633 }
1634
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001635 if ((changed & BSS_CHANGED_BSSID) &&
1636 /*
1637 * Now we know the correct bssid, so we send a new join command
1638 * and enable the BSSID filter
1639 */
1640 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
1641 wl->rx_config |= CFG_BSSID_FILTER_EN;
1642 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
1643 ret = wl1271_cmd_build_null_data(wl);
1644 if (ret < 0) {
1645 wl1271_warning("cmd buld null data failed %d",
1646 ret);
1647 goto out_sleep;
1648 }
1649
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001650 /* Need to update the BSSID (for filtering etc) */
1651 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001652 }
1653
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001654 if (changed & BSS_CHANGED_ASSOC) {
1655 if (bss_conf->assoc) {
1656 wl->aid = bss_conf->aid;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001657 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001658
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001659 /*
1660 * with wl1271, we don't need to update the
1661 * beacon_int and dtim_period, because the firmware
1662 * updates it by itself when the first beacon is
1663 * received after a join.
1664 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001665 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1666 if (ret < 0)
1667 goto out_sleep;
1668
1669 ret = wl1271_acx_aid(wl, wl->aid);
1670 if (ret < 0)
1671 goto out_sleep;
1672
1673 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001674 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1675 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001676 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001677 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001678 if (ret < 0)
1679 goto out_sleep;
1680 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001681 } else {
1682 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001683 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001684 wl->aid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001685 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001686
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001687 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001688
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001689 if (changed & BSS_CHANGED_ERP_SLOT) {
1690 if (bss_conf->use_short_slot)
1691 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1692 else
1693 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1694 if (ret < 0) {
1695 wl1271_warning("Set slot time failed %d", ret);
1696 goto out_sleep;
1697 }
1698 }
1699
1700 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1701 if (bss_conf->use_short_preamble)
1702 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1703 else
1704 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1705 }
1706
1707 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1708 if (bss_conf->use_cts_prot)
1709 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1710 else
1711 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1712 if (ret < 0) {
1713 wl1271_warning("Set ctsprotect failed %d", ret);
1714 goto out_sleep;
1715 }
1716 }
1717
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001718 if (do_join) {
Juuso Oikarinen15305492010-02-22 08:38:32 +02001719 ret = wl1271_cmd_join(wl, wl->bss_type);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001720 if (ret < 0) {
1721 wl1271_warning("cmd join failed %d", ret);
1722 goto out_sleep;
1723 }
1724 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1725 }
1726
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001727out_sleep:
1728 wl1271_ps_elp_sleep(wl);
1729
1730out:
1731 mutex_unlock(&wl->mutex);
1732}
1733
Kalle Valoc6999d82010-02-18 13:25:41 +02001734static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1735 const struct ieee80211_tx_queue_params *params)
1736{
1737 struct wl1271 *wl = hw->priv;
1738 int ret;
1739
1740 mutex_lock(&wl->mutex);
1741
1742 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1743
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001744 ret = wl1271_ps_elp_wakeup(wl, false);
1745 if (ret < 0)
1746 goto out;
1747
Kalle Valoc6999d82010-02-18 13:25:41 +02001748 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1749 params->cw_min, params->cw_max,
1750 params->aifs, params->txop);
1751 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001752 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001753
1754 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1755 CONF_CHANNEL_TYPE_EDCF,
1756 wl1271_tx_get_queue(queue),
1757 CONF_PS_SCHEME_LEGACY_PSPOLL,
1758 CONF_ACK_POLICY_LEGACY, 0, 0);
1759 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001760 goto out_sleep;
1761
1762out_sleep:
1763 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001764
1765out:
1766 mutex_unlock(&wl->mutex);
1767
1768 return ret;
1769}
1770
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001771
1772/* can't be const, mac80211 writes to this */
1773static struct ieee80211_rate wl1271_rates[] = {
1774 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001775 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1776 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001777 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001778 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1779 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001780 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1781 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001782 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1783 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001784 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1785 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001786 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1787 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001788 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1789 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001790 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1791 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001792 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001793 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1794 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001795 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001796 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1797 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001798 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001799 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1800 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001801 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001802 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1803 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001804 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001805 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1806 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001807 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001808 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1809 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001810 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001811 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1812 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001813};
1814
1815/* can't be const, mac80211 writes to this */
1816static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001817 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1818 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1819 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1820 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1821 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1822 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1823 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1824 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1825 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1826 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1827 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1828 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1829 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001830};
1831
1832/* can't be const, mac80211 writes to this */
1833static struct ieee80211_supported_band wl1271_band_2ghz = {
1834 .channels = wl1271_channels,
1835 .n_channels = ARRAY_SIZE(wl1271_channels),
1836 .bitrates = wl1271_rates,
1837 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1838};
1839
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001840/* 5 GHz data rates for WL1273 */
1841static struct ieee80211_rate wl1271_rates_5ghz[] = {
1842 { .bitrate = 60,
1843 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1844 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
1845 { .bitrate = 90,
1846 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1847 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
1848 { .bitrate = 120,
1849 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1850 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
1851 { .bitrate = 180,
1852 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1853 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
1854 { .bitrate = 240,
1855 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1856 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
1857 { .bitrate = 360,
1858 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1859 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
1860 { .bitrate = 480,
1861 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1862 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
1863 { .bitrate = 540,
1864 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1865 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
1866};
1867
1868/* 5 GHz band channels for WL1273 */
1869static struct ieee80211_channel wl1271_channels_5ghz[] = {
1870 { .hw_value = 183, .center_freq = 4915},
1871 { .hw_value = 184, .center_freq = 4920},
1872 { .hw_value = 185, .center_freq = 4925},
1873 { .hw_value = 187, .center_freq = 4935},
1874 { .hw_value = 188, .center_freq = 4940},
1875 { .hw_value = 189, .center_freq = 4945},
1876 { .hw_value = 192, .center_freq = 4960},
1877 { .hw_value = 196, .center_freq = 4980},
1878 { .hw_value = 7, .center_freq = 5035},
1879 { .hw_value = 8, .center_freq = 5040},
1880 { .hw_value = 9, .center_freq = 5045},
1881 { .hw_value = 11, .center_freq = 5055},
1882 { .hw_value = 12, .center_freq = 5060},
1883 { .hw_value = 16, .center_freq = 5080},
1884 { .hw_value = 34, .center_freq = 5170},
1885 { .hw_value = 36, .center_freq = 5180},
1886 { .hw_value = 38, .center_freq = 5190},
1887 { .hw_value = 40, .center_freq = 5200},
1888 { .hw_value = 42, .center_freq = 5210},
1889 { .hw_value = 44, .center_freq = 5220},
1890 { .hw_value = 46, .center_freq = 5230},
1891 { .hw_value = 48, .center_freq = 5240},
1892 { .hw_value = 52, .center_freq = 5260},
1893 { .hw_value = 56, .center_freq = 5280},
1894 { .hw_value = 60, .center_freq = 5300},
1895 { .hw_value = 64, .center_freq = 5320},
1896 { .hw_value = 100, .center_freq = 5500},
1897 { .hw_value = 104, .center_freq = 5520},
1898 { .hw_value = 108, .center_freq = 5540},
1899 { .hw_value = 112, .center_freq = 5560},
1900 { .hw_value = 116, .center_freq = 5580},
1901 { .hw_value = 120, .center_freq = 5600},
1902 { .hw_value = 124, .center_freq = 5620},
1903 { .hw_value = 128, .center_freq = 5640},
1904 { .hw_value = 132, .center_freq = 5660},
1905 { .hw_value = 136, .center_freq = 5680},
1906 { .hw_value = 140, .center_freq = 5700},
1907 { .hw_value = 149, .center_freq = 5745},
1908 { .hw_value = 153, .center_freq = 5765},
1909 { .hw_value = 157, .center_freq = 5785},
1910 { .hw_value = 161, .center_freq = 5805},
1911 { .hw_value = 165, .center_freq = 5825},
1912};
1913
1914
1915static struct ieee80211_supported_band wl1271_band_5ghz = {
1916 .channels = wl1271_channels_5ghz,
1917 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
1918 .bitrates = wl1271_rates_5ghz,
1919 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
1920};
1921
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001922static const struct ieee80211_ops wl1271_ops = {
1923 .start = wl1271_op_start,
1924 .stop = wl1271_op_stop,
1925 .add_interface = wl1271_op_add_interface,
1926 .remove_interface = wl1271_op_remove_interface,
1927 .config = wl1271_op_config,
1928/* .config_interface = wl1271_op_config_interface, */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001929 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001930 .configure_filter = wl1271_op_configure_filter,
1931 .tx = wl1271_op_tx,
1932 .set_key = wl1271_op_set_key,
1933 .hw_scan = wl1271_op_hw_scan,
1934 .bss_info_changed = wl1271_op_bss_info_changed,
1935 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02001936 .conf_tx = wl1271_op_conf_tx,
Kalle Valoc8c90872010-02-18 13:25:53 +02001937 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001938};
1939
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02001940int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001941{
1942 int ret;
1943
1944 if (wl->mac80211_registered)
1945 return 0;
1946
1947 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
1948
1949 ret = ieee80211_register_hw(wl->hw);
1950 if (ret < 0) {
1951 wl1271_error("unable to register mac80211 hw: %d", ret);
1952 return ret;
1953 }
1954
1955 wl->mac80211_registered = true;
1956
1957 wl1271_notice("loaded");
1958
1959 return 0;
1960}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02001961EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001962
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02001963int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001964{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03001965 /* The tx descriptor buffer and the TKIP space. */
1966 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
1967 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001968
1969 /* unit us */
1970 /* FIXME: find a proper value */
1971 wl->hw->channel_change_time = 10000;
1972
1973 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03001974 IEEE80211_HW_NOISE_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02001975 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02001976 IEEE80211_HW_SUPPORTS_PS |
1977 IEEE80211_HW_HAS_RATE_CONTROL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001978
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001979 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
1980 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001981 wl->hw->wiphy->max_scan_ssids = 1;
1982 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
1983
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001984 if (wl1271_11a_enabled())
1985 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
1986
Teemu Paasikivi8197b712010-02-22 08:38:23 +02001987 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001988
1989 return 0;
1990}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02001991EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001992
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001993#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02001994
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02001995struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001996{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001997 struct ieee80211_hw *hw;
1998 struct wl1271 *wl;
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02001999 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002000
2001 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2002 if (!hw) {
2003 wl1271_error("could not alloc ieee80211_hw");
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002004 return ERR_PTR(-ENOMEM);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002005 }
2006
2007 wl = hw->priv;
2008 memset(wl, 0, sizeof(*wl));
2009
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002010 INIT_LIST_HEAD(&wl->list);
2011
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002012 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002013
2014 skb_queue_head_init(&wl->tx_queue);
2015
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002016 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002017 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002018 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002019 wl->rx_counter = 0;
2020 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2021 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002022 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002023 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002024 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002025 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2026 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002027 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002028 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002029 wl->flags = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002030
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002031 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002032 wl->tx_frames[i] = NULL;
2033
2034 spin_lock_init(&wl->wl_lock);
2035
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002036 wl->state = WL1271_STATE_OFF;
2037 mutex_init(&wl->mutex);
2038
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002039 /* Apply default driver configuration. */
2040 wl1271_conf_init(wl);
2041
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002042 wl1271_debugfs_init(wl);
2043
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002044 return hw;
2045}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002046EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002047
2048int wl1271_free_hw(struct wl1271 *wl)
2049{
2050 ieee80211_unregister_hw(wl->hw);
2051
2052 wl1271_debugfs_exit(wl);
2053
2054 kfree(wl->target_mem_map);
2055 vfree(wl->fw);
2056 wl->fw = NULL;
2057 kfree(wl->nvs);
2058 wl->nvs = NULL;
2059
2060 kfree(wl->fw_status);
2061 kfree(wl->tx_res_if);
2062
2063 ieee80211_free_hw(wl->hw);
2064
2065 return 0;
2066}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002067EXPORT_SYMBOL_GPL(wl1271_free_hw);
2068
2069MODULE_LICENSE("GPL");
2070MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2071MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");