blob: 5cc778f658b9129e9af0223cfab9ddacf9080a22 [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) {
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300456 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300457
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300458 /* check for tx results */
Juuso Oikarinenffb591c2010-02-22 08:38:31 +0200459 if (wl->fw_status->tx_results_counter !=
460 (wl->tx_results_count & 0xff))
461 wl1271_tx_complete(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300462
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300463 wl1271_rx(wl, wl->fw_status);
464 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300465
466out_sleep:
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200467 wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
468 WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300469 wl1271_ps_elp_sleep(wl);
470
471out:
472 mutex_unlock(&wl->mutex);
473}
474
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300475static int wl1271_fetch_firmware(struct wl1271 *wl)
476{
477 const struct firmware *fw;
478 int ret;
479
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200480 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300481
482 if (ret < 0) {
483 wl1271_error("could not get firmware: %d", ret);
484 return ret;
485 }
486
487 if (fw->size % 4) {
488 wl1271_error("firmware size is not multiple of 32 bits: %zu",
489 fw->size);
490 ret = -EILSEQ;
491 goto out;
492 }
493
494 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300495 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300496
497 if (!wl->fw) {
498 wl1271_error("could not allocate memory for the firmware");
499 ret = -ENOMEM;
500 goto out;
501 }
502
503 memcpy(wl->fw, fw->data, wl->fw_len);
504
505 ret = 0;
506
507out:
508 release_firmware(fw);
509
510 return ret;
511}
512
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200513static int wl1271_update_mac_addr(struct wl1271 *wl)
514{
515 int ret = 0;
516 u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
517
518 /* get mac address from the NVS */
519 wl->mac_addr[0] = nvs_ptr[11];
520 wl->mac_addr[1] = nvs_ptr[10];
521 wl->mac_addr[2] = nvs_ptr[6];
522 wl->mac_addr[3] = nvs_ptr[5];
523 wl->mac_addr[4] = nvs_ptr[4];
524 wl->mac_addr[5] = nvs_ptr[3];
525
526 /* FIXME: if it is a zero-address, we should bail out. Now, instead,
527 we randomize an address */
528 if (is_zero_ether_addr(wl->mac_addr)) {
529 static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
530 memcpy(wl->mac_addr, nokia_oui, 3);
531 get_random_bytes(wl->mac_addr + 3, 3);
Juuso Oikarinene2e77b52010-02-18 13:25:46 +0200532
533 /* update this address to the NVS */
534 nvs_ptr[11] = wl->mac_addr[0];
535 nvs_ptr[10] = wl->mac_addr[1];
536 nvs_ptr[6] = wl->mac_addr[2];
537 nvs_ptr[5] = wl->mac_addr[3];
538 nvs_ptr[4] = wl->mac_addr[4];
539 nvs_ptr[3] = wl->mac_addr[5];
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200540 }
541
542 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
543
544 return ret;
545}
546
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300547static int wl1271_fetch_nvs(struct wl1271 *wl)
548{
549 const struct firmware *fw;
550 int ret;
551
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200552 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300553
554 if (ret < 0) {
555 wl1271_error("could not get nvs file: %d", ret);
556 return ret;
557 }
558
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200559 if (fw->size != sizeof(struct wl1271_nvs_file)) {
560 wl1271_error("nvs size is not as expected: %zu != %zu",
561 fw->size, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300562 ret = -EILSEQ;
563 goto out;
564 }
565
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200566 wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300567
568 if (!wl->nvs) {
569 wl1271_error("could not allocate memory for the nvs file");
570 ret = -ENOMEM;
571 goto out;
572 }
573
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200574 memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300575
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200576 ret = wl1271_update_mac_addr(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300577
578out:
579 release_firmware(fw);
580
581 return ret;
582}
583
584static void wl1271_fw_wakeup(struct wl1271 *wl)
585{
586 u32 elp_reg;
587
588 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300589 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300590}
591
592static int wl1271_setup(struct wl1271 *wl)
593{
594 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
595 if (!wl->fw_status)
596 return -ENOMEM;
597
598 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
599 if (!wl->tx_res_if) {
600 kfree(wl->fw_status);
601 return -ENOMEM;
602 }
603
604 INIT_WORK(&wl->irq_work, wl1271_irq_work);
605 INIT_WORK(&wl->tx_work, wl1271_tx_work);
606 return 0;
607}
608
609static int wl1271_chip_wakeup(struct wl1271 *wl)
610{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300611 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300612 int ret = 0;
613
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200614 msleep(WL1271_PRE_POWER_ON_SLEEP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300615 wl1271_power_on(wl);
616 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200617 wl1271_io_reset(wl);
618 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300619
620 /* We don't need a real memory partition here, because we only want
621 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300622 memset(&partition, 0, sizeof(partition));
623 partition.reg.start = REGISTERS_BASE;
624 partition.reg.size = REGISTERS_DOWN_SIZE;
625 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300626
627 /* ELP module wake up */
628 wl1271_fw_wakeup(wl);
629
630 /* whal_FwCtrl_BootSm() */
631
632 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200633 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300634
635 /* 1. check if chip id is valid */
636
637 switch (wl->chip.id) {
638 case CHIP_ID_1271_PG10:
639 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
640 wl->chip.id);
641
642 ret = wl1271_setup(wl);
643 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200644 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300645 break;
646 case CHIP_ID_1271_PG20:
647 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
648 wl->chip.id);
649
650 ret = wl1271_setup(wl);
651 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200652 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300653 break;
654 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200655 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300656 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200657 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300658 }
659
660 if (wl->fw == NULL) {
661 ret = wl1271_fetch_firmware(wl);
662 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200663 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300664 }
665
666 /* No NVS from netlink, try to get it from the filesystem */
667 if (wl->nvs == NULL) {
668 ret = wl1271_fetch_nvs(wl);
669 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200670 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300671 }
672
673out:
674 return ret;
675}
676
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300677int wl1271_plt_start(struct wl1271 *wl)
678{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200679 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300680 int ret;
681
682 mutex_lock(&wl->mutex);
683
684 wl1271_notice("power up");
685
686 if (wl->state != WL1271_STATE_OFF) {
687 wl1271_error("cannot go into PLT state because not "
688 "in off state: %d", wl->state);
689 ret = -EBUSY;
690 goto out;
691 }
692
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200693 while (retries) {
694 retries--;
695 ret = wl1271_chip_wakeup(wl);
696 if (ret < 0)
697 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300698
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200699 ret = wl1271_boot(wl);
700 if (ret < 0)
701 goto power_off;
702
703 ret = wl1271_plt_init(wl);
704 if (ret < 0)
705 goto irq_disable;
706
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200707 wl->state = WL1271_STATE_PLT;
708 wl1271_notice("firmware booted in PLT mode (%s)",
709 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300710 goto out;
711
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200712irq_disable:
713 wl1271_disable_interrupts(wl);
714 mutex_unlock(&wl->mutex);
715 /* Unlocking the mutex in the middle of handling is
716 inherently unsafe. In this case we deem it safe to do,
717 because we need to let any possibly pending IRQ out of
718 the system (and while we are WL1271_STATE_OFF the IRQ
719 work function will not do anything.) Also, any other
720 possible concurrent operations will fail due to the
721 current state, hence the wl1271 struct should be safe. */
722 cancel_work_sync(&wl->irq_work);
723 mutex_lock(&wl->mutex);
724power_off:
725 wl1271_power_off(wl);
726 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300727
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200728 wl1271_error("firmware boot in PLT mode failed despite %d retries",
729 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300730out:
731 mutex_unlock(&wl->mutex);
732
733 return ret;
734}
735
736int wl1271_plt_stop(struct wl1271 *wl)
737{
738 int ret = 0;
739
740 mutex_lock(&wl->mutex);
741
742 wl1271_notice("power down");
743
744 if (wl->state != WL1271_STATE_PLT) {
745 wl1271_error("cannot power down because not in PLT "
746 "state: %d", wl->state);
747 ret = -EBUSY;
748 goto out;
749 }
750
751 wl1271_disable_interrupts(wl);
752 wl1271_power_off(wl);
753
754 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300755 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300756
757out:
758 mutex_unlock(&wl->mutex);
759
760 return ret;
761}
762
763
764static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
765{
766 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200767 struct ieee80211_conf *conf = &hw->conf;
768 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
769 struct ieee80211_sta *sta = txinfo->control.sta;
770 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300771
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200772 /* peek into the rates configured in the STA entry */
773 spin_lock_irqsave(&wl->wl_lock, flags);
774 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
775 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
776 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
777 }
778 spin_unlock_irqrestore(&wl->wl_lock, flags);
779
780 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300781 skb_queue_tail(&wl->tx_queue, skb);
782
783 /*
784 * The chip specific setup must run before the first TX packet -
785 * before that, the tx_work will not be initialized!
786 */
787
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300788 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300789
790 /*
791 * The workqueue is slow to process the tx_queue and we need stop
792 * the queue here, otherwise the queue will get too long.
793 */
794 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) {
795 ieee80211_stop_queues(wl->hw);
796
797 /*
798 * FIXME: this is racy, the variable is not properly
799 * protected. Maybe fix this by removing the stupid
800 * variable altogether and checking the real queue state?
801 */
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200802 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300803 }
804
805 return NETDEV_TX_OK;
806}
807
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300808static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
809 void *arg)
810{
811 struct net_device *dev;
812 struct wireless_dev *wdev;
813 struct wiphy *wiphy;
814 struct ieee80211_hw *hw;
815 struct wl1271 *wl;
816 struct wl1271 *wl_temp;
817 struct in_device *idev;
818 struct in_ifaddr *ifa = arg;
819 int ret = 0;
820
821 /* FIXME: this ugly function should probably be implemented in the
822 * mac80211, and here should only be a simple callback handling actual
823 * setting of the filters. Now we need to dig up references to
824 * various structures to gain access to what we need.
825 * Also, because of this, there is no "initial" setting of the filter
826 * in "op_start", because we don't want to dig up struct net_device
827 * there - the filter will be set upon first change of the interface
828 * IP address. */
829
830 dev = ifa->ifa_dev->dev;
831
832 wdev = dev->ieee80211_ptr;
833 if (wdev == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200834 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300835
836 wiphy = wdev->wiphy;
837 if (wiphy == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200838 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300839
840 hw = wiphy_priv(wiphy);
841 if (hw == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200842 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300843
844 /* Check that the interface is one supported by this driver. */
845 wl_temp = hw->priv;
846 list_for_each_entry(wl, &wl_list, list) {
847 if (wl == wl_temp)
848 break;
849 }
850 if (wl == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200851 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300852
853 /* Get the interface IP address for the device. "ifa" will become
854 NULL if:
855 - there is no IPV4 protocol address configured
856 - there are multiple (virtual) IPV4 addresses configured
857 When "ifa" is NULL, filtering will be disabled.
858 */
859 ifa = NULL;
860 idev = dev->ip_ptr;
861 if (idev)
862 ifa = idev->ifa_list;
863
864 if (ifa && ifa->ifa_next)
865 ifa = NULL;
866
867 mutex_lock(&wl->mutex);
868
869 if (wl->state == WL1271_STATE_OFF)
870 goto out;
871
872 ret = wl1271_ps_elp_wakeup(wl, false);
873 if (ret < 0)
874 goto out;
875 if (ifa)
876 ret = wl1271_acx_arp_ip_filter(wl, true,
877 (u8 *)&ifa->ifa_address,
878 ACX_IPV4_VERSION);
879 else
880 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
881 ACX_IPV4_VERSION);
882 wl1271_ps_elp_sleep(wl);
883
884out:
885 mutex_unlock(&wl->mutex);
886
Luciano Coelho17d72652009-11-23 23:22:15 +0200887 return NOTIFY_OK;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300888}
889
890static struct notifier_block wl1271_dev_notifier = {
891 .notifier_call = wl1271_dev_notify,
892};
893
894
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300895static int wl1271_op_start(struct ieee80211_hw *hw)
896{
897 struct wl1271 *wl = hw->priv;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200898 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300899 int ret = 0;
900
901 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
902
903 mutex_lock(&wl->mutex);
904
905 if (wl->state != WL1271_STATE_OFF) {
906 wl1271_error("cannot start because not in off state: %d",
907 wl->state);
908 ret = -EBUSY;
909 goto out;
910 }
911
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200912 while (retries) {
913 retries--;
914 ret = wl1271_chip_wakeup(wl);
915 if (ret < 0)
916 goto power_off;
917
918 ret = wl1271_boot(wl);
919 if (ret < 0)
920 goto power_off;
921
922 ret = wl1271_hw_init(wl);
923 if (ret < 0)
924 goto irq_disable;
925
926 wl->state = WL1271_STATE_ON;
927 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300928 goto out;
929
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200930irq_disable:
931 wl1271_disable_interrupts(wl);
932 mutex_unlock(&wl->mutex);
933 /* Unlocking the mutex in the middle of handling is
934 inherently unsafe. In this case we deem it safe to do,
935 because we need to let any possibly pending IRQ out of
936 the system (and while we are WL1271_STATE_OFF the IRQ
937 work function will not do anything.) Also, any other
938 possible concurrent operations will fail due to the
939 current state, hence the wl1271 struct should be safe. */
940 cancel_work_sync(&wl->irq_work);
941 mutex_lock(&wl->mutex);
942power_off:
943 wl1271_power_off(wl);
944 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300945
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200946 wl1271_error("firmware boot failed despite %d retries",
947 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300948out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300949 mutex_unlock(&wl->mutex);
950
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300951 if (!ret) {
952 list_add(&wl->list, &wl_list);
953 register_inetaddr_notifier(&wl1271_dev_notifier);
954 }
955
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300956 return ret;
957}
958
959static void wl1271_op_stop(struct ieee80211_hw *hw)
960{
961 struct wl1271 *wl = hw->priv;
962 int i;
963
964 wl1271_info("down");
965
966 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
967
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300968 unregister_inetaddr_notifier(&wl1271_dev_notifier);
969 list_del(&wl->list);
970
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300971 mutex_lock(&wl->mutex);
972
973 WARN_ON(wl->state != WL1271_STATE_ON);
974
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200975 if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300976 mutex_unlock(&wl->mutex);
977 ieee80211_scan_completed(wl->hw, true);
978 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300979 }
980
981 wl->state = WL1271_STATE_OFF;
982
983 wl1271_disable_interrupts(wl);
984
985 mutex_unlock(&wl->mutex);
986
987 cancel_work_sync(&wl->irq_work);
988 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300989
990 mutex_lock(&wl->mutex);
991
992 /* let's notify MAC80211 about the remaining pending TX frames */
993 wl1271_tx_flush(wl);
994 wl1271_power_off(wl);
995
996 memset(wl->bssid, 0, ETH_ALEN);
997 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
998 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300999 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001000 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001001
1002 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001003 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001004 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1005 wl->tx_blocks_available = 0;
1006 wl->tx_results_count = 0;
1007 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001008 wl->tx_security_last_seq = 0;
1009 wl->tx_security_seq_16 = 0;
1010 wl->tx_security_seq_32 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001011 wl->time_offset = 0;
1012 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001013 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1014 wl->sta_rate_set = 0;
1015 wl->flags = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001016
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001017 for (i = 0; i < NUM_TX_QUEUES; i++)
1018 wl->tx_blocks_freed[i] = 0;
1019
1020 wl1271_debugfs_reset(wl);
1021 mutex_unlock(&wl->mutex);
1022}
1023
1024static int wl1271_op_add_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +01001025 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001026{
1027 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001028 int ret = 0;
1029
John W. Linvillee5539bc2009-08-18 10:50:34 -04001030 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Johannes Berg1ed32e42009-12-23 13:15:45 +01001031 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001032
1033 mutex_lock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001034 if (wl->vif) {
1035 ret = -EBUSY;
1036 goto out;
1037 }
1038
Johannes Berg1ed32e42009-12-23 13:15:45 +01001039 wl->vif = vif;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001040
Johannes Berg1ed32e42009-12-23 13:15:45 +01001041 switch (vif->type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001042 case NL80211_IFTYPE_STATION:
1043 wl->bss_type = BSS_TYPE_STA_BSS;
1044 break;
1045 case NL80211_IFTYPE_ADHOC:
1046 wl->bss_type = BSS_TYPE_IBSS;
1047 break;
1048 default:
1049 ret = -EOPNOTSUPP;
1050 goto out;
1051 }
1052
1053 /* FIXME: what if conf->mac_addr changes? */
1054
1055out:
1056 mutex_unlock(&wl->mutex);
1057 return ret;
1058}
1059
1060static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +01001061 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001062{
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001063 struct wl1271 *wl = hw->priv;
1064
1065 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001066 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001067 wl->vif = NULL;
1068 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001069}
1070
1071#if 0
1072static int wl1271_op_config_interface(struct ieee80211_hw *hw,
1073 struct ieee80211_vif *vif,
1074 struct ieee80211_if_conf *conf)
1075{
1076 struct wl1271 *wl = hw->priv;
1077 struct sk_buff *beacon;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001078 int ret;
1079
David S. Miller32646902009-09-17 10:18:30 -07001080 wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM",
1081 conf->bssid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001082 wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid,
1083 conf->ssid_len);
1084
1085 mutex_lock(&wl->mutex);
1086
1087 ret = wl1271_ps_elp_wakeup(wl, false);
1088 if (ret < 0)
1089 goto out;
1090
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001091 if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
1092 wl1271_debug(DEBUG_MAC80211, "bssid changed");
1093
1094 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
1095
1096 ret = wl1271_cmd_join(wl);
1097 if (ret < 0)
1098 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001099
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001100 ret = wl1271_cmd_build_null_data(wl);
1101 if (ret < 0)
1102 goto out_sleep;
1103 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001104
1105 wl->ssid_len = conf->ssid_len;
1106 if (wl->ssid_len)
1107 memcpy(wl->ssid, conf->ssid, wl->ssid_len);
1108
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001109 if (conf->changed & IEEE80211_IFCC_BEACON) {
1110 beacon = ieee80211_beacon_get(hw, vif);
1111 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1112 beacon->data, beacon->len);
1113
1114 if (ret < 0) {
1115 dev_kfree_skb(beacon);
1116 goto out_sleep;
1117 }
1118
1119 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE,
1120 beacon->data, beacon->len);
1121
1122 dev_kfree_skb(beacon);
1123
1124 if (ret < 0)
1125 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001126 }
1127
1128out_sleep:
1129 wl1271_ps_elp_sleep(wl);
1130
1131out:
1132 mutex_unlock(&wl->mutex);
1133
1134 return ret;
1135}
1136#endif
1137
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001138static int wl1271_join_channel(struct wl1271 *wl, int channel)
1139{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001140 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001141 /* we need to use a dummy BSSID for now */
1142 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1143 0xad, 0xbe, 0xef };
1144
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001145 /* the dummy join is not required for ad-hoc */
1146 if (wl->bss_type == BSS_TYPE_IBSS)
1147 goto out;
1148
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001149 /* disable mac filter, so we hear everything */
1150 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1151
1152 wl->channel = channel;
1153 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1154
1155 ret = wl1271_cmd_join(wl);
1156 if (ret < 0)
1157 goto out;
1158
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001159 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001160
1161out:
1162 return ret;
1163}
1164
1165static int wl1271_unjoin_channel(struct wl1271 *wl)
1166{
1167 int ret;
1168
1169 /* to stop listening to a channel, we disconnect */
1170 ret = wl1271_cmd_disconnect(wl);
1171 if (ret < 0)
1172 goto out;
1173
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001174 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001175 wl->channel = 0;
1176 memset(wl->bssid, 0, ETH_ALEN);
1177 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1178
1179out:
1180 return ret;
1181}
1182
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001183static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1184{
1185 struct wl1271 *wl = hw->priv;
1186 struct ieee80211_conf *conf = &hw->conf;
1187 int channel, ret = 0;
1188
1189 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1190
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001191 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001192 channel,
1193 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001194 conf->power_level,
1195 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001196
1197 mutex_lock(&wl->mutex);
1198
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001199 wl->band = conf->channel->band;
1200
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001201 ret = wl1271_ps_elp_wakeup(wl, false);
1202 if (ret < 0)
1203 goto out;
1204
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001205 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001206 if (conf->flags & IEEE80211_CONF_IDLE &&
1207 test_bit(WL1271_FLAG_JOINED, &wl->flags))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001208 wl1271_unjoin_channel(wl);
Juuso Oikarinen8f648c02009-12-11 15:41:10 +02001209 else if (!(conf->flags & IEEE80211_CONF_IDLE))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001210 wl1271_join_channel(wl, channel);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001211
1212 if (conf->flags & IEEE80211_CONF_IDLE) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001213 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1214 wl->sta_rate_set = 0;
1215 wl1271_acx_rate_policies(wl);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001216 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001217 }
1218
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001219 /* if the channel changes while joined, join again */
Juuso Oikarinenddb01a52010-02-18 13:25:37 +02001220 if (channel != wl->channel &&
1221 test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1222 wl->channel = channel;
1223 /* FIXME: maybe use CMD_CHANNEL_SWITCH for this? */
1224 ret = wl1271_cmd_join(wl);
1225 if (ret < 0)
1226 wl1271_warning("cmd join to update channel failed %d",
1227 ret);
1228 } else
1229 wl->channel = channel;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001230
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001231 if (conf->flags & IEEE80211_CONF_PS &&
1232 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1233 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001234
1235 /*
1236 * We enter PSM only if we're already associated.
1237 * If we're not, we'll enter it when joining an SSID,
1238 * through the bss_info_changed() hook.
1239 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001240 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001241 wl1271_info("psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001242 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1243 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001244 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001245 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001246 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001247 wl1271_info("psm disabled");
1248
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001249 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001250
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001251 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001252 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1253 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001254 }
1255
1256 if (conf->power_level != wl->power_level) {
1257 ret = wl1271_acx_tx_power(wl, conf->power_level);
1258 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001259 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001260
1261 wl->power_level = conf->power_level;
1262 }
1263
1264out_sleep:
1265 wl1271_ps_elp_sleep(wl);
1266
1267out:
1268 mutex_unlock(&wl->mutex);
1269
1270 return ret;
1271}
1272
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001273struct wl1271_filter_params {
1274 bool enabled;
1275 int mc_list_length;
1276 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1277};
1278
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001279static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1280 struct dev_addr_list *mc_list)
1281{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001282 struct wl1271_filter_params *fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001283 int i;
1284
Juuso Oikarinen74441132009-10-13 12:47:53 +03001285 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001286 if (!fp) {
1287 wl1271_error("Out of memory setting filters.");
1288 return 0;
1289 }
1290
1291 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001292 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001293 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1294 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001295 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001296 }
1297
1298 fp->mc_list_length = 0;
1299 for (i = 0; i < mc_count; i++) {
1300 if (mc_list->da_addrlen == ETH_ALEN) {
1301 memcpy(fp->mc_list[fp->mc_list_length],
1302 mc_list->da_addr, ETH_ALEN);
1303 fp->mc_list_length++;
1304 } else
1305 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001306 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001307 }
1308
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001309 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001310}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001311
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001312#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1313 FIF_ALLMULTI | \
1314 FIF_FCSFAIL | \
1315 FIF_BCN_PRBRESP_PROMISC | \
1316 FIF_CONTROL | \
1317 FIF_OTHER_BSS)
1318
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001319static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1320 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001321 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001322{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001323 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001324 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001325 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001326
1327 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1328
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001329 mutex_lock(&wl->mutex);
1330
1331 if (wl->state == WL1271_STATE_OFF)
1332 goto out;
1333
1334 ret = wl1271_ps_elp_wakeup(wl, false);
1335 if (ret < 0)
1336 goto out;
1337
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001338 *total &= WL1271_SUPPORTED_FILTERS;
1339 changed &= WL1271_SUPPORTED_FILTERS;
1340
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001341 if (*total & FIF_ALLMULTI)
1342 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1343 else if (fp)
1344 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1345 fp->mc_list,
1346 fp->mc_list_length);
1347 if (ret < 0)
1348 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001349
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001350 kfree(fp);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001351
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001352 /* FIXME: We still need to set our filters properly */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001353
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001354 /* determine, whether supported filter values have changed */
1355 if (changed == 0)
1356 goto out_sleep;
1357
1358 /* apply configured filters */
1359 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1360 if (ret < 0)
1361 goto out_sleep;
1362
1363out_sleep:
1364 wl1271_ps_elp_sleep(wl);
1365
1366out:
1367 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001368}
1369
1370static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1371 struct ieee80211_vif *vif,
1372 struct ieee80211_sta *sta,
1373 struct ieee80211_key_conf *key_conf)
1374{
1375 struct wl1271 *wl = hw->priv;
1376 const u8 *addr;
1377 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001378 u32 tx_seq_32 = 0;
1379 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001380 u8 key_type;
1381
1382 static const u8 bcast_addr[ETH_ALEN] =
1383 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1384
1385 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1386
1387 addr = sta ? sta->addr : bcast_addr;
1388
1389 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1390 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1391 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1392 key_conf->alg, key_conf->keyidx,
1393 key_conf->keylen, key_conf->flags);
1394 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1395
1396 if (is_zero_ether_addr(addr)) {
1397 /* We dont support TX only encryption */
1398 ret = -EOPNOTSUPP;
1399 goto out;
1400 }
1401
1402 mutex_lock(&wl->mutex);
1403
1404 ret = wl1271_ps_elp_wakeup(wl, false);
1405 if (ret < 0)
1406 goto out_unlock;
1407
1408 switch (key_conf->alg) {
1409 case ALG_WEP:
1410 key_type = KEY_WEP;
1411
1412 key_conf->hw_key_idx = key_conf->keyidx;
1413 break;
1414 case ALG_TKIP:
1415 key_type = KEY_TKIP;
1416
1417 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001418 tx_seq_32 = wl->tx_security_seq_32;
1419 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001420 break;
1421 case ALG_CCMP:
1422 key_type = KEY_AES;
1423
1424 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001425 tx_seq_32 = wl->tx_security_seq_32;
1426 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001427 break;
1428 default:
1429 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1430
1431 ret = -EOPNOTSUPP;
1432 goto out_sleep;
1433 }
1434
1435 switch (cmd) {
1436 case SET_KEY:
1437 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1438 key_conf->keyidx, key_type,
1439 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001440 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001441 if (ret < 0) {
1442 wl1271_error("Could not add or replace key");
1443 goto out_sleep;
1444 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001445
1446 /* the default WEP key needs to be configured at least once */
1447 if (key_type == KEY_WEP) {
1448 ret = wl1271_cmd_set_default_wep_key(wl,
1449 wl->default_key);
1450 if (ret < 0)
1451 goto out_sleep;
1452 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001453 break;
1454
1455 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001456 /* The wl1271 does not allow to remove unicast keys - they
1457 will be cleared automatically on next CMD_JOIN. Ignore the
1458 request silently, as we dont want the mac80211 to emit
1459 an error message. */
1460 if (!is_broadcast_ether_addr(addr))
1461 break;
1462
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001463 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1464 key_conf->keyidx, key_type,
1465 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001466 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001467 if (ret < 0) {
1468 wl1271_error("Could not remove key");
1469 goto out_sleep;
1470 }
1471 break;
1472
1473 default:
1474 wl1271_error("Unsupported key cmd 0x%x", cmd);
1475 ret = -EOPNOTSUPP;
1476 goto out_sleep;
1477
1478 break;
1479 }
1480
1481out_sleep:
1482 wl1271_ps_elp_sleep(wl);
1483
1484out_unlock:
1485 mutex_unlock(&wl->mutex);
1486
1487out:
1488 return ret;
1489}
1490
1491static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1492 struct cfg80211_scan_request *req)
1493{
1494 struct wl1271 *wl = hw->priv;
1495 int ret;
1496 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001497 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001498
1499 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1500
1501 if (req->n_ssids) {
1502 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001503 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001504 }
1505
1506 mutex_lock(&wl->mutex);
1507
1508 ret = wl1271_ps_elp_wakeup(wl, false);
1509 if (ret < 0)
1510 goto out;
1511
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001512 if (wl1271_11a_enabled())
1513 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1514 WL1271_SCAN_BAND_DUAL, 3);
1515 else
1516 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1517 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001518
1519 wl1271_ps_elp_sleep(wl);
1520
1521out:
1522 mutex_unlock(&wl->mutex);
1523
1524 return ret;
1525}
1526
1527static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1528{
1529 struct wl1271 *wl = hw->priv;
1530 int ret;
1531
1532 mutex_lock(&wl->mutex);
1533
1534 ret = wl1271_ps_elp_wakeup(wl, false);
1535 if (ret < 0)
1536 goto out;
1537
1538 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1539 if (ret < 0)
1540 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1541
1542 wl1271_ps_elp_sleep(wl);
1543
1544out:
1545 mutex_unlock(&wl->mutex);
1546
1547 return ret;
1548}
1549
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001550static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1551{
1552 u8 *ptr = beacon->data +
1553 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1554
1555 /* find the location of the ssid in the beacon */
1556 while (ptr < beacon->data + beacon->len) {
1557 if (ptr[0] == WLAN_EID_SSID) {
1558 wl->ssid_len = ptr[1];
1559 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1560 return;
1561 }
1562 ptr += ptr[1];
1563 }
1564 wl1271_error("ad-hoc beacon template has no SSID!\n");
1565}
1566
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001567static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1568 struct ieee80211_vif *vif,
1569 struct ieee80211_bss_conf *bss_conf,
1570 u32 changed)
1571{
1572 enum wl1271_cmd_ps_mode mode;
1573 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001574 bool do_join = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001575 int ret;
1576
1577 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1578
1579 mutex_lock(&wl->mutex);
1580
1581 ret = wl1271_ps_elp_wakeup(wl, false);
1582 if (ret < 0)
1583 goto out;
1584
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001585 if (wl->bss_type == BSS_TYPE_IBSS) {
1586 /* FIXME: This implements rudimentary ad-hoc support -
1587 proper templates are on the wish list and notification
1588 on when they change. This patch will update the templates
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001589 on every call to this function. */
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001590 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1591
1592 if (beacon) {
1593 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001594
1595 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001596 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1597 beacon->data,
1598 beacon->len);
1599
1600 if (ret < 0) {
1601 dev_kfree_skb(beacon);
1602 goto out_sleep;
1603 }
1604
1605 hdr = (struct ieee80211_hdr *) beacon->data;
1606 hdr->frame_control = cpu_to_le16(
1607 IEEE80211_FTYPE_MGMT |
1608 IEEE80211_STYPE_PROBE_RESP);
1609
1610 ret = wl1271_cmd_template_set(wl,
1611 CMD_TEMPL_PROBE_RESPONSE,
1612 beacon->data,
1613 beacon->len);
1614 dev_kfree_skb(beacon);
1615 if (ret < 0)
1616 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001617
1618 /* Need to update the SSID (for filtering etc) */
1619 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001620 }
1621 }
1622
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001623 if ((changed & BSS_CHANGED_BSSID) &&
1624 /*
1625 * Now we know the correct bssid, so we send a new join command
1626 * and enable the BSSID filter
1627 */
1628 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
1629 wl->rx_config |= CFG_BSSID_FILTER_EN;
1630 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
1631 ret = wl1271_cmd_build_null_data(wl);
1632 if (ret < 0) {
1633 wl1271_warning("cmd buld null data failed %d",
1634 ret);
1635 goto out_sleep;
1636 }
1637
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001638 /* Need to update the BSSID (for filtering etc) */
1639 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001640 }
1641
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001642 if (changed & BSS_CHANGED_ASSOC) {
1643 if (bss_conf->assoc) {
1644 wl->aid = bss_conf->aid;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001645 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001646
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001647 /*
1648 * with wl1271, we don't need to update the
1649 * beacon_int and dtim_period, because the firmware
1650 * updates it by itself when the first beacon is
1651 * received after a join.
1652 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001653 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1654 if (ret < 0)
1655 goto out_sleep;
1656
1657 ret = wl1271_acx_aid(wl, wl->aid);
1658 if (ret < 0)
1659 goto out_sleep;
1660
1661 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001662 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1663 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001664 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001665 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001666 if (ret < 0)
1667 goto out_sleep;
1668 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001669 } else {
1670 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001671 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001672 wl->aid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001673 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001674
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001675 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001676
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001677 if (changed & BSS_CHANGED_ERP_SLOT) {
1678 if (bss_conf->use_short_slot)
1679 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1680 else
1681 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1682 if (ret < 0) {
1683 wl1271_warning("Set slot time failed %d", ret);
1684 goto out_sleep;
1685 }
1686 }
1687
1688 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1689 if (bss_conf->use_short_preamble)
1690 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1691 else
1692 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1693 }
1694
1695 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1696 if (bss_conf->use_cts_prot)
1697 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1698 else
1699 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1700 if (ret < 0) {
1701 wl1271_warning("Set ctsprotect failed %d", ret);
1702 goto out_sleep;
1703 }
1704 }
1705
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001706 if (do_join) {
1707 ret = wl1271_cmd_join(wl);
1708 if (ret < 0) {
1709 wl1271_warning("cmd join failed %d", ret);
1710 goto out_sleep;
1711 }
1712 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1713 }
1714
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001715out_sleep:
1716 wl1271_ps_elp_sleep(wl);
1717
1718out:
1719 mutex_unlock(&wl->mutex);
1720}
1721
Kalle Valoc6999d82010-02-18 13:25:41 +02001722static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1723 const struct ieee80211_tx_queue_params *params)
1724{
1725 struct wl1271 *wl = hw->priv;
1726 int ret;
1727
1728 mutex_lock(&wl->mutex);
1729
1730 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1731
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001732 ret = wl1271_ps_elp_wakeup(wl, false);
1733 if (ret < 0)
1734 goto out;
1735
Kalle Valoc6999d82010-02-18 13:25:41 +02001736 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1737 params->cw_min, params->cw_max,
1738 params->aifs, params->txop);
1739 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001740 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001741
1742 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1743 CONF_CHANNEL_TYPE_EDCF,
1744 wl1271_tx_get_queue(queue),
1745 CONF_PS_SCHEME_LEGACY_PSPOLL,
1746 CONF_ACK_POLICY_LEGACY, 0, 0);
1747 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001748 goto out_sleep;
1749
1750out_sleep:
1751 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001752
1753out:
1754 mutex_unlock(&wl->mutex);
1755
1756 return ret;
1757}
1758
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001759
1760/* can't be const, mac80211 writes to this */
1761static struct ieee80211_rate wl1271_rates[] = {
1762 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001763 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1764 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001765 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001766 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1767 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001768 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1769 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001770 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1771 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001772 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1773 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001774 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1775 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001776 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1777 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001778 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1779 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001780 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001781 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1782 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001783 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001784 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1785 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001786 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001787 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1788 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001789 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001790 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1791 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001792 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001793 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1794 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001795 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001796 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1797 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001798 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001799 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1800 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001801};
1802
1803/* can't be const, mac80211 writes to this */
1804static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001805 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1806 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1807 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1808 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1809 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1810 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1811 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1812 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1813 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1814 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1815 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1816 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1817 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001818};
1819
1820/* can't be const, mac80211 writes to this */
1821static struct ieee80211_supported_band wl1271_band_2ghz = {
1822 .channels = wl1271_channels,
1823 .n_channels = ARRAY_SIZE(wl1271_channels),
1824 .bitrates = wl1271_rates,
1825 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1826};
1827
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001828/* 5 GHz data rates for WL1273 */
1829static struct ieee80211_rate wl1271_rates_5ghz[] = {
1830 { .bitrate = 60,
1831 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1832 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
1833 { .bitrate = 90,
1834 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1835 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
1836 { .bitrate = 120,
1837 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1838 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
1839 { .bitrate = 180,
1840 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1841 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
1842 { .bitrate = 240,
1843 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1844 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
1845 { .bitrate = 360,
1846 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1847 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
1848 { .bitrate = 480,
1849 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1850 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
1851 { .bitrate = 540,
1852 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1853 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
1854};
1855
1856/* 5 GHz band channels for WL1273 */
1857static struct ieee80211_channel wl1271_channels_5ghz[] = {
1858 { .hw_value = 183, .center_freq = 4915},
1859 { .hw_value = 184, .center_freq = 4920},
1860 { .hw_value = 185, .center_freq = 4925},
1861 { .hw_value = 187, .center_freq = 4935},
1862 { .hw_value = 188, .center_freq = 4940},
1863 { .hw_value = 189, .center_freq = 4945},
1864 { .hw_value = 192, .center_freq = 4960},
1865 { .hw_value = 196, .center_freq = 4980},
1866 { .hw_value = 7, .center_freq = 5035},
1867 { .hw_value = 8, .center_freq = 5040},
1868 { .hw_value = 9, .center_freq = 5045},
1869 { .hw_value = 11, .center_freq = 5055},
1870 { .hw_value = 12, .center_freq = 5060},
1871 { .hw_value = 16, .center_freq = 5080},
1872 { .hw_value = 34, .center_freq = 5170},
1873 { .hw_value = 36, .center_freq = 5180},
1874 { .hw_value = 38, .center_freq = 5190},
1875 { .hw_value = 40, .center_freq = 5200},
1876 { .hw_value = 42, .center_freq = 5210},
1877 { .hw_value = 44, .center_freq = 5220},
1878 { .hw_value = 46, .center_freq = 5230},
1879 { .hw_value = 48, .center_freq = 5240},
1880 { .hw_value = 52, .center_freq = 5260},
1881 { .hw_value = 56, .center_freq = 5280},
1882 { .hw_value = 60, .center_freq = 5300},
1883 { .hw_value = 64, .center_freq = 5320},
1884 { .hw_value = 100, .center_freq = 5500},
1885 { .hw_value = 104, .center_freq = 5520},
1886 { .hw_value = 108, .center_freq = 5540},
1887 { .hw_value = 112, .center_freq = 5560},
1888 { .hw_value = 116, .center_freq = 5580},
1889 { .hw_value = 120, .center_freq = 5600},
1890 { .hw_value = 124, .center_freq = 5620},
1891 { .hw_value = 128, .center_freq = 5640},
1892 { .hw_value = 132, .center_freq = 5660},
1893 { .hw_value = 136, .center_freq = 5680},
1894 { .hw_value = 140, .center_freq = 5700},
1895 { .hw_value = 149, .center_freq = 5745},
1896 { .hw_value = 153, .center_freq = 5765},
1897 { .hw_value = 157, .center_freq = 5785},
1898 { .hw_value = 161, .center_freq = 5805},
1899 { .hw_value = 165, .center_freq = 5825},
1900};
1901
1902
1903static struct ieee80211_supported_band wl1271_band_5ghz = {
1904 .channels = wl1271_channels_5ghz,
1905 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
1906 .bitrates = wl1271_rates_5ghz,
1907 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
1908};
1909
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001910static const struct ieee80211_ops wl1271_ops = {
1911 .start = wl1271_op_start,
1912 .stop = wl1271_op_stop,
1913 .add_interface = wl1271_op_add_interface,
1914 .remove_interface = wl1271_op_remove_interface,
1915 .config = wl1271_op_config,
1916/* .config_interface = wl1271_op_config_interface, */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001917 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001918 .configure_filter = wl1271_op_configure_filter,
1919 .tx = wl1271_op_tx,
1920 .set_key = wl1271_op_set_key,
1921 .hw_scan = wl1271_op_hw_scan,
1922 .bss_info_changed = wl1271_op_bss_info_changed,
1923 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02001924 .conf_tx = wl1271_op_conf_tx,
Kalle Valoc8c90872010-02-18 13:25:53 +02001925 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001926};
1927
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02001928int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001929{
1930 int ret;
1931
1932 if (wl->mac80211_registered)
1933 return 0;
1934
1935 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
1936
1937 ret = ieee80211_register_hw(wl->hw);
1938 if (ret < 0) {
1939 wl1271_error("unable to register mac80211 hw: %d", ret);
1940 return ret;
1941 }
1942
1943 wl->mac80211_registered = true;
1944
1945 wl1271_notice("loaded");
1946
1947 return 0;
1948}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02001949EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001950
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02001951int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001952{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03001953 /* The tx descriptor buffer and the TKIP space. */
1954 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
1955 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001956
1957 /* unit us */
1958 /* FIXME: find a proper value */
1959 wl->hw->channel_change_time = 10000;
1960
1961 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03001962 IEEE80211_HW_NOISE_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02001963 IEEE80211_HW_BEACON_FILTER |
1964 IEEE80211_HW_SUPPORTS_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001965
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001966 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
1967 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001968 wl->hw->wiphy->max_scan_ssids = 1;
1969 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
1970
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001971 if (wl1271_11a_enabled())
1972 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
1973
Teemu Paasikivi8197b712010-02-22 08:38:23 +02001974 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001975
1976 return 0;
1977}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02001978EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001979
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001980#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02001981
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02001982struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001983{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001984 struct ieee80211_hw *hw;
1985 struct wl1271 *wl;
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02001986 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001987
1988 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
1989 if (!hw) {
1990 wl1271_error("could not alloc ieee80211_hw");
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02001991 return ERR_PTR(-ENOMEM);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001992 }
1993
1994 wl = hw->priv;
1995 memset(wl, 0, sizeof(*wl));
1996
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001997 INIT_LIST_HEAD(&wl->list);
1998
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001999 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002000
2001 skb_queue_head_init(&wl->tx_queue);
2002
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002003 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002004 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002005 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002006 wl->rx_counter = 0;
2007 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2008 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002009 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002010 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002011 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002012 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2013 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002014 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002015 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002016 wl->flags = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002017
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002018 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002019 wl->tx_frames[i] = NULL;
2020
2021 spin_lock_init(&wl->wl_lock);
2022
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002023 wl->state = WL1271_STATE_OFF;
2024 mutex_init(&wl->mutex);
2025
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002026 /* Apply default driver configuration. */
2027 wl1271_conf_init(wl);
2028
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002029 wl1271_debugfs_init(wl);
2030
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002031 return hw;
2032}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002033EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002034
2035int wl1271_free_hw(struct wl1271 *wl)
2036{
2037 ieee80211_unregister_hw(wl->hw);
2038
2039 wl1271_debugfs_exit(wl);
2040
2041 kfree(wl->target_mem_map);
2042 vfree(wl->fw);
2043 wl->fw = NULL;
2044 kfree(wl->nvs);
2045 wl->nvs = NULL;
2046
2047 kfree(wl->fw_status);
2048 kfree(wl->tx_res_if);
2049
2050 ieee80211_free_hw(wl->hw);
2051
2052 return 0;
2053}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002054EXPORT_SYMBOL_GPL(wl1271_free_hw);
2055
2056MODULE_LICENSE("GPL");
2057MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2058MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");