blob: 86132bb007875820c08303314e6a436f1644ea5d [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++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300400 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
401 wl->tx_blocks_freed[i];
402
403 wl->tx_blocks_freed[i] =
404 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300405 wl->tx_blocks_available += cnt;
406 total += cnt;
407 }
408
409 /* if more blocks are available now, schedule some tx work */
410 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300411 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300412
413 /* update the host-chipset time offset */
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300414 wl->time_offset = jiffies_to_usecs(jiffies) -
415 le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300416}
417
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300418static void wl1271_irq_work(struct work_struct *work)
419{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300420 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300421 u32 intr;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300422 struct wl1271 *wl =
423 container_of(work, struct wl1271, irq_work);
424
425 mutex_lock(&wl->mutex);
426
427 wl1271_debug(DEBUG_IRQ, "IRQ work");
428
429 if (wl->state == WL1271_STATE_OFF)
430 goto out;
431
432 ret = wl1271_ps_elp_wakeup(wl, true);
433 if (ret < 0)
434 goto out;
435
Juuso Oikarinen74621412009-10-12 15:08:54 +0300436 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300437
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300438 wl1271_fw_status(wl, wl->fw_status);
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300439 intr = le32_to_cpu(wl->fw_status->intr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300440 if (!intr) {
441 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
442 goto out_sleep;
443 }
444
445 intr &= WL1271_INTR_MASK;
446
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300447 if (intr & WL1271_ACX_INTR_EVENT_A) {
448 bool do_ack = (intr & WL1271_ACX_INTR_EVENT_B) ? false : true;
449 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
450 wl1271_event_handle(wl, 0, do_ack);
451 }
452
453 if (intr & WL1271_ACX_INTR_EVENT_B) {
454 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
455 wl1271_event_handle(wl, 1, true);
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300456 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300457
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300458 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
459 wl1271_debug(DEBUG_IRQ,
460 "WL1271_ACX_INTR_INIT_COMPLETE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300461
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300462 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
463 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300464
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300465 if (intr & WL1271_ACX_INTR_DATA) {
466 u8 tx_res_cnt = wl->fw_status->tx_results_counter -
467 wl->tx_results_count;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300468
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300469 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300470
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300471 /* check for tx results */
472 if (tx_res_cnt)
473 wl1271_tx_complete(wl, tx_res_cnt);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300474
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300475 wl1271_rx(wl, wl->fw_status);
476 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300477
478out_sleep:
Juuso Oikarinen74621412009-10-12 15:08:54 +0300479 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
Luciano Coelho73d0a132009-08-11 11:58:27 +0300480 WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300481 wl1271_ps_elp_sleep(wl);
482
483out:
484 mutex_unlock(&wl->mutex);
485}
486
487static irqreturn_t wl1271_irq(int irq, void *cookie)
488{
489 struct wl1271 *wl;
490 unsigned long flags;
491
492 wl1271_debug(DEBUG_IRQ, "IRQ");
493
494 wl = cookie;
495
496 /* complete the ELP completion */
497 spin_lock_irqsave(&wl->wl_lock, flags);
498 if (wl->elp_compl) {
499 complete(wl->elp_compl);
500 wl->elp_compl = NULL;
501 }
502
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300503 ieee80211_queue_work(wl->hw, &wl->irq_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300504 spin_unlock_irqrestore(&wl->wl_lock, flags);
505
506 return IRQ_HANDLED;
507}
508
509static int wl1271_fetch_firmware(struct wl1271 *wl)
510{
511 const struct firmware *fw;
512 int ret;
513
514 ret = request_firmware(&fw, WL1271_FW_NAME, &wl->spi->dev);
515
516 if (ret < 0) {
517 wl1271_error("could not get firmware: %d", ret);
518 return ret;
519 }
520
521 if (fw->size % 4) {
522 wl1271_error("firmware size is not multiple of 32 bits: %zu",
523 fw->size);
524 ret = -EILSEQ;
525 goto out;
526 }
527
528 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300529 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300530
531 if (!wl->fw) {
532 wl1271_error("could not allocate memory for the firmware");
533 ret = -ENOMEM;
534 goto out;
535 }
536
537 memcpy(wl->fw, fw->data, wl->fw_len);
538
539 ret = 0;
540
541out:
542 release_firmware(fw);
543
544 return ret;
545}
546
547static int wl1271_fetch_nvs(struct wl1271 *wl)
548{
549 const struct firmware *fw;
550 int ret;
551
552 ret = request_firmware(&fw, WL1271_NVS_NAME, &wl->spi->dev);
553
554 if (ret < 0) {
555 wl1271_error("could not get nvs file: %d", ret);
556 return ret;
557 }
558
559 if (fw->size % 4) {
560 wl1271_error("nvs size is not multiple of 32 bits: %zu",
561 fw->size);
562 ret = -EILSEQ;
563 goto out;
564 }
565
566 wl->nvs_len = fw->size;
567 wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL);
568
569 if (!wl->nvs) {
570 wl1271_error("could not allocate memory for the nvs file");
571 ret = -ENOMEM;
572 goto out;
573 }
574
575 memcpy(wl->nvs, fw->data, wl->nvs_len);
576
577 ret = 0;
578
579out:
580 release_firmware(fw);
581
582 return ret;
583}
584
585static void wl1271_fw_wakeup(struct wl1271 *wl)
586{
587 u32 elp_reg;
588
589 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300590 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300591}
592
593static int wl1271_setup(struct wl1271 *wl)
594{
595 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
596 if (!wl->fw_status)
597 return -ENOMEM;
598
599 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
600 if (!wl->tx_res_if) {
601 kfree(wl->fw_status);
602 return -ENOMEM;
603 }
604
605 INIT_WORK(&wl->irq_work, wl1271_irq_work);
606 INIT_WORK(&wl->tx_work, wl1271_tx_work);
607 return 0;
608}
609
610static int wl1271_chip_wakeup(struct wl1271 *wl)
611{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300612 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300613 int ret = 0;
614
615 wl1271_power_on(wl);
616 msleep(WL1271_POWER_ON_SLEEP);
617 wl1271_spi_reset(wl);
618 wl1271_spi_init(wl);
619
620 /* We don't need a real memory partition here, because we only want
621 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300622 memset(&partition, 0, sizeof(partition));
623 partition.reg.start = REGISTERS_BASE;
624 partition.reg.size = REGISTERS_DOWN_SIZE;
625 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300626
627 /* ELP module wake up */
628 wl1271_fw_wakeup(wl);
629
630 /* whal_FwCtrl_BootSm() */
631
632 /* 0. read chip id from CHIP_ID */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300633 wl->chip.id = wl1271_spi_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300634
635 /* 1. check if chip id is valid */
636
637 switch (wl->chip.id) {
638 case CHIP_ID_1271_PG10:
639 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
640 wl->chip.id);
641
642 ret = wl1271_setup(wl);
643 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300644 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300645 break;
646 case CHIP_ID_1271_PG20:
647 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
648 wl->chip.id);
649
650 ret = wl1271_setup(wl);
651 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300652 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300653 break;
654 default:
655 wl1271_error("unsupported chip id: 0x%x", wl->chip.id);
656 ret = -ENODEV;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300657 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300658 }
659
660 if (wl->fw == NULL) {
661 ret = wl1271_fetch_firmware(wl);
662 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300663 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300664 }
665
666 /* No NVS from netlink, try to get it from the filesystem */
667 if (wl->nvs == NULL) {
668 ret = wl1271_fetch_nvs(wl);
669 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300670 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300671 }
672
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300673 goto out;
674
675out_power_off:
676 wl1271_power_off(wl);
677
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300678out:
679 return ret;
680}
681
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300682int wl1271_plt_start(struct wl1271 *wl)
683{
684 int ret;
685
686 mutex_lock(&wl->mutex);
687
688 wl1271_notice("power up");
689
690 if (wl->state != WL1271_STATE_OFF) {
691 wl1271_error("cannot go into PLT state because not "
692 "in off state: %d", wl->state);
693 ret = -EBUSY;
694 goto out;
695 }
696
697 wl->state = WL1271_STATE_PLT;
698
699 ret = wl1271_chip_wakeup(wl);
700 if (ret < 0)
701 goto out;
702
703 ret = wl1271_boot(wl);
704 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300705 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300706
707 wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver);
708
709 ret = wl1271_plt_init(wl);
710 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300711 goto out_irq_disable;
712
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300713 /* Make sure power saving is disabled */
714 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
715 if (ret < 0)
716 goto out_irq_disable;
717
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300718 goto out;
719
720out_irq_disable:
721 wl1271_disable_interrupts(wl);
722
723out_power_off:
724 wl1271_power_off(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300725
726out:
727 mutex_unlock(&wl->mutex);
728
729 return ret;
730}
731
732int wl1271_plt_stop(struct wl1271 *wl)
733{
734 int ret = 0;
735
736 mutex_lock(&wl->mutex);
737
738 wl1271_notice("power down");
739
740 if (wl->state != WL1271_STATE_PLT) {
741 wl1271_error("cannot power down because not in PLT "
742 "state: %d", wl->state);
743 ret = -EBUSY;
744 goto out;
745 }
746
747 wl1271_disable_interrupts(wl);
748 wl1271_power_off(wl);
749
750 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300751 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300752
753out:
754 mutex_unlock(&wl->mutex);
755
756 return ret;
757}
758
759
760static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
761{
762 struct wl1271 *wl = hw->priv;
763
764 skb_queue_tail(&wl->tx_queue, skb);
765
766 /*
767 * The chip specific setup must run before the first TX packet -
768 * before that, the tx_work will not be initialized!
769 */
770
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300771 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300772
773 /*
774 * The workqueue is slow to process the tx_queue and we need stop
775 * the queue here, otherwise the queue will get too long.
776 */
777 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) {
778 ieee80211_stop_queues(wl->hw);
779
780 /*
781 * FIXME: this is racy, the variable is not properly
782 * protected. Maybe fix this by removing the stupid
783 * variable altogether and checking the real queue state?
784 */
785 wl->tx_queue_stopped = true;
786 }
787
788 return NETDEV_TX_OK;
789}
790
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300791static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
792 void *arg)
793{
794 struct net_device *dev;
795 struct wireless_dev *wdev;
796 struct wiphy *wiphy;
797 struct ieee80211_hw *hw;
798 struct wl1271 *wl;
799 struct wl1271 *wl_temp;
800 struct in_device *idev;
801 struct in_ifaddr *ifa = arg;
802 int ret = 0;
803
804 /* FIXME: this ugly function should probably be implemented in the
805 * mac80211, and here should only be a simple callback handling actual
806 * setting of the filters. Now we need to dig up references to
807 * various structures to gain access to what we need.
808 * Also, because of this, there is no "initial" setting of the filter
809 * in "op_start", because we don't want to dig up struct net_device
810 * there - the filter will be set upon first change of the interface
811 * IP address. */
812
813 dev = ifa->ifa_dev->dev;
814
815 wdev = dev->ieee80211_ptr;
816 if (wdev == NULL)
817 return -ENODEV;
818
819 wiphy = wdev->wiphy;
820 if (wiphy == NULL)
821 return -ENODEV;
822
823 hw = wiphy_priv(wiphy);
824 if (hw == NULL)
825 return -ENODEV;
826
827 /* Check that the interface is one supported by this driver. */
828 wl_temp = hw->priv;
829 list_for_each_entry(wl, &wl_list, list) {
830 if (wl == wl_temp)
831 break;
832 }
833 if (wl == NULL)
834 return -ENODEV;
835
836 /* Get the interface IP address for the device. "ifa" will become
837 NULL if:
838 - there is no IPV4 protocol address configured
839 - there are multiple (virtual) IPV4 addresses configured
840 When "ifa" is NULL, filtering will be disabled.
841 */
842 ifa = NULL;
843 idev = dev->ip_ptr;
844 if (idev)
845 ifa = idev->ifa_list;
846
847 if (ifa && ifa->ifa_next)
848 ifa = NULL;
849
850 mutex_lock(&wl->mutex);
851
852 if (wl->state == WL1271_STATE_OFF)
853 goto out;
854
855 ret = wl1271_ps_elp_wakeup(wl, false);
856 if (ret < 0)
857 goto out;
858 if (ifa)
859 ret = wl1271_acx_arp_ip_filter(wl, true,
860 (u8 *)&ifa->ifa_address,
861 ACX_IPV4_VERSION);
862 else
863 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
864 ACX_IPV4_VERSION);
865 wl1271_ps_elp_sleep(wl);
866
867out:
868 mutex_unlock(&wl->mutex);
869
870 return ret;
871}
872
873static struct notifier_block wl1271_dev_notifier = {
874 .notifier_call = wl1271_dev_notify,
875};
876
877
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300878static int wl1271_op_start(struct ieee80211_hw *hw)
879{
880 struct wl1271 *wl = hw->priv;
881 int ret = 0;
882
883 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
884
885 mutex_lock(&wl->mutex);
886
887 if (wl->state != WL1271_STATE_OFF) {
888 wl1271_error("cannot start because not in off state: %d",
889 wl->state);
890 ret = -EBUSY;
891 goto out;
892 }
893
894 ret = wl1271_chip_wakeup(wl);
895 if (ret < 0)
896 goto out;
897
898 ret = wl1271_boot(wl);
899 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300900 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300901
902 ret = wl1271_hw_init(wl);
903 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300904 goto out_irq_disable;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300905
906 wl->state = WL1271_STATE_ON;
907
908 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
909
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300910 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300911
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300912out_irq_disable:
913 wl1271_disable_interrupts(wl);
914
915out_power_off:
916 wl1271_power_off(wl);
917
918out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300919 mutex_unlock(&wl->mutex);
920
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300921 if (!ret) {
922 list_add(&wl->list, &wl_list);
923 register_inetaddr_notifier(&wl1271_dev_notifier);
924 }
925
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300926 return ret;
927}
928
929static void wl1271_op_stop(struct ieee80211_hw *hw)
930{
931 struct wl1271 *wl = hw->priv;
932 int i;
933
934 wl1271_info("down");
935
936 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
937
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300938 unregister_inetaddr_notifier(&wl1271_dev_notifier);
939 list_del(&wl->list);
940
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300941 mutex_lock(&wl->mutex);
942
943 WARN_ON(wl->state != WL1271_STATE_ON);
944
945 if (wl->scanning) {
946 mutex_unlock(&wl->mutex);
947 ieee80211_scan_completed(wl->hw, true);
948 mutex_lock(&wl->mutex);
949 wl->scanning = false;
950 }
951
952 wl->state = WL1271_STATE_OFF;
953
954 wl1271_disable_interrupts(wl);
955
956 mutex_unlock(&wl->mutex);
957
958 cancel_work_sync(&wl->irq_work);
959 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300960
961 mutex_lock(&wl->mutex);
962
963 /* let's notify MAC80211 about the remaining pending TX frames */
964 wl1271_tx_flush(wl);
965 wl1271_power_off(wl);
966
967 memset(wl->bssid, 0, ETH_ALEN);
968 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
969 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300970 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +0300971 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300972
973 wl->rx_counter = 0;
974 wl->elp = false;
975 wl->psm = 0;
976 wl->tx_queue_stopped = false;
977 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
978 wl->tx_blocks_available = 0;
979 wl->tx_results_count = 0;
980 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +0300981 wl->tx_security_last_seq = 0;
982 wl->tx_security_seq_16 = 0;
983 wl->tx_security_seq_32 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300984 wl->time_offset = 0;
985 wl->session_counter = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +0300986 wl->joined = false;
987
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300988 for (i = 0; i < NUM_TX_QUEUES; i++)
989 wl->tx_blocks_freed[i] = 0;
990
991 wl1271_debugfs_reset(wl);
992 mutex_unlock(&wl->mutex);
993}
994
995static int wl1271_op_add_interface(struct ieee80211_hw *hw,
996 struct ieee80211_if_init_conf *conf)
997{
998 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300999 int ret = 0;
1000
John W. Linvillee5539bc2009-08-18 10:50:34 -04001001 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1002 conf->type, conf->mac_addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001003
1004 mutex_lock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001005 if (wl->vif) {
1006 ret = -EBUSY;
1007 goto out;
1008 }
1009
1010 wl->vif = conf->vif;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001011
1012 switch (conf->type) {
1013 case NL80211_IFTYPE_STATION:
1014 wl->bss_type = BSS_TYPE_STA_BSS;
1015 break;
1016 case NL80211_IFTYPE_ADHOC:
1017 wl->bss_type = BSS_TYPE_IBSS;
1018 break;
1019 default:
1020 ret = -EOPNOTSUPP;
1021 goto out;
1022 }
1023
1024 /* FIXME: what if conf->mac_addr changes? */
1025
1026out:
1027 mutex_unlock(&wl->mutex);
1028 return ret;
1029}
1030
1031static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1032 struct ieee80211_if_init_conf *conf)
1033{
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001034 struct wl1271 *wl = hw->priv;
1035
1036 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001037 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001038 wl->vif = NULL;
1039 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001040}
1041
1042#if 0
1043static int wl1271_op_config_interface(struct ieee80211_hw *hw,
1044 struct ieee80211_vif *vif,
1045 struct ieee80211_if_conf *conf)
1046{
1047 struct wl1271 *wl = hw->priv;
1048 struct sk_buff *beacon;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001049 int ret;
1050
David S. Miller32646902009-09-17 10:18:30 -07001051 wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM",
1052 conf->bssid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001053 wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid,
1054 conf->ssid_len);
1055
1056 mutex_lock(&wl->mutex);
1057
1058 ret = wl1271_ps_elp_wakeup(wl, false);
1059 if (ret < 0)
1060 goto out;
1061
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001062 if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
1063 wl1271_debug(DEBUG_MAC80211, "bssid changed");
1064
1065 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
1066
1067 ret = wl1271_cmd_join(wl);
1068 if (ret < 0)
1069 goto out_sleep;
1070 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001071
1072 ret = wl1271_cmd_build_null_data(wl);
1073 if (ret < 0)
1074 goto out_sleep;
1075
1076 wl->ssid_len = conf->ssid_len;
1077 if (wl->ssid_len)
1078 memcpy(wl->ssid, conf->ssid, wl->ssid_len);
1079
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001080 if (conf->changed & IEEE80211_IFCC_BEACON) {
1081 beacon = ieee80211_beacon_get(hw, vif);
1082 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1083 beacon->data, beacon->len);
1084
1085 if (ret < 0) {
1086 dev_kfree_skb(beacon);
1087 goto out_sleep;
1088 }
1089
1090 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE,
1091 beacon->data, beacon->len);
1092
1093 dev_kfree_skb(beacon);
1094
1095 if (ret < 0)
1096 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001097 }
1098
1099out_sleep:
1100 wl1271_ps_elp_sleep(wl);
1101
1102out:
1103 mutex_unlock(&wl->mutex);
1104
1105 return ret;
1106}
1107#endif
1108
1109static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1110{
1111 struct wl1271 *wl = hw->priv;
1112 struct ieee80211_conf *conf = &hw->conf;
1113 int channel, ret = 0;
1114
1115 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1116
1117 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
1118 channel,
1119 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
1120 conf->power_level);
1121
1122 mutex_lock(&wl->mutex);
1123
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001124 wl->band = conf->channel->band;
1125
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001126 ret = wl1271_ps_elp_wakeup(wl, false);
1127 if (ret < 0)
1128 goto out;
1129
1130 if (channel != wl->channel) {
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001131 /*
1132 * We assume that the stack will configure the right channel
1133 * before associating, so we don't need to send a join
1134 * command here. We will join the right channel when the
1135 * BSSID changes
1136 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001137 wl->channel = channel;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001138 }
1139
1140 ret = wl1271_cmd_build_null_data(wl);
1141 if (ret < 0)
1142 goto out_sleep;
1143
1144 if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) {
1145 wl1271_info("psm enabled");
1146
1147 wl->psm_requested = true;
1148
1149 /*
1150 * We enter PSM only if we're already associated.
1151 * If we're not, we'll enter it when joining an SSID,
1152 * through the bss_info_changed() hook.
1153 */
1154 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
1155 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
1156 wl->psm_requested) {
1157 wl1271_info("psm disabled");
1158
1159 wl->psm_requested = false;
1160
1161 if (wl->psm)
1162 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE);
1163 }
1164
1165 if (conf->power_level != wl->power_level) {
1166 ret = wl1271_acx_tx_power(wl, conf->power_level);
1167 if (ret < 0)
1168 goto out;
1169
1170 wl->power_level = conf->power_level;
1171 }
1172
1173out_sleep:
1174 wl1271_ps_elp_sleep(wl);
1175
1176out:
1177 mutex_unlock(&wl->mutex);
1178
1179 return ret;
1180}
1181
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001182struct wl1271_filter_params {
1183 bool enabled;
1184 int mc_list_length;
1185 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1186};
1187
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001188static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1189 struct dev_addr_list *mc_list)
1190{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001191 struct wl1271_filter_params *fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001192 int i;
1193
Juuso Oikarinen74441132009-10-13 12:47:53 +03001194 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001195 if (!fp) {
1196 wl1271_error("Out of memory setting filters.");
1197 return 0;
1198 }
1199
1200 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001201 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001202 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1203 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001204 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001205 }
1206
1207 fp->mc_list_length = 0;
1208 for (i = 0; i < mc_count; i++) {
1209 if (mc_list->da_addrlen == ETH_ALEN) {
1210 memcpy(fp->mc_list[fp->mc_list_length],
1211 mc_list->da_addr, ETH_ALEN);
1212 fp->mc_list_length++;
1213 } else
1214 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001215 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001216 }
1217
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001218 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001219}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001220
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001221#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1222 FIF_ALLMULTI | \
1223 FIF_FCSFAIL | \
1224 FIF_BCN_PRBRESP_PROMISC | \
1225 FIF_CONTROL | \
1226 FIF_OTHER_BSS)
1227
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001228static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1229 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001230 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001231{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001232 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001233 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001234 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001235
1236 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1237
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001238 mutex_lock(&wl->mutex);
1239
1240 if (wl->state == WL1271_STATE_OFF)
1241 goto out;
1242
1243 ret = wl1271_ps_elp_wakeup(wl, false);
1244 if (ret < 0)
1245 goto out;
1246
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001247 *total &= WL1271_SUPPORTED_FILTERS;
1248 changed &= WL1271_SUPPORTED_FILTERS;
1249
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001250 if (*total & FIF_ALLMULTI)
1251 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1252 else if (fp)
1253 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1254 fp->mc_list,
1255 fp->mc_list_length);
1256 if (ret < 0)
1257 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001258
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001259 kfree(fp);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001260
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001261 /* FIXME: We still need to set our filters properly */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001262
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001263 /* determine, whether supported filter values have changed */
1264 if (changed == 0)
1265 goto out_sleep;
1266
1267 /* apply configured filters */
1268 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1269 if (ret < 0)
1270 goto out_sleep;
1271
1272out_sleep:
1273 wl1271_ps_elp_sleep(wl);
1274
1275out:
1276 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001277}
1278
1279static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1280 struct ieee80211_vif *vif,
1281 struct ieee80211_sta *sta,
1282 struct ieee80211_key_conf *key_conf)
1283{
1284 struct wl1271 *wl = hw->priv;
1285 const u8 *addr;
1286 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001287 u32 tx_seq_32 = 0;
1288 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001289 u8 key_type;
1290
1291 static const u8 bcast_addr[ETH_ALEN] =
1292 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1293
1294 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1295
1296 addr = sta ? sta->addr : bcast_addr;
1297
1298 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1299 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1300 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1301 key_conf->alg, key_conf->keyidx,
1302 key_conf->keylen, key_conf->flags);
1303 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1304
1305 if (is_zero_ether_addr(addr)) {
1306 /* We dont support TX only encryption */
1307 ret = -EOPNOTSUPP;
1308 goto out;
1309 }
1310
1311 mutex_lock(&wl->mutex);
1312
1313 ret = wl1271_ps_elp_wakeup(wl, false);
1314 if (ret < 0)
1315 goto out_unlock;
1316
1317 switch (key_conf->alg) {
1318 case ALG_WEP:
1319 key_type = KEY_WEP;
1320
1321 key_conf->hw_key_idx = key_conf->keyidx;
1322 break;
1323 case ALG_TKIP:
1324 key_type = KEY_TKIP;
1325
1326 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001327 tx_seq_32 = wl->tx_security_seq_32;
1328 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001329 break;
1330 case ALG_CCMP:
1331 key_type = KEY_AES;
1332
1333 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001334 tx_seq_32 = wl->tx_security_seq_32;
1335 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001336 break;
1337 default:
1338 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1339
1340 ret = -EOPNOTSUPP;
1341 goto out_sleep;
1342 }
1343
1344 switch (cmd) {
1345 case SET_KEY:
1346 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1347 key_conf->keyidx, key_type,
1348 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001349 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001350 if (ret < 0) {
1351 wl1271_error("Could not add or replace key");
1352 goto out_sleep;
1353 }
1354 break;
1355
1356 case DISABLE_KEY:
1357 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1358 key_conf->keyidx, key_type,
1359 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001360 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001361 if (ret < 0) {
1362 wl1271_error("Could not remove key");
1363 goto out_sleep;
1364 }
1365 break;
1366
1367 default:
1368 wl1271_error("Unsupported key cmd 0x%x", cmd);
1369 ret = -EOPNOTSUPP;
1370 goto out_sleep;
1371
1372 break;
1373 }
1374
1375out_sleep:
1376 wl1271_ps_elp_sleep(wl);
1377
1378out_unlock:
1379 mutex_unlock(&wl->mutex);
1380
1381out:
1382 return ret;
1383}
1384
1385static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1386 struct cfg80211_scan_request *req)
1387{
1388 struct wl1271 *wl = hw->priv;
1389 int ret;
1390 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001391 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001392
1393 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1394
1395 if (req->n_ssids) {
1396 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001397 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001398 }
1399
1400 mutex_lock(&wl->mutex);
1401
1402 ret = wl1271_ps_elp_wakeup(wl, false);
1403 if (ret < 0)
1404 goto out;
1405
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001406 if (wl1271_11a_enabled())
1407 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1408 WL1271_SCAN_BAND_DUAL, 3);
1409 else
1410 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1411 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001412
1413 wl1271_ps_elp_sleep(wl);
1414
1415out:
1416 mutex_unlock(&wl->mutex);
1417
1418 return ret;
1419}
1420
1421static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1422{
1423 struct wl1271 *wl = hw->priv;
1424 int ret;
1425
1426 mutex_lock(&wl->mutex);
1427
1428 ret = wl1271_ps_elp_wakeup(wl, false);
1429 if (ret < 0)
1430 goto out;
1431
1432 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1433 if (ret < 0)
1434 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1435
1436 wl1271_ps_elp_sleep(wl);
1437
1438out:
1439 mutex_unlock(&wl->mutex);
1440
1441 return ret;
1442}
1443
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001444static u32 wl1271_enabled_rates_get(struct wl1271 *wl, u64 basic_rate_set)
1445{
1446 struct ieee80211_supported_band *band;
1447 u32 enabled_rates = 0;
1448 int bit;
1449
1450 band = wl->hw->wiphy->bands[wl->band];
1451 for (bit = 0; bit < band->n_bitrates; bit++) {
1452 if (basic_rate_set & 0x1)
1453 enabled_rates |= band->bitrates[bit].hw_value;
1454 basic_rate_set >>= 1;
1455 }
1456
1457 return enabled_rates;
1458}
1459
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001460static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1461 struct ieee80211_vif *vif,
1462 struct ieee80211_bss_conf *bss_conf,
1463 u32 changed)
1464{
1465 enum wl1271_cmd_ps_mode mode;
1466 struct wl1271 *wl = hw->priv;
1467 int ret;
1468
1469 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1470
1471 mutex_lock(&wl->mutex);
1472
1473 ret = wl1271_ps_elp_wakeup(wl, false);
1474 if (ret < 0)
1475 goto out;
1476
1477 if (changed & BSS_CHANGED_ASSOC) {
1478 if (bss_conf->assoc) {
1479 wl->aid = bss_conf->aid;
1480
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001481 /*
1482 * with wl1271, we don't need to update the
1483 * beacon_int and dtim_period, because the firmware
1484 * updates it by itself when the first beacon is
1485 * received after a join.
1486 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001487 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1488 if (ret < 0)
1489 goto out_sleep;
1490
1491 ret = wl1271_acx_aid(wl, wl->aid);
1492 if (ret < 0)
1493 goto out_sleep;
1494
1495 /* If we want to go in PSM but we're not there yet */
1496 if (wl->psm_requested && !wl->psm) {
1497 mode = STATION_POWER_SAVE_MODE;
1498 ret = wl1271_ps_set_mode(wl, mode);
1499 if (ret < 0)
1500 goto out_sleep;
1501 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001502 } else {
1503 /* use defaults when not associated */
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001504 wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
1505 wl->aid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001506 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001507
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001508 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001509
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001510 if (changed & BSS_CHANGED_ERP_SLOT) {
1511 if (bss_conf->use_short_slot)
1512 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1513 else
1514 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1515 if (ret < 0) {
1516 wl1271_warning("Set slot time failed %d", ret);
1517 goto out_sleep;
1518 }
1519 }
1520
1521 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1522 if (bss_conf->use_short_preamble)
1523 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1524 else
1525 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1526 }
1527
1528 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1529 if (bss_conf->use_cts_prot)
1530 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1531 else
1532 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1533 if (ret < 0) {
1534 wl1271_warning("Set ctsprotect failed %d", ret);
1535 goto out_sleep;
1536 }
1537 }
1538
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001539 if (changed & BSS_CHANGED_BASIC_RATES) {
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001540 wl->basic_rate_set = wl1271_enabled_rates_get(
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001541 wl, bss_conf->basic_rates);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001542
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001543 ret = wl1271_acx_rate_policies(wl, wl->basic_rate_set);
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001544 if (ret < 0) {
1545 wl1271_warning("Set rate policies failed %d", ret);
1546 goto out_sleep;
1547 }
1548 }
1549
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001550out_sleep:
1551 wl1271_ps_elp_sleep(wl);
1552
1553out:
1554 mutex_unlock(&wl->mutex);
1555}
1556
1557
1558/* can't be const, mac80211 writes to this */
1559static struct ieee80211_rate wl1271_rates[] = {
1560 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001561 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1562 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001563 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001564 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1565 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001566 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1567 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001568 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1569 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001570 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1571 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001572 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1573 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001574 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1575 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001576 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1577 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001578 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001579 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1580 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001581 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001582 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1583 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001584 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001585 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1586 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001587 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001588 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1589 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001590 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001591 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1592 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001593 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001594 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1595 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001596 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001597 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1598 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001599};
1600
1601/* can't be const, mac80211 writes to this */
1602static struct ieee80211_channel wl1271_channels[] = {
1603 { .hw_value = 1, .center_freq = 2412},
1604 { .hw_value = 2, .center_freq = 2417},
1605 { .hw_value = 3, .center_freq = 2422},
1606 { .hw_value = 4, .center_freq = 2427},
1607 { .hw_value = 5, .center_freq = 2432},
1608 { .hw_value = 6, .center_freq = 2437},
1609 { .hw_value = 7, .center_freq = 2442},
1610 { .hw_value = 8, .center_freq = 2447},
1611 { .hw_value = 9, .center_freq = 2452},
1612 { .hw_value = 10, .center_freq = 2457},
1613 { .hw_value = 11, .center_freq = 2462},
1614 { .hw_value = 12, .center_freq = 2467},
1615 { .hw_value = 13, .center_freq = 2472},
1616};
1617
1618/* can't be const, mac80211 writes to this */
1619static struct ieee80211_supported_band wl1271_band_2ghz = {
1620 .channels = wl1271_channels,
1621 .n_channels = ARRAY_SIZE(wl1271_channels),
1622 .bitrates = wl1271_rates,
1623 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1624};
1625
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001626/* 5 GHz data rates for WL1273 */
1627static struct ieee80211_rate wl1271_rates_5ghz[] = {
1628 { .bitrate = 60,
1629 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1630 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
1631 { .bitrate = 90,
1632 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1633 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
1634 { .bitrate = 120,
1635 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1636 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
1637 { .bitrate = 180,
1638 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1639 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
1640 { .bitrate = 240,
1641 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1642 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
1643 { .bitrate = 360,
1644 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1645 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
1646 { .bitrate = 480,
1647 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1648 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
1649 { .bitrate = 540,
1650 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1651 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
1652};
1653
1654/* 5 GHz band channels for WL1273 */
1655static struct ieee80211_channel wl1271_channels_5ghz[] = {
1656 { .hw_value = 183, .center_freq = 4915},
1657 { .hw_value = 184, .center_freq = 4920},
1658 { .hw_value = 185, .center_freq = 4925},
1659 { .hw_value = 187, .center_freq = 4935},
1660 { .hw_value = 188, .center_freq = 4940},
1661 { .hw_value = 189, .center_freq = 4945},
1662 { .hw_value = 192, .center_freq = 4960},
1663 { .hw_value = 196, .center_freq = 4980},
1664 { .hw_value = 7, .center_freq = 5035},
1665 { .hw_value = 8, .center_freq = 5040},
1666 { .hw_value = 9, .center_freq = 5045},
1667 { .hw_value = 11, .center_freq = 5055},
1668 { .hw_value = 12, .center_freq = 5060},
1669 { .hw_value = 16, .center_freq = 5080},
1670 { .hw_value = 34, .center_freq = 5170},
1671 { .hw_value = 36, .center_freq = 5180},
1672 { .hw_value = 38, .center_freq = 5190},
1673 { .hw_value = 40, .center_freq = 5200},
1674 { .hw_value = 42, .center_freq = 5210},
1675 { .hw_value = 44, .center_freq = 5220},
1676 { .hw_value = 46, .center_freq = 5230},
1677 { .hw_value = 48, .center_freq = 5240},
1678 { .hw_value = 52, .center_freq = 5260},
1679 { .hw_value = 56, .center_freq = 5280},
1680 { .hw_value = 60, .center_freq = 5300},
1681 { .hw_value = 64, .center_freq = 5320},
1682 { .hw_value = 100, .center_freq = 5500},
1683 { .hw_value = 104, .center_freq = 5520},
1684 { .hw_value = 108, .center_freq = 5540},
1685 { .hw_value = 112, .center_freq = 5560},
1686 { .hw_value = 116, .center_freq = 5580},
1687 { .hw_value = 120, .center_freq = 5600},
1688 { .hw_value = 124, .center_freq = 5620},
1689 { .hw_value = 128, .center_freq = 5640},
1690 { .hw_value = 132, .center_freq = 5660},
1691 { .hw_value = 136, .center_freq = 5680},
1692 { .hw_value = 140, .center_freq = 5700},
1693 { .hw_value = 149, .center_freq = 5745},
1694 { .hw_value = 153, .center_freq = 5765},
1695 { .hw_value = 157, .center_freq = 5785},
1696 { .hw_value = 161, .center_freq = 5805},
1697 { .hw_value = 165, .center_freq = 5825},
1698};
1699
1700
1701static struct ieee80211_supported_band wl1271_band_5ghz = {
1702 .channels = wl1271_channels_5ghz,
1703 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
1704 .bitrates = wl1271_rates_5ghz,
1705 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
1706};
1707
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001708static const struct ieee80211_ops wl1271_ops = {
1709 .start = wl1271_op_start,
1710 .stop = wl1271_op_stop,
1711 .add_interface = wl1271_op_add_interface,
1712 .remove_interface = wl1271_op_remove_interface,
1713 .config = wl1271_op_config,
1714/* .config_interface = wl1271_op_config_interface, */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001715 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001716 .configure_filter = wl1271_op_configure_filter,
1717 .tx = wl1271_op_tx,
1718 .set_key = wl1271_op_set_key,
1719 .hw_scan = wl1271_op_hw_scan,
1720 .bss_info_changed = wl1271_op_bss_info_changed,
1721 .set_rts_threshold = wl1271_op_set_rts_threshold,
1722};
1723
1724static int wl1271_register_hw(struct wl1271 *wl)
1725{
1726 int ret;
1727
1728 if (wl->mac80211_registered)
1729 return 0;
1730
1731 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
1732
1733 ret = ieee80211_register_hw(wl->hw);
1734 if (ret < 0) {
1735 wl1271_error("unable to register mac80211 hw: %d", ret);
1736 return ret;
1737 }
1738
1739 wl->mac80211_registered = true;
1740
1741 wl1271_notice("loaded");
1742
1743 return 0;
1744}
1745
1746static int wl1271_init_ieee80211(struct wl1271 *wl)
1747{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03001748 /* The tx descriptor buffer and the TKIP space. */
1749 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
1750 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001751
1752 /* unit us */
1753 /* FIXME: find a proper value */
1754 wl->hw->channel_change_time = 10000;
1755
1756 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03001757 IEEE80211_HW_NOISE_DBM |
1758 IEEE80211_HW_BEACON_FILTER;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001759
1760 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
1761 wl->hw->wiphy->max_scan_ssids = 1;
1762 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
1763
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001764 if (wl1271_11a_enabled())
1765 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
1766
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001767 SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
1768
1769 return 0;
1770}
1771
1772static void wl1271_device_release(struct device *dev)
1773{
1774
1775}
1776
1777static struct platform_device wl1271_device = {
1778 .name = "wl1271",
1779 .id = -1,
1780
1781 /* device model insists to have a release function */
1782 .dev = {
1783 .release = wl1271_device_release,
1784 },
1785};
1786
1787#define WL1271_DEFAULT_CHANNEL 0
1788static int __devinit wl1271_probe(struct spi_device *spi)
1789{
1790 struct wl12xx_platform_data *pdata;
1791 struct ieee80211_hw *hw;
1792 struct wl1271 *wl;
1793 int ret, i;
1794 static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
1795
1796 pdata = spi->dev.platform_data;
1797 if (!pdata) {
1798 wl1271_error("no platform data");
1799 return -ENODEV;
1800 }
1801
1802 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
1803 if (!hw) {
1804 wl1271_error("could not alloc ieee80211_hw");
1805 return -ENOMEM;
1806 }
1807
1808 wl = hw->priv;
1809 memset(wl, 0, sizeof(*wl));
1810
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001811 INIT_LIST_HEAD(&wl->list);
1812
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001813 wl->hw = hw;
1814 dev_set_drvdata(&spi->dev, wl);
1815 wl->spi = spi;
1816
1817 skb_queue_head_init(&wl->tx_queue);
1818
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03001819 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001820 wl->channel = WL1271_DEFAULT_CHANNEL;
1821 wl->scanning = false;
1822 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001823 wl->rx_counter = 0;
1824 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1825 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1826 wl->elp = false;
1827 wl->psm = 0;
1828 wl->psm_requested = false;
1829 wl->tx_queue_stopped = false;
1830 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001831 wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001832 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001833 wl->vif = NULL;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001834 wl->joined = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001835
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03001836 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001837 wl->tx_frames[i] = NULL;
1838
1839 spin_lock_init(&wl->wl_lock);
1840
1841 /*
1842 * In case our MAC address is not correctly set,
1843 * we use a random but Nokia MAC.
1844 */
1845 memcpy(wl->mac_addr, nokia_oui, 3);
1846 get_random_bytes(wl->mac_addr + 3, 3);
1847
1848 wl->state = WL1271_STATE_OFF;
1849 mutex_init(&wl->mutex);
1850
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001851 /* This is the only SPI value that we need to set here, the rest
1852 * comes from the board-peripherals file */
1853 spi->bits_per_word = 32;
1854
1855 ret = spi_setup(spi);
1856 if (ret < 0) {
1857 wl1271_error("spi_setup failed");
1858 goto out_free;
1859 }
1860
1861 wl->set_power = pdata->set_power;
1862 if (!wl->set_power) {
1863 wl1271_error("set power function missing in platform data");
1864 ret = -ENODEV;
1865 goto out_free;
1866 }
1867
1868 wl->irq = spi->irq;
1869 if (wl->irq < 0) {
1870 wl1271_error("irq missing in platform data");
1871 ret = -ENODEV;
1872 goto out_free;
1873 }
1874
1875 ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
1876 if (ret < 0) {
1877 wl1271_error("request_irq() failed: %d", ret);
1878 goto out_free;
1879 }
1880
1881 set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
1882
1883 disable_irq(wl->irq);
1884
1885 ret = platform_device_register(&wl1271_device);
1886 if (ret) {
1887 wl1271_error("couldn't register platform device");
1888 goto out_irq;
1889 }
1890 dev_set_drvdata(&wl1271_device.dev, wl);
1891
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001892 /* Apply default driver configuration. */
1893 wl1271_conf_init(wl);
1894
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001895 ret = wl1271_init_ieee80211(wl);
1896 if (ret)
1897 goto out_platform;
1898
1899 ret = wl1271_register_hw(wl);
1900 if (ret)
1901 goto out_platform;
1902
1903 wl1271_debugfs_init(wl);
1904
1905 wl1271_notice("initialized");
1906
1907 return 0;
1908
1909 out_platform:
1910 platform_device_unregister(&wl1271_device);
1911
1912 out_irq:
1913 free_irq(wl->irq, wl);
1914
1915 out_free:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001916 ieee80211_free_hw(hw);
1917
1918 return ret;
1919}
1920
1921static int __devexit wl1271_remove(struct spi_device *spi)
1922{
1923 struct wl1271 *wl = dev_get_drvdata(&spi->dev);
1924
1925 ieee80211_unregister_hw(wl->hw);
1926
1927 wl1271_debugfs_exit(wl);
1928 platform_device_unregister(&wl1271_device);
1929 free_irq(wl->irq, wl);
1930 kfree(wl->target_mem_map);
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001931 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001932 wl->fw = NULL;
1933 kfree(wl->nvs);
1934 wl->nvs = NULL;
1935
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001936 kfree(wl->fw_status);
1937 kfree(wl->tx_res_if);
1938
1939 ieee80211_free_hw(wl->hw);
1940
1941 return 0;
1942}
1943
1944
1945static struct spi_driver wl1271_spi_driver = {
1946 .driver = {
1947 .name = "wl1271",
1948 .bus = &spi_bus_type,
1949 .owner = THIS_MODULE,
1950 },
1951
1952 .probe = wl1271_probe,
1953 .remove = __devexit_p(wl1271_remove),
1954};
1955
1956static int __init wl1271_init(void)
1957{
1958 int ret;
1959
1960 ret = spi_register_driver(&wl1271_spi_driver);
1961 if (ret < 0) {
1962 wl1271_error("failed to register spi driver: %d", ret);
1963 goto out;
1964 }
1965
1966out:
1967 return ret;
1968}
1969
1970static void __exit wl1271_exit(void)
1971{
1972 spi_unregister_driver(&wl1271_spi_driver);
1973
1974 wl1271_notice("unloaded");
1975}
1976
1977module_init(wl1271_init);
1978module_exit(wl1271_exit);
1979
1980MODULE_LICENSE("GPL");
1981MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
Luciano Coelho2f018722009-10-08 21:56:27 +03001982MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");