blob: 6501d6e2d3b20882464b5559a891e37e6a28a77b [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
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>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinen01c09162009-10-13 12:47:55 +030031#include <linux/inetdevice.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030032
33#include "wl1271.h"
34#include "wl12xx_80211.h"
35#include "wl1271_reg.h"
Teemu Paasikivi7b048c52010-02-18 13:25:55 +020036#include "wl1271_io.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030037#include "wl1271_event.h"
38#include "wl1271_tx.h"
39#include "wl1271_rx.h"
40#include "wl1271_ps.h"
41#include "wl1271_init.h"
42#include "wl1271_debugfs.h"
43#include "wl1271_cmd.h"
44#include "wl1271_boot.h"
Kalle Valoc8c90872010-02-18 13:25:53 +020045#include "wl1271_testmode.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030046
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020047#define WL1271_BOOT_RETRIES 3
48
Juuso Oikarinen8a080482009-10-13 12:47:44 +030049static struct conf_drv_settings default_conf = {
50 .sg = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020051 .params = {
52 [CONF_SG_BT_PER_THRESHOLD] = 7500,
53 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
54 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
55 [CONF_SG_BT_LOAD_RATIO] = 50,
56 [CONF_SG_AUTO_PS_MODE] = 0,
57 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
58 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
59 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
60 [CONF_SG_BEACON_MISS_PERCENT] = 60,
61 [CONF_SG_RATE_ADAPT_THRESH] = 12,
62 [CONF_SG_RATE_ADAPT_SNR] = 0,
63 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
64 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
65 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
66 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
67 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
68 /* Note: with UPSD, this should be 4 */
69 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
70 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
71 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
72 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
73 /* Note: with UPDS, this should be 15 */
74 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
75 /* Note: with UPDS, this should be 50 */
76 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
77 /* Note: with UPDS, this should be 10 */
78 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
79 [CONF_SG_RXT] = 1200,
80 [CONF_SG_TXT] = 1000,
81 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
82 [CONF_SG_PS_POLL_TIMEOUT] = 10,
83 [CONF_SG_UPSD_TIMEOUT] = 10,
84 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
85 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
86 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
87 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
88 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
89 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
90 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
91 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
92 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
93 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
94 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
95 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
96 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
97 [CONF_SG_HV3_MAX_SERVED] = 6,
98 [CONF_SG_DHCP_TIME] = 5000,
99 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
100 },
101 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300102 },
103 .rx = {
104 .rx_msdu_life_time = 512000,
105 .packet_detection_threshold = 0,
106 .ps_poll_timeout = 15,
107 .upsd_timeout = 15,
108 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200109 .rx_cca_threshold = 0,
110 .irq_blk_threshold = 0xFFFF,
111 .irq_pkt_threshold = 0,
112 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300113 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
114 },
115 .tx = {
116 .tx_energy_detection = 0,
117 .rc_conf = {
Juuso Oikarinenec078d92009-12-11 15:41:05 +0200118 .enabled_rates = CONF_HW_BIT_RATE_1MBPS |
119 CONF_HW_BIT_RATE_2MBPS,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300120 .short_retry_limit = 10,
121 .long_retry_limit = 10,
122 .aflags = 0
123 },
124 .ac_conf_count = 4,
125 .ac_conf = {
126 [0] = {
127 .ac = CONF_TX_AC_BE,
128 .cw_min = 15,
129 .cw_max = 63,
130 .aifsn = 3,
131 .tx_op_limit = 0,
132 },
133 [1] = {
134 .ac = CONF_TX_AC_BK,
135 .cw_min = 15,
136 .cw_max = 63,
137 .aifsn = 7,
138 .tx_op_limit = 0,
139 },
140 [2] = {
141 .ac = CONF_TX_AC_VI,
142 .cw_min = 15,
143 .cw_max = 63,
144 .aifsn = CONF_TX_AIFS_PIFS,
145 .tx_op_limit = 3008,
146 },
147 [3] = {
148 .ac = CONF_TX_AC_VO,
149 .cw_min = 15,
150 .cw_max = 63,
151 .aifsn = CONF_TX_AIFS_PIFS,
152 .tx_op_limit = 1504,
153 },
154 },
155 .tid_conf_count = 7,
156 .tid_conf = {
157 [0] = {
158 .queue_id = 0,
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 [1] = {
166 .queue_id = 1,
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 [2] = {
174 .queue_id = 2,
175 .channel_type = CONF_CHANNEL_TYPE_DCF,
176 .tsid = CONF_TX_AC_BE,
177 .ps_scheme = CONF_PS_SCHEME_LEGACY,
178 .ack_policy = CONF_ACK_POLICY_LEGACY,
179 .apsd_conf = {0, 0},
180 },
181 [3] = {
182 .queue_id = 3,
183 .channel_type = CONF_CHANNEL_TYPE_DCF,
184 .tsid = CONF_TX_AC_BE,
185 .ps_scheme = CONF_PS_SCHEME_LEGACY,
186 .ack_policy = CONF_ACK_POLICY_LEGACY,
187 .apsd_conf = {0, 0},
188 },
189 [4] = {
190 .queue_id = 4,
191 .channel_type = CONF_CHANNEL_TYPE_DCF,
192 .tsid = CONF_TX_AC_BE,
193 .ps_scheme = CONF_PS_SCHEME_LEGACY,
194 .ack_policy = CONF_ACK_POLICY_LEGACY,
195 .apsd_conf = {0, 0},
196 },
197 [5] = {
198 .queue_id = 5,
199 .channel_type = CONF_CHANNEL_TYPE_DCF,
200 .tsid = CONF_TX_AC_BE,
201 .ps_scheme = CONF_PS_SCHEME_LEGACY,
202 .ack_policy = CONF_ACK_POLICY_LEGACY,
203 .apsd_conf = {0, 0},
204 },
205 [6] = {
206 .queue_id = 6,
207 .channel_type = CONF_CHANNEL_TYPE_DCF,
208 .tsid = CONF_TX_AC_BE,
209 .ps_scheme = CONF_PS_SCHEME_LEGACY,
210 .ack_policy = CONF_ACK_POLICY_LEGACY,
211 .apsd_conf = {0, 0},
212 }
213 },
214 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200215 .tx_compl_timeout = 700,
216 .tx_compl_threshold = 4
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300217 },
218 .conn = {
219 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
220 .listen_interval = 0,
221 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
222 .bcn_filt_ie_count = 1,
223 .bcn_filt_ie = {
224 [0] = {
225 .ie = WLAN_EID_CHANNEL_SWITCH,
226 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
227 }
228 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200229 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300230 .bss_lose_timeout = 100,
231 .beacon_rx_timeout = 10000,
232 .broadcast_timeout = 20000,
233 .rx_broadcast_in_ps = 1,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200234 .ps_poll_threshold = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300235 .sig_trigger_count = 2,
236 .sig_trigger = {
237 [0] = {
238 .threshold = -75,
239 .pacing = 500,
240 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
241 .type = CONF_TRIG_EVENT_TYPE_EDGE,
242 .direction = CONF_TRIG_EVENT_DIR_LOW,
243 .hysteresis = 2,
244 .index = 0,
245 .enable = 1
246 },
247 [1] = {
248 .threshold = -75,
249 .pacing = 500,
250 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
251 .type = CONF_TRIG_EVENT_TYPE_EDGE,
252 .direction = CONF_TRIG_EVENT_DIR_HIGH,
253 .hysteresis = 2,
254 .index = 1,
255 .enable = 1
256 }
257 },
258 .sig_weights = {
259 .rssi_bcn_avg_weight = 10,
260 .rssi_pkt_avg_weight = 10,
261 .snr_bcn_avg_weight = 10,
262 .snr_pkt_avg_weight = 10
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300263 },
264 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200265 .bet_max_consecutive = 10,
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200266 .psm_entry_retries = 3
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300267 },
268 .init = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300269 .radioparam = {
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200270 .fem = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300271 }
Luciano Coelho6e92b412009-12-11 15:40:50 +0200272 },
273 .itrim = {
274 .enable = false,
275 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200276 },
277 .pm_config = {
278 .host_clk_settling_time = 5000,
279 .host_fast_wakeup_support = false
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300280 }
281};
282
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300283static LIST_HEAD(wl_list);
284
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300285static void wl1271_conf_init(struct wl1271 *wl)
286{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300287
288 /*
289 * This function applies the default configuration to the driver. This
290 * function is invoked upon driver load (spi probe.)
291 *
292 * The configuration is stored in a run-time structure in order to
293 * facilitate for run-time adjustment of any of the parameters. Making
294 * changes to the configuration structure will apply the new values on
295 * the next interface up (wl1271_op_start.)
296 */
297
298 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300299 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300300}
301
302
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300303static int wl1271_plt_init(struct wl1271 *wl)
304{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200305 struct conf_tx_ac_category *conf_ac;
306 struct conf_tx_tid *conf_tid;
307 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300308
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200309 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200310 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200311 return ret;
312
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200313 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200314 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200315 return ret;
316
Luciano Coelho12419cc2010-02-18 13:25:44 +0200317 ret = wl1271_init_templates_config(wl);
318 if (ret < 0)
319 return ret;
320
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300321 ret = wl1271_acx_init_mem_config(wl);
322 if (ret < 0)
323 return ret;
324
Luciano Coelho12419cc2010-02-18 13:25:44 +0200325 /* PHY layer config */
326 ret = wl1271_init_phy_config(wl);
327 if (ret < 0)
328 goto out_free_memmap;
329
330 ret = wl1271_acx_dco_itrim_params(wl);
331 if (ret < 0)
332 goto out_free_memmap;
333
334 /* Initialize connection monitoring thresholds */
335 ret = wl1271_acx_conn_monit_params(wl);
336 if (ret < 0)
337 goto out_free_memmap;
338
339 /* Bluetooth WLAN coexistence */
340 ret = wl1271_init_pta(wl);
341 if (ret < 0)
342 goto out_free_memmap;
343
344 /* Energy detection */
345 ret = wl1271_init_energy_detection(wl);
346 if (ret < 0)
347 goto out_free_memmap;
348
349 /* Default fragmentation threshold */
350 ret = wl1271_acx_frag_threshold(wl);
351 if (ret < 0)
352 goto out_free_memmap;
353
354 /* Default TID configuration */
355 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
356 conf_tid = &wl->conf.tx.tid_conf[i];
357 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
358 conf_tid->channel_type,
359 conf_tid->tsid,
360 conf_tid->ps_scheme,
361 conf_tid->ack_policy,
362 conf_tid->apsd_conf[0],
363 conf_tid->apsd_conf[1]);
364 if (ret < 0)
365 goto out_free_memmap;
366 }
367
368 /* Default AC configuration */
369 for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
370 conf_ac = &wl->conf.tx.ac_conf[i];
371 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
372 conf_ac->cw_max, conf_ac->aifsn,
373 conf_ac->tx_op_limit);
374 if (ret < 0)
375 goto out_free_memmap;
376 }
377
378 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200379 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300380 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200381 goto out_free_memmap;
382
383 /* Configure for CAM power saving (ie. always active) */
384 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
385 if (ret < 0)
386 goto out_free_memmap;
387
388 /* configure PM */
389 ret = wl1271_acx_pm_config(wl);
390 if (ret < 0)
391 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300392
393 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200394
395 out_free_memmap:
396 kfree(wl->target_mem_map);
397 wl->target_mem_map = NULL;
398
399 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300400}
401
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300402static void wl1271_fw_status(struct wl1271 *wl,
403 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300404{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200405 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300406 u32 total = 0;
407 int i;
408
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200409 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300410
411 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
412 "drv_rx_counter = %d, tx_results_counter = %d)",
413 status->intr,
414 status->fw_rx_counter,
415 status->drv_rx_counter,
416 status->tx_results_counter);
417
418 /* update number of available TX blocks */
419 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300420 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
421 wl->tx_blocks_freed[i];
422
423 wl->tx_blocks_freed[i] =
424 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300425 wl->tx_blocks_available += cnt;
426 total += cnt;
427 }
428
429 /* if more blocks are available now, schedule some tx work */
430 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300431 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300432
433 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200434 getnstimeofday(&ts);
435 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
436 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300437}
438
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200439#define WL1271_IRQ_MAX_LOOPS 10
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;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200445 int loopcount = WL1271_IRQ_MAX_LOOPS;
446 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300447 struct wl1271 *wl =
448 container_of(work, struct wl1271, irq_work);
449
450 mutex_lock(&wl->mutex);
451
452 wl1271_debug(DEBUG_IRQ, "IRQ work");
453
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200454 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300455 goto out;
456
457 ret = wl1271_ps_elp_wakeup(wl, true);
458 if (ret < 0)
459 goto out;
460
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200461 spin_lock_irqsave(&wl->wl_lock, flags);
462 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
463 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
464 spin_unlock_irqrestore(&wl->wl_lock, flags);
465 loopcount--;
466
467 wl1271_fw_status(wl, wl->fw_status);
468 intr = le32_to_cpu(wl->fw_status->intr);
469 if (!intr) {
470 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
471 continue;
472 }
473
474 intr &= WL1271_INTR_MASK;
475
476 if (intr & WL1271_ACX_INTR_DATA) {
477 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
478
479 /* check for tx results */
480 if (wl->fw_status->tx_results_counter !=
481 (wl->tx_results_count & 0xff))
482 wl1271_tx_complete(wl);
483
484 wl1271_rx(wl, wl->fw_status);
485 }
486
487 if (intr & WL1271_ACX_INTR_EVENT_A) {
488 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
489 wl1271_event_handle(wl, 0);
490 }
491
492 if (intr & WL1271_ACX_INTR_EVENT_B) {
493 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
494 wl1271_event_handle(wl, 1);
495 }
496
497 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
498 wl1271_debug(DEBUG_IRQ,
499 "WL1271_ACX_INTR_INIT_COMPLETE");
500
501 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
502 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
503
504 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300505 }
506
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200507 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
508 ieee80211_queue_work(wl->hw, &wl->irq_work);
509 else
510 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
511 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300512
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300513 wl1271_ps_elp_sleep(wl);
514
515out:
516 mutex_unlock(&wl->mutex);
517}
518
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300519static int wl1271_fetch_firmware(struct wl1271 *wl)
520{
521 const struct firmware *fw;
522 int ret;
523
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200524 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300525
526 if (ret < 0) {
527 wl1271_error("could not get firmware: %d", ret);
528 return ret;
529 }
530
531 if (fw->size % 4) {
532 wl1271_error("firmware size is not multiple of 32 bits: %zu",
533 fw->size);
534 ret = -EILSEQ;
535 goto out;
536 }
537
538 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300539 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300540
541 if (!wl->fw) {
542 wl1271_error("could not allocate memory for the firmware");
543 ret = -ENOMEM;
544 goto out;
545 }
546
547 memcpy(wl->fw, fw->data, wl->fw_len);
548
549 ret = 0;
550
551out:
552 release_firmware(fw);
553
554 return ret;
555}
556
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200557static int wl1271_update_mac_addr(struct wl1271 *wl)
558{
559 int ret = 0;
560 u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
561
562 /* get mac address from the NVS */
563 wl->mac_addr[0] = nvs_ptr[11];
564 wl->mac_addr[1] = nvs_ptr[10];
565 wl->mac_addr[2] = nvs_ptr[6];
566 wl->mac_addr[3] = nvs_ptr[5];
567 wl->mac_addr[4] = nvs_ptr[4];
568 wl->mac_addr[5] = nvs_ptr[3];
569
570 /* FIXME: if it is a zero-address, we should bail out. Now, instead,
571 we randomize an address */
572 if (is_zero_ether_addr(wl->mac_addr)) {
573 static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
574 memcpy(wl->mac_addr, nokia_oui, 3);
575 get_random_bytes(wl->mac_addr + 3, 3);
Juuso Oikarinene2e77b52010-02-18 13:25:46 +0200576
577 /* update this address to the NVS */
578 nvs_ptr[11] = wl->mac_addr[0];
579 nvs_ptr[10] = wl->mac_addr[1];
580 nvs_ptr[6] = wl->mac_addr[2];
581 nvs_ptr[5] = wl->mac_addr[3];
582 nvs_ptr[4] = wl->mac_addr[4];
583 nvs_ptr[3] = wl->mac_addr[5];
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200584 }
585
586 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
587
588 return ret;
589}
590
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300591static int wl1271_fetch_nvs(struct wl1271 *wl)
592{
593 const struct firmware *fw;
594 int ret;
595
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200596 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300597
598 if (ret < 0) {
599 wl1271_error("could not get nvs file: %d", ret);
600 return ret;
601 }
602
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200603 if (fw->size != sizeof(struct wl1271_nvs_file)) {
604 wl1271_error("nvs size is not as expected: %zu != %zu",
605 fw->size, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300606 ret = -EILSEQ;
607 goto out;
608 }
609
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200610 wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300611
612 if (!wl->nvs) {
613 wl1271_error("could not allocate memory for the nvs file");
614 ret = -ENOMEM;
615 goto out;
616 }
617
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200618 memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300619
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200620 ret = wl1271_update_mac_addr(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300621
622out:
623 release_firmware(fw);
624
625 return ret;
626}
627
628static void wl1271_fw_wakeup(struct wl1271 *wl)
629{
630 u32 elp_reg;
631
632 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300633 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300634}
635
636static int wl1271_setup(struct wl1271 *wl)
637{
638 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
639 if (!wl->fw_status)
640 return -ENOMEM;
641
642 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
643 if (!wl->tx_res_if) {
644 kfree(wl->fw_status);
645 return -ENOMEM;
646 }
647
648 INIT_WORK(&wl->irq_work, wl1271_irq_work);
649 INIT_WORK(&wl->tx_work, wl1271_tx_work);
650 return 0;
651}
652
653static int wl1271_chip_wakeup(struct wl1271 *wl)
654{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300655 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300656 int ret = 0;
657
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200658 msleep(WL1271_PRE_POWER_ON_SLEEP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300659 wl1271_power_on(wl);
660 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200661 wl1271_io_reset(wl);
662 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300663
664 /* We don't need a real memory partition here, because we only want
665 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300666 memset(&partition, 0, sizeof(partition));
667 partition.reg.start = REGISTERS_BASE;
668 partition.reg.size = REGISTERS_DOWN_SIZE;
669 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300670
671 /* ELP module wake up */
672 wl1271_fw_wakeup(wl);
673
674 /* whal_FwCtrl_BootSm() */
675
676 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200677 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300678
679 /* 1. check if chip id is valid */
680
681 switch (wl->chip.id) {
682 case CHIP_ID_1271_PG10:
683 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
684 wl->chip.id);
685
686 ret = wl1271_setup(wl);
687 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200688 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300689 break;
690 case CHIP_ID_1271_PG20:
691 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
692 wl->chip.id);
693
694 ret = wl1271_setup(wl);
695 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200696 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300697 break;
698 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200699 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300700 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200701 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300702 }
703
704 if (wl->fw == NULL) {
705 ret = wl1271_fetch_firmware(wl);
706 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200707 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300708 }
709
710 /* No NVS from netlink, try to get it from the filesystem */
711 if (wl->nvs == NULL) {
712 ret = wl1271_fetch_nvs(wl);
713 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200714 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300715 }
716
717out:
718 return ret;
719}
720
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300721int wl1271_plt_start(struct wl1271 *wl)
722{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200723 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300724 int ret;
725
726 mutex_lock(&wl->mutex);
727
728 wl1271_notice("power up");
729
730 if (wl->state != WL1271_STATE_OFF) {
731 wl1271_error("cannot go into PLT state because not "
732 "in off state: %d", wl->state);
733 ret = -EBUSY;
734 goto out;
735 }
736
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200737 while (retries) {
738 retries--;
739 ret = wl1271_chip_wakeup(wl);
740 if (ret < 0)
741 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300742
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200743 ret = wl1271_boot(wl);
744 if (ret < 0)
745 goto power_off;
746
747 ret = wl1271_plt_init(wl);
748 if (ret < 0)
749 goto irq_disable;
750
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200751 wl->state = WL1271_STATE_PLT;
752 wl1271_notice("firmware booted in PLT mode (%s)",
753 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300754 goto out;
755
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200756irq_disable:
757 wl1271_disable_interrupts(wl);
758 mutex_unlock(&wl->mutex);
759 /* Unlocking the mutex in the middle of handling is
760 inherently unsafe. In this case we deem it safe to do,
761 because we need to let any possibly pending IRQ out of
762 the system (and while we are WL1271_STATE_OFF the IRQ
763 work function will not do anything.) Also, any other
764 possible concurrent operations will fail due to the
765 current state, hence the wl1271 struct should be safe. */
766 cancel_work_sync(&wl->irq_work);
767 mutex_lock(&wl->mutex);
768power_off:
769 wl1271_power_off(wl);
770 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300771
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200772 wl1271_error("firmware boot in PLT mode failed despite %d retries",
773 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300774out:
775 mutex_unlock(&wl->mutex);
776
777 return ret;
778}
779
780int wl1271_plt_stop(struct wl1271 *wl)
781{
782 int ret = 0;
783
784 mutex_lock(&wl->mutex);
785
786 wl1271_notice("power down");
787
788 if (wl->state != WL1271_STATE_PLT) {
789 wl1271_error("cannot power down because not in PLT "
790 "state: %d", wl->state);
791 ret = -EBUSY;
792 goto out;
793 }
794
795 wl1271_disable_interrupts(wl);
796 wl1271_power_off(wl);
797
798 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300799 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300800
801out:
802 mutex_unlock(&wl->mutex);
803
804 return ret;
805}
806
807
808static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
809{
810 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200811 struct ieee80211_conf *conf = &hw->conf;
812 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
813 struct ieee80211_sta *sta = txinfo->control.sta;
814 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300815
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200816 /* peek into the rates configured in the STA entry */
817 spin_lock_irqsave(&wl->wl_lock, flags);
818 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
819 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
820 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
821 }
822 spin_unlock_irqrestore(&wl->wl_lock, flags);
823
824 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300825 skb_queue_tail(&wl->tx_queue, skb);
826
827 /*
828 * The chip specific setup must run before the first TX packet -
829 * before that, the tx_work will not be initialized!
830 */
831
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300832 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300833
834 /*
835 * The workqueue is slow to process the tx_queue and we need stop
836 * the queue here, otherwise the queue will get too long.
837 */
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200838 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
839 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300840
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200841 spin_lock_irqsave(&wl->wl_lock, flags);
842 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200843 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200844 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300845 }
846
847 return NETDEV_TX_OK;
848}
849
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300850static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
851 void *arg)
852{
853 struct net_device *dev;
854 struct wireless_dev *wdev;
855 struct wiphy *wiphy;
856 struct ieee80211_hw *hw;
857 struct wl1271 *wl;
858 struct wl1271 *wl_temp;
859 struct in_device *idev;
860 struct in_ifaddr *ifa = arg;
861 int ret = 0;
862
863 /* FIXME: this ugly function should probably be implemented in the
864 * mac80211, and here should only be a simple callback handling actual
865 * setting of the filters. Now we need to dig up references to
866 * various structures to gain access to what we need.
867 * Also, because of this, there is no "initial" setting of the filter
868 * in "op_start", because we don't want to dig up struct net_device
869 * there - the filter will be set upon first change of the interface
870 * IP address. */
871
872 dev = ifa->ifa_dev->dev;
873
874 wdev = dev->ieee80211_ptr;
875 if (wdev == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200876 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300877
878 wiphy = wdev->wiphy;
879 if (wiphy == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200880 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300881
882 hw = wiphy_priv(wiphy);
883 if (hw == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200884 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300885
886 /* Check that the interface is one supported by this driver. */
887 wl_temp = hw->priv;
888 list_for_each_entry(wl, &wl_list, list) {
889 if (wl == wl_temp)
890 break;
891 }
892 if (wl == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200893 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300894
895 /* Get the interface IP address for the device. "ifa" will become
896 NULL if:
897 - there is no IPV4 protocol address configured
898 - there are multiple (virtual) IPV4 addresses configured
899 When "ifa" is NULL, filtering will be disabled.
900 */
901 ifa = NULL;
902 idev = dev->ip_ptr;
903 if (idev)
904 ifa = idev->ifa_list;
905
906 if (ifa && ifa->ifa_next)
907 ifa = NULL;
908
909 mutex_lock(&wl->mutex);
910
911 if (wl->state == WL1271_STATE_OFF)
912 goto out;
913
914 ret = wl1271_ps_elp_wakeup(wl, false);
915 if (ret < 0)
916 goto out;
917 if (ifa)
918 ret = wl1271_acx_arp_ip_filter(wl, true,
919 (u8 *)&ifa->ifa_address,
920 ACX_IPV4_VERSION);
921 else
922 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
923 ACX_IPV4_VERSION);
924 wl1271_ps_elp_sleep(wl);
925
926out:
927 mutex_unlock(&wl->mutex);
928
Luciano Coelho17d72652009-11-23 23:22:15 +0200929 return NOTIFY_OK;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300930}
931
932static struct notifier_block wl1271_dev_notifier = {
933 .notifier_call = wl1271_dev_notify,
934};
935
936
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300937static int wl1271_op_start(struct ieee80211_hw *hw)
938{
939 struct wl1271 *wl = hw->priv;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200940 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300941 int ret = 0;
942
943 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
944
945 mutex_lock(&wl->mutex);
946
947 if (wl->state != WL1271_STATE_OFF) {
948 wl1271_error("cannot start because not in off state: %d",
949 wl->state);
950 ret = -EBUSY;
951 goto out;
952 }
953
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200954 while (retries) {
955 retries--;
956 ret = wl1271_chip_wakeup(wl);
957 if (ret < 0)
958 goto power_off;
959
960 ret = wl1271_boot(wl);
961 if (ret < 0)
962 goto power_off;
963
964 ret = wl1271_hw_init(wl);
965 if (ret < 0)
966 goto irq_disable;
967
968 wl->state = WL1271_STATE_ON;
969 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300970 goto out;
971
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200972irq_disable:
973 wl1271_disable_interrupts(wl);
974 mutex_unlock(&wl->mutex);
975 /* Unlocking the mutex in the middle of handling is
976 inherently unsafe. In this case we deem it safe to do,
977 because we need to let any possibly pending IRQ out of
978 the system (and while we are WL1271_STATE_OFF the IRQ
979 work function will not do anything.) Also, any other
980 possible concurrent operations will fail due to the
981 current state, hence the wl1271 struct should be safe. */
982 cancel_work_sync(&wl->irq_work);
983 mutex_lock(&wl->mutex);
984power_off:
985 wl1271_power_off(wl);
986 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300987
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200988 wl1271_error("firmware boot failed despite %d retries",
989 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300990out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300991 mutex_unlock(&wl->mutex);
992
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300993 if (!ret) {
994 list_add(&wl->list, &wl_list);
995 register_inetaddr_notifier(&wl1271_dev_notifier);
996 }
997
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300998 return ret;
999}
1000
1001static void wl1271_op_stop(struct ieee80211_hw *hw)
1002{
1003 struct wl1271 *wl = hw->priv;
1004 int i;
1005
1006 wl1271_info("down");
1007
1008 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1009
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001010 unregister_inetaddr_notifier(&wl1271_dev_notifier);
1011 list_del(&wl->list);
1012
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001013 mutex_lock(&wl->mutex);
1014
1015 WARN_ON(wl->state != WL1271_STATE_ON);
1016
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001017 if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001018 mutex_unlock(&wl->mutex);
1019 ieee80211_scan_completed(wl->hw, true);
1020 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001021 }
1022
1023 wl->state = WL1271_STATE_OFF;
1024
1025 wl1271_disable_interrupts(wl);
1026
1027 mutex_unlock(&wl->mutex);
1028
1029 cancel_work_sync(&wl->irq_work);
1030 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001031
1032 mutex_lock(&wl->mutex);
1033
1034 /* let's notify MAC80211 about the remaining pending TX frames */
1035 wl1271_tx_flush(wl);
1036 wl1271_power_off(wl);
1037
1038 memset(wl->bssid, 0, ETH_ALEN);
1039 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1040 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001041 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001042 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001043
1044 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001045 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001046 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1047 wl->tx_blocks_available = 0;
1048 wl->tx_results_count = 0;
1049 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001050 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001051 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001052 wl->time_offset = 0;
1053 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001054 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1055 wl->sta_rate_set = 0;
1056 wl->flags = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001057
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001058 for (i = 0; i < NUM_TX_QUEUES; i++)
1059 wl->tx_blocks_freed[i] = 0;
1060
1061 wl1271_debugfs_reset(wl);
1062 mutex_unlock(&wl->mutex);
1063}
1064
1065static int wl1271_op_add_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +01001066 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001067{
1068 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001069 int ret = 0;
1070
John W. Linvillee5539bc2009-08-18 10:50:34 -04001071 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Johannes Berg1ed32e42009-12-23 13:15:45 +01001072 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001073
1074 mutex_lock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001075 if (wl->vif) {
1076 ret = -EBUSY;
1077 goto out;
1078 }
1079
Johannes Berg1ed32e42009-12-23 13:15:45 +01001080 wl->vif = vif;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001081
Johannes Berg1ed32e42009-12-23 13:15:45 +01001082 switch (vif->type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001083 case NL80211_IFTYPE_STATION:
1084 wl->bss_type = BSS_TYPE_STA_BSS;
1085 break;
1086 case NL80211_IFTYPE_ADHOC:
1087 wl->bss_type = BSS_TYPE_IBSS;
1088 break;
1089 default:
1090 ret = -EOPNOTSUPP;
1091 goto out;
1092 }
1093
1094 /* FIXME: what if conf->mac_addr changes? */
1095
1096out:
1097 mutex_unlock(&wl->mutex);
1098 return ret;
1099}
1100
1101static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +01001102 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001103{
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001104 struct wl1271 *wl = hw->priv;
1105
1106 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001107 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001108 wl->vif = NULL;
1109 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001110}
1111
1112#if 0
1113static int wl1271_op_config_interface(struct ieee80211_hw *hw,
1114 struct ieee80211_vif *vif,
1115 struct ieee80211_if_conf *conf)
1116{
1117 struct wl1271 *wl = hw->priv;
1118 struct sk_buff *beacon;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001119 int ret;
1120
David S. Miller32646902009-09-17 10:18:30 -07001121 wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM",
1122 conf->bssid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001123 wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid,
1124 conf->ssid_len);
1125
1126 mutex_lock(&wl->mutex);
1127
1128 ret = wl1271_ps_elp_wakeup(wl, false);
1129 if (ret < 0)
1130 goto out;
1131
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001132 if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
1133 wl1271_debug(DEBUG_MAC80211, "bssid changed");
1134
1135 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
1136
Juuso Oikarinen15305492010-02-22 08:38:32 +02001137 ret = wl1271_cmd_join(wl, wl->bss_type);
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001138 if (ret < 0)
1139 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001140
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001141 ret = wl1271_cmd_build_null_data(wl);
1142 if (ret < 0)
1143 goto out_sleep;
1144 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001145
1146 wl->ssid_len = conf->ssid_len;
1147 if (wl->ssid_len)
1148 memcpy(wl->ssid, conf->ssid, wl->ssid_len);
1149
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001150 if (conf->changed & IEEE80211_IFCC_BEACON) {
1151 beacon = ieee80211_beacon_get(hw, vif);
1152 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1153 beacon->data, beacon->len);
1154
1155 if (ret < 0) {
1156 dev_kfree_skb(beacon);
1157 goto out_sleep;
1158 }
1159
1160 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE,
1161 beacon->data, beacon->len);
1162
1163 dev_kfree_skb(beacon);
1164
1165 if (ret < 0)
1166 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001167 }
1168
1169out_sleep:
1170 wl1271_ps_elp_sleep(wl);
1171
1172out:
1173 mutex_unlock(&wl->mutex);
1174
1175 return ret;
1176}
1177#endif
1178
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001179static int wl1271_join_channel(struct wl1271 *wl, int channel)
1180{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001181 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001182 /* we need to use a dummy BSSID for now */
1183 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1184 0xad, 0xbe, 0xef };
1185
1186 /* disable mac filter, so we hear everything */
1187 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1188
1189 wl->channel = channel;
1190 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1191
Juuso Oikarinen15305492010-02-22 08:38:32 +02001192 /* the dummy join is performed always with STATION BSS type to allow
1193 also ad-hoc mode to listen to the surroundings without sending any
1194 beacons yet. */
1195 ret = wl1271_cmd_join(wl, BSS_TYPE_STA_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001196 if (ret < 0)
1197 goto out;
1198
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001199 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001200
1201out:
1202 return ret;
1203}
1204
1205static int wl1271_unjoin_channel(struct wl1271 *wl)
1206{
1207 int ret;
1208
1209 /* to stop listening to a channel, we disconnect */
1210 ret = wl1271_cmd_disconnect(wl);
1211 if (ret < 0)
1212 goto out;
1213
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001214 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001215 wl->channel = 0;
1216 memset(wl->bssid, 0, ETH_ALEN);
1217 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1218
1219out:
1220 return ret;
1221}
1222
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001223static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1224{
1225 struct wl1271 *wl = hw->priv;
1226 struct ieee80211_conf *conf = &hw->conf;
1227 int channel, ret = 0;
1228
1229 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1230
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001231 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001232 channel,
1233 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001234 conf->power_level,
1235 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001236
1237 mutex_lock(&wl->mutex);
1238
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001239 wl->band = conf->channel->band;
1240
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001241 ret = wl1271_ps_elp_wakeup(wl, false);
1242 if (ret < 0)
1243 goto out;
1244
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001245 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001246 if (conf->flags & IEEE80211_CONF_IDLE &&
1247 test_bit(WL1271_FLAG_JOINED, &wl->flags))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001248 wl1271_unjoin_channel(wl);
Juuso Oikarinen8f648c02009-12-11 15:41:10 +02001249 else if (!(conf->flags & IEEE80211_CONF_IDLE))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001250 wl1271_join_channel(wl, channel);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001251
1252 if (conf->flags & IEEE80211_CONF_IDLE) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001253 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1254 wl->sta_rate_set = 0;
1255 wl1271_acx_rate_policies(wl);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001256 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001257 }
1258
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001259 /* if the channel changes while joined, join again */
Juuso Oikarinenddb01a52010-02-18 13:25:37 +02001260 if (channel != wl->channel &&
1261 test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1262 wl->channel = channel;
1263 /* FIXME: maybe use CMD_CHANNEL_SWITCH for this? */
Juuso Oikarinen15305492010-02-22 08:38:32 +02001264 ret = wl1271_cmd_join(wl, wl->bss_type);
Juuso Oikarinenddb01a52010-02-18 13:25:37 +02001265 if (ret < 0)
1266 wl1271_warning("cmd join to update channel failed %d",
1267 ret);
1268 } else
1269 wl->channel = channel;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001270
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001271 if (conf->flags & IEEE80211_CONF_PS &&
1272 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1273 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001274
1275 /*
1276 * We enter PSM only if we're already associated.
1277 * If we're not, we'll enter it when joining an SSID,
1278 * through the bss_info_changed() hook.
1279 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001280 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001281 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001282 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1283 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001284 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001285 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001286 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001287 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001288
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001289 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001290
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001291 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001292 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1293 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001294 }
1295
1296 if (conf->power_level != wl->power_level) {
1297 ret = wl1271_acx_tx_power(wl, conf->power_level);
1298 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001299 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001300
1301 wl->power_level = conf->power_level;
1302 }
1303
1304out_sleep:
1305 wl1271_ps_elp_sleep(wl);
1306
1307out:
1308 mutex_unlock(&wl->mutex);
1309
1310 return ret;
1311}
1312
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001313struct wl1271_filter_params {
1314 bool enabled;
1315 int mc_list_length;
1316 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1317};
1318
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001319static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1320 struct dev_addr_list *mc_list)
1321{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001322 struct wl1271_filter_params *fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001323 int i;
1324
Juuso Oikarinen74441132009-10-13 12:47:53 +03001325 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001326 if (!fp) {
1327 wl1271_error("Out of memory setting filters.");
1328 return 0;
1329 }
1330
1331 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001332 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001333 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1334 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001335 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001336 }
1337
1338 fp->mc_list_length = 0;
1339 for (i = 0; i < mc_count; i++) {
1340 if (mc_list->da_addrlen == ETH_ALEN) {
1341 memcpy(fp->mc_list[fp->mc_list_length],
1342 mc_list->da_addr, ETH_ALEN);
1343 fp->mc_list_length++;
1344 } else
1345 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001346 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001347 }
1348
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001349 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001350}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001351
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001352#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1353 FIF_ALLMULTI | \
1354 FIF_FCSFAIL | \
1355 FIF_BCN_PRBRESP_PROMISC | \
1356 FIF_CONTROL | \
1357 FIF_OTHER_BSS)
1358
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001359static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1360 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001361 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001362{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001363 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001364 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001365 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001366
1367 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1368
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001369 mutex_lock(&wl->mutex);
1370
1371 if (wl->state == WL1271_STATE_OFF)
1372 goto out;
1373
1374 ret = wl1271_ps_elp_wakeup(wl, false);
1375 if (ret < 0)
1376 goto out;
1377
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001378 *total &= WL1271_SUPPORTED_FILTERS;
1379 changed &= WL1271_SUPPORTED_FILTERS;
1380
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001381 if (*total & FIF_ALLMULTI)
1382 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1383 else if (fp)
1384 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1385 fp->mc_list,
1386 fp->mc_list_length);
1387 if (ret < 0)
1388 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001389
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001390 kfree(fp);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001391
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001392 /* FIXME: We still need to set our filters properly */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001393
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001394 /* determine, whether supported filter values have changed */
1395 if (changed == 0)
1396 goto out_sleep;
1397
1398 /* apply configured filters */
1399 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1400 if (ret < 0)
1401 goto out_sleep;
1402
1403out_sleep:
1404 wl1271_ps_elp_sleep(wl);
1405
1406out:
1407 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001408}
1409
1410static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1411 struct ieee80211_vif *vif,
1412 struct ieee80211_sta *sta,
1413 struct ieee80211_key_conf *key_conf)
1414{
1415 struct wl1271 *wl = hw->priv;
1416 const u8 *addr;
1417 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001418 u32 tx_seq_32 = 0;
1419 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001420 u8 key_type;
1421
1422 static const u8 bcast_addr[ETH_ALEN] =
1423 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1424
1425 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1426
1427 addr = sta ? sta->addr : bcast_addr;
1428
1429 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1430 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1431 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1432 key_conf->alg, key_conf->keyidx,
1433 key_conf->keylen, key_conf->flags);
1434 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1435
1436 if (is_zero_ether_addr(addr)) {
1437 /* We dont support TX only encryption */
1438 ret = -EOPNOTSUPP;
1439 goto out;
1440 }
1441
1442 mutex_lock(&wl->mutex);
1443
1444 ret = wl1271_ps_elp_wakeup(wl, false);
1445 if (ret < 0)
1446 goto out_unlock;
1447
1448 switch (key_conf->alg) {
1449 case ALG_WEP:
1450 key_type = KEY_WEP;
1451
1452 key_conf->hw_key_idx = key_conf->keyidx;
1453 break;
1454 case ALG_TKIP:
1455 key_type = KEY_TKIP;
1456
1457 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001458 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1459 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001460 break;
1461 case ALG_CCMP:
1462 key_type = KEY_AES;
1463
1464 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001465 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1466 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001467 break;
1468 default:
1469 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1470
1471 ret = -EOPNOTSUPP;
1472 goto out_sleep;
1473 }
1474
1475 switch (cmd) {
1476 case SET_KEY:
1477 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1478 key_conf->keyidx, key_type,
1479 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001480 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001481 if (ret < 0) {
1482 wl1271_error("Could not add or replace key");
1483 goto out_sleep;
1484 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001485
1486 /* the default WEP key needs to be configured at least once */
1487 if (key_type == KEY_WEP) {
1488 ret = wl1271_cmd_set_default_wep_key(wl,
1489 wl->default_key);
1490 if (ret < 0)
1491 goto out_sleep;
1492 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001493 break;
1494
1495 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001496 /* The wl1271 does not allow to remove unicast keys - they
1497 will be cleared automatically on next CMD_JOIN. Ignore the
1498 request silently, as we dont want the mac80211 to emit
1499 an error message. */
1500 if (!is_broadcast_ether_addr(addr))
1501 break;
1502
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001503 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1504 key_conf->keyidx, key_type,
1505 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001506 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001507 if (ret < 0) {
1508 wl1271_error("Could not remove key");
1509 goto out_sleep;
1510 }
1511 break;
1512
1513 default:
1514 wl1271_error("Unsupported key cmd 0x%x", cmd);
1515 ret = -EOPNOTSUPP;
1516 goto out_sleep;
1517
1518 break;
1519 }
1520
1521out_sleep:
1522 wl1271_ps_elp_sleep(wl);
1523
1524out_unlock:
1525 mutex_unlock(&wl->mutex);
1526
1527out:
1528 return ret;
1529}
1530
1531static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1532 struct cfg80211_scan_request *req)
1533{
1534 struct wl1271 *wl = hw->priv;
1535 int ret;
1536 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001537 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001538
1539 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1540
1541 if (req->n_ssids) {
1542 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001543 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001544 }
1545
1546 mutex_lock(&wl->mutex);
1547
1548 ret = wl1271_ps_elp_wakeup(wl, false);
1549 if (ret < 0)
1550 goto out;
1551
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001552 if (wl1271_11a_enabled())
1553 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1554 WL1271_SCAN_BAND_DUAL, 3);
1555 else
1556 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1557 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001558
1559 wl1271_ps_elp_sleep(wl);
1560
1561out:
1562 mutex_unlock(&wl->mutex);
1563
1564 return ret;
1565}
1566
1567static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1568{
1569 struct wl1271 *wl = hw->priv;
1570 int ret;
1571
1572 mutex_lock(&wl->mutex);
1573
1574 ret = wl1271_ps_elp_wakeup(wl, false);
1575 if (ret < 0)
1576 goto out;
1577
1578 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1579 if (ret < 0)
1580 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1581
1582 wl1271_ps_elp_sleep(wl);
1583
1584out:
1585 mutex_unlock(&wl->mutex);
1586
1587 return ret;
1588}
1589
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001590static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1591{
1592 u8 *ptr = beacon->data +
1593 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1594
1595 /* find the location of the ssid in the beacon */
1596 while (ptr < beacon->data + beacon->len) {
1597 if (ptr[0] == WLAN_EID_SSID) {
1598 wl->ssid_len = ptr[1];
1599 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1600 return;
1601 }
1602 ptr += ptr[1];
1603 }
1604 wl1271_error("ad-hoc beacon template has no SSID!\n");
1605}
1606
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001607static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1608 struct ieee80211_vif *vif,
1609 struct ieee80211_bss_conf *bss_conf,
1610 u32 changed)
1611{
1612 enum wl1271_cmd_ps_mode mode;
1613 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001614 bool do_join = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001615 int ret;
1616
1617 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1618
1619 mutex_lock(&wl->mutex);
1620
1621 ret = wl1271_ps_elp_wakeup(wl, false);
1622 if (ret < 0)
1623 goto out;
1624
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001625 if (wl->bss_type == BSS_TYPE_IBSS) {
1626 /* FIXME: This implements rudimentary ad-hoc support -
1627 proper templates are on the wish list and notification
1628 on when they change. This patch will update the templates
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001629 on every call to this function. */
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001630 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1631
1632 if (beacon) {
1633 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001634
1635 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001636 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1637 beacon->data,
1638 beacon->len);
1639
1640 if (ret < 0) {
1641 dev_kfree_skb(beacon);
1642 goto out_sleep;
1643 }
1644
1645 hdr = (struct ieee80211_hdr *) beacon->data;
1646 hdr->frame_control = cpu_to_le16(
1647 IEEE80211_FTYPE_MGMT |
1648 IEEE80211_STYPE_PROBE_RESP);
1649
1650 ret = wl1271_cmd_template_set(wl,
1651 CMD_TEMPL_PROBE_RESPONSE,
1652 beacon->data,
1653 beacon->len);
1654 dev_kfree_skb(beacon);
1655 if (ret < 0)
1656 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001657
1658 /* Need to update the SSID (for filtering etc) */
1659 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001660 }
1661 }
1662
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001663 if ((changed & BSS_CHANGED_BSSID) &&
1664 /*
1665 * Now we know the correct bssid, so we send a new join command
1666 * and enable the BSSID filter
1667 */
1668 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
1669 wl->rx_config |= CFG_BSSID_FILTER_EN;
1670 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
1671 ret = wl1271_cmd_build_null_data(wl);
1672 if (ret < 0) {
1673 wl1271_warning("cmd buld null data failed %d",
1674 ret);
1675 goto out_sleep;
1676 }
1677
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001678 /* Need to update the BSSID (for filtering etc) */
1679 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001680 }
1681
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001682 if (changed & BSS_CHANGED_ASSOC) {
1683 if (bss_conf->assoc) {
1684 wl->aid = bss_conf->aid;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001685 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001686
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001687 /*
1688 * with wl1271, we don't need to update the
1689 * beacon_int and dtim_period, because the firmware
1690 * updates it by itself when the first beacon is
1691 * received after a join.
1692 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001693 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1694 if (ret < 0)
1695 goto out_sleep;
1696
1697 ret = wl1271_acx_aid(wl, wl->aid);
1698 if (ret < 0)
1699 goto out_sleep;
1700
1701 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001702 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1703 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001704 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001705 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001706 if (ret < 0)
1707 goto out_sleep;
1708 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001709 } else {
1710 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001711 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001712 wl->aid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001713 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001714
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001715 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001716
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001717 if (changed & BSS_CHANGED_ERP_SLOT) {
1718 if (bss_conf->use_short_slot)
1719 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1720 else
1721 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1722 if (ret < 0) {
1723 wl1271_warning("Set slot time failed %d", ret);
1724 goto out_sleep;
1725 }
1726 }
1727
1728 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1729 if (bss_conf->use_short_preamble)
1730 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1731 else
1732 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1733 }
1734
1735 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1736 if (bss_conf->use_cts_prot)
1737 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1738 else
1739 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1740 if (ret < 0) {
1741 wl1271_warning("Set ctsprotect failed %d", ret);
1742 goto out_sleep;
1743 }
1744 }
1745
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001746 if (do_join) {
Juuso Oikarinen15305492010-02-22 08:38:32 +02001747 ret = wl1271_cmd_join(wl, wl->bss_type);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001748 if (ret < 0) {
1749 wl1271_warning("cmd join failed %d", ret);
1750 goto out_sleep;
1751 }
1752 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1753 }
1754
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001755out_sleep:
1756 wl1271_ps_elp_sleep(wl);
1757
1758out:
1759 mutex_unlock(&wl->mutex);
1760}
1761
Kalle Valoc6999d82010-02-18 13:25:41 +02001762static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1763 const struct ieee80211_tx_queue_params *params)
1764{
1765 struct wl1271 *wl = hw->priv;
1766 int ret;
1767
1768 mutex_lock(&wl->mutex);
1769
1770 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1771
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001772 ret = wl1271_ps_elp_wakeup(wl, false);
1773 if (ret < 0)
1774 goto out;
1775
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001776 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001777 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1778 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001779 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001780 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001781 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001782
1783 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1784 CONF_CHANNEL_TYPE_EDCF,
1785 wl1271_tx_get_queue(queue),
1786 CONF_PS_SCHEME_LEGACY_PSPOLL,
1787 CONF_ACK_POLICY_LEGACY, 0, 0);
1788 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001789 goto out_sleep;
1790
1791out_sleep:
1792 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001793
1794out:
1795 mutex_unlock(&wl->mutex);
1796
1797 return ret;
1798}
1799
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001800
1801/* can't be const, mac80211 writes to this */
1802static struct ieee80211_rate wl1271_rates[] = {
1803 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001804 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1805 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001806 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001807 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1808 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001809 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1810 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001811 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1812 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001813 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1814 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001815 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1816 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001817 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1818 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001819 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1820 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001821 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001822 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1823 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001824 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001825 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1826 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001827 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001828 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1829 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001830 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001831 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1832 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001833 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001834 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1835 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001836 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001837 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1838 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001839 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001840 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1841 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001842};
1843
1844/* can't be const, mac80211 writes to this */
1845static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001846 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1847 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1848 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1849 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1850 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1851 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1852 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1853 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1854 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1855 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1856 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1857 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1858 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001859};
1860
1861/* can't be const, mac80211 writes to this */
1862static struct ieee80211_supported_band wl1271_band_2ghz = {
1863 .channels = wl1271_channels,
1864 .n_channels = ARRAY_SIZE(wl1271_channels),
1865 .bitrates = wl1271_rates,
1866 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1867};
1868
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001869/* 5 GHz data rates for WL1273 */
1870static struct ieee80211_rate wl1271_rates_5ghz[] = {
1871 { .bitrate = 60,
1872 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1873 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
1874 { .bitrate = 90,
1875 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1876 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
1877 { .bitrate = 120,
1878 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1879 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
1880 { .bitrate = 180,
1881 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1882 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
1883 { .bitrate = 240,
1884 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1885 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
1886 { .bitrate = 360,
1887 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1888 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
1889 { .bitrate = 480,
1890 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1891 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
1892 { .bitrate = 540,
1893 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1894 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
1895};
1896
1897/* 5 GHz band channels for WL1273 */
1898static struct ieee80211_channel wl1271_channels_5ghz[] = {
1899 { .hw_value = 183, .center_freq = 4915},
1900 { .hw_value = 184, .center_freq = 4920},
1901 { .hw_value = 185, .center_freq = 4925},
1902 { .hw_value = 187, .center_freq = 4935},
1903 { .hw_value = 188, .center_freq = 4940},
1904 { .hw_value = 189, .center_freq = 4945},
1905 { .hw_value = 192, .center_freq = 4960},
1906 { .hw_value = 196, .center_freq = 4980},
1907 { .hw_value = 7, .center_freq = 5035},
1908 { .hw_value = 8, .center_freq = 5040},
1909 { .hw_value = 9, .center_freq = 5045},
1910 { .hw_value = 11, .center_freq = 5055},
1911 { .hw_value = 12, .center_freq = 5060},
1912 { .hw_value = 16, .center_freq = 5080},
1913 { .hw_value = 34, .center_freq = 5170},
1914 { .hw_value = 36, .center_freq = 5180},
1915 { .hw_value = 38, .center_freq = 5190},
1916 { .hw_value = 40, .center_freq = 5200},
1917 { .hw_value = 42, .center_freq = 5210},
1918 { .hw_value = 44, .center_freq = 5220},
1919 { .hw_value = 46, .center_freq = 5230},
1920 { .hw_value = 48, .center_freq = 5240},
1921 { .hw_value = 52, .center_freq = 5260},
1922 { .hw_value = 56, .center_freq = 5280},
1923 { .hw_value = 60, .center_freq = 5300},
1924 { .hw_value = 64, .center_freq = 5320},
1925 { .hw_value = 100, .center_freq = 5500},
1926 { .hw_value = 104, .center_freq = 5520},
1927 { .hw_value = 108, .center_freq = 5540},
1928 { .hw_value = 112, .center_freq = 5560},
1929 { .hw_value = 116, .center_freq = 5580},
1930 { .hw_value = 120, .center_freq = 5600},
1931 { .hw_value = 124, .center_freq = 5620},
1932 { .hw_value = 128, .center_freq = 5640},
1933 { .hw_value = 132, .center_freq = 5660},
1934 { .hw_value = 136, .center_freq = 5680},
1935 { .hw_value = 140, .center_freq = 5700},
1936 { .hw_value = 149, .center_freq = 5745},
1937 { .hw_value = 153, .center_freq = 5765},
1938 { .hw_value = 157, .center_freq = 5785},
1939 { .hw_value = 161, .center_freq = 5805},
1940 { .hw_value = 165, .center_freq = 5825},
1941};
1942
1943
1944static struct ieee80211_supported_band wl1271_band_5ghz = {
1945 .channels = wl1271_channels_5ghz,
1946 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
1947 .bitrates = wl1271_rates_5ghz,
1948 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
1949};
1950
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001951static const struct ieee80211_ops wl1271_ops = {
1952 .start = wl1271_op_start,
1953 .stop = wl1271_op_stop,
1954 .add_interface = wl1271_op_add_interface,
1955 .remove_interface = wl1271_op_remove_interface,
1956 .config = wl1271_op_config,
1957/* .config_interface = wl1271_op_config_interface, */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001958 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001959 .configure_filter = wl1271_op_configure_filter,
1960 .tx = wl1271_op_tx,
1961 .set_key = wl1271_op_set_key,
1962 .hw_scan = wl1271_op_hw_scan,
1963 .bss_info_changed = wl1271_op_bss_info_changed,
1964 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02001965 .conf_tx = wl1271_op_conf_tx,
Kalle Valoc8c90872010-02-18 13:25:53 +02001966 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001967};
1968
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02001969int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001970{
1971 int ret;
1972
1973 if (wl->mac80211_registered)
1974 return 0;
1975
1976 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
1977
1978 ret = ieee80211_register_hw(wl->hw);
1979 if (ret < 0) {
1980 wl1271_error("unable to register mac80211 hw: %d", ret);
1981 return ret;
1982 }
1983
1984 wl->mac80211_registered = true;
1985
1986 wl1271_notice("loaded");
1987
1988 return 0;
1989}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02001990EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001991
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02001992int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001993{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03001994 /* The tx descriptor buffer and the TKIP space. */
1995 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
1996 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001997
1998 /* unit us */
1999 /* FIXME: find a proper value */
2000 wl->hw->channel_change_time = 10000;
2001
2002 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03002003 IEEE80211_HW_NOISE_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002004 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002005 IEEE80211_HW_SUPPORTS_PS |
2006 IEEE80211_HW_HAS_RATE_CONTROL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002007
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002008 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2009 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002010 wl->hw->wiphy->max_scan_ssids = 1;
2011 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
2012
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002013 if (wl1271_11a_enabled())
2014 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
2015
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002016 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002017
2018 return 0;
2019}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002020EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002021
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002022#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002023
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002024struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002025{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002026 struct ieee80211_hw *hw;
2027 struct wl1271 *wl;
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002028 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002029
2030 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2031 if (!hw) {
2032 wl1271_error("could not alloc ieee80211_hw");
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002033 return ERR_PTR(-ENOMEM);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002034 }
2035
2036 wl = hw->priv;
2037 memset(wl, 0, sizeof(*wl));
2038
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002039 INIT_LIST_HEAD(&wl->list);
2040
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002041 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002042
2043 skb_queue_head_init(&wl->tx_queue);
2044
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002045 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002046 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002047 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002048 wl->rx_counter = 0;
2049 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2050 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002051 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002052 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002053 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002054 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2055 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002056 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002057 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002058 wl->flags = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002059
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002060 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002061 wl->tx_frames[i] = NULL;
2062
2063 spin_lock_init(&wl->wl_lock);
2064
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002065 wl->state = WL1271_STATE_OFF;
2066 mutex_init(&wl->mutex);
2067
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002068 /* Apply default driver configuration. */
2069 wl1271_conf_init(wl);
2070
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002071 wl1271_debugfs_init(wl);
2072
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002073 return hw;
2074}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002075EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002076
2077int wl1271_free_hw(struct wl1271 *wl)
2078{
2079 ieee80211_unregister_hw(wl->hw);
2080
2081 wl1271_debugfs_exit(wl);
2082
2083 kfree(wl->target_mem_map);
2084 vfree(wl->fw);
2085 wl->fw = NULL;
2086 kfree(wl->nvs);
2087 wl->nvs = NULL;
2088
2089 kfree(wl->fw_status);
2090 kfree(wl->tx_res_if);
2091
2092 ieee80211_free_hw(wl->hw);
2093
2094 return 0;
2095}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002096EXPORT_SYMBOL_GPL(wl1271_free_hw);
2097
2098MODULE_LICENSE("GPL");
2099MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2100MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");