blob: dfa08a1886320ddabc23f0e8d4fe8f2272235f17 [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,
225 .bet_max_consecutive = 100
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300226 },
227 .init = {
228 .sr_err_tbl = {
229 [0] = {
230 .len = 7,
231 .upper_limit = 0x03,
232 .values = {
233 0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8,
234 0x00 }
235 },
236 [1] = {
237 .len = 7,
238 .upper_limit = 0x03,
239 .values = {
240 0x18, 0x10, 0x05, 0xf6, 0xf0, 0xe8,
241 0x00 }
242 },
243 [2] = {
244 .len = 7,
245 .upper_limit = 0x03,
246 .values = {
247 0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8,
248 0x00 }
249 }
250 },
251 .sr_enable = 1,
252 .genparam = {
253 /*
254 * FIXME: The correct value CONF_REF_CLK_38_4_E
255 * causes the firmware to crash on boot.
256 * The value 5 apparently is an
257 * unnoficial XTAL configuration of the
258 * same frequency, which appears to work.
259 */
260 .ref_clk = 5,
261 .settling_time = 5,
262 .clk_valid_on_wakeup = 0,
263 .dc2dcmode = 0,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300264 .single_dual_band = CONF_SINGLE_BAND,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300265 .tx_bip_fem_autodetect = 0,
266 .tx_bip_fem_manufacturer = 1,
267 .settings = 1,
268 },
269 .radioparam = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300270 .rx_trace_loss = 10,
271 .tx_trace_loss = 10,
272 .rx_rssi_and_proc_compens = {
273 0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8,
274 0xfc, 0x00, 0x08, 0x10, 0xf0, 0xf8,
275 0x00, 0x0a, 0x14 },
276 .rx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 },
277 .tx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 },
278 .rx_rssi_and_proc_compens_5 = {
279 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
280 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
281 0x00, 0x00, 0x00 },
282 .tx_ref_pd_voltage = 0x24e,
283 .tx_ref_power = 0x78,
284 .tx_offset_db = 0x0,
285 .tx_rate_limits_normal = {
286 0x1e, 0x1f, 0x22, 0x24, 0x28, 0x29 },
287 .tx_rate_limits_degraded = {
288 0x1b, 0x1c, 0x1e, 0x20, 0x24, 0x25 },
289 .tx_channel_limits_11b = {
290 0x22, 0x50, 0x50, 0x50, 0x50, 0x50,
291 0x50, 0x50, 0x50, 0x50, 0x22, 0x50,
292 0x22, 0x50 },
293 .tx_channel_limits_ofdm = {
294 0x20, 0x50, 0x50, 0x50, 0x50, 0x50,
295 0x50, 0x50, 0x50, 0x50, 0x20, 0x50,
296 0x20, 0x50 },
297 .tx_pdv_rate_offsets = {
298 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
299 .tx_ibias = {
300 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x27 },
301 .rx_fem_insertion_loss = 0x14,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300302 .tx_ref_pd_voltage_5 = {
303 0x0190, 0x01a4, 0x01c3, 0x01d8,
304 0x020a, 0x021c },
305 .tx_ref_power_5 = {
306 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 },
307 .tx_offset_db_5 = {
308 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300309 .tx_rate_limits_normal_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300310 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300311 .tx_rate_limits_degraded_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300312 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300313 .tx_channel_limits_ofdm_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300314 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, 0x50, 0x50, 0x50, 0x50, 0x50,
318 0x50, 0x50, 0x50 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300319 .tx_pdv_rate_offsets_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300320 0x01, 0x02, 0x02, 0x02, 0x02, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300321 .tx_ibias_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300322 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
323 .rx_fem_insertion_loss_5 = {
324 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300325 }
326 }
327};
328
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300329static LIST_HEAD(wl_list);
330
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300331static void wl1271_conf_init(struct wl1271 *wl)
332{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300333
334 /*
335 * This function applies the default configuration to the driver. This
336 * function is invoked upon driver load (spi probe.)
337 *
338 * The configuration is stored in a run-time structure in order to
339 * facilitate for run-time adjustment of any of the parameters. Making
340 * changes to the configuration structure will apply the new values on
341 * the next interface up (wl1271_op_start.)
342 */
343
344 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300345 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300346
347 if (wl1271_11a_enabled())
348 wl->conf.init.genparam.single_dual_band = CONF_DUAL_BAND;
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300349}
350
351
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300352static int wl1271_plt_init(struct wl1271 *wl)
353{
354 int ret;
355
356 ret = wl1271_acx_init_mem_config(wl);
357 if (ret < 0)
358 return ret;
359
360 ret = wl1271_cmd_data_path(wl, wl->channel, 1);
361 if (ret < 0)
362 return ret;
363
364 return 0;
365}
366
367static void wl1271_disable_interrupts(struct wl1271 *wl)
368{
369 disable_irq(wl->irq);
370}
371
372static void wl1271_power_off(struct wl1271 *wl)
373{
374 wl->set_power(false);
375}
376
377static void wl1271_power_on(struct wl1271 *wl)
378{
379 wl->set_power(true);
380}
381
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300382static void wl1271_fw_status(struct wl1271 *wl,
383 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300384{
385 u32 total = 0;
386 int i;
387
Juuso Oikarinen74621412009-10-12 15:08:54 +0300388 wl1271_spi_read(wl, FW_STATUS_ADDR, status,
389 sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300390
391 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
392 "drv_rx_counter = %d, tx_results_counter = %d)",
393 status->intr,
394 status->fw_rx_counter,
395 status->drv_rx_counter,
396 status->tx_results_counter);
397
398 /* update number of available TX blocks */
399 for (i = 0; i < NUM_TX_QUEUES; i++) {
400 u32 cnt = status->tx_released_blks[i] - wl->tx_blocks_freed[i];
401 wl->tx_blocks_freed[i] = status->tx_released_blks[i];
402 wl->tx_blocks_available += cnt;
403 total += cnt;
404 }
405
406 /* if more blocks are available now, schedule some tx work */
407 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300408 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300409
410 /* update the host-chipset time offset */
411 wl->time_offset = jiffies_to_usecs(jiffies) - status->fw_localtime;
412}
413
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300414static void wl1271_irq_work(struct work_struct *work)
415{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300416 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300417 u32 intr;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300418 struct wl1271 *wl =
419 container_of(work, struct wl1271, irq_work);
420
421 mutex_lock(&wl->mutex);
422
423 wl1271_debug(DEBUG_IRQ, "IRQ work");
424
425 if (wl->state == WL1271_STATE_OFF)
426 goto out;
427
428 ret = wl1271_ps_elp_wakeup(wl, true);
429 if (ret < 0)
430 goto out;
431
Juuso Oikarinen74621412009-10-12 15:08:54 +0300432 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300433
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300434 wl1271_fw_status(wl, wl->fw_status);
435 intr = wl->fw_status->intr;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300436 if (!intr) {
437 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
438 goto out_sleep;
439 }
440
441 intr &= WL1271_INTR_MASK;
442
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300443 if (intr & WL1271_ACX_INTR_EVENT_A) {
444 bool do_ack = (intr & WL1271_ACX_INTR_EVENT_B) ? false : true;
445 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
446 wl1271_event_handle(wl, 0, do_ack);
447 }
448
449 if (intr & WL1271_ACX_INTR_EVENT_B) {
450 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
451 wl1271_event_handle(wl, 1, true);
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300452 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300453
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300454 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
455 wl1271_debug(DEBUG_IRQ,
456 "WL1271_ACX_INTR_INIT_COMPLETE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300457
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300458 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
459 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300460
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300461 if (intr & WL1271_ACX_INTR_DATA) {
462 u8 tx_res_cnt = wl->fw_status->tx_results_counter -
463 wl->tx_results_count;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300464
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300465 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300466
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300467 /* check for tx results */
468 if (tx_res_cnt)
469 wl1271_tx_complete(wl, tx_res_cnt);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300470
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300471 wl1271_rx(wl, wl->fw_status);
472 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300473
474out_sleep:
Juuso Oikarinen74621412009-10-12 15:08:54 +0300475 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
Luciano Coelho73d0a132009-08-11 11:58:27 +0300476 WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300477 wl1271_ps_elp_sleep(wl);
478
479out:
480 mutex_unlock(&wl->mutex);
481}
482
483static irqreturn_t wl1271_irq(int irq, void *cookie)
484{
485 struct wl1271 *wl;
486 unsigned long flags;
487
488 wl1271_debug(DEBUG_IRQ, "IRQ");
489
490 wl = cookie;
491
492 /* complete the ELP completion */
493 spin_lock_irqsave(&wl->wl_lock, flags);
494 if (wl->elp_compl) {
495 complete(wl->elp_compl);
496 wl->elp_compl = NULL;
497 }
498
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300499 ieee80211_queue_work(wl->hw, &wl->irq_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300500 spin_unlock_irqrestore(&wl->wl_lock, flags);
501
502 return IRQ_HANDLED;
503}
504
505static int wl1271_fetch_firmware(struct wl1271 *wl)
506{
507 const struct firmware *fw;
508 int ret;
509
510 ret = request_firmware(&fw, WL1271_FW_NAME, &wl->spi->dev);
511
512 if (ret < 0) {
513 wl1271_error("could not get firmware: %d", ret);
514 return ret;
515 }
516
517 if (fw->size % 4) {
518 wl1271_error("firmware size is not multiple of 32 bits: %zu",
519 fw->size);
520 ret = -EILSEQ;
521 goto out;
522 }
523
524 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300525 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300526
527 if (!wl->fw) {
528 wl1271_error("could not allocate memory for the firmware");
529 ret = -ENOMEM;
530 goto out;
531 }
532
533 memcpy(wl->fw, fw->data, wl->fw_len);
534
535 ret = 0;
536
537out:
538 release_firmware(fw);
539
540 return ret;
541}
542
543static int wl1271_fetch_nvs(struct wl1271 *wl)
544{
545 const struct firmware *fw;
546 int ret;
547
548 ret = request_firmware(&fw, WL1271_NVS_NAME, &wl->spi->dev);
549
550 if (ret < 0) {
551 wl1271_error("could not get nvs file: %d", ret);
552 return ret;
553 }
554
555 if (fw->size % 4) {
556 wl1271_error("nvs size is not multiple of 32 bits: %zu",
557 fw->size);
558 ret = -EILSEQ;
559 goto out;
560 }
561
562 wl->nvs_len = fw->size;
563 wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL);
564
565 if (!wl->nvs) {
566 wl1271_error("could not allocate memory for the nvs file");
567 ret = -ENOMEM;
568 goto out;
569 }
570
571 memcpy(wl->nvs, fw->data, wl->nvs_len);
572
573 ret = 0;
574
575out:
576 release_firmware(fw);
577
578 return ret;
579}
580
581static void wl1271_fw_wakeup(struct wl1271 *wl)
582{
583 u32 elp_reg;
584
585 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300586 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300587}
588
589static int wl1271_setup(struct wl1271 *wl)
590{
591 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
592 if (!wl->fw_status)
593 return -ENOMEM;
594
595 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
596 if (!wl->tx_res_if) {
597 kfree(wl->fw_status);
598 return -ENOMEM;
599 }
600
601 INIT_WORK(&wl->irq_work, wl1271_irq_work);
602 INIT_WORK(&wl->tx_work, wl1271_tx_work);
603 return 0;
604}
605
606static int wl1271_chip_wakeup(struct wl1271 *wl)
607{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300608 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300609 int ret = 0;
610
611 wl1271_power_on(wl);
612 msleep(WL1271_POWER_ON_SLEEP);
613 wl1271_spi_reset(wl);
614 wl1271_spi_init(wl);
615
616 /* We don't need a real memory partition here, because we only want
617 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300618 memset(&partition, 0, sizeof(partition));
619 partition.reg.start = REGISTERS_BASE;
620 partition.reg.size = REGISTERS_DOWN_SIZE;
621 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300622
623 /* ELP module wake up */
624 wl1271_fw_wakeup(wl);
625
626 /* whal_FwCtrl_BootSm() */
627
628 /* 0. read chip id from CHIP_ID */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300629 wl->chip.id = wl1271_spi_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300630
631 /* 1. check if chip id is valid */
632
633 switch (wl->chip.id) {
634 case CHIP_ID_1271_PG10:
635 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
636 wl->chip.id);
637
638 ret = wl1271_setup(wl);
639 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300640 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300641 break;
642 case CHIP_ID_1271_PG20:
643 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
644 wl->chip.id);
645
646 ret = wl1271_setup(wl);
647 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300648 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300649 break;
650 default:
651 wl1271_error("unsupported chip id: 0x%x", wl->chip.id);
652 ret = -ENODEV;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300653 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300654 }
655
656 if (wl->fw == NULL) {
657 ret = wl1271_fetch_firmware(wl);
658 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300659 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300660 }
661
662 /* No NVS from netlink, try to get it from the filesystem */
663 if (wl->nvs == NULL) {
664 ret = wl1271_fetch_nvs(wl);
665 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300666 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300667 }
668
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300669 goto out;
670
671out_power_off:
672 wl1271_power_off(wl);
673
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300674out:
675 return ret;
676}
677
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300678struct wl1271_filter_params {
679 unsigned int filters;
680 unsigned int changed;
681 int mc_list_length;
682 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
683};
684
685#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
686 FIF_ALLMULTI | \
687 FIF_FCSFAIL | \
688 FIF_BCN_PRBRESP_PROMISC | \
689 FIF_CONTROL | \
690 FIF_OTHER_BSS)
691
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300692static void wl1271_filter_work(struct work_struct *work)
693{
694 struct wl1271 *wl =
695 container_of(work, struct wl1271, filter_work);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300696 struct wl1271_filter_params *fp;
697 unsigned long flags;
698 bool enabled = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300699 int ret;
700
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300701 /* first, get the filter parameters */
702 spin_lock_irqsave(&wl->wl_lock, flags);
703 fp = wl->filter_params;
704 wl->filter_params = NULL;
705 spin_unlock_irqrestore(&wl->wl_lock, flags);
706
707 if (!fp)
708 return;
709
710 /* then, lock the mutex without risk of lock-up */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300711 mutex_lock(&wl->mutex);
712
713 if (wl->state == WL1271_STATE_OFF)
714 goto out;
715
716 ret = wl1271_ps_elp_wakeup(wl, false);
717 if (ret < 0)
718 goto out;
719
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300720 /* configure the mc filter regardless of the changed flags */
721 if (fp->filters & FIF_ALLMULTI)
722 enabled = false;
723
724 ret = wl1271_acx_group_address_tbl(wl, enabled,
725 fp->mc_list, fp->mc_list_length);
726 if (ret < 0)
727 goto out_sleep;
728
729 /* determine, whether supported filter values have changed */
730 if (fp->changed == 0)
731 goto out;
732
733 /* apply configured filters */
Luciano Coelho0535d9f2009-10-12 15:08:56 +0300734 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300735 if (ret < 0)
736 goto out_sleep;
737
738out_sleep:
739 wl1271_ps_elp_sleep(wl);
740
741out:
742 mutex_unlock(&wl->mutex);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300743 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300744}
745
746int wl1271_plt_start(struct wl1271 *wl)
747{
748 int ret;
749
750 mutex_lock(&wl->mutex);
751
752 wl1271_notice("power up");
753
754 if (wl->state != WL1271_STATE_OFF) {
755 wl1271_error("cannot go into PLT state because not "
756 "in off state: %d", wl->state);
757 ret = -EBUSY;
758 goto out;
759 }
760
761 wl->state = WL1271_STATE_PLT;
762
763 ret = wl1271_chip_wakeup(wl);
764 if (ret < 0)
765 goto out;
766
767 ret = wl1271_boot(wl);
768 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300769 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300770
771 wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver);
772
773 ret = wl1271_plt_init(wl);
774 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300775 goto out_irq_disable;
776
777 goto out;
778
779out_irq_disable:
780 wl1271_disable_interrupts(wl);
781
782out_power_off:
783 wl1271_power_off(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300784
785out:
786 mutex_unlock(&wl->mutex);
787
788 return ret;
789}
790
791int wl1271_plt_stop(struct wl1271 *wl)
792{
793 int ret = 0;
794
795 mutex_lock(&wl->mutex);
796
797 wl1271_notice("power down");
798
799 if (wl->state != WL1271_STATE_PLT) {
800 wl1271_error("cannot power down because not in PLT "
801 "state: %d", wl->state);
802 ret = -EBUSY;
803 goto out;
804 }
805
806 wl1271_disable_interrupts(wl);
807 wl1271_power_off(wl);
808
809 wl->state = WL1271_STATE_OFF;
810
811out:
812 mutex_unlock(&wl->mutex);
813
814 return ret;
815}
816
817
818static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
819{
820 struct wl1271 *wl = hw->priv;
821
822 skb_queue_tail(&wl->tx_queue, skb);
823
824 /*
825 * The chip specific setup must run before the first TX packet -
826 * before that, the tx_work will not be initialized!
827 */
828
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300829 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300830
831 /*
832 * The workqueue is slow to process the tx_queue and we need stop
833 * the queue here, otherwise the queue will get too long.
834 */
835 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) {
836 ieee80211_stop_queues(wl->hw);
837
838 /*
839 * FIXME: this is racy, the variable is not properly
840 * protected. Maybe fix this by removing the stupid
841 * variable altogether and checking the real queue state?
842 */
843 wl->tx_queue_stopped = true;
844 }
845
846 return NETDEV_TX_OK;
847}
848
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300849static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
850 void *arg)
851{
852 struct net_device *dev;
853 struct wireless_dev *wdev;
854 struct wiphy *wiphy;
855 struct ieee80211_hw *hw;
856 struct wl1271 *wl;
857 struct wl1271 *wl_temp;
858 struct in_device *idev;
859 struct in_ifaddr *ifa = arg;
860 int ret = 0;
861
862 /* FIXME: this ugly function should probably be implemented in the
863 * mac80211, and here should only be a simple callback handling actual
864 * setting of the filters. Now we need to dig up references to
865 * various structures to gain access to what we need.
866 * Also, because of this, there is no "initial" setting of the filter
867 * in "op_start", because we don't want to dig up struct net_device
868 * there - the filter will be set upon first change of the interface
869 * IP address. */
870
871 dev = ifa->ifa_dev->dev;
872
873 wdev = dev->ieee80211_ptr;
874 if (wdev == NULL)
875 return -ENODEV;
876
877 wiphy = wdev->wiphy;
878 if (wiphy == NULL)
879 return -ENODEV;
880
881 hw = wiphy_priv(wiphy);
882 if (hw == NULL)
883 return -ENODEV;
884
885 /* Check that the interface is one supported by this driver. */
886 wl_temp = hw->priv;
887 list_for_each_entry(wl, &wl_list, list) {
888 if (wl == wl_temp)
889 break;
890 }
891 if (wl == NULL)
892 return -ENODEV;
893
894 /* Get the interface IP address for the device. "ifa" will become
895 NULL if:
896 - there is no IPV4 protocol address configured
897 - there are multiple (virtual) IPV4 addresses configured
898 When "ifa" is NULL, filtering will be disabled.
899 */
900 ifa = NULL;
901 idev = dev->ip_ptr;
902 if (idev)
903 ifa = idev->ifa_list;
904
905 if (ifa && ifa->ifa_next)
906 ifa = NULL;
907
908 mutex_lock(&wl->mutex);
909
910 if (wl->state == WL1271_STATE_OFF)
911 goto out;
912
913 ret = wl1271_ps_elp_wakeup(wl, false);
914 if (ret < 0)
915 goto out;
916 if (ifa)
917 ret = wl1271_acx_arp_ip_filter(wl, true,
918 (u8 *)&ifa->ifa_address,
919 ACX_IPV4_VERSION);
920 else
921 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
922 ACX_IPV4_VERSION);
923 wl1271_ps_elp_sleep(wl);
924
925out:
926 mutex_unlock(&wl->mutex);
927
928 return ret;
929}
930
931static struct notifier_block wl1271_dev_notifier = {
932 .notifier_call = wl1271_dev_notify,
933};
934
935
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300936static int wl1271_op_start(struct ieee80211_hw *hw)
937{
938 struct wl1271 *wl = hw->priv;
939 int ret = 0;
940
941 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
942
943 mutex_lock(&wl->mutex);
944
945 if (wl->state != WL1271_STATE_OFF) {
946 wl1271_error("cannot start because not in off state: %d",
947 wl->state);
948 ret = -EBUSY;
949 goto out;
950 }
951
952 ret = wl1271_chip_wakeup(wl);
953 if (ret < 0)
954 goto out;
955
956 ret = wl1271_boot(wl);
957 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300958 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300959
960 ret = wl1271_hw_init(wl);
961 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300962 goto out_irq_disable;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300963
964 wl->state = WL1271_STATE_ON;
965
966 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
967
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300968 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300969
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300970out_irq_disable:
971 wl1271_disable_interrupts(wl);
972
973out_power_off:
974 wl1271_power_off(wl);
975
976out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300977 mutex_unlock(&wl->mutex);
978
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300979 if (!ret) {
980 list_add(&wl->list, &wl_list);
981 register_inetaddr_notifier(&wl1271_dev_notifier);
982 }
983
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300984 return ret;
985}
986
987static void wl1271_op_stop(struct ieee80211_hw *hw)
988{
989 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300990 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300991 int i;
992
993 wl1271_info("down");
994
995 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
996
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300997 /* complete/cancel ongoing work */
998 cancel_work_sync(&wl->filter_work);
999 spin_lock_irqsave(&wl->wl_lock, flags);
1000 kfree(wl->filter_params);
1001 wl->filter_params = NULL;
1002 spin_unlock_irqrestore(&wl->wl_lock, flags);
1003
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001004 unregister_inetaddr_notifier(&wl1271_dev_notifier);
1005 list_del(&wl->list);
1006
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001007 mutex_lock(&wl->mutex);
1008
1009 WARN_ON(wl->state != WL1271_STATE_ON);
1010
1011 if (wl->scanning) {
1012 mutex_unlock(&wl->mutex);
1013 ieee80211_scan_completed(wl->hw, true);
1014 mutex_lock(&wl->mutex);
1015 wl->scanning = false;
1016 }
1017
1018 wl->state = WL1271_STATE_OFF;
1019
1020 wl1271_disable_interrupts(wl);
1021
1022 mutex_unlock(&wl->mutex);
1023
1024 cancel_work_sync(&wl->irq_work);
1025 cancel_work_sync(&wl->tx_work);
1026 cancel_work_sync(&wl->filter_work);
1027
1028 mutex_lock(&wl->mutex);
1029
1030 /* let's notify MAC80211 about the remaining pending TX frames */
1031 wl1271_tx_flush(wl);
1032 wl1271_power_off(wl);
1033
1034 memset(wl->bssid, 0, ETH_ALEN);
1035 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1036 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001037 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001038 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001039
1040 wl->rx_counter = 0;
1041 wl->elp = false;
1042 wl->psm = 0;
1043 wl->tx_queue_stopped = false;
1044 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1045 wl->tx_blocks_available = 0;
1046 wl->tx_results_count = 0;
1047 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001048 wl->tx_security_last_seq = 0;
1049 wl->tx_security_seq_16 = 0;
1050 wl->tx_security_seq_32 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001051 wl->time_offset = 0;
1052 wl->session_counter = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001053 wl->joined = false;
1054
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001055 for (i = 0; i < NUM_TX_QUEUES; i++)
1056 wl->tx_blocks_freed[i] = 0;
1057
1058 wl1271_debugfs_reset(wl);
1059 mutex_unlock(&wl->mutex);
1060}
1061
1062static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1063 struct ieee80211_if_init_conf *conf)
1064{
1065 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001066 int ret = 0;
1067
John W. Linvillee5539bc2009-08-18 10:50:34 -04001068 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1069 conf->type, conf->mac_addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001070
1071 mutex_lock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001072 if (wl->vif) {
1073 ret = -EBUSY;
1074 goto out;
1075 }
1076
1077 wl->vif = conf->vif;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001078
1079 switch (conf->type) {
1080 case NL80211_IFTYPE_STATION:
1081 wl->bss_type = BSS_TYPE_STA_BSS;
1082 break;
1083 case NL80211_IFTYPE_ADHOC:
1084 wl->bss_type = BSS_TYPE_IBSS;
1085 break;
1086 default:
1087 ret = -EOPNOTSUPP;
1088 goto out;
1089 }
1090
1091 /* FIXME: what if conf->mac_addr changes? */
1092
1093out:
1094 mutex_unlock(&wl->mutex);
1095 return ret;
1096}
1097
1098static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1099 struct ieee80211_if_init_conf *conf)
1100{
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001101 struct wl1271 *wl = hw->priv;
1102
1103 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001104 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001105 wl->vif = NULL;
1106 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001107}
1108
1109#if 0
1110static int wl1271_op_config_interface(struct ieee80211_hw *hw,
1111 struct ieee80211_vif *vif,
1112 struct ieee80211_if_conf *conf)
1113{
1114 struct wl1271 *wl = hw->priv;
1115 struct sk_buff *beacon;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001116 int ret;
1117
David S. Miller32646902009-09-17 10:18:30 -07001118 wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM",
1119 conf->bssid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001120 wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid,
1121 conf->ssid_len);
1122
1123 mutex_lock(&wl->mutex);
1124
1125 ret = wl1271_ps_elp_wakeup(wl, false);
1126 if (ret < 0)
1127 goto out;
1128
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001129 if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
1130 wl1271_debug(DEBUG_MAC80211, "bssid changed");
1131
1132 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
1133
1134 ret = wl1271_cmd_join(wl);
1135 if (ret < 0)
1136 goto out_sleep;
1137 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001138
1139 ret = wl1271_cmd_build_null_data(wl);
1140 if (ret < 0)
1141 goto out_sleep;
1142
1143 wl->ssid_len = conf->ssid_len;
1144 if (wl->ssid_len)
1145 memcpy(wl->ssid, conf->ssid, wl->ssid_len);
1146
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001147 if (conf->changed & IEEE80211_IFCC_BEACON) {
1148 beacon = ieee80211_beacon_get(hw, vif);
1149 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1150 beacon->data, beacon->len);
1151
1152 if (ret < 0) {
1153 dev_kfree_skb(beacon);
1154 goto out_sleep;
1155 }
1156
1157 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE,
1158 beacon->data, beacon->len);
1159
1160 dev_kfree_skb(beacon);
1161
1162 if (ret < 0)
1163 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001164 }
1165
1166out_sleep:
1167 wl1271_ps_elp_sleep(wl);
1168
1169out:
1170 mutex_unlock(&wl->mutex);
1171
1172 return ret;
1173}
1174#endif
1175
1176static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1177{
1178 struct wl1271 *wl = hw->priv;
1179 struct ieee80211_conf *conf = &hw->conf;
1180 int channel, ret = 0;
1181
1182 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1183
1184 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
1185 channel,
1186 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
1187 conf->power_level);
1188
1189 mutex_lock(&wl->mutex);
1190
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001191 wl->band = conf->channel->band;
1192
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001193 ret = wl1271_ps_elp_wakeup(wl, false);
1194 if (ret < 0)
1195 goto out;
1196
1197 if (channel != wl->channel) {
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001198 /*
1199 * We assume that the stack will configure the right channel
1200 * before associating, so we don't need to send a join
1201 * command here. We will join the right channel when the
1202 * BSSID changes
1203 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001204 wl->channel = channel;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001205 }
1206
1207 ret = wl1271_cmd_build_null_data(wl);
1208 if (ret < 0)
1209 goto out_sleep;
1210
1211 if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) {
1212 wl1271_info("psm enabled");
1213
1214 wl->psm_requested = true;
1215
1216 /*
1217 * We enter PSM only if we're already associated.
1218 * If we're not, we'll enter it when joining an SSID,
1219 * through the bss_info_changed() hook.
1220 */
1221 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
1222 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
1223 wl->psm_requested) {
1224 wl1271_info("psm disabled");
1225
1226 wl->psm_requested = false;
1227
1228 if (wl->psm)
1229 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE);
1230 }
1231
1232 if (conf->power_level != wl->power_level) {
1233 ret = wl1271_acx_tx_power(wl, conf->power_level);
1234 if (ret < 0)
1235 goto out;
1236
1237 wl->power_level = conf->power_level;
1238 }
1239
1240out_sleep:
1241 wl1271_ps_elp_sleep(wl);
1242
1243out:
1244 mutex_unlock(&wl->mutex);
1245
1246 return ret;
1247}
1248
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001249static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1250 struct dev_addr_list *mc_list)
1251{
1252 struct wl1271 *wl = hw->priv;
1253 struct wl1271_filter_params *fp;
1254 unsigned long flags;
1255 int i;
1256
1257 /*
1258 * FIXME: we should return a hash that will be passed to
1259 * configure_filter() instead of saving everything in the context.
1260 */
1261
Juuso Oikarinen74441132009-10-13 12:47:53 +03001262 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001263 if (!fp) {
1264 wl1271_error("Out of memory setting filters.");
1265 return 0;
1266 }
1267
1268 /* update multicast filtering parameters */
1269 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1270 mc_count = 0;
1271 fp->filters |= FIF_ALLMULTI;
1272 }
1273
1274 fp->mc_list_length = 0;
1275 for (i = 0; i < mc_count; i++) {
1276 if (mc_list->da_addrlen == ETH_ALEN) {
1277 memcpy(fp->mc_list[fp->mc_list_length],
1278 mc_list->da_addr, ETH_ALEN);
1279 fp->mc_list_length++;
1280 } else
1281 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001282 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001283 }
1284
Luciano Coelho0535d9f2009-10-12 15:08:56 +03001285 /* FIXME: We still need to set our filters properly */
1286
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001287 spin_lock_irqsave(&wl->wl_lock, flags);
1288 kfree(wl->filter_params);
1289 wl->filter_params = fp;
1290 spin_unlock_irqrestore(&wl->wl_lock, flags);
1291
1292 return 1;
1293}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001294
1295static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1296 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001297 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001298{
1299 struct wl1271 *wl = hw->priv;
1300
1301 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1302
1303 *total &= WL1271_SUPPORTED_FILTERS;
1304 changed &= WL1271_SUPPORTED_FILTERS;
1305
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001306 if (!multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001307 return;
1308
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001309 /*
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001310 * FIXME: for now we are still using a workqueue for filter
1311 * configuration, but with the new mac80211, this is not needed,
1312 * since configure_filter can now sleep. We now have
1313 * prepare_multicast, which needs to be atomic instead.
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001314 */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001315
1316 /* store current filter config */
1317 wl->filter_params->filters = *total;
1318 wl->filter_params->changed = changed;
1319
1320 ieee80211_queue_work(wl->hw, &wl->filter_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001321}
1322
1323static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1324 struct ieee80211_vif *vif,
1325 struct ieee80211_sta *sta,
1326 struct ieee80211_key_conf *key_conf)
1327{
1328 struct wl1271 *wl = hw->priv;
1329 const u8 *addr;
1330 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001331 u32 tx_seq_32 = 0;
1332 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001333 u8 key_type;
1334
1335 static const u8 bcast_addr[ETH_ALEN] =
1336 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1337
1338 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1339
1340 addr = sta ? sta->addr : bcast_addr;
1341
1342 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1343 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1344 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1345 key_conf->alg, key_conf->keyidx,
1346 key_conf->keylen, key_conf->flags);
1347 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1348
1349 if (is_zero_ether_addr(addr)) {
1350 /* We dont support TX only encryption */
1351 ret = -EOPNOTSUPP;
1352 goto out;
1353 }
1354
1355 mutex_lock(&wl->mutex);
1356
1357 ret = wl1271_ps_elp_wakeup(wl, false);
1358 if (ret < 0)
1359 goto out_unlock;
1360
1361 switch (key_conf->alg) {
1362 case ALG_WEP:
1363 key_type = KEY_WEP;
1364
1365 key_conf->hw_key_idx = key_conf->keyidx;
1366 break;
1367 case ALG_TKIP:
1368 key_type = KEY_TKIP;
1369
1370 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001371 tx_seq_32 = wl->tx_security_seq_32;
1372 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001373 break;
1374 case ALG_CCMP:
1375 key_type = KEY_AES;
1376
1377 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001378 tx_seq_32 = wl->tx_security_seq_32;
1379 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001380 break;
1381 default:
1382 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1383
1384 ret = -EOPNOTSUPP;
1385 goto out_sleep;
1386 }
1387
1388 switch (cmd) {
1389 case SET_KEY:
1390 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1391 key_conf->keyidx, key_type,
1392 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001393 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001394 if (ret < 0) {
1395 wl1271_error("Could not add or replace key");
1396 goto out_sleep;
1397 }
1398 break;
1399
1400 case DISABLE_KEY:
1401 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1402 key_conf->keyidx, key_type,
1403 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001404 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001405 if (ret < 0) {
1406 wl1271_error("Could not remove key");
1407 goto out_sleep;
1408 }
1409 break;
1410
1411 default:
1412 wl1271_error("Unsupported key cmd 0x%x", cmd);
1413 ret = -EOPNOTSUPP;
1414 goto out_sleep;
1415
1416 break;
1417 }
1418
1419out_sleep:
1420 wl1271_ps_elp_sleep(wl);
1421
1422out_unlock:
1423 mutex_unlock(&wl->mutex);
1424
1425out:
1426 return ret;
1427}
1428
1429static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1430 struct cfg80211_scan_request *req)
1431{
1432 struct wl1271 *wl = hw->priv;
1433 int ret;
1434 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001435 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001436
1437 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1438
1439 if (req->n_ssids) {
1440 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001441 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001442 }
1443
1444 mutex_lock(&wl->mutex);
1445
1446 ret = wl1271_ps_elp_wakeup(wl, false);
1447 if (ret < 0)
1448 goto out;
1449
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001450 if (wl1271_11a_enabled())
1451 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1452 WL1271_SCAN_BAND_DUAL, 3);
1453 else
1454 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1455 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001456
1457 wl1271_ps_elp_sleep(wl);
1458
1459out:
1460 mutex_unlock(&wl->mutex);
1461
1462 return ret;
1463}
1464
1465static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1466{
1467 struct wl1271 *wl = hw->priv;
1468 int ret;
1469
1470 mutex_lock(&wl->mutex);
1471
1472 ret = wl1271_ps_elp_wakeup(wl, false);
1473 if (ret < 0)
1474 goto out;
1475
1476 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1477 if (ret < 0)
1478 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1479
1480 wl1271_ps_elp_sleep(wl);
1481
1482out:
1483 mutex_unlock(&wl->mutex);
1484
1485 return ret;
1486}
1487
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001488static u32 wl1271_enabled_rates_get(struct wl1271 *wl, u64 basic_rate_set)
1489{
1490 struct ieee80211_supported_band *band;
1491 u32 enabled_rates = 0;
1492 int bit;
1493
1494 band = wl->hw->wiphy->bands[wl->band];
1495 for (bit = 0; bit < band->n_bitrates; bit++) {
1496 if (basic_rate_set & 0x1)
1497 enabled_rates |= band->bitrates[bit].hw_value;
1498 basic_rate_set >>= 1;
1499 }
1500
1501 return enabled_rates;
1502}
1503
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001504static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1505 struct ieee80211_vif *vif,
1506 struct ieee80211_bss_conf *bss_conf,
1507 u32 changed)
1508{
1509 enum wl1271_cmd_ps_mode mode;
1510 struct wl1271 *wl = hw->priv;
1511 int ret;
1512
1513 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1514
1515 mutex_lock(&wl->mutex);
1516
1517 ret = wl1271_ps_elp_wakeup(wl, false);
1518 if (ret < 0)
1519 goto out;
1520
1521 if (changed & BSS_CHANGED_ASSOC) {
1522 if (bss_conf->assoc) {
1523 wl->aid = bss_conf->aid;
1524
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001525 /*
1526 * with wl1271, we don't need to update the
1527 * beacon_int and dtim_period, because the firmware
1528 * updates it by itself when the first beacon is
1529 * received after a join.
1530 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001531 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1532 if (ret < 0)
1533 goto out_sleep;
1534
1535 ret = wl1271_acx_aid(wl, wl->aid);
1536 if (ret < 0)
1537 goto out_sleep;
1538
1539 /* If we want to go in PSM but we're not there yet */
1540 if (wl->psm_requested && !wl->psm) {
1541 mode = STATION_POWER_SAVE_MODE;
1542 ret = wl1271_ps_set_mode(wl, mode);
1543 if (ret < 0)
1544 goto out_sleep;
1545 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001546 } else {
1547 /* use defaults when not associated */
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001548 wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
1549 wl->aid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001550 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001551
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001552 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001553
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001554 if (changed & BSS_CHANGED_ERP_SLOT) {
1555 if (bss_conf->use_short_slot)
1556 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1557 else
1558 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1559 if (ret < 0) {
1560 wl1271_warning("Set slot time failed %d", ret);
1561 goto out_sleep;
1562 }
1563 }
1564
1565 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1566 if (bss_conf->use_short_preamble)
1567 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1568 else
1569 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1570 }
1571
1572 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1573 if (bss_conf->use_cts_prot)
1574 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1575 else
1576 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1577 if (ret < 0) {
1578 wl1271_warning("Set ctsprotect failed %d", ret);
1579 goto out_sleep;
1580 }
1581 }
1582
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001583 if (changed & BSS_CHANGED_BASIC_RATES) {
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001584 wl->basic_rate_set = wl1271_enabled_rates_get(
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001585 wl, bss_conf->basic_rates);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001586
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001587 ret = wl1271_acx_rate_policies(wl, wl->basic_rate_set);
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001588 if (ret < 0) {
1589 wl1271_warning("Set rate policies failed %d", ret);
1590 goto out_sleep;
1591 }
1592 }
1593
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001594out_sleep:
1595 wl1271_ps_elp_sleep(wl);
1596
1597out:
1598 mutex_unlock(&wl->mutex);
1599}
1600
1601
1602/* can't be const, mac80211 writes to this */
1603static struct ieee80211_rate wl1271_rates[] = {
1604 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001605 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1606 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001607 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001608 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1609 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001610 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1611 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001612 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1613 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001614 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1615 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001616 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1617 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001618 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1619 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001620 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1621 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001622 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001623 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1624 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001625 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001626 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1627 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001628 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001629 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1630 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001631 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001632 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1633 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001634 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001635 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1636 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001637 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001638 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1639 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001640 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001641 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1642 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001643};
1644
1645/* can't be const, mac80211 writes to this */
1646static struct ieee80211_channel wl1271_channels[] = {
1647 { .hw_value = 1, .center_freq = 2412},
1648 { .hw_value = 2, .center_freq = 2417},
1649 { .hw_value = 3, .center_freq = 2422},
1650 { .hw_value = 4, .center_freq = 2427},
1651 { .hw_value = 5, .center_freq = 2432},
1652 { .hw_value = 6, .center_freq = 2437},
1653 { .hw_value = 7, .center_freq = 2442},
1654 { .hw_value = 8, .center_freq = 2447},
1655 { .hw_value = 9, .center_freq = 2452},
1656 { .hw_value = 10, .center_freq = 2457},
1657 { .hw_value = 11, .center_freq = 2462},
1658 { .hw_value = 12, .center_freq = 2467},
1659 { .hw_value = 13, .center_freq = 2472},
1660};
1661
1662/* can't be const, mac80211 writes to this */
1663static struct ieee80211_supported_band wl1271_band_2ghz = {
1664 .channels = wl1271_channels,
1665 .n_channels = ARRAY_SIZE(wl1271_channels),
1666 .bitrates = wl1271_rates,
1667 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1668};
1669
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001670/* 5 GHz data rates for WL1273 */
1671static struct ieee80211_rate wl1271_rates_5ghz[] = {
1672 { .bitrate = 60,
1673 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1674 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
1675 { .bitrate = 90,
1676 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1677 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
1678 { .bitrate = 120,
1679 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1680 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
1681 { .bitrate = 180,
1682 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1683 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
1684 { .bitrate = 240,
1685 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1686 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
1687 { .bitrate = 360,
1688 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1689 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
1690 { .bitrate = 480,
1691 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1692 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
1693 { .bitrate = 540,
1694 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1695 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
1696};
1697
1698/* 5 GHz band channels for WL1273 */
1699static struct ieee80211_channel wl1271_channels_5ghz[] = {
1700 { .hw_value = 183, .center_freq = 4915},
1701 { .hw_value = 184, .center_freq = 4920},
1702 { .hw_value = 185, .center_freq = 4925},
1703 { .hw_value = 187, .center_freq = 4935},
1704 { .hw_value = 188, .center_freq = 4940},
1705 { .hw_value = 189, .center_freq = 4945},
1706 { .hw_value = 192, .center_freq = 4960},
1707 { .hw_value = 196, .center_freq = 4980},
1708 { .hw_value = 7, .center_freq = 5035},
1709 { .hw_value = 8, .center_freq = 5040},
1710 { .hw_value = 9, .center_freq = 5045},
1711 { .hw_value = 11, .center_freq = 5055},
1712 { .hw_value = 12, .center_freq = 5060},
1713 { .hw_value = 16, .center_freq = 5080},
1714 { .hw_value = 34, .center_freq = 5170},
1715 { .hw_value = 36, .center_freq = 5180},
1716 { .hw_value = 38, .center_freq = 5190},
1717 { .hw_value = 40, .center_freq = 5200},
1718 { .hw_value = 42, .center_freq = 5210},
1719 { .hw_value = 44, .center_freq = 5220},
1720 { .hw_value = 46, .center_freq = 5230},
1721 { .hw_value = 48, .center_freq = 5240},
1722 { .hw_value = 52, .center_freq = 5260},
1723 { .hw_value = 56, .center_freq = 5280},
1724 { .hw_value = 60, .center_freq = 5300},
1725 { .hw_value = 64, .center_freq = 5320},
1726 { .hw_value = 100, .center_freq = 5500},
1727 { .hw_value = 104, .center_freq = 5520},
1728 { .hw_value = 108, .center_freq = 5540},
1729 { .hw_value = 112, .center_freq = 5560},
1730 { .hw_value = 116, .center_freq = 5580},
1731 { .hw_value = 120, .center_freq = 5600},
1732 { .hw_value = 124, .center_freq = 5620},
1733 { .hw_value = 128, .center_freq = 5640},
1734 { .hw_value = 132, .center_freq = 5660},
1735 { .hw_value = 136, .center_freq = 5680},
1736 { .hw_value = 140, .center_freq = 5700},
1737 { .hw_value = 149, .center_freq = 5745},
1738 { .hw_value = 153, .center_freq = 5765},
1739 { .hw_value = 157, .center_freq = 5785},
1740 { .hw_value = 161, .center_freq = 5805},
1741 { .hw_value = 165, .center_freq = 5825},
1742};
1743
1744
1745static struct ieee80211_supported_band wl1271_band_5ghz = {
1746 .channels = wl1271_channels_5ghz,
1747 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
1748 .bitrates = wl1271_rates_5ghz,
1749 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
1750};
1751
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001752static const struct ieee80211_ops wl1271_ops = {
1753 .start = wl1271_op_start,
1754 .stop = wl1271_op_stop,
1755 .add_interface = wl1271_op_add_interface,
1756 .remove_interface = wl1271_op_remove_interface,
1757 .config = wl1271_op_config,
1758/* .config_interface = wl1271_op_config_interface, */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001759 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001760 .configure_filter = wl1271_op_configure_filter,
1761 .tx = wl1271_op_tx,
1762 .set_key = wl1271_op_set_key,
1763 .hw_scan = wl1271_op_hw_scan,
1764 .bss_info_changed = wl1271_op_bss_info_changed,
1765 .set_rts_threshold = wl1271_op_set_rts_threshold,
1766};
1767
1768static int wl1271_register_hw(struct wl1271 *wl)
1769{
1770 int ret;
1771
1772 if (wl->mac80211_registered)
1773 return 0;
1774
1775 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
1776
1777 ret = ieee80211_register_hw(wl->hw);
1778 if (ret < 0) {
1779 wl1271_error("unable to register mac80211 hw: %d", ret);
1780 return ret;
1781 }
1782
1783 wl->mac80211_registered = true;
1784
1785 wl1271_notice("loaded");
1786
1787 return 0;
1788}
1789
1790static int wl1271_init_ieee80211(struct wl1271 *wl)
1791{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03001792 /* The tx descriptor buffer and the TKIP space. */
1793 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
1794 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001795
1796 /* unit us */
1797 /* FIXME: find a proper value */
1798 wl->hw->channel_change_time = 10000;
1799
1800 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03001801 IEEE80211_HW_NOISE_DBM |
1802 IEEE80211_HW_BEACON_FILTER;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001803
1804 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
1805 wl->hw->wiphy->max_scan_ssids = 1;
1806 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
1807
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001808 if (wl1271_11a_enabled())
1809 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
1810
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001811 SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
1812
1813 return 0;
1814}
1815
1816static void wl1271_device_release(struct device *dev)
1817{
1818
1819}
1820
1821static struct platform_device wl1271_device = {
1822 .name = "wl1271",
1823 .id = -1,
1824
1825 /* device model insists to have a release function */
1826 .dev = {
1827 .release = wl1271_device_release,
1828 },
1829};
1830
1831#define WL1271_DEFAULT_CHANNEL 0
1832static int __devinit wl1271_probe(struct spi_device *spi)
1833{
1834 struct wl12xx_platform_data *pdata;
1835 struct ieee80211_hw *hw;
1836 struct wl1271 *wl;
1837 int ret, i;
1838 static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
1839
1840 pdata = spi->dev.platform_data;
1841 if (!pdata) {
1842 wl1271_error("no platform data");
1843 return -ENODEV;
1844 }
1845
1846 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
1847 if (!hw) {
1848 wl1271_error("could not alloc ieee80211_hw");
1849 return -ENOMEM;
1850 }
1851
1852 wl = hw->priv;
1853 memset(wl, 0, sizeof(*wl));
1854
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001855 INIT_LIST_HEAD(&wl->list);
1856
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001857 wl->hw = hw;
1858 dev_set_drvdata(&spi->dev, wl);
1859 wl->spi = spi;
1860
1861 skb_queue_head_init(&wl->tx_queue);
1862
1863 INIT_WORK(&wl->filter_work, wl1271_filter_work);
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03001864 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001865 wl->channel = WL1271_DEFAULT_CHANNEL;
1866 wl->scanning = false;
1867 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001868 wl->rx_counter = 0;
1869 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1870 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1871 wl->elp = false;
1872 wl->psm = 0;
1873 wl->psm_requested = false;
1874 wl->tx_queue_stopped = false;
1875 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001876 wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001877 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001878 wl->vif = NULL;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001879 wl->joined = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001880
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03001881 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001882 wl->tx_frames[i] = NULL;
1883
1884 spin_lock_init(&wl->wl_lock);
1885
1886 /*
1887 * In case our MAC address is not correctly set,
1888 * we use a random but Nokia MAC.
1889 */
1890 memcpy(wl->mac_addr, nokia_oui, 3);
1891 get_random_bytes(wl->mac_addr + 3, 3);
1892
1893 wl->state = WL1271_STATE_OFF;
1894 mutex_init(&wl->mutex);
1895
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001896 /* This is the only SPI value that we need to set here, the rest
1897 * comes from the board-peripherals file */
1898 spi->bits_per_word = 32;
1899
1900 ret = spi_setup(spi);
1901 if (ret < 0) {
1902 wl1271_error("spi_setup failed");
1903 goto out_free;
1904 }
1905
1906 wl->set_power = pdata->set_power;
1907 if (!wl->set_power) {
1908 wl1271_error("set power function missing in platform data");
1909 ret = -ENODEV;
1910 goto out_free;
1911 }
1912
1913 wl->irq = spi->irq;
1914 if (wl->irq < 0) {
1915 wl1271_error("irq missing in platform data");
1916 ret = -ENODEV;
1917 goto out_free;
1918 }
1919
1920 ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
1921 if (ret < 0) {
1922 wl1271_error("request_irq() failed: %d", ret);
1923 goto out_free;
1924 }
1925
1926 set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
1927
1928 disable_irq(wl->irq);
1929
1930 ret = platform_device_register(&wl1271_device);
1931 if (ret) {
1932 wl1271_error("couldn't register platform device");
1933 goto out_irq;
1934 }
1935 dev_set_drvdata(&wl1271_device.dev, wl);
1936
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001937 /* Apply default driver configuration. */
1938 wl1271_conf_init(wl);
1939
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001940 ret = wl1271_init_ieee80211(wl);
1941 if (ret)
1942 goto out_platform;
1943
1944 ret = wl1271_register_hw(wl);
1945 if (ret)
1946 goto out_platform;
1947
1948 wl1271_debugfs_init(wl);
1949
1950 wl1271_notice("initialized");
1951
1952 return 0;
1953
1954 out_platform:
1955 platform_device_unregister(&wl1271_device);
1956
1957 out_irq:
1958 free_irq(wl->irq, wl);
1959
1960 out_free:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001961 ieee80211_free_hw(hw);
1962
1963 return ret;
1964}
1965
1966static int __devexit wl1271_remove(struct spi_device *spi)
1967{
1968 struct wl1271 *wl = dev_get_drvdata(&spi->dev);
1969
1970 ieee80211_unregister_hw(wl->hw);
1971
1972 wl1271_debugfs_exit(wl);
1973 platform_device_unregister(&wl1271_device);
1974 free_irq(wl->irq, wl);
1975 kfree(wl->target_mem_map);
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001976 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001977 wl->fw = NULL;
1978 kfree(wl->nvs);
1979 wl->nvs = NULL;
1980
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001981 kfree(wl->fw_status);
1982 kfree(wl->tx_res_if);
1983
1984 ieee80211_free_hw(wl->hw);
1985
1986 return 0;
1987}
1988
1989
1990static struct spi_driver wl1271_spi_driver = {
1991 .driver = {
1992 .name = "wl1271",
1993 .bus = &spi_bus_type,
1994 .owner = THIS_MODULE,
1995 },
1996
1997 .probe = wl1271_probe,
1998 .remove = __devexit_p(wl1271_remove),
1999};
2000
2001static int __init wl1271_init(void)
2002{
2003 int ret;
2004
2005 ret = spi_register_driver(&wl1271_spi_driver);
2006 if (ret < 0) {
2007 wl1271_error("failed to register spi driver: %d", ret);
2008 goto out;
2009 }
2010
2011out:
2012 return ret;
2013}
2014
2015static void __exit wl1271_exit(void)
2016{
2017 spi_unregister_driver(&wl1271_spi_driver);
2018
2019 wl1271_notice("unloaded");
2020}
2021
2022module_init(wl1271_init);
2023module_exit(wl1271_exit);
2024
2025MODULE_LICENSE("GPL");
2026MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
Luciano Coelho2f018722009-10-08 21:56:27 +03002027MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");