blob: 310f58c66231b6771de0ed318a1a080a851475fb [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinen01c09162009-10-13 12:47:55 +030031#include <linux/inetdevice.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030032
33#include "wl1271.h"
34#include "wl12xx_80211.h"
35#include "wl1271_reg.h"
Teemu Paasikivi7b048c52010-02-18 13:25:55 +020036#include "wl1271_io.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030037#include "wl1271_event.h"
38#include "wl1271_tx.h"
39#include "wl1271_rx.h"
40#include "wl1271_ps.h"
41#include "wl1271_init.h"
42#include "wl1271_debugfs.h"
43#include "wl1271_cmd.h"
44#include "wl1271_boot.h"
Kalle Valoc8c90872010-02-18 13:25:53 +020045#include "wl1271_testmode.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030046
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020047#define WL1271_BOOT_RETRIES 3
48
Juuso Oikarinen8a080482009-10-13 12:47:44 +030049static struct conf_drv_settings default_conf = {
50 .sg = {
51 .per_threshold = 7500,
52 .max_scan_compensation_time = 120000,
53 .nfs_sample_interval = 400,
54 .load_ratio = 50,
55 .auto_ps_mode = 0,
56 .probe_req_compensation = 170,
57 .scan_window_compensation = 50,
58 .antenna_config = 0,
59 .beacon_miss_threshold = 60,
60 .rate_adaptation_threshold = CONF_HW_BIT_RATE_12MBPS,
61 .rate_adaptation_snr = 0
62 },
63 .rx = {
64 .rx_msdu_life_time = 512000,
65 .packet_detection_threshold = 0,
66 .ps_poll_timeout = 15,
67 .upsd_timeout = 15,
68 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +020069 .rx_cca_threshold = 0,
70 .irq_blk_threshold = 0xFFFF,
71 .irq_pkt_threshold = 0,
72 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +030073 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
74 },
75 .tx = {
76 .tx_energy_detection = 0,
77 .rc_conf = {
Juuso Oikarinenec078d92009-12-11 15:41:05 +020078 .enabled_rates = CONF_HW_BIT_RATE_1MBPS |
79 CONF_HW_BIT_RATE_2MBPS,
Juuso Oikarinen8a080482009-10-13 12:47:44 +030080 .short_retry_limit = 10,
81 .long_retry_limit = 10,
82 .aflags = 0
83 },
84 .ac_conf_count = 4,
85 .ac_conf = {
86 [0] = {
87 .ac = CONF_TX_AC_BE,
88 .cw_min = 15,
89 .cw_max = 63,
90 .aifsn = 3,
91 .tx_op_limit = 0,
92 },
93 [1] = {
94 .ac = CONF_TX_AC_BK,
95 .cw_min = 15,
96 .cw_max = 63,
97 .aifsn = 7,
98 .tx_op_limit = 0,
99 },
100 [2] = {
101 .ac = CONF_TX_AC_VI,
102 .cw_min = 15,
103 .cw_max = 63,
104 .aifsn = CONF_TX_AIFS_PIFS,
105 .tx_op_limit = 3008,
106 },
107 [3] = {
108 .ac = CONF_TX_AC_VO,
109 .cw_min = 15,
110 .cw_max = 63,
111 .aifsn = CONF_TX_AIFS_PIFS,
112 .tx_op_limit = 1504,
113 },
114 },
115 .tid_conf_count = 7,
116 .tid_conf = {
117 [0] = {
118 .queue_id = 0,
119 .channel_type = CONF_CHANNEL_TYPE_DCF,
120 .tsid = CONF_TX_AC_BE,
121 .ps_scheme = CONF_PS_SCHEME_LEGACY,
122 .ack_policy = CONF_ACK_POLICY_LEGACY,
123 .apsd_conf = {0, 0},
124 },
125 [1] = {
126 .queue_id = 1,
127 .channel_type = CONF_CHANNEL_TYPE_DCF,
128 .tsid = CONF_TX_AC_BE,
129 .ps_scheme = CONF_PS_SCHEME_LEGACY,
130 .ack_policy = CONF_ACK_POLICY_LEGACY,
131 .apsd_conf = {0, 0},
132 },
133 [2] = {
134 .queue_id = 2,
135 .channel_type = CONF_CHANNEL_TYPE_DCF,
136 .tsid = CONF_TX_AC_BE,
137 .ps_scheme = CONF_PS_SCHEME_LEGACY,
138 .ack_policy = CONF_ACK_POLICY_LEGACY,
139 .apsd_conf = {0, 0},
140 },
141 [3] = {
142 .queue_id = 3,
143 .channel_type = CONF_CHANNEL_TYPE_DCF,
144 .tsid = CONF_TX_AC_BE,
145 .ps_scheme = CONF_PS_SCHEME_LEGACY,
146 .ack_policy = CONF_ACK_POLICY_LEGACY,
147 .apsd_conf = {0, 0},
148 },
149 [4] = {
150 .queue_id = 4,
151 .channel_type = CONF_CHANNEL_TYPE_DCF,
152 .tsid = CONF_TX_AC_BE,
153 .ps_scheme = CONF_PS_SCHEME_LEGACY,
154 .ack_policy = CONF_ACK_POLICY_LEGACY,
155 .apsd_conf = {0, 0},
156 },
157 [5] = {
158 .queue_id = 5,
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 [6] = {
166 .queue_id = 6,
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 },
174 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200175 .tx_compl_timeout = 700,
176 .tx_compl_threshold = 4
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300177 },
178 .conn = {
179 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
180 .listen_interval = 0,
181 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
182 .bcn_filt_ie_count = 1,
183 .bcn_filt_ie = {
184 [0] = {
185 .ie = WLAN_EID_CHANNEL_SWITCH,
186 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
187 }
188 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200189 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300190 .bss_lose_timeout = 100,
191 .beacon_rx_timeout = 10000,
192 .broadcast_timeout = 20000,
193 .rx_broadcast_in_ps = 1,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200194 .ps_poll_threshold = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300195 .sig_trigger_count = 2,
196 .sig_trigger = {
197 [0] = {
198 .threshold = -75,
199 .pacing = 500,
200 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
201 .type = CONF_TRIG_EVENT_TYPE_EDGE,
202 .direction = CONF_TRIG_EVENT_DIR_LOW,
203 .hysteresis = 2,
204 .index = 0,
205 .enable = 1
206 },
207 [1] = {
208 .threshold = -75,
209 .pacing = 500,
210 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
211 .type = CONF_TRIG_EVENT_TYPE_EDGE,
212 .direction = CONF_TRIG_EVENT_DIR_HIGH,
213 .hysteresis = 2,
214 .index = 1,
215 .enable = 1
216 }
217 },
218 .sig_weights = {
219 .rssi_bcn_avg_weight = 10,
220 .rssi_pkt_avg_weight = 10,
221 .snr_bcn_avg_weight = 10,
222 .snr_pkt_avg_weight = 10
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300223 },
224 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200225 .bet_max_consecutive = 10,
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200226 .psm_entry_retries = 3
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300227 },
228 .init = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300229 .radioparam = {
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200230 .fem = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300231 }
Luciano Coelho6e92b412009-12-11 15:40:50 +0200232 },
233 .itrim = {
234 .enable = false,
235 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200236 },
237 .pm_config = {
238 .host_clk_settling_time = 5000,
239 .host_fast_wakeup_support = false
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300240 }
241};
242
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300243static LIST_HEAD(wl_list);
244
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300245static void wl1271_conf_init(struct wl1271 *wl)
246{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300247
248 /*
249 * This function applies the default configuration to the driver. This
250 * function is invoked upon driver load (spi probe.)
251 *
252 * The configuration is stored in a run-time structure in order to
253 * facilitate for run-time adjustment of any of the parameters. Making
254 * changes to the configuration structure will apply the new values on
255 * the next interface up (wl1271_op_start.)
256 */
257
258 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300259 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300260}
261
262
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300263static int wl1271_plt_init(struct wl1271 *wl)
264{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200265 struct conf_tx_ac_category *conf_ac;
266 struct conf_tx_tid *conf_tid;
267 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300268
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200269 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200270 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200271 return ret;
272
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200273 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200274 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200275 return ret;
276
Luciano Coelho12419cc2010-02-18 13:25:44 +0200277 ret = wl1271_init_templates_config(wl);
278 if (ret < 0)
279 return ret;
280
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300281 ret = wl1271_acx_init_mem_config(wl);
282 if (ret < 0)
283 return ret;
284
Luciano Coelho12419cc2010-02-18 13:25:44 +0200285 /* PHY layer config */
286 ret = wl1271_init_phy_config(wl);
287 if (ret < 0)
288 goto out_free_memmap;
289
290 ret = wl1271_acx_dco_itrim_params(wl);
291 if (ret < 0)
292 goto out_free_memmap;
293
294 /* Initialize connection monitoring thresholds */
295 ret = wl1271_acx_conn_monit_params(wl);
296 if (ret < 0)
297 goto out_free_memmap;
298
299 /* Bluetooth WLAN coexistence */
300 ret = wl1271_init_pta(wl);
301 if (ret < 0)
302 goto out_free_memmap;
303
304 /* Energy detection */
305 ret = wl1271_init_energy_detection(wl);
306 if (ret < 0)
307 goto out_free_memmap;
308
309 /* Default fragmentation threshold */
310 ret = wl1271_acx_frag_threshold(wl);
311 if (ret < 0)
312 goto out_free_memmap;
313
314 /* Default TID configuration */
315 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
316 conf_tid = &wl->conf.tx.tid_conf[i];
317 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
318 conf_tid->channel_type,
319 conf_tid->tsid,
320 conf_tid->ps_scheme,
321 conf_tid->ack_policy,
322 conf_tid->apsd_conf[0],
323 conf_tid->apsd_conf[1]);
324 if (ret < 0)
325 goto out_free_memmap;
326 }
327
328 /* Default AC configuration */
329 for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
330 conf_ac = &wl->conf.tx.ac_conf[i];
331 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
332 conf_ac->cw_max, conf_ac->aifsn,
333 conf_ac->tx_op_limit);
334 if (ret < 0)
335 goto out_free_memmap;
336 }
337
338 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200339 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300340 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200341 goto out_free_memmap;
342
343 /* Configure for CAM power saving (ie. always active) */
344 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
345 if (ret < 0)
346 goto out_free_memmap;
347
348 /* configure PM */
349 ret = wl1271_acx_pm_config(wl);
350 if (ret < 0)
351 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300352
353 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200354
355 out_free_memmap:
356 kfree(wl->target_mem_map);
357 wl->target_mem_map = NULL;
358
359 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300360}
361
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300362static void wl1271_power_off(struct wl1271 *wl)
363{
364 wl->set_power(false);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200365 clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300366}
367
368static void wl1271_power_on(struct wl1271 *wl)
369{
370 wl->set_power(true);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200371 set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300372}
373
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300374static void wl1271_fw_status(struct wl1271 *wl,
375 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300376{
377 u32 total = 0;
378 int i;
379
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200380 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300381
382 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
383 "drv_rx_counter = %d, tx_results_counter = %d)",
384 status->intr,
385 status->fw_rx_counter,
386 status->drv_rx_counter,
387 status->tx_results_counter);
388
389 /* update number of available TX blocks */
390 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300391 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
392 wl->tx_blocks_freed[i];
393
394 wl->tx_blocks_freed[i] =
395 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300396 wl->tx_blocks_available += cnt;
397 total += cnt;
398 }
399
400 /* if more blocks are available now, schedule some tx work */
401 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300402 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300403
404 /* update the host-chipset time offset */
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300405 wl->time_offset = jiffies_to_usecs(jiffies) -
406 le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300407}
408
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300409static void wl1271_irq_work(struct work_struct *work)
410{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300411 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300412 u32 intr;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300413 struct wl1271 *wl =
414 container_of(work, struct wl1271, irq_work);
415
416 mutex_lock(&wl->mutex);
417
418 wl1271_debug(DEBUG_IRQ, "IRQ work");
419
420 if (wl->state == WL1271_STATE_OFF)
421 goto out;
422
423 ret = wl1271_ps_elp_wakeup(wl, true);
424 if (ret < 0)
425 goto out;
426
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200427 wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300428
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300429 wl1271_fw_status(wl, wl->fw_status);
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300430 intr = le32_to_cpu(wl->fw_status->intr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300431 if (!intr) {
432 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
433 goto out_sleep;
434 }
435
436 intr &= WL1271_INTR_MASK;
437
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300438 if (intr & WL1271_ACX_INTR_EVENT_A) {
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300439 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
Juuso Oikarinen13f2dc52009-12-11 15:40:59 +0200440 wl1271_event_handle(wl, 0);
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300441 }
442
443 if (intr & WL1271_ACX_INTR_EVENT_B) {
444 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
Juuso Oikarinen13f2dc52009-12-11 15:40:59 +0200445 wl1271_event_handle(wl, 1);
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300446 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300447
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300448 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
449 wl1271_debug(DEBUG_IRQ,
450 "WL1271_ACX_INTR_INIT_COMPLETE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300451
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300452 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
453 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300454
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300455 if (intr & WL1271_ACX_INTR_DATA) {
456 u8 tx_res_cnt = wl->fw_status->tx_results_counter -
457 wl->tx_results_count;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300458
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300459 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300460
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300461 /* check for tx results */
462 if (tx_res_cnt)
463 wl1271_tx_complete(wl, tx_res_cnt);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300464
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300465 wl1271_rx(wl, wl->fw_status);
466 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300467
468out_sleep:
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200469 wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
470 WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300471 wl1271_ps_elp_sleep(wl);
472
473out:
474 mutex_unlock(&wl->mutex);
475}
476
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300477static int wl1271_fetch_firmware(struct wl1271 *wl)
478{
479 const struct firmware *fw;
480 int ret;
481
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200482 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300483
484 if (ret < 0) {
485 wl1271_error("could not get firmware: %d", ret);
486 return ret;
487 }
488
489 if (fw->size % 4) {
490 wl1271_error("firmware size is not multiple of 32 bits: %zu",
491 fw->size);
492 ret = -EILSEQ;
493 goto out;
494 }
495
496 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300497 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300498
499 if (!wl->fw) {
500 wl1271_error("could not allocate memory for the firmware");
501 ret = -ENOMEM;
502 goto out;
503 }
504
505 memcpy(wl->fw, fw->data, wl->fw_len);
506
507 ret = 0;
508
509out:
510 release_firmware(fw);
511
512 return ret;
513}
514
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200515static int wl1271_update_mac_addr(struct wl1271 *wl)
516{
517 int ret = 0;
518 u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
519
520 /* get mac address from the NVS */
521 wl->mac_addr[0] = nvs_ptr[11];
522 wl->mac_addr[1] = nvs_ptr[10];
523 wl->mac_addr[2] = nvs_ptr[6];
524 wl->mac_addr[3] = nvs_ptr[5];
525 wl->mac_addr[4] = nvs_ptr[4];
526 wl->mac_addr[5] = nvs_ptr[3];
527
528 /* FIXME: if it is a zero-address, we should bail out. Now, instead,
529 we randomize an address */
530 if (is_zero_ether_addr(wl->mac_addr)) {
531 static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
532 memcpy(wl->mac_addr, nokia_oui, 3);
533 get_random_bytes(wl->mac_addr + 3, 3);
Juuso Oikarinene2e77b52010-02-18 13:25:46 +0200534
535 /* update this address to the NVS */
536 nvs_ptr[11] = wl->mac_addr[0];
537 nvs_ptr[10] = wl->mac_addr[1];
538 nvs_ptr[6] = wl->mac_addr[2];
539 nvs_ptr[5] = wl->mac_addr[3];
540 nvs_ptr[4] = wl->mac_addr[4];
541 nvs_ptr[3] = wl->mac_addr[5];
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200542 }
543
544 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
545
546 return ret;
547}
548
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300549static int wl1271_fetch_nvs(struct wl1271 *wl)
550{
551 const struct firmware *fw;
552 int ret;
553
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200554 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300555
556 if (ret < 0) {
557 wl1271_error("could not get nvs file: %d", ret);
558 return ret;
559 }
560
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200561 if (fw->size != sizeof(struct wl1271_nvs_file)) {
562 wl1271_error("nvs size is not as expected: %zu != %zu",
563 fw->size, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300564 ret = -EILSEQ;
565 goto out;
566 }
567
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200568 wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300569
570 if (!wl->nvs) {
571 wl1271_error("could not allocate memory for the nvs file");
572 ret = -ENOMEM;
573 goto out;
574 }
575
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200576 memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300577
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200578 ret = wl1271_update_mac_addr(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300579
580out:
581 release_firmware(fw);
582
583 return ret;
584}
585
586static void wl1271_fw_wakeup(struct wl1271 *wl)
587{
588 u32 elp_reg;
589
590 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300591 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300592}
593
594static int wl1271_setup(struct wl1271 *wl)
595{
596 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
597 if (!wl->fw_status)
598 return -ENOMEM;
599
600 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
601 if (!wl->tx_res_if) {
602 kfree(wl->fw_status);
603 return -ENOMEM;
604 }
605
606 INIT_WORK(&wl->irq_work, wl1271_irq_work);
607 INIT_WORK(&wl->tx_work, wl1271_tx_work);
608 return 0;
609}
610
611static int wl1271_chip_wakeup(struct wl1271 *wl)
612{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300613 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300614 int ret = 0;
615
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200616 msleep(WL1271_PRE_POWER_ON_SLEEP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300617 wl1271_power_on(wl);
618 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200619 wl1271_io_reset(wl);
620 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300621
622 /* We don't need a real memory partition here, because we only want
623 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300624 memset(&partition, 0, sizeof(partition));
625 partition.reg.start = REGISTERS_BASE;
626 partition.reg.size = REGISTERS_DOWN_SIZE;
627 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300628
629 /* ELP module wake up */
630 wl1271_fw_wakeup(wl);
631
632 /* whal_FwCtrl_BootSm() */
633
634 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200635 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300636
637 /* 1. check if chip id is valid */
638
639 switch (wl->chip.id) {
640 case CHIP_ID_1271_PG10:
641 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
642 wl->chip.id);
643
644 ret = wl1271_setup(wl);
645 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200646 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300647 break;
648 case CHIP_ID_1271_PG20:
649 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
650 wl->chip.id);
651
652 ret = wl1271_setup(wl);
653 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200654 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300655 break;
656 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200657 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300658 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200659 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300660 }
661
662 if (wl->fw == NULL) {
663 ret = wl1271_fetch_firmware(wl);
664 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200665 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300666 }
667
668 /* No NVS from netlink, try to get it from the filesystem */
669 if (wl->nvs == NULL) {
670 ret = wl1271_fetch_nvs(wl);
671 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200672 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300673 }
674
675out:
676 return ret;
677}
678
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300679int wl1271_plt_start(struct wl1271 *wl)
680{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200681 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300682 int ret;
683
684 mutex_lock(&wl->mutex);
685
686 wl1271_notice("power up");
687
688 if (wl->state != WL1271_STATE_OFF) {
689 wl1271_error("cannot go into PLT state because not "
690 "in off state: %d", wl->state);
691 ret = -EBUSY;
692 goto out;
693 }
694
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200695 while (retries) {
696 retries--;
697 ret = wl1271_chip_wakeup(wl);
698 if (ret < 0)
699 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300700
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200701 ret = wl1271_boot(wl);
702 if (ret < 0)
703 goto power_off;
704
705 ret = wl1271_plt_init(wl);
706 if (ret < 0)
707 goto irq_disable;
708
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200709 wl->state = WL1271_STATE_PLT;
710 wl1271_notice("firmware booted in PLT mode (%s)",
711 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300712 goto out;
713
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200714irq_disable:
715 wl1271_disable_interrupts(wl);
716 mutex_unlock(&wl->mutex);
717 /* Unlocking the mutex in the middle of handling is
718 inherently unsafe. In this case we deem it safe to do,
719 because we need to let any possibly pending IRQ out of
720 the system (and while we are WL1271_STATE_OFF the IRQ
721 work function will not do anything.) Also, any other
722 possible concurrent operations will fail due to the
723 current state, hence the wl1271 struct should be safe. */
724 cancel_work_sync(&wl->irq_work);
725 mutex_lock(&wl->mutex);
726power_off:
727 wl1271_power_off(wl);
728 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300729
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200730 wl1271_error("firmware boot in PLT mode failed despite %d retries",
731 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300732out:
733 mutex_unlock(&wl->mutex);
734
735 return ret;
736}
737
738int wl1271_plt_stop(struct wl1271 *wl)
739{
740 int ret = 0;
741
742 mutex_lock(&wl->mutex);
743
744 wl1271_notice("power down");
745
746 if (wl->state != WL1271_STATE_PLT) {
747 wl1271_error("cannot power down because not in PLT "
748 "state: %d", wl->state);
749 ret = -EBUSY;
750 goto out;
751 }
752
753 wl1271_disable_interrupts(wl);
754 wl1271_power_off(wl);
755
756 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300757 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300758
759out:
760 mutex_unlock(&wl->mutex);
761
762 return ret;
763}
764
765
766static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
767{
768 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200769 struct ieee80211_conf *conf = &hw->conf;
770 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
771 struct ieee80211_sta *sta = txinfo->control.sta;
772 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300773
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200774 /* peek into the rates configured in the STA entry */
775 spin_lock_irqsave(&wl->wl_lock, flags);
776 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
777 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
778 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
779 }
780 spin_unlock_irqrestore(&wl->wl_lock, flags);
781
782 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300783 skb_queue_tail(&wl->tx_queue, skb);
784
785 /*
786 * The chip specific setup must run before the first TX packet -
787 * before that, the tx_work will not be initialized!
788 */
789
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300790 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300791
792 /*
793 * The workqueue is slow to process the tx_queue and we need stop
794 * the queue here, otherwise the queue will get too long.
795 */
796 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) {
797 ieee80211_stop_queues(wl->hw);
798
799 /*
800 * FIXME: this is racy, the variable is not properly
801 * protected. Maybe fix this by removing the stupid
802 * variable altogether and checking the real queue state?
803 */
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200804 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300805 }
806
807 return NETDEV_TX_OK;
808}
809
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300810static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
811 void *arg)
812{
813 struct net_device *dev;
814 struct wireless_dev *wdev;
815 struct wiphy *wiphy;
816 struct ieee80211_hw *hw;
817 struct wl1271 *wl;
818 struct wl1271 *wl_temp;
819 struct in_device *idev;
820 struct in_ifaddr *ifa = arg;
821 int ret = 0;
822
823 /* FIXME: this ugly function should probably be implemented in the
824 * mac80211, and here should only be a simple callback handling actual
825 * setting of the filters. Now we need to dig up references to
826 * various structures to gain access to what we need.
827 * Also, because of this, there is no "initial" setting of the filter
828 * in "op_start", because we don't want to dig up struct net_device
829 * there - the filter will be set upon first change of the interface
830 * IP address. */
831
832 dev = ifa->ifa_dev->dev;
833
834 wdev = dev->ieee80211_ptr;
835 if (wdev == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200836 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300837
838 wiphy = wdev->wiphy;
839 if (wiphy == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200840 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300841
842 hw = wiphy_priv(wiphy);
843 if (hw == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200844 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300845
846 /* Check that the interface is one supported by this driver. */
847 wl_temp = hw->priv;
848 list_for_each_entry(wl, &wl_list, list) {
849 if (wl == wl_temp)
850 break;
851 }
852 if (wl == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200853 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300854
855 /* Get the interface IP address for the device. "ifa" will become
856 NULL if:
857 - there is no IPV4 protocol address configured
858 - there are multiple (virtual) IPV4 addresses configured
859 When "ifa" is NULL, filtering will be disabled.
860 */
861 ifa = NULL;
862 idev = dev->ip_ptr;
863 if (idev)
864 ifa = idev->ifa_list;
865
866 if (ifa && ifa->ifa_next)
867 ifa = NULL;
868
869 mutex_lock(&wl->mutex);
870
871 if (wl->state == WL1271_STATE_OFF)
872 goto out;
873
874 ret = wl1271_ps_elp_wakeup(wl, false);
875 if (ret < 0)
876 goto out;
877 if (ifa)
878 ret = wl1271_acx_arp_ip_filter(wl, true,
879 (u8 *)&ifa->ifa_address,
880 ACX_IPV4_VERSION);
881 else
882 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
883 ACX_IPV4_VERSION);
884 wl1271_ps_elp_sleep(wl);
885
886out:
887 mutex_unlock(&wl->mutex);
888
Luciano Coelho17d72652009-11-23 23:22:15 +0200889 return NOTIFY_OK;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300890}
891
892static struct notifier_block wl1271_dev_notifier = {
893 .notifier_call = wl1271_dev_notify,
894};
895
896
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300897static int wl1271_op_start(struct ieee80211_hw *hw)
898{
899 struct wl1271 *wl = hw->priv;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200900 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300901 int ret = 0;
902
903 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
904
905 mutex_lock(&wl->mutex);
906
907 if (wl->state != WL1271_STATE_OFF) {
908 wl1271_error("cannot start because not in off state: %d",
909 wl->state);
910 ret = -EBUSY;
911 goto out;
912 }
913
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200914 while (retries) {
915 retries--;
916 ret = wl1271_chip_wakeup(wl);
917 if (ret < 0)
918 goto power_off;
919
920 ret = wl1271_boot(wl);
921 if (ret < 0)
922 goto power_off;
923
924 ret = wl1271_hw_init(wl);
925 if (ret < 0)
926 goto irq_disable;
927
928 wl->state = WL1271_STATE_ON;
929 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300930 goto out;
931
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200932irq_disable:
933 wl1271_disable_interrupts(wl);
934 mutex_unlock(&wl->mutex);
935 /* Unlocking the mutex in the middle of handling is
936 inherently unsafe. In this case we deem it safe to do,
937 because we need to let any possibly pending IRQ out of
938 the system (and while we are WL1271_STATE_OFF the IRQ
939 work function will not do anything.) Also, any other
940 possible concurrent operations will fail due to the
941 current state, hence the wl1271 struct should be safe. */
942 cancel_work_sync(&wl->irq_work);
943 mutex_lock(&wl->mutex);
944power_off:
945 wl1271_power_off(wl);
946 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300947
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200948 wl1271_error("firmware boot failed despite %d retries",
949 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300950out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300951 mutex_unlock(&wl->mutex);
952
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300953 if (!ret) {
954 list_add(&wl->list, &wl_list);
955 register_inetaddr_notifier(&wl1271_dev_notifier);
956 }
957
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300958 return ret;
959}
960
961static void wl1271_op_stop(struct ieee80211_hw *hw)
962{
963 struct wl1271 *wl = hw->priv;
964 int i;
965
966 wl1271_info("down");
967
968 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
969
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300970 unregister_inetaddr_notifier(&wl1271_dev_notifier);
971 list_del(&wl->list);
972
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300973 mutex_lock(&wl->mutex);
974
975 WARN_ON(wl->state != WL1271_STATE_ON);
976
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200977 if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300978 mutex_unlock(&wl->mutex);
979 ieee80211_scan_completed(wl->hw, true);
980 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300981 }
982
983 wl->state = WL1271_STATE_OFF;
984
985 wl1271_disable_interrupts(wl);
986
987 mutex_unlock(&wl->mutex);
988
989 cancel_work_sync(&wl->irq_work);
990 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300991
992 mutex_lock(&wl->mutex);
993
994 /* let's notify MAC80211 about the remaining pending TX frames */
995 wl1271_tx_flush(wl);
996 wl1271_power_off(wl);
997
998 memset(wl->bssid, 0, ETH_ALEN);
999 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1000 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001001 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001002 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001003
1004 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001005 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001006 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1007 wl->tx_blocks_available = 0;
1008 wl->tx_results_count = 0;
1009 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001010 wl->tx_security_last_seq = 0;
1011 wl->tx_security_seq_16 = 0;
1012 wl->tx_security_seq_32 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001013 wl->time_offset = 0;
1014 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001015 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1016 wl->sta_rate_set = 0;
1017 wl->flags = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001018
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001019 for (i = 0; i < NUM_TX_QUEUES; i++)
1020 wl->tx_blocks_freed[i] = 0;
1021
1022 wl1271_debugfs_reset(wl);
1023 mutex_unlock(&wl->mutex);
1024}
1025
1026static int wl1271_op_add_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +01001027 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001028{
1029 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001030 int ret = 0;
1031
John W. Linvillee5539bc2009-08-18 10:50:34 -04001032 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Johannes Berg1ed32e42009-12-23 13:15:45 +01001033 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001034
1035 mutex_lock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001036 if (wl->vif) {
1037 ret = -EBUSY;
1038 goto out;
1039 }
1040
Johannes Berg1ed32e42009-12-23 13:15:45 +01001041 wl->vif = vif;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001042
Johannes Berg1ed32e42009-12-23 13:15:45 +01001043 switch (vif->type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001044 case NL80211_IFTYPE_STATION:
1045 wl->bss_type = BSS_TYPE_STA_BSS;
1046 break;
1047 case NL80211_IFTYPE_ADHOC:
1048 wl->bss_type = BSS_TYPE_IBSS;
1049 break;
1050 default:
1051 ret = -EOPNOTSUPP;
1052 goto out;
1053 }
1054
1055 /* FIXME: what if conf->mac_addr changes? */
1056
1057out:
1058 mutex_unlock(&wl->mutex);
1059 return ret;
1060}
1061
1062static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +01001063 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001064{
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001065 struct wl1271 *wl = hw->priv;
1066
1067 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001068 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001069 wl->vif = NULL;
1070 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001071}
1072
1073#if 0
1074static int wl1271_op_config_interface(struct ieee80211_hw *hw,
1075 struct ieee80211_vif *vif,
1076 struct ieee80211_if_conf *conf)
1077{
1078 struct wl1271 *wl = hw->priv;
1079 struct sk_buff *beacon;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001080 int ret;
1081
David S. Miller32646902009-09-17 10:18:30 -07001082 wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM",
1083 conf->bssid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001084 wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid,
1085 conf->ssid_len);
1086
1087 mutex_lock(&wl->mutex);
1088
1089 ret = wl1271_ps_elp_wakeup(wl, false);
1090 if (ret < 0)
1091 goto out;
1092
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001093 if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
1094 wl1271_debug(DEBUG_MAC80211, "bssid changed");
1095
1096 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
1097
1098 ret = wl1271_cmd_join(wl);
1099 if (ret < 0)
1100 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001101
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001102 ret = wl1271_cmd_build_null_data(wl);
1103 if (ret < 0)
1104 goto out_sleep;
1105 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001106
1107 wl->ssid_len = conf->ssid_len;
1108 if (wl->ssid_len)
1109 memcpy(wl->ssid, conf->ssid, wl->ssid_len);
1110
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001111 if (conf->changed & IEEE80211_IFCC_BEACON) {
1112 beacon = ieee80211_beacon_get(hw, vif);
1113 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1114 beacon->data, beacon->len);
1115
1116 if (ret < 0) {
1117 dev_kfree_skb(beacon);
1118 goto out_sleep;
1119 }
1120
1121 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE,
1122 beacon->data, beacon->len);
1123
1124 dev_kfree_skb(beacon);
1125
1126 if (ret < 0)
1127 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001128 }
1129
1130out_sleep:
1131 wl1271_ps_elp_sleep(wl);
1132
1133out:
1134 mutex_unlock(&wl->mutex);
1135
1136 return ret;
1137}
1138#endif
1139
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001140static int wl1271_join_channel(struct wl1271 *wl, int channel)
1141{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001142 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001143 /* we need to use a dummy BSSID for now */
1144 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1145 0xad, 0xbe, 0xef };
1146
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001147 /* the dummy join is not required for ad-hoc */
1148 if (wl->bss_type == BSS_TYPE_IBSS)
1149 goto out;
1150
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001151 /* disable mac filter, so we hear everything */
1152 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1153
1154 wl->channel = channel;
1155 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1156
1157 ret = wl1271_cmd_join(wl);
1158 if (ret < 0)
1159 goto out;
1160
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001161 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001162
1163out:
1164 return ret;
1165}
1166
1167static int wl1271_unjoin_channel(struct wl1271 *wl)
1168{
1169 int ret;
1170
1171 /* to stop listening to a channel, we disconnect */
1172 ret = wl1271_cmd_disconnect(wl);
1173 if (ret < 0)
1174 goto out;
1175
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001176 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001177 wl->channel = 0;
1178 memset(wl->bssid, 0, ETH_ALEN);
1179 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1180
1181out:
1182 return ret;
1183}
1184
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001185static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1186{
1187 struct wl1271 *wl = hw->priv;
1188 struct ieee80211_conf *conf = &hw->conf;
1189 int channel, ret = 0;
1190
1191 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1192
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001193 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001194 channel,
1195 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001196 conf->power_level,
1197 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001198
1199 mutex_lock(&wl->mutex);
1200
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001201 wl->band = conf->channel->band;
1202
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001203 ret = wl1271_ps_elp_wakeup(wl, false);
1204 if (ret < 0)
1205 goto out;
1206
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001207 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001208 if (conf->flags & IEEE80211_CONF_IDLE &&
1209 test_bit(WL1271_FLAG_JOINED, &wl->flags))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001210 wl1271_unjoin_channel(wl);
Juuso Oikarinen8f648c02009-12-11 15:41:10 +02001211 else if (!(conf->flags & IEEE80211_CONF_IDLE))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001212 wl1271_join_channel(wl, channel);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001213
1214 if (conf->flags & IEEE80211_CONF_IDLE) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001215 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1216 wl->sta_rate_set = 0;
1217 wl1271_acx_rate_policies(wl);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001218 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001219 }
1220
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001221 /* if the channel changes while joined, join again */
Juuso Oikarinenddb01a52010-02-18 13:25:37 +02001222 if (channel != wl->channel &&
1223 test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1224 wl->channel = channel;
1225 /* FIXME: maybe use CMD_CHANNEL_SWITCH for this? */
1226 ret = wl1271_cmd_join(wl);
1227 if (ret < 0)
1228 wl1271_warning("cmd join to update channel failed %d",
1229 ret);
1230 } else
1231 wl->channel = channel;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001232
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001233 if (conf->flags & IEEE80211_CONF_PS &&
1234 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1235 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001236
1237 /*
1238 * We enter PSM only if we're already associated.
1239 * If we're not, we'll enter it when joining an SSID,
1240 * through the bss_info_changed() hook.
1241 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001242 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001243 wl1271_info("psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001244 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1245 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001246 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001247 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001248 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001249 wl1271_info("psm disabled");
1250
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001251 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001252
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001253 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001254 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1255 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001256 }
1257
1258 if (conf->power_level != wl->power_level) {
1259 ret = wl1271_acx_tx_power(wl, conf->power_level);
1260 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001261 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001262
1263 wl->power_level = conf->power_level;
1264 }
1265
1266out_sleep:
1267 wl1271_ps_elp_sleep(wl);
1268
1269out:
1270 mutex_unlock(&wl->mutex);
1271
1272 return ret;
1273}
1274
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001275struct wl1271_filter_params {
1276 bool enabled;
1277 int mc_list_length;
1278 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1279};
1280
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001281static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1282 struct dev_addr_list *mc_list)
1283{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001284 struct wl1271_filter_params *fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001285 int i;
1286
Juuso Oikarinen74441132009-10-13 12:47:53 +03001287 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001288 if (!fp) {
1289 wl1271_error("Out of memory setting filters.");
1290 return 0;
1291 }
1292
1293 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001294 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001295 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1296 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001297 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001298 }
1299
1300 fp->mc_list_length = 0;
1301 for (i = 0; i < mc_count; i++) {
1302 if (mc_list->da_addrlen == ETH_ALEN) {
1303 memcpy(fp->mc_list[fp->mc_list_length],
1304 mc_list->da_addr, ETH_ALEN);
1305 fp->mc_list_length++;
1306 } else
1307 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001308 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001309 }
1310
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001311 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001312}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001313
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001314#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1315 FIF_ALLMULTI | \
1316 FIF_FCSFAIL | \
1317 FIF_BCN_PRBRESP_PROMISC | \
1318 FIF_CONTROL | \
1319 FIF_OTHER_BSS)
1320
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001321static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1322 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001323 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001324{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001325 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001326 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001327 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001328
1329 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1330
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001331 mutex_lock(&wl->mutex);
1332
1333 if (wl->state == WL1271_STATE_OFF)
1334 goto out;
1335
1336 ret = wl1271_ps_elp_wakeup(wl, false);
1337 if (ret < 0)
1338 goto out;
1339
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001340 *total &= WL1271_SUPPORTED_FILTERS;
1341 changed &= WL1271_SUPPORTED_FILTERS;
1342
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001343 if (*total & FIF_ALLMULTI)
1344 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1345 else if (fp)
1346 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1347 fp->mc_list,
1348 fp->mc_list_length);
1349 if (ret < 0)
1350 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001351
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001352 kfree(fp);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001353
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001354 /* FIXME: We still need to set our filters properly */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001355
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001356 /* determine, whether supported filter values have changed */
1357 if (changed == 0)
1358 goto out_sleep;
1359
1360 /* apply configured filters */
1361 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1362 if (ret < 0)
1363 goto out_sleep;
1364
1365out_sleep:
1366 wl1271_ps_elp_sleep(wl);
1367
1368out:
1369 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001370}
1371
1372static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1373 struct ieee80211_vif *vif,
1374 struct ieee80211_sta *sta,
1375 struct ieee80211_key_conf *key_conf)
1376{
1377 struct wl1271 *wl = hw->priv;
1378 const u8 *addr;
1379 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001380 u32 tx_seq_32 = 0;
1381 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001382 u8 key_type;
1383
1384 static const u8 bcast_addr[ETH_ALEN] =
1385 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1386
1387 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1388
1389 addr = sta ? sta->addr : bcast_addr;
1390
1391 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1392 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1393 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1394 key_conf->alg, key_conf->keyidx,
1395 key_conf->keylen, key_conf->flags);
1396 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1397
1398 if (is_zero_ether_addr(addr)) {
1399 /* We dont support TX only encryption */
1400 ret = -EOPNOTSUPP;
1401 goto out;
1402 }
1403
1404 mutex_lock(&wl->mutex);
1405
1406 ret = wl1271_ps_elp_wakeup(wl, false);
1407 if (ret < 0)
1408 goto out_unlock;
1409
1410 switch (key_conf->alg) {
1411 case ALG_WEP:
1412 key_type = KEY_WEP;
1413
1414 key_conf->hw_key_idx = key_conf->keyidx;
1415 break;
1416 case ALG_TKIP:
1417 key_type = KEY_TKIP;
1418
1419 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001420 tx_seq_32 = wl->tx_security_seq_32;
1421 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001422 break;
1423 case ALG_CCMP:
1424 key_type = KEY_AES;
1425
1426 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001427 tx_seq_32 = wl->tx_security_seq_32;
1428 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001429 break;
1430 default:
1431 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1432
1433 ret = -EOPNOTSUPP;
1434 goto out_sleep;
1435 }
1436
1437 switch (cmd) {
1438 case SET_KEY:
1439 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1440 key_conf->keyidx, key_type,
1441 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001442 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001443 if (ret < 0) {
1444 wl1271_error("Could not add or replace key");
1445 goto out_sleep;
1446 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001447
1448 /* the default WEP key needs to be configured at least once */
1449 if (key_type == KEY_WEP) {
1450 ret = wl1271_cmd_set_default_wep_key(wl,
1451 wl->default_key);
1452 if (ret < 0)
1453 goto out_sleep;
1454 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001455 break;
1456
1457 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001458 /* The wl1271 does not allow to remove unicast keys - they
1459 will be cleared automatically on next CMD_JOIN. Ignore the
1460 request silently, as we dont want the mac80211 to emit
1461 an error message. */
1462 if (!is_broadcast_ether_addr(addr))
1463 break;
1464
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001465 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1466 key_conf->keyidx, key_type,
1467 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001468 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001469 if (ret < 0) {
1470 wl1271_error("Could not remove key");
1471 goto out_sleep;
1472 }
1473 break;
1474
1475 default:
1476 wl1271_error("Unsupported key cmd 0x%x", cmd);
1477 ret = -EOPNOTSUPP;
1478 goto out_sleep;
1479
1480 break;
1481 }
1482
1483out_sleep:
1484 wl1271_ps_elp_sleep(wl);
1485
1486out_unlock:
1487 mutex_unlock(&wl->mutex);
1488
1489out:
1490 return ret;
1491}
1492
1493static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1494 struct cfg80211_scan_request *req)
1495{
1496 struct wl1271 *wl = hw->priv;
1497 int ret;
1498 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001499 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001500
1501 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1502
1503 if (req->n_ssids) {
1504 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001505 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001506 }
1507
1508 mutex_lock(&wl->mutex);
1509
1510 ret = wl1271_ps_elp_wakeup(wl, false);
1511 if (ret < 0)
1512 goto out;
1513
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001514 if (wl1271_11a_enabled())
1515 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1516 WL1271_SCAN_BAND_DUAL, 3);
1517 else
1518 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1519 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001520
1521 wl1271_ps_elp_sleep(wl);
1522
1523out:
1524 mutex_unlock(&wl->mutex);
1525
1526 return ret;
1527}
1528
1529static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1530{
1531 struct wl1271 *wl = hw->priv;
1532 int ret;
1533
1534 mutex_lock(&wl->mutex);
1535
1536 ret = wl1271_ps_elp_wakeup(wl, false);
1537 if (ret < 0)
1538 goto out;
1539
1540 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1541 if (ret < 0)
1542 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1543
1544 wl1271_ps_elp_sleep(wl);
1545
1546out:
1547 mutex_unlock(&wl->mutex);
1548
1549 return ret;
1550}
1551
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001552static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1553{
1554 u8 *ptr = beacon->data +
1555 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1556
1557 /* find the location of the ssid in the beacon */
1558 while (ptr < beacon->data + beacon->len) {
1559 if (ptr[0] == WLAN_EID_SSID) {
1560 wl->ssid_len = ptr[1];
1561 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1562 return;
1563 }
1564 ptr += ptr[1];
1565 }
1566 wl1271_error("ad-hoc beacon template has no SSID!\n");
1567}
1568
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001569static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1570 struct ieee80211_vif *vif,
1571 struct ieee80211_bss_conf *bss_conf,
1572 u32 changed)
1573{
1574 enum wl1271_cmd_ps_mode mode;
1575 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001576 bool do_join = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001577 int ret;
1578
1579 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1580
1581 mutex_lock(&wl->mutex);
1582
1583 ret = wl1271_ps_elp_wakeup(wl, false);
1584 if (ret < 0)
1585 goto out;
1586
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001587 if (wl->bss_type == BSS_TYPE_IBSS) {
1588 /* FIXME: This implements rudimentary ad-hoc support -
1589 proper templates are on the wish list and notification
1590 on when they change. This patch will update the templates
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001591 on every call to this function. */
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001592 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1593
1594 if (beacon) {
1595 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001596
1597 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001598 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1599 beacon->data,
1600 beacon->len);
1601
1602 if (ret < 0) {
1603 dev_kfree_skb(beacon);
1604 goto out_sleep;
1605 }
1606
1607 hdr = (struct ieee80211_hdr *) beacon->data;
1608 hdr->frame_control = cpu_to_le16(
1609 IEEE80211_FTYPE_MGMT |
1610 IEEE80211_STYPE_PROBE_RESP);
1611
1612 ret = wl1271_cmd_template_set(wl,
1613 CMD_TEMPL_PROBE_RESPONSE,
1614 beacon->data,
1615 beacon->len);
1616 dev_kfree_skb(beacon);
1617 if (ret < 0)
1618 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001619
1620 /* Need to update the SSID (for filtering etc) */
1621 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001622 }
1623 }
1624
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001625 if ((changed & BSS_CHANGED_BSSID) &&
1626 /*
1627 * Now we know the correct bssid, so we send a new join command
1628 * and enable the BSSID filter
1629 */
1630 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
1631 wl->rx_config |= CFG_BSSID_FILTER_EN;
1632 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
1633 ret = wl1271_cmd_build_null_data(wl);
1634 if (ret < 0) {
1635 wl1271_warning("cmd buld null data failed %d",
1636 ret);
1637 goto out_sleep;
1638 }
1639
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001640 /* Need to update the BSSID (for filtering etc) */
1641 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001642 }
1643
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001644 if (changed & BSS_CHANGED_ASSOC) {
1645 if (bss_conf->assoc) {
1646 wl->aid = bss_conf->aid;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001647 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001648
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001649 /*
1650 * with wl1271, we don't need to update the
1651 * beacon_int and dtim_period, because the firmware
1652 * updates it by itself when the first beacon is
1653 * received after a join.
1654 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001655 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1656 if (ret < 0)
1657 goto out_sleep;
1658
1659 ret = wl1271_acx_aid(wl, wl->aid);
1660 if (ret < 0)
1661 goto out_sleep;
1662
1663 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001664 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1665 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001666 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001667 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001668 if (ret < 0)
1669 goto out_sleep;
1670 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001671 } else {
1672 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001673 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001674 wl->aid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001675 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001676
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001677 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001678
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001679 if (changed & BSS_CHANGED_ERP_SLOT) {
1680 if (bss_conf->use_short_slot)
1681 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1682 else
1683 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1684 if (ret < 0) {
1685 wl1271_warning("Set slot time failed %d", ret);
1686 goto out_sleep;
1687 }
1688 }
1689
1690 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1691 if (bss_conf->use_short_preamble)
1692 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1693 else
1694 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1695 }
1696
1697 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1698 if (bss_conf->use_cts_prot)
1699 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1700 else
1701 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1702 if (ret < 0) {
1703 wl1271_warning("Set ctsprotect failed %d", ret);
1704 goto out_sleep;
1705 }
1706 }
1707
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001708 if (do_join) {
1709 ret = wl1271_cmd_join(wl);
1710 if (ret < 0) {
1711 wl1271_warning("cmd join failed %d", ret);
1712 goto out_sleep;
1713 }
1714 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1715 }
1716
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001717out_sleep:
1718 wl1271_ps_elp_sleep(wl);
1719
1720out:
1721 mutex_unlock(&wl->mutex);
1722}
1723
Kalle Valoc6999d82010-02-18 13:25:41 +02001724static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1725 const struct ieee80211_tx_queue_params *params)
1726{
1727 struct wl1271 *wl = hw->priv;
1728 int ret;
1729
1730 mutex_lock(&wl->mutex);
1731
1732 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1733
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001734 ret = wl1271_ps_elp_wakeup(wl, false);
1735 if (ret < 0)
1736 goto out;
1737
Kalle Valoc6999d82010-02-18 13:25:41 +02001738 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1739 params->cw_min, params->cw_max,
1740 params->aifs, params->txop);
1741 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001742 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001743
1744 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1745 CONF_CHANNEL_TYPE_EDCF,
1746 wl1271_tx_get_queue(queue),
1747 CONF_PS_SCHEME_LEGACY_PSPOLL,
1748 CONF_ACK_POLICY_LEGACY, 0, 0);
1749 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001750 goto out_sleep;
1751
1752out_sleep:
1753 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001754
1755out:
1756 mutex_unlock(&wl->mutex);
1757
1758 return ret;
1759}
1760
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001761
1762/* can't be const, mac80211 writes to this */
1763static struct ieee80211_rate wl1271_rates[] = {
1764 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001765 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1766 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001767 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001768 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1769 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001770 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1771 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001772 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1773 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001774 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1775 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001776 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1777 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001778 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1779 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001780 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1781 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001782 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001783 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1784 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001785 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001786 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1787 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001788 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001789 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1790 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001791 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001792 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1793 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001794 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001795 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1796 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001797 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001798 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1799 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001800 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001801 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1802 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001803};
1804
1805/* can't be const, mac80211 writes to this */
1806static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001807 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1808 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1809 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1810 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1811 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1812 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1813 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1814 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1815 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1816 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1817 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1818 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1819 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001820};
1821
1822/* can't be const, mac80211 writes to this */
1823static struct ieee80211_supported_band wl1271_band_2ghz = {
1824 .channels = wl1271_channels,
1825 .n_channels = ARRAY_SIZE(wl1271_channels),
1826 .bitrates = wl1271_rates,
1827 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1828};
1829
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001830/* 5 GHz data rates for WL1273 */
1831static struct ieee80211_rate wl1271_rates_5ghz[] = {
1832 { .bitrate = 60,
1833 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1834 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
1835 { .bitrate = 90,
1836 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1837 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
1838 { .bitrate = 120,
1839 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1840 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
1841 { .bitrate = 180,
1842 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1843 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
1844 { .bitrate = 240,
1845 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1846 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
1847 { .bitrate = 360,
1848 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1849 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
1850 { .bitrate = 480,
1851 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1852 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
1853 { .bitrate = 540,
1854 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1855 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
1856};
1857
1858/* 5 GHz band channels for WL1273 */
1859static struct ieee80211_channel wl1271_channels_5ghz[] = {
1860 { .hw_value = 183, .center_freq = 4915},
1861 { .hw_value = 184, .center_freq = 4920},
1862 { .hw_value = 185, .center_freq = 4925},
1863 { .hw_value = 187, .center_freq = 4935},
1864 { .hw_value = 188, .center_freq = 4940},
1865 { .hw_value = 189, .center_freq = 4945},
1866 { .hw_value = 192, .center_freq = 4960},
1867 { .hw_value = 196, .center_freq = 4980},
1868 { .hw_value = 7, .center_freq = 5035},
1869 { .hw_value = 8, .center_freq = 5040},
1870 { .hw_value = 9, .center_freq = 5045},
1871 { .hw_value = 11, .center_freq = 5055},
1872 { .hw_value = 12, .center_freq = 5060},
1873 { .hw_value = 16, .center_freq = 5080},
1874 { .hw_value = 34, .center_freq = 5170},
1875 { .hw_value = 36, .center_freq = 5180},
1876 { .hw_value = 38, .center_freq = 5190},
1877 { .hw_value = 40, .center_freq = 5200},
1878 { .hw_value = 42, .center_freq = 5210},
1879 { .hw_value = 44, .center_freq = 5220},
1880 { .hw_value = 46, .center_freq = 5230},
1881 { .hw_value = 48, .center_freq = 5240},
1882 { .hw_value = 52, .center_freq = 5260},
1883 { .hw_value = 56, .center_freq = 5280},
1884 { .hw_value = 60, .center_freq = 5300},
1885 { .hw_value = 64, .center_freq = 5320},
1886 { .hw_value = 100, .center_freq = 5500},
1887 { .hw_value = 104, .center_freq = 5520},
1888 { .hw_value = 108, .center_freq = 5540},
1889 { .hw_value = 112, .center_freq = 5560},
1890 { .hw_value = 116, .center_freq = 5580},
1891 { .hw_value = 120, .center_freq = 5600},
1892 { .hw_value = 124, .center_freq = 5620},
1893 { .hw_value = 128, .center_freq = 5640},
1894 { .hw_value = 132, .center_freq = 5660},
1895 { .hw_value = 136, .center_freq = 5680},
1896 { .hw_value = 140, .center_freq = 5700},
1897 { .hw_value = 149, .center_freq = 5745},
1898 { .hw_value = 153, .center_freq = 5765},
1899 { .hw_value = 157, .center_freq = 5785},
1900 { .hw_value = 161, .center_freq = 5805},
1901 { .hw_value = 165, .center_freq = 5825},
1902};
1903
1904
1905static struct ieee80211_supported_band wl1271_band_5ghz = {
1906 .channels = wl1271_channels_5ghz,
1907 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
1908 .bitrates = wl1271_rates_5ghz,
1909 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
1910};
1911
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001912static const struct ieee80211_ops wl1271_ops = {
1913 .start = wl1271_op_start,
1914 .stop = wl1271_op_stop,
1915 .add_interface = wl1271_op_add_interface,
1916 .remove_interface = wl1271_op_remove_interface,
1917 .config = wl1271_op_config,
1918/* .config_interface = wl1271_op_config_interface, */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001919 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001920 .configure_filter = wl1271_op_configure_filter,
1921 .tx = wl1271_op_tx,
1922 .set_key = wl1271_op_set_key,
1923 .hw_scan = wl1271_op_hw_scan,
1924 .bss_info_changed = wl1271_op_bss_info_changed,
1925 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02001926 .conf_tx = wl1271_op_conf_tx,
Kalle Valoc8c90872010-02-18 13:25:53 +02001927 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001928};
1929
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02001930int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001931{
1932 int ret;
1933
1934 if (wl->mac80211_registered)
1935 return 0;
1936
1937 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
1938
1939 ret = ieee80211_register_hw(wl->hw);
1940 if (ret < 0) {
1941 wl1271_error("unable to register mac80211 hw: %d", ret);
1942 return ret;
1943 }
1944
1945 wl->mac80211_registered = true;
1946
1947 wl1271_notice("loaded");
1948
1949 return 0;
1950}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02001951EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001952
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02001953int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001954{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03001955 /* The tx descriptor buffer and the TKIP space. */
1956 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
1957 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001958
1959 /* unit us */
1960 /* FIXME: find a proper value */
1961 wl->hw->channel_change_time = 10000;
1962
1963 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03001964 IEEE80211_HW_NOISE_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02001965 IEEE80211_HW_BEACON_FILTER |
1966 IEEE80211_HW_SUPPORTS_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001967
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001968 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
1969 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001970 wl->hw->wiphy->max_scan_ssids = 1;
1971 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
1972
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001973 if (wl1271_11a_enabled())
1974 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
1975
Teemu Paasikivi8197b712010-02-22 08:38:23 +02001976 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001977
1978 return 0;
1979}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02001980EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001981
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001982#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02001983
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02001984struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001985{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001986 struct ieee80211_hw *hw;
1987 struct wl1271 *wl;
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02001988 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001989
1990 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
1991 if (!hw) {
1992 wl1271_error("could not alloc ieee80211_hw");
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02001993 return ERR_PTR(-ENOMEM);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001994 }
1995
1996 wl = hw->priv;
1997 memset(wl, 0, sizeof(*wl));
1998
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001999 INIT_LIST_HEAD(&wl->list);
2000
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002001 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002002
2003 skb_queue_head_init(&wl->tx_queue);
2004
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002005 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002006 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002007 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002008 wl->rx_counter = 0;
2009 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2010 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002011 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002012 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002013 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002014 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2015 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002016 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002017 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002018 wl->flags = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002019
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002020 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002021 wl->tx_frames[i] = NULL;
2022
2023 spin_lock_init(&wl->wl_lock);
2024
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002025 wl->state = WL1271_STATE_OFF;
2026 mutex_init(&wl->mutex);
2027
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002028 /* Apply default driver configuration. */
2029 wl1271_conf_init(wl);
2030
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002031 wl1271_debugfs_init(wl);
2032
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002033 return hw;
2034}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002035EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002036
2037int wl1271_free_hw(struct wl1271 *wl)
2038{
2039 ieee80211_unregister_hw(wl->hw);
2040
2041 wl1271_debugfs_exit(wl);
2042
2043 kfree(wl->target_mem_map);
2044 vfree(wl->fw);
2045 wl->fw = NULL;
2046 kfree(wl->nvs);
2047 wl->nvs = NULL;
2048
2049 kfree(wl->fw_status);
2050 kfree(wl->tx_res_if);
2051
2052 ieee80211_free_hw(wl->hw);
2053
2054 return 0;
2055}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002056EXPORT_SYMBOL_GPL(wl1271_free_hw);
2057
2058MODULE_LICENSE("GPL");
2059MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2060MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");