GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / net / wireless / ti / wl18xx / acx.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * This file is part of wl18xx
4  *
5  * Copyright (C) 2011 Texas Instruments Inc.
6  */
7
8 #include "../wlcore/cmd.h"
9 #include "../wlcore/debug.h"
10 #include "../wlcore/acx.h"
11
12 #include "acx.h"
13 #include "wl18xx.h"
14
15 int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,
16                                   u32 sdio_blk_size, u32 extra_mem_blks,
17                                   u32 len_field_size)
18 {
19         struct wl18xx_acx_host_config_bitmap *bitmap_conf;
20         int ret;
21
22         wl1271_debug(DEBUG_ACX, "acx cfg bitmap %d blk %d spare %d field %d",
23                      host_cfg_bitmap, sdio_blk_size, extra_mem_blks,
24                      len_field_size);
25
26         bitmap_conf = kzalloc(sizeof(*bitmap_conf), GFP_KERNEL);
27         if (!bitmap_conf) {
28                 ret = -ENOMEM;
29                 goto out;
30         }
31
32         bitmap_conf->host_cfg_bitmap = cpu_to_le32(host_cfg_bitmap);
33         bitmap_conf->host_sdio_block_size = cpu_to_le32(sdio_blk_size);
34         bitmap_conf->extra_mem_blocks = cpu_to_le32(extra_mem_blks);
35         bitmap_conf->length_field_size = cpu_to_le32(len_field_size);
36
37         ret = wl1271_cmd_configure(wl, ACX_HOST_IF_CFG_BITMAP,
38                                    bitmap_conf, sizeof(*bitmap_conf));
39         if (ret < 0) {
40                 wl1271_warning("wl1271 bitmap config opt failed: %d", ret);
41                 goto out;
42         }
43
44 out:
45         kfree(bitmap_conf);
46
47         return ret;
48 }
49
50 int wl18xx_acx_set_checksum_state(struct wl1271 *wl)
51 {
52         struct wl18xx_acx_checksum_state *acx;
53         int ret;
54
55         wl1271_debug(DEBUG_ACX, "acx checksum state");
56
57         acx = kzalloc(sizeof(*acx), GFP_KERNEL);
58         if (!acx) {
59                 ret = -ENOMEM;
60                 goto out;
61         }
62
63         acx->checksum_state = CHECKSUM_OFFLOAD_ENABLED;
64
65         ret = wl1271_cmd_configure(wl, ACX_CSUM_CONFIG, acx, sizeof(*acx));
66         if (ret < 0) {
67                 wl1271_warning("failed to set Tx checksum state: %d", ret);
68                 goto out;
69         }
70
71 out:
72         kfree(acx);
73         return ret;
74 }
75
76 int wl18xx_acx_clear_statistics(struct wl1271 *wl)
77 {
78         struct wl18xx_acx_clear_statistics *acx;
79         int ret = 0;
80
81         wl1271_debug(DEBUG_ACX, "acx clear statistics");
82
83         acx = kzalloc(sizeof(*acx), GFP_KERNEL);
84         if (!acx) {
85                 ret = -ENOMEM;
86                 goto out;
87         }
88
89         ret = wl1271_cmd_configure(wl, ACX_CLEAR_STATISTICS, acx, sizeof(*acx));
90         if (ret < 0) {
91                 wl1271_warning("failed to clear firmware statistics: %d", ret);
92                 goto out;
93         }
94
95 out:
96         kfree(acx);
97         return ret;
98 }
99
100 int wl18xx_acx_peer_ht_operation_mode(struct wl1271 *wl, u8 hlid, bool wide)
101 {
102         struct wlcore_peer_ht_operation_mode *acx;
103         int ret;
104
105         wl1271_debug(DEBUG_ACX, "acx peer ht operation mode hlid %d bw %d",
106                      hlid, wide);
107
108         acx = kzalloc(sizeof(*acx), GFP_KERNEL);
109         if (!acx) {
110                 ret = -ENOMEM;
111                 goto out;
112         }
113
114         acx->hlid = hlid;
115         acx->bandwidth = wide ? WLCORE_BANDWIDTH_40MHZ : WLCORE_BANDWIDTH_20MHZ;
116
117         ret = wl1271_cmd_configure(wl, ACX_PEER_HT_OPERATION_MODE_CFG, acx,
118                                    sizeof(*acx));
119
120         if (ret < 0) {
121                 wl1271_warning("acx peer ht operation mode failed: %d", ret);
122                 goto out;
123         }
124
125 out:
126         kfree(acx);
127         return ret;
128
129 }
130
131 /*
132  * this command is basically the same as wl1271_acx_ht_capabilities,
133  * with the addition of supported rates. they should be unified in
134  * the next fw api change
135  */
136 int wl18xx_acx_set_peer_cap(struct wl1271 *wl,
137                             struct ieee80211_sta_ht_cap *ht_cap,
138                             bool allow_ht_operation,
139                             u32 rate_set, u8 hlid)
140 {
141         struct wlcore_acx_peer_cap *acx;
142         int ret = 0;
143         u32 ht_capabilites = 0;
144
145         wl1271_debug(DEBUG_ACX,
146                      "acx set cap ht_supp: %d ht_cap: %d rates: 0x%x",
147                      ht_cap->ht_supported, ht_cap->cap, rate_set);
148
149         acx = kzalloc(sizeof(*acx), GFP_KERNEL);
150         if (!acx) {
151                 ret = -ENOMEM;
152                 goto out;
153         }
154
155         if (allow_ht_operation && ht_cap->ht_supported) {
156                 /* no need to translate capabilities - use the spec values */
157                 ht_capabilites = ht_cap->cap;
158
159                 /*
160                  * this bit is not employed by the spec but only by FW to
161                  * indicate peer HT support
162                  */
163                 ht_capabilites |= WL12XX_HT_CAP_HT_OPERATION;
164
165                 /* get data from A-MPDU parameters field */
166                 acx->ampdu_max_length = ht_cap->ampdu_factor;
167                 acx->ampdu_min_spacing = ht_cap->ampdu_density;
168         }
169
170         acx->hlid = hlid;
171         acx->ht_capabilites = cpu_to_le32(ht_capabilites);
172         acx->supported_rates = cpu_to_le32(rate_set);
173
174         ret = wl1271_cmd_configure(wl, ACX_PEER_CAP, acx, sizeof(*acx));
175         if (ret < 0) {
176                 wl1271_warning("acx ht capabilities setting failed: %d", ret);
177                 goto out;
178         }
179
180 out:
181         kfree(acx);
182         return ret;
183 }
184
185 /*
186  * When the host is suspended, we don't want to get any fast-link/PSM
187  * notifications
188  */
189 int wl18xx_acx_interrupt_notify_config(struct wl1271 *wl,
190                                        bool action)
191 {
192         struct wl18xx_acx_interrupt_notify *acx;
193         int ret = 0;
194
195         acx = kzalloc(sizeof(*acx), GFP_KERNEL);
196         if (!acx) {
197                 ret = -ENOMEM;
198                 goto out;
199         }
200
201         acx->enable = action;
202         ret = wl1271_cmd_configure(wl, ACX_INTERRUPT_NOTIFY, acx, sizeof(*acx));
203         if (ret < 0) {
204                 wl1271_warning("acx interrupt notify setting failed: %d", ret);
205                 goto out;
206         }
207
208 out:
209         kfree(acx);
210         return ret;
211 }
212
213 /*
214  * When the host is suspended, we can configure the FW to disable RX BA
215  * notifications.
216  */
217 int wl18xx_acx_rx_ba_filter(struct wl1271 *wl, bool action)
218 {
219         struct wl18xx_acx_rx_ba_filter *acx;
220         int ret = 0;
221
222         acx = kzalloc(sizeof(*acx), GFP_KERNEL);
223         if (!acx) {
224                 ret = -ENOMEM;
225                 goto out;
226         }
227
228         acx->enable = (u32)action;
229         ret = wl1271_cmd_configure(wl, ACX_RX_BA_FILTER, acx, sizeof(*acx));
230         if (ret < 0) {
231                 wl1271_warning("acx rx ba activity filter setting failed: %d",
232                                ret);
233                 goto out;
234         }
235
236 out:
237         kfree(acx);
238         return ret;
239 }
240
241 int wl18xx_acx_ap_sleep(struct wl1271 *wl)
242 {
243         struct wl18xx_priv *priv = wl->priv;
244         struct acx_ap_sleep_cfg *acx;
245         struct conf_ap_sleep_settings *conf = &priv->conf.ap_sleep;
246         int ret;
247
248         wl1271_debug(DEBUG_ACX, "acx config ap sleep");
249
250         acx = kzalloc(sizeof(*acx), GFP_KERNEL);
251         if (!acx) {
252                 ret = -ENOMEM;
253                 goto out;
254         }
255
256         acx->idle_duty_cycle = conf->idle_duty_cycle;
257         acx->connected_duty_cycle = conf->connected_duty_cycle;
258         acx->max_stations_thresh = conf->max_stations_thresh;
259         acx->idle_conn_thresh = conf->idle_conn_thresh;
260
261         ret = wl1271_cmd_configure(wl, ACX_AP_SLEEP_CFG, acx, sizeof(*acx));
262         if (ret < 0) {
263                 wl1271_warning("acx config ap-sleep failed: %d", ret);
264                 goto out;
265         }
266
267 out:
268         kfree(acx);
269         return ret;
270 }
271
272 int wl18xx_acx_dynamic_fw_traces(struct wl1271 *wl)
273 {
274         struct acx_dynamic_fw_traces_cfg *acx;
275         int ret;
276
277         wl1271_debug(DEBUG_ACX, "acx dynamic fw traces config %d",
278                      wl->dynamic_fw_traces);
279
280         acx = kzalloc(sizeof(*acx), GFP_KERNEL);
281         if (!acx) {
282                 ret = -ENOMEM;
283                 goto out;
284         }
285
286         acx->dynamic_fw_traces = cpu_to_le32(wl->dynamic_fw_traces);
287
288         ret = wl1271_cmd_configure(wl, ACX_DYNAMIC_TRACES_CFG,
289                                    acx, sizeof(*acx));
290         if (ret < 0) {
291                 wl1271_warning("acx config dynamic fw traces failed: %d", ret);
292                 goto out;
293         }
294 out:
295         kfree(acx);
296         return ret;
297 }
298
299 int wl18xx_acx_time_sync_cfg(struct wl1271 *wl)
300 {
301         struct acx_time_sync_cfg *acx;
302         int ret;
303
304         wl1271_debug(DEBUG_ACX, "acx time sync cfg: mode %d, addr: %pM",
305                      wl->conf.sg.params[WL18XX_CONF_SG_TIME_SYNC],
306                      wl->zone_master_mac_addr);
307
308         acx = kzalloc(sizeof(*acx), GFP_KERNEL);
309         if (!acx) {
310                 ret = -ENOMEM;
311                 goto out;
312         }
313
314         acx->sync_mode = wl->conf.sg.params[WL18XX_CONF_SG_TIME_SYNC];
315         memcpy(acx->zone_mac_addr, wl->zone_master_mac_addr, ETH_ALEN);
316
317         ret = wl1271_cmd_configure(wl, ACX_TIME_SYNC_CFG,
318                                    acx, sizeof(*acx));
319         if (ret < 0) {
320                 wl1271_warning("acx time sync cfg failed: %d", ret);
321                 goto out;
322         }
323 out:
324         kfree(acx);
325         return ret;
326 }