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
18int 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
37int 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
89int 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
104int 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
131int 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
147int 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
162int 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
173int 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
184int wl1251_hw_init_power_auth(struct wl1251 *wl)
185{
186	return wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM);
187}
188
189int 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
217static 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
256static 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
287out:
288	kfree(config);
289	return ret;
290}
291
292static 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
313int 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