blob: b7974b4dbb346b22181b6abdcadb36a3bc5e8b19 [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
Luciano Coelho0f4e3122011-10-07 11:02:42 +030028#include "debug.h"
Shahar Levi00d20102010-11-08 11:20:10 +000029#include "init.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030030#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000031#include "acx.h"
32#include "cmd.h"
Arik Nemtsove0fe3712010-10-16 18:19:53 +020033#include "tx.h"
Shahar Levi48a61472011-03-06 16:32:08 +020034#include "io.h"
Arik Nemtsov8a9affc2011-12-13 12:15:09 +020035#include "hw_ops.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036
Eliad Peller92c77c72011-10-05 11:55:40 +020037int wl1271_init_templates_config(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030038{
Juuso Oikarinenbfb24c92010-03-26 12:53:31 +020039 int ret, i;
Eliad Peller5ec8a442012-02-02 12:22:09 +020040 size_t max_size;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030041
42 /* send empty templates for fw memory reservation */
Eliad Pellercdaac622012-01-31 11:57:16 +020043 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
Eliad Peller78e28062012-11-22 18:06:15 +020044 wl->scan_templ_id_2_4, NULL,
Ido Reisc08e3712012-02-02 13:54:27 +020045 WL1271_CMD_TEMPL_MAX_SIZE,
Juuso Oikarinen606c1482010-04-01 11:38:21 +030046 0, WL1271_RATE_AUTOMATIC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030047 if (ret < 0)
48 return ret;
49
Eliad Pellercdaac622012-01-31 11:57:16 +020050 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
Eliad Peller78e28062012-11-22 18:06:15 +020051 wl->scan_templ_id_5,
Ido Reisc08e3712012-02-02 13:54:27 +020052 NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0,
Juuso Oikarinen11eb5422010-08-24 06:28:03 +030053 WL1271_RATE_AUTOMATIC);
54 if (ret < 0)
55 return ret;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +030056
Yoni Divinsky3df74f42012-06-27 13:01:44 +030057 if (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL) {
58 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
Eliad Peller78e28062012-11-22 18:06:15 +020059 wl->sched_scan_templ_id_2_4,
60 NULL,
Yoni Divinsky3df74f42012-06-27 13:01:44 +030061 WL1271_CMD_TEMPL_MAX_SIZE,
62 0, WL1271_RATE_AUTOMATIC);
63 if (ret < 0)
64 return ret;
65
66 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
Eliad Peller78e28062012-11-22 18:06:15 +020067 wl->sched_scan_templ_id_5,
68 NULL,
Yoni Divinsky3df74f42012-06-27 13:01:44 +030069 WL1271_CMD_TEMPL_MAX_SIZE,
70 0, WL1271_RATE_AUTOMATIC);
71 if (ret < 0)
72 return ret;
73 }
74
Eliad Pellercdaac622012-01-31 11:57:16 +020075 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
76 CMD_TEMPL_NULL_DATA, NULL,
Juuso Oikarinenbfb24c92010-03-26 12:53:31 +020077 sizeof(struct wl12xx_null_data_template),
Juuso Oikarinen606c1482010-04-01 11:38:21 +030078 0, WL1271_RATE_AUTOMATIC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030079 if (ret < 0)
80 return ret;
81
Eliad Pellercdaac622012-01-31 11:57:16 +020082 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
83 CMD_TEMPL_PS_POLL, NULL,
Juuso Oikarinenbfb24c92010-03-26 12:53:31 +020084 sizeof(struct wl12xx_ps_poll_template),
Juuso Oikarinen606c1482010-04-01 11:38:21 +030085 0, WL1271_RATE_AUTOMATIC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030086 if (ret < 0)
87 return ret;
88
Eliad Pellercdaac622012-01-31 11:57:16 +020089 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
90 CMD_TEMPL_QOS_NULL_DATA, NULL,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030091 sizeof
Eliad Peller97127e62011-11-09 13:12:45 +020092 (struct ieee80211_qos_hdr),
Juuso Oikarinen606c1482010-04-01 11:38:21 +030093 0, WL1271_RATE_AUTOMATIC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030094 if (ret < 0)
95 return ret;
96
Eliad Pellercdaac622012-01-31 11:57:16 +020097 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
98 CMD_TEMPL_PROBE_RESPONSE, NULL,
Eliad Peller154037d2011-08-14 13:17:12 +030099 WL1271_CMD_TEMPL_DFLT_SIZE,
Juuso Oikarinen606c1482010-04-01 11:38:21 +0300100 0, WL1271_RATE_AUTOMATIC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300101 if (ret < 0)
102 return ret;
103
Eliad Pellercdaac622012-01-31 11:57:16 +0200104 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
105 CMD_TEMPL_BEACON, NULL,
Eliad Peller154037d2011-08-14 13:17:12 +0300106 WL1271_CMD_TEMPL_DFLT_SIZE,
Juuso Oikarinen606c1482010-04-01 11:38:21 +0300107 0, WL1271_RATE_AUTOMATIC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300108 if (ret < 0)
109 return ret;
110
Eliad Peller5ec8a442012-02-02 12:22:09 +0200111 max_size = sizeof(struct wl12xx_arp_rsp_template) +
112 WL1271_EXTRA_SPACE_MAX;
Eliad Pellercdaac622012-01-31 11:57:16 +0200113 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
114 CMD_TEMPL_ARP_RSP, NULL,
Eliad Peller5ec8a442012-02-02 12:22:09 +0200115 max_size,
Eliad Pellerc5312772010-12-09 11:31:27 +0200116 0, WL1271_RATE_AUTOMATIC);
117 if (ret < 0)
118 return ret;
119
Eliad Peller92c77c72011-10-05 11:55:40 +0200120 /*
121 * Put very large empty placeholders for all templates. These
122 * reserve memory for later.
123 */
Eliad Pellercdaac622012-01-31 11:57:16 +0200124 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
125 CMD_TEMPL_AP_PROBE_RESPONSE, NULL,
Eliad Peller92c77c72011-10-05 11:55:40 +0200126 WL1271_CMD_TEMPL_MAX_SIZE,
127 0, WL1271_RATE_AUTOMATIC);
128 if (ret < 0)
129 return ret;
130
Eliad Pellercdaac622012-01-31 11:57:16 +0200131 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
132 CMD_TEMPL_AP_BEACON, NULL,
Eliad Peller92c77c72011-10-05 11:55:40 +0200133 WL1271_CMD_TEMPL_MAX_SIZE,
134 0, WL1271_RATE_AUTOMATIC);
135 if (ret < 0)
136 return ret;
137
Eliad Pellercdaac622012-01-31 11:57:16 +0200138 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
139 CMD_TEMPL_DEAUTH_AP, NULL,
Eliad Peller92c77c72011-10-05 11:55:40 +0200140 sizeof
141 (struct wl12xx_disconn_template),
142 0, WL1271_RATE_AUTOMATIC);
143 if (ret < 0)
144 return ret;
145
Eliad Peller001e39a2012-08-16 13:52:47 +0300146 for (i = 0; i < WLCORE_MAX_KLV_TEMPLATES; i++) {
Eliad Pellercdaac622012-01-31 11:57:16 +0200147 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
148 CMD_TEMPL_KLV, NULL,
Eliad Peller97127e62011-11-09 13:12:45 +0200149 sizeof(struct ieee80211_qos_hdr),
150 i, WL1271_RATE_AUTOMATIC);
Juuso Oikarinenbfb24c92010-03-26 12:53:31 +0200151 if (ret < 0)
152 return ret;
153 }
154
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300155 return 0;
156}
157
Eliad Peller87fbcb02011-10-05 11:55:41 +0200158static int wl1271_ap_init_deauth_template(struct wl1271 *wl,
159 struct wl12xx_vif *wlvif)
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200160{
161 struct wl12xx_disconn_template *tmpl;
162 int ret;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +0300163 u32 rate;
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200164
165 tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL);
166 if (!tmpl) {
167 ret = -ENOMEM;
168 goto out;
169 }
170
171 tmpl->header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT |
172 IEEE80211_STYPE_DEAUTH);
173
Eliad Peller87fbcb02011-10-05 11:55:41 +0200174 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Eliad Pellercdaac622012-01-31 11:57:16 +0200175 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
176 CMD_TEMPL_DEAUTH_AP,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +0300177 tmpl, sizeof(*tmpl), 0, rate);
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200178
179out:
180 kfree(tmpl);
181 return ret;
182}
183
Eliad Peller784f6942011-10-05 11:55:39 +0200184static int wl1271_ap_init_null_template(struct wl1271 *wl,
185 struct ieee80211_vif *vif)
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200186{
Eliad Peller87fbcb02011-10-05 11:55:41 +0200187 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200188 struct ieee80211_hdr_3addr *nullfunc;
189 int ret;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +0300190 u32 rate;
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200191
192 nullfunc = kzalloc(sizeof(*nullfunc), GFP_KERNEL);
193 if (!nullfunc) {
194 ret = -ENOMEM;
195 goto out;
196 }
197
198 nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
199 IEEE80211_STYPE_NULLFUNC |
200 IEEE80211_FCTL_FROMDS);
201
202 /* nullfunc->addr1 is filled by FW */
203
Eliad Peller784f6942011-10-05 11:55:39 +0200204 memcpy(nullfunc->addr2, vif->addr, ETH_ALEN);
205 memcpy(nullfunc->addr3, vif->addr, ETH_ALEN);
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200206
Eliad Peller87fbcb02011-10-05 11:55:41 +0200207 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Eliad Pellercdaac622012-01-31 11:57:16 +0200208 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
209 CMD_TEMPL_NULL_DATA, nullfunc,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +0300210 sizeof(*nullfunc), 0, rate);
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200211
212out:
213 kfree(nullfunc);
214 return ret;
215}
216
Eliad Peller784f6942011-10-05 11:55:39 +0200217static int wl1271_ap_init_qos_null_template(struct wl1271 *wl,
218 struct ieee80211_vif *vif)
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200219{
Eliad Peller87fbcb02011-10-05 11:55:41 +0200220 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200221 struct ieee80211_qos_hdr *qosnull;
222 int ret;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +0300223 u32 rate;
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200224
225 qosnull = kzalloc(sizeof(*qosnull), GFP_KERNEL);
226 if (!qosnull) {
227 ret = -ENOMEM;
228 goto out;
229 }
230
231 qosnull->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
232 IEEE80211_STYPE_QOS_NULLFUNC |
233 IEEE80211_FCTL_FROMDS);
234
235 /* qosnull->addr1 is filled by FW */
236
Eliad Peller784f6942011-10-05 11:55:39 +0200237 memcpy(qosnull->addr2, vif->addr, ETH_ALEN);
238 memcpy(qosnull->addr3, vif->addr, ETH_ALEN);
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200239
Eliad Peller87fbcb02011-10-05 11:55:41 +0200240 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Eliad Pellercdaac622012-01-31 11:57:16 +0200241 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
242 CMD_TEMPL_QOS_NULL_DATA, qosnull,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +0300243 sizeof(*qosnull), 0, rate);
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200244
245out:
246 kfree(qosnull);
247 return ret;
248}
249
Eliad Peller08c1d1c2011-08-14 13:17:04 +0300250static int wl12xx_init_rx_config(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300251{
252 int ret;
253
Juuso Oikarinen8793f9b2009-10-13 12:47:40 +0300254 ret = wl1271_acx_rx_msdu_life_time(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300255 if (ret < 0)
256 return ret;
257
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300258 return 0;
259}
260
Eliad Peller0603d892011-10-05 11:55:51 +0200261static int wl12xx_init_phy_vif_config(struct wl1271 *wl,
262 struct wl12xx_vif *wlvif)
Eliad Peller92c77c72011-10-05 11:55:40 +0200263{
264 int ret;
265
Eliad Peller0603d892011-10-05 11:55:51 +0200266 ret = wl1271_acx_slot(wl, wlvif, DEFAULT_SLOT_TIME);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300267 if (ret < 0)
268 return ret;
269
Eliad Peller0603d892011-10-05 11:55:51 +0200270 ret = wl1271_acx_service_period_timeout(wl, wlvif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300271 if (ret < 0)
272 return ret;
273
Eliad Peller0603d892011-10-05 11:55:51 +0200274 ret = wl1271_acx_rts_threshold(wl, wlvif, wl->hw->wiphy->rts_threshold);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300275 if (ret < 0)
276 return ret;
277
278 return 0;
279}
280
Arik Nemtsova6935342011-10-24 17:25:20 +0200281static int wl1271_init_sta_beacon_filter(struct wl1271 *wl,
282 struct wl12xx_vif *wlvif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300283{
284 int ret;
285
Arik Nemtsova6935342011-10-24 17:25:20 +0200286 ret = wl1271_acx_beacon_filter_table(wl, wlvif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300287 if (ret < 0)
288 return ret;
289
Eliad Pellerd881fa22014-02-10 13:47:33 +0200290 /* disable beacon filtering until we get the first beacon */
291 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300292 if (ret < 0)
293 return ret;
294
295 return 0;
296}
297
Luciano Coelho12419cce2010-02-18 13:25:44 +0200298int wl1271_init_pta(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300299{
300 int ret;
301
Eliad Peller3be41122011-08-14 13:17:19 +0300302 ret = wl12xx_acx_sg_cfg(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300303 if (ret < 0)
304 return ret;
305
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +0200306 ret = wl1271_acx_sg_enable(wl, wl->sg_enabled);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300307 if (ret < 0)
308 return ret;
309
310 return 0;
311}
312
Luciano Coelho12419cce2010-02-18 13:25:44 +0200313int wl1271_init_energy_detection(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300314{
315 int ret;
316
317 ret = wl1271_acx_cca_threshold(wl);
318 if (ret < 0)
319 return ret;
320
321 return 0;
322}
323
Eliad Peller0603d892011-10-05 11:55:51 +0200324static int wl1271_init_beacon_broadcast(struct wl1271 *wl,
325 struct wl12xx_vif *wlvif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300326{
327 int ret;
328
Eliad Peller0603d892011-10-05 11:55:51 +0200329 ret = wl1271_acx_bcn_dtim_options(wl, wlvif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300330 if (ret < 0)
331 return ret;
332
333 return 0;
334}
335
Ido Yariv95dac04f2011-06-06 14:57:06 +0300336static int wl12xx_init_fwlog(struct wl1271 *wl)
337{
338 int ret;
339
Luciano Coelho6f7dd162011-11-29 16:27:31 +0200340 if (wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED)
Ido Yariv95dac04f2011-06-06 14:57:06 +0300341 return 0;
342
343 ret = wl12xx_cmd_config_fwlog(wl);
344 if (ret < 0)
345 return ret;
346
347 return 0;
348}
349
Eliad Peller92c77c72011-10-05 11:55:40 +0200350/* generic sta initialization (non vif-specific) */
Eliad Peller7845af32015-07-30 22:38:22 +0300351int wl1271_sta_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200352{
353 int ret;
354
Eliad Pellerc8bde242011-02-02 09:59:35 +0200355 /* PS config */
Eliad Pellerd2d66c52011-10-05 11:55:43 +0200356 ret = wl12xx_acx_config_ps(wl, wlvif);
Eliad Pellerc8bde242011-02-02 09:59:35 +0200357 if (ret < 0)
358 return ret;
359
Shahar Leviff868432011-04-11 15:41:46 +0300360 /* FM WLAN coexistence */
361 ret = wl1271_acx_fm_coex(wl);
362 if (ret < 0)
363 return ret;
364
Eliad Peller30d0c8f2011-10-05 11:55:42 +0200365 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200366 if (ret < 0)
367 return ret;
368
369 return 0;
370}
371
Eliad Peller0603d892011-10-05 11:55:51 +0200372static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl,
373 struct ieee80211_vif *vif)
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200374{
Eliad Peller0603d892011-10-05 11:55:51 +0200375 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller001e39a2012-08-16 13:52:47 +0300376 int ret;
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200377
378 /* disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +0200379 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200380 if (ret < 0)
381 return ret;
382
383 return 0;
384}
385
Eliad Peller92c77c72011-10-05 11:55:40 +0200386/* generic ap initialization (non vif-specific) */
Eliad Peller87fbcb02011-10-05 11:55:41 +0200387static int wl1271_ap_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200388{
Arik Nemtsov70f47422011-04-18 14:15:25 +0300389 int ret;
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200390
Eliad Peller87fbcb02011-10-05 11:55:41 +0200391 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200392 if (ret < 0)
393 return ret;
394
Kobi Le2f1e502014-12-29 08:24:06 +0200395 /* configure AP sleep, if enabled */
396 ret = wlcore_hw_ap_sleep(wl);
397 if (ret < 0)
398 return ret;
399
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200400 return 0;
401}
402
Eliad Peller784f6942011-10-05 11:55:39 +0200403int wl1271_ap_init_templates(struct wl1271 *wl, struct ieee80211_vif *vif)
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200404{
Eliad Peller87fbcb02011-10-05 11:55:41 +0200405 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200406 int ret;
407
Eliad Peller87fbcb02011-10-05 11:55:41 +0200408 ret = wl1271_ap_init_deauth_template(wl, wlvif);
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200409 if (ret < 0)
410 return ret;
411
Eliad Peller784f6942011-10-05 11:55:39 +0200412 ret = wl1271_ap_init_null_template(wl, vif);
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200413 if (ret < 0)
414 return ret;
415
Eliad Peller784f6942011-10-05 11:55:39 +0200416 ret = wl1271_ap_init_qos_null_template(wl, vif);
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200417 if (ret < 0)
418 return ret;
419
Arik Nemtsov521a4a22011-04-18 14:15:22 +0300420 /*
421 * when operating as AP we want to receive external beacons for
422 * configuring ERP protection.
423 */
Eliad Peller0603d892011-10-05 11:55:51 +0200424 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
Arik Nemtsov521a4a22011-04-18 14:15:22 +0300425 if (ret < 0)
426 return ret;
427
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200428 return 0;
429}
430
Eliad Peller784f6942011-10-05 11:55:39 +0200431static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl,
432 struct ieee80211_vif *vif)
Arik Nemtsovc45a85b2011-04-18 14:15:26 +0300433{
Eliad Peller784f6942011-10-05 11:55:39 +0200434 return wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +0300435}
436
Eliad Peller87fbcb02011-10-05 11:55:41 +0200437int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov70f47422011-04-18 14:15:25 +0300438{
439 int i, ret;
440 struct conf_tx_rate_class rc;
441 u32 supported_rates;
442
Eliad Peller87fbcb02011-10-05 11:55:41 +0200443 wl1271_debug(DEBUG_AP, "AP basic rate set: 0x%x",
444 wlvif->basic_rate_set);
Arik Nemtsov70f47422011-04-18 14:15:25 +0300445
Eliad Peller87fbcb02011-10-05 11:55:41 +0200446 if (wlvif->basic_rate_set == 0)
Arik Nemtsov70f47422011-04-18 14:15:25 +0300447 return -EINVAL;
448
Eliad Peller87fbcb02011-10-05 11:55:41 +0200449 rc.enabled_rates = wlvif->basic_rate_set;
Arik Nemtsov70f47422011-04-18 14:15:25 +0300450 rc.long_retry_limit = 10;
451 rc.short_retry_limit = 10;
452 rc.aflags = 0;
Eliad Pellere5a359f2011-10-10 10:13:15 +0200453 ret = wl1271_acx_ap_rate_policy(wl, &rc, wlvif->ap.mgmt_rate_idx);
Arik Nemtsov70f47422011-04-18 14:15:25 +0300454 if (ret < 0)
455 return ret;
456
457 /* use the min basic rate for AP broadcast/multicast */
Eliad Peller87fbcb02011-10-05 11:55:41 +0200458 rc.enabled_rates = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsov70f47422011-04-18 14:15:25 +0300459 rc.short_retry_limit = 10;
460 rc.long_retry_limit = 10;
461 rc.aflags = 0;
Eliad Pellere5a359f2011-10-10 10:13:15 +0200462 ret = wl1271_acx_ap_rate_policy(wl, &rc, wlvif->ap.bcast_rate_idx);
Arik Nemtsov70f47422011-04-18 14:15:25 +0300463 if (ret < 0)
464 return ret;
465
466 /*
467 * If the basic rates contain OFDM rates, use OFDM only
468 * rates for unicast TX as well. Else use all supported rates.
469 */
Arik Nemtsovbc566f92014-02-10 13:47:28 +0200470 if (wl->ofdm_only_ap && (wlvif->basic_rate_set & CONF_TX_OFDM_RATES))
Arik Nemtsov70f47422011-04-18 14:15:25 +0300471 supported_rates = CONF_TX_OFDM_RATES;
472 else
Eliad Peller42ec1f82012-11-20 13:20:08 +0200473 supported_rates = CONF_TX_ENABLED_RATES;
Arik Nemtsov70f47422011-04-18 14:15:25 +0300474
Arik Nemtsov1a8adb62011-08-14 13:17:29 +0300475 /* unconditionally enable HT rates */
476 supported_rates |= CONF_TX_MCS_RATES;
477
Arik Nemtsovebc7e572012-05-10 12:13:34 +0300478 /* get extra MIMO or wide-chan rates where the HW supports it */
479 supported_rates |= wlcore_hw_ap_get_mimo_wide_rate_mask(wl, wlvif);
480
Arik Nemtsov70f47422011-04-18 14:15:25 +0300481 /* configure unicast TX rate classes */
482 for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
483 rc.enabled_rates = supported_rates;
484 rc.short_retry_limit = 10;
485 rc.long_retry_limit = 10;
486 rc.aflags = 0;
Eliad Pellere5a359f2011-10-10 10:13:15 +0200487 ret = wl1271_acx_ap_rate_policy(wl, &rc,
488 wlvif->ap.ucast_rate_idx[i]);
Arik Nemtsov70f47422011-04-18 14:15:25 +0300489 if (ret < 0)
490 return ret;
491 }
492
493 return 0;
494}
495
Eliad Peller536129c2011-10-05 11:55:45 +0200496static int wl1271_set_ba_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100497{
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100498 /* Reset the BA RX indicators */
Eliad Pellerd0802ab2011-10-05 11:56:04 +0200499 wlvif->ba_allowed = true;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300500 wl->ba_rx_session_count = 0;
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100501
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300502 /* BA is supported in STA/AP modes */
Eliad Peller536129c2011-10-05 11:55:45 +0200503 if (wlvif->bss_type != BSS_TYPE_AP_BSS &&
504 wlvif->bss_type != BSS_TYPE_STA_BSS) {
Eliad Pellerd0802ab2011-10-05 11:56:04 +0200505 wlvif->ba_support = false;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300506 return 0;
507 }
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100508
Eliad Pellerd0802ab2011-10-05 11:56:04 +0200509 wlvif->ba_support = true;
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100510
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300511 /* 802.11n initiator BA session setting */
Eliad Peller0603d892011-10-05 11:55:51 +0200512 return wl12xx_acx_set_ba_initiator_policy(wl, wlvif);
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100513}
514
Eliad Peller92c77c72011-10-05 11:55:40 +0200515/* vif-specifc initialization */
Eliad Peller0603d892011-10-05 11:55:51 +0200516static int wl12xx_init_sta_role(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Peller92c77c72011-10-05 11:55:40 +0200517{
518 int ret;
Shahar Levi48a61472011-03-06 16:32:08 +0200519
Eliad Peller0603d892011-10-05 11:55:51 +0200520 ret = wl1271_acx_group_address_tbl(wl, wlvif, true, NULL, 0);
Eliad Peller92c77c72011-10-05 11:55:40 +0200521 if (ret < 0)
522 return ret;
523
524 /* Initialize connection monitoring thresholds */
Eliad Peller0603d892011-10-05 11:55:51 +0200525 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Eliad Peller92c77c72011-10-05 11:55:40 +0200526 if (ret < 0)
527 return ret;
528
529 /* Beacon filtering */
Arik Nemtsova6935342011-10-24 17:25:20 +0200530 ret = wl1271_init_sta_beacon_filter(wl, wlvif);
Eliad Peller92c77c72011-10-05 11:55:40 +0200531 if (ret < 0)
532 return ret;
533
534 /* Beacons and broadcast settings */
Eliad Peller0603d892011-10-05 11:55:51 +0200535 ret = wl1271_init_beacon_broadcast(wl, wlvif);
Eliad Peller92c77c72011-10-05 11:55:40 +0200536 if (ret < 0)
537 return ret;
538
539 /* Configure rssi/snr averaging weights */
Eliad Peller0603d892011-10-05 11:55:51 +0200540 ret = wl1271_acx_rssi_snr_avg_weights(wl, wlvif);
Eliad Peller92c77c72011-10-05 11:55:40 +0200541 if (ret < 0)
542 return ret;
543
544 return 0;
545}
546
547/* vif-specific intialization */
Eliad Peller0603d892011-10-05 11:55:51 +0200548static int wl12xx_init_ap_role(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Peller92c77c72011-10-05 11:55:40 +0200549{
550 int ret;
551
Jimmy Perchetddcf65e82016-05-09 10:32:04 -0700552 /* Disable filtering */
553 ret = wl1271_acx_group_address_tbl(wl, wlvif, false, NULL, 0);
554 if (ret < 0)
555 return ret;
556
Eliad Peller0603d892011-10-05 11:55:51 +0200557 ret = wl1271_acx_ap_max_tx_retry(wl, wlvif);
Eliad Peller92c77c72011-10-05 11:55:40 +0200558 if (ret < 0)
559 return ret;
560
561 /* initialize Tx power */
Eliad Peller6bd65022011-10-10 10:13:11 +0200562 ret = wl1271_acx_tx_power(wl, wlvif, wlvif->power_level);
Eliad Peller92c77c72011-10-05 11:55:40 +0200563 if (ret < 0)
564 return ret;
565
Eliad Peller8cf77e12016-03-07 00:28:09 +0200566 if (wl->radar_debug_mode)
567 wlcore_cmd_generic_cfg(wl, wlvif,
568 WLCORE_CFG_FEATURE_RADAR_DEBUG,
569 wl->radar_debug_mode, 0);
570
Eliad Peller92c77c72011-10-05 11:55:40 +0200571 return 0;
572}
573
574int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300575{
Eliad Peller87fbcb02011-10-05 11:55:41 +0200576 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo243eeb52010-02-18 13:25:39 +0200577 struct conf_tx_ac_category *conf_ac;
Kalle Valof2054df2010-02-18 13:25:40 +0200578 struct conf_tx_tid *conf_tid;
Eliad Peller536129c2011-10-05 11:55:45 +0200579 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Eliad Peller92c77c72011-10-05 11:55:40 +0200580 int ret, i;
581
Arik Nemtsov2f18cf72012-06-10 19:10:45 +0300582 /* consider all existing roles before configuring psm. */
583
584 if (wl->ap_count == 0 && is_ap) { /* first AP */
Kobi Le2f1e502014-12-29 08:24:06 +0200585 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
Arik Nemtsov2f18cf72012-06-10 19:10:45 +0300586 if (ret < 0)
587 return ret;
Eliad Peller71e996b2013-09-09 12:24:34 +0300588
589 /* unmask ap events */
590 wl->event_mask |= wl->ap_event_mask;
591 ret = wl1271_event_unmask(wl);
592 if (ret < 0)
593 return ret;
Arik Nemtsov2f18cf72012-06-10 19:10:45 +0300594 /* first STA, no APs */
595 } else if (wl->sta_count == 0 && wl->ap_count == 0 && !is_ap) {
596 u8 sta_auth = wl->conf.conn.sta_sleep_auth;
597 /* Configure for power according to debugfs */
598 if (sta_auth != WL1271_PSM_ILLEGAL)
599 ret = wl1271_acx_sleep_auth(wl, sta_auth);
Arik Nemtsov2f18cf72012-06-10 19:10:45 +0300600 /* Configure for ELP power saving */
601 else
602 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
603
604 if (ret < 0)
605 return ret;
Eliad Pellera4e41302011-10-11 11:49:15 +0200606 }
607
Eliad Peller92c77c72011-10-05 11:55:40 +0200608 /* Mode specific init */
609 if (is_ap) {
Eliad Peller87fbcb02011-10-05 11:55:41 +0200610 ret = wl1271_ap_hw_init(wl, wlvif);
Eliad Peller92c77c72011-10-05 11:55:40 +0200611 if (ret < 0)
612 return ret;
613
Eliad Peller0603d892011-10-05 11:55:51 +0200614 ret = wl12xx_init_ap_role(wl, wlvif);
Eliad Peller92c77c72011-10-05 11:55:40 +0200615 if (ret < 0)
616 return ret;
617 } else {
Eliad Peller30d0c8f2011-10-05 11:55:42 +0200618 ret = wl1271_sta_hw_init(wl, wlvif);
Eliad Peller92c77c72011-10-05 11:55:40 +0200619 if (ret < 0)
620 return ret;
621
Eliad Peller0603d892011-10-05 11:55:51 +0200622 ret = wl12xx_init_sta_role(wl, wlvif);
Eliad Peller92c77c72011-10-05 11:55:40 +0200623 if (ret < 0)
624 return ret;
625 }
626
Eliad Peller0603d892011-10-05 11:55:51 +0200627 wl12xx_init_phy_vif_config(wl, wlvif);
Eliad Peller92c77c72011-10-05 11:55:40 +0200628
629 /* Default TID/AC configuration */
630 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
631 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
632 conf_ac = &wl->conf.tx.ac_conf[i];
Eliad Peller0603d892011-10-05 11:55:51 +0200633 ret = wl1271_acx_ac_cfg(wl, wlvif, conf_ac->ac,
634 conf_ac->cw_min, conf_ac->cw_max,
635 conf_ac->aifsn, conf_ac->tx_op_limit);
Eliad Peller92c77c72011-10-05 11:55:40 +0200636 if (ret < 0)
637 return ret;
638
639 conf_tid = &wl->conf.tx.tid_conf[i];
Eliad Peller0603d892011-10-05 11:55:51 +0200640 ret = wl1271_acx_tid_cfg(wl, wlvif,
Eliad Peller92c77c72011-10-05 11:55:40 +0200641 conf_tid->queue_id,
642 conf_tid->channel_type,
643 conf_tid->tsid,
644 conf_tid->ps_scheme,
645 conf_tid->ack_policy,
646 conf_tid->apsd_conf[0],
647 conf_tid->apsd_conf[1]);
648 if (ret < 0)
649 return ret;
650 }
651
652 /* Configure HW encryption */
Eliad Peller0603d892011-10-05 11:55:51 +0200653 ret = wl1271_acx_feature_cfg(wl, wlvif);
Eliad Peller92c77c72011-10-05 11:55:40 +0200654 if (ret < 0)
655 return ret;
656
657 /* Mode specific init - post mem init */
658 if (is_ap)
659 ret = wl1271_ap_hw_init_post_mem(wl, vif);
660 else
Eliad Peller0603d892011-10-05 11:55:51 +0200661 ret = wl1271_sta_hw_init_post_mem(wl, vif);
Eliad Peller92c77c72011-10-05 11:55:40 +0200662
663 if (ret < 0)
664 return ret;
665
666 /* Configure initiator BA sessions policies */
Eliad Peller536129c2011-10-05 11:55:45 +0200667 ret = wl1271_set_ba_policies(wl, wlvif);
Eliad Peller92c77c72011-10-05 11:55:40 +0200668 if (ret < 0)
669 return ret;
670
Arik Nemtsov8a9affc2011-12-13 12:15:09 +0200671 ret = wlcore_hw_init_vif(wl, wlvif);
672 if (ret < 0)
673 return ret;
674
Eliad Peller92c77c72011-10-05 11:55:40 +0200675 return 0;
676}
677
678int wl1271_hw_init(struct wl1271 *wl)
679{
680 int ret;
681
Luciano Coelho9d68d1e2011-12-02 00:47:45 +0200682 /* Chip-specific hw init */
683 ret = wl->ops->hw_init(wl);
Shahar Levi48a61472011-03-06 16:32:08 +0200684 if (ret < 0)
685 return ret;
686
Eliad Peller92c77c72011-10-05 11:55:40 +0200687 /* Init templates */
688 ret = wl1271_init_templates_config(wl);
689 if (ret < 0)
690 return ret;
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200691
Eliad Peller92c77c72011-10-05 11:55:40 +0200692 ret = wl12xx_acx_mem_cfg(wl);
693 if (ret < 0)
694 return ret;
695
696 /* Configure the FW logger */
697 ret = wl12xx_init_fwlog(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300698 if (ret < 0)
699 return ret;
700
Victor Goldenshtein6b70e7e2012-11-25 18:26:59 +0200701 ret = wlcore_cmd_regdomain_config_locked(wl);
702 if (ret < 0)
703 return ret;
704
Arik Nemtsov801f8702011-04-18 14:15:20 +0300705 /* Bluetooth WLAN coexistence */
706 ret = wl1271_init_pta(wl);
707 if (ret < 0)
708 return ret;
709
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300710 /* Default memory configuration */
711 ret = wl1271_acx_init_mem_config(wl);
712 if (ret < 0)
713 return ret;
714
715 /* RX config */
Eliad Peller08c1d1c2011-08-14 13:17:04 +0300716 ret = wl12xx_init_rx_config(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300717 if (ret < 0)
718 goto out_free_memmap;
719
Luciano Coelho6e92b412009-12-11 15:40:50 +0200720 ret = wl1271_acx_dco_itrim_params(wl);
721 if (ret < 0)
722 goto out_free_memmap;
723
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300724 /* Configure TX patch complete interrupt behavior */
725 ret = wl1271_acx_tx_config_options(wl);
726 if (ret < 0)
727 goto out_free_memmap;
728
729 /* RX complete interrupt pacing */
730 ret = wl1271_acx_init_rx_interrupt(wl);
731 if (ret < 0)
732 goto out_free_memmap;
733
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300734 /* Energy detection */
735 ret = wl1271_init_energy_detection(wl);
736 if (ret < 0)
737 goto out_free_memmap;
738
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300739 /* Default fragmentation threshold */
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300740 ret = wl1271_acx_frag_threshold(wl, wl->hw->wiphy->frag_threshold);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300741 if (ret < 0)
742 goto out_free_memmap;
743
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300744 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200745 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300746 if (ret < 0)
747 goto out_free_memmap;
748
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200749 /* configure PM */
750 ret = wl1271_acx_pm_config(wl);
751 if (ret < 0)
752 goto out_free_memmap;
753
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300754 ret = wl12xx_acx_set_rate_mgmt_params(wl);
755 if (ret < 0)
756 goto out_free_memmap;
757
Eliad Peller94877752011-08-28 15:11:56 +0300758 /* configure hangover */
759 ret = wl12xx_acx_config_hangover(wl);
760 if (ret < 0)
761 goto out_free_memmap;
762
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300763 return 0;
764
765 out_free_memmap:
766 kfree(wl->target_mem_map);
Juuso Oikarinen34415232009-10-08 21:56:33 +0300767 wl->target_mem_map = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300768
769 return ret;
770}