blob: 65a1aeba2419116f793a5cfba18ffae7b44839d7 [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>
25#include <linux/platform_device.h>
26#include <linux/interrupt.h>
27#include <linux/firmware.h>
28#include <linux/delay.h>
29#include <linux/irq.h>
30#include <linux/spi/spi.h>
31#include <linux/crc32.h>
32#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030033#include <linux/vmalloc.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030034#include <linux/spi/wl12xx.h>
Juuso Oikarinen01c09162009-10-13 12:47:55 +030035#include <linux/inetdevice.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090036#include <linux/slab.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030037
38#include "wl1271.h"
39#include "wl12xx_80211.h"
40#include "wl1271_reg.h"
41#include "wl1271_spi.h"
Teemu Paasikivi7b048c52010-02-18 13:25:55 +020042#include "wl1271_io.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030043#include "wl1271_event.h"
44#include "wl1271_tx.h"
45#include "wl1271_rx.h"
46#include "wl1271_ps.h"
47#include "wl1271_init.h"
48#include "wl1271_debugfs.h"
49#include "wl1271_cmd.h"
50#include "wl1271_boot.h"
Kalle Valoc8c90872010-02-18 13:25:53 +020051#include "wl1271_testmode.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030052
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020053#define WL1271_BOOT_RETRIES 3
54
Juuso Oikarinen8a080482009-10-13 12:47:44 +030055static struct conf_drv_settings default_conf = {
56 .sg = {
57 .per_threshold = 7500,
58 .max_scan_compensation_time = 120000,
59 .nfs_sample_interval = 400,
60 .load_ratio = 50,
61 .auto_ps_mode = 0,
62 .probe_req_compensation = 170,
63 .scan_window_compensation = 50,
64 .antenna_config = 0,
65 .beacon_miss_threshold = 60,
66 .rate_adaptation_threshold = CONF_HW_BIT_RATE_12MBPS,
67 .rate_adaptation_snr = 0
68 },
69 .rx = {
70 .rx_msdu_life_time = 512000,
71 .packet_detection_threshold = 0,
72 .ps_poll_timeout = 15,
73 .upsd_timeout = 15,
74 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +020075 .rx_cca_threshold = 0,
76 .irq_blk_threshold = 0xFFFF,
77 .irq_pkt_threshold = 0,
78 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +030079 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
80 },
81 .tx = {
82 .tx_energy_detection = 0,
83 .rc_conf = {
Juuso Oikarinenec078d92009-12-11 15:41:05 +020084 .enabled_rates = CONF_HW_BIT_RATE_1MBPS |
85 CONF_HW_BIT_RATE_2MBPS,
Juuso Oikarinen8a080482009-10-13 12:47:44 +030086 .short_retry_limit = 10,
87 .long_retry_limit = 10,
88 .aflags = 0
89 },
90 .ac_conf_count = 4,
91 .ac_conf = {
92 [0] = {
93 .ac = CONF_TX_AC_BE,
94 .cw_min = 15,
95 .cw_max = 63,
96 .aifsn = 3,
97 .tx_op_limit = 0,
98 },
99 [1] = {
100 .ac = CONF_TX_AC_BK,
101 .cw_min = 15,
102 .cw_max = 63,
103 .aifsn = 7,
104 .tx_op_limit = 0,
105 },
106 [2] = {
107 .ac = CONF_TX_AC_VI,
108 .cw_min = 15,
109 .cw_max = 63,
110 .aifsn = CONF_TX_AIFS_PIFS,
111 .tx_op_limit = 3008,
112 },
113 [3] = {
114 .ac = CONF_TX_AC_VO,
115 .cw_min = 15,
116 .cw_max = 63,
117 .aifsn = CONF_TX_AIFS_PIFS,
118 .tx_op_limit = 1504,
119 },
120 },
121 .tid_conf_count = 7,
122 .tid_conf = {
123 [0] = {
124 .queue_id = 0,
125 .channel_type = CONF_CHANNEL_TYPE_DCF,
126 .tsid = CONF_TX_AC_BE,
127 .ps_scheme = CONF_PS_SCHEME_LEGACY,
128 .ack_policy = CONF_ACK_POLICY_LEGACY,
129 .apsd_conf = {0, 0},
130 },
131 [1] = {
132 .queue_id = 1,
133 .channel_type = CONF_CHANNEL_TYPE_DCF,
134 .tsid = CONF_TX_AC_BE,
135 .ps_scheme = CONF_PS_SCHEME_LEGACY,
136 .ack_policy = CONF_ACK_POLICY_LEGACY,
137 .apsd_conf = {0, 0},
138 },
139 [2] = {
140 .queue_id = 2,
141 .channel_type = CONF_CHANNEL_TYPE_DCF,
142 .tsid = CONF_TX_AC_BE,
143 .ps_scheme = CONF_PS_SCHEME_LEGACY,
144 .ack_policy = CONF_ACK_POLICY_LEGACY,
145 .apsd_conf = {0, 0},
146 },
147 [3] = {
148 .queue_id = 3,
149 .channel_type = CONF_CHANNEL_TYPE_DCF,
150 .tsid = CONF_TX_AC_BE,
151 .ps_scheme = CONF_PS_SCHEME_LEGACY,
152 .ack_policy = CONF_ACK_POLICY_LEGACY,
153 .apsd_conf = {0, 0},
154 },
155 [4] = {
156 .queue_id = 4,
157 .channel_type = CONF_CHANNEL_TYPE_DCF,
158 .tsid = CONF_TX_AC_BE,
159 .ps_scheme = CONF_PS_SCHEME_LEGACY,
160 .ack_policy = CONF_ACK_POLICY_LEGACY,
161 .apsd_conf = {0, 0},
162 },
163 [5] = {
164 .queue_id = 5,
165 .channel_type = CONF_CHANNEL_TYPE_DCF,
166 .tsid = CONF_TX_AC_BE,
167 .ps_scheme = CONF_PS_SCHEME_LEGACY,
168 .ack_policy = CONF_ACK_POLICY_LEGACY,
169 .apsd_conf = {0, 0},
170 },
171 [6] = {
172 .queue_id = 6,
173 .channel_type = CONF_CHANNEL_TYPE_DCF,
174 .tsid = CONF_TX_AC_BE,
175 .ps_scheme = CONF_PS_SCHEME_LEGACY,
176 .ack_policy = CONF_ACK_POLICY_LEGACY,
177 .apsd_conf = {0, 0},
178 }
179 },
180 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200181 .tx_compl_timeout = 700,
182 .tx_compl_threshold = 4
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300183 },
184 .conn = {
185 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
186 .listen_interval = 0,
187 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
188 .bcn_filt_ie_count = 1,
189 .bcn_filt_ie = {
190 [0] = {
191 .ie = WLAN_EID_CHANNEL_SWITCH,
192 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
193 }
194 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200195 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300196 .bss_lose_timeout = 100,
197 .beacon_rx_timeout = 10000,
198 .broadcast_timeout = 20000,
199 .rx_broadcast_in_ps = 1,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200200 .ps_poll_threshold = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300201 .sig_trigger_count = 2,
202 .sig_trigger = {
203 [0] = {
204 .threshold = -75,
205 .pacing = 500,
206 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
207 .type = CONF_TRIG_EVENT_TYPE_EDGE,
208 .direction = CONF_TRIG_EVENT_DIR_LOW,
209 .hysteresis = 2,
210 .index = 0,
211 .enable = 1
212 },
213 [1] = {
214 .threshold = -75,
215 .pacing = 500,
216 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
217 .type = CONF_TRIG_EVENT_TYPE_EDGE,
218 .direction = CONF_TRIG_EVENT_DIR_HIGH,
219 .hysteresis = 2,
220 .index = 1,
221 .enable = 1
222 }
223 },
224 .sig_weights = {
225 .rssi_bcn_avg_weight = 10,
226 .rssi_pkt_avg_weight = 10,
227 .snr_bcn_avg_weight = 10,
228 .snr_pkt_avg_weight = 10
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300229 },
230 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200231 .bet_max_consecutive = 10,
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200232 .psm_entry_retries = 3
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300233 },
234 .init = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300235 .radioparam = {
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200236 .fem = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300237 }
Luciano Coelho6e92b412009-12-11 15:40:50 +0200238 },
239 .itrim = {
240 .enable = false,
241 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200242 },
243 .pm_config = {
244 .host_clk_settling_time = 5000,
245 .host_fast_wakeup_support = false
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300246 }
247};
248
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300249static LIST_HEAD(wl_list);
250
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300251static void wl1271_conf_init(struct wl1271 *wl)
252{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300253
254 /*
255 * This function applies the default configuration to the driver. This
256 * function is invoked upon driver load (spi probe.)
257 *
258 * The configuration is stored in a run-time structure in order to
259 * facilitate for run-time adjustment of any of the parameters. Making
260 * changes to the configuration structure will apply the new values on
261 * the next interface up (wl1271_op_start.)
262 */
263
264 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300265 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300266}
267
268
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300269static int wl1271_plt_init(struct wl1271 *wl)
270{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200271 struct conf_tx_ac_category *conf_ac;
272 struct conf_tx_tid *conf_tid;
273 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300274
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200275 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200276 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200277 return ret;
278
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200279 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200280 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200281 return ret;
282
Luciano Coelho12419cc2010-02-18 13:25:44 +0200283 ret = wl1271_init_templates_config(wl);
284 if (ret < 0)
285 return ret;
286
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300287 ret = wl1271_acx_init_mem_config(wl);
288 if (ret < 0)
289 return ret;
290
Luciano Coelho12419cc2010-02-18 13:25:44 +0200291 /* PHY layer config */
292 ret = wl1271_init_phy_config(wl);
293 if (ret < 0)
294 goto out_free_memmap;
295
296 ret = wl1271_acx_dco_itrim_params(wl);
297 if (ret < 0)
298 goto out_free_memmap;
299
300 /* Initialize connection monitoring thresholds */
301 ret = wl1271_acx_conn_monit_params(wl);
302 if (ret < 0)
303 goto out_free_memmap;
304
305 /* Bluetooth WLAN coexistence */
306 ret = wl1271_init_pta(wl);
307 if (ret < 0)
308 goto out_free_memmap;
309
310 /* Energy detection */
311 ret = wl1271_init_energy_detection(wl);
312 if (ret < 0)
313 goto out_free_memmap;
314
315 /* Default fragmentation threshold */
316 ret = wl1271_acx_frag_threshold(wl);
317 if (ret < 0)
318 goto out_free_memmap;
319
320 /* Default TID configuration */
321 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
322 conf_tid = &wl->conf.tx.tid_conf[i];
323 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
324 conf_tid->channel_type,
325 conf_tid->tsid,
326 conf_tid->ps_scheme,
327 conf_tid->ack_policy,
328 conf_tid->apsd_conf[0],
329 conf_tid->apsd_conf[1]);
330 if (ret < 0)
331 goto out_free_memmap;
332 }
333
334 /* Default AC configuration */
335 for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
336 conf_ac = &wl->conf.tx.ac_conf[i];
337 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
338 conf_ac->cw_max, conf_ac->aifsn,
339 conf_ac->tx_op_limit);
340 if (ret < 0)
341 goto out_free_memmap;
342 }
343
344 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200345 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300346 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200347 goto out_free_memmap;
348
349 /* Configure for CAM power saving (ie. always active) */
350 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
351 if (ret < 0)
352 goto out_free_memmap;
353
354 /* configure PM */
355 ret = wl1271_acx_pm_config(wl);
356 if (ret < 0)
357 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300358
359 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200360
361 out_free_memmap:
362 kfree(wl->target_mem_map);
363 wl->target_mem_map = NULL;
364
365 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300366}
367
368static void wl1271_disable_interrupts(struct wl1271 *wl)
369{
370 disable_irq(wl->irq);
371}
372
373static void wl1271_power_off(struct wl1271 *wl)
374{
375 wl->set_power(false);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200376 clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300377}
378
379static void wl1271_power_on(struct wl1271 *wl)
380{
381 wl->set_power(true);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200382 set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300383}
384
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300385static void wl1271_fw_status(struct wl1271 *wl,
386 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300387{
388 u32 total = 0;
389 int i;
390
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200391 wl1271_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300392
393 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
394 "drv_rx_counter = %d, tx_results_counter = %d)",
395 status->intr,
396 status->fw_rx_counter,
397 status->drv_rx_counter,
398 status->tx_results_counter);
399
400 /* update number of available TX blocks */
401 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300402 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
403 wl->tx_blocks_freed[i];
404
405 wl->tx_blocks_freed[i] =
406 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300407 wl->tx_blocks_available += cnt;
408 total += cnt;
409 }
410
411 /* if more blocks are available now, schedule some tx work */
412 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300413 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300414
415 /* update the host-chipset time offset */
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300416 wl->time_offset = jiffies_to_usecs(jiffies) -
417 le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300418}
419
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300420static void wl1271_irq_work(struct work_struct *work)
421{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300422 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300423 u32 intr;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300424 struct wl1271 *wl =
425 container_of(work, struct wl1271, irq_work);
426
427 mutex_lock(&wl->mutex);
428
429 wl1271_debug(DEBUG_IRQ, "IRQ work");
430
431 if (wl->state == WL1271_STATE_OFF)
432 goto out;
433
434 ret = wl1271_ps_elp_wakeup(wl, true);
435 if (ret < 0)
436 goto out;
437
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200438 wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300439
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300440 wl1271_fw_status(wl, wl->fw_status);
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300441 intr = le32_to_cpu(wl->fw_status->intr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300442 if (!intr) {
443 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
444 goto out_sleep;
445 }
446
447 intr &= WL1271_INTR_MASK;
448
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300449 if (intr & WL1271_ACX_INTR_EVENT_A) {
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300450 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
Juuso Oikarinen13f2dc52009-12-11 15:40:59 +0200451 wl1271_event_handle(wl, 0);
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300452 }
453
454 if (intr & WL1271_ACX_INTR_EVENT_B) {
455 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
Juuso Oikarinen13f2dc52009-12-11 15:40:59 +0200456 wl1271_event_handle(wl, 1);
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300457 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300458
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300459 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
460 wl1271_debug(DEBUG_IRQ,
461 "WL1271_ACX_INTR_INIT_COMPLETE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300462
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300463 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
464 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300465
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300466 if (intr & WL1271_ACX_INTR_DATA) {
467 u8 tx_res_cnt = wl->fw_status->tx_results_counter -
468 wl->tx_results_count;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300469
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300470 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300471
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300472 /* check for tx results */
473 if (tx_res_cnt)
474 wl1271_tx_complete(wl, tx_res_cnt);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300475
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300476 wl1271_rx(wl, wl->fw_status);
477 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300478
479out_sleep:
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200480 wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
481 WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300482 wl1271_ps_elp_sleep(wl);
483
484out:
485 mutex_unlock(&wl->mutex);
486}
487
488static irqreturn_t wl1271_irq(int irq, void *cookie)
489{
490 struct wl1271 *wl;
491 unsigned long flags;
492
493 wl1271_debug(DEBUG_IRQ, "IRQ");
494
495 wl = cookie;
496
497 /* complete the ELP completion */
498 spin_lock_irqsave(&wl->wl_lock, flags);
499 if (wl->elp_compl) {
500 complete(wl->elp_compl);
501 wl->elp_compl = NULL;
502 }
503
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300504 ieee80211_queue_work(wl->hw, &wl->irq_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300505 spin_unlock_irqrestore(&wl->wl_lock, flags);
506
507 return IRQ_HANDLED;
508}
509
510static int wl1271_fetch_firmware(struct wl1271 *wl)
511{
512 const struct firmware *fw;
513 int ret;
514
515 ret = request_firmware(&fw, WL1271_FW_NAME, &wl->spi->dev);
516
517 if (ret < 0) {
518 wl1271_error("could not get firmware: %d", ret);
519 return ret;
520 }
521
522 if (fw->size % 4) {
523 wl1271_error("firmware size is not multiple of 32 bits: %zu",
524 fw->size);
525 ret = -EILSEQ;
526 goto out;
527 }
528
529 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300530 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300531
532 if (!wl->fw) {
533 wl1271_error("could not allocate memory for the firmware");
534 ret = -ENOMEM;
535 goto out;
536 }
537
538 memcpy(wl->fw, fw->data, wl->fw_len);
539
540 ret = 0;
541
542out:
543 release_firmware(fw);
544
545 return ret;
546}
547
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200548static int wl1271_update_mac_addr(struct wl1271 *wl)
549{
550 int ret = 0;
551 u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
552
553 /* get mac address from the NVS */
554 wl->mac_addr[0] = nvs_ptr[11];
555 wl->mac_addr[1] = nvs_ptr[10];
556 wl->mac_addr[2] = nvs_ptr[6];
557 wl->mac_addr[3] = nvs_ptr[5];
558 wl->mac_addr[4] = nvs_ptr[4];
559 wl->mac_addr[5] = nvs_ptr[3];
560
561 /* FIXME: if it is a zero-address, we should bail out. Now, instead,
562 we randomize an address */
563 if (is_zero_ether_addr(wl->mac_addr)) {
564 static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
565 memcpy(wl->mac_addr, nokia_oui, 3);
566 get_random_bytes(wl->mac_addr + 3, 3);
Juuso Oikarinene2e77b52010-02-18 13:25:46 +0200567
568 /* update this address to the NVS */
569 nvs_ptr[11] = wl->mac_addr[0];
570 nvs_ptr[10] = wl->mac_addr[1];
571 nvs_ptr[6] = wl->mac_addr[2];
572 nvs_ptr[5] = wl->mac_addr[3];
573 nvs_ptr[4] = wl->mac_addr[4];
574 nvs_ptr[3] = wl->mac_addr[5];
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200575 }
576
577 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
578
579 return ret;
580}
581
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300582static int wl1271_fetch_nvs(struct wl1271 *wl)
583{
584 const struct firmware *fw;
585 int ret;
586
587 ret = request_firmware(&fw, WL1271_NVS_NAME, &wl->spi->dev);
588
589 if (ret < 0) {
590 wl1271_error("could not get nvs file: %d", ret);
591 return ret;
592 }
593
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200594 if (fw->size != sizeof(struct wl1271_nvs_file)) {
595 wl1271_error("nvs size is not as expected: %zu != %zu",
596 fw->size, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300597 ret = -EILSEQ;
598 goto out;
599 }
600
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200601 wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300602
603 if (!wl->nvs) {
604 wl1271_error("could not allocate memory for the nvs file");
605 ret = -ENOMEM;
606 goto out;
607 }
608
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200609 memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300610
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200611 ret = wl1271_update_mac_addr(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300612
613out:
614 release_firmware(fw);
615
616 return ret;
617}
618
619static void wl1271_fw_wakeup(struct wl1271 *wl)
620{
621 u32 elp_reg;
622
623 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300624 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300625}
626
627static int wl1271_setup(struct wl1271 *wl)
628{
629 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
630 if (!wl->fw_status)
631 return -ENOMEM;
632
633 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
634 if (!wl->tx_res_if) {
635 kfree(wl->fw_status);
636 return -ENOMEM;
637 }
638
639 INIT_WORK(&wl->irq_work, wl1271_irq_work);
640 INIT_WORK(&wl->tx_work, wl1271_tx_work);
641 return 0;
642}
643
644static int wl1271_chip_wakeup(struct wl1271 *wl)
645{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300646 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300647 int ret = 0;
648
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200649 msleep(WL1271_PRE_POWER_ON_SLEEP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300650 wl1271_power_on(wl);
651 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200652 wl1271_io_reset(wl);
653 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300654
655 /* We don't need a real memory partition here, because we only want
656 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300657 memset(&partition, 0, sizeof(partition));
658 partition.reg.start = REGISTERS_BASE;
659 partition.reg.size = REGISTERS_DOWN_SIZE;
660 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300661
662 /* ELP module wake up */
663 wl1271_fw_wakeup(wl);
664
665 /* whal_FwCtrl_BootSm() */
666
667 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200668 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300669
670 /* 1. check if chip id is valid */
671
672 switch (wl->chip.id) {
673 case CHIP_ID_1271_PG10:
674 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
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 case CHIP_ID_1271_PG20:
682 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
683 wl->chip.id);
684
685 ret = wl1271_setup(wl);
686 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200687 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300688 break;
689 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200690 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300691 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200692 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300693 }
694
695 if (wl->fw == NULL) {
696 ret = wl1271_fetch_firmware(wl);
697 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200698 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300699 }
700
701 /* No NVS from netlink, try to get it from the filesystem */
702 if (wl->nvs == NULL) {
703 ret = wl1271_fetch_nvs(wl);
704 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200705 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300706 }
707
708out:
709 return ret;
710}
711
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300712int wl1271_plt_start(struct wl1271 *wl)
713{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200714 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300715 int ret;
716
717 mutex_lock(&wl->mutex);
718
719 wl1271_notice("power up");
720
721 if (wl->state != WL1271_STATE_OFF) {
722 wl1271_error("cannot go into PLT state because not "
723 "in off state: %d", wl->state);
724 ret = -EBUSY;
725 goto out;
726 }
727
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200728 while (retries) {
729 retries--;
730 ret = wl1271_chip_wakeup(wl);
731 if (ret < 0)
732 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300733
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200734 ret = wl1271_boot(wl);
735 if (ret < 0)
736 goto power_off;
737
738 ret = wl1271_plt_init(wl);
739 if (ret < 0)
740 goto irq_disable;
741
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200742 wl->state = WL1271_STATE_PLT;
743 wl1271_notice("firmware booted in PLT mode (%s)",
744 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300745 goto out;
746
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200747irq_disable:
748 wl1271_disable_interrupts(wl);
749 mutex_unlock(&wl->mutex);
750 /* Unlocking the mutex in the middle of handling is
751 inherently unsafe. In this case we deem it safe to do,
752 because we need to let any possibly pending IRQ out of
753 the system (and while we are WL1271_STATE_OFF the IRQ
754 work function will not do anything.) Also, any other
755 possible concurrent operations will fail due to the
756 current state, hence the wl1271 struct should be safe. */
757 cancel_work_sync(&wl->irq_work);
758 mutex_lock(&wl->mutex);
759power_off:
760 wl1271_power_off(wl);
761 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300762
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200763 wl1271_error("firmware boot in PLT mode failed despite %d retries",
764 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300765out:
766 mutex_unlock(&wl->mutex);
767
768 return ret;
769}
770
771int wl1271_plt_stop(struct wl1271 *wl)
772{
773 int ret = 0;
774
775 mutex_lock(&wl->mutex);
776
777 wl1271_notice("power down");
778
779 if (wl->state != WL1271_STATE_PLT) {
780 wl1271_error("cannot power down because not in PLT "
781 "state: %d", wl->state);
782 ret = -EBUSY;
783 goto out;
784 }
785
786 wl1271_disable_interrupts(wl);
787 wl1271_power_off(wl);
788
789 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300790 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300791
792out:
793 mutex_unlock(&wl->mutex);
794
795 return ret;
796}
797
798
799static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
800{
801 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200802 struct ieee80211_conf *conf = &hw->conf;
803 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
804 struct ieee80211_sta *sta = txinfo->control.sta;
805 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300806
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200807 /* peek into the rates configured in the STA entry */
808 spin_lock_irqsave(&wl->wl_lock, flags);
809 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
810 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
811 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
812 }
813 spin_unlock_irqrestore(&wl->wl_lock, flags);
814
815 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300816 skb_queue_tail(&wl->tx_queue, skb);
817
818 /*
819 * The chip specific setup must run before the first TX packet -
820 * before that, the tx_work will not be initialized!
821 */
822
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300823 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300824
825 /*
826 * The workqueue is slow to process the tx_queue and we need stop
827 * the queue here, otherwise the queue will get too long.
828 */
829 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) {
830 ieee80211_stop_queues(wl->hw);
831
832 /*
833 * FIXME: this is racy, the variable is not properly
834 * protected. Maybe fix this by removing the stupid
835 * variable altogether and checking the real queue state?
836 */
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200837 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300838 }
839
840 return NETDEV_TX_OK;
841}
842
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300843static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
844 void *arg)
845{
846 struct net_device *dev;
847 struct wireless_dev *wdev;
848 struct wiphy *wiphy;
849 struct ieee80211_hw *hw;
850 struct wl1271 *wl;
851 struct wl1271 *wl_temp;
852 struct in_device *idev;
853 struct in_ifaddr *ifa = arg;
854 int ret = 0;
855
856 /* FIXME: this ugly function should probably be implemented in the
857 * mac80211, and here should only be a simple callback handling actual
858 * setting of the filters. Now we need to dig up references to
859 * various structures to gain access to what we need.
860 * Also, because of this, there is no "initial" setting of the filter
861 * in "op_start", because we don't want to dig up struct net_device
862 * there - the filter will be set upon first change of the interface
863 * IP address. */
864
865 dev = ifa->ifa_dev->dev;
866
867 wdev = dev->ieee80211_ptr;
868 if (wdev == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200869 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300870
871 wiphy = wdev->wiphy;
872 if (wiphy == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200873 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300874
875 hw = wiphy_priv(wiphy);
876 if (hw == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200877 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300878
879 /* Check that the interface is one supported by this driver. */
880 wl_temp = hw->priv;
881 list_for_each_entry(wl, &wl_list, list) {
882 if (wl == wl_temp)
883 break;
884 }
885 if (wl == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200886 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300887
888 /* Get the interface IP address for the device. "ifa" will become
889 NULL if:
890 - there is no IPV4 protocol address configured
891 - there are multiple (virtual) IPV4 addresses configured
892 When "ifa" is NULL, filtering will be disabled.
893 */
894 ifa = NULL;
895 idev = dev->ip_ptr;
896 if (idev)
897 ifa = idev->ifa_list;
898
899 if (ifa && ifa->ifa_next)
900 ifa = NULL;
901
902 mutex_lock(&wl->mutex);
903
904 if (wl->state == WL1271_STATE_OFF)
905 goto out;
906
907 ret = wl1271_ps_elp_wakeup(wl, false);
908 if (ret < 0)
909 goto out;
910 if (ifa)
911 ret = wl1271_acx_arp_ip_filter(wl, true,
912 (u8 *)&ifa->ifa_address,
913 ACX_IPV4_VERSION);
914 else
915 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
916 ACX_IPV4_VERSION);
917 wl1271_ps_elp_sleep(wl);
918
919out:
920 mutex_unlock(&wl->mutex);
921
Luciano Coelho17d72652009-11-23 23:22:15 +0200922 return NOTIFY_OK;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300923}
924
925static struct notifier_block wl1271_dev_notifier = {
926 .notifier_call = wl1271_dev_notify,
927};
928
929
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300930static int wl1271_op_start(struct ieee80211_hw *hw)
931{
932 struct wl1271 *wl = hw->priv;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200933 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300934 int ret = 0;
935
936 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
937
938 mutex_lock(&wl->mutex);
939
940 if (wl->state != WL1271_STATE_OFF) {
941 wl1271_error("cannot start because not in off state: %d",
942 wl->state);
943 ret = -EBUSY;
944 goto out;
945 }
946
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200947 while (retries) {
948 retries--;
949 ret = wl1271_chip_wakeup(wl);
950 if (ret < 0)
951 goto power_off;
952
953 ret = wl1271_boot(wl);
954 if (ret < 0)
955 goto power_off;
956
957 ret = wl1271_hw_init(wl);
958 if (ret < 0)
959 goto irq_disable;
960
961 wl->state = WL1271_STATE_ON;
962 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300963 goto out;
964
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200965irq_disable:
966 wl1271_disable_interrupts(wl);
967 mutex_unlock(&wl->mutex);
968 /* Unlocking the mutex in the middle of handling is
969 inherently unsafe. In this case we deem it safe to do,
970 because we need to let any possibly pending IRQ out of
971 the system (and while we are WL1271_STATE_OFF the IRQ
972 work function will not do anything.) Also, any other
973 possible concurrent operations will fail due to the
974 current state, hence the wl1271 struct should be safe. */
975 cancel_work_sync(&wl->irq_work);
976 mutex_lock(&wl->mutex);
977power_off:
978 wl1271_power_off(wl);
979 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300980
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200981 wl1271_error("firmware boot failed despite %d retries",
982 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300983out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300984 mutex_unlock(&wl->mutex);
985
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300986 if (!ret) {
987 list_add(&wl->list, &wl_list);
988 register_inetaddr_notifier(&wl1271_dev_notifier);
989 }
990
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300991 return ret;
992}
993
994static void wl1271_op_stop(struct ieee80211_hw *hw)
995{
996 struct wl1271 *wl = hw->priv;
997 int i;
998
999 wl1271_info("down");
1000
1001 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1002
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001003 unregister_inetaddr_notifier(&wl1271_dev_notifier);
1004 list_del(&wl->list);
1005
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001006 mutex_lock(&wl->mutex);
1007
1008 WARN_ON(wl->state != WL1271_STATE_ON);
1009
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001010 if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001011 mutex_unlock(&wl->mutex);
1012 ieee80211_scan_completed(wl->hw, true);
1013 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001014 }
1015
1016 wl->state = WL1271_STATE_OFF;
1017
1018 wl1271_disable_interrupts(wl);
1019
1020 mutex_unlock(&wl->mutex);
1021
1022 cancel_work_sync(&wl->irq_work);
1023 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001024
1025 mutex_lock(&wl->mutex);
1026
1027 /* let's notify MAC80211 about the remaining pending TX frames */
1028 wl1271_tx_flush(wl);
1029 wl1271_power_off(wl);
1030
1031 memset(wl->bssid, 0, ETH_ALEN);
1032 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1033 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001034 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001035 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001036
1037 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001038 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001039 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1040 wl->tx_blocks_available = 0;
1041 wl->tx_results_count = 0;
1042 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001043 wl->tx_security_last_seq = 0;
1044 wl->tx_security_seq_16 = 0;
1045 wl->tx_security_seq_32 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001046 wl->time_offset = 0;
1047 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001048 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1049 wl->sta_rate_set = 0;
1050 wl->flags = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001051
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001052 for (i = 0; i < NUM_TX_QUEUES; i++)
1053 wl->tx_blocks_freed[i] = 0;
1054
1055 wl1271_debugfs_reset(wl);
1056 mutex_unlock(&wl->mutex);
1057}
1058
1059static int wl1271_op_add_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +01001060 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001061{
1062 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001063 int ret = 0;
1064
John W. Linvillee5539bc2009-08-18 10:50:34 -04001065 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Johannes Berg1ed32e42009-12-23 13:15:45 +01001066 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001067
1068 mutex_lock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001069 if (wl->vif) {
1070 ret = -EBUSY;
1071 goto out;
1072 }
1073
Johannes Berg1ed32e42009-12-23 13:15:45 +01001074 wl->vif = vif;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001075
Johannes Berg1ed32e42009-12-23 13:15:45 +01001076 switch (vif->type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001077 case NL80211_IFTYPE_STATION:
1078 wl->bss_type = BSS_TYPE_STA_BSS;
1079 break;
1080 case NL80211_IFTYPE_ADHOC:
1081 wl->bss_type = BSS_TYPE_IBSS;
1082 break;
1083 default:
1084 ret = -EOPNOTSUPP;
1085 goto out;
1086 }
1087
1088 /* FIXME: what if conf->mac_addr changes? */
1089
1090out:
1091 mutex_unlock(&wl->mutex);
1092 return ret;
1093}
1094
1095static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +01001096 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001097{
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001098 struct wl1271 *wl = hw->priv;
1099
1100 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001101 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001102 wl->vif = NULL;
1103 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001104}
1105
1106#if 0
1107static int wl1271_op_config_interface(struct ieee80211_hw *hw,
1108 struct ieee80211_vif *vif,
1109 struct ieee80211_if_conf *conf)
1110{
1111 struct wl1271 *wl = hw->priv;
1112 struct sk_buff *beacon;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001113 int ret;
1114
David S. Miller32646902009-09-17 10:18:30 -07001115 wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM",
1116 conf->bssid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001117 wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid,
1118 conf->ssid_len);
1119
1120 mutex_lock(&wl->mutex);
1121
1122 ret = wl1271_ps_elp_wakeup(wl, false);
1123 if (ret < 0)
1124 goto out;
1125
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001126 if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
1127 wl1271_debug(DEBUG_MAC80211, "bssid changed");
1128
1129 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
1130
1131 ret = wl1271_cmd_join(wl);
1132 if (ret < 0)
1133 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001134
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001135 ret = wl1271_cmd_build_null_data(wl);
1136 if (ret < 0)
1137 goto out_sleep;
1138 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001139
1140 wl->ssid_len = conf->ssid_len;
1141 if (wl->ssid_len)
1142 memcpy(wl->ssid, conf->ssid, wl->ssid_len);
1143
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001144 if (conf->changed & IEEE80211_IFCC_BEACON) {
1145 beacon = ieee80211_beacon_get(hw, vif);
1146 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1147 beacon->data, beacon->len);
1148
1149 if (ret < 0) {
1150 dev_kfree_skb(beacon);
1151 goto out_sleep;
1152 }
1153
1154 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE,
1155 beacon->data, beacon->len);
1156
1157 dev_kfree_skb(beacon);
1158
1159 if (ret < 0)
1160 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001161 }
1162
1163out_sleep:
1164 wl1271_ps_elp_sleep(wl);
1165
1166out:
1167 mutex_unlock(&wl->mutex);
1168
1169 return ret;
1170}
1171#endif
1172
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001173static int wl1271_join_channel(struct wl1271 *wl, int channel)
1174{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001175 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001176 /* we need to use a dummy BSSID for now */
1177 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1178 0xad, 0xbe, 0xef };
1179
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001180 /* the dummy join is not required for ad-hoc */
1181 if (wl->bss_type == BSS_TYPE_IBSS)
1182 goto out;
1183
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001184 /* disable mac filter, so we hear everything */
1185 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1186
1187 wl->channel = channel;
1188 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1189
1190 ret = wl1271_cmd_join(wl);
1191 if (ret < 0)
1192 goto out;
1193
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001194 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001195
1196out:
1197 return ret;
1198}
1199
1200static int wl1271_unjoin_channel(struct wl1271 *wl)
1201{
1202 int ret;
1203
1204 /* to stop listening to a channel, we disconnect */
1205 ret = wl1271_cmd_disconnect(wl);
1206 if (ret < 0)
1207 goto out;
1208
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001209 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001210 wl->channel = 0;
1211 memset(wl->bssid, 0, ETH_ALEN);
1212 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1213
1214out:
1215 return ret;
1216}
1217
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001218static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1219{
1220 struct wl1271 *wl = hw->priv;
1221 struct ieee80211_conf *conf = &hw->conf;
1222 int channel, ret = 0;
1223
1224 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1225
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001226 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001227 channel,
1228 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001229 conf->power_level,
1230 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001231
1232 mutex_lock(&wl->mutex);
1233
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001234 wl->band = conf->channel->band;
1235
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001236 ret = wl1271_ps_elp_wakeup(wl, false);
1237 if (ret < 0)
1238 goto out;
1239
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001240 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001241 if (conf->flags & IEEE80211_CONF_IDLE &&
1242 test_bit(WL1271_FLAG_JOINED, &wl->flags))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001243 wl1271_unjoin_channel(wl);
Juuso Oikarinen8f648c02009-12-11 15:41:10 +02001244 else if (!(conf->flags & IEEE80211_CONF_IDLE))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001245 wl1271_join_channel(wl, channel);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001246
1247 if (conf->flags & IEEE80211_CONF_IDLE) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001248 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1249 wl->sta_rate_set = 0;
1250 wl1271_acx_rate_policies(wl);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001251 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001252 }
1253
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001254 /* if the channel changes while joined, join again */
Juuso Oikarinenddb01a52010-02-18 13:25:37 +02001255 if (channel != wl->channel &&
1256 test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1257 wl->channel = channel;
1258 /* FIXME: maybe use CMD_CHANNEL_SWITCH for this? */
1259 ret = wl1271_cmd_join(wl);
1260 if (ret < 0)
1261 wl1271_warning("cmd join to update channel failed %d",
1262 ret);
1263 } else
1264 wl->channel = channel;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001265
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001266 if (conf->flags & IEEE80211_CONF_PS &&
1267 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1268 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001269
1270 /*
1271 * We enter PSM only if we're already associated.
1272 * If we're not, we'll enter it when joining an SSID,
1273 * through the bss_info_changed() hook.
1274 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001275 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001276 wl1271_info("psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001277 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1278 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001279 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001280 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001281 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001282 wl1271_info("psm disabled");
1283
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001284 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001285
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001286 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001287 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1288 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001289 }
1290
1291 if (conf->power_level != wl->power_level) {
1292 ret = wl1271_acx_tx_power(wl, conf->power_level);
1293 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001294 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001295
1296 wl->power_level = conf->power_level;
1297 }
1298
1299out_sleep:
1300 wl1271_ps_elp_sleep(wl);
1301
1302out:
1303 mutex_unlock(&wl->mutex);
1304
1305 return ret;
1306}
1307
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001308struct wl1271_filter_params {
1309 bool enabled;
1310 int mc_list_length;
1311 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1312};
1313
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001314static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1315 struct dev_addr_list *mc_list)
1316{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001317 struct wl1271_filter_params *fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001318 int i;
1319
Juuso Oikarinen74441132009-10-13 12:47:53 +03001320 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001321 if (!fp) {
1322 wl1271_error("Out of memory setting filters.");
1323 return 0;
1324 }
1325
1326 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001327 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001328 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1329 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001330 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001331 }
1332
1333 fp->mc_list_length = 0;
1334 for (i = 0; i < mc_count; i++) {
1335 if (mc_list->da_addrlen == ETH_ALEN) {
1336 memcpy(fp->mc_list[fp->mc_list_length],
1337 mc_list->da_addr, ETH_ALEN);
1338 fp->mc_list_length++;
1339 } else
1340 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001341 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001342 }
1343
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001344 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001345}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001346
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001347#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1348 FIF_ALLMULTI | \
1349 FIF_FCSFAIL | \
1350 FIF_BCN_PRBRESP_PROMISC | \
1351 FIF_CONTROL | \
1352 FIF_OTHER_BSS)
1353
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001354static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1355 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001356 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001357{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001358 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001359 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001360 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001361
1362 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1363
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001364 mutex_lock(&wl->mutex);
1365
1366 if (wl->state == WL1271_STATE_OFF)
1367 goto out;
1368
1369 ret = wl1271_ps_elp_wakeup(wl, false);
1370 if (ret < 0)
1371 goto out;
1372
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001373 *total &= WL1271_SUPPORTED_FILTERS;
1374 changed &= WL1271_SUPPORTED_FILTERS;
1375
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001376 if (*total & FIF_ALLMULTI)
1377 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1378 else if (fp)
1379 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1380 fp->mc_list,
1381 fp->mc_list_length);
1382 if (ret < 0)
1383 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001384
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001385 kfree(fp);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001386
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001387 /* FIXME: We still need to set our filters properly */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001388
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001389 /* determine, whether supported filter values have changed */
1390 if (changed == 0)
1391 goto out_sleep;
1392
1393 /* apply configured filters */
1394 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1395 if (ret < 0)
1396 goto out_sleep;
1397
1398out_sleep:
1399 wl1271_ps_elp_sleep(wl);
1400
1401out:
1402 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001403}
1404
1405static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1406 struct ieee80211_vif *vif,
1407 struct ieee80211_sta *sta,
1408 struct ieee80211_key_conf *key_conf)
1409{
1410 struct wl1271 *wl = hw->priv;
1411 const u8 *addr;
1412 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001413 u32 tx_seq_32 = 0;
1414 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001415 u8 key_type;
1416
1417 static const u8 bcast_addr[ETH_ALEN] =
1418 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1419
1420 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1421
1422 addr = sta ? sta->addr : bcast_addr;
1423
1424 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1425 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1426 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1427 key_conf->alg, key_conf->keyidx,
1428 key_conf->keylen, key_conf->flags);
1429 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1430
1431 if (is_zero_ether_addr(addr)) {
1432 /* We dont support TX only encryption */
1433 ret = -EOPNOTSUPP;
1434 goto out;
1435 }
1436
1437 mutex_lock(&wl->mutex);
1438
1439 ret = wl1271_ps_elp_wakeup(wl, false);
1440 if (ret < 0)
1441 goto out_unlock;
1442
1443 switch (key_conf->alg) {
1444 case ALG_WEP:
1445 key_type = KEY_WEP;
1446
1447 key_conf->hw_key_idx = key_conf->keyidx;
1448 break;
1449 case ALG_TKIP:
1450 key_type = KEY_TKIP;
1451
1452 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001453 tx_seq_32 = wl->tx_security_seq_32;
1454 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001455 break;
1456 case ALG_CCMP:
1457 key_type = KEY_AES;
1458
1459 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001460 tx_seq_32 = wl->tx_security_seq_32;
1461 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001462 break;
1463 default:
1464 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1465
1466 ret = -EOPNOTSUPP;
1467 goto out_sleep;
1468 }
1469
1470 switch (cmd) {
1471 case SET_KEY:
1472 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1473 key_conf->keyidx, key_type,
1474 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001475 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001476 if (ret < 0) {
1477 wl1271_error("Could not add or replace key");
1478 goto out_sleep;
1479 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001480
1481 /* the default WEP key needs to be configured at least once */
1482 if (key_type == KEY_WEP) {
1483 ret = wl1271_cmd_set_default_wep_key(wl,
1484 wl->default_key);
1485 if (ret < 0)
1486 goto out_sleep;
1487 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001488 break;
1489
1490 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001491 /* The wl1271 does not allow to remove unicast keys - they
1492 will be cleared automatically on next CMD_JOIN. Ignore the
1493 request silently, as we dont want the mac80211 to emit
1494 an error message. */
1495 if (!is_broadcast_ether_addr(addr))
1496 break;
1497
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001498 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1499 key_conf->keyidx, key_type,
1500 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001501 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001502 if (ret < 0) {
1503 wl1271_error("Could not remove key");
1504 goto out_sleep;
1505 }
1506 break;
1507
1508 default:
1509 wl1271_error("Unsupported key cmd 0x%x", cmd);
1510 ret = -EOPNOTSUPP;
1511 goto out_sleep;
1512
1513 break;
1514 }
1515
1516out_sleep:
1517 wl1271_ps_elp_sleep(wl);
1518
1519out_unlock:
1520 mutex_unlock(&wl->mutex);
1521
1522out:
1523 return ret;
1524}
1525
1526static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1527 struct cfg80211_scan_request *req)
1528{
1529 struct wl1271 *wl = hw->priv;
1530 int ret;
1531 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001532 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001533
1534 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1535
1536 if (req->n_ssids) {
1537 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001538 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001539 }
1540
1541 mutex_lock(&wl->mutex);
1542
1543 ret = wl1271_ps_elp_wakeup(wl, false);
1544 if (ret < 0)
1545 goto out;
1546
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001547 if (wl1271_11a_enabled())
1548 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1549 WL1271_SCAN_BAND_DUAL, 3);
1550 else
1551 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1552 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001553
1554 wl1271_ps_elp_sleep(wl);
1555
1556out:
1557 mutex_unlock(&wl->mutex);
1558
1559 return ret;
1560}
1561
1562static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1563{
1564 struct wl1271 *wl = hw->priv;
1565 int ret;
1566
1567 mutex_lock(&wl->mutex);
1568
1569 ret = wl1271_ps_elp_wakeup(wl, false);
1570 if (ret < 0)
1571 goto out;
1572
1573 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1574 if (ret < 0)
1575 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1576
1577 wl1271_ps_elp_sleep(wl);
1578
1579out:
1580 mutex_unlock(&wl->mutex);
1581
1582 return ret;
1583}
1584
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001585static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1586{
1587 u8 *ptr = beacon->data +
1588 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1589
1590 /* find the location of the ssid in the beacon */
1591 while (ptr < beacon->data + beacon->len) {
1592 if (ptr[0] == WLAN_EID_SSID) {
1593 wl->ssid_len = ptr[1];
1594 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1595 return;
1596 }
1597 ptr += ptr[1];
1598 }
1599 wl1271_error("ad-hoc beacon template has no SSID!\n");
1600}
1601
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001602static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1603 struct ieee80211_vif *vif,
1604 struct ieee80211_bss_conf *bss_conf,
1605 u32 changed)
1606{
1607 enum wl1271_cmd_ps_mode mode;
1608 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001609 bool do_join = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001610 int ret;
1611
1612 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1613
1614 mutex_lock(&wl->mutex);
1615
1616 ret = wl1271_ps_elp_wakeup(wl, false);
1617 if (ret < 0)
1618 goto out;
1619
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001620 if (wl->bss_type == BSS_TYPE_IBSS) {
1621 /* FIXME: This implements rudimentary ad-hoc support -
1622 proper templates are on the wish list and notification
1623 on when they change. This patch will update the templates
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001624 on every call to this function. */
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001625 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1626
1627 if (beacon) {
1628 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001629
1630 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001631 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1632 beacon->data,
1633 beacon->len);
1634
1635 if (ret < 0) {
1636 dev_kfree_skb(beacon);
1637 goto out_sleep;
1638 }
1639
1640 hdr = (struct ieee80211_hdr *) beacon->data;
1641 hdr->frame_control = cpu_to_le16(
1642 IEEE80211_FTYPE_MGMT |
1643 IEEE80211_STYPE_PROBE_RESP);
1644
1645 ret = wl1271_cmd_template_set(wl,
1646 CMD_TEMPL_PROBE_RESPONSE,
1647 beacon->data,
1648 beacon->len);
1649 dev_kfree_skb(beacon);
1650 if (ret < 0)
1651 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001652
1653 /* Need to update the SSID (for filtering etc) */
1654 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001655 }
1656 }
1657
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001658 if ((changed & BSS_CHANGED_BSSID) &&
1659 /*
1660 * Now we know the correct bssid, so we send a new join command
1661 * and enable the BSSID filter
1662 */
1663 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
1664 wl->rx_config |= CFG_BSSID_FILTER_EN;
1665 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
1666 ret = wl1271_cmd_build_null_data(wl);
1667 if (ret < 0) {
1668 wl1271_warning("cmd buld null data failed %d",
1669 ret);
1670 goto out_sleep;
1671 }
1672
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001673 /* Need to update the BSSID (for filtering etc) */
1674 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001675 }
1676
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001677 if (changed & BSS_CHANGED_ASSOC) {
1678 if (bss_conf->assoc) {
1679 wl->aid = bss_conf->aid;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001680 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001681
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001682 /*
1683 * with wl1271, we don't need to update the
1684 * beacon_int and dtim_period, because the firmware
1685 * updates it by itself when the first beacon is
1686 * received after a join.
1687 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001688 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1689 if (ret < 0)
1690 goto out_sleep;
1691
1692 ret = wl1271_acx_aid(wl, wl->aid);
1693 if (ret < 0)
1694 goto out_sleep;
1695
1696 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001697 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1698 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001699 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001700 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001701 if (ret < 0)
1702 goto out_sleep;
1703 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001704 } else {
1705 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001706 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001707 wl->aid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001708 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001709
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001710 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001711
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001712 if (changed & BSS_CHANGED_ERP_SLOT) {
1713 if (bss_conf->use_short_slot)
1714 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1715 else
1716 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1717 if (ret < 0) {
1718 wl1271_warning("Set slot time failed %d", ret);
1719 goto out_sleep;
1720 }
1721 }
1722
1723 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1724 if (bss_conf->use_short_preamble)
1725 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1726 else
1727 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1728 }
1729
1730 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1731 if (bss_conf->use_cts_prot)
1732 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1733 else
1734 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1735 if (ret < 0) {
1736 wl1271_warning("Set ctsprotect failed %d", ret);
1737 goto out_sleep;
1738 }
1739 }
1740
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001741 if (do_join) {
1742 ret = wl1271_cmd_join(wl);
1743 if (ret < 0) {
1744 wl1271_warning("cmd join failed %d", ret);
1745 goto out_sleep;
1746 }
1747 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1748 }
1749
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001750out_sleep:
1751 wl1271_ps_elp_sleep(wl);
1752
1753out:
1754 mutex_unlock(&wl->mutex);
1755}
1756
Kalle Valoc6999d82010-02-18 13:25:41 +02001757static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1758 const struct ieee80211_tx_queue_params *params)
1759{
1760 struct wl1271 *wl = hw->priv;
1761 int ret;
1762
1763 mutex_lock(&wl->mutex);
1764
1765 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1766
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001767 ret = wl1271_ps_elp_wakeup(wl, false);
1768 if (ret < 0)
1769 goto out;
1770
Kalle Valoc6999d82010-02-18 13:25:41 +02001771 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1772 params->cw_min, params->cw_max,
1773 params->aifs, params->txop);
1774 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001775 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001776
1777 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1778 CONF_CHANNEL_TYPE_EDCF,
1779 wl1271_tx_get_queue(queue),
1780 CONF_PS_SCHEME_LEGACY_PSPOLL,
1781 CONF_ACK_POLICY_LEGACY, 0, 0);
1782 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001783 goto out_sleep;
1784
1785out_sleep:
1786 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001787
1788out:
1789 mutex_unlock(&wl->mutex);
1790
1791 return ret;
1792}
1793
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001794
1795/* can't be const, mac80211 writes to this */
1796static struct ieee80211_rate wl1271_rates[] = {
1797 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001798 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1799 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001800 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001801 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1802 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001803 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1804 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001805 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1806 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001807 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1808 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001809 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1810 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001811 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1812 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001813 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1814 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001815 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001816 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1817 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001818 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001819 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1820 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001821 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001822 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1823 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001824 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001825 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1826 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001827 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001828 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1829 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001830 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001831 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1832 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001833 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001834 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1835 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001836};
1837
1838/* can't be const, mac80211 writes to this */
1839static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001840 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1841 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1842 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1843 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1844 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1845 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1846 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1847 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1848 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1849 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1850 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1851 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1852 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001853};
1854
1855/* can't be const, mac80211 writes to this */
1856static struct ieee80211_supported_band wl1271_band_2ghz = {
1857 .channels = wl1271_channels,
1858 .n_channels = ARRAY_SIZE(wl1271_channels),
1859 .bitrates = wl1271_rates,
1860 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1861};
1862
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001863/* 5 GHz data rates for WL1273 */
1864static struct ieee80211_rate wl1271_rates_5ghz[] = {
1865 { .bitrate = 60,
1866 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1867 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
1868 { .bitrate = 90,
1869 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1870 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
1871 { .bitrate = 120,
1872 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1873 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
1874 { .bitrate = 180,
1875 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1876 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
1877 { .bitrate = 240,
1878 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1879 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
1880 { .bitrate = 360,
1881 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1882 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
1883 { .bitrate = 480,
1884 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1885 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
1886 { .bitrate = 540,
1887 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1888 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
1889};
1890
1891/* 5 GHz band channels for WL1273 */
1892static struct ieee80211_channel wl1271_channels_5ghz[] = {
1893 { .hw_value = 183, .center_freq = 4915},
1894 { .hw_value = 184, .center_freq = 4920},
1895 { .hw_value = 185, .center_freq = 4925},
1896 { .hw_value = 187, .center_freq = 4935},
1897 { .hw_value = 188, .center_freq = 4940},
1898 { .hw_value = 189, .center_freq = 4945},
1899 { .hw_value = 192, .center_freq = 4960},
1900 { .hw_value = 196, .center_freq = 4980},
1901 { .hw_value = 7, .center_freq = 5035},
1902 { .hw_value = 8, .center_freq = 5040},
1903 { .hw_value = 9, .center_freq = 5045},
1904 { .hw_value = 11, .center_freq = 5055},
1905 { .hw_value = 12, .center_freq = 5060},
1906 { .hw_value = 16, .center_freq = 5080},
1907 { .hw_value = 34, .center_freq = 5170},
1908 { .hw_value = 36, .center_freq = 5180},
1909 { .hw_value = 38, .center_freq = 5190},
1910 { .hw_value = 40, .center_freq = 5200},
1911 { .hw_value = 42, .center_freq = 5210},
1912 { .hw_value = 44, .center_freq = 5220},
1913 { .hw_value = 46, .center_freq = 5230},
1914 { .hw_value = 48, .center_freq = 5240},
1915 { .hw_value = 52, .center_freq = 5260},
1916 { .hw_value = 56, .center_freq = 5280},
1917 { .hw_value = 60, .center_freq = 5300},
1918 { .hw_value = 64, .center_freq = 5320},
1919 { .hw_value = 100, .center_freq = 5500},
1920 { .hw_value = 104, .center_freq = 5520},
1921 { .hw_value = 108, .center_freq = 5540},
1922 { .hw_value = 112, .center_freq = 5560},
1923 { .hw_value = 116, .center_freq = 5580},
1924 { .hw_value = 120, .center_freq = 5600},
1925 { .hw_value = 124, .center_freq = 5620},
1926 { .hw_value = 128, .center_freq = 5640},
1927 { .hw_value = 132, .center_freq = 5660},
1928 { .hw_value = 136, .center_freq = 5680},
1929 { .hw_value = 140, .center_freq = 5700},
1930 { .hw_value = 149, .center_freq = 5745},
1931 { .hw_value = 153, .center_freq = 5765},
1932 { .hw_value = 157, .center_freq = 5785},
1933 { .hw_value = 161, .center_freq = 5805},
1934 { .hw_value = 165, .center_freq = 5825},
1935};
1936
1937
1938static struct ieee80211_supported_band wl1271_band_5ghz = {
1939 .channels = wl1271_channels_5ghz,
1940 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
1941 .bitrates = wl1271_rates_5ghz,
1942 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
1943};
1944
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001945static const struct ieee80211_ops wl1271_ops = {
1946 .start = wl1271_op_start,
1947 .stop = wl1271_op_stop,
1948 .add_interface = wl1271_op_add_interface,
1949 .remove_interface = wl1271_op_remove_interface,
1950 .config = wl1271_op_config,
1951/* .config_interface = wl1271_op_config_interface, */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001952 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001953 .configure_filter = wl1271_op_configure_filter,
1954 .tx = wl1271_op_tx,
1955 .set_key = wl1271_op_set_key,
1956 .hw_scan = wl1271_op_hw_scan,
1957 .bss_info_changed = wl1271_op_bss_info_changed,
1958 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02001959 .conf_tx = wl1271_op_conf_tx,
Kalle Valoc8c90872010-02-18 13:25:53 +02001960 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001961};
1962
1963static int wl1271_register_hw(struct wl1271 *wl)
1964{
1965 int ret;
1966
1967 if (wl->mac80211_registered)
1968 return 0;
1969
1970 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
1971
1972 ret = ieee80211_register_hw(wl->hw);
1973 if (ret < 0) {
1974 wl1271_error("unable to register mac80211 hw: %d", ret);
1975 return ret;
1976 }
1977
1978 wl->mac80211_registered = true;
1979
1980 wl1271_notice("loaded");
1981
1982 return 0;
1983}
1984
1985static int wl1271_init_ieee80211(struct wl1271 *wl)
1986{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03001987 /* The tx descriptor buffer and the TKIP space. */
1988 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
1989 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001990
1991 /* unit us */
1992 /* FIXME: find a proper value */
1993 wl->hw->channel_change_time = 10000;
1994
1995 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03001996 IEEE80211_HW_NOISE_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02001997 IEEE80211_HW_BEACON_FILTER |
1998 IEEE80211_HW_SUPPORTS_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001999
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002000 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2001 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002002 wl->hw->wiphy->max_scan_ssids = 1;
2003 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
2004
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002005 if (wl1271_11a_enabled())
2006 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
2007
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002008 SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
2009
2010 return 0;
2011}
2012
2013static void wl1271_device_release(struct device *dev)
2014{
2015
2016}
2017
2018static struct platform_device wl1271_device = {
2019 .name = "wl1271",
2020 .id = -1,
2021
2022 /* device model insists to have a release function */
2023 .dev = {
2024 .release = wl1271_device_release,
2025 },
2026};
2027
2028#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002029
2030static struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002031{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002032 struct ieee80211_hw *hw;
2033 struct wl1271 *wl;
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002034 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002035
2036 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2037 if (!hw) {
2038 wl1271_error("could not alloc ieee80211_hw");
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002039 return ERR_PTR(-ENOMEM);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002040 }
2041
2042 wl = hw->priv;
2043 memset(wl, 0, sizeof(*wl));
2044
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002045 INIT_LIST_HEAD(&wl->list);
2046
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002047 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002048
2049 skb_queue_head_init(&wl->tx_queue);
2050
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002051 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002052 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002053 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002054 wl->rx_counter = 0;
2055 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2056 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002057 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002058 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002059 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002060 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2061 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002062 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002063 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002064 wl->flags = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002065
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002066 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002067 wl->tx_frames[i] = NULL;
2068
2069 spin_lock_init(&wl->wl_lock);
2070
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002071 wl->state = WL1271_STATE_OFF;
2072 mutex_init(&wl->mutex);
2073
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002074 /* Apply default driver configuration. */
2075 wl1271_conf_init(wl);
2076
2077 return hw;
2078}
2079
2080int wl1271_free_hw(struct wl1271 *wl)
2081{
2082 ieee80211_unregister_hw(wl->hw);
2083
2084 wl1271_debugfs_exit(wl);
2085
2086 kfree(wl->target_mem_map);
2087 vfree(wl->fw);
2088 wl->fw = NULL;
2089 kfree(wl->nvs);
2090 wl->nvs = NULL;
2091
2092 kfree(wl->fw_status);
2093 kfree(wl->tx_res_if);
2094
2095 ieee80211_free_hw(wl->hw);
2096
2097 return 0;
2098}
2099
2100static int __devinit wl1271_probe(struct spi_device *spi)
2101{
2102 struct wl12xx_platform_data *pdata;
2103 struct ieee80211_hw *hw;
2104 struct wl1271 *wl;
2105 int ret;
2106
2107 pdata = spi->dev.platform_data;
2108 if (!pdata) {
2109 wl1271_error("no platform data");
2110 return -ENODEV;
2111 }
2112
2113 hw = wl1271_alloc_hw();
2114 if (IS_ERR(hw))
2115 return PTR_ERR(hw);
2116
2117 wl = hw->priv;
2118
2119 dev_set_drvdata(&spi->dev, wl);
2120 wl->spi = spi;
2121
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002122 /* This is the only SPI value that we need to set here, the rest
2123 * comes from the board-peripherals file */
2124 spi->bits_per_word = 32;
2125
2126 ret = spi_setup(spi);
2127 if (ret < 0) {
2128 wl1271_error("spi_setup failed");
2129 goto out_free;
2130 }
2131
2132 wl->set_power = pdata->set_power;
2133 if (!wl->set_power) {
2134 wl1271_error("set power function missing in platform data");
2135 ret = -ENODEV;
2136 goto out_free;
2137 }
2138
2139 wl->irq = spi->irq;
2140 if (wl->irq < 0) {
2141 wl1271_error("irq missing in platform data");
2142 ret = -ENODEV;
2143 goto out_free;
2144 }
2145
2146 ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
2147 if (ret < 0) {
2148 wl1271_error("request_irq() failed: %d", ret);
2149 goto out_free;
2150 }
2151
2152 set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
2153
2154 disable_irq(wl->irq);
2155
2156 ret = platform_device_register(&wl1271_device);
2157 if (ret) {
2158 wl1271_error("couldn't register platform device");
2159 goto out_irq;
2160 }
2161 dev_set_drvdata(&wl1271_device.dev, wl);
2162
2163 ret = wl1271_init_ieee80211(wl);
2164 if (ret)
2165 goto out_platform;
2166
2167 ret = wl1271_register_hw(wl);
2168 if (ret)
2169 goto out_platform;
2170
2171 wl1271_debugfs_init(wl);
2172
2173 wl1271_notice("initialized");
2174
2175 return 0;
2176
2177 out_platform:
2178 platform_device_unregister(&wl1271_device);
2179
2180 out_irq:
2181 free_irq(wl->irq, wl);
2182
2183 out_free:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002184 ieee80211_free_hw(hw);
2185
2186 return ret;
2187}
2188
2189static int __devexit wl1271_remove(struct spi_device *spi)
2190{
2191 struct wl1271 *wl = dev_get_drvdata(&spi->dev);
2192
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002193 platform_device_unregister(&wl1271_device);
2194 free_irq(wl->irq, wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002195
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002196 wl1271_free_hw(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002197
2198 return 0;
2199}
2200
2201
2202static struct spi_driver wl1271_spi_driver = {
2203 .driver = {
2204 .name = "wl1271",
2205 .bus = &spi_bus_type,
2206 .owner = THIS_MODULE,
2207 },
2208
2209 .probe = wl1271_probe,
2210 .remove = __devexit_p(wl1271_remove),
2211};
2212
2213static int __init wl1271_init(void)
2214{
2215 int ret;
2216
2217 ret = spi_register_driver(&wl1271_spi_driver);
2218 if (ret < 0) {
2219 wl1271_error("failed to register spi driver: %d", ret);
2220 goto out;
2221 }
2222
2223out:
2224 return ret;
2225}
2226
2227static void __exit wl1271_exit(void)
2228{
2229 spi_unregister_driver(&wl1271_spi_driver);
2230
2231 wl1271_notice("unloaded");
2232}
2233
2234module_init(wl1271_init);
2235module_exit(wl1271_exit);
2236
2237MODULE_LICENSE("GPL");
2238MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
Luciano Coelho2f018722009-10-08 21:56:27 +03002239MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
Ben Hutchings49f146d2009-11-07 22:02:15 +00002240MODULE_FIRMWARE(WL1271_FW_NAME);