blob: d6d1a4c1b11464cd45fc9fecc0d3ab992f44453d [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>
35
36#include "wl1271.h"
37#include "wl12xx_80211.h"
38#include "wl1271_reg.h"
39#include "wl1271_spi.h"
40#include "wl1271_event.h"
41#include "wl1271_tx.h"
42#include "wl1271_rx.h"
43#include "wl1271_ps.h"
44#include "wl1271_init.h"
45#include "wl1271_debugfs.h"
46#include "wl1271_cmd.h"
47#include "wl1271_boot.h"
48
Juuso Oikarinen8a080482009-10-13 12:47:44 +030049static struct conf_drv_settings default_conf = {
50 .sg = {
51 .per_threshold = 7500,
52 .max_scan_compensation_time = 120000,
53 .nfs_sample_interval = 400,
54 .load_ratio = 50,
55 .auto_ps_mode = 0,
56 .probe_req_compensation = 170,
57 .scan_window_compensation = 50,
58 .antenna_config = 0,
59 .beacon_miss_threshold = 60,
60 .rate_adaptation_threshold = CONF_HW_BIT_RATE_12MBPS,
61 .rate_adaptation_snr = 0
62 },
63 .rx = {
64 .rx_msdu_life_time = 512000,
65 .packet_detection_threshold = 0,
66 .ps_poll_timeout = 15,
67 .upsd_timeout = 15,
68 .rts_threshold = 2347,
69 .rx_cca_threshold = 0xFFEF,
70 .irq_blk_threshold = 0,
71 .irq_pkt_threshold = USHORT_MAX,
72 .irq_timeout = 5,
73 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
74 },
75 .tx = {
76 .tx_energy_detection = 0,
77 .rc_conf = {
78 .enabled_rates = CONF_TX_RATE_MASK_UNSPECIFIED,
79 .short_retry_limit = 10,
80 .long_retry_limit = 10,
81 .aflags = 0
82 },
83 .ac_conf_count = 4,
84 .ac_conf = {
85 [0] = {
86 .ac = CONF_TX_AC_BE,
87 .cw_min = 15,
88 .cw_max = 63,
89 .aifsn = 3,
90 .tx_op_limit = 0,
91 },
92 [1] = {
93 .ac = CONF_TX_AC_BK,
94 .cw_min = 15,
95 .cw_max = 63,
96 .aifsn = 7,
97 .tx_op_limit = 0,
98 },
99 [2] = {
100 .ac = CONF_TX_AC_VI,
101 .cw_min = 15,
102 .cw_max = 63,
103 .aifsn = CONF_TX_AIFS_PIFS,
104 .tx_op_limit = 3008,
105 },
106 [3] = {
107 .ac = CONF_TX_AC_VO,
108 .cw_min = 15,
109 .cw_max = 63,
110 .aifsn = CONF_TX_AIFS_PIFS,
111 .tx_op_limit = 1504,
112 },
113 },
114 .tid_conf_count = 7,
115 .tid_conf = {
116 [0] = {
117 .queue_id = 0,
118 .channel_type = CONF_CHANNEL_TYPE_DCF,
119 .tsid = CONF_TX_AC_BE,
120 .ps_scheme = CONF_PS_SCHEME_LEGACY,
121 .ack_policy = CONF_ACK_POLICY_LEGACY,
122 .apsd_conf = {0, 0},
123 },
124 [1] = {
125 .queue_id = 1,
126 .channel_type = CONF_CHANNEL_TYPE_DCF,
127 .tsid = CONF_TX_AC_BE,
128 .ps_scheme = CONF_PS_SCHEME_LEGACY,
129 .ack_policy = CONF_ACK_POLICY_LEGACY,
130 .apsd_conf = {0, 0},
131 },
132 [2] = {
133 .queue_id = 2,
134 .channel_type = CONF_CHANNEL_TYPE_DCF,
135 .tsid = CONF_TX_AC_BE,
136 .ps_scheme = CONF_PS_SCHEME_LEGACY,
137 .ack_policy = CONF_ACK_POLICY_LEGACY,
138 .apsd_conf = {0, 0},
139 },
140 [3] = {
141 .queue_id = 3,
142 .channel_type = CONF_CHANNEL_TYPE_DCF,
143 .tsid = CONF_TX_AC_BE,
144 .ps_scheme = CONF_PS_SCHEME_LEGACY,
145 .ack_policy = CONF_ACK_POLICY_LEGACY,
146 .apsd_conf = {0, 0},
147 },
148 [4] = {
149 .queue_id = 4,
150 .channel_type = CONF_CHANNEL_TYPE_DCF,
151 .tsid = CONF_TX_AC_BE,
152 .ps_scheme = CONF_PS_SCHEME_LEGACY,
153 .ack_policy = CONF_ACK_POLICY_LEGACY,
154 .apsd_conf = {0, 0},
155 },
156 [5] = {
157 .queue_id = 5,
158 .channel_type = CONF_CHANNEL_TYPE_DCF,
159 .tsid = CONF_TX_AC_BE,
160 .ps_scheme = CONF_PS_SCHEME_LEGACY,
161 .ack_policy = CONF_ACK_POLICY_LEGACY,
162 .apsd_conf = {0, 0},
163 },
164 [6] = {
165 .queue_id = 6,
166 .channel_type = CONF_CHANNEL_TYPE_DCF,
167 .tsid = CONF_TX_AC_BE,
168 .ps_scheme = CONF_PS_SCHEME_LEGACY,
169 .ack_policy = CONF_ACK_POLICY_LEGACY,
170 .apsd_conf = {0, 0},
171 }
172 },
173 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
174 .tx_compl_timeout = 5,
175 .tx_compl_threshold = 5
176 },
177 .conn = {
178 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
179 .listen_interval = 0,
180 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
181 .bcn_filt_ie_count = 1,
182 .bcn_filt_ie = {
183 [0] = {
184 .ie = WLAN_EID_CHANNEL_SWITCH,
185 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
186 }
187 },
188 .synch_fail_thold = 5,
189 .bss_lose_timeout = 100,
190 .beacon_rx_timeout = 10000,
191 .broadcast_timeout = 20000,
192 .rx_broadcast_in_ps = 1,
193 .ps_poll_threshold = 4,
194 .sig_trigger_count = 2,
195 .sig_trigger = {
196 [0] = {
197 .threshold = -75,
198 .pacing = 500,
199 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
200 .type = CONF_TRIG_EVENT_TYPE_EDGE,
201 .direction = CONF_TRIG_EVENT_DIR_LOW,
202 .hysteresis = 2,
203 .index = 0,
204 .enable = 1
205 },
206 [1] = {
207 .threshold = -75,
208 .pacing = 500,
209 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
210 .type = CONF_TRIG_EVENT_TYPE_EDGE,
211 .direction = CONF_TRIG_EVENT_DIR_HIGH,
212 .hysteresis = 2,
213 .index = 1,
214 .enable = 1
215 }
216 },
217 .sig_weights = {
218 .rssi_bcn_avg_weight = 10,
219 .rssi_pkt_avg_weight = 10,
220 .snr_bcn_avg_weight = 10,
221 .snr_pkt_avg_weight = 10
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300222 },
223 .bet_enable = CONF_BET_MODE_ENABLE,
224 .bet_max_consecutive = 100
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300225 },
226 .init = {
227 .sr_err_tbl = {
228 [0] = {
229 .len = 7,
230 .upper_limit = 0x03,
231 .values = {
232 0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8,
233 0x00 }
234 },
235 [1] = {
236 .len = 7,
237 .upper_limit = 0x03,
238 .values = {
239 0x18, 0x10, 0x05, 0xf6, 0xf0, 0xe8,
240 0x00 }
241 },
242 [2] = {
243 .len = 7,
244 .upper_limit = 0x03,
245 .values = {
246 0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8,
247 0x00 }
248 }
249 },
250 .sr_enable = 1,
251 .genparam = {
252 /*
253 * FIXME: The correct value CONF_REF_CLK_38_4_E
254 * causes the firmware to crash on boot.
255 * The value 5 apparently is an
256 * unnoficial XTAL configuration of the
257 * same frequency, which appears to work.
258 */
259 .ref_clk = 5,
260 .settling_time = 5,
261 .clk_valid_on_wakeup = 0,
262 .dc2dcmode = 0,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300263 .single_dual_band = CONF_SINGLE_BAND,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300264 .tx_bip_fem_autodetect = 0,
265 .tx_bip_fem_manufacturer = 1,
266 .settings = 1,
267 },
268 .radioparam = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300269 .rx_trace_loss = 10,
270 .tx_trace_loss = 10,
271 .rx_rssi_and_proc_compens = {
272 0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8,
273 0xfc, 0x00, 0x08, 0x10, 0xf0, 0xf8,
274 0x00, 0x0a, 0x14 },
275 .rx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 },
276 .tx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 },
277 .rx_rssi_and_proc_compens_5 = {
278 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
279 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
280 0x00, 0x00, 0x00 },
281 .tx_ref_pd_voltage = 0x24e,
282 .tx_ref_power = 0x78,
283 .tx_offset_db = 0x0,
284 .tx_rate_limits_normal = {
285 0x1e, 0x1f, 0x22, 0x24, 0x28, 0x29 },
286 .tx_rate_limits_degraded = {
287 0x1b, 0x1c, 0x1e, 0x20, 0x24, 0x25 },
288 .tx_channel_limits_11b = {
289 0x22, 0x50, 0x50, 0x50, 0x50, 0x50,
290 0x50, 0x50, 0x50, 0x50, 0x22, 0x50,
291 0x22, 0x50 },
292 .tx_channel_limits_ofdm = {
293 0x20, 0x50, 0x50, 0x50, 0x50, 0x50,
294 0x50, 0x50, 0x50, 0x50, 0x20, 0x50,
295 0x20, 0x50 },
296 .tx_pdv_rate_offsets = {
297 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
298 .tx_ibias = {
299 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x27 },
300 .rx_fem_insertion_loss = 0x14,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300301 .tx_ref_pd_voltage_5 = {
302 0x0190, 0x01a4, 0x01c3, 0x01d8,
303 0x020a, 0x021c },
304 .tx_ref_power_5 = {
305 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 },
306 .tx_offset_db_5 = {
307 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300308 .tx_rate_limits_normal_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300309 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300310 .tx_rate_limits_degraded_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300311 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300312 .tx_channel_limits_ofdm_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300313 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
314 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
315 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
316 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
317 0x50, 0x50, 0x50 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300318 .tx_pdv_rate_offsets_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300319 0x01, 0x02, 0x02, 0x02, 0x02, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300320 .tx_ibias_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300321 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
322 .rx_fem_insertion_loss_5 = {
323 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300324 }
325 }
326};
327
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300328static void wl1271_conf_init(struct wl1271 *wl)
329{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300330
331 /*
332 * This function applies the default configuration to the driver. This
333 * function is invoked upon driver load (spi probe.)
334 *
335 * The configuration is stored in a run-time structure in order to
336 * facilitate for run-time adjustment of any of the parameters. Making
337 * changes to the configuration structure will apply the new values on
338 * the next interface up (wl1271_op_start.)
339 */
340
341 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300342 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300343
344 if (wl1271_11a_enabled())
345 wl->conf.init.genparam.single_dual_band = CONF_DUAL_BAND;
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300346}
347
348
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300349static int wl1271_plt_init(struct wl1271 *wl)
350{
351 int ret;
352
353 ret = wl1271_acx_init_mem_config(wl);
354 if (ret < 0)
355 return ret;
356
357 ret = wl1271_cmd_data_path(wl, wl->channel, 1);
358 if (ret < 0)
359 return ret;
360
361 return 0;
362}
363
364static void wl1271_disable_interrupts(struct wl1271 *wl)
365{
366 disable_irq(wl->irq);
367}
368
369static void wl1271_power_off(struct wl1271 *wl)
370{
371 wl->set_power(false);
372}
373
374static void wl1271_power_on(struct wl1271 *wl)
375{
376 wl->set_power(true);
377}
378
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300379static void wl1271_fw_status(struct wl1271 *wl,
380 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300381{
382 u32 total = 0;
383 int i;
384
Juuso Oikarinen74621412009-10-12 15:08:54 +0300385 wl1271_spi_read(wl, FW_STATUS_ADDR, status,
386 sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300387
388 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
389 "drv_rx_counter = %d, tx_results_counter = %d)",
390 status->intr,
391 status->fw_rx_counter,
392 status->drv_rx_counter,
393 status->tx_results_counter);
394
395 /* update number of available TX blocks */
396 for (i = 0; i < NUM_TX_QUEUES; i++) {
397 u32 cnt = status->tx_released_blks[i] - wl->tx_blocks_freed[i];
398 wl->tx_blocks_freed[i] = status->tx_released_blks[i];
399 wl->tx_blocks_available += cnt;
400 total += cnt;
401 }
402
403 /* if more blocks are available now, schedule some tx work */
404 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300405 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300406
407 /* update the host-chipset time offset */
408 wl->time_offset = jiffies_to_usecs(jiffies) - status->fw_localtime;
409}
410
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300411static void wl1271_irq_work(struct work_struct *work)
412{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300413 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300414 u32 intr;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300415 struct wl1271 *wl =
416 container_of(work, struct wl1271, irq_work);
417
418 mutex_lock(&wl->mutex);
419
420 wl1271_debug(DEBUG_IRQ, "IRQ work");
421
422 if (wl->state == WL1271_STATE_OFF)
423 goto out;
424
425 ret = wl1271_ps_elp_wakeup(wl, true);
426 if (ret < 0)
427 goto out;
428
Juuso Oikarinen74621412009-10-12 15:08:54 +0300429 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300430
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300431 wl1271_fw_status(wl, wl->fw_status);
432 intr = wl->fw_status->intr;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300433 if (!intr) {
434 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
435 goto out_sleep;
436 }
437
438 intr &= WL1271_INTR_MASK;
439
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300440 if (intr & WL1271_ACX_INTR_EVENT_A) {
441 bool do_ack = (intr & WL1271_ACX_INTR_EVENT_B) ? false : true;
442 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
443 wl1271_event_handle(wl, 0, do_ack);
444 }
445
446 if (intr & WL1271_ACX_INTR_EVENT_B) {
447 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
448 wl1271_event_handle(wl, 1, true);
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300449 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300450
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300451 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
452 wl1271_debug(DEBUG_IRQ,
453 "WL1271_ACX_INTR_INIT_COMPLETE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300454
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300455 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
456 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300457
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300458 if (intr & WL1271_ACX_INTR_DATA) {
459 u8 tx_res_cnt = wl->fw_status->tx_results_counter -
460 wl->tx_results_count;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300461
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300462 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300463
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300464 /* check for tx results */
465 if (tx_res_cnt)
466 wl1271_tx_complete(wl, tx_res_cnt);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300467
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300468 wl1271_rx(wl, wl->fw_status);
469 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300470
471out_sleep:
Juuso Oikarinen74621412009-10-12 15:08:54 +0300472 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
Luciano Coelho73d0a132009-08-11 11:58:27 +0300473 WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300474 wl1271_ps_elp_sleep(wl);
475
476out:
477 mutex_unlock(&wl->mutex);
478}
479
480static irqreturn_t wl1271_irq(int irq, void *cookie)
481{
482 struct wl1271 *wl;
483 unsigned long flags;
484
485 wl1271_debug(DEBUG_IRQ, "IRQ");
486
487 wl = cookie;
488
489 /* complete the ELP completion */
490 spin_lock_irqsave(&wl->wl_lock, flags);
491 if (wl->elp_compl) {
492 complete(wl->elp_compl);
493 wl->elp_compl = NULL;
494 }
495
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300496 ieee80211_queue_work(wl->hw, &wl->irq_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300497 spin_unlock_irqrestore(&wl->wl_lock, flags);
498
499 return IRQ_HANDLED;
500}
501
502static int wl1271_fetch_firmware(struct wl1271 *wl)
503{
504 const struct firmware *fw;
505 int ret;
506
507 ret = request_firmware(&fw, WL1271_FW_NAME, &wl->spi->dev);
508
509 if (ret < 0) {
510 wl1271_error("could not get firmware: %d", ret);
511 return ret;
512 }
513
514 if (fw->size % 4) {
515 wl1271_error("firmware size is not multiple of 32 bits: %zu",
516 fw->size);
517 ret = -EILSEQ;
518 goto out;
519 }
520
521 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300522 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300523
524 if (!wl->fw) {
525 wl1271_error("could not allocate memory for the firmware");
526 ret = -ENOMEM;
527 goto out;
528 }
529
530 memcpy(wl->fw, fw->data, wl->fw_len);
531
532 ret = 0;
533
534out:
535 release_firmware(fw);
536
537 return ret;
538}
539
540static int wl1271_fetch_nvs(struct wl1271 *wl)
541{
542 const struct firmware *fw;
543 int ret;
544
545 ret = request_firmware(&fw, WL1271_NVS_NAME, &wl->spi->dev);
546
547 if (ret < 0) {
548 wl1271_error("could not get nvs file: %d", ret);
549 return ret;
550 }
551
552 if (fw->size % 4) {
553 wl1271_error("nvs size is not multiple of 32 bits: %zu",
554 fw->size);
555 ret = -EILSEQ;
556 goto out;
557 }
558
559 wl->nvs_len = fw->size;
560 wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL);
561
562 if (!wl->nvs) {
563 wl1271_error("could not allocate memory for the nvs file");
564 ret = -ENOMEM;
565 goto out;
566 }
567
568 memcpy(wl->nvs, fw->data, wl->nvs_len);
569
570 ret = 0;
571
572out:
573 release_firmware(fw);
574
575 return ret;
576}
577
578static void wl1271_fw_wakeup(struct wl1271 *wl)
579{
580 u32 elp_reg;
581
582 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300583 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300584}
585
586static int wl1271_setup(struct wl1271 *wl)
587{
588 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
589 if (!wl->fw_status)
590 return -ENOMEM;
591
592 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
593 if (!wl->tx_res_if) {
594 kfree(wl->fw_status);
595 return -ENOMEM;
596 }
597
598 INIT_WORK(&wl->irq_work, wl1271_irq_work);
599 INIT_WORK(&wl->tx_work, wl1271_tx_work);
600 return 0;
601}
602
603static int wl1271_chip_wakeup(struct wl1271 *wl)
604{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300605 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300606 int ret = 0;
607
608 wl1271_power_on(wl);
609 msleep(WL1271_POWER_ON_SLEEP);
610 wl1271_spi_reset(wl);
611 wl1271_spi_init(wl);
612
613 /* We don't need a real memory partition here, because we only want
614 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300615 memset(&partition, 0, sizeof(partition));
616 partition.reg.start = REGISTERS_BASE;
617 partition.reg.size = REGISTERS_DOWN_SIZE;
618 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300619
620 /* ELP module wake up */
621 wl1271_fw_wakeup(wl);
622
623 /* whal_FwCtrl_BootSm() */
624
625 /* 0. read chip id from CHIP_ID */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300626 wl->chip.id = wl1271_spi_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300627
628 /* 1. check if chip id is valid */
629
630 switch (wl->chip.id) {
631 case CHIP_ID_1271_PG10:
632 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
633 wl->chip.id);
634
635 ret = wl1271_setup(wl);
636 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300637 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300638 break;
639 case CHIP_ID_1271_PG20:
640 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
641 wl->chip.id);
642
643 ret = wl1271_setup(wl);
644 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300645 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300646 break;
647 default:
648 wl1271_error("unsupported chip id: 0x%x", wl->chip.id);
649 ret = -ENODEV;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300650 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300651 }
652
653 if (wl->fw == NULL) {
654 ret = wl1271_fetch_firmware(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 }
658
659 /* No NVS from netlink, try to get it from the filesystem */
660 if (wl->nvs == NULL) {
661 ret = wl1271_fetch_nvs(wl);
662 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300663 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300664 }
665
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300666 goto out;
667
668out_power_off:
669 wl1271_power_off(wl);
670
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300671out:
672 return ret;
673}
674
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300675struct wl1271_filter_params {
676 unsigned int filters;
677 unsigned int changed;
678 int mc_list_length;
679 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
680};
681
682#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
683 FIF_ALLMULTI | \
684 FIF_FCSFAIL | \
685 FIF_BCN_PRBRESP_PROMISC | \
686 FIF_CONTROL | \
687 FIF_OTHER_BSS)
688
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300689static void wl1271_filter_work(struct work_struct *work)
690{
691 struct wl1271 *wl =
692 container_of(work, struct wl1271, filter_work);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300693 struct wl1271_filter_params *fp;
694 unsigned long flags;
695 bool enabled = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300696 int ret;
697
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300698 /* first, get the filter parameters */
699 spin_lock_irqsave(&wl->wl_lock, flags);
700 fp = wl->filter_params;
701 wl->filter_params = NULL;
702 spin_unlock_irqrestore(&wl->wl_lock, flags);
703
704 if (!fp)
705 return;
706
707 /* then, lock the mutex without risk of lock-up */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300708 mutex_lock(&wl->mutex);
709
710 if (wl->state == WL1271_STATE_OFF)
711 goto out;
712
713 ret = wl1271_ps_elp_wakeup(wl, false);
714 if (ret < 0)
715 goto out;
716
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300717 /* configure the mc filter regardless of the changed flags */
718 if (fp->filters & FIF_ALLMULTI)
719 enabled = false;
720
721 ret = wl1271_acx_group_address_tbl(wl, enabled,
722 fp->mc_list, fp->mc_list_length);
723 if (ret < 0)
724 goto out_sleep;
725
726 /* determine, whether supported filter values have changed */
727 if (fp->changed == 0)
728 goto out;
729
730 /* apply configured filters */
Luciano Coelho0535d9f2009-10-12 15:08:56 +0300731 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300732 if (ret < 0)
733 goto out_sleep;
734
735out_sleep:
736 wl1271_ps_elp_sleep(wl);
737
738out:
739 mutex_unlock(&wl->mutex);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300740 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300741}
742
743int wl1271_plt_start(struct wl1271 *wl)
744{
745 int ret;
746
747 mutex_lock(&wl->mutex);
748
749 wl1271_notice("power up");
750
751 if (wl->state != WL1271_STATE_OFF) {
752 wl1271_error("cannot go into PLT state because not "
753 "in off state: %d", wl->state);
754 ret = -EBUSY;
755 goto out;
756 }
757
758 wl->state = WL1271_STATE_PLT;
759
760 ret = wl1271_chip_wakeup(wl);
761 if (ret < 0)
762 goto out;
763
764 ret = wl1271_boot(wl);
765 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300766 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300767
768 wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver);
769
770 ret = wl1271_plt_init(wl);
771 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300772 goto out_irq_disable;
773
774 goto out;
775
776out_irq_disable:
777 wl1271_disable_interrupts(wl);
778
779out_power_off:
780 wl1271_power_off(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300781
782out:
783 mutex_unlock(&wl->mutex);
784
785 return ret;
786}
787
788int wl1271_plt_stop(struct wl1271 *wl)
789{
790 int ret = 0;
791
792 mutex_lock(&wl->mutex);
793
794 wl1271_notice("power down");
795
796 if (wl->state != WL1271_STATE_PLT) {
797 wl1271_error("cannot power down because not in PLT "
798 "state: %d", wl->state);
799 ret = -EBUSY;
800 goto out;
801 }
802
803 wl1271_disable_interrupts(wl);
804 wl1271_power_off(wl);
805
806 wl->state = WL1271_STATE_OFF;
807
808out:
809 mutex_unlock(&wl->mutex);
810
811 return ret;
812}
813
814
815static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
816{
817 struct wl1271 *wl = hw->priv;
818
819 skb_queue_tail(&wl->tx_queue, skb);
820
821 /*
822 * The chip specific setup must run before the first TX packet -
823 * before that, the tx_work will not be initialized!
824 */
825
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300826 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300827
828 /*
829 * The workqueue is slow to process the tx_queue and we need stop
830 * the queue here, otherwise the queue will get too long.
831 */
832 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) {
833 ieee80211_stop_queues(wl->hw);
834
835 /*
836 * FIXME: this is racy, the variable is not properly
837 * protected. Maybe fix this by removing the stupid
838 * variable altogether and checking the real queue state?
839 */
840 wl->tx_queue_stopped = true;
841 }
842
843 return NETDEV_TX_OK;
844}
845
846static int wl1271_op_start(struct ieee80211_hw *hw)
847{
848 struct wl1271 *wl = hw->priv;
849 int ret = 0;
850
851 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
852
853 mutex_lock(&wl->mutex);
854
855 if (wl->state != WL1271_STATE_OFF) {
856 wl1271_error("cannot start because not in off state: %d",
857 wl->state);
858 ret = -EBUSY;
859 goto out;
860 }
861
862 ret = wl1271_chip_wakeup(wl);
863 if (ret < 0)
864 goto out;
865
866 ret = wl1271_boot(wl);
867 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300868 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300869
870 ret = wl1271_hw_init(wl);
871 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300872 goto out_irq_disable;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300873
874 wl->state = WL1271_STATE_ON;
875
876 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
877
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300878 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300879
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300880out_irq_disable:
881 wl1271_disable_interrupts(wl);
882
883out_power_off:
884 wl1271_power_off(wl);
885
886out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300887 mutex_unlock(&wl->mutex);
888
889 return ret;
890}
891
892static void wl1271_op_stop(struct ieee80211_hw *hw)
893{
894 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300895 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300896 int i;
897
898 wl1271_info("down");
899
900 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
901
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300902 /* complete/cancel ongoing work */
903 cancel_work_sync(&wl->filter_work);
904 spin_lock_irqsave(&wl->wl_lock, flags);
905 kfree(wl->filter_params);
906 wl->filter_params = NULL;
907 spin_unlock_irqrestore(&wl->wl_lock, flags);
908
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300909 mutex_lock(&wl->mutex);
910
911 WARN_ON(wl->state != WL1271_STATE_ON);
912
913 if (wl->scanning) {
914 mutex_unlock(&wl->mutex);
915 ieee80211_scan_completed(wl->hw, true);
916 mutex_lock(&wl->mutex);
917 wl->scanning = false;
918 }
919
920 wl->state = WL1271_STATE_OFF;
921
922 wl1271_disable_interrupts(wl);
923
924 mutex_unlock(&wl->mutex);
925
926 cancel_work_sync(&wl->irq_work);
927 cancel_work_sync(&wl->tx_work);
928 cancel_work_sync(&wl->filter_work);
929
930 mutex_lock(&wl->mutex);
931
932 /* let's notify MAC80211 about the remaining pending TX frames */
933 wl1271_tx_flush(wl);
934 wl1271_power_off(wl);
935
936 memset(wl->bssid, 0, ETH_ALEN);
937 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
938 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300939 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +0300940 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300941
942 wl->rx_counter = 0;
943 wl->elp = false;
944 wl->psm = 0;
945 wl->tx_queue_stopped = false;
946 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
947 wl->tx_blocks_available = 0;
948 wl->tx_results_count = 0;
949 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +0300950 wl->tx_security_last_seq = 0;
951 wl->tx_security_seq_16 = 0;
952 wl->tx_security_seq_32 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300953 wl->time_offset = 0;
954 wl->session_counter = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +0300955 wl->joined = false;
956
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300957 for (i = 0; i < NUM_TX_QUEUES; i++)
958 wl->tx_blocks_freed[i] = 0;
959
960 wl1271_debugfs_reset(wl);
961 mutex_unlock(&wl->mutex);
962}
963
964static int wl1271_op_add_interface(struct ieee80211_hw *hw,
965 struct ieee80211_if_init_conf *conf)
966{
967 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300968 int ret = 0;
969
John W. Linvillee5539bc2009-08-18 10:50:34 -0400970 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
971 conf->type, conf->mac_addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300972
973 mutex_lock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +0300974 if (wl->vif) {
975 ret = -EBUSY;
976 goto out;
977 }
978
979 wl->vif = conf->vif;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300980
981 switch (conf->type) {
982 case NL80211_IFTYPE_STATION:
983 wl->bss_type = BSS_TYPE_STA_BSS;
984 break;
985 case NL80211_IFTYPE_ADHOC:
986 wl->bss_type = BSS_TYPE_IBSS;
987 break;
988 default:
989 ret = -EOPNOTSUPP;
990 goto out;
991 }
992
993 /* FIXME: what if conf->mac_addr changes? */
994
995out:
996 mutex_unlock(&wl->mutex);
997 return ret;
998}
999
1000static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1001 struct ieee80211_if_init_conf *conf)
1002{
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001003 struct wl1271 *wl = hw->priv;
1004
1005 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001006 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001007 wl->vif = NULL;
1008 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001009}
1010
1011#if 0
1012static int wl1271_op_config_interface(struct ieee80211_hw *hw,
1013 struct ieee80211_vif *vif,
1014 struct ieee80211_if_conf *conf)
1015{
1016 struct wl1271 *wl = hw->priv;
1017 struct sk_buff *beacon;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001018 int ret;
1019
David S. Miller32646902009-09-17 10:18:30 -07001020 wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM",
1021 conf->bssid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001022 wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid,
1023 conf->ssid_len);
1024
1025 mutex_lock(&wl->mutex);
1026
1027 ret = wl1271_ps_elp_wakeup(wl, false);
1028 if (ret < 0)
1029 goto out;
1030
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001031 if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
1032 wl1271_debug(DEBUG_MAC80211, "bssid changed");
1033
1034 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
1035
1036 ret = wl1271_cmd_join(wl);
1037 if (ret < 0)
1038 goto out_sleep;
1039 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001040
1041 ret = wl1271_cmd_build_null_data(wl);
1042 if (ret < 0)
1043 goto out_sleep;
1044
1045 wl->ssid_len = conf->ssid_len;
1046 if (wl->ssid_len)
1047 memcpy(wl->ssid, conf->ssid, wl->ssid_len);
1048
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001049 if (conf->changed & IEEE80211_IFCC_BEACON) {
1050 beacon = ieee80211_beacon_get(hw, vif);
1051 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1052 beacon->data, beacon->len);
1053
1054 if (ret < 0) {
1055 dev_kfree_skb(beacon);
1056 goto out_sleep;
1057 }
1058
1059 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE,
1060 beacon->data, beacon->len);
1061
1062 dev_kfree_skb(beacon);
1063
1064 if (ret < 0)
1065 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001066 }
1067
1068out_sleep:
1069 wl1271_ps_elp_sleep(wl);
1070
1071out:
1072 mutex_unlock(&wl->mutex);
1073
1074 return ret;
1075}
1076#endif
1077
1078static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1079{
1080 struct wl1271 *wl = hw->priv;
1081 struct ieee80211_conf *conf = &hw->conf;
1082 int channel, ret = 0;
1083
1084 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1085
1086 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
1087 channel,
1088 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
1089 conf->power_level);
1090
1091 mutex_lock(&wl->mutex);
1092
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001093 wl->band = conf->channel->band;
1094
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001095 ret = wl1271_ps_elp_wakeup(wl, false);
1096 if (ret < 0)
1097 goto out;
1098
1099 if (channel != wl->channel) {
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001100 /*
1101 * We assume that the stack will configure the right channel
1102 * before associating, so we don't need to send a join
1103 * command here. We will join the right channel when the
1104 * BSSID changes
1105 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001106 wl->channel = channel;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001107 }
1108
1109 ret = wl1271_cmd_build_null_data(wl);
1110 if (ret < 0)
1111 goto out_sleep;
1112
1113 if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) {
1114 wl1271_info("psm enabled");
1115
1116 wl->psm_requested = true;
1117
1118 /*
1119 * We enter PSM only if we're already associated.
1120 * If we're not, we'll enter it when joining an SSID,
1121 * through the bss_info_changed() hook.
1122 */
1123 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
1124 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
1125 wl->psm_requested) {
1126 wl1271_info("psm disabled");
1127
1128 wl->psm_requested = false;
1129
1130 if (wl->psm)
1131 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE);
1132 }
1133
1134 if (conf->power_level != wl->power_level) {
1135 ret = wl1271_acx_tx_power(wl, conf->power_level);
1136 if (ret < 0)
1137 goto out;
1138
1139 wl->power_level = conf->power_level;
1140 }
1141
1142out_sleep:
1143 wl1271_ps_elp_sleep(wl);
1144
1145out:
1146 mutex_unlock(&wl->mutex);
1147
1148 return ret;
1149}
1150
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001151static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1152 struct dev_addr_list *mc_list)
1153{
1154 struct wl1271 *wl = hw->priv;
1155 struct wl1271_filter_params *fp;
1156 unsigned long flags;
1157 int i;
1158
1159 /*
1160 * FIXME: we should return a hash that will be passed to
1161 * configure_filter() instead of saving everything in the context.
1162 */
1163
Juuso Oikarinen74441132009-10-13 12:47:53 +03001164 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001165 if (!fp) {
1166 wl1271_error("Out of memory setting filters.");
1167 return 0;
1168 }
1169
1170 /* update multicast filtering parameters */
1171 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1172 mc_count = 0;
1173 fp->filters |= FIF_ALLMULTI;
1174 }
1175
1176 fp->mc_list_length = 0;
1177 for (i = 0; i < mc_count; i++) {
1178 if (mc_list->da_addrlen == ETH_ALEN) {
1179 memcpy(fp->mc_list[fp->mc_list_length],
1180 mc_list->da_addr, ETH_ALEN);
1181 fp->mc_list_length++;
1182 } else
1183 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001184 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001185 }
1186
Luciano Coelho0535d9f2009-10-12 15:08:56 +03001187 /* FIXME: We still need to set our filters properly */
1188
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001189 spin_lock_irqsave(&wl->wl_lock, flags);
1190 kfree(wl->filter_params);
1191 wl->filter_params = fp;
1192 spin_unlock_irqrestore(&wl->wl_lock, flags);
1193
1194 return 1;
1195}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001196
1197static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1198 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001199 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001200{
1201 struct wl1271 *wl = hw->priv;
1202
1203 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1204
1205 *total &= WL1271_SUPPORTED_FILTERS;
1206 changed &= WL1271_SUPPORTED_FILTERS;
1207
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001208 if (!multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001209 return;
1210
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001211 /*
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001212 * FIXME: for now we are still using a workqueue for filter
1213 * configuration, but with the new mac80211, this is not needed,
1214 * since configure_filter can now sleep. We now have
1215 * prepare_multicast, which needs to be atomic instead.
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001216 */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001217
1218 /* store current filter config */
1219 wl->filter_params->filters = *total;
1220 wl->filter_params->changed = changed;
1221
1222 ieee80211_queue_work(wl->hw, &wl->filter_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001223}
1224
1225static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1226 struct ieee80211_vif *vif,
1227 struct ieee80211_sta *sta,
1228 struct ieee80211_key_conf *key_conf)
1229{
1230 struct wl1271 *wl = hw->priv;
1231 const u8 *addr;
1232 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001233 u32 tx_seq_32 = 0;
1234 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001235 u8 key_type;
1236
1237 static const u8 bcast_addr[ETH_ALEN] =
1238 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1239
1240 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1241
1242 addr = sta ? sta->addr : bcast_addr;
1243
1244 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1245 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1246 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1247 key_conf->alg, key_conf->keyidx,
1248 key_conf->keylen, key_conf->flags);
1249 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1250
1251 if (is_zero_ether_addr(addr)) {
1252 /* We dont support TX only encryption */
1253 ret = -EOPNOTSUPP;
1254 goto out;
1255 }
1256
1257 mutex_lock(&wl->mutex);
1258
1259 ret = wl1271_ps_elp_wakeup(wl, false);
1260 if (ret < 0)
1261 goto out_unlock;
1262
1263 switch (key_conf->alg) {
1264 case ALG_WEP:
1265 key_type = KEY_WEP;
1266
1267 key_conf->hw_key_idx = key_conf->keyidx;
1268 break;
1269 case ALG_TKIP:
1270 key_type = KEY_TKIP;
1271
1272 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001273 tx_seq_32 = wl->tx_security_seq_32;
1274 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001275 break;
1276 case ALG_CCMP:
1277 key_type = KEY_AES;
1278
1279 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001280 tx_seq_32 = wl->tx_security_seq_32;
1281 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001282 break;
1283 default:
1284 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1285
1286 ret = -EOPNOTSUPP;
1287 goto out_sleep;
1288 }
1289
1290 switch (cmd) {
1291 case SET_KEY:
1292 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1293 key_conf->keyidx, key_type,
1294 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001295 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001296 if (ret < 0) {
1297 wl1271_error("Could not add or replace key");
1298 goto out_sleep;
1299 }
1300 break;
1301
1302 case DISABLE_KEY:
1303 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1304 key_conf->keyidx, key_type,
1305 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001306 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001307 if (ret < 0) {
1308 wl1271_error("Could not remove key");
1309 goto out_sleep;
1310 }
1311 break;
1312
1313 default:
1314 wl1271_error("Unsupported key cmd 0x%x", cmd);
1315 ret = -EOPNOTSUPP;
1316 goto out_sleep;
1317
1318 break;
1319 }
1320
1321out_sleep:
1322 wl1271_ps_elp_sleep(wl);
1323
1324out_unlock:
1325 mutex_unlock(&wl->mutex);
1326
1327out:
1328 return ret;
1329}
1330
1331static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1332 struct cfg80211_scan_request *req)
1333{
1334 struct wl1271 *wl = hw->priv;
1335 int ret;
1336 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001337 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001338
1339 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1340
1341 if (req->n_ssids) {
1342 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001343 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001344 }
1345
1346 mutex_lock(&wl->mutex);
1347
1348 ret = wl1271_ps_elp_wakeup(wl, false);
1349 if (ret < 0)
1350 goto out;
1351
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001352 if (wl1271_11a_enabled())
1353 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1354 WL1271_SCAN_BAND_DUAL, 3);
1355 else
1356 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1357 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001358
1359 wl1271_ps_elp_sleep(wl);
1360
1361out:
1362 mutex_unlock(&wl->mutex);
1363
1364 return ret;
1365}
1366
1367static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1368{
1369 struct wl1271 *wl = hw->priv;
1370 int ret;
1371
1372 mutex_lock(&wl->mutex);
1373
1374 ret = wl1271_ps_elp_wakeup(wl, false);
1375 if (ret < 0)
1376 goto out;
1377
1378 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1379 if (ret < 0)
1380 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1381
1382 wl1271_ps_elp_sleep(wl);
1383
1384out:
1385 mutex_unlock(&wl->mutex);
1386
1387 return ret;
1388}
1389
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001390static u32 wl1271_enabled_rates_get(struct wl1271 *wl, u64 basic_rate_set)
1391{
1392 struct ieee80211_supported_band *band;
1393 u32 enabled_rates = 0;
1394 int bit;
1395
1396 band = wl->hw->wiphy->bands[wl->band];
1397 for (bit = 0; bit < band->n_bitrates; bit++) {
1398 if (basic_rate_set & 0x1)
1399 enabled_rates |= band->bitrates[bit].hw_value;
1400 basic_rate_set >>= 1;
1401 }
1402
1403 return enabled_rates;
1404}
1405
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001406static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1407 struct ieee80211_vif *vif,
1408 struct ieee80211_bss_conf *bss_conf,
1409 u32 changed)
1410{
1411 enum wl1271_cmd_ps_mode mode;
1412 struct wl1271 *wl = hw->priv;
1413 int ret;
1414
1415 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1416
1417 mutex_lock(&wl->mutex);
1418
1419 ret = wl1271_ps_elp_wakeup(wl, false);
1420 if (ret < 0)
1421 goto out;
1422
1423 if (changed & BSS_CHANGED_ASSOC) {
1424 if (bss_conf->assoc) {
1425 wl->aid = bss_conf->aid;
1426
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001427 /*
1428 * with wl1271, we don't need to update the
1429 * beacon_int and dtim_period, because the firmware
1430 * updates it by itself when the first beacon is
1431 * received after a join.
1432 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001433 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1434 if (ret < 0)
1435 goto out_sleep;
1436
1437 ret = wl1271_acx_aid(wl, wl->aid);
1438 if (ret < 0)
1439 goto out_sleep;
1440
1441 /* If we want to go in PSM but we're not there yet */
1442 if (wl->psm_requested && !wl->psm) {
1443 mode = STATION_POWER_SAVE_MODE;
1444 ret = wl1271_ps_set_mode(wl, mode);
1445 if (ret < 0)
1446 goto out_sleep;
1447 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001448 } else {
1449 /* use defaults when not associated */
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001450 wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
1451 wl->aid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001452 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001453
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001454 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001455
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001456 if (changed & BSS_CHANGED_ERP_SLOT) {
1457 if (bss_conf->use_short_slot)
1458 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1459 else
1460 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1461 if (ret < 0) {
1462 wl1271_warning("Set slot time failed %d", ret);
1463 goto out_sleep;
1464 }
1465 }
1466
1467 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1468 if (bss_conf->use_short_preamble)
1469 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1470 else
1471 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1472 }
1473
1474 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1475 if (bss_conf->use_cts_prot)
1476 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1477 else
1478 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1479 if (ret < 0) {
1480 wl1271_warning("Set ctsprotect failed %d", ret);
1481 goto out_sleep;
1482 }
1483 }
1484
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001485 if (changed & BSS_CHANGED_BASIC_RATES) {
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001486 wl->basic_rate_set = wl1271_enabled_rates_get(
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001487 wl, bss_conf->basic_rates);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001488
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001489 ret = wl1271_acx_rate_policies(wl, wl->basic_rate_set);
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001490 if (ret < 0) {
1491 wl1271_warning("Set rate policies failed %d", ret);
1492 goto out_sleep;
1493 }
1494 }
1495
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001496out_sleep:
1497 wl1271_ps_elp_sleep(wl);
1498
1499out:
1500 mutex_unlock(&wl->mutex);
1501}
1502
1503
1504/* can't be const, mac80211 writes to this */
1505static struct ieee80211_rate wl1271_rates[] = {
1506 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001507 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1508 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001509 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001510 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1511 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001512 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1513 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001514 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1515 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001516 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1517 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001518 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1519 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001520 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1521 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001522 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1523 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001524 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001525 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1526 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001527 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001528 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1529 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001530 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001531 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1532 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001533 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001534 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1535 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001536 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001537 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1538 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001539 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001540 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1541 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001542 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001543 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1544 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001545};
1546
1547/* can't be const, mac80211 writes to this */
1548static struct ieee80211_channel wl1271_channels[] = {
1549 { .hw_value = 1, .center_freq = 2412},
1550 { .hw_value = 2, .center_freq = 2417},
1551 { .hw_value = 3, .center_freq = 2422},
1552 { .hw_value = 4, .center_freq = 2427},
1553 { .hw_value = 5, .center_freq = 2432},
1554 { .hw_value = 6, .center_freq = 2437},
1555 { .hw_value = 7, .center_freq = 2442},
1556 { .hw_value = 8, .center_freq = 2447},
1557 { .hw_value = 9, .center_freq = 2452},
1558 { .hw_value = 10, .center_freq = 2457},
1559 { .hw_value = 11, .center_freq = 2462},
1560 { .hw_value = 12, .center_freq = 2467},
1561 { .hw_value = 13, .center_freq = 2472},
1562};
1563
1564/* can't be const, mac80211 writes to this */
1565static struct ieee80211_supported_band wl1271_band_2ghz = {
1566 .channels = wl1271_channels,
1567 .n_channels = ARRAY_SIZE(wl1271_channels),
1568 .bitrates = wl1271_rates,
1569 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1570};
1571
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001572/* 5 GHz data rates for WL1273 */
1573static struct ieee80211_rate wl1271_rates_5ghz[] = {
1574 { .bitrate = 60,
1575 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1576 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
1577 { .bitrate = 90,
1578 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1579 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
1580 { .bitrate = 120,
1581 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1582 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
1583 { .bitrate = 180,
1584 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1585 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
1586 { .bitrate = 240,
1587 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1588 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
1589 { .bitrate = 360,
1590 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1591 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
1592 { .bitrate = 480,
1593 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1594 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
1595 { .bitrate = 540,
1596 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1597 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
1598};
1599
1600/* 5 GHz band channels for WL1273 */
1601static struct ieee80211_channel wl1271_channels_5ghz[] = {
1602 { .hw_value = 183, .center_freq = 4915},
1603 { .hw_value = 184, .center_freq = 4920},
1604 { .hw_value = 185, .center_freq = 4925},
1605 { .hw_value = 187, .center_freq = 4935},
1606 { .hw_value = 188, .center_freq = 4940},
1607 { .hw_value = 189, .center_freq = 4945},
1608 { .hw_value = 192, .center_freq = 4960},
1609 { .hw_value = 196, .center_freq = 4980},
1610 { .hw_value = 7, .center_freq = 5035},
1611 { .hw_value = 8, .center_freq = 5040},
1612 { .hw_value = 9, .center_freq = 5045},
1613 { .hw_value = 11, .center_freq = 5055},
1614 { .hw_value = 12, .center_freq = 5060},
1615 { .hw_value = 16, .center_freq = 5080},
1616 { .hw_value = 34, .center_freq = 5170},
1617 { .hw_value = 36, .center_freq = 5180},
1618 { .hw_value = 38, .center_freq = 5190},
1619 { .hw_value = 40, .center_freq = 5200},
1620 { .hw_value = 42, .center_freq = 5210},
1621 { .hw_value = 44, .center_freq = 5220},
1622 { .hw_value = 46, .center_freq = 5230},
1623 { .hw_value = 48, .center_freq = 5240},
1624 { .hw_value = 52, .center_freq = 5260},
1625 { .hw_value = 56, .center_freq = 5280},
1626 { .hw_value = 60, .center_freq = 5300},
1627 { .hw_value = 64, .center_freq = 5320},
1628 { .hw_value = 100, .center_freq = 5500},
1629 { .hw_value = 104, .center_freq = 5520},
1630 { .hw_value = 108, .center_freq = 5540},
1631 { .hw_value = 112, .center_freq = 5560},
1632 { .hw_value = 116, .center_freq = 5580},
1633 { .hw_value = 120, .center_freq = 5600},
1634 { .hw_value = 124, .center_freq = 5620},
1635 { .hw_value = 128, .center_freq = 5640},
1636 { .hw_value = 132, .center_freq = 5660},
1637 { .hw_value = 136, .center_freq = 5680},
1638 { .hw_value = 140, .center_freq = 5700},
1639 { .hw_value = 149, .center_freq = 5745},
1640 { .hw_value = 153, .center_freq = 5765},
1641 { .hw_value = 157, .center_freq = 5785},
1642 { .hw_value = 161, .center_freq = 5805},
1643 { .hw_value = 165, .center_freq = 5825},
1644};
1645
1646
1647static struct ieee80211_supported_band wl1271_band_5ghz = {
1648 .channels = wl1271_channels_5ghz,
1649 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
1650 .bitrates = wl1271_rates_5ghz,
1651 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
1652};
1653
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001654static const struct ieee80211_ops wl1271_ops = {
1655 .start = wl1271_op_start,
1656 .stop = wl1271_op_stop,
1657 .add_interface = wl1271_op_add_interface,
1658 .remove_interface = wl1271_op_remove_interface,
1659 .config = wl1271_op_config,
1660/* .config_interface = wl1271_op_config_interface, */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001661 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001662 .configure_filter = wl1271_op_configure_filter,
1663 .tx = wl1271_op_tx,
1664 .set_key = wl1271_op_set_key,
1665 .hw_scan = wl1271_op_hw_scan,
1666 .bss_info_changed = wl1271_op_bss_info_changed,
1667 .set_rts_threshold = wl1271_op_set_rts_threshold,
1668};
1669
1670static int wl1271_register_hw(struct wl1271 *wl)
1671{
1672 int ret;
1673
1674 if (wl->mac80211_registered)
1675 return 0;
1676
1677 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
1678
1679 ret = ieee80211_register_hw(wl->hw);
1680 if (ret < 0) {
1681 wl1271_error("unable to register mac80211 hw: %d", ret);
1682 return ret;
1683 }
1684
1685 wl->mac80211_registered = true;
1686
1687 wl1271_notice("loaded");
1688
1689 return 0;
1690}
1691
1692static int wl1271_init_ieee80211(struct wl1271 *wl)
1693{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03001694 /* The tx descriptor buffer and the TKIP space. */
1695 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
1696 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001697
1698 /* unit us */
1699 /* FIXME: find a proper value */
1700 wl->hw->channel_change_time = 10000;
1701
1702 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03001703 IEEE80211_HW_NOISE_DBM |
1704 IEEE80211_HW_BEACON_FILTER;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001705
1706 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
1707 wl->hw->wiphy->max_scan_ssids = 1;
1708 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
1709
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001710 if (wl1271_11a_enabled())
1711 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
1712
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001713 SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
1714
1715 return 0;
1716}
1717
1718static void wl1271_device_release(struct device *dev)
1719{
1720
1721}
1722
1723static struct platform_device wl1271_device = {
1724 .name = "wl1271",
1725 .id = -1,
1726
1727 /* device model insists to have a release function */
1728 .dev = {
1729 .release = wl1271_device_release,
1730 },
1731};
1732
1733#define WL1271_DEFAULT_CHANNEL 0
1734static int __devinit wl1271_probe(struct spi_device *spi)
1735{
1736 struct wl12xx_platform_data *pdata;
1737 struct ieee80211_hw *hw;
1738 struct wl1271 *wl;
1739 int ret, i;
1740 static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
1741
1742 pdata = spi->dev.platform_data;
1743 if (!pdata) {
1744 wl1271_error("no platform data");
1745 return -ENODEV;
1746 }
1747
1748 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
1749 if (!hw) {
1750 wl1271_error("could not alloc ieee80211_hw");
1751 return -ENOMEM;
1752 }
1753
1754 wl = hw->priv;
1755 memset(wl, 0, sizeof(*wl));
1756
1757 wl->hw = hw;
1758 dev_set_drvdata(&spi->dev, wl);
1759 wl->spi = spi;
1760
1761 skb_queue_head_init(&wl->tx_queue);
1762
1763 INIT_WORK(&wl->filter_work, wl1271_filter_work);
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03001764 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001765 wl->channel = WL1271_DEFAULT_CHANNEL;
1766 wl->scanning = false;
1767 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001768 wl->rx_counter = 0;
1769 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1770 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1771 wl->elp = false;
1772 wl->psm = 0;
1773 wl->psm_requested = false;
1774 wl->tx_queue_stopped = false;
1775 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001776 wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001777 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001778 wl->vif = NULL;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001779 wl->joined = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001780
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03001781 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001782 wl->tx_frames[i] = NULL;
1783
1784 spin_lock_init(&wl->wl_lock);
1785
1786 /*
1787 * In case our MAC address is not correctly set,
1788 * we use a random but Nokia MAC.
1789 */
1790 memcpy(wl->mac_addr, nokia_oui, 3);
1791 get_random_bytes(wl->mac_addr + 3, 3);
1792
1793 wl->state = WL1271_STATE_OFF;
1794 mutex_init(&wl->mutex);
1795
1796 wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL);
1797 if (!wl->rx_descriptor) {
1798 wl1271_error("could not allocate memory for rx descriptor");
1799 ret = -ENOMEM;
1800 goto out_free;
1801 }
1802
1803 /* This is the only SPI value that we need to set here, the rest
1804 * comes from the board-peripherals file */
1805 spi->bits_per_word = 32;
1806
1807 ret = spi_setup(spi);
1808 if (ret < 0) {
1809 wl1271_error("spi_setup failed");
1810 goto out_free;
1811 }
1812
1813 wl->set_power = pdata->set_power;
1814 if (!wl->set_power) {
1815 wl1271_error("set power function missing in platform data");
1816 ret = -ENODEV;
1817 goto out_free;
1818 }
1819
1820 wl->irq = spi->irq;
1821 if (wl->irq < 0) {
1822 wl1271_error("irq missing in platform data");
1823 ret = -ENODEV;
1824 goto out_free;
1825 }
1826
1827 ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
1828 if (ret < 0) {
1829 wl1271_error("request_irq() failed: %d", ret);
1830 goto out_free;
1831 }
1832
1833 set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
1834
1835 disable_irq(wl->irq);
1836
1837 ret = platform_device_register(&wl1271_device);
1838 if (ret) {
1839 wl1271_error("couldn't register platform device");
1840 goto out_irq;
1841 }
1842 dev_set_drvdata(&wl1271_device.dev, wl);
1843
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001844 /* Apply default driver configuration. */
1845 wl1271_conf_init(wl);
1846
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001847 ret = wl1271_init_ieee80211(wl);
1848 if (ret)
1849 goto out_platform;
1850
1851 ret = wl1271_register_hw(wl);
1852 if (ret)
1853 goto out_platform;
1854
1855 wl1271_debugfs_init(wl);
1856
1857 wl1271_notice("initialized");
1858
1859 return 0;
1860
1861 out_platform:
1862 platform_device_unregister(&wl1271_device);
1863
1864 out_irq:
1865 free_irq(wl->irq, wl);
1866
1867 out_free:
1868 kfree(wl->rx_descriptor);
1869 wl->rx_descriptor = NULL;
1870
1871 ieee80211_free_hw(hw);
1872
1873 return ret;
1874}
1875
1876static int __devexit wl1271_remove(struct spi_device *spi)
1877{
1878 struct wl1271 *wl = dev_get_drvdata(&spi->dev);
1879
1880 ieee80211_unregister_hw(wl->hw);
1881
1882 wl1271_debugfs_exit(wl);
1883 platform_device_unregister(&wl1271_device);
1884 free_irq(wl->irq, wl);
1885 kfree(wl->target_mem_map);
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001886 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001887 wl->fw = NULL;
1888 kfree(wl->nvs);
1889 wl->nvs = NULL;
1890
1891 kfree(wl->rx_descriptor);
1892 wl->rx_descriptor = NULL;
1893
1894 kfree(wl->fw_status);
1895 kfree(wl->tx_res_if);
1896
1897 ieee80211_free_hw(wl->hw);
1898
1899 return 0;
1900}
1901
1902
1903static struct spi_driver wl1271_spi_driver = {
1904 .driver = {
1905 .name = "wl1271",
1906 .bus = &spi_bus_type,
1907 .owner = THIS_MODULE,
1908 },
1909
1910 .probe = wl1271_probe,
1911 .remove = __devexit_p(wl1271_remove),
1912};
1913
1914static int __init wl1271_init(void)
1915{
1916 int ret;
1917
1918 ret = spi_register_driver(&wl1271_spi_driver);
1919 if (ret < 0) {
1920 wl1271_error("failed to register spi driver: %d", ret);
1921 goto out;
1922 }
1923
1924out:
1925 return ret;
1926}
1927
1928static void __exit wl1271_exit(void)
1929{
1930 spi_unregister_driver(&wl1271_spi_driver);
1931
1932 wl1271_notice("unloaded");
1933}
1934
1935module_init(wl1271_init);
1936module_exit(wl1271_exit);
1937
1938MODULE_LICENSE("GPL");
1939MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
Luciano Coelho2f018722009-10-08 21:56:27 +03001940MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");