blob: 66fb9a0a8efaa3b7eef76e5d803063715b98a622 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
25#include <linux/platform_device.h>
26#include <linux/interrupt.h>
27#include <linux/firmware.h>
28#include <linux/delay.h>
29#include <linux/irq.h>
30#include <linux/spi/spi.h>
31#include <linux/crc32.h>
32#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030033#include <linux/vmalloc.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030034#include <linux/spi/wl12xx.h>
Juuso Oikarinen01c09162009-10-13 12:47:55 +030035#include <linux/inetdevice.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036
37#include "wl1271.h"
38#include "wl12xx_80211.h"
39#include "wl1271_reg.h"
40#include "wl1271_spi.h"
Teemu Paasikivi7b048c52010-02-18 13:25:55 +020041#include "wl1271_io.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030042#include "wl1271_event.h"
43#include "wl1271_tx.h"
44#include "wl1271_rx.h"
45#include "wl1271_ps.h"
46#include "wl1271_init.h"
47#include "wl1271_debugfs.h"
48#include "wl1271_cmd.h"
49#include "wl1271_boot.h"
Kalle Valoc8c90872010-02-18 13:25:53 +020050#include "wl1271_testmode.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030051
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020052#define WL1271_BOOT_RETRIES 3
53
Juuso Oikarinen8a080482009-10-13 12:47:44 +030054static struct conf_drv_settings default_conf = {
55 .sg = {
56 .per_threshold = 7500,
57 .max_scan_compensation_time = 120000,
58 .nfs_sample_interval = 400,
59 .load_ratio = 50,
60 .auto_ps_mode = 0,
61 .probe_req_compensation = 170,
62 .scan_window_compensation = 50,
63 .antenna_config = 0,
64 .beacon_miss_threshold = 60,
65 .rate_adaptation_threshold = CONF_HW_BIT_RATE_12MBPS,
66 .rate_adaptation_snr = 0
67 },
68 .rx = {
69 .rx_msdu_life_time = 512000,
70 .packet_detection_threshold = 0,
71 .ps_poll_timeout = 15,
72 .upsd_timeout = 15,
73 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +020074 .rx_cca_threshold = 0,
75 .irq_blk_threshold = 0xFFFF,
76 .irq_pkt_threshold = 0,
77 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +030078 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
79 },
80 .tx = {
81 .tx_energy_detection = 0,
82 .rc_conf = {
Juuso Oikarinenec078d92009-12-11 15:41:05 +020083 .enabled_rates = CONF_HW_BIT_RATE_1MBPS |
84 CONF_HW_BIT_RATE_2MBPS,
Juuso Oikarinen8a080482009-10-13 12:47:44 +030085 .short_retry_limit = 10,
86 .long_retry_limit = 10,
87 .aflags = 0
88 },
89 .ac_conf_count = 4,
90 .ac_conf = {
91 [0] = {
92 .ac = CONF_TX_AC_BE,
93 .cw_min = 15,
94 .cw_max = 63,
95 .aifsn = 3,
96 .tx_op_limit = 0,
97 },
98 [1] = {
99 .ac = CONF_TX_AC_BK,
100 .cw_min = 15,
101 .cw_max = 63,
102 .aifsn = 7,
103 .tx_op_limit = 0,
104 },
105 [2] = {
106 .ac = CONF_TX_AC_VI,
107 .cw_min = 15,
108 .cw_max = 63,
109 .aifsn = CONF_TX_AIFS_PIFS,
110 .tx_op_limit = 3008,
111 },
112 [3] = {
113 .ac = CONF_TX_AC_VO,
114 .cw_min = 15,
115 .cw_max = 63,
116 .aifsn = CONF_TX_AIFS_PIFS,
117 .tx_op_limit = 1504,
118 },
119 },
120 .tid_conf_count = 7,
121 .tid_conf = {
122 [0] = {
123 .queue_id = 0,
124 .channel_type = CONF_CHANNEL_TYPE_DCF,
125 .tsid = CONF_TX_AC_BE,
126 .ps_scheme = CONF_PS_SCHEME_LEGACY,
127 .ack_policy = CONF_ACK_POLICY_LEGACY,
128 .apsd_conf = {0, 0},
129 },
130 [1] = {
131 .queue_id = 1,
132 .channel_type = CONF_CHANNEL_TYPE_DCF,
133 .tsid = CONF_TX_AC_BE,
134 .ps_scheme = CONF_PS_SCHEME_LEGACY,
135 .ack_policy = CONF_ACK_POLICY_LEGACY,
136 .apsd_conf = {0, 0},
137 },
138 [2] = {
139 .queue_id = 2,
140 .channel_type = CONF_CHANNEL_TYPE_DCF,
141 .tsid = CONF_TX_AC_BE,
142 .ps_scheme = CONF_PS_SCHEME_LEGACY,
143 .ack_policy = CONF_ACK_POLICY_LEGACY,
144 .apsd_conf = {0, 0},
145 },
146 [3] = {
147 .queue_id = 3,
148 .channel_type = CONF_CHANNEL_TYPE_DCF,
149 .tsid = CONF_TX_AC_BE,
150 .ps_scheme = CONF_PS_SCHEME_LEGACY,
151 .ack_policy = CONF_ACK_POLICY_LEGACY,
152 .apsd_conf = {0, 0},
153 },
154 [4] = {
155 .queue_id = 4,
156 .channel_type = CONF_CHANNEL_TYPE_DCF,
157 .tsid = CONF_TX_AC_BE,
158 .ps_scheme = CONF_PS_SCHEME_LEGACY,
159 .ack_policy = CONF_ACK_POLICY_LEGACY,
160 .apsd_conf = {0, 0},
161 },
162 [5] = {
163 .queue_id = 5,
164 .channel_type = CONF_CHANNEL_TYPE_DCF,
165 .tsid = CONF_TX_AC_BE,
166 .ps_scheme = CONF_PS_SCHEME_LEGACY,
167 .ack_policy = CONF_ACK_POLICY_LEGACY,
168 .apsd_conf = {0, 0},
169 },
170 [6] = {
171 .queue_id = 6,
172 .channel_type = CONF_CHANNEL_TYPE_DCF,
173 .tsid = CONF_TX_AC_BE,
174 .ps_scheme = CONF_PS_SCHEME_LEGACY,
175 .ack_policy = CONF_ACK_POLICY_LEGACY,
176 .apsd_conf = {0, 0},
177 }
178 },
179 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200180 .tx_compl_timeout = 700,
181 .tx_compl_threshold = 4
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300182 },
183 .conn = {
184 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
185 .listen_interval = 0,
186 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
187 .bcn_filt_ie_count = 1,
188 .bcn_filt_ie = {
189 [0] = {
190 .ie = WLAN_EID_CHANNEL_SWITCH,
191 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
192 }
193 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200194 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300195 .bss_lose_timeout = 100,
196 .beacon_rx_timeout = 10000,
197 .broadcast_timeout = 20000,
198 .rx_broadcast_in_ps = 1,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200199 .ps_poll_threshold = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300200 .sig_trigger_count = 2,
201 .sig_trigger = {
202 [0] = {
203 .threshold = -75,
204 .pacing = 500,
205 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
206 .type = CONF_TRIG_EVENT_TYPE_EDGE,
207 .direction = CONF_TRIG_EVENT_DIR_LOW,
208 .hysteresis = 2,
209 .index = 0,
210 .enable = 1
211 },
212 [1] = {
213 .threshold = -75,
214 .pacing = 500,
215 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
216 .type = CONF_TRIG_EVENT_TYPE_EDGE,
217 .direction = CONF_TRIG_EVENT_DIR_HIGH,
218 .hysteresis = 2,
219 .index = 1,
220 .enable = 1
221 }
222 },
223 .sig_weights = {
224 .rssi_bcn_avg_weight = 10,
225 .rssi_pkt_avg_weight = 10,
226 .snr_bcn_avg_weight = 10,
227 .snr_pkt_avg_weight = 10
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300228 },
229 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200230 .bet_max_consecutive = 10,
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200231 .psm_entry_retries = 3
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300232 },
233 .init = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300234 .radioparam = {
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200235 .fem = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300236 }
Luciano Coelho6e92b412009-12-11 15:40:50 +0200237 },
238 .itrim = {
239 .enable = false,
240 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200241 },
242 .pm_config = {
243 .host_clk_settling_time = 5000,
244 .host_fast_wakeup_support = false
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300245 }
246};
247
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300248static LIST_HEAD(wl_list);
249
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300250static void wl1271_conf_init(struct wl1271 *wl)
251{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300252
253 /*
254 * This function applies the default configuration to the driver. This
255 * function is invoked upon driver load (spi probe.)
256 *
257 * The configuration is stored in a run-time structure in order to
258 * facilitate for run-time adjustment of any of the parameters. Making
259 * changes to the configuration structure will apply the new values on
260 * the next interface up (wl1271_op_start.)
261 */
262
263 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300264 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300265}
266
267
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300268static int wl1271_plt_init(struct wl1271 *wl)
269{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200270 struct conf_tx_ac_category *conf_ac;
271 struct conf_tx_tid *conf_tid;
272 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300273
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200274 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200275 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200276 return ret;
277
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200278 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200279 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200280 return ret;
281
Luciano Coelho12419cc2010-02-18 13:25:44 +0200282 ret = wl1271_init_templates_config(wl);
283 if (ret < 0)
284 return ret;
285
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300286 ret = wl1271_acx_init_mem_config(wl);
287 if (ret < 0)
288 return ret;
289
Luciano Coelho12419cc2010-02-18 13:25:44 +0200290 /* PHY layer config */
291 ret = wl1271_init_phy_config(wl);
292 if (ret < 0)
293 goto out_free_memmap;
294
295 ret = wl1271_acx_dco_itrim_params(wl);
296 if (ret < 0)
297 goto out_free_memmap;
298
299 /* Initialize connection monitoring thresholds */
300 ret = wl1271_acx_conn_monit_params(wl);
301 if (ret < 0)
302 goto out_free_memmap;
303
304 /* Bluetooth WLAN coexistence */
305 ret = wl1271_init_pta(wl);
306 if (ret < 0)
307 goto out_free_memmap;
308
309 /* Energy detection */
310 ret = wl1271_init_energy_detection(wl);
311 if (ret < 0)
312 goto out_free_memmap;
313
314 /* Default fragmentation threshold */
315 ret = wl1271_acx_frag_threshold(wl);
316 if (ret < 0)
317 goto out_free_memmap;
318
319 /* Default TID configuration */
320 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
321 conf_tid = &wl->conf.tx.tid_conf[i];
322 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
323 conf_tid->channel_type,
324 conf_tid->tsid,
325 conf_tid->ps_scheme,
326 conf_tid->ack_policy,
327 conf_tid->apsd_conf[0],
328 conf_tid->apsd_conf[1]);
329 if (ret < 0)
330 goto out_free_memmap;
331 }
332
333 /* Default AC configuration */
334 for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
335 conf_ac = &wl->conf.tx.ac_conf[i];
336 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
337 conf_ac->cw_max, conf_ac->aifsn,
338 conf_ac->tx_op_limit);
339 if (ret < 0)
340 goto out_free_memmap;
341 }
342
343 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200344 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300345 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200346 goto out_free_memmap;
347
348 /* Configure for CAM power saving (ie. always active) */
349 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
350 if (ret < 0)
351 goto out_free_memmap;
352
353 /* configure PM */
354 ret = wl1271_acx_pm_config(wl);
355 if (ret < 0)
356 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300357
358 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200359
360 out_free_memmap:
361 kfree(wl->target_mem_map);
362 wl->target_mem_map = NULL;
363
364 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300365}
366
367static void wl1271_disable_interrupts(struct wl1271 *wl)
368{
369 disable_irq(wl->irq);
370}
371
372static void wl1271_power_off(struct wl1271 *wl)
373{
374 wl->set_power(false);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200375 clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300376}
377
378static void wl1271_power_on(struct wl1271 *wl)
379{
380 wl->set_power(true);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200381 set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300382}
383
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300384static void wl1271_fw_status(struct wl1271 *wl,
385 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300386{
387 u32 total = 0;
388 int i;
389
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200390 wl1271_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300391
392 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
393 "drv_rx_counter = %d, tx_results_counter = %d)",
394 status->intr,
395 status->fw_rx_counter,
396 status->drv_rx_counter,
397 status->tx_results_counter);
398
399 /* update number of available TX blocks */
400 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300401 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
402 wl->tx_blocks_freed[i];
403
404 wl->tx_blocks_freed[i] =
405 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300406 wl->tx_blocks_available += cnt;
407 total += cnt;
408 }
409
410 /* if more blocks are available now, schedule some tx work */
411 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300412 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300413
414 /* update the host-chipset time offset */
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300415 wl->time_offset = jiffies_to_usecs(jiffies) -
416 le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300417}
418
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300419static void wl1271_irq_work(struct work_struct *work)
420{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300421 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300422 u32 intr;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300423 struct wl1271 *wl =
424 container_of(work, struct wl1271, irq_work);
425
426 mutex_lock(&wl->mutex);
427
428 wl1271_debug(DEBUG_IRQ, "IRQ work");
429
430 if (wl->state == WL1271_STATE_OFF)
431 goto out;
432
433 ret = wl1271_ps_elp_wakeup(wl, true);
434 if (ret < 0)
435 goto out;
436
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200437 wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300438
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300439 wl1271_fw_status(wl, wl->fw_status);
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300440 intr = le32_to_cpu(wl->fw_status->intr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300441 if (!intr) {
442 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
443 goto out_sleep;
444 }
445
446 intr &= WL1271_INTR_MASK;
447
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300448 if (intr & WL1271_ACX_INTR_EVENT_A) {
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300449 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
Juuso Oikarinen13f2dc52009-12-11 15:40:59 +0200450 wl1271_event_handle(wl, 0);
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300451 }
452
453 if (intr & WL1271_ACX_INTR_EVENT_B) {
454 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
Juuso Oikarinen13f2dc52009-12-11 15:40:59 +0200455 wl1271_event_handle(wl, 1);
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300456 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300457
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300458 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
459 wl1271_debug(DEBUG_IRQ,
460 "WL1271_ACX_INTR_INIT_COMPLETE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300461
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300462 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
463 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300464
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300465 if (intr & WL1271_ACX_INTR_DATA) {
466 u8 tx_res_cnt = wl->fw_status->tx_results_counter -
467 wl->tx_results_count;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300468
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300469 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300470
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300471 /* check for tx results */
472 if (tx_res_cnt)
473 wl1271_tx_complete(wl, tx_res_cnt);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300474
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300475 wl1271_rx(wl, wl->fw_status);
476 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300477
478out_sleep:
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200479 wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
480 WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300481 wl1271_ps_elp_sleep(wl);
482
483out:
484 mutex_unlock(&wl->mutex);
485}
486
487static irqreturn_t wl1271_irq(int irq, void *cookie)
488{
489 struct wl1271 *wl;
490 unsigned long flags;
491
492 wl1271_debug(DEBUG_IRQ, "IRQ");
493
494 wl = cookie;
495
496 /* complete the ELP completion */
497 spin_lock_irqsave(&wl->wl_lock, flags);
498 if (wl->elp_compl) {
499 complete(wl->elp_compl);
500 wl->elp_compl = NULL;
501 }
502
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300503 ieee80211_queue_work(wl->hw, &wl->irq_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300504 spin_unlock_irqrestore(&wl->wl_lock, flags);
505
506 return IRQ_HANDLED;
507}
508
509static int wl1271_fetch_firmware(struct wl1271 *wl)
510{
511 const struct firmware *fw;
512 int ret;
513
514 ret = request_firmware(&fw, WL1271_FW_NAME, &wl->spi->dev);
515
516 if (ret < 0) {
517 wl1271_error("could not get firmware: %d", ret);
518 return ret;
519 }
520
521 if (fw->size % 4) {
522 wl1271_error("firmware size is not multiple of 32 bits: %zu",
523 fw->size);
524 ret = -EILSEQ;
525 goto out;
526 }
527
528 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300529 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300530
531 if (!wl->fw) {
532 wl1271_error("could not allocate memory for the firmware");
533 ret = -ENOMEM;
534 goto out;
535 }
536
537 memcpy(wl->fw, fw->data, wl->fw_len);
538
539 ret = 0;
540
541out:
542 release_firmware(fw);
543
544 return ret;
545}
546
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200547static int wl1271_update_mac_addr(struct wl1271 *wl)
548{
549 int ret = 0;
550 u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
551
552 /* get mac address from the NVS */
553 wl->mac_addr[0] = nvs_ptr[11];
554 wl->mac_addr[1] = nvs_ptr[10];
555 wl->mac_addr[2] = nvs_ptr[6];
556 wl->mac_addr[3] = nvs_ptr[5];
557 wl->mac_addr[4] = nvs_ptr[4];
558 wl->mac_addr[5] = nvs_ptr[3];
559
560 /* FIXME: if it is a zero-address, we should bail out. Now, instead,
561 we randomize an address */
562 if (is_zero_ether_addr(wl->mac_addr)) {
563 static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
564 memcpy(wl->mac_addr, nokia_oui, 3);
565 get_random_bytes(wl->mac_addr + 3, 3);
Juuso Oikarinene2e77b52010-02-18 13:25:46 +0200566
567 /* update this address to the NVS */
568 nvs_ptr[11] = wl->mac_addr[0];
569 nvs_ptr[10] = wl->mac_addr[1];
570 nvs_ptr[6] = wl->mac_addr[2];
571 nvs_ptr[5] = wl->mac_addr[3];
572 nvs_ptr[4] = wl->mac_addr[4];
573 nvs_ptr[3] = wl->mac_addr[5];
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200574 }
575
576 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
577
578 return ret;
579}
580
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300581static int wl1271_fetch_nvs(struct wl1271 *wl)
582{
583 const struct firmware *fw;
584 int ret;
585
586 ret = request_firmware(&fw, WL1271_NVS_NAME, &wl->spi->dev);
587
588 if (ret < 0) {
589 wl1271_error("could not get nvs file: %d", ret);
590 return ret;
591 }
592
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200593 if (fw->size != sizeof(struct wl1271_nvs_file)) {
594 wl1271_error("nvs size is not as expected: %zu != %zu",
595 fw->size, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300596 ret = -EILSEQ;
597 goto out;
598 }
599
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200600 wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300601
602 if (!wl->nvs) {
603 wl1271_error("could not allocate memory for the nvs file");
604 ret = -ENOMEM;
605 goto out;
606 }
607
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200608 memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300609
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200610 ret = wl1271_update_mac_addr(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300611
612out:
613 release_firmware(fw);
614
615 return ret;
616}
617
618static void wl1271_fw_wakeup(struct wl1271 *wl)
619{
620 u32 elp_reg;
621
622 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300623 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300624}
625
626static int wl1271_setup(struct wl1271 *wl)
627{
628 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
629 if (!wl->fw_status)
630 return -ENOMEM;
631
632 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
633 if (!wl->tx_res_if) {
634 kfree(wl->fw_status);
635 return -ENOMEM;
636 }
637
638 INIT_WORK(&wl->irq_work, wl1271_irq_work);
639 INIT_WORK(&wl->tx_work, wl1271_tx_work);
640 return 0;
641}
642
643static int wl1271_chip_wakeup(struct wl1271 *wl)
644{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300645 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300646 int ret = 0;
647
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200648 msleep(WL1271_PRE_POWER_ON_SLEEP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300649 wl1271_power_on(wl);
650 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200651 wl1271_io_reset(wl);
652 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300653
654 /* We don't need a real memory partition here, because we only want
655 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300656 memset(&partition, 0, sizeof(partition));
657 partition.reg.start = REGISTERS_BASE;
658 partition.reg.size = REGISTERS_DOWN_SIZE;
659 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300660
661 /* ELP module wake up */
662 wl1271_fw_wakeup(wl);
663
664 /* whal_FwCtrl_BootSm() */
665
666 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200667 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300668
669 /* 1. check if chip id is valid */
670
671 switch (wl->chip.id) {
672 case CHIP_ID_1271_PG10:
673 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
674 wl->chip.id);
675
676 ret = wl1271_setup(wl);
677 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200678 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300679 break;
680 case CHIP_ID_1271_PG20:
681 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
682 wl->chip.id);
683
684 ret = wl1271_setup(wl);
685 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200686 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300687 break;
688 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200689 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300690 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200691 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300692 }
693
694 if (wl->fw == NULL) {
695 ret = wl1271_fetch_firmware(wl);
696 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200697 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300698 }
699
700 /* No NVS from netlink, try to get it from the filesystem */
701 if (wl->nvs == NULL) {
702 ret = wl1271_fetch_nvs(wl);
703 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200704 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300705 }
706
707out:
708 return ret;
709}
710
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300711int wl1271_plt_start(struct wl1271 *wl)
712{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200713 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300714 int ret;
715
716 mutex_lock(&wl->mutex);
717
718 wl1271_notice("power up");
719
720 if (wl->state != WL1271_STATE_OFF) {
721 wl1271_error("cannot go into PLT state because not "
722 "in off state: %d", wl->state);
723 ret = -EBUSY;
724 goto out;
725 }
726
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200727 while (retries) {
728 retries--;
729 ret = wl1271_chip_wakeup(wl);
730 if (ret < 0)
731 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300732
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200733 ret = wl1271_boot(wl);
734 if (ret < 0)
735 goto power_off;
736
737 ret = wl1271_plt_init(wl);
738 if (ret < 0)
739 goto irq_disable;
740
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200741 wl->state = WL1271_STATE_PLT;
742 wl1271_notice("firmware booted in PLT mode (%s)",
743 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300744 goto out;
745
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200746irq_disable:
747 wl1271_disable_interrupts(wl);
748 mutex_unlock(&wl->mutex);
749 /* Unlocking the mutex in the middle of handling is
750 inherently unsafe. In this case we deem it safe to do,
751 because we need to let any possibly pending IRQ out of
752 the system (and while we are WL1271_STATE_OFF the IRQ
753 work function will not do anything.) Also, any other
754 possible concurrent operations will fail due to the
755 current state, hence the wl1271 struct should be safe. */
756 cancel_work_sync(&wl->irq_work);
757 mutex_lock(&wl->mutex);
758power_off:
759 wl1271_power_off(wl);
760 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300761
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200762 wl1271_error("firmware boot in PLT mode failed despite %d retries",
763 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300764out:
765 mutex_unlock(&wl->mutex);
766
767 return ret;
768}
769
770int wl1271_plt_stop(struct wl1271 *wl)
771{
772 int ret = 0;
773
774 mutex_lock(&wl->mutex);
775
776 wl1271_notice("power down");
777
778 if (wl->state != WL1271_STATE_PLT) {
779 wl1271_error("cannot power down because not in PLT "
780 "state: %d", wl->state);
781 ret = -EBUSY;
782 goto out;
783 }
784
785 wl1271_disable_interrupts(wl);
786 wl1271_power_off(wl);
787
788 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300789 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300790
791out:
792 mutex_unlock(&wl->mutex);
793
794 return ret;
795}
796
797
798static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
799{
800 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200801 struct ieee80211_conf *conf = &hw->conf;
802 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
803 struct ieee80211_sta *sta = txinfo->control.sta;
804 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300805
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200806 /* peek into the rates configured in the STA entry */
807 spin_lock_irqsave(&wl->wl_lock, flags);
808 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
809 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
810 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
811 }
812 spin_unlock_irqrestore(&wl->wl_lock, flags);
813
814 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300815 skb_queue_tail(&wl->tx_queue, skb);
816
817 /*
818 * The chip specific setup must run before the first TX packet -
819 * before that, the tx_work will not be initialized!
820 */
821
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300822 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300823
824 /*
825 * The workqueue is slow to process the tx_queue and we need stop
826 * the queue here, otherwise the queue will get too long.
827 */
828 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) {
829 ieee80211_stop_queues(wl->hw);
830
831 /*
832 * FIXME: this is racy, the variable is not properly
833 * protected. Maybe fix this by removing the stupid
834 * variable altogether and checking the real queue state?
835 */
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200836 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300837 }
838
839 return NETDEV_TX_OK;
840}
841
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300842static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
843 void *arg)
844{
845 struct net_device *dev;
846 struct wireless_dev *wdev;
847 struct wiphy *wiphy;
848 struct ieee80211_hw *hw;
849 struct wl1271 *wl;
850 struct wl1271 *wl_temp;
851 struct in_device *idev;
852 struct in_ifaddr *ifa = arg;
853 int ret = 0;
854
855 /* FIXME: this ugly function should probably be implemented in the
856 * mac80211, and here should only be a simple callback handling actual
857 * setting of the filters. Now we need to dig up references to
858 * various structures to gain access to what we need.
859 * Also, because of this, there is no "initial" setting of the filter
860 * in "op_start", because we don't want to dig up struct net_device
861 * there - the filter will be set upon first change of the interface
862 * IP address. */
863
864 dev = ifa->ifa_dev->dev;
865
866 wdev = dev->ieee80211_ptr;
867 if (wdev == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200868 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300869
870 wiphy = wdev->wiphy;
871 if (wiphy == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200872 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300873
874 hw = wiphy_priv(wiphy);
875 if (hw == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200876 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300877
878 /* Check that the interface is one supported by this driver. */
879 wl_temp = hw->priv;
880 list_for_each_entry(wl, &wl_list, list) {
881 if (wl == wl_temp)
882 break;
883 }
884 if (wl == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200885 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300886
887 /* Get the interface IP address for the device. "ifa" will become
888 NULL if:
889 - there is no IPV4 protocol address configured
890 - there are multiple (virtual) IPV4 addresses configured
891 When "ifa" is NULL, filtering will be disabled.
892 */
893 ifa = NULL;
894 idev = dev->ip_ptr;
895 if (idev)
896 ifa = idev->ifa_list;
897
898 if (ifa && ifa->ifa_next)
899 ifa = NULL;
900
901 mutex_lock(&wl->mutex);
902
903 if (wl->state == WL1271_STATE_OFF)
904 goto out;
905
906 ret = wl1271_ps_elp_wakeup(wl, false);
907 if (ret < 0)
908 goto out;
909 if (ifa)
910 ret = wl1271_acx_arp_ip_filter(wl, true,
911 (u8 *)&ifa->ifa_address,
912 ACX_IPV4_VERSION);
913 else
914 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
915 ACX_IPV4_VERSION);
916 wl1271_ps_elp_sleep(wl);
917
918out:
919 mutex_unlock(&wl->mutex);
920
Luciano Coelho17d72652009-11-23 23:22:15 +0200921 return NOTIFY_OK;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300922}
923
924static struct notifier_block wl1271_dev_notifier = {
925 .notifier_call = wl1271_dev_notify,
926};
927
928
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300929static int wl1271_op_start(struct ieee80211_hw *hw)
930{
931 struct wl1271 *wl = hw->priv;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200932 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300933 int ret = 0;
934
935 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
936
937 mutex_lock(&wl->mutex);
938
939 if (wl->state != WL1271_STATE_OFF) {
940 wl1271_error("cannot start because not in off state: %d",
941 wl->state);
942 ret = -EBUSY;
943 goto out;
944 }
945
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200946 while (retries) {
947 retries--;
948 ret = wl1271_chip_wakeup(wl);
949 if (ret < 0)
950 goto power_off;
951
952 ret = wl1271_boot(wl);
953 if (ret < 0)
954 goto power_off;
955
956 ret = wl1271_hw_init(wl);
957 if (ret < 0)
958 goto irq_disable;
959
960 wl->state = WL1271_STATE_ON;
961 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300962 goto out;
963
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200964irq_disable:
965 wl1271_disable_interrupts(wl);
966 mutex_unlock(&wl->mutex);
967 /* Unlocking the mutex in the middle of handling is
968 inherently unsafe. In this case we deem it safe to do,
969 because we need to let any possibly pending IRQ out of
970 the system (and while we are WL1271_STATE_OFF the IRQ
971 work function will not do anything.) Also, any other
972 possible concurrent operations will fail due to the
973 current state, hence the wl1271 struct should be safe. */
974 cancel_work_sync(&wl->irq_work);
975 mutex_lock(&wl->mutex);
976power_off:
977 wl1271_power_off(wl);
978 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300979
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200980 wl1271_error("firmware boot failed despite %d retries",
981 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300982out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300983 mutex_unlock(&wl->mutex);
984
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300985 if (!ret) {
986 list_add(&wl->list, &wl_list);
987 register_inetaddr_notifier(&wl1271_dev_notifier);
988 }
989
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300990 return ret;
991}
992
993static void wl1271_op_stop(struct ieee80211_hw *hw)
994{
995 struct wl1271 *wl = hw->priv;
996 int i;
997
998 wl1271_info("down");
999
1000 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1001
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001002 unregister_inetaddr_notifier(&wl1271_dev_notifier);
1003 list_del(&wl->list);
1004
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001005 mutex_lock(&wl->mutex);
1006
1007 WARN_ON(wl->state != WL1271_STATE_ON);
1008
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001009 if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001010 mutex_unlock(&wl->mutex);
1011 ieee80211_scan_completed(wl->hw, true);
1012 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001013 }
1014
1015 wl->state = WL1271_STATE_OFF;
1016
1017 wl1271_disable_interrupts(wl);
1018
1019 mutex_unlock(&wl->mutex);
1020
1021 cancel_work_sync(&wl->irq_work);
1022 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001023
1024 mutex_lock(&wl->mutex);
1025
1026 /* let's notify MAC80211 about the remaining pending TX frames */
1027 wl1271_tx_flush(wl);
1028 wl1271_power_off(wl);
1029
1030 memset(wl->bssid, 0, ETH_ALEN);
1031 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1032 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001033 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001034 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001035
1036 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001037 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001038 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1039 wl->tx_blocks_available = 0;
1040 wl->tx_results_count = 0;
1041 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001042 wl->tx_security_last_seq = 0;
1043 wl->tx_security_seq_16 = 0;
1044 wl->tx_security_seq_32 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001045 wl->time_offset = 0;
1046 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001047 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1048 wl->sta_rate_set = 0;
1049 wl->flags = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001050
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001051 for (i = 0; i < NUM_TX_QUEUES; i++)
1052 wl->tx_blocks_freed[i] = 0;
1053
1054 wl1271_debugfs_reset(wl);
1055 mutex_unlock(&wl->mutex);
1056}
1057
1058static int wl1271_op_add_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +01001059 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001060{
1061 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001062 int ret = 0;
1063
John W. Linvillee5539bc2009-08-18 10:50:34 -04001064 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Johannes Berg1ed32e42009-12-23 13:15:45 +01001065 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001066
1067 mutex_lock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001068 if (wl->vif) {
1069 ret = -EBUSY;
1070 goto out;
1071 }
1072
Johannes Berg1ed32e42009-12-23 13:15:45 +01001073 wl->vif = vif;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001074
Johannes Berg1ed32e42009-12-23 13:15:45 +01001075 switch (vif->type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001076 case NL80211_IFTYPE_STATION:
1077 wl->bss_type = BSS_TYPE_STA_BSS;
1078 break;
1079 case NL80211_IFTYPE_ADHOC:
1080 wl->bss_type = BSS_TYPE_IBSS;
1081 break;
1082 default:
1083 ret = -EOPNOTSUPP;
1084 goto out;
1085 }
1086
1087 /* FIXME: what if conf->mac_addr changes? */
1088
1089out:
1090 mutex_unlock(&wl->mutex);
1091 return ret;
1092}
1093
1094static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +01001095 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001096{
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001097 struct wl1271 *wl = hw->priv;
1098
1099 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001100 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001101 wl->vif = NULL;
1102 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001103}
1104
1105#if 0
1106static int wl1271_op_config_interface(struct ieee80211_hw *hw,
1107 struct ieee80211_vif *vif,
1108 struct ieee80211_if_conf *conf)
1109{
1110 struct wl1271 *wl = hw->priv;
1111 struct sk_buff *beacon;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001112 int ret;
1113
David S. Miller32646902009-09-17 10:18:30 -07001114 wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM",
1115 conf->bssid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001116 wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid,
1117 conf->ssid_len);
1118
1119 mutex_lock(&wl->mutex);
1120
1121 ret = wl1271_ps_elp_wakeup(wl, false);
1122 if (ret < 0)
1123 goto out;
1124
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001125 if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
1126 wl1271_debug(DEBUG_MAC80211, "bssid changed");
1127
1128 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
1129
1130 ret = wl1271_cmd_join(wl);
1131 if (ret < 0)
1132 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001133
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001134 ret = wl1271_cmd_build_null_data(wl);
1135 if (ret < 0)
1136 goto out_sleep;
1137 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001138
1139 wl->ssid_len = conf->ssid_len;
1140 if (wl->ssid_len)
1141 memcpy(wl->ssid, conf->ssid, wl->ssid_len);
1142
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001143 if (conf->changed & IEEE80211_IFCC_BEACON) {
1144 beacon = ieee80211_beacon_get(hw, vif);
1145 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1146 beacon->data, beacon->len);
1147
1148 if (ret < 0) {
1149 dev_kfree_skb(beacon);
1150 goto out_sleep;
1151 }
1152
1153 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE,
1154 beacon->data, beacon->len);
1155
1156 dev_kfree_skb(beacon);
1157
1158 if (ret < 0)
1159 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001160 }
1161
1162out_sleep:
1163 wl1271_ps_elp_sleep(wl);
1164
1165out:
1166 mutex_unlock(&wl->mutex);
1167
1168 return ret;
1169}
1170#endif
1171
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001172static int wl1271_join_channel(struct wl1271 *wl, int channel)
1173{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001174 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001175 /* we need to use a dummy BSSID for now */
1176 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1177 0xad, 0xbe, 0xef };
1178
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001179 /* the dummy join is not required for ad-hoc */
1180 if (wl->bss_type == BSS_TYPE_IBSS)
1181 goto out;
1182
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001183 /* disable mac filter, so we hear everything */
1184 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1185
1186 wl->channel = channel;
1187 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1188
1189 ret = wl1271_cmd_join(wl);
1190 if (ret < 0)
1191 goto out;
1192
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001193 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001194
1195out:
1196 return ret;
1197}
1198
1199static int wl1271_unjoin_channel(struct wl1271 *wl)
1200{
1201 int ret;
1202
1203 /* to stop listening to a channel, we disconnect */
1204 ret = wl1271_cmd_disconnect(wl);
1205 if (ret < 0)
1206 goto out;
1207
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001208 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001209 wl->channel = 0;
1210 memset(wl->bssid, 0, ETH_ALEN);
1211 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1212
1213out:
1214 return ret;
1215}
1216
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001217static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1218{
1219 struct wl1271 *wl = hw->priv;
1220 struct ieee80211_conf *conf = &hw->conf;
1221 int channel, ret = 0;
1222
1223 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1224
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001225 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001226 channel,
1227 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001228 conf->power_level,
1229 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001230
1231 mutex_lock(&wl->mutex);
1232
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001233 wl->band = conf->channel->band;
1234
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001235 ret = wl1271_ps_elp_wakeup(wl, false);
1236 if (ret < 0)
1237 goto out;
1238
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001239 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001240 if (conf->flags & IEEE80211_CONF_IDLE &&
1241 test_bit(WL1271_FLAG_JOINED, &wl->flags))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001242 wl1271_unjoin_channel(wl);
Juuso Oikarinen8f648c02009-12-11 15:41:10 +02001243 else if (!(conf->flags & IEEE80211_CONF_IDLE))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001244 wl1271_join_channel(wl, channel);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001245
1246 if (conf->flags & IEEE80211_CONF_IDLE) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001247 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1248 wl->sta_rate_set = 0;
1249 wl1271_acx_rate_policies(wl);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001250 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001251 }
1252
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001253 /* if the channel changes while joined, join again */
Juuso Oikarinenddb01a52010-02-18 13:25:37 +02001254 if (channel != wl->channel &&
1255 test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1256 wl->channel = channel;
1257 /* FIXME: maybe use CMD_CHANNEL_SWITCH for this? */
1258 ret = wl1271_cmd_join(wl);
1259 if (ret < 0)
1260 wl1271_warning("cmd join to update channel failed %d",
1261 ret);
1262 } else
1263 wl->channel = channel;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001264
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001265 if (conf->flags & IEEE80211_CONF_PS &&
1266 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1267 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001268
1269 /*
1270 * We enter PSM only if we're already associated.
1271 * If we're not, we'll enter it when joining an SSID,
1272 * through the bss_info_changed() hook.
1273 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001274 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001275 wl1271_info("psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001276 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1277 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001278 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001279 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001280 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001281 wl1271_info("psm disabled");
1282
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001283 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001284
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001285 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001286 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1287 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001288 }
1289
1290 if (conf->power_level != wl->power_level) {
1291 ret = wl1271_acx_tx_power(wl, conf->power_level);
1292 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001293 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001294
1295 wl->power_level = conf->power_level;
1296 }
1297
1298out_sleep:
1299 wl1271_ps_elp_sleep(wl);
1300
1301out:
1302 mutex_unlock(&wl->mutex);
1303
1304 return ret;
1305}
1306
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001307struct wl1271_filter_params {
1308 bool enabled;
1309 int mc_list_length;
1310 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1311};
1312
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001313static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1314 struct dev_addr_list *mc_list)
1315{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001316 struct wl1271_filter_params *fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001317 int i;
1318
Juuso Oikarinen74441132009-10-13 12:47:53 +03001319 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001320 if (!fp) {
1321 wl1271_error("Out of memory setting filters.");
1322 return 0;
1323 }
1324
1325 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001326 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001327 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1328 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001329 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001330 }
1331
1332 fp->mc_list_length = 0;
1333 for (i = 0; i < mc_count; i++) {
1334 if (mc_list->da_addrlen == ETH_ALEN) {
1335 memcpy(fp->mc_list[fp->mc_list_length],
1336 mc_list->da_addr, ETH_ALEN);
1337 fp->mc_list_length++;
1338 } else
1339 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001340 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001341 }
1342
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001343 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001344}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001345
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001346#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1347 FIF_ALLMULTI | \
1348 FIF_FCSFAIL | \
1349 FIF_BCN_PRBRESP_PROMISC | \
1350 FIF_CONTROL | \
1351 FIF_OTHER_BSS)
1352
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001353static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1354 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001355 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001356{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001357 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001358 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001359 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001360
1361 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1362
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001363 mutex_lock(&wl->mutex);
1364
1365 if (wl->state == WL1271_STATE_OFF)
1366 goto out;
1367
1368 ret = wl1271_ps_elp_wakeup(wl, false);
1369 if (ret < 0)
1370 goto out;
1371
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001372 *total &= WL1271_SUPPORTED_FILTERS;
1373 changed &= WL1271_SUPPORTED_FILTERS;
1374
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001375 if (*total & FIF_ALLMULTI)
1376 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1377 else if (fp)
1378 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1379 fp->mc_list,
1380 fp->mc_list_length);
1381 if (ret < 0)
1382 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001383
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001384 kfree(fp);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001385
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001386 /* FIXME: We still need to set our filters properly */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001387
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001388 /* determine, whether supported filter values have changed */
1389 if (changed == 0)
1390 goto out_sleep;
1391
1392 /* apply configured filters */
1393 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1394 if (ret < 0)
1395 goto out_sleep;
1396
1397out_sleep:
1398 wl1271_ps_elp_sleep(wl);
1399
1400out:
1401 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001402}
1403
1404static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1405 struct ieee80211_vif *vif,
1406 struct ieee80211_sta *sta,
1407 struct ieee80211_key_conf *key_conf)
1408{
1409 struct wl1271 *wl = hw->priv;
1410 const u8 *addr;
1411 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001412 u32 tx_seq_32 = 0;
1413 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001414 u8 key_type;
1415
1416 static const u8 bcast_addr[ETH_ALEN] =
1417 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1418
1419 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1420
1421 addr = sta ? sta->addr : bcast_addr;
1422
1423 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1424 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1425 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1426 key_conf->alg, key_conf->keyidx,
1427 key_conf->keylen, key_conf->flags);
1428 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1429
1430 if (is_zero_ether_addr(addr)) {
1431 /* We dont support TX only encryption */
1432 ret = -EOPNOTSUPP;
1433 goto out;
1434 }
1435
1436 mutex_lock(&wl->mutex);
1437
1438 ret = wl1271_ps_elp_wakeup(wl, false);
1439 if (ret < 0)
1440 goto out_unlock;
1441
1442 switch (key_conf->alg) {
1443 case ALG_WEP:
1444 key_type = KEY_WEP;
1445
1446 key_conf->hw_key_idx = key_conf->keyidx;
1447 break;
1448 case ALG_TKIP:
1449 key_type = KEY_TKIP;
1450
1451 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001452 tx_seq_32 = wl->tx_security_seq_32;
1453 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001454 break;
1455 case ALG_CCMP:
1456 key_type = KEY_AES;
1457
1458 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001459 tx_seq_32 = wl->tx_security_seq_32;
1460 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001461 break;
1462 default:
1463 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1464
1465 ret = -EOPNOTSUPP;
1466 goto out_sleep;
1467 }
1468
1469 switch (cmd) {
1470 case SET_KEY:
1471 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1472 key_conf->keyidx, key_type,
1473 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001474 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001475 if (ret < 0) {
1476 wl1271_error("Could not add or replace key");
1477 goto out_sleep;
1478 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001479
1480 /* the default WEP key needs to be configured at least once */
1481 if (key_type == KEY_WEP) {
1482 ret = wl1271_cmd_set_default_wep_key(wl,
1483 wl->default_key);
1484 if (ret < 0)
1485 goto out_sleep;
1486 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001487 break;
1488
1489 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001490 /* The wl1271 does not allow to remove unicast keys - they
1491 will be cleared automatically on next CMD_JOIN. Ignore the
1492 request silently, as we dont want the mac80211 to emit
1493 an error message. */
1494 if (!is_broadcast_ether_addr(addr))
1495 break;
1496
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001497 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1498 key_conf->keyidx, key_type,
1499 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001500 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001501 if (ret < 0) {
1502 wl1271_error("Could not remove key");
1503 goto out_sleep;
1504 }
1505 break;
1506
1507 default:
1508 wl1271_error("Unsupported key cmd 0x%x", cmd);
1509 ret = -EOPNOTSUPP;
1510 goto out_sleep;
1511
1512 break;
1513 }
1514
1515out_sleep:
1516 wl1271_ps_elp_sleep(wl);
1517
1518out_unlock:
1519 mutex_unlock(&wl->mutex);
1520
1521out:
1522 return ret;
1523}
1524
1525static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1526 struct cfg80211_scan_request *req)
1527{
1528 struct wl1271 *wl = hw->priv;
1529 int ret;
1530 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001531 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001532
1533 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1534
1535 if (req->n_ssids) {
1536 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001537 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001538 }
1539
1540 mutex_lock(&wl->mutex);
1541
1542 ret = wl1271_ps_elp_wakeup(wl, false);
1543 if (ret < 0)
1544 goto out;
1545
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001546 if (wl1271_11a_enabled())
1547 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1548 WL1271_SCAN_BAND_DUAL, 3);
1549 else
1550 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1551 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001552
1553 wl1271_ps_elp_sleep(wl);
1554
1555out:
1556 mutex_unlock(&wl->mutex);
1557
1558 return ret;
1559}
1560
1561static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1562{
1563 struct wl1271 *wl = hw->priv;
1564 int ret;
1565
1566 mutex_lock(&wl->mutex);
1567
1568 ret = wl1271_ps_elp_wakeup(wl, false);
1569 if (ret < 0)
1570 goto out;
1571
1572 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1573 if (ret < 0)
1574 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1575
1576 wl1271_ps_elp_sleep(wl);
1577
1578out:
1579 mutex_unlock(&wl->mutex);
1580
1581 return ret;
1582}
1583
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001584static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1585{
1586 u8 *ptr = beacon->data +
1587 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1588
1589 /* find the location of the ssid in the beacon */
1590 while (ptr < beacon->data + beacon->len) {
1591 if (ptr[0] == WLAN_EID_SSID) {
1592 wl->ssid_len = ptr[1];
1593 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1594 return;
1595 }
1596 ptr += ptr[1];
1597 }
1598 wl1271_error("ad-hoc beacon template has no SSID!\n");
1599}
1600
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001601static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1602 struct ieee80211_vif *vif,
1603 struct ieee80211_bss_conf *bss_conf,
1604 u32 changed)
1605{
1606 enum wl1271_cmd_ps_mode mode;
1607 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001608 bool do_join = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001609 int ret;
1610
1611 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1612
1613 mutex_lock(&wl->mutex);
1614
1615 ret = wl1271_ps_elp_wakeup(wl, false);
1616 if (ret < 0)
1617 goto out;
1618
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001619 if (wl->bss_type == BSS_TYPE_IBSS) {
1620 /* FIXME: This implements rudimentary ad-hoc support -
1621 proper templates are on the wish list and notification
1622 on when they change. This patch will update the templates
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001623 on every call to this function. */
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001624 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1625
1626 if (beacon) {
1627 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001628
1629 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001630 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1631 beacon->data,
1632 beacon->len);
1633
1634 if (ret < 0) {
1635 dev_kfree_skb(beacon);
1636 goto out_sleep;
1637 }
1638
1639 hdr = (struct ieee80211_hdr *) beacon->data;
1640 hdr->frame_control = cpu_to_le16(
1641 IEEE80211_FTYPE_MGMT |
1642 IEEE80211_STYPE_PROBE_RESP);
1643
1644 ret = wl1271_cmd_template_set(wl,
1645 CMD_TEMPL_PROBE_RESPONSE,
1646 beacon->data,
1647 beacon->len);
1648 dev_kfree_skb(beacon);
1649 if (ret < 0)
1650 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001651
1652 /* Need to update the SSID (for filtering etc) */
1653 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001654 }
1655 }
1656
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001657 if ((changed & BSS_CHANGED_BSSID) &&
1658 /*
1659 * Now we know the correct bssid, so we send a new join command
1660 * and enable the BSSID filter
1661 */
1662 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
1663 wl->rx_config |= CFG_BSSID_FILTER_EN;
1664 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
1665 ret = wl1271_cmd_build_null_data(wl);
1666 if (ret < 0) {
1667 wl1271_warning("cmd buld null data failed %d",
1668 ret);
1669 goto out_sleep;
1670 }
1671
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001672 /* Need to update the BSSID (for filtering etc) */
1673 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001674 }
1675
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001676 if (changed & BSS_CHANGED_ASSOC) {
1677 if (bss_conf->assoc) {
1678 wl->aid = bss_conf->aid;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001679 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001680
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001681 /*
1682 * with wl1271, we don't need to update the
1683 * beacon_int and dtim_period, because the firmware
1684 * updates it by itself when the first beacon is
1685 * received after a join.
1686 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001687 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1688 if (ret < 0)
1689 goto out_sleep;
1690
1691 ret = wl1271_acx_aid(wl, wl->aid);
1692 if (ret < 0)
1693 goto out_sleep;
1694
1695 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001696 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1697 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001698 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001699 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001700 if (ret < 0)
1701 goto out_sleep;
1702 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001703 } else {
1704 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001705 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001706 wl->aid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001707 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001708
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001709 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001710
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001711 if (changed & BSS_CHANGED_ERP_SLOT) {
1712 if (bss_conf->use_short_slot)
1713 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1714 else
1715 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1716 if (ret < 0) {
1717 wl1271_warning("Set slot time failed %d", ret);
1718 goto out_sleep;
1719 }
1720 }
1721
1722 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1723 if (bss_conf->use_short_preamble)
1724 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1725 else
1726 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1727 }
1728
1729 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1730 if (bss_conf->use_cts_prot)
1731 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1732 else
1733 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1734 if (ret < 0) {
1735 wl1271_warning("Set ctsprotect failed %d", ret);
1736 goto out_sleep;
1737 }
1738 }
1739
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001740 if (do_join) {
1741 ret = wl1271_cmd_join(wl);
1742 if (ret < 0) {
1743 wl1271_warning("cmd join failed %d", ret);
1744 goto out_sleep;
1745 }
1746 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1747 }
1748
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001749out_sleep:
1750 wl1271_ps_elp_sleep(wl);
1751
1752out:
1753 mutex_unlock(&wl->mutex);
1754}
1755
Kalle Valoc6999d82010-02-18 13:25:41 +02001756static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1757 const struct ieee80211_tx_queue_params *params)
1758{
1759 struct wl1271 *wl = hw->priv;
1760 int ret;
1761
1762 mutex_lock(&wl->mutex);
1763
1764 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1765
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001766 ret = wl1271_ps_elp_wakeup(wl, false);
1767 if (ret < 0)
1768 goto out;
1769
Kalle Valoc6999d82010-02-18 13:25:41 +02001770 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1771 params->cw_min, params->cw_max,
1772 params->aifs, params->txop);
1773 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001774 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001775
1776 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1777 CONF_CHANNEL_TYPE_EDCF,
1778 wl1271_tx_get_queue(queue),
1779 CONF_PS_SCHEME_LEGACY_PSPOLL,
1780 CONF_ACK_POLICY_LEGACY, 0, 0);
1781 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001782 goto out_sleep;
1783
1784out_sleep:
1785 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001786
1787out:
1788 mutex_unlock(&wl->mutex);
1789
1790 return ret;
1791}
1792
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001793
1794/* can't be const, mac80211 writes to this */
1795static struct ieee80211_rate wl1271_rates[] = {
1796 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001797 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1798 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001799 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001800 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1801 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001802 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1803 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001804 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1805 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001806 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1807 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001808 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1809 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001810 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1811 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001812 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1813 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001814 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001815 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1816 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001817 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001818 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1819 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001820 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001821 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1822 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001823 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001824 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1825 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001826 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001827 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1828 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001829 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001830 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1831 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001832 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001833 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1834 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001835};
1836
1837/* can't be const, mac80211 writes to this */
1838static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001839 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1840 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1841 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1842 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1843 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1844 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1845 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1846 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1847 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1848 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1849 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1850 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1851 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001852};
1853
1854/* can't be const, mac80211 writes to this */
1855static struct ieee80211_supported_band wl1271_band_2ghz = {
1856 .channels = wl1271_channels,
1857 .n_channels = ARRAY_SIZE(wl1271_channels),
1858 .bitrates = wl1271_rates,
1859 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1860};
1861
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001862/* 5 GHz data rates for WL1273 */
1863static struct ieee80211_rate wl1271_rates_5ghz[] = {
1864 { .bitrate = 60,
1865 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1866 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
1867 { .bitrate = 90,
1868 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1869 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
1870 { .bitrate = 120,
1871 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1872 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
1873 { .bitrate = 180,
1874 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1875 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
1876 { .bitrate = 240,
1877 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1878 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
1879 { .bitrate = 360,
1880 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1881 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
1882 { .bitrate = 480,
1883 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1884 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
1885 { .bitrate = 540,
1886 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1887 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
1888};
1889
1890/* 5 GHz band channels for WL1273 */
1891static struct ieee80211_channel wl1271_channels_5ghz[] = {
1892 { .hw_value = 183, .center_freq = 4915},
1893 { .hw_value = 184, .center_freq = 4920},
1894 { .hw_value = 185, .center_freq = 4925},
1895 { .hw_value = 187, .center_freq = 4935},
1896 { .hw_value = 188, .center_freq = 4940},
1897 { .hw_value = 189, .center_freq = 4945},
1898 { .hw_value = 192, .center_freq = 4960},
1899 { .hw_value = 196, .center_freq = 4980},
1900 { .hw_value = 7, .center_freq = 5035},
1901 { .hw_value = 8, .center_freq = 5040},
1902 { .hw_value = 9, .center_freq = 5045},
1903 { .hw_value = 11, .center_freq = 5055},
1904 { .hw_value = 12, .center_freq = 5060},
1905 { .hw_value = 16, .center_freq = 5080},
1906 { .hw_value = 34, .center_freq = 5170},
1907 { .hw_value = 36, .center_freq = 5180},
1908 { .hw_value = 38, .center_freq = 5190},
1909 { .hw_value = 40, .center_freq = 5200},
1910 { .hw_value = 42, .center_freq = 5210},
1911 { .hw_value = 44, .center_freq = 5220},
1912 { .hw_value = 46, .center_freq = 5230},
1913 { .hw_value = 48, .center_freq = 5240},
1914 { .hw_value = 52, .center_freq = 5260},
1915 { .hw_value = 56, .center_freq = 5280},
1916 { .hw_value = 60, .center_freq = 5300},
1917 { .hw_value = 64, .center_freq = 5320},
1918 { .hw_value = 100, .center_freq = 5500},
1919 { .hw_value = 104, .center_freq = 5520},
1920 { .hw_value = 108, .center_freq = 5540},
1921 { .hw_value = 112, .center_freq = 5560},
1922 { .hw_value = 116, .center_freq = 5580},
1923 { .hw_value = 120, .center_freq = 5600},
1924 { .hw_value = 124, .center_freq = 5620},
1925 { .hw_value = 128, .center_freq = 5640},
1926 { .hw_value = 132, .center_freq = 5660},
1927 { .hw_value = 136, .center_freq = 5680},
1928 { .hw_value = 140, .center_freq = 5700},
1929 { .hw_value = 149, .center_freq = 5745},
1930 { .hw_value = 153, .center_freq = 5765},
1931 { .hw_value = 157, .center_freq = 5785},
1932 { .hw_value = 161, .center_freq = 5805},
1933 { .hw_value = 165, .center_freq = 5825},
1934};
1935
1936
1937static struct ieee80211_supported_band wl1271_band_5ghz = {
1938 .channels = wl1271_channels_5ghz,
1939 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
1940 .bitrates = wl1271_rates_5ghz,
1941 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
1942};
1943
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001944static const struct ieee80211_ops wl1271_ops = {
1945 .start = wl1271_op_start,
1946 .stop = wl1271_op_stop,
1947 .add_interface = wl1271_op_add_interface,
1948 .remove_interface = wl1271_op_remove_interface,
1949 .config = wl1271_op_config,
1950/* .config_interface = wl1271_op_config_interface, */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001951 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001952 .configure_filter = wl1271_op_configure_filter,
1953 .tx = wl1271_op_tx,
1954 .set_key = wl1271_op_set_key,
1955 .hw_scan = wl1271_op_hw_scan,
1956 .bss_info_changed = wl1271_op_bss_info_changed,
1957 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02001958 .conf_tx = wl1271_op_conf_tx,
Kalle Valoc8c90872010-02-18 13:25:53 +02001959 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001960};
1961
1962static int wl1271_register_hw(struct wl1271 *wl)
1963{
1964 int ret;
1965
1966 if (wl->mac80211_registered)
1967 return 0;
1968
1969 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
1970
1971 ret = ieee80211_register_hw(wl->hw);
1972 if (ret < 0) {
1973 wl1271_error("unable to register mac80211 hw: %d", ret);
1974 return ret;
1975 }
1976
1977 wl->mac80211_registered = true;
1978
1979 wl1271_notice("loaded");
1980
1981 return 0;
1982}
1983
1984static int wl1271_init_ieee80211(struct wl1271 *wl)
1985{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03001986 /* The tx descriptor buffer and the TKIP space. */
1987 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
1988 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001989
1990 /* unit us */
1991 /* FIXME: find a proper value */
1992 wl->hw->channel_change_time = 10000;
1993
1994 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03001995 IEEE80211_HW_NOISE_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02001996 IEEE80211_HW_BEACON_FILTER |
1997 IEEE80211_HW_SUPPORTS_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001998
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001999 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2000 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002001 wl->hw->wiphy->max_scan_ssids = 1;
2002 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
2003
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002004 if (wl1271_11a_enabled())
2005 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
2006
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002007 SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
2008
2009 return 0;
2010}
2011
2012static void wl1271_device_release(struct device *dev)
2013{
2014
2015}
2016
2017static struct platform_device wl1271_device = {
2018 .name = "wl1271",
2019 .id = -1,
2020
2021 /* device model insists to have a release function */
2022 .dev = {
2023 .release = wl1271_device_release,
2024 },
2025};
2026
2027#define WL1271_DEFAULT_CHANNEL 0
2028static int __devinit wl1271_probe(struct spi_device *spi)
2029{
2030 struct wl12xx_platform_data *pdata;
2031 struct ieee80211_hw *hw;
2032 struct wl1271 *wl;
2033 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002034
2035 pdata = spi->dev.platform_data;
2036 if (!pdata) {
2037 wl1271_error("no platform data");
2038 return -ENODEV;
2039 }
2040
2041 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2042 if (!hw) {
2043 wl1271_error("could not alloc ieee80211_hw");
2044 return -ENOMEM;
2045 }
2046
2047 wl = hw->priv;
2048 memset(wl, 0, sizeof(*wl));
2049
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002050 INIT_LIST_HEAD(&wl->list);
2051
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002052 wl->hw = hw;
2053 dev_set_drvdata(&spi->dev, wl);
2054 wl->spi = spi;
2055
2056 skb_queue_head_init(&wl->tx_queue);
2057
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002058 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002059 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002060 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002061 wl->rx_counter = 0;
2062 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2063 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002064 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002065 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002066 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002067 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2068 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002069 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002070 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002071 wl->flags = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002072
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002073 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002074 wl->tx_frames[i] = NULL;
2075
2076 spin_lock_init(&wl->wl_lock);
2077
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002078 wl->state = WL1271_STATE_OFF;
2079 mutex_init(&wl->mutex);
2080
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002081 /* This is the only SPI value that we need to set here, the rest
2082 * comes from the board-peripherals file */
2083 spi->bits_per_word = 32;
2084
2085 ret = spi_setup(spi);
2086 if (ret < 0) {
2087 wl1271_error("spi_setup failed");
2088 goto out_free;
2089 }
2090
2091 wl->set_power = pdata->set_power;
2092 if (!wl->set_power) {
2093 wl1271_error("set power function missing in platform data");
2094 ret = -ENODEV;
2095 goto out_free;
2096 }
2097
2098 wl->irq = spi->irq;
2099 if (wl->irq < 0) {
2100 wl1271_error("irq missing in platform data");
2101 ret = -ENODEV;
2102 goto out_free;
2103 }
2104
2105 ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
2106 if (ret < 0) {
2107 wl1271_error("request_irq() failed: %d", ret);
2108 goto out_free;
2109 }
2110
2111 set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
2112
2113 disable_irq(wl->irq);
2114
2115 ret = platform_device_register(&wl1271_device);
2116 if (ret) {
2117 wl1271_error("couldn't register platform device");
2118 goto out_irq;
2119 }
2120 dev_set_drvdata(&wl1271_device.dev, wl);
2121
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002122 /* Apply default driver configuration. */
2123 wl1271_conf_init(wl);
2124
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002125 ret = wl1271_init_ieee80211(wl);
2126 if (ret)
2127 goto out_platform;
2128
2129 ret = wl1271_register_hw(wl);
2130 if (ret)
2131 goto out_platform;
2132
2133 wl1271_debugfs_init(wl);
2134
2135 wl1271_notice("initialized");
2136
2137 return 0;
2138
2139 out_platform:
2140 platform_device_unregister(&wl1271_device);
2141
2142 out_irq:
2143 free_irq(wl->irq, wl);
2144
2145 out_free:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002146 ieee80211_free_hw(hw);
2147
2148 return ret;
2149}
2150
2151static int __devexit wl1271_remove(struct spi_device *spi)
2152{
2153 struct wl1271 *wl = dev_get_drvdata(&spi->dev);
2154
2155 ieee80211_unregister_hw(wl->hw);
2156
2157 wl1271_debugfs_exit(wl);
2158 platform_device_unregister(&wl1271_device);
2159 free_irq(wl->irq, wl);
2160 kfree(wl->target_mem_map);
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03002161 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002162 wl->fw = NULL;
2163 kfree(wl->nvs);
2164 wl->nvs = NULL;
2165
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002166 kfree(wl->fw_status);
2167 kfree(wl->tx_res_if);
2168
2169 ieee80211_free_hw(wl->hw);
2170
2171 return 0;
2172}
2173
2174
2175static struct spi_driver wl1271_spi_driver = {
2176 .driver = {
2177 .name = "wl1271",
2178 .bus = &spi_bus_type,
2179 .owner = THIS_MODULE,
2180 },
2181
2182 .probe = wl1271_probe,
2183 .remove = __devexit_p(wl1271_remove),
2184};
2185
2186static int __init wl1271_init(void)
2187{
2188 int ret;
2189
2190 ret = spi_register_driver(&wl1271_spi_driver);
2191 if (ret < 0) {
2192 wl1271_error("failed to register spi driver: %d", ret);
2193 goto out;
2194 }
2195
2196out:
2197 return ret;
2198}
2199
2200static void __exit wl1271_exit(void)
2201{
2202 spi_unregister_driver(&wl1271_spi_driver);
2203
2204 wl1271_notice("unloaded");
2205}
2206
2207module_init(wl1271_init);
2208module_exit(wl1271_exit);
2209
2210MODULE_LICENSE("GPL");
2211MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
Luciano Coelho2f018722009-10-08 21:56:27 +03002212MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
Ben Hutchings49f146d2009-11-07 22:02:15 +00002213MODULE_FIRMWARE(WL1271_FW_NAME);