blob: 5c32d8d723612fcbc1220ab6fe66b65d27e915c7 [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>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020032#include <linux/platform_device.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030033
34#include "wl1271.h"
35#include "wl12xx_80211.h"
36#include "wl1271_reg.h"
Teemu Paasikivi7b048c52010-02-18 13:25:55 +020037#include "wl1271_io.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030038#include "wl1271_event.h"
39#include "wl1271_tx.h"
40#include "wl1271_rx.h"
41#include "wl1271_ps.h"
42#include "wl1271_init.h"
43#include "wl1271_debugfs.h"
44#include "wl1271_cmd.h"
45#include "wl1271_boot.h"
Kalle Valoc8c90872010-02-18 13:25:53 +020046#include "wl1271_testmode.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030047
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020048#define WL1271_BOOT_RETRIES 3
49
Juuso Oikarinen8a080482009-10-13 12:47:44 +030050static struct conf_drv_settings default_conf = {
51 .sg = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020052 .params = {
53 [CONF_SG_BT_PER_THRESHOLD] = 7500,
54 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
55 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
56 [CONF_SG_BT_LOAD_RATIO] = 50,
57 [CONF_SG_AUTO_PS_MODE] = 0,
58 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
59 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
60 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
61 [CONF_SG_BEACON_MISS_PERCENT] = 60,
62 [CONF_SG_RATE_ADAPT_THRESH] = 12,
63 [CONF_SG_RATE_ADAPT_SNR] = 0,
64 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
65 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
66 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
67 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
68 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
69 /* Note: with UPSD, this should be 4 */
70 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
71 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
72 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
73 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
74 /* Note: with UPDS, this should be 15 */
75 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
76 /* Note: with UPDS, this should be 50 */
77 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
78 /* Note: with UPDS, this should be 10 */
79 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
80 [CONF_SG_RXT] = 1200,
81 [CONF_SG_TXT] = 1000,
82 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
83 [CONF_SG_PS_POLL_TIMEOUT] = 10,
84 [CONF_SG_UPSD_TIMEOUT] = 10,
85 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
86 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
87 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
88 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
89 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
90 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
91 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
92 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
93 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
94 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
95 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
96 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
97 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
98 [CONF_SG_HV3_MAX_SERVED] = 6,
99 [CONF_SG_DHCP_TIME] = 5000,
100 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
101 },
102 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300103 },
104 .rx = {
105 .rx_msdu_life_time = 512000,
106 .packet_detection_threshold = 0,
107 .ps_poll_timeout = 15,
108 .upsd_timeout = 15,
109 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200110 .rx_cca_threshold = 0,
111 .irq_blk_threshold = 0xFFFF,
112 .irq_pkt_threshold = 0,
113 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300114 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
115 },
116 .tx = {
117 .tx_energy_detection = 0,
118 .rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300119 .enabled_rates = 0,
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,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300216 .tx_compl_threshold = 4,
217 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
218 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300219 },
220 .conn = {
221 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300222 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300223 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
224 .bcn_filt_ie_count = 1,
225 .bcn_filt_ie = {
226 [0] = {
227 .ie = WLAN_EID_CHANNEL_SWITCH,
228 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
229 }
230 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200231 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300232 .bss_lose_timeout = 100,
233 .beacon_rx_timeout = 10000,
234 .broadcast_timeout = 20000,
235 .rx_broadcast_in_ps = 1,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200236 .ps_poll_threshold = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300237 .sig_trigger_count = 2,
238 .sig_trigger = {
239 [0] = {
240 .threshold = -75,
241 .pacing = 500,
242 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
243 .type = CONF_TRIG_EVENT_TYPE_EDGE,
244 .direction = CONF_TRIG_EVENT_DIR_LOW,
245 .hysteresis = 2,
246 .index = 0,
247 .enable = 1
248 },
249 [1] = {
250 .threshold = -75,
251 .pacing = 500,
252 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
253 .type = CONF_TRIG_EVENT_TYPE_EDGE,
254 .direction = CONF_TRIG_EVENT_DIR_HIGH,
255 .hysteresis = 2,
256 .index = 1,
257 .enable = 1
258 }
259 },
260 .sig_weights = {
261 .rssi_bcn_avg_weight = 10,
262 .rssi_pkt_avg_weight = 10,
263 .snr_bcn_avg_weight = 10,
264 .snr_pkt_avg_weight = 10
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300265 },
266 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200267 .bet_max_consecutive = 10,
Juuso Oikarinenc1899552010-03-26 12:53:32 +0200268 .psm_entry_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300269 .keep_alive_interval = 55000,
270 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300271 },
272 .init = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300273 .radioparam = {
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200274 .fem = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300275 }
Luciano Coelho6e92b412009-12-11 15:40:50 +0200276 },
277 .itrim = {
278 .enable = false,
279 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200280 },
281 .pm_config = {
282 .host_clk_settling_time = 5000,
283 .host_fast_wakeup_support = false
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300284 }
285};
286
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200287static void wl1271_device_release(struct device *dev)
288{
289
290}
291
292static struct platform_device wl1271_device = {
293 .name = "wl1271",
294 .id = -1,
295
296 /* device model insists to have a release function */
297 .dev = {
298 .release = wl1271_device_release,
299 },
300};
301
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300302static LIST_HEAD(wl_list);
303
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300304static void wl1271_conf_init(struct wl1271 *wl)
305{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300306
307 /*
308 * This function applies the default configuration to the driver. This
309 * function is invoked upon driver load (spi probe.)
310 *
311 * The configuration is stored in a run-time structure in order to
312 * facilitate for run-time adjustment of any of the parameters. Making
313 * changes to the configuration structure will apply the new values on
314 * the next interface up (wl1271_op_start.)
315 */
316
317 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300318 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300319}
320
321
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300322static int wl1271_plt_init(struct wl1271 *wl)
323{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200324 struct conf_tx_ac_category *conf_ac;
325 struct conf_tx_tid *conf_tid;
326 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300327
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200328 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200329 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200330 return ret;
331
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200332 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200333 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200334 return ret;
335
Luciano Coelho12419cc2010-02-18 13:25:44 +0200336 ret = wl1271_init_templates_config(wl);
337 if (ret < 0)
338 return ret;
339
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300340 ret = wl1271_acx_init_mem_config(wl);
341 if (ret < 0)
342 return ret;
343
Luciano Coelho12419cc2010-02-18 13:25:44 +0200344 /* PHY layer config */
345 ret = wl1271_init_phy_config(wl);
346 if (ret < 0)
347 goto out_free_memmap;
348
349 ret = wl1271_acx_dco_itrim_params(wl);
350 if (ret < 0)
351 goto out_free_memmap;
352
353 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200354 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200355 if (ret < 0)
356 goto out_free_memmap;
357
358 /* Bluetooth WLAN coexistence */
359 ret = wl1271_init_pta(wl);
360 if (ret < 0)
361 goto out_free_memmap;
362
363 /* Energy detection */
364 ret = wl1271_init_energy_detection(wl);
365 if (ret < 0)
366 goto out_free_memmap;
367
368 /* Default fragmentation threshold */
369 ret = wl1271_acx_frag_threshold(wl);
370 if (ret < 0)
371 goto out_free_memmap;
372
373 /* Default TID configuration */
374 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
375 conf_tid = &wl->conf.tx.tid_conf[i];
376 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
377 conf_tid->channel_type,
378 conf_tid->tsid,
379 conf_tid->ps_scheme,
380 conf_tid->ack_policy,
381 conf_tid->apsd_conf[0],
382 conf_tid->apsd_conf[1]);
383 if (ret < 0)
384 goto out_free_memmap;
385 }
386
387 /* Default AC configuration */
388 for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
389 conf_ac = &wl->conf.tx.ac_conf[i];
390 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
391 conf_ac->cw_max, conf_ac->aifsn,
392 conf_ac->tx_op_limit);
393 if (ret < 0)
394 goto out_free_memmap;
395 }
396
397 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200398 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300399 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200400 goto out_free_memmap;
401
402 /* Configure for CAM power saving (ie. always active) */
403 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
404 if (ret < 0)
405 goto out_free_memmap;
406
407 /* configure PM */
408 ret = wl1271_acx_pm_config(wl);
409 if (ret < 0)
410 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300411
412 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200413
414 out_free_memmap:
415 kfree(wl->target_mem_map);
416 wl->target_mem_map = NULL;
417
418 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300419}
420
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300421static void wl1271_fw_status(struct wl1271 *wl,
422 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300423{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200424 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300425 u32 total = 0;
426 int i;
427
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200428 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300429
430 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
431 "drv_rx_counter = %d, tx_results_counter = %d)",
432 status->intr,
433 status->fw_rx_counter,
434 status->drv_rx_counter,
435 status->tx_results_counter);
436
437 /* update number of available TX blocks */
438 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300439 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
440 wl->tx_blocks_freed[i];
441
442 wl->tx_blocks_freed[i] =
443 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300444 wl->tx_blocks_available += cnt;
445 total += cnt;
446 }
447
448 /* if more blocks are available now, schedule some tx work */
449 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300450 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300451
452 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200453 getnstimeofday(&ts);
454 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
455 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300456}
457
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200458#define WL1271_IRQ_MAX_LOOPS 10
459
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300460static void wl1271_irq_work(struct work_struct *work)
461{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300462 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300463 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200464 int loopcount = WL1271_IRQ_MAX_LOOPS;
465 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300466 struct wl1271 *wl =
467 container_of(work, struct wl1271, irq_work);
468
469 mutex_lock(&wl->mutex);
470
471 wl1271_debug(DEBUG_IRQ, "IRQ work");
472
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200473 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300474 goto out;
475
476 ret = wl1271_ps_elp_wakeup(wl, true);
477 if (ret < 0)
478 goto out;
479
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200480 spin_lock_irqsave(&wl->wl_lock, flags);
481 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
482 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
483 spin_unlock_irqrestore(&wl->wl_lock, flags);
484 loopcount--;
485
486 wl1271_fw_status(wl, wl->fw_status);
487 intr = le32_to_cpu(wl->fw_status->intr);
488 if (!intr) {
489 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
490 continue;
491 }
492
493 intr &= WL1271_INTR_MASK;
494
495 if (intr & WL1271_ACX_INTR_DATA) {
496 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
497
498 /* check for tx results */
499 if (wl->fw_status->tx_results_counter !=
500 (wl->tx_results_count & 0xff))
501 wl1271_tx_complete(wl);
502
503 wl1271_rx(wl, wl->fw_status);
504 }
505
506 if (intr & WL1271_ACX_INTR_EVENT_A) {
507 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
508 wl1271_event_handle(wl, 0);
509 }
510
511 if (intr & WL1271_ACX_INTR_EVENT_B) {
512 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
513 wl1271_event_handle(wl, 1);
514 }
515
516 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
517 wl1271_debug(DEBUG_IRQ,
518 "WL1271_ACX_INTR_INIT_COMPLETE");
519
520 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
521 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
522
523 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300524 }
525
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200526 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
527 ieee80211_queue_work(wl->hw, &wl->irq_work);
528 else
529 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
530 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300531
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300532 wl1271_ps_elp_sleep(wl);
533
534out:
535 mutex_unlock(&wl->mutex);
536}
537
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300538static int wl1271_fetch_firmware(struct wl1271 *wl)
539{
540 const struct firmware *fw;
541 int ret;
542
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200543 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300544
545 if (ret < 0) {
546 wl1271_error("could not get firmware: %d", ret);
547 return ret;
548 }
549
550 if (fw->size % 4) {
551 wl1271_error("firmware size is not multiple of 32 bits: %zu",
552 fw->size);
553 ret = -EILSEQ;
554 goto out;
555 }
556
557 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300558 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300559
560 if (!wl->fw) {
561 wl1271_error("could not allocate memory for the firmware");
562 ret = -ENOMEM;
563 goto out;
564 }
565
566 memcpy(wl->fw, fw->data, wl->fw_len);
567
568 ret = 0;
569
570out:
571 release_firmware(fw);
572
573 return ret;
574}
575
576static int wl1271_fetch_nvs(struct wl1271 *wl)
577{
578 const struct firmware *fw;
579 int ret;
580
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200581 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300582
583 if (ret < 0) {
584 wl1271_error("could not get nvs file: %d", ret);
585 return ret;
586 }
587
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200588 if (fw->size != sizeof(struct wl1271_nvs_file)) {
589 wl1271_error("nvs size is not as expected: %zu != %zu",
590 fw->size, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300591 ret = -EILSEQ;
592 goto out;
593 }
594
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200595 wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300596
597 if (!wl->nvs) {
598 wl1271_error("could not allocate memory for the nvs file");
599 ret = -ENOMEM;
600 goto out;
601 }
602
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200603 memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300604
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300605out:
606 release_firmware(fw);
607
608 return ret;
609}
610
611static void wl1271_fw_wakeup(struct wl1271 *wl)
612{
613 u32 elp_reg;
614
615 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300616 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300617}
618
619static int wl1271_setup(struct wl1271 *wl)
620{
621 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
622 if (!wl->fw_status)
623 return -ENOMEM;
624
625 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
626 if (!wl->tx_res_if) {
627 kfree(wl->fw_status);
628 return -ENOMEM;
629 }
630
631 INIT_WORK(&wl->irq_work, wl1271_irq_work);
632 INIT_WORK(&wl->tx_work, wl1271_tx_work);
633 return 0;
634}
635
636static int wl1271_chip_wakeup(struct wl1271 *wl)
637{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300638 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300639 int ret = 0;
640
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200641 msleep(WL1271_PRE_POWER_ON_SLEEP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300642 wl1271_power_on(wl);
643 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200644 wl1271_io_reset(wl);
645 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300646
647 /* We don't need a real memory partition here, because we only want
648 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300649 memset(&partition, 0, sizeof(partition));
650 partition.reg.start = REGISTERS_BASE;
651 partition.reg.size = REGISTERS_DOWN_SIZE;
652 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300653
654 /* ELP module wake up */
655 wl1271_fw_wakeup(wl);
656
657 /* whal_FwCtrl_BootSm() */
658
659 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200660 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300661
662 /* 1. check if chip id is valid */
663
664 switch (wl->chip.id) {
665 case CHIP_ID_1271_PG10:
666 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
667 wl->chip.id);
668
669 ret = wl1271_setup(wl);
670 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200671 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300672 break;
673 case CHIP_ID_1271_PG20:
674 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
675 wl->chip.id);
676
677 ret = wl1271_setup(wl);
678 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200679 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300680 break;
681 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200682 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300683 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200684 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300685 }
686
687 if (wl->fw == NULL) {
688 ret = wl1271_fetch_firmware(wl);
689 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200690 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300691 }
692
693 /* No NVS from netlink, try to get it from the filesystem */
694 if (wl->nvs == NULL) {
695 ret = wl1271_fetch_nvs(wl);
696 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200697 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300698 }
699
700out:
701 return ret;
702}
703
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300704int wl1271_plt_start(struct wl1271 *wl)
705{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200706 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300707 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
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200720 while (retries) {
721 retries--;
722 ret = wl1271_chip_wakeup(wl);
723 if (ret < 0)
724 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300725
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200726 ret = wl1271_boot(wl);
727 if (ret < 0)
728 goto power_off;
729
730 ret = wl1271_plt_init(wl);
731 if (ret < 0)
732 goto irq_disable;
733
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200734 wl->state = WL1271_STATE_PLT;
735 wl1271_notice("firmware booted in PLT mode (%s)",
736 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300737 goto out;
738
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200739irq_disable:
740 wl1271_disable_interrupts(wl);
741 mutex_unlock(&wl->mutex);
742 /* Unlocking the mutex in the middle of handling is
743 inherently unsafe. In this case we deem it safe to do,
744 because we need to let any possibly pending IRQ out of
745 the system (and while we are WL1271_STATE_OFF the IRQ
746 work function will not do anything.) Also, any other
747 possible concurrent operations will fail due to the
748 current state, hence the wl1271 struct should be safe. */
749 cancel_work_sync(&wl->irq_work);
750 mutex_lock(&wl->mutex);
751power_off:
752 wl1271_power_off(wl);
753 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300754
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200755 wl1271_error("firmware boot in PLT mode failed despite %d retries",
756 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300757out:
758 mutex_unlock(&wl->mutex);
759
760 return ret;
761}
762
763int wl1271_plt_stop(struct wl1271 *wl)
764{
765 int ret = 0;
766
767 mutex_lock(&wl->mutex);
768
769 wl1271_notice("power down");
770
771 if (wl->state != WL1271_STATE_PLT) {
772 wl1271_error("cannot power down because not in PLT "
773 "state: %d", wl->state);
774 ret = -EBUSY;
775 goto out;
776 }
777
778 wl1271_disable_interrupts(wl);
779 wl1271_power_off(wl);
780
781 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300782 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300783
784out:
785 mutex_unlock(&wl->mutex);
786
787 return ret;
788}
789
790
791static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
792{
793 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200794 struct ieee80211_conf *conf = &hw->conf;
795 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
796 struct ieee80211_sta *sta = txinfo->control.sta;
797 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300798
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200799 /* peek into the rates configured in the STA entry */
800 spin_lock_irqsave(&wl->wl_lock, flags);
801 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
802 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
803 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
804 }
805 spin_unlock_irqrestore(&wl->wl_lock, flags);
806
807 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300808 skb_queue_tail(&wl->tx_queue, skb);
809
810 /*
811 * The chip specific setup must run before the first TX packet -
812 * before that, the tx_work will not be initialized!
813 */
814
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300815 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300816
817 /*
818 * The workqueue is slow to process the tx_queue and we need stop
819 * the queue here, otherwise the queue will get too long.
820 */
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200821 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
822 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300823
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200824 spin_lock_irqsave(&wl->wl_lock, flags);
825 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200826 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200827 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300828 }
829
830 return NETDEV_TX_OK;
831}
832
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300833static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
834 void *arg)
835{
836 struct net_device *dev;
837 struct wireless_dev *wdev;
838 struct wiphy *wiphy;
839 struct ieee80211_hw *hw;
840 struct wl1271 *wl;
841 struct wl1271 *wl_temp;
842 struct in_device *idev;
843 struct in_ifaddr *ifa = arg;
844 int ret = 0;
845
846 /* FIXME: this ugly function should probably be implemented in the
847 * mac80211, and here should only be a simple callback handling actual
848 * setting of the filters. Now we need to dig up references to
849 * various structures to gain access to what we need.
850 * Also, because of this, there is no "initial" setting of the filter
851 * in "op_start", because we don't want to dig up struct net_device
852 * there - the filter will be set upon first change of the interface
853 * IP address. */
854
855 dev = ifa->ifa_dev->dev;
856
857 wdev = dev->ieee80211_ptr;
858 if (wdev == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200859 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300860
861 wiphy = wdev->wiphy;
862 if (wiphy == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200863 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300864
865 hw = wiphy_priv(wiphy);
866 if (hw == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200867 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300868
869 /* Check that the interface is one supported by this driver. */
870 wl_temp = hw->priv;
871 list_for_each_entry(wl, &wl_list, list) {
872 if (wl == wl_temp)
873 break;
874 }
875 if (wl == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200876 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300877
878 /* Get the interface IP address for the device. "ifa" will become
879 NULL if:
880 - there is no IPV4 protocol address configured
881 - there are multiple (virtual) IPV4 addresses configured
882 When "ifa" is NULL, filtering will be disabled.
883 */
884 ifa = NULL;
885 idev = dev->ip_ptr;
886 if (idev)
887 ifa = idev->ifa_list;
888
889 if (ifa && ifa->ifa_next)
890 ifa = NULL;
891
892 mutex_lock(&wl->mutex);
893
894 if (wl->state == WL1271_STATE_OFF)
895 goto out;
896
897 ret = wl1271_ps_elp_wakeup(wl, false);
898 if (ret < 0)
899 goto out;
900 if (ifa)
901 ret = wl1271_acx_arp_ip_filter(wl, true,
902 (u8 *)&ifa->ifa_address,
903 ACX_IPV4_VERSION);
904 else
905 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
906 ACX_IPV4_VERSION);
907 wl1271_ps_elp_sleep(wl);
908
909out:
910 mutex_unlock(&wl->mutex);
911
Luciano Coelho17d72652009-11-23 23:22:15 +0200912 return NOTIFY_OK;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300913}
914
915static struct notifier_block wl1271_dev_notifier = {
916 .notifier_call = wl1271_dev_notify,
917};
918
919
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300920static int wl1271_op_start(struct ieee80211_hw *hw)
921{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200922 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
923
924 /*
925 * We have to delay the booting of the hardware because
926 * we need to know the local MAC address before downloading and
927 * initializing the firmware. The MAC address cannot be changed
928 * after boot, and without the proper MAC address, the firmware
929 * will not function properly.
930 *
931 * The MAC address is first known when the corresponding interface
932 * is added. That is where we will initialize the hardware.
933 */
934
935 return 0;
936}
937
938static void wl1271_op_stop(struct ieee80211_hw *hw)
939{
940 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
941}
942
943static int wl1271_op_add_interface(struct ieee80211_hw *hw,
944 struct ieee80211_vif *vif)
945{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300946 struct wl1271 *wl = hw->priv;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200947 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300948 int ret = 0;
949
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200950 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
951 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300952
953 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200954 if (wl->vif) {
955 ret = -EBUSY;
956 goto out;
957 }
958
959 wl->vif = vif;
960
961 switch (vif->type) {
962 case NL80211_IFTYPE_STATION:
963 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200964 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200965 break;
966 case NL80211_IFTYPE_ADHOC:
967 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200968 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200969 break;
970 default:
971 ret = -EOPNOTSUPP;
972 goto out;
973 }
974
975 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300976
977 if (wl->state != WL1271_STATE_OFF) {
978 wl1271_error("cannot start because not in off state: %d",
979 wl->state);
980 ret = -EBUSY;
981 goto out;
982 }
983
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200984 while (retries) {
985 retries--;
986 ret = wl1271_chip_wakeup(wl);
987 if (ret < 0)
988 goto power_off;
989
990 ret = wl1271_boot(wl);
991 if (ret < 0)
992 goto power_off;
993
994 ret = wl1271_hw_init(wl);
995 if (ret < 0)
996 goto irq_disable;
997
998 wl->state = WL1271_STATE_ON;
999 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001000 goto out;
1001
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001002irq_disable:
1003 wl1271_disable_interrupts(wl);
1004 mutex_unlock(&wl->mutex);
1005 /* Unlocking the mutex in the middle of handling is
1006 inherently unsafe. In this case we deem it safe to do,
1007 because we need to let any possibly pending IRQ out of
1008 the system (and while we are WL1271_STATE_OFF the IRQ
1009 work function will not do anything.) Also, any other
1010 possible concurrent operations will fail due to the
1011 current state, hence the wl1271 struct should be safe. */
1012 cancel_work_sync(&wl->irq_work);
1013 mutex_lock(&wl->mutex);
1014power_off:
1015 wl1271_power_off(wl);
1016 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001017
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001018 wl1271_error("firmware boot failed despite %d retries",
1019 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001020out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001021 mutex_unlock(&wl->mutex);
1022
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001023 if (!ret) {
1024 list_add(&wl->list, &wl_list);
1025 register_inetaddr_notifier(&wl1271_dev_notifier);
1026 }
1027
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001028 return ret;
1029}
1030
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001031static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1032 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001033{
1034 struct wl1271 *wl = hw->priv;
1035 int i;
1036
Juuso Oikarinen2ea9fb32010-03-18 12:26:45 +02001037 unregister_inetaddr_notifier(&wl1271_dev_notifier);
1038
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001039 mutex_lock(&wl->mutex);
1040 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001041
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001042 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001043
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001044 list_del(&wl->list);
1045
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001046 WARN_ON(wl->state != WL1271_STATE_ON);
1047
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001048 if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001049 mutex_unlock(&wl->mutex);
1050 ieee80211_scan_completed(wl->hw, true);
1051 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001052 }
1053
1054 wl->state = WL1271_STATE_OFF;
1055
1056 wl1271_disable_interrupts(wl);
1057
1058 mutex_unlock(&wl->mutex);
1059
1060 cancel_work_sync(&wl->irq_work);
1061 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001062
1063 mutex_lock(&wl->mutex);
1064
1065 /* let's notify MAC80211 about the remaining pending TX frames */
1066 wl1271_tx_flush(wl);
1067 wl1271_power_off(wl);
1068
1069 memset(wl->bssid, 0, ETH_ALEN);
1070 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1071 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001072 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001073 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001074 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001075
1076 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001077 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001078 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1079 wl->tx_blocks_available = 0;
1080 wl->tx_results_count = 0;
1081 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001082 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001083 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001084 wl->time_offset = 0;
1085 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001086 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1087 wl->sta_rate_set = 0;
1088 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001089 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001090 wl->filters = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001091
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001092 for (i = 0; i < NUM_TX_QUEUES; i++)
1093 wl->tx_blocks_freed[i] = 0;
1094
1095 wl1271_debugfs_reset(wl);
1096 mutex_unlock(&wl->mutex);
1097}
1098
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001099static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1100{
1101 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1102 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1103
1104 /* combine requested filters with current filter config */
1105 filters = wl->filters | filters;
1106
1107 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1108
1109 if (filters & FIF_PROMISC_IN_BSS) {
1110 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1111 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1112 wl->rx_config |= CFG_BSSID_FILTER_EN;
1113 }
1114 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1115 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1116 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1117 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1118 }
1119 if (filters & FIF_OTHER_BSS) {
1120 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1121 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1122 }
1123 if (filters & FIF_CONTROL) {
1124 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1125 wl->rx_filter |= CFG_RX_CTL_EN;
1126 }
1127 if (filters & FIF_FCSFAIL) {
1128 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1129 wl->rx_filter |= CFG_RX_FCS_ERROR;
1130 }
1131}
1132
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001133static int wl1271_join_channel(struct wl1271 *wl, int channel)
1134{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001135 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001136 /* 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
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001140 wl->channel = channel;
1141 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1142
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001143 /* pass through frames from all BSS */
1144 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1145
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001146 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001147 if (ret < 0)
1148 goto out;
1149
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001150 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001151
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
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001165 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001166 wl->channel = 0;
1167 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001168
1169 /* stop filterting packets based on bssid */
1170 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001171
1172out:
1173 return ret;
1174}
1175
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001176static void wl1271_set_band_rate(struct wl1271 *wl)
1177{
1178 if (wl->band == IEEE80211_BAND_2GHZ)
1179 wl->basic_rate_set = wl->conf.tx.basic_rate;
1180 else
1181 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1182}
1183
1184static u32 wl1271_min_rate_get(struct wl1271 *wl)
1185{
1186 int i;
1187 u32 rate = 0;
1188
1189 if (!wl->basic_rate_set) {
1190 WARN_ON(1);
1191 wl->basic_rate_set = wl->conf.tx.basic_rate;
1192 }
1193
1194 for (i = 0; !rate; i++) {
1195 if ((wl->basic_rate_set >> i) & 0x1)
1196 rate = 1 << i;
1197 }
1198
1199 return rate;
1200}
1201
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001202static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1203{
1204 struct wl1271 *wl = hw->priv;
1205 struct ieee80211_conf *conf = &hw->conf;
1206 int channel, ret = 0;
1207
1208 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1209
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001210 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001211 channel,
1212 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001213 conf->power_level,
1214 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001215
1216 mutex_lock(&wl->mutex);
1217
1218 ret = wl1271_ps_elp_wakeup(wl, false);
1219 if (ret < 0)
1220 goto out;
1221
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001222 /* if the channel changes while joined, join again */
1223 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
1224 wl->band = conf->channel->band;
1225 wl->channel = channel;
1226
1227 /*
1228 * FIXME: the mac80211 should really provide a fixed rate
1229 * to use here. for now, just use the smallest possible rate
1230 * for the band as a fixed rate for association frames and
1231 * other control messages.
1232 */
1233 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1234 wl1271_set_band_rate(wl);
1235
1236 wl->basic_rate = wl1271_min_rate_get(wl);
1237 ret = wl1271_acx_rate_policies(wl);
1238 if (ret < 0)
1239 wl1271_warning("rate policy for update channel "
1240 "failed %d", ret);
1241
1242 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1243 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1244 if (ret < 0)
1245 wl1271_warning("cmd join to update channel "
1246 "failed %d", ret);
1247 }
1248 }
1249
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001250 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001251 if (conf->flags & IEEE80211_CONF_IDLE &&
1252 test_bit(WL1271_FLAG_JOINED, &wl->flags))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001253 wl1271_unjoin_channel(wl);
Juuso Oikarinen8f648c02009-12-11 15:41:10 +02001254 else if (!(conf->flags & IEEE80211_CONF_IDLE))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001255 wl1271_join_channel(wl, channel);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001256
1257 if (conf->flags & IEEE80211_CONF_IDLE) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001258 wl->rate_set = wl1271_min_rate_get(wl);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001259 wl->sta_rate_set = 0;
1260 wl1271_acx_rate_policies(wl);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001261 wl1271_acx_keep_alive_config(
1262 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1263 ACX_KEEP_ALIVE_TPL_INVALID);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001264 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001265 }
1266
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001267 if (conf->flags & IEEE80211_CONF_PS &&
1268 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1269 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001270
1271 /*
1272 * We enter PSM only if we're already associated.
1273 * If we're not, we'll enter it when joining an SSID,
1274 * through the bss_info_changed() hook.
1275 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001276 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001277 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001278 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1279 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001280 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001281 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001282 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001283 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001284
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001285 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001286
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001287 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001288 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1289 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001290 }
1291
1292 if (conf->power_level != wl->power_level) {
1293 ret = wl1271_acx_tx_power(wl, conf->power_level);
1294 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001295 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001296
1297 wl->power_level = conf->power_level;
1298 }
1299
1300out_sleep:
1301 wl1271_ps_elp_sleep(wl);
1302
1303out:
1304 mutex_unlock(&wl->mutex);
1305
1306 return ret;
1307}
1308
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001309struct wl1271_filter_params {
1310 bool enabled;
1311 int mc_list_length;
1312 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1313};
1314
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001315static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1316 struct dev_addr_list *mc_list)
1317{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001318 struct wl1271_filter_params *fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001319 int i;
1320
Juuso Oikarinen74441132009-10-13 12:47:53 +03001321 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001322 if (!fp) {
1323 wl1271_error("Out of memory setting filters.");
1324 return 0;
1325 }
1326
1327 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001328 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001329 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1330 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001331 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001332 }
1333
1334 fp->mc_list_length = 0;
1335 for (i = 0; i < mc_count; i++) {
1336 if (mc_list->da_addrlen == ETH_ALEN) {
1337 memcpy(fp->mc_list[fp->mc_list_length],
1338 mc_list->da_addr, ETH_ALEN);
1339 fp->mc_list_length++;
1340 } else
1341 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001342 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001343 }
1344
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001345 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001346}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001347
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001348#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1349 FIF_ALLMULTI | \
1350 FIF_FCSFAIL | \
1351 FIF_BCN_PRBRESP_PROMISC | \
1352 FIF_CONTROL | \
1353 FIF_OTHER_BSS)
1354
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001355static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1356 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001357 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001358{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001359 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001360 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001361 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001362
1363 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1364
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001365 mutex_lock(&wl->mutex);
1366
1367 if (wl->state == WL1271_STATE_OFF)
1368 goto out;
1369
1370 ret = wl1271_ps_elp_wakeup(wl, false);
1371 if (ret < 0)
1372 goto out;
1373
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001374 *total &= WL1271_SUPPORTED_FILTERS;
1375 changed &= WL1271_SUPPORTED_FILTERS;
1376
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001377 if (*total & FIF_ALLMULTI)
1378 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1379 else if (fp)
1380 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1381 fp->mc_list,
1382 fp->mc_list_length);
1383 if (ret < 0)
1384 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001385
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001386 /* determine, whether supported filter values have changed */
1387 if (changed == 0)
1388 goto out_sleep;
1389
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001390 /* configure filters */
1391 wl->filters = *total;
1392 wl1271_configure_filters(wl, 0);
1393
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001394 /* apply configured filters */
1395 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1396 if (ret < 0)
1397 goto out_sleep;
1398
1399out_sleep:
1400 wl1271_ps_elp_sleep(wl);
1401
1402out:
1403 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001404 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001405}
1406
1407static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1408 struct ieee80211_vif *vif,
1409 struct ieee80211_sta *sta,
1410 struct ieee80211_key_conf *key_conf)
1411{
1412 struct wl1271 *wl = hw->priv;
1413 const u8 *addr;
1414 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001415 u32 tx_seq_32 = 0;
1416 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001417 u8 key_type;
1418
1419 static const u8 bcast_addr[ETH_ALEN] =
1420 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1421
1422 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1423
1424 addr = sta ? sta->addr : bcast_addr;
1425
1426 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1427 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1428 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1429 key_conf->alg, key_conf->keyidx,
1430 key_conf->keylen, key_conf->flags);
1431 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1432
1433 if (is_zero_ether_addr(addr)) {
1434 /* We dont support TX only encryption */
1435 ret = -EOPNOTSUPP;
1436 goto out;
1437 }
1438
1439 mutex_lock(&wl->mutex);
1440
1441 ret = wl1271_ps_elp_wakeup(wl, false);
1442 if (ret < 0)
1443 goto out_unlock;
1444
1445 switch (key_conf->alg) {
1446 case ALG_WEP:
1447 key_type = KEY_WEP;
1448
1449 key_conf->hw_key_idx = key_conf->keyidx;
1450 break;
1451 case ALG_TKIP:
1452 key_type = KEY_TKIP;
1453
1454 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001455 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1456 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001457 break;
1458 case ALG_CCMP:
1459 key_type = KEY_AES;
1460
1461 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001462 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1463 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001464 break;
1465 default:
1466 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1467
1468 ret = -EOPNOTSUPP;
1469 goto out_sleep;
1470 }
1471
1472 switch (cmd) {
1473 case SET_KEY:
1474 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1475 key_conf->keyidx, key_type,
1476 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001477 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001478 if (ret < 0) {
1479 wl1271_error("Could not add or replace key");
1480 goto out_sleep;
1481 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001482
1483 /* the default WEP key needs to be configured at least once */
1484 if (key_type == KEY_WEP) {
1485 ret = wl1271_cmd_set_default_wep_key(wl,
1486 wl->default_key);
1487 if (ret < 0)
1488 goto out_sleep;
1489 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001490 break;
1491
1492 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001493 /* The wl1271 does not allow to remove unicast keys - they
1494 will be cleared automatically on next CMD_JOIN. Ignore the
1495 request silently, as we dont want the mac80211 to emit
1496 an error message. */
1497 if (!is_broadcast_ether_addr(addr))
1498 break;
1499
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001500 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1501 key_conf->keyidx, key_type,
1502 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001503 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001504 if (ret < 0) {
1505 wl1271_error("Could not remove key");
1506 goto out_sleep;
1507 }
1508 break;
1509
1510 default:
1511 wl1271_error("Unsupported key cmd 0x%x", cmd);
1512 ret = -EOPNOTSUPP;
1513 goto out_sleep;
1514
1515 break;
1516 }
1517
1518out_sleep:
1519 wl1271_ps_elp_sleep(wl);
1520
1521out_unlock:
1522 mutex_unlock(&wl->mutex);
1523
1524out:
1525 return ret;
1526}
1527
1528static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1529 struct cfg80211_scan_request *req)
1530{
1531 struct wl1271 *wl = hw->priv;
1532 int ret;
1533 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001534 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001535
1536 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1537
1538 if (req->n_ssids) {
1539 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001540 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001541 }
1542
1543 mutex_lock(&wl->mutex);
1544
1545 ret = wl1271_ps_elp_wakeup(wl, false);
1546 if (ret < 0)
1547 goto out;
1548
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001549 if (wl1271_11a_enabled())
Kalle Valo818e3062010-03-18 12:26:35 +02001550 ret = wl1271_cmd_scan(hw->priv, ssid, len,
1551 req->ie, req->ie_len, 1, 0,
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001552 WL1271_SCAN_BAND_DUAL, 3);
1553 else
Kalle Valo818e3062010-03-18 12:26:35 +02001554 ret = wl1271_cmd_scan(hw->priv, ssid, len,
1555 req->ie, req->ie_len, 1, 0,
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001556 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001557
1558 wl1271_ps_elp_sleep(wl);
1559
1560out:
1561 mutex_unlock(&wl->mutex);
1562
1563 return ret;
1564}
1565
1566static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1567{
1568 struct wl1271 *wl = hw->priv;
1569 int ret;
1570
1571 mutex_lock(&wl->mutex);
1572
1573 ret = wl1271_ps_elp_wakeup(wl, false);
1574 if (ret < 0)
1575 goto out;
1576
1577 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1578 if (ret < 0)
1579 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1580
1581 wl1271_ps_elp_sleep(wl);
1582
1583out:
1584 mutex_unlock(&wl->mutex);
1585
1586 return ret;
1587}
1588
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001589static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1590{
1591 u8 *ptr = beacon->data +
1592 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1593
1594 /* find the location of the ssid in the beacon */
1595 while (ptr < beacon->data + beacon->len) {
1596 if (ptr[0] == WLAN_EID_SSID) {
1597 wl->ssid_len = ptr[1];
1598 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1599 return;
1600 }
1601 ptr += ptr[1];
1602 }
1603 wl1271_error("ad-hoc beacon template has no SSID!\n");
1604}
1605
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001606static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1607 struct ieee80211_vif *vif,
1608 struct ieee80211_bss_conf *bss_conf,
1609 u32 changed)
1610{
1611 enum wl1271_cmd_ps_mode mode;
1612 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001613 bool do_join = false;
Juuso Oikarinen40b359c2010-04-01 11:38:19 +03001614 bool do_keepalive = 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 Oikarinen60e84c22010-03-26 12:53:25 +02001625 if ((changed && BSS_CHANGED_BEACON_INT) &&
1626 (wl->bss_type == BSS_TYPE_IBSS)) {
1627 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1628 bss_conf->beacon_int);
1629
1630 wl->beacon_int = bss_conf->beacon_int;
1631 do_join = true;
1632 }
1633
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001634 if ((changed && BSS_CHANGED_BEACON) &&
1635 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001636 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1637
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001638 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1639
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001640 if (beacon) {
1641 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001642
1643 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001644 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1645 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001646 beacon->len, 0,
1647 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001648
1649 if (ret < 0) {
1650 dev_kfree_skb(beacon);
1651 goto out_sleep;
1652 }
1653
1654 hdr = (struct ieee80211_hdr *) beacon->data;
1655 hdr->frame_control = cpu_to_le16(
1656 IEEE80211_FTYPE_MGMT |
1657 IEEE80211_STYPE_PROBE_RESP);
1658
1659 ret = wl1271_cmd_template_set(wl,
1660 CMD_TEMPL_PROBE_RESPONSE,
1661 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001662 beacon->len, 0,
1663 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001664 dev_kfree_skb(beacon);
1665 if (ret < 0)
1666 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001667
1668 /* Need to update the SSID (for filtering etc) */
1669 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001670 }
1671 }
1672
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001673 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1674 (wl->bss_type == BSS_TYPE_IBSS)) {
1675 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1676 bss_conf->enable_beacon ? "enabled" : "disabled");
1677
1678 if (bss_conf->enable_beacon)
1679 wl->set_bss_type = BSS_TYPE_IBSS;
1680 else
1681 wl->set_bss_type = BSS_TYPE_STA_BSS;
1682 do_join = true;
1683 }
1684
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001685 if ((changed & BSS_CHANGED_BSSID) &&
1686 /*
1687 * Now we know the correct bssid, so we send a new join command
1688 * and enable the BSSID filter
1689 */
1690 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001691 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001692
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001693 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001694 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001695 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001696
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001697 /* filter out all packets not from this BSSID */
1698 wl1271_configure_filters(wl, 0);
1699
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001700 /* Need to update the BSSID (for filtering etc) */
1701 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001702 }
1703
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001704 if (changed & BSS_CHANGED_ASSOC) {
1705 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001706 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001707 wl->aid = bss_conf->aid;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001708 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001709
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001710 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001711 * use basic rates from AP, and determine lowest rate
1712 * to use with control frames.
1713 */
1714 rates = bss_conf->basic_rates;
1715 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1716 rates);
1717 wl->basic_rate = wl1271_min_rate_get(wl);
1718 ret = wl1271_acx_rate_policies(wl);
1719 if (ret < 0)
1720 goto out_sleep;
1721
1722 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001723 * with wl1271, we don't need to update the
1724 * beacon_int and dtim_period, because the firmware
1725 * updates it by itself when the first beacon is
1726 * received after a join.
1727 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001728 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1729 if (ret < 0)
1730 goto out_sleep;
1731
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001732 /*
1733 * The SSID is intentionally set to NULL here - the
1734 * firmware will set the probe request with a
1735 * broadcast SSID regardless of what we set in the
1736 * template.
1737 */
1738 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1739 NULL, 0, wl->band);
1740
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001741 /* Enable the keep-alive feature */
1742 ret = wl1271_acx_keep_alive_mode(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001743 if (ret < 0)
1744 goto out_sleep;
1745
Juuso Oikarinen40b359c2010-04-01 11:38:19 +03001746 /*
1747 * This is awkward. The keep-alive configs must be done
1748 * *after* the join command, because otherwise it will
1749 * not work, but it must only be done *once* because
1750 * otherwise the firmware will start complaining.
1751 */
1752 do_keepalive = true;
1753
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001754 /* enable the connection monitoring feature */
1755 ret = wl1271_acx_conn_monit_params(wl, true);
1756 if (ret < 0)
1757 goto out_sleep;
1758
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001759 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001760 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1761 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001762 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001763 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001764 if (ret < 0)
1765 goto out_sleep;
1766 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001767 } else {
1768 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001769 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001770 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001771
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001772 /* revert back to minimum rates for the current band */
1773 wl1271_set_band_rate(wl);
1774 wl->basic_rate = wl1271_min_rate_get(wl);
1775 ret = wl1271_acx_rate_policies(wl);
1776 if (ret < 0)
1777 goto out_sleep;
1778
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001779 /* disable connection monitor features */
1780 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001781
1782 /* Disable the keep-alive feature */
1783 ret = wl1271_acx_keep_alive_mode(wl, false);
1784
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001785 if (ret < 0)
1786 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001787 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001788
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001789 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001790
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001791 if (changed & BSS_CHANGED_ERP_SLOT) {
1792 if (bss_conf->use_short_slot)
1793 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1794 else
1795 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1796 if (ret < 0) {
1797 wl1271_warning("Set slot time failed %d", ret);
1798 goto out_sleep;
1799 }
1800 }
1801
1802 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1803 if (bss_conf->use_short_preamble)
1804 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1805 else
1806 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1807 }
1808
1809 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1810 if (bss_conf->use_cts_prot)
1811 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1812 else
1813 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1814 if (ret < 0) {
1815 wl1271_warning("Set ctsprotect failed %d", ret);
1816 goto out_sleep;
1817 }
1818 }
1819
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001820 if (do_join) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001821 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001822 if (ret < 0) {
1823 wl1271_warning("cmd join failed %d", ret);
1824 goto out_sleep;
1825 }
1826 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1827 }
1828
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001829 /*
1830 * The JOIN operation shuts down the firmware keep-alive as a side
1831 * effect, and the ACX_AID will start the keep-alive as a side effect.
1832 * Hence, for non-IBSS, the ACX_AID must always happen *after* the
1833 * JOIN operation, and the template config after the ACX_AID.
1834 */
1835 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
1836 ret = wl1271_acx_aid(wl, wl->aid);
1837 if (ret < 0)
1838 goto out_sleep;
Juuso Oikarinen40b359c2010-04-01 11:38:19 +03001839 }
1840
1841 if (do_keepalive) {
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001842 ret = wl1271_cmd_build_klv_null_data(wl);
1843 if (ret < 0)
1844 goto out_sleep;
1845 ret = wl1271_acx_keep_alive_config(
1846 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1847 ACX_KEEP_ALIVE_TPL_VALID);
1848 if (ret < 0)
1849 goto out_sleep;
1850 }
1851
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001852out_sleep:
1853 wl1271_ps_elp_sleep(wl);
1854
1855out:
1856 mutex_unlock(&wl->mutex);
1857}
1858
Kalle Valoc6999d82010-02-18 13:25:41 +02001859static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1860 const struct ieee80211_tx_queue_params *params)
1861{
1862 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02001863 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02001864 int ret;
1865
1866 mutex_lock(&wl->mutex);
1867
1868 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1869
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001870 ret = wl1271_ps_elp_wakeup(wl, false);
1871 if (ret < 0)
1872 goto out;
1873
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001874 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001875 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1876 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001877 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001878 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001879 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001880
Kalle Valo4695dc92010-03-18 12:26:38 +02001881 if (params->uapsd)
1882 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
1883 else
1884 ps_scheme = CONF_PS_SCHEME_LEGACY;
1885
Kalle Valoc6999d82010-02-18 13:25:41 +02001886 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1887 CONF_CHANNEL_TYPE_EDCF,
1888 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02001889 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02001890 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001891 goto out_sleep;
1892
1893out_sleep:
1894 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001895
1896out:
1897 mutex_unlock(&wl->mutex);
1898
1899 return ret;
1900}
1901
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001902
1903/* can't be const, mac80211 writes to this */
1904static struct ieee80211_rate wl1271_rates[] = {
1905 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001906 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1907 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001908 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001909 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1910 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001911 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1912 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001913 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1914 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001915 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1916 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001917 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1918 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001919 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1920 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001921 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1922 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001923 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001924 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1925 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001926 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001927 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1928 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001929 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001930 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1931 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001932 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001933 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1934 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001935 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001936 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1937 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001938 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001939 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1940 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001941 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001942 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1943 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001944};
1945
1946/* can't be const, mac80211 writes to this */
1947static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001948 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1949 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1950 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1951 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1952 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1953 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1954 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1955 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1956 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1957 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1958 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1959 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1960 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001961};
1962
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02001963/* mapping to indexes for wl1271_rates */
1964const static u8 wl1271_rate_to_idx_2ghz[] = {
1965 /* MCS rates are used only with 11n */
1966 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
1967 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
1968 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
1969 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
1970 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
1971 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
1972 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
1973 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
1974
1975 11, /* CONF_HW_RXTX_RATE_54 */
1976 10, /* CONF_HW_RXTX_RATE_48 */
1977 9, /* CONF_HW_RXTX_RATE_36 */
1978 8, /* CONF_HW_RXTX_RATE_24 */
1979
1980 /* TI-specific rate */
1981 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
1982
1983 7, /* CONF_HW_RXTX_RATE_18 */
1984 6, /* CONF_HW_RXTX_RATE_12 */
1985 3, /* CONF_HW_RXTX_RATE_11 */
1986 5, /* CONF_HW_RXTX_RATE_9 */
1987 4, /* CONF_HW_RXTX_RATE_6 */
1988 2, /* CONF_HW_RXTX_RATE_5_5 */
1989 1, /* CONF_HW_RXTX_RATE_2 */
1990 0 /* CONF_HW_RXTX_RATE_1 */
1991};
1992
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001993/* can't be const, mac80211 writes to this */
1994static struct ieee80211_supported_band wl1271_band_2ghz = {
1995 .channels = wl1271_channels,
1996 .n_channels = ARRAY_SIZE(wl1271_channels),
1997 .bitrates = wl1271_rates,
1998 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1999};
2000
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002001/* 5 GHz data rates for WL1273 */
2002static struct ieee80211_rate wl1271_rates_5ghz[] = {
2003 { .bitrate = 60,
2004 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2005 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2006 { .bitrate = 90,
2007 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2008 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2009 { .bitrate = 120,
2010 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2011 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2012 { .bitrate = 180,
2013 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2014 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2015 { .bitrate = 240,
2016 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2017 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2018 { .bitrate = 360,
2019 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2020 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2021 { .bitrate = 480,
2022 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2023 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2024 { .bitrate = 540,
2025 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2026 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2027};
2028
2029/* 5 GHz band channels for WL1273 */
2030static struct ieee80211_channel wl1271_channels_5ghz[] = {
2031 { .hw_value = 183, .center_freq = 4915},
2032 { .hw_value = 184, .center_freq = 4920},
2033 { .hw_value = 185, .center_freq = 4925},
2034 { .hw_value = 187, .center_freq = 4935},
2035 { .hw_value = 188, .center_freq = 4940},
2036 { .hw_value = 189, .center_freq = 4945},
2037 { .hw_value = 192, .center_freq = 4960},
2038 { .hw_value = 196, .center_freq = 4980},
2039 { .hw_value = 7, .center_freq = 5035},
2040 { .hw_value = 8, .center_freq = 5040},
2041 { .hw_value = 9, .center_freq = 5045},
2042 { .hw_value = 11, .center_freq = 5055},
2043 { .hw_value = 12, .center_freq = 5060},
2044 { .hw_value = 16, .center_freq = 5080},
2045 { .hw_value = 34, .center_freq = 5170},
2046 { .hw_value = 36, .center_freq = 5180},
2047 { .hw_value = 38, .center_freq = 5190},
2048 { .hw_value = 40, .center_freq = 5200},
2049 { .hw_value = 42, .center_freq = 5210},
2050 { .hw_value = 44, .center_freq = 5220},
2051 { .hw_value = 46, .center_freq = 5230},
2052 { .hw_value = 48, .center_freq = 5240},
2053 { .hw_value = 52, .center_freq = 5260},
2054 { .hw_value = 56, .center_freq = 5280},
2055 { .hw_value = 60, .center_freq = 5300},
2056 { .hw_value = 64, .center_freq = 5320},
2057 { .hw_value = 100, .center_freq = 5500},
2058 { .hw_value = 104, .center_freq = 5520},
2059 { .hw_value = 108, .center_freq = 5540},
2060 { .hw_value = 112, .center_freq = 5560},
2061 { .hw_value = 116, .center_freq = 5580},
2062 { .hw_value = 120, .center_freq = 5600},
2063 { .hw_value = 124, .center_freq = 5620},
2064 { .hw_value = 128, .center_freq = 5640},
2065 { .hw_value = 132, .center_freq = 5660},
2066 { .hw_value = 136, .center_freq = 5680},
2067 { .hw_value = 140, .center_freq = 5700},
2068 { .hw_value = 149, .center_freq = 5745},
2069 { .hw_value = 153, .center_freq = 5765},
2070 { .hw_value = 157, .center_freq = 5785},
2071 { .hw_value = 161, .center_freq = 5805},
2072 { .hw_value = 165, .center_freq = 5825},
2073};
2074
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002075/* mapping to indexes for wl1271_rates_5ghz */
2076const static u8 wl1271_rate_to_idx_5ghz[] = {
2077 /* MCS rates are used only with 11n */
2078 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2079 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2080 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2081 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2082 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2083 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2084 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2085 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2086
2087 7, /* CONF_HW_RXTX_RATE_54 */
2088 6, /* CONF_HW_RXTX_RATE_48 */
2089 5, /* CONF_HW_RXTX_RATE_36 */
2090 4, /* CONF_HW_RXTX_RATE_24 */
2091
2092 /* TI-specific rate */
2093 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2094
2095 3, /* CONF_HW_RXTX_RATE_18 */
2096 2, /* CONF_HW_RXTX_RATE_12 */
2097 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2098 1, /* CONF_HW_RXTX_RATE_9 */
2099 0, /* CONF_HW_RXTX_RATE_6 */
2100 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2101 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2102 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2103};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002104
2105static struct ieee80211_supported_band wl1271_band_5ghz = {
2106 .channels = wl1271_channels_5ghz,
2107 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2108 .bitrates = wl1271_rates_5ghz,
2109 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
2110};
2111
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002112const static u8 *wl1271_band_rate_to_idx[] = {
2113 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2114 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2115};
2116
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002117static const struct ieee80211_ops wl1271_ops = {
2118 .start = wl1271_op_start,
2119 .stop = wl1271_op_stop,
2120 .add_interface = wl1271_op_add_interface,
2121 .remove_interface = wl1271_op_remove_interface,
2122 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002123 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002124 .configure_filter = wl1271_op_configure_filter,
2125 .tx = wl1271_op_tx,
2126 .set_key = wl1271_op_set_key,
2127 .hw_scan = wl1271_op_hw_scan,
2128 .bss_info_changed = wl1271_op_bss_info_changed,
2129 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002130 .conf_tx = wl1271_op_conf_tx,
Kalle Valoc8c90872010-02-18 13:25:53 +02002131 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002132};
2133
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002134
2135u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
2136{
2137 u8 idx;
2138
2139 BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
2140
2141 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2142 wl1271_error("Illegal RX rate from HW: %d", rate);
2143 return 0;
2144 }
2145
2146 idx = wl1271_band_rate_to_idx[wl->band][rate];
2147 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2148 wl1271_error("Unsupported RX rate from HW: %d", rate);
2149 return 0;
2150 }
2151
2152 return idx;
2153}
2154
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002155static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2156 struct device_attribute *attr,
2157 char *buf)
2158{
2159 struct wl1271 *wl = dev_get_drvdata(dev);
2160 ssize_t len;
2161
2162 /* FIXME: what's the maximum length of buf? page size?*/
2163 len = 500;
2164
2165 mutex_lock(&wl->mutex);
2166 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2167 wl->sg_enabled);
2168 mutex_unlock(&wl->mutex);
2169
2170 return len;
2171
2172}
2173
2174static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2175 struct device_attribute *attr,
2176 const char *buf, size_t count)
2177{
2178 struct wl1271 *wl = dev_get_drvdata(dev);
2179 unsigned long res;
2180 int ret;
2181
2182 ret = strict_strtoul(buf, 10, &res);
2183
2184 if (ret < 0) {
2185 wl1271_warning("incorrect value written to bt_coex_mode");
2186 return count;
2187 }
2188
2189 mutex_lock(&wl->mutex);
2190
2191 res = !!res;
2192
2193 if (res == wl->sg_enabled)
2194 goto out;
2195
2196 wl->sg_enabled = res;
2197
2198 if (wl->state == WL1271_STATE_OFF)
2199 goto out;
2200
2201 ret = wl1271_ps_elp_wakeup(wl, false);
2202 if (ret < 0)
2203 goto out;
2204
2205 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2206 wl1271_ps_elp_sleep(wl);
2207
2208 out:
2209 mutex_unlock(&wl->mutex);
2210 return count;
2211}
2212
2213static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2214 wl1271_sysfs_show_bt_coex_state,
2215 wl1271_sysfs_store_bt_coex_state);
2216
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002217int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002218{
2219 int ret;
2220
2221 if (wl->mac80211_registered)
2222 return 0;
2223
2224 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2225
2226 ret = ieee80211_register_hw(wl->hw);
2227 if (ret < 0) {
2228 wl1271_error("unable to register mac80211 hw: %d", ret);
2229 return ret;
2230 }
2231
2232 wl->mac80211_registered = true;
2233
2234 wl1271_notice("loaded");
2235
2236 return 0;
2237}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002238EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002239
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002240void wl1271_unregister_hw(struct wl1271 *wl)
2241{
2242 ieee80211_unregister_hw(wl->hw);
2243 wl->mac80211_registered = false;
2244
2245}
2246EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2247
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002248int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002249{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002250 /* The tx descriptor buffer and the TKIP space. */
2251 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2252 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002253
2254 /* unit us */
2255 /* FIXME: find a proper value */
2256 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002257 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002258
2259 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03002260 IEEE80211_HW_NOISE_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002261 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002262 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002263 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002264 IEEE80211_HW_HAS_RATE_CONTROL |
2265 IEEE80211_HW_CONNECTION_MONITOR;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002266
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002267 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2268 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002269 wl->hw->wiphy->max_scan_ssids = 1;
2270 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
2271
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002272 if (wl1271_11a_enabled())
2273 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
2274
Kalle Valo12bd8942010-03-18 12:26:33 +02002275 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002276 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002277
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002278 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002279
2280 return 0;
2281}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002282EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002283
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002284#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002285
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002286struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002287{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002288 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002289 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002290 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002291 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002292
2293 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2294 if (!hw) {
2295 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002296 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002297 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002298 }
2299
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002300 plat_dev = kmalloc(sizeof(wl1271_device), GFP_KERNEL);
2301 if (!plat_dev) {
2302 wl1271_error("could not allocate platform_device");
2303 ret = -ENOMEM;
2304 goto err_plat_alloc;
2305 }
2306
2307 memcpy(plat_dev, &wl1271_device, sizeof(wl1271_device));
2308
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002309 wl = hw->priv;
2310 memset(wl, 0, sizeof(*wl));
2311
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002312 INIT_LIST_HEAD(&wl->list);
2313
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002314 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002315 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002316
2317 skb_queue_head_init(&wl->tx_queue);
2318
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002319 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002320 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002321 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002322 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002323 wl->rx_counter = 0;
2324 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2325 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002326 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002327 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002328 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002329 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002330 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2331 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002332 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002333 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002334 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002335 wl->sg_enabled = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002336
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002337 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002338 wl->tx_frames[i] = NULL;
2339
2340 spin_lock_init(&wl->wl_lock);
2341
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002342 wl->state = WL1271_STATE_OFF;
2343 mutex_init(&wl->mutex);
2344
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002345 /* Apply default driver configuration. */
2346 wl1271_conf_init(wl);
2347
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002348 wl1271_debugfs_init(wl);
2349
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002350 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002351 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002352 if (ret) {
2353 wl1271_error("couldn't register platform device");
2354 goto err_hw;
2355 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002356 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002357
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002358 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002359 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002360 if (ret < 0) {
2361 wl1271_error("failed to create sysfs file bt_coex_state");
2362 goto err_platform;
2363 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002364
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002365 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002366
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002367err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002368 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002369
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002370err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002371 wl1271_debugfs_exit(wl);
2372 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002373
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002374err_plat_alloc:
2375 ieee80211_free_hw(hw);
2376
2377err_hw_alloc:
2378
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002379 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002380}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002381EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002382
2383int wl1271_free_hw(struct wl1271 *wl)
2384{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002385 platform_device_unregister(wl->plat_dev);
2386 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002387
2388 wl1271_debugfs_exit(wl);
2389
2390 kfree(wl->target_mem_map);
2391 vfree(wl->fw);
2392 wl->fw = NULL;
2393 kfree(wl->nvs);
2394 wl->nvs = NULL;
2395
2396 kfree(wl->fw_status);
2397 kfree(wl->tx_res_if);
2398
2399 ieee80211_free_hw(wl->hw);
2400
2401 return 0;
2402}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002403EXPORT_SYMBOL_GPL(wl1271_free_hw);
2404
2405MODULE_LICENSE("GPL");
2406MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2407MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");