blob: 18347c3a5e19d1b8724dcd2c36231b537e5fdf84 [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"
36#include "wl1271_spi.h"
Teemu Paasikivi7b048c52010-02-18 13:25:55 +020037#include "wl1271_io.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030038#include "wl1271_event.h"
39#include "wl1271_tx.h"
40#include "wl1271_rx.h"
41#include "wl1271_ps.h"
42#include "wl1271_init.h"
43#include "wl1271_debugfs.h"
44#include "wl1271_cmd.h"
45#include "wl1271_boot.h"
Kalle Valoc8c90872010-02-18 13:25:53 +020046#include "wl1271_testmode.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030047
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020048#define WL1271_BOOT_RETRIES 3
49
Juuso Oikarinen8a080482009-10-13 12:47:44 +030050static struct conf_drv_settings default_conf = {
51 .sg = {
52 .per_threshold = 7500,
53 .max_scan_compensation_time = 120000,
54 .nfs_sample_interval = 400,
55 .load_ratio = 50,
56 .auto_ps_mode = 0,
57 .probe_req_compensation = 170,
58 .scan_window_compensation = 50,
59 .antenna_config = 0,
60 .beacon_miss_threshold = 60,
61 .rate_adaptation_threshold = CONF_HW_BIT_RATE_12MBPS,
62 .rate_adaptation_snr = 0
63 },
64 .rx = {
65 .rx_msdu_life_time = 512000,
66 .packet_detection_threshold = 0,
67 .ps_poll_timeout = 15,
68 .upsd_timeout = 15,
69 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +020070 .rx_cca_threshold = 0,
71 .irq_blk_threshold = 0xFFFF,
72 .irq_pkt_threshold = 0,
73 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +030074 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
75 },
76 .tx = {
77 .tx_energy_detection = 0,
78 .rc_conf = {
Juuso Oikarinenec078d92009-12-11 15:41:05 +020079 .enabled_rates = CONF_HW_BIT_RATE_1MBPS |
80 CONF_HW_BIT_RATE_2MBPS,
Juuso Oikarinen8a080482009-10-13 12:47:44 +030081 .short_retry_limit = 10,
82 .long_retry_limit = 10,
83 .aflags = 0
84 },
85 .ac_conf_count = 4,
86 .ac_conf = {
87 [0] = {
88 .ac = CONF_TX_AC_BE,
89 .cw_min = 15,
90 .cw_max = 63,
91 .aifsn = 3,
92 .tx_op_limit = 0,
93 },
94 [1] = {
95 .ac = CONF_TX_AC_BK,
96 .cw_min = 15,
97 .cw_max = 63,
98 .aifsn = 7,
99 .tx_op_limit = 0,
100 },
101 [2] = {
102 .ac = CONF_TX_AC_VI,
103 .cw_min = 15,
104 .cw_max = 63,
105 .aifsn = CONF_TX_AIFS_PIFS,
106 .tx_op_limit = 3008,
107 },
108 [3] = {
109 .ac = CONF_TX_AC_VO,
110 .cw_min = 15,
111 .cw_max = 63,
112 .aifsn = CONF_TX_AIFS_PIFS,
113 .tx_op_limit = 1504,
114 },
115 },
116 .tid_conf_count = 7,
117 .tid_conf = {
118 [0] = {
119 .queue_id = 0,
120 .channel_type = CONF_CHANNEL_TYPE_DCF,
121 .tsid = CONF_TX_AC_BE,
122 .ps_scheme = CONF_PS_SCHEME_LEGACY,
123 .ack_policy = CONF_ACK_POLICY_LEGACY,
124 .apsd_conf = {0, 0},
125 },
126 [1] = {
127 .queue_id = 1,
128 .channel_type = CONF_CHANNEL_TYPE_DCF,
129 .tsid = CONF_TX_AC_BE,
130 .ps_scheme = CONF_PS_SCHEME_LEGACY,
131 .ack_policy = CONF_ACK_POLICY_LEGACY,
132 .apsd_conf = {0, 0},
133 },
134 [2] = {
135 .queue_id = 2,
136 .channel_type = CONF_CHANNEL_TYPE_DCF,
137 .tsid = CONF_TX_AC_BE,
138 .ps_scheme = CONF_PS_SCHEME_LEGACY,
139 .ack_policy = CONF_ACK_POLICY_LEGACY,
140 .apsd_conf = {0, 0},
141 },
142 [3] = {
143 .queue_id = 3,
144 .channel_type = CONF_CHANNEL_TYPE_DCF,
145 .tsid = CONF_TX_AC_BE,
146 .ps_scheme = CONF_PS_SCHEME_LEGACY,
147 .ack_policy = CONF_ACK_POLICY_LEGACY,
148 .apsd_conf = {0, 0},
149 },
150 [4] = {
151 .queue_id = 4,
152 .channel_type = CONF_CHANNEL_TYPE_DCF,
153 .tsid = CONF_TX_AC_BE,
154 .ps_scheme = CONF_PS_SCHEME_LEGACY,
155 .ack_policy = CONF_ACK_POLICY_LEGACY,
156 .apsd_conf = {0, 0},
157 },
158 [5] = {
159 .queue_id = 5,
160 .channel_type = CONF_CHANNEL_TYPE_DCF,
161 .tsid = CONF_TX_AC_BE,
162 .ps_scheme = CONF_PS_SCHEME_LEGACY,
163 .ack_policy = CONF_ACK_POLICY_LEGACY,
164 .apsd_conf = {0, 0},
165 },
166 [6] = {
167 .queue_id = 6,
168 .channel_type = CONF_CHANNEL_TYPE_DCF,
169 .tsid = CONF_TX_AC_BE,
170 .ps_scheme = CONF_PS_SCHEME_LEGACY,
171 .ack_policy = CONF_ACK_POLICY_LEGACY,
172 .apsd_conf = {0, 0},
173 }
174 },
175 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200176 .tx_compl_timeout = 700,
177 .tx_compl_threshold = 4
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300178 },
179 .conn = {
180 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
181 .listen_interval = 0,
182 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
183 .bcn_filt_ie_count = 1,
184 .bcn_filt_ie = {
185 [0] = {
186 .ie = WLAN_EID_CHANNEL_SWITCH,
187 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
188 }
189 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200190 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300191 .bss_lose_timeout = 100,
192 .beacon_rx_timeout = 10000,
193 .broadcast_timeout = 20000,
194 .rx_broadcast_in_ps = 1,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200195 .ps_poll_threshold = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300196 .sig_trigger_count = 2,
197 .sig_trigger = {
198 [0] = {
199 .threshold = -75,
200 .pacing = 500,
201 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
202 .type = CONF_TRIG_EVENT_TYPE_EDGE,
203 .direction = CONF_TRIG_EVENT_DIR_LOW,
204 .hysteresis = 2,
205 .index = 0,
206 .enable = 1
207 },
208 [1] = {
209 .threshold = -75,
210 .pacing = 500,
211 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
212 .type = CONF_TRIG_EVENT_TYPE_EDGE,
213 .direction = CONF_TRIG_EVENT_DIR_HIGH,
214 .hysteresis = 2,
215 .index = 1,
216 .enable = 1
217 }
218 },
219 .sig_weights = {
220 .rssi_bcn_avg_weight = 10,
221 .rssi_pkt_avg_weight = 10,
222 .snr_bcn_avg_weight = 10,
223 .snr_pkt_avg_weight = 10
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300224 },
225 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200226 .bet_max_consecutive = 10,
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200227 .psm_entry_retries = 3
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300228 },
229 .init = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300230 .radioparam = {
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200231 .fem = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300232 }
Luciano Coelho6e92b412009-12-11 15:40:50 +0200233 },
234 .itrim = {
235 .enable = false,
236 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200237 },
238 .pm_config = {
239 .host_clk_settling_time = 5000,
240 .host_fast_wakeup_support = false
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300241 }
242};
243
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300244static LIST_HEAD(wl_list);
245
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300246static void wl1271_conf_init(struct wl1271 *wl)
247{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300248
249 /*
250 * This function applies the default configuration to the driver. This
251 * function is invoked upon driver load (spi probe.)
252 *
253 * The configuration is stored in a run-time structure in order to
254 * facilitate for run-time adjustment of any of the parameters. Making
255 * changes to the configuration structure will apply the new values on
256 * the next interface up (wl1271_op_start.)
257 */
258
259 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300260 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300261}
262
263
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300264static int wl1271_plt_init(struct wl1271 *wl)
265{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200266 struct conf_tx_ac_category *conf_ac;
267 struct conf_tx_tid *conf_tid;
268 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300269
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200270 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200271 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200272 return ret;
273
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200274 ret = wl1271_cmd_radio_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 Coelho12419cc2010-02-18 13:25:44 +0200278 ret = wl1271_init_templates_config(wl);
279 if (ret < 0)
280 return ret;
281
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300282 ret = wl1271_acx_init_mem_config(wl);
283 if (ret < 0)
284 return ret;
285
Luciano Coelho12419cc2010-02-18 13:25:44 +0200286 /* PHY layer config */
287 ret = wl1271_init_phy_config(wl);
288 if (ret < 0)
289 goto out_free_memmap;
290
291 ret = wl1271_acx_dco_itrim_params(wl);
292 if (ret < 0)
293 goto out_free_memmap;
294
295 /* Initialize connection monitoring thresholds */
296 ret = wl1271_acx_conn_monit_params(wl);
297 if (ret < 0)
298 goto out_free_memmap;
299
300 /* Bluetooth WLAN coexistence */
301 ret = wl1271_init_pta(wl);
302 if (ret < 0)
303 goto out_free_memmap;
304
305 /* Energy detection */
306 ret = wl1271_init_energy_detection(wl);
307 if (ret < 0)
308 goto out_free_memmap;
309
310 /* Default fragmentation threshold */
311 ret = wl1271_acx_frag_threshold(wl);
312 if (ret < 0)
313 goto out_free_memmap;
314
315 /* Default TID configuration */
316 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
317 conf_tid = &wl->conf.tx.tid_conf[i];
318 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
319 conf_tid->channel_type,
320 conf_tid->tsid,
321 conf_tid->ps_scheme,
322 conf_tid->ack_policy,
323 conf_tid->apsd_conf[0],
324 conf_tid->apsd_conf[1]);
325 if (ret < 0)
326 goto out_free_memmap;
327 }
328
329 /* Default AC configuration */
330 for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
331 conf_ac = &wl->conf.tx.ac_conf[i];
332 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
333 conf_ac->cw_max, conf_ac->aifsn,
334 conf_ac->tx_op_limit);
335 if (ret < 0)
336 goto out_free_memmap;
337 }
338
339 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200340 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300341 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200342 goto out_free_memmap;
343
344 /* Configure for CAM power saving (ie. always active) */
345 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
346 if (ret < 0)
347 goto out_free_memmap;
348
349 /* configure PM */
350 ret = wl1271_acx_pm_config(wl);
351 if (ret < 0)
352 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300353
354 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200355
356 out_free_memmap:
357 kfree(wl->target_mem_map);
358 wl->target_mem_map = NULL;
359
360 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300361}
362
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300363static void wl1271_power_off(struct wl1271 *wl)
364{
365 wl->set_power(false);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200366 clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300367}
368
369static void wl1271_power_on(struct wl1271 *wl)
370{
371 wl->set_power(true);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200372 set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300373}
374
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300375static void wl1271_fw_status(struct wl1271 *wl,
376 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300377{
378 u32 total = 0;
379 int i;
380
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200381 wl1271_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300382
383 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
384 "drv_rx_counter = %d, tx_results_counter = %d)",
385 status->intr,
386 status->fw_rx_counter,
387 status->drv_rx_counter,
388 status->tx_results_counter);
389
390 /* update number of available TX blocks */
391 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300392 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
393 wl->tx_blocks_freed[i];
394
395 wl->tx_blocks_freed[i] =
396 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300397 wl->tx_blocks_available += cnt;
398 total += cnt;
399 }
400
401 /* if more blocks are available now, schedule some tx work */
402 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300403 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300404
405 /* update the host-chipset time offset */
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300406 wl->time_offset = jiffies_to_usecs(jiffies) -
407 le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300408}
409
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300410static void wl1271_irq_work(struct work_struct *work)
411{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300412 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300413 u32 intr;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300414 struct wl1271 *wl =
415 container_of(work, struct wl1271, irq_work);
416
417 mutex_lock(&wl->mutex);
418
419 wl1271_debug(DEBUG_IRQ, "IRQ work");
420
421 if (wl->state == WL1271_STATE_OFF)
422 goto out;
423
424 ret = wl1271_ps_elp_wakeup(wl, true);
425 if (ret < 0)
426 goto out;
427
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200428 wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300429
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300430 wl1271_fw_status(wl, wl->fw_status);
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300431 intr = le32_to_cpu(wl->fw_status->intr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300432 if (!intr) {
433 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
434 goto out_sleep;
435 }
436
437 intr &= WL1271_INTR_MASK;
438
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300439 if (intr & WL1271_ACX_INTR_EVENT_A) {
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300440 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
Juuso Oikarinen13f2dc52009-12-11 15:40:59 +0200441 wl1271_event_handle(wl, 0);
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300442 }
443
444 if (intr & WL1271_ACX_INTR_EVENT_B) {
445 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
Juuso Oikarinen13f2dc52009-12-11 15:40:59 +0200446 wl1271_event_handle(wl, 1);
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300447 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300448
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300449 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
450 wl1271_debug(DEBUG_IRQ,
451 "WL1271_ACX_INTR_INIT_COMPLETE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300452
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300453 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
454 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300455
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300456 if (intr & WL1271_ACX_INTR_DATA) {
457 u8 tx_res_cnt = wl->fw_status->tx_results_counter -
458 wl->tx_results_count;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300459
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300460 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300461
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300462 /* check for tx results */
463 if (tx_res_cnt)
464 wl1271_tx_complete(wl, tx_res_cnt);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300465
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300466 wl1271_rx(wl, wl->fw_status);
467 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300468
469out_sleep:
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200470 wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
471 WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300472 wl1271_ps_elp_sleep(wl);
473
474out:
475 mutex_unlock(&wl->mutex);
476}
477
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300478static int wl1271_fetch_firmware(struct wl1271 *wl)
479{
480 const struct firmware *fw;
481 int ret;
482
483 ret = request_firmware(&fw, WL1271_FW_NAME, &wl->spi->dev);
484
485 if (ret < 0) {
486 wl1271_error("could not get firmware: %d", ret);
487 return ret;
488 }
489
490 if (fw->size % 4) {
491 wl1271_error("firmware size is not multiple of 32 bits: %zu",
492 fw->size);
493 ret = -EILSEQ;
494 goto out;
495 }
496
497 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300498 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300499
500 if (!wl->fw) {
501 wl1271_error("could not allocate memory for the firmware");
502 ret = -ENOMEM;
503 goto out;
504 }
505
506 memcpy(wl->fw, fw->data, wl->fw_len);
507
508 ret = 0;
509
510out:
511 release_firmware(fw);
512
513 return ret;
514}
515
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200516static int wl1271_update_mac_addr(struct wl1271 *wl)
517{
518 int ret = 0;
519 u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
520
521 /* get mac address from the NVS */
522 wl->mac_addr[0] = nvs_ptr[11];
523 wl->mac_addr[1] = nvs_ptr[10];
524 wl->mac_addr[2] = nvs_ptr[6];
525 wl->mac_addr[3] = nvs_ptr[5];
526 wl->mac_addr[4] = nvs_ptr[4];
527 wl->mac_addr[5] = nvs_ptr[3];
528
529 /* FIXME: if it is a zero-address, we should bail out. Now, instead,
530 we randomize an address */
531 if (is_zero_ether_addr(wl->mac_addr)) {
532 static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
533 memcpy(wl->mac_addr, nokia_oui, 3);
534 get_random_bytes(wl->mac_addr + 3, 3);
Juuso Oikarinene2e77b52010-02-18 13:25:46 +0200535
536 /* update this address to the NVS */
537 nvs_ptr[11] = wl->mac_addr[0];
538 nvs_ptr[10] = wl->mac_addr[1];
539 nvs_ptr[6] = wl->mac_addr[2];
540 nvs_ptr[5] = wl->mac_addr[3];
541 nvs_ptr[4] = wl->mac_addr[4];
542 nvs_ptr[3] = wl->mac_addr[5];
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200543 }
544
545 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
546
547 return ret;
548}
549
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300550static int wl1271_fetch_nvs(struct wl1271 *wl)
551{
552 const struct firmware *fw;
553 int ret;
554
555 ret = request_firmware(&fw, WL1271_NVS_NAME, &wl->spi->dev);
556
557 if (ret < 0) {
558 wl1271_error("could not get nvs file: %d", ret);
559 return ret;
560 }
561
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200562 if (fw->size != sizeof(struct wl1271_nvs_file)) {
563 wl1271_error("nvs size is not as expected: %zu != %zu",
564 fw->size, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300565 ret = -EILSEQ;
566 goto out;
567 }
568
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200569 wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300570
571 if (!wl->nvs) {
572 wl1271_error("could not allocate memory for the nvs file");
573 ret = -ENOMEM;
574 goto out;
575 }
576
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200577 memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300578
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200579 ret = wl1271_update_mac_addr(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300580
581out:
582 release_firmware(fw);
583
584 return ret;
585}
586
587static void wl1271_fw_wakeup(struct wl1271 *wl)
588{
589 u32 elp_reg;
590
591 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300592 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300593}
594
595static int wl1271_setup(struct wl1271 *wl)
596{
597 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
598 if (!wl->fw_status)
599 return -ENOMEM;
600
601 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
602 if (!wl->tx_res_if) {
603 kfree(wl->fw_status);
604 return -ENOMEM;
605 }
606
607 INIT_WORK(&wl->irq_work, wl1271_irq_work);
608 INIT_WORK(&wl->tx_work, wl1271_tx_work);
609 return 0;
610}
611
612static int wl1271_chip_wakeup(struct wl1271 *wl)
613{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300614 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300615 int ret = 0;
616
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200617 msleep(WL1271_PRE_POWER_ON_SLEEP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300618 wl1271_power_on(wl);
619 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200620 wl1271_io_reset(wl);
621 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300622
623 /* We don't need a real memory partition here, because we only want
624 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300625 memset(&partition, 0, sizeof(partition));
626 partition.reg.start = REGISTERS_BASE;
627 partition.reg.size = REGISTERS_DOWN_SIZE;
628 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300629
630 /* ELP module wake up */
631 wl1271_fw_wakeup(wl);
632
633 /* whal_FwCtrl_BootSm() */
634
635 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200636 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300637
638 /* 1. check if chip id is valid */
639
640 switch (wl->chip.id) {
641 case CHIP_ID_1271_PG10:
642 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
643 wl->chip.id);
644
645 ret = wl1271_setup(wl);
646 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200647 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300648 break;
649 case CHIP_ID_1271_PG20:
650 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
651 wl->chip.id);
652
653 ret = wl1271_setup(wl);
654 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200655 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300656 break;
657 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200658 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300659 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200660 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300661 }
662
663 if (wl->fw == NULL) {
664 ret = wl1271_fetch_firmware(wl);
665 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200666 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300667 }
668
669 /* No NVS from netlink, try to get it from the filesystem */
670 if (wl->nvs == NULL) {
671 ret = wl1271_fetch_nvs(wl);
672 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200673 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300674 }
675
676out:
677 return ret;
678}
679
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300680int wl1271_plt_start(struct wl1271 *wl)
681{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200682 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300683 int ret;
684
685 mutex_lock(&wl->mutex);
686
687 wl1271_notice("power up");
688
689 if (wl->state != WL1271_STATE_OFF) {
690 wl1271_error("cannot go into PLT state because not "
691 "in off state: %d", wl->state);
692 ret = -EBUSY;
693 goto out;
694 }
695
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200696 while (retries) {
697 retries--;
698 ret = wl1271_chip_wakeup(wl);
699 if (ret < 0)
700 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300701
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200702 ret = wl1271_boot(wl);
703 if (ret < 0)
704 goto power_off;
705
706 ret = wl1271_plt_init(wl);
707 if (ret < 0)
708 goto irq_disable;
709
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200710 wl->state = WL1271_STATE_PLT;
711 wl1271_notice("firmware booted in PLT mode (%s)",
712 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300713 goto out;
714
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200715irq_disable:
716 wl1271_disable_interrupts(wl);
717 mutex_unlock(&wl->mutex);
718 /* Unlocking the mutex in the middle of handling is
719 inherently unsafe. In this case we deem it safe to do,
720 because we need to let any possibly pending IRQ out of
721 the system (and while we are WL1271_STATE_OFF the IRQ
722 work function will not do anything.) Also, any other
723 possible concurrent operations will fail due to the
724 current state, hence the wl1271 struct should be safe. */
725 cancel_work_sync(&wl->irq_work);
726 mutex_lock(&wl->mutex);
727power_off:
728 wl1271_power_off(wl);
729 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300730
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200731 wl1271_error("firmware boot in PLT mode failed despite %d retries",
732 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300733out:
734 mutex_unlock(&wl->mutex);
735
736 return ret;
737}
738
739int wl1271_plt_stop(struct wl1271 *wl)
740{
741 int ret = 0;
742
743 mutex_lock(&wl->mutex);
744
745 wl1271_notice("power down");
746
747 if (wl->state != WL1271_STATE_PLT) {
748 wl1271_error("cannot power down because not in PLT "
749 "state: %d", wl->state);
750 ret = -EBUSY;
751 goto out;
752 }
753
754 wl1271_disable_interrupts(wl);
755 wl1271_power_off(wl);
756
757 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300758 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300759
760out:
761 mutex_unlock(&wl->mutex);
762
763 return ret;
764}
765
766
767static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
768{
769 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200770 struct ieee80211_conf *conf = &hw->conf;
771 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
772 struct ieee80211_sta *sta = txinfo->control.sta;
773 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300774
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200775 /* peek into the rates configured in the STA entry */
776 spin_lock_irqsave(&wl->wl_lock, flags);
777 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
778 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
779 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
780 }
781 spin_unlock_irqrestore(&wl->wl_lock, flags);
782
783 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300784 skb_queue_tail(&wl->tx_queue, skb);
785
786 /*
787 * The chip specific setup must run before the first TX packet -
788 * before that, the tx_work will not be initialized!
789 */
790
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300791 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300792
793 /*
794 * The workqueue is slow to process the tx_queue and we need stop
795 * the queue here, otherwise the queue will get too long.
796 */
797 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) {
798 ieee80211_stop_queues(wl->hw);
799
800 /*
801 * FIXME: this is racy, the variable is not properly
802 * protected. Maybe fix this by removing the stupid
803 * variable altogether and checking the real queue state?
804 */
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200805 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300806 }
807
808 return NETDEV_TX_OK;
809}
810
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300811static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
812 void *arg)
813{
814 struct net_device *dev;
815 struct wireless_dev *wdev;
816 struct wiphy *wiphy;
817 struct ieee80211_hw *hw;
818 struct wl1271 *wl;
819 struct wl1271 *wl_temp;
820 struct in_device *idev;
821 struct in_ifaddr *ifa = arg;
822 int ret = 0;
823
824 /* FIXME: this ugly function should probably be implemented in the
825 * mac80211, and here should only be a simple callback handling actual
826 * setting of the filters. Now we need to dig up references to
827 * various structures to gain access to what we need.
828 * Also, because of this, there is no "initial" setting of the filter
829 * in "op_start", because we don't want to dig up struct net_device
830 * there - the filter will be set upon first change of the interface
831 * IP address. */
832
833 dev = ifa->ifa_dev->dev;
834
835 wdev = dev->ieee80211_ptr;
836 if (wdev == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200837 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300838
839 wiphy = wdev->wiphy;
840 if (wiphy == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200841 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300842
843 hw = wiphy_priv(wiphy);
844 if (hw == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200845 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300846
847 /* Check that the interface is one supported by this driver. */
848 wl_temp = hw->priv;
849 list_for_each_entry(wl, &wl_list, list) {
850 if (wl == wl_temp)
851 break;
852 }
853 if (wl == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200854 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300855
856 /* Get the interface IP address for the device. "ifa" will become
857 NULL if:
858 - there is no IPV4 protocol address configured
859 - there are multiple (virtual) IPV4 addresses configured
860 When "ifa" is NULL, filtering will be disabled.
861 */
862 ifa = NULL;
863 idev = dev->ip_ptr;
864 if (idev)
865 ifa = idev->ifa_list;
866
867 if (ifa && ifa->ifa_next)
868 ifa = NULL;
869
870 mutex_lock(&wl->mutex);
871
872 if (wl->state == WL1271_STATE_OFF)
873 goto out;
874
875 ret = wl1271_ps_elp_wakeup(wl, false);
876 if (ret < 0)
877 goto out;
878 if (ifa)
879 ret = wl1271_acx_arp_ip_filter(wl, true,
880 (u8 *)&ifa->ifa_address,
881 ACX_IPV4_VERSION);
882 else
883 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
884 ACX_IPV4_VERSION);
885 wl1271_ps_elp_sleep(wl);
886
887out:
888 mutex_unlock(&wl->mutex);
889
Luciano Coelho17d72652009-11-23 23:22:15 +0200890 return NOTIFY_OK;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300891}
892
893static struct notifier_block wl1271_dev_notifier = {
894 .notifier_call = wl1271_dev_notify,
895};
896
897
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300898static int wl1271_op_start(struct ieee80211_hw *hw)
899{
900 struct wl1271 *wl = hw->priv;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200901 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300902 int ret = 0;
903
904 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
905
906 mutex_lock(&wl->mutex);
907
908 if (wl->state != WL1271_STATE_OFF) {
909 wl1271_error("cannot start because not in off state: %d",
910 wl->state);
911 ret = -EBUSY;
912 goto out;
913 }
914
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200915 while (retries) {
916 retries--;
917 ret = wl1271_chip_wakeup(wl);
918 if (ret < 0)
919 goto power_off;
920
921 ret = wl1271_boot(wl);
922 if (ret < 0)
923 goto power_off;
924
925 ret = wl1271_hw_init(wl);
926 if (ret < 0)
927 goto irq_disable;
928
929 wl->state = WL1271_STATE_ON;
930 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300931 goto out;
932
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200933irq_disable:
934 wl1271_disable_interrupts(wl);
935 mutex_unlock(&wl->mutex);
936 /* Unlocking the mutex in the middle of handling is
937 inherently unsafe. In this case we deem it safe to do,
938 because we need to let any possibly pending IRQ out of
939 the system (and while we are WL1271_STATE_OFF the IRQ
940 work function will not do anything.) Also, any other
941 possible concurrent operations will fail due to the
942 current state, hence the wl1271 struct should be safe. */
943 cancel_work_sync(&wl->irq_work);
944 mutex_lock(&wl->mutex);
945power_off:
946 wl1271_power_off(wl);
947 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300948
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200949 wl1271_error("firmware boot failed despite %d retries",
950 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300951out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300952 mutex_unlock(&wl->mutex);
953
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300954 if (!ret) {
955 list_add(&wl->list, &wl_list);
956 register_inetaddr_notifier(&wl1271_dev_notifier);
957 }
958
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300959 return ret;
960}
961
962static void wl1271_op_stop(struct ieee80211_hw *hw)
963{
964 struct wl1271 *wl = hw->priv;
965 int i;
966
967 wl1271_info("down");
968
969 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
970
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300971 unregister_inetaddr_notifier(&wl1271_dev_notifier);
972 list_del(&wl->list);
973
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300974 mutex_lock(&wl->mutex);
975
976 WARN_ON(wl->state != WL1271_STATE_ON);
977
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200978 if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300979 mutex_unlock(&wl->mutex);
980 ieee80211_scan_completed(wl->hw, true);
981 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300982 }
983
984 wl->state = WL1271_STATE_OFF;
985
986 wl1271_disable_interrupts(wl);
987
988 mutex_unlock(&wl->mutex);
989
990 cancel_work_sync(&wl->irq_work);
991 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300992
993 mutex_lock(&wl->mutex);
994
995 /* let's notify MAC80211 about the remaining pending TX frames */
996 wl1271_tx_flush(wl);
997 wl1271_power_off(wl);
998
999 memset(wl->bssid, 0, ETH_ALEN);
1000 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1001 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001002 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001003 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001004
1005 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001006 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001007 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1008 wl->tx_blocks_available = 0;
1009 wl->tx_results_count = 0;
1010 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001011 wl->tx_security_last_seq = 0;
1012 wl->tx_security_seq_16 = 0;
1013 wl->tx_security_seq_32 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001014 wl->time_offset = 0;
1015 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001016 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1017 wl->sta_rate_set = 0;
1018 wl->flags = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001019
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001020 for (i = 0; i < NUM_TX_QUEUES; i++)
1021 wl->tx_blocks_freed[i] = 0;
1022
1023 wl1271_debugfs_reset(wl);
1024 mutex_unlock(&wl->mutex);
1025}
1026
1027static int wl1271_op_add_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +01001028 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001029{
1030 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001031 int ret = 0;
1032
John W. Linvillee5539bc2009-08-18 10:50:34 -04001033 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Johannes Berg1ed32e42009-12-23 13:15:45 +01001034 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001035
1036 mutex_lock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001037 if (wl->vif) {
1038 ret = -EBUSY;
1039 goto out;
1040 }
1041
Johannes Berg1ed32e42009-12-23 13:15:45 +01001042 wl->vif = vif;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001043
Johannes Berg1ed32e42009-12-23 13:15:45 +01001044 switch (vif->type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001045 case NL80211_IFTYPE_STATION:
1046 wl->bss_type = BSS_TYPE_STA_BSS;
1047 break;
1048 case NL80211_IFTYPE_ADHOC:
1049 wl->bss_type = BSS_TYPE_IBSS;
1050 break;
1051 default:
1052 ret = -EOPNOTSUPP;
1053 goto out;
1054 }
1055
1056 /* FIXME: what if conf->mac_addr changes? */
1057
1058out:
1059 mutex_unlock(&wl->mutex);
1060 return ret;
1061}
1062
1063static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +01001064 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001065{
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001066 struct wl1271 *wl = hw->priv;
1067
1068 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001069 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001070 wl->vif = NULL;
1071 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001072}
1073
1074#if 0
1075static int wl1271_op_config_interface(struct ieee80211_hw *hw,
1076 struct ieee80211_vif *vif,
1077 struct ieee80211_if_conf *conf)
1078{
1079 struct wl1271 *wl = hw->priv;
1080 struct sk_buff *beacon;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001081 int ret;
1082
David S. Miller32646902009-09-17 10:18:30 -07001083 wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM",
1084 conf->bssid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001085 wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid,
1086 conf->ssid_len);
1087
1088 mutex_lock(&wl->mutex);
1089
1090 ret = wl1271_ps_elp_wakeup(wl, false);
1091 if (ret < 0)
1092 goto out;
1093
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001094 if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
1095 wl1271_debug(DEBUG_MAC80211, "bssid changed");
1096
1097 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
1098
1099 ret = wl1271_cmd_join(wl);
1100 if (ret < 0)
1101 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001102
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001103 ret = wl1271_cmd_build_null_data(wl);
1104 if (ret < 0)
1105 goto out_sleep;
1106 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001107
1108 wl->ssid_len = conf->ssid_len;
1109 if (wl->ssid_len)
1110 memcpy(wl->ssid, conf->ssid, wl->ssid_len);
1111
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001112 if (conf->changed & IEEE80211_IFCC_BEACON) {
1113 beacon = ieee80211_beacon_get(hw, vif);
1114 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1115 beacon->data, beacon->len);
1116
1117 if (ret < 0) {
1118 dev_kfree_skb(beacon);
1119 goto out_sleep;
1120 }
1121
1122 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE,
1123 beacon->data, beacon->len);
1124
1125 dev_kfree_skb(beacon);
1126
1127 if (ret < 0)
1128 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001129 }
1130
1131out_sleep:
1132 wl1271_ps_elp_sleep(wl);
1133
1134out:
1135 mutex_unlock(&wl->mutex);
1136
1137 return ret;
1138}
1139#endif
1140
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001141static int wl1271_join_channel(struct wl1271 *wl, int channel)
1142{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001143 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001144 /* we need to use a dummy BSSID for now */
1145 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1146 0xad, 0xbe, 0xef };
1147
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001148 /* the dummy join is not required for ad-hoc */
1149 if (wl->bss_type == BSS_TYPE_IBSS)
1150 goto out;
1151
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001152 /* disable mac filter, so we hear everything */
1153 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1154
1155 wl->channel = channel;
1156 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1157
1158 ret = wl1271_cmd_join(wl);
1159 if (ret < 0)
1160 goto out;
1161
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001162 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001163
1164out:
1165 return ret;
1166}
1167
1168static int wl1271_unjoin_channel(struct wl1271 *wl)
1169{
1170 int ret;
1171
1172 /* to stop listening to a channel, we disconnect */
1173 ret = wl1271_cmd_disconnect(wl);
1174 if (ret < 0)
1175 goto out;
1176
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001177 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001178 wl->channel = 0;
1179 memset(wl->bssid, 0, ETH_ALEN);
1180 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1181
1182out:
1183 return ret;
1184}
1185
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001186static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1187{
1188 struct wl1271 *wl = hw->priv;
1189 struct ieee80211_conf *conf = &hw->conf;
1190 int channel, ret = 0;
1191
1192 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1193
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001194 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001195 channel,
1196 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001197 conf->power_level,
1198 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001199
1200 mutex_lock(&wl->mutex);
1201
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001202 wl->band = conf->channel->band;
1203
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001204 ret = wl1271_ps_elp_wakeup(wl, false);
1205 if (ret < 0)
1206 goto out;
1207
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001208 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001209 if (conf->flags & IEEE80211_CONF_IDLE &&
1210 test_bit(WL1271_FLAG_JOINED, &wl->flags))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001211 wl1271_unjoin_channel(wl);
Juuso Oikarinen8f648c02009-12-11 15:41:10 +02001212 else if (!(conf->flags & IEEE80211_CONF_IDLE))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001213 wl1271_join_channel(wl, channel);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001214
1215 if (conf->flags & IEEE80211_CONF_IDLE) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001216 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1217 wl->sta_rate_set = 0;
1218 wl1271_acx_rate_policies(wl);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001219 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001220 }
1221
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001222 /* if the channel changes while joined, join again */
Juuso Oikarinenddb01a52010-02-18 13:25:37 +02001223 if (channel != wl->channel &&
1224 test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1225 wl->channel = channel;
1226 /* FIXME: maybe use CMD_CHANNEL_SWITCH for this? */
1227 ret = wl1271_cmd_join(wl);
1228 if (ret < 0)
1229 wl1271_warning("cmd join to update channel failed %d",
1230 ret);
1231 } else
1232 wl->channel = channel;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001233
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001234 if (conf->flags & IEEE80211_CONF_PS &&
1235 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1236 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001237
1238 /*
1239 * We enter PSM only if we're already associated.
1240 * If we're not, we'll enter it when joining an SSID,
1241 * through the bss_info_changed() hook.
1242 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001243 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001244 wl1271_info("psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001245 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1246 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001247 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001248 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001249 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001250 wl1271_info("psm disabled");
1251
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001252 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001253
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001254 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001255 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1256 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001257 }
1258
1259 if (conf->power_level != wl->power_level) {
1260 ret = wl1271_acx_tx_power(wl, conf->power_level);
1261 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001262 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001263
1264 wl->power_level = conf->power_level;
1265 }
1266
1267out_sleep:
1268 wl1271_ps_elp_sleep(wl);
1269
1270out:
1271 mutex_unlock(&wl->mutex);
1272
1273 return ret;
1274}
1275
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001276struct wl1271_filter_params {
1277 bool enabled;
1278 int mc_list_length;
1279 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1280};
1281
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001282static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1283 struct dev_addr_list *mc_list)
1284{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001285 struct wl1271_filter_params *fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001286 int i;
1287
Juuso Oikarinen74441132009-10-13 12:47:53 +03001288 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001289 if (!fp) {
1290 wl1271_error("Out of memory setting filters.");
1291 return 0;
1292 }
1293
1294 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001295 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001296 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1297 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001298 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001299 }
1300
1301 fp->mc_list_length = 0;
1302 for (i = 0; i < mc_count; i++) {
1303 if (mc_list->da_addrlen == ETH_ALEN) {
1304 memcpy(fp->mc_list[fp->mc_list_length],
1305 mc_list->da_addr, ETH_ALEN);
1306 fp->mc_list_length++;
1307 } else
1308 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001309 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001310 }
1311
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001312 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001313}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001314
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001315#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1316 FIF_ALLMULTI | \
1317 FIF_FCSFAIL | \
1318 FIF_BCN_PRBRESP_PROMISC | \
1319 FIF_CONTROL | \
1320 FIF_OTHER_BSS)
1321
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001322static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1323 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001324 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001325{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001326 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001327 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001328 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001329
1330 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1331
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001332 mutex_lock(&wl->mutex);
1333
1334 if (wl->state == WL1271_STATE_OFF)
1335 goto out;
1336
1337 ret = wl1271_ps_elp_wakeup(wl, false);
1338 if (ret < 0)
1339 goto out;
1340
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001341 *total &= WL1271_SUPPORTED_FILTERS;
1342 changed &= WL1271_SUPPORTED_FILTERS;
1343
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001344 if (*total & FIF_ALLMULTI)
1345 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1346 else if (fp)
1347 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1348 fp->mc_list,
1349 fp->mc_list_length);
1350 if (ret < 0)
1351 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001352
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001353 kfree(fp);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001354
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001355 /* FIXME: We still need to set our filters properly */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001356
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001357 /* determine, whether supported filter values have changed */
1358 if (changed == 0)
1359 goto out_sleep;
1360
1361 /* apply configured filters */
1362 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1363 if (ret < 0)
1364 goto out_sleep;
1365
1366out_sleep:
1367 wl1271_ps_elp_sleep(wl);
1368
1369out:
1370 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001371}
1372
1373static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1374 struct ieee80211_vif *vif,
1375 struct ieee80211_sta *sta,
1376 struct ieee80211_key_conf *key_conf)
1377{
1378 struct wl1271 *wl = hw->priv;
1379 const u8 *addr;
1380 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001381 u32 tx_seq_32 = 0;
1382 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001383 u8 key_type;
1384
1385 static const u8 bcast_addr[ETH_ALEN] =
1386 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1387
1388 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1389
1390 addr = sta ? sta->addr : bcast_addr;
1391
1392 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1393 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1394 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1395 key_conf->alg, key_conf->keyidx,
1396 key_conf->keylen, key_conf->flags);
1397 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1398
1399 if (is_zero_ether_addr(addr)) {
1400 /* We dont support TX only encryption */
1401 ret = -EOPNOTSUPP;
1402 goto out;
1403 }
1404
1405 mutex_lock(&wl->mutex);
1406
1407 ret = wl1271_ps_elp_wakeup(wl, false);
1408 if (ret < 0)
1409 goto out_unlock;
1410
1411 switch (key_conf->alg) {
1412 case ALG_WEP:
1413 key_type = KEY_WEP;
1414
1415 key_conf->hw_key_idx = key_conf->keyidx;
1416 break;
1417 case ALG_TKIP:
1418 key_type = KEY_TKIP;
1419
1420 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001421 tx_seq_32 = wl->tx_security_seq_32;
1422 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001423 break;
1424 case ALG_CCMP:
1425 key_type = KEY_AES;
1426
1427 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001428 tx_seq_32 = wl->tx_security_seq_32;
1429 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001430 break;
1431 default:
1432 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1433
1434 ret = -EOPNOTSUPP;
1435 goto out_sleep;
1436 }
1437
1438 switch (cmd) {
1439 case SET_KEY:
1440 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1441 key_conf->keyidx, key_type,
1442 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001443 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001444 if (ret < 0) {
1445 wl1271_error("Could not add or replace key");
1446 goto out_sleep;
1447 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001448
1449 /* the default WEP key needs to be configured at least once */
1450 if (key_type == KEY_WEP) {
1451 ret = wl1271_cmd_set_default_wep_key(wl,
1452 wl->default_key);
1453 if (ret < 0)
1454 goto out_sleep;
1455 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001456 break;
1457
1458 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001459 /* The wl1271 does not allow to remove unicast keys - they
1460 will be cleared automatically on next CMD_JOIN. Ignore the
1461 request silently, as we dont want the mac80211 to emit
1462 an error message. */
1463 if (!is_broadcast_ether_addr(addr))
1464 break;
1465
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001466 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1467 key_conf->keyidx, key_type,
1468 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001469 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001470 if (ret < 0) {
1471 wl1271_error("Could not remove key");
1472 goto out_sleep;
1473 }
1474 break;
1475
1476 default:
1477 wl1271_error("Unsupported key cmd 0x%x", cmd);
1478 ret = -EOPNOTSUPP;
1479 goto out_sleep;
1480
1481 break;
1482 }
1483
1484out_sleep:
1485 wl1271_ps_elp_sleep(wl);
1486
1487out_unlock:
1488 mutex_unlock(&wl->mutex);
1489
1490out:
1491 return ret;
1492}
1493
1494static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1495 struct cfg80211_scan_request *req)
1496{
1497 struct wl1271 *wl = hw->priv;
1498 int ret;
1499 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001500 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001501
1502 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1503
1504 if (req->n_ssids) {
1505 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001506 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001507 }
1508
1509 mutex_lock(&wl->mutex);
1510
1511 ret = wl1271_ps_elp_wakeup(wl, false);
1512 if (ret < 0)
1513 goto out;
1514
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001515 if (wl1271_11a_enabled())
1516 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1517 WL1271_SCAN_BAND_DUAL, 3);
1518 else
1519 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1520 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001521
1522 wl1271_ps_elp_sleep(wl);
1523
1524out:
1525 mutex_unlock(&wl->mutex);
1526
1527 return ret;
1528}
1529
1530static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1531{
1532 struct wl1271 *wl = hw->priv;
1533 int ret;
1534
1535 mutex_lock(&wl->mutex);
1536
1537 ret = wl1271_ps_elp_wakeup(wl, false);
1538 if (ret < 0)
1539 goto out;
1540
1541 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1542 if (ret < 0)
1543 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1544
1545 wl1271_ps_elp_sleep(wl);
1546
1547out:
1548 mutex_unlock(&wl->mutex);
1549
1550 return ret;
1551}
1552
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001553static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1554{
1555 u8 *ptr = beacon->data +
1556 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1557
1558 /* find the location of the ssid in the beacon */
1559 while (ptr < beacon->data + beacon->len) {
1560 if (ptr[0] == WLAN_EID_SSID) {
1561 wl->ssid_len = ptr[1];
1562 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1563 return;
1564 }
1565 ptr += ptr[1];
1566 }
1567 wl1271_error("ad-hoc beacon template has no SSID!\n");
1568}
1569
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001570static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1571 struct ieee80211_vif *vif,
1572 struct ieee80211_bss_conf *bss_conf,
1573 u32 changed)
1574{
1575 enum wl1271_cmd_ps_mode mode;
1576 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001577 bool do_join = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001578 int ret;
1579
1580 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1581
1582 mutex_lock(&wl->mutex);
1583
1584 ret = wl1271_ps_elp_wakeup(wl, false);
1585 if (ret < 0)
1586 goto out;
1587
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001588 if (wl->bss_type == BSS_TYPE_IBSS) {
1589 /* FIXME: This implements rudimentary ad-hoc support -
1590 proper templates are on the wish list and notification
1591 on when they change. This patch will update the templates
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001592 on every call to this function. */
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001593 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1594
1595 if (beacon) {
1596 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001597
1598 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001599 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1600 beacon->data,
1601 beacon->len);
1602
1603 if (ret < 0) {
1604 dev_kfree_skb(beacon);
1605 goto out_sleep;
1606 }
1607
1608 hdr = (struct ieee80211_hdr *) beacon->data;
1609 hdr->frame_control = cpu_to_le16(
1610 IEEE80211_FTYPE_MGMT |
1611 IEEE80211_STYPE_PROBE_RESP);
1612
1613 ret = wl1271_cmd_template_set(wl,
1614 CMD_TEMPL_PROBE_RESPONSE,
1615 beacon->data,
1616 beacon->len);
1617 dev_kfree_skb(beacon);
1618 if (ret < 0)
1619 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001620
1621 /* Need to update the SSID (for filtering etc) */
1622 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001623 }
1624 }
1625
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001626 if ((changed & BSS_CHANGED_BSSID) &&
1627 /*
1628 * Now we know the correct bssid, so we send a new join command
1629 * and enable the BSSID filter
1630 */
1631 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
1632 wl->rx_config |= CFG_BSSID_FILTER_EN;
1633 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
1634 ret = wl1271_cmd_build_null_data(wl);
1635 if (ret < 0) {
1636 wl1271_warning("cmd buld null data failed %d",
1637 ret);
1638 goto out_sleep;
1639 }
1640
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001641 /* Need to update the BSSID (for filtering etc) */
1642 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001643 }
1644
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001645 if (changed & BSS_CHANGED_ASSOC) {
1646 if (bss_conf->assoc) {
1647 wl->aid = bss_conf->aid;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001648 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001649
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001650 /*
1651 * with wl1271, we don't need to update the
1652 * beacon_int and dtim_period, because the firmware
1653 * updates it by itself when the first beacon is
1654 * received after a join.
1655 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001656 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1657 if (ret < 0)
1658 goto out_sleep;
1659
1660 ret = wl1271_acx_aid(wl, wl->aid);
1661 if (ret < 0)
1662 goto out_sleep;
1663
1664 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001665 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1666 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001667 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001668 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001669 if (ret < 0)
1670 goto out_sleep;
1671 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001672 } else {
1673 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001674 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001675 wl->aid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001676 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001677
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001678 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001679
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001680 if (changed & BSS_CHANGED_ERP_SLOT) {
1681 if (bss_conf->use_short_slot)
1682 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1683 else
1684 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1685 if (ret < 0) {
1686 wl1271_warning("Set slot time failed %d", ret);
1687 goto out_sleep;
1688 }
1689 }
1690
1691 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1692 if (bss_conf->use_short_preamble)
1693 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1694 else
1695 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1696 }
1697
1698 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1699 if (bss_conf->use_cts_prot)
1700 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1701 else
1702 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1703 if (ret < 0) {
1704 wl1271_warning("Set ctsprotect failed %d", ret);
1705 goto out_sleep;
1706 }
1707 }
1708
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001709 if (do_join) {
1710 ret = wl1271_cmd_join(wl);
1711 if (ret < 0) {
1712 wl1271_warning("cmd join failed %d", ret);
1713 goto out_sleep;
1714 }
1715 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1716 }
1717
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001718out_sleep:
1719 wl1271_ps_elp_sleep(wl);
1720
1721out:
1722 mutex_unlock(&wl->mutex);
1723}
1724
Kalle Valoc6999d82010-02-18 13:25:41 +02001725static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1726 const struct ieee80211_tx_queue_params *params)
1727{
1728 struct wl1271 *wl = hw->priv;
1729 int ret;
1730
1731 mutex_lock(&wl->mutex);
1732
1733 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1734
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001735 ret = wl1271_ps_elp_wakeup(wl, false);
1736 if (ret < 0)
1737 goto out;
1738
Kalle Valoc6999d82010-02-18 13:25:41 +02001739 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1740 params->cw_min, params->cw_max,
1741 params->aifs, params->txop);
1742 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001743 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001744
1745 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1746 CONF_CHANNEL_TYPE_EDCF,
1747 wl1271_tx_get_queue(queue),
1748 CONF_PS_SCHEME_LEGACY_PSPOLL,
1749 CONF_ACK_POLICY_LEGACY, 0, 0);
1750 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001751 goto out_sleep;
1752
1753out_sleep:
1754 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001755
1756out:
1757 mutex_unlock(&wl->mutex);
1758
1759 return ret;
1760}
1761
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001762
1763/* can't be const, mac80211 writes to this */
1764static struct ieee80211_rate wl1271_rates[] = {
1765 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001766 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1767 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001768 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001769 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1770 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001771 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1772 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001773 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1774 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001775 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1776 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001777 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1778 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001779 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1780 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001781 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1782 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001783 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001784 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1785 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001786 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001787 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1788 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001789 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001790 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1791 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001792 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001793 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1794 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001795 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001796 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1797 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001798 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001799 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1800 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001801 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001802 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1803 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001804};
1805
1806/* can't be const, mac80211 writes to this */
1807static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001808 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1809 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1810 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1811 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1812 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1813 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1814 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1815 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1816 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1817 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1818 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1819 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1820 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001821};
1822
1823/* can't be const, mac80211 writes to this */
1824static struct ieee80211_supported_band wl1271_band_2ghz = {
1825 .channels = wl1271_channels,
1826 .n_channels = ARRAY_SIZE(wl1271_channels),
1827 .bitrates = wl1271_rates,
1828 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1829};
1830
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001831/* 5 GHz data rates for WL1273 */
1832static struct ieee80211_rate wl1271_rates_5ghz[] = {
1833 { .bitrate = 60,
1834 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1835 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
1836 { .bitrate = 90,
1837 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1838 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
1839 { .bitrate = 120,
1840 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1841 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
1842 { .bitrate = 180,
1843 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1844 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
1845 { .bitrate = 240,
1846 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1847 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
1848 { .bitrate = 360,
1849 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1850 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
1851 { .bitrate = 480,
1852 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1853 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
1854 { .bitrate = 540,
1855 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1856 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
1857};
1858
1859/* 5 GHz band channels for WL1273 */
1860static struct ieee80211_channel wl1271_channels_5ghz[] = {
1861 { .hw_value = 183, .center_freq = 4915},
1862 { .hw_value = 184, .center_freq = 4920},
1863 { .hw_value = 185, .center_freq = 4925},
1864 { .hw_value = 187, .center_freq = 4935},
1865 { .hw_value = 188, .center_freq = 4940},
1866 { .hw_value = 189, .center_freq = 4945},
1867 { .hw_value = 192, .center_freq = 4960},
1868 { .hw_value = 196, .center_freq = 4980},
1869 { .hw_value = 7, .center_freq = 5035},
1870 { .hw_value = 8, .center_freq = 5040},
1871 { .hw_value = 9, .center_freq = 5045},
1872 { .hw_value = 11, .center_freq = 5055},
1873 { .hw_value = 12, .center_freq = 5060},
1874 { .hw_value = 16, .center_freq = 5080},
1875 { .hw_value = 34, .center_freq = 5170},
1876 { .hw_value = 36, .center_freq = 5180},
1877 { .hw_value = 38, .center_freq = 5190},
1878 { .hw_value = 40, .center_freq = 5200},
1879 { .hw_value = 42, .center_freq = 5210},
1880 { .hw_value = 44, .center_freq = 5220},
1881 { .hw_value = 46, .center_freq = 5230},
1882 { .hw_value = 48, .center_freq = 5240},
1883 { .hw_value = 52, .center_freq = 5260},
1884 { .hw_value = 56, .center_freq = 5280},
1885 { .hw_value = 60, .center_freq = 5300},
1886 { .hw_value = 64, .center_freq = 5320},
1887 { .hw_value = 100, .center_freq = 5500},
1888 { .hw_value = 104, .center_freq = 5520},
1889 { .hw_value = 108, .center_freq = 5540},
1890 { .hw_value = 112, .center_freq = 5560},
1891 { .hw_value = 116, .center_freq = 5580},
1892 { .hw_value = 120, .center_freq = 5600},
1893 { .hw_value = 124, .center_freq = 5620},
1894 { .hw_value = 128, .center_freq = 5640},
1895 { .hw_value = 132, .center_freq = 5660},
1896 { .hw_value = 136, .center_freq = 5680},
1897 { .hw_value = 140, .center_freq = 5700},
1898 { .hw_value = 149, .center_freq = 5745},
1899 { .hw_value = 153, .center_freq = 5765},
1900 { .hw_value = 157, .center_freq = 5785},
1901 { .hw_value = 161, .center_freq = 5805},
1902 { .hw_value = 165, .center_freq = 5825},
1903};
1904
1905
1906static struct ieee80211_supported_band wl1271_band_5ghz = {
1907 .channels = wl1271_channels_5ghz,
1908 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
1909 .bitrates = wl1271_rates_5ghz,
1910 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
1911};
1912
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001913static const struct ieee80211_ops wl1271_ops = {
1914 .start = wl1271_op_start,
1915 .stop = wl1271_op_stop,
1916 .add_interface = wl1271_op_add_interface,
1917 .remove_interface = wl1271_op_remove_interface,
1918 .config = wl1271_op_config,
1919/* .config_interface = wl1271_op_config_interface, */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001920 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001921 .configure_filter = wl1271_op_configure_filter,
1922 .tx = wl1271_op_tx,
1923 .set_key = wl1271_op_set_key,
1924 .hw_scan = wl1271_op_hw_scan,
1925 .bss_info_changed = wl1271_op_bss_info_changed,
1926 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02001927 .conf_tx = wl1271_op_conf_tx,
Kalle Valoc8c90872010-02-18 13:25:53 +02001928 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001929};
1930
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02001931int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001932{
1933 int ret;
1934
1935 if (wl->mac80211_registered)
1936 return 0;
1937
1938 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
1939
1940 ret = ieee80211_register_hw(wl->hw);
1941 if (ret < 0) {
1942 wl1271_error("unable to register mac80211 hw: %d", ret);
1943 return ret;
1944 }
1945
1946 wl->mac80211_registered = true;
1947
1948 wl1271_notice("loaded");
1949
1950 return 0;
1951}
1952
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02001953int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001954{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03001955 /* The tx descriptor buffer and the TKIP space. */
1956 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
1957 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001958
1959 /* unit us */
1960 /* FIXME: find a proper value */
1961 wl->hw->channel_change_time = 10000;
1962
1963 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03001964 IEEE80211_HW_NOISE_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02001965 IEEE80211_HW_BEACON_FILTER |
1966 IEEE80211_HW_SUPPORTS_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001967
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001968 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
1969 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001970 wl->hw->wiphy->max_scan_ssids = 1;
1971 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
1972
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001973 if (wl1271_11a_enabled())
1974 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
1975
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001976 SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
1977
1978 return 0;
1979}
1980
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001981#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02001982
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02001983struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001984{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001985 struct ieee80211_hw *hw;
1986 struct wl1271 *wl;
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02001987 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001988
1989 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
1990 if (!hw) {
1991 wl1271_error("could not alloc ieee80211_hw");
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02001992 return ERR_PTR(-ENOMEM);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001993 }
1994
1995 wl = hw->priv;
1996 memset(wl, 0, sizeof(*wl));
1997
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001998 INIT_LIST_HEAD(&wl->list);
1999
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002000 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002001
2002 skb_queue_head_init(&wl->tx_queue);
2003
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002004 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002005 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002006 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002007 wl->rx_counter = 0;
2008 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2009 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002010 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002011 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002012 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002013 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2014 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002015 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002016 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002017 wl->flags = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002018
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002019 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002020 wl->tx_frames[i] = NULL;
2021
2022 spin_lock_init(&wl->wl_lock);
2023
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002024 wl->state = WL1271_STATE_OFF;
2025 mutex_init(&wl->mutex);
2026
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002027 /* Apply default driver configuration. */
2028 wl1271_conf_init(wl);
2029
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002030 wl1271_debugfs_init(wl);
2031
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002032 return hw;
2033}
2034
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}