blob: 551714164ff50738a96aa19d7dd7895485f1d909 [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
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001226 if (unlikely(wl->state == WL1271_STATE_OFF))
1227 goto out;
1228
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001229 ret = wl1271_ps_elp_wakeup(wl, false);
1230 if (ret < 0)
1231 goto out;
1232
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001233 /* if the channel changes while joined, join again */
1234 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
1235 wl->band = conf->channel->band;
1236 wl->channel = channel;
1237
1238 /*
1239 * FIXME: the mac80211 should really provide a fixed rate
1240 * to use here. for now, just use the smallest possible rate
1241 * for the band as a fixed rate for association frames and
1242 * other control messages.
1243 */
1244 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1245 wl1271_set_band_rate(wl);
1246
1247 wl->basic_rate = wl1271_min_rate_get(wl);
1248 ret = wl1271_acx_rate_policies(wl);
1249 if (ret < 0)
1250 wl1271_warning("rate policy for update channel "
1251 "failed %d", ret);
1252
1253 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1254 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1255 if (ret < 0)
1256 wl1271_warning("cmd join to update channel "
1257 "failed %d", ret);
1258 }
1259 }
1260
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001261 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001262 if (conf->flags & IEEE80211_CONF_IDLE &&
1263 test_bit(WL1271_FLAG_JOINED, &wl->flags))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001264 wl1271_unjoin_channel(wl);
Juuso Oikarinen8f648c02009-12-11 15:41:10 +02001265 else if (!(conf->flags & IEEE80211_CONF_IDLE))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001266 wl1271_join_channel(wl, channel);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001267
1268 if (conf->flags & IEEE80211_CONF_IDLE) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001269 wl->rate_set = wl1271_min_rate_get(wl);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001270 wl->sta_rate_set = 0;
1271 wl1271_acx_rate_policies(wl);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001272 wl1271_acx_keep_alive_config(
1273 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1274 ACX_KEEP_ALIVE_TPL_INVALID);
Juuso Oikarinene1972812010-04-09 11:07:29 +03001275 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1276 } else
1277 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001278 }
1279
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001280 if (conf->flags & IEEE80211_CONF_PS &&
1281 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1282 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001283
1284 /*
1285 * We enter PSM only if we're already associated.
1286 * If we're not, we'll enter it when joining an SSID,
1287 * through the bss_info_changed() hook.
1288 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001289 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001290 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001291 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1292 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001293 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001294 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001295 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001296 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001297
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001298 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001299
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001300 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001301 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1302 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001303 }
1304
1305 if (conf->power_level != wl->power_level) {
1306 ret = wl1271_acx_tx_power(wl, conf->power_level);
1307 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001308 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001309
1310 wl->power_level = conf->power_level;
1311 }
1312
1313out_sleep:
1314 wl1271_ps_elp_sleep(wl);
1315
1316out:
1317 mutex_unlock(&wl->mutex);
1318
1319 return ret;
1320}
1321
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001322struct wl1271_filter_params {
1323 bool enabled;
1324 int mc_list_length;
1325 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1326};
1327
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001328static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1329 struct dev_addr_list *mc_list)
1330{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001331 struct wl1271_filter_params *fp;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001332 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001333 int i;
1334
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001335 if (unlikely(wl->state == WL1271_STATE_OFF))
1336 return 0;
1337
Juuso Oikarinen74441132009-10-13 12:47:53 +03001338 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001339 if (!fp) {
1340 wl1271_error("Out of memory setting filters.");
1341 return 0;
1342 }
1343
1344 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001345 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001346 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1347 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001348 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001349 }
1350
1351 fp->mc_list_length = 0;
1352 for (i = 0; i < mc_count; i++) {
1353 if (mc_list->da_addrlen == ETH_ALEN) {
1354 memcpy(fp->mc_list[fp->mc_list_length],
1355 mc_list->da_addr, ETH_ALEN);
1356 fp->mc_list_length++;
1357 } else
1358 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001359 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001360 }
1361
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001362 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001363}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001364
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001365#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1366 FIF_ALLMULTI | \
1367 FIF_FCSFAIL | \
1368 FIF_BCN_PRBRESP_PROMISC | \
1369 FIF_CONTROL | \
1370 FIF_OTHER_BSS)
1371
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001372static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1373 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001374 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001375{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001376 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001377 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001378 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001379
1380 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1381
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001382 mutex_lock(&wl->mutex);
1383
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001384 *total &= WL1271_SUPPORTED_FILTERS;
1385 changed &= WL1271_SUPPORTED_FILTERS;
1386
1387 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001388 goto out;
1389
1390 ret = wl1271_ps_elp_wakeup(wl, false);
1391 if (ret < 0)
1392 goto out;
1393
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001394
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001395 if (*total & FIF_ALLMULTI)
1396 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1397 else if (fp)
1398 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1399 fp->mc_list,
1400 fp->mc_list_length);
1401 if (ret < 0)
1402 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001403
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001404 /* determine, whether supported filter values have changed */
1405 if (changed == 0)
1406 goto out_sleep;
1407
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001408 /* configure filters */
1409 wl->filters = *total;
1410 wl1271_configure_filters(wl, 0);
1411
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001412 /* apply configured filters */
1413 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1414 if (ret < 0)
1415 goto out_sleep;
1416
1417out_sleep:
1418 wl1271_ps_elp_sleep(wl);
1419
1420out:
1421 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001422 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001423}
1424
1425static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1426 struct ieee80211_vif *vif,
1427 struct ieee80211_sta *sta,
1428 struct ieee80211_key_conf *key_conf)
1429{
1430 struct wl1271 *wl = hw->priv;
1431 const u8 *addr;
1432 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001433 u32 tx_seq_32 = 0;
1434 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001435 u8 key_type;
1436
1437 static const u8 bcast_addr[ETH_ALEN] =
1438 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1439
1440 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1441
1442 addr = sta ? sta->addr : bcast_addr;
1443
1444 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1445 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1446 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1447 key_conf->alg, key_conf->keyidx,
1448 key_conf->keylen, key_conf->flags);
1449 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1450
1451 if (is_zero_ether_addr(addr)) {
1452 /* We dont support TX only encryption */
1453 ret = -EOPNOTSUPP;
1454 goto out;
1455 }
1456
1457 mutex_lock(&wl->mutex);
1458
1459 ret = wl1271_ps_elp_wakeup(wl, false);
1460 if (ret < 0)
1461 goto out_unlock;
1462
1463 switch (key_conf->alg) {
1464 case ALG_WEP:
1465 key_type = KEY_WEP;
1466
1467 key_conf->hw_key_idx = key_conf->keyidx;
1468 break;
1469 case ALG_TKIP:
1470 key_type = KEY_TKIP;
1471
1472 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001473 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1474 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001475 break;
1476 case ALG_CCMP:
1477 key_type = KEY_AES;
1478
1479 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001480 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1481 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001482 break;
1483 default:
1484 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1485
1486 ret = -EOPNOTSUPP;
1487 goto out_sleep;
1488 }
1489
1490 switch (cmd) {
1491 case SET_KEY:
1492 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1493 key_conf->keyidx, key_type,
1494 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001495 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001496 if (ret < 0) {
1497 wl1271_error("Could not add or replace key");
1498 goto out_sleep;
1499 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001500
1501 /* the default WEP key needs to be configured at least once */
1502 if (key_type == KEY_WEP) {
1503 ret = wl1271_cmd_set_default_wep_key(wl,
1504 wl->default_key);
1505 if (ret < 0)
1506 goto out_sleep;
1507 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001508 break;
1509
1510 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001511 /* The wl1271 does not allow to remove unicast keys - they
1512 will be cleared automatically on next CMD_JOIN. Ignore the
1513 request silently, as we dont want the mac80211 to emit
1514 an error message. */
1515 if (!is_broadcast_ether_addr(addr))
1516 break;
1517
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001518 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1519 key_conf->keyidx, key_type,
1520 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001521 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001522 if (ret < 0) {
1523 wl1271_error("Could not remove key");
1524 goto out_sleep;
1525 }
1526 break;
1527
1528 default:
1529 wl1271_error("Unsupported key cmd 0x%x", cmd);
1530 ret = -EOPNOTSUPP;
1531 goto out_sleep;
1532
1533 break;
1534 }
1535
1536out_sleep:
1537 wl1271_ps_elp_sleep(wl);
1538
1539out_unlock:
1540 mutex_unlock(&wl->mutex);
1541
1542out:
1543 return ret;
1544}
1545
1546static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1547 struct cfg80211_scan_request *req)
1548{
1549 struct wl1271 *wl = hw->priv;
1550 int ret;
1551 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001552 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001553
1554 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1555
1556 if (req->n_ssids) {
1557 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001558 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001559 }
1560
1561 mutex_lock(&wl->mutex);
1562
1563 ret = wl1271_ps_elp_wakeup(wl, false);
1564 if (ret < 0)
1565 goto out;
1566
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001567 if (wl1271_11a_enabled())
Kalle Valo818e3062010-03-18 12:26:35 +02001568 ret = wl1271_cmd_scan(hw->priv, ssid, len,
1569 req->ie, req->ie_len, 1, 0,
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001570 WL1271_SCAN_BAND_DUAL, 3);
1571 else
Kalle Valo818e3062010-03-18 12:26:35 +02001572 ret = wl1271_cmd_scan(hw->priv, ssid, len,
1573 req->ie, req->ie_len, 1, 0,
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001574 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001575
1576 wl1271_ps_elp_sleep(wl);
1577
1578out:
1579 mutex_unlock(&wl->mutex);
1580
1581 return ret;
1582}
1583
1584static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1585{
1586 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001587 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001588
1589 mutex_lock(&wl->mutex);
1590
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001591 if (unlikely(wl->state == WL1271_STATE_OFF))
1592 goto out;
1593
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001594 ret = wl1271_ps_elp_wakeup(wl, false);
1595 if (ret < 0)
1596 goto out;
1597
1598 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1599 if (ret < 0)
1600 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1601
1602 wl1271_ps_elp_sleep(wl);
1603
1604out:
1605 mutex_unlock(&wl->mutex);
1606
1607 return ret;
1608}
1609
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001610static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1611{
1612 u8 *ptr = beacon->data +
1613 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1614
1615 /* find the location of the ssid in the beacon */
1616 while (ptr < beacon->data + beacon->len) {
1617 if (ptr[0] == WLAN_EID_SSID) {
1618 wl->ssid_len = ptr[1];
1619 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1620 return;
1621 }
1622 ptr += ptr[1];
1623 }
1624 wl1271_error("ad-hoc beacon template has no SSID!\n");
1625}
1626
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001627static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1628 struct ieee80211_vif *vif,
1629 struct ieee80211_bss_conf *bss_conf,
1630 u32 changed)
1631{
1632 enum wl1271_cmd_ps_mode mode;
1633 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001634 bool do_join = false;
Juuso Oikarinen40b359c2010-04-01 11:38:19 +03001635 bool do_keepalive = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001636 int ret;
1637
1638 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1639
1640 mutex_lock(&wl->mutex);
1641
1642 ret = wl1271_ps_elp_wakeup(wl, false);
1643 if (ret < 0)
1644 goto out;
1645
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001646 if ((changed && BSS_CHANGED_BEACON_INT) &&
1647 (wl->bss_type == BSS_TYPE_IBSS)) {
1648 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1649 bss_conf->beacon_int);
1650
1651 wl->beacon_int = bss_conf->beacon_int;
1652 do_join = true;
1653 }
1654
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001655 if ((changed && BSS_CHANGED_BEACON) &&
1656 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001657 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1658
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001659 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1660
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001661 if (beacon) {
1662 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001663
1664 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001665 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1666 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001667 beacon->len, 0,
1668 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001669
1670 if (ret < 0) {
1671 dev_kfree_skb(beacon);
1672 goto out_sleep;
1673 }
1674
1675 hdr = (struct ieee80211_hdr *) beacon->data;
1676 hdr->frame_control = cpu_to_le16(
1677 IEEE80211_FTYPE_MGMT |
1678 IEEE80211_STYPE_PROBE_RESP);
1679
1680 ret = wl1271_cmd_template_set(wl,
1681 CMD_TEMPL_PROBE_RESPONSE,
1682 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001683 beacon->len, 0,
1684 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001685 dev_kfree_skb(beacon);
1686 if (ret < 0)
1687 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001688
1689 /* Need to update the SSID (for filtering etc) */
1690 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001691 }
1692 }
1693
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001694 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1695 (wl->bss_type == BSS_TYPE_IBSS)) {
1696 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1697 bss_conf->enable_beacon ? "enabled" : "disabled");
1698
1699 if (bss_conf->enable_beacon)
1700 wl->set_bss_type = BSS_TYPE_IBSS;
1701 else
1702 wl->set_bss_type = BSS_TYPE_STA_BSS;
1703 do_join = true;
1704 }
1705
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001706 if ((changed & BSS_CHANGED_BSSID) &&
1707 /*
1708 * Now we know the correct bssid, so we send a new join command
1709 * and enable the BSSID filter
1710 */
1711 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001712 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001713
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001714 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001715 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001716 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001717
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001718 /* filter out all packets not from this BSSID */
1719 wl1271_configure_filters(wl, 0);
1720
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001721 /* Need to update the BSSID (for filtering etc) */
1722 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001723 }
1724
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001725 if (changed & BSS_CHANGED_ASSOC) {
1726 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001727 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001728 wl->aid = bss_conf->aid;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001729 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001730
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001731 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001732 * use basic rates from AP, and determine lowest rate
1733 * to use with control frames.
1734 */
1735 rates = bss_conf->basic_rates;
1736 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1737 rates);
1738 wl->basic_rate = wl1271_min_rate_get(wl);
1739 ret = wl1271_acx_rate_policies(wl);
1740 if (ret < 0)
1741 goto out_sleep;
1742
1743 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001744 * with wl1271, we don't need to update the
1745 * beacon_int and dtim_period, because the firmware
1746 * updates it by itself when the first beacon is
1747 * received after a join.
1748 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001749 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1750 if (ret < 0)
1751 goto out_sleep;
1752
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001753 /*
1754 * The SSID is intentionally set to NULL here - the
1755 * firmware will set the probe request with a
1756 * broadcast SSID regardless of what we set in the
1757 * template.
1758 */
1759 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1760 NULL, 0, wl->band);
1761
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001762 /* Enable the keep-alive feature */
1763 ret = wl1271_acx_keep_alive_mode(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001764 if (ret < 0)
1765 goto out_sleep;
1766
Juuso Oikarinen40b359c2010-04-01 11:38:19 +03001767 /*
1768 * This is awkward. The keep-alive configs must be done
1769 * *after* the join command, because otherwise it will
1770 * not work, but it must only be done *once* because
1771 * otherwise the firmware will start complaining.
1772 */
1773 do_keepalive = true;
1774
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001775 /* enable the connection monitoring feature */
1776 ret = wl1271_acx_conn_monit_params(wl, true);
1777 if (ret < 0)
1778 goto out_sleep;
1779
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001780 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001781 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1782 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001783 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001784 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001785 if (ret < 0)
1786 goto out_sleep;
1787 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001788 } else {
1789 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001790 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001791 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001792
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001793 /* revert back to minimum rates for the current band */
1794 wl1271_set_band_rate(wl);
1795 wl->basic_rate = wl1271_min_rate_get(wl);
1796 ret = wl1271_acx_rate_policies(wl);
1797 if (ret < 0)
1798 goto out_sleep;
1799
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001800 /* disable connection monitor features */
1801 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001802
1803 /* Disable the keep-alive feature */
1804 ret = wl1271_acx_keep_alive_mode(wl, false);
1805
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001806 if (ret < 0)
1807 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001808 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001809
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001810 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001811
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001812 if (changed & BSS_CHANGED_ERP_SLOT) {
1813 if (bss_conf->use_short_slot)
1814 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1815 else
1816 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1817 if (ret < 0) {
1818 wl1271_warning("Set slot time failed %d", ret);
1819 goto out_sleep;
1820 }
1821 }
1822
1823 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1824 if (bss_conf->use_short_preamble)
1825 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1826 else
1827 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1828 }
1829
1830 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1831 if (bss_conf->use_cts_prot)
1832 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1833 else
1834 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1835 if (ret < 0) {
1836 wl1271_warning("Set ctsprotect failed %d", ret);
1837 goto out_sleep;
1838 }
1839 }
1840
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001841 if (do_join) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001842 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001843 if (ret < 0) {
1844 wl1271_warning("cmd join failed %d", ret);
1845 goto out_sleep;
1846 }
1847 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1848 }
1849
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001850 /*
1851 * The JOIN operation shuts down the firmware keep-alive as a side
1852 * effect, and the ACX_AID will start the keep-alive as a side effect.
1853 * Hence, for non-IBSS, the ACX_AID must always happen *after* the
1854 * JOIN operation, and the template config after the ACX_AID.
1855 */
1856 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
1857 ret = wl1271_acx_aid(wl, wl->aid);
1858 if (ret < 0)
1859 goto out_sleep;
Juuso Oikarinen40b359c2010-04-01 11:38:19 +03001860 }
1861
1862 if (do_keepalive) {
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001863 ret = wl1271_cmd_build_klv_null_data(wl);
1864 if (ret < 0)
1865 goto out_sleep;
1866 ret = wl1271_acx_keep_alive_config(
1867 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1868 ACX_KEEP_ALIVE_TPL_VALID);
1869 if (ret < 0)
1870 goto out_sleep;
1871 }
1872
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001873out_sleep:
1874 wl1271_ps_elp_sleep(wl);
1875
1876out:
1877 mutex_unlock(&wl->mutex);
1878}
1879
Kalle Valoc6999d82010-02-18 13:25:41 +02001880static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1881 const struct ieee80211_tx_queue_params *params)
1882{
1883 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02001884 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02001885 int ret;
1886
1887 mutex_lock(&wl->mutex);
1888
1889 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1890
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001891 ret = wl1271_ps_elp_wakeup(wl, false);
1892 if (ret < 0)
1893 goto out;
1894
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001895 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001896 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1897 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001898 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001899 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001900 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001901
Kalle Valo4695dc92010-03-18 12:26:38 +02001902 if (params->uapsd)
1903 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
1904 else
1905 ps_scheme = CONF_PS_SCHEME_LEGACY;
1906
Kalle Valoc6999d82010-02-18 13:25:41 +02001907 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1908 CONF_CHANNEL_TYPE_EDCF,
1909 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02001910 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02001911 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001912 goto out_sleep;
1913
1914out_sleep:
1915 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001916
1917out:
1918 mutex_unlock(&wl->mutex);
1919
1920 return ret;
1921}
1922
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001923
1924/* can't be const, mac80211 writes to this */
1925static struct ieee80211_rate wl1271_rates[] = {
1926 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001927 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1928 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001929 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001930 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1931 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001932 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1933 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001934 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1935 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001936 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1937 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001938 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1939 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001940 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1941 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001942 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1943 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001944 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001945 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1946 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001947 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001948 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1949 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001950 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001951 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1952 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001953 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001954 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1955 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001956 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001957 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1958 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001959 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001960 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1961 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001962 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001963 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1964 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001965};
1966
1967/* can't be const, mac80211 writes to this */
1968static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001969 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1970 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1971 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1972 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1973 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1974 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1975 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1976 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1977 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1978 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1979 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1980 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1981 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001982};
1983
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02001984/* mapping to indexes for wl1271_rates */
1985const static u8 wl1271_rate_to_idx_2ghz[] = {
1986 /* MCS rates are used only with 11n */
1987 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
1988 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
1989 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
1990 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
1991 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
1992 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
1993 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
1994 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
1995
1996 11, /* CONF_HW_RXTX_RATE_54 */
1997 10, /* CONF_HW_RXTX_RATE_48 */
1998 9, /* CONF_HW_RXTX_RATE_36 */
1999 8, /* CONF_HW_RXTX_RATE_24 */
2000
2001 /* TI-specific rate */
2002 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2003
2004 7, /* CONF_HW_RXTX_RATE_18 */
2005 6, /* CONF_HW_RXTX_RATE_12 */
2006 3, /* CONF_HW_RXTX_RATE_11 */
2007 5, /* CONF_HW_RXTX_RATE_9 */
2008 4, /* CONF_HW_RXTX_RATE_6 */
2009 2, /* CONF_HW_RXTX_RATE_5_5 */
2010 1, /* CONF_HW_RXTX_RATE_2 */
2011 0 /* CONF_HW_RXTX_RATE_1 */
2012};
2013
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002014/* can't be const, mac80211 writes to this */
2015static struct ieee80211_supported_band wl1271_band_2ghz = {
2016 .channels = wl1271_channels,
2017 .n_channels = ARRAY_SIZE(wl1271_channels),
2018 .bitrates = wl1271_rates,
2019 .n_bitrates = ARRAY_SIZE(wl1271_rates),
2020};
2021
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002022/* 5 GHz data rates for WL1273 */
2023static struct ieee80211_rate wl1271_rates_5ghz[] = {
2024 { .bitrate = 60,
2025 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2026 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2027 { .bitrate = 90,
2028 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2029 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2030 { .bitrate = 120,
2031 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2032 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2033 { .bitrate = 180,
2034 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2035 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2036 { .bitrate = 240,
2037 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2038 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2039 { .bitrate = 360,
2040 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2041 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2042 { .bitrate = 480,
2043 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2044 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2045 { .bitrate = 540,
2046 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2047 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2048};
2049
2050/* 5 GHz band channels for WL1273 */
2051static struct ieee80211_channel wl1271_channels_5ghz[] = {
2052 { .hw_value = 183, .center_freq = 4915},
2053 { .hw_value = 184, .center_freq = 4920},
2054 { .hw_value = 185, .center_freq = 4925},
2055 { .hw_value = 187, .center_freq = 4935},
2056 { .hw_value = 188, .center_freq = 4940},
2057 { .hw_value = 189, .center_freq = 4945},
2058 { .hw_value = 192, .center_freq = 4960},
2059 { .hw_value = 196, .center_freq = 4980},
2060 { .hw_value = 7, .center_freq = 5035},
2061 { .hw_value = 8, .center_freq = 5040},
2062 { .hw_value = 9, .center_freq = 5045},
2063 { .hw_value = 11, .center_freq = 5055},
2064 { .hw_value = 12, .center_freq = 5060},
2065 { .hw_value = 16, .center_freq = 5080},
2066 { .hw_value = 34, .center_freq = 5170},
2067 { .hw_value = 36, .center_freq = 5180},
2068 { .hw_value = 38, .center_freq = 5190},
2069 { .hw_value = 40, .center_freq = 5200},
2070 { .hw_value = 42, .center_freq = 5210},
2071 { .hw_value = 44, .center_freq = 5220},
2072 { .hw_value = 46, .center_freq = 5230},
2073 { .hw_value = 48, .center_freq = 5240},
2074 { .hw_value = 52, .center_freq = 5260},
2075 { .hw_value = 56, .center_freq = 5280},
2076 { .hw_value = 60, .center_freq = 5300},
2077 { .hw_value = 64, .center_freq = 5320},
2078 { .hw_value = 100, .center_freq = 5500},
2079 { .hw_value = 104, .center_freq = 5520},
2080 { .hw_value = 108, .center_freq = 5540},
2081 { .hw_value = 112, .center_freq = 5560},
2082 { .hw_value = 116, .center_freq = 5580},
2083 { .hw_value = 120, .center_freq = 5600},
2084 { .hw_value = 124, .center_freq = 5620},
2085 { .hw_value = 128, .center_freq = 5640},
2086 { .hw_value = 132, .center_freq = 5660},
2087 { .hw_value = 136, .center_freq = 5680},
2088 { .hw_value = 140, .center_freq = 5700},
2089 { .hw_value = 149, .center_freq = 5745},
2090 { .hw_value = 153, .center_freq = 5765},
2091 { .hw_value = 157, .center_freq = 5785},
2092 { .hw_value = 161, .center_freq = 5805},
2093 { .hw_value = 165, .center_freq = 5825},
2094};
2095
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002096/* mapping to indexes for wl1271_rates_5ghz */
2097const static u8 wl1271_rate_to_idx_5ghz[] = {
2098 /* MCS rates are used only with 11n */
2099 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2100 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2101 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2102 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2103 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2104 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2105 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2106 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2107
2108 7, /* CONF_HW_RXTX_RATE_54 */
2109 6, /* CONF_HW_RXTX_RATE_48 */
2110 5, /* CONF_HW_RXTX_RATE_36 */
2111 4, /* CONF_HW_RXTX_RATE_24 */
2112
2113 /* TI-specific rate */
2114 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2115
2116 3, /* CONF_HW_RXTX_RATE_18 */
2117 2, /* CONF_HW_RXTX_RATE_12 */
2118 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2119 1, /* CONF_HW_RXTX_RATE_9 */
2120 0, /* CONF_HW_RXTX_RATE_6 */
2121 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2122 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2123 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2124};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002125
2126static struct ieee80211_supported_band wl1271_band_5ghz = {
2127 .channels = wl1271_channels_5ghz,
2128 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2129 .bitrates = wl1271_rates_5ghz,
2130 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
2131};
2132
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002133const static u8 *wl1271_band_rate_to_idx[] = {
2134 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2135 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2136};
2137
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002138static const struct ieee80211_ops wl1271_ops = {
2139 .start = wl1271_op_start,
2140 .stop = wl1271_op_stop,
2141 .add_interface = wl1271_op_add_interface,
2142 .remove_interface = wl1271_op_remove_interface,
2143 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002144 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002145 .configure_filter = wl1271_op_configure_filter,
2146 .tx = wl1271_op_tx,
2147 .set_key = wl1271_op_set_key,
2148 .hw_scan = wl1271_op_hw_scan,
2149 .bss_info_changed = wl1271_op_bss_info_changed,
2150 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002151 .conf_tx = wl1271_op_conf_tx,
Kalle Valoc8c90872010-02-18 13:25:53 +02002152 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002153};
2154
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002155
2156u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
2157{
2158 u8 idx;
2159
2160 BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
2161
2162 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2163 wl1271_error("Illegal RX rate from HW: %d", rate);
2164 return 0;
2165 }
2166
2167 idx = wl1271_band_rate_to_idx[wl->band][rate];
2168 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2169 wl1271_error("Unsupported RX rate from HW: %d", rate);
2170 return 0;
2171 }
2172
2173 return idx;
2174}
2175
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002176static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2177 struct device_attribute *attr,
2178 char *buf)
2179{
2180 struct wl1271 *wl = dev_get_drvdata(dev);
2181 ssize_t len;
2182
2183 /* FIXME: what's the maximum length of buf? page size?*/
2184 len = 500;
2185
2186 mutex_lock(&wl->mutex);
2187 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2188 wl->sg_enabled);
2189 mutex_unlock(&wl->mutex);
2190
2191 return len;
2192
2193}
2194
2195static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2196 struct device_attribute *attr,
2197 const char *buf, size_t count)
2198{
2199 struct wl1271 *wl = dev_get_drvdata(dev);
2200 unsigned long res;
2201 int ret;
2202
2203 ret = strict_strtoul(buf, 10, &res);
2204
2205 if (ret < 0) {
2206 wl1271_warning("incorrect value written to bt_coex_mode");
2207 return count;
2208 }
2209
2210 mutex_lock(&wl->mutex);
2211
2212 res = !!res;
2213
2214 if (res == wl->sg_enabled)
2215 goto out;
2216
2217 wl->sg_enabled = res;
2218
2219 if (wl->state == WL1271_STATE_OFF)
2220 goto out;
2221
2222 ret = wl1271_ps_elp_wakeup(wl, false);
2223 if (ret < 0)
2224 goto out;
2225
2226 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2227 wl1271_ps_elp_sleep(wl);
2228
2229 out:
2230 mutex_unlock(&wl->mutex);
2231 return count;
2232}
2233
2234static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2235 wl1271_sysfs_show_bt_coex_state,
2236 wl1271_sysfs_store_bt_coex_state);
2237
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002238int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002239{
2240 int ret;
2241
2242 if (wl->mac80211_registered)
2243 return 0;
2244
2245 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2246
2247 ret = ieee80211_register_hw(wl->hw);
2248 if (ret < 0) {
2249 wl1271_error("unable to register mac80211 hw: %d", ret);
2250 return ret;
2251 }
2252
2253 wl->mac80211_registered = true;
2254
2255 wl1271_notice("loaded");
2256
2257 return 0;
2258}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002259EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002260
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002261void wl1271_unregister_hw(struct wl1271 *wl)
2262{
2263 ieee80211_unregister_hw(wl->hw);
2264 wl->mac80211_registered = false;
2265
2266}
2267EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2268
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002269int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002270{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002271 /* The tx descriptor buffer and the TKIP space. */
2272 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2273 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002274
2275 /* unit us */
2276 /* FIXME: find a proper value */
2277 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002278 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002279
2280 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03002281 IEEE80211_HW_NOISE_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002282 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002283 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002284 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002285 IEEE80211_HW_HAS_RATE_CONTROL |
2286 IEEE80211_HW_CONNECTION_MONITOR;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002287
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002288 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2289 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002290 wl->hw->wiphy->max_scan_ssids = 1;
2291 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
2292
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002293 if (wl1271_11a_enabled())
2294 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
2295
Kalle Valo12bd8942010-03-18 12:26:33 +02002296 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002297 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002298
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002299 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002300
2301 return 0;
2302}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002303EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002304
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002305#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002306
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002307struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002308{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002309 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002310 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002311 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002312 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002313
2314 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2315 if (!hw) {
2316 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002317 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002318 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002319 }
2320
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002321 plat_dev = kmalloc(sizeof(wl1271_device), GFP_KERNEL);
2322 if (!plat_dev) {
2323 wl1271_error("could not allocate platform_device");
2324 ret = -ENOMEM;
2325 goto err_plat_alloc;
2326 }
2327
2328 memcpy(plat_dev, &wl1271_device, sizeof(wl1271_device));
2329
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002330 wl = hw->priv;
2331 memset(wl, 0, sizeof(*wl));
2332
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002333 INIT_LIST_HEAD(&wl->list);
2334
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002335 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002336 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002337
2338 skb_queue_head_init(&wl->tx_queue);
2339
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002340 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002341 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002342 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002343 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002344 wl->rx_counter = 0;
2345 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2346 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002347 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002348 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002349 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002350 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002351 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2352 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002353 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002354 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002355 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002356 wl->sg_enabled = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002357
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002358 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002359 wl->tx_frames[i] = NULL;
2360
2361 spin_lock_init(&wl->wl_lock);
2362
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002363 wl->state = WL1271_STATE_OFF;
2364 mutex_init(&wl->mutex);
2365
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002366 /* Apply default driver configuration. */
2367 wl1271_conf_init(wl);
2368
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002369 wl1271_debugfs_init(wl);
2370
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002371 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002372 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002373 if (ret) {
2374 wl1271_error("couldn't register platform device");
2375 goto err_hw;
2376 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002377 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002378
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002379 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002380 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002381 if (ret < 0) {
2382 wl1271_error("failed to create sysfs file bt_coex_state");
2383 goto err_platform;
2384 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002385
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002386 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002387
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002388err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002389 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002390
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002391err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002392 wl1271_debugfs_exit(wl);
2393 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002394
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002395err_plat_alloc:
2396 ieee80211_free_hw(hw);
2397
2398err_hw_alloc:
2399
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002400 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002401}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002402EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002403
2404int wl1271_free_hw(struct wl1271 *wl)
2405{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002406 platform_device_unregister(wl->plat_dev);
2407 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002408
2409 wl1271_debugfs_exit(wl);
2410
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002411 vfree(wl->fw);
2412 wl->fw = NULL;
2413 kfree(wl->nvs);
2414 wl->nvs = NULL;
2415
2416 kfree(wl->fw_status);
2417 kfree(wl->tx_res_if);
2418
2419 ieee80211_free_hw(wl->hw);
2420
2421 return 0;
2422}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002423EXPORT_SYMBOL_GPL(wl1271_free_hw);
2424
2425MODULE_LICENSE("GPL");
2426MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2427MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");