xref: /openbmc/linux/drivers/net/wireless/ti/wl1251/init.c (revision 71de0a05)
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 
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 
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 
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 
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 
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 
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 
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 
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 
184 int wl1251_hw_init_power_auth(struct wl1251 *wl)
185 {
186 	return wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM);
187 }
188 
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 
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 
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 
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 
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