1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * This file is part of wl1251
4 *
5 * Copyright (C) 2009 Nokia Corporation
6 */
7
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/slab.h>
11
12 #include "init.h"
13 #include "wl12xx_80211.h"
14 #include "acx.h"
15 #include "cmd.h"
16 #include "reg.h"
17
wl1251_hw_init_hwenc_config(struct wl1251 * wl)18 int wl1251_hw_init_hwenc_config(struct wl1251 *wl)
19 {
20 int ret;
21
22 ret = wl1251_acx_feature_cfg(wl, 0);
23 if (ret < 0) {
24 wl1251_warning("couldn't set feature config");
25 return ret;
26 }
27
28 ret = wl1251_acx_default_key(wl, wl->default_key);
29 if (ret < 0) {
30 wl1251_warning("couldn't set default key");
31 return ret;
32 }
33
34 return 0;
35 }
36
wl1251_hw_init_templates_config(struct wl1251 * wl)37 int wl1251_hw_init_templates_config(struct wl1251 *wl)
38 {
39 int ret;
40 u8 partial_vbm[PARTIAL_VBM_MAX];
41
42 /* send empty templates for fw memory reservation */
43 ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, NULL,
44 sizeof(struct wl12xx_probe_req_template));
45 if (ret < 0)
46 return ret;
47
48 ret = wl1251_cmd_template_set(wl, CMD_NULL_DATA, NULL,
49 sizeof(struct wl12xx_null_data_template));
50 if (ret < 0)
51 return ret;
52
53 ret = wl1251_cmd_template_set(wl, CMD_PS_POLL, NULL,
54 sizeof(struct wl12xx_ps_poll_template));
55 if (ret < 0)
56 return ret;
57
58 ret = wl1251_cmd_template_set(wl, CMD_QOS_NULL_DATA, NULL,
59 sizeof
60 (struct wl12xx_qos_null_data_template));
61 if (ret < 0)
62 return ret;
63
64 ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, NULL,
65 sizeof
66 (struct wl12xx_probe_resp_template));
67 if (ret < 0)
68 return ret;
69
70 ret = wl1251_cmd_template_set(wl, CMD_BEACON, NULL,
71 sizeof
72 (struct wl12xx_beacon_template));
73 if (ret < 0)
74 return ret;
75
76 /* tim templates, first reserve space then allocate an empty one */
77 memset(partial_vbm, 0, PARTIAL_VBM_MAX);
78 ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, PARTIAL_VBM_MAX, 0);
79 if (ret < 0)
80 return ret;
81
82 ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, 1, 0);
83 if (ret < 0)
84 return ret;
85
86 return 0;
87 }
88
wl1251_hw_init_rx_config(struct wl1251 * wl,u32 config,u32 filter)89 int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter)
90 {
91 int ret;
92
93 ret = wl1251_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF);
94 if (ret < 0)
95 return ret;
96
97 ret = wl1251_acx_rx_config(wl, config, filter);
98 if (ret < 0)
99 return ret;
100
101 return 0;
102 }
103
wl1251_hw_init_phy_config(struct wl1251 * wl)104 int wl1251_hw_init_phy_config(struct wl1251 *wl)
105 {
106 int ret;
107
108 ret = wl1251_acx_pd_threshold(wl);
109 if (ret < 0)
110 return ret;
111
112 ret = wl1251_acx_slot(wl, DEFAULT_SLOT_TIME);
113 if (ret < 0)
114 return ret;
115
116 ret = wl1251_acx_group_address_tbl(wl, true, NULL, 0);
117 if (ret < 0)
118 return ret;
119
120 ret = wl1251_acx_service_period_timeout(wl);
121 if (ret < 0)
122 return ret;
123
124 ret = wl1251_acx_rts_threshold(wl, RTS_THRESHOLD_DEF);
125 if (ret < 0)
126 return ret;
127
128 return 0;
129 }
130
wl1251_hw_init_beacon_filter(struct wl1251 * wl)131 int wl1251_hw_init_beacon_filter(struct wl1251 *wl)
132 {
133 int ret;
134
135 /* disable beacon filtering at this stage */
136 ret = wl1251_acx_beacon_filter_opt(wl, false);
137 if (ret < 0)
138 return ret;
139
140 ret = wl1251_acx_beacon_filter_table(wl);
141 if (ret < 0)
142 return ret;
143
144 return 0;
145 }
146
wl1251_hw_init_pta(struct wl1251 * wl)147 int wl1251_hw_init_pta(struct wl1251 *wl)
148 {
149 int ret;
150
151 ret = wl1251_acx_sg_enable(wl);
152 if (ret < 0)
153 return ret;
154
155 ret = wl1251_acx_sg_cfg(wl);
156 if (ret < 0)
157 return ret;
158
159 return 0;
160 }
161
wl1251_hw_init_energy_detection(struct wl1251 * wl)162 int wl1251_hw_init_energy_detection(struct wl1251 *wl)
163 {
164 int ret;
165
166 ret = wl1251_acx_cca_threshold(wl);
167 if (ret < 0)
168 return ret;
169
170 return 0;
171 }
172
wl1251_hw_init_beacon_broadcast(struct wl1251 * wl)173 int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl)
174 {
175 int ret;
176
177 ret = wl1251_acx_bcn_dtim_options(wl);
178 if (ret < 0)
179 return ret;
180
181 return 0;
182 }
183
wl1251_hw_init_power_auth(struct wl1251 * wl)184 int wl1251_hw_init_power_auth(struct wl1251 *wl)
185 {
186 return wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM);
187 }
188
wl1251_hw_init_mem_config(struct wl1251 * wl)189 int wl1251_hw_init_mem_config(struct wl1251 *wl)
190 {
191 int ret;
192
193 ret = wl1251_acx_mem_cfg(wl);
194 if (ret < 0)
195 return ret;
196
197 wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map),
198 GFP_KERNEL);
199 if (!wl->target_mem_map) {
200 wl1251_error("couldn't allocate target memory map");
201 return -ENOMEM;
202 }
203
204 /* we now ask for the firmware built memory map */
205 ret = wl1251_acx_mem_map(wl, wl->target_mem_map,
206 sizeof(struct wl1251_acx_mem_map));
207 if (ret < 0) {
208 wl1251_error("couldn't retrieve firmware memory map");
209 kfree(wl->target_mem_map);
210 wl->target_mem_map = NULL;
211 return ret;
212 }
213
214 return 0;
215 }
216
wl1251_hw_init_txq_fill(u8 qid,struct acx_tx_queue_qos_config * config,u32 num_blocks)217 static int wl1251_hw_init_txq_fill(u8 qid,
218 struct acx_tx_queue_qos_config *config,
219 u32 num_blocks)
220 {
221 config->qid = qid;
222
223 switch (qid) {
224 case QOS_AC_BE:
225 config->high_threshold =
226 (QOS_TX_HIGH_BE_DEF * num_blocks) / 100;
227 config->low_threshold =
228 (QOS_TX_LOW_BE_DEF * num_blocks) / 100;
229 break;
230 case QOS_AC_BK:
231 config->high_threshold =
232 (QOS_TX_HIGH_BK_DEF * num_blocks) / 100;
233 config->low_threshold =
234 (QOS_TX_LOW_BK_DEF * num_blocks) / 100;
235 break;
236 case QOS_AC_VI:
237 config->high_threshold =
238 (QOS_TX_HIGH_VI_DEF * num_blocks) / 100;
239 config->low_threshold =
240 (QOS_TX_LOW_VI_DEF * num_blocks) / 100;
241 break;
242 case QOS_AC_VO:
243 config->high_threshold =
244 (QOS_TX_HIGH_VO_DEF * num_blocks) / 100;
245 config->low_threshold =
246 (QOS_TX_LOW_VO_DEF * num_blocks) / 100;
247 break;
248 default:
249 wl1251_error("Invalid TX queue id: %d", qid);
250 return -EINVAL;
251 }
252
253 return 0;
254 }
255
wl1251_hw_init_tx_queue_config(struct wl1251 * wl)256 static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl)
257 {
258 struct acx_tx_queue_qos_config *config;
259 struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map;
260 int ret, i;
261
262 wl1251_debug(DEBUG_ACX, "acx tx queue config");
263
264 config = kzalloc(sizeof(*config), GFP_KERNEL);
265 if (!config) {
266 ret = -ENOMEM;
267 goto out;
268 }
269
270 for (i = 0; i < MAX_NUM_OF_AC; i++) {
271 ret = wl1251_hw_init_txq_fill(i, config,
272 wl_mem_map->num_tx_mem_blocks);
273 if (ret < 0)
274 goto out;
275
276 ret = wl1251_cmd_configure(wl, ACX_TX_QUEUE_CFG,
277 config, sizeof(*config));
278 if (ret < 0)
279 goto out;
280 }
281
282 wl1251_acx_ac_cfg(wl, AC_BE, CWMIN_BE, CWMAX_BE, AIFS_DIFS, TXOP_BE);
283 wl1251_acx_ac_cfg(wl, AC_BK, CWMIN_BK, CWMAX_BK, AIFS_DIFS, TXOP_BK);
284 wl1251_acx_ac_cfg(wl, AC_VI, CWMIN_VI, CWMAX_VI, AIFS_DIFS, TXOP_VI);
285 wl1251_acx_ac_cfg(wl, AC_VO, CWMIN_VO, CWMAX_VO, AIFS_DIFS, TXOP_VO);
286
287 out:
288 kfree(config);
289 return ret;
290 }
291
wl1251_hw_init_data_path_config(struct wl1251 * wl)292 static int wl1251_hw_init_data_path_config(struct wl1251 *wl)
293 {
294 int ret;
295
296 /* asking for the data path parameters */
297 wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp),
298 GFP_KERNEL);
299 if (!wl->data_path)
300 return -ENOMEM;
301
302 ret = wl1251_acx_data_path_params(wl, wl->data_path);
303 if (ret < 0) {
304 kfree(wl->data_path);
305 wl->data_path = NULL;
306 return ret;
307 }
308
309 return 0;
310 }
311
312
wl1251_hw_init(struct wl1251 * wl)313 int wl1251_hw_init(struct wl1251 *wl)
314 {
315 struct wl1251_acx_mem_map *wl_mem_map;
316 int ret;
317
318 ret = wl1251_hw_init_hwenc_config(wl);
319 if (ret < 0)
320 return ret;
321
322 /* Template settings */
323 ret = wl1251_hw_init_templates_config(wl);
324 if (ret < 0)
325 return ret;
326
327 /* Default memory configuration */
328 ret = wl1251_hw_init_mem_config(wl);
329 if (ret < 0)
330 return ret;
331
332 /* Default data path configuration */
333 ret = wl1251_hw_init_data_path_config(wl);
334 if (ret < 0)
335 goto out_free_memmap;
336
337 /* RX config */
338 ret = wl1251_hw_init_rx_config(wl,
339 RX_CFG_PROMISCUOUS | RX_CFG_TSF,
340 RX_FILTER_OPTION_DEF);
341 /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS,
342 RX_FILTER_OPTION_FILTER_ALL); */
343 if (ret < 0)
344 goto out_free_data_path;
345
346 /* TX queues config */
347 ret = wl1251_hw_init_tx_queue_config(wl);
348 if (ret < 0)
349 goto out_free_data_path;
350
351 /* PHY layer config */
352 ret = wl1251_hw_init_phy_config(wl);
353 if (ret < 0)
354 goto out_free_data_path;
355
356 /* Initialize connection monitoring thresholds */
357 ret = wl1251_acx_conn_monit_params(wl);
358 if (ret < 0)
359 goto out_free_data_path;
360
361 /* Beacon filtering */
362 ret = wl1251_hw_init_beacon_filter(wl);
363 if (ret < 0)
364 goto out_free_data_path;
365
366 /* Bluetooth WLAN coexistence */
367 ret = wl1251_hw_init_pta(wl);
368 if (ret < 0)
369 goto out_free_data_path;
370
371 /* Energy detection */
372 ret = wl1251_hw_init_energy_detection(wl);
373 if (ret < 0)
374 goto out_free_data_path;
375
376 /* Beacons and broadcast settings */
377 ret = wl1251_hw_init_beacon_broadcast(wl);
378 if (ret < 0)
379 goto out_free_data_path;
380
381 /* Enable rx data path */
382 ret = wl1251_cmd_data_path_rx(wl, wl->channel, 1);
383 if (ret < 0)
384 goto out_free_data_path;
385
386 /* Enable tx data path */
387 ret = wl1251_cmd_data_path_tx(wl, wl->channel, 1);
388 if (ret < 0)
389 goto out_free_data_path;
390
391 /* Default power state */
392 ret = wl1251_hw_init_power_auth(wl);
393 if (ret < 0)
394 goto out_free_data_path;
395
396 wl_mem_map = wl->target_mem_map;
397 wl1251_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x",
398 wl_mem_map->num_tx_mem_blocks,
399 wl->data_path->tx_control_addr,
400 wl_mem_map->num_rx_mem_blocks,
401 wl->data_path->rx_control_addr);
402
403 return 0;
404
405 out_free_data_path:
406 kfree(wl->data_path);
407
408 out_free_memmap:
409 kfree(wl->target_mem_map);
410
411 return ret;
412 }
413