blob: 0392e37f0d6608664471cdd49a7435a84648a0b2 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 *
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/kernel.h>
25#include <linux/module.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090026#include <linux/slab.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027
Shahar Levi00d20102010-11-08 11:20:10 +000028#include "init.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030029#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000030#include "acx.h"
31#include "cmd.h"
32#include "reg.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030033
34static int wl1271_init_hwenc_config(struct wl1271 *wl)
35{
36 int ret;
37
38 ret = wl1271_acx_feature_cfg(wl);
39 if (ret < 0) {
40 wl1271_warning("couldn't set feature config");
41 return ret;
42 }
43
44 ret = wl1271_cmd_set_default_wep_key(wl, wl->default_key);
45 if (ret < 0) {
46 wl1271_warning("couldn't set default key");
47 return ret;
48 }
49
50 return 0;
51}
52
Luciano Coelho12419cc2010-02-18 13:25:44 +020053int wl1271_init_templates_config(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030054{
Juuso Oikarinenbfb24c92010-03-26 12:53:31 +020055 int ret, i;
Juuso Oikarinen11eb5422010-08-24 06:28:03 +030056 size_t size;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030057
58 /* send empty templates for fw memory reservation */
59 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL,
Juuso Oikarinenbfb24c92010-03-26 12:53:31 +020060 sizeof(struct wl12xx_probe_req_template),
Juuso Oikarinen606c1482010-04-01 11:38:21 +030061 0, WL1271_RATE_AUTOMATIC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030062 if (ret < 0)
63 return ret;
64
Juuso Oikarinen11eb5422010-08-24 06:28:03 +030065 size = sizeof(struct wl12xx_probe_req_template);
66 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
67 NULL, size, 0,
68 WL1271_RATE_AUTOMATIC);
69 if (ret < 0)
70 return ret;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +030071
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030072 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL,
Juuso Oikarinenbfb24c92010-03-26 12:53:31 +020073 sizeof(struct wl12xx_null_data_template),
Juuso Oikarinen606c1482010-04-01 11:38:21 +030074 0, WL1271_RATE_AUTOMATIC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030075 if (ret < 0)
76 return ret;
77
78 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, NULL,
Juuso Oikarinenbfb24c92010-03-26 12:53:31 +020079 sizeof(struct wl12xx_ps_poll_template),
Juuso Oikarinen606c1482010-04-01 11:38:21 +030080 0, WL1271_RATE_AUTOMATIC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030081 if (ret < 0)
82 return ret;
83
84 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, NULL,
85 sizeof
Juuso Oikarinenbfb24c92010-03-26 12:53:31 +020086 (struct wl12xx_qos_null_data_template),
Juuso Oikarinen606c1482010-04-01 11:38:21 +030087 0, WL1271_RATE_AUTOMATIC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030088 if (ret < 0)
89 return ret;
90
91 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, NULL,
92 sizeof
Juuso Oikarinenbfb24c92010-03-26 12:53:31 +020093 (struct wl12xx_probe_resp_template),
Juuso Oikarinen606c1482010-04-01 11:38:21 +030094 0, WL1271_RATE_AUTOMATIC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030095 if (ret < 0)
96 return ret;
97
98 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, NULL,
99 sizeof
Juuso Oikarinenbfb24c92010-03-26 12:53:31 +0200100 (struct wl12xx_beacon_template),
Juuso Oikarinen606c1482010-04-01 11:38:21 +0300101 0, WL1271_RATE_AUTOMATIC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300102 if (ret < 0)
103 return ret;
104
Eliad Pellerc5312772010-12-09 11:31:27 +0200105 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP, NULL,
106 sizeof
107 (struct wl12xx_arp_rsp_template),
108 0, WL1271_RATE_AUTOMATIC);
109 if (ret < 0)
110 return ret;
111
Juuso Oikarinenbfb24c92010-03-26 12:53:31 +0200112 for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
113 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, NULL,
Juuso Oikarinen606c1482010-04-01 11:38:21 +0300114 WL1271_CMD_TEMPL_MAX_SIZE, i,
115 WL1271_RATE_AUTOMATIC);
Juuso Oikarinenbfb24c92010-03-26 12:53:31 +0200116 if (ret < 0)
117 return ret;
118 }
119
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300120 return 0;
121}
122
123static int wl1271_init_rx_config(struct wl1271 *wl, u32 config, u32 filter)
124{
125 int ret;
126
Juuso Oikarinen8793f9b2009-10-13 12:47:40 +0300127 ret = wl1271_acx_rx_msdu_life_time(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300128 if (ret < 0)
129 return ret;
130
131 ret = wl1271_acx_rx_config(wl, config, filter);
132 if (ret < 0)
133 return ret;
134
135 return 0;
136}
137
Luciano Coelho12419cc2010-02-18 13:25:44 +0200138int wl1271_init_phy_config(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300139{
140 int ret;
141
142 ret = wl1271_acx_pd_threshold(wl);
143 if (ret < 0)
144 return ret;
145
146 ret = wl1271_acx_slot(wl, DEFAULT_SLOT_TIME);
147 if (ret < 0)
148 return ret;
149
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300150 ret = wl1271_acx_group_address_tbl(wl, true, NULL, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300151 if (ret < 0)
152 return ret;
153
154 ret = wl1271_acx_service_period_timeout(wl);
155 if (ret < 0)
156 return ret;
157
Juuso Oikarinen8793f9b2009-10-13 12:47:40 +0300158 ret = wl1271_acx_rts_threshold(wl, wl->conf.rx.rts_threshold);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300159 if (ret < 0)
160 return ret;
161
162 return 0;
163}
164
165static int wl1271_init_beacon_filter(struct wl1271 *wl)
166{
167 int ret;
168
Juuso Oikarinen19221672009-10-08 21:56:35 +0300169 /* disable beacon filtering at this stage */
170 ret = wl1271_acx_beacon_filter_opt(wl, false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300171 if (ret < 0)
172 return ret;
173
174 ret = wl1271_acx_beacon_filter_table(wl);
175 if (ret < 0)
176 return ret;
177
178 return 0;
179}
180
Luciano Coelho12419cc2010-02-18 13:25:44 +0200181int wl1271_init_pta(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300182{
183 int ret;
184
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200185 ret = wl1271_acx_sg_cfg(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300186 if (ret < 0)
187 return ret;
188
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +0200189 ret = wl1271_acx_sg_enable(wl, wl->sg_enabled);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300190 if (ret < 0)
191 return ret;
192
193 return 0;
194}
195
Luciano Coelho12419cc2010-02-18 13:25:44 +0200196int wl1271_init_energy_detection(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300197{
198 int ret;
199
200 ret = wl1271_acx_cca_threshold(wl);
201 if (ret < 0)
202 return ret;
203
204 return 0;
205}
206
207static int wl1271_init_beacon_broadcast(struct wl1271 *wl)
208{
209 int ret;
210
211 ret = wl1271_acx_bcn_dtim_options(wl);
212 if (ret < 0)
213 return ret;
214
215 return 0;
216}
217
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300218int wl1271_hw_init(struct wl1271 *wl)
219{
Kalle Valo243eeb52010-02-18 13:25:39 +0200220 struct conf_tx_ac_category *conf_ac;
Kalle Valof2054df2010-02-18 13:25:40 +0200221 struct conf_tx_tid *conf_tid;
Kalle Valo243eeb52010-02-18 13:25:39 +0200222 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300223
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200224 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200225 if (ret < 0)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300226 return ret;
227
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200228 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200229 if (ret < 0)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300230 return ret;
231
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200232 ret = wl1271_cmd_ext_radio_parms(wl);
233 if (ret < 0)
234 return ret;
235
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300236 /* Template settings */
237 ret = wl1271_init_templates_config(wl);
238 if (ret < 0)
239 return ret;
240
241 /* Default memory configuration */
242 ret = wl1271_acx_init_mem_config(wl);
243 if (ret < 0)
244 return ret;
245
246 /* RX config */
247 ret = wl1271_init_rx_config(wl,
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300248 RX_CFG_PROMISCUOUS | RX_CFG_TSF,
249 RX_FILTER_OPTION_DEF);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300250 /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS,
251 RX_FILTER_OPTION_FILTER_ALL); */
252 if (ret < 0)
253 goto out_free_memmap;
254
255 /* PHY layer config */
256 ret = wl1271_init_phy_config(wl);
257 if (ret < 0)
258 goto out_free_memmap;
259
Luciano Coelho6e92b412009-12-11 15:40:50 +0200260 ret = wl1271_acx_dco_itrim_params(wl);
261 if (ret < 0)
262 goto out_free_memmap;
263
Juuso Oikarinen34415232009-10-08 21:56:33 +0300264 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200265 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinen34415232009-10-08 21:56:33 +0300266 if (ret < 0)
267 goto out_free_memmap;
268
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300269 /* Beacon filtering */
270 ret = wl1271_init_beacon_filter(wl);
271 if (ret < 0)
272 goto out_free_memmap;
273
274 /* Configure TX patch complete interrupt behavior */
275 ret = wl1271_acx_tx_config_options(wl);
276 if (ret < 0)
277 goto out_free_memmap;
278
279 /* RX complete interrupt pacing */
280 ret = wl1271_acx_init_rx_interrupt(wl);
281 if (ret < 0)
282 goto out_free_memmap;
283
284 /* Bluetooth WLAN coexistence */
285 ret = wl1271_init_pta(wl);
286 if (ret < 0)
287 goto out_free_memmap;
288
289 /* Energy detection */
290 ret = wl1271_init_energy_detection(wl);
291 if (ret < 0)
292 goto out_free_memmap;
293
294 /* Beacons and boradcast settings */
295 ret = wl1271_init_beacon_broadcast(wl);
296 if (ret < 0)
297 goto out_free_memmap;
298
299 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100300 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300301 if (ret < 0)
302 goto out_free_memmap;
303
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200304 /* Default TID/AC configuration */
305 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Kalle Valof2054df2010-02-18 13:25:40 +0200306 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200307 conf_ac = &wl->conf.tx.ac_conf[i];
308 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
309 conf_ac->cw_max, conf_ac->aifsn,
310 conf_ac->tx_op_limit);
311 if (ret < 0)
312 goto out_free_memmap;
313
Kalle Valof2054df2010-02-18 13:25:40 +0200314 conf_tid = &wl->conf.tx.tid_conf[i];
315 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
316 conf_tid->channel_type,
317 conf_tid->tsid,
318 conf_tid->ps_scheme,
319 conf_tid->ack_policy,
320 conf_tid->apsd_conf[0],
321 conf_tid->apsd_conf[1]);
322 if (ret < 0)
323 goto out_free_memmap;
324 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300325
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300326 /* Configure TX rate classes */
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200327 ret = wl1271_acx_rate_policies(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300328 if (ret < 0)
329 goto out_free_memmap;
330
331 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200332 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300333 if (ret < 0)
334 goto out_free_memmap;
335
336 /* Configure for ELP power saving */
337 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
338 if (ret < 0)
339 goto out_free_memmap;
340
341 /* Configure HW encryption */
342 ret = wl1271_init_hwenc_config(wl);
343 if (ret < 0)
344 goto out_free_memmap;
345
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200346 /* configure PM */
347 ret = wl1271_acx_pm_config(wl);
348 if (ret < 0)
349 goto out_free_memmap;
350
Juuso Oikarinenc1899552010-03-26 12:53:32 +0200351 /* disable all keep-alive templates */
352 for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
353 ret = wl1271_acx_keep_alive_config(wl, i,
354 ACX_KEEP_ALIVE_TPL_INVALID);
355 if (ret < 0)
356 goto out_free_memmap;
357 }
358
359 /* disable the keep-alive feature */
360 ret = wl1271_acx_keep_alive_mode(wl, false);
361 if (ret < 0)
362 goto out_free_memmap;
363
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300364 /* Configure rssi/snr averaging weights */
365 ret = wl1271_acx_rssi_snr_avg_weights(wl);
366 if (ret < 0)
367 goto out_free_memmap;
368
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300369 return 0;
370
371 out_free_memmap:
372 kfree(wl->target_mem_map);
Juuso Oikarinen34415232009-10-08 21:56:33 +0300373 wl->target_mem_map = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300374
375 return ret;
376}