blob: fb1e6a8088d8cb298d477066cc5d7fe266ffc071 [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>
25#include <linux/platform_device.h>
26#include <linux/interrupt.h>
27#include <linux/firmware.h>
28#include <linux/delay.h>
29#include <linux/irq.h>
30#include <linux/spi/spi.h>
31#include <linux/crc32.h>
32#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030033#include <linux/vmalloc.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030034#include <linux/spi/wl12xx.h>
Juuso Oikarinen01c09162009-10-13 12:47:55 +030035#include <linux/inetdevice.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036
37#include "wl1271.h"
38#include "wl12xx_80211.h"
39#include "wl1271_reg.h"
40#include "wl1271_spi.h"
41#include "wl1271_event.h"
42#include "wl1271_tx.h"
43#include "wl1271_rx.h"
44#include "wl1271_ps.h"
45#include "wl1271_init.h"
46#include "wl1271_debugfs.h"
47#include "wl1271_cmd.h"
48#include "wl1271_boot.h"
49
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020050#define WL1271_BOOT_RETRIES 3
51
Juuso Oikarinen8a080482009-10-13 12:47:44 +030052static struct conf_drv_settings default_conf = {
53 .sg = {
54 .per_threshold = 7500,
55 .max_scan_compensation_time = 120000,
56 .nfs_sample_interval = 400,
57 .load_ratio = 50,
58 .auto_ps_mode = 0,
59 .probe_req_compensation = 170,
60 .scan_window_compensation = 50,
61 .antenna_config = 0,
62 .beacon_miss_threshold = 60,
63 .rate_adaptation_threshold = CONF_HW_BIT_RATE_12MBPS,
64 .rate_adaptation_snr = 0
65 },
66 .rx = {
67 .rx_msdu_life_time = 512000,
68 .packet_detection_threshold = 0,
69 .ps_poll_timeout = 15,
70 .upsd_timeout = 15,
71 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +020072 .rx_cca_threshold = 0,
73 .irq_blk_threshold = 0xFFFF,
74 .irq_pkt_threshold = 0,
75 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +030076 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
77 },
78 .tx = {
79 .tx_energy_detection = 0,
80 .rc_conf = {
Juuso Oikarinenec078d92009-12-11 15:41:05 +020081 .enabled_rates = CONF_HW_BIT_RATE_1MBPS |
82 CONF_HW_BIT_RATE_2MBPS,
Juuso Oikarinen8a080482009-10-13 12:47:44 +030083 .short_retry_limit = 10,
84 .long_retry_limit = 10,
85 .aflags = 0
86 },
87 .ac_conf_count = 4,
88 .ac_conf = {
89 [0] = {
90 .ac = CONF_TX_AC_BE,
91 .cw_min = 15,
92 .cw_max = 63,
93 .aifsn = 3,
94 .tx_op_limit = 0,
95 },
96 [1] = {
97 .ac = CONF_TX_AC_BK,
98 .cw_min = 15,
99 .cw_max = 63,
100 .aifsn = 7,
101 .tx_op_limit = 0,
102 },
103 [2] = {
104 .ac = CONF_TX_AC_VI,
105 .cw_min = 15,
106 .cw_max = 63,
107 .aifsn = CONF_TX_AIFS_PIFS,
108 .tx_op_limit = 3008,
109 },
110 [3] = {
111 .ac = CONF_TX_AC_VO,
112 .cw_min = 15,
113 .cw_max = 63,
114 .aifsn = CONF_TX_AIFS_PIFS,
115 .tx_op_limit = 1504,
116 },
117 },
118 .tid_conf_count = 7,
119 .tid_conf = {
120 [0] = {
121 .queue_id = 0,
122 .channel_type = CONF_CHANNEL_TYPE_DCF,
123 .tsid = CONF_TX_AC_BE,
124 .ps_scheme = CONF_PS_SCHEME_LEGACY,
125 .ack_policy = CONF_ACK_POLICY_LEGACY,
126 .apsd_conf = {0, 0},
127 },
128 [1] = {
129 .queue_id = 1,
130 .channel_type = CONF_CHANNEL_TYPE_DCF,
131 .tsid = CONF_TX_AC_BE,
132 .ps_scheme = CONF_PS_SCHEME_LEGACY,
133 .ack_policy = CONF_ACK_POLICY_LEGACY,
134 .apsd_conf = {0, 0},
135 },
136 [2] = {
137 .queue_id = 2,
138 .channel_type = CONF_CHANNEL_TYPE_DCF,
139 .tsid = CONF_TX_AC_BE,
140 .ps_scheme = CONF_PS_SCHEME_LEGACY,
141 .ack_policy = CONF_ACK_POLICY_LEGACY,
142 .apsd_conf = {0, 0},
143 },
144 [3] = {
145 .queue_id = 3,
146 .channel_type = CONF_CHANNEL_TYPE_DCF,
147 .tsid = CONF_TX_AC_BE,
148 .ps_scheme = CONF_PS_SCHEME_LEGACY,
149 .ack_policy = CONF_ACK_POLICY_LEGACY,
150 .apsd_conf = {0, 0},
151 },
152 [4] = {
153 .queue_id = 4,
154 .channel_type = CONF_CHANNEL_TYPE_DCF,
155 .tsid = CONF_TX_AC_BE,
156 .ps_scheme = CONF_PS_SCHEME_LEGACY,
157 .ack_policy = CONF_ACK_POLICY_LEGACY,
158 .apsd_conf = {0, 0},
159 },
160 [5] = {
161 .queue_id = 5,
162 .channel_type = CONF_CHANNEL_TYPE_DCF,
163 .tsid = CONF_TX_AC_BE,
164 .ps_scheme = CONF_PS_SCHEME_LEGACY,
165 .ack_policy = CONF_ACK_POLICY_LEGACY,
166 .apsd_conf = {0, 0},
167 },
168 [6] = {
169 .queue_id = 6,
170 .channel_type = CONF_CHANNEL_TYPE_DCF,
171 .tsid = CONF_TX_AC_BE,
172 .ps_scheme = CONF_PS_SCHEME_LEGACY,
173 .ack_policy = CONF_ACK_POLICY_LEGACY,
174 .apsd_conf = {0, 0},
175 }
176 },
177 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200178 .tx_compl_timeout = 700,
179 .tx_compl_threshold = 4
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300180 },
181 .conn = {
182 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
183 .listen_interval = 0,
184 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
185 .bcn_filt_ie_count = 1,
186 .bcn_filt_ie = {
187 [0] = {
188 .ie = WLAN_EID_CHANNEL_SWITCH,
189 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
190 }
191 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200192 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300193 .bss_lose_timeout = 100,
194 .beacon_rx_timeout = 10000,
195 .broadcast_timeout = 20000,
196 .rx_broadcast_in_ps = 1,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200197 .ps_poll_threshold = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300198 .sig_trigger_count = 2,
199 .sig_trigger = {
200 [0] = {
201 .threshold = -75,
202 .pacing = 500,
203 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
204 .type = CONF_TRIG_EVENT_TYPE_EDGE,
205 .direction = CONF_TRIG_EVENT_DIR_LOW,
206 .hysteresis = 2,
207 .index = 0,
208 .enable = 1
209 },
210 [1] = {
211 .threshold = -75,
212 .pacing = 500,
213 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
214 .type = CONF_TRIG_EVENT_TYPE_EDGE,
215 .direction = CONF_TRIG_EVENT_DIR_HIGH,
216 .hysteresis = 2,
217 .index = 1,
218 .enable = 1
219 }
220 },
221 .sig_weights = {
222 .rssi_bcn_avg_weight = 10,
223 .rssi_pkt_avg_weight = 10,
224 .snr_bcn_avg_weight = 10,
225 .snr_pkt_avg_weight = 10
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300226 },
227 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200228 .bet_max_consecutive = 10,
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200229 .psm_entry_retries = 3
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300230 },
231 .init = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300232 .radioparam = {
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200233 .fem = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300234 }
Luciano Coelho6e92b412009-12-11 15:40:50 +0200235 },
236 .itrim = {
237 .enable = false,
238 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200239 },
240 .pm_config = {
241 .host_clk_settling_time = 5000,
242 .host_fast_wakeup_support = false
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300243 }
244};
245
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300246static LIST_HEAD(wl_list);
247
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300248static void wl1271_conf_init(struct wl1271 *wl)
249{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300250
251 /*
252 * This function applies the default configuration to the driver. This
253 * function is invoked upon driver load (spi probe.)
254 *
255 * The configuration is stored in a run-time structure in order to
256 * facilitate for run-time adjustment of any of the parameters. Making
257 * changes to the configuration structure will apply the new values on
258 * the next interface up (wl1271_op_start.)
259 */
260
261 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300262 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300263}
264
265
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300266static int wl1271_plt_init(struct wl1271 *wl)
267{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200268 struct conf_tx_ac_category *conf_ac;
269 struct conf_tx_tid *conf_tid;
270 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300271
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200272 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200273 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200274 return ret;
275
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200276 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200277 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200278 return ret;
279
Luciano Coelho12419cc2010-02-18 13:25:44 +0200280 ret = wl1271_init_templates_config(wl);
281 if (ret < 0)
282 return ret;
283
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300284 ret = wl1271_acx_init_mem_config(wl);
285 if (ret < 0)
286 return ret;
287
Luciano Coelho12419cc2010-02-18 13:25:44 +0200288 /* PHY layer config */
289 ret = wl1271_init_phy_config(wl);
290 if (ret < 0)
291 goto out_free_memmap;
292
293 ret = wl1271_acx_dco_itrim_params(wl);
294 if (ret < 0)
295 goto out_free_memmap;
296
297 /* Initialize connection monitoring thresholds */
298 ret = wl1271_acx_conn_monit_params(wl);
299 if (ret < 0)
300 goto out_free_memmap;
301
302 /* Bluetooth WLAN coexistence */
303 ret = wl1271_init_pta(wl);
304 if (ret < 0)
305 goto out_free_memmap;
306
307 /* Energy detection */
308 ret = wl1271_init_energy_detection(wl);
309 if (ret < 0)
310 goto out_free_memmap;
311
312 /* Default fragmentation threshold */
313 ret = wl1271_acx_frag_threshold(wl);
314 if (ret < 0)
315 goto out_free_memmap;
316
317 /* Default TID configuration */
318 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
319 conf_tid = &wl->conf.tx.tid_conf[i];
320 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
321 conf_tid->channel_type,
322 conf_tid->tsid,
323 conf_tid->ps_scheme,
324 conf_tid->ack_policy,
325 conf_tid->apsd_conf[0],
326 conf_tid->apsd_conf[1]);
327 if (ret < 0)
328 goto out_free_memmap;
329 }
330
331 /* Default AC configuration */
332 for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
333 conf_ac = &wl->conf.tx.ac_conf[i];
334 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
335 conf_ac->cw_max, conf_ac->aifsn,
336 conf_ac->tx_op_limit);
337 if (ret < 0)
338 goto out_free_memmap;
339 }
340
341 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200342 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300343 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200344 goto out_free_memmap;
345
346 /* Configure for CAM power saving (ie. always active) */
347 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
348 if (ret < 0)
349 goto out_free_memmap;
350
351 /* configure PM */
352 ret = wl1271_acx_pm_config(wl);
353 if (ret < 0)
354 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300355
356 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200357
358 out_free_memmap:
359 kfree(wl->target_mem_map);
360 wl->target_mem_map = NULL;
361
362 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300363}
364
365static void wl1271_disable_interrupts(struct wl1271 *wl)
366{
367 disable_irq(wl->irq);
368}
369
370static void wl1271_power_off(struct wl1271 *wl)
371{
372 wl->set_power(false);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200373 clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300374}
375
376static void wl1271_power_on(struct wl1271 *wl)
377{
378 wl->set_power(true);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200379 set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300380}
381
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300382static void wl1271_fw_status(struct wl1271 *wl,
383 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300384{
385 u32 total = 0;
386 int i;
387
Juuso Oikarinen74621412009-10-12 15:08:54 +0300388 wl1271_spi_read(wl, FW_STATUS_ADDR, status,
389 sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300390
391 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
392 "drv_rx_counter = %d, tx_results_counter = %d)",
393 status->intr,
394 status->fw_rx_counter,
395 status->drv_rx_counter,
396 status->tx_results_counter);
397
398 /* update number of available TX blocks */
399 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300400 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
401 wl->tx_blocks_freed[i];
402
403 wl->tx_blocks_freed[i] =
404 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300405 wl->tx_blocks_available += cnt;
406 total += cnt;
407 }
408
409 /* if more blocks are available now, schedule some tx work */
410 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300411 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300412
413 /* update the host-chipset time offset */
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300414 wl->time_offset = jiffies_to_usecs(jiffies) -
415 le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300416}
417
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300418static void wl1271_irq_work(struct work_struct *work)
419{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300420 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300421 u32 intr;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300422 struct wl1271 *wl =
423 container_of(work, struct wl1271, irq_work);
424
425 mutex_lock(&wl->mutex);
426
427 wl1271_debug(DEBUG_IRQ, "IRQ work");
428
429 if (wl->state == WL1271_STATE_OFF)
430 goto out;
431
432 ret = wl1271_ps_elp_wakeup(wl, true);
433 if (ret < 0)
434 goto out;
435
Juuso Oikarinen74621412009-10-12 15:08:54 +0300436 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300437
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300438 wl1271_fw_status(wl, wl->fw_status);
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300439 intr = le32_to_cpu(wl->fw_status->intr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300440 if (!intr) {
441 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
442 goto out_sleep;
443 }
444
445 intr &= WL1271_INTR_MASK;
446
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300447 if (intr & WL1271_ACX_INTR_EVENT_A) {
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300448 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
Juuso Oikarinen13f2dc52009-12-11 15:40:59 +0200449 wl1271_event_handle(wl, 0);
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300450 }
451
452 if (intr & WL1271_ACX_INTR_EVENT_B) {
453 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
Juuso Oikarinen13f2dc52009-12-11 15:40:59 +0200454 wl1271_event_handle(wl, 1);
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300455 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300456
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300457 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
458 wl1271_debug(DEBUG_IRQ,
459 "WL1271_ACX_INTR_INIT_COMPLETE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300460
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300461 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
462 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300463
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300464 if (intr & WL1271_ACX_INTR_DATA) {
465 u8 tx_res_cnt = wl->fw_status->tx_results_counter -
466 wl->tx_results_count;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300467
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300468 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300469
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300470 /* check for tx results */
471 if (tx_res_cnt)
472 wl1271_tx_complete(wl, tx_res_cnt);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300473
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300474 wl1271_rx(wl, wl->fw_status);
475 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300476
477out_sleep:
Juuso Oikarinen74621412009-10-12 15:08:54 +0300478 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
Luciano Coelho73d0a132009-08-11 11:58:27 +0300479 WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300480 wl1271_ps_elp_sleep(wl);
481
482out:
483 mutex_unlock(&wl->mutex);
484}
485
486static irqreturn_t wl1271_irq(int irq, void *cookie)
487{
488 struct wl1271 *wl;
489 unsigned long flags;
490
491 wl1271_debug(DEBUG_IRQ, "IRQ");
492
493 wl = cookie;
494
495 /* complete the ELP completion */
496 spin_lock_irqsave(&wl->wl_lock, flags);
497 if (wl->elp_compl) {
498 complete(wl->elp_compl);
499 wl->elp_compl = NULL;
500 }
501
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300502 ieee80211_queue_work(wl->hw, &wl->irq_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300503 spin_unlock_irqrestore(&wl->wl_lock, flags);
504
505 return IRQ_HANDLED;
506}
507
508static int wl1271_fetch_firmware(struct wl1271 *wl)
509{
510 const struct firmware *fw;
511 int ret;
512
513 ret = request_firmware(&fw, WL1271_FW_NAME, &wl->spi->dev);
514
515 if (ret < 0) {
516 wl1271_error("could not get firmware: %d", ret);
517 return ret;
518 }
519
520 if (fw->size % 4) {
521 wl1271_error("firmware size is not multiple of 32 bits: %zu",
522 fw->size);
523 ret = -EILSEQ;
524 goto out;
525 }
526
527 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300528 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300529
530 if (!wl->fw) {
531 wl1271_error("could not allocate memory for the firmware");
532 ret = -ENOMEM;
533 goto out;
534 }
535
536 memcpy(wl->fw, fw->data, wl->fw_len);
537
538 ret = 0;
539
540out:
541 release_firmware(fw);
542
543 return ret;
544}
545
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200546static int wl1271_update_mac_addr(struct wl1271 *wl)
547{
548 int ret = 0;
549 u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
550
551 /* get mac address from the NVS */
552 wl->mac_addr[0] = nvs_ptr[11];
553 wl->mac_addr[1] = nvs_ptr[10];
554 wl->mac_addr[2] = nvs_ptr[6];
555 wl->mac_addr[3] = nvs_ptr[5];
556 wl->mac_addr[4] = nvs_ptr[4];
557 wl->mac_addr[5] = nvs_ptr[3];
558
559 /* FIXME: if it is a zero-address, we should bail out. Now, instead,
560 we randomize an address */
561 if (is_zero_ether_addr(wl->mac_addr)) {
562 static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
563 memcpy(wl->mac_addr, nokia_oui, 3);
564 get_random_bytes(wl->mac_addr + 3, 3);
Juuso Oikarinene2e77b52010-02-18 13:25:46 +0200565
566 /* update this address to the NVS */
567 nvs_ptr[11] = wl->mac_addr[0];
568 nvs_ptr[10] = wl->mac_addr[1];
569 nvs_ptr[6] = wl->mac_addr[2];
570 nvs_ptr[5] = wl->mac_addr[3];
571 nvs_ptr[4] = wl->mac_addr[4];
572 nvs_ptr[3] = wl->mac_addr[5];
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200573 }
574
575 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
576
577 return ret;
578}
579
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300580static int wl1271_fetch_nvs(struct wl1271 *wl)
581{
582 const struct firmware *fw;
583 int ret;
584
585 ret = request_firmware(&fw, WL1271_NVS_NAME, &wl->spi->dev);
586
587 if (ret < 0) {
588 wl1271_error("could not get nvs file: %d", ret);
589 return ret;
590 }
591
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200592 if (fw->size != sizeof(struct wl1271_nvs_file)) {
593 wl1271_error("nvs size is not as expected: %zu != %zu",
594 fw->size, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300595 ret = -EILSEQ;
596 goto out;
597 }
598
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200599 wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300600
601 if (!wl->nvs) {
602 wl1271_error("could not allocate memory for the nvs file");
603 ret = -ENOMEM;
604 goto out;
605 }
606
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200607 memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300608
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200609 ret = wl1271_update_mac_addr(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300610
611out:
612 release_firmware(fw);
613
614 return ret;
615}
616
617static void wl1271_fw_wakeup(struct wl1271 *wl)
618{
619 u32 elp_reg;
620
621 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300622 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300623}
624
625static int wl1271_setup(struct wl1271 *wl)
626{
627 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
628 if (!wl->fw_status)
629 return -ENOMEM;
630
631 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
632 if (!wl->tx_res_if) {
633 kfree(wl->fw_status);
634 return -ENOMEM;
635 }
636
637 INIT_WORK(&wl->irq_work, wl1271_irq_work);
638 INIT_WORK(&wl->tx_work, wl1271_tx_work);
639 return 0;
640}
641
642static int wl1271_chip_wakeup(struct wl1271 *wl)
643{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300644 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300645 int ret = 0;
646
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200647 msleep(WL1271_PRE_POWER_ON_SLEEP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300648 wl1271_power_on(wl);
649 msleep(WL1271_POWER_ON_SLEEP);
650 wl1271_spi_reset(wl);
651 wl1271_spi_init(wl);
652
653 /* We don't need a real memory partition here, because we only want
654 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300655 memset(&partition, 0, sizeof(partition));
656 partition.reg.start = REGISTERS_BASE;
657 partition.reg.size = REGISTERS_DOWN_SIZE;
658 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300659
660 /* ELP module wake up */
661 wl1271_fw_wakeup(wl);
662
663 /* whal_FwCtrl_BootSm() */
664
665 /* 0. read chip id from CHIP_ID */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300666 wl->chip.id = wl1271_spi_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300667
668 /* 1. check if chip id is valid */
669
670 switch (wl->chip.id) {
671 case CHIP_ID_1271_PG10:
672 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
673 wl->chip.id);
674
675 ret = wl1271_setup(wl);
676 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200677 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300678 break;
679 case CHIP_ID_1271_PG20:
680 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
681 wl->chip.id);
682
683 ret = wl1271_setup(wl);
684 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200685 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300686 break;
687 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200688 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300689 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200690 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300691 }
692
693 if (wl->fw == NULL) {
694 ret = wl1271_fetch_firmware(wl);
695 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200696 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300697 }
698
699 /* No NVS from netlink, try to get it from the filesystem */
700 if (wl->nvs == NULL) {
701 ret = wl1271_fetch_nvs(wl);
702 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200703 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300704 }
705
706out:
707 return ret;
708}
709
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300710int wl1271_plt_start(struct wl1271 *wl)
711{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200712 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300713 int ret;
714
715 mutex_lock(&wl->mutex);
716
717 wl1271_notice("power up");
718
719 if (wl->state != WL1271_STATE_OFF) {
720 wl1271_error("cannot go into PLT state because not "
721 "in off state: %d", wl->state);
722 ret = -EBUSY;
723 goto out;
724 }
725
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200726 while (retries) {
727 retries--;
728 ret = wl1271_chip_wakeup(wl);
729 if (ret < 0)
730 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300731
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200732 ret = wl1271_boot(wl);
733 if (ret < 0)
734 goto power_off;
735
736 ret = wl1271_plt_init(wl);
737 if (ret < 0)
738 goto irq_disable;
739
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200740 wl->state = WL1271_STATE_PLT;
741 wl1271_notice("firmware booted in PLT mode (%s)",
742 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300743 goto out;
744
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200745irq_disable:
746 wl1271_disable_interrupts(wl);
747 mutex_unlock(&wl->mutex);
748 /* Unlocking the mutex in the middle of handling is
749 inherently unsafe. In this case we deem it safe to do,
750 because we need to let any possibly pending IRQ out of
751 the system (and while we are WL1271_STATE_OFF the IRQ
752 work function will not do anything.) Also, any other
753 possible concurrent operations will fail due to the
754 current state, hence the wl1271 struct should be safe. */
755 cancel_work_sync(&wl->irq_work);
756 mutex_lock(&wl->mutex);
757power_off:
758 wl1271_power_off(wl);
759 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300760
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200761 wl1271_error("firmware boot in PLT mode failed despite %d retries",
762 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300763out:
764 mutex_unlock(&wl->mutex);
765
766 return ret;
767}
768
769int wl1271_plt_stop(struct wl1271 *wl)
770{
771 int ret = 0;
772
773 mutex_lock(&wl->mutex);
774
775 wl1271_notice("power down");
776
777 if (wl->state != WL1271_STATE_PLT) {
778 wl1271_error("cannot power down because not in PLT "
779 "state: %d", wl->state);
780 ret = -EBUSY;
781 goto out;
782 }
783
784 wl1271_disable_interrupts(wl);
785 wl1271_power_off(wl);
786
787 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300788 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300789
790out:
791 mutex_unlock(&wl->mutex);
792
793 return ret;
794}
795
796
797static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
798{
799 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200800 struct ieee80211_conf *conf = &hw->conf;
801 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
802 struct ieee80211_sta *sta = txinfo->control.sta;
803 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300804
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200805 /* peek into the rates configured in the STA entry */
806 spin_lock_irqsave(&wl->wl_lock, flags);
807 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
808 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
809 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
810 }
811 spin_unlock_irqrestore(&wl->wl_lock, flags);
812
813 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300814 skb_queue_tail(&wl->tx_queue, skb);
815
816 /*
817 * The chip specific setup must run before the first TX packet -
818 * before that, the tx_work will not be initialized!
819 */
820
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300821 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300822
823 /*
824 * The workqueue is slow to process the tx_queue and we need stop
825 * the queue here, otherwise the queue will get too long.
826 */
827 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) {
828 ieee80211_stop_queues(wl->hw);
829
830 /*
831 * FIXME: this is racy, the variable is not properly
832 * protected. Maybe fix this by removing the stupid
833 * variable altogether and checking the real queue state?
834 */
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200835 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300836 }
837
838 return NETDEV_TX_OK;
839}
840
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300841static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
842 void *arg)
843{
844 struct net_device *dev;
845 struct wireless_dev *wdev;
846 struct wiphy *wiphy;
847 struct ieee80211_hw *hw;
848 struct wl1271 *wl;
849 struct wl1271 *wl_temp;
850 struct in_device *idev;
851 struct in_ifaddr *ifa = arg;
852 int ret = 0;
853
854 /* FIXME: this ugly function should probably be implemented in the
855 * mac80211, and here should only be a simple callback handling actual
856 * setting of the filters. Now we need to dig up references to
857 * various structures to gain access to what we need.
858 * Also, because of this, there is no "initial" setting of the filter
859 * in "op_start", because we don't want to dig up struct net_device
860 * there - the filter will be set upon first change of the interface
861 * IP address. */
862
863 dev = ifa->ifa_dev->dev;
864
865 wdev = dev->ieee80211_ptr;
866 if (wdev == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200867 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300868
869 wiphy = wdev->wiphy;
870 if (wiphy == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200871 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300872
873 hw = wiphy_priv(wiphy);
874 if (hw == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200875 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300876
877 /* Check that the interface is one supported by this driver. */
878 wl_temp = hw->priv;
879 list_for_each_entry(wl, &wl_list, list) {
880 if (wl == wl_temp)
881 break;
882 }
883 if (wl == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200884 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300885
886 /* Get the interface IP address for the device. "ifa" will become
887 NULL if:
888 - there is no IPV4 protocol address configured
889 - there are multiple (virtual) IPV4 addresses configured
890 When "ifa" is NULL, filtering will be disabled.
891 */
892 ifa = NULL;
893 idev = dev->ip_ptr;
894 if (idev)
895 ifa = idev->ifa_list;
896
897 if (ifa && ifa->ifa_next)
898 ifa = NULL;
899
900 mutex_lock(&wl->mutex);
901
902 if (wl->state == WL1271_STATE_OFF)
903 goto out;
904
905 ret = wl1271_ps_elp_wakeup(wl, false);
906 if (ret < 0)
907 goto out;
908 if (ifa)
909 ret = wl1271_acx_arp_ip_filter(wl, true,
910 (u8 *)&ifa->ifa_address,
911 ACX_IPV4_VERSION);
912 else
913 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
914 ACX_IPV4_VERSION);
915 wl1271_ps_elp_sleep(wl);
916
917out:
918 mutex_unlock(&wl->mutex);
919
Luciano Coelho17d72652009-11-23 23:22:15 +0200920 return NOTIFY_OK;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300921}
922
923static struct notifier_block wl1271_dev_notifier = {
924 .notifier_call = wl1271_dev_notify,
925};
926
927
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300928static int wl1271_op_start(struct ieee80211_hw *hw)
929{
930 struct wl1271 *wl = hw->priv;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200931 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300932 int ret = 0;
933
934 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
935
936 mutex_lock(&wl->mutex);
937
938 if (wl->state != WL1271_STATE_OFF) {
939 wl1271_error("cannot start because not in off state: %d",
940 wl->state);
941 ret = -EBUSY;
942 goto out;
943 }
944
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200945 while (retries) {
946 retries--;
947 ret = wl1271_chip_wakeup(wl);
948 if (ret < 0)
949 goto power_off;
950
951 ret = wl1271_boot(wl);
952 if (ret < 0)
953 goto power_off;
954
955 ret = wl1271_hw_init(wl);
956 if (ret < 0)
957 goto irq_disable;
958
959 wl->state = WL1271_STATE_ON;
960 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300961 goto out;
962
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200963irq_disable:
964 wl1271_disable_interrupts(wl);
965 mutex_unlock(&wl->mutex);
966 /* Unlocking the mutex in the middle of handling is
967 inherently unsafe. In this case we deem it safe to do,
968 because we need to let any possibly pending IRQ out of
969 the system (and while we are WL1271_STATE_OFF the IRQ
970 work function will not do anything.) Also, any other
971 possible concurrent operations will fail due to the
972 current state, hence the wl1271 struct should be safe. */
973 cancel_work_sync(&wl->irq_work);
974 mutex_lock(&wl->mutex);
975power_off:
976 wl1271_power_off(wl);
977 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300978
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200979 wl1271_error("firmware boot failed despite %d retries",
980 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300981out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300982 mutex_unlock(&wl->mutex);
983
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300984 if (!ret) {
985 list_add(&wl->list, &wl_list);
986 register_inetaddr_notifier(&wl1271_dev_notifier);
987 }
988
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300989 return ret;
990}
991
992static void wl1271_op_stop(struct ieee80211_hw *hw)
993{
994 struct wl1271 *wl = hw->priv;
995 int i;
996
997 wl1271_info("down");
998
999 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1000
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001001 unregister_inetaddr_notifier(&wl1271_dev_notifier);
1002 list_del(&wl->list);
1003
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001004 mutex_lock(&wl->mutex);
1005
1006 WARN_ON(wl->state != WL1271_STATE_ON);
1007
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001008 if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001009 mutex_unlock(&wl->mutex);
1010 ieee80211_scan_completed(wl->hw, true);
1011 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001012 }
1013
1014 wl->state = WL1271_STATE_OFF;
1015
1016 wl1271_disable_interrupts(wl);
1017
1018 mutex_unlock(&wl->mutex);
1019
1020 cancel_work_sync(&wl->irq_work);
1021 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001022
1023 mutex_lock(&wl->mutex);
1024
1025 /* let's notify MAC80211 about the remaining pending TX frames */
1026 wl1271_tx_flush(wl);
1027 wl1271_power_off(wl);
1028
1029 memset(wl->bssid, 0, ETH_ALEN);
1030 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1031 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001032 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001033 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001034
1035 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001036 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001037 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1038 wl->tx_blocks_available = 0;
1039 wl->tx_results_count = 0;
1040 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001041 wl->tx_security_last_seq = 0;
1042 wl->tx_security_seq_16 = 0;
1043 wl->tx_security_seq_32 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001044 wl->time_offset = 0;
1045 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001046 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1047 wl->sta_rate_set = 0;
1048 wl->flags = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001049
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001050 for (i = 0; i < NUM_TX_QUEUES; i++)
1051 wl->tx_blocks_freed[i] = 0;
1052
1053 wl1271_debugfs_reset(wl);
1054 mutex_unlock(&wl->mutex);
1055}
1056
1057static int wl1271_op_add_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +01001058 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001059{
1060 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001061 int ret = 0;
1062
John W. Linvillee5539bc2009-08-18 10:50:34 -04001063 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Johannes Berg1ed32e42009-12-23 13:15:45 +01001064 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001065
1066 mutex_lock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001067 if (wl->vif) {
1068 ret = -EBUSY;
1069 goto out;
1070 }
1071
Johannes Berg1ed32e42009-12-23 13:15:45 +01001072 wl->vif = vif;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001073
Johannes Berg1ed32e42009-12-23 13:15:45 +01001074 switch (vif->type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001075 case NL80211_IFTYPE_STATION:
1076 wl->bss_type = BSS_TYPE_STA_BSS;
1077 break;
1078 case NL80211_IFTYPE_ADHOC:
1079 wl->bss_type = BSS_TYPE_IBSS;
1080 break;
1081 default:
1082 ret = -EOPNOTSUPP;
1083 goto out;
1084 }
1085
1086 /* FIXME: what if conf->mac_addr changes? */
1087
1088out:
1089 mutex_unlock(&wl->mutex);
1090 return ret;
1091}
1092
1093static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +01001094 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001095{
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001096 struct wl1271 *wl = hw->priv;
1097
1098 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001099 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001100 wl->vif = NULL;
1101 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001102}
1103
1104#if 0
1105static int wl1271_op_config_interface(struct ieee80211_hw *hw,
1106 struct ieee80211_vif *vif,
1107 struct ieee80211_if_conf *conf)
1108{
1109 struct wl1271 *wl = hw->priv;
1110 struct sk_buff *beacon;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001111 int ret;
1112
David S. Miller32646902009-09-17 10:18:30 -07001113 wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM",
1114 conf->bssid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001115 wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid,
1116 conf->ssid_len);
1117
1118 mutex_lock(&wl->mutex);
1119
1120 ret = wl1271_ps_elp_wakeup(wl, false);
1121 if (ret < 0)
1122 goto out;
1123
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001124 if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
1125 wl1271_debug(DEBUG_MAC80211, "bssid changed");
1126
1127 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
1128
1129 ret = wl1271_cmd_join(wl);
1130 if (ret < 0)
1131 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001132
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001133 ret = wl1271_cmd_build_null_data(wl);
1134 if (ret < 0)
1135 goto out_sleep;
1136 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001137
1138 wl->ssid_len = conf->ssid_len;
1139 if (wl->ssid_len)
1140 memcpy(wl->ssid, conf->ssid, wl->ssid_len);
1141
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001142 if (conf->changed & IEEE80211_IFCC_BEACON) {
1143 beacon = ieee80211_beacon_get(hw, vif);
1144 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1145 beacon->data, beacon->len);
1146
1147 if (ret < 0) {
1148 dev_kfree_skb(beacon);
1149 goto out_sleep;
1150 }
1151
1152 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE,
1153 beacon->data, beacon->len);
1154
1155 dev_kfree_skb(beacon);
1156
1157 if (ret < 0)
1158 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001159 }
1160
1161out_sleep:
1162 wl1271_ps_elp_sleep(wl);
1163
1164out:
1165 mutex_unlock(&wl->mutex);
1166
1167 return ret;
1168}
1169#endif
1170
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001171static int wl1271_join_channel(struct wl1271 *wl, int channel)
1172{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001173 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001174 /* we need to use a dummy BSSID for now */
1175 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1176 0xad, 0xbe, 0xef };
1177
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001178 /* the dummy join is not required for ad-hoc */
1179 if (wl->bss_type == BSS_TYPE_IBSS)
1180 goto out;
1181
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001182 /* disable mac filter, so we hear everything */
1183 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1184
1185 wl->channel = channel;
1186 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1187
1188 ret = wl1271_cmd_join(wl);
1189 if (ret < 0)
1190 goto out;
1191
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001192 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001193
1194out:
1195 return ret;
1196}
1197
1198static int wl1271_unjoin_channel(struct wl1271 *wl)
1199{
1200 int ret;
1201
1202 /* to stop listening to a channel, we disconnect */
1203 ret = wl1271_cmd_disconnect(wl);
1204 if (ret < 0)
1205 goto out;
1206
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001207 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001208 wl->channel = 0;
1209 memset(wl->bssid, 0, ETH_ALEN);
1210 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1211
1212out:
1213 return ret;
1214}
1215
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001216static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1217{
1218 struct wl1271 *wl = hw->priv;
1219 struct ieee80211_conf *conf = &hw->conf;
1220 int channel, ret = 0;
1221
1222 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1223
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001224 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001225 channel,
1226 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001227 conf->power_level,
1228 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001229
1230 mutex_lock(&wl->mutex);
1231
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001232 wl->band = conf->channel->band;
1233
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001234 ret = wl1271_ps_elp_wakeup(wl, false);
1235 if (ret < 0)
1236 goto out;
1237
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001238 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001239 if (conf->flags & IEEE80211_CONF_IDLE &&
1240 test_bit(WL1271_FLAG_JOINED, &wl->flags))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001241 wl1271_unjoin_channel(wl);
Juuso Oikarinen8f648c02009-12-11 15:41:10 +02001242 else if (!(conf->flags & IEEE80211_CONF_IDLE))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001243 wl1271_join_channel(wl, channel);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001244
1245 if (conf->flags & IEEE80211_CONF_IDLE) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001246 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1247 wl->sta_rate_set = 0;
1248 wl1271_acx_rate_policies(wl);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001249 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001250 }
1251
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001252 /* if the channel changes while joined, join again */
Juuso Oikarinenddb01a52010-02-18 13:25:37 +02001253 if (channel != wl->channel &&
1254 test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1255 wl->channel = channel;
1256 /* FIXME: maybe use CMD_CHANNEL_SWITCH for this? */
1257 ret = wl1271_cmd_join(wl);
1258 if (ret < 0)
1259 wl1271_warning("cmd join to update channel failed %d",
1260 ret);
1261 } else
1262 wl->channel = channel;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001263
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001264 if (conf->flags & IEEE80211_CONF_PS &&
1265 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1266 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001267
1268 /*
1269 * We enter PSM only if we're already associated.
1270 * If we're not, we'll enter it when joining an SSID,
1271 * through the bss_info_changed() hook.
1272 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001273 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001274 wl1271_info("psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001275 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1276 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001277 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001278 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001279 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001280 wl1271_info("psm disabled");
1281
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001282 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001283
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001284 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001285 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1286 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001287 }
1288
1289 if (conf->power_level != wl->power_level) {
1290 ret = wl1271_acx_tx_power(wl, conf->power_level);
1291 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001292 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001293
1294 wl->power_level = conf->power_level;
1295 }
1296
1297out_sleep:
1298 wl1271_ps_elp_sleep(wl);
1299
1300out:
1301 mutex_unlock(&wl->mutex);
1302
1303 return ret;
1304}
1305
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001306struct wl1271_filter_params {
1307 bool enabled;
1308 int mc_list_length;
1309 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1310};
1311
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001312static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1313 struct dev_addr_list *mc_list)
1314{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001315 struct wl1271_filter_params *fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001316 int i;
1317
Juuso Oikarinen74441132009-10-13 12:47:53 +03001318 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001319 if (!fp) {
1320 wl1271_error("Out of memory setting filters.");
1321 return 0;
1322 }
1323
1324 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001325 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001326 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1327 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001328 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001329 }
1330
1331 fp->mc_list_length = 0;
1332 for (i = 0; i < mc_count; i++) {
1333 if (mc_list->da_addrlen == ETH_ALEN) {
1334 memcpy(fp->mc_list[fp->mc_list_length],
1335 mc_list->da_addr, ETH_ALEN);
1336 fp->mc_list_length++;
1337 } else
1338 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001339 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001340 }
1341
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001342 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001343}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001344
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001345#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1346 FIF_ALLMULTI | \
1347 FIF_FCSFAIL | \
1348 FIF_BCN_PRBRESP_PROMISC | \
1349 FIF_CONTROL | \
1350 FIF_OTHER_BSS)
1351
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001352static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1353 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001354 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001355{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001356 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001357 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001358 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001359
1360 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1361
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001362 mutex_lock(&wl->mutex);
1363
1364 if (wl->state == WL1271_STATE_OFF)
1365 goto out;
1366
1367 ret = wl1271_ps_elp_wakeup(wl, false);
1368 if (ret < 0)
1369 goto out;
1370
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001371 *total &= WL1271_SUPPORTED_FILTERS;
1372 changed &= WL1271_SUPPORTED_FILTERS;
1373
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001374 if (*total & FIF_ALLMULTI)
1375 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1376 else if (fp)
1377 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1378 fp->mc_list,
1379 fp->mc_list_length);
1380 if (ret < 0)
1381 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001382
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001383 kfree(fp);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001384
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001385 /* FIXME: We still need to set our filters properly */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001386
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001387 /* determine, whether supported filter values have changed */
1388 if (changed == 0)
1389 goto out_sleep;
1390
1391 /* apply configured filters */
1392 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1393 if (ret < 0)
1394 goto out_sleep;
1395
1396out_sleep:
1397 wl1271_ps_elp_sleep(wl);
1398
1399out:
1400 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001401}
1402
1403static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1404 struct ieee80211_vif *vif,
1405 struct ieee80211_sta *sta,
1406 struct ieee80211_key_conf *key_conf)
1407{
1408 struct wl1271 *wl = hw->priv;
1409 const u8 *addr;
1410 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001411 u32 tx_seq_32 = 0;
1412 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001413 u8 key_type;
1414
1415 static const u8 bcast_addr[ETH_ALEN] =
1416 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1417
1418 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1419
1420 addr = sta ? sta->addr : bcast_addr;
1421
1422 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1423 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1424 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1425 key_conf->alg, key_conf->keyidx,
1426 key_conf->keylen, key_conf->flags);
1427 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1428
1429 if (is_zero_ether_addr(addr)) {
1430 /* We dont support TX only encryption */
1431 ret = -EOPNOTSUPP;
1432 goto out;
1433 }
1434
1435 mutex_lock(&wl->mutex);
1436
1437 ret = wl1271_ps_elp_wakeup(wl, false);
1438 if (ret < 0)
1439 goto out_unlock;
1440
1441 switch (key_conf->alg) {
1442 case ALG_WEP:
1443 key_type = KEY_WEP;
1444
1445 key_conf->hw_key_idx = key_conf->keyidx;
1446 break;
1447 case ALG_TKIP:
1448 key_type = KEY_TKIP;
1449
1450 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001451 tx_seq_32 = wl->tx_security_seq_32;
1452 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001453 break;
1454 case ALG_CCMP:
1455 key_type = KEY_AES;
1456
1457 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001458 tx_seq_32 = wl->tx_security_seq_32;
1459 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001460 break;
1461 default:
1462 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1463
1464 ret = -EOPNOTSUPP;
1465 goto out_sleep;
1466 }
1467
1468 switch (cmd) {
1469 case SET_KEY:
1470 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1471 key_conf->keyidx, key_type,
1472 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001473 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001474 if (ret < 0) {
1475 wl1271_error("Could not add or replace key");
1476 goto out_sleep;
1477 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001478
1479 /* the default WEP key needs to be configured at least once */
1480 if (key_type == KEY_WEP) {
1481 ret = wl1271_cmd_set_default_wep_key(wl,
1482 wl->default_key);
1483 if (ret < 0)
1484 goto out_sleep;
1485 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001486 break;
1487
1488 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001489 /* The wl1271 does not allow to remove unicast keys - they
1490 will be cleared automatically on next CMD_JOIN. Ignore the
1491 request silently, as we dont want the mac80211 to emit
1492 an error message. */
1493 if (!is_broadcast_ether_addr(addr))
1494 break;
1495
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001496 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1497 key_conf->keyidx, key_type,
1498 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001499 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001500 if (ret < 0) {
1501 wl1271_error("Could not remove key");
1502 goto out_sleep;
1503 }
1504 break;
1505
1506 default:
1507 wl1271_error("Unsupported key cmd 0x%x", cmd);
1508 ret = -EOPNOTSUPP;
1509 goto out_sleep;
1510
1511 break;
1512 }
1513
1514out_sleep:
1515 wl1271_ps_elp_sleep(wl);
1516
1517out_unlock:
1518 mutex_unlock(&wl->mutex);
1519
1520out:
1521 return ret;
1522}
1523
1524static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1525 struct cfg80211_scan_request *req)
1526{
1527 struct wl1271 *wl = hw->priv;
1528 int ret;
1529 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001530 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001531
1532 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1533
1534 if (req->n_ssids) {
1535 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001536 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001537 }
1538
1539 mutex_lock(&wl->mutex);
1540
1541 ret = wl1271_ps_elp_wakeup(wl, false);
1542 if (ret < 0)
1543 goto out;
1544
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001545 if (wl1271_11a_enabled())
1546 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1547 WL1271_SCAN_BAND_DUAL, 3);
1548 else
1549 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1550 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001551
1552 wl1271_ps_elp_sleep(wl);
1553
1554out:
1555 mutex_unlock(&wl->mutex);
1556
1557 return ret;
1558}
1559
1560static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1561{
1562 struct wl1271 *wl = hw->priv;
1563 int ret;
1564
1565 mutex_lock(&wl->mutex);
1566
1567 ret = wl1271_ps_elp_wakeup(wl, false);
1568 if (ret < 0)
1569 goto out;
1570
1571 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1572 if (ret < 0)
1573 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1574
1575 wl1271_ps_elp_sleep(wl);
1576
1577out:
1578 mutex_unlock(&wl->mutex);
1579
1580 return ret;
1581}
1582
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001583static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1584{
1585 u8 *ptr = beacon->data +
1586 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1587
1588 /* find the location of the ssid in the beacon */
1589 while (ptr < beacon->data + beacon->len) {
1590 if (ptr[0] == WLAN_EID_SSID) {
1591 wl->ssid_len = ptr[1];
1592 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1593 return;
1594 }
1595 ptr += ptr[1];
1596 }
1597 wl1271_error("ad-hoc beacon template has no SSID!\n");
1598}
1599
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001600static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1601 struct ieee80211_vif *vif,
1602 struct ieee80211_bss_conf *bss_conf,
1603 u32 changed)
1604{
1605 enum wl1271_cmd_ps_mode mode;
1606 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001607 bool do_join = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001608 int ret;
1609
1610 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1611
1612 mutex_lock(&wl->mutex);
1613
1614 ret = wl1271_ps_elp_wakeup(wl, false);
1615 if (ret < 0)
1616 goto out;
1617
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001618 if (wl->bss_type == BSS_TYPE_IBSS) {
1619 /* FIXME: This implements rudimentary ad-hoc support -
1620 proper templates are on the wish list and notification
1621 on when they change. This patch will update the templates
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001622 on every call to this function. */
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001623 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1624
1625 if (beacon) {
1626 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001627
1628 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001629 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1630 beacon->data,
1631 beacon->len);
1632
1633 if (ret < 0) {
1634 dev_kfree_skb(beacon);
1635 goto out_sleep;
1636 }
1637
1638 hdr = (struct ieee80211_hdr *) beacon->data;
1639 hdr->frame_control = cpu_to_le16(
1640 IEEE80211_FTYPE_MGMT |
1641 IEEE80211_STYPE_PROBE_RESP);
1642
1643 ret = wl1271_cmd_template_set(wl,
1644 CMD_TEMPL_PROBE_RESPONSE,
1645 beacon->data,
1646 beacon->len);
1647 dev_kfree_skb(beacon);
1648 if (ret < 0)
1649 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001650
1651 /* Need to update the SSID (for filtering etc) */
1652 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001653 }
1654 }
1655
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001656 if ((changed & BSS_CHANGED_BSSID) &&
1657 /*
1658 * Now we know the correct bssid, so we send a new join command
1659 * and enable the BSSID filter
1660 */
1661 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
1662 wl->rx_config |= CFG_BSSID_FILTER_EN;
1663 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
1664 ret = wl1271_cmd_build_null_data(wl);
1665 if (ret < 0) {
1666 wl1271_warning("cmd buld null data failed %d",
1667 ret);
1668 goto out_sleep;
1669 }
1670
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001671 /* Need to update the BSSID (for filtering etc) */
1672 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001673 }
1674
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001675 if (changed & BSS_CHANGED_ASSOC) {
1676 if (bss_conf->assoc) {
1677 wl->aid = bss_conf->aid;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001678 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001679
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001680 /*
1681 * with wl1271, we don't need to update the
1682 * beacon_int and dtim_period, because the firmware
1683 * updates it by itself when the first beacon is
1684 * received after a join.
1685 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001686 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1687 if (ret < 0)
1688 goto out_sleep;
1689
1690 ret = wl1271_acx_aid(wl, wl->aid);
1691 if (ret < 0)
1692 goto out_sleep;
1693
1694 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001695 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1696 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001697 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001698 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001699 if (ret < 0)
1700 goto out_sleep;
1701 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001702 } else {
1703 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001704 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001705 wl->aid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001706 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001707
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001708 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001709
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001710 if (changed & BSS_CHANGED_ERP_SLOT) {
1711 if (bss_conf->use_short_slot)
1712 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1713 else
1714 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1715 if (ret < 0) {
1716 wl1271_warning("Set slot time failed %d", ret);
1717 goto out_sleep;
1718 }
1719 }
1720
1721 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1722 if (bss_conf->use_short_preamble)
1723 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1724 else
1725 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1726 }
1727
1728 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1729 if (bss_conf->use_cts_prot)
1730 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1731 else
1732 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1733 if (ret < 0) {
1734 wl1271_warning("Set ctsprotect failed %d", ret);
1735 goto out_sleep;
1736 }
1737 }
1738
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001739 if (do_join) {
1740 ret = wl1271_cmd_join(wl);
1741 if (ret < 0) {
1742 wl1271_warning("cmd join failed %d", ret);
1743 goto out_sleep;
1744 }
1745 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1746 }
1747
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001748out_sleep:
1749 wl1271_ps_elp_sleep(wl);
1750
1751out:
1752 mutex_unlock(&wl->mutex);
1753}
1754
Kalle Valoc6999d82010-02-18 13:25:41 +02001755static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1756 const struct ieee80211_tx_queue_params *params)
1757{
1758 struct wl1271 *wl = hw->priv;
1759 int ret;
1760
1761 mutex_lock(&wl->mutex);
1762
1763 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1764
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001765 ret = wl1271_ps_elp_wakeup(wl, false);
1766 if (ret < 0)
1767 goto out;
1768
Kalle Valoc6999d82010-02-18 13:25:41 +02001769 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1770 params->cw_min, params->cw_max,
1771 params->aifs, params->txop);
1772 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001773 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001774
1775 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1776 CONF_CHANNEL_TYPE_EDCF,
1777 wl1271_tx_get_queue(queue),
1778 CONF_PS_SCHEME_LEGACY_PSPOLL,
1779 CONF_ACK_POLICY_LEGACY, 0, 0);
1780 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001781 goto out_sleep;
1782
1783out_sleep:
1784 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001785
1786out:
1787 mutex_unlock(&wl->mutex);
1788
1789 return ret;
1790}
1791
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001792
1793/* can't be const, mac80211 writes to this */
1794static struct ieee80211_rate wl1271_rates[] = {
1795 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001796 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1797 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001798 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001799 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1800 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001801 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1802 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001803 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1804 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001805 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1806 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001807 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1808 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001809 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1810 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001811 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1812 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001813 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001814 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1815 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001816 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001817 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1818 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001819 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001820 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1821 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001822 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001823 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1824 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001825 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001826 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1827 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001828 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001829 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1830 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001831 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001832 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1833 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001834};
1835
1836/* can't be const, mac80211 writes to this */
1837static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001838 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1839 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1840 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1841 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1842 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1843 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1844 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1845 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1846 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1847 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1848 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1849 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1850 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001851};
1852
1853/* can't be const, mac80211 writes to this */
1854static struct ieee80211_supported_band wl1271_band_2ghz = {
1855 .channels = wl1271_channels,
1856 .n_channels = ARRAY_SIZE(wl1271_channels),
1857 .bitrates = wl1271_rates,
1858 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1859};
1860
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001861/* 5 GHz data rates for WL1273 */
1862static struct ieee80211_rate wl1271_rates_5ghz[] = {
1863 { .bitrate = 60,
1864 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1865 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
1866 { .bitrate = 90,
1867 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1868 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
1869 { .bitrate = 120,
1870 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1871 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
1872 { .bitrate = 180,
1873 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1874 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
1875 { .bitrate = 240,
1876 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1877 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
1878 { .bitrate = 360,
1879 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1880 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
1881 { .bitrate = 480,
1882 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1883 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
1884 { .bitrate = 540,
1885 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1886 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
1887};
1888
1889/* 5 GHz band channels for WL1273 */
1890static struct ieee80211_channel wl1271_channels_5ghz[] = {
1891 { .hw_value = 183, .center_freq = 4915},
1892 { .hw_value = 184, .center_freq = 4920},
1893 { .hw_value = 185, .center_freq = 4925},
1894 { .hw_value = 187, .center_freq = 4935},
1895 { .hw_value = 188, .center_freq = 4940},
1896 { .hw_value = 189, .center_freq = 4945},
1897 { .hw_value = 192, .center_freq = 4960},
1898 { .hw_value = 196, .center_freq = 4980},
1899 { .hw_value = 7, .center_freq = 5035},
1900 { .hw_value = 8, .center_freq = 5040},
1901 { .hw_value = 9, .center_freq = 5045},
1902 { .hw_value = 11, .center_freq = 5055},
1903 { .hw_value = 12, .center_freq = 5060},
1904 { .hw_value = 16, .center_freq = 5080},
1905 { .hw_value = 34, .center_freq = 5170},
1906 { .hw_value = 36, .center_freq = 5180},
1907 { .hw_value = 38, .center_freq = 5190},
1908 { .hw_value = 40, .center_freq = 5200},
1909 { .hw_value = 42, .center_freq = 5210},
1910 { .hw_value = 44, .center_freq = 5220},
1911 { .hw_value = 46, .center_freq = 5230},
1912 { .hw_value = 48, .center_freq = 5240},
1913 { .hw_value = 52, .center_freq = 5260},
1914 { .hw_value = 56, .center_freq = 5280},
1915 { .hw_value = 60, .center_freq = 5300},
1916 { .hw_value = 64, .center_freq = 5320},
1917 { .hw_value = 100, .center_freq = 5500},
1918 { .hw_value = 104, .center_freq = 5520},
1919 { .hw_value = 108, .center_freq = 5540},
1920 { .hw_value = 112, .center_freq = 5560},
1921 { .hw_value = 116, .center_freq = 5580},
1922 { .hw_value = 120, .center_freq = 5600},
1923 { .hw_value = 124, .center_freq = 5620},
1924 { .hw_value = 128, .center_freq = 5640},
1925 { .hw_value = 132, .center_freq = 5660},
1926 { .hw_value = 136, .center_freq = 5680},
1927 { .hw_value = 140, .center_freq = 5700},
1928 { .hw_value = 149, .center_freq = 5745},
1929 { .hw_value = 153, .center_freq = 5765},
1930 { .hw_value = 157, .center_freq = 5785},
1931 { .hw_value = 161, .center_freq = 5805},
1932 { .hw_value = 165, .center_freq = 5825},
1933};
1934
1935
1936static struct ieee80211_supported_band wl1271_band_5ghz = {
1937 .channels = wl1271_channels_5ghz,
1938 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
1939 .bitrates = wl1271_rates_5ghz,
1940 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
1941};
1942
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001943static const struct ieee80211_ops wl1271_ops = {
1944 .start = wl1271_op_start,
1945 .stop = wl1271_op_stop,
1946 .add_interface = wl1271_op_add_interface,
1947 .remove_interface = wl1271_op_remove_interface,
1948 .config = wl1271_op_config,
1949/* .config_interface = wl1271_op_config_interface, */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001950 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001951 .configure_filter = wl1271_op_configure_filter,
1952 .tx = wl1271_op_tx,
1953 .set_key = wl1271_op_set_key,
1954 .hw_scan = wl1271_op_hw_scan,
1955 .bss_info_changed = wl1271_op_bss_info_changed,
1956 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02001957 .conf_tx = wl1271_op_conf_tx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001958};
1959
1960static int wl1271_register_hw(struct wl1271 *wl)
1961{
1962 int ret;
1963
1964 if (wl->mac80211_registered)
1965 return 0;
1966
1967 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
1968
1969 ret = ieee80211_register_hw(wl->hw);
1970 if (ret < 0) {
1971 wl1271_error("unable to register mac80211 hw: %d", ret);
1972 return ret;
1973 }
1974
1975 wl->mac80211_registered = true;
1976
1977 wl1271_notice("loaded");
1978
1979 return 0;
1980}
1981
1982static int wl1271_init_ieee80211(struct wl1271 *wl)
1983{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03001984 /* The tx descriptor buffer and the TKIP space. */
1985 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
1986 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001987
1988 /* unit us */
1989 /* FIXME: find a proper value */
1990 wl->hw->channel_change_time = 10000;
1991
1992 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03001993 IEEE80211_HW_NOISE_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02001994 IEEE80211_HW_BEACON_FILTER |
1995 IEEE80211_HW_SUPPORTS_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001996
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001997 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
1998 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001999 wl->hw->wiphy->max_scan_ssids = 1;
2000 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
2001
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002002 if (wl1271_11a_enabled())
2003 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
2004
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002005 SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
2006
2007 return 0;
2008}
2009
2010static void wl1271_device_release(struct device *dev)
2011{
2012
2013}
2014
2015static struct platform_device wl1271_device = {
2016 .name = "wl1271",
2017 .id = -1,
2018
2019 /* device model insists to have a release function */
2020 .dev = {
2021 .release = wl1271_device_release,
2022 },
2023};
2024
2025#define WL1271_DEFAULT_CHANNEL 0
2026static int __devinit wl1271_probe(struct spi_device *spi)
2027{
2028 struct wl12xx_platform_data *pdata;
2029 struct ieee80211_hw *hw;
2030 struct wl1271 *wl;
2031 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002032
2033 pdata = spi->dev.platform_data;
2034 if (!pdata) {
2035 wl1271_error("no platform data");
2036 return -ENODEV;
2037 }
2038
2039 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2040 if (!hw) {
2041 wl1271_error("could not alloc ieee80211_hw");
2042 return -ENOMEM;
2043 }
2044
2045 wl = hw->priv;
2046 memset(wl, 0, sizeof(*wl));
2047
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002048 INIT_LIST_HEAD(&wl->list);
2049
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002050 wl->hw = hw;
2051 dev_set_drvdata(&spi->dev, wl);
2052 wl->spi = spi;
2053
2054 skb_queue_head_init(&wl->tx_queue);
2055
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002056 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002057 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002058 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002059 wl->rx_counter = 0;
2060 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2061 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002062 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002063 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002064 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002065 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2066 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002067 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002068 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002069 wl->flags = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002070
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002071 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002072 wl->tx_frames[i] = NULL;
2073
2074 spin_lock_init(&wl->wl_lock);
2075
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002076 wl->state = WL1271_STATE_OFF;
2077 mutex_init(&wl->mutex);
2078
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002079 /* This is the only SPI value that we need to set here, the rest
2080 * comes from the board-peripherals file */
2081 spi->bits_per_word = 32;
2082
2083 ret = spi_setup(spi);
2084 if (ret < 0) {
2085 wl1271_error("spi_setup failed");
2086 goto out_free;
2087 }
2088
2089 wl->set_power = pdata->set_power;
2090 if (!wl->set_power) {
2091 wl1271_error("set power function missing in platform data");
2092 ret = -ENODEV;
2093 goto out_free;
2094 }
2095
2096 wl->irq = spi->irq;
2097 if (wl->irq < 0) {
2098 wl1271_error("irq missing in platform data");
2099 ret = -ENODEV;
2100 goto out_free;
2101 }
2102
2103 ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
2104 if (ret < 0) {
2105 wl1271_error("request_irq() failed: %d", ret);
2106 goto out_free;
2107 }
2108
2109 set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
2110
2111 disable_irq(wl->irq);
2112
2113 ret = platform_device_register(&wl1271_device);
2114 if (ret) {
2115 wl1271_error("couldn't register platform device");
2116 goto out_irq;
2117 }
2118 dev_set_drvdata(&wl1271_device.dev, wl);
2119
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002120 /* Apply default driver configuration. */
2121 wl1271_conf_init(wl);
2122
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002123 ret = wl1271_init_ieee80211(wl);
2124 if (ret)
2125 goto out_platform;
2126
2127 ret = wl1271_register_hw(wl);
2128 if (ret)
2129 goto out_platform;
2130
2131 wl1271_debugfs_init(wl);
2132
2133 wl1271_notice("initialized");
2134
2135 return 0;
2136
2137 out_platform:
2138 platform_device_unregister(&wl1271_device);
2139
2140 out_irq:
2141 free_irq(wl->irq, wl);
2142
2143 out_free:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002144 ieee80211_free_hw(hw);
2145
2146 return ret;
2147}
2148
2149static int __devexit wl1271_remove(struct spi_device *spi)
2150{
2151 struct wl1271 *wl = dev_get_drvdata(&spi->dev);
2152
2153 ieee80211_unregister_hw(wl->hw);
2154
2155 wl1271_debugfs_exit(wl);
2156 platform_device_unregister(&wl1271_device);
2157 free_irq(wl->irq, wl);
2158 kfree(wl->target_mem_map);
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03002159 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002160 wl->fw = NULL;
2161 kfree(wl->nvs);
2162 wl->nvs = NULL;
2163
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002164 kfree(wl->fw_status);
2165 kfree(wl->tx_res_if);
2166
2167 ieee80211_free_hw(wl->hw);
2168
2169 return 0;
2170}
2171
2172
2173static struct spi_driver wl1271_spi_driver = {
2174 .driver = {
2175 .name = "wl1271",
2176 .bus = &spi_bus_type,
2177 .owner = THIS_MODULE,
2178 },
2179
2180 .probe = wl1271_probe,
2181 .remove = __devexit_p(wl1271_remove),
2182};
2183
2184static int __init wl1271_init(void)
2185{
2186 int ret;
2187
2188 ret = spi_register_driver(&wl1271_spi_driver);
2189 if (ret < 0) {
2190 wl1271_error("failed to register spi driver: %d", ret);
2191 goto out;
2192 }
2193
2194out:
2195 return ret;
2196}
2197
2198static void __exit wl1271_exit(void)
2199{
2200 spi_unregister_driver(&wl1271_spi_driver);
2201
2202 wl1271_notice("unloaded");
2203}
2204
2205module_init(wl1271_init);
2206module_exit(wl1271_exit);
2207
2208MODULE_LICENSE("GPL");
2209MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
Luciano Coelho2f018722009-10-08 21:56:27 +03002210MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
Ben Hutchings49f146d2009-11-07 22:02:15 +00002211MODULE_FIRMWARE(WL1271_FW_NAME);