xref: /openbmc/linux/drivers/net/wireless/ti/wl18xx/acx.c (revision 2b27bdcc)
12b27bdccSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2b8422dcbSLuciano Coelho /*
3b8422dcbSLuciano Coelho  * This file is part of wl18xx
4b8422dcbSLuciano Coelho  *
5b8422dcbSLuciano Coelho  * Copyright (C) 2011 Texas Instruments Inc.
6b8422dcbSLuciano Coelho  */
7b8422dcbSLuciano Coelho 
8b8422dcbSLuciano Coelho #include "../wlcore/cmd.h"
9b8422dcbSLuciano Coelho #include "../wlcore/debug.h"
10b8422dcbSLuciano Coelho #include "../wlcore/acx.h"
11b8422dcbSLuciano Coelho 
12b8422dcbSLuciano Coelho #include "acx.h"
13e2f1e50fSKobi L #include "wl18xx.h"
14b8422dcbSLuciano Coelho 
wl18xx_acx_host_if_cfg_bitmap(struct wl1271 * wl,u32 host_cfg_bitmap,u32 sdio_blk_size,u32 extra_mem_blks,u32 len_field_size)15b8422dcbSLuciano Coelho int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,
16b8422dcbSLuciano Coelho 				  u32 sdio_blk_size, u32 extra_mem_blks,
17b8422dcbSLuciano Coelho 				  u32 len_field_size)
18b8422dcbSLuciano Coelho {
19b8422dcbSLuciano Coelho 	struct wl18xx_acx_host_config_bitmap *bitmap_conf;
20b8422dcbSLuciano Coelho 	int ret;
21b8422dcbSLuciano Coelho 
22a1c597f2SArik Nemtsov 	wl1271_debug(DEBUG_ACX, "acx cfg bitmap %d blk %d spare %d field %d",
23a1c597f2SArik Nemtsov 		     host_cfg_bitmap, sdio_blk_size, extra_mem_blks,
24a1c597f2SArik Nemtsov 		     len_field_size);
25a1c597f2SArik Nemtsov 
26b8422dcbSLuciano Coelho 	bitmap_conf = kzalloc(sizeof(*bitmap_conf), GFP_KERNEL);
27b8422dcbSLuciano Coelho 	if (!bitmap_conf) {
28b8422dcbSLuciano Coelho 		ret = -ENOMEM;
29b8422dcbSLuciano Coelho 		goto out;
30b8422dcbSLuciano Coelho 	}
31b8422dcbSLuciano Coelho 
32b8422dcbSLuciano Coelho 	bitmap_conf->host_cfg_bitmap = cpu_to_le32(host_cfg_bitmap);
33b8422dcbSLuciano Coelho 	bitmap_conf->host_sdio_block_size = cpu_to_le32(sdio_blk_size);
34b8422dcbSLuciano Coelho 	bitmap_conf->extra_mem_blocks = cpu_to_le32(extra_mem_blks);
35b8422dcbSLuciano Coelho 	bitmap_conf->length_field_size = cpu_to_le32(len_field_size);
36b8422dcbSLuciano Coelho 
37b8422dcbSLuciano Coelho 	ret = wl1271_cmd_configure(wl, ACX_HOST_IF_CFG_BITMAP,
38b8422dcbSLuciano Coelho 				   bitmap_conf, sizeof(*bitmap_conf));
39b8422dcbSLuciano Coelho 	if (ret < 0) {
40b8422dcbSLuciano Coelho 		wl1271_warning("wl1271 bitmap config opt failed: %d", ret);
41b8422dcbSLuciano Coelho 		goto out;
42b8422dcbSLuciano Coelho 	}
43b8422dcbSLuciano Coelho 
44b8422dcbSLuciano Coelho out:
45b8422dcbSLuciano Coelho 	kfree(bitmap_conf);
46b8422dcbSLuciano Coelho 
47b8422dcbSLuciano Coelho 	return ret;
48b8422dcbSLuciano Coelho }
492fc28de5SArik Nemtsov 
wl18xx_acx_set_checksum_state(struct wl1271 * wl)502fc28de5SArik Nemtsov int wl18xx_acx_set_checksum_state(struct wl1271 *wl)
512fc28de5SArik Nemtsov {
522fc28de5SArik Nemtsov 	struct wl18xx_acx_checksum_state *acx;
532fc28de5SArik Nemtsov 	int ret;
542fc28de5SArik Nemtsov 
552fc28de5SArik Nemtsov 	wl1271_debug(DEBUG_ACX, "acx checksum state");
562fc28de5SArik Nemtsov 
572fc28de5SArik Nemtsov 	acx = kzalloc(sizeof(*acx), GFP_KERNEL);
582fc28de5SArik Nemtsov 	if (!acx) {
592fc28de5SArik Nemtsov 		ret = -ENOMEM;
602fc28de5SArik Nemtsov 		goto out;
612fc28de5SArik Nemtsov 	}
622fc28de5SArik Nemtsov 
632fc28de5SArik Nemtsov 	acx->checksum_state = CHECKSUM_OFFLOAD_ENABLED;
642fc28de5SArik Nemtsov 
65b6acb4e0SEliad Peller 	ret = wl1271_cmd_configure(wl, ACX_CSUM_CONFIG, acx, sizeof(*acx));
662fc28de5SArik Nemtsov 	if (ret < 0) {
672fc28de5SArik Nemtsov 		wl1271_warning("failed to set Tx checksum state: %d", ret);
682fc28de5SArik Nemtsov 		goto out;
692fc28de5SArik Nemtsov 	}
702fc28de5SArik Nemtsov 
712fc28de5SArik Nemtsov out:
722fc28de5SArik Nemtsov 	kfree(acx);
732fc28de5SArik Nemtsov 	return ret;
742fc28de5SArik Nemtsov }
75f74ea74bSLuciano Coelho 
wl18xx_acx_clear_statistics(struct wl1271 * wl)76f74ea74bSLuciano Coelho int wl18xx_acx_clear_statistics(struct wl1271 *wl)
77f74ea74bSLuciano Coelho {
78f74ea74bSLuciano Coelho 	struct wl18xx_acx_clear_statistics *acx;
79f74ea74bSLuciano Coelho 	int ret = 0;
80f74ea74bSLuciano Coelho 
81f74ea74bSLuciano Coelho 	wl1271_debug(DEBUG_ACX, "acx clear statistics");
82f74ea74bSLuciano Coelho 
83f74ea74bSLuciano Coelho 	acx = kzalloc(sizeof(*acx), GFP_KERNEL);
84f74ea74bSLuciano Coelho 	if (!acx) {
85f74ea74bSLuciano Coelho 		ret = -ENOMEM;
86f74ea74bSLuciano Coelho 		goto out;
87f74ea74bSLuciano Coelho 	}
88f74ea74bSLuciano Coelho 
89f74ea74bSLuciano Coelho 	ret = wl1271_cmd_configure(wl, ACX_CLEAR_STATISTICS, acx, sizeof(*acx));
90f74ea74bSLuciano Coelho 	if (ret < 0) {
91f74ea74bSLuciano Coelho 		wl1271_warning("failed to clear firmware statistics: %d", ret);
92f74ea74bSLuciano Coelho 		goto out;
93f74ea74bSLuciano Coelho 	}
94f74ea74bSLuciano Coelho 
95f74ea74bSLuciano Coelho out:
96f74ea74bSLuciano Coelho 	kfree(acx);
97f74ea74bSLuciano Coelho 	return ret;
98f74ea74bSLuciano Coelho }
995f9b6777SArik Nemtsov 
wl18xx_acx_peer_ht_operation_mode(struct wl1271 * wl,u8 hlid,bool wide)1005f9b6777SArik Nemtsov int wl18xx_acx_peer_ht_operation_mode(struct wl1271 *wl, u8 hlid, bool wide)
1015f9b6777SArik Nemtsov {
1025f9b6777SArik Nemtsov 	struct wlcore_peer_ht_operation_mode *acx;
1035f9b6777SArik Nemtsov 	int ret;
1045f9b6777SArik Nemtsov 
1055f9b6777SArik Nemtsov 	wl1271_debug(DEBUG_ACX, "acx peer ht operation mode hlid %d bw %d",
1065f9b6777SArik Nemtsov 		     hlid, wide);
1075f9b6777SArik Nemtsov 
1085f9b6777SArik Nemtsov 	acx = kzalloc(sizeof(*acx), GFP_KERNEL);
1095f9b6777SArik Nemtsov 	if (!acx) {
1105f9b6777SArik Nemtsov 		ret = -ENOMEM;
1115f9b6777SArik Nemtsov 		goto out;
1125f9b6777SArik Nemtsov 	}
1135f9b6777SArik Nemtsov 
1145f9b6777SArik Nemtsov 	acx->hlid = hlid;
1155f9b6777SArik Nemtsov 	acx->bandwidth = wide ? WLCORE_BANDWIDTH_40MHZ : WLCORE_BANDWIDTH_20MHZ;
1165f9b6777SArik Nemtsov 
1175f9b6777SArik Nemtsov 	ret = wl1271_cmd_configure(wl, ACX_PEER_HT_OPERATION_MODE_CFG, acx,
1185f9b6777SArik Nemtsov 				   sizeof(*acx));
1195f9b6777SArik Nemtsov 
1205f9b6777SArik Nemtsov 	if (ret < 0) {
1215f9b6777SArik Nemtsov 		wl1271_warning("acx peer ht operation mode failed: %d", ret);
1225f9b6777SArik Nemtsov 		goto out;
1235f9b6777SArik Nemtsov 	}
1245f9b6777SArik Nemtsov 
1255f9b6777SArik Nemtsov out:
1265f9b6777SArik Nemtsov 	kfree(acx);
1275f9b6777SArik Nemtsov 	return ret;
1285f9b6777SArik Nemtsov 
1295f9b6777SArik Nemtsov }
130530abe19SEliad Peller 
131530abe19SEliad Peller /*
132530abe19SEliad Peller  * this command is basically the same as wl1271_acx_ht_capabilities,
133530abe19SEliad Peller  * with the addition of supported rates. they should be unified in
134530abe19SEliad Peller  * the next fw api change
135530abe19SEliad Peller  */
wl18xx_acx_set_peer_cap(struct wl1271 * wl,struct ieee80211_sta_ht_cap * ht_cap,bool allow_ht_operation,u32 rate_set,u8 hlid)136530abe19SEliad Peller int wl18xx_acx_set_peer_cap(struct wl1271 *wl,
137530abe19SEliad Peller 			    struct ieee80211_sta_ht_cap *ht_cap,
138530abe19SEliad Peller 			    bool allow_ht_operation,
139530abe19SEliad Peller 			    u32 rate_set, u8 hlid)
140530abe19SEliad Peller {
141530abe19SEliad Peller 	struct wlcore_acx_peer_cap *acx;
142530abe19SEliad Peller 	int ret = 0;
143530abe19SEliad Peller 	u32 ht_capabilites = 0;
144530abe19SEliad Peller 
145530abe19SEliad Peller 	wl1271_debug(DEBUG_ACX,
146530abe19SEliad Peller 		     "acx set cap ht_supp: %d ht_cap: %d rates: 0x%x",
147530abe19SEliad Peller 		     ht_cap->ht_supported, ht_cap->cap, rate_set);
148530abe19SEliad Peller 
149530abe19SEliad Peller 	acx = kzalloc(sizeof(*acx), GFP_KERNEL);
150530abe19SEliad Peller 	if (!acx) {
151530abe19SEliad Peller 		ret = -ENOMEM;
152530abe19SEliad Peller 		goto out;
153530abe19SEliad Peller 	}
154530abe19SEliad Peller 
155530abe19SEliad Peller 	if (allow_ht_operation && ht_cap->ht_supported) {
156530abe19SEliad Peller 		/* no need to translate capabilities - use the spec values */
157530abe19SEliad Peller 		ht_capabilites = ht_cap->cap;
158530abe19SEliad Peller 
159530abe19SEliad Peller 		/*
160530abe19SEliad Peller 		 * this bit is not employed by the spec but only by FW to
161530abe19SEliad Peller 		 * indicate peer HT support
162530abe19SEliad Peller 		 */
163530abe19SEliad Peller 		ht_capabilites |= WL12XX_HT_CAP_HT_OPERATION;
164530abe19SEliad Peller 
165530abe19SEliad Peller 		/* get data from A-MPDU parameters field */
166530abe19SEliad Peller 		acx->ampdu_max_length = ht_cap->ampdu_factor;
167530abe19SEliad Peller 		acx->ampdu_min_spacing = ht_cap->ampdu_density;
168530abe19SEliad Peller 	}
169530abe19SEliad Peller 
170530abe19SEliad Peller 	acx->hlid = hlid;
171530abe19SEliad Peller 	acx->ht_capabilites = cpu_to_le32(ht_capabilites);
172530abe19SEliad Peller 	acx->supported_rates = cpu_to_le32(rate_set);
173530abe19SEliad Peller 
174530abe19SEliad Peller 	ret = wl1271_cmd_configure(wl, ACX_PEER_CAP, acx, sizeof(*acx));
175530abe19SEliad Peller 	if (ret < 0) {
176530abe19SEliad Peller 		wl1271_warning("acx ht capabilities setting failed: %d", ret);
177530abe19SEliad Peller 		goto out;
178530abe19SEliad Peller 	}
179530abe19SEliad Peller 
180530abe19SEliad Peller out:
181530abe19SEliad Peller 	kfree(acx);
182530abe19SEliad Peller 	return ret;
183530abe19SEliad Peller }
1846d5a748dSRam Amrani 
1856d5a748dSRam Amrani /*
1866d5a748dSRam Amrani  * When the host is suspended, we don't want to get any fast-link/PSM
1876d5a748dSRam Amrani  * notifications
1886d5a748dSRam Amrani  */
wl18xx_acx_interrupt_notify_config(struct wl1271 * wl,bool action)1896d5a748dSRam Amrani int wl18xx_acx_interrupt_notify_config(struct wl1271 *wl,
1906d5a748dSRam Amrani 				       bool action)
1916d5a748dSRam Amrani {
1926d5a748dSRam Amrani 	struct wl18xx_acx_interrupt_notify *acx;
1936d5a748dSRam Amrani 	int ret = 0;
1946d5a748dSRam Amrani 
1956d5a748dSRam Amrani 	acx = kzalloc(sizeof(*acx), GFP_KERNEL);
1966d5a748dSRam Amrani 	if (!acx) {
1976d5a748dSRam Amrani 		ret = -ENOMEM;
1986d5a748dSRam Amrani 		goto out;
1996d5a748dSRam Amrani 	}
2006d5a748dSRam Amrani 
2016d5a748dSRam Amrani 	acx->enable = action;
2026d5a748dSRam Amrani 	ret = wl1271_cmd_configure(wl, ACX_INTERRUPT_NOTIFY, acx, sizeof(*acx));
2036d5a748dSRam Amrani 	if (ret < 0) {
2046d5a748dSRam Amrani 		wl1271_warning("acx interrupt notify setting failed: %d", ret);
2056d5a748dSRam Amrani 		goto out;
2066d5a748dSRam Amrani 	}
2076d5a748dSRam Amrani 
2086d5a748dSRam Amrani out:
2096d5a748dSRam Amrani 	kfree(acx);
2106d5a748dSRam Amrani 	return ret;
2116d5a748dSRam Amrani }
2126d5a748dSRam Amrani 
2136d5a748dSRam Amrani /*
2146d5a748dSRam Amrani  * When the host is suspended, we can configure the FW to disable RX BA
2156d5a748dSRam Amrani  * notifications.
2166d5a748dSRam Amrani  */
wl18xx_acx_rx_ba_filter(struct wl1271 * wl,bool action)2176d5a748dSRam Amrani int wl18xx_acx_rx_ba_filter(struct wl1271 *wl, bool action)
2186d5a748dSRam Amrani {
2196d5a748dSRam Amrani 	struct wl18xx_acx_rx_ba_filter *acx;
2206d5a748dSRam Amrani 	int ret = 0;
2216d5a748dSRam Amrani 
2226d5a748dSRam Amrani 	acx = kzalloc(sizeof(*acx), GFP_KERNEL);
2236d5a748dSRam Amrani 	if (!acx) {
2246d5a748dSRam Amrani 		ret = -ENOMEM;
2256d5a748dSRam Amrani 		goto out;
2266d5a748dSRam Amrani 	}
2276d5a748dSRam Amrani 
2286d5a748dSRam Amrani 	acx->enable = (u32)action;
2296d5a748dSRam Amrani 	ret = wl1271_cmd_configure(wl, ACX_RX_BA_FILTER, acx, sizeof(*acx));
2306d5a748dSRam Amrani 	if (ret < 0) {
2316d5a748dSRam Amrani 		wl1271_warning("acx rx ba activity filter setting failed: %d",
2326d5a748dSRam Amrani 			       ret);
2336d5a748dSRam Amrani 		goto out;
2346d5a748dSRam Amrani 	}
2356d5a748dSRam Amrani 
2366d5a748dSRam Amrani out:
2376d5a748dSRam Amrani 	kfree(acx);
2386d5a748dSRam Amrani 	return ret;
2396d5a748dSRam Amrani }
240e2f1e50fSKobi L 
wl18xx_acx_ap_sleep(struct wl1271 * wl)241e2f1e50fSKobi L int wl18xx_acx_ap_sleep(struct wl1271 *wl)
242e2f1e50fSKobi L {
243e2f1e50fSKobi L 	struct wl18xx_priv *priv = wl->priv;
244e2f1e50fSKobi L 	struct acx_ap_sleep_cfg *acx;
245e2f1e50fSKobi L 	struct conf_ap_sleep_settings *conf = &priv->conf.ap_sleep;
246e2f1e50fSKobi L 	int ret;
247e2f1e50fSKobi L 
248e2f1e50fSKobi L 	wl1271_debug(DEBUG_ACX, "acx config ap sleep");
249e2f1e50fSKobi L 
250e2f1e50fSKobi L 	acx = kzalloc(sizeof(*acx), GFP_KERNEL);
251e2f1e50fSKobi L 	if (!acx) {
252e2f1e50fSKobi L 		ret = -ENOMEM;
253e2f1e50fSKobi L 		goto out;
254e2f1e50fSKobi L 	}
255e2f1e50fSKobi L 
256e2f1e50fSKobi L 	acx->idle_duty_cycle = conf->idle_duty_cycle;
257e2f1e50fSKobi L 	acx->connected_duty_cycle = conf->connected_duty_cycle;
258e2f1e50fSKobi L 	acx->max_stations_thresh = conf->max_stations_thresh;
259e2f1e50fSKobi L 	acx->idle_conn_thresh = conf->idle_conn_thresh;
260e2f1e50fSKobi L 
261e2f1e50fSKobi L 	ret = wl1271_cmd_configure(wl, ACX_AP_SLEEP_CFG, acx, sizeof(*acx));
262e2f1e50fSKobi L 	if (ret < 0) {
263e2f1e50fSKobi L 		wl1271_warning("acx config ap-sleep failed: %d", ret);
264e2f1e50fSKobi L 		goto out;
265e2f1e50fSKobi L 	}
266e2f1e50fSKobi L 
267e2f1e50fSKobi L out:
268e2f1e50fSKobi L 	kfree(acx);
269e2f1e50fSKobi L 	return ret;
270e2f1e50fSKobi L }
271d1c54096SGuy Mishol 
wl18xx_acx_dynamic_fw_traces(struct wl1271 * wl)272d1c54096SGuy Mishol int wl18xx_acx_dynamic_fw_traces(struct wl1271 *wl)
273d1c54096SGuy Mishol {
274d1c54096SGuy Mishol 	struct acx_dynamic_fw_traces_cfg *acx;
275d1c54096SGuy Mishol 	int ret;
276d1c54096SGuy Mishol 
277d1c54096SGuy Mishol 	wl1271_debug(DEBUG_ACX, "acx dynamic fw traces config %d",
278d1c54096SGuy Mishol 		     wl->dynamic_fw_traces);
279d1c54096SGuy Mishol 
280d1c54096SGuy Mishol 	acx = kzalloc(sizeof(*acx), GFP_KERNEL);
281d1c54096SGuy Mishol 	if (!acx) {
282d1c54096SGuy Mishol 		ret = -ENOMEM;
283d1c54096SGuy Mishol 		goto out;
284d1c54096SGuy Mishol 	}
285d1c54096SGuy Mishol 
286d1c54096SGuy Mishol 	acx->dynamic_fw_traces = cpu_to_le32(wl->dynamic_fw_traces);
287d1c54096SGuy Mishol 
288d1c54096SGuy Mishol 	ret = wl1271_cmd_configure(wl, ACX_DYNAMIC_TRACES_CFG,
289d1c54096SGuy Mishol 				   acx, sizeof(*acx));
290d1c54096SGuy Mishol 	if (ret < 0) {
291d1c54096SGuy Mishol 		wl1271_warning("acx config dynamic fw traces failed: %d", ret);
292d1c54096SGuy Mishol 		goto out;
293d1c54096SGuy Mishol 	}
294d1c54096SGuy Mishol out:
295d1c54096SGuy Mishol 	kfree(acx);
296d1c54096SGuy Mishol 	return ret;
297d1c54096SGuy Mishol }
298c5aa9541SGuy Mishol 
wl18xx_acx_time_sync_cfg(struct wl1271 * wl)299c5aa9541SGuy Mishol int wl18xx_acx_time_sync_cfg(struct wl1271 *wl)
300c5aa9541SGuy Mishol {
301c5aa9541SGuy Mishol 	struct acx_time_sync_cfg *acx;
302c5aa9541SGuy Mishol 	int ret;
303c5aa9541SGuy Mishol 
304c5aa9541SGuy Mishol 	wl1271_debug(DEBUG_ACX, "acx time sync cfg: mode %d, addr: %pM",
305c5aa9541SGuy Mishol 		     wl->conf.sg.params[WL18XX_CONF_SG_TIME_SYNC],
306c5aa9541SGuy Mishol 		     wl->zone_master_mac_addr);
307c5aa9541SGuy Mishol 
308c5aa9541SGuy Mishol 	acx = kzalloc(sizeof(*acx), GFP_KERNEL);
309c5aa9541SGuy Mishol 	if (!acx) {
310c5aa9541SGuy Mishol 		ret = -ENOMEM;
311c5aa9541SGuy Mishol 		goto out;
312c5aa9541SGuy Mishol 	}
313c5aa9541SGuy Mishol 
314c5aa9541SGuy Mishol 	acx->sync_mode = wl->conf.sg.params[WL18XX_CONF_SG_TIME_SYNC];
315c5aa9541SGuy Mishol 	memcpy(acx->zone_mac_addr, wl->zone_master_mac_addr, ETH_ALEN);
316c5aa9541SGuy Mishol 
317c5aa9541SGuy Mishol 	ret = wl1271_cmd_configure(wl, ACX_TIME_SYNC_CFG,
318c5aa9541SGuy Mishol 				   acx, sizeof(*acx));
319c5aa9541SGuy Mishol 	if (ret < 0) {
320c5aa9541SGuy Mishol 		wl1271_warning("acx time sync cfg failed: %d", ret);
321c5aa9541SGuy Mishol 		goto out;
322c5aa9541SGuy Mishol 	}
323c5aa9541SGuy Mishol out:
324c5aa9541SGuy Mishol 	kfree(acx);
325c5aa9541SGuy Mishol 	return ret;
326c5aa9541SGuy Mishol }
327