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