blob: 4e9754056d456251afa7be048b8663d9b257f691 [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);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001096
1097 kfree(wl->fw_status);
1098 wl->fw_status = NULL;
1099 kfree(wl->tx_res_if);
1100 wl->tx_res_if = NULL;
1101 kfree(wl->target_mem_map);
1102 wl->target_mem_map = NULL;
1103
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001104 mutex_unlock(&wl->mutex);
1105}
1106
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001107static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1108{
1109 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1110 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1111
1112 /* combine requested filters with current filter config */
1113 filters = wl->filters | filters;
1114
1115 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1116
1117 if (filters & FIF_PROMISC_IN_BSS) {
1118 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1119 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1120 wl->rx_config |= CFG_BSSID_FILTER_EN;
1121 }
1122 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1123 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1124 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1125 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1126 }
1127 if (filters & FIF_OTHER_BSS) {
1128 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1129 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1130 }
1131 if (filters & FIF_CONTROL) {
1132 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1133 wl->rx_filter |= CFG_RX_CTL_EN;
1134 }
1135 if (filters & FIF_FCSFAIL) {
1136 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1137 wl->rx_filter |= CFG_RX_FCS_ERROR;
1138 }
1139}
1140
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001141static int wl1271_join_channel(struct wl1271 *wl, int channel)
1142{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001143 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001144 /* we need to use a dummy BSSID for now */
1145 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1146 0xad, 0xbe, 0xef };
1147
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001148 wl->channel = channel;
1149 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1150
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001151 /* pass through frames from all BSS */
1152 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1153
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001154 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001155 if (ret < 0)
1156 goto out;
1157
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001158 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001159
1160out:
1161 return ret;
1162}
1163
1164static int wl1271_unjoin_channel(struct wl1271 *wl)
1165{
1166 int ret;
1167
1168 /* to stop listening to a channel, we disconnect */
1169 ret = wl1271_cmd_disconnect(wl);
1170 if (ret < 0)
1171 goto out;
1172
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001173 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001174 wl->channel = 0;
1175 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001176
1177 /* stop filterting packets based on bssid */
1178 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001179
1180out:
1181 return ret;
1182}
1183
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001184static void wl1271_set_band_rate(struct wl1271 *wl)
1185{
1186 if (wl->band == IEEE80211_BAND_2GHZ)
1187 wl->basic_rate_set = wl->conf.tx.basic_rate;
1188 else
1189 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1190}
1191
1192static u32 wl1271_min_rate_get(struct wl1271 *wl)
1193{
1194 int i;
1195 u32 rate = 0;
1196
1197 if (!wl->basic_rate_set) {
1198 WARN_ON(1);
1199 wl->basic_rate_set = wl->conf.tx.basic_rate;
1200 }
1201
1202 for (i = 0; !rate; i++) {
1203 if ((wl->basic_rate_set >> i) & 0x1)
1204 rate = 1 << i;
1205 }
1206
1207 return rate;
1208}
1209
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001210static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1211{
1212 struct wl1271 *wl = hw->priv;
1213 struct ieee80211_conf *conf = &hw->conf;
1214 int channel, ret = 0;
1215
1216 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1217
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001218 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001219 channel,
1220 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001221 conf->power_level,
1222 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001223
1224 mutex_lock(&wl->mutex);
1225
1226 ret = wl1271_ps_elp_wakeup(wl, false);
1227 if (ret < 0)
1228 goto out;
1229
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001230 /* if the channel changes while joined, join again */
1231 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
1232 wl->band = conf->channel->band;
1233 wl->channel = channel;
1234
1235 /*
1236 * FIXME: the mac80211 should really provide a fixed rate
1237 * to use here. for now, just use the smallest possible rate
1238 * for the band as a fixed rate for association frames and
1239 * other control messages.
1240 */
1241 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1242 wl1271_set_band_rate(wl);
1243
1244 wl->basic_rate = wl1271_min_rate_get(wl);
1245 ret = wl1271_acx_rate_policies(wl);
1246 if (ret < 0)
1247 wl1271_warning("rate policy for update channel "
1248 "failed %d", ret);
1249
1250 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1251 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1252 if (ret < 0)
1253 wl1271_warning("cmd join to update channel "
1254 "failed %d", ret);
1255 }
1256 }
1257
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001258 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001259 if (conf->flags & IEEE80211_CONF_IDLE &&
1260 test_bit(WL1271_FLAG_JOINED, &wl->flags))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001261 wl1271_unjoin_channel(wl);
Juuso Oikarinen8f648c02009-12-11 15:41:10 +02001262 else if (!(conf->flags & IEEE80211_CONF_IDLE))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001263 wl1271_join_channel(wl, channel);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001264
1265 if (conf->flags & IEEE80211_CONF_IDLE) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001266 wl->rate_set = wl1271_min_rate_get(wl);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001267 wl->sta_rate_set = 0;
1268 wl1271_acx_rate_policies(wl);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001269 wl1271_acx_keep_alive_config(
1270 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1271 ACX_KEEP_ALIVE_TPL_INVALID);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001272 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001273 }
1274
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001275 if (conf->flags & IEEE80211_CONF_PS &&
1276 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1277 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001278
1279 /*
1280 * We enter PSM only if we're already associated.
1281 * If we're not, we'll enter it when joining an SSID,
1282 * through the bss_info_changed() hook.
1283 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001284 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001285 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001286 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1287 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001288 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001289 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001290 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001291 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001292
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001293 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001294
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001295 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001296 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1297 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001298 }
1299
1300 if (conf->power_level != wl->power_level) {
1301 ret = wl1271_acx_tx_power(wl, conf->power_level);
1302 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001303 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001304
1305 wl->power_level = conf->power_level;
1306 }
1307
1308out_sleep:
1309 wl1271_ps_elp_sleep(wl);
1310
1311out:
1312 mutex_unlock(&wl->mutex);
1313
1314 return ret;
1315}
1316
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001317struct wl1271_filter_params {
1318 bool enabled;
1319 int mc_list_length;
1320 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1321};
1322
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001323static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1324 struct dev_addr_list *mc_list)
1325{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001326 struct wl1271_filter_params *fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001327 int i;
1328
Juuso Oikarinen74441132009-10-13 12:47:53 +03001329 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001330 if (!fp) {
1331 wl1271_error("Out of memory setting filters.");
1332 return 0;
1333 }
1334
1335 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001336 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001337 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1338 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001339 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001340 }
1341
1342 fp->mc_list_length = 0;
1343 for (i = 0; i < mc_count; i++) {
1344 if (mc_list->da_addrlen == ETH_ALEN) {
1345 memcpy(fp->mc_list[fp->mc_list_length],
1346 mc_list->da_addr, ETH_ALEN);
1347 fp->mc_list_length++;
1348 } else
1349 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001350 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001351 }
1352
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001353 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001354}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001355
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001356#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1357 FIF_ALLMULTI | \
1358 FIF_FCSFAIL | \
1359 FIF_BCN_PRBRESP_PROMISC | \
1360 FIF_CONTROL | \
1361 FIF_OTHER_BSS)
1362
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001363static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1364 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001365 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001366{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001367 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001368 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001369 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001370
1371 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1372
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001373 mutex_lock(&wl->mutex);
1374
1375 if (wl->state == WL1271_STATE_OFF)
1376 goto out;
1377
1378 ret = wl1271_ps_elp_wakeup(wl, false);
1379 if (ret < 0)
1380 goto out;
1381
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001382 *total &= WL1271_SUPPORTED_FILTERS;
1383 changed &= WL1271_SUPPORTED_FILTERS;
1384
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001385 if (*total & FIF_ALLMULTI)
1386 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1387 else if (fp)
1388 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1389 fp->mc_list,
1390 fp->mc_list_length);
1391 if (ret < 0)
1392 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +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
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001398 /* configure filters */
1399 wl->filters = *total;
1400 wl1271_configure_filters(wl, 0);
1401
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001402 /* apply configured filters */
1403 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1404 if (ret < 0)
1405 goto out_sleep;
1406
1407out_sleep:
1408 wl1271_ps_elp_sleep(wl);
1409
1410out:
1411 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001412 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001413}
1414
1415static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1416 struct ieee80211_vif *vif,
1417 struct ieee80211_sta *sta,
1418 struct ieee80211_key_conf *key_conf)
1419{
1420 struct wl1271 *wl = hw->priv;
1421 const u8 *addr;
1422 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001423 u32 tx_seq_32 = 0;
1424 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001425 u8 key_type;
1426
1427 static const u8 bcast_addr[ETH_ALEN] =
1428 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1429
1430 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1431
1432 addr = sta ? sta->addr : bcast_addr;
1433
1434 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1435 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1436 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1437 key_conf->alg, key_conf->keyidx,
1438 key_conf->keylen, key_conf->flags);
1439 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1440
1441 if (is_zero_ether_addr(addr)) {
1442 /* We dont support TX only encryption */
1443 ret = -EOPNOTSUPP;
1444 goto out;
1445 }
1446
1447 mutex_lock(&wl->mutex);
1448
1449 ret = wl1271_ps_elp_wakeup(wl, false);
1450 if (ret < 0)
1451 goto out_unlock;
1452
1453 switch (key_conf->alg) {
1454 case ALG_WEP:
1455 key_type = KEY_WEP;
1456
1457 key_conf->hw_key_idx = key_conf->keyidx;
1458 break;
1459 case ALG_TKIP:
1460 key_type = KEY_TKIP;
1461
1462 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001463 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1464 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001465 break;
1466 case ALG_CCMP:
1467 key_type = KEY_AES;
1468
1469 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001470 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1471 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001472 break;
1473 default:
1474 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1475
1476 ret = -EOPNOTSUPP;
1477 goto out_sleep;
1478 }
1479
1480 switch (cmd) {
1481 case SET_KEY:
1482 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1483 key_conf->keyidx, key_type,
1484 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001485 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001486 if (ret < 0) {
1487 wl1271_error("Could not add or replace key");
1488 goto out_sleep;
1489 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001490
1491 /* the default WEP key needs to be configured at least once */
1492 if (key_type == KEY_WEP) {
1493 ret = wl1271_cmd_set_default_wep_key(wl,
1494 wl->default_key);
1495 if (ret < 0)
1496 goto out_sleep;
1497 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001498 break;
1499
1500 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001501 /* The wl1271 does not allow to remove unicast keys - they
1502 will be cleared automatically on next CMD_JOIN. Ignore the
1503 request silently, as we dont want the mac80211 to emit
1504 an error message. */
1505 if (!is_broadcast_ether_addr(addr))
1506 break;
1507
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001508 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1509 key_conf->keyidx, key_type,
1510 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001511 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001512 if (ret < 0) {
1513 wl1271_error("Could not remove key");
1514 goto out_sleep;
1515 }
1516 break;
1517
1518 default:
1519 wl1271_error("Unsupported key cmd 0x%x", cmd);
1520 ret = -EOPNOTSUPP;
1521 goto out_sleep;
1522
1523 break;
1524 }
1525
1526out_sleep:
1527 wl1271_ps_elp_sleep(wl);
1528
1529out_unlock:
1530 mutex_unlock(&wl->mutex);
1531
1532out:
1533 return ret;
1534}
1535
1536static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1537 struct cfg80211_scan_request *req)
1538{
1539 struct wl1271 *wl = hw->priv;
1540 int ret;
1541 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001542 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001543
1544 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1545
1546 if (req->n_ssids) {
1547 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001548 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001549 }
1550
1551 mutex_lock(&wl->mutex);
1552
1553 ret = wl1271_ps_elp_wakeup(wl, false);
1554 if (ret < 0)
1555 goto out;
1556
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001557 if (wl1271_11a_enabled())
Kalle Valo818e3062010-03-18 12:26:35 +02001558 ret = wl1271_cmd_scan(hw->priv, ssid, len,
1559 req->ie, req->ie_len, 1, 0,
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001560 WL1271_SCAN_BAND_DUAL, 3);
1561 else
Kalle Valo818e3062010-03-18 12:26:35 +02001562 ret = wl1271_cmd_scan(hw->priv, ssid, len,
1563 req->ie, req->ie_len, 1, 0,
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001564 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001565
1566 wl1271_ps_elp_sleep(wl);
1567
1568out:
1569 mutex_unlock(&wl->mutex);
1570
1571 return ret;
1572}
1573
1574static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1575{
1576 struct wl1271 *wl = hw->priv;
1577 int ret;
1578
1579 mutex_lock(&wl->mutex);
1580
1581 ret = wl1271_ps_elp_wakeup(wl, false);
1582 if (ret < 0)
1583 goto out;
1584
1585 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1586 if (ret < 0)
1587 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1588
1589 wl1271_ps_elp_sleep(wl);
1590
1591out:
1592 mutex_unlock(&wl->mutex);
1593
1594 return ret;
1595}
1596
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001597static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1598{
1599 u8 *ptr = beacon->data +
1600 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1601
1602 /* find the location of the ssid in the beacon */
1603 while (ptr < beacon->data + beacon->len) {
1604 if (ptr[0] == WLAN_EID_SSID) {
1605 wl->ssid_len = ptr[1];
1606 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1607 return;
1608 }
1609 ptr += ptr[1];
1610 }
1611 wl1271_error("ad-hoc beacon template has no SSID!\n");
1612}
1613
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001614static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1615 struct ieee80211_vif *vif,
1616 struct ieee80211_bss_conf *bss_conf,
1617 u32 changed)
1618{
1619 enum wl1271_cmd_ps_mode mode;
1620 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001621 bool do_join = false;
Juuso Oikarinen40b359c2010-04-01 11:38:19 +03001622 bool do_keepalive = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001623 int ret;
1624
1625 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1626
1627 mutex_lock(&wl->mutex);
1628
1629 ret = wl1271_ps_elp_wakeup(wl, false);
1630 if (ret < 0)
1631 goto out;
1632
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001633 if ((changed && BSS_CHANGED_BEACON_INT) &&
1634 (wl->bss_type == BSS_TYPE_IBSS)) {
1635 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1636 bss_conf->beacon_int);
1637
1638 wl->beacon_int = bss_conf->beacon_int;
1639 do_join = true;
1640 }
1641
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001642 if ((changed && BSS_CHANGED_BEACON) &&
1643 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001644 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1645
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001646 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1647
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001648 if (beacon) {
1649 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001650
1651 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001652 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1653 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001654 beacon->len, 0,
1655 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001656
1657 if (ret < 0) {
1658 dev_kfree_skb(beacon);
1659 goto out_sleep;
1660 }
1661
1662 hdr = (struct ieee80211_hdr *) beacon->data;
1663 hdr->frame_control = cpu_to_le16(
1664 IEEE80211_FTYPE_MGMT |
1665 IEEE80211_STYPE_PROBE_RESP);
1666
1667 ret = wl1271_cmd_template_set(wl,
1668 CMD_TEMPL_PROBE_RESPONSE,
1669 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001670 beacon->len, 0,
1671 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001672 dev_kfree_skb(beacon);
1673 if (ret < 0)
1674 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001675
1676 /* Need to update the SSID (for filtering etc) */
1677 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001678 }
1679 }
1680
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001681 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1682 (wl->bss_type == BSS_TYPE_IBSS)) {
1683 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1684 bss_conf->enable_beacon ? "enabled" : "disabled");
1685
1686 if (bss_conf->enable_beacon)
1687 wl->set_bss_type = BSS_TYPE_IBSS;
1688 else
1689 wl->set_bss_type = BSS_TYPE_STA_BSS;
1690 do_join = true;
1691 }
1692
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001693 if ((changed & BSS_CHANGED_BSSID) &&
1694 /*
1695 * Now we know the correct bssid, so we send a new join command
1696 * and enable the BSSID filter
1697 */
1698 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001699 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001700
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001701 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001702 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001703 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001704
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001705 /* filter out all packets not from this BSSID */
1706 wl1271_configure_filters(wl, 0);
1707
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001708 /* Need to update the BSSID (for filtering etc) */
1709 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001710 }
1711
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001712 if (changed & BSS_CHANGED_ASSOC) {
1713 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001714 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001715 wl->aid = bss_conf->aid;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001716 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001717
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001718 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001719 * use basic rates from AP, and determine lowest rate
1720 * to use with control frames.
1721 */
1722 rates = bss_conf->basic_rates;
1723 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1724 rates);
1725 wl->basic_rate = wl1271_min_rate_get(wl);
1726 ret = wl1271_acx_rate_policies(wl);
1727 if (ret < 0)
1728 goto out_sleep;
1729
1730 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001731 * with wl1271, we don't need to update the
1732 * beacon_int and dtim_period, because the firmware
1733 * updates it by itself when the first beacon is
1734 * received after a join.
1735 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001736 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1737 if (ret < 0)
1738 goto out_sleep;
1739
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001740 /*
1741 * The SSID is intentionally set to NULL here - the
1742 * firmware will set the probe request with a
1743 * broadcast SSID regardless of what we set in the
1744 * template.
1745 */
1746 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1747 NULL, 0, wl->band);
1748
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001749 /* Enable the keep-alive feature */
1750 ret = wl1271_acx_keep_alive_mode(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001751 if (ret < 0)
1752 goto out_sleep;
1753
Juuso Oikarinen40b359c2010-04-01 11:38:19 +03001754 /*
1755 * This is awkward. The keep-alive configs must be done
1756 * *after* the join command, because otherwise it will
1757 * not work, but it must only be done *once* because
1758 * otherwise the firmware will start complaining.
1759 */
1760 do_keepalive = true;
1761
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001762 /* enable the connection monitoring feature */
1763 ret = wl1271_acx_conn_monit_params(wl, true);
1764 if (ret < 0)
1765 goto out_sleep;
1766
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001767 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001768 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1769 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001770 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001771 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001772 if (ret < 0)
1773 goto out_sleep;
1774 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001775 } else {
1776 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001777 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001778 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001779
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001780 /* revert back to minimum rates for the current band */
1781 wl1271_set_band_rate(wl);
1782 wl->basic_rate = wl1271_min_rate_get(wl);
1783 ret = wl1271_acx_rate_policies(wl);
1784 if (ret < 0)
1785 goto out_sleep;
1786
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001787 /* disable connection monitor features */
1788 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001789
1790 /* Disable the keep-alive feature */
1791 ret = wl1271_acx_keep_alive_mode(wl, false);
1792
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001793 if (ret < 0)
1794 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001795 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001796
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001797 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001798
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001799 if (changed & BSS_CHANGED_ERP_SLOT) {
1800 if (bss_conf->use_short_slot)
1801 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1802 else
1803 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1804 if (ret < 0) {
1805 wl1271_warning("Set slot time failed %d", ret);
1806 goto out_sleep;
1807 }
1808 }
1809
1810 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1811 if (bss_conf->use_short_preamble)
1812 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1813 else
1814 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1815 }
1816
1817 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1818 if (bss_conf->use_cts_prot)
1819 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1820 else
1821 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1822 if (ret < 0) {
1823 wl1271_warning("Set ctsprotect failed %d", ret);
1824 goto out_sleep;
1825 }
1826 }
1827
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001828 if (do_join) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001829 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001830 if (ret < 0) {
1831 wl1271_warning("cmd join failed %d", ret);
1832 goto out_sleep;
1833 }
1834 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1835 }
1836
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001837 /*
1838 * The JOIN operation shuts down the firmware keep-alive as a side
1839 * effect, and the ACX_AID will start the keep-alive as a side effect.
1840 * Hence, for non-IBSS, the ACX_AID must always happen *after* the
1841 * JOIN operation, and the template config after the ACX_AID.
1842 */
1843 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
1844 ret = wl1271_acx_aid(wl, wl->aid);
1845 if (ret < 0)
1846 goto out_sleep;
Juuso Oikarinen40b359c2010-04-01 11:38:19 +03001847 }
1848
1849 if (do_keepalive) {
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001850 ret = wl1271_cmd_build_klv_null_data(wl);
1851 if (ret < 0)
1852 goto out_sleep;
1853 ret = wl1271_acx_keep_alive_config(
1854 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1855 ACX_KEEP_ALIVE_TPL_VALID);
1856 if (ret < 0)
1857 goto out_sleep;
1858 }
1859
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001860out_sleep:
1861 wl1271_ps_elp_sleep(wl);
1862
1863out:
1864 mutex_unlock(&wl->mutex);
1865}
1866
Kalle Valoc6999d82010-02-18 13:25:41 +02001867static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1868 const struct ieee80211_tx_queue_params *params)
1869{
1870 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02001871 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02001872 int ret;
1873
1874 mutex_lock(&wl->mutex);
1875
1876 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1877
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001878 ret = wl1271_ps_elp_wakeup(wl, false);
1879 if (ret < 0)
1880 goto out;
1881
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001882 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001883 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1884 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001885 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001886 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001887 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001888
Kalle Valo4695dc92010-03-18 12:26:38 +02001889 if (params->uapsd)
1890 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
1891 else
1892 ps_scheme = CONF_PS_SCHEME_LEGACY;
1893
Kalle Valoc6999d82010-02-18 13:25:41 +02001894 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1895 CONF_CHANNEL_TYPE_EDCF,
1896 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02001897 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02001898 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001899 goto out_sleep;
1900
1901out_sleep:
1902 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001903
1904out:
1905 mutex_unlock(&wl->mutex);
1906
1907 return ret;
1908}
1909
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001910
1911/* can't be const, mac80211 writes to this */
1912static struct ieee80211_rate wl1271_rates[] = {
1913 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001914 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1915 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001916 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001917 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1918 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001919 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1920 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001921 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1922 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001923 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1924 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001925 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1926 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001927 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1928 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001929 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1930 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001931 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001932 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1933 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001934 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001935 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1936 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001937 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001938 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1939 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001940 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001941 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1942 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001943 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001944 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1945 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001946 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001947 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1948 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001949 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001950 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1951 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001952};
1953
1954/* can't be const, mac80211 writes to this */
1955static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001956 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1957 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1958 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1959 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1960 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1961 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1962 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1963 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1964 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1965 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1966 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1967 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1968 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001969};
1970
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02001971/* mapping to indexes for wl1271_rates */
1972const static u8 wl1271_rate_to_idx_2ghz[] = {
1973 /* MCS rates are used only with 11n */
1974 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
1975 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
1976 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
1977 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
1978 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
1979 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
1980 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
1981 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
1982
1983 11, /* CONF_HW_RXTX_RATE_54 */
1984 10, /* CONF_HW_RXTX_RATE_48 */
1985 9, /* CONF_HW_RXTX_RATE_36 */
1986 8, /* CONF_HW_RXTX_RATE_24 */
1987
1988 /* TI-specific rate */
1989 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
1990
1991 7, /* CONF_HW_RXTX_RATE_18 */
1992 6, /* CONF_HW_RXTX_RATE_12 */
1993 3, /* CONF_HW_RXTX_RATE_11 */
1994 5, /* CONF_HW_RXTX_RATE_9 */
1995 4, /* CONF_HW_RXTX_RATE_6 */
1996 2, /* CONF_HW_RXTX_RATE_5_5 */
1997 1, /* CONF_HW_RXTX_RATE_2 */
1998 0 /* CONF_HW_RXTX_RATE_1 */
1999};
2000
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002001/* can't be const, mac80211 writes to this */
2002static struct ieee80211_supported_band wl1271_band_2ghz = {
2003 .channels = wl1271_channels,
2004 .n_channels = ARRAY_SIZE(wl1271_channels),
2005 .bitrates = wl1271_rates,
2006 .n_bitrates = ARRAY_SIZE(wl1271_rates),
2007};
2008
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002009/* 5 GHz data rates for WL1273 */
2010static struct ieee80211_rate wl1271_rates_5ghz[] = {
2011 { .bitrate = 60,
2012 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2013 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2014 { .bitrate = 90,
2015 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2016 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2017 { .bitrate = 120,
2018 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2019 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2020 { .bitrate = 180,
2021 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2022 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2023 { .bitrate = 240,
2024 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2025 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2026 { .bitrate = 360,
2027 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2028 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2029 { .bitrate = 480,
2030 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2031 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2032 { .bitrate = 540,
2033 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2034 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2035};
2036
2037/* 5 GHz band channels for WL1273 */
2038static struct ieee80211_channel wl1271_channels_5ghz[] = {
2039 { .hw_value = 183, .center_freq = 4915},
2040 { .hw_value = 184, .center_freq = 4920},
2041 { .hw_value = 185, .center_freq = 4925},
2042 { .hw_value = 187, .center_freq = 4935},
2043 { .hw_value = 188, .center_freq = 4940},
2044 { .hw_value = 189, .center_freq = 4945},
2045 { .hw_value = 192, .center_freq = 4960},
2046 { .hw_value = 196, .center_freq = 4980},
2047 { .hw_value = 7, .center_freq = 5035},
2048 { .hw_value = 8, .center_freq = 5040},
2049 { .hw_value = 9, .center_freq = 5045},
2050 { .hw_value = 11, .center_freq = 5055},
2051 { .hw_value = 12, .center_freq = 5060},
2052 { .hw_value = 16, .center_freq = 5080},
2053 { .hw_value = 34, .center_freq = 5170},
2054 { .hw_value = 36, .center_freq = 5180},
2055 { .hw_value = 38, .center_freq = 5190},
2056 { .hw_value = 40, .center_freq = 5200},
2057 { .hw_value = 42, .center_freq = 5210},
2058 { .hw_value = 44, .center_freq = 5220},
2059 { .hw_value = 46, .center_freq = 5230},
2060 { .hw_value = 48, .center_freq = 5240},
2061 { .hw_value = 52, .center_freq = 5260},
2062 { .hw_value = 56, .center_freq = 5280},
2063 { .hw_value = 60, .center_freq = 5300},
2064 { .hw_value = 64, .center_freq = 5320},
2065 { .hw_value = 100, .center_freq = 5500},
2066 { .hw_value = 104, .center_freq = 5520},
2067 { .hw_value = 108, .center_freq = 5540},
2068 { .hw_value = 112, .center_freq = 5560},
2069 { .hw_value = 116, .center_freq = 5580},
2070 { .hw_value = 120, .center_freq = 5600},
2071 { .hw_value = 124, .center_freq = 5620},
2072 { .hw_value = 128, .center_freq = 5640},
2073 { .hw_value = 132, .center_freq = 5660},
2074 { .hw_value = 136, .center_freq = 5680},
2075 { .hw_value = 140, .center_freq = 5700},
2076 { .hw_value = 149, .center_freq = 5745},
2077 { .hw_value = 153, .center_freq = 5765},
2078 { .hw_value = 157, .center_freq = 5785},
2079 { .hw_value = 161, .center_freq = 5805},
2080 { .hw_value = 165, .center_freq = 5825},
2081};
2082
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002083/* mapping to indexes for wl1271_rates_5ghz */
2084const static u8 wl1271_rate_to_idx_5ghz[] = {
2085 /* MCS rates are used only with 11n */
2086 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2087 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2088 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2089 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2090 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2091 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2092 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2093 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2094
2095 7, /* CONF_HW_RXTX_RATE_54 */
2096 6, /* CONF_HW_RXTX_RATE_48 */
2097 5, /* CONF_HW_RXTX_RATE_36 */
2098 4, /* CONF_HW_RXTX_RATE_24 */
2099
2100 /* TI-specific rate */
2101 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2102
2103 3, /* CONF_HW_RXTX_RATE_18 */
2104 2, /* CONF_HW_RXTX_RATE_12 */
2105 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2106 1, /* CONF_HW_RXTX_RATE_9 */
2107 0, /* CONF_HW_RXTX_RATE_6 */
2108 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2109 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2110 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2111};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002112
2113static struct ieee80211_supported_band wl1271_band_5ghz = {
2114 .channels = wl1271_channels_5ghz,
2115 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2116 .bitrates = wl1271_rates_5ghz,
2117 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
2118};
2119
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002120const static u8 *wl1271_band_rate_to_idx[] = {
2121 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2122 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2123};
2124
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002125static const struct ieee80211_ops wl1271_ops = {
2126 .start = wl1271_op_start,
2127 .stop = wl1271_op_stop,
2128 .add_interface = wl1271_op_add_interface,
2129 .remove_interface = wl1271_op_remove_interface,
2130 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002131 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002132 .configure_filter = wl1271_op_configure_filter,
2133 .tx = wl1271_op_tx,
2134 .set_key = wl1271_op_set_key,
2135 .hw_scan = wl1271_op_hw_scan,
2136 .bss_info_changed = wl1271_op_bss_info_changed,
2137 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002138 .conf_tx = wl1271_op_conf_tx,
Kalle Valoc8c90872010-02-18 13:25:53 +02002139 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002140};
2141
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002142
2143u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
2144{
2145 u8 idx;
2146
2147 BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
2148
2149 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2150 wl1271_error("Illegal RX rate from HW: %d", rate);
2151 return 0;
2152 }
2153
2154 idx = wl1271_band_rate_to_idx[wl->band][rate];
2155 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2156 wl1271_error("Unsupported RX rate from HW: %d", rate);
2157 return 0;
2158 }
2159
2160 return idx;
2161}
2162
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002163static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2164 struct device_attribute *attr,
2165 char *buf)
2166{
2167 struct wl1271 *wl = dev_get_drvdata(dev);
2168 ssize_t len;
2169
2170 /* FIXME: what's the maximum length of buf? page size?*/
2171 len = 500;
2172
2173 mutex_lock(&wl->mutex);
2174 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2175 wl->sg_enabled);
2176 mutex_unlock(&wl->mutex);
2177
2178 return len;
2179
2180}
2181
2182static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2183 struct device_attribute *attr,
2184 const char *buf, size_t count)
2185{
2186 struct wl1271 *wl = dev_get_drvdata(dev);
2187 unsigned long res;
2188 int ret;
2189
2190 ret = strict_strtoul(buf, 10, &res);
2191
2192 if (ret < 0) {
2193 wl1271_warning("incorrect value written to bt_coex_mode");
2194 return count;
2195 }
2196
2197 mutex_lock(&wl->mutex);
2198
2199 res = !!res;
2200
2201 if (res == wl->sg_enabled)
2202 goto out;
2203
2204 wl->sg_enabled = res;
2205
2206 if (wl->state == WL1271_STATE_OFF)
2207 goto out;
2208
2209 ret = wl1271_ps_elp_wakeup(wl, false);
2210 if (ret < 0)
2211 goto out;
2212
2213 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2214 wl1271_ps_elp_sleep(wl);
2215
2216 out:
2217 mutex_unlock(&wl->mutex);
2218 return count;
2219}
2220
2221static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2222 wl1271_sysfs_show_bt_coex_state,
2223 wl1271_sysfs_store_bt_coex_state);
2224
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002225int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002226{
2227 int ret;
2228
2229 if (wl->mac80211_registered)
2230 return 0;
2231
2232 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2233
2234 ret = ieee80211_register_hw(wl->hw);
2235 if (ret < 0) {
2236 wl1271_error("unable to register mac80211 hw: %d", ret);
2237 return ret;
2238 }
2239
2240 wl->mac80211_registered = true;
2241
2242 wl1271_notice("loaded");
2243
2244 return 0;
2245}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002246EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002247
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002248void wl1271_unregister_hw(struct wl1271 *wl)
2249{
2250 ieee80211_unregister_hw(wl->hw);
2251 wl->mac80211_registered = false;
2252
2253}
2254EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2255
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002256int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002257{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002258 /* The tx descriptor buffer and the TKIP space. */
2259 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2260 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002261
2262 /* unit us */
2263 /* FIXME: find a proper value */
2264 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002265 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002266
2267 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03002268 IEEE80211_HW_NOISE_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002269 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002270 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002271 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002272 IEEE80211_HW_HAS_RATE_CONTROL |
2273 IEEE80211_HW_CONNECTION_MONITOR;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002274
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002275 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2276 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002277 wl->hw->wiphy->max_scan_ssids = 1;
2278 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
2279
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002280 if (wl1271_11a_enabled())
2281 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
2282
Kalle Valo12bd8942010-03-18 12:26:33 +02002283 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002284 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002285
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002286 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002287
2288 return 0;
2289}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002290EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002291
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002292#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002293
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002294struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002295{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002296 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002297 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002298 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002299 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002300
2301 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2302 if (!hw) {
2303 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002304 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002305 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002306 }
2307
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002308 plat_dev = kmalloc(sizeof(wl1271_device), GFP_KERNEL);
2309 if (!plat_dev) {
2310 wl1271_error("could not allocate platform_device");
2311 ret = -ENOMEM;
2312 goto err_plat_alloc;
2313 }
2314
2315 memcpy(plat_dev, &wl1271_device, sizeof(wl1271_device));
2316
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002317 wl = hw->priv;
2318 memset(wl, 0, sizeof(*wl));
2319
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002320 INIT_LIST_HEAD(&wl->list);
2321
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002322 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002323 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002324
2325 skb_queue_head_init(&wl->tx_queue);
2326
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002327 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002328 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002329 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002330 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002331 wl->rx_counter = 0;
2332 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2333 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002334 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002335 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002336 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002337 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002338 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2339 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002340 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002341 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002342 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002343 wl->sg_enabled = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002344
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002345 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002346 wl->tx_frames[i] = NULL;
2347
2348 spin_lock_init(&wl->wl_lock);
2349
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002350 wl->state = WL1271_STATE_OFF;
2351 mutex_init(&wl->mutex);
2352
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002353 /* Apply default driver configuration. */
2354 wl1271_conf_init(wl);
2355
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002356 wl1271_debugfs_init(wl);
2357
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002358 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002359 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002360 if (ret) {
2361 wl1271_error("couldn't register platform device");
2362 goto err_hw;
2363 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002364 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002365
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002366 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002367 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002368 if (ret < 0) {
2369 wl1271_error("failed to create sysfs file bt_coex_state");
2370 goto err_platform;
2371 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002372
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002373 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002374
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002375err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002376 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002377
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002378err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002379 wl1271_debugfs_exit(wl);
2380 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002381
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002382err_plat_alloc:
2383 ieee80211_free_hw(hw);
2384
2385err_hw_alloc:
2386
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002387 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002388}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002389EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002390
2391int wl1271_free_hw(struct wl1271 *wl)
2392{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002393 platform_device_unregister(wl->plat_dev);
2394 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002395
2396 wl1271_debugfs_exit(wl);
2397
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002398 vfree(wl->fw);
2399 wl->fw = NULL;
2400 kfree(wl->nvs);
2401 wl->nvs = NULL;
2402
2403 kfree(wl->fw_status);
2404 kfree(wl->tx_res_if);
2405
2406 ieee80211_free_hw(wl->hw);
2407
2408 return 0;
2409}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002410EXPORT_SYMBOL_GPL(wl1271_free_hw);
2411
2412MODULE_LICENSE("GPL");
2413MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2414MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");