blob: d4e603993996b33480a13312aad47bef01a6d282 [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 Oikarinen8a080482009-10-13 12:47:44 +030050static struct conf_drv_settings default_conf = {
51 .sg = {
52 .per_threshold = 7500,
53 .max_scan_compensation_time = 120000,
54 .nfs_sample_interval = 400,
55 .load_ratio = 50,
56 .auto_ps_mode = 0,
57 .probe_req_compensation = 170,
58 .scan_window_compensation = 50,
59 .antenna_config = 0,
60 .beacon_miss_threshold = 60,
61 .rate_adaptation_threshold = CONF_HW_BIT_RATE_12MBPS,
62 .rate_adaptation_snr = 0
63 },
64 .rx = {
65 .rx_msdu_life_time = 512000,
66 .packet_detection_threshold = 0,
67 .ps_poll_timeout = 15,
68 .upsd_timeout = 15,
69 .rts_threshold = 2347,
70 .rx_cca_threshold = 0xFFEF,
71 .irq_blk_threshold = 0,
72 .irq_pkt_threshold = USHORT_MAX,
73 .irq_timeout = 5,
74 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
75 },
76 .tx = {
77 .tx_energy_detection = 0,
78 .rc_conf = {
79 .enabled_rates = CONF_TX_RATE_MASK_UNSPECIFIED,
80 .short_retry_limit = 10,
81 .long_retry_limit = 10,
82 .aflags = 0
83 },
84 .ac_conf_count = 4,
85 .ac_conf = {
86 [0] = {
87 .ac = CONF_TX_AC_BE,
88 .cw_min = 15,
89 .cw_max = 63,
90 .aifsn = 3,
91 .tx_op_limit = 0,
92 },
93 [1] = {
94 .ac = CONF_TX_AC_BK,
95 .cw_min = 15,
96 .cw_max = 63,
97 .aifsn = 7,
98 .tx_op_limit = 0,
99 },
100 [2] = {
101 .ac = CONF_TX_AC_VI,
102 .cw_min = 15,
103 .cw_max = 63,
104 .aifsn = CONF_TX_AIFS_PIFS,
105 .tx_op_limit = 3008,
106 },
107 [3] = {
108 .ac = CONF_TX_AC_VO,
109 .cw_min = 15,
110 .cw_max = 63,
111 .aifsn = CONF_TX_AIFS_PIFS,
112 .tx_op_limit = 1504,
113 },
114 },
115 .tid_conf_count = 7,
116 .tid_conf = {
117 [0] = {
118 .queue_id = 0,
119 .channel_type = CONF_CHANNEL_TYPE_DCF,
120 .tsid = CONF_TX_AC_BE,
121 .ps_scheme = CONF_PS_SCHEME_LEGACY,
122 .ack_policy = CONF_ACK_POLICY_LEGACY,
123 .apsd_conf = {0, 0},
124 },
125 [1] = {
126 .queue_id = 1,
127 .channel_type = CONF_CHANNEL_TYPE_DCF,
128 .tsid = CONF_TX_AC_BE,
129 .ps_scheme = CONF_PS_SCHEME_LEGACY,
130 .ack_policy = CONF_ACK_POLICY_LEGACY,
131 .apsd_conf = {0, 0},
132 },
133 [2] = {
134 .queue_id = 2,
135 .channel_type = CONF_CHANNEL_TYPE_DCF,
136 .tsid = CONF_TX_AC_BE,
137 .ps_scheme = CONF_PS_SCHEME_LEGACY,
138 .ack_policy = CONF_ACK_POLICY_LEGACY,
139 .apsd_conf = {0, 0},
140 },
141 [3] = {
142 .queue_id = 3,
143 .channel_type = CONF_CHANNEL_TYPE_DCF,
144 .tsid = CONF_TX_AC_BE,
145 .ps_scheme = CONF_PS_SCHEME_LEGACY,
146 .ack_policy = CONF_ACK_POLICY_LEGACY,
147 .apsd_conf = {0, 0},
148 },
149 [4] = {
150 .queue_id = 4,
151 .channel_type = CONF_CHANNEL_TYPE_DCF,
152 .tsid = CONF_TX_AC_BE,
153 .ps_scheme = CONF_PS_SCHEME_LEGACY,
154 .ack_policy = CONF_ACK_POLICY_LEGACY,
155 .apsd_conf = {0, 0},
156 },
157 [5] = {
158 .queue_id = 5,
159 .channel_type = CONF_CHANNEL_TYPE_DCF,
160 .tsid = CONF_TX_AC_BE,
161 .ps_scheme = CONF_PS_SCHEME_LEGACY,
162 .ack_policy = CONF_ACK_POLICY_LEGACY,
163 .apsd_conf = {0, 0},
164 },
165 [6] = {
166 .queue_id = 6,
167 .channel_type = CONF_CHANNEL_TYPE_DCF,
168 .tsid = CONF_TX_AC_BE,
169 .ps_scheme = CONF_PS_SCHEME_LEGACY,
170 .ack_policy = CONF_ACK_POLICY_LEGACY,
171 .apsd_conf = {0, 0},
172 }
173 },
174 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
175 .tx_compl_timeout = 5,
176 .tx_compl_threshold = 5
177 },
178 .conn = {
179 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
180 .listen_interval = 0,
181 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
182 .bcn_filt_ie_count = 1,
183 .bcn_filt_ie = {
184 [0] = {
185 .ie = WLAN_EID_CHANNEL_SWITCH,
186 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
187 }
188 },
189 .synch_fail_thold = 5,
190 .bss_lose_timeout = 100,
191 .beacon_rx_timeout = 10000,
192 .broadcast_timeout = 20000,
193 .rx_broadcast_in_ps = 1,
194 .ps_poll_threshold = 4,
195 .sig_trigger_count = 2,
196 .sig_trigger = {
197 [0] = {
198 .threshold = -75,
199 .pacing = 500,
200 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
201 .type = CONF_TRIG_EVENT_TYPE_EDGE,
202 .direction = CONF_TRIG_EVENT_DIR_LOW,
203 .hysteresis = 2,
204 .index = 0,
205 .enable = 1
206 },
207 [1] = {
208 .threshold = -75,
209 .pacing = 500,
210 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
211 .type = CONF_TRIG_EVENT_TYPE_EDGE,
212 .direction = CONF_TRIG_EVENT_DIR_HIGH,
213 .hysteresis = 2,
214 .index = 1,
215 .enable = 1
216 }
217 },
218 .sig_weights = {
219 .rssi_bcn_avg_weight = 10,
220 .rssi_pkt_avg_weight = 10,
221 .snr_bcn_avg_weight = 10,
222 .snr_pkt_avg_weight = 10
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300223 },
224 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200225 .bet_max_consecutive = 10,
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200226 .psm_entry_retries = 3
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300227 },
228 .init = {
229 .sr_err_tbl = {
230 [0] = {
231 .len = 7,
232 .upper_limit = 0x03,
233 .values = {
234 0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8,
235 0x00 }
236 },
237 [1] = {
238 .len = 7,
239 .upper_limit = 0x03,
240 .values = {
241 0x18, 0x10, 0x05, 0xf6, 0xf0, 0xe8,
242 0x00 }
243 },
244 [2] = {
245 .len = 7,
246 .upper_limit = 0x03,
247 .values = {
248 0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8,
249 0x00 }
250 }
251 },
252 .sr_enable = 1,
253 .genparam = {
254 /*
255 * FIXME: The correct value CONF_REF_CLK_38_4_E
256 * causes the firmware to crash on boot.
257 * The value 5 apparently is an
258 * unnoficial XTAL configuration of the
259 * same frequency, which appears to work.
260 */
261 .ref_clk = 5,
262 .settling_time = 5,
263 .clk_valid_on_wakeup = 0,
264 .dc2dcmode = 0,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300265 .single_dual_band = CONF_SINGLE_BAND,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300266 .tx_bip_fem_autodetect = 0,
267 .tx_bip_fem_manufacturer = 1,
268 .settings = 1,
269 },
270 .radioparam = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300271 .rx_trace_loss = 10,
272 .tx_trace_loss = 10,
273 .rx_rssi_and_proc_compens = {
274 0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8,
275 0xfc, 0x00, 0x08, 0x10, 0xf0, 0xf8,
276 0x00, 0x0a, 0x14 },
277 .rx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 },
278 .tx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 },
279 .rx_rssi_and_proc_compens_5 = {
280 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
281 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
282 0x00, 0x00, 0x00 },
283 .tx_ref_pd_voltage = 0x24e,
284 .tx_ref_power = 0x78,
285 .tx_offset_db = 0x0,
286 .tx_rate_limits_normal = {
287 0x1e, 0x1f, 0x22, 0x24, 0x28, 0x29 },
288 .tx_rate_limits_degraded = {
289 0x1b, 0x1c, 0x1e, 0x20, 0x24, 0x25 },
290 .tx_channel_limits_11b = {
291 0x22, 0x50, 0x50, 0x50, 0x50, 0x50,
292 0x50, 0x50, 0x50, 0x50, 0x22, 0x50,
293 0x22, 0x50 },
294 .tx_channel_limits_ofdm = {
295 0x20, 0x50, 0x50, 0x50, 0x50, 0x50,
296 0x50, 0x50, 0x50, 0x50, 0x20, 0x50,
297 0x20, 0x50 },
298 .tx_pdv_rate_offsets = {
299 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
300 .tx_ibias = {
301 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x27 },
302 .rx_fem_insertion_loss = 0x14,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300303 .tx_ref_pd_voltage_5 = {
304 0x0190, 0x01a4, 0x01c3, 0x01d8,
305 0x020a, 0x021c },
306 .tx_ref_power_5 = {
307 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 },
308 .tx_offset_db_5 = {
309 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300310 .tx_rate_limits_normal_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300311 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300312 .tx_rate_limits_degraded_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300313 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300314 .tx_channel_limits_ofdm_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300315 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
316 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
317 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
318 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
319 0x50, 0x50, 0x50 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300320 .tx_pdv_rate_offsets_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300321 0x01, 0x02, 0x02, 0x02, 0x02, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300322 .tx_ibias_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300323 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
324 .rx_fem_insertion_loss_5 = {
325 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300326 }
327 }
328};
329
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300330static LIST_HEAD(wl_list);
331
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300332static void wl1271_conf_init(struct wl1271 *wl)
333{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300334
335 /*
336 * This function applies the default configuration to the driver. This
337 * function is invoked upon driver load (spi probe.)
338 *
339 * The configuration is stored in a run-time structure in order to
340 * facilitate for run-time adjustment of any of the parameters. Making
341 * changes to the configuration structure will apply the new values on
342 * the next interface up (wl1271_op_start.)
343 */
344
345 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300346 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300347
348 if (wl1271_11a_enabled())
349 wl->conf.init.genparam.single_dual_band = CONF_DUAL_BAND;
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300350}
351
352
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300353static int wl1271_plt_init(struct wl1271 *wl)
354{
355 int ret;
356
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200357 /* FIXME: the following parameter setting functions return error
358 * codes - the reason is so far unknown. The -EIO is therefore
359 * ignored for the time being. */
360 ret = wl1271_init_general_parms(wl);
361 if (ret < 0 && ret != -EIO)
362 return ret;
363
364 ret = wl1271_init_radio_parms(wl);
365 if (ret < 0 && ret != -EIO)
366 return ret;
367
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300368 ret = wl1271_acx_init_mem_config(wl);
369 if (ret < 0)
370 return ret;
371
372 ret = wl1271_cmd_data_path(wl, wl->channel, 1);
373 if (ret < 0)
374 return ret;
375
376 return 0;
377}
378
379static void wl1271_disable_interrupts(struct wl1271 *wl)
380{
381 disable_irq(wl->irq);
382}
383
384static void wl1271_power_off(struct wl1271 *wl)
385{
386 wl->set_power(false);
387}
388
389static void wl1271_power_on(struct wl1271 *wl)
390{
391 wl->set_power(true);
392}
393
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300394static void wl1271_fw_status(struct wl1271 *wl,
395 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300396{
397 u32 total = 0;
398 int i;
399
Juuso Oikarinen74621412009-10-12 15:08:54 +0300400 wl1271_spi_read(wl, FW_STATUS_ADDR, status,
401 sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300402
403 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
404 "drv_rx_counter = %d, tx_results_counter = %d)",
405 status->intr,
406 status->fw_rx_counter,
407 status->drv_rx_counter,
408 status->tx_results_counter);
409
410 /* update number of available TX blocks */
411 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300412 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
413 wl->tx_blocks_freed[i];
414
415 wl->tx_blocks_freed[i] =
416 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300417 wl->tx_blocks_available += cnt;
418 total += cnt;
419 }
420
421 /* if more blocks are available now, schedule some tx work */
422 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300423 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300424
425 /* update the host-chipset time offset */
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300426 wl->time_offset = jiffies_to_usecs(jiffies) -
427 le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300428}
429
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300430static void wl1271_irq_work(struct work_struct *work)
431{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300432 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300433 u32 intr;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300434 struct wl1271 *wl =
435 container_of(work, struct wl1271, irq_work);
436
437 mutex_lock(&wl->mutex);
438
439 wl1271_debug(DEBUG_IRQ, "IRQ work");
440
441 if (wl->state == WL1271_STATE_OFF)
442 goto out;
443
444 ret = wl1271_ps_elp_wakeup(wl, true);
445 if (ret < 0)
446 goto out;
447
Juuso Oikarinen74621412009-10-12 15:08:54 +0300448 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300449
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300450 wl1271_fw_status(wl, wl->fw_status);
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300451 intr = le32_to_cpu(wl->fw_status->intr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300452 if (!intr) {
453 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
454 goto out_sleep;
455 }
456
457 intr &= WL1271_INTR_MASK;
458
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300459 if (intr & WL1271_ACX_INTR_EVENT_A) {
460 bool do_ack = (intr & WL1271_ACX_INTR_EVENT_B) ? false : true;
461 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
462 wl1271_event_handle(wl, 0, do_ack);
463 }
464
465 if (intr & WL1271_ACX_INTR_EVENT_B) {
466 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
467 wl1271_event_handle(wl, 1, true);
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300468 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300469
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300470 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
471 wl1271_debug(DEBUG_IRQ,
472 "WL1271_ACX_INTR_INIT_COMPLETE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300473
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300474 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
475 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300476
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300477 if (intr & WL1271_ACX_INTR_DATA) {
478 u8 tx_res_cnt = wl->fw_status->tx_results_counter -
479 wl->tx_results_count;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300480
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300481 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300482
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300483 /* check for tx results */
484 if (tx_res_cnt)
485 wl1271_tx_complete(wl, tx_res_cnt);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300486
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300487 wl1271_rx(wl, wl->fw_status);
488 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300489
490out_sleep:
Juuso Oikarinen74621412009-10-12 15:08:54 +0300491 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
Luciano Coelho73d0a132009-08-11 11:58:27 +0300492 WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300493 wl1271_ps_elp_sleep(wl);
494
495out:
496 mutex_unlock(&wl->mutex);
497}
498
499static irqreturn_t wl1271_irq(int irq, void *cookie)
500{
501 struct wl1271 *wl;
502 unsigned long flags;
503
504 wl1271_debug(DEBUG_IRQ, "IRQ");
505
506 wl = cookie;
507
508 /* complete the ELP completion */
509 spin_lock_irqsave(&wl->wl_lock, flags);
510 if (wl->elp_compl) {
511 complete(wl->elp_compl);
512 wl->elp_compl = NULL;
513 }
514
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300515 ieee80211_queue_work(wl->hw, &wl->irq_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300516 spin_unlock_irqrestore(&wl->wl_lock, flags);
517
518 return IRQ_HANDLED;
519}
520
521static int wl1271_fetch_firmware(struct wl1271 *wl)
522{
523 const struct firmware *fw;
524 int ret;
525
526 ret = request_firmware(&fw, WL1271_FW_NAME, &wl->spi->dev);
527
528 if (ret < 0) {
529 wl1271_error("could not get firmware: %d", ret);
530 return ret;
531 }
532
533 if (fw->size % 4) {
534 wl1271_error("firmware size is not multiple of 32 bits: %zu",
535 fw->size);
536 ret = -EILSEQ;
537 goto out;
538 }
539
540 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300541 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300542
543 if (!wl->fw) {
544 wl1271_error("could not allocate memory for the firmware");
545 ret = -ENOMEM;
546 goto out;
547 }
548
549 memcpy(wl->fw, fw->data, wl->fw_len);
550
551 ret = 0;
552
553out:
554 release_firmware(fw);
555
556 return ret;
557}
558
559static int wl1271_fetch_nvs(struct wl1271 *wl)
560{
561 const struct firmware *fw;
562 int ret;
563
564 ret = request_firmware(&fw, WL1271_NVS_NAME, &wl->spi->dev);
565
566 if (ret < 0) {
567 wl1271_error("could not get nvs file: %d", ret);
568 return ret;
569 }
570
571 if (fw->size % 4) {
572 wl1271_error("nvs size is not multiple of 32 bits: %zu",
573 fw->size);
574 ret = -EILSEQ;
575 goto out;
576 }
577
578 wl->nvs_len = fw->size;
579 wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL);
580
581 if (!wl->nvs) {
582 wl1271_error("could not allocate memory for the nvs file");
583 ret = -ENOMEM;
584 goto out;
585 }
586
587 memcpy(wl->nvs, fw->data, wl->nvs_len);
588
589 ret = 0;
590
591out:
592 release_firmware(fw);
593
594 return ret;
595}
596
597static void wl1271_fw_wakeup(struct wl1271 *wl)
598{
599 u32 elp_reg;
600
601 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300602 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300603}
604
605static int wl1271_setup(struct wl1271 *wl)
606{
607 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
608 if (!wl->fw_status)
609 return -ENOMEM;
610
611 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
612 if (!wl->tx_res_if) {
613 kfree(wl->fw_status);
614 return -ENOMEM;
615 }
616
617 INIT_WORK(&wl->irq_work, wl1271_irq_work);
618 INIT_WORK(&wl->tx_work, wl1271_tx_work);
619 return 0;
620}
621
622static int wl1271_chip_wakeup(struct wl1271 *wl)
623{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300624 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300625 int ret = 0;
626
627 wl1271_power_on(wl);
628 msleep(WL1271_POWER_ON_SLEEP);
629 wl1271_spi_reset(wl);
630 wl1271_spi_init(wl);
631
632 /* We don't need a real memory partition here, because we only want
633 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300634 memset(&partition, 0, sizeof(partition));
635 partition.reg.start = REGISTERS_BASE;
636 partition.reg.size = REGISTERS_DOWN_SIZE;
637 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300638
639 /* ELP module wake up */
640 wl1271_fw_wakeup(wl);
641
642 /* whal_FwCtrl_BootSm() */
643
644 /* 0. read chip id from CHIP_ID */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300645 wl->chip.id = wl1271_spi_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300646
647 /* 1. check if chip id is valid */
648
649 switch (wl->chip.id) {
650 case CHIP_ID_1271_PG10:
651 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
652 wl->chip.id);
653
654 ret = wl1271_setup(wl);
655 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300656 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300657 break;
658 case CHIP_ID_1271_PG20:
659 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
660 wl->chip.id);
661
662 ret = wl1271_setup(wl);
663 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300664 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300665 break;
666 default:
667 wl1271_error("unsupported chip id: 0x%x", wl->chip.id);
668 ret = -ENODEV;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300669 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300670 }
671
672 if (wl->fw == NULL) {
673 ret = wl1271_fetch_firmware(wl);
674 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300675 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300676 }
677
678 /* No NVS from netlink, try to get it from the filesystem */
679 if (wl->nvs == NULL) {
680 ret = wl1271_fetch_nvs(wl);
681 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300682 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300683 }
684
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300685 goto out;
686
687out_power_off:
688 wl1271_power_off(wl);
689
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300690out:
691 return ret;
692}
693
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300694int wl1271_plt_start(struct wl1271 *wl)
695{
696 int ret;
697
698 mutex_lock(&wl->mutex);
699
700 wl1271_notice("power up");
701
702 if (wl->state != WL1271_STATE_OFF) {
703 wl1271_error("cannot go into PLT state because not "
704 "in off state: %d", wl->state);
705 ret = -EBUSY;
706 goto out;
707 }
708
709 wl->state = WL1271_STATE_PLT;
710
711 ret = wl1271_chip_wakeup(wl);
712 if (ret < 0)
713 goto out;
714
715 ret = wl1271_boot(wl);
716 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300717 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300718
719 wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver);
720
721 ret = wl1271_plt_init(wl);
722 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300723 goto out_irq_disable;
724
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300725 /* Make sure power saving is disabled */
726 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
727 if (ret < 0)
728 goto out_irq_disable;
729
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300730 goto out;
731
732out_irq_disable:
733 wl1271_disable_interrupts(wl);
734
735out_power_off:
736 wl1271_power_off(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300737
738out:
739 mutex_unlock(&wl->mutex);
740
741 return ret;
742}
743
744int wl1271_plt_stop(struct wl1271 *wl)
745{
746 int ret = 0;
747
748 mutex_lock(&wl->mutex);
749
750 wl1271_notice("power down");
751
752 if (wl->state != WL1271_STATE_PLT) {
753 wl1271_error("cannot power down because not in PLT "
754 "state: %d", wl->state);
755 ret = -EBUSY;
756 goto out;
757 }
758
759 wl1271_disable_interrupts(wl);
760 wl1271_power_off(wl);
761
762 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300763 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300764
765out:
766 mutex_unlock(&wl->mutex);
767
768 return ret;
769}
770
771
772static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
773{
774 struct wl1271 *wl = hw->priv;
775
776 skb_queue_tail(&wl->tx_queue, skb);
777
778 /*
779 * The chip specific setup must run before the first TX packet -
780 * before that, the tx_work will not be initialized!
781 */
782
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300783 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300784
785 /*
786 * The workqueue is slow to process the tx_queue and we need stop
787 * the queue here, otherwise the queue will get too long.
788 */
789 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) {
790 ieee80211_stop_queues(wl->hw);
791
792 /*
793 * FIXME: this is racy, the variable is not properly
794 * protected. Maybe fix this by removing the stupid
795 * variable altogether and checking the real queue state?
796 */
797 wl->tx_queue_stopped = true;
798 }
799
800 return NETDEV_TX_OK;
801}
802
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300803static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
804 void *arg)
805{
806 struct net_device *dev;
807 struct wireless_dev *wdev;
808 struct wiphy *wiphy;
809 struct ieee80211_hw *hw;
810 struct wl1271 *wl;
811 struct wl1271 *wl_temp;
812 struct in_device *idev;
813 struct in_ifaddr *ifa = arg;
814 int ret = 0;
815
816 /* FIXME: this ugly function should probably be implemented in the
817 * mac80211, and here should only be a simple callback handling actual
818 * setting of the filters. Now we need to dig up references to
819 * various structures to gain access to what we need.
820 * Also, because of this, there is no "initial" setting of the filter
821 * in "op_start", because we don't want to dig up struct net_device
822 * there - the filter will be set upon first change of the interface
823 * IP address. */
824
825 dev = ifa->ifa_dev->dev;
826
827 wdev = dev->ieee80211_ptr;
828 if (wdev == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200829 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300830
831 wiphy = wdev->wiphy;
832 if (wiphy == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200833 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300834
835 hw = wiphy_priv(wiphy);
836 if (hw == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200837 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300838
839 /* Check that the interface is one supported by this driver. */
840 wl_temp = hw->priv;
841 list_for_each_entry(wl, &wl_list, list) {
842 if (wl == wl_temp)
843 break;
844 }
845 if (wl == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200846 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300847
848 /* Get the interface IP address for the device. "ifa" will become
849 NULL if:
850 - there is no IPV4 protocol address configured
851 - there are multiple (virtual) IPV4 addresses configured
852 When "ifa" is NULL, filtering will be disabled.
853 */
854 ifa = NULL;
855 idev = dev->ip_ptr;
856 if (idev)
857 ifa = idev->ifa_list;
858
859 if (ifa && ifa->ifa_next)
860 ifa = NULL;
861
862 mutex_lock(&wl->mutex);
863
864 if (wl->state == WL1271_STATE_OFF)
865 goto out;
866
867 ret = wl1271_ps_elp_wakeup(wl, false);
868 if (ret < 0)
869 goto out;
870 if (ifa)
871 ret = wl1271_acx_arp_ip_filter(wl, true,
872 (u8 *)&ifa->ifa_address,
873 ACX_IPV4_VERSION);
874 else
875 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
876 ACX_IPV4_VERSION);
877 wl1271_ps_elp_sleep(wl);
878
879out:
880 mutex_unlock(&wl->mutex);
881
Luciano Coelho17d72652009-11-23 23:22:15 +0200882 return NOTIFY_OK;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300883}
884
885static struct notifier_block wl1271_dev_notifier = {
886 .notifier_call = wl1271_dev_notify,
887};
888
889
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300890static int wl1271_op_start(struct ieee80211_hw *hw)
891{
892 struct wl1271 *wl = hw->priv;
893 int ret = 0;
894
895 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
896
897 mutex_lock(&wl->mutex);
898
899 if (wl->state != WL1271_STATE_OFF) {
900 wl1271_error("cannot start because not in off state: %d",
901 wl->state);
902 ret = -EBUSY;
903 goto out;
904 }
905
906 ret = wl1271_chip_wakeup(wl);
907 if (ret < 0)
908 goto out;
909
910 ret = wl1271_boot(wl);
911 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300912 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300913
914 ret = wl1271_hw_init(wl);
915 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300916 goto out_irq_disable;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300917
918 wl->state = WL1271_STATE_ON;
919
920 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
921
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300922 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300923
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300924out_irq_disable:
925 wl1271_disable_interrupts(wl);
926
927out_power_off:
928 wl1271_power_off(wl);
929
930out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300931 mutex_unlock(&wl->mutex);
932
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300933 if (!ret) {
934 list_add(&wl->list, &wl_list);
935 register_inetaddr_notifier(&wl1271_dev_notifier);
936 }
937
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300938 return ret;
939}
940
941static void wl1271_op_stop(struct ieee80211_hw *hw)
942{
943 struct wl1271 *wl = hw->priv;
944 int i;
945
946 wl1271_info("down");
947
948 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
949
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300950 unregister_inetaddr_notifier(&wl1271_dev_notifier);
951 list_del(&wl->list);
952
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300953 mutex_lock(&wl->mutex);
954
955 WARN_ON(wl->state != WL1271_STATE_ON);
956
957 if (wl->scanning) {
958 mutex_unlock(&wl->mutex);
959 ieee80211_scan_completed(wl->hw, true);
960 mutex_lock(&wl->mutex);
961 wl->scanning = false;
962 }
963
964 wl->state = WL1271_STATE_OFF;
965
966 wl1271_disable_interrupts(wl);
967
968 mutex_unlock(&wl->mutex);
969
970 cancel_work_sync(&wl->irq_work);
971 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300972
973 mutex_lock(&wl->mutex);
974
975 /* let's notify MAC80211 about the remaining pending TX frames */
976 wl1271_tx_flush(wl);
977 wl1271_power_off(wl);
978
979 memset(wl->bssid, 0, ETH_ALEN);
980 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
981 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300982 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +0300983 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300984
985 wl->rx_counter = 0;
986 wl->elp = false;
987 wl->psm = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200988 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300989 wl->tx_queue_stopped = false;
990 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
991 wl->tx_blocks_available = 0;
992 wl->tx_results_count = 0;
993 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +0300994 wl->tx_security_last_seq = 0;
995 wl->tx_security_seq_16 = 0;
996 wl->tx_security_seq_32 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300997 wl->time_offset = 0;
998 wl->session_counter = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +0300999 wl->joined = false;
1000
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001001 for (i = 0; i < NUM_TX_QUEUES; i++)
1002 wl->tx_blocks_freed[i] = 0;
1003
1004 wl1271_debugfs_reset(wl);
1005 mutex_unlock(&wl->mutex);
1006}
1007
1008static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1009 struct ieee80211_if_init_conf *conf)
1010{
1011 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001012 int ret = 0;
1013
John W. Linvillee5539bc2009-08-18 10:50:34 -04001014 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1015 conf->type, conf->mac_addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001016
1017 mutex_lock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001018 if (wl->vif) {
1019 ret = -EBUSY;
1020 goto out;
1021 }
1022
1023 wl->vif = conf->vif;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001024
1025 switch (conf->type) {
1026 case NL80211_IFTYPE_STATION:
1027 wl->bss_type = BSS_TYPE_STA_BSS;
1028 break;
1029 case NL80211_IFTYPE_ADHOC:
1030 wl->bss_type = BSS_TYPE_IBSS;
1031 break;
1032 default:
1033 ret = -EOPNOTSUPP;
1034 goto out;
1035 }
1036
1037 /* FIXME: what if conf->mac_addr changes? */
1038
1039out:
1040 mutex_unlock(&wl->mutex);
1041 return ret;
1042}
1043
1044static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1045 struct ieee80211_if_init_conf *conf)
1046{
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001047 struct wl1271 *wl = hw->priv;
1048
1049 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001050 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001051 wl->vif = NULL;
1052 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001053}
1054
1055#if 0
1056static int wl1271_op_config_interface(struct ieee80211_hw *hw,
1057 struct ieee80211_vif *vif,
1058 struct ieee80211_if_conf *conf)
1059{
1060 struct wl1271 *wl = hw->priv;
1061 struct sk_buff *beacon;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001062 int ret;
1063
David S. Miller32646902009-09-17 10:18:30 -07001064 wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM",
1065 conf->bssid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001066 wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid,
1067 conf->ssid_len);
1068
1069 mutex_lock(&wl->mutex);
1070
1071 ret = wl1271_ps_elp_wakeup(wl, false);
1072 if (ret < 0)
1073 goto out;
1074
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001075 if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
1076 wl1271_debug(DEBUG_MAC80211, "bssid changed");
1077
1078 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
1079
1080 ret = wl1271_cmd_join(wl);
1081 if (ret < 0)
1082 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001083
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001084 ret = wl1271_cmd_build_null_data(wl);
1085 if (ret < 0)
1086 goto out_sleep;
1087 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001088
1089 wl->ssid_len = conf->ssid_len;
1090 if (wl->ssid_len)
1091 memcpy(wl->ssid, conf->ssid, wl->ssid_len);
1092
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001093 if (conf->changed & IEEE80211_IFCC_BEACON) {
1094 beacon = ieee80211_beacon_get(hw, vif);
1095 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1096 beacon->data, beacon->len);
1097
1098 if (ret < 0) {
1099 dev_kfree_skb(beacon);
1100 goto out_sleep;
1101 }
1102
1103 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE,
1104 beacon->data, beacon->len);
1105
1106 dev_kfree_skb(beacon);
1107
1108 if (ret < 0)
1109 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001110 }
1111
1112out_sleep:
1113 wl1271_ps_elp_sleep(wl);
1114
1115out:
1116 mutex_unlock(&wl->mutex);
1117
1118 return ret;
1119}
1120#endif
1121
1122static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1123{
1124 struct wl1271 *wl = hw->priv;
1125 struct ieee80211_conf *conf = &hw->conf;
1126 int channel, ret = 0;
1127
1128 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1129
1130 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
1131 channel,
1132 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
1133 conf->power_level);
1134
1135 mutex_lock(&wl->mutex);
1136
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001137 wl->band = conf->channel->band;
1138
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001139 ret = wl1271_ps_elp_wakeup(wl, false);
1140 if (ret < 0)
1141 goto out;
1142
1143 if (channel != wl->channel) {
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001144 /*
1145 * We assume that the stack will configure the right channel
1146 * before associating, so we don't need to send a join
1147 * command here. We will join the right channel when the
1148 * BSSID changes
1149 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001150 wl->channel = channel;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001151 }
1152
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001153 if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) {
1154 wl1271_info("psm enabled");
1155
1156 wl->psm_requested = true;
1157
1158 /*
1159 * We enter PSM only if we're already associated.
1160 * If we're not, we'll enter it when joining an SSID,
1161 * through the bss_info_changed() hook.
1162 */
1163 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
1164 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
1165 wl->psm_requested) {
1166 wl1271_info("psm disabled");
1167
1168 wl->psm_requested = false;
1169
1170 if (wl->psm)
1171 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE);
1172 }
1173
1174 if (conf->power_level != wl->power_level) {
1175 ret = wl1271_acx_tx_power(wl, conf->power_level);
1176 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001177 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001178
1179 wl->power_level = conf->power_level;
1180 }
1181
1182out_sleep:
1183 wl1271_ps_elp_sleep(wl);
1184
1185out:
1186 mutex_unlock(&wl->mutex);
1187
1188 return ret;
1189}
1190
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001191struct wl1271_filter_params {
1192 bool enabled;
1193 int mc_list_length;
1194 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1195};
1196
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001197static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1198 struct dev_addr_list *mc_list)
1199{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001200 struct wl1271_filter_params *fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001201 int i;
1202
Juuso Oikarinen74441132009-10-13 12:47:53 +03001203 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001204 if (!fp) {
1205 wl1271_error("Out of memory setting filters.");
1206 return 0;
1207 }
1208
1209 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001210 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001211 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1212 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001213 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001214 }
1215
1216 fp->mc_list_length = 0;
1217 for (i = 0; i < mc_count; i++) {
1218 if (mc_list->da_addrlen == ETH_ALEN) {
1219 memcpy(fp->mc_list[fp->mc_list_length],
1220 mc_list->da_addr, ETH_ALEN);
1221 fp->mc_list_length++;
1222 } else
1223 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001224 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001225 }
1226
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001227 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001228}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001229
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001230#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1231 FIF_ALLMULTI | \
1232 FIF_FCSFAIL | \
1233 FIF_BCN_PRBRESP_PROMISC | \
1234 FIF_CONTROL | \
1235 FIF_OTHER_BSS)
1236
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001237static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1238 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001239 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001240{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001241 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001242 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001243 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001244
1245 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1246
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001247 mutex_lock(&wl->mutex);
1248
1249 if (wl->state == WL1271_STATE_OFF)
1250 goto out;
1251
1252 ret = wl1271_ps_elp_wakeup(wl, false);
1253 if (ret < 0)
1254 goto out;
1255
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001256 *total &= WL1271_SUPPORTED_FILTERS;
1257 changed &= WL1271_SUPPORTED_FILTERS;
1258
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001259 if (*total & FIF_ALLMULTI)
1260 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1261 else if (fp)
1262 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1263 fp->mc_list,
1264 fp->mc_list_length);
1265 if (ret < 0)
1266 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001267
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001268 kfree(fp);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001269
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001270 /* FIXME: We still need to set our filters properly */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001271
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001272 /* determine, whether supported filter values have changed */
1273 if (changed == 0)
1274 goto out_sleep;
1275
1276 /* apply configured filters */
1277 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1278 if (ret < 0)
1279 goto out_sleep;
1280
1281out_sleep:
1282 wl1271_ps_elp_sleep(wl);
1283
1284out:
1285 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001286}
1287
1288static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1289 struct ieee80211_vif *vif,
1290 struct ieee80211_sta *sta,
1291 struct ieee80211_key_conf *key_conf)
1292{
1293 struct wl1271 *wl = hw->priv;
1294 const u8 *addr;
1295 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001296 u32 tx_seq_32 = 0;
1297 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001298 u8 key_type;
1299
1300 static const u8 bcast_addr[ETH_ALEN] =
1301 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1302
1303 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1304
1305 addr = sta ? sta->addr : bcast_addr;
1306
1307 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1308 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1309 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1310 key_conf->alg, key_conf->keyidx,
1311 key_conf->keylen, key_conf->flags);
1312 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1313
1314 if (is_zero_ether_addr(addr)) {
1315 /* We dont support TX only encryption */
1316 ret = -EOPNOTSUPP;
1317 goto out;
1318 }
1319
1320 mutex_lock(&wl->mutex);
1321
1322 ret = wl1271_ps_elp_wakeup(wl, false);
1323 if (ret < 0)
1324 goto out_unlock;
1325
1326 switch (key_conf->alg) {
1327 case ALG_WEP:
1328 key_type = KEY_WEP;
1329
1330 key_conf->hw_key_idx = key_conf->keyidx;
1331 break;
1332 case ALG_TKIP:
1333 key_type = KEY_TKIP;
1334
1335 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001336 tx_seq_32 = wl->tx_security_seq_32;
1337 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001338 break;
1339 case ALG_CCMP:
1340 key_type = KEY_AES;
1341
1342 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001343 tx_seq_32 = wl->tx_security_seq_32;
1344 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001345 break;
1346 default:
1347 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1348
1349 ret = -EOPNOTSUPP;
1350 goto out_sleep;
1351 }
1352
1353 switch (cmd) {
1354 case SET_KEY:
1355 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1356 key_conf->keyidx, key_type,
1357 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001358 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001359 if (ret < 0) {
1360 wl1271_error("Could not add or replace key");
1361 goto out_sleep;
1362 }
1363 break;
1364
1365 case DISABLE_KEY:
1366 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1367 key_conf->keyidx, key_type,
1368 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001369 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001370 if (ret < 0) {
1371 wl1271_error("Could not remove key");
1372 goto out_sleep;
1373 }
1374 break;
1375
1376 default:
1377 wl1271_error("Unsupported key cmd 0x%x", cmd);
1378 ret = -EOPNOTSUPP;
1379 goto out_sleep;
1380
1381 break;
1382 }
1383
1384out_sleep:
1385 wl1271_ps_elp_sleep(wl);
1386
1387out_unlock:
1388 mutex_unlock(&wl->mutex);
1389
1390out:
1391 return ret;
1392}
1393
1394static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1395 struct cfg80211_scan_request *req)
1396{
1397 struct wl1271 *wl = hw->priv;
1398 int ret;
1399 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001400 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001401
1402 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1403
1404 if (req->n_ssids) {
1405 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001406 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001407 }
1408
1409 mutex_lock(&wl->mutex);
1410
1411 ret = wl1271_ps_elp_wakeup(wl, false);
1412 if (ret < 0)
1413 goto out;
1414
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001415 if (wl1271_11a_enabled())
1416 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1417 WL1271_SCAN_BAND_DUAL, 3);
1418 else
1419 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1420 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001421
1422 wl1271_ps_elp_sleep(wl);
1423
1424out:
1425 mutex_unlock(&wl->mutex);
1426
1427 return ret;
1428}
1429
1430static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1431{
1432 struct wl1271 *wl = hw->priv;
1433 int ret;
1434
1435 mutex_lock(&wl->mutex);
1436
1437 ret = wl1271_ps_elp_wakeup(wl, false);
1438 if (ret < 0)
1439 goto out;
1440
1441 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1442 if (ret < 0)
1443 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1444
1445 wl1271_ps_elp_sleep(wl);
1446
1447out:
1448 mutex_unlock(&wl->mutex);
1449
1450 return ret;
1451}
1452
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001453static u32 wl1271_enabled_rates_get(struct wl1271 *wl, u64 basic_rate_set)
1454{
1455 struct ieee80211_supported_band *band;
1456 u32 enabled_rates = 0;
1457 int bit;
1458
1459 band = wl->hw->wiphy->bands[wl->band];
1460 for (bit = 0; bit < band->n_bitrates; bit++) {
1461 if (basic_rate_set & 0x1)
1462 enabled_rates |= band->bitrates[bit].hw_value;
1463 basic_rate_set >>= 1;
1464 }
1465
1466 return enabled_rates;
1467}
1468
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001469static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1470 struct ieee80211_vif *vif,
1471 struct ieee80211_bss_conf *bss_conf,
1472 u32 changed)
1473{
1474 enum wl1271_cmd_ps_mode mode;
1475 struct wl1271 *wl = hw->priv;
1476 int ret;
1477
1478 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1479
1480 mutex_lock(&wl->mutex);
1481
1482 ret = wl1271_ps_elp_wakeup(wl, false);
1483 if (ret < 0)
1484 goto out;
1485
1486 if (changed & BSS_CHANGED_ASSOC) {
1487 if (bss_conf->assoc) {
1488 wl->aid = bss_conf->aid;
1489
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001490 /*
1491 * with wl1271, we don't need to update the
1492 * beacon_int and dtim_period, because the firmware
1493 * updates it by itself when the first beacon is
1494 * received after a join.
1495 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001496 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1497 if (ret < 0)
1498 goto out_sleep;
1499
1500 ret = wl1271_acx_aid(wl, wl->aid);
1501 if (ret < 0)
1502 goto out_sleep;
1503
1504 /* If we want to go in PSM but we're not there yet */
1505 if (wl->psm_requested && !wl->psm) {
1506 mode = STATION_POWER_SAVE_MODE;
1507 ret = wl1271_ps_set_mode(wl, mode);
1508 if (ret < 0)
1509 goto out_sleep;
1510 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001511 } else {
1512 /* use defaults when not associated */
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001513 wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
1514 wl->aid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001515 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001516
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001517 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001518
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001519 if (changed & BSS_CHANGED_ERP_SLOT) {
1520 if (bss_conf->use_short_slot)
1521 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1522 else
1523 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1524 if (ret < 0) {
1525 wl1271_warning("Set slot time failed %d", ret);
1526 goto out_sleep;
1527 }
1528 }
1529
1530 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1531 if (bss_conf->use_short_preamble)
1532 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1533 else
1534 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1535 }
1536
1537 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1538 if (bss_conf->use_cts_prot)
1539 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1540 else
1541 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1542 if (ret < 0) {
1543 wl1271_warning("Set ctsprotect failed %d", ret);
1544 goto out_sleep;
1545 }
1546 }
1547
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001548 if (changed & BSS_CHANGED_BASIC_RATES) {
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001549 wl->basic_rate_set = wl1271_enabled_rates_get(
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001550 wl, bss_conf->basic_rates);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001551
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001552 ret = wl1271_acx_rate_policies(wl, wl->basic_rate_set);
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001553 if (ret < 0) {
1554 wl1271_warning("Set rate policies failed %d", ret);
1555 goto out_sleep;
1556 }
1557 }
1558
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001559out_sleep:
1560 wl1271_ps_elp_sleep(wl);
1561
1562out:
1563 mutex_unlock(&wl->mutex);
1564}
1565
1566
1567/* can't be const, mac80211 writes to this */
1568static struct ieee80211_rate wl1271_rates[] = {
1569 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001570 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1571 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001572 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001573 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1574 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001575 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1576 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001577 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1578 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001579 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1580 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001581 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1582 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001583 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1584 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001585 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1586 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001587 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001588 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1589 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001590 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001591 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1592 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001593 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001594 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1595 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001596 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001597 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1598 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001599 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001600 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1601 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001602 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001603 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1604 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001605 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001606 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1607 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001608};
1609
1610/* can't be const, mac80211 writes to this */
1611static struct ieee80211_channel wl1271_channels[] = {
1612 { .hw_value = 1, .center_freq = 2412},
1613 { .hw_value = 2, .center_freq = 2417},
1614 { .hw_value = 3, .center_freq = 2422},
1615 { .hw_value = 4, .center_freq = 2427},
1616 { .hw_value = 5, .center_freq = 2432},
1617 { .hw_value = 6, .center_freq = 2437},
1618 { .hw_value = 7, .center_freq = 2442},
1619 { .hw_value = 8, .center_freq = 2447},
1620 { .hw_value = 9, .center_freq = 2452},
1621 { .hw_value = 10, .center_freq = 2457},
1622 { .hw_value = 11, .center_freq = 2462},
1623 { .hw_value = 12, .center_freq = 2467},
1624 { .hw_value = 13, .center_freq = 2472},
1625};
1626
1627/* can't be const, mac80211 writes to this */
1628static struct ieee80211_supported_band wl1271_band_2ghz = {
1629 .channels = wl1271_channels,
1630 .n_channels = ARRAY_SIZE(wl1271_channels),
1631 .bitrates = wl1271_rates,
1632 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1633};
1634
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001635/* 5 GHz data rates for WL1273 */
1636static struct ieee80211_rate wl1271_rates_5ghz[] = {
1637 { .bitrate = 60,
1638 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1639 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
1640 { .bitrate = 90,
1641 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1642 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
1643 { .bitrate = 120,
1644 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1645 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
1646 { .bitrate = 180,
1647 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1648 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
1649 { .bitrate = 240,
1650 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1651 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
1652 { .bitrate = 360,
1653 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1654 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
1655 { .bitrate = 480,
1656 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1657 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
1658 { .bitrate = 540,
1659 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1660 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
1661};
1662
1663/* 5 GHz band channels for WL1273 */
1664static struct ieee80211_channel wl1271_channels_5ghz[] = {
1665 { .hw_value = 183, .center_freq = 4915},
1666 { .hw_value = 184, .center_freq = 4920},
1667 { .hw_value = 185, .center_freq = 4925},
1668 { .hw_value = 187, .center_freq = 4935},
1669 { .hw_value = 188, .center_freq = 4940},
1670 { .hw_value = 189, .center_freq = 4945},
1671 { .hw_value = 192, .center_freq = 4960},
1672 { .hw_value = 196, .center_freq = 4980},
1673 { .hw_value = 7, .center_freq = 5035},
1674 { .hw_value = 8, .center_freq = 5040},
1675 { .hw_value = 9, .center_freq = 5045},
1676 { .hw_value = 11, .center_freq = 5055},
1677 { .hw_value = 12, .center_freq = 5060},
1678 { .hw_value = 16, .center_freq = 5080},
1679 { .hw_value = 34, .center_freq = 5170},
1680 { .hw_value = 36, .center_freq = 5180},
1681 { .hw_value = 38, .center_freq = 5190},
1682 { .hw_value = 40, .center_freq = 5200},
1683 { .hw_value = 42, .center_freq = 5210},
1684 { .hw_value = 44, .center_freq = 5220},
1685 { .hw_value = 46, .center_freq = 5230},
1686 { .hw_value = 48, .center_freq = 5240},
1687 { .hw_value = 52, .center_freq = 5260},
1688 { .hw_value = 56, .center_freq = 5280},
1689 { .hw_value = 60, .center_freq = 5300},
1690 { .hw_value = 64, .center_freq = 5320},
1691 { .hw_value = 100, .center_freq = 5500},
1692 { .hw_value = 104, .center_freq = 5520},
1693 { .hw_value = 108, .center_freq = 5540},
1694 { .hw_value = 112, .center_freq = 5560},
1695 { .hw_value = 116, .center_freq = 5580},
1696 { .hw_value = 120, .center_freq = 5600},
1697 { .hw_value = 124, .center_freq = 5620},
1698 { .hw_value = 128, .center_freq = 5640},
1699 { .hw_value = 132, .center_freq = 5660},
1700 { .hw_value = 136, .center_freq = 5680},
1701 { .hw_value = 140, .center_freq = 5700},
1702 { .hw_value = 149, .center_freq = 5745},
1703 { .hw_value = 153, .center_freq = 5765},
1704 { .hw_value = 157, .center_freq = 5785},
1705 { .hw_value = 161, .center_freq = 5805},
1706 { .hw_value = 165, .center_freq = 5825},
1707};
1708
1709
1710static struct ieee80211_supported_band wl1271_band_5ghz = {
1711 .channels = wl1271_channels_5ghz,
1712 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
1713 .bitrates = wl1271_rates_5ghz,
1714 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
1715};
1716
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001717static const struct ieee80211_ops wl1271_ops = {
1718 .start = wl1271_op_start,
1719 .stop = wl1271_op_stop,
1720 .add_interface = wl1271_op_add_interface,
1721 .remove_interface = wl1271_op_remove_interface,
1722 .config = wl1271_op_config,
1723/* .config_interface = wl1271_op_config_interface, */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001724 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001725 .configure_filter = wl1271_op_configure_filter,
1726 .tx = wl1271_op_tx,
1727 .set_key = wl1271_op_set_key,
1728 .hw_scan = wl1271_op_hw_scan,
1729 .bss_info_changed = wl1271_op_bss_info_changed,
1730 .set_rts_threshold = wl1271_op_set_rts_threshold,
1731};
1732
1733static int wl1271_register_hw(struct wl1271 *wl)
1734{
1735 int ret;
1736
1737 if (wl->mac80211_registered)
1738 return 0;
1739
1740 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
1741
1742 ret = ieee80211_register_hw(wl->hw);
1743 if (ret < 0) {
1744 wl1271_error("unable to register mac80211 hw: %d", ret);
1745 return ret;
1746 }
1747
1748 wl->mac80211_registered = true;
1749
1750 wl1271_notice("loaded");
1751
1752 return 0;
1753}
1754
1755static int wl1271_init_ieee80211(struct wl1271 *wl)
1756{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03001757 /* The tx descriptor buffer and the TKIP space. */
1758 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
1759 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001760
1761 /* unit us */
1762 /* FIXME: find a proper value */
1763 wl->hw->channel_change_time = 10000;
1764
1765 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03001766 IEEE80211_HW_NOISE_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02001767 IEEE80211_HW_BEACON_FILTER |
1768 IEEE80211_HW_SUPPORTS_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001769
1770 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
1771 wl->hw->wiphy->max_scan_ssids = 1;
1772 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
1773
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001774 if (wl1271_11a_enabled())
1775 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
1776
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001777 SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
1778
1779 return 0;
1780}
1781
1782static void wl1271_device_release(struct device *dev)
1783{
1784
1785}
1786
1787static struct platform_device wl1271_device = {
1788 .name = "wl1271",
1789 .id = -1,
1790
1791 /* device model insists to have a release function */
1792 .dev = {
1793 .release = wl1271_device_release,
1794 },
1795};
1796
1797#define WL1271_DEFAULT_CHANNEL 0
1798static int __devinit wl1271_probe(struct spi_device *spi)
1799{
1800 struct wl12xx_platform_data *pdata;
1801 struct ieee80211_hw *hw;
1802 struct wl1271 *wl;
1803 int ret, i;
1804 static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
1805
1806 pdata = spi->dev.platform_data;
1807 if (!pdata) {
1808 wl1271_error("no platform data");
1809 return -ENODEV;
1810 }
1811
1812 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
1813 if (!hw) {
1814 wl1271_error("could not alloc ieee80211_hw");
1815 return -ENOMEM;
1816 }
1817
1818 wl = hw->priv;
1819 memset(wl, 0, sizeof(*wl));
1820
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001821 INIT_LIST_HEAD(&wl->list);
1822
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001823 wl->hw = hw;
1824 dev_set_drvdata(&spi->dev, wl);
1825 wl->spi = spi;
1826
1827 skb_queue_head_init(&wl->tx_queue);
1828
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03001829 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001830 wl->channel = WL1271_DEFAULT_CHANNEL;
1831 wl->scanning = false;
1832 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001833 wl->rx_counter = 0;
1834 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1835 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1836 wl->elp = false;
1837 wl->psm = 0;
1838 wl->psm_requested = false;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001839 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001840 wl->tx_queue_stopped = false;
1841 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001842 wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001843 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001844 wl->vif = NULL;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001845 wl->joined = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001846
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03001847 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001848 wl->tx_frames[i] = NULL;
1849
1850 spin_lock_init(&wl->wl_lock);
1851
1852 /*
1853 * In case our MAC address is not correctly set,
1854 * we use a random but Nokia MAC.
1855 */
1856 memcpy(wl->mac_addr, nokia_oui, 3);
1857 get_random_bytes(wl->mac_addr + 3, 3);
1858
1859 wl->state = WL1271_STATE_OFF;
1860 mutex_init(&wl->mutex);
1861
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001862 /* This is the only SPI value that we need to set here, the rest
1863 * comes from the board-peripherals file */
1864 spi->bits_per_word = 32;
1865
1866 ret = spi_setup(spi);
1867 if (ret < 0) {
1868 wl1271_error("spi_setup failed");
1869 goto out_free;
1870 }
1871
1872 wl->set_power = pdata->set_power;
1873 if (!wl->set_power) {
1874 wl1271_error("set power function missing in platform data");
1875 ret = -ENODEV;
1876 goto out_free;
1877 }
1878
1879 wl->irq = spi->irq;
1880 if (wl->irq < 0) {
1881 wl1271_error("irq missing in platform data");
1882 ret = -ENODEV;
1883 goto out_free;
1884 }
1885
1886 ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
1887 if (ret < 0) {
1888 wl1271_error("request_irq() failed: %d", ret);
1889 goto out_free;
1890 }
1891
1892 set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
1893
1894 disable_irq(wl->irq);
1895
1896 ret = platform_device_register(&wl1271_device);
1897 if (ret) {
1898 wl1271_error("couldn't register platform device");
1899 goto out_irq;
1900 }
1901 dev_set_drvdata(&wl1271_device.dev, wl);
1902
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001903 /* Apply default driver configuration. */
1904 wl1271_conf_init(wl);
1905
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001906 ret = wl1271_init_ieee80211(wl);
1907 if (ret)
1908 goto out_platform;
1909
1910 ret = wl1271_register_hw(wl);
1911 if (ret)
1912 goto out_platform;
1913
1914 wl1271_debugfs_init(wl);
1915
1916 wl1271_notice("initialized");
1917
1918 return 0;
1919
1920 out_platform:
1921 platform_device_unregister(&wl1271_device);
1922
1923 out_irq:
1924 free_irq(wl->irq, wl);
1925
1926 out_free:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001927 ieee80211_free_hw(hw);
1928
1929 return ret;
1930}
1931
1932static int __devexit wl1271_remove(struct spi_device *spi)
1933{
1934 struct wl1271 *wl = dev_get_drvdata(&spi->dev);
1935
1936 ieee80211_unregister_hw(wl->hw);
1937
1938 wl1271_debugfs_exit(wl);
1939 platform_device_unregister(&wl1271_device);
1940 free_irq(wl->irq, wl);
1941 kfree(wl->target_mem_map);
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001942 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001943 wl->fw = NULL;
1944 kfree(wl->nvs);
1945 wl->nvs = NULL;
1946
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001947 kfree(wl->fw_status);
1948 kfree(wl->tx_res_if);
1949
1950 ieee80211_free_hw(wl->hw);
1951
1952 return 0;
1953}
1954
1955
1956static struct spi_driver wl1271_spi_driver = {
1957 .driver = {
1958 .name = "wl1271",
1959 .bus = &spi_bus_type,
1960 .owner = THIS_MODULE,
1961 },
1962
1963 .probe = wl1271_probe,
1964 .remove = __devexit_p(wl1271_remove),
1965};
1966
1967static int __init wl1271_init(void)
1968{
1969 int ret;
1970
1971 ret = spi_register_driver(&wl1271_spi_driver);
1972 if (ret < 0) {
1973 wl1271_error("failed to register spi driver: %d", ret);
1974 goto out;
1975 }
1976
1977out:
1978 return ret;
1979}
1980
1981static void __exit wl1271_exit(void)
1982{
1983 spi_unregister_driver(&wl1271_spi_driver);
1984
1985 wl1271_notice("unloaded");
1986}
1987
1988module_init(wl1271_init);
1989module_exit(wl1271_exit);
1990
1991MODULE_LICENSE("GPL");
1992MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
Luciano Coelho2f018722009-10-08 21:56:27 +03001993MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
Ben Hutchings49f146d2009-11-07 22:02:15 +00001994MODULE_FIRMWARE(WL1271_FW_NAME);