1 | /* |
2 | * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com> |
3 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any |
5 | * purpose with or without fee is hereby granted, provided that the above |
6 | * copyright notice and this permission notice appear in all copies. |
7 | * |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | */ |
16 | |
17 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
18 | |
19 | #include <linux/bitfield.h> |
20 | #include <linux/etherdevice.h> |
21 | #include <linux/firmware.h> |
22 | #include <linux/bitops.h> |
23 | #include <linux/rpmsg.h> |
24 | #include "smd.h" |
25 | #include "firmware.h" |
26 | |
27 | struct wcn36xx_cfg_val { |
28 | u32 cfg_id; |
29 | u32 value; |
30 | }; |
31 | |
32 | #define WCN36XX_CFG_VAL(id, val) \ |
33 | { \ |
34 | .cfg_id = WCN36XX_HAL_CFG_ ## id, \ |
35 | .value = val \ |
36 | } |
37 | |
38 | static struct wcn36xx_cfg_val wcn36xx_cfg_vals[] = { |
39 | WCN36XX_CFG_VAL(CURRENT_TX_ANTENNA, 1), |
40 | WCN36XX_CFG_VAL(CURRENT_RX_ANTENNA, 1), |
41 | WCN36XX_CFG_VAL(LOW_GAIN_OVERRIDE, 0), |
42 | WCN36XX_CFG_VAL(POWER_STATE_PER_CHAIN, 785), |
43 | WCN36XX_CFG_VAL(CAL_PERIOD, 5), |
44 | WCN36XX_CFG_VAL(CAL_CONTROL, 1), |
45 | WCN36XX_CFG_VAL(PROXIMITY, 0), |
46 | WCN36XX_CFG_VAL(NETWORK_DENSITY, 3), |
47 | WCN36XX_CFG_VAL(MAX_MEDIUM_TIME, 6000), |
48 | WCN36XX_CFG_VAL(MAX_MPDUS_IN_AMPDU, 64), |
49 | WCN36XX_CFG_VAL(RTS_THRESHOLD, 2347), |
50 | WCN36XX_CFG_VAL(SHORT_RETRY_LIMIT, 15), |
51 | WCN36XX_CFG_VAL(LONG_RETRY_LIMIT, 15), |
52 | WCN36XX_CFG_VAL(FRAGMENTATION_THRESHOLD, 8000), |
53 | WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_ZERO, 5), |
54 | WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_ONE, 10), |
55 | WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_TWO, 15), |
56 | WCN36XX_CFG_VAL(FIXED_RATE, 0), |
57 | WCN36XX_CFG_VAL(RETRYRATE_POLICY, 4), |
58 | WCN36XX_CFG_VAL(RETRYRATE_SECONDARY, 0), |
59 | WCN36XX_CFG_VAL(RETRYRATE_TERTIARY, 0), |
60 | WCN36XX_CFG_VAL(FORCE_POLICY_PROTECTION, 5), |
61 | WCN36XX_CFG_VAL(FIXED_RATE_MULTICAST_24GHZ, 1), |
62 | WCN36XX_CFG_VAL(FIXED_RATE_MULTICAST_5GHZ, 5), |
63 | WCN36XX_CFG_VAL(DEFAULT_RATE_INDEX_5GHZ, 5), |
64 | WCN36XX_CFG_VAL(MAX_BA_SESSIONS, 40), |
65 | WCN36XX_CFG_VAL(PS_DATA_INACTIVITY_TIMEOUT, 200), |
66 | WCN36XX_CFG_VAL(PS_ENABLE_BCN_FILTER, 1), |
67 | WCN36XX_CFG_VAL(PS_ENABLE_RSSI_MONITOR, 1), |
68 | WCN36XX_CFG_VAL(NUM_BEACON_PER_RSSI_AVERAGE, 20), |
69 | WCN36XX_CFG_VAL(STATS_PERIOD, 10), |
70 | WCN36XX_CFG_VAL(CFP_MAX_DURATION, 30000), |
71 | WCN36XX_CFG_VAL(FRAME_TRANS_ENABLED, 0), |
72 | WCN36XX_CFG_VAL(BA_THRESHOLD_HIGH, 128), |
73 | WCN36XX_CFG_VAL(MAX_BA_BUFFERS, 2560), |
74 | WCN36XX_CFG_VAL(DYNAMIC_PS_POLL_VALUE, 0), |
75 | WCN36XX_CFG_VAL(TX_PWR_CTRL_ENABLE, 1), |
76 | WCN36XX_CFG_VAL(ENABLE_CLOSE_LOOP, 1), |
77 | WCN36XX_CFG_VAL(ENABLE_LPWR_IMG_TRANSITION, 0), |
78 | WCN36XX_CFG_VAL(BTC_STATIC_LEN_LE_BT, 120000), |
79 | WCN36XX_CFG_VAL(BTC_STATIC_LEN_LE_WLAN, 30000), |
80 | WCN36XX_CFG_VAL(MAX_ASSOC_LIMIT, 10), |
81 | WCN36XX_CFG_VAL(ENABLE_MCC_ADAPTIVE_SCHEDULER, 0), |
82 | WCN36XX_CFG_VAL(ENABLE_DYNAMIC_RA_START_RATE, 133), /* MCS 5 */ |
83 | WCN36XX_CFG_VAL(LINK_FAIL_TX_CNT, 1000), |
84 | }; |
85 | |
86 | static struct wcn36xx_cfg_val wcn3680_cfg_vals[] = { |
87 | WCN36XX_CFG_VAL(CURRENT_TX_ANTENNA, 1), |
88 | WCN36XX_CFG_VAL(CURRENT_RX_ANTENNA, 1), |
89 | WCN36XX_CFG_VAL(LOW_GAIN_OVERRIDE, 0), |
90 | WCN36XX_CFG_VAL(POWER_STATE_PER_CHAIN, 785), |
91 | WCN36XX_CFG_VAL(CAL_PERIOD, 5), |
92 | WCN36XX_CFG_VAL(CAL_CONTROL, 1), |
93 | WCN36XX_CFG_VAL(PROXIMITY, 0), |
94 | WCN36XX_CFG_VAL(NETWORK_DENSITY, 3), |
95 | WCN36XX_CFG_VAL(MAX_MEDIUM_TIME, 4096), |
96 | WCN36XX_CFG_VAL(MAX_MPDUS_IN_AMPDU, 64), |
97 | WCN36XX_CFG_VAL(RTS_THRESHOLD, 2347), |
98 | WCN36XX_CFG_VAL(SHORT_RETRY_LIMIT, 15), |
99 | WCN36XX_CFG_VAL(LONG_RETRY_LIMIT, 15), |
100 | WCN36XX_CFG_VAL(FRAGMENTATION_THRESHOLD, 8000), |
101 | WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_ZERO, 5), |
102 | WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_ONE, 10), |
103 | WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_TWO, 15), |
104 | WCN36XX_CFG_VAL(FIXED_RATE, 0), |
105 | WCN36XX_CFG_VAL(RETRYRATE_POLICY, 4), |
106 | WCN36XX_CFG_VAL(RETRYRATE_SECONDARY, 0), |
107 | WCN36XX_CFG_VAL(RETRYRATE_TERTIARY, 0), |
108 | WCN36XX_CFG_VAL(FORCE_POLICY_PROTECTION, 5), |
109 | WCN36XX_CFG_VAL(FIXED_RATE_MULTICAST_24GHZ, 1), |
110 | WCN36XX_CFG_VAL(FIXED_RATE_MULTICAST_5GHZ, 5), |
111 | WCN36XX_CFG_VAL(DEFAULT_RATE_INDEX_24GHZ, 1), |
112 | WCN36XX_CFG_VAL(DEFAULT_RATE_INDEX_5GHZ, 5), |
113 | WCN36XX_CFG_VAL(MAX_BA_SESSIONS, 40), |
114 | WCN36XX_CFG_VAL(PS_DATA_INACTIVITY_TIMEOUT, 200), |
115 | WCN36XX_CFG_VAL(PS_ENABLE_BCN_FILTER, 1), |
116 | WCN36XX_CFG_VAL(PS_ENABLE_RSSI_MONITOR, 1), |
117 | WCN36XX_CFG_VAL(NUM_BEACON_PER_RSSI_AVERAGE, 20), |
118 | WCN36XX_CFG_VAL(STATS_PERIOD, 10), |
119 | WCN36XX_CFG_VAL(CFP_MAX_DURATION, 30000), |
120 | WCN36XX_CFG_VAL(FRAME_TRANS_ENABLED, 0), |
121 | WCN36XX_CFG_VAL(BA_THRESHOLD_HIGH, 128), |
122 | WCN36XX_CFG_VAL(MAX_BA_BUFFERS, 2560), |
123 | WCN36XX_CFG_VAL(DYNAMIC_PS_POLL_VALUE, 0), |
124 | WCN36XX_CFG_VAL(TX_PWR_CTRL_ENABLE, 1), |
125 | WCN36XX_CFG_VAL(ENABLE_CLOSE_LOOP, 1), |
126 | WCN36XX_CFG_VAL(ENABLE_LPWR_IMG_TRANSITION, 0), |
127 | WCN36XX_CFG_VAL(BTC_STATIC_LEN_LE_BT, 120000), |
128 | WCN36XX_CFG_VAL(BTC_STATIC_LEN_LE_WLAN, 30000), |
129 | WCN36XX_CFG_VAL(MAX_ASSOC_LIMIT, 10), |
130 | WCN36XX_CFG_VAL(ENABLE_MCC_ADAPTIVE_SCHEDULER, 0), |
131 | WCN36XX_CFG_VAL(TDLS_PUAPSD_MASK, 0), |
132 | WCN36XX_CFG_VAL(TDLS_PUAPSD_BUFFER_STA_CAPABLE, 1), |
133 | WCN36XX_CFG_VAL(TDLS_PUAPSD_INACTIVITY_TIME, 0), |
134 | WCN36XX_CFG_VAL(TDLS_PUAPSD_RX_FRAME_THRESHOLD, 10), |
135 | WCN36XX_CFG_VAL(TDLS_OFF_CHANNEL_CAPABLE, 1), |
136 | WCN36XX_CFG_VAL(ENABLE_ADAPTIVE_RX_DRAIN, 1), |
137 | WCN36XX_CFG_VAL(FLEXCONNECT_POWER_FACTOR, 0), |
138 | WCN36XX_CFG_VAL(ANTENNA_DIVERSITY, 3), |
139 | WCN36XX_CFG_VAL(ATH_DISABLE, 0), |
140 | WCN36XX_CFG_VAL(BTC_STATIC_OPP_WLAN_ACTIVE_WLAN_LEN, 60000), |
141 | WCN36XX_CFG_VAL(BTC_STATIC_OPP_WLAN_ACTIVE_BT_LEN, 90000), |
142 | WCN36XX_CFG_VAL(BTC_SAP_STATIC_OPP_ACTIVE_WLAN_LEN, 30000), |
143 | WCN36XX_CFG_VAL(BTC_SAP_STATIC_OPP_ACTIVE_BT_LEN, 30000), |
144 | WCN36XX_CFG_VAL(ASD_PROBE_INTERVAL, 50), |
145 | WCN36XX_CFG_VAL(ASD_TRIGGER_THRESHOLD, -60), |
146 | WCN36XX_CFG_VAL(ASD_RTT_RSSI_HYST_THRESHOLD, 3), |
147 | WCN36XX_CFG_VAL(BTC_CTS2S_ON_STA_DURING_SCO, 0), |
148 | WCN36XX_CFG_VAL(RA_FILTER_ENABLE, 0), |
149 | WCN36XX_CFG_VAL(RA_RATE_LIMIT_INTERVAL, 60), |
150 | WCN36XX_CFG_VAL(BTC_FATAL_HID_NSNIFF_BLK, 2), |
151 | WCN36XX_CFG_VAL(BTC_CRITICAL_HID_NSNIFF_BLK, 1), |
152 | WCN36XX_CFG_VAL(BTC_DYN_A2DP_TX_QUEUE_THOLD, 0), |
153 | WCN36XX_CFG_VAL(BTC_DYN_OPP_TX_QUEUE_THOLD, 1), |
154 | WCN36XX_CFG_VAL(MAX_UAPSD_CONSEC_SP, 10), |
155 | WCN36XX_CFG_VAL(MAX_UAPSD_CONSEC_RX_CNT, 50), |
156 | WCN36XX_CFG_VAL(MAX_UAPSD_CONSEC_TX_CNT, 50), |
157 | WCN36XX_CFG_VAL(MAX_UAPSD_CONSEC_TX_CNT_MEAS_WINDOW, 500), |
158 | WCN36XX_CFG_VAL(MAX_UAPSD_CONSEC_RX_CNT_MEAS_WINDOW, 500), |
159 | WCN36XX_CFG_VAL(MAX_PSPOLL_IN_WMM_UAPSD_PS_MODE, 0), |
160 | WCN36XX_CFG_VAL(MAX_UAPSD_INACTIVITY_INTERVALS, 10), |
161 | WCN36XX_CFG_VAL(ENABLE_DYNAMIC_WMMPS, 1), |
162 | WCN36XX_CFG_VAL(BURST_MODE_BE_TXOP_VALUE, 0), |
163 | WCN36XX_CFG_VAL(ENABLE_DYNAMIC_RA_START_RATE, 136), |
164 | WCN36XX_CFG_VAL(BTC_FAST_WLAN_CONN_PREF, 1), |
165 | WCN36XX_CFG_VAL(ENABLE_RTSCTS_HTVHT, 0), |
166 | WCN36XX_CFG_VAL(BTC_STATIC_OPP_WLAN_IDLE_WLAN_LEN, 30000), |
167 | WCN36XX_CFG_VAL(BTC_STATIC_OPP_WLAN_IDLE_BT_LEN, 120000), |
168 | WCN36XX_CFG_VAL(LINK_FAIL_TX_CNT, 1000), |
169 | WCN36XX_CFG_VAL(TOGGLE_ARP_BDRATES, 0), |
170 | WCN36XX_CFG_VAL(OPTIMIZE_CA_EVENT, 0), |
171 | WCN36XX_CFG_VAL(EXT_SCAN_CONC_MODE, 0), |
172 | WCN36XX_CFG_VAL(BAR_WAKEUP_HOST_DISABLE, 0), |
173 | WCN36XX_CFG_VAL(SAR_BOFFSET_CORRECTION_ENABLE, 0), |
174 | WCN36XX_CFG_VAL(BTC_DISABLE_WLAN_LINK_CRITICAL, 5), |
175 | WCN36XX_CFG_VAL(DISABLE_SCAN_DURING_SCO, 2), |
176 | WCN36XX_CFG_VAL(CONS_BCNMISS_COUNT, 0), |
177 | WCN36XX_CFG_VAL(UNITS_OF_BCN_WAIT_TIME, 0), |
178 | WCN36XX_CFG_VAL(TRIGGER_NULLFRAME_BEFORE_HB, 0), |
179 | WCN36XX_CFG_VAL(ENABLE_POWERSAVE_OFFLOAD, 0), |
180 | }; |
181 | |
182 | static int put_cfg_tlv_u32(struct wcn36xx *wcn, size_t *len, u32 id, u32 value) |
183 | { |
184 | struct wcn36xx_hal_cfg *entry; |
185 | u32 *val; |
186 | |
187 | if (*len + sizeof(*entry) + sizeof(u32) >= WCN36XX_HAL_BUF_SIZE) { |
188 | wcn36xx_err("Not enough room for TLV entry\n" ); |
189 | return -ENOMEM; |
190 | } |
191 | |
192 | entry = (struct wcn36xx_hal_cfg *) (wcn->hal_buf + *len); |
193 | entry->id = id; |
194 | entry->len = sizeof(u32); |
195 | entry->pad_bytes = 0; |
196 | entry->reserve = 0; |
197 | |
198 | val = (u32 *) (entry + 1); |
199 | *val = value; |
200 | |
201 | *len += sizeof(*entry) + sizeof(u32); |
202 | |
203 | return 0; |
204 | } |
205 | |
206 | static void wcn36xx_smd_set_bss_nw_type(struct wcn36xx *wcn, |
207 | struct ieee80211_sta *sta, |
208 | struct wcn36xx_hal_config_bss_params *bss_params) |
209 | { |
210 | if (NL80211_BAND_5GHZ == WCN36XX_BAND(wcn)) |
211 | bss_params->nw_type = WCN36XX_HAL_11A_NW_TYPE; |
212 | else if (sta && sta->deflink.ht_cap.ht_supported) |
213 | bss_params->nw_type = WCN36XX_HAL_11N_NW_TYPE; |
214 | else if (sta && (sta->deflink.supp_rates[NL80211_BAND_2GHZ] & 0x7f)) |
215 | bss_params->nw_type = WCN36XX_HAL_11G_NW_TYPE; |
216 | else |
217 | bss_params->nw_type = WCN36XX_HAL_11B_NW_TYPE; |
218 | } |
219 | |
220 | static inline u8 is_cap_supported(unsigned long caps, unsigned long flag) |
221 | { |
222 | return caps & flag ? 1 : 0; |
223 | } |
224 | |
225 | static void wcn36xx_smd_set_bss_ht_params(struct ieee80211_vif *vif, |
226 | struct ieee80211_sta *sta, |
227 | struct wcn36xx_hal_config_bss_params *bss_params) |
228 | { |
229 | if (sta && sta->deflink.ht_cap.ht_supported) { |
230 | unsigned long caps = sta->deflink.ht_cap.cap; |
231 | |
232 | bss_params->ht = sta->deflink.ht_cap.ht_supported; |
233 | bss_params->tx_channel_width_set = is_cap_supported(caps, |
234 | IEEE80211_HT_CAP_SUP_WIDTH_20_40); |
235 | bss_params->lsig_tx_op_protection_full_support = |
236 | is_cap_supported(caps, |
237 | IEEE80211_HT_CAP_LSIG_TXOP_PROT); |
238 | |
239 | bss_params->ht_oper_mode = vif->bss_conf.ht_operation_mode; |
240 | bss_params->lln_non_gf_coexist = |
241 | !!(vif->bss_conf.ht_operation_mode & |
242 | IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); |
243 | /* IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT */ |
244 | bss_params->dual_cts_protection = 0; |
245 | /* IEEE80211_HT_OP_MODE_PROTECTION_20MHZ */ |
246 | bss_params->ht20_coexist = 0; |
247 | } |
248 | } |
249 | |
250 | static void |
251 | wcn36xx_smd_set_bss_vht_params(struct ieee80211_vif *vif, |
252 | struct ieee80211_sta *sta, |
253 | struct wcn36xx_hal_config_bss_params_v1 *bss) |
254 | { |
255 | if (sta && sta->deflink.vht_cap.vht_supported) |
256 | bss->vht_capable = 1; |
257 | } |
258 | |
259 | static void wcn36xx_smd_set_sta_ht_params(struct ieee80211_sta *sta, |
260 | struct wcn36xx_hal_config_sta_params *sta_params) |
261 | { |
262 | if (sta->deflink.ht_cap.ht_supported) { |
263 | unsigned long caps = sta->deflink.ht_cap.cap; |
264 | |
265 | sta_params->ht_capable = sta->deflink.ht_cap.ht_supported; |
266 | sta_params->tx_channel_width_set = is_cap_supported(caps, |
267 | IEEE80211_HT_CAP_SUP_WIDTH_20_40); |
268 | sta_params->lsig_txop_protection = is_cap_supported(caps, |
269 | IEEE80211_HT_CAP_LSIG_TXOP_PROT); |
270 | |
271 | sta_params->max_ampdu_size = sta->deflink.ht_cap.ampdu_factor; |
272 | sta_params->max_ampdu_density = sta->deflink.ht_cap.ampdu_density; |
273 | /* max_amsdu_size: 1 : 3839 bytes, 0 : 7935 bytes (max) */ |
274 | sta_params->max_amsdu_size = !is_cap_supported(caps, |
275 | IEEE80211_HT_CAP_MAX_AMSDU); |
276 | sta_params->sgi_20Mhz = is_cap_supported(caps, |
277 | IEEE80211_HT_CAP_SGI_20); |
278 | sta_params->sgi_40mhz = is_cap_supported(caps, |
279 | IEEE80211_HT_CAP_SGI_40); |
280 | sta_params->green_field_capable = is_cap_supported(caps, |
281 | IEEE80211_HT_CAP_GRN_FLD); |
282 | sta_params->delayed_ba_support = is_cap_supported(caps, |
283 | IEEE80211_HT_CAP_DELAY_BA); |
284 | sta_params->dsss_cck_mode_40mhz = is_cap_supported(caps, |
285 | IEEE80211_HT_CAP_DSSSCCK40); |
286 | } |
287 | } |
288 | |
289 | static void wcn36xx_smd_set_sta_vht_params(struct wcn36xx *wcn, |
290 | struct ieee80211_sta *sta, |
291 | struct wcn36xx_hal_config_sta_params_v1 *sta_params) |
292 | { |
293 | if (sta->deflink.vht_cap.vht_supported) { |
294 | unsigned long caps = sta->deflink.vht_cap.cap; |
295 | |
296 | sta_params->vht_capable = sta->deflink.vht_cap.vht_supported; |
297 | sta_params->vht_ldpc_enabled = |
298 | is_cap_supported(caps, IEEE80211_VHT_CAP_RXLDPC); |
299 | if (wcn36xx_firmware_get_feat_caps(bitmap: wcn->fw_feat_caps, cap: MU_MIMO)) { |
300 | sta_params->vht_tx_mu_beamformee_capable = |
301 | is_cap_supported(caps, IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE); |
302 | if (sta_params->vht_tx_mu_beamformee_capable) |
303 | sta_params->vht_tx_bf_enabled = 1; |
304 | } else { |
305 | sta_params->vht_tx_mu_beamformee_capable = 0; |
306 | } |
307 | sta_params->vht_tx_channel_width_set = 0; |
308 | } |
309 | } |
310 | |
311 | static void wcn36xx_smd_set_sta_ht_ldpc_params(struct ieee80211_sta *sta, |
312 | struct wcn36xx_hal_config_sta_params_v1 *sta_params) |
313 | { |
314 | if (sta->deflink.ht_cap.ht_supported) { |
315 | sta_params->ht_ldpc_enabled = |
316 | is_cap_supported(caps: sta->deflink.ht_cap.cap, |
317 | IEEE80211_HT_CAP_LDPC_CODING); |
318 | } |
319 | } |
320 | |
321 | static void wcn36xx_smd_set_sta_default_ht_params( |
322 | struct wcn36xx_hal_config_sta_params *sta_params) |
323 | { |
324 | sta_params->ht_capable = 1; |
325 | sta_params->tx_channel_width_set = 1; |
326 | sta_params->lsig_txop_protection = 1; |
327 | sta_params->max_ampdu_size = 3; |
328 | sta_params->max_ampdu_density = 5; |
329 | sta_params->max_amsdu_size = 0; |
330 | sta_params->sgi_20Mhz = 1; |
331 | sta_params->sgi_40mhz = 1; |
332 | sta_params->green_field_capable = 1; |
333 | sta_params->delayed_ba_support = 0; |
334 | sta_params->dsss_cck_mode_40mhz = 1; |
335 | } |
336 | |
337 | static void wcn36xx_smd_set_sta_default_vht_params(struct wcn36xx *wcn, |
338 | struct wcn36xx_hal_config_sta_params_v1 *sta_params) |
339 | { |
340 | if (wcn->rf_id == RF_IRIS_WCN3680) { |
341 | sta_params->vht_capable = 1; |
342 | sta_params->vht_tx_mu_beamformee_capable = 1; |
343 | } else { |
344 | sta_params->vht_capable = 0; |
345 | sta_params->vht_tx_mu_beamformee_capable = 0; |
346 | } |
347 | |
348 | sta_params->vht_ldpc_enabled = 0; |
349 | sta_params->vht_tx_channel_width_set = 0; |
350 | sta_params->vht_tx_bf_enabled = 0; |
351 | } |
352 | |
353 | static void wcn36xx_smd_set_sta_default_ht_ldpc_params(struct wcn36xx *wcn, |
354 | struct wcn36xx_hal_config_sta_params_v1 *sta_params) |
355 | { |
356 | if (wcn->rf_id == RF_IRIS_WCN3680) |
357 | sta_params->ht_ldpc_enabled = 1; |
358 | else |
359 | sta_params->ht_ldpc_enabled = 0; |
360 | } |
361 | |
362 | static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn, |
363 | struct ieee80211_vif *vif, |
364 | struct ieee80211_sta *sta, |
365 | struct wcn36xx_hal_config_sta_params *sta_params) |
366 | { |
367 | struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); |
368 | struct wcn36xx_sta *sta_priv = NULL; |
369 | if (vif->type == NL80211_IFTYPE_ADHOC || |
370 | vif->type == NL80211_IFTYPE_AP || |
371 | vif->type == NL80211_IFTYPE_MESH_POINT) { |
372 | sta_params->type = 1; |
373 | sta_params->sta_index = WCN36XX_HAL_STA_INVALID_IDX; |
374 | } else { |
375 | sta_params->type = 0; |
376 | sta_params->sta_index = vif_priv->self_sta_index; |
377 | } |
378 | |
379 | sta_params->listen_interval = WCN36XX_LISTEN_INTERVAL(wcn); |
380 | |
381 | /* |
382 | * In STA mode ieee80211_sta contains bssid and ieee80211_vif |
383 | * contains our mac address. In AP mode we are bssid so vif |
384 | * contains bssid and ieee80211_sta contains mac. |
385 | */ |
386 | if (NL80211_IFTYPE_STATION == vif->type) |
387 | memcpy(&sta_params->mac, vif->addr, ETH_ALEN); |
388 | else |
389 | memcpy(&sta_params->bssid, vif->addr, ETH_ALEN); |
390 | |
391 | sta_params->encrypt_type = vif_priv->encrypt_type; |
392 | sta_params->short_preamble_supported = true; |
393 | |
394 | sta_params->rifs_mode = 0; |
395 | sta_params->rmf = 0; |
396 | sta_params->action = 0; |
397 | sta_params->uapsd = 0; |
398 | sta_params->mimo_ps = WCN36XX_HAL_HT_MIMO_PS_STATIC; |
399 | sta_params->max_ampdu_duration = 0; |
400 | sta_params->bssid_index = vif_priv->bss_index; |
401 | sta_params->p2p = 0; |
402 | |
403 | if (sta) { |
404 | sta_priv = wcn36xx_sta_to_priv(sta); |
405 | if (NL80211_IFTYPE_STATION == vif->type) |
406 | memcpy(&sta_params->bssid, sta->addr, ETH_ALEN); |
407 | else |
408 | memcpy(&sta_params->mac, sta->addr, ETH_ALEN); |
409 | sta_params->wmm_enabled = sta->wme; |
410 | sta_params->max_sp_len = sta->max_sp; |
411 | sta_params->aid = sta_priv->aid; |
412 | wcn36xx_smd_set_sta_ht_params(sta, sta_params); |
413 | memcpy(&sta_params->supported_rates, &sta_priv->supported_rates, |
414 | sizeof(struct wcn36xx_hal_supported_rates)); |
415 | } else { |
416 | wcn36xx_set_default_rates(rates: (struct wcn36xx_hal_supported_rates *) |
417 | &sta_params->supported_rates); |
418 | wcn36xx_smd_set_sta_default_ht_params(sta_params); |
419 | } |
420 | } |
421 | |
422 | static int wcn36xx_smd_send_and_wait(struct wcn36xx *wcn, size_t len) |
423 | { |
424 | int ret; |
425 | unsigned long start; |
426 | struct wcn36xx_hal_msg_header *hdr = |
427 | (struct wcn36xx_hal_msg_header *)wcn->hal_buf; |
428 | u16 req_type = hdr->msg_type; |
429 | |
430 | wcn36xx_dbg_dump(WCN36XX_DBG_SMD_DUMP, "HAL >>> " , wcn->hal_buf, len); |
431 | |
432 | init_completion(x: &wcn->hal_rsp_compl); |
433 | start = jiffies; |
434 | ret = rpmsg_send(ept: wcn->smd_channel, data: wcn->hal_buf, len); |
435 | if (ret) { |
436 | wcn36xx_err("HAL TX failed for req %d\n" , req_type); |
437 | goto out; |
438 | } |
439 | if (wait_for_completion_timeout(x: &wcn->hal_rsp_compl, |
440 | timeout: msecs_to_jiffies(HAL_MSG_TIMEOUT)) <= 0) { |
441 | wcn36xx_err("Timeout! No SMD response to req %d in %dms\n" , |
442 | req_type, HAL_MSG_TIMEOUT); |
443 | ret = -ETIME; |
444 | goto out; |
445 | } |
446 | wcn36xx_dbg(WCN36XX_DBG_SMD, |
447 | "SMD command (req %d, rsp %d) completed in %dms\n" , |
448 | req_type, hdr->msg_type, |
449 | jiffies_to_msecs(jiffies - start)); |
450 | out: |
451 | return ret; |
452 | } |
453 | |
454 | #define __INIT_HAL_MSG(msg_body, type, version) \ |
455 | do { \ |
456 | memset(&(msg_body), 0, sizeof(msg_body)); \ |
457 | (msg_body).header.msg_type = type; \ |
458 | (msg_body).header.msg_version = version; \ |
459 | (msg_body).header.len = sizeof(msg_body); \ |
460 | } while (0) \ |
461 | |
462 | #define INIT_HAL_MSG(msg_body, type) \ |
463 | __INIT_HAL_MSG(msg_body, type, WCN36XX_HAL_MSG_VERSION0) |
464 | |
465 | #define INIT_HAL_MSG_V1(msg_body, type) \ |
466 | __INIT_HAL_MSG(msg_body, type, WCN36XX_HAL_MSG_VERSION1) |
467 | |
468 | #define INIT_HAL_PTT_MSG(p_msg_body, ppt_msg_len) \ |
469 | do { \ |
470 | memset(p_msg_body, 0, sizeof(*p_msg_body) + ppt_msg_len); \ |
471 | p_msg_body->header.msg_type = WCN36XX_HAL_PROCESS_PTT_REQ; \ |
472 | p_msg_body->header.msg_version = WCN36XX_HAL_MSG_VERSION0; \ |
473 | p_msg_body->header.len = sizeof(*p_msg_body) + ppt_msg_len; \ |
474 | } while (0) |
475 | |
476 | #define PREPARE_HAL_BUF(send_buf, msg_body) \ |
477 | do { \ |
478 | memcpy_and_pad(send_buf, msg_body.header.len, \ |
479 | &msg_body, sizeof(msg_body), 0); \ |
480 | } while (0) \ |
481 | |
482 | #define PREPARE_HAL_PTT_MSG_BUF(send_buf, p_msg_body) \ |
483 | do { \ |
484 | memcpy(send_buf, p_msg_body, p_msg_body->header.len); \ |
485 | } while (0) |
486 | |
487 | static int wcn36xx_smd_rsp_status_check(void *buf, size_t len) |
488 | { |
489 | struct wcn36xx_fw_msg_status_rsp *rsp; |
490 | |
491 | if (len < sizeof(struct wcn36xx_hal_msg_header) + |
492 | sizeof(struct wcn36xx_fw_msg_status_rsp)) |
493 | return -EIO; |
494 | |
495 | rsp = (struct wcn36xx_fw_msg_status_rsp *) |
496 | (buf + sizeof(struct wcn36xx_hal_msg_header)); |
497 | |
498 | if (WCN36XX_FW_MSG_RESULT_SUCCESS != rsp->status) |
499 | return rsp->status; |
500 | |
501 | return 0; |
502 | } |
503 | |
504 | int wcn36xx_smd_load_nv(struct wcn36xx *wcn) |
505 | { |
506 | struct nv_data *nv_d; |
507 | struct wcn36xx_hal_nv_img_download_req_msg msg_body; |
508 | int fw_bytes_left; |
509 | int ret; |
510 | u16 fm_offset = 0; |
511 | |
512 | if (!wcn->nv) { |
513 | ret = request_firmware(fw: &wcn->nv, name: wcn->nv_file, device: wcn->dev); |
514 | if (ret) { |
515 | wcn36xx_err("Failed to load nv file %s: %d\n" , |
516 | wcn->nv_file, ret); |
517 | goto out; |
518 | } |
519 | } |
520 | |
521 | nv_d = (struct nv_data *)wcn->nv->data; |
522 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_DOWNLOAD_NV_REQ); |
523 | |
524 | msg_body.header.len += WCN36XX_NV_FRAGMENT_SIZE; |
525 | |
526 | msg_body.frag_number = 0; |
527 | /* hal_buf must be protected with mutex */ |
528 | mutex_lock(&wcn->hal_mutex); |
529 | |
530 | do { |
531 | fw_bytes_left = wcn->nv->size - fm_offset - 4; |
532 | if (fw_bytes_left > WCN36XX_NV_FRAGMENT_SIZE) { |
533 | msg_body.last_fragment = 0; |
534 | msg_body.nv_img_buffer_size = WCN36XX_NV_FRAGMENT_SIZE; |
535 | } else { |
536 | msg_body.last_fragment = 1; |
537 | msg_body.nv_img_buffer_size = fw_bytes_left; |
538 | |
539 | /* Do not forget update general message len */ |
540 | msg_body.header.len = sizeof(msg_body) + fw_bytes_left; |
541 | |
542 | } |
543 | |
544 | /* Add load NV request message header */ |
545 | memcpy(wcn->hal_buf, &msg_body, sizeof(msg_body)); |
546 | |
547 | /* Add NV body itself */ |
548 | memcpy(wcn->hal_buf + sizeof(msg_body), |
549 | &nv_d->table + fm_offset, |
550 | msg_body.nv_img_buffer_size); |
551 | |
552 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
553 | if (ret) |
554 | goto out_unlock; |
555 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, |
556 | len: wcn->hal_rsp_len); |
557 | if (ret) { |
558 | wcn36xx_err("hal_load_nv response failed err=%d\n" , |
559 | ret); |
560 | goto out_unlock; |
561 | } |
562 | msg_body.frag_number++; |
563 | fm_offset += WCN36XX_NV_FRAGMENT_SIZE; |
564 | |
565 | } while (msg_body.last_fragment != 1); |
566 | |
567 | out_unlock: |
568 | mutex_unlock(lock: &wcn->hal_mutex); |
569 | out: return ret; |
570 | } |
571 | |
572 | static int wcn36xx_smd_start_rsp(struct wcn36xx *wcn, void *buf, size_t len) |
573 | { |
574 | struct wcn36xx_hal_mac_start_rsp_msg *rsp; |
575 | |
576 | if (len < sizeof(*rsp)) |
577 | return -EIO; |
578 | |
579 | rsp = buf; |
580 | |
581 | if (WCN36XX_FW_MSG_RESULT_SUCCESS != rsp->start_rsp_params.status) |
582 | return -EIO; |
583 | |
584 | memcpy(wcn->crm_version, rsp->start_rsp_params.crm_version, |
585 | WCN36XX_HAL_VERSION_LENGTH); |
586 | memcpy(wcn->wlan_version, rsp->start_rsp_params.wlan_version, |
587 | WCN36XX_HAL_VERSION_LENGTH); |
588 | |
589 | /* null terminate the strings, just in case */ |
590 | wcn->crm_version[WCN36XX_HAL_VERSION_LENGTH] = '\0'; |
591 | wcn->wlan_version[WCN36XX_HAL_VERSION_LENGTH] = '\0'; |
592 | |
593 | wcn->fw_revision = rsp->start_rsp_params.version.revision; |
594 | wcn->fw_version = rsp->start_rsp_params.version.version; |
595 | wcn->fw_minor = rsp->start_rsp_params.version.minor; |
596 | wcn->fw_major = rsp->start_rsp_params.version.major; |
597 | |
598 | if (wcn->first_boot) { |
599 | wcn->first_boot = false; |
600 | wcn36xx_info("firmware WLAN version '%s' and CRM version '%s'\n" , |
601 | wcn->wlan_version, wcn->crm_version); |
602 | |
603 | wcn36xx_info("firmware API %u.%u.%u.%u, %u stations, %u bssids\n" , |
604 | wcn->fw_major, wcn->fw_minor, |
605 | wcn->fw_version, wcn->fw_revision, |
606 | rsp->start_rsp_params.stations, |
607 | rsp->start_rsp_params.bssids); |
608 | } |
609 | return 0; |
610 | } |
611 | |
612 | int wcn36xx_smd_start(struct wcn36xx *wcn) |
613 | { |
614 | struct wcn36xx_hal_mac_start_req_msg msg_body, *body; |
615 | int ret; |
616 | int i; |
617 | size_t len; |
618 | int cfg_elements; |
619 | static struct wcn36xx_cfg_val *cfg_vals; |
620 | |
621 | mutex_lock(&wcn->hal_mutex); |
622 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_START_REQ); |
623 | |
624 | msg_body.params.type = DRIVER_TYPE_PRODUCTION; |
625 | msg_body.params.len = 0; |
626 | |
627 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
628 | |
629 | body = (struct wcn36xx_hal_mac_start_req_msg *)wcn->hal_buf; |
630 | len = body->header.len; |
631 | |
632 | if (wcn->rf_id == RF_IRIS_WCN3680) { |
633 | cfg_vals = wcn3680_cfg_vals; |
634 | cfg_elements = ARRAY_SIZE(wcn3680_cfg_vals); |
635 | } else { |
636 | cfg_vals = wcn36xx_cfg_vals; |
637 | cfg_elements = ARRAY_SIZE(wcn36xx_cfg_vals); |
638 | } |
639 | |
640 | for (i = 0; i < cfg_elements; i++) { |
641 | ret = put_cfg_tlv_u32(wcn, len: &len, id: cfg_vals[i].cfg_id, |
642 | value: cfg_vals[i].value); |
643 | if (ret) |
644 | goto out; |
645 | } |
646 | body->header.len = len; |
647 | body->params.len = len - sizeof(*body); |
648 | |
649 | wcn36xx_dbg(WCN36XX_DBG_HAL, "hal start type %d\n" , |
650 | msg_body.params.type); |
651 | |
652 | ret = wcn36xx_smd_send_and_wait(wcn, len: body->header.len); |
653 | if (ret) { |
654 | wcn36xx_err("Sending hal_start failed\n" ); |
655 | goto out; |
656 | } |
657 | |
658 | ret = wcn36xx_smd_start_rsp(wcn, buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
659 | if (ret) { |
660 | wcn36xx_err("hal_start response failed err=%d\n" , ret); |
661 | goto out; |
662 | } |
663 | |
664 | out: |
665 | mutex_unlock(lock: &wcn->hal_mutex); |
666 | return ret; |
667 | } |
668 | |
669 | int wcn36xx_smd_stop(struct wcn36xx *wcn) |
670 | { |
671 | struct wcn36xx_hal_mac_stop_req_msg msg_body; |
672 | int ret; |
673 | |
674 | mutex_lock(&wcn->hal_mutex); |
675 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_STOP_REQ); |
676 | |
677 | msg_body.stop_req_params.reason = HAL_STOP_TYPE_RF_KILL; |
678 | |
679 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
680 | |
681 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
682 | if (ret) { |
683 | wcn36xx_err("Sending hal_stop failed\n" ); |
684 | goto out; |
685 | } |
686 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
687 | if (ret) { |
688 | wcn36xx_err("hal_stop response failed err=%d\n" , ret); |
689 | goto out; |
690 | } |
691 | out: |
692 | mutex_unlock(lock: &wcn->hal_mutex); |
693 | return ret; |
694 | } |
695 | |
696 | int wcn36xx_smd_init_scan(struct wcn36xx *wcn, enum wcn36xx_hal_sys_mode mode, |
697 | struct ieee80211_vif *vif) |
698 | { |
699 | struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); |
700 | struct wcn36xx_hal_init_scan_req_msg msg_body; |
701 | int ret; |
702 | |
703 | mutex_lock(&wcn->hal_mutex); |
704 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_INIT_SCAN_REQ); |
705 | |
706 | msg_body.mode = mode; |
707 | if (vif_priv->bss_index != WCN36XX_HAL_BSS_INVALID_IDX) { |
708 | /* Notify BSSID with null DATA packet */ |
709 | msg_body.frame_type = 2; |
710 | msg_body.notify = 1; |
711 | msg_body.scan_entry.bss_index[0] = vif_priv->bss_index; |
712 | msg_body.scan_entry.active_bss_count = 1; |
713 | } |
714 | |
715 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
716 | |
717 | wcn36xx_dbg(WCN36XX_DBG_HAL, "hal init scan mode %d\n" , msg_body.mode); |
718 | |
719 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
720 | if (ret) { |
721 | wcn36xx_err("Sending hal_init_scan failed\n" ); |
722 | goto out; |
723 | } |
724 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
725 | if (ret) { |
726 | wcn36xx_err("hal_init_scan response failed err=%d\n" , ret); |
727 | goto out; |
728 | } |
729 | wcn->sw_scan_init = true; |
730 | out: |
731 | mutex_unlock(lock: &wcn->hal_mutex); |
732 | return ret; |
733 | } |
734 | |
735 | int wcn36xx_smd_start_scan(struct wcn36xx *wcn, u8 scan_channel) |
736 | { |
737 | struct wcn36xx_hal_start_scan_req_msg msg_body; |
738 | int ret; |
739 | |
740 | mutex_lock(&wcn->hal_mutex); |
741 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_START_SCAN_REQ); |
742 | |
743 | msg_body.scan_channel = scan_channel; |
744 | |
745 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
746 | |
747 | wcn36xx_dbg(WCN36XX_DBG_HAL, "hal start scan channel %d\n" , |
748 | msg_body.scan_channel); |
749 | |
750 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
751 | if (ret) { |
752 | wcn36xx_err("Sending hal_start_scan failed\n" ); |
753 | goto out; |
754 | } |
755 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
756 | if (ret) { |
757 | wcn36xx_err("hal_start_scan response failed err=%d\n" , ret); |
758 | goto out; |
759 | } |
760 | wcn->sw_scan_channel = scan_channel; |
761 | out: |
762 | mutex_unlock(lock: &wcn->hal_mutex); |
763 | return ret; |
764 | } |
765 | |
766 | int wcn36xx_smd_end_scan(struct wcn36xx *wcn, u8 scan_channel) |
767 | { |
768 | struct wcn36xx_hal_end_scan_req_msg msg_body; |
769 | int ret; |
770 | |
771 | mutex_lock(&wcn->hal_mutex); |
772 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_END_SCAN_REQ); |
773 | |
774 | msg_body.scan_channel = scan_channel; |
775 | |
776 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
777 | |
778 | wcn36xx_dbg(WCN36XX_DBG_HAL, "hal end scan channel %d\n" , |
779 | msg_body.scan_channel); |
780 | |
781 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
782 | if (ret) { |
783 | wcn36xx_err("Sending hal_end_scan failed\n" ); |
784 | goto out; |
785 | } |
786 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
787 | if (ret) { |
788 | wcn36xx_err("hal_end_scan response failed err=%d\n" , ret); |
789 | goto out; |
790 | } |
791 | wcn->sw_scan_channel = 0; |
792 | out: |
793 | mutex_unlock(lock: &wcn->hal_mutex); |
794 | return ret; |
795 | } |
796 | |
797 | int wcn36xx_smd_finish_scan(struct wcn36xx *wcn, |
798 | enum wcn36xx_hal_sys_mode mode, |
799 | struct ieee80211_vif *vif) |
800 | { |
801 | struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); |
802 | struct wcn36xx_hal_finish_scan_req_msg msg_body; |
803 | int ret; |
804 | |
805 | mutex_lock(&wcn->hal_mutex); |
806 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_FINISH_SCAN_REQ); |
807 | |
808 | msg_body.mode = mode; |
809 | msg_body.oper_channel = WCN36XX_HW_CHANNEL(wcn); |
810 | if (vif_priv->bss_index != WCN36XX_HAL_BSS_INVALID_IDX) { |
811 | /* Notify BSSID with null data packet */ |
812 | msg_body.notify = 1; |
813 | msg_body.frame_type = 2; |
814 | msg_body.scan_entry.bss_index[0] = vif_priv->bss_index; |
815 | msg_body.scan_entry.active_bss_count = 1; |
816 | } |
817 | |
818 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
819 | |
820 | wcn36xx_dbg(WCN36XX_DBG_HAL, "hal finish scan mode %d\n" , |
821 | msg_body.mode); |
822 | |
823 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
824 | if (ret) { |
825 | wcn36xx_err("Sending hal_finish_scan failed\n" ); |
826 | goto out; |
827 | } |
828 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
829 | if (ret) { |
830 | wcn36xx_err("hal_finish_scan response failed err=%d\n" , ret); |
831 | goto out; |
832 | } |
833 | wcn->sw_scan_init = false; |
834 | out: |
835 | mutex_unlock(lock: &wcn->hal_mutex); |
836 | return ret; |
837 | } |
838 | |
839 | int wcn36xx_smd_start_hw_scan(struct wcn36xx *wcn, struct ieee80211_vif *vif, |
840 | struct cfg80211_scan_request *req) |
841 | { |
842 | struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); |
843 | struct wcn36xx_hal_start_scan_offload_req_msg *msg_body; |
844 | int ret, i; |
845 | |
846 | if (req->ie_len > WCN36XX_MAX_SCAN_IE_LEN) |
847 | return -EINVAL; |
848 | |
849 | mutex_lock(&wcn->hal_mutex); |
850 | msg_body = kzalloc(size: sizeof(*msg_body), GFP_KERNEL); |
851 | if (!msg_body) { |
852 | ret = -ENOMEM; |
853 | goto out; |
854 | } |
855 | |
856 | INIT_HAL_MSG((*msg_body), WCN36XX_HAL_START_SCAN_OFFLOAD_REQ); |
857 | |
858 | msg_body->scan_type = WCN36XX_HAL_SCAN_TYPE_ACTIVE; |
859 | msg_body->min_ch_time = 30; |
860 | msg_body->max_ch_time = 100; |
861 | msg_body->scan_hidden = 1; |
862 | memcpy(msg_body->mac, vif->addr, ETH_ALEN); |
863 | msg_body->bss_type = vif_priv->bss_type; |
864 | msg_body->p2p_search = vif->p2p; |
865 | |
866 | msg_body->num_ssid = min_t(u8, req->n_ssids, ARRAY_SIZE(msg_body->ssids)); |
867 | for (i = 0; i < msg_body->num_ssid; i++) { |
868 | msg_body->ssids[i].length = min_t(u8, req->ssids[i].ssid_len, |
869 | sizeof(msg_body->ssids[i].ssid)); |
870 | memcpy(msg_body->ssids[i].ssid, req->ssids[i].ssid, |
871 | msg_body->ssids[i].length); |
872 | } |
873 | |
874 | msg_body->num_channel = min_t(u8, req->n_channels, |
875 | sizeof(msg_body->channels)); |
876 | for (i = 0; i < msg_body->num_channel; i++) { |
877 | msg_body->channels[i] = |
878 | HW_VALUE_CHANNEL(req->channels[i]->hw_value); |
879 | } |
880 | |
881 | msg_body->header.len -= WCN36XX_MAX_SCAN_IE_LEN; |
882 | |
883 | if (req->ie_len > 0) { |
884 | msg_body->ie_len = req->ie_len; |
885 | msg_body->header.len += req->ie_len; |
886 | memcpy(msg_body->ie, req->ie, req->ie_len); |
887 | } |
888 | |
889 | PREPARE_HAL_BUF(wcn->hal_buf, (*msg_body)); |
890 | |
891 | wcn36xx_dbg(WCN36XX_DBG_HAL, |
892 | "hal start hw-scan (channels: %u; ssids: %u; p2p: %s)\n" , |
893 | msg_body->num_channel, msg_body->num_ssid, |
894 | msg_body->p2p_search ? "yes" : "no" ); |
895 | |
896 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body->header.len); |
897 | if (ret) { |
898 | wcn36xx_err("Sending hal_start_scan_offload failed\n" ); |
899 | goto out; |
900 | } |
901 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
902 | if (ret) { |
903 | wcn36xx_err("hal_start_scan_offload response failed err=%d\n" , |
904 | ret); |
905 | goto out; |
906 | } |
907 | out: |
908 | kfree(objp: msg_body); |
909 | mutex_unlock(lock: &wcn->hal_mutex); |
910 | return ret; |
911 | } |
912 | |
913 | int wcn36xx_smd_stop_hw_scan(struct wcn36xx *wcn) |
914 | { |
915 | struct wcn36xx_hal_stop_scan_offload_req_msg msg_body; |
916 | int ret; |
917 | |
918 | mutex_lock(&wcn->hal_mutex); |
919 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_STOP_SCAN_OFFLOAD_REQ); |
920 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
921 | |
922 | wcn36xx_dbg(WCN36XX_DBG_HAL, "hal stop hw-scan\n" ); |
923 | |
924 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
925 | if (ret) { |
926 | wcn36xx_err("Sending hal_stop_scan_offload failed\n" ); |
927 | goto out; |
928 | } |
929 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
930 | if (ret) { |
931 | wcn36xx_err("hal_stop_scan_offload response failed err=%d\n" , |
932 | ret); |
933 | goto out; |
934 | } |
935 | out: |
936 | mutex_unlock(lock: &wcn->hal_mutex); |
937 | return ret; |
938 | } |
939 | |
940 | int wcn36xx_smd_update_channel_list(struct wcn36xx *wcn, struct cfg80211_scan_request *req) |
941 | { |
942 | struct wcn36xx_hal_update_channel_list_req_msg *msg_body; |
943 | int ret, i; |
944 | |
945 | msg_body = kzalloc(size: sizeof(*msg_body), GFP_KERNEL); |
946 | if (!msg_body) |
947 | return -ENOMEM; |
948 | |
949 | INIT_HAL_MSG((*msg_body), WCN36XX_HAL_UPDATE_CHANNEL_LIST_REQ); |
950 | |
951 | msg_body->num_channel = min_t(u8, req->n_channels, ARRAY_SIZE(msg_body->channels)); |
952 | for (i = 0; i < msg_body->num_channel; i++) { |
953 | struct wcn36xx_hal_channel_param *param = &msg_body->channels[i]; |
954 | u32 min_power = WCN36XX_HAL_DEFAULT_MIN_POWER; |
955 | u32 ant_gain = WCN36XX_HAL_DEFAULT_ANT_GAIN; |
956 | |
957 | param->mhz = req->channels[i]->center_freq; |
958 | param->band_center_freq1 = req->channels[i]->center_freq; |
959 | param->band_center_freq2 = 0; |
960 | |
961 | if (req->channels[i]->flags & IEEE80211_CHAN_NO_IR) |
962 | param->channel_info |= WCN36XX_HAL_CHAN_INFO_FLAG_PASSIVE; |
963 | |
964 | if (req->channels[i]->flags & IEEE80211_CHAN_RADAR) |
965 | param->channel_info |= WCN36XX_HAL_CHAN_INFO_FLAG_DFS; |
966 | |
967 | if (req->channels[i]->band == NL80211_BAND_5GHZ) { |
968 | param->channel_info |= WCN36XX_HAL_CHAN_INFO_FLAG_HT; |
969 | param->channel_info |= WCN36XX_HAL_CHAN_INFO_FLAG_VHT; |
970 | param->channel_info |= WCN36XX_HAL_CHAN_INFO_PHY_11A; |
971 | } else { |
972 | param->channel_info |= WCN36XX_HAL_CHAN_INFO_PHY_11BG; |
973 | } |
974 | |
975 | if (min_power > req->channels[i]->max_power) |
976 | min_power = req->channels[i]->max_power; |
977 | |
978 | if (req->channels[i]->max_antenna_gain) |
979 | ant_gain = req->channels[i]->max_antenna_gain; |
980 | |
981 | u32p_replace_bits(p: ¶m->reg_info_1, val: min_power, |
982 | WCN36XX_HAL_CHAN_REG1_MIN_PWR_MASK); |
983 | u32p_replace_bits(p: ¶m->reg_info_1, val: req->channels[i]->max_power, |
984 | WCN36XX_HAL_CHAN_REG1_MAX_PWR_MASK); |
985 | u32p_replace_bits(p: ¶m->reg_info_1, val: req->channels[i]->max_reg_power, |
986 | WCN36XX_HAL_CHAN_REG1_REG_PWR_MASK); |
987 | u32p_replace_bits(p: ¶m->reg_info_1, val: 0, |
988 | WCN36XX_HAL_CHAN_REG1_CLASS_ID_MASK); |
989 | u32p_replace_bits(p: ¶m->reg_info_2, val: ant_gain, |
990 | WCN36XX_HAL_CHAN_REG2_ANT_GAIN_MASK); |
991 | |
992 | wcn36xx_dbg(WCN36XX_DBG_HAL, |
993 | "%s: freq=%u, channel_info=%08x, reg_info1=%08x, reg_info2=%08x\n" , |
994 | __func__, param->mhz, param->channel_info, param->reg_info_1, |
995 | param->reg_info_2); |
996 | } |
997 | |
998 | mutex_lock(&wcn->hal_mutex); |
999 | |
1000 | PREPARE_HAL_BUF(wcn->hal_buf, (*msg_body)); |
1001 | |
1002 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body->header.len); |
1003 | if (ret) { |
1004 | wcn36xx_err("Sending hal_update_channel_list failed\n" ); |
1005 | goto out; |
1006 | } |
1007 | |
1008 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
1009 | if (ret) { |
1010 | wcn36xx_err("hal_update_channel_list response failed err=%d\n" , ret); |
1011 | goto out; |
1012 | } |
1013 | |
1014 | out: |
1015 | kfree(objp: msg_body); |
1016 | mutex_unlock(lock: &wcn->hal_mutex); |
1017 | return ret; |
1018 | } |
1019 | |
1020 | static int wcn36xx_smd_switch_channel_rsp(void *buf, size_t len) |
1021 | { |
1022 | struct wcn36xx_hal_switch_channel_rsp_msg *rsp; |
1023 | int ret; |
1024 | |
1025 | ret = wcn36xx_smd_rsp_status_check(buf, len); |
1026 | if (ret) |
1027 | return ret; |
1028 | rsp = buf; |
1029 | wcn36xx_dbg(WCN36XX_DBG_HAL, "channel switched to: %d, status: %d\n" , |
1030 | rsp->channel_number, rsp->status); |
1031 | return ret; |
1032 | } |
1033 | |
1034 | int wcn36xx_smd_switch_channel(struct wcn36xx *wcn, |
1035 | struct ieee80211_vif *vif, int ch) |
1036 | { |
1037 | struct wcn36xx_hal_switch_channel_req_msg msg_body; |
1038 | int ret; |
1039 | |
1040 | mutex_lock(&wcn->hal_mutex); |
1041 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_CH_SWITCH_REQ); |
1042 | |
1043 | msg_body.channel_number = (u8)ch; |
1044 | msg_body.tx_mgmt_power = 0xbf; |
1045 | msg_body.max_tx_power = 0xbf; |
1046 | memcpy(msg_body.self_sta_mac_addr, vif->addr, ETH_ALEN); |
1047 | |
1048 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
1049 | |
1050 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
1051 | if (ret) { |
1052 | wcn36xx_err("Sending hal_switch_channel failed\n" ); |
1053 | goto out; |
1054 | } |
1055 | ret = wcn36xx_smd_switch_channel_rsp(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
1056 | if (ret) { |
1057 | wcn36xx_err("hal_switch_channel response failed err=%d\n" , ret); |
1058 | goto out; |
1059 | } |
1060 | out: |
1061 | mutex_unlock(lock: &wcn->hal_mutex); |
1062 | return ret; |
1063 | } |
1064 | |
1065 | static int wcn36xx_smd_process_ptt_msg_rsp(void *buf, size_t len, |
1066 | void **p_ptt_rsp_msg) |
1067 | { |
1068 | struct wcn36xx_hal_process_ptt_msg_rsp_msg *rsp; |
1069 | int ret; |
1070 | |
1071 | ret = wcn36xx_smd_rsp_status_check(buf, len); |
1072 | if (ret) |
1073 | return ret; |
1074 | |
1075 | rsp = buf; |
1076 | |
1077 | wcn36xx_dbg(WCN36XX_DBG_HAL, "process ptt msg responded with length %d\n" , |
1078 | rsp->header.len); |
1079 | wcn36xx_dbg_dump(WCN36XX_DBG_HAL_DUMP, "HAL_PTT_MSG_RSP:" , rsp->ptt_msg, |
1080 | rsp->header.len - sizeof(rsp->ptt_msg_resp_status)); |
1081 | |
1082 | if (rsp->header.len > 0) { |
1083 | *p_ptt_rsp_msg = kmemdup(p: rsp->ptt_msg, size: rsp->header.len, |
1084 | GFP_ATOMIC); |
1085 | if (!*p_ptt_rsp_msg) |
1086 | return -ENOMEM; |
1087 | } |
1088 | return ret; |
1089 | } |
1090 | |
1091 | int wcn36xx_smd_process_ptt_msg(struct wcn36xx *wcn, |
1092 | struct ieee80211_vif *vif, void *ptt_msg, size_t len, |
1093 | void **ptt_rsp_msg) |
1094 | { |
1095 | struct wcn36xx_hal_process_ptt_msg_req_msg *p_msg_body; |
1096 | int ret; |
1097 | |
1098 | mutex_lock(&wcn->hal_mutex); |
1099 | p_msg_body = kmalloc( |
1100 | size: sizeof(struct wcn36xx_hal_process_ptt_msg_req_msg) + len, |
1101 | GFP_ATOMIC); |
1102 | if (!p_msg_body) { |
1103 | ret = -ENOMEM; |
1104 | goto out_nomem; |
1105 | } |
1106 | INIT_HAL_PTT_MSG(p_msg_body, len); |
1107 | |
1108 | memcpy(&p_msg_body->ptt_msg, ptt_msg, len); |
1109 | |
1110 | PREPARE_HAL_PTT_MSG_BUF(wcn->hal_buf, p_msg_body); |
1111 | |
1112 | ret = wcn36xx_smd_send_and_wait(wcn, len: p_msg_body->header.len); |
1113 | if (ret) { |
1114 | wcn36xx_err("Sending hal_process_ptt_msg failed\n" ); |
1115 | goto out; |
1116 | } |
1117 | ret = wcn36xx_smd_process_ptt_msg_rsp(buf: wcn->hal_buf, len: wcn->hal_rsp_len, |
1118 | p_ptt_rsp_msg: ptt_rsp_msg); |
1119 | if (ret) { |
1120 | wcn36xx_err("process_ptt_msg response failed err=%d\n" , ret); |
1121 | goto out; |
1122 | } |
1123 | out: |
1124 | kfree(objp: p_msg_body); |
1125 | out_nomem: |
1126 | mutex_unlock(lock: &wcn->hal_mutex); |
1127 | return ret; |
1128 | } |
1129 | |
1130 | static int wcn36xx_smd_update_scan_params_rsp(void *buf, size_t len) |
1131 | { |
1132 | struct wcn36xx_hal_update_scan_params_resp *rsp; |
1133 | |
1134 | rsp = buf; |
1135 | |
1136 | /* Remove the PNO version bit */ |
1137 | rsp->status &= (~(WCN36XX_FW_MSG_PNO_VERSION_MASK)); |
1138 | |
1139 | if (WCN36XX_FW_MSG_RESULT_SUCCESS != rsp->status) { |
1140 | wcn36xx_warn("error response from update scan\n" ); |
1141 | return rsp->status; |
1142 | } |
1143 | |
1144 | return 0; |
1145 | } |
1146 | |
1147 | int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn, |
1148 | u8 *channels, size_t channel_count) |
1149 | { |
1150 | struct wcn36xx_hal_update_scan_params_req_ex msg_body; |
1151 | int ret; |
1152 | |
1153 | mutex_lock(&wcn->hal_mutex); |
1154 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_UPDATE_SCAN_PARAM_REQ); |
1155 | |
1156 | msg_body.dot11d_enabled = false; |
1157 | msg_body.dot11d_resolved = true; |
1158 | |
1159 | msg_body.channel_count = channel_count; |
1160 | memcpy(msg_body.channels, channels, channel_count); |
1161 | msg_body.active_min_ch_time = 60; |
1162 | msg_body.active_max_ch_time = 120; |
1163 | msg_body.passive_min_ch_time = 60; |
1164 | msg_body.passive_max_ch_time = 110; |
1165 | msg_body.state = PHY_SINGLE_CHANNEL_CENTERED; |
1166 | |
1167 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
1168 | |
1169 | wcn36xx_dbg(WCN36XX_DBG_HAL, |
1170 | "hal update scan params channel_count %d\n" , |
1171 | msg_body.channel_count); |
1172 | |
1173 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
1174 | if (ret) { |
1175 | wcn36xx_err("Sending hal_update_scan_params failed\n" ); |
1176 | goto out; |
1177 | } |
1178 | ret = wcn36xx_smd_update_scan_params_rsp(buf: wcn->hal_buf, |
1179 | len: wcn->hal_rsp_len); |
1180 | if (ret) { |
1181 | wcn36xx_err("hal_update_scan_params response failed err=%d\n" , |
1182 | ret); |
1183 | goto out; |
1184 | } |
1185 | out: |
1186 | mutex_unlock(lock: &wcn->hal_mutex); |
1187 | return ret; |
1188 | } |
1189 | |
1190 | static int wcn36xx_smd_add_sta_self_rsp(struct wcn36xx *wcn, |
1191 | struct ieee80211_vif *vif, |
1192 | void *buf, |
1193 | size_t len) |
1194 | { |
1195 | struct wcn36xx_hal_add_sta_self_rsp_msg *rsp; |
1196 | struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); |
1197 | |
1198 | if (len < sizeof(*rsp)) |
1199 | return -EINVAL; |
1200 | |
1201 | rsp = buf; |
1202 | |
1203 | if (rsp->status != WCN36XX_FW_MSG_RESULT_SUCCESS) { |
1204 | wcn36xx_warn("hal add sta self failure: %d\n" , |
1205 | rsp->status); |
1206 | return rsp->status; |
1207 | } |
1208 | |
1209 | wcn36xx_dbg(WCN36XX_DBG_HAL, |
1210 | "hal add sta self status %d self_sta_index %d dpu_index %d\n" , |
1211 | rsp->status, rsp->self_sta_index, rsp->dpu_index); |
1212 | |
1213 | vif_priv->self_sta_index = rsp->self_sta_index; |
1214 | vif_priv->self_dpu_desc_index = rsp->dpu_index; |
1215 | |
1216 | return 0; |
1217 | } |
1218 | |
1219 | int wcn36xx_smd_add_sta_self(struct wcn36xx *wcn, struct ieee80211_vif *vif) |
1220 | { |
1221 | struct wcn36xx_hal_add_sta_self_req msg_body; |
1222 | int ret; |
1223 | |
1224 | mutex_lock(&wcn->hal_mutex); |
1225 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_ADD_STA_SELF_REQ); |
1226 | |
1227 | memcpy(&msg_body.self_addr, vif->addr, ETH_ALEN); |
1228 | |
1229 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
1230 | |
1231 | wcn36xx_dbg(WCN36XX_DBG_HAL, |
1232 | "hal add sta self self_addr %pM status %d\n" , |
1233 | msg_body.self_addr, msg_body.status); |
1234 | |
1235 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
1236 | if (ret) { |
1237 | wcn36xx_err("Sending hal_add_sta_self failed\n" ); |
1238 | goto out; |
1239 | } |
1240 | ret = wcn36xx_smd_add_sta_self_rsp(wcn, |
1241 | vif, |
1242 | buf: wcn->hal_buf, |
1243 | len: wcn->hal_rsp_len); |
1244 | if (ret) { |
1245 | wcn36xx_err("hal_add_sta_self response failed err=%d\n" , ret); |
1246 | goto out; |
1247 | } |
1248 | out: |
1249 | mutex_unlock(lock: &wcn->hal_mutex); |
1250 | return ret; |
1251 | } |
1252 | |
1253 | int wcn36xx_smd_delete_sta_self(struct wcn36xx *wcn, u8 *addr) |
1254 | { |
1255 | struct wcn36xx_hal_del_sta_self_req_msg msg_body; |
1256 | int ret; |
1257 | |
1258 | mutex_lock(&wcn->hal_mutex); |
1259 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_DEL_STA_SELF_REQ); |
1260 | |
1261 | memcpy(&msg_body.self_addr, addr, ETH_ALEN); |
1262 | |
1263 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
1264 | |
1265 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
1266 | if (ret) { |
1267 | wcn36xx_err("Sending hal_delete_sta_self failed\n" ); |
1268 | goto out; |
1269 | } |
1270 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
1271 | if (ret) { |
1272 | wcn36xx_err("hal_delete_sta_self response failed err=%d\n" , |
1273 | ret); |
1274 | goto out; |
1275 | } |
1276 | out: |
1277 | mutex_unlock(lock: &wcn->hal_mutex); |
1278 | return ret; |
1279 | } |
1280 | |
1281 | int wcn36xx_smd_delete_sta(struct wcn36xx *wcn, u8 sta_index) |
1282 | { |
1283 | struct wcn36xx_hal_delete_sta_req_msg msg_body; |
1284 | int ret; |
1285 | |
1286 | mutex_lock(&wcn->hal_mutex); |
1287 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_DELETE_STA_REQ); |
1288 | |
1289 | msg_body.sta_index = sta_index; |
1290 | |
1291 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
1292 | |
1293 | wcn36xx_dbg(WCN36XX_DBG_HAL, |
1294 | "hal delete sta sta_index %d\n" , |
1295 | msg_body.sta_index); |
1296 | |
1297 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
1298 | if (ret) { |
1299 | wcn36xx_err("Sending hal_delete_sta failed\n" ); |
1300 | goto out; |
1301 | } |
1302 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
1303 | if (ret) { |
1304 | wcn36xx_err("hal_delete_sta response failed err=%d\n" , ret); |
1305 | goto out; |
1306 | } |
1307 | out: |
1308 | mutex_unlock(lock: &wcn->hal_mutex); |
1309 | return ret; |
1310 | } |
1311 | |
1312 | static int wcn36xx_smd_join_rsp(void *buf, size_t len) |
1313 | { |
1314 | struct wcn36xx_hal_join_rsp_msg *rsp; |
1315 | |
1316 | if (wcn36xx_smd_rsp_status_check(buf, len)) |
1317 | return -EIO; |
1318 | |
1319 | rsp = buf; |
1320 | |
1321 | wcn36xx_dbg(WCN36XX_DBG_HAL, |
1322 | "hal rsp join status %d tx_mgmt_power %d\n" , |
1323 | rsp->status, rsp->tx_mgmt_power); |
1324 | |
1325 | return 0; |
1326 | } |
1327 | |
1328 | int wcn36xx_smd_join(struct wcn36xx *wcn, const u8 *bssid, u8 *vif, u8 ch) |
1329 | { |
1330 | struct wcn36xx_hal_join_req_msg msg_body; |
1331 | int ret; |
1332 | |
1333 | mutex_lock(&wcn->hal_mutex); |
1334 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_JOIN_REQ); |
1335 | |
1336 | memcpy(&msg_body.bssid, bssid, ETH_ALEN); |
1337 | memcpy(&msg_body.self_sta_mac_addr, vif, ETH_ALEN); |
1338 | msg_body.channel = ch; |
1339 | |
1340 | if (conf_is_ht40_minus(conf: &wcn->hw->conf)) |
1341 | msg_body.secondary_channel_offset = |
1342 | PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; |
1343 | else if (conf_is_ht40_plus(conf: &wcn->hw->conf)) |
1344 | msg_body.secondary_channel_offset = |
1345 | PHY_DOUBLE_CHANNEL_LOW_PRIMARY; |
1346 | else |
1347 | msg_body.secondary_channel_offset = |
1348 | PHY_SINGLE_CHANNEL_CENTERED; |
1349 | |
1350 | msg_body.link_state = WCN36XX_HAL_LINK_PREASSOC_STATE; |
1351 | |
1352 | msg_body.max_tx_power = 0xbf; |
1353 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
1354 | |
1355 | wcn36xx_dbg(WCN36XX_DBG_HAL, |
1356 | "hal join req bssid %pM self_sta_mac_addr %pM channel %d link_state %d\n" , |
1357 | msg_body.bssid, msg_body.self_sta_mac_addr, |
1358 | msg_body.channel, msg_body.link_state); |
1359 | |
1360 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
1361 | if (ret) { |
1362 | wcn36xx_err("Sending hal_join failed\n" ); |
1363 | goto out; |
1364 | } |
1365 | ret = wcn36xx_smd_join_rsp(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
1366 | if (ret) { |
1367 | wcn36xx_err("hal_join response failed err=%d\n" , ret); |
1368 | goto out; |
1369 | } |
1370 | out: |
1371 | mutex_unlock(lock: &wcn->hal_mutex); |
1372 | return ret; |
1373 | } |
1374 | |
1375 | int wcn36xx_smd_set_link_st(struct wcn36xx *wcn, const u8 *bssid, |
1376 | const u8 *sta_mac, |
1377 | enum wcn36xx_hal_link_state state) |
1378 | { |
1379 | struct wcn36xx_hal_set_link_state_req_msg msg_body; |
1380 | int ret; |
1381 | |
1382 | mutex_lock(&wcn->hal_mutex); |
1383 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_SET_LINK_ST_REQ); |
1384 | |
1385 | memcpy(&msg_body.bssid, bssid, ETH_ALEN); |
1386 | memcpy(&msg_body.self_mac_addr, sta_mac, ETH_ALEN); |
1387 | msg_body.state = state; |
1388 | |
1389 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
1390 | |
1391 | wcn36xx_dbg(WCN36XX_DBG_HAL, |
1392 | "hal set link state bssid %pM self_mac_addr %pM state %d\n" , |
1393 | msg_body.bssid, msg_body.self_mac_addr, msg_body.state); |
1394 | |
1395 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
1396 | if (ret) { |
1397 | wcn36xx_err("Sending hal_set_link_st failed\n" ); |
1398 | goto out; |
1399 | } |
1400 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
1401 | if (ret) { |
1402 | wcn36xx_err("hal_set_link_st response failed err=%d\n" , ret); |
1403 | goto out; |
1404 | } |
1405 | out: |
1406 | mutex_unlock(lock: &wcn->hal_mutex); |
1407 | return ret; |
1408 | } |
1409 | |
1410 | static void wcn36xx_smd_convert_sta_to_v1(struct wcn36xx *wcn, |
1411 | const struct wcn36xx_hal_config_sta_params *orig, |
1412 | struct wcn36xx_hal_config_sta_params_v1 *v1) |
1413 | { |
1414 | /* convert orig to v1 format */ |
1415 | memcpy(&v1->bssid, orig->bssid, ETH_ALEN); |
1416 | memcpy(&v1->mac, orig->mac, ETH_ALEN); |
1417 | v1->aid = orig->aid; |
1418 | v1->type = orig->type; |
1419 | v1->short_preamble_supported = orig->short_preamble_supported; |
1420 | v1->listen_interval = orig->listen_interval; |
1421 | v1->wmm_enabled = orig->wmm_enabled; |
1422 | v1->ht_capable = orig->ht_capable; |
1423 | v1->tx_channel_width_set = orig->tx_channel_width_set; |
1424 | v1->rifs_mode = orig->rifs_mode; |
1425 | v1->lsig_txop_protection = orig->lsig_txop_protection; |
1426 | v1->max_ampdu_size = orig->max_ampdu_size; |
1427 | v1->max_ampdu_density = orig->max_ampdu_density; |
1428 | v1->sgi_40mhz = orig->sgi_40mhz; |
1429 | v1->sgi_20Mhz = orig->sgi_20Mhz; |
1430 | v1->rmf = orig->rmf; |
1431 | v1->encrypt_type = orig->encrypt_type; |
1432 | v1->action = orig->action; |
1433 | v1->uapsd = orig->uapsd; |
1434 | v1->max_sp_len = orig->max_sp_len; |
1435 | v1->green_field_capable = orig->green_field_capable; |
1436 | v1->mimo_ps = orig->mimo_ps; |
1437 | v1->delayed_ba_support = orig->delayed_ba_support; |
1438 | v1->max_ampdu_duration = orig->max_ampdu_duration; |
1439 | v1->dsss_cck_mode_40mhz = orig->dsss_cck_mode_40mhz; |
1440 | memcpy(&v1->supported_rates, &orig->supported_rates, |
1441 | sizeof(orig->supported_rates)); |
1442 | v1->sta_index = orig->sta_index; |
1443 | v1->bssid_index = orig->bssid_index; |
1444 | v1->p2p = orig->p2p; |
1445 | } |
1446 | |
1447 | static void |
1448 | wcn36xx_smd_set_sta_params_v1(struct wcn36xx *wcn, |
1449 | struct ieee80211_vif *vif, |
1450 | struct ieee80211_sta *sta, |
1451 | struct wcn36xx_hal_config_sta_params_v1 *sta_par) |
1452 | { |
1453 | struct wcn36xx_sta *sta_priv = NULL; |
1454 | struct wcn36xx_hal_config_sta_params sta_par_v0; |
1455 | |
1456 | wcn36xx_smd_set_sta_params(wcn, vif, sta, sta_params: &sta_par_v0); |
1457 | wcn36xx_smd_convert_sta_to_v1(wcn, orig: &sta_par_v0, v1: sta_par); |
1458 | |
1459 | if (sta) { |
1460 | sta_priv = wcn36xx_sta_to_priv(sta); |
1461 | wcn36xx_smd_set_sta_vht_params(wcn, sta, sta_params: sta_par); |
1462 | wcn36xx_smd_set_sta_ht_ldpc_params(sta, sta_params: sta_par); |
1463 | memcpy(&sta_par->supported_rates, &sta_priv->supported_rates, |
1464 | sizeof(sta_par->supported_rates)); |
1465 | } else { |
1466 | wcn36xx_set_default_rates_v1(rates: &sta_par->supported_rates); |
1467 | wcn36xx_smd_set_sta_default_vht_params(wcn, sta_params: sta_par); |
1468 | wcn36xx_smd_set_sta_default_ht_ldpc_params(wcn, sta_params: sta_par); |
1469 | } |
1470 | } |
1471 | |
1472 | static int wcn36xx_smd_config_sta_rsp(struct wcn36xx *wcn, |
1473 | struct ieee80211_sta *sta, |
1474 | void *buf, |
1475 | size_t len) |
1476 | { |
1477 | struct wcn36xx_hal_config_sta_rsp_msg *rsp; |
1478 | struct config_sta_rsp_params *params; |
1479 | struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta); |
1480 | |
1481 | if (len < sizeof(*rsp)) |
1482 | return -EINVAL; |
1483 | |
1484 | rsp = buf; |
1485 | params = &rsp->params; |
1486 | |
1487 | if (params->status != WCN36XX_FW_MSG_RESULT_SUCCESS) { |
1488 | wcn36xx_warn("hal config sta response failure: %d\n" , |
1489 | params->status); |
1490 | return -EIO; |
1491 | } |
1492 | |
1493 | sta_priv->sta_index = params->sta_index; |
1494 | sta_priv->dpu_desc_index = params->dpu_index; |
1495 | sta_priv->ucast_dpu_sign = params->uc_ucast_sig; |
1496 | |
1497 | wcn36xx_dbg(WCN36XX_DBG_HAL, |
1498 | "hal config sta rsp status %d sta_index %d bssid_index %d uc_ucast_sig %d p2p %d\n" , |
1499 | params->status, params->sta_index, params->bssid_index, |
1500 | params->uc_ucast_sig, params->p2p); |
1501 | |
1502 | return 0; |
1503 | } |
1504 | |
1505 | static int wcn36xx_smd_config_sta_v1(struct wcn36xx *wcn, |
1506 | struct ieee80211_vif *vif, |
1507 | struct ieee80211_sta *sta) |
1508 | { |
1509 | struct wcn36xx_hal_config_sta_req_msg_v1 msg_body; |
1510 | struct wcn36xx_hal_config_sta_params_v1 *sta_params; |
1511 | |
1512 | if (wcn->rf_id == RF_IRIS_WCN3680) { |
1513 | INIT_HAL_MSG_V1(msg_body, WCN36XX_HAL_CONFIG_STA_REQ); |
1514 | } else { |
1515 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_CONFIG_STA_REQ); |
1516 | msg_body.header.len -= WCN36XX_DIFF_STA_PARAMS_V1_NOVHT; |
1517 | } |
1518 | |
1519 | sta_params = &msg_body.sta_params; |
1520 | |
1521 | wcn36xx_smd_set_sta_params_v1(wcn, vif, sta, sta_par: sta_params); |
1522 | |
1523 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
1524 | |
1525 | wcn36xx_dbg(WCN36XX_DBG_HAL, |
1526 | "hal config sta v1 action %d sta_index %d bssid_index %d bssid %pM type %d mac %pM aid %d\n" , |
1527 | sta_params->action, sta_params->sta_index, sta_params->bssid_index, |
1528 | sta_params->bssid, sta_params->type, sta_params->mac, sta_params->aid); |
1529 | |
1530 | return wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
1531 | } |
1532 | |
1533 | static int wcn36xx_smd_config_sta_v0(struct wcn36xx *wcn, |
1534 | struct ieee80211_vif *vif, |
1535 | struct ieee80211_sta *sta) |
1536 | { |
1537 | struct wcn36xx_hal_config_sta_req_msg msg; |
1538 | struct wcn36xx_hal_config_sta_params *sta_params; |
1539 | |
1540 | INIT_HAL_MSG(msg, WCN36XX_HAL_CONFIG_STA_REQ); |
1541 | |
1542 | sta_params = &msg.sta_params; |
1543 | |
1544 | wcn36xx_smd_set_sta_params(wcn, vif, sta, sta_params); |
1545 | |
1546 | PREPARE_HAL_BUF(wcn->hal_buf, msg); |
1547 | |
1548 | wcn36xx_dbg(WCN36XX_DBG_HAL, |
1549 | "hal config sta action %d sta_index %d bssid_index %d bssid %pM type %d mac %pM aid %d\n" , |
1550 | sta_params->action, sta_params->sta_index, |
1551 | sta_params->bssid_index, sta_params->bssid, |
1552 | sta_params->type, sta_params->mac, sta_params->aid); |
1553 | |
1554 | return wcn36xx_smd_send_and_wait(wcn, len: msg.header.len); |
1555 | } |
1556 | |
1557 | int wcn36xx_smd_config_sta(struct wcn36xx *wcn, struct ieee80211_vif *vif, |
1558 | struct ieee80211_sta *sta) |
1559 | { |
1560 | int ret; |
1561 | |
1562 | mutex_lock(&wcn->hal_mutex); |
1563 | |
1564 | if (!wcn36xx_is_fw_version(wcn, major: 1, minor: 2, version: 2, revision: 24)) |
1565 | ret = wcn36xx_smd_config_sta_v1(wcn, vif, sta); |
1566 | else |
1567 | ret = wcn36xx_smd_config_sta_v0(wcn, vif, sta); |
1568 | |
1569 | if (ret) { |
1570 | wcn36xx_err("Sending hal_config_sta failed\n" ); |
1571 | goto out; |
1572 | } |
1573 | ret = wcn36xx_smd_config_sta_rsp(wcn, |
1574 | sta, |
1575 | buf: wcn->hal_buf, |
1576 | len: wcn->hal_rsp_len); |
1577 | if (ret) { |
1578 | wcn36xx_err("hal_config_sta response failed err=%d\n" , ret); |
1579 | goto out; |
1580 | } |
1581 | out: |
1582 | mutex_unlock(lock: &wcn->hal_mutex); |
1583 | return ret; |
1584 | } |
1585 | |
1586 | static void wcn36xx_smd_set_bss_params(struct wcn36xx *wcn, |
1587 | struct ieee80211_vif *vif, |
1588 | struct ieee80211_sta *sta, |
1589 | const u8 *bssid, |
1590 | bool update, |
1591 | struct wcn36xx_hal_config_bss_params *bss) |
1592 | { |
1593 | struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); |
1594 | |
1595 | WARN_ON(is_zero_ether_addr(bssid)); |
1596 | |
1597 | memcpy(&bss->bssid, bssid, ETH_ALEN); |
1598 | |
1599 | memcpy(bss->self_mac_addr, vif->addr, ETH_ALEN); |
1600 | |
1601 | if (vif->type == NL80211_IFTYPE_STATION) { |
1602 | bss->bss_type = WCN36XX_HAL_INFRASTRUCTURE_MODE; |
1603 | |
1604 | /* STA */ |
1605 | bss->oper_mode = 1; |
1606 | bss->wcn36xx_hal_persona = WCN36XX_HAL_STA_MODE; |
1607 | } else if (vif->type == NL80211_IFTYPE_AP || |
1608 | vif->type == NL80211_IFTYPE_MESH_POINT) { |
1609 | bss->bss_type = WCN36XX_HAL_INFRA_AP_MODE; |
1610 | |
1611 | /* AP */ |
1612 | bss->oper_mode = 0; |
1613 | bss->wcn36xx_hal_persona = WCN36XX_HAL_STA_SAP_MODE; |
1614 | } else if (vif->type == NL80211_IFTYPE_ADHOC) { |
1615 | bss->bss_type = WCN36XX_HAL_IBSS_MODE; |
1616 | |
1617 | /* STA */ |
1618 | bss->oper_mode = 1; |
1619 | } else { |
1620 | wcn36xx_warn("Unknown type for bss config: %d\n" , vif->type); |
1621 | } |
1622 | |
1623 | if (vif->type == NL80211_IFTYPE_STATION) |
1624 | wcn36xx_smd_set_bss_nw_type(wcn, sta, bss_params: bss); |
1625 | else |
1626 | bss->nw_type = WCN36XX_HAL_11N_NW_TYPE; |
1627 | |
1628 | bss->short_slot_time_supported = vif->bss_conf.use_short_slot; |
1629 | bss->lla_coexist = 0; |
1630 | bss->llb_coexist = 0; |
1631 | bss->llg_coexist = 0; |
1632 | bss->rifs_mode = 0; |
1633 | bss->beacon_interval = vif->bss_conf.beacon_int; |
1634 | bss->dtim_period = vif_priv->dtim_period; |
1635 | |
1636 | wcn36xx_smd_set_bss_ht_params(vif, sta, bss_params: bss); |
1637 | |
1638 | bss->oper_channel = WCN36XX_HW_CHANNEL(wcn); |
1639 | |
1640 | if (conf_is_ht40_minus(conf: &wcn->hw->conf)) |
1641 | bss->ext_channel = IEEE80211_HT_PARAM_CHA_SEC_BELOW; |
1642 | else if (conf_is_ht40_plus(conf: &wcn->hw->conf)) |
1643 | bss->ext_channel = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; |
1644 | else |
1645 | bss->ext_channel = IEEE80211_HT_PARAM_CHA_SEC_NONE; |
1646 | |
1647 | bss->reserved = 0; |
1648 | |
1649 | /* wcn->ssid is only valid in AP and IBSS mode */ |
1650 | bss->ssid.length = vif_priv->ssid.length; |
1651 | memcpy(bss->ssid.ssid, vif_priv->ssid.ssid, vif_priv->ssid.length); |
1652 | |
1653 | bss->obss_prot_enabled = 0; |
1654 | bss->rmf = 0; |
1655 | bss->max_probe_resp_retry_limit = 0; |
1656 | bss->hidden_ssid = vif->bss_conf.hidden_ssid; |
1657 | bss->proxy_probe_resp = 0; |
1658 | bss->edca_params_valid = 0; |
1659 | |
1660 | /* FIXME: set acbe, acbk, acvi and acvo */ |
1661 | |
1662 | bss->ext_set_sta_key_param_valid = 0; |
1663 | |
1664 | /* FIXME: set ext_set_sta_key_param */ |
1665 | |
1666 | bss->spectrum_mgt_enable = 0; |
1667 | bss->tx_mgmt_power = 0; |
1668 | bss->max_tx_power = WCN36XX_MAX_POWER(wcn); |
1669 | bss->action = update; |
1670 | |
1671 | vif_priv->bss_type = bss->bss_type; |
1672 | } |
1673 | |
1674 | static int wcn36xx_smd_config_bss_v1(struct wcn36xx *wcn, |
1675 | struct ieee80211_vif *vif, |
1676 | struct ieee80211_sta *sta_80211, |
1677 | const u8 *bssid, |
1678 | bool update) |
1679 | { |
1680 | struct wcn36xx_hal_config_bss_req_msg_v1 *msg_body; |
1681 | struct wcn36xx_hal_config_bss_params_v1 *bss; |
1682 | struct wcn36xx_hal_config_bss_params bss_v0; |
1683 | struct wcn36xx_hal_config_sta_params_v1 *sta; |
1684 | struct cfg80211_chan_def *chandef; |
1685 | int ret; |
1686 | |
1687 | msg_body = kzalloc(size: sizeof(*msg_body), GFP_KERNEL); |
1688 | if (!msg_body) |
1689 | return -ENOMEM; |
1690 | |
1691 | if (wcn->rf_id == RF_IRIS_WCN3680) { |
1692 | INIT_HAL_MSG_V1((*msg_body), WCN36XX_HAL_CONFIG_BSS_REQ); |
1693 | } else { |
1694 | INIT_HAL_MSG((*msg_body), WCN36XX_HAL_CONFIG_BSS_REQ); |
1695 | msg_body->header.len -= WCN36XX_DIFF_BSS_PARAMS_V1_NOVHT; |
1696 | } |
1697 | |
1698 | bss = &msg_body->bss_params; |
1699 | sta = &bss->sta; |
1700 | |
1701 | memset(&bss_v0, 0x00, sizeof(bss_v0)); |
1702 | wcn36xx_smd_set_bss_params(wcn, vif, sta: sta_80211, bssid, update, bss: &bss_v0); |
1703 | wcn36xx_smd_set_sta_params_v1(wcn, vif, sta: sta_80211, sta_par: sta); |
1704 | |
1705 | /* convert orig to v1 */ |
1706 | memcpy(bss->bssid, &bss_v0.bssid, ETH_ALEN); |
1707 | memcpy(bss->self_mac_addr, &bss_v0.self_mac_addr, ETH_ALEN); |
1708 | |
1709 | bss->bss_type = bss_v0.bss_type; |
1710 | bss->oper_mode = bss_v0.oper_mode; |
1711 | bss->nw_type = bss_v0.nw_type; |
1712 | |
1713 | bss->short_slot_time_supported = |
1714 | bss_v0.short_slot_time_supported; |
1715 | bss->lla_coexist = bss_v0.lla_coexist; |
1716 | bss->llb_coexist = bss_v0.llb_coexist; |
1717 | bss->llg_coexist = bss_v0.llg_coexist; |
1718 | bss->ht20_coexist = bss_v0.ht20_coexist; |
1719 | bss->lln_non_gf_coexist = bss_v0.lln_non_gf_coexist; |
1720 | |
1721 | bss->lsig_tx_op_protection_full_support = |
1722 | bss_v0.lsig_tx_op_protection_full_support; |
1723 | bss->rifs_mode = bss_v0.rifs_mode; |
1724 | bss->beacon_interval = bss_v0.beacon_interval; |
1725 | bss->dtim_period = bss_v0.dtim_period; |
1726 | bss->tx_channel_width_set = bss_v0.tx_channel_width_set; |
1727 | bss->oper_channel = bss_v0.oper_channel; |
1728 | |
1729 | if (wcn->hw->conf.chandef.width == NL80211_CHAN_WIDTH_80) { |
1730 | chandef = &wcn->hw->conf.chandef; |
1731 | bss->ext_channel = HW_VALUE_PHY(chandef->chan->hw_value); |
1732 | } else { |
1733 | bss->ext_channel = bss_v0.ext_channel; |
1734 | } |
1735 | |
1736 | bss->reserved = bss_v0.reserved; |
1737 | |
1738 | memcpy(&bss->ssid, &bss_v0.ssid, |
1739 | sizeof(bss_v0.ssid)); |
1740 | |
1741 | bss->action = bss_v0.action; |
1742 | bss->rateset = bss_v0.rateset; |
1743 | bss->ht = bss_v0.ht; |
1744 | bss->obss_prot_enabled = bss_v0.obss_prot_enabled; |
1745 | bss->rmf = bss_v0.rmf; |
1746 | bss->ht_oper_mode = bss_v0.ht_oper_mode; |
1747 | bss->dual_cts_protection = bss_v0.dual_cts_protection; |
1748 | |
1749 | bss->max_probe_resp_retry_limit = |
1750 | bss_v0.max_probe_resp_retry_limit; |
1751 | bss->hidden_ssid = bss_v0.hidden_ssid; |
1752 | bss->proxy_probe_resp = bss_v0.proxy_probe_resp; |
1753 | bss->edca_params_valid = bss_v0.edca_params_valid; |
1754 | |
1755 | memcpy(&bss->acbe, &bss_v0.acbe, |
1756 | sizeof(bss_v0.acbe)); |
1757 | memcpy(&bss->acbk, &bss_v0.acbk, |
1758 | sizeof(bss_v0.acbk)); |
1759 | memcpy(&bss->acvi, &bss_v0.acvi, |
1760 | sizeof(bss_v0.acvi)); |
1761 | memcpy(&bss->acvo, &bss_v0.acvo, |
1762 | sizeof(bss_v0.acvo)); |
1763 | |
1764 | bss->ext_set_sta_key_param_valid = |
1765 | bss_v0.ext_set_sta_key_param_valid; |
1766 | |
1767 | memcpy(&bss->ext_set_sta_key_param, |
1768 | &bss_v0.ext_set_sta_key_param, |
1769 | sizeof(bss_v0.acvo)); |
1770 | |
1771 | bss->wcn36xx_hal_persona = bss_v0.wcn36xx_hal_persona; |
1772 | bss->spectrum_mgt_enable = bss_v0.spectrum_mgt_enable; |
1773 | bss->tx_mgmt_power = bss_v0.tx_mgmt_power; |
1774 | bss->max_tx_power = bss_v0.max_tx_power; |
1775 | |
1776 | wcn36xx_smd_set_bss_vht_params(vif, sta: sta_80211, bss); |
1777 | |
1778 | PREPARE_HAL_BUF(wcn->hal_buf, (*msg_body)); |
1779 | |
1780 | wcn36xx_dbg(WCN36XX_DBG_HAL, |
1781 | "hal config bss v1 bssid %pM self_mac_addr %pM bss_type %d oper_mode %d nw_type %d\n" , |
1782 | bss->bssid, bss->self_mac_addr, bss->bss_type, |
1783 | bss->oper_mode, bss->nw_type); |
1784 | |
1785 | wcn36xx_dbg(WCN36XX_DBG_HAL, |
1786 | "- sta bssid %pM action %d sta_index %d bssid_index %d aid %d type %d mac %pM\n" , |
1787 | sta->bssid, sta->action, sta->sta_index, |
1788 | sta->bssid_index, sta->aid, sta->type, sta->mac); |
1789 | |
1790 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body->header.len); |
1791 | kfree(objp: msg_body); |
1792 | |
1793 | return ret; |
1794 | } |
1795 | |
1796 | static int wcn36xx_smd_config_bss_v0(struct wcn36xx *wcn, |
1797 | struct ieee80211_vif *vif, |
1798 | struct ieee80211_sta *sta, |
1799 | const u8 *bssid, |
1800 | bool update) |
1801 | { |
1802 | struct wcn36xx_hal_config_bss_req_msg *msg; |
1803 | struct wcn36xx_hal_config_bss_params *bss; |
1804 | struct wcn36xx_hal_config_sta_params *sta_params; |
1805 | int ret; |
1806 | |
1807 | msg = kzalloc(size: sizeof(*msg), GFP_KERNEL); |
1808 | if (!msg) |
1809 | return -ENOMEM; |
1810 | |
1811 | INIT_HAL_MSG((*msg), WCN36XX_HAL_CONFIG_BSS_REQ); |
1812 | |
1813 | bss = &msg->bss_params; |
1814 | sta_params = &bss->sta; |
1815 | |
1816 | wcn36xx_smd_set_bss_params(wcn, vif, sta, bssid, update, bss); |
1817 | wcn36xx_smd_set_sta_params(wcn, vif, sta, sta_params); |
1818 | |
1819 | PREPARE_HAL_BUF(wcn->hal_buf, (*msg)); |
1820 | |
1821 | wcn36xx_dbg(WCN36XX_DBG_HAL, |
1822 | "hal config bss bssid %pM self_mac_addr %pM bss_type %d oper_mode %d nw_type %d\n" , |
1823 | bss->bssid, bss->self_mac_addr, bss->bss_type, |
1824 | bss->oper_mode, bss->nw_type); |
1825 | |
1826 | wcn36xx_dbg(WCN36XX_DBG_HAL, |
1827 | "- sta bssid %pM action %d sta_index %d bssid_index %d aid %d type %d mac %pM\n" , |
1828 | sta_params->bssid, sta_params->action, |
1829 | sta_params->sta_index, sta_params->bssid_index, |
1830 | sta_params->aid, sta_params->type, |
1831 | sta_params->mac); |
1832 | |
1833 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg->header.len); |
1834 | kfree(objp: msg); |
1835 | |
1836 | return ret; |
1837 | } |
1838 | |
1839 | static int wcn36xx_smd_config_bss_rsp(struct wcn36xx *wcn, |
1840 | struct ieee80211_vif *vif, |
1841 | struct ieee80211_sta *sta, |
1842 | void *buf, |
1843 | size_t len) |
1844 | { |
1845 | struct wcn36xx_hal_config_bss_rsp_msg *rsp; |
1846 | struct wcn36xx_hal_config_bss_rsp_params *params; |
1847 | struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); |
1848 | |
1849 | if (len < sizeof(*rsp)) |
1850 | return -EINVAL; |
1851 | |
1852 | rsp = buf; |
1853 | params = &rsp->bss_rsp_params; |
1854 | |
1855 | if (params->status != WCN36XX_FW_MSG_RESULT_SUCCESS) { |
1856 | wcn36xx_warn("hal config bss response failure: %d\n" , |
1857 | params->status); |
1858 | return -EIO; |
1859 | } |
1860 | |
1861 | wcn36xx_dbg(WCN36XX_DBG_HAL, |
1862 | "hal config bss rsp status %d bss_idx %d dpu_desc_index %d" |
1863 | " sta_idx %d self_idx %d bcast_idx %d mac %pM" |
1864 | " power %d ucast_dpu_signature %d\n" , |
1865 | params->status, params->bss_index, params->dpu_desc_index, |
1866 | params->bss_sta_index, params->bss_self_sta_index, |
1867 | params->bss_bcast_sta_idx, params->mac, |
1868 | params->tx_mgmt_power, params->ucast_dpu_signature); |
1869 | |
1870 | vif_priv->bss_index = params->bss_index; |
1871 | |
1872 | if (sta) { |
1873 | struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta); |
1874 | sta_priv->bss_sta_index = params->bss_sta_index; |
1875 | sta_priv->bss_dpu_desc_index = params->dpu_desc_index; |
1876 | } |
1877 | |
1878 | vif_priv->self_ucast_dpu_sign = params->ucast_dpu_signature; |
1879 | |
1880 | return 0; |
1881 | } |
1882 | |
1883 | int wcn36xx_smd_config_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif, |
1884 | struct ieee80211_sta *sta, const u8 *bssid, |
1885 | bool update) |
1886 | { |
1887 | int ret; |
1888 | |
1889 | mutex_lock(&wcn->hal_mutex); |
1890 | |
1891 | if (!wcn36xx_is_fw_version(wcn, major: 1, minor: 2, version: 2, revision: 24)) |
1892 | ret = wcn36xx_smd_config_bss_v1(wcn, vif, sta_80211: sta, bssid, update); |
1893 | else |
1894 | ret = wcn36xx_smd_config_bss_v0(wcn, vif, sta, bssid, update); |
1895 | |
1896 | if (ret) { |
1897 | wcn36xx_err("Sending hal_config_bss failed\n" ); |
1898 | goto out; |
1899 | } |
1900 | ret = wcn36xx_smd_config_bss_rsp(wcn, |
1901 | vif, |
1902 | sta, |
1903 | buf: wcn->hal_buf, |
1904 | len: wcn->hal_rsp_len); |
1905 | if (ret) |
1906 | wcn36xx_err("hal_config_bss response failed err=%d\n" , ret); |
1907 | |
1908 | out: |
1909 | mutex_unlock(lock: &wcn->hal_mutex); |
1910 | return ret; |
1911 | } |
1912 | |
1913 | int wcn36xx_smd_delete_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif) |
1914 | { |
1915 | struct wcn36xx_hal_delete_bss_req_msg msg_body; |
1916 | struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); |
1917 | int ret = 0; |
1918 | |
1919 | mutex_lock(&wcn->hal_mutex); |
1920 | |
1921 | if (vif_priv->bss_index == WCN36XX_HAL_BSS_INVALID_IDX) |
1922 | goto out; |
1923 | |
1924 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_DELETE_BSS_REQ); |
1925 | |
1926 | msg_body.bss_index = vif_priv->bss_index; |
1927 | |
1928 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
1929 | |
1930 | wcn36xx_dbg(WCN36XX_DBG_HAL, "hal delete bss %d\n" , msg_body.bss_index); |
1931 | |
1932 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
1933 | if (ret) { |
1934 | wcn36xx_err("Sending hal_delete_bss failed\n" ); |
1935 | goto out; |
1936 | } |
1937 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
1938 | if (ret) { |
1939 | wcn36xx_err("hal_delete_bss response failed err=%d\n" , ret); |
1940 | goto out; |
1941 | } |
1942 | |
1943 | vif_priv->bss_index = WCN36XX_HAL_BSS_INVALID_IDX; |
1944 | out: |
1945 | mutex_unlock(lock: &wcn->hal_mutex); |
1946 | return ret; |
1947 | } |
1948 | |
1949 | int wcn36xx_smd_send_beacon(struct wcn36xx *wcn, struct ieee80211_vif *vif, |
1950 | struct sk_buff *skb_beacon, u16 tim_off, |
1951 | u16 p2p_off) |
1952 | { |
1953 | struct wcn36xx_hal_send_beacon_req_msg msg_body; |
1954 | int ret, pad, pvm_len; |
1955 | |
1956 | mutex_lock(&wcn->hal_mutex); |
1957 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_SEND_BEACON_REQ); |
1958 | |
1959 | pvm_len = skb_beacon->data[tim_off + 1] - 3; |
1960 | pad = TIM_MIN_PVM_SIZE - pvm_len; |
1961 | |
1962 | /* Padding is irrelevant to mesh mode since tim_off is always 0. */ |
1963 | if (vif->type == NL80211_IFTYPE_MESH_POINT) |
1964 | pad = 0; |
1965 | |
1966 | msg_body.beacon_length = skb_beacon->len + pad; |
1967 | /* TODO need to find out why + 6 is needed */ |
1968 | msg_body.beacon_length6 = msg_body.beacon_length + 6; |
1969 | |
1970 | if (msg_body.beacon_length > BEACON_TEMPLATE_SIZE) { |
1971 | wcn36xx_err("Beacon is too big: beacon size=%d\n" , |
1972 | msg_body.beacon_length); |
1973 | ret = -ENOMEM; |
1974 | goto out; |
1975 | } |
1976 | memcpy(msg_body.beacon, skb_beacon->data, skb_beacon->len); |
1977 | memcpy(msg_body.bssid, vif->addr, ETH_ALEN); |
1978 | |
1979 | if (pad > 0) { |
1980 | /* |
1981 | * The wcn36xx FW has a fixed size for the PVM in the TIM. If |
1982 | * given the beacon template from mac80211 with a PVM shorter |
1983 | * than the FW expectes it will overwrite the data after the |
1984 | * TIM. |
1985 | */ |
1986 | wcn36xx_dbg(WCN36XX_DBG_HAL, "Pad TIM PVM. %d bytes at %d\n" , |
1987 | pad, pvm_len); |
1988 | memmove(&msg_body.beacon[tim_off + 5 + pvm_len + pad], |
1989 | &msg_body.beacon[tim_off + 5 + pvm_len], |
1990 | skb_beacon->len - (tim_off + 5 + pvm_len)); |
1991 | memset(&msg_body.beacon[tim_off + 5 + pvm_len], 0, pad); |
1992 | msg_body.beacon[tim_off + 1] += pad; |
1993 | } |
1994 | |
1995 | /* TODO need to find out why this is needed? */ |
1996 | if (vif->type == NL80211_IFTYPE_MESH_POINT) |
1997 | /* mesh beacon don't need this, so push further down */ |
1998 | msg_body.tim_ie_offset = 256; |
1999 | else |
2000 | msg_body.tim_ie_offset = tim_off+4; |
2001 | msg_body.p2p_ie_offset = p2p_off; |
2002 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
2003 | |
2004 | wcn36xx_dbg(WCN36XX_DBG_HAL, |
2005 | "hal send beacon beacon_length %d\n" , |
2006 | msg_body.beacon_length); |
2007 | |
2008 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
2009 | if (ret) { |
2010 | wcn36xx_err("Sending hal_send_beacon failed\n" ); |
2011 | goto out; |
2012 | } |
2013 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
2014 | if (ret) { |
2015 | wcn36xx_err("hal_send_beacon response failed err=%d\n" , ret); |
2016 | goto out; |
2017 | } |
2018 | out: |
2019 | mutex_unlock(lock: &wcn->hal_mutex); |
2020 | return ret; |
2021 | } |
2022 | |
2023 | int wcn36xx_smd_update_proberesp_tmpl(struct wcn36xx *wcn, |
2024 | struct ieee80211_vif *vif, |
2025 | struct sk_buff *skb) |
2026 | { |
2027 | struct wcn36xx_hal_send_probe_resp_req_msg msg; |
2028 | int ret; |
2029 | |
2030 | mutex_lock(&wcn->hal_mutex); |
2031 | INIT_HAL_MSG(msg, WCN36XX_HAL_UPDATE_PROBE_RSP_TEMPLATE_REQ); |
2032 | |
2033 | if (skb->len > BEACON_TEMPLATE_SIZE) { |
2034 | wcn36xx_warn("probe response template is too big: %d\n" , |
2035 | skb->len); |
2036 | ret = -E2BIG; |
2037 | goto out; |
2038 | } |
2039 | |
2040 | msg.probe_resp_template_len = skb->len; |
2041 | memcpy(&msg.probe_resp_template, skb->data, skb->len); |
2042 | |
2043 | memcpy(msg.bssid, vif->addr, ETH_ALEN); |
2044 | |
2045 | PREPARE_HAL_BUF(wcn->hal_buf, msg); |
2046 | |
2047 | wcn36xx_dbg(WCN36XX_DBG_HAL, |
2048 | "hal update probe rsp len %d bssid %pM\n" , |
2049 | msg.probe_resp_template_len, msg.bssid); |
2050 | |
2051 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg.header.len); |
2052 | if (ret) { |
2053 | wcn36xx_err("Sending hal_update_proberesp_tmpl failed\n" ); |
2054 | goto out; |
2055 | } |
2056 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
2057 | if (ret) { |
2058 | wcn36xx_err("hal_update_proberesp_tmpl response failed err=%d\n" , |
2059 | ret); |
2060 | goto out; |
2061 | } |
2062 | out: |
2063 | mutex_unlock(lock: &wcn->hal_mutex); |
2064 | return ret; |
2065 | } |
2066 | |
2067 | int wcn36xx_smd_set_stakey(struct wcn36xx *wcn, |
2068 | enum ani_ed_type enc_type, |
2069 | u8 keyidx, |
2070 | u8 keylen, |
2071 | u8 *key, |
2072 | u8 sta_index) |
2073 | { |
2074 | struct wcn36xx_hal_set_sta_key_req_msg msg_body; |
2075 | int ret; |
2076 | |
2077 | mutex_lock(&wcn->hal_mutex); |
2078 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_SET_STAKEY_REQ); |
2079 | |
2080 | msg_body.set_sta_key_params.sta_index = sta_index; |
2081 | msg_body.set_sta_key_params.enc_type = enc_type; |
2082 | |
2083 | if (enc_type == WCN36XX_HAL_ED_WEP104 || |
2084 | enc_type == WCN36XX_HAL_ED_WEP40) { |
2085 | /* Use bss key for wep (static) */ |
2086 | msg_body.set_sta_key_params.def_wep_idx = keyidx; |
2087 | msg_body.set_sta_key_params.wep_type = 0; |
2088 | } else { |
2089 | msg_body.set_sta_key_params.key[0].id = keyidx; |
2090 | msg_body.set_sta_key_params.key[0].unicast = 1; |
2091 | msg_body.set_sta_key_params.key[0].direction = WCN36XX_HAL_TX_RX; |
2092 | msg_body.set_sta_key_params.key[0].pae_role = 0; |
2093 | msg_body.set_sta_key_params.key[0].length = keylen; |
2094 | memcpy(msg_body.set_sta_key_params.key[0].key, key, keylen); |
2095 | } |
2096 | |
2097 | msg_body.set_sta_key_params.single_tid_rc = 1; |
2098 | |
2099 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
2100 | |
2101 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
2102 | if (ret) { |
2103 | wcn36xx_err("Sending hal_set_stakey failed\n" ); |
2104 | goto out; |
2105 | } |
2106 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
2107 | if (ret) { |
2108 | wcn36xx_err("hal_set_stakey response failed err=%d\n" , ret); |
2109 | goto out; |
2110 | } |
2111 | out: |
2112 | mutex_unlock(lock: &wcn->hal_mutex); |
2113 | return ret; |
2114 | } |
2115 | |
2116 | int wcn36xx_smd_set_bsskey(struct wcn36xx *wcn, |
2117 | enum ani_ed_type enc_type, |
2118 | u8 bssidx, |
2119 | u8 keyidx, |
2120 | u8 keylen, |
2121 | u8 *key) |
2122 | { |
2123 | struct wcn36xx_hal_set_bss_key_req_msg msg_body; |
2124 | int ret; |
2125 | |
2126 | mutex_lock(&wcn->hal_mutex); |
2127 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_SET_BSSKEY_REQ); |
2128 | msg_body.bss_idx = bssidx; |
2129 | msg_body.enc_type = enc_type; |
2130 | msg_body.num_keys = 1; |
2131 | msg_body.keys[0].id = keyidx; |
2132 | msg_body.keys[0].unicast = 0; |
2133 | msg_body.keys[0].direction = WCN36XX_HAL_RX_ONLY; |
2134 | msg_body.keys[0].pae_role = 0; |
2135 | msg_body.keys[0].length = keylen; |
2136 | memcpy(msg_body.keys[0].key, key, keylen); |
2137 | |
2138 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
2139 | |
2140 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
2141 | if (ret) { |
2142 | wcn36xx_err("Sending hal_set_bsskey failed\n" ); |
2143 | goto out; |
2144 | } |
2145 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
2146 | if (ret) { |
2147 | wcn36xx_err("hal_set_bsskey response failed err=%d\n" , ret); |
2148 | goto out; |
2149 | } |
2150 | out: |
2151 | mutex_unlock(lock: &wcn->hal_mutex); |
2152 | return ret; |
2153 | } |
2154 | |
2155 | int wcn36xx_smd_remove_stakey(struct wcn36xx *wcn, |
2156 | enum ani_ed_type enc_type, |
2157 | u8 keyidx, |
2158 | u8 sta_index) |
2159 | { |
2160 | struct wcn36xx_hal_remove_sta_key_req_msg msg_body; |
2161 | int ret; |
2162 | |
2163 | mutex_lock(&wcn->hal_mutex); |
2164 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_RMV_STAKEY_REQ); |
2165 | |
2166 | msg_body.sta_idx = sta_index; |
2167 | msg_body.enc_type = enc_type; |
2168 | msg_body.key_id = keyidx; |
2169 | |
2170 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
2171 | |
2172 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
2173 | if (ret) { |
2174 | wcn36xx_err("Sending hal_remove_stakey failed\n" ); |
2175 | goto out; |
2176 | } |
2177 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
2178 | if (ret) { |
2179 | wcn36xx_err("hal_remove_stakey response failed err=%d\n" , ret); |
2180 | goto out; |
2181 | } |
2182 | out: |
2183 | mutex_unlock(lock: &wcn->hal_mutex); |
2184 | return ret; |
2185 | } |
2186 | |
2187 | int wcn36xx_smd_remove_bsskey(struct wcn36xx *wcn, |
2188 | enum ani_ed_type enc_type, |
2189 | u8 bssidx, |
2190 | u8 keyidx) |
2191 | { |
2192 | struct wcn36xx_hal_remove_bss_key_req_msg msg_body; |
2193 | int ret; |
2194 | |
2195 | mutex_lock(&wcn->hal_mutex); |
2196 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_RMV_BSSKEY_REQ); |
2197 | msg_body.bss_idx = bssidx; |
2198 | msg_body.enc_type = enc_type; |
2199 | msg_body.key_id = keyidx; |
2200 | |
2201 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
2202 | |
2203 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
2204 | if (ret) { |
2205 | wcn36xx_err("Sending hal_remove_bsskey failed\n" ); |
2206 | goto out; |
2207 | } |
2208 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
2209 | if (ret) { |
2210 | wcn36xx_err("hal_remove_bsskey response failed err=%d\n" , ret); |
2211 | goto out; |
2212 | } |
2213 | out: |
2214 | mutex_unlock(lock: &wcn->hal_mutex); |
2215 | return ret; |
2216 | } |
2217 | |
2218 | int wcn36xx_smd_enter_bmps(struct wcn36xx *wcn, struct ieee80211_vif *vif) |
2219 | { |
2220 | struct wcn36xx_hal_enter_bmps_req_msg msg_body; |
2221 | struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); |
2222 | int ret; |
2223 | |
2224 | mutex_lock(&wcn->hal_mutex); |
2225 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_ENTER_BMPS_REQ); |
2226 | |
2227 | msg_body.bss_index = vif_priv->bss_index; |
2228 | msg_body.tbtt = vif->bss_conf.sync_tsf; |
2229 | msg_body.dtim_period = vif_priv->dtim_period; |
2230 | |
2231 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
2232 | |
2233 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
2234 | if (ret) { |
2235 | wcn36xx_err("Sending hal_enter_bmps failed\n" ); |
2236 | goto out; |
2237 | } |
2238 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
2239 | if (ret) { |
2240 | wcn36xx_err("hal_enter_bmps response failed err=%d\n" , ret); |
2241 | goto out; |
2242 | } |
2243 | out: |
2244 | mutex_unlock(lock: &wcn->hal_mutex); |
2245 | return ret; |
2246 | } |
2247 | |
2248 | int wcn36xx_smd_exit_bmps(struct wcn36xx *wcn, struct ieee80211_vif *vif) |
2249 | { |
2250 | struct wcn36xx_hal_exit_bmps_req_msg msg_body; |
2251 | struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); |
2252 | int ret; |
2253 | |
2254 | mutex_lock(&wcn->hal_mutex); |
2255 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_EXIT_BMPS_REQ); |
2256 | |
2257 | msg_body.bss_index = vif_priv->bss_index; |
2258 | msg_body.send_data_null = 1; |
2259 | |
2260 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
2261 | |
2262 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
2263 | if (ret) { |
2264 | wcn36xx_err("Sending hal_exit_bmps failed\n" ); |
2265 | goto out; |
2266 | } |
2267 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
2268 | if (ret) { |
2269 | wcn36xx_err("hal_exit_bmps response failed err=%d\n" , ret); |
2270 | goto out; |
2271 | } |
2272 | out: |
2273 | mutex_unlock(lock: &wcn->hal_mutex); |
2274 | return ret; |
2275 | } |
2276 | |
2277 | int wcn36xx_smd_enter_imps(struct wcn36xx *wcn) |
2278 | { |
2279 | struct wcn36xx_hal_enter_imps_req_msg msg_body; |
2280 | int ret; |
2281 | |
2282 | mutex_lock(&wcn->hal_mutex); |
2283 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_ENTER_IMPS_REQ); |
2284 | |
2285 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
2286 | |
2287 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
2288 | if (ret) { |
2289 | wcn36xx_err("Sending hal_enter_imps failed\n" ); |
2290 | goto out; |
2291 | } |
2292 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
2293 | if (ret) { |
2294 | wcn36xx_err("hal_enter_imps response failed err=%d\n" , ret); |
2295 | goto out; |
2296 | } |
2297 | |
2298 | wcn36xx_dbg(WCN36XX_DBG_HAL, "Entered idle mode\n" ); |
2299 | out: |
2300 | mutex_unlock(lock: &wcn->hal_mutex); |
2301 | return ret; |
2302 | } |
2303 | |
2304 | int wcn36xx_smd_exit_imps(struct wcn36xx *wcn) |
2305 | { |
2306 | struct wcn36xx_hal_exit_imps_req_msg msg_body; |
2307 | int ret; |
2308 | |
2309 | mutex_lock(&wcn->hal_mutex); |
2310 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_EXIT_IMPS_REQ); |
2311 | |
2312 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
2313 | |
2314 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
2315 | if (ret) { |
2316 | wcn36xx_err("Sending hal_exit_imps failed\n" ); |
2317 | goto out; |
2318 | } |
2319 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
2320 | if (ret) { |
2321 | wcn36xx_err("hal_exit_imps response failed err=%d\n" , ret); |
2322 | goto out; |
2323 | } |
2324 | wcn36xx_dbg(WCN36XX_DBG_HAL, "Exited idle mode\n" ); |
2325 | out: |
2326 | mutex_unlock(lock: &wcn->hal_mutex); |
2327 | return ret; |
2328 | } |
2329 | |
2330 | int wcn36xx_smd_set_power_params(struct wcn36xx *wcn, bool ignore_dtim) |
2331 | { |
2332 | struct wcn36xx_hal_set_power_params_req_msg msg_body; |
2333 | int ret; |
2334 | |
2335 | mutex_lock(&wcn->hal_mutex); |
2336 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_SET_POWER_PARAMS_REQ); |
2337 | |
2338 | /* |
2339 | * When host is down ignore every second dtim |
2340 | */ |
2341 | if (ignore_dtim) { |
2342 | msg_body.ignore_dtim = 1; |
2343 | msg_body.dtim_period = 2; |
2344 | } |
2345 | msg_body.listen_interval = WCN36XX_LISTEN_INTERVAL(wcn); |
2346 | |
2347 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
2348 | |
2349 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
2350 | if (ret) { |
2351 | wcn36xx_err("Sending hal_set_power_params failed\n" ); |
2352 | goto out; |
2353 | } |
2354 | |
2355 | out: |
2356 | mutex_unlock(lock: &wcn->hal_mutex); |
2357 | return ret; |
2358 | } |
2359 | |
2360 | /* Notice: This function should be called after associated, or else it |
2361 | * will be invalid |
2362 | */ |
2363 | int wcn36xx_smd_keep_alive_req(struct wcn36xx *wcn, |
2364 | struct ieee80211_vif *vif, |
2365 | int packet_type) |
2366 | { |
2367 | struct wcn36xx_hal_keep_alive_req_msg msg_body; |
2368 | struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); |
2369 | int ret; |
2370 | |
2371 | mutex_lock(&wcn->hal_mutex); |
2372 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_KEEP_ALIVE_REQ); |
2373 | |
2374 | if (packet_type == WCN36XX_HAL_KEEP_ALIVE_NULL_PKT) { |
2375 | msg_body.bss_index = vif_priv->bss_index; |
2376 | msg_body.packet_type = WCN36XX_HAL_KEEP_ALIVE_NULL_PKT; |
2377 | msg_body.time_period = WCN36XX_KEEP_ALIVE_TIME_PERIOD; |
2378 | } else if (packet_type == WCN36XX_HAL_KEEP_ALIVE_UNSOLICIT_ARP_RSP) { |
2379 | /* TODO: it also support ARP response type */ |
2380 | } else { |
2381 | wcn36xx_warn("unknown keep alive packet type %d\n" , packet_type); |
2382 | ret = -EINVAL; |
2383 | goto out; |
2384 | } |
2385 | |
2386 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
2387 | |
2388 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
2389 | if (ret) { |
2390 | wcn36xx_err("Sending hal_keep_alive failed\n" ); |
2391 | goto out; |
2392 | } |
2393 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
2394 | if (ret) { |
2395 | wcn36xx_err("hal_keep_alive response failed err=%d\n" , ret); |
2396 | goto out; |
2397 | } |
2398 | out: |
2399 | mutex_unlock(lock: &wcn->hal_mutex); |
2400 | return ret; |
2401 | } |
2402 | |
2403 | int wcn36xx_smd_dump_cmd_req(struct wcn36xx *wcn, u32 arg1, u32 arg2, |
2404 | u32 arg3, u32 arg4, u32 arg5) |
2405 | { |
2406 | struct wcn36xx_hal_dump_cmd_req_msg msg_body; |
2407 | int ret; |
2408 | |
2409 | mutex_lock(&wcn->hal_mutex); |
2410 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_DUMP_COMMAND_REQ); |
2411 | |
2412 | msg_body.arg1 = arg1; |
2413 | msg_body.arg2 = arg2; |
2414 | msg_body.arg3 = arg3; |
2415 | msg_body.arg4 = arg4; |
2416 | msg_body.arg5 = arg5; |
2417 | |
2418 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
2419 | |
2420 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
2421 | if (ret) { |
2422 | wcn36xx_err("Sending hal_dump_cmd failed\n" ); |
2423 | goto out; |
2424 | } |
2425 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
2426 | if (ret) { |
2427 | wcn36xx_err("hal_dump_cmd response failed err=%d\n" , ret); |
2428 | goto out; |
2429 | } |
2430 | out: |
2431 | mutex_unlock(lock: &wcn->hal_mutex); |
2432 | return ret; |
2433 | } |
2434 | |
2435 | int wcn36xx_smd_feature_caps_exchange(struct wcn36xx *wcn) |
2436 | { |
2437 | struct wcn36xx_hal_feat_caps_msg msg_body, *rsp; |
2438 | int ret, i; |
2439 | |
2440 | mutex_lock(&wcn->hal_mutex); |
2441 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_FEATURE_CAPS_EXCHANGE_REQ); |
2442 | |
2443 | wcn36xx_firmware_set_feat_caps(bitmap: msg_body.feat_caps, cap: STA_POWERSAVE); |
2444 | if (wcn->rf_id == RF_IRIS_WCN3680) { |
2445 | wcn36xx_firmware_set_feat_caps(bitmap: msg_body.feat_caps, cap: DOT11AC); |
2446 | wcn36xx_firmware_set_feat_caps(bitmap: msg_body.feat_caps, cap: WLAN_CH144); |
2447 | wcn36xx_firmware_set_feat_caps(bitmap: msg_body.feat_caps, |
2448 | cap: ANTENNA_DIVERSITY_SELECTION); |
2449 | } |
2450 | |
2451 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
2452 | |
2453 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
2454 | if (ret) { |
2455 | wcn36xx_err("Sending hal_feature_caps_exchange failed\n" ); |
2456 | goto out; |
2457 | } |
2458 | if (wcn->hal_rsp_len != sizeof(*rsp)) { |
2459 | wcn36xx_err("Invalid hal_feature_caps_exchange response" ); |
2460 | goto out; |
2461 | } |
2462 | |
2463 | rsp = (struct wcn36xx_hal_feat_caps_msg *) wcn->hal_buf; |
2464 | |
2465 | for (i = 0; i < WCN36XX_HAL_CAPS_SIZE; i++) |
2466 | wcn->fw_feat_caps[i] = rsp->feat_caps[i]; |
2467 | out: |
2468 | mutex_unlock(lock: &wcn->hal_mutex); |
2469 | return ret; |
2470 | } |
2471 | |
2472 | static int wcn36xx_smd_add_ba_session_rsp(void *buf, int len, u8 *session) |
2473 | { |
2474 | struct wcn36xx_hal_add_ba_session_rsp_msg *rsp; |
2475 | |
2476 | if (len < sizeof(*rsp)) |
2477 | return -EINVAL; |
2478 | |
2479 | rsp = buf; |
2480 | if (rsp->status != WCN36XX_FW_MSG_RESULT_SUCCESS) |
2481 | return rsp->status; |
2482 | |
2483 | *session = rsp->ba_session_id; |
2484 | |
2485 | return 0; |
2486 | } |
2487 | |
2488 | int wcn36xx_smd_add_ba_session(struct wcn36xx *wcn, |
2489 | struct ieee80211_sta *sta, |
2490 | u16 tid, |
2491 | u16 *ssn, |
2492 | u8 direction, |
2493 | u8 sta_index) |
2494 | { |
2495 | struct wcn36xx_hal_add_ba_session_req_msg msg_body; |
2496 | u8 session_id; |
2497 | int ret; |
2498 | |
2499 | mutex_lock(&wcn->hal_mutex); |
2500 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_ADD_BA_SESSION_REQ); |
2501 | |
2502 | msg_body.sta_index = sta_index; |
2503 | memcpy(&msg_body.mac_addr, sta->addr, ETH_ALEN); |
2504 | msg_body.dialog_token = 0x10; |
2505 | msg_body.tid = tid; |
2506 | |
2507 | /* Immediate BA because Delayed BA is not supported */ |
2508 | msg_body.policy = 1; |
2509 | msg_body.buffer_size = WCN36XX_AGGR_BUFFER_SIZE; |
2510 | msg_body.timeout = 0; |
2511 | if (ssn) |
2512 | msg_body.ssn = *ssn; |
2513 | msg_body.direction = direction; |
2514 | |
2515 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
2516 | |
2517 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
2518 | if (ret) { |
2519 | wcn36xx_err("Sending hal_add_ba_session failed\n" ); |
2520 | goto out; |
2521 | } |
2522 | ret = wcn36xx_smd_add_ba_session_rsp(buf: wcn->hal_buf, len: wcn->hal_rsp_len, |
2523 | session: &session_id); |
2524 | if (ret) { |
2525 | wcn36xx_err("hal_add_ba_session response failed err=%d\n" , ret); |
2526 | ret = -EINVAL; |
2527 | goto out; |
2528 | } |
2529 | |
2530 | ret = session_id; |
2531 | out: |
2532 | mutex_unlock(lock: &wcn->hal_mutex); |
2533 | return ret; |
2534 | } |
2535 | |
2536 | int wcn36xx_smd_add_ba(struct wcn36xx *wcn, u8 session_id) |
2537 | { |
2538 | struct wcn36xx_hal_add_ba_req_msg msg_body; |
2539 | int ret; |
2540 | |
2541 | mutex_lock(&wcn->hal_mutex); |
2542 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_ADD_BA_REQ); |
2543 | |
2544 | msg_body.session_id = session_id; |
2545 | msg_body.win_size = WCN36XX_AGGR_BUFFER_SIZE; |
2546 | |
2547 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
2548 | |
2549 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
2550 | if (ret) { |
2551 | wcn36xx_err("Sending hal_add_ba failed\n" ); |
2552 | goto out; |
2553 | } |
2554 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
2555 | if (ret) { |
2556 | wcn36xx_err("hal_add_ba response failed err=%d\n" , ret); |
2557 | goto out; |
2558 | } |
2559 | out: |
2560 | mutex_unlock(lock: &wcn->hal_mutex); |
2561 | return ret; |
2562 | } |
2563 | |
2564 | int wcn36xx_smd_del_ba(struct wcn36xx *wcn, u16 tid, u8 direction, u8 sta_index) |
2565 | { |
2566 | struct wcn36xx_hal_del_ba_req_msg msg_body; |
2567 | int ret; |
2568 | |
2569 | mutex_lock(&wcn->hal_mutex); |
2570 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_DEL_BA_REQ); |
2571 | |
2572 | msg_body.sta_index = sta_index; |
2573 | msg_body.tid = tid; |
2574 | msg_body.direction = direction; |
2575 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
2576 | |
2577 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
2578 | if (ret) { |
2579 | wcn36xx_err("Sending hal_del_ba failed\n" ); |
2580 | goto out; |
2581 | } |
2582 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
2583 | if (ret) { |
2584 | wcn36xx_err("hal_del_ba response failed err=%d\n" , ret); |
2585 | goto out; |
2586 | } |
2587 | out: |
2588 | mutex_unlock(lock: &wcn->hal_mutex); |
2589 | return ret; |
2590 | } |
2591 | |
2592 | int wcn36xx_smd_get_stats(struct wcn36xx *wcn, u8 sta_index, u32 stats_mask, |
2593 | struct station_info *sinfo) |
2594 | { |
2595 | struct wcn36xx_hal_stats_req_msg msg_body; |
2596 | struct wcn36xx_hal_stats_rsp_msg *rsp; |
2597 | void *rsp_body; |
2598 | int ret; |
2599 | |
2600 | if (stats_mask & ~HAL_GLOBAL_CLASS_A_STATS_INFO) { |
2601 | wcn36xx_err("stats_mask 0x%x contains unimplemented types\n" , |
2602 | stats_mask); |
2603 | return -EINVAL; |
2604 | } |
2605 | |
2606 | mutex_lock(&wcn->hal_mutex); |
2607 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_GET_STATS_REQ); |
2608 | |
2609 | msg_body.sta_id = sta_index; |
2610 | msg_body.stats_mask = stats_mask; |
2611 | |
2612 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
2613 | |
2614 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
2615 | if (ret) { |
2616 | wcn36xx_err("sending hal_get_stats failed\n" ); |
2617 | goto out; |
2618 | } |
2619 | |
2620 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
2621 | if (ret) { |
2622 | wcn36xx_err("hal_get_stats response failed err=%d\n" , ret); |
2623 | goto out; |
2624 | } |
2625 | |
2626 | rsp = (struct wcn36xx_hal_stats_rsp_msg *)wcn->hal_buf; |
2627 | rsp_body = (wcn->hal_buf + sizeof(struct wcn36xx_hal_stats_rsp_msg)); |
2628 | |
2629 | if (rsp->stats_mask != stats_mask) { |
2630 | wcn36xx_err("stats_mask 0x%x differs from requested 0x%x\n" , |
2631 | rsp->stats_mask, stats_mask); |
2632 | goto out; |
2633 | } |
2634 | |
2635 | if (rsp->stats_mask & HAL_GLOBAL_CLASS_A_STATS_INFO) { |
2636 | struct ani_global_class_a_stats_info *stats_info = rsp_body; |
2637 | |
2638 | wcn36xx_process_tx_rate(stats: stats_info, info: &sinfo->txrate); |
2639 | sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); |
2640 | rsp_body += sizeof(struct ani_global_class_a_stats_info); |
2641 | } |
2642 | out: |
2643 | mutex_unlock(lock: &wcn->hal_mutex); |
2644 | |
2645 | return ret; |
2646 | } |
2647 | |
2648 | static int wcn36xx_smd_trigger_ba_rsp(void *buf, int len, struct add_ba_info *ba_info) |
2649 | { |
2650 | struct wcn36xx_hal_trigger_ba_rsp_candidate *candidate; |
2651 | struct wcn36xx_hal_trigger_ba_rsp_msg *rsp; |
2652 | int i; |
2653 | |
2654 | if (len < sizeof(*rsp)) |
2655 | return -EINVAL; |
2656 | |
2657 | rsp = buf; |
2658 | |
2659 | if (rsp->candidate_cnt < 1) |
2660 | return rsp->status ? rsp->status : -EINVAL; |
2661 | |
2662 | candidate = (struct wcn36xx_hal_trigger_ba_rsp_candidate *)(buf + sizeof(*rsp)); |
2663 | |
2664 | for (i = 0; i < STACFG_MAX_TC; i++) { |
2665 | ba_info[i] = candidate->ba_info[i]; |
2666 | } |
2667 | |
2668 | return rsp->status; |
2669 | } |
2670 | |
2671 | int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index, u16 tid, u16 *ssn) |
2672 | { |
2673 | struct wcn36xx_hal_trigger_ba_req_msg msg_body; |
2674 | struct wcn36xx_hal_trigger_ba_req_candidate *candidate; |
2675 | struct add_ba_info ba_info[STACFG_MAX_TC]; |
2676 | int ret; |
2677 | |
2678 | if (tid >= STACFG_MAX_TC) |
2679 | return -EINVAL; |
2680 | |
2681 | mutex_lock(&wcn->hal_mutex); |
2682 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_TRIGGER_BA_REQ); |
2683 | |
2684 | msg_body.session_id = 0; /* not really used */ |
2685 | msg_body.candidate_cnt = 1; |
2686 | msg_body.header.len += sizeof(*candidate); |
2687 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
2688 | |
2689 | candidate = (struct wcn36xx_hal_trigger_ba_req_candidate *) |
2690 | (wcn->hal_buf + sizeof(msg_body)); |
2691 | candidate->sta_index = sta_index; |
2692 | candidate->tid_bitmap = 1 << tid; |
2693 | |
2694 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
2695 | if (ret) { |
2696 | wcn36xx_err("Sending hal_trigger_ba failed\n" ); |
2697 | goto out; |
2698 | } |
2699 | ret = wcn36xx_smd_trigger_ba_rsp(buf: wcn->hal_buf, len: wcn->hal_rsp_len, ba_info); |
2700 | if (ret) { |
2701 | wcn36xx_err("hal_trigger_ba response failed err=%d\n" , ret); |
2702 | goto out; |
2703 | } |
2704 | out: |
2705 | mutex_unlock(lock: &wcn->hal_mutex); |
2706 | |
2707 | if (ssn) |
2708 | *ssn = ba_info[tid].starting_seq_num; |
2709 | |
2710 | return ret; |
2711 | } |
2712 | |
2713 | static int wcn36xx_smd_tx_compl_ind(struct wcn36xx *wcn, void *buf, size_t len) |
2714 | { |
2715 | struct wcn36xx_hal_tx_compl_ind_msg *rsp = buf; |
2716 | |
2717 | if (len != sizeof(*rsp)) { |
2718 | wcn36xx_warn("Bad TX complete indication\n" ); |
2719 | return -EIO; |
2720 | } |
2721 | |
2722 | wcn36xx_dxe_tx_ack_ind(wcn, status: rsp->status); |
2723 | |
2724 | return 0; |
2725 | } |
2726 | |
2727 | static int wcn36xx_smd_hw_scan_ind(struct wcn36xx *wcn, void *buf, size_t len) |
2728 | { |
2729 | struct wcn36xx_hal_scan_offload_ind *rsp = buf; |
2730 | struct cfg80211_scan_info scan_info = {}; |
2731 | |
2732 | if (len != sizeof(*rsp)) { |
2733 | wcn36xx_warn("Corrupted delete scan indication\n" ); |
2734 | return -EIO; |
2735 | } |
2736 | |
2737 | wcn36xx_dbg(WCN36XX_DBG_HAL, "scan indication (type %x)\n" , rsp->type); |
2738 | |
2739 | switch (rsp->type) { |
2740 | case WCN36XX_HAL_SCAN_IND_FAILED: |
2741 | case WCN36XX_HAL_SCAN_IND_DEQUEUED: |
2742 | scan_info.aborted = true; |
2743 | fallthrough; |
2744 | case WCN36XX_HAL_SCAN_IND_COMPLETED: |
2745 | mutex_lock(&wcn->scan_lock); |
2746 | wcn->scan_req = NULL; |
2747 | if (wcn->scan_aborted) |
2748 | scan_info.aborted = true; |
2749 | mutex_unlock(lock: &wcn->scan_lock); |
2750 | ieee80211_scan_completed(hw: wcn->hw, info: &scan_info); |
2751 | break; |
2752 | case WCN36XX_HAL_SCAN_IND_STARTED: |
2753 | case WCN36XX_HAL_SCAN_IND_FOREIGN_CHANNEL: |
2754 | case WCN36XX_HAL_SCAN_IND_PREEMPTED: |
2755 | case WCN36XX_HAL_SCAN_IND_RESTARTED: |
2756 | break; |
2757 | default: |
2758 | wcn36xx_warn("Unknown scan indication type %x\n" , rsp->type); |
2759 | } |
2760 | |
2761 | return 0; |
2762 | } |
2763 | |
2764 | static int wcn36xx_smd_missed_beacon_ind(struct wcn36xx *wcn, |
2765 | void *buf, |
2766 | size_t len) |
2767 | { |
2768 | struct wcn36xx_hal_missed_beacon_ind_msg *rsp = buf; |
2769 | struct ieee80211_vif *vif = NULL; |
2770 | struct wcn36xx_vif *tmp; |
2771 | |
2772 | /* Old FW does not have bss index */ |
2773 | if (wcn36xx_is_fw_version(wcn, major: 1, minor: 2, version: 2, revision: 24)) { |
2774 | list_for_each_entry(tmp, &wcn->vif_list, list) { |
2775 | wcn36xx_dbg(WCN36XX_DBG_HAL, "beacon missed bss_index %d\n" , |
2776 | tmp->bss_index); |
2777 | vif = wcn36xx_priv_to_vif(vif_priv: tmp); |
2778 | ieee80211_beacon_loss(vif); |
2779 | } |
2780 | return 0; |
2781 | } |
2782 | |
2783 | if (len != sizeof(*rsp)) { |
2784 | wcn36xx_warn("Corrupted missed beacon indication\n" ); |
2785 | return -EIO; |
2786 | } |
2787 | |
2788 | list_for_each_entry(tmp, &wcn->vif_list, list) { |
2789 | if (tmp->bss_index == rsp->bss_index) { |
2790 | wcn36xx_dbg(WCN36XX_DBG_HAL, "beacon missed bss_index %d\n" , |
2791 | rsp->bss_index); |
2792 | vif = wcn36xx_priv_to_vif(vif_priv: tmp); |
2793 | ieee80211_beacon_loss(vif); |
2794 | return 0; |
2795 | } |
2796 | } |
2797 | |
2798 | wcn36xx_warn("BSS index %d not found\n" , rsp->bss_index); |
2799 | return -ENOENT; |
2800 | } |
2801 | |
2802 | static int wcn36xx_smd_delete_sta_context_ind(struct wcn36xx *wcn, |
2803 | void *buf, |
2804 | size_t len) |
2805 | { |
2806 | struct wcn36xx_hal_delete_sta_context_ind_msg *rsp = buf; |
2807 | struct wcn36xx_vif *vif_priv; |
2808 | struct ieee80211_vif *vif; |
2809 | struct ieee80211_bss_conf *bss_conf; |
2810 | struct ieee80211_sta *sta; |
2811 | bool found = false; |
2812 | |
2813 | if (len != sizeof(*rsp)) { |
2814 | wcn36xx_warn("Corrupted delete sta indication\n" ); |
2815 | return -EIO; |
2816 | } |
2817 | |
2818 | wcn36xx_dbg(WCN36XX_DBG_HAL, |
2819 | "delete station indication %pM index %d reason %d\n" , |
2820 | rsp->addr2, rsp->sta_id, rsp->reason_code); |
2821 | |
2822 | list_for_each_entry(vif_priv, &wcn->vif_list, list) { |
2823 | rcu_read_lock(); |
2824 | vif = wcn36xx_priv_to_vif(vif_priv); |
2825 | |
2826 | if (vif->type == NL80211_IFTYPE_STATION) { |
2827 | /* We could call ieee80211_find_sta too, but checking |
2828 | * bss_conf is clearer. |
2829 | */ |
2830 | bss_conf = &vif->bss_conf; |
2831 | if (vif_priv->sta_assoc && |
2832 | !memcmp(p: bss_conf->bssid, q: rsp->addr2, ETH_ALEN)) { |
2833 | found = true; |
2834 | wcn36xx_dbg(WCN36XX_DBG_HAL, |
2835 | "connection loss bss_index %d\n" , |
2836 | vif_priv->bss_index); |
2837 | ieee80211_connection_loss(vif); |
2838 | } |
2839 | } else { |
2840 | sta = ieee80211_find_sta(vif, addr: rsp->addr2); |
2841 | if (sta) { |
2842 | found = true; |
2843 | ieee80211_report_low_ack(sta, num_packets: 0); |
2844 | } |
2845 | } |
2846 | |
2847 | rcu_read_unlock(); |
2848 | if (found) |
2849 | return 0; |
2850 | } |
2851 | |
2852 | wcn36xx_warn("BSS or STA with addr %pM not found\n" , rsp->addr2); |
2853 | return -ENOENT; |
2854 | } |
2855 | |
2856 | static int wcn36xx_smd_print_reg_info_ind(struct wcn36xx *wcn, |
2857 | void *buf, |
2858 | size_t len) |
2859 | { |
2860 | struct wcn36xx_hal_print_reg_info_ind *rsp = buf; |
2861 | int i; |
2862 | |
2863 | if (len < sizeof(*rsp)) { |
2864 | wcn36xx_warn("Corrupted print reg info indication\n" ); |
2865 | return -EIO; |
2866 | } |
2867 | |
2868 | wcn36xx_dbg(WCN36XX_DBG_HAL, |
2869 | "reginfo indication, scenario: 0x%x reason: 0x%x\n" , |
2870 | rsp->scenario, rsp->reason); |
2871 | |
2872 | for (i = 0; i < rsp->count; i++) { |
2873 | wcn36xx_dbg(WCN36XX_DBG_HAL, "\t0x%x: 0x%x\n" , |
2874 | rsp->regs[i].addr, rsp->regs[i].value); |
2875 | } |
2876 | |
2877 | return 0; |
2878 | } |
2879 | |
2880 | int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value) |
2881 | { |
2882 | struct wcn36xx_hal_update_cfg_req_msg msg_body, *body; |
2883 | size_t len; |
2884 | int ret; |
2885 | |
2886 | mutex_lock(&wcn->hal_mutex); |
2887 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_UPDATE_CFG_REQ); |
2888 | |
2889 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
2890 | |
2891 | body = (struct wcn36xx_hal_update_cfg_req_msg *) wcn->hal_buf; |
2892 | len = msg_body.header.len; |
2893 | |
2894 | put_cfg_tlv_u32(wcn, len: &len, id: cfg_id, value); |
2895 | body->header.len = len; |
2896 | body->len = len - sizeof(*body); |
2897 | |
2898 | ret = wcn36xx_smd_send_and_wait(wcn, len: body->header.len); |
2899 | if (ret) { |
2900 | wcn36xx_err("Sending hal_update_cfg failed\n" ); |
2901 | goto out; |
2902 | } |
2903 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
2904 | if (ret) { |
2905 | wcn36xx_err("hal_update_cfg response failed err=%d\n" , ret); |
2906 | goto out; |
2907 | } |
2908 | out: |
2909 | mutex_unlock(lock: &wcn->hal_mutex); |
2910 | return ret; |
2911 | } |
2912 | |
2913 | int wcn36xx_smd_set_mc_list(struct wcn36xx *wcn, |
2914 | struct ieee80211_vif *vif, |
2915 | struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp) |
2916 | { |
2917 | struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); |
2918 | struct wcn36xx_hal_rcv_flt_pkt_set_mc_list_req_msg *msg_body = NULL; |
2919 | int ret; |
2920 | |
2921 | mutex_lock(&wcn->hal_mutex); |
2922 | |
2923 | msg_body = (struct wcn36xx_hal_rcv_flt_pkt_set_mc_list_req_msg *) |
2924 | wcn->hal_buf; |
2925 | INIT_HAL_MSG(*msg_body, WCN36XX_HAL_8023_MULTICAST_LIST_REQ); |
2926 | |
2927 | /* An empty list means all mc traffic will be received */ |
2928 | if (fp) |
2929 | memcpy(&msg_body->mc_addr_list, fp, |
2930 | sizeof(msg_body->mc_addr_list)); |
2931 | else |
2932 | msg_body->mc_addr_list.mc_addr_count = 0; |
2933 | |
2934 | msg_body->mc_addr_list.bss_index = vif_priv->bss_index; |
2935 | |
2936 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body->header.len); |
2937 | if (ret) { |
2938 | wcn36xx_err("Sending HAL_8023_MULTICAST_LIST failed\n" ); |
2939 | goto out; |
2940 | } |
2941 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
2942 | if (ret) { |
2943 | wcn36xx_err("HAL_8023_MULTICAST_LIST rsp failed err=%d\n" , ret); |
2944 | goto out; |
2945 | } |
2946 | out: |
2947 | mutex_unlock(lock: &wcn->hal_mutex); |
2948 | return ret; |
2949 | } |
2950 | |
2951 | int wcn36xx_smd_arp_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif, |
2952 | bool enable) |
2953 | { |
2954 | struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); |
2955 | struct wcn36xx_hal_host_offload_req_msg msg_body; |
2956 | int ret; |
2957 | |
2958 | mutex_lock(&wcn->hal_mutex); |
2959 | |
2960 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_HOST_OFFLOAD_REQ); |
2961 | msg_body.host_offload_params.offload_type = |
2962 | WCN36XX_HAL_IPV4_ARP_REPLY_OFFLOAD; |
2963 | if (enable) { |
2964 | msg_body.host_offload_params.enable = |
2965 | WCN36XX_HAL_OFFLOAD_ARP_AND_BCAST_FILTER_ENABLE; |
2966 | memcpy(&msg_body.host_offload_params.u, |
2967 | &vif->cfg.arp_addr_list[0], sizeof(__be32)); |
2968 | } |
2969 | msg_body.ns_offload_params.bss_index = vif_priv->bss_index; |
2970 | |
2971 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
2972 | |
2973 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
2974 | if (ret) { |
2975 | wcn36xx_err("Sending host_offload_arp failed\n" ); |
2976 | goto out; |
2977 | } |
2978 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
2979 | if (ret) { |
2980 | wcn36xx_err("host_offload_arp failed err=%d\n" , ret); |
2981 | goto out; |
2982 | } |
2983 | out: |
2984 | mutex_unlock(lock: &wcn->hal_mutex); |
2985 | return ret; |
2986 | } |
2987 | |
2988 | #if IS_ENABLED(CONFIG_IPV6) |
2989 | int wcn36xx_smd_ipv6_ns_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif, |
2990 | bool enable) |
2991 | { |
2992 | struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); |
2993 | struct wcn36xx_hal_host_offload_req_msg msg_body; |
2994 | struct wcn36xx_hal_ns_offload_params *ns_params; |
2995 | struct wcn36xx_hal_host_offload_req *ho_params; |
2996 | int ret; |
2997 | |
2998 | mutex_lock(&wcn->hal_mutex); |
2999 | |
3000 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_HOST_OFFLOAD_REQ); |
3001 | ho_params = &msg_body.host_offload_params; |
3002 | ns_params = &msg_body.ns_offload_params; |
3003 | |
3004 | ho_params->offload_type = WCN36XX_HAL_IPV6_NS_OFFLOAD; |
3005 | if (enable) { |
3006 | ho_params->enable = |
3007 | WCN36XX_HAL_OFFLOAD_NS_AND_MCAST_FILTER_ENABLE; |
3008 | if (vif_priv->num_target_ipv6_addrs) { |
3009 | memcpy(&ho_params->u, |
3010 | &vif_priv->target_ipv6_addrs[0].in6_u, |
3011 | sizeof(struct in6_addr)); |
3012 | memcpy(&ns_params->target_ipv6_addr1, |
3013 | &vif_priv->target_ipv6_addrs[0].in6_u, |
3014 | sizeof(struct in6_addr)); |
3015 | ns_params->target_ipv6_addr1_valid = 1; |
3016 | } |
3017 | if (vif_priv->num_target_ipv6_addrs > 1) { |
3018 | memcpy(&ns_params->target_ipv6_addr2, |
3019 | &vif_priv->target_ipv6_addrs[1].in6_u, |
3020 | sizeof(struct in6_addr)); |
3021 | ns_params->target_ipv6_addr2_valid = 1; |
3022 | } |
3023 | } |
3024 | memcpy(&ns_params->self_addr, vif->addr, ETH_ALEN); |
3025 | ns_params->bss_index = vif_priv->bss_index; |
3026 | |
3027 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
3028 | |
3029 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
3030 | if (ret) { |
3031 | wcn36xx_err("Sending host_offload_arp failed\n" ); |
3032 | goto out; |
3033 | } |
3034 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
3035 | if (ret) { |
3036 | wcn36xx_err("host_offload_arp failed err=%d\n" , ret); |
3037 | goto out; |
3038 | } |
3039 | out: |
3040 | mutex_unlock(lock: &wcn->hal_mutex); |
3041 | return ret; |
3042 | } |
3043 | #else |
3044 | int wcn36xx_smd_ipv6_ns_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif, |
3045 | bool enable) |
3046 | { |
3047 | return 0; |
3048 | } |
3049 | #endif |
3050 | |
3051 | int wcn36xx_smd_gtk_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif, |
3052 | bool enable) |
3053 | { |
3054 | struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); |
3055 | struct wcn36xx_hal_gtk_offload_req_msg msg_body; |
3056 | int ret; |
3057 | |
3058 | mutex_lock(&wcn->hal_mutex); |
3059 | |
3060 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_GTK_OFFLOAD_REQ); |
3061 | |
3062 | if (enable) { |
3063 | memcpy(&msg_body.kek, vif_priv->rekey_data.kek, NL80211_KEK_LEN); |
3064 | memcpy(&msg_body.kck, vif_priv->rekey_data.kck, NL80211_KCK_LEN); |
3065 | msg_body.key_replay_counter = |
3066 | le64_to_cpu(vif_priv->rekey_data.replay_ctr); |
3067 | msg_body.bss_index = vif_priv->bss_index; |
3068 | } else { |
3069 | msg_body.flags = WCN36XX_HAL_GTK_OFFLOAD_FLAGS_DISABLE; |
3070 | } |
3071 | |
3072 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
3073 | |
3074 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
3075 | if (ret) { |
3076 | wcn36xx_err("Sending host_offload_arp failed\n" ); |
3077 | goto out; |
3078 | } |
3079 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
3080 | if (ret) { |
3081 | wcn36xx_err("host_offload_arp failed err=%d\n" , ret); |
3082 | goto out; |
3083 | } |
3084 | out: |
3085 | mutex_unlock(lock: &wcn->hal_mutex); |
3086 | return ret; |
3087 | } |
3088 | |
3089 | static int wcn36xx_smd_gtk_offload_get_info_rsp(struct wcn36xx *wcn, |
3090 | struct ieee80211_vif *vif) |
3091 | { |
3092 | struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); |
3093 | struct wcn36xx_hal_gtk_offload_get_info_rsp_msg *rsp; |
3094 | __be64 replay_ctr; |
3095 | |
3096 | if (wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len)) |
3097 | return -EIO; |
3098 | |
3099 | rsp = (struct wcn36xx_hal_gtk_offload_get_info_rsp_msg *)wcn->hal_buf; |
3100 | |
3101 | if (rsp->bss_index != vif_priv->bss_index) { |
3102 | wcn36xx_err("gtk_offload_info invalid response bss index %d\n" , |
3103 | rsp->bss_index); |
3104 | return -ENOENT; |
3105 | } |
3106 | |
3107 | if (vif_priv->rekey_data.replay_ctr != cpu_to_le64(rsp->key_replay_counter)) { |
3108 | replay_ctr = cpu_to_be64(rsp->key_replay_counter); |
3109 | vif_priv->rekey_data.replay_ctr = |
3110 | cpu_to_le64(rsp->key_replay_counter); |
3111 | ieee80211_gtk_rekey_notify(vif, bssid: vif->bss_conf.bssid, |
3112 | replay_ctr: (void *)&replay_ctr, GFP_KERNEL); |
3113 | wcn36xx_dbg(WCN36XX_DBG_HAL, |
3114 | "GTK replay counter increment %llu\n" , |
3115 | rsp->key_replay_counter); |
3116 | } |
3117 | |
3118 | wcn36xx_dbg(WCN36XX_DBG_HAL, |
3119 | "gtk offload info status %d last_rekey_status %d " |
3120 | "replay_counter %llu total_rekey_count %d gtk_rekey_count %d " |
3121 | "igtk_rekey_count %d bss_index %d\n" , |
3122 | rsp->status, rsp->last_rekey_status, |
3123 | rsp->key_replay_counter, rsp->total_rekey_count, |
3124 | rsp->gtk_rekey_count, rsp->igtk_rekey_count, |
3125 | rsp->bss_index); |
3126 | |
3127 | return 0; |
3128 | } |
3129 | |
3130 | int wcn36xx_smd_gtk_offload_get_info(struct wcn36xx *wcn, |
3131 | struct ieee80211_vif *vif) |
3132 | { |
3133 | struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); |
3134 | struct wcn36xx_hal_gtk_offload_get_info_req_msg msg_body; |
3135 | int ret; |
3136 | |
3137 | mutex_lock(&wcn->hal_mutex); |
3138 | |
3139 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_GTK_OFFLOAD_GETINFO_REQ); |
3140 | |
3141 | msg_body.bss_index = vif_priv->bss_index; |
3142 | |
3143 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
3144 | |
3145 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
3146 | if (ret) { |
3147 | wcn36xx_err("Sending gtk_offload_get_info failed\n" ); |
3148 | goto out; |
3149 | } |
3150 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
3151 | if (ret) { |
3152 | wcn36xx_err("gtk_offload_get_info failed err=%d\n" , ret); |
3153 | goto out; |
3154 | } |
3155 | ret = wcn36xx_smd_gtk_offload_get_info_rsp(wcn, vif); |
3156 | out: |
3157 | mutex_unlock(lock: &wcn->hal_mutex); |
3158 | return ret; |
3159 | } |
3160 | |
3161 | int wcn36xx_smd_wlan_host_suspend_ind(struct wcn36xx *wcn) |
3162 | { |
3163 | struct wcn36xx_hal_wlan_host_suspend_ind_msg msg_body; |
3164 | int ret; |
3165 | |
3166 | mutex_lock(&wcn->hal_mutex); |
3167 | |
3168 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_HOST_SUSPEND_IND); |
3169 | msg_body.configured_mcst_bcst_filter_setting = 0; |
3170 | msg_body.active_session_count = 1; |
3171 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
3172 | |
3173 | ret = rpmsg_send(ept: wcn->smd_channel, data: wcn->hal_buf, len: msg_body.header.len); |
3174 | |
3175 | mutex_unlock(lock: &wcn->hal_mutex); |
3176 | |
3177 | return ret; |
3178 | } |
3179 | |
3180 | int wcn36xx_smd_host_resume(struct wcn36xx *wcn) |
3181 | { |
3182 | struct wcn36xx_hal_wlan_host_resume_req_msg msg_body; |
3183 | struct wcn36xx_hal_host_resume_rsp_msg *rsp; |
3184 | int ret; |
3185 | |
3186 | mutex_lock(&wcn->hal_mutex); |
3187 | |
3188 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_HOST_RESUME_REQ); |
3189 | msg_body.configured_mcst_bcst_filter_setting = 0; |
3190 | |
3191 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
3192 | |
3193 | ret = wcn36xx_smd_send_and_wait(wcn, len: msg_body.header.len); |
3194 | if (ret) { |
3195 | wcn36xx_err("Sending wlan_host_resume failed\n" ); |
3196 | goto out; |
3197 | } |
3198 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
3199 | if (ret) { |
3200 | wcn36xx_err("wlan_host_resume err=%d\n" , ret); |
3201 | goto out; |
3202 | } |
3203 | |
3204 | rsp = (struct wcn36xx_hal_host_resume_rsp_msg *)wcn->hal_buf; |
3205 | if (rsp->status) |
3206 | wcn36xx_warn("wlan_host_resume status=%d\n" , rsp->status); |
3207 | |
3208 | out: |
3209 | mutex_unlock(lock: &wcn->hal_mutex); |
3210 | |
3211 | return ret; |
3212 | } |
3213 | |
3214 | #define BEACON_FILTER(eid, presence, offs, val, mask, ref_val) \ |
3215 | { \ |
3216 | .element_id = eid, \ |
3217 | .check_ie_presence = presence, \ |
3218 | .offset = offs, \ |
3219 | .value = val, \ |
3220 | .bitmask = mask, \ |
3221 | .ref = ref_val, \ |
3222 | } |
3223 | |
3224 | static const struct beacon_filter_ie bcn_filter_ies[] = { |
3225 | BEACON_FILTER(WLAN_EID_DS_PARAMS, 0, 0, 0, |
3226 | WCN36XX_FILTER_IE_DS_CHANNEL_MASK, 0), |
3227 | BEACON_FILTER(WLAN_EID_ERP_INFO, 0, 0, 0, |
3228 | WCN36XX_FILTER_IE_ERP_FILTER_MASK, 0), |
3229 | BEACON_FILTER(WLAN_EID_EDCA_PARAM_SET, 0, 0, 0, |
3230 | WCN36XX_FILTER_IE_EDCA_FILTER_MASK, 0), |
3231 | BEACON_FILTER(WLAN_EID_QOS_CAPA, 0, 0, 0, |
3232 | WCN36XX_FILTER_IE_QOS_FILTER_MASK, 0), |
3233 | BEACON_FILTER(WLAN_EID_CHANNEL_SWITCH, 1, 0, 0, |
3234 | WCN36XX_FILTER_IE_CHANNEL_SWITCH_MASK, 0), |
3235 | BEACON_FILTER(WLAN_EID_HT_OPERATION, 0, 0, 0, |
3236 | WCN36XX_FILTER_IE_HT_BYTE0_FILTER_MASK, 0), |
3237 | BEACON_FILTER(WLAN_EID_HT_OPERATION, 0, 2, 0, |
3238 | WCN36XX_FILTER_IE_HT_BYTE2_FILTER_MASK, 0), |
3239 | BEACON_FILTER(WLAN_EID_HT_OPERATION, 0, 5, 0, |
3240 | WCN36XX_FILTER_IE_HT_BYTE5_FILTER_MASK, 0), |
3241 | BEACON_FILTER(WLAN_EID_PWR_CONSTRAINT, 0, 0, 0, |
3242 | WCN36XX_FILTER_IE_PWR_CONSTRAINT_MASK, 0), |
3243 | BEACON_FILTER(WLAN_EID_OPMODE_NOTIF, 0, 0, 0, |
3244 | WCN36XX_FILTER_IE_OPMODE_NOTIF_MASK, 0), |
3245 | BEACON_FILTER(WLAN_EID_VHT_OPERATION, 0, 0, 0, |
3246 | WCN36XX_FILTER_IE_VHTOP_CHWIDTH_MASK, 0), |
3247 | BEACON_FILTER(WLAN_EID_RSN, 1, 0, 0, |
3248 | WCN36XX_FILTER_IE_RSN_MASK, 0), |
3249 | BEACON_FILTER(WLAN_EID_VENDOR_SPECIFIC, 1, 0, 0, |
3250 | WCN36XX_FILTER_IE_VENDOR_MASK, 0), |
3251 | }; |
3252 | |
3253 | int wcn36xx_smd_add_beacon_filter(struct wcn36xx *wcn, |
3254 | struct ieee80211_vif *vif) |
3255 | { |
3256 | struct wcn36xx_hal_add_bcn_filter_req_msg msg_body, *body; |
3257 | struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); |
3258 | u8 *payload; |
3259 | size_t payload_size; |
3260 | int ret; |
3261 | |
3262 | if (!wcn36xx_firmware_get_feat_caps(bitmap: wcn->fw_feat_caps, cap: BCN_FILTER)) |
3263 | return -EOPNOTSUPP; |
3264 | |
3265 | mutex_lock(&wcn->hal_mutex); |
3266 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_ADD_BCN_FILTER_REQ); |
3267 | |
3268 | PREPARE_HAL_BUF(wcn->hal_buf, msg_body); |
3269 | |
3270 | body = (struct wcn36xx_hal_add_bcn_filter_req_msg *)wcn->hal_buf; |
3271 | body->capability_info = vif->bss_conf.assoc_capability; |
3272 | body->capability_mask = WCN36XX_FILTER_CAPABILITY_MASK; |
3273 | body->beacon_interval = vif->bss_conf.beacon_int; |
3274 | body->ie_num = ARRAY_SIZE(bcn_filter_ies); |
3275 | body->bss_index = vif_priv->bss_index; |
3276 | |
3277 | payload = ((u8 *)body) + body->header.len; |
3278 | payload_size = sizeof(bcn_filter_ies); |
3279 | memcpy(payload, &bcn_filter_ies, payload_size); |
3280 | |
3281 | body->header.len += payload_size; |
3282 | |
3283 | ret = wcn36xx_smd_send_and_wait(wcn, len: body->header.len); |
3284 | if (ret) { |
3285 | wcn36xx_err("Sending add bcn_filter failed\n" ); |
3286 | goto out; |
3287 | } |
3288 | |
3289 | ret = wcn36xx_smd_rsp_status_check(buf: wcn->hal_buf, len: wcn->hal_rsp_len); |
3290 | if (ret) { |
3291 | wcn36xx_err("add bcn filter response failed err=%d\n" , ret); |
3292 | goto out; |
3293 | } |
3294 | out: |
3295 | mutex_unlock(lock: &wcn->hal_mutex); |
3296 | return ret; |
3297 | } |
3298 | |
3299 | int wcn36xx_smd_rsp_process(struct rpmsg_device *rpdev, |
3300 | void *buf, int len, void *priv, u32 addr) |
3301 | { |
3302 | const struct wcn36xx_hal_msg_header * = buf; |
3303 | struct ieee80211_hw *hw = priv; |
3304 | struct wcn36xx *wcn = hw->priv; |
3305 | struct wcn36xx_hal_ind_msg *msg_ind; |
3306 | wcn36xx_dbg_dump(WCN36XX_DBG_SMD_DUMP, "SMD <<< " , buf, len); |
3307 | |
3308 | switch (msg_header->msg_type) { |
3309 | case WCN36XX_HAL_START_RSP: |
3310 | case WCN36XX_HAL_CONFIG_STA_RSP: |
3311 | case WCN36XX_HAL_CONFIG_BSS_RSP: |
3312 | case WCN36XX_HAL_ADD_STA_SELF_RSP: |
3313 | case WCN36XX_HAL_STOP_RSP: |
3314 | case WCN36XX_HAL_DEL_STA_SELF_RSP: |
3315 | case WCN36XX_HAL_DELETE_STA_RSP: |
3316 | case WCN36XX_HAL_INIT_SCAN_RSP: |
3317 | case WCN36XX_HAL_START_SCAN_RSP: |
3318 | case WCN36XX_HAL_END_SCAN_RSP: |
3319 | case WCN36XX_HAL_FINISH_SCAN_RSP: |
3320 | case WCN36XX_HAL_DOWNLOAD_NV_RSP: |
3321 | case WCN36XX_HAL_DELETE_BSS_RSP: |
3322 | case WCN36XX_HAL_SEND_BEACON_RSP: |
3323 | case WCN36XX_HAL_SET_LINK_ST_RSP: |
3324 | case WCN36XX_HAL_UPDATE_PROBE_RSP_TEMPLATE_RSP: |
3325 | case WCN36XX_HAL_SET_BSSKEY_RSP: |
3326 | case WCN36XX_HAL_SET_STAKEY_RSP: |
3327 | case WCN36XX_HAL_RMV_STAKEY_RSP: |
3328 | case WCN36XX_HAL_RMV_BSSKEY_RSP: |
3329 | case WCN36XX_HAL_ENTER_BMPS_RSP: |
3330 | case WCN36XX_HAL_SET_POWER_PARAMS_RSP: |
3331 | case WCN36XX_HAL_EXIT_BMPS_RSP: |
3332 | case WCN36XX_HAL_KEEP_ALIVE_RSP: |
3333 | case WCN36XX_HAL_DUMP_COMMAND_RSP: |
3334 | case WCN36XX_HAL_ADD_BA_SESSION_RSP: |
3335 | case WCN36XX_HAL_ADD_BA_RSP: |
3336 | case WCN36XX_HAL_DEL_BA_RSP: |
3337 | case WCN36XX_HAL_GET_STATS_RSP: |
3338 | case WCN36XX_HAL_TRIGGER_BA_RSP: |
3339 | case WCN36XX_HAL_UPDATE_CFG_RSP: |
3340 | case WCN36XX_HAL_JOIN_RSP: |
3341 | case WCN36XX_HAL_UPDATE_SCAN_PARAM_RSP: |
3342 | case WCN36XX_HAL_CH_SWITCH_RSP: |
3343 | case WCN36XX_HAL_PROCESS_PTT_RSP: |
3344 | case WCN36XX_HAL_FEATURE_CAPS_EXCHANGE_RSP: |
3345 | case WCN36XX_HAL_8023_MULTICAST_LIST_RSP: |
3346 | case WCN36XX_HAL_START_SCAN_OFFLOAD_RSP: |
3347 | case WCN36XX_HAL_STOP_SCAN_OFFLOAD_RSP: |
3348 | case WCN36XX_HAL_HOST_OFFLOAD_RSP: |
3349 | case WCN36XX_HAL_GTK_OFFLOAD_RSP: |
3350 | case WCN36XX_HAL_GTK_OFFLOAD_GETINFO_RSP: |
3351 | case WCN36XX_HAL_HOST_RESUME_RSP: |
3352 | case WCN36XX_HAL_ENTER_IMPS_RSP: |
3353 | case WCN36XX_HAL_EXIT_IMPS_RSP: |
3354 | case WCN36XX_HAL_UPDATE_CHANNEL_LIST_RSP: |
3355 | case WCN36XX_HAL_ADD_BCN_FILTER_RSP: |
3356 | memcpy(wcn->hal_buf, buf, len); |
3357 | wcn->hal_rsp_len = len; |
3358 | complete(&wcn->hal_rsp_compl); |
3359 | break; |
3360 | |
3361 | case WCN36XX_HAL_COEX_IND: |
3362 | case WCN36XX_HAL_AVOID_FREQ_RANGE_IND: |
3363 | case WCN36XX_HAL_DEL_BA_IND: |
3364 | case WCN36XX_HAL_OTA_TX_COMPL_IND: |
3365 | case WCN36XX_HAL_MISSED_BEACON_IND: |
3366 | case WCN36XX_HAL_DELETE_STA_CONTEXT_IND: |
3367 | case WCN36XX_HAL_PRINT_REG_INFO_IND: |
3368 | case WCN36XX_HAL_SCAN_OFFLOAD_IND: |
3369 | msg_ind = kmalloc(struct_size(msg_ind, msg, len), GFP_ATOMIC); |
3370 | if (!msg_ind) { |
3371 | wcn36xx_err("Run out of memory while handling SMD_EVENT (%d)\n" , |
3372 | msg_header->msg_type); |
3373 | return -ENOMEM; |
3374 | } |
3375 | |
3376 | msg_ind->msg_len = len; |
3377 | memcpy(msg_ind->msg, buf, len); |
3378 | |
3379 | spin_lock(lock: &wcn->hal_ind_lock); |
3380 | list_add_tail(new: &msg_ind->list, head: &wcn->hal_ind_queue); |
3381 | queue_work(wq: wcn->hal_ind_wq, work: &wcn->hal_ind_work); |
3382 | spin_unlock(lock: &wcn->hal_ind_lock); |
3383 | wcn36xx_dbg(WCN36XX_DBG_HAL, "indication arrived\n" ); |
3384 | break; |
3385 | default: |
3386 | wcn36xx_err("SMD_EVENT (%d) not supported\n" , |
3387 | msg_header->msg_type); |
3388 | } |
3389 | |
3390 | return 0; |
3391 | } |
3392 | |
3393 | static void wcn36xx_ind_smd_work(struct work_struct *work) |
3394 | { |
3395 | struct wcn36xx *wcn = |
3396 | container_of(work, struct wcn36xx, hal_ind_work); |
3397 | |
3398 | for (;;) { |
3399 | struct wcn36xx_hal_msg_header *; |
3400 | struct wcn36xx_hal_ind_msg *hal_ind_msg; |
3401 | unsigned long flags; |
3402 | |
3403 | spin_lock_irqsave(&wcn->hal_ind_lock, flags); |
3404 | |
3405 | if (list_empty(head: &wcn->hal_ind_queue)) { |
3406 | spin_unlock_irqrestore(lock: &wcn->hal_ind_lock, flags); |
3407 | return; |
3408 | } |
3409 | |
3410 | hal_ind_msg = list_first_entry(&wcn->hal_ind_queue, |
3411 | struct wcn36xx_hal_ind_msg, |
3412 | list); |
3413 | list_del(entry: &hal_ind_msg->list); |
3414 | spin_unlock_irqrestore(lock: &wcn->hal_ind_lock, flags); |
3415 | |
3416 | msg_header = (struct wcn36xx_hal_msg_header *)hal_ind_msg->msg; |
3417 | |
3418 | switch (msg_header->msg_type) { |
3419 | case WCN36XX_HAL_COEX_IND: |
3420 | case WCN36XX_HAL_DEL_BA_IND: |
3421 | case WCN36XX_HAL_AVOID_FREQ_RANGE_IND: |
3422 | break; |
3423 | case WCN36XX_HAL_OTA_TX_COMPL_IND: |
3424 | wcn36xx_smd_tx_compl_ind(wcn, |
3425 | buf: hal_ind_msg->msg, |
3426 | len: hal_ind_msg->msg_len); |
3427 | break; |
3428 | case WCN36XX_HAL_MISSED_BEACON_IND: |
3429 | wcn36xx_smd_missed_beacon_ind(wcn, |
3430 | buf: hal_ind_msg->msg, |
3431 | len: hal_ind_msg->msg_len); |
3432 | break; |
3433 | case WCN36XX_HAL_DELETE_STA_CONTEXT_IND: |
3434 | wcn36xx_smd_delete_sta_context_ind(wcn, |
3435 | buf: hal_ind_msg->msg, |
3436 | len: hal_ind_msg->msg_len); |
3437 | break; |
3438 | case WCN36XX_HAL_PRINT_REG_INFO_IND: |
3439 | wcn36xx_smd_print_reg_info_ind(wcn, |
3440 | buf: hal_ind_msg->msg, |
3441 | len: hal_ind_msg->msg_len); |
3442 | break; |
3443 | case WCN36XX_HAL_SCAN_OFFLOAD_IND: |
3444 | wcn36xx_smd_hw_scan_ind(wcn, buf: hal_ind_msg->msg, |
3445 | len: hal_ind_msg->msg_len); |
3446 | break; |
3447 | default: |
3448 | wcn36xx_err("SMD_EVENT (%d) not supported\n" , |
3449 | msg_header->msg_type); |
3450 | } |
3451 | |
3452 | kfree(objp: hal_ind_msg); |
3453 | } |
3454 | } |
3455 | |
3456 | int wcn36xx_smd_open(struct wcn36xx *wcn) |
3457 | { |
3458 | wcn->hal_ind_wq = create_freezable_workqueue("wcn36xx_smd_ind" ); |
3459 | if (!wcn->hal_ind_wq) |
3460 | return -ENOMEM; |
3461 | |
3462 | INIT_WORK(&wcn->hal_ind_work, wcn36xx_ind_smd_work); |
3463 | INIT_LIST_HEAD(list: &wcn->hal_ind_queue); |
3464 | spin_lock_init(&wcn->hal_ind_lock); |
3465 | |
3466 | return 0; |
3467 | } |
3468 | |
3469 | void wcn36xx_smd_close(struct wcn36xx *wcn) |
3470 | { |
3471 | struct wcn36xx_hal_ind_msg *msg, *tmp; |
3472 | |
3473 | cancel_work_sync(work: &wcn->hal_ind_work); |
3474 | destroy_workqueue(wq: wcn->hal_ind_wq); |
3475 | |
3476 | list_for_each_entry_safe(msg, tmp, &wcn->hal_ind_queue, list) |
3477 | kfree(objp: msg); |
3478 | } |
3479 | |