blob: f6d42e613a56c7859306139dc467702ad5ae5ccd [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,
Luciano Coelhoa3e84842009-12-11 15:40:42 +0200259 .tx_bip_fem_autodetect = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300260 .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 = {
Luciano Coelhoa3e84842009-12-11 15:40:42 +0200277 .rx_trace_loss = 0x24,
278 .tx_trace_loss = 0x0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300279 .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 },
Luciano Coelhoa3e84842009-12-11 15:40:42 +0200289 .tx_ref_pd_voltage = 0x1a9,
290 .tx_ref_power = 0x80,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300291 .tx_offset_db = 0x0,
292 .tx_rate_limits_normal = {
Luciano Coelhoa3e84842009-12-11 15:40:42 +0200293 0x1d, 0x1f, 0x24, 0x28, 0x28, 0x29 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300294 .tx_rate_limits_degraded = {
Luciano Coelhoa3e84842009-12-11 15:40:42 +0200295 0x19, 0x1f, 0x22, 0x23, 0x27, 0x28 },
Luciano Coelhocf18be42009-12-11 15:40:43 +0200296 .tx_rate_limits_extreme = {
297 0x19, 0x1c, 0x1e, 0x20, 0x24, 0x25 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300298 .tx_channel_limits_11b = {
299 0x22, 0x50, 0x50, 0x50, 0x50, 0x50,
300 0x50, 0x50, 0x50, 0x50, 0x22, 0x50,
301 0x22, 0x50 },
302 .tx_channel_limits_ofdm = {
303 0x20, 0x50, 0x50, 0x50, 0x50, 0x50,
304 0x50, 0x50, 0x50, 0x50, 0x20, 0x50,
305 0x20, 0x50 },
306 .tx_pdv_rate_offsets = {
Luciano Coelhoa3e84842009-12-11 15:40:42 +0200307 0x07, 0x08, 0x04, 0x02, 0x02, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300308 .tx_ibias = {
Luciano Coelhoa3e84842009-12-11 15:40:42 +0200309 0x11, 0x11, 0x15, 0x11, 0x15, 0x0f },
310 .rx_fem_insertion_loss = 0x0e,
Luciano Coelhocf18be42009-12-11 15:40:43 +0200311 .degraded_low_to_normal_threshold = 0x1e,
312 .degraded_normal_to_high_threshold = 0x2d,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300313 .tx_ref_pd_voltage_5 = {
314 0x0190, 0x01a4, 0x01c3, 0x01d8,
315 0x020a, 0x021c },
316 .tx_ref_power_5 = {
317 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 },
318 .tx_offset_db_5 = {
319 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300320 .tx_rate_limits_normal_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300321 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300322 .tx_rate_limits_degraded_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300323 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
Luciano Coelhocf18be42009-12-11 15:40:43 +0200324 .tx_rate_limits_extreme_5 = {
325 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300326 .tx_channel_limits_ofdm_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300327 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
328 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
329 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
330 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
331 0x50, 0x50, 0x50 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300332 .tx_pdv_rate_offsets_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300333 0x01, 0x02, 0x02, 0x02, 0x02, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300334 .tx_ibias_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300335 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
336 .rx_fem_insertion_loss_5 = {
Luciano Coelhocf18be42009-12-11 15:40:43 +0200337 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
338 .degraded_low_to_normal_threshold_5 = 0x00,
339 .degraded_normal_to_high_threshold_5 = 0x00
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300340 }
341 }
342};
343
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300344static LIST_HEAD(wl_list);
345
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300346static void wl1271_conf_init(struct wl1271 *wl)
347{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300348
349 /*
350 * This function applies the default configuration to the driver. This
351 * function is invoked upon driver load (spi probe.)
352 *
353 * The configuration is stored in a run-time structure in order to
354 * facilitate for run-time adjustment of any of the parameters. Making
355 * changes to the configuration structure will apply the new values on
356 * the next interface up (wl1271_op_start.)
357 */
358
359 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300360 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300361
362 if (wl1271_11a_enabled())
363 wl->conf.init.genparam.single_dual_band = CONF_DUAL_BAND;
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300364}
365
366
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300367static int wl1271_plt_init(struct wl1271 *wl)
368{
369 int ret;
370
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200371 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200372 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200373 return ret;
374
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200375 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200376 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200377 return ret;
378
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300379 ret = wl1271_acx_init_mem_config(wl);
380 if (ret < 0)
381 return ret;
382
383 ret = wl1271_cmd_data_path(wl, wl->channel, 1);
384 if (ret < 0)
385 return ret;
386
387 return 0;
388}
389
390static void wl1271_disable_interrupts(struct wl1271 *wl)
391{
392 disable_irq(wl->irq);
393}
394
395static void wl1271_power_off(struct wl1271 *wl)
396{
397 wl->set_power(false);
398}
399
400static void wl1271_power_on(struct wl1271 *wl)
401{
402 wl->set_power(true);
403}
404
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300405static void wl1271_fw_status(struct wl1271 *wl,
406 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300407{
408 u32 total = 0;
409 int i;
410
Juuso Oikarinen74621412009-10-12 15:08:54 +0300411 wl1271_spi_read(wl, FW_STATUS_ADDR, status,
412 sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300413
414 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
415 "drv_rx_counter = %d, tx_results_counter = %d)",
416 status->intr,
417 status->fw_rx_counter,
418 status->drv_rx_counter,
419 status->tx_results_counter);
420
421 /* update number of available TX blocks */
422 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300423 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
424 wl->tx_blocks_freed[i];
425
426 wl->tx_blocks_freed[i] =
427 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300428 wl->tx_blocks_available += cnt;
429 total += cnt;
430 }
431
432 /* if more blocks are available now, schedule some tx work */
433 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300434 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300435
436 /* update the host-chipset time offset */
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300437 wl->time_offset = jiffies_to_usecs(jiffies) -
438 le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300439}
440
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300441static void wl1271_irq_work(struct work_struct *work)
442{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300443 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300444 u32 intr;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300445 struct wl1271 *wl =
446 container_of(work, struct wl1271, irq_work);
447
448 mutex_lock(&wl->mutex);
449
450 wl1271_debug(DEBUG_IRQ, "IRQ work");
451
452 if (wl->state == WL1271_STATE_OFF)
453 goto out;
454
455 ret = wl1271_ps_elp_wakeup(wl, true);
456 if (ret < 0)
457 goto out;
458
Juuso Oikarinen74621412009-10-12 15:08:54 +0300459 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300460
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300461 wl1271_fw_status(wl, wl->fw_status);
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300462 intr = le32_to_cpu(wl->fw_status->intr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300463 if (!intr) {
464 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
465 goto out_sleep;
466 }
467
468 intr &= WL1271_INTR_MASK;
469
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300470 if (intr & WL1271_ACX_INTR_EVENT_A) {
471 bool do_ack = (intr & WL1271_ACX_INTR_EVENT_B) ? false : true;
472 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
473 wl1271_event_handle(wl, 0, do_ack);
474 }
475
476 if (intr & WL1271_ACX_INTR_EVENT_B) {
477 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
478 wl1271_event_handle(wl, 1, true);
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300479 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300480
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300481 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
482 wl1271_debug(DEBUG_IRQ,
483 "WL1271_ACX_INTR_INIT_COMPLETE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300484
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300485 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
486 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300487
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300488 if (intr & WL1271_ACX_INTR_DATA) {
489 u8 tx_res_cnt = wl->fw_status->tx_results_counter -
490 wl->tx_results_count;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300491
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300492 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300493
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300494 /* check for tx results */
495 if (tx_res_cnt)
496 wl1271_tx_complete(wl, tx_res_cnt);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300497
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300498 wl1271_rx(wl, wl->fw_status);
499 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300500
501out_sleep:
Juuso Oikarinen74621412009-10-12 15:08:54 +0300502 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
Luciano Coelho73d0a132009-08-11 11:58:27 +0300503 WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300504 wl1271_ps_elp_sleep(wl);
505
506out:
507 mutex_unlock(&wl->mutex);
508}
509
510static irqreturn_t wl1271_irq(int irq, void *cookie)
511{
512 struct wl1271 *wl;
513 unsigned long flags;
514
515 wl1271_debug(DEBUG_IRQ, "IRQ");
516
517 wl = cookie;
518
519 /* complete the ELP completion */
520 spin_lock_irqsave(&wl->wl_lock, flags);
521 if (wl->elp_compl) {
522 complete(wl->elp_compl);
523 wl->elp_compl = NULL;
524 }
525
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300526 ieee80211_queue_work(wl->hw, &wl->irq_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300527 spin_unlock_irqrestore(&wl->wl_lock, flags);
528
529 return IRQ_HANDLED;
530}
531
532static int wl1271_fetch_firmware(struct wl1271 *wl)
533{
534 const struct firmware *fw;
535 int ret;
536
537 ret = request_firmware(&fw, WL1271_FW_NAME, &wl->spi->dev);
538
539 if (ret < 0) {
540 wl1271_error("could not get firmware: %d", ret);
541 return ret;
542 }
543
544 if (fw->size % 4) {
545 wl1271_error("firmware size is not multiple of 32 bits: %zu",
546 fw->size);
547 ret = -EILSEQ;
548 goto out;
549 }
550
551 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300552 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300553
554 if (!wl->fw) {
555 wl1271_error("could not allocate memory for the firmware");
556 ret = -ENOMEM;
557 goto out;
558 }
559
560 memcpy(wl->fw, fw->data, wl->fw_len);
561
562 ret = 0;
563
564out:
565 release_firmware(fw);
566
567 return ret;
568}
569
570static int wl1271_fetch_nvs(struct wl1271 *wl)
571{
572 const struct firmware *fw;
573 int ret;
574
575 ret = request_firmware(&fw, WL1271_NVS_NAME, &wl->spi->dev);
576
577 if (ret < 0) {
578 wl1271_error("could not get nvs file: %d", ret);
579 return ret;
580 }
581
582 if (fw->size % 4) {
583 wl1271_error("nvs size is not multiple of 32 bits: %zu",
584 fw->size);
585 ret = -EILSEQ;
586 goto out;
587 }
588
589 wl->nvs_len = fw->size;
590 wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL);
591
592 if (!wl->nvs) {
593 wl1271_error("could not allocate memory for the nvs file");
594 ret = -ENOMEM;
595 goto out;
596 }
597
598 memcpy(wl->nvs, fw->data, wl->nvs_len);
599
600 ret = 0;
601
602out:
603 release_firmware(fw);
604
605 return ret;
606}
607
608static void wl1271_fw_wakeup(struct wl1271 *wl)
609{
610 u32 elp_reg;
611
612 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300613 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300614}
615
616static int wl1271_setup(struct wl1271 *wl)
617{
618 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
619 if (!wl->fw_status)
620 return -ENOMEM;
621
622 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
623 if (!wl->tx_res_if) {
624 kfree(wl->fw_status);
625 return -ENOMEM;
626 }
627
628 INIT_WORK(&wl->irq_work, wl1271_irq_work);
629 INIT_WORK(&wl->tx_work, wl1271_tx_work);
630 return 0;
631}
632
633static int wl1271_chip_wakeup(struct wl1271 *wl)
634{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300635 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300636 int ret = 0;
637
638 wl1271_power_on(wl);
639 msleep(WL1271_POWER_ON_SLEEP);
640 wl1271_spi_reset(wl);
641 wl1271_spi_init(wl);
642
643 /* We don't need a real memory partition here, because we only want
644 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300645 memset(&partition, 0, sizeof(partition));
646 partition.reg.start = REGISTERS_BASE;
647 partition.reg.size = REGISTERS_DOWN_SIZE;
648 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300649
650 /* ELP module wake up */
651 wl1271_fw_wakeup(wl);
652
653 /* whal_FwCtrl_BootSm() */
654
655 /* 0. read chip id from CHIP_ID */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300656 wl->chip.id = wl1271_spi_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300657
658 /* 1. check if chip id is valid */
659
660 switch (wl->chip.id) {
661 case CHIP_ID_1271_PG10:
662 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
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 case CHIP_ID_1271_PG20:
670 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
671 wl->chip.id);
672
673 ret = wl1271_setup(wl);
674 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300675 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300676 break;
677 default:
678 wl1271_error("unsupported chip id: 0x%x", wl->chip.id);
679 ret = -ENODEV;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300680 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300681 }
682
683 if (wl->fw == NULL) {
684 ret = wl1271_fetch_firmware(wl);
685 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300686 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300687 }
688
689 /* No NVS from netlink, try to get it from the filesystem */
690 if (wl->nvs == NULL) {
691 ret = wl1271_fetch_nvs(wl);
692 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300693 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300694 }
695
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300696 goto out;
697
698out_power_off:
699 wl1271_power_off(wl);
700
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300701out:
702 return ret;
703}
704
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300705int wl1271_plt_start(struct wl1271 *wl)
706{
707 int ret;
708
709 mutex_lock(&wl->mutex);
710
711 wl1271_notice("power up");
712
713 if (wl->state != WL1271_STATE_OFF) {
714 wl1271_error("cannot go into PLT state because not "
715 "in off state: %d", wl->state);
716 ret = -EBUSY;
717 goto out;
718 }
719
720 wl->state = WL1271_STATE_PLT;
721
722 ret = wl1271_chip_wakeup(wl);
723 if (ret < 0)
724 goto out;
725
726 ret = wl1271_boot(wl);
727 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300728 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300729
730 wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver);
731
732 ret = wl1271_plt_init(wl);
733 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300734 goto out_irq_disable;
735
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300736 /* Make sure power saving is disabled */
737 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
738 if (ret < 0)
739 goto out_irq_disable;
740
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300741 goto out;
742
743out_irq_disable:
744 wl1271_disable_interrupts(wl);
745
746out_power_off:
747 wl1271_power_off(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300748
749out:
750 mutex_unlock(&wl->mutex);
751
752 return ret;
753}
754
755int wl1271_plt_stop(struct wl1271 *wl)
756{
757 int ret = 0;
758
759 mutex_lock(&wl->mutex);
760
761 wl1271_notice("power down");
762
763 if (wl->state != WL1271_STATE_PLT) {
764 wl1271_error("cannot power down because not in PLT "
765 "state: %d", wl->state);
766 ret = -EBUSY;
767 goto out;
768 }
769
770 wl1271_disable_interrupts(wl);
771 wl1271_power_off(wl);
772
773 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300774 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300775
776out:
777 mutex_unlock(&wl->mutex);
778
779 return ret;
780}
781
782
783static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
784{
785 struct wl1271 *wl = hw->priv;
786
787 skb_queue_tail(&wl->tx_queue, skb);
788
789 /*
790 * The chip specific setup must run before the first TX packet -
791 * before that, the tx_work will not be initialized!
792 */
793
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300794 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300795
796 /*
797 * The workqueue is slow to process the tx_queue and we need stop
798 * the queue here, otherwise the queue will get too long.
799 */
800 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) {
801 ieee80211_stop_queues(wl->hw);
802
803 /*
804 * FIXME: this is racy, the variable is not properly
805 * protected. Maybe fix this by removing the stupid
806 * variable altogether and checking the real queue state?
807 */
808 wl->tx_queue_stopped = true;
809 }
810
811 return NETDEV_TX_OK;
812}
813
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300814static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
815 void *arg)
816{
817 struct net_device *dev;
818 struct wireless_dev *wdev;
819 struct wiphy *wiphy;
820 struct ieee80211_hw *hw;
821 struct wl1271 *wl;
822 struct wl1271 *wl_temp;
823 struct in_device *idev;
824 struct in_ifaddr *ifa = arg;
825 int ret = 0;
826
827 /* FIXME: this ugly function should probably be implemented in the
828 * mac80211, and here should only be a simple callback handling actual
829 * setting of the filters. Now we need to dig up references to
830 * various structures to gain access to what we need.
831 * Also, because of this, there is no "initial" setting of the filter
832 * in "op_start", because we don't want to dig up struct net_device
833 * there - the filter will be set upon first change of the interface
834 * IP address. */
835
836 dev = ifa->ifa_dev->dev;
837
838 wdev = dev->ieee80211_ptr;
839 if (wdev == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200840 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300841
842 wiphy = wdev->wiphy;
843 if (wiphy == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200844 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300845
846 hw = wiphy_priv(wiphy);
847 if (hw == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200848 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300849
850 /* Check that the interface is one supported by this driver. */
851 wl_temp = hw->priv;
852 list_for_each_entry(wl, &wl_list, list) {
853 if (wl == wl_temp)
854 break;
855 }
856 if (wl == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200857 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300858
859 /* Get the interface IP address for the device. "ifa" will become
860 NULL if:
861 - there is no IPV4 protocol address configured
862 - there are multiple (virtual) IPV4 addresses configured
863 When "ifa" is NULL, filtering will be disabled.
864 */
865 ifa = NULL;
866 idev = dev->ip_ptr;
867 if (idev)
868 ifa = idev->ifa_list;
869
870 if (ifa && ifa->ifa_next)
871 ifa = NULL;
872
873 mutex_lock(&wl->mutex);
874
875 if (wl->state == WL1271_STATE_OFF)
876 goto out;
877
878 ret = wl1271_ps_elp_wakeup(wl, false);
879 if (ret < 0)
880 goto out;
881 if (ifa)
882 ret = wl1271_acx_arp_ip_filter(wl, true,
883 (u8 *)&ifa->ifa_address,
884 ACX_IPV4_VERSION);
885 else
886 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
887 ACX_IPV4_VERSION);
888 wl1271_ps_elp_sleep(wl);
889
890out:
891 mutex_unlock(&wl->mutex);
892
Luciano Coelho17d72652009-11-23 23:22:15 +0200893 return NOTIFY_OK;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300894}
895
896static struct notifier_block wl1271_dev_notifier = {
897 .notifier_call = wl1271_dev_notify,
898};
899
900
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300901static int wl1271_op_start(struct ieee80211_hw *hw)
902{
903 struct wl1271 *wl = hw->priv;
904 int ret = 0;
905
906 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
907
908 mutex_lock(&wl->mutex);
909
910 if (wl->state != WL1271_STATE_OFF) {
911 wl1271_error("cannot start because not in off state: %d",
912 wl->state);
913 ret = -EBUSY;
914 goto out;
915 }
916
917 ret = wl1271_chip_wakeup(wl);
918 if (ret < 0)
919 goto out;
920
921 ret = wl1271_boot(wl);
922 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300923 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300924
925 ret = wl1271_hw_init(wl);
926 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300927 goto out_irq_disable;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300928
929 wl->state = WL1271_STATE_ON;
930
931 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
932
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300933 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300934
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300935out_irq_disable:
936 wl1271_disable_interrupts(wl);
937
938out_power_off:
939 wl1271_power_off(wl);
940
941out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300942 mutex_unlock(&wl->mutex);
943
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300944 if (!ret) {
945 list_add(&wl->list, &wl_list);
946 register_inetaddr_notifier(&wl1271_dev_notifier);
947 }
948
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300949 return ret;
950}
951
952static void wl1271_op_stop(struct ieee80211_hw *hw)
953{
954 struct wl1271 *wl = hw->priv;
955 int i;
956
957 wl1271_info("down");
958
959 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
960
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300961 unregister_inetaddr_notifier(&wl1271_dev_notifier);
962 list_del(&wl->list);
963
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300964 mutex_lock(&wl->mutex);
965
966 WARN_ON(wl->state != WL1271_STATE_ON);
967
968 if (wl->scanning) {
969 mutex_unlock(&wl->mutex);
970 ieee80211_scan_completed(wl->hw, true);
971 mutex_lock(&wl->mutex);
972 wl->scanning = false;
973 }
974
975 wl->state = WL1271_STATE_OFF;
976
977 wl1271_disable_interrupts(wl);
978
979 mutex_unlock(&wl->mutex);
980
981 cancel_work_sync(&wl->irq_work);
982 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300983
984 mutex_lock(&wl->mutex);
985
986 /* let's notify MAC80211 about the remaining pending TX frames */
987 wl1271_tx_flush(wl);
988 wl1271_power_off(wl);
989
990 memset(wl->bssid, 0, ETH_ALEN);
991 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
992 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300993 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +0300994 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300995
996 wl->rx_counter = 0;
997 wl->elp = false;
998 wl->psm = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200999 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001000 wl->tx_queue_stopped = false;
1001 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1002 wl->tx_blocks_available = 0;
1003 wl->tx_results_count = 0;
1004 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001005 wl->tx_security_last_seq = 0;
1006 wl->tx_security_seq_16 = 0;
1007 wl->tx_security_seq_32 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001008 wl->time_offset = 0;
1009 wl->session_counter = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001010 wl->joined = false;
1011
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001012 for (i = 0; i < NUM_TX_QUEUES; i++)
1013 wl->tx_blocks_freed[i] = 0;
1014
1015 wl1271_debugfs_reset(wl);
1016 mutex_unlock(&wl->mutex);
1017}
1018
1019static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1020 struct ieee80211_if_init_conf *conf)
1021{
1022 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001023 int ret = 0;
1024
John W. Linvillee5539bc2009-08-18 10:50:34 -04001025 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1026 conf->type, conf->mac_addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001027
1028 mutex_lock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001029 if (wl->vif) {
1030 ret = -EBUSY;
1031 goto out;
1032 }
1033
1034 wl->vif = conf->vif;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001035
1036 switch (conf->type) {
1037 case NL80211_IFTYPE_STATION:
1038 wl->bss_type = BSS_TYPE_STA_BSS;
1039 break;
1040 case NL80211_IFTYPE_ADHOC:
1041 wl->bss_type = BSS_TYPE_IBSS;
1042 break;
1043 default:
1044 ret = -EOPNOTSUPP;
1045 goto out;
1046 }
1047
1048 /* FIXME: what if conf->mac_addr changes? */
1049
1050out:
1051 mutex_unlock(&wl->mutex);
1052 return ret;
1053}
1054
1055static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1056 struct ieee80211_if_init_conf *conf)
1057{
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001058 struct wl1271 *wl = hw->priv;
1059
1060 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001061 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001062 wl->vif = NULL;
1063 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001064}
1065
1066#if 0
1067static int wl1271_op_config_interface(struct ieee80211_hw *hw,
1068 struct ieee80211_vif *vif,
1069 struct ieee80211_if_conf *conf)
1070{
1071 struct wl1271 *wl = hw->priv;
1072 struct sk_buff *beacon;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001073 int ret;
1074
David S. Miller32646902009-09-17 10:18:30 -07001075 wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM",
1076 conf->bssid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001077 wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid,
1078 conf->ssid_len);
1079
1080 mutex_lock(&wl->mutex);
1081
1082 ret = wl1271_ps_elp_wakeup(wl, false);
1083 if (ret < 0)
1084 goto out;
1085
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001086 if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
1087 wl1271_debug(DEBUG_MAC80211, "bssid changed");
1088
1089 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
1090
1091 ret = wl1271_cmd_join(wl);
1092 if (ret < 0)
1093 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001094
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001095 ret = wl1271_cmd_build_null_data(wl);
1096 if (ret < 0)
1097 goto out_sleep;
1098 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001099
1100 wl->ssid_len = conf->ssid_len;
1101 if (wl->ssid_len)
1102 memcpy(wl->ssid, conf->ssid, wl->ssid_len);
1103
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001104 if (conf->changed & IEEE80211_IFCC_BEACON) {
1105 beacon = ieee80211_beacon_get(hw, vif);
1106 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1107 beacon->data, beacon->len);
1108
1109 if (ret < 0) {
1110 dev_kfree_skb(beacon);
1111 goto out_sleep;
1112 }
1113
1114 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE,
1115 beacon->data, beacon->len);
1116
1117 dev_kfree_skb(beacon);
1118
1119 if (ret < 0)
1120 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001121 }
1122
1123out_sleep:
1124 wl1271_ps_elp_sleep(wl);
1125
1126out:
1127 mutex_unlock(&wl->mutex);
1128
1129 return ret;
1130}
1131#endif
1132
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001133static int wl1271_join_channel(struct wl1271 *wl, int channel)
1134{
1135 int ret;
1136 /* we need to use a dummy BSSID for now */
1137 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1138 0xad, 0xbe, 0xef };
1139
1140 /* disable mac filter, so we hear everything */
1141 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1142
1143 wl->channel = channel;
1144 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1145
1146 ret = wl1271_cmd_join(wl);
1147 if (ret < 0)
1148 goto out;
1149
1150 wl->joined = true;
1151
1152out:
1153 return ret;
1154}
1155
1156static int wl1271_unjoin_channel(struct wl1271 *wl)
1157{
1158 int ret;
1159
1160 /* to stop listening to a channel, we disconnect */
1161 ret = wl1271_cmd_disconnect(wl);
1162 if (ret < 0)
1163 goto out;
1164
1165 wl->joined = false;
1166 wl->channel = 0;
1167 memset(wl->bssid, 0, ETH_ALEN);
1168 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1169
1170out:
1171 return ret;
1172}
1173
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001174static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1175{
1176 struct wl1271 *wl = hw->priv;
1177 struct ieee80211_conf *conf = &hw->conf;
1178 int channel, ret = 0;
1179
1180 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1181
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001182 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001183 channel,
1184 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001185 conf->power_level,
1186 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001187
1188 mutex_lock(&wl->mutex);
1189
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001190 wl->band = conf->channel->band;
1191
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001192 ret = wl1271_ps_elp_wakeup(wl, false);
1193 if (ret < 0)
1194 goto out;
1195
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001196 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
1197 if (conf->flags & IEEE80211_CONF_IDLE && wl->joined)
1198 wl1271_unjoin_channel(wl);
1199 else
1200 wl1271_join_channel(wl, channel);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001201 }
1202
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001203 /* if the channel changes while joined, join again */
1204 if (channel != wl->channel && wl->joined)
1205 wl1271_join_channel(wl, channel);
1206
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001207 if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) {
1208 wl1271_info("psm enabled");
1209
1210 wl->psm_requested = true;
1211
1212 /*
1213 * We enter PSM only if we're already associated.
1214 * If we're not, we'll enter it when joining an SSID,
1215 * through the bss_info_changed() hook.
1216 */
1217 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
1218 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
1219 wl->psm_requested) {
1220 wl1271_info("psm disabled");
1221
1222 wl->psm_requested = false;
1223
1224 if (wl->psm)
1225 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE);
1226 }
1227
1228 if (conf->power_level != wl->power_level) {
1229 ret = wl1271_acx_tx_power(wl, conf->power_level);
1230 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001231 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001232
1233 wl->power_level = conf->power_level;
1234 }
1235
1236out_sleep:
1237 wl1271_ps_elp_sleep(wl);
1238
1239out:
1240 mutex_unlock(&wl->mutex);
1241
1242 return ret;
1243}
1244
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001245struct wl1271_filter_params {
1246 bool enabled;
1247 int mc_list_length;
1248 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1249};
1250
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001251static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1252 struct dev_addr_list *mc_list)
1253{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001254 struct wl1271_filter_params *fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001255 int i;
1256
Juuso Oikarinen74441132009-10-13 12:47:53 +03001257 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001258 if (!fp) {
1259 wl1271_error("Out of memory setting filters.");
1260 return 0;
1261 }
1262
1263 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001264 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001265 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1266 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001267 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001268 }
1269
1270 fp->mc_list_length = 0;
1271 for (i = 0; i < mc_count; i++) {
1272 if (mc_list->da_addrlen == ETH_ALEN) {
1273 memcpy(fp->mc_list[fp->mc_list_length],
1274 mc_list->da_addr, ETH_ALEN);
1275 fp->mc_list_length++;
1276 } else
1277 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001278 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001279 }
1280
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001281 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001282}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001283
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001284#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1285 FIF_ALLMULTI | \
1286 FIF_FCSFAIL | \
1287 FIF_BCN_PRBRESP_PROMISC | \
1288 FIF_CONTROL | \
1289 FIF_OTHER_BSS)
1290
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001291static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1292 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001293 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001294{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001295 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001296 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001297 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001298
1299 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1300
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001301 mutex_lock(&wl->mutex);
1302
1303 if (wl->state == WL1271_STATE_OFF)
1304 goto out;
1305
1306 ret = wl1271_ps_elp_wakeup(wl, false);
1307 if (ret < 0)
1308 goto out;
1309
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001310 *total &= WL1271_SUPPORTED_FILTERS;
1311 changed &= WL1271_SUPPORTED_FILTERS;
1312
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001313 if (*total & FIF_ALLMULTI)
1314 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1315 else if (fp)
1316 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1317 fp->mc_list,
1318 fp->mc_list_length);
1319 if (ret < 0)
1320 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001321
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001322 kfree(fp);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001323
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001324 /* FIXME: We still need to set our filters properly */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001325
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001326 /* determine, whether supported filter values have changed */
1327 if (changed == 0)
1328 goto out_sleep;
1329
1330 /* apply configured filters */
1331 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1332 if (ret < 0)
1333 goto out_sleep;
1334
1335out_sleep:
1336 wl1271_ps_elp_sleep(wl);
1337
1338out:
1339 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001340}
1341
1342static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1343 struct ieee80211_vif *vif,
1344 struct ieee80211_sta *sta,
1345 struct ieee80211_key_conf *key_conf)
1346{
1347 struct wl1271 *wl = hw->priv;
1348 const u8 *addr;
1349 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001350 u32 tx_seq_32 = 0;
1351 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001352 u8 key_type;
1353
1354 static const u8 bcast_addr[ETH_ALEN] =
1355 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1356
1357 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1358
1359 addr = sta ? sta->addr : bcast_addr;
1360
1361 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1362 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1363 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1364 key_conf->alg, key_conf->keyidx,
1365 key_conf->keylen, key_conf->flags);
1366 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1367
1368 if (is_zero_ether_addr(addr)) {
1369 /* We dont support TX only encryption */
1370 ret = -EOPNOTSUPP;
1371 goto out;
1372 }
1373
1374 mutex_lock(&wl->mutex);
1375
1376 ret = wl1271_ps_elp_wakeup(wl, false);
1377 if (ret < 0)
1378 goto out_unlock;
1379
1380 switch (key_conf->alg) {
1381 case ALG_WEP:
1382 key_type = KEY_WEP;
1383
1384 key_conf->hw_key_idx = key_conf->keyidx;
1385 break;
1386 case ALG_TKIP:
1387 key_type = KEY_TKIP;
1388
1389 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001390 tx_seq_32 = wl->tx_security_seq_32;
1391 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001392 break;
1393 case ALG_CCMP:
1394 key_type = KEY_AES;
1395
1396 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001397 tx_seq_32 = wl->tx_security_seq_32;
1398 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001399 break;
1400 default:
1401 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1402
1403 ret = -EOPNOTSUPP;
1404 goto out_sleep;
1405 }
1406
1407 switch (cmd) {
1408 case SET_KEY:
1409 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1410 key_conf->keyidx, key_type,
1411 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001412 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001413 if (ret < 0) {
1414 wl1271_error("Could not add or replace key");
1415 goto out_sleep;
1416 }
1417 break;
1418
1419 case DISABLE_KEY:
1420 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1421 key_conf->keyidx, key_type,
1422 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001423 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001424 if (ret < 0) {
1425 wl1271_error("Could not remove key");
1426 goto out_sleep;
1427 }
1428 break;
1429
1430 default:
1431 wl1271_error("Unsupported key cmd 0x%x", cmd);
1432 ret = -EOPNOTSUPP;
1433 goto out_sleep;
1434
1435 break;
1436 }
1437
1438out_sleep:
1439 wl1271_ps_elp_sleep(wl);
1440
1441out_unlock:
1442 mutex_unlock(&wl->mutex);
1443
1444out:
1445 return ret;
1446}
1447
1448static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1449 struct cfg80211_scan_request *req)
1450{
1451 struct wl1271 *wl = hw->priv;
1452 int ret;
1453 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001454 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001455
1456 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1457
1458 if (req->n_ssids) {
1459 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001460 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001461 }
1462
1463 mutex_lock(&wl->mutex);
1464
1465 ret = wl1271_ps_elp_wakeup(wl, false);
1466 if (ret < 0)
1467 goto out;
1468
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001469 if (wl1271_11a_enabled())
1470 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1471 WL1271_SCAN_BAND_DUAL, 3);
1472 else
1473 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1474 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001475
1476 wl1271_ps_elp_sleep(wl);
1477
1478out:
1479 mutex_unlock(&wl->mutex);
1480
1481 return ret;
1482}
1483
1484static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1485{
1486 struct wl1271 *wl = hw->priv;
1487 int ret;
1488
1489 mutex_lock(&wl->mutex);
1490
1491 ret = wl1271_ps_elp_wakeup(wl, false);
1492 if (ret < 0)
1493 goto out;
1494
1495 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1496 if (ret < 0)
1497 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1498
1499 wl1271_ps_elp_sleep(wl);
1500
1501out:
1502 mutex_unlock(&wl->mutex);
1503
1504 return ret;
1505}
1506
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001507static u32 wl1271_enabled_rates_get(struct wl1271 *wl, u64 basic_rate_set)
1508{
1509 struct ieee80211_supported_band *band;
1510 u32 enabled_rates = 0;
1511 int bit;
1512
1513 band = wl->hw->wiphy->bands[wl->band];
1514 for (bit = 0; bit < band->n_bitrates; bit++) {
1515 if (basic_rate_set & 0x1)
1516 enabled_rates |= band->bitrates[bit].hw_value;
1517 basic_rate_set >>= 1;
1518 }
1519
1520 return enabled_rates;
1521}
1522
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001523static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1524 struct ieee80211_vif *vif,
1525 struct ieee80211_bss_conf *bss_conf,
1526 u32 changed)
1527{
1528 enum wl1271_cmd_ps_mode mode;
1529 struct wl1271 *wl = hw->priv;
1530 int ret;
1531
1532 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1533
1534 mutex_lock(&wl->mutex);
1535
1536 ret = wl1271_ps_elp_wakeup(wl, false);
1537 if (ret < 0)
1538 goto out;
1539
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001540 if ((changed & BSS_CHANGED_BSSID) &&
1541 /*
1542 * Now we know the correct bssid, so we send a new join command
1543 * and enable the BSSID filter
1544 */
1545 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
1546 wl->rx_config |= CFG_BSSID_FILTER_EN;
1547 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
1548 wl1271_cmd_join(wl);
1549 wl->joined = true;
1550 }
1551
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001552 if (changed & BSS_CHANGED_ASSOC) {
1553 if (bss_conf->assoc) {
1554 wl->aid = bss_conf->aid;
1555
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001556 /*
1557 * with wl1271, we don't need to update the
1558 * beacon_int and dtim_period, because the firmware
1559 * updates it by itself when the first beacon is
1560 * received after a join.
1561 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001562 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1563 if (ret < 0)
1564 goto out_sleep;
1565
1566 ret = wl1271_acx_aid(wl, wl->aid);
1567 if (ret < 0)
1568 goto out_sleep;
1569
1570 /* If we want to go in PSM but we're not there yet */
1571 if (wl->psm_requested && !wl->psm) {
1572 mode = STATION_POWER_SAVE_MODE;
1573 ret = wl1271_ps_set_mode(wl, mode);
1574 if (ret < 0)
1575 goto out_sleep;
1576 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001577 } else {
1578 /* use defaults when not associated */
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001579 wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
1580 wl->aid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001581 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001582
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001583 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001584
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001585 if (changed & BSS_CHANGED_ERP_SLOT) {
1586 if (bss_conf->use_short_slot)
1587 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1588 else
1589 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1590 if (ret < 0) {
1591 wl1271_warning("Set slot time failed %d", ret);
1592 goto out_sleep;
1593 }
1594 }
1595
1596 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1597 if (bss_conf->use_short_preamble)
1598 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1599 else
1600 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1601 }
1602
1603 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1604 if (bss_conf->use_cts_prot)
1605 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1606 else
1607 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1608 if (ret < 0) {
1609 wl1271_warning("Set ctsprotect failed %d", ret);
1610 goto out_sleep;
1611 }
1612 }
1613
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001614 if (changed & BSS_CHANGED_BASIC_RATES) {
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001615 wl->basic_rate_set = wl1271_enabled_rates_get(
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001616 wl, bss_conf->basic_rates);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001617
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001618 ret = wl1271_acx_rate_policies(wl, wl->basic_rate_set);
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001619 if (ret < 0) {
1620 wl1271_warning("Set rate policies failed %d", ret);
1621 goto out_sleep;
1622 }
1623 }
1624
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001625out_sleep:
1626 wl1271_ps_elp_sleep(wl);
1627
1628out:
1629 mutex_unlock(&wl->mutex);
1630}
1631
1632
1633/* can't be const, mac80211 writes to this */
1634static struct ieee80211_rate wl1271_rates[] = {
1635 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001636 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1637 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001638 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001639 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1640 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001641 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1642 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001643 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1644 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001645 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1646 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001647 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1648 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001649 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1650 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001651 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1652 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001653 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001654 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1655 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001656 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001657 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1658 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001659 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001660 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1661 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001662 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001663 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1664 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001665 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001666 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1667 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001668 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001669 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1670 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001671 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001672 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1673 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001674};
1675
1676/* can't be const, mac80211 writes to this */
1677static struct ieee80211_channel wl1271_channels[] = {
1678 { .hw_value = 1, .center_freq = 2412},
1679 { .hw_value = 2, .center_freq = 2417},
1680 { .hw_value = 3, .center_freq = 2422},
1681 { .hw_value = 4, .center_freq = 2427},
1682 { .hw_value = 5, .center_freq = 2432},
1683 { .hw_value = 6, .center_freq = 2437},
1684 { .hw_value = 7, .center_freq = 2442},
1685 { .hw_value = 8, .center_freq = 2447},
1686 { .hw_value = 9, .center_freq = 2452},
1687 { .hw_value = 10, .center_freq = 2457},
1688 { .hw_value = 11, .center_freq = 2462},
1689 { .hw_value = 12, .center_freq = 2467},
1690 { .hw_value = 13, .center_freq = 2472},
1691};
1692
1693/* can't be const, mac80211 writes to this */
1694static struct ieee80211_supported_band wl1271_band_2ghz = {
1695 .channels = wl1271_channels,
1696 .n_channels = ARRAY_SIZE(wl1271_channels),
1697 .bitrates = wl1271_rates,
1698 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1699};
1700
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001701/* 5 GHz data rates for WL1273 */
1702static struct ieee80211_rate wl1271_rates_5ghz[] = {
1703 { .bitrate = 60,
1704 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1705 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
1706 { .bitrate = 90,
1707 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1708 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
1709 { .bitrate = 120,
1710 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1711 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
1712 { .bitrate = 180,
1713 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1714 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
1715 { .bitrate = 240,
1716 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1717 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
1718 { .bitrate = 360,
1719 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1720 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
1721 { .bitrate = 480,
1722 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1723 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
1724 { .bitrate = 540,
1725 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1726 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
1727};
1728
1729/* 5 GHz band channels for WL1273 */
1730static struct ieee80211_channel wl1271_channels_5ghz[] = {
1731 { .hw_value = 183, .center_freq = 4915},
1732 { .hw_value = 184, .center_freq = 4920},
1733 { .hw_value = 185, .center_freq = 4925},
1734 { .hw_value = 187, .center_freq = 4935},
1735 { .hw_value = 188, .center_freq = 4940},
1736 { .hw_value = 189, .center_freq = 4945},
1737 { .hw_value = 192, .center_freq = 4960},
1738 { .hw_value = 196, .center_freq = 4980},
1739 { .hw_value = 7, .center_freq = 5035},
1740 { .hw_value = 8, .center_freq = 5040},
1741 { .hw_value = 9, .center_freq = 5045},
1742 { .hw_value = 11, .center_freq = 5055},
1743 { .hw_value = 12, .center_freq = 5060},
1744 { .hw_value = 16, .center_freq = 5080},
1745 { .hw_value = 34, .center_freq = 5170},
1746 { .hw_value = 36, .center_freq = 5180},
1747 { .hw_value = 38, .center_freq = 5190},
1748 { .hw_value = 40, .center_freq = 5200},
1749 { .hw_value = 42, .center_freq = 5210},
1750 { .hw_value = 44, .center_freq = 5220},
1751 { .hw_value = 46, .center_freq = 5230},
1752 { .hw_value = 48, .center_freq = 5240},
1753 { .hw_value = 52, .center_freq = 5260},
1754 { .hw_value = 56, .center_freq = 5280},
1755 { .hw_value = 60, .center_freq = 5300},
1756 { .hw_value = 64, .center_freq = 5320},
1757 { .hw_value = 100, .center_freq = 5500},
1758 { .hw_value = 104, .center_freq = 5520},
1759 { .hw_value = 108, .center_freq = 5540},
1760 { .hw_value = 112, .center_freq = 5560},
1761 { .hw_value = 116, .center_freq = 5580},
1762 { .hw_value = 120, .center_freq = 5600},
1763 { .hw_value = 124, .center_freq = 5620},
1764 { .hw_value = 128, .center_freq = 5640},
1765 { .hw_value = 132, .center_freq = 5660},
1766 { .hw_value = 136, .center_freq = 5680},
1767 { .hw_value = 140, .center_freq = 5700},
1768 { .hw_value = 149, .center_freq = 5745},
1769 { .hw_value = 153, .center_freq = 5765},
1770 { .hw_value = 157, .center_freq = 5785},
1771 { .hw_value = 161, .center_freq = 5805},
1772 { .hw_value = 165, .center_freq = 5825},
1773};
1774
1775
1776static struct ieee80211_supported_band wl1271_band_5ghz = {
1777 .channels = wl1271_channels_5ghz,
1778 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
1779 .bitrates = wl1271_rates_5ghz,
1780 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
1781};
1782
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001783static const struct ieee80211_ops wl1271_ops = {
1784 .start = wl1271_op_start,
1785 .stop = wl1271_op_stop,
1786 .add_interface = wl1271_op_add_interface,
1787 .remove_interface = wl1271_op_remove_interface,
1788 .config = wl1271_op_config,
1789/* .config_interface = wl1271_op_config_interface, */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001790 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001791 .configure_filter = wl1271_op_configure_filter,
1792 .tx = wl1271_op_tx,
1793 .set_key = wl1271_op_set_key,
1794 .hw_scan = wl1271_op_hw_scan,
1795 .bss_info_changed = wl1271_op_bss_info_changed,
1796 .set_rts_threshold = wl1271_op_set_rts_threshold,
1797};
1798
1799static int wl1271_register_hw(struct wl1271 *wl)
1800{
1801 int ret;
1802
1803 if (wl->mac80211_registered)
1804 return 0;
1805
1806 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
1807
1808 ret = ieee80211_register_hw(wl->hw);
1809 if (ret < 0) {
1810 wl1271_error("unable to register mac80211 hw: %d", ret);
1811 return ret;
1812 }
1813
1814 wl->mac80211_registered = true;
1815
1816 wl1271_notice("loaded");
1817
1818 return 0;
1819}
1820
1821static int wl1271_init_ieee80211(struct wl1271 *wl)
1822{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03001823 /* The tx descriptor buffer and the TKIP space. */
1824 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
1825 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001826
1827 /* unit us */
1828 /* FIXME: find a proper value */
1829 wl->hw->channel_change_time = 10000;
1830
1831 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03001832 IEEE80211_HW_NOISE_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02001833 IEEE80211_HW_BEACON_FILTER |
1834 IEEE80211_HW_SUPPORTS_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001835
1836 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
1837 wl->hw->wiphy->max_scan_ssids = 1;
1838 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
1839
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001840 if (wl1271_11a_enabled())
1841 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
1842
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001843 SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
1844
1845 return 0;
1846}
1847
1848static void wl1271_device_release(struct device *dev)
1849{
1850
1851}
1852
1853static struct platform_device wl1271_device = {
1854 .name = "wl1271",
1855 .id = -1,
1856
1857 /* device model insists to have a release function */
1858 .dev = {
1859 .release = wl1271_device_release,
1860 },
1861};
1862
1863#define WL1271_DEFAULT_CHANNEL 0
1864static int __devinit wl1271_probe(struct spi_device *spi)
1865{
1866 struct wl12xx_platform_data *pdata;
1867 struct ieee80211_hw *hw;
1868 struct wl1271 *wl;
1869 int ret, i;
1870 static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
1871
1872 pdata = spi->dev.platform_data;
1873 if (!pdata) {
1874 wl1271_error("no platform data");
1875 return -ENODEV;
1876 }
1877
1878 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
1879 if (!hw) {
1880 wl1271_error("could not alloc ieee80211_hw");
1881 return -ENOMEM;
1882 }
1883
1884 wl = hw->priv;
1885 memset(wl, 0, sizeof(*wl));
1886
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001887 INIT_LIST_HEAD(&wl->list);
1888
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001889 wl->hw = hw;
1890 dev_set_drvdata(&spi->dev, wl);
1891 wl->spi = spi;
1892
1893 skb_queue_head_init(&wl->tx_queue);
1894
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03001895 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001896 wl->channel = WL1271_DEFAULT_CHANNEL;
1897 wl->scanning = false;
1898 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001899 wl->rx_counter = 0;
1900 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1901 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1902 wl->elp = false;
1903 wl->psm = 0;
1904 wl->psm_requested = false;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001905 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001906 wl->tx_queue_stopped = false;
1907 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001908 wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001909 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001910 wl->vif = NULL;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001911 wl->joined = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001912
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03001913 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001914 wl->tx_frames[i] = NULL;
1915
1916 spin_lock_init(&wl->wl_lock);
1917
1918 /*
1919 * In case our MAC address is not correctly set,
1920 * we use a random but Nokia MAC.
1921 */
1922 memcpy(wl->mac_addr, nokia_oui, 3);
1923 get_random_bytes(wl->mac_addr + 3, 3);
1924
1925 wl->state = WL1271_STATE_OFF;
1926 mutex_init(&wl->mutex);
1927
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001928 /* This is the only SPI value that we need to set here, the rest
1929 * comes from the board-peripherals file */
1930 spi->bits_per_word = 32;
1931
1932 ret = spi_setup(spi);
1933 if (ret < 0) {
1934 wl1271_error("spi_setup failed");
1935 goto out_free;
1936 }
1937
1938 wl->set_power = pdata->set_power;
1939 if (!wl->set_power) {
1940 wl1271_error("set power function missing in platform data");
1941 ret = -ENODEV;
1942 goto out_free;
1943 }
1944
1945 wl->irq = spi->irq;
1946 if (wl->irq < 0) {
1947 wl1271_error("irq missing in platform data");
1948 ret = -ENODEV;
1949 goto out_free;
1950 }
1951
1952 ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
1953 if (ret < 0) {
1954 wl1271_error("request_irq() failed: %d", ret);
1955 goto out_free;
1956 }
1957
1958 set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
1959
1960 disable_irq(wl->irq);
1961
1962 ret = platform_device_register(&wl1271_device);
1963 if (ret) {
1964 wl1271_error("couldn't register platform device");
1965 goto out_irq;
1966 }
1967 dev_set_drvdata(&wl1271_device.dev, wl);
1968
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001969 /* Apply default driver configuration. */
1970 wl1271_conf_init(wl);
1971
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001972 ret = wl1271_init_ieee80211(wl);
1973 if (ret)
1974 goto out_platform;
1975
1976 ret = wl1271_register_hw(wl);
1977 if (ret)
1978 goto out_platform;
1979
1980 wl1271_debugfs_init(wl);
1981
1982 wl1271_notice("initialized");
1983
1984 return 0;
1985
1986 out_platform:
1987 platform_device_unregister(&wl1271_device);
1988
1989 out_irq:
1990 free_irq(wl->irq, wl);
1991
1992 out_free:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001993 ieee80211_free_hw(hw);
1994
1995 return ret;
1996}
1997
1998static int __devexit wl1271_remove(struct spi_device *spi)
1999{
2000 struct wl1271 *wl = dev_get_drvdata(&spi->dev);
2001
2002 ieee80211_unregister_hw(wl->hw);
2003
2004 wl1271_debugfs_exit(wl);
2005 platform_device_unregister(&wl1271_device);
2006 free_irq(wl->irq, wl);
2007 kfree(wl->target_mem_map);
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03002008 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002009 wl->fw = NULL;
2010 kfree(wl->nvs);
2011 wl->nvs = NULL;
2012
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002013 kfree(wl->fw_status);
2014 kfree(wl->tx_res_if);
2015
2016 ieee80211_free_hw(wl->hw);
2017
2018 return 0;
2019}
2020
2021
2022static struct spi_driver wl1271_spi_driver = {
2023 .driver = {
2024 .name = "wl1271",
2025 .bus = &spi_bus_type,
2026 .owner = THIS_MODULE,
2027 },
2028
2029 .probe = wl1271_probe,
2030 .remove = __devexit_p(wl1271_remove),
2031};
2032
2033static int __init wl1271_init(void)
2034{
2035 int ret;
2036
2037 ret = spi_register_driver(&wl1271_spi_driver);
2038 if (ret < 0) {
2039 wl1271_error("failed to register spi driver: %d", ret);
2040 goto out;
2041 }
2042
2043out:
2044 return ret;
2045}
2046
2047static void __exit wl1271_exit(void)
2048{
2049 spi_unregister_driver(&wl1271_spi_driver);
2050
2051 wl1271_notice("unloaded");
2052}
2053
2054module_init(wl1271_init);
2055module_exit(wl1271_exit);
2056
2057MODULE_LICENSE("GPL");
2058MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
Luciano Coelho2f018722009-10-08 21:56:27 +03002059MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
Ben Hutchings49f146d2009-11-07 22:02:15 +00002060MODULE_FIRMWARE(WL1271_FW_NAME);