blob: 4a0a15bcd67e3155d4e312f3d02c42150b13dc2e [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
4 * Copyright (C) 2008-2009 Nokia Corporation
5 *
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 Coelhod6e19d132009-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 }
1478 break;
1479
1480 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001481 /* The wl1271 does not allow to remove unicast keys - they
1482 will be cleared automatically on next CMD_JOIN. Ignore the
1483 request silently, as we dont want the mac80211 to emit
1484 an error message. */
1485 if (!is_broadcast_ether_addr(addr))
1486 break;
1487
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001488 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1489 key_conf->keyidx, key_type,
1490 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001491 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001492 if (ret < 0) {
1493 wl1271_error("Could not remove key");
1494 goto out_sleep;
1495 }
1496 break;
1497
1498 default:
1499 wl1271_error("Unsupported key cmd 0x%x", cmd);
1500 ret = -EOPNOTSUPP;
1501 goto out_sleep;
1502
1503 break;
1504 }
1505
1506out_sleep:
1507 wl1271_ps_elp_sleep(wl);
1508
1509out_unlock:
1510 mutex_unlock(&wl->mutex);
1511
1512out:
1513 return ret;
1514}
1515
1516static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1517 struct cfg80211_scan_request *req)
1518{
1519 struct wl1271 *wl = hw->priv;
1520 int ret;
1521 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001522 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001523
1524 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1525
1526 if (req->n_ssids) {
1527 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001528 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001529 }
1530
1531 mutex_lock(&wl->mutex);
1532
1533 ret = wl1271_ps_elp_wakeup(wl, false);
1534 if (ret < 0)
1535 goto out;
1536
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001537 if (wl1271_11a_enabled())
1538 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1539 WL1271_SCAN_BAND_DUAL, 3);
1540 else
1541 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1542 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001543
1544 wl1271_ps_elp_sleep(wl);
1545
1546out:
1547 mutex_unlock(&wl->mutex);
1548
1549 return ret;
1550}
1551
1552static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1553{
1554 struct wl1271 *wl = hw->priv;
1555 int ret;
1556
1557 mutex_lock(&wl->mutex);
1558
1559 ret = wl1271_ps_elp_wakeup(wl, false);
1560 if (ret < 0)
1561 goto out;
1562
1563 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1564 if (ret < 0)
1565 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1566
1567 wl1271_ps_elp_sleep(wl);
1568
1569out:
1570 mutex_unlock(&wl->mutex);
1571
1572 return ret;
1573}
1574
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001575static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1576{
1577 u8 *ptr = beacon->data +
1578 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1579
1580 /* find the location of the ssid in the beacon */
1581 while (ptr < beacon->data + beacon->len) {
1582 if (ptr[0] == WLAN_EID_SSID) {
1583 wl->ssid_len = ptr[1];
1584 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1585 return;
1586 }
1587 ptr += ptr[1];
1588 }
1589 wl1271_error("ad-hoc beacon template has no SSID!\n");
1590}
1591
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001592static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1593 struct ieee80211_vif *vif,
1594 struct ieee80211_bss_conf *bss_conf,
1595 u32 changed)
1596{
1597 enum wl1271_cmd_ps_mode mode;
1598 struct wl1271 *wl = hw->priv;
1599 int ret;
1600
1601 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1602
1603 mutex_lock(&wl->mutex);
1604
1605 ret = wl1271_ps_elp_wakeup(wl, false);
1606 if (ret < 0)
1607 goto out;
1608
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001609 if (wl->bss_type == BSS_TYPE_IBSS) {
1610 /* FIXME: This implements rudimentary ad-hoc support -
1611 proper templates are on the wish list and notification
1612 on when they change. This patch will update the templates
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001613 on every call to this function. */
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001614 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1615
1616 if (beacon) {
1617 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001618
1619 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001620 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1621 beacon->data,
1622 beacon->len);
1623
1624 if (ret < 0) {
1625 dev_kfree_skb(beacon);
1626 goto out_sleep;
1627 }
1628
1629 hdr = (struct ieee80211_hdr *) beacon->data;
1630 hdr->frame_control = cpu_to_le16(
1631 IEEE80211_FTYPE_MGMT |
1632 IEEE80211_STYPE_PROBE_RESP);
1633
1634 ret = wl1271_cmd_template_set(wl,
1635 CMD_TEMPL_PROBE_RESPONSE,
1636 beacon->data,
1637 beacon->len);
1638 dev_kfree_skb(beacon);
1639 if (ret < 0)
1640 goto out_sleep;
1641 }
1642 }
1643
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001644 if ((changed & BSS_CHANGED_BSSID) &&
1645 /*
1646 * Now we know the correct bssid, so we send a new join command
1647 * and enable the BSSID filter
1648 */
1649 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
1650 wl->rx_config |= CFG_BSSID_FILTER_EN;
1651 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
1652 ret = wl1271_cmd_build_null_data(wl);
1653 if (ret < 0) {
1654 wl1271_warning("cmd buld null data failed %d",
1655 ret);
1656 goto out_sleep;
1657 }
1658
1659 ret = wl1271_cmd_join(wl);
1660 if (ret < 0) {
1661 wl1271_warning("cmd join failed %d", ret);
1662 goto out_sleep;
1663 }
1664 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1665 }
1666
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001667 if (changed & BSS_CHANGED_ASSOC) {
1668 if (bss_conf->assoc) {
1669 wl->aid = bss_conf->aid;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001670 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001671
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001672 /*
1673 * with wl1271, we don't need to update the
1674 * beacon_int and dtim_period, because the firmware
1675 * updates it by itself when the first beacon is
1676 * received after a join.
1677 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001678 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1679 if (ret < 0)
1680 goto out_sleep;
1681
1682 ret = wl1271_acx_aid(wl, wl->aid);
1683 if (ret < 0)
1684 goto out_sleep;
1685
1686 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001687 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1688 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001689 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001690 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001691 if (ret < 0)
1692 goto out_sleep;
1693 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001694 } else {
1695 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001696 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001697 wl->aid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001698 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001699
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001700 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001701
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001702 if (changed & BSS_CHANGED_ERP_SLOT) {
1703 if (bss_conf->use_short_slot)
1704 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1705 else
1706 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1707 if (ret < 0) {
1708 wl1271_warning("Set slot time failed %d", ret);
1709 goto out_sleep;
1710 }
1711 }
1712
1713 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1714 if (bss_conf->use_short_preamble)
1715 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1716 else
1717 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1718 }
1719
1720 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1721 if (bss_conf->use_cts_prot)
1722 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1723 else
1724 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1725 if (ret < 0) {
1726 wl1271_warning("Set ctsprotect failed %d", ret);
1727 goto out_sleep;
1728 }
1729 }
1730
1731out_sleep:
1732 wl1271_ps_elp_sleep(wl);
1733
1734out:
1735 mutex_unlock(&wl->mutex);
1736}
1737
Kalle Valoc6999d82010-02-18 13:25:41 +02001738static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1739 const struct ieee80211_tx_queue_params *params)
1740{
1741 struct wl1271 *wl = hw->priv;
1742 int ret;
1743
1744 mutex_lock(&wl->mutex);
1745
1746 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1747
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001748 ret = wl1271_ps_elp_wakeup(wl, false);
1749 if (ret < 0)
1750 goto out;
1751
Kalle Valoc6999d82010-02-18 13:25:41 +02001752 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1753 params->cw_min, params->cw_max,
1754 params->aifs, params->txop);
1755 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001756 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001757
1758 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1759 CONF_CHANNEL_TYPE_EDCF,
1760 wl1271_tx_get_queue(queue),
1761 CONF_PS_SCHEME_LEGACY_PSPOLL,
1762 CONF_ACK_POLICY_LEGACY, 0, 0);
1763 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001764 goto out_sleep;
1765
1766out_sleep:
1767 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001768
1769out:
1770 mutex_unlock(&wl->mutex);
1771
1772 return ret;
1773}
1774
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001775
1776/* can't be const, mac80211 writes to this */
1777static struct ieee80211_rate wl1271_rates[] = {
1778 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001779 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1780 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001781 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001782 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1783 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001784 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1785 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001786 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1787 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001788 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1789 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001790 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1791 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001792 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1793 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001794 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1795 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001796 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001797 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1798 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001799 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001800 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1801 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001802 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001803 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1804 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001805 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001806 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1807 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001808 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001809 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1810 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001811 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001812 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1813 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001814 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001815 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1816 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001817};
1818
1819/* can't be const, mac80211 writes to this */
1820static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001821 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1822 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1823 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1824 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1825 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1826 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1827 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1828 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1829 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1830 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1831 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1832 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1833 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001834};
1835
1836/* can't be const, mac80211 writes to this */
1837static struct ieee80211_supported_band wl1271_band_2ghz = {
1838 .channels = wl1271_channels,
1839 .n_channels = ARRAY_SIZE(wl1271_channels),
1840 .bitrates = wl1271_rates,
1841 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1842};
1843
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001844/* 5 GHz data rates for WL1273 */
1845static struct ieee80211_rate wl1271_rates_5ghz[] = {
1846 { .bitrate = 60,
1847 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1848 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
1849 { .bitrate = 90,
1850 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1851 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
1852 { .bitrate = 120,
1853 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1854 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
1855 { .bitrate = 180,
1856 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1857 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
1858 { .bitrate = 240,
1859 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1860 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
1861 { .bitrate = 360,
1862 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1863 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
1864 { .bitrate = 480,
1865 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1866 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
1867 { .bitrate = 540,
1868 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1869 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
1870};
1871
1872/* 5 GHz band channels for WL1273 */
1873static struct ieee80211_channel wl1271_channels_5ghz[] = {
1874 { .hw_value = 183, .center_freq = 4915},
1875 { .hw_value = 184, .center_freq = 4920},
1876 { .hw_value = 185, .center_freq = 4925},
1877 { .hw_value = 187, .center_freq = 4935},
1878 { .hw_value = 188, .center_freq = 4940},
1879 { .hw_value = 189, .center_freq = 4945},
1880 { .hw_value = 192, .center_freq = 4960},
1881 { .hw_value = 196, .center_freq = 4980},
1882 { .hw_value = 7, .center_freq = 5035},
1883 { .hw_value = 8, .center_freq = 5040},
1884 { .hw_value = 9, .center_freq = 5045},
1885 { .hw_value = 11, .center_freq = 5055},
1886 { .hw_value = 12, .center_freq = 5060},
1887 { .hw_value = 16, .center_freq = 5080},
1888 { .hw_value = 34, .center_freq = 5170},
1889 { .hw_value = 36, .center_freq = 5180},
1890 { .hw_value = 38, .center_freq = 5190},
1891 { .hw_value = 40, .center_freq = 5200},
1892 { .hw_value = 42, .center_freq = 5210},
1893 { .hw_value = 44, .center_freq = 5220},
1894 { .hw_value = 46, .center_freq = 5230},
1895 { .hw_value = 48, .center_freq = 5240},
1896 { .hw_value = 52, .center_freq = 5260},
1897 { .hw_value = 56, .center_freq = 5280},
1898 { .hw_value = 60, .center_freq = 5300},
1899 { .hw_value = 64, .center_freq = 5320},
1900 { .hw_value = 100, .center_freq = 5500},
1901 { .hw_value = 104, .center_freq = 5520},
1902 { .hw_value = 108, .center_freq = 5540},
1903 { .hw_value = 112, .center_freq = 5560},
1904 { .hw_value = 116, .center_freq = 5580},
1905 { .hw_value = 120, .center_freq = 5600},
1906 { .hw_value = 124, .center_freq = 5620},
1907 { .hw_value = 128, .center_freq = 5640},
1908 { .hw_value = 132, .center_freq = 5660},
1909 { .hw_value = 136, .center_freq = 5680},
1910 { .hw_value = 140, .center_freq = 5700},
1911 { .hw_value = 149, .center_freq = 5745},
1912 { .hw_value = 153, .center_freq = 5765},
1913 { .hw_value = 157, .center_freq = 5785},
1914 { .hw_value = 161, .center_freq = 5805},
1915 { .hw_value = 165, .center_freq = 5825},
1916};
1917
1918
1919static struct ieee80211_supported_band wl1271_band_5ghz = {
1920 .channels = wl1271_channels_5ghz,
1921 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
1922 .bitrates = wl1271_rates_5ghz,
1923 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
1924};
1925
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001926static const struct ieee80211_ops wl1271_ops = {
1927 .start = wl1271_op_start,
1928 .stop = wl1271_op_stop,
1929 .add_interface = wl1271_op_add_interface,
1930 .remove_interface = wl1271_op_remove_interface,
1931 .config = wl1271_op_config,
1932/* .config_interface = wl1271_op_config_interface, */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001933 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001934 .configure_filter = wl1271_op_configure_filter,
1935 .tx = wl1271_op_tx,
1936 .set_key = wl1271_op_set_key,
1937 .hw_scan = wl1271_op_hw_scan,
1938 .bss_info_changed = wl1271_op_bss_info_changed,
1939 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02001940 .conf_tx = wl1271_op_conf_tx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001941};
1942
1943static int wl1271_register_hw(struct wl1271 *wl)
1944{
1945 int ret;
1946
1947 if (wl->mac80211_registered)
1948 return 0;
1949
1950 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
1951
1952 ret = ieee80211_register_hw(wl->hw);
1953 if (ret < 0) {
1954 wl1271_error("unable to register mac80211 hw: %d", ret);
1955 return ret;
1956 }
1957
1958 wl->mac80211_registered = true;
1959
1960 wl1271_notice("loaded");
1961
1962 return 0;
1963}
1964
1965static int wl1271_init_ieee80211(struct wl1271 *wl)
1966{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03001967 /* The tx descriptor buffer and the TKIP space. */
1968 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
1969 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001970
1971 /* unit us */
1972 /* FIXME: find a proper value */
1973 wl->hw->channel_change_time = 10000;
1974
1975 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03001976 IEEE80211_HW_NOISE_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02001977 IEEE80211_HW_BEACON_FILTER |
1978 IEEE80211_HW_SUPPORTS_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001979
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001980 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
1981 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001982 wl->hw->wiphy->max_scan_ssids = 1;
1983 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
1984
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001985 if (wl1271_11a_enabled())
1986 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
1987
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001988 SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
1989
1990 return 0;
1991}
1992
1993static void wl1271_device_release(struct device *dev)
1994{
1995
1996}
1997
1998static struct platform_device wl1271_device = {
1999 .name = "wl1271",
2000 .id = -1,
2001
2002 /* device model insists to have a release function */
2003 .dev = {
2004 .release = wl1271_device_release,
2005 },
2006};
2007
2008#define WL1271_DEFAULT_CHANNEL 0
2009static int __devinit wl1271_probe(struct spi_device *spi)
2010{
2011 struct wl12xx_platform_data *pdata;
2012 struct ieee80211_hw *hw;
2013 struct wl1271 *wl;
2014 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002015
2016 pdata = spi->dev.platform_data;
2017 if (!pdata) {
2018 wl1271_error("no platform data");
2019 return -ENODEV;
2020 }
2021
2022 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2023 if (!hw) {
2024 wl1271_error("could not alloc ieee80211_hw");
2025 return -ENOMEM;
2026 }
2027
2028 wl = hw->priv;
2029 memset(wl, 0, sizeof(*wl));
2030
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002031 INIT_LIST_HEAD(&wl->list);
2032
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002033 wl->hw = hw;
2034 dev_set_drvdata(&spi->dev, wl);
2035 wl->spi = spi;
2036
2037 skb_queue_head_init(&wl->tx_queue);
2038
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002039 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002040 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002041 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002042 wl->rx_counter = 0;
2043 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2044 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002045 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002046 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002047 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002048 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2049 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002050 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002051 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002052 wl->flags = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002053
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002054 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002055 wl->tx_frames[i] = NULL;
2056
2057 spin_lock_init(&wl->wl_lock);
2058
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002059 wl->state = WL1271_STATE_OFF;
2060 mutex_init(&wl->mutex);
2061
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002062 /* This is the only SPI value that we need to set here, the rest
2063 * comes from the board-peripherals file */
2064 spi->bits_per_word = 32;
2065
2066 ret = spi_setup(spi);
2067 if (ret < 0) {
2068 wl1271_error("spi_setup failed");
2069 goto out_free;
2070 }
2071
2072 wl->set_power = pdata->set_power;
2073 if (!wl->set_power) {
2074 wl1271_error("set power function missing in platform data");
2075 ret = -ENODEV;
2076 goto out_free;
2077 }
2078
2079 wl->irq = spi->irq;
2080 if (wl->irq < 0) {
2081 wl1271_error("irq missing in platform data");
2082 ret = -ENODEV;
2083 goto out_free;
2084 }
2085
2086 ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
2087 if (ret < 0) {
2088 wl1271_error("request_irq() failed: %d", ret);
2089 goto out_free;
2090 }
2091
2092 set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
2093
2094 disable_irq(wl->irq);
2095
2096 ret = platform_device_register(&wl1271_device);
2097 if (ret) {
2098 wl1271_error("couldn't register platform device");
2099 goto out_irq;
2100 }
2101 dev_set_drvdata(&wl1271_device.dev, wl);
2102
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002103 /* Apply default driver configuration. */
2104 wl1271_conf_init(wl);
2105
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002106 ret = wl1271_init_ieee80211(wl);
2107 if (ret)
2108 goto out_platform;
2109
2110 ret = wl1271_register_hw(wl);
2111 if (ret)
2112 goto out_platform;
2113
2114 wl1271_debugfs_init(wl);
2115
2116 wl1271_notice("initialized");
2117
2118 return 0;
2119
2120 out_platform:
2121 platform_device_unregister(&wl1271_device);
2122
2123 out_irq:
2124 free_irq(wl->irq, wl);
2125
2126 out_free:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002127 ieee80211_free_hw(hw);
2128
2129 return ret;
2130}
2131
2132static int __devexit wl1271_remove(struct spi_device *spi)
2133{
2134 struct wl1271 *wl = dev_get_drvdata(&spi->dev);
2135
2136 ieee80211_unregister_hw(wl->hw);
2137
2138 wl1271_debugfs_exit(wl);
2139 platform_device_unregister(&wl1271_device);
2140 free_irq(wl->irq, wl);
2141 kfree(wl->target_mem_map);
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03002142 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002143 wl->fw = NULL;
2144 kfree(wl->nvs);
2145 wl->nvs = NULL;
2146
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002147 kfree(wl->fw_status);
2148 kfree(wl->tx_res_if);
2149
2150 ieee80211_free_hw(wl->hw);
2151
2152 return 0;
2153}
2154
2155
2156static struct spi_driver wl1271_spi_driver = {
2157 .driver = {
2158 .name = "wl1271",
2159 .bus = &spi_bus_type,
2160 .owner = THIS_MODULE,
2161 },
2162
2163 .probe = wl1271_probe,
2164 .remove = __devexit_p(wl1271_remove),
2165};
2166
2167static int __init wl1271_init(void)
2168{
2169 int ret;
2170
2171 ret = spi_register_driver(&wl1271_spi_driver);
2172 if (ret < 0) {
2173 wl1271_error("failed to register spi driver: %d", ret);
2174 goto out;
2175 }
2176
2177out:
2178 return ret;
2179}
2180
2181static void __exit wl1271_exit(void)
2182{
2183 spi_unregister_driver(&wl1271_spi_driver);
2184
2185 wl1271_notice("unloaded");
2186}
2187
2188module_init(wl1271_init);
2189module_exit(wl1271_exit);
2190
2191MODULE_LICENSE("GPL");
2192MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
Luciano Coelho2f018722009-10-08 21:56:27 +03002193MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
Ben Hutchings49f146d2009-11-07 22:02:15 +00002194MODULE_FIRMWARE(WL1271_FW_NAME);