blob: ee7ffafaa2748ed6675673799989fcbe94ba5fc6 [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
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300678int wl1271_plt_start(struct wl1271 *wl)
679{
680 int ret;
681
682 mutex_lock(&wl->mutex);
683
684 wl1271_notice("power up");
685
686 if (wl->state != WL1271_STATE_OFF) {
687 wl1271_error("cannot go into PLT state because not "
688 "in off state: %d", wl->state);
689 ret = -EBUSY;
690 goto out;
691 }
692
693 wl->state = WL1271_STATE_PLT;
694
695 ret = wl1271_chip_wakeup(wl);
696 if (ret < 0)
697 goto out;
698
699 ret = wl1271_boot(wl);
700 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300701 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300702
703 wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver);
704
705 ret = wl1271_plt_init(wl);
706 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300707 goto out_irq_disable;
708
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300709 /* Make sure power saving is disabled */
710 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
711 if (ret < 0)
712 goto out_irq_disable;
713
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300714 goto out;
715
716out_irq_disable:
717 wl1271_disable_interrupts(wl);
718
719out_power_off:
720 wl1271_power_off(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300721
722out:
723 mutex_unlock(&wl->mutex);
724
725 return ret;
726}
727
728int wl1271_plt_stop(struct wl1271 *wl)
729{
730 int ret = 0;
731
732 mutex_lock(&wl->mutex);
733
734 wl1271_notice("power down");
735
736 if (wl->state != WL1271_STATE_PLT) {
737 wl1271_error("cannot power down because not in PLT "
738 "state: %d", wl->state);
739 ret = -EBUSY;
740 goto out;
741 }
742
743 wl1271_disable_interrupts(wl);
744 wl1271_power_off(wl);
745
746 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300747 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300748
749out:
750 mutex_unlock(&wl->mutex);
751
752 return ret;
753}
754
755
756static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
757{
758 struct wl1271 *wl = hw->priv;
759
760 skb_queue_tail(&wl->tx_queue, skb);
761
762 /*
763 * The chip specific setup must run before the first TX packet -
764 * before that, the tx_work will not be initialized!
765 */
766
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300767 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300768
769 /*
770 * The workqueue is slow to process the tx_queue and we need stop
771 * the queue here, otherwise the queue will get too long.
772 */
773 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) {
774 ieee80211_stop_queues(wl->hw);
775
776 /*
777 * FIXME: this is racy, the variable is not properly
778 * protected. Maybe fix this by removing the stupid
779 * variable altogether and checking the real queue state?
780 */
781 wl->tx_queue_stopped = true;
782 }
783
784 return NETDEV_TX_OK;
785}
786
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300787static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
788 void *arg)
789{
790 struct net_device *dev;
791 struct wireless_dev *wdev;
792 struct wiphy *wiphy;
793 struct ieee80211_hw *hw;
794 struct wl1271 *wl;
795 struct wl1271 *wl_temp;
796 struct in_device *idev;
797 struct in_ifaddr *ifa = arg;
798 int ret = 0;
799
800 /* FIXME: this ugly function should probably be implemented in the
801 * mac80211, and here should only be a simple callback handling actual
802 * setting of the filters. Now we need to dig up references to
803 * various structures to gain access to what we need.
804 * Also, because of this, there is no "initial" setting of the filter
805 * in "op_start", because we don't want to dig up struct net_device
806 * there - the filter will be set upon first change of the interface
807 * IP address. */
808
809 dev = ifa->ifa_dev->dev;
810
811 wdev = dev->ieee80211_ptr;
812 if (wdev == NULL)
813 return -ENODEV;
814
815 wiphy = wdev->wiphy;
816 if (wiphy == NULL)
817 return -ENODEV;
818
819 hw = wiphy_priv(wiphy);
820 if (hw == NULL)
821 return -ENODEV;
822
823 /* Check that the interface is one supported by this driver. */
824 wl_temp = hw->priv;
825 list_for_each_entry(wl, &wl_list, list) {
826 if (wl == wl_temp)
827 break;
828 }
829 if (wl == NULL)
830 return -ENODEV;
831
832 /* Get the interface IP address for the device. "ifa" will become
833 NULL if:
834 - there is no IPV4 protocol address configured
835 - there are multiple (virtual) IPV4 addresses configured
836 When "ifa" is NULL, filtering will be disabled.
837 */
838 ifa = NULL;
839 idev = dev->ip_ptr;
840 if (idev)
841 ifa = idev->ifa_list;
842
843 if (ifa && ifa->ifa_next)
844 ifa = NULL;
845
846 mutex_lock(&wl->mutex);
847
848 if (wl->state == WL1271_STATE_OFF)
849 goto out;
850
851 ret = wl1271_ps_elp_wakeup(wl, false);
852 if (ret < 0)
853 goto out;
854 if (ifa)
855 ret = wl1271_acx_arp_ip_filter(wl, true,
856 (u8 *)&ifa->ifa_address,
857 ACX_IPV4_VERSION);
858 else
859 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
860 ACX_IPV4_VERSION);
861 wl1271_ps_elp_sleep(wl);
862
863out:
864 mutex_unlock(&wl->mutex);
865
866 return ret;
867}
868
869static struct notifier_block wl1271_dev_notifier = {
870 .notifier_call = wl1271_dev_notify,
871};
872
873
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300874static int wl1271_op_start(struct ieee80211_hw *hw)
875{
876 struct wl1271 *wl = hw->priv;
877 int ret = 0;
878
879 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
880
881 mutex_lock(&wl->mutex);
882
883 if (wl->state != WL1271_STATE_OFF) {
884 wl1271_error("cannot start because not in off state: %d",
885 wl->state);
886 ret = -EBUSY;
887 goto out;
888 }
889
890 ret = wl1271_chip_wakeup(wl);
891 if (ret < 0)
892 goto out;
893
894 ret = wl1271_boot(wl);
895 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300896 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300897
898 ret = wl1271_hw_init(wl);
899 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300900 goto out_irq_disable;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300901
902 wl->state = WL1271_STATE_ON;
903
904 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
905
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300906 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300907
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300908out_irq_disable:
909 wl1271_disable_interrupts(wl);
910
911out_power_off:
912 wl1271_power_off(wl);
913
914out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300915 mutex_unlock(&wl->mutex);
916
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300917 if (!ret) {
918 list_add(&wl->list, &wl_list);
919 register_inetaddr_notifier(&wl1271_dev_notifier);
920 }
921
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300922 return ret;
923}
924
925static void wl1271_op_stop(struct ieee80211_hw *hw)
926{
927 struct wl1271 *wl = hw->priv;
928 int i;
929
930 wl1271_info("down");
931
932 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
933
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300934 unregister_inetaddr_notifier(&wl1271_dev_notifier);
935 list_del(&wl->list);
936
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300937 mutex_lock(&wl->mutex);
938
939 WARN_ON(wl->state != WL1271_STATE_ON);
940
941 if (wl->scanning) {
942 mutex_unlock(&wl->mutex);
943 ieee80211_scan_completed(wl->hw, true);
944 mutex_lock(&wl->mutex);
945 wl->scanning = false;
946 }
947
948 wl->state = WL1271_STATE_OFF;
949
950 wl1271_disable_interrupts(wl);
951
952 mutex_unlock(&wl->mutex);
953
954 cancel_work_sync(&wl->irq_work);
955 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300956
957 mutex_lock(&wl->mutex);
958
959 /* let's notify MAC80211 about the remaining pending TX frames */
960 wl1271_tx_flush(wl);
961 wl1271_power_off(wl);
962
963 memset(wl->bssid, 0, ETH_ALEN);
964 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
965 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300966 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +0300967 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300968
969 wl->rx_counter = 0;
970 wl->elp = false;
971 wl->psm = 0;
972 wl->tx_queue_stopped = false;
973 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
974 wl->tx_blocks_available = 0;
975 wl->tx_results_count = 0;
976 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +0300977 wl->tx_security_last_seq = 0;
978 wl->tx_security_seq_16 = 0;
979 wl->tx_security_seq_32 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300980 wl->time_offset = 0;
981 wl->session_counter = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +0300982 wl->joined = false;
983
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300984 for (i = 0; i < NUM_TX_QUEUES; i++)
985 wl->tx_blocks_freed[i] = 0;
986
987 wl1271_debugfs_reset(wl);
988 mutex_unlock(&wl->mutex);
989}
990
991static int wl1271_op_add_interface(struct ieee80211_hw *hw,
992 struct ieee80211_if_init_conf *conf)
993{
994 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300995 int ret = 0;
996
John W. Linvillee5539bc2009-08-18 10:50:34 -0400997 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
998 conf->type, conf->mac_addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300999
1000 mutex_lock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001001 if (wl->vif) {
1002 ret = -EBUSY;
1003 goto out;
1004 }
1005
1006 wl->vif = conf->vif;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001007
1008 switch (conf->type) {
1009 case NL80211_IFTYPE_STATION:
1010 wl->bss_type = BSS_TYPE_STA_BSS;
1011 break;
1012 case NL80211_IFTYPE_ADHOC:
1013 wl->bss_type = BSS_TYPE_IBSS;
1014 break;
1015 default:
1016 ret = -EOPNOTSUPP;
1017 goto out;
1018 }
1019
1020 /* FIXME: what if conf->mac_addr changes? */
1021
1022out:
1023 mutex_unlock(&wl->mutex);
1024 return ret;
1025}
1026
1027static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1028 struct ieee80211_if_init_conf *conf)
1029{
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001030 struct wl1271 *wl = hw->priv;
1031
1032 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001033 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001034 wl->vif = NULL;
1035 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001036}
1037
1038#if 0
1039static int wl1271_op_config_interface(struct ieee80211_hw *hw,
1040 struct ieee80211_vif *vif,
1041 struct ieee80211_if_conf *conf)
1042{
1043 struct wl1271 *wl = hw->priv;
1044 struct sk_buff *beacon;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001045 int ret;
1046
David S. Miller32646902009-09-17 10:18:30 -07001047 wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM",
1048 conf->bssid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001049 wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid,
1050 conf->ssid_len);
1051
1052 mutex_lock(&wl->mutex);
1053
1054 ret = wl1271_ps_elp_wakeup(wl, false);
1055 if (ret < 0)
1056 goto out;
1057
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001058 if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
1059 wl1271_debug(DEBUG_MAC80211, "bssid changed");
1060
1061 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
1062
1063 ret = wl1271_cmd_join(wl);
1064 if (ret < 0)
1065 goto out_sleep;
1066 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001067
1068 ret = wl1271_cmd_build_null_data(wl);
1069 if (ret < 0)
1070 goto out_sleep;
1071
1072 wl->ssid_len = conf->ssid_len;
1073 if (wl->ssid_len)
1074 memcpy(wl->ssid, conf->ssid, wl->ssid_len);
1075
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001076 if (conf->changed & IEEE80211_IFCC_BEACON) {
1077 beacon = ieee80211_beacon_get(hw, vif);
1078 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1079 beacon->data, beacon->len);
1080
1081 if (ret < 0) {
1082 dev_kfree_skb(beacon);
1083 goto out_sleep;
1084 }
1085
1086 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE,
1087 beacon->data, beacon->len);
1088
1089 dev_kfree_skb(beacon);
1090
1091 if (ret < 0)
1092 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001093 }
1094
1095out_sleep:
1096 wl1271_ps_elp_sleep(wl);
1097
1098out:
1099 mutex_unlock(&wl->mutex);
1100
1101 return ret;
1102}
1103#endif
1104
1105static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1106{
1107 struct wl1271 *wl = hw->priv;
1108 struct ieee80211_conf *conf = &hw->conf;
1109 int channel, ret = 0;
1110
1111 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1112
1113 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
1114 channel,
1115 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
1116 conf->power_level);
1117
1118 mutex_lock(&wl->mutex);
1119
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001120 wl->band = conf->channel->band;
1121
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001122 ret = wl1271_ps_elp_wakeup(wl, false);
1123 if (ret < 0)
1124 goto out;
1125
1126 if (channel != wl->channel) {
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001127 /*
1128 * We assume that the stack will configure the right channel
1129 * before associating, so we don't need to send a join
1130 * command here. We will join the right channel when the
1131 * BSSID changes
1132 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001133 wl->channel = channel;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001134 }
1135
1136 ret = wl1271_cmd_build_null_data(wl);
1137 if (ret < 0)
1138 goto out_sleep;
1139
1140 if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) {
1141 wl1271_info("psm enabled");
1142
1143 wl->psm_requested = true;
1144
1145 /*
1146 * We enter PSM only if we're already associated.
1147 * If we're not, we'll enter it when joining an SSID,
1148 * through the bss_info_changed() hook.
1149 */
1150 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
1151 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
1152 wl->psm_requested) {
1153 wl1271_info("psm disabled");
1154
1155 wl->psm_requested = false;
1156
1157 if (wl->psm)
1158 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE);
1159 }
1160
1161 if (conf->power_level != wl->power_level) {
1162 ret = wl1271_acx_tx_power(wl, conf->power_level);
1163 if (ret < 0)
1164 goto out;
1165
1166 wl->power_level = conf->power_level;
1167 }
1168
1169out_sleep:
1170 wl1271_ps_elp_sleep(wl);
1171
1172out:
1173 mutex_unlock(&wl->mutex);
1174
1175 return ret;
1176}
1177
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001178struct wl1271_filter_params {
1179 bool enabled;
1180 int mc_list_length;
1181 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1182};
1183
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001184static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1185 struct dev_addr_list *mc_list)
1186{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001187 struct wl1271_filter_params *fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001188 int i;
1189
Juuso Oikarinen74441132009-10-13 12:47:53 +03001190 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001191 if (!fp) {
1192 wl1271_error("Out of memory setting filters.");
1193 return 0;
1194 }
1195
1196 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001197 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001198 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1199 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001200 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001201 }
1202
1203 fp->mc_list_length = 0;
1204 for (i = 0; i < mc_count; i++) {
1205 if (mc_list->da_addrlen == ETH_ALEN) {
1206 memcpy(fp->mc_list[fp->mc_list_length],
1207 mc_list->da_addr, ETH_ALEN);
1208 fp->mc_list_length++;
1209 } else
1210 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001211 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001212 }
1213
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001214 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001215}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001216
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001217#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1218 FIF_ALLMULTI | \
1219 FIF_FCSFAIL | \
1220 FIF_BCN_PRBRESP_PROMISC | \
1221 FIF_CONTROL | \
1222 FIF_OTHER_BSS)
1223
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001224static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1225 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001226 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001227{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001228 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001229 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001230 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001231
1232 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1233
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001234 mutex_lock(&wl->mutex);
1235
1236 if (wl->state == WL1271_STATE_OFF)
1237 goto out;
1238
1239 ret = wl1271_ps_elp_wakeup(wl, false);
1240 if (ret < 0)
1241 goto out;
1242
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001243 *total &= WL1271_SUPPORTED_FILTERS;
1244 changed &= WL1271_SUPPORTED_FILTERS;
1245
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001246 if (*total & FIF_ALLMULTI)
1247 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1248 else if (fp)
1249 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1250 fp->mc_list,
1251 fp->mc_list_length);
1252 if (ret < 0)
1253 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001254
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001255 kfree(fp);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001256
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001257 /* FIXME: We still need to set our filters properly */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001258
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001259 /* determine, whether supported filter values have changed */
1260 if (changed == 0)
1261 goto out_sleep;
1262
1263 /* apply configured filters */
1264 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1265 if (ret < 0)
1266 goto out_sleep;
1267
1268out_sleep:
1269 wl1271_ps_elp_sleep(wl);
1270
1271out:
1272 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001273}
1274
1275static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1276 struct ieee80211_vif *vif,
1277 struct ieee80211_sta *sta,
1278 struct ieee80211_key_conf *key_conf)
1279{
1280 struct wl1271 *wl = hw->priv;
1281 const u8 *addr;
1282 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001283 u32 tx_seq_32 = 0;
1284 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001285 u8 key_type;
1286
1287 static const u8 bcast_addr[ETH_ALEN] =
1288 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1289
1290 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1291
1292 addr = sta ? sta->addr : bcast_addr;
1293
1294 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1295 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1296 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1297 key_conf->alg, key_conf->keyidx,
1298 key_conf->keylen, key_conf->flags);
1299 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1300
1301 if (is_zero_ether_addr(addr)) {
1302 /* We dont support TX only encryption */
1303 ret = -EOPNOTSUPP;
1304 goto out;
1305 }
1306
1307 mutex_lock(&wl->mutex);
1308
1309 ret = wl1271_ps_elp_wakeup(wl, false);
1310 if (ret < 0)
1311 goto out_unlock;
1312
1313 switch (key_conf->alg) {
1314 case ALG_WEP:
1315 key_type = KEY_WEP;
1316
1317 key_conf->hw_key_idx = key_conf->keyidx;
1318 break;
1319 case ALG_TKIP:
1320 key_type = KEY_TKIP;
1321
1322 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001323 tx_seq_32 = wl->tx_security_seq_32;
1324 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001325 break;
1326 case ALG_CCMP:
1327 key_type = KEY_AES;
1328
1329 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001330 tx_seq_32 = wl->tx_security_seq_32;
1331 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001332 break;
1333 default:
1334 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1335
1336 ret = -EOPNOTSUPP;
1337 goto out_sleep;
1338 }
1339
1340 switch (cmd) {
1341 case SET_KEY:
1342 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1343 key_conf->keyidx, key_type,
1344 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001345 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001346 if (ret < 0) {
1347 wl1271_error("Could not add or replace key");
1348 goto out_sleep;
1349 }
1350 break;
1351
1352 case DISABLE_KEY:
1353 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1354 key_conf->keyidx, key_type,
1355 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001356 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001357 if (ret < 0) {
1358 wl1271_error("Could not remove key");
1359 goto out_sleep;
1360 }
1361 break;
1362
1363 default:
1364 wl1271_error("Unsupported key cmd 0x%x", cmd);
1365 ret = -EOPNOTSUPP;
1366 goto out_sleep;
1367
1368 break;
1369 }
1370
1371out_sleep:
1372 wl1271_ps_elp_sleep(wl);
1373
1374out_unlock:
1375 mutex_unlock(&wl->mutex);
1376
1377out:
1378 return ret;
1379}
1380
1381static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1382 struct cfg80211_scan_request *req)
1383{
1384 struct wl1271 *wl = hw->priv;
1385 int ret;
1386 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001387 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001388
1389 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1390
1391 if (req->n_ssids) {
1392 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001393 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001394 }
1395
1396 mutex_lock(&wl->mutex);
1397
1398 ret = wl1271_ps_elp_wakeup(wl, false);
1399 if (ret < 0)
1400 goto out;
1401
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001402 if (wl1271_11a_enabled())
1403 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1404 WL1271_SCAN_BAND_DUAL, 3);
1405 else
1406 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1407 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001408
1409 wl1271_ps_elp_sleep(wl);
1410
1411out:
1412 mutex_unlock(&wl->mutex);
1413
1414 return ret;
1415}
1416
1417static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1418{
1419 struct wl1271 *wl = hw->priv;
1420 int ret;
1421
1422 mutex_lock(&wl->mutex);
1423
1424 ret = wl1271_ps_elp_wakeup(wl, false);
1425 if (ret < 0)
1426 goto out;
1427
1428 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1429 if (ret < 0)
1430 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1431
1432 wl1271_ps_elp_sleep(wl);
1433
1434out:
1435 mutex_unlock(&wl->mutex);
1436
1437 return ret;
1438}
1439
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001440static u32 wl1271_enabled_rates_get(struct wl1271 *wl, u64 basic_rate_set)
1441{
1442 struct ieee80211_supported_band *band;
1443 u32 enabled_rates = 0;
1444 int bit;
1445
1446 band = wl->hw->wiphy->bands[wl->band];
1447 for (bit = 0; bit < band->n_bitrates; bit++) {
1448 if (basic_rate_set & 0x1)
1449 enabled_rates |= band->bitrates[bit].hw_value;
1450 basic_rate_set >>= 1;
1451 }
1452
1453 return enabled_rates;
1454}
1455
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001456static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1457 struct ieee80211_vif *vif,
1458 struct ieee80211_bss_conf *bss_conf,
1459 u32 changed)
1460{
1461 enum wl1271_cmd_ps_mode mode;
1462 struct wl1271 *wl = hw->priv;
1463 int ret;
1464
1465 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1466
1467 mutex_lock(&wl->mutex);
1468
1469 ret = wl1271_ps_elp_wakeup(wl, false);
1470 if (ret < 0)
1471 goto out;
1472
1473 if (changed & BSS_CHANGED_ASSOC) {
1474 if (bss_conf->assoc) {
1475 wl->aid = bss_conf->aid;
1476
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001477 /*
1478 * with wl1271, we don't need to update the
1479 * beacon_int and dtim_period, because the firmware
1480 * updates it by itself when the first beacon is
1481 * received after a join.
1482 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001483 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1484 if (ret < 0)
1485 goto out_sleep;
1486
1487 ret = wl1271_acx_aid(wl, wl->aid);
1488 if (ret < 0)
1489 goto out_sleep;
1490
1491 /* If we want to go in PSM but we're not there yet */
1492 if (wl->psm_requested && !wl->psm) {
1493 mode = STATION_POWER_SAVE_MODE;
1494 ret = wl1271_ps_set_mode(wl, mode);
1495 if (ret < 0)
1496 goto out_sleep;
1497 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001498 } else {
1499 /* use defaults when not associated */
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001500 wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
1501 wl->aid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001502 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001503
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001504 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001505
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001506 if (changed & BSS_CHANGED_ERP_SLOT) {
1507 if (bss_conf->use_short_slot)
1508 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1509 else
1510 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1511 if (ret < 0) {
1512 wl1271_warning("Set slot time failed %d", ret);
1513 goto out_sleep;
1514 }
1515 }
1516
1517 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1518 if (bss_conf->use_short_preamble)
1519 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1520 else
1521 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1522 }
1523
1524 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1525 if (bss_conf->use_cts_prot)
1526 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1527 else
1528 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1529 if (ret < 0) {
1530 wl1271_warning("Set ctsprotect failed %d", ret);
1531 goto out_sleep;
1532 }
1533 }
1534
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001535 if (changed & BSS_CHANGED_BASIC_RATES) {
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001536 wl->basic_rate_set = wl1271_enabled_rates_get(
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001537 wl, bss_conf->basic_rates);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001538
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001539 ret = wl1271_acx_rate_policies(wl, wl->basic_rate_set);
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001540 if (ret < 0) {
1541 wl1271_warning("Set rate policies failed %d", ret);
1542 goto out_sleep;
1543 }
1544 }
1545
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001546out_sleep:
1547 wl1271_ps_elp_sleep(wl);
1548
1549out:
1550 mutex_unlock(&wl->mutex);
1551}
1552
1553
1554/* can't be const, mac80211 writes to this */
1555static struct ieee80211_rate wl1271_rates[] = {
1556 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001557 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1558 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001559 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001560 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1561 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001562 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1563 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001564 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1565 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001566 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1567 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001568 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1569 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001570 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1571 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001572 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1573 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001574 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001575 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1576 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001577 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001578 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1579 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001580 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001581 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1582 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001583 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001584 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1585 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001586 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001587 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1588 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001589 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001590 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1591 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001592 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001593 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1594 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001595};
1596
1597/* can't be const, mac80211 writes to this */
1598static struct ieee80211_channel wl1271_channels[] = {
1599 { .hw_value = 1, .center_freq = 2412},
1600 { .hw_value = 2, .center_freq = 2417},
1601 { .hw_value = 3, .center_freq = 2422},
1602 { .hw_value = 4, .center_freq = 2427},
1603 { .hw_value = 5, .center_freq = 2432},
1604 { .hw_value = 6, .center_freq = 2437},
1605 { .hw_value = 7, .center_freq = 2442},
1606 { .hw_value = 8, .center_freq = 2447},
1607 { .hw_value = 9, .center_freq = 2452},
1608 { .hw_value = 10, .center_freq = 2457},
1609 { .hw_value = 11, .center_freq = 2462},
1610 { .hw_value = 12, .center_freq = 2467},
1611 { .hw_value = 13, .center_freq = 2472},
1612};
1613
1614/* can't be const, mac80211 writes to this */
1615static struct ieee80211_supported_band wl1271_band_2ghz = {
1616 .channels = wl1271_channels,
1617 .n_channels = ARRAY_SIZE(wl1271_channels),
1618 .bitrates = wl1271_rates,
1619 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1620};
1621
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001622/* 5 GHz data rates for WL1273 */
1623static struct ieee80211_rate wl1271_rates_5ghz[] = {
1624 { .bitrate = 60,
1625 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1626 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
1627 { .bitrate = 90,
1628 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1629 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
1630 { .bitrate = 120,
1631 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1632 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
1633 { .bitrate = 180,
1634 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1635 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
1636 { .bitrate = 240,
1637 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1638 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
1639 { .bitrate = 360,
1640 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1641 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
1642 { .bitrate = 480,
1643 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1644 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
1645 { .bitrate = 540,
1646 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1647 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
1648};
1649
1650/* 5 GHz band channels for WL1273 */
1651static struct ieee80211_channel wl1271_channels_5ghz[] = {
1652 { .hw_value = 183, .center_freq = 4915},
1653 { .hw_value = 184, .center_freq = 4920},
1654 { .hw_value = 185, .center_freq = 4925},
1655 { .hw_value = 187, .center_freq = 4935},
1656 { .hw_value = 188, .center_freq = 4940},
1657 { .hw_value = 189, .center_freq = 4945},
1658 { .hw_value = 192, .center_freq = 4960},
1659 { .hw_value = 196, .center_freq = 4980},
1660 { .hw_value = 7, .center_freq = 5035},
1661 { .hw_value = 8, .center_freq = 5040},
1662 { .hw_value = 9, .center_freq = 5045},
1663 { .hw_value = 11, .center_freq = 5055},
1664 { .hw_value = 12, .center_freq = 5060},
1665 { .hw_value = 16, .center_freq = 5080},
1666 { .hw_value = 34, .center_freq = 5170},
1667 { .hw_value = 36, .center_freq = 5180},
1668 { .hw_value = 38, .center_freq = 5190},
1669 { .hw_value = 40, .center_freq = 5200},
1670 { .hw_value = 42, .center_freq = 5210},
1671 { .hw_value = 44, .center_freq = 5220},
1672 { .hw_value = 46, .center_freq = 5230},
1673 { .hw_value = 48, .center_freq = 5240},
1674 { .hw_value = 52, .center_freq = 5260},
1675 { .hw_value = 56, .center_freq = 5280},
1676 { .hw_value = 60, .center_freq = 5300},
1677 { .hw_value = 64, .center_freq = 5320},
1678 { .hw_value = 100, .center_freq = 5500},
1679 { .hw_value = 104, .center_freq = 5520},
1680 { .hw_value = 108, .center_freq = 5540},
1681 { .hw_value = 112, .center_freq = 5560},
1682 { .hw_value = 116, .center_freq = 5580},
1683 { .hw_value = 120, .center_freq = 5600},
1684 { .hw_value = 124, .center_freq = 5620},
1685 { .hw_value = 128, .center_freq = 5640},
1686 { .hw_value = 132, .center_freq = 5660},
1687 { .hw_value = 136, .center_freq = 5680},
1688 { .hw_value = 140, .center_freq = 5700},
1689 { .hw_value = 149, .center_freq = 5745},
1690 { .hw_value = 153, .center_freq = 5765},
1691 { .hw_value = 157, .center_freq = 5785},
1692 { .hw_value = 161, .center_freq = 5805},
1693 { .hw_value = 165, .center_freq = 5825},
1694};
1695
1696
1697static struct ieee80211_supported_band wl1271_band_5ghz = {
1698 .channels = wl1271_channels_5ghz,
1699 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
1700 .bitrates = wl1271_rates_5ghz,
1701 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
1702};
1703
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001704static const struct ieee80211_ops wl1271_ops = {
1705 .start = wl1271_op_start,
1706 .stop = wl1271_op_stop,
1707 .add_interface = wl1271_op_add_interface,
1708 .remove_interface = wl1271_op_remove_interface,
1709 .config = wl1271_op_config,
1710/* .config_interface = wl1271_op_config_interface, */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001711 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001712 .configure_filter = wl1271_op_configure_filter,
1713 .tx = wl1271_op_tx,
1714 .set_key = wl1271_op_set_key,
1715 .hw_scan = wl1271_op_hw_scan,
1716 .bss_info_changed = wl1271_op_bss_info_changed,
1717 .set_rts_threshold = wl1271_op_set_rts_threshold,
1718};
1719
1720static int wl1271_register_hw(struct wl1271 *wl)
1721{
1722 int ret;
1723
1724 if (wl->mac80211_registered)
1725 return 0;
1726
1727 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
1728
1729 ret = ieee80211_register_hw(wl->hw);
1730 if (ret < 0) {
1731 wl1271_error("unable to register mac80211 hw: %d", ret);
1732 return ret;
1733 }
1734
1735 wl->mac80211_registered = true;
1736
1737 wl1271_notice("loaded");
1738
1739 return 0;
1740}
1741
1742static int wl1271_init_ieee80211(struct wl1271 *wl)
1743{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03001744 /* The tx descriptor buffer and the TKIP space. */
1745 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
1746 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001747
1748 /* unit us */
1749 /* FIXME: find a proper value */
1750 wl->hw->channel_change_time = 10000;
1751
1752 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03001753 IEEE80211_HW_NOISE_DBM |
1754 IEEE80211_HW_BEACON_FILTER;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001755
1756 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
1757 wl->hw->wiphy->max_scan_ssids = 1;
1758 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
1759
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001760 if (wl1271_11a_enabled())
1761 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
1762
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001763 SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
1764
1765 return 0;
1766}
1767
1768static void wl1271_device_release(struct device *dev)
1769{
1770
1771}
1772
1773static struct platform_device wl1271_device = {
1774 .name = "wl1271",
1775 .id = -1,
1776
1777 /* device model insists to have a release function */
1778 .dev = {
1779 .release = wl1271_device_release,
1780 },
1781};
1782
1783#define WL1271_DEFAULT_CHANNEL 0
1784static int __devinit wl1271_probe(struct spi_device *spi)
1785{
1786 struct wl12xx_platform_data *pdata;
1787 struct ieee80211_hw *hw;
1788 struct wl1271 *wl;
1789 int ret, i;
1790 static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
1791
1792 pdata = spi->dev.platform_data;
1793 if (!pdata) {
1794 wl1271_error("no platform data");
1795 return -ENODEV;
1796 }
1797
1798 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
1799 if (!hw) {
1800 wl1271_error("could not alloc ieee80211_hw");
1801 return -ENOMEM;
1802 }
1803
1804 wl = hw->priv;
1805 memset(wl, 0, sizeof(*wl));
1806
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001807 INIT_LIST_HEAD(&wl->list);
1808
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001809 wl->hw = hw;
1810 dev_set_drvdata(&spi->dev, wl);
1811 wl->spi = spi;
1812
1813 skb_queue_head_init(&wl->tx_queue);
1814
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03001815 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001816 wl->channel = WL1271_DEFAULT_CHANNEL;
1817 wl->scanning = false;
1818 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001819 wl->rx_counter = 0;
1820 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1821 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1822 wl->elp = false;
1823 wl->psm = 0;
1824 wl->psm_requested = false;
1825 wl->tx_queue_stopped = false;
1826 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001827 wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001828 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001829 wl->vif = NULL;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001830 wl->joined = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001831
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03001832 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001833 wl->tx_frames[i] = NULL;
1834
1835 spin_lock_init(&wl->wl_lock);
1836
1837 /*
1838 * In case our MAC address is not correctly set,
1839 * we use a random but Nokia MAC.
1840 */
1841 memcpy(wl->mac_addr, nokia_oui, 3);
1842 get_random_bytes(wl->mac_addr + 3, 3);
1843
1844 wl->state = WL1271_STATE_OFF;
1845 mutex_init(&wl->mutex);
1846
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001847 /* This is the only SPI value that we need to set here, the rest
1848 * comes from the board-peripherals file */
1849 spi->bits_per_word = 32;
1850
1851 ret = spi_setup(spi);
1852 if (ret < 0) {
1853 wl1271_error("spi_setup failed");
1854 goto out_free;
1855 }
1856
1857 wl->set_power = pdata->set_power;
1858 if (!wl->set_power) {
1859 wl1271_error("set power function missing in platform data");
1860 ret = -ENODEV;
1861 goto out_free;
1862 }
1863
1864 wl->irq = spi->irq;
1865 if (wl->irq < 0) {
1866 wl1271_error("irq missing in platform data");
1867 ret = -ENODEV;
1868 goto out_free;
1869 }
1870
1871 ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
1872 if (ret < 0) {
1873 wl1271_error("request_irq() failed: %d", ret);
1874 goto out_free;
1875 }
1876
1877 set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
1878
1879 disable_irq(wl->irq);
1880
1881 ret = platform_device_register(&wl1271_device);
1882 if (ret) {
1883 wl1271_error("couldn't register platform device");
1884 goto out_irq;
1885 }
1886 dev_set_drvdata(&wl1271_device.dev, wl);
1887
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001888 /* Apply default driver configuration. */
1889 wl1271_conf_init(wl);
1890
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001891 ret = wl1271_init_ieee80211(wl);
1892 if (ret)
1893 goto out_platform;
1894
1895 ret = wl1271_register_hw(wl);
1896 if (ret)
1897 goto out_platform;
1898
1899 wl1271_debugfs_init(wl);
1900
1901 wl1271_notice("initialized");
1902
1903 return 0;
1904
1905 out_platform:
1906 platform_device_unregister(&wl1271_device);
1907
1908 out_irq:
1909 free_irq(wl->irq, wl);
1910
1911 out_free:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001912 ieee80211_free_hw(hw);
1913
1914 return ret;
1915}
1916
1917static int __devexit wl1271_remove(struct spi_device *spi)
1918{
1919 struct wl1271 *wl = dev_get_drvdata(&spi->dev);
1920
1921 ieee80211_unregister_hw(wl->hw);
1922
1923 wl1271_debugfs_exit(wl);
1924 platform_device_unregister(&wl1271_device);
1925 free_irq(wl->irq, wl);
1926 kfree(wl->target_mem_map);
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001927 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001928 wl->fw = NULL;
1929 kfree(wl->nvs);
1930 wl->nvs = NULL;
1931
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001932 kfree(wl->fw_status);
1933 kfree(wl->tx_res_if);
1934
1935 ieee80211_free_hw(wl->hw);
1936
1937 return 0;
1938}
1939
1940
1941static struct spi_driver wl1271_spi_driver = {
1942 .driver = {
1943 .name = "wl1271",
1944 .bus = &spi_bus_type,
1945 .owner = THIS_MODULE,
1946 },
1947
1948 .probe = wl1271_probe,
1949 .remove = __devexit_p(wl1271_remove),
1950};
1951
1952static int __init wl1271_init(void)
1953{
1954 int ret;
1955
1956 ret = spi_register_driver(&wl1271_spi_driver);
1957 if (ret < 0) {
1958 wl1271_error("failed to register spi driver: %d", ret);
1959 goto out;
1960 }
1961
1962out:
1963 return ret;
1964}
1965
1966static void __exit wl1271_exit(void)
1967{
1968 spi_unregister_driver(&wl1271_spi_driver);
1969
1970 wl1271_notice("unloaded");
1971}
1972
1973module_init(wl1271_init);
1974module_exit(wl1271_exit);
1975
1976MODULE_LICENSE("GPL");
1977MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
Luciano Coelho2f018722009-10-08 21:56:27 +03001978MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");