blob: 64d05265f7e0316de9c8a2ed787240aa95352c38 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
4 * Copyright (C) 2008-2009 Nokia Corporation
5 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
25#include <linux/platform_device.h>
26#include <linux/interrupt.h>
27#include <linux/firmware.h>
28#include <linux/delay.h>
29#include <linux/irq.h>
30#include <linux/spi/spi.h>
31#include <linux/crc32.h>
32#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030033#include <linux/vmalloc.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030034#include <linux/spi/wl12xx.h>
Juuso Oikarinen01c09162009-10-13 12:47:55 +030035#include <linux/inetdevice.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036
37#include "wl1271.h"
38#include "wl12xx_80211.h"
39#include "wl1271_reg.h"
40#include "wl1271_spi.h"
41#include "wl1271_event.h"
42#include "wl1271_tx.h"
43#include "wl1271_rx.h"
44#include "wl1271_ps.h"
45#include "wl1271_init.h"
46#include "wl1271_debugfs.h"
47#include "wl1271_cmd.h"
48#include "wl1271_boot.h"
49
Juuso Oikarinen8a080482009-10-13 12:47:44 +030050static struct conf_drv_settings default_conf = {
51 .sg = {
52 .per_threshold = 7500,
53 .max_scan_compensation_time = 120000,
54 .nfs_sample_interval = 400,
55 .load_ratio = 50,
56 .auto_ps_mode = 0,
57 .probe_req_compensation = 170,
58 .scan_window_compensation = 50,
59 .antenna_config = 0,
60 .beacon_miss_threshold = 60,
61 .rate_adaptation_threshold = CONF_HW_BIT_RATE_12MBPS,
62 .rate_adaptation_snr = 0
63 },
64 .rx = {
65 .rx_msdu_life_time = 512000,
66 .packet_detection_threshold = 0,
67 .ps_poll_timeout = 15,
68 .upsd_timeout = 15,
69 .rts_threshold = 2347,
70 .rx_cca_threshold = 0xFFEF,
71 .irq_blk_threshold = 0,
72 .irq_pkt_threshold = USHORT_MAX,
73 .irq_timeout = 5,
74 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
75 },
76 .tx = {
77 .tx_energy_detection = 0,
78 .rc_conf = {
79 .enabled_rates = CONF_TX_RATE_MASK_UNSPECIFIED,
80 .short_retry_limit = 10,
81 .long_retry_limit = 10,
82 .aflags = 0
83 },
84 .ac_conf_count = 4,
85 .ac_conf = {
86 [0] = {
87 .ac = CONF_TX_AC_BE,
88 .cw_min = 15,
89 .cw_max = 63,
90 .aifsn = 3,
91 .tx_op_limit = 0,
92 },
93 [1] = {
94 .ac = CONF_TX_AC_BK,
95 .cw_min = 15,
96 .cw_max = 63,
97 .aifsn = 7,
98 .tx_op_limit = 0,
99 },
100 [2] = {
101 .ac = CONF_TX_AC_VI,
102 .cw_min = 15,
103 .cw_max = 63,
104 .aifsn = CONF_TX_AIFS_PIFS,
105 .tx_op_limit = 3008,
106 },
107 [3] = {
108 .ac = CONF_TX_AC_VO,
109 .cw_min = 15,
110 .cw_max = 63,
111 .aifsn = CONF_TX_AIFS_PIFS,
112 .tx_op_limit = 1504,
113 },
114 },
115 .tid_conf_count = 7,
116 .tid_conf = {
117 [0] = {
118 .queue_id = 0,
119 .channel_type = CONF_CHANNEL_TYPE_DCF,
120 .tsid = CONF_TX_AC_BE,
121 .ps_scheme = CONF_PS_SCHEME_LEGACY,
122 .ack_policy = CONF_ACK_POLICY_LEGACY,
123 .apsd_conf = {0, 0},
124 },
125 [1] = {
126 .queue_id = 1,
127 .channel_type = CONF_CHANNEL_TYPE_DCF,
128 .tsid = CONF_TX_AC_BE,
129 .ps_scheme = CONF_PS_SCHEME_LEGACY,
130 .ack_policy = CONF_ACK_POLICY_LEGACY,
131 .apsd_conf = {0, 0},
132 },
133 [2] = {
134 .queue_id = 2,
135 .channel_type = CONF_CHANNEL_TYPE_DCF,
136 .tsid = CONF_TX_AC_BE,
137 .ps_scheme = CONF_PS_SCHEME_LEGACY,
138 .ack_policy = CONF_ACK_POLICY_LEGACY,
139 .apsd_conf = {0, 0},
140 },
141 [3] = {
142 .queue_id = 3,
143 .channel_type = CONF_CHANNEL_TYPE_DCF,
144 .tsid = CONF_TX_AC_BE,
145 .ps_scheme = CONF_PS_SCHEME_LEGACY,
146 .ack_policy = CONF_ACK_POLICY_LEGACY,
147 .apsd_conf = {0, 0},
148 },
149 [4] = {
150 .queue_id = 4,
151 .channel_type = CONF_CHANNEL_TYPE_DCF,
152 .tsid = CONF_TX_AC_BE,
153 .ps_scheme = CONF_PS_SCHEME_LEGACY,
154 .ack_policy = CONF_ACK_POLICY_LEGACY,
155 .apsd_conf = {0, 0},
156 },
157 [5] = {
158 .queue_id = 5,
159 .channel_type = CONF_CHANNEL_TYPE_DCF,
160 .tsid = CONF_TX_AC_BE,
161 .ps_scheme = CONF_PS_SCHEME_LEGACY,
162 .ack_policy = CONF_ACK_POLICY_LEGACY,
163 .apsd_conf = {0, 0},
164 },
165 [6] = {
166 .queue_id = 6,
167 .channel_type = CONF_CHANNEL_TYPE_DCF,
168 .tsid = CONF_TX_AC_BE,
169 .ps_scheme = CONF_PS_SCHEME_LEGACY,
170 .ack_policy = CONF_ACK_POLICY_LEGACY,
171 .apsd_conf = {0, 0},
172 }
173 },
174 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
175 .tx_compl_timeout = 5,
176 .tx_compl_threshold = 5
177 },
178 .conn = {
179 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
180 .listen_interval = 0,
181 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
182 .bcn_filt_ie_count = 1,
183 .bcn_filt_ie = {
184 [0] = {
185 .ie = WLAN_EID_CHANNEL_SWITCH,
186 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
187 }
188 },
189 .synch_fail_thold = 5,
190 .bss_lose_timeout = 100,
191 .beacon_rx_timeout = 10000,
192 .broadcast_timeout = 20000,
193 .rx_broadcast_in_ps = 1,
194 .ps_poll_threshold = 4,
195 .sig_trigger_count = 2,
196 .sig_trigger = {
197 [0] = {
198 .threshold = -75,
199 .pacing = 500,
200 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
201 .type = CONF_TRIG_EVENT_TYPE_EDGE,
202 .direction = CONF_TRIG_EVENT_DIR_LOW,
203 .hysteresis = 2,
204 .index = 0,
205 .enable = 1
206 },
207 [1] = {
208 .threshold = -75,
209 .pacing = 500,
210 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
211 .type = CONF_TRIG_EVENT_TYPE_EDGE,
212 .direction = CONF_TRIG_EVENT_DIR_HIGH,
213 .hysteresis = 2,
214 .index = 1,
215 .enable = 1
216 }
217 },
218 .sig_weights = {
219 .rssi_bcn_avg_weight = 10,
220 .rssi_pkt_avg_weight = 10,
221 .snr_bcn_avg_weight = 10,
222 .snr_pkt_avg_weight = 10
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300223 },
224 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200225 .bet_max_consecutive = 10,
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200226 .psm_entry_retries = 3
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300227 },
228 .init = {
229 .sr_err_tbl = {
230 [0] = {
231 .len = 7,
232 .upper_limit = 0x03,
233 .values = {
234 0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8,
235 0x00 }
236 },
237 [1] = {
238 .len = 7,
239 .upper_limit = 0x03,
240 .values = {
241 0x18, 0x10, 0x05, 0xf6, 0xf0, 0xe8,
242 0x00 }
243 },
244 [2] = {
245 .len = 7,
246 .upper_limit = 0x03,
247 .values = {
248 0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8,
249 0x00 }
250 }
251 },
252 .sr_enable = 1,
253 .genparam = {
254 /*
255 * FIXME: The correct value CONF_REF_CLK_38_4_E
256 * causes the firmware to crash on boot.
257 * The value 5 apparently is an
258 * unnoficial XTAL configuration of the
259 * same frequency, which appears to work.
260 */
261 .ref_clk = 5,
262 .settling_time = 5,
263 .clk_valid_on_wakeup = 0,
264 .dc2dcmode = 0,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300265 .single_dual_band = CONF_SINGLE_BAND,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300266 .tx_bip_fem_autodetect = 0,
267 .tx_bip_fem_manufacturer = 1,
268 .settings = 1,
269 },
270 .radioparam = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300271 .rx_trace_loss = 10,
272 .tx_trace_loss = 10,
273 .rx_rssi_and_proc_compens = {
274 0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8,
275 0xfc, 0x00, 0x08, 0x10, 0xf0, 0xf8,
276 0x00, 0x0a, 0x14 },
277 .rx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 },
278 .tx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 },
279 .rx_rssi_and_proc_compens_5 = {
280 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
281 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
282 0x00, 0x00, 0x00 },
283 .tx_ref_pd_voltage = 0x24e,
284 .tx_ref_power = 0x78,
285 .tx_offset_db = 0x0,
286 .tx_rate_limits_normal = {
287 0x1e, 0x1f, 0x22, 0x24, 0x28, 0x29 },
288 .tx_rate_limits_degraded = {
289 0x1b, 0x1c, 0x1e, 0x20, 0x24, 0x25 },
290 .tx_channel_limits_11b = {
291 0x22, 0x50, 0x50, 0x50, 0x50, 0x50,
292 0x50, 0x50, 0x50, 0x50, 0x22, 0x50,
293 0x22, 0x50 },
294 .tx_channel_limits_ofdm = {
295 0x20, 0x50, 0x50, 0x50, 0x50, 0x50,
296 0x50, 0x50, 0x50, 0x50, 0x20, 0x50,
297 0x20, 0x50 },
298 .tx_pdv_rate_offsets = {
299 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
300 .tx_ibias = {
301 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x27 },
302 .rx_fem_insertion_loss = 0x14,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300303 .tx_ref_pd_voltage_5 = {
304 0x0190, 0x01a4, 0x01c3, 0x01d8,
305 0x020a, 0x021c },
306 .tx_ref_power_5 = {
307 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 },
308 .tx_offset_db_5 = {
309 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300310 .tx_rate_limits_normal_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300311 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300312 .tx_rate_limits_degraded_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300313 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300314 .tx_channel_limits_ofdm_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300315 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
316 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
317 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
318 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
319 0x50, 0x50, 0x50 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300320 .tx_pdv_rate_offsets_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300321 0x01, 0x02, 0x02, 0x02, 0x02, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300322 .tx_ibias_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300323 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
324 .rx_fem_insertion_loss_5 = {
325 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300326 }
327 }
328};
329
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300330static LIST_HEAD(wl_list);
331
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300332static void wl1271_conf_init(struct wl1271 *wl)
333{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300334
335 /*
336 * This function applies the default configuration to the driver. This
337 * function is invoked upon driver load (spi probe.)
338 *
339 * The configuration is stored in a run-time structure in order to
340 * facilitate for run-time adjustment of any of the parameters. Making
341 * changes to the configuration structure will apply the new values on
342 * the next interface up (wl1271_op_start.)
343 */
344
345 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300346 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300347
348 if (wl1271_11a_enabled())
349 wl->conf.init.genparam.single_dual_band = CONF_DUAL_BAND;
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300350}
351
352
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300353static int wl1271_plt_init(struct wl1271 *wl)
354{
355 int ret;
356
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200357 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200358 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200359 return ret;
360
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200361 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200362 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200363 return ret;
364
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300365 ret = wl1271_acx_init_mem_config(wl);
366 if (ret < 0)
367 return ret;
368
369 ret = wl1271_cmd_data_path(wl, wl->channel, 1);
370 if (ret < 0)
371 return ret;
372
373 return 0;
374}
375
376static void wl1271_disable_interrupts(struct wl1271 *wl)
377{
378 disable_irq(wl->irq);
379}
380
381static void wl1271_power_off(struct wl1271 *wl)
382{
383 wl->set_power(false);
384}
385
386static void wl1271_power_on(struct wl1271 *wl)
387{
388 wl->set_power(true);
389}
390
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300391static void wl1271_fw_status(struct wl1271 *wl,
392 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300393{
394 u32 total = 0;
395 int i;
396
Juuso Oikarinen74621412009-10-12 15:08:54 +0300397 wl1271_spi_read(wl, FW_STATUS_ADDR, status,
398 sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300399
400 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
401 "drv_rx_counter = %d, tx_results_counter = %d)",
402 status->intr,
403 status->fw_rx_counter,
404 status->drv_rx_counter,
405 status->tx_results_counter);
406
407 /* update number of available TX blocks */
408 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300409 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
410 wl->tx_blocks_freed[i];
411
412 wl->tx_blocks_freed[i] =
413 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300414 wl->tx_blocks_available += cnt;
415 total += cnt;
416 }
417
418 /* if more blocks are available now, schedule some tx work */
419 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300420 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300421
422 /* update the host-chipset time offset */
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300423 wl->time_offset = jiffies_to_usecs(jiffies) -
424 le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300425}
426
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300427static void wl1271_irq_work(struct work_struct *work)
428{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300429 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300430 u32 intr;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300431 struct wl1271 *wl =
432 container_of(work, struct wl1271, irq_work);
433
434 mutex_lock(&wl->mutex);
435
436 wl1271_debug(DEBUG_IRQ, "IRQ work");
437
438 if (wl->state == WL1271_STATE_OFF)
439 goto out;
440
441 ret = wl1271_ps_elp_wakeup(wl, true);
442 if (ret < 0)
443 goto out;
444
Juuso Oikarinen74621412009-10-12 15:08:54 +0300445 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300446
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300447 wl1271_fw_status(wl, wl->fw_status);
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300448 intr = le32_to_cpu(wl->fw_status->intr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300449 if (!intr) {
450 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
451 goto out_sleep;
452 }
453
454 intr &= WL1271_INTR_MASK;
455
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300456 if (intr & WL1271_ACX_INTR_EVENT_A) {
457 bool do_ack = (intr & WL1271_ACX_INTR_EVENT_B) ? false : true;
458 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
459 wl1271_event_handle(wl, 0, do_ack);
460 }
461
462 if (intr & WL1271_ACX_INTR_EVENT_B) {
463 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
464 wl1271_event_handle(wl, 1, true);
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300465 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300466
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300467 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
468 wl1271_debug(DEBUG_IRQ,
469 "WL1271_ACX_INTR_INIT_COMPLETE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300470
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300471 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
472 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300473
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300474 if (intr & WL1271_ACX_INTR_DATA) {
475 u8 tx_res_cnt = wl->fw_status->tx_results_counter -
476 wl->tx_results_count;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300477
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300478 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300479
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300480 /* check for tx results */
481 if (tx_res_cnt)
482 wl1271_tx_complete(wl, tx_res_cnt);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300483
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300484 wl1271_rx(wl, wl->fw_status);
485 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300486
487out_sleep:
Juuso Oikarinen74621412009-10-12 15:08:54 +0300488 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
Luciano Coelho73d0a132009-08-11 11:58:27 +0300489 WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300490 wl1271_ps_elp_sleep(wl);
491
492out:
493 mutex_unlock(&wl->mutex);
494}
495
496static irqreturn_t wl1271_irq(int irq, void *cookie)
497{
498 struct wl1271 *wl;
499 unsigned long flags;
500
501 wl1271_debug(DEBUG_IRQ, "IRQ");
502
503 wl = cookie;
504
505 /* complete the ELP completion */
506 spin_lock_irqsave(&wl->wl_lock, flags);
507 if (wl->elp_compl) {
508 complete(wl->elp_compl);
509 wl->elp_compl = NULL;
510 }
511
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300512 ieee80211_queue_work(wl->hw, &wl->irq_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300513 spin_unlock_irqrestore(&wl->wl_lock, flags);
514
515 return IRQ_HANDLED;
516}
517
518static int wl1271_fetch_firmware(struct wl1271 *wl)
519{
520 const struct firmware *fw;
521 int ret;
522
523 ret = request_firmware(&fw, WL1271_FW_NAME, &wl->spi->dev);
524
525 if (ret < 0) {
526 wl1271_error("could not get firmware: %d", ret);
527 return ret;
528 }
529
530 if (fw->size % 4) {
531 wl1271_error("firmware size is not multiple of 32 bits: %zu",
532 fw->size);
533 ret = -EILSEQ;
534 goto out;
535 }
536
537 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300538 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300539
540 if (!wl->fw) {
541 wl1271_error("could not allocate memory for the firmware");
542 ret = -ENOMEM;
543 goto out;
544 }
545
546 memcpy(wl->fw, fw->data, wl->fw_len);
547
548 ret = 0;
549
550out:
551 release_firmware(fw);
552
553 return ret;
554}
555
556static int wl1271_fetch_nvs(struct wl1271 *wl)
557{
558 const struct firmware *fw;
559 int ret;
560
561 ret = request_firmware(&fw, WL1271_NVS_NAME, &wl->spi->dev);
562
563 if (ret < 0) {
564 wl1271_error("could not get nvs file: %d", ret);
565 return ret;
566 }
567
568 if (fw->size % 4) {
569 wl1271_error("nvs size is not multiple of 32 bits: %zu",
570 fw->size);
571 ret = -EILSEQ;
572 goto out;
573 }
574
575 wl->nvs_len = fw->size;
576 wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL);
577
578 if (!wl->nvs) {
579 wl1271_error("could not allocate memory for the nvs file");
580 ret = -ENOMEM;
581 goto out;
582 }
583
584 memcpy(wl->nvs, fw->data, wl->nvs_len);
585
586 ret = 0;
587
588out:
589 release_firmware(fw);
590
591 return ret;
592}
593
594static void wl1271_fw_wakeup(struct wl1271 *wl)
595{
596 u32 elp_reg;
597
598 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300599 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300600}
601
602static int wl1271_setup(struct wl1271 *wl)
603{
604 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
605 if (!wl->fw_status)
606 return -ENOMEM;
607
608 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
609 if (!wl->tx_res_if) {
610 kfree(wl->fw_status);
611 return -ENOMEM;
612 }
613
614 INIT_WORK(&wl->irq_work, wl1271_irq_work);
615 INIT_WORK(&wl->tx_work, wl1271_tx_work);
616 return 0;
617}
618
619static int wl1271_chip_wakeup(struct wl1271 *wl)
620{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300621 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300622 int ret = 0;
623
624 wl1271_power_on(wl);
625 msleep(WL1271_POWER_ON_SLEEP);
626 wl1271_spi_reset(wl);
627 wl1271_spi_init(wl);
628
629 /* We don't need a real memory partition here, because we only want
630 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300631 memset(&partition, 0, sizeof(partition));
632 partition.reg.start = REGISTERS_BASE;
633 partition.reg.size = REGISTERS_DOWN_SIZE;
634 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300635
636 /* ELP module wake up */
637 wl1271_fw_wakeup(wl);
638
639 /* whal_FwCtrl_BootSm() */
640
641 /* 0. read chip id from CHIP_ID */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300642 wl->chip.id = wl1271_spi_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300643
644 /* 1. check if chip id is valid */
645
646 switch (wl->chip.id) {
647 case CHIP_ID_1271_PG10:
648 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
649 wl->chip.id);
650
651 ret = wl1271_setup(wl);
652 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300653 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300654 break;
655 case CHIP_ID_1271_PG20:
656 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
657 wl->chip.id);
658
659 ret = wl1271_setup(wl);
660 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300661 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300662 break;
663 default:
664 wl1271_error("unsupported chip id: 0x%x", wl->chip.id);
665 ret = -ENODEV;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300666 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300667 }
668
669 if (wl->fw == NULL) {
670 ret = wl1271_fetch_firmware(wl);
671 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300672 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300673 }
674
675 /* No NVS from netlink, try to get it from the filesystem */
676 if (wl->nvs == NULL) {
677 ret = wl1271_fetch_nvs(wl);
678 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300679 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300680 }
681
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300682 goto out;
683
684out_power_off:
685 wl1271_power_off(wl);
686
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300687out:
688 return ret;
689}
690
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300691int wl1271_plt_start(struct wl1271 *wl)
692{
693 int ret;
694
695 mutex_lock(&wl->mutex);
696
697 wl1271_notice("power up");
698
699 if (wl->state != WL1271_STATE_OFF) {
700 wl1271_error("cannot go into PLT state because not "
701 "in off state: %d", wl->state);
702 ret = -EBUSY;
703 goto out;
704 }
705
706 wl->state = WL1271_STATE_PLT;
707
708 ret = wl1271_chip_wakeup(wl);
709 if (ret < 0)
710 goto out;
711
712 ret = wl1271_boot(wl);
713 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300714 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300715
716 wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver);
717
718 ret = wl1271_plt_init(wl);
719 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300720 goto out_irq_disable;
721
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300722 /* Make sure power saving is disabled */
723 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
724 if (ret < 0)
725 goto out_irq_disable;
726
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300727 goto out;
728
729out_irq_disable:
730 wl1271_disable_interrupts(wl);
731
732out_power_off:
733 wl1271_power_off(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300734
735out:
736 mutex_unlock(&wl->mutex);
737
738 return ret;
739}
740
741int wl1271_plt_stop(struct wl1271 *wl)
742{
743 int ret = 0;
744
745 mutex_lock(&wl->mutex);
746
747 wl1271_notice("power down");
748
749 if (wl->state != WL1271_STATE_PLT) {
750 wl1271_error("cannot power down because not in PLT "
751 "state: %d", wl->state);
752 ret = -EBUSY;
753 goto out;
754 }
755
756 wl1271_disable_interrupts(wl);
757 wl1271_power_off(wl);
758
759 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300760 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300761
762out:
763 mutex_unlock(&wl->mutex);
764
765 return ret;
766}
767
768
769static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
770{
771 struct wl1271 *wl = hw->priv;
772
773 skb_queue_tail(&wl->tx_queue, skb);
774
775 /*
776 * The chip specific setup must run before the first TX packet -
777 * before that, the tx_work will not be initialized!
778 */
779
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300780 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300781
782 /*
783 * The workqueue is slow to process the tx_queue and we need stop
784 * the queue here, otherwise the queue will get too long.
785 */
786 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) {
787 ieee80211_stop_queues(wl->hw);
788
789 /*
790 * FIXME: this is racy, the variable is not properly
791 * protected. Maybe fix this by removing the stupid
792 * variable altogether and checking the real queue state?
793 */
794 wl->tx_queue_stopped = true;
795 }
796
797 return NETDEV_TX_OK;
798}
799
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300800static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
801 void *arg)
802{
803 struct net_device *dev;
804 struct wireless_dev *wdev;
805 struct wiphy *wiphy;
806 struct ieee80211_hw *hw;
807 struct wl1271 *wl;
808 struct wl1271 *wl_temp;
809 struct in_device *idev;
810 struct in_ifaddr *ifa = arg;
811 int ret = 0;
812
813 /* FIXME: this ugly function should probably be implemented in the
814 * mac80211, and here should only be a simple callback handling actual
815 * setting of the filters. Now we need to dig up references to
816 * various structures to gain access to what we need.
817 * Also, because of this, there is no "initial" setting of the filter
818 * in "op_start", because we don't want to dig up struct net_device
819 * there - the filter will be set upon first change of the interface
820 * IP address. */
821
822 dev = ifa->ifa_dev->dev;
823
824 wdev = dev->ieee80211_ptr;
825 if (wdev == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200826 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300827
828 wiphy = wdev->wiphy;
829 if (wiphy == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200830 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300831
832 hw = wiphy_priv(wiphy);
833 if (hw == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200834 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300835
836 /* Check that the interface is one supported by this driver. */
837 wl_temp = hw->priv;
838 list_for_each_entry(wl, &wl_list, list) {
839 if (wl == wl_temp)
840 break;
841 }
842 if (wl == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200843 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300844
845 /* Get the interface IP address for the device. "ifa" will become
846 NULL if:
847 - there is no IPV4 protocol address configured
848 - there are multiple (virtual) IPV4 addresses configured
849 When "ifa" is NULL, filtering will be disabled.
850 */
851 ifa = NULL;
852 idev = dev->ip_ptr;
853 if (idev)
854 ifa = idev->ifa_list;
855
856 if (ifa && ifa->ifa_next)
857 ifa = NULL;
858
859 mutex_lock(&wl->mutex);
860
861 if (wl->state == WL1271_STATE_OFF)
862 goto out;
863
864 ret = wl1271_ps_elp_wakeup(wl, false);
865 if (ret < 0)
866 goto out;
867 if (ifa)
868 ret = wl1271_acx_arp_ip_filter(wl, true,
869 (u8 *)&ifa->ifa_address,
870 ACX_IPV4_VERSION);
871 else
872 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
873 ACX_IPV4_VERSION);
874 wl1271_ps_elp_sleep(wl);
875
876out:
877 mutex_unlock(&wl->mutex);
878
Luciano Coelho17d72652009-11-23 23:22:15 +0200879 return NOTIFY_OK;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300880}
881
882static struct notifier_block wl1271_dev_notifier = {
883 .notifier_call = wl1271_dev_notify,
884};
885
886
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300887static int wl1271_op_start(struct ieee80211_hw *hw)
888{
889 struct wl1271 *wl = hw->priv;
890 int ret = 0;
891
892 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
893
894 mutex_lock(&wl->mutex);
895
896 if (wl->state != WL1271_STATE_OFF) {
897 wl1271_error("cannot start because not in off state: %d",
898 wl->state);
899 ret = -EBUSY;
900 goto out;
901 }
902
903 ret = wl1271_chip_wakeup(wl);
904 if (ret < 0)
905 goto out;
906
907 ret = wl1271_boot(wl);
908 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300909 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300910
911 ret = wl1271_hw_init(wl);
912 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300913 goto out_irq_disable;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300914
915 wl->state = WL1271_STATE_ON;
916
917 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
918
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300919 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300920
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300921out_irq_disable:
922 wl1271_disable_interrupts(wl);
923
924out_power_off:
925 wl1271_power_off(wl);
926
927out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300928 mutex_unlock(&wl->mutex);
929
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300930 if (!ret) {
931 list_add(&wl->list, &wl_list);
932 register_inetaddr_notifier(&wl1271_dev_notifier);
933 }
934
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300935 return ret;
936}
937
938static void wl1271_op_stop(struct ieee80211_hw *hw)
939{
940 struct wl1271 *wl = hw->priv;
941 int i;
942
943 wl1271_info("down");
944
945 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
946
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300947 unregister_inetaddr_notifier(&wl1271_dev_notifier);
948 list_del(&wl->list);
949
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300950 mutex_lock(&wl->mutex);
951
952 WARN_ON(wl->state != WL1271_STATE_ON);
953
954 if (wl->scanning) {
955 mutex_unlock(&wl->mutex);
956 ieee80211_scan_completed(wl->hw, true);
957 mutex_lock(&wl->mutex);
958 wl->scanning = false;
959 }
960
961 wl->state = WL1271_STATE_OFF;
962
963 wl1271_disable_interrupts(wl);
964
965 mutex_unlock(&wl->mutex);
966
967 cancel_work_sync(&wl->irq_work);
968 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300969
970 mutex_lock(&wl->mutex);
971
972 /* let's notify MAC80211 about the remaining pending TX frames */
973 wl1271_tx_flush(wl);
974 wl1271_power_off(wl);
975
976 memset(wl->bssid, 0, ETH_ALEN);
977 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
978 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300979 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +0300980 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300981
982 wl->rx_counter = 0;
983 wl->elp = false;
984 wl->psm = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200985 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300986 wl->tx_queue_stopped = false;
987 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
988 wl->tx_blocks_available = 0;
989 wl->tx_results_count = 0;
990 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +0300991 wl->tx_security_last_seq = 0;
992 wl->tx_security_seq_16 = 0;
993 wl->tx_security_seq_32 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300994 wl->time_offset = 0;
995 wl->session_counter = 0;
Luciano Coelhod6e19d132009-10-12 15:08:43 +0300996 wl->joined = false;
997
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300998 for (i = 0; i < NUM_TX_QUEUES; i++)
999 wl->tx_blocks_freed[i] = 0;
1000
1001 wl1271_debugfs_reset(wl);
1002 mutex_unlock(&wl->mutex);
1003}
1004
1005static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1006 struct ieee80211_if_init_conf *conf)
1007{
1008 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001009 int ret = 0;
1010
John W. Linvillee5539bc2009-08-18 10:50:34 -04001011 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1012 conf->type, conf->mac_addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001013
1014 mutex_lock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001015 if (wl->vif) {
1016 ret = -EBUSY;
1017 goto out;
1018 }
1019
1020 wl->vif = conf->vif;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001021
1022 switch (conf->type) {
1023 case NL80211_IFTYPE_STATION:
1024 wl->bss_type = BSS_TYPE_STA_BSS;
1025 break;
1026 case NL80211_IFTYPE_ADHOC:
1027 wl->bss_type = BSS_TYPE_IBSS;
1028 break;
1029 default:
1030 ret = -EOPNOTSUPP;
1031 goto out;
1032 }
1033
1034 /* FIXME: what if conf->mac_addr changes? */
1035
1036out:
1037 mutex_unlock(&wl->mutex);
1038 return ret;
1039}
1040
1041static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1042 struct ieee80211_if_init_conf *conf)
1043{
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001044 struct wl1271 *wl = hw->priv;
1045
1046 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001047 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001048 wl->vif = NULL;
1049 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001050}
1051
1052#if 0
1053static int wl1271_op_config_interface(struct ieee80211_hw *hw,
1054 struct ieee80211_vif *vif,
1055 struct ieee80211_if_conf *conf)
1056{
1057 struct wl1271 *wl = hw->priv;
1058 struct sk_buff *beacon;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001059 int ret;
1060
David S. Miller32646902009-09-17 10:18:30 -07001061 wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM",
1062 conf->bssid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001063 wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid,
1064 conf->ssid_len);
1065
1066 mutex_lock(&wl->mutex);
1067
1068 ret = wl1271_ps_elp_wakeup(wl, false);
1069 if (ret < 0)
1070 goto out;
1071
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001072 if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
1073 wl1271_debug(DEBUG_MAC80211, "bssid changed");
1074
1075 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
1076
1077 ret = wl1271_cmd_join(wl);
1078 if (ret < 0)
1079 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001080
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001081 ret = wl1271_cmd_build_null_data(wl);
1082 if (ret < 0)
1083 goto out_sleep;
1084 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001085
1086 wl->ssid_len = conf->ssid_len;
1087 if (wl->ssid_len)
1088 memcpy(wl->ssid, conf->ssid, wl->ssid_len);
1089
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001090 if (conf->changed & IEEE80211_IFCC_BEACON) {
1091 beacon = ieee80211_beacon_get(hw, vif);
1092 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1093 beacon->data, beacon->len);
1094
1095 if (ret < 0) {
1096 dev_kfree_skb(beacon);
1097 goto out_sleep;
1098 }
1099
1100 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE,
1101 beacon->data, beacon->len);
1102
1103 dev_kfree_skb(beacon);
1104
1105 if (ret < 0)
1106 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001107 }
1108
1109out_sleep:
1110 wl1271_ps_elp_sleep(wl);
1111
1112out:
1113 mutex_unlock(&wl->mutex);
1114
1115 return ret;
1116}
1117#endif
1118
1119static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1120{
1121 struct wl1271 *wl = hw->priv;
1122 struct ieee80211_conf *conf = &hw->conf;
1123 int channel, ret = 0;
1124
1125 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1126
1127 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
1128 channel,
1129 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
1130 conf->power_level);
1131
1132 mutex_lock(&wl->mutex);
1133
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001134 wl->band = conf->channel->band;
1135
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001136 ret = wl1271_ps_elp_wakeup(wl, false);
1137 if (ret < 0)
1138 goto out;
1139
1140 if (channel != wl->channel) {
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001141 /*
1142 * We assume that the stack will configure the right channel
1143 * before associating, so we don't need to send a join
1144 * command here. We will join the right channel when the
1145 * BSSID changes
1146 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001147 wl->channel = channel;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001148 }
1149
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001150 if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) {
1151 wl1271_info("psm enabled");
1152
1153 wl->psm_requested = true;
1154
1155 /*
1156 * We enter PSM only if we're already associated.
1157 * If we're not, we'll enter it when joining an SSID,
1158 * through the bss_info_changed() hook.
1159 */
1160 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
1161 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
1162 wl->psm_requested) {
1163 wl1271_info("psm disabled");
1164
1165 wl->psm_requested = false;
1166
1167 if (wl->psm)
1168 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE);
1169 }
1170
1171 if (conf->power_level != wl->power_level) {
1172 ret = wl1271_acx_tx_power(wl, conf->power_level);
1173 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001174 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001175
1176 wl->power_level = conf->power_level;
1177 }
1178
1179out_sleep:
1180 wl1271_ps_elp_sleep(wl);
1181
1182out:
1183 mutex_unlock(&wl->mutex);
1184
1185 return ret;
1186}
1187
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001188struct wl1271_filter_params {
1189 bool enabled;
1190 int mc_list_length;
1191 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1192};
1193
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001194static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1195 struct dev_addr_list *mc_list)
1196{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001197 struct wl1271_filter_params *fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001198 int i;
1199
Juuso Oikarinen74441132009-10-13 12:47:53 +03001200 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001201 if (!fp) {
1202 wl1271_error("Out of memory setting filters.");
1203 return 0;
1204 }
1205
1206 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001207 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001208 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1209 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001210 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001211 }
1212
1213 fp->mc_list_length = 0;
1214 for (i = 0; i < mc_count; i++) {
1215 if (mc_list->da_addrlen == ETH_ALEN) {
1216 memcpy(fp->mc_list[fp->mc_list_length],
1217 mc_list->da_addr, ETH_ALEN);
1218 fp->mc_list_length++;
1219 } else
1220 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001221 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001222 }
1223
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001224 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001225}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001226
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001227#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1228 FIF_ALLMULTI | \
1229 FIF_FCSFAIL | \
1230 FIF_BCN_PRBRESP_PROMISC | \
1231 FIF_CONTROL | \
1232 FIF_OTHER_BSS)
1233
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001234static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1235 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001236 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001237{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001238 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001239 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001240 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001241
1242 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1243
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001244 mutex_lock(&wl->mutex);
1245
1246 if (wl->state == WL1271_STATE_OFF)
1247 goto out;
1248
1249 ret = wl1271_ps_elp_wakeup(wl, false);
1250 if (ret < 0)
1251 goto out;
1252
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001253 *total &= WL1271_SUPPORTED_FILTERS;
1254 changed &= WL1271_SUPPORTED_FILTERS;
1255
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001256 if (*total & FIF_ALLMULTI)
1257 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1258 else if (fp)
1259 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1260 fp->mc_list,
1261 fp->mc_list_length);
1262 if (ret < 0)
1263 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001264
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001265 kfree(fp);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001266
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001267 /* FIXME: We still need to set our filters properly */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001268
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001269 /* determine, whether supported filter values have changed */
1270 if (changed == 0)
1271 goto out_sleep;
1272
1273 /* apply configured filters */
1274 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1275 if (ret < 0)
1276 goto out_sleep;
1277
1278out_sleep:
1279 wl1271_ps_elp_sleep(wl);
1280
1281out:
1282 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001283}
1284
1285static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1286 struct ieee80211_vif *vif,
1287 struct ieee80211_sta *sta,
1288 struct ieee80211_key_conf *key_conf)
1289{
1290 struct wl1271 *wl = hw->priv;
1291 const u8 *addr;
1292 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001293 u32 tx_seq_32 = 0;
1294 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001295 u8 key_type;
1296
1297 static const u8 bcast_addr[ETH_ALEN] =
1298 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1299
1300 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1301
1302 addr = sta ? sta->addr : bcast_addr;
1303
1304 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1305 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1306 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1307 key_conf->alg, key_conf->keyidx,
1308 key_conf->keylen, key_conf->flags);
1309 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1310
1311 if (is_zero_ether_addr(addr)) {
1312 /* We dont support TX only encryption */
1313 ret = -EOPNOTSUPP;
1314 goto out;
1315 }
1316
1317 mutex_lock(&wl->mutex);
1318
1319 ret = wl1271_ps_elp_wakeup(wl, false);
1320 if (ret < 0)
1321 goto out_unlock;
1322
1323 switch (key_conf->alg) {
1324 case ALG_WEP:
1325 key_type = KEY_WEP;
1326
1327 key_conf->hw_key_idx = key_conf->keyidx;
1328 break;
1329 case ALG_TKIP:
1330 key_type = KEY_TKIP;
1331
1332 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001333 tx_seq_32 = wl->tx_security_seq_32;
1334 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001335 break;
1336 case ALG_CCMP:
1337 key_type = KEY_AES;
1338
1339 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001340 tx_seq_32 = wl->tx_security_seq_32;
1341 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001342 break;
1343 default:
1344 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1345
1346 ret = -EOPNOTSUPP;
1347 goto out_sleep;
1348 }
1349
1350 switch (cmd) {
1351 case SET_KEY:
1352 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1353 key_conf->keyidx, key_type,
1354 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001355 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001356 if (ret < 0) {
1357 wl1271_error("Could not add or replace key");
1358 goto out_sleep;
1359 }
1360 break;
1361
1362 case DISABLE_KEY:
1363 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1364 key_conf->keyidx, key_type,
1365 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001366 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001367 if (ret < 0) {
1368 wl1271_error("Could not remove key");
1369 goto out_sleep;
1370 }
1371 break;
1372
1373 default:
1374 wl1271_error("Unsupported key cmd 0x%x", cmd);
1375 ret = -EOPNOTSUPP;
1376 goto out_sleep;
1377
1378 break;
1379 }
1380
1381out_sleep:
1382 wl1271_ps_elp_sleep(wl);
1383
1384out_unlock:
1385 mutex_unlock(&wl->mutex);
1386
1387out:
1388 return ret;
1389}
1390
1391static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1392 struct cfg80211_scan_request *req)
1393{
1394 struct wl1271 *wl = hw->priv;
1395 int ret;
1396 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001397 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001398
1399 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1400
1401 if (req->n_ssids) {
1402 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001403 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001404 }
1405
1406 mutex_lock(&wl->mutex);
1407
1408 ret = wl1271_ps_elp_wakeup(wl, false);
1409 if (ret < 0)
1410 goto out;
1411
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001412 if (wl1271_11a_enabled())
1413 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1414 WL1271_SCAN_BAND_DUAL, 3);
1415 else
1416 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1417 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001418
1419 wl1271_ps_elp_sleep(wl);
1420
1421out:
1422 mutex_unlock(&wl->mutex);
1423
1424 return ret;
1425}
1426
1427static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1428{
1429 struct wl1271 *wl = hw->priv;
1430 int ret;
1431
1432 mutex_lock(&wl->mutex);
1433
1434 ret = wl1271_ps_elp_wakeup(wl, false);
1435 if (ret < 0)
1436 goto out;
1437
1438 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1439 if (ret < 0)
1440 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1441
1442 wl1271_ps_elp_sleep(wl);
1443
1444out:
1445 mutex_unlock(&wl->mutex);
1446
1447 return ret;
1448}
1449
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001450static u32 wl1271_enabled_rates_get(struct wl1271 *wl, u64 basic_rate_set)
1451{
1452 struct ieee80211_supported_band *band;
1453 u32 enabled_rates = 0;
1454 int bit;
1455
1456 band = wl->hw->wiphy->bands[wl->band];
1457 for (bit = 0; bit < band->n_bitrates; bit++) {
1458 if (basic_rate_set & 0x1)
1459 enabled_rates |= band->bitrates[bit].hw_value;
1460 basic_rate_set >>= 1;
1461 }
1462
1463 return enabled_rates;
1464}
1465
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001466static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1467 struct ieee80211_vif *vif,
1468 struct ieee80211_bss_conf *bss_conf,
1469 u32 changed)
1470{
1471 enum wl1271_cmd_ps_mode mode;
1472 struct wl1271 *wl = hw->priv;
1473 int ret;
1474
1475 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1476
1477 mutex_lock(&wl->mutex);
1478
1479 ret = wl1271_ps_elp_wakeup(wl, false);
1480 if (ret < 0)
1481 goto out;
1482
1483 if (changed & BSS_CHANGED_ASSOC) {
1484 if (bss_conf->assoc) {
1485 wl->aid = bss_conf->aid;
1486
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001487 /*
1488 * with wl1271, we don't need to update the
1489 * beacon_int and dtim_period, because the firmware
1490 * updates it by itself when the first beacon is
1491 * received after a join.
1492 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001493 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1494 if (ret < 0)
1495 goto out_sleep;
1496
1497 ret = wl1271_acx_aid(wl, wl->aid);
1498 if (ret < 0)
1499 goto out_sleep;
1500
1501 /* If we want to go in PSM but we're not there yet */
1502 if (wl->psm_requested && !wl->psm) {
1503 mode = STATION_POWER_SAVE_MODE;
1504 ret = wl1271_ps_set_mode(wl, mode);
1505 if (ret < 0)
1506 goto out_sleep;
1507 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001508 } else {
1509 /* use defaults when not associated */
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001510 wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
1511 wl->aid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001512 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001513
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001514 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001515
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001516 if (changed & BSS_CHANGED_ERP_SLOT) {
1517 if (bss_conf->use_short_slot)
1518 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1519 else
1520 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1521 if (ret < 0) {
1522 wl1271_warning("Set slot time failed %d", ret);
1523 goto out_sleep;
1524 }
1525 }
1526
1527 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1528 if (bss_conf->use_short_preamble)
1529 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1530 else
1531 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1532 }
1533
1534 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1535 if (bss_conf->use_cts_prot)
1536 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1537 else
1538 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1539 if (ret < 0) {
1540 wl1271_warning("Set ctsprotect failed %d", ret);
1541 goto out_sleep;
1542 }
1543 }
1544
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001545 if (changed & BSS_CHANGED_BASIC_RATES) {
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001546 wl->basic_rate_set = wl1271_enabled_rates_get(
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001547 wl, bss_conf->basic_rates);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001548
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001549 ret = wl1271_acx_rate_policies(wl, wl->basic_rate_set);
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001550 if (ret < 0) {
1551 wl1271_warning("Set rate policies failed %d", ret);
1552 goto out_sleep;
1553 }
1554 }
1555
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001556out_sleep:
1557 wl1271_ps_elp_sleep(wl);
1558
1559out:
1560 mutex_unlock(&wl->mutex);
1561}
1562
1563
1564/* can't be const, mac80211 writes to this */
1565static struct ieee80211_rate wl1271_rates[] = {
1566 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001567 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1568 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001569 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001570 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1571 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001572 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1573 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001574 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1575 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001576 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1577 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001578 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1579 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001580 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1581 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001582 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1583 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001584 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001585 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1586 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001587 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001588 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1589 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001590 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001591 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1592 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001593 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001594 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1595 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001596 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001597 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1598 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001599 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001600 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1601 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001602 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001603 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1604 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001605};
1606
1607/* can't be const, mac80211 writes to this */
1608static struct ieee80211_channel wl1271_channels[] = {
1609 { .hw_value = 1, .center_freq = 2412},
1610 { .hw_value = 2, .center_freq = 2417},
1611 { .hw_value = 3, .center_freq = 2422},
1612 { .hw_value = 4, .center_freq = 2427},
1613 { .hw_value = 5, .center_freq = 2432},
1614 { .hw_value = 6, .center_freq = 2437},
1615 { .hw_value = 7, .center_freq = 2442},
1616 { .hw_value = 8, .center_freq = 2447},
1617 { .hw_value = 9, .center_freq = 2452},
1618 { .hw_value = 10, .center_freq = 2457},
1619 { .hw_value = 11, .center_freq = 2462},
1620 { .hw_value = 12, .center_freq = 2467},
1621 { .hw_value = 13, .center_freq = 2472},
1622};
1623
1624/* can't be const, mac80211 writes to this */
1625static struct ieee80211_supported_band wl1271_band_2ghz = {
1626 .channels = wl1271_channels,
1627 .n_channels = ARRAY_SIZE(wl1271_channels),
1628 .bitrates = wl1271_rates,
1629 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1630};
1631
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001632/* 5 GHz data rates for WL1273 */
1633static struct ieee80211_rate wl1271_rates_5ghz[] = {
1634 { .bitrate = 60,
1635 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1636 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
1637 { .bitrate = 90,
1638 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1639 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
1640 { .bitrate = 120,
1641 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1642 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
1643 { .bitrate = 180,
1644 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1645 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
1646 { .bitrate = 240,
1647 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1648 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
1649 { .bitrate = 360,
1650 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1651 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
1652 { .bitrate = 480,
1653 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1654 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
1655 { .bitrate = 540,
1656 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1657 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
1658};
1659
1660/* 5 GHz band channels for WL1273 */
1661static struct ieee80211_channel wl1271_channels_5ghz[] = {
1662 { .hw_value = 183, .center_freq = 4915},
1663 { .hw_value = 184, .center_freq = 4920},
1664 { .hw_value = 185, .center_freq = 4925},
1665 { .hw_value = 187, .center_freq = 4935},
1666 { .hw_value = 188, .center_freq = 4940},
1667 { .hw_value = 189, .center_freq = 4945},
1668 { .hw_value = 192, .center_freq = 4960},
1669 { .hw_value = 196, .center_freq = 4980},
1670 { .hw_value = 7, .center_freq = 5035},
1671 { .hw_value = 8, .center_freq = 5040},
1672 { .hw_value = 9, .center_freq = 5045},
1673 { .hw_value = 11, .center_freq = 5055},
1674 { .hw_value = 12, .center_freq = 5060},
1675 { .hw_value = 16, .center_freq = 5080},
1676 { .hw_value = 34, .center_freq = 5170},
1677 { .hw_value = 36, .center_freq = 5180},
1678 { .hw_value = 38, .center_freq = 5190},
1679 { .hw_value = 40, .center_freq = 5200},
1680 { .hw_value = 42, .center_freq = 5210},
1681 { .hw_value = 44, .center_freq = 5220},
1682 { .hw_value = 46, .center_freq = 5230},
1683 { .hw_value = 48, .center_freq = 5240},
1684 { .hw_value = 52, .center_freq = 5260},
1685 { .hw_value = 56, .center_freq = 5280},
1686 { .hw_value = 60, .center_freq = 5300},
1687 { .hw_value = 64, .center_freq = 5320},
1688 { .hw_value = 100, .center_freq = 5500},
1689 { .hw_value = 104, .center_freq = 5520},
1690 { .hw_value = 108, .center_freq = 5540},
1691 { .hw_value = 112, .center_freq = 5560},
1692 { .hw_value = 116, .center_freq = 5580},
1693 { .hw_value = 120, .center_freq = 5600},
1694 { .hw_value = 124, .center_freq = 5620},
1695 { .hw_value = 128, .center_freq = 5640},
1696 { .hw_value = 132, .center_freq = 5660},
1697 { .hw_value = 136, .center_freq = 5680},
1698 { .hw_value = 140, .center_freq = 5700},
1699 { .hw_value = 149, .center_freq = 5745},
1700 { .hw_value = 153, .center_freq = 5765},
1701 { .hw_value = 157, .center_freq = 5785},
1702 { .hw_value = 161, .center_freq = 5805},
1703 { .hw_value = 165, .center_freq = 5825},
1704};
1705
1706
1707static struct ieee80211_supported_band wl1271_band_5ghz = {
1708 .channels = wl1271_channels_5ghz,
1709 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
1710 .bitrates = wl1271_rates_5ghz,
1711 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
1712};
1713
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001714static const struct ieee80211_ops wl1271_ops = {
1715 .start = wl1271_op_start,
1716 .stop = wl1271_op_stop,
1717 .add_interface = wl1271_op_add_interface,
1718 .remove_interface = wl1271_op_remove_interface,
1719 .config = wl1271_op_config,
1720/* .config_interface = wl1271_op_config_interface, */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001721 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001722 .configure_filter = wl1271_op_configure_filter,
1723 .tx = wl1271_op_tx,
1724 .set_key = wl1271_op_set_key,
1725 .hw_scan = wl1271_op_hw_scan,
1726 .bss_info_changed = wl1271_op_bss_info_changed,
1727 .set_rts_threshold = wl1271_op_set_rts_threshold,
1728};
1729
1730static int wl1271_register_hw(struct wl1271 *wl)
1731{
1732 int ret;
1733
1734 if (wl->mac80211_registered)
1735 return 0;
1736
1737 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
1738
1739 ret = ieee80211_register_hw(wl->hw);
1740 if (ret < 0) {
1741 wl1271_error("unable to register mac80211 hw: %d", ret);
1742 return ret;
1743 }
1744
1745 wl->mac80211_registered = true;
1746
1747 wl1271_notice("loaded");
1748
1749 return 0;
1750}
1751
1752static int wl1271_init_ieee80211(struct wl1271 *wl)
1753{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03001754 /* The tx descriptor buffer and the TKIP space. */
1755 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
1756 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001757
1758 /* unit us */
1759 /* FIXME: find a proper value */
1760 wl->hw->channel_change_time = 10000;
1761
1762 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03001763 IEEE80211_HW_NOISE_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02001764 IEEE80211_HW_BEACON_FILTER |
1765 IEEE80211_HW_SUPPORTS_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001766
1767 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
1768 wl->hw->wiphy->max_scan_ssids = 1;
1769 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
1770
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001771 if (wl1271_11a_enabled())
1772 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
1773
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001774 SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
1775
1776 return 0;
1777}
1778
1779static void wl1271_device_release(struct device *dev)
1780{
1781
1782}
1783
1784static struct platform_device wl1271_device = {
1785 .name = "wl1271",
1786 .id = -1,
1787
1788 /* device model insists to have a release function */
1789 .dev = {
1790 .release = wl1271_device_release,
1791 },
1792};
1793
1794#define WL1271_DEFAULT_CHANNEL 0
1795static int __devinit wl1271_probe(struct spi_device *spi)
1796{
1797 struct wl12xx_platform_data *pdata;
1798 struct ieee80211_hw *hw;
1799 struct wl1271 *wl;
1800 int ret, i;
1801 static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
1802
1803 pdata = spi->dev.platform_data;
1804 if (!pdata) {
1805 wl1271_error("no platform data");
1806 return -ENODEV;
1807 }
1808
1809 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
1810 if (!hw) {
1811 wl1271_error("could not alloc ieee80211_hw");
1812 return -ENOMEM;
1813 }
1814
1815 wl = hw->priv;
1816 memset(wl, 0, sizeof(*wl));
1817
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001818 INIT_LIST_HEAD(&wl->list);
1819
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001820 wl->hw = hw;
1821 dev_set_drvdata(&spi->dev, wl);
1822 wl->spi = spi;
1823
1824 skb_queue_head_init(&wl->tx_queue);
1825
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03001826 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001827 wl->channel = WL1271_DEFAULT_CHANNEL;
1828 wl->scanning = false;
1829 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001830 wl->rx_counter = 0;
1831 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1832 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1833 wl->elp = false;
1834 wl->psm = 0;
1835 wl->psm_requested = false;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001836 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001837 wl->tx_queue_stopped = false;
1838 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001839 wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001840 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001841 wl->vif = NULL;
Luciano Coelhod6e19d132009-10-12 15:08:43 +03001842 wl->joined = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001843
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03001844 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001845 wl->tx_frames[i] = NULL;
1846
1847 spin_lock_init(&wl->wl_lock);
1848
1849 /*
1850 * In case our MAC address is not correctly set,
1851 * we use a random but Nokia MAC.
1852 */
1853 memcpy(wl->mac_addr, nokia_oui, 3);
1854 get_random_bytes(wl->mac_addr + 3, 3);
1855
1856 wl->state = WL1271_STATE_OFF;
1857 mutex_init(&wl->mutex);
1858
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001859 /* This is the only SPI value that we need to set here, the rest
1860 * comes from the board-peripherals file */
1861 spi->bits_per_word = 32;
1862
1863 ret = spi_setup(spi);
1864 if (ret < 0) {
1865 wl1271_error("spi_setup failed");
1866 goto out_free;
1867 }
1868
1869 wl->set_power = pdata->set_power;
1870 if (!wl->set_power) {
1871 wl1271_error("set power function missing in platform data");
1872 ret = -ENODEV;
1873 goto out_free;
1874 }
1875
1876 wl->irq = spi->irq;
1877 if (wl->irq < 0) {
1878 wl1271_error("irq missing in platform data");
1879 ret = -ENODEV;
1880 goto out_free;
1881 }
1882
1883 ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
1884 if (ret < 0) {
1885 wl1271_error("request_irq() failed: %d", ret);
1886 goto out_free;
1887 }
1888
1889 set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
1890
1891 disable_irq(wl->irq);
1892
1893 ret = platform_device_register(&wl1271_device);
1894 if (ret) {
1895 wl1271_error("couldn't register platform device");
1896 goto out_irq;
1897 }
1898 dev_set_drvdata(&wl1271_device.dev, wl);
1899
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001900 /* Apply default driver configuration. */
1901 wl1271_conf_init(wl);
1902
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001903 ret = wl1271_init_ieee80211(wl);
1904 if (ret)
1905 goto out_platform;
1906
1907 ret = wl1271_register_hw(wl);
1908 if (ret)
1909 goto out_platform;
1910
1911 wl1271_debugfs_init(wl);
1912
1913 wl1271_notice("initialized");
1914
1915 return 0;
1916
1917 out_platform:
1918 platform_device_unregister(&wl1271_device);
1919
1920 out_irq:
1921 free_irq(wl->irq, wl);
1922
1923 out_free:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001924 ieee80211_free_hw(hw);
1925
1926 return ret;
1927}
1928
1929static int __devexit wl1271_remove(struct spi_device *spi)
1930{
1931 struct wl1271 *wl = dev_get_drvdata(&spi->dev);
1932
1933 ieee80211_unregister_hw(wl->hw);
1934
1935 wl1271_debugfs_exit(wl);
1936 platform_device_unregister(&wl1271_device);
1937 free_irq(wl->irq, wl);
1938 kfree(wl->target_mem_map);
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001939 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001940 wl->fw = NULL;
1941 kfree(wl->nvs);
1942 wl->nvs = NULL;
1943
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001944 kfree(wl->fw_status);
1945 kfree(wl->tx_res_if);
1946
1947 ieee80211_free_hw(wl->hw);
1948
1949 return 0;
1950}
1951
1952
1953static struct spi_driver wl1271_spi_driver = {
1954 .driver = {
1955 .name = "wl1271",
1956 .bus = &spi_bus_type,
1957 .owner = THIS_MODULE,
1958 },
1959
1960 .probe = wl1271_probe,
1961 .remove = __devexit_p(wl1271_remove),
1962};
1963
1964static int __init wl1271_init(void)
1965{
1966 int ret;
1967
1968 ret = spi_register_driver(&wl1271_spi_driver);
1969 if (ret < 0) {
1970 wl1271_error("failed to register spi driver: %d", ret);
1971 goto out;
1972 }
1973
1974out:
1975 return ret;
1976}
1977
1978static void __exit wl1271_exit(void)
1979{
1980 spi_unregister_driver(&wl1271_spi_driver);
1981
1982 wl1271_notice("unloaded");
1983}
1984
1985module_init(wl1271_init);
1986module_exit(wl1271_exit);
1987
1988MODULE_LICENSE("GPL");
1989MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
Luciano Coelho2f018722009-10-08 21:56:27 +03001990MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
Ben Hutchings49f146d2009-11-07 22:02:15 +00001991MODULE_FIRMWARE(WL1271_FW_NAME);