]>
Commit | Line | Data |
---|---|---|
2b27bdcc | 1 | // SPDX-License-Identifier: GPL-2.0-only |
b8422dcb LC |
2 | /* |
3 | * This file is part of wl18xx | |
4 | * | |
5 | * Copyright (C) 2011 Texas Instruments Inc. | |
b8422dcb LC |
6 | */ |
7 | ||
8 | #include "../wlcore/cmd.h" | |
9 | #include "../wlcore/debug.h" | |
10 | #include "../wlcore/acx.h" | |
11 | ||
12 | #include "acx.h" | |
e2f1e50f | 13 | #include "wl18xx.h" |
b8422dcb LC |
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 | ||
a1c597f2 AN |
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 | ||
b8422dcb LC |
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 | } | |
2fc28de5 AN |
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 | ||
b6acb4e0 | 65 | ret = wl1271_cmd_configure(wl, ACX_CSUM_CONFIG, acx, sizeof(*acx)); |
2fc28de5 AN |
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 | } | |
f74ea74b LC |
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 | } | |
5f9b6777 AN |
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 | } | |
530abe19 EP |
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 | } | |
6d5a748d RA |
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 | } | |
e2f1e50f K |
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 | } | |
d1c54096 GM |
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 | } | |
c5aa9541 GM |
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 | } |