blob: 7ab45c446ab85b2938a61661623388c62c7ab09b [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 = {
Luciano Coelhoc7c8adb2009-11-23 23:22:19 +0200254 .ref_clk = CONF_REF_CLK_38_4_E,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300255 .settling_time = 5,
256 .clk_valid_on_wakeup = 0,
257 .dc2dcmode = 0,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300258 .single_dual_band = CONF_SINGLE_BAND,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300259 .tx_bip_fem_autodetect = 0,
260 .tx_bip_fem_manufacturer = 1,
261 .settings = 1,
Luciano Coelho76c0f8d2009-12-11 15:40:41 +0200262 .sr_state = 1,
263 .srf1 = { 0, 0, 0, 0, 0, 0, 0, 0,
264 0, 0, 0, 0, 0, 0, 0, 0 },
265 .srf2 = { 0, 0, 0, 0, 0, 0, 0, 0,
266 0, 0, 0, 0, 0, 0, 0, 0 },
267 .srf3 = { 0, 0, 0, 0, 0, 0, 0, 0,
268 0, 0, 0, 0, 0, 0, 0, 0 },
269 .sr_debug_table = { 0, 0, 0, 0, 0, 0, 0, 0,
270 0, 0, 0, 0, 0, 0, 0, 0 },
271 .sr_sen_n_p = 0,
272 .sr_sen_n_p_gain = 0,
273 .sr_sen_nrn = 0,
274 .sr_sen_prn = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300275 },
276 .radioparam = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300277 .rx_trace_loss = 10,
278 .tx_trace_loss = 10,
279 .rx_rssi_and_proc_compens = {
280 0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8,
281 0xfc, 0x00, 0x08, 0x10, 0xf0, 0xf8,
282 0x00, 0x0a, 0x14 },
283 .rx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 },
284 .tx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 },
285 .rx_rssi_and_proc_compens_5 = {
286 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
287 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
288 0x00, 0x00, 0x00 },
289 .tx_ref_pd_voltage = 0x24e,
290 .tx_ref_power = 0x78,
291 .tx_offset_db = 0x0,
292 .tx_rate_limits_normal = {
293 0x1e, 0x1f, 0x22, 0x24, 0x28, 0x29 },
294 .tx_rate_limits_degraded = {
295 0x1b, 0x1c, 0x1e, 0x20, 0x24, 0x25 },
296 .tx_channel_limits_11b = {
297 0x22, 0x50, 0x50, 0x50, 0x50, 0x50,
298 0x50, 0x50, 0x50, 0x50, 0x22, 0x50,
299 0x22, 0x50 },
300 .tx_channel_limits_ofdm = {
301 0x20, 0x50, 0x50, 0x50, 0x50, 0x50,
302 0x50, 0x50, 0x50, 0x50, 0x20, 0x50,
303 0x20, 0x50 },
304 .tx_pdv_rate_offsets = {
305 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
306 .tx_ibias = {
307 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x27 },
308 .rx_fem_insertion_loss = 0x14,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300309 .tx_ref_pd_voltage_5 = {
310 0x0190, 0x01a4, 0x01c3, 0x01d8,
311 0x020a, 0x021c },
312 .tx_ref_power_5 = {
313 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 },
314 .tx_offset_db_5 = {
315 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300316 .tx_rate_limits_normal_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300317 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300318 .tx_rate_limits_degraded_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300319 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300320 .tx_channel_limits_ofdm_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300321 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
322 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
323 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
324 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
325 0x50, 0x50, 0x50 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300326 .tx_pdv_rate_offsets_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300327 0x01, 0x02, 0x02, 0x02, 0x02, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300328 .tx_ibias_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300329 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
330 .rx_fem_insertion_loss_5 = {
331 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300332 }
333 }
334};
335
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300336static LIST_HEAD(wl_list);
337
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300338static void wl1271_conf_init(struct wl1271 *wl)
339{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300340
341 /*
342 * This function applies the default configuration to the driver. This
343 * function is invoked upon driver load (spi probe.)
344 *
345 * The configuration is stored in a run-time structure in order to
346 * facilitate for run-time adjustment of any of the parameters. Making
347 * changes to the configuration structure will apply the new values on
348 * the next interface up (wl1271_op_start.)
349 */
350
351 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300352 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300353
354 if (wl1271_11a_enabled())
355 wl->conf.init.genparam.single_dual_band = CONF_DUAL_BAND;
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300356}
357
358
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300359static int wl1271_plt_init(struct wl1271 *wl)
360{
361 int ret;
362
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200363 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200364 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200365 return ret;
366
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200367 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200368 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200369 return ret;
370
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300371 ret = wl1271_acx_init_mem_config(wl);
372 if (ret < 0)
373 return ret;
374
375 ret = wl1271_cmd_data_path(wl, wl->channel, 1);
376 if (ret < 0)
377 return ret;
378
379 return 0;
380}
381
382static void wl1271_disable_interrupts(struct wl1271 *wl)
383{
384 disable_irq(wl->irq);
385}
386
387static void wl1271_power_off(struct wl1271 *wl)
388{
389 wl->set_power(false);
390}
391
392static void wl1271_power_on(struct wl1271 *wl)
393{
394 wl->set_power(true);
395}
396
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300397static void wl1271_fw_status(struct wl1271 *wl,
398 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300399{
400 u32 total = 0;
401 int i;
402
Juuso Oikarinen74621412009-10-12 15:08:54 +0300403 wl1271_spi_read(wl, FW_STATUS_ADDR, status,
404 sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300405
406 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
407 "drv_rx_counter = %d, tx_results_counter = %d)",
408 status->intr,
409 status->fw_rx_counter,
410 status->drv_rx_counter,
411 status->tx_results_counter);
412
413 /* update number of available TX blocks */
414 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300415 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
416 wl->tx_blocks_freed[i];
417
418 wl->tx_blocks_freed[i] =
419 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300420 wl->tx_blocks_available += cnt;
421 total += cnt;
422 }
423
424 /* if more blocks are available now, schedule some tx work */
425 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300426 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300427
428 /* update the host-chipset time offset */
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300429 wl->time_offset = jiffies_to_usecs(jiffies) -
430 le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300431}
432
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300433static void wl1271_irq_work(struct work_struct *work)
434{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300435 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300436 u32 intr;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300437 struct wl1271 *wl =
438 container_of(work, struct wl1271, irq_work);
439
440 mutex_lock(&wl->mutex);
441
442 wl1271_debug(DEBUG_IRQ, "IRQ work");
443
444 if (wl->state == WL1271_STATE_OFF)
445 goto out;
446
447 ret = wl1271_ps_elp_wakeup(wl, true);
448 if (ret < 0)
449 goto out;
450
Juuso Oikarinen74621412009-10-12 15:08:54 +0300451 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300452
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300453 wl1271_fw_status(wl, wl->fw_status);
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300454 intr = le32_to_cpu(wl->fw_status->intr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300455 if (!intr) {
456 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
457 goto out_sleep;
458 }
459
460 intr &= WL1271_INTR_MASK;
461
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300462 if (intr & WL1271_ACX_INTR_EVENT_A) {
463 bool do_ack = (intr & WL1271_ACX_INTR_EVENT_B) ? false : true;
464 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
465 wl1271_event_handle(wl, 0, do_ack);
466 }
467
468 if (intr & WL1271_ACX_INTR_EVENT_B) {
469 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
470 wl1271_event_handle(wl, 1, true);
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300471 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300472
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300473 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
474 wl1271_debug(DEBUG_IRQ,
475 "WL1271_ACX_INTR_INIT_COMPLETE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300476
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300477 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
478 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300479
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300480 if (intr & WL1271_ACX_INTR_DATA) {
481 u8 tx_res_cnt = wl->fw_status->tx_results_counter -
482 wl->tx_results_count;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300483
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300484 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300485
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300486 /* check for tx results */
487 if (tx_res_cnt)
488 wl1271_tx_complete(wl, tx_res_cnt);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300489
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300490 wl1271_rx(wl, wl->fw_status);
491 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300492
493out_sleep:
Juuso Oikarinen74621412009-10-12 15:08:54 +0300494 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
Luciano Coelho73d0a132009-08-11 11:58:27 +0300495 WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300496 wl1271_ps_elp_sleep(wl);
497
498out:
499 mutex_unlock(&wl->mutex);
500}
501
502static irqreturn_t wl1271_irq(int irq, void *cookie)
503{
504 struct wl1271 *wl;
505 unsigned long flags;
506
507 wl1271_debug(DEBUG_IRQ, "IRQ");
508
509 wl = cookie;
510
511 /* complete the ELP completion */
512 spin_lock_irqsave(&wl->wl_lock, flags);
513 if (wl->elp_compl) {
514 complete(wl->elp_compl);
515 wl->elp_compl = NULL;
516 }
517
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300518 ieee80211_queue_work(wl->hw, &wl->irq_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300519 spin_unlock_irqrestore(&wl->wl_lock, flags);
520
521 return IRQ_HANDLED;
522}
523
524static int wl1271_fetch_firmware(struct wl1271 *wl)
525{
526 const struct firmware *fw;
527 int ret;
528
529 ret = request_firmware(&fw, WL1271_FW_NAME, &wl->spi->dev);
530
531 if (ret < 0) {
532 wl1271_error("could not get firmware: %d", ret);
533 return ret;
534 }
535
536 if (fw->size % 4) {
537 wl1271_error("firmware size is not multiple of 32 bits: %zu",
538 fw->size);
539 ret = -EILSEQ;
540 goto out;
541 }
542
543 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300544 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300545
546 if (!wl->fw) {
547 wl1271_error("could not allocate memory for the firmware");
548 ret = -ENOMEM;
549 goto out;
550 }
551
552 memcpy(wl->fw, fw->data, wl->fw_len);
553
554 ret = 0;
555
556out:
557 release_firmware(fw);
558
559 return ret;
560}
561
562static int wl1271_fetch_nvs(struct wl1271 *wl)
563{
564 const struct firmware *fw;
565 int ret;
566
567 ret = request_firmware(&fw, WL1271_NVS_NAME, &wl->spi->dev);
568
569 if (ret < 0) {
570 wl1271_error("could not get nvs file: %d", ret);
571 return ret;
572 }
573
574 if (fw->size % 4) {
575 wl1271_error("nvs size is not multiple of 32 bits: %zu",
576 fw->size);
577 ret = -EILSEQ;
578 goto out;
579 }
580
581 wl->nvs_len = fw->size;
582 wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL);
583
584 if (!wl->nvs) {
585 wl1271_error("could not allocate memory for the nvs file");
586 ret = -ENOMEM;
587 goto out;
588 }
589
590 memcpy(wl->nvs, fw->data, wl->nvs_len);
591
592 ret = 0;
593
594out:
595 release_firmware(fw);
596
597 return ret;
598}
599
600static void wl1271_fw_wakeup(struct wl1271 *wl)
601{
602 u32 elp_reg;
603
604 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300605 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300606}
607
608static int wl1271_setup(struct wl1271 *wl)
609{
610 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
611 if (!wl->fw_status)
612 return -ENOMEM;
613
614 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
615 if (!wl->tx_res_if) {
616 kfree(wl->fw_status);
617 return -ENOMEM;
618 }
619
620 INIT_WORK(&wl->irq_work, wl1271_irq_work);
621 INIT_WORK(&wl->tx_work, wl1271_tx_work);
622 return 0;
623}
624
625static int wl1271_chip_wakeup(struct wl1271 *wl)
626{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300627 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300628 int ret = 0;
629
630 wl1271_power_on(wl);
631 msleep(WL1271_POWER_ON_SLEEP);
632 wl1271_spi_reset(wl);
633 wl1271_spi_init(wl);
634
635 /* We don't need a real memory partition here, because we only want
636 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300637 memset(&partition, 0, sizeof(partition));
638 partition.reg.start = REGISTERS_BASE;
639 partition.reg.size = REGISTERS_DOWN_SIZE;
640 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300641
642 /* ELP module wake up */
643 wl1271_fw_wakeup(wl);
644
645 /* whal_FwCtrl_BootSm() */
646
647 /* 0. read chip id from CHIP_ID */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300648 wl->chip.id = wl1271_spi_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300649
650 /* 1. check if chip id is valid */
651
652 switch (wl->chip.id) {
653 case CHIP_ID_1271_PG10:
654 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
655 wl->chip.id);
656
657 ret = wl1271_setup(wl);
658 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300659 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300660 break;
661 case CHIP_ID_1271_PG20:
662 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
663 wl->chip.id);
664
665 ret = wl1271_setup(wl);
666 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300667 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300668 break;
669 default:
670 wl1271_error("unsupported chip id: 0x%x", wl->chip.id);
671 ret = -ENODEV;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300672 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300673 }
674
675 if (wl->fw == NULL) {
676 ret = wl1271_fetch_firmware(wl);
677 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300678 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300679 }
680
681 /* No NVS from netlink, try to get it from the filesystem */
682 if (wl->nvs == NULL) {
683 ret = wl1271_fetch_nvs(wl);
684 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300685 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300686 }
687
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300688 goto out;
689
690out_power_off:
691 wl1271_power_off(wl);
692
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300693out:
694 return ret;
695}
696
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300697int wl1271_plt_start(struct wl1271 *wl)
698{
699 int ret;
700
701 mutex_lock(&wl->mutex);
702
703 wl1271_notice("power up");
704
705 if (wl->state != WL1271_STATE_OFF) {
706 wl1271_error("cannot go into PLT state because not "
707 "in off state: %d", wl->state);
708 ret = -EBUSY;
709 goto out;
710 }
711
712 wl->state = WL1271_STATE_PLT;
713
714 ret = wl1271_chip_wakeup(wl);
715 if (ret < 0)
716 goto out;
717
718 ret = wl1271_boot(wl);
719 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300720 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300721
722 wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver);
723
724 ret = wl1271_plt_init(wl);
725 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300726 goto out_irq_disable;
727
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300728 /* Make sure power saving is disabled */
729 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
730 if (ret < 0)
731 goto out_irq_disable;
732
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300733 goto out;
734
735out_irq_disable:
736 wl1271_disable_interrupts(wl);
737
738out_power_off:
739 wl1271_power_off(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300740
741out:
742 mutex_unlock(&wl->mutex);
743
744 return ret;
745}
746
747int wl1271_plt_stop(struct wl1271 *wl)
748{
749 int ret = 0;
750
751 mutex_lock(&wl->mutex);
752
753 wl1271_notice("power down");
754
755 if (wl->state != WL1271_STATE_PLT) {
756 wl1271_error("cannot power down because not in PLT "
757 "state: %d", wl->state);
758 ret = -EBUSY;
759 goto out;
760 }
761
762 wl1271_disable_interrupts(wl);
763 wl1271_power_off(wl);
764
765 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300766 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300767
768out:
769 mutex_unlock(&wl->mutex);
770
771 return ret;
772}
773
774
775static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
776{
777 struct wl1271 *wl = hw->priv;
778
779 skb_queue_tail(&wl->tx_queue, skb);
780
781 /*
782 * The chip specific setup must run before the first TX packet -
783 * before that, the tx_work will not be initialized!
784 */
785
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300786 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300787
788 /*
789 * The workqueue is slow to process the tx_queue and we need stop
790 * the queue here, otherwise the queue will get too long.
791 */
792 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) {
793 ieee80211_stop_queues(wl->hw);
794
795 /*
796 * FIXME: this is racy, the variable is not properly
797 * protected. Maybe fix this by removing the stupid
798 * variable altogether and checking the real queue state?
799 */
800 wl->tx_queue_stopped = true;
801 }
802
803 return NETDEV_TX_OK;
804}
805
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300806static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
807 void *arg)
808{
809 struct net_device *dev;
810 struct wireless_dev *wdev;
811 struct wiphy *wiphy;
812 struct ieee80211_hw *hw;
813 struct wl1271 *wl;
814 struct wl1271 *wl_temp;
815 struct in_device *idev;
816 struct in_ifaddr *ifa = arg;
817 int ret = 0;
818
819 /* FIXME: this ugly function should probably be implemented in the
820 * mac80211, and here should only be a simple callback handling actual
821 * setting of the filters. Now we need to dig up references to
822 * various structures to gain access to what we need.
823 * Also, because of this, there is no "initial" setting of the filter
824 * in "op_start", because we don't want to dig up struct net_device
825 * there - the filter will be set upon first change of the interface
826 * IP address. */
827
828 dev = ifa->ifa_dev->dev;
829
830 wdev = dev->ieee80211_ptr;
831 if (wdev == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200832 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300833
834 wiphy = wdev->wiphy;
835 if (wiphy == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200836 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300837
838 hw = wiphy_priv(wiphy);
839 if (hw == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200840 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300841
842 /* Check that the interface is one supported by this driver. */
843 wl_temp = hw->priv;
844 list_for_each_entry(wl, &wl_list, list) {
845 if (wl == wl_temp)
846 break;
847 }
848 if (wl == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200849 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300850
851 /* Get the interface IP address for the device. "ifa" will become
852 NULL if:
853 - there is no IPV4 protocol address configured
854 - there are multiple (virtual) IPV4 addresses configured
855 When "ifa" is NULL, filtering will be disabled.
856 */
857 ifa = NULL;
858 idev = dev->ip_ptr;
859 if (idev)
860 ifa = idev->ifa_list;
861
862 if (ifa && ifa->ifa_next)
863 ifa = NULL;
864
865 mutex_lock(&wl->mutex);
866
867 if (wl->state == WL1271_STATE_OFF)
868 goto out;
869
870 ret = wl1271_ps_elp_wakeup(wl, false);
871 if (ret < 0)
872 goto out;
873 if (ifa)
874 ret = wl1271_acx_arp_ip_filter(wl, true,
875 (u8 *)&ifa->ifa_address,
876 ACX_IPV4_VERSION);
877 else
878 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
879 ACX_IPV4_VERSION);
880 wl1271_ps_elp_sleep(wl);
881
882out:
883 mutex_unlock(&wl->mutex);
884
Luciano Coelho17d72652009-11-23 23:22:15 +0200885 return NOTIFY_OK;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300886}
887
888static struct notifier_block wl1271_dev_notifier = {
889 .notifier_call = wl1271_dev_notify,
890};
891
892
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300893static int wl1271_op_start(struct ieee80211_hw *hw)
894{
895 struct wl1271 *wl = hw->priv;
896 int ret = 0;
897
898 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
899
900 mutex_lock(&wl->mutex);
901
902 if (wl->state != WL1271_STATE_OFF) {
903 wl1271_error("cannot start because not in off state: %d",
904 wl->state);
905 ret = -EBUSY;
906 goto out;
907 }
908
909 ret = wl1271_chip_wakeup(wl);
910 if (ret < 0)
911 goto out;
912
913 ret = wl1271_boot(wl);
914 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300915 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300916
917 ret = wl1271_hw_init(wl);
918 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300919 goto out_irq_disable;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300920
921 wl->state = WL1271_STATE_ON;
922
923 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
924
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300925 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300926
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300927out_irq_disable:
928 wl1271_disable_interrupts(wl);
929
930out_power_off:
931 wl1271_power_off(wl);
932
933out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300934 mutex_unlock(&wl->mutex);
935
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300936 if (!ret) {
937 list_add(&wl->list, &wl_list);
938 register_inetaddr_notifier(&wl1271_dev_notifier);
939 }
940
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300941 return ret;
942}
943
944static void wl1271_op_stop(struct ieee80211_hw *hw)
945{
946 struct wl1271 *wl = hw->priv;
947 int i;
948
949 wl1271_info("down");
950
951 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
952
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300953 unregister_inetaddr_notifier(&wl1271_dev_notifier);
954 list_del(&wl->list);
955
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300956 mutex_lock(&wl->mutex);
957
958 WARN_ON(wl->state != WL1271_STATE_ON);
959
960 if (wl->scanning) {
961 mutex_unlock(&wl->mutex);
962 ieee80211_scan_completed(wl->hw, true);
963 mutex_lock(&wl->mutex);
964 wl->scanning = false;
965 }
966
967 wl->state = WL1271_STATE_OFF;
968
969 wl1271_disable_interrupts(wl);
970
971 mutex_unlock(&wl->mutex);
972
973 cancel_work_sync(&wl->irq_work);
974 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300975
976 mutex_lock(&wl->mutex);
977
978 /* let's notify MAC80211 about the remaining pending TX frames */
979 wl1271_tx_flush(wl);
980 wl1271_power_off(wl);
981
982 memset(wl->bssid, 0, ETH_ALEN);
983 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
984 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300985 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +0300986 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300987
988 wl->rx_counter = 0;
989 wl->elp = false;
990 wl->psm = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200991 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300992 wl->tx_queue_stopped = false;
993 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
994 wl->tx_blocks_available = 0;
995 wl->tx_results_count = 0;
996 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +0300997 wl->tx_security_last_seq = 0;
998 wl->tx_security_seq_16 = 0;
999 wl->tx_security_seq_32 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001000 wl->time_offset = 0;
1001 wl->session_counter = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001002 wl->joined = false;
1003
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001004 for (i = 0; i < NUM_TX_QUEUES; i++)
1005 wl->tx_blocks_freed[i] = 0;
1006
1007 wl1271_debugfs_reset(wl);
1008 mutex_unlock(&wl->mutex);
1009}
1010
1011static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1012 struct ieee80211_if_init_conf *conf)
1013{
1014 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001015 int ret = 0;
1016
John W. Linvillee5539bc2009-08-18 10:50:34 -04001017 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1018 conf->type, conf->mac_addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001019
1020 mutex_lock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001021 if (wl->vif) {
1022 ret = -EBUSY;
1023 goto out;
1024 }
1025
1026 wl->vif = conf->vif;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001027
1028 switch (conf->type) {
1029 case NL80211_IFTYPE_STATION:
1030 wl->bss_type = BSS_TYPE_STA_BSS;
1031 break;
1032 case NL80211_IFTYPE_ADHOC:
1033 wl->bss_type = BSS_TYPE_IBSS;
1034 break;
1035 default:
1036 ret = -EOPNOTSUPP;
1037 goto out;
1038 }
1039
1040 /* FIXME: what if conf->mac_addr changes? */
1041
1042out:
1043 mutex_unlock(&wl->mutex);
1044 return ret;
1045}
1046
1047static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1048 struct ieee80211_if_init_conf *conf)
1049{
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001050 struct wl1271 *wl = hw->priv;
1051
1052 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001053 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001054 wl->vif = NULL;
1055 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001056}
1057
1058#if 0
1059static int wl1271_op_config_interface(struct ieee80211_hw *hw,
1060 struct ieee80211_vif *vif,
1061 struct ieee80211_if_conf *conf)
1062{
1063 struct wl1271 *wl = hw->priv;
1064 struct sk_buff *beacon;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001065 int ret;
1066
David S. Miller32646902009-09-17 10:18:30 -07001067 wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM",
1068 conf->bssid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001069 wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid,
1070 conf->ssid_len);
1071
1072 mutex_lock(&wl->mutex);
1073
1074 ret = wl1271_ps_elp_wakeup(wl, false);
1075 if (ret < 0)
1076 goto out;
1077
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001078 if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
1079 wl1271_debug(DEBUG_MAC80211, "bssid changed");
1080
1081 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
1082
1083 ret = wl1271_cmd_join(wl);
1084 if (ret < 0)
1085 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001086
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001087 ret = wl1271_cmd_build_null_data(wl);
1088 if (ret < 0)
1089 goto out_sleep;
1090 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001091
1092 wl->ssid_len = conf->ssid_len;
1093 if (wl->ssid_len)
1094 memcpy(wl->ssid, conf->ssid, wl->ssid_len);
1095
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001096 if (conf->changed & IEEE80211_IFCC_BEACON) {
1097 beacon = ieee80211_beacon_get(hw, vif);
1098 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1099 beacon->data, beacon->len);
1100
1101 if (ret < 0) {
1102 dev_kfree_skb(beacon);
1103 goto out_sleep;
1104 }
1105
1106 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE,
1107 beacon->data, beacon->len);
1108
1109 dev_kfree_skb(beacon);
1110
1111 if (ret < 0)
1112 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001113 }
1114
1115out_sleep:
1116 wl1271_ps_elp_sleep(wl);
1117
1118out:
1119 mutex_unlock(&wl->mutex);
1120
1121 return ret;
1122}
1123#endif
1124
1125static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1126{
1127 struct wl1271 *wl = hw->priv;
1128 struct ieee80211_conf *conf = &hw->conf;
1129 int channel, ret = 0;
1130
1131 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1132
1133 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
1134 channel,
1135 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
1136 conf->power_level);
1137
1138 mutex_lock(&wl->mutex);
1139
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001140 wl->band = conf->channel->band;
1141
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001142 ret = wl1271_ps_elp_wakeup(wl, false);
1143 if (ret < 0)
1144 goto out;
1145
1146 if (channel != wl->channel) {
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001147 /*
1148 * We assume that the stack will configure the right channel
1149 * before associating, so we don't need to send a join
1150 * command here. We will join the right channel when the
1151 * BSSID changes
1152 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001153 wl->channel = channel;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001154 }
1155
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001156 if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) {
1157 wl1271_info("psm enabled");
1158
1159 wl->psm_requested = true;
1160
1161 /*
1162 * We enter PSM only if we're already associated.
1163 * If we're not, we'll enter it when joining an SSID,
1164 * through the bss_info_changed() hook.
1165 */
1166 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
1167 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
1168 wl->psm_requested) {
1169 wl1271_info("psm disabled");
1170
1171 wl->psm_requested = false;
1172
1173 if (wl->psm)
1174 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE);
1175 }
1176
1177 if (conf->power_level != wl->power_level) {
1178 ret = wl1271_acx_tx_power(wl, conf->power_level);
1179 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001180 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001181
1182 wl->power_level = conf->power_level;
1183 }
1184
1185out_sleep:
1186 wl1271_ps_elp_sleep(wl);
1187
1188out:
1189 mutex_unlock(&wl->mutex);
1190
1191 return ret;
1192}
1193
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001194struct wl1271_filter_params {
1195 bool enabled;
1196 int mc_list_length;
1197 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1198};
1199
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001200static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1201 struct dev_addr_list *mc_list)
1202{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001203 struct wl1271_filter_params *fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001204 int i;
1205
Juuso Oikarinen74441132009-10-13 12:47:53 +03001206 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001207 if (!fp) {
1208 wl1271_error("Out of memory setting filters.");
1209 return 0;
1210 }
1211
1212 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001213 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001214 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1215 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001216 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001217 }
1218
1219 fp->mc_list_length = 0;
1220 for (i = 0; i < mc_count; i++) {
1221 if (mc_list->da_addrlen == ETH_ALEN) {
1222 memcpy(fp->mc_list[fp->mc_list_length],
1223 mc_list->da_addr, ETH_ALEN);
1224 fp->mc_list_length++;
1225 } else
1226 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001227 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001228 }
1229
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001230 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001231}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001232
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001233#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1234 FIF_ALLMULTI | \
1235 FIF_FCSFAIL | \
1236 FIF_BCN_PRBRESP_PROMISC | \
1237 FIF_CONTROL | \
1238 FIF_OTHER_BSS)
1239
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001240static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1241 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001242 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001243{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001244 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001245 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001246 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001247
1248 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1249
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001250 mutex_lock(&wl->mutex);
1251
1252 if (wl->state == WL1271_STATE_OFF)
1253 goto out;
1254
1255 ret = wl1271_ps_elp_wakeup(wl, false);
1256 if (ret < 0)
1257 goto out;
1258
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001259 *total &= WL1271_SUPPORTED_FILTERS;
1260 changed &= WL1271_SUPPORTED_FILTERS;
1261
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001262 if (*total & FIF_ALLMULTI)
1263 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1264 else if (fp)
1265 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1266 fp->mc_list,
1267 fp->mc_list_length);
1268 if (ret < 0)
1269 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001270
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001271 kfree(fp);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001272
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001273 /* FIXME: We still need to set our filters properly */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001274
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001275 /* determine, whether supported filter values have changed */
1276 if (changed == 0)
1277 goto out_sleep;
1278
1279 /* apply configured filters */
1280 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1281 if (ret < 0)
1282 goto out_sleep;
1283
1284out_sleep:
1285 wl1271_ps_elp_sleep(wl);
1286
1287out:
1288 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001289}
1290
1291static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1292 struct ieee80211_vif *vif,
1293 struct ieee80211_sta *sta,
1294 struct ieee80211_key_conf *key_conf)
1295{
1296 struct wl1271 *wl = hw->priv;
1297 const u8 *addr;
1298 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001299 u32 tx_seq_32 = 0;
1300 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001301 u8 key_type;
1302
1303 static const u8 bcast_addr[ETH_ALEN] =
1304 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1305
1306 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1307
1308 addr = sta ? sta->addr : bcast_addr;
1309
1310 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1311 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1312 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1313 key_conf->alg, key_conf->keyidx,
1314 key_conf->keylen, key_conf->flags);
1315 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1316
1317 if (is_zero_ether_addr(addr)) {
1318 /* We dont support TX only encryption */
1319 ret = -EOPNOTSUPP;
1320 goto out;
1321 }
1322
1323 mutex_lock(&wl->mutex);
1324
1325 ret = wl1271_ps_elp_wakeup(wl, false);
1326 if (ret < 0)
1327 goto out_unlock;
1328
1329 switch (key_conf->alg) {
1330 case ALG_WEP:
1331 key_type = KEY_WEP;
1332
1333 key_conf->hw_key_idx = key_conf->keyidx;
1334 break;
1335 case ALG_TKIP:
1336 key_type = KEY_TKIP;
1337
1338 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001339 tx_seq_32 = wl->tx_security_seq_32;
1340 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001341 break;
1342 case ALG_CCMP:
1343 key_type = KEY_AES;
1344
1345 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001346 tx_seq_32 = wl->tx_security_seq_32;
1347 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001348 break;
1349 default:
1350 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1351
1352 ret = -EOPNOTSUPP;
1353 goto out_sleep;
1354 }
1355
1356 switch (cmd) {
1357 case SET_KEY:
1358 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1359 key_conf->keyidx, key_type,
1360 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001361 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001362 if (ret < 0) {
1363 wl1271_error("Could not add or replace key");
1364 goto out_sleep;
1365 }
1366 break;
1367
1368 case DISABLE_KEY:
1369 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1370 key_conf->keyidx, key_type,
1371 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001372 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001373 if (ret < 0) {
1374 wl1271_error("Could not remove key");
1375 goto out_sleep;
1376 }
1377 break;
1378
1379 default:
1380 wl1271_error("Unsupported key cmd 0x%x", cmd);
1381 ret = -EOPNOTSUPP;
1382 goto out_sleep;
1383
1384 break;
1385 }
1386
1387out_sleep:
1388 wl1271_ps_elp_sleep(wl);
1389
1390out_unlock:
1391 mutex_unlock(&wl->mutex);
1392
1393out:
1394 return ret;
1395}
1396
1397static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1398 struct cfg80211_scan_request *req)
1399{
1400 struct wl1271 *wl = hw->priv;
1401 int ret;
1402 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001403 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001404
1405 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1406
1407 if (req->n_ssids) {
1408 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001409 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001410 }
1411
1412 mutex_lock(&wl->mutex);
1413
1414 ret = wl1271_ps_elp_wakeup(wl, false);
1415 if (ret < 0)
1416 goto out;
1417
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001418 if (wl1271_11a_enabled())
1419 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1420 WL1271_SCAN_BAND_DUAL, 3);
1421 else
1422 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1423 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001424
1425 wl1271_ps_elp_sleep(wl);
1426
1427out:
1428 mutex_unlock(&wl->mutex);
1429
1430 return ret;
1431}
1432
1433static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1434{
1435 struct wl1271 *wl = hw->priv;
1436 int ret;
1437
1438 mutex_lock(&wl->mutex);
1439
1440 ret = wl1271_ps_elp_wakeup(wl, false);
1441 if (ret < 0)
1442 goto out;
1443
1444 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1445 if (ret < 0)
1446 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1447
1448 wl1271_ps_elp_sleep(wl);
1449
1450out:
1451 mutex_unlock(&wl->mutex);
1452
1453 return ret;
1454}
1455
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001456static u32 wl1271_enabled_rates_get(struct wl1271 *wl, u64 basic_rate_set)
1457{
1458 struct ieee80211_supported_band *band;
1459 u32 enabled_rates = 0;
1460 int bit;
1461
1462 band = wl->hw->wiphy->bands[wl->band];
1463 for (bit = 0; bit < band->n_bitrates; bit++) {
1464 if (basic_rate_set & 0x1)
1465 enabled_rates |= band->bitrates[bit].hw_value;
1466 basic_rate_set >>= 1;
1467 }
1468
1469 return enabled_rates;
1470}
1471
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001472static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1473 struct ieee80211_vif *vif,
1474 struct ieee80211_bss_conf *bss_conf,
1475 u32 changed)
1476{
1477 enum wl1271_cmd_ps_mode mode;
1478 struct wl1271 *wl = hw->priv;
1479 int ret;
1480
1481 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1482
1483 mutex_lock(&wl->mutex);
1484
1485 ret = wl1271_ps_elp_wakeup(wl, false);
1486 if (ret < 0)
1487 goto out;
1488
1489 if (changed & BSS_CHANGED_ASSOC) {
1490 if (bss_conf->assoc) {
1491 wl->aid = bss_conf->aid;
1492
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001493 /*
1494 * with wl1271, we don't need to update the
1495 * beacon_int and dtim_period, because the firmware
1496 * updates it by itself when the first beacon is
1497 * received after a join.
1498 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001499 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1500 if (ret < 0)
1501 goto out_sleep;
1502
1503 ret = wl1271_acx_aid(wl, wl->aid);
1504 if (ret < 0)
1505 goto out_sleep;
1506
1507 /* If we want to go in PSM but we're not there yet */
1508 if (wl->psm_requested && !wl->psm) {
1509 mode = STATION_POWER_SAVE_MODE;
1510 ret = wl1271_ps_set_mode(wl, mode);
1511 if (ret < 0)
1512 goto out_sleep;
1513 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001514 } else {
1515 /* use defaults when not associated */
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001516 wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
1517 wl->aid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001518 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001519
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001520 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001521
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001522 if (changed & BSS_CHANGED_ERP_SLOT) {
1523 if (bss_conf->use_short_slot)
1524 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1525 else
1526 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1527 if (ret < 0) {
1528 wl1271_warning("Set slot time failed %d", ret);
1529 goto out_sleep;
1530 }
1531 }
1532
1533 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1534 if (bss_conf->use_short_preamble)
1535 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1536 else
1537 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1538 }
1539
1540 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1541 if (bss_conf->use_cts_prot)
1542 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1543 else
1544 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1545 if (ret < 0) {
1546 wl1271_warning("Set ctsprotect failed %d", ret);
1547 goto out_sleep;
1548 }
1549 }
1550
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001551 if (changed & BSS_CHANGED_BASIC_RATES) {
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001552 wl->basic_rate_set = wl1271_enabled_rates_get(
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001553 wl, bss_conf->basic_rates);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001554
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001555 ret = wl1271_acx_rate_policies(wl, wl->basic_rate_set);
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001556 if (ret < 0) {
1557 wl1271_warning("Set rate policies failed %d", ret);
1558 goto out_sleep;
1559 }
1560 }
1561
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001562out_sleep:
1563 wl1271_ps_elp_sleep(wl);
1564
1565out:
1566 mutex_unlock(&wl->mutex);
1567}
1568
1569
1570/* can't be const, mac80211 writes to this */
1571static struct ieee80211_rate wl1271_rates[] = {
1572 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001573 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1574 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001575 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001576 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1577 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001578 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1579 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001580 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1581 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001582 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1583 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001584 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1585 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001586 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1587 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001588 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1589 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001590 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001591 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1592 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001593 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001594 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1595 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001596 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001597 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1598 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001599 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001600 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1601 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001602 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001603 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1604 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001605 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001606 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1607 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001608 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001609 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1610 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001611};
1612
1613/* can't be const, mac80211 writes to this */
1614static struct ieee80211_channel wl1271_channels[] = {
1615 { .hw_value = 1, .center_freq = 2412},
1616 { .hw_value = 2, .center_freq = 2417},
1617 { .hw_value = 3, .center_freq = 2422},
1618 { .hw_value = 4, .center_freq = 2427},
1619 { .hw_value = 5, .center_freq = 2432},
1620 { .hw_value = 6, .center_freq = 2437},
1621 { .hw_value = 7, .center_freq = 2442},
1622 { .hw_value = 8, .center_freq = 2447},
1623 { .hw_value = 9, .center_freq = 2452},
1624 { .hw_value = 10, .center_freq = 2457},
1625 { .hw_value = 11, .center_freq = 2462},
1626 { .hw_value = 12, .center_freq = 2467},
1627 { .hw_value = 13, .center_freq = 2472},
1628};
1629
1630/* can't be const, mac80211 writes to this */
1631static struct ieee80211_supported_band wl1271_band_2ghz = {
1632 .channels = wl1271_channels,
1633 .n_channels = ARRAY_SIZE(wl1271_channels),
1634 .bitrates = wl1271_rates,
1635 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1636};
1637
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001638/* 5 GHz data rates for WL1273 */
1639static struct ieee80211_rate wl1271_rates_5ghz[] = {
1640 { .bitrate = 60,
1641 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1642 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
1643 { .bitrate = 90,
1644 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1645 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
1646 { .bitrate = 120,
1647 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1648 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
1649 { .bitrate = 180,
1650 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1651 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
1652 { .bitrate = 240,
1653 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1654 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
1655 { .bitrate = 360,
1656 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1657 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
1658 { .bitrate = 480,
1659 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1660 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
1661 { .bitrate = 540,
1662 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1663 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
1664};
1665
1666/* 5 GHz band channels for WL1273 */
1667static struct ieee80211_channel wl1271_channels_5ghz[] = {
1668 { .hw_value = 183, .center_freq = 4915},
1669 { .hw_value = 184, .center_freq = 4920},
1670 { .hw_value = 185, .center_freq = 4925},
1671 { .hw_value = 187, .center_freq = 4935},
1672 { .hw_value = 188, .center_freq = 4940},
1673 { .hw_value = 189, .center_freq = 4945},
1674 { .hw_value = 192, .center_freq = 4960},
1675 { .hw_value = 196, .center_freq = 4980},
1676 { .hw_value = 7, .center_freq = 5035},
1677 { .hw_value = 8, .center_freq = 5040},
1678 { .hw_value = 9, .center_freq = 5045},
1679 { .hw_value = 11, .center_freq = 5055},
1680 { .hw_value = 12, .center_freq = 5060},
1681 { .hw_value = 16, .center_freq = 5080},
1682 { .hw_value = 34, .center_freq = 5170},
1683 { .hw_value = 36, .center_freq = 5180},
1684 { .hw_value = 38, .center_freq = 5190},
1685 { .hw_value = 40, .center_freq = 5200},
1686 { .hw_value = 42, .center_freq = 5210},
1687 { .hw_value = 44, .center_freq = 5220},
1688 { .hw_value = 46, .center_freq = 5230},
1689 { .hw_value = 48, .center_freq = 5240},
1690 { .hw_value = 52, .center_freq = 5260},
1691 { .hw_value = 56, .center_freq = 5280},
1692 { .hw_value = 60, .center_freq = 5300},
1693 { .hw_value = 64, .center_freq = 5320},
1694 { .hw_value = 100, .center_freq = 5500},
1695 { .hw_value = 104, .center_freq = 5520},
1696 { .hw_value = 108, .center_freq = 5540},
1697 { .hw_value = 112, .center_freq = 5560},
1698 { .hw_value = 116, .center_freq = 5580},
1699 { .hw_value = 120, .center_freq = 5600},
1700 { .hw_value = 124, .center_freq = 5620},
1701 { .hw_value = 128, .center_freq = 5640},
1702 { .hw_value = 132, .center_freq = 5660},
1703 { .hw_value = 136, .center_freq = 5680},
1704 { .hw_value = 140, .center_freq = 5700},
1705 { .hw_value = 149, .center_freq = 5745},
1706 { .hw_value = 153, .center_freq = 5765},
1707 { .hw_value = 157, .center_freq = 5785},
1708 { .hw_value = 161, .center_freq = 5805},
1709 { .hw_value = 165, .center_freq = 5825},
1710};
1711
1712
1713static struct ieee80211_supported_band wl1271_band_5ghz = {
1714 .channels = wl1271_channels_5ghz,
1715 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
1716 .bitrates = wl1271_rates_5ghz,
1717 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
1718};
1719
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001720static const struct ieee80211_ops wl1271_ops = {
1721 .start = wl1271_op_start,
1722 .stop = wl1271_op_stop,
1723 .add_interface = wl1271_op_add_interface,
1724 .remove_interface = wl1271_op_remove_interface,
1725 .config = wl1271_op_config,
1726/* .config_interface = wl1271_op_config_interface, */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001727 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001728 .configure_filter = wl1271_op_configure_filter,
1729 .tx = wl1271_op_tx,
1730 .set_key = wl1271_op_set_key,
1731 .hw_scan = wl1271_op_hw_scan,
1732 .bss_info_changed = wl1271_op_bss_info_changed,
1733 .set_rts_threshold = wl1271_op_set_rts_threshold,
1734};
1735
1736static int wl1271_register_hw(struct wl1271 *wl)
1737{
1738 int ret;
1739
1740 if (wl->mac80211_registered)
1741 return 0;
1742
1743 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
1744
1745 ret = ieee80211_register_hw(wl->hw);
1746 if (ret < 0) {
1747 wl1271_error("unable to register mac80211 hw: %d", ret);
1748 return ret;
1749 }
1750
1751 wl->mac80211_registered = true;
1752
1753 wl1271_notice("loaded");
1754
1755 return 0;
1756}
1757
1758static int wl1271_init_ieee80211(struct wl1271 *wl)
1759{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03001760 /* The tx descriptor buffer and the TKIP space. */
1761 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
1762 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001763
1764 /* unit us */
1765 /* FIXME: find a proper value */
1766 wl->hw->channel_change_time = 10000;
1767
1768 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03001769 IEEE80211_HW_NOISE_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02001770 IEEE80211_HW_BEACON_FILTER |
1771 IEEE80211_HW_SUPPORTS_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001772
1773 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
1774 wl->hw->wiphy->max_scan_ssids = 1;
1775 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
1776
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001777 if (wl1271_11a_enabled())
1778 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
1779
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001780 SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
1781
1782 return 0;
1783}
1784
1785static void wl1271_device_release(struct device *dev)
1786{
1787
1788}
1789
1790static struct platform_device wl1271_device = {
1791 .name = "wl1271",
1792 .id = -1,
1793
1794 /* device model insists to have a release function */
1795 .dev = {
1796 .release = wl1271_device_release,
1797 },
1798};
1799
1800#define WL1271_DEFAULT_CHANNEL 0
1801static int __devinit wl1271_probe(struct spi_device *spi)
1802{
1803 struct wl12xx_platform_data *pdata;
1804 struct ieee80211_hw *hw;
1805 struct wl1271 *wl;
1806 int ret, i;
1807 static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
1808
1809 pdata = spi->dev.platform_data;
1810 if (!pdata) {
1811 wl1271_error("no platform data");
1812 return -ENODEV;
1813 }
1814
1815 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
1816 if (!hw) {
1817 wl1271_error("could not alloc ieee80211_hw");
1818 return -ENOMEM;
1819 }
1820
1821 wl = hw->priv;
1822 memset(wl, 0, sizeof(*wl));
1823
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001824 INIT_LIST_HEAD(&wl->list);
1825
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001826 wl->hw = hw;
1827 dev_set_drvdata(&spi->dev, wl);
1828 wl->spi = spi;
1829
1830 skb_queue_head_init(&wl->tx_queue);
1831
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03001832 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001833 wl->channel = WL1271_DEFAULT_CHANNEL;
1834 wl->scanning = false;
1835 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001836 wl->rx_counter = 0;
1837 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1838 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1839 wl->elp = false;
1840 wl->psm = 0;
1841 wl->psm_requested = false;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001842 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001843 wl->tx_queue_stopped = false;
1844 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001845 wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001846 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001847 wl->vif = NULL;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001848 wl->joined = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001849
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03001850 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001851 wl->tx_frames[i] = NULL;
1852
1853 spin_lock_init(&wl->wl_lock);
1854
1855 /*
1856 * In case our MAC address is not correctly set,
1857 * we use a random but Nokia MAC.
1858 */
1859 memcpy(wl->mac_addr, nokia_oui, 3);
1860 get_random_bytes(wl->mac_addr + 3, 3);
1861
1862 wl->state = WL1271_STATE_OFF;
1863 mutex_init(&wl->mutex);
1864
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001865 /* This is the only SPI value that we need to set here, the rest
1866 * comes from the board-peripherals file */
1867 spi->bits_per_word = 32;
1868
1869 ret = spi_setup(spi);
1870 if (ret < 0) {
1871 wl1271_error("spi_setup failed");
1872 goto out_free;
1873 }
1874
1875 wl->set_power = pdata->set_power;
1876 if (!wl->set_power) {
1877 wl1271_error("set power function missing in platform data");
1878 ret = -ENODEV;
1879 goto out_free;
1880 }
1881
1882 wl->irq = spi->irq;
1883 if (wl->irq < 0) {
1884 wl1271_error("irq missing in platform data");
1885 ret = -ENODEV;
1886 goto out_free;
1887 }
1888
1889 ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
1890 if (ret < 0) {
1891 wl1271_error("request_irq() failed: %d", ret);
1892 goto out_free;
1893 }
1894
1895 set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
1896
1897 disable_irq(wl->irq);
1898
1899 ret = platform_device_register(&wl1271_device);
1900 if (ret) {
1901 wl1271_error("couldn't register platform device");
1902 goto out_irq;
1903 }
1904 dev_set_drvdata(&wl1271_device.dev, wl);
1905
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001906 /* Apply default driver configuration. */
1907 wl1271_conf_init(wl);
1908
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001909 ret = wl1271_init_ieee80211(wl);
1910 if (ret)
1911 goto out_platform;
1912
1913 ret = wl1271_register_hw(wl);
1914 if (ret)
1915 goto out_platform;
1916
1917 wl1271_debugfs_init(wl);
1918
1919 wl1271_notice("initialized");
1920
1921 return 0;
1922
1923 out_platform:
1924 platform_device_unregister(&wl1271_device);
1925
1926 out_irq:
1927 free_irq(wl->irq, wl);
1928
1929 out_free:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001930 ieee80211_free_hw(hw);
1931
1932 return ret;
1933}
1934
1935static int __devexit wl1271_remove(struct spi_device *spi)
1936{
1937 struct wl1271 *wl = dev_get_drvdata(&spi->dev);
1938
1939 ieee80211_unregister_hw(wl->hw);
1940
1941 wl1271_debugfs_exit(wl);
1942 platform_device_unregister(&wl1271_device);
1943 free_irq(wl->irq, wl);
1944 kfree(wl->target_mem_map);
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001945 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001946 wl->fw = NULL;
1947 kfree(wl->nvs);
1948 wl->nvs = NULL;
1949
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001950 kfree(wl->fw_status);
1951 kfree(wl->tx_res_if);
1952
1953 ieee80211_free_hw(wl->hw);
1954
1955 return 0;
1956}
1957
1958
1959static struct spi_driver wl1271_spi_driver = {
1960 .driver = {
1961 .name = "wl1271",
1962 .bus = &spi_bus_type,
1963 .owner = THIS_MODULE,
1964 },
1965
1966 .probe = wl1271_probe,
1967 .remove = __devexit_p(wl1271_remove),
1968};
1969
1970static int __init wl1271_init(void)
1971{
1972 int ret;
1973
1974 ret = spi_register_driver(&wl1271_spi_driver);
1975 if (ret < 0) {
1976 wl1271_error("failed to register spi driver: %d", ret);
1977 goto out;
1978 }
1979
1980out:
1981 return ret;
1982}
1983
1984static void __exit wl1271_exit(void)
1985{
1986 spi_unregister_driver(&wl1271_spi_driver);
1987
1988 wl1271_notice("unloaded");
1989}
1990
1991module_init(wl1271_init);
1992module_exit(wl1271_exit);
1993
1994MODULE_LICENSE("GPL");
1995MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
Luciano Coelho2f018722009-10-08 21:56:27 +03001996MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
Ben Hutchings49f146d2009-11-07 22:02:15 +00001997MODULE_FIRMWARE(WL1271_FW_NAME);