]>
Commit | Line | Data |
---|---|---|
5e3dd157 KV |
1 | /* |
2 | * Copyright (c) 2005-2011 Atheros Communications Inc. | |
3 | * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. | |
4 | * | |
5 | * Permission to use, copy, modify, and/or distribute this software for any | |
6 | * purpose with or without fee is hereby granted, provided that the above | |
7 | * copyright notice and this permission notice appear in all copies. | |
8 | * | |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
16 | */ | |
17 | ||
18 | #include <linux/module.h> | |
19 | #include <linux/firmware.h> | |
5aabff05 | 20 | #include <linux/of.h> |
5e3dd157 KV |
21 | |
22 | #include "core.h" | |
23 | #include "mac.h" | |
24 | #include "htc.h" | |
25 | #include "hif.h" | |
26 | #include "wmi.h" | |
27 | #include "bmi.h" | |
28 | #include "debug.h" | |
29 | #include "htt.h" | |
43d2a30f | 30 | #include "testmode.h" |
d7579d12 | 31 | #include "wmi-ops.h" |
5e3dd157 KV |
32 | |
33 | unsigned int ath10k_debug_mask; | |
ccec9038 | 34 | static unsigned int ath10k_cryptmode_param; |
5e3dd157 | 35 | static bool uart_print; |
8868b12c | 36 | static bool skip_otp; |
b6c7bafa | 37 | static bool rawmode; |
8868b12c | 38 | |
5e3dd157 | 39 | module_param_named(debug_mask, ath10k_debug_mask, uint, 0644); |
ccec9038 | 40 | module_param_named(cryptmode, ath10k_cryptmode_param, uint, 0644); |
5e3dd157 | 41 | module_param(uart_print, bool, 0644); |
8868b12c | 42 | module_param(skip_otp, bool, 0644); |
b6c7bafa | 43 | module_param(rawmode, bool, 0644); |
8868b12c | 44 | |
5e3dd157 KV |
45 | MODULE_PARM_DESC(debug_mask, "Debugging mask"); |
46 | MODULE_PARM_DESC(uart_print, "Uart target debugging"); | |
8868b12c | 47 | MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); |
ccec9038 | 48 | MODULE_PARM_DESC(cryptmode, "Crypto mode: 0-hardware, 1-software"); |
b6c7bafa | 49 | MODULE_PARM_DESC(rawmode, "Use raw 802.11 frame datapath"); |
5e3dd157 KV |
50 | |
51 | static const struct ath10k_hw_params ath10k_hw_params_list[] = { | |
5e3dd157 KV |
52 | { |
53 | .id = QCA988X_HW_2_0_VERSION, | |
54 | .name = "qca988x hw2.0", | |
55 | .patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR, | |
3a8200b2 | 56 | .uart_pin = 7, |
587f7031 | 57 | .has_shifted_cc_wraparound = true, |
d772703e | 58 | .otp_exe_param = 0, |
9c8fb548 | 59 | .channel_counters_freq_hz = 88000, |
7b7da0a0 | 60 | .max_probe_resp_desc_thres = 0, |
b8d55fca | 61 | .hw_4addr_pad = ATH10K_HW_4ADDR_PAD_AFTER, |
5e3dd157 KV |
62 | .fw = { |
63 | .dir = QCA988X_HW_2_0_FW_DIR, | |
64 | .fw = QCA988X_HW_2_0_FW_FILE, | |
65 | .otp = QCA988X_HW_2_0_OTP_FILE, | |
66 | .board = QCA988X_HW_2_0_BOARD_DATA_FILE, | |
9764a2af MK |
67 | .board_size = QCA988X_BOARD_DATA_SZ, |
68 | .board_ext_size = QCA988X_BOARD_EXT_DATA_SZ, | |
5e3dd157 KV |
69 | }, |
70 | }, | |
d63955b3 MK |
71 | { |
72 | .id = QCA6174_HW_2_1_VERSION, | |
73 | .name = "qca6174 hw2.1", | |
74 | .patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR, | |
75 | .uart_pin = 6, | |
d772703e | 76 | .otp_exe_param = 0, |
9c8fb548 | 77 | .channel_counters_freq_hz = 88000, |
7b7da0a0 | 78 | .max_probe_resp_desc_thres = 0, |
b8d55fca | 79 | .hw_4addr_pad = ATH10K_HW_4ADDR_PAD_AFTER, |
d63955b3 MK |
80 | .fw = { |
81 | .dir = QCA6174_HW_2_1_FW_DIR, | |
82 | .fw = QCA6174_HW_2_1_FW_FILE, | |
83 | .otp = QCA6174_HW_2_1_OTP_FILE, | |
84 | .board = QCA6174_HW_2_1_BOARD_DATA_FILE, | |
85 | .board_size = QCA6174_BOARD_DATA_SZ, | |
86 | .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ, | |
87 | }, | |
88 | }, | |
89 | { | |
90 | .id = QCA6174_HW_3_0_VERSION, | |
91 | .name = "qca6174 hw3.0", | |
92 | .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR, | |
93 | .uart_pin = 6, | |
d772703e | 94 | .otp_exe_param = 0, |
9c8fb548 | 95 | .channel_counters_freq_hz = 88000, |
7b7da0a0 | 96 | .max_probe_resp_desc_thres = 0, |
b8d55fca | 97 | .hw_4addr_pad = ATH10K_HW_4ADDR_PAD_AFTER, |
d63955b3 MK |
98 | .fw = { |
99 | .dir = QCA6174_HW_3_0_FW_DIR, | |
100 | .fw = QCA6174_HW_3_0_FW_FILE, | |
101 | .otp = QCA6174_HW_3_0_OTP_FILE, | |
102 | .board = QCA6174_HW_3_0_BOARD_DATA_FILE, | |
103 | .board_size = QCA6174_BOARD_DATA_SZ, | |
104 | .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ, | |
105 | }, | |
106 | }, | |
608b8f73 MK |
107 | { |
108 | .id = QCA6174_HW_3_2_VERSION, | |
109 | .name = "qca6174 hw3.2", | |
110 | .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR, | |
111 | .uart_pin = 6, | |
d772703e | 112 | .otp_exe_param = 0, |
9c8fb548 | 113 | .channel_counters_freq_hz = 88000, |
7b7da0a0 | 114 | .max_probe_resp_desc_thres = 0, |
b8d55fca | 115 | .hw_4addr_pad = ATH10K_HW_4ADDR_PAD_AFTER, |
608b8f73 MK |
116 | .fw = { |
117 | /* uses same binaries as hw3.0 */ | |
118 | .dir = QCA6174_HW_3_0_FW_DIR, | |
119 | .fw = QCA6174_HW_3_0_FW_FILE, | |
120 | .otp = QCA6174_HW_3_0_OTP_FILE, | |
121 | .board = QCA6174_HW_3_0_BOARD_DATA_FILE, | |
122 | .board_size = QCA6174_BOARD_DATA_SZ, | |
123 | .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ, | |
124 | }, | |
125 | }, | |
8bd47021 VT |
126 | { |
127 | .id = QCA99X0_HW_2_0_DEV_VERSION, | |
128 | .name = "qca99x0 hw2.0", | |
129 | .patch_load_addr = QCA99X0_HW_2_0_PATCH_LOAD_ADDR, | |
130 | .uart_pin = 7, | |
d772703e | 131 | .otp_exe_param = 0x00000700, |
d9156b5f | 132 | .continuous_frag_desc = true, |
9c8fb548 | 133 | .channel_counters_freq_hz = 150000, |
7b7da0a0 | 134 | .max_probe_resp_desc_thres = 24, |
b8d55fca | 135 | .hw_4addr_pad = ATH10K_HW_4ADDR_PAD_BEFORE, |
8bd47021 VT |
136 | .fw = { |
137 | .dir = QCA99X0_HW_2_0_FW_DIR, | |
138 | .fw = QCA99X0_HW_2_0_FW_FILE, | |
139 | .otp = QCA99X0_HW_2_0_OTP_FILE, | |
140 | .board = QCA99X0_HW_2_0_BOARD_DATA_FILE, | |
141 | .board_size = QCA99X0_BOARD_DATA_SZ, | |
142 | .board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ, | |
143 | }, | |
144 | }, | |
a226b519 BM |
145 | { |
146 | .id = QCA9377_HW_1_0_DEV_VERSION, | |
147 | .name = "qca9377 hw1.0", | |
148 | .patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR, | |
149 | .uart_pin = 7, | |
150 | .otp_exe_param = 0, | |
151 | .fw = { | |
152 | .dir = QCA9377_HW_1_0_FW_DIR, | |
153 | .fw = QCA9377_HW_1_0_FW_FILE, | |
154 | .otp = QCA9377_HW_1_0_OTP_FILE, | |
155 | .board = QCA9377_HW_1_0_BOARD_DATA_FILE, | |
156 | .board_size = QCA9377_BOARD_DATA_SZ, | |
157 | .board_ext_size = QCA9377_BOARD_EXT_DATA_SZ, | |
158 | }, | |
159 | }, | |
5e3dd157 KV |
160 | }; |
161 | ||
b27bc5a4 MK |
162 | static const char *const ath10k_core_fw_feature_str[] = { |
163 | [ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX] = "wmi-mgmt-rx", | |
164 | [ATH10K_FW_FEATURE_WMI_10X] = "wmi-10.x", | |
165 | [ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX] = "has-wmi-mgmt-tx", | |
166 | [ATH10K_FW_FEATURE_NO_P2P] = "no-p2p", | |
167 | [ATH10K_FW_FEATURE_WMI_10_2] = "wmi-10.2", | |
168 | [ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT] = "multi-vif-ps", | |
169 | [ATH10K_FW_FEATURE_WOWLAN_SUPPORT] = "wowlan", | |
170 | [ATH10K_FW_FEATURE_IGNORE_OTP_RESULT] = "ignore-otp", | |
171 | [ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING] = "no-4addr-pad", | |
172 | [ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT] = "skip-clock-init", | |
5af82fa6 | 173 | [ATH10K_FW_FEATURE_RAW_MODE_SUPPORT] = "raw-mode", |
62f77f09 | 174 | [ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA] = "adaptive-cca", |
90eceb3b | 175 | [ATH10K_FW_FEATURE_MFP_SUPPORT] = "mfp", |
b27bc5a4 MK |
176 | }; |
177 | ||
178 | static unsigned int ath10k_core_get_fw_feature_str(char *buf, | |
179 | size_t buf_len, | |
180 | enum ath10k_fw_features feat) | |
181 | { | |
5af82fa6 KV |
182 | /* make sure that ath10k_core_fw_feature_str[] gets updated */ |
183 | BUILD_BUG_ON(ARRAY_SIZE(ath10k_core_fw_feature_str) != | |
184 | ATH10K_FW_FEATURE_COUNT); | |
185 | ||
b27bc5a4 MK |
186 | if (feat >= ARRAY_SIZE(ath10k_core_fw_feature_str) || |
187 | WARN_ON(!ath10k_core_fw_feature_str[feat])) { | |
188 | return scnprintf(buf, buf_len, "bit%d", feat); | |
189 | } | |
190 | ||
191 | return scnprintf(buf, buf_len, "%s", ath10k_core_fw_feature_str[feat]); | |
192 | } | |
193 | ||
194 | void ath10k_core_get_fw_features_str(struct ath10k *ar, | |
195 | char *buf, | |
196 | size_t buf_len) | |
197 | { | |
198 | unsigned int len = 0; | |
199 | int i; | |
200 | ||
201 | for (i = 0; i < ATH10K_FW_FEATURE_COUNT; i++) { | |
202 | if (test_bit(i, ar->fw_features)) { | |
203 | if (len > 0) | |
204 | len += scnprintf(buf + len, buf_len - len, ","); | |
205 | ||
206 | len += ath10k_core_get_fw_feature_str(buf + len, | |
207 | buf_len - len, | |
208 | i); | |
209 | } | |
210 | } | |
211 | } | |
212 | ||
5e3dd157 KV |
213 | static void ath10k_send_suspend_complete(struct ath10k *ar) |
214 | { | |
7aa7a72a | 215 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot suspend complete\n"); |
5e3dd157 | 216 | |
9042e17d | 217 | complete(&ar->target_suspend); |
5e3dd157 KV |
218 | } |
219 | ||
5e3dd157 KV |
220 | static int ath10k_init_configure_target(struct ath10k *ar) |
221 | { | |
222 | u32 param_host; | |
223 | int ret; | |
224 | ||
225 | /* tell target which HTC version it is used*/ | |
226 | ret = ath10k_bmi_write32(ar, hi_app_host_interest, | |
227 | HTC_PROTOCOL_VERSION); | |
228 | if (ret) { | |
7aa7a72a | 229 | ath10k_err(ar, "settings HTC version failed\n"); |
5e3dd157 KV |
230 | return ret; |
231 | } | |
232 | ||
233 | /* set the firmware mode to STA/IBSS/AP */ | |
234 | ret = ath10k_bmi_read32(ar, hi_option_flag, ¶m_host); | |
235 | if (ret) { | |
7aa7a72a | 236 | ath10k_err(ar, "setting firmware mode (1/2) failed\n"); |
5e3dd157 KV |
237 | return ret; |
238 | } | |
239 | ||
240 | /* TODO following parameters need to be re-visited. */ | |
241 | /* num_device */ | |
242 | param_host |= (1 << HI_OPTION_NUM_DEV_SHIFT); | |
243 | /* Firmware mode */ | |
244 | /* FIXME: Why FW_MODE_AP ??.*/ | |
245 | param_host |= (HI_OPTION_FW_MODE_AP << HI_OPTION_FW_MODE_SHIFT); | |
246 | /* mac_addr_method */ | |
247 | param_host |= (1 << HI_OPTION_MAC_ADDR_METHOD_SHIFT); | |
248 | /* firmware_bridge */ | |
249 | param_host |= (0 << HI_OPTION_FW_BRIDGE_SHIFT); | |
250 | /* fwsubmode */ | |
251 | param_host |= (0 << HI_OPTION_FW_SUBMODE_SHIFT); | |
252 | ||
253 | ret = ath10k_bmi_write32(ar, hi_option_flag, param_host); | |
254 | if (ret) { | |
7aa7a72a | 255 | ath10k_err(ar, "setting firmware mode (2/2) failed\n"); |
5e3dd157 KV |
256 | return ret; |
257 | } | |
258 | ||
259 | /* We do all byte-swapping on the host */ | |
260 | ret = ath10k_bmi_write32(ar, hi_be, 0); | |
261 | if (ret) { | |
7aa7a72a | 262 | ath10k_err(ar, "setting host CPU BE mode failed\n"); |
5e3dd157 KV |
263 | return ret; |
264 | } | |
265 | ||
266 | /* FW descriptor/Data swap flags */ | |
267 | ret = ath10k_bmi_write32(ar, hi_fw_swap, 0); | |
268 | ||
269 | if (ret) { | |
7aa7a72a | 270 | ath10k_err(ar, "setting FW data/desc swap flags failed\n"); |
5e3dd157 KV |
271 | return ret; |
272 | } | |
273 | ||
36582e5d MK |
274 | /* Some devices have a special sanity check that verifies the PCI |
275 | * Device ID is written to this host interest var. It is known to be | |
276 | * required to boot QCA6164. | |
277 | */ | |
278 | ret = ath10k_bmi_write32(ar, hi_hci_uart_pwr_mgmt_params_ext, | |
279 | ar->dev_id); | |
280 | if (ret) { | |
281 | ath10k_err(ar, "failed to set pwr_mgmt_params: %d\n", ret); | |
282 | return ret; | |
283 | } | |
284 | ||
5e3dd157 KV |
285 | return 0; |
286 | } | |
287 | ||
288 | static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, | |
289 | const char *dir, | |
290 | const char *file) | |
291 | { | |
292 | char filename[100]; | |
293 | const struct firmware *fw; | |
294 | int ret; | |
295 | ||
296 | if (file == NULL) | |
297 | return ERR_PTR(-ENOENT); | |
298 | ||
299 | if (dir == NULL) | |
300 | dir = "."; | |
301 | ||
302 | snprintf(filename, sizeof(filename), "%s/%s", dir, file); | |
303 | ret = request_firmware(&fw, filename, ar->dev); | |
304 | if (ret) | |
305 | return ERR_PTR(ret); | |
306 | ||
307 | return fw; | |
308 | } | |
309 | ||
a58227ef KV |
310 | static int ath10k_push_board_ext_data(struct ath10k *ar, const void *data, |
311 | size_t data_len) | |
5e3dd157 | 312 | { |
9764a2af MK |
313 | u32 board_data_size = ar->hw_params.fw.board_size; |
314 | u32 board_ext_data_size = ar->hw_params.fw.board_ext_size; | |
5e3dd157 KV |
315 | u32 board_ext_data_addr; |
316 | int ret; | |
317 | ||
318 | ret = ath10k_bmi_read32(ar, hi_board_ext_data, &board_ext_data_addr); | |
319 | if (ret) { | |
7aa7a72a MK |
320 | ath10k_err(ar, "could not read board ext data addr (%d)\n", |
321 | ret); | |
5e3dd157 KV |
322 | return ret; |
323 | } | |
324 | ||
7aa7a72a | 325 | ath10k_dbg(ar, ATH10K_DBG_BOOT, |
effea968 | 326 | "boot push board extended data addr 0x%x\n", |
5e3dd157 KV |
327 | board_ext_data_addr); |
328 | ||
329 | if (board_ext_data_addr == 0) | |
330 | return 0; | |
331 | ||
a58227ef | 332 | if (data_len != (board_data_size + board_ext_data_size)) { |
7aa7a72a | 333 | ath10k_err(ar, "invalid board (ext) data sizes %zu != %d+%d\n", |
a58227ef | 334 | data_len, board_data_size, board_ext_data_size); |
5e3dd157 KV |
335 | return -EINVAL; |
336 | } | |
337 | ||
338 | ret = ath10k_bmi_write_memory(ar, board_ext_data_addr, | |
a58227ef | 339 | data + board_data_size, |
5e3dd157 KV |
340 | board_ext_data_size); |
341 | if (ret) { | |
7aa7a72a | 342 | ath10k_err(ar, "could not write board ext data (%d)\n", ret); |
5e3dd157 KV |
343 | return ret; |
344 | } | |
345 | ||
346 | ret = ath10k_bmi_write32(ar, hi_board_ext_data_config, | |
347 | (board_ext_data_size << 16) | 1); | |
348 | if (ret) { | |
7aa7a72a MK |
349 | ath10k_err(ar, "could not write board ext data bit (%d)\n", |
350 | ret); | |
5e3dd157 KV |
351 | return ret; |
352 | } | |
353 | ||
354 | return 0; | |
355 | } | |
356 | ||
a58227ef KV |
357 | static int ath10k_download_board_data(struct ath10k *ar, const void *data, |
358 | size_t data_len) | |
5e3dd157 | 359 | { |
9764a2af | 360 | u32 board_data_size = ar->hw_params.fw.board_size; |
5e3dd157 | 361 | u32 address; |
5e3dd157 KV |
362 | int ret; |
363 | ||
a58227ef | 364 | ret = ath10k_push_board_ext_data(ar, data, data_len); |
5e3dd157 | 365 | if (ret) { |
7aa7a72a | 366 | ath10k_err(ar, "could not push board ext data (%d)\n", ret); |
5e3dd157 KV |
367 | goto exit; |
368 | } | |
369 | ||
370 | ret = ath10k_bmi_read32(ar, hi_board_data, &address); | |
371 | if (ret) { | |
7aa7a72a | 372 | ath10k_err(ar, "could not read board data addr (%d)\n", ret); |
5e3dd157 KV |
373 | goto exit; |
374 | } | |
375 | ||
a58227ef | 376 | ret = ath10k_bmi_write_memory(ar, address, data, |
958df3a0 | 377 | min_t(u32, board_data_size, |
a58227ef | 378 | data_len)); |
5e3dd157 | 379 | if (ret) { |
7aa7a72a | 380 | ath10k_err(ar, "could not write board data (%d)\n", ret); |
5e3dd157 KV |
381 | goto exit; |
382 | } | |
383 | ||
384 | ret = ath10k_bmi_write32(ar, hi_board_data_initialized, 1); | |
385 | if (ret) { | |
7aa7a72a | 386 | ath10k_err(ar, "could not write board data bit (%d)\n", ret); |
5e3dd157 KV |
387 | goto exit; |
388 | } | |
389 | ||
390 | exit: | |
5e3dd157 KV |
391 | return ret; |
392 | } | |
393 | ||
a58227ef KV |
394 | static int ath10k_download_cal_file(struct ath10k *ar) |
395 | { | |
396 | int ret; | |
397 | ||
398 | if (!ar->cal_file) | |
399 | return -ENOENT; | |
400 | ||
401 | if (IS_ERR(ar->cal_file)) | |
402 | return PTR_ERR(ar->cal_file); | |
403 | ||
404 | ret = ath10k_download_board_data(ar, ar->cal_file->data, | |
405 | ar->cal_file->size); | |
406 | if (ret) { | |
407 | ath10k_err(ar, "failed to download cal_file data: %d\n", ret); | |
408 | return ret; | |
409 | } | |
410 | ||
411 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cal file downloaded\n"); | |
412 | ||
413 | return 0; | |
414 | } | |
415 | ||
5aabff05 TK |
416 | static int ath10k_download_cal_dt(struct ath10k *ar) |
417 | { | |
418 | struct device_node *node; | |
419 | int data_len; | |
420 | void *data; | |
421 | int ret; | |
422 | ||
423 | node = ar->dev->of_node; | |
424 | if (!node) | |
425 | /* Device Tree is optional, don't print any warnings if | |
426 | * there's no node for ath10k. | |
427 | */ | |
428 | return -ENOENT; | |
429 | ||
430 | if (!of_get_property(node, "qcom,ath10k-calibration-data", | |
431 | &data_len)) { | |
432 | /* The calibration data node is optional */ | |
433 | return -ENOENT; | |
434 | } | |
435 | ||
436 | if (data_len != QCA988X_CAL_DATA_LEN) { | |
437 | ath10k_warn(ar, "invalid calibration data length in DT: %d\n", | |
438 | data_len); | |
439 | ret = -EMSGSIZE; | |
440 | goto out; | |
441 | } | |
442 | ||
443 | data = kmalloc(data_len, GFP_KERNEL); | |
444 | if (!data) { | |
445 | ret = -ENOMEM; | |
446 | goto out; | |
447 | } | |
448 | ||
449 | ret = of_property_read_u8_array(node, "qcom,ath10k-calibration-data", | |
450 | data, data_len); | |
451 | if (ret) { | |
452 | ath10k_warn(ar, "failed to read calibration data from DT: %d\n", | |
453 | ret); | |
454 | goto out_free; | |
455 | } | |
456 | ||
457 | ret = ath10k_download_board_data(ar, data, data_len); | |
458 | if (ret) { | |
459 | ath10k_warn(ar, "failed to download calibration data from Device Tree: %d\n", | |
460 | ret); | |
461 | goto out_free; | |
462 | } | |
463 | ||
464 | ret = 0; | |
465 | ||
466 | out_free: | |
467 | kfree(data); | |
468 | ||
469 | out: | |
470 | return ret; | |
471 | } | |
472 | ||
db0984e5 MP |
473 | static int ath10k_core_get_board_id_from_otp(struct ath10k *ar) |
474 | { | |
475 | u32 result, address; | |
476 | u8 board_id, chip_id; | |
477 | int ret; | |
478 | ||
479 | address = ar->hw_params.patch_load_addr; | |
480 | ||
481 | if (!ar->otp_data || !ar->otp_len) { | |
482 | ath10k_warn(ar, | |
483 | "failed to retrieve board id because of invalid otp\n"); | |
484 | return -ENODATA; | |
485 | } | |
486 | ||
487 | ath10k_dbg(ar, ATH10K_DBG_BOOT, | |
488 | "boot upload otp to 0x%x len %zd for board id\n", | |
489 | address, ar->otp_len); | |
490 | ||
491 | ret = ath10k_bmi_fast_download(ar, address, ar->otp_data, ar->otp_len); | |
492 | if (ret) { | |
493 | ath10k_err(ar, "could not write otp for board id check: %d\n", | |
494 | ret); | |
495 | return ret; | |
496 | } | |
497 | ||
498 | ret = ath10k_bmi_execute(ar, address, BMI_PARAM_GET_EEPROM_BOARD_ID, | |
499 | &result); | |
500 | if (ret) { | |
501 | ath10k_err(ar, "could not execute otp for board id check: %d\n", | |
502 | ret); | |
503 | return ret; | |
504 | } | |
505 | ||
506 | board_id = MS(result, ATH10K_BMI_BOARD_ID_FROM_OTP); | |
507 | chip_id = MS(result, ATH10K_BMI_CHIP_ID_FROM_OTP); | |
508 | ||
509 | ath10k_dbg(ar, ATH10K_DBG_BOOT, | |
510 | "boot get otp board id result 0x%08x board_id %d chip_id %d\n", | |
511 | result, board_id, chip_id); | |
512 | ||
513 | if ((result & ATH10K_BMI_BOARD_ID_STATUS_MASK) != 0) | |
514 | return -EOPNOTSUPP; | |
515 | ||
516 | ar->id.bmi_ids_valid = true; | |
517 | ar->id.bmi_board_id = board_id; | |
518 | ar->id.bmi_chip_id = chip_id; | |
519 | ||
520 | return 0; | |
521 | } | |
522 | ||
5e3dd157 KV |
523 | static int ath10k_download_and_run_otp(struct ath10k *ar) |
524 | { | |
d6d4a58d | 525 | u32 result, address = ar->hw_params.patch_load_addr; |
d772703e | 526 | u32 bmi_otp_exe_param = ar->hw_params.otp_exe_param; |
5e3dd157 KV |
527 | int ret; |
528 | ||
a58227ef | 529 | ret = ath10k_download_board_data(ar, ar->board_data, ar->board_len); |
83091559 KV |
530 | if (ret) { |
531 | ath10k_err(ar, "failed to download board data: %d\n", ret); | |
532 | return ret; | |
533 | } | |
534 | ||
5e3dd157 KV |
535 | /* OTP is optional */ |
536 | ||
7f06ea1e | 537 | if (!ar->otp_data || !ar->otp_len) { |
7aa7a72a | 538 | ath10k_warn(ar, "Not running otp, calibration will be incorrect (otp-data %p otp_len %zd)!\n", |
36a8f413 | 539 | ar->otp_data, ar->otp_len); |
5e3dd157 | 540 | return 0; |
7f06ea1e KV |
541 | } |
542 | ||
7aa7a72a | 543 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n", |
7f06ea1e | 544 | address, ar->otp_len); |
5e3dd157 | 545 | |
958df3a0 | 546 | ret = ath10k_bmi_fast_download(ar, address, ar->otp_data, ar->otp_len); |
5e3dd157 | 547 | if (ret) { |
7aa7a72a | 548 | ath10k_err(ar, "could not write otp (%d)\n", ret); |
7f06ea1e | 549 | return ret; |
5e3dd157 KV |
550 | } |
551 | ||
d772703e | 552 | ret = ath10k_bmi_execute(ar, address, bmi_otp_exe_param, &result); |
5e3dd157 | 553 | if (ret) { |
7aa7a72a | 554 | ath10k_err(ar, "could not execute otp (%d)\n", ret); |
7f06ea1e | 555 | return ret; |
5e3dd157 KV |
556 | } |
557 | ||
7aa7a72a | 558 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result); |
7f06ea1e | 559 | |
d9153546 | 560 | if (!(skip_otp || test_bit(ATH10K_FW_FEATURE_IGNORE_OTP_RESULT, |
be62e92a KV |
561 | ar->fw_features)) && |
562 | result != 0) { | |
7aa7a72a | 563 | ath10k_err(ar, "otp calibration failed: %d", result); |
7f06ea1e KV |
564 | return -EINVAL; |
565 | } | |
566 | ||
567 | return 0; | |
5e3dd157 KV |
568 | } |
569 | ||
43d2a30f | 570 | static int ath10k_download_fw(struct ath10k *ar, enum ath10k_firmware_mode mode) |
5e3dd157 | 571 | { |
43d2a30f KV |
572 | u32 address, data_len; |
573 | const char *mode_name; | |
574 | const void *data; | |
5e3dd157 KV |
575 | int ret; |
576 | ||
5e3dd157 KV |
577 | address = ar->hw_params.patch_load_addr; |
578 | ||
43d2a30f KV |
579 | switch (mode) { |
580 | case ATH10K_FIRMWARE_MODE_NORMAL: | |
581 | data = ar->firmware_data; | |
582 | data_len = ar->firmware_len; | |
583 | mode_name = "normal"; | |
dcb02db1 | 584 | ret = ath10k_swap_code_seg_configure(ar, |
617b0f4d | 585 | ATH10K_SWAP_CODE_SEG_BIN_TYPE_FW); |
dcb02db1 VT |
586 | if (ret) { |
587 | ath10k_err(ar, "failed to configure fw code swap: %d\n", | |
588 | ret); | |
589 | return ret; | |
590 | } | |
43d2a30f KV |
591 | break; |
592 | case ATH10K_FIRMWARE_MODE_UTF: | |
a81a98ce AL |
593 | data = ar->testmode.utf_firmware_data; |
594 | data_len = ar->testmode.utf_firmware_len; | |
43d2a30f KV |
595 | mode_name = "utf"; |
596 | break; | |
597 | default: | |
598 | ath10k_err(ar, "unknown firmware mode: %d\n", mode); | |
599 | return -EINVAL; | |
600 | } | |
601 | ||
602 | ath10k_dbg(ar, ATH10K_DBG_BOOT, | |
603 | "boot uploading firmware image %p len %d mode %s\n", | |
604 | data, data_len, mode_name); | |
605 | ||
606 | ret = ath10k_bmi_fast_download(ar, address, data, data_len); | |
5e3dd157 | 607 | if (ret) { |
43d2a30f KV |
608 | ath10k_err(ar, "failed to download %s firmware: %d\n", |
609 | mode_name, ret); | |
610 | return ret; | |
5e3dd157 KV |
611 | } |
612 | ||
29385057 MK |
613 | return ret; |
614 | } | |
615 | ||
0a51b343 | 616 | static void ath10k_core_free_board_files(struct ath10k *ar) |
29385057 | 617 | { |
db2cf865 | 618 | if (!IS_ERR(ar->board)) |
36527916 | 619 | release_firmware(ar->board); |
29385057 | 620 | |
0a51b343 MP |
621 | ar->board = NULL; |
622 | ar->board_data = NULL; | |
623 | ar->board_len = 0; | |
624 | } | |
625 | ||
626 | static void ath10k_core_free_firmware_files(struct ath10k *ar) | |
627 | { | |
db2cf865 | 628 | if (!IS_ERR(ar->otp)) |
29385057 MK |
629 | release_firmware(ar->otp); |
630 | ||
db2cf865 | 631 | if (!IS_ERR(ar->firmware)) |
29385057 MK |
632 | release_firmware(ar->firmware); |
633 | ||
db2cf865 | 634 | if (!IS_ERR(ar->cal_file)) |
a58227ef KV |
635 | release_firmware(ar->cal_file); |
636 | ||
dcb02db1 VT |
637 | ath10k_swap_code_seg_release(ar); |
638 | ||
29385057 | 639 | ar->otp = NULL; |
958df3a0 KV |
640 | ar->otp_data = NULL; |
641 | ar->otp_len = 0; | |
642 | ||
29385057 | 643 | ar->firmware = NULL; |
958df3a0 KV |
644 | ar->firmware_data = NULL; |
645 | ar->firmware_len = 0; | |
a58227ef KV |
646 | |
647 | ar->cal_file = NULL; | |
648 | } | |
649 | ||
650 | static int ath10k_fetch_cal_file(struct ath10k *ar) | |
651 | { | |
652 | char filename[100]; | |
653 | ||
654 | /* cal-<bus>-<id>.bin */ | |
655 | scnprintf(filename, sizeof(filename), "cal-%s-%s.bin", | |
656 | ath10k_bus_str(ar->hif.bus), dev_name(ar->dev)); | |
657 | ||
658 | ar->cal_file = ath10k_fetch_fw_file(ar, ATH10K_FW_DIR, filename); | |
659 | if (IS_ERR(ar->cal_file)) | |
660 | /* calibration file is optional, don't print any warnings */ | |
661 | return PTR_ERR(ar->cal_file); | |
662 | ||
663 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "found calibration file %s/%s\n", | |
664 | ATH10K_FW_DIR, filename); | |
665 | ||
666 | return 0; | |
29385057 MK |
667 | } |
668 | ||
0a51b343 | 669 | static int ath10k_core_fetch_board_data_api_1(struct ath10k *ar) |
29385057 | 670 | { |
0a51b343 MP |
671 | if (!ar->hw_params.fw.board) { |
672 | ath10k_err(ar, "failed to find board file fw entry\n"); | |
673 | return -EINVAL; | |
674 | } | |
de57e2c8 | 675 | |
0a51b343 MP |
676 | ar->board = ath10k_fetch_fw_file(ar, |
677 | ar->hw_params.fw.dir, | |
678 | ar->hw_params.fw.board); | |
de57e2c8 MK |
679 | if (IS_ERR(ar->board)) |
680 | return PTR_ERR(ar->board); | |
681 | ||
682 | ar->board_data = ar->board->data; | |
683 | ar->board_len = ar->board->size; | |
29385057 | 684 | |
de57e2c8 MK |
685 | return 0; |
686 | } | |
687 | ||
0a51b343 MP |
688 | static int ath10k_core_parse_bd_ie_board(struct ath10k *ar, |
689 | const void *buf, size_t buf_len, | |
690 | const char *boardname) | |
de57e2c8 | 691 | { |
0a51b343 MP |
692 | const struct ath10k_fw_ie *hdr; |
693 | bool name_match_found; | |
694 | int ret, board_ie_id; | |
695 | size_t board_ie_len; | |
696 | const void *board_ie_data; | |
697 | ||
698 | name_match_found = false; | |
699 | ||
700 | /* go through ATH10K_BD_IE_BOARD_ elements */ | |
701 | while (buf_len > sizeof(struct ath10k_fw_ie)) { | |
702 | hdr = buf; | |
703 | board_ie_id = le32_to_cpu(hdr->id); | |
704 | board_ie_len = le32_to_cpu(hdr->len); | |
705 | board_ie_data = hdr->data; | |
706 | ||
707 | buf_len -= sizeof(*hdr); | |
708 | buf += sizeof(*hdr); | |
709 | ||
710 | if (buf_len < ALIGN(board_ie_len, 4)) { | |
711 | ath10k_err(ar, "invalid ATH10K_BD_IE_BOARD length: %zu < %zu\n", | |
712 | buf_len, ALIGN(board_ie_len, 4)); | |
713 | ret = -EINVAL; | |
714 | goto out; | |
715 | } | |
716 | ||
717 | switch (board_ie_id) { | |
718 | case ATH10K_BD_IE_BOARD_NAME: | |
719 | ath10k_dbg_dump(ar, ATH10K_DBG_BOOT, "board name", "", | |
720 | board_ie_data, board_ie_len); | |
721 | ||
722 | if (board_ie_len != strlen(boardname)) | |
723 | break; | |
724 | ||
725 | ret = memcmp(board_ie_data, boardname, strlen(boardname)); | |
726 | if (ret) | |
727 | break; | |
728 | ||
729 | name_match_found = true; | |
730 | ath10k_dbg(ar, ATH10K_DBG_BOOT, | |
731 | "boot found match for name '%s'", | |
732 | boardname); | |
733 | break; | |
734 | case ATH10K_BD_IE_BOARD_DATA: | |
735 | if (!name_match_found) | |
736 | /* no match found */ | |
737 | break; | |
738 | ||
739 | ath10k_dbg(ar, ATH10K_DBG_BOOT, | |
740 | "boot found board data for '%s'", | |
741 | boardname); | |
742 | ||
743 | ar->board_data = board_ie_data; | |
744 | ar->board_len = board_ie_len; | |
745 | ||
746 | ret = 0; | |
747 | goto out; | |
748 | default: | |
749 | ath10k_warn(ar, "unknown ATH10K_BD_IE_BOARD found: %d\n", | |
750 | board_ie_id); | |
751 | break; | |
752 | } | |
753 | ||
754 | /* jump over the padding */ | |
755 | board_ie_len = ALIGN(board_ie_len, 4); | |
756 | ||
757 | buf_len -= board_ie_len; | |
758 | buf += board_ie_len; | |
29385057 MK |
759 | } |
760 | ||
0a51b343 MP |
761 | /* no match found */ |
762 | ret = -ENOENT; | |
763 | ||
764 | out: | |
765 | return ret; | |
766 | } | |
767 | ||
768 | static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar, | |
769 | const char *boardname, | |
770 | const char *filename) | |
771 | { | |
772 | size_t len, magic_len, ie_len; | |
773 | struct ath10k_fw_ie *hdr; | |
774 | const u8 *data; | |
775 | int ret, ie_id; | |
776 | ||
777 | ar->board = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, filename); | |
de57e2c8 MK |
778 | if (IS_ERR(ar->board)) |
779 | return PTR_ERR(ar->board); | |
29385057 | 780 | |
0a51b343 MP |
781 | data = ar->board->data; |
782 | len = ar->board->size; | |
783 | ||
784 | /* magic has extra null byte padded */ | |
785 | magic_len = strlen(ATH10K_BOARD_MAGIC) + 1; | |
786 | if (len < magic_len) { | |
787 | ath10k_err(ar, "failed to find magic value in %s/%s, file too short: %zu\n", | |
788 | ar->hw_params.fw.dir, filename, len); | |
789 | ret = -EINVAL; | |
790 | goto err; | |
791 | } | |
792 | ||
793 | if (memcmp(data, ATH10K_BOARD_MAGIC, magic_len)) { | |
794 | ath10k_err(ar, "found invalid board magic\n"); | |
795 | ret = -EINVAL; | |
796 | goto err; | |
797 | } | |
798 | ||
799 | /* magic is padded to 4 bytes */ | |
800 | magic_len = ALIGN(magic_len, 4); | |
801 | if (len < magic_len) { | |
802 | ath10k_err(ar, "failed: %s/%s too small to contain board data, len: %zu\n", | |
803 | ar->hw_params.fw.dir, filename, len); | |
804 | ret = -EINVAL; | |
805 | goto err; | |
806 | } | |
807 | ||
808 | data += magic_len; | |
809 | len -= magic_len; | |
810 | ||
811 | while (len > sizeof(struct ath10k_fw_ie)) { | |
812 | hdr = (struct ath10k_fw_ie *)data; | |
813 | ie_id = le32_to_cpu(hdr->id); | |
814 | ie_len = le32_to_cpu(hdr->len); | |
815 | ||
816 | len -= sizeof(*hdr); | |
817 | data = hdr->data; | |
818 | ||
819 | if (len < ALIGN(ie_len, 4)) { | |
820 | ath10k_err(ar, "invalid length for board ie_id %d ie_len %zu len %zu\n", | |
821 | ie_id, ie_len, len); | |
822 | ret = -EINVAL; | |
823 | goto err; | |
824 | } | |
825 | ||
826 | switch (ie_id) { | |
827 | case ATH10K_BD_IE_BOARD: | |
828 | ret = ath10k_core_parse_bd_ie_board(ar, data, ie_len, | |
829 | boardname); | |
830 | if (ret == -ENOENT) | |
831 | /* no match found, continue */ | |
832 | break; | |
833 | else if (ret) | |
834 | /* there was an error, bail out */ | |
835 | goto err; | |
836 | ||
837 | /* board data found */ | |
838 | goto out; | |
839 | } | |
840 | ||
841 | /* jump over the padding */ | |
842 | ie_len = ALIGN(ie_len, 4); | |
843 | ||
844 | len -= ie_len; | |
845 | data += ie_len; | |
846 | } | |
847 | ||
848 | out: | |
849 | if (!ar->board_data || !ar->board_len) { | |
850 | ath10k_err(ar, | |
851 | "failed to fetch board data for %s from %s/%s\n", | |
852 | ar->hw_params.fw.dir, boardname, filename); | |
853 | ret = -ENODATA; | |
854 | goto err; | |
855 | } | |
856 | ||
857 | return 0; | |
858 | ||
859 | err: | |
860 | ath10k_core_free_board_files(ar); | |
861 | return ret; | |
862 | } | |
863 | ||
864 | static int ath10k_core_create_board_name(struct ath10k *ar, char *name, | |
865 | size_t name_len) | |
866 | { | |
db0984e5 MP |
867 | if (ar->id.bmi_ids_valid) { |
868 | scnprintf(name, name_len, | |
869 | "bus=%s,bmi-chip-id=%d,bmi-board-id=%d", | |
870 | ath10k_bus_str(ar->hif.bus), | |
871 | ar->id.bmi_chip_id, | |
872 | ar->id.bmi_board_id); | |
873 | goto out; | |
874 | } | |
875 | ||
0a51b343 MP |
876 | scnprintf(name, name_len, |
877 | "bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x", | |
878 | ath10k_bus_str(ar->hif.bus), | |
879 | ar->id.vendor, ar->id.device, | |
880 | ar->id.subsystem_vendor, ar->id.subsystem_device); | |
881 | ||
db0984e5 | 882 | out: |
0a51b343 | 883 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot using board name '%s'\n", name); |
de57e2c8 MK |
884 | |
885 | return 0; | |
886 | } | |
887 | ||
888 | static int ath10k_core_fetch_board_file(struct ath10k *ar) | |
889 | { | |
0a51b343 | 890 | char boardname[100]; |
de57e2c8 MK |
891 | int ret; |
892 | ||
0a51b343 MP |
893 | ret = ath10k_core_create_board_name(ar, boardname, sizeof(boardname)); |
894 | if (ret) { | |
895 | ath10k_err(ar, "failed to create board name: %d", ret); | |
896 | return ret; | |
de57e2c8 MK |
897 | } |
898 | ||
0a51b343 MP |
899 | ar->bd_api = 2; |
900 | ret = ath10k_core_fetch_board_data_api_n(ar, boardname, | |
901 | ATH10K_BOARD_API2_FILE); | |
902 | if (!ret) | |
903 | goto success; | |
904 | ||
905 | ar->bd_api = 1; | |
906 | ret = ath10k_core_fetch_board_data_api_1(ar); | |
de57e2c8 | 907 | if (ret) { |
0a51b343 | 908 | ath10k_err(ar, "failed to fetch board data\n"); |
de57e2c8 MK |
909 | return ret; |
910 | } | |
958df3a0 | 911 | |
0a51b343 MP |
912 | success: |
913 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "using board api %d\n", ar->bd_api); | |
d0ed74f3 MK |
914 | return 0; |
915 | } | |
916 | ||
917 | static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar) | |
918 | { | |
919 | int ret = 0; | |
920 | ||
921 | if (ar->hw_params.fw.fw == NULL) { | |
922 | ath10k_err(ar, "firmware file not defined\n"); | |
923 | return -EINVAL; | |
924 | } | |
925 | ||
29385057 MK |
926 | ar->firmware = ath10k_fetch_fw_file(ar, |
927 | ar->hw_params.fw.dir, | |
928 | ar->hw_params.fw.fw); | |
929 | if (IS_ERR(ar->firmware)) { | |
930 | ret = PTR_ERR(ar->firmware); | |
7aa7a72a | 931 | ath10k_err(ar, "could not fetch firmware (%d)\n", ret); |
29385057 MK |
932 | goto err; |
933 | } | |
934 | ||
958df3a0 KV |
935 | ar->firmware_data = ar->firmware->data; |
936 | ar->firmware_len = ar->firmware->size; | |
937 | ||
29385057 MK |
938 | /* OTP may be undefined. If so, don't fetch it at all */ |
939 | if (ar->hw_params.fw.otp == NULL) | |
940 | return 0; | |
941 | ||
942 | ar->otp = ath10k_fetch_fw_file(ar, | |
943 | ar->hw_params.fw.dir, | |
944 | ar->hw_params.fw.otp); | |
945 | if (IS_ERR(ar->otp)) { | |
946 | ret = PTR_ERR(ar->otp); | |
7aa7a72a | 947 | ath10k_err(ar, "could not fetch otp (%d)\n", ret); |
29385057 MK |
948 | goto err; |
949 | } | |
950 | ||
958df3a0 KV |
951 | ar->otp_data = ar->otp->data; |
952 | ar->otp_len = ar->otp->size; | |
953 | ||
29385057 MK |
954 | return 0; |
955 | ||
956 | err: | |
957 | ath10k_core_free_firmware_files(ar); | |
5e3dd157 KV |
958 | return ret; |
959 | } | |
960 | ||
1a222435 KV |
961 | static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) |
962 | { | |
963 | size_t magic_len, len, ie_len; | |
964 | int ie_id, i, index, bit, ret; | |
965 | struct ath10k_fw_ie *hdr; | |
966 | const u8 *data; | |
202e86e6 | 967 | __le32 *timestamp, *version; |
1a222435 KV |
968 | |
969 | /* first fetch the firmware file (firmware-*.bin) */ | |
970 | ar->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, name); | |
971 | if (IS_ERR(ar->firmware)) { | |
7aa7a72a | 972 | ath10k_err(ar, "could not fetch firmware file '%s/%s': %ld\n", |
53c02284 | 973 | ar->hw_params.fw.dir, name, PTR_ERR(ar->firmware)); |
1a222435 KV |
974 | return PTR_ERR(ar->firmware); |
975 | } | |
976 | ||
977 | data = ar->firmware->data; | |
978 | len = ar->firmware->size; | |
979 | ||
980 | /* magic also includes the null byte, check that as well */ | |
981 | magic_len = strlen(ATH10K_FIRMWARE_MAGIC) + 1; | |
982 | ||
983 | if (len < magic_len) { | |
7aa7a72a | 984 | ath10k_err(ar, "firmware file '%s/%s' too small to contain magic: %zu\n", |
53c02284 | 985 | ar->hw_params.fw.dir, name, len); |
9bab1cc0 MK |
986 | ret = -EINVAL; |
987 | goto err; | |
1a222435 KV |
988 | } |
989 | ||
990 | if (memcmp(data, ATH10K_FIRMWARE_MAGIC, magic_len) != 0) { | |
7aa7a72a | 991 | ath10k_err(ar, "invalid firmware magic\n"); |
9bab1cc0 MK |
992 | ret = -EINVAL; |
993 | goto err; | |
1a222435 KV |
994 | } |
995 | ||
996 | /* jump over the padding */ | |
997 | magic_len = ALIGN(magic_len, 4); | |
998 | ||
999 | len -= magic_len; | |
1000 | data += magic_len; | |
1001 | ||
1002 | /* loop elements */ | |
1003 | while (len > sizeof(struct ath10k_fw_ie)) { | |
1004 | hdr = (struct ath10k_fw_ie *)data; | |
1005 | ||
1006 | ie_id = le32_to_cpu(hdr->id); | |
1007 | ie_len = le32_to_cpu(hdr->len); | |
1008 | ||
1009 | len -= sizeof(*hdr); | |
1010 | data += sizeof(*hdr); | |
1011 | ||
1012 | if (len < ie_len) { | |
7aa7a72a | 1013 | ath10k_err(ar, "invalid length for FW IE %d (%zu < %zu)\n", |
1a222435 | 1014 | ie_id, len, ie_len); |
9bab1cc0 MK |
1015 | ret = -EINVAL; |
1016 | goto err; | |
1a222435 KV |
1017 | } |
1018 | ||
1019 | switch (ie_id) { | |
1020 | case ATH10K_FW_IE_FW_VERSION: | |
1021 | if (ie_len > sizeof(ar->hw->wiphy->fw_version) - 1) | |
1022 | break; | |
1023 | ||
1024 | memcpy(ar->hw->wiphy->fw_version, data, ie_len); | |
1025 | ar->hw->wiphy->fw_version[ie_len] = '\0'; | |
1026 | ||
7aa7a72a | 1027 | ath10k_dbg(ar, ATH10K_DBG_BOOT, |
1a222435 KV |
1028 | "found fw version %s\n", |
1029 | ar->hw->wiphy->fw_version); | |
1030 | break; | |
1031 | case ATH10K_FW_IE_TIMESTAMP: | |
1032 | if (ie_len != sizeof(u32)) | |
1033 | break; | |
1034 | ||
1035 | timestamp = (__le32 *)data; | |
1036 | ||
7aa7a72a | 1037 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw timestamp %d\n", |
1a222435 KV |
1038 | le32_to_cpup(timestamp)); |
1039 | break; | |
1040 | case ATH10K_FW_IE_FEATURES: | |
7aa7a72a | 1041 | ath10k_dbg(ar, ATH10K_DBG_BOOT, |
1a222435 KV |
1042 | "found firmware features ie (%zd B)\n", |
1043 | ie_len); | |
1044 | ||
1045 | for (i = 0; i < ATH10K_FW_FEATURE_COUNT; i++) { | |
1046 | index = i / 8; | |
1047 | bit = i % 8; | |
1048 | ||
1049 | if (index == ie_len) | |
1050 | break; | |
1051 | ||
f591a1a5 | 1052 | if (data[index] & (1 << bit)) { |
7aa7a72a | 1053 | ath10k_dbg(ar, ATH10K_DBG_BOOT, |
f591a1a5 BG |
1054 | "Enabling feature bit: %i\n", |
1055 | i); | |
1a222435 | 1056 | __set_bit(i, ar->fw_features); |
f591a1a5 | 1057 | } |
1a222435 KV |
1058 | } |
1059 | ||
7aa7a72a | 1060 | ath10k_dbg_dump(ar, ATH10K_DBG_BOOT, "features", "", |
1a222435 KV |
1061 | ar->fw_features, |
1062 | sizeof(ar->fw_features)); | |
1063 | break; | |
1064 | case ATH10K_FW_IE_FW_IMAGE: | |
7aa7a72a | 1065 | ath10k_dbg(ar, ATH10K_DBG_BOOT, |
1a222435 KV |
1066 | "found fw image ie (%zd B)\n", |
1067 | ie_len); | |
1068 | ||
1069 | ar->firmware_data = data; | |
1070 | ar->firmware_len = ie_len; | |
1071 | ||
1072 | break; | |
1073 | case ATH10K_FW_IE_OTP_IMAGE: | |
7aa7a72a | 1074 | ath10k_dbg(ar, ATH10K_DBG_BOOT, |
1a222435 KV |
1075 | "found otp image ie (%zd B)\n", |
1076 | ie_len); | |
1077 | ||
1078 | ar->otp_data = data; | |
1079 | ar->otp_len = ie_len; | |
1080 | ||
1081 | break; | |
202e86e6 KV |
1082 | case ATH10K_FW_IE_WMI_OP_VERSION: |
1083 | if (ie_len != sizeof(u32)) | |
1084 | break; | |
1085 | ||
1086 | version = (__le32 *)data; | |
1087 | ||
1088 | ar->wmi.op_version = le32_to_cpup(version); | |
1089 | ||
1090 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw ie wmi op version %d\n", | |
1091 | ar->wmi.op_version); | |
1092 | break; | |
8348db29 RM |
1093 | case ATH10K_FW_IE_HTT_OP_VERSION: |
1094 | if (ie_len != sizeof(u32)) | |
1095 | break; | |
1096 | ||
1097 | version = (__le32 *)data; | |
1098 | ||
1099 | ar->htt.op_version = le32_to_cpup(version); | |
1100 | ||
1101 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw ie htt op version %d\n", | |
1102 | ar->htt.op_version); | |
1103 | break; | |
dcb02db1 VT |
1104 | case ATH10K_FW_IE_FW_CODE_SWAP_IMAGE: |
1105 | ath10k_dbg(ar, ATH10K_DBG_BOOT, | |
1106 | "found fw code swap image ie (%zd B)\n", | |
1107 | ie_len); | |
1108 | ar->swap.firmware_codeswap_data = data; | |
1109 | ar->swap.firmware_codeswap_len = ie_len; | |
1110 | break; | |
1a222435 | 1111 | default: |
7aa7a72a | 1112 | ath10k_warn(ar, "Unknown FW IE: %u\n", |
1a222435 KV |
1113 | le32_to_cpu(hdr->id)); |
1114 | break; | |
1115 | } | |
1116 | ||
1117 | /* jump over the padding */ | |
1118 | ie_len = ALIGN(ie_len, 4); | |
1119 | ||
1120 | len -= ie_len; | |
1121 | data += ie_len; | |
e05634ee | 1122 | } |
1a222435 KV |
1123 | |
1124 | if (!ar->firmware_data || !ar->firmware_len) { | |
7aa7a72a | 1125 | ath10k_warn(ar, "No ATH10K_FW_IE_FW_IMAGE found from '%s/%s', skipping\n", |
53c02284 | 1126 | ar->hw_params.fw.dir, name); |
1a222435 KV |
1127 | ret = -ENOMEDIUM; |
1128 | goto err; | |
1129 | } | |
1130 | ||
1a222435 KV |
1131 | return 0; |
1132 | ||
1133 | err: | |
1134 | ath10k_core_free_firmware_files(ar); | |
1135 | return ret; | |
1136 | } | |
1137 | ||
1138 | static int ath10k_core_fetch_firmware_files(struct ath10k *ar) | |
1139 | { | |
1140 | int ret; | |
1141 | ||
a58227ef KV |
1142 | /* calibration file is optional, don't check for any errors */ |
1143 | ath10k_fetch_cal_file(ar); | |
1144 | ||
53513c30 KV |
1145 | ar->fw_api = 5; |
1146 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); | |
1147 | ||
1148 | ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API5_FILE); | |
1149 | if (ret == 0) | |
1150 | goto success; | |
1151 | ||
4a16fbec RM |
1152 | ar->fw_api = 4; |
1153 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); | |
1154 | ||
1155 | ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API4_FILE); | |
1156 | if (ret == 0) | |
1157 | goto success; | |
1158 | ||
24c88f78 | 1159 | ar->fw_api = 3; |
7aa7a72a | 1160 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); |
24c88f78 MK |
1161 | |
1162 | ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API3_FILE); | |
1163 | if (ret == 0) | |
1164 | goto success; | |
1165 | ||
53c02284 | 1166 | ar->fw_api = 2; |
7aa7a72a | 1167 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); |
53c02284 | 1168 | |
1a222435 | 1169 | ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API2_FILE); |
53c02284 BG |
1170 | if (ret == 0) |
1171 | goto success; | |
1172 | ||
1173 | ar->fw_api = 1; | |
7aa7a72a | 1174 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); |
1a222435 KV |
1175 | |
1176 | ret = ath10k_core_fetch_firmware_api_1(ar); | |
1177 | if (ret) | |
1178 | return ret; | |
1179 | ||
53c02284 | 1180 | success: |
7aa7a72a | 1181 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "using fw api %d\n", ar->fw_api); |
1a222435 KV |
1182 | |
1183 | return 0; | |
1184 | } | |
1185 | ||
83091559 | 1186 | static int ath10k_download_cal_data(struct ath10k *ar) |
5e3dd157 KV |
1187 | { |
1188 | int ret; | |
1189 | ||
a58227ef KV |
1190 | ret = ath10k_download_cal_file(ar); |
1191 | if (ret == 0) { | |
1192 | ar->cal_mode = ATH10K_CAL_MODE_FILE; | |
1193 | goto done; | |
1194 | } | |
1195 | ||
1196 | ath10k_dbg(ar, ATH10K_DBG_BOOT, | |
5aabff05 TK |
1197 | "boot did not find a calibration file, try DT next: %d\n", |
1198 | ret); | |
1199 | ||
1200 | ret = ath10k_download_cal_dt(ar); | |
1201 | if (ret == 0) { | |
1202 | ar->cal_mode = ATH10K_CAL_MODE_DT; | |
1203 | goto done; | |
1204 | } | |
1205 | ||
1206 | ath10k_dbg(ar, ATH10K_DBG_BOOT, | |
1207 | "boot did not find DT entry, try OTP next: %d\n", | |
a58227ef KV |
1208 | ret); |
1209 | ||
5e3dd157 | 1210 | ret = ath10k_download_and_run_otp(ar); |
36a8f413 | 1211 | if (ret) { |
7aa7a72a | 1212 | ath10k_err(ar, "failed to run otp: %d\n", ret); |
5e3dd157 | 1213 | return ret; |
36a8f413 | 1214 | } |
5e3dd157 | 1215 | |
a58227ef KV |
1216 | ar->cal_mode = ATH10K_CAL_MODE_OTP; |
1217 | ||
1218 | done: | |
1219 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot using calibration mode %s\n", | |
1220 | ath10k_cal_mode_str(ar->cal_mode)); | |
1221 | return 0; | |
5e3dd157 KV |
1222 | } |
1223 | ||
1224 | static int ath10k_init_uart(struct ath10k *ar) | |
1225 | { | |
1226 | int ret; | |
1227 | ||
1228 | /* | |
1229 | * Explicitly setting UART prints to zero as target turns it on | |
1230 | * based on scratch registers. | |
1231 | */ | |
1232 | ret = ath10k_bmi_write32(ar, hi_serial_enable, 0); | |
1233 | if (ret) { | |
7aa7a72a | 1234 | ath10k_warn(ar, "could not disable UART prints (%d)\n", ret); |
5e3dd157 KV |
1235 | return ret; |
1236 | } | |
1237 | ||
c8c39afe | 1238 | if (!uart_print) |
5e3dd157 | 1239 | return 0; |
5e3dd157 | 1240 | |
3a8200b2 | 1241 | ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, ar->hw_params.uart_pin); |
5e3dd157 | 1242 | if (ret) { |
7aa7a72a | 1243 | ath10k_warn(ar, "could not enable UART prints (%d)\n", ret); |
5e3dd157 KV |
1244 | return ret; |
1245 | } | |
1246 | ||
1247 | ret = ath10k_bmi_write32(ar, hi_serial_enable, 1); | |
1248 | if (ret) { | |
7aa7a72a | 1249 | ath10k_warn(ar, "could not enable UART prints (%d)\n", ret); |
5e3dd157 KV |
1250 | return ret; |
1251 | } | |
1252 | ||
03fc137b BM |
1253 | /* Set the UART baud rate to 19200. */ |
1254 | ret = ath10k_bmi_write32(ar, hi_desired_baud_rate, 19200); | |
1255 | if (ret) { | |
7aa7a72a | 1256 | ath10k_warn(ar, "could not set the baud rate (%d)\n", ret); |
03fc137b BM |
1257 | return ret; |
1258 | } | |
1259 | ||
7aa7a72a | 1260 | ath10k_info(ar, "UART prints enabled\n"); |
5e3dd157 KV |
1261 | return 0; |
1262 | } | |
1263 | ||
1264 | static int ath10k_init_hw_params(struct ath10k *ar) | |
1265 | { | |
1266 | const struct ath10k_hw_params *uninitialized_var(hw_params); | |
1267 | int i; | |
1268 | ||
1269 | for (i = 0; i < ARRAY_SIZE(ath10k_hw_params_list); i++) { | |
1270 | hw_params = &ath10k_hw_params_list[i]; | |
1271 | ||
1272 | if (hw_params->id == ar->target_version) | |
1273 | break; | |
1274 | } | |
1275 | ||
1276 | if (i == ARRAY_SIZE(ath10k_hw_params_list)) { | |
7aa7a72a | 1277 | ath10k_err(ar, "Unsupported hardware version: 0x%x\n", |
5e3dd157 KV |
1278 | ar->target_version); |
1279 | return -EINVAL; | |
1280 | } | |
1281 | ||
1282 | ar->hw_params = *hw_params; | |
1283 | ||
7aa7a72a | 1284 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "Hardware name %s version 0x%x\n", |
c8c39afe | 1285 | ar->hw_params.name, ar->target_version); |
5e3dd157 KV |
1286 | |
1287 | return 0; | |
1288 | } | |
1289 | ||
affd3217 MK |
1290 | static void ath10k_core_restart(struct work_struct *work) |
1291 | { | |
1292 | struct ath10k *ar = container_of(work, struct ath10k, restart_work); | |
1293 | ||
7962b0d8 MK |
1294 | set_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags); |
1295 | ||
1296 | /* Place a barrier to make sure the compiler doesn't reorder | |
1297 | * CRASH_FLUSH and calling other functions. | |
1298 | */ | |
1299 | barrier(); | |
1300 | ||
1301 | ieee80211_stop_queues(ar->hw); | |
1302 | ath10k_drain_tx(ar); | |
1303 | complete_all(&ar->scan.started); | |
1304 | complete_all(&ar->scan.completed); | |
1305 | complete_all(&ar->scan.on_channel); | |
1306 | complete_all(&ar->offchan_tx_completed); | |
1307 | complete_all(&ar->install_key_done); | |
1308 | complete_all(&ar->vdev_setup_done); | |
ac2953fc | 1309 | complete_all(&ar->thermal.wmi_sync); |
7962b0d8 MK |
1310 | wake_up(&ar->htt.empty_tx_wq); |
1311 | wake_up(&ar->wmi.tx_credits_wq); | |
1312 | wake_up(&ar->peer_mapping_wq); | |
1313 | ||
affd3217 MK |
1314 | mutex_lock(&ar->conf_mutex); |
1315 | ||
1316 | switch (ar->state) { | |
1317 | case ATH10K_STATE_ON: | |
affd3217 | 1318 | ar->state = ATH10K_STATE_RESTARTING; |
61e9aab7 | 1319 | ath10k_hif_stop(ar); |
5c81c7fd | 1320 | ath10k_scan_finish(ar); |
affd3217 MK |
1321 | ieee80211_restart_hw(ar->hw); |
1322 | break; | |
1323 | case ATH10K_STATE_OFF: | |
5e90de86 MK |
1324 | /* this can happen if driver is being unloaded |
1325 | * or if the crash happens during FW probing */ | |
7aa7a72a | 1326 | ath10k_warn(ar, "cannot restart a device that hasn't been started\n"); |
affd3217 MK |
1327 | break; |
1328 | case ATH10K_STATE_RESTARTING: | |
c5058f5b MK |
1329 | /* hw restart might be requested from multiple places */ |
1330 | break; | |
affd3217 MK |
1331 | case ATH10K_STATE_RESTARTED: |
1332 | ar->state = ATH10K_STATE_WEDGED; | |
1333 | /* fall through */ | |
1334 | case ATH10K_STATE_WEDGED: | |
7aa7a72a | 1335 | ath10k_warn(ar, "device is wedged, will not restart\n"); |
affd3217 | 1336 | break; |
43d2a30f KV |
1337 | case ATH10K_STATE_UTF: |
1338 | ath10k_warn(ar, "firmware restart in UTF mode not supported\n"); | |
1339 | break; | |
affd3217 MK |
1340 | } |
1341 | ||
1342 | mutex_unlock(&ar->conf_mutex); | |
1343 | } | |
1344 | ||
5f2144d9 | 1345 | static int ath10k_core_init_firmware_features(struct ath10k *ar) |
cfd1061e | 1346 | { |
5f2144d9 KV |
1347 | if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features) && |
1348 | !test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { | |
1349 | ath10k_err(ar, "feature bits corrupted: 10.2 feature requires 10.x feature to be set as well"); | |
1350 | return -EINVAL; | |
1351 | } | |
1352 | ||
202e86e6 KV |
1353 | if (ar->wmi.op_version >= ATH10K_FW_WMI_OP_VERSION_MAX) { |
1354 | ath10k_err(ar, "unsupported WMI OP version (max %d): %d\n", | |
1355 | ATH10K_FW_WMI_OP_VERSION_MAX, ar->wmi.op_version); | |
1356 | return -EINVAL; | |
1357 | } | |
1358 | ||
ccec9038 DL |
1359 | ar->wmi.rx_decap_mode = ATH10K_HW_TXRX_NATIVE_WIFI; |
1360 | switch (ath10k_cryptmode_param) { | |
1361 | case ATH10K_CRYPT_MODE_HW: | |
1362 | clear_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags); | |
1363 | clear_bit(ATH10K_FLAG_HW_CRYPTO_DISABLED, &ar->dev_flags); | |
1364 | break; | |
1365 | case ATH10K_CRYPT_MODE_SW: | |
1366 | if (!test_bit(ATH10K_FW_FEATURE_RAW_MODE_SUPPORT, | |
1367 | ar->fw_features)) { | |
1368 | ath10k_err(ar, "cryptmode > 0 requires raw mode support from firmware"); | |
1369 | return -EINVAL; | |
1370 | } | |
1371 | ||
1372 | set_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags); | |
1373 | set_bit(ATH10K_FLAG_HW_CRYPTO_DISABLED, &ar->dev_flags); | |
1374 | break; | |
1375 | default: | |
1376 | ath10k_info(ar, "invalid cryptmode: %d\n", | |
1377 | ath10k_cryptmode_param); | |
1378 | return -EINVAL; | |
1379 | } | |
1380 | ||
1381 | ar->htt.max_num_amsdu = ATH10K_HTT_MAX_NUM_AMSDU_DEFAULT; | |
1382 | ar->htt.max_num_ampdu = ATH10K_HTT_MAX_NUM_AMPDU_DEFAULT; | |
1383 | ||
b6c7bafa BC |
1384 | if (rawmode) { |
1385 | if (!test_bit(ATH10K_FW_FEATURE_RAW_MODE_SUPPORT, | |
1386 | ar->fw_features)) { | |
1387 | ath10k_err(ar, "rawmode = 1 requires support from firmware"); | |
1388 | return -EINVAL; | |
1389 | } | |
1390 | set_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags); | |
1391 | } | |
1392 | ||
ccec9038 DL |
1393 | if (test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) { |
1394 | ar->wmi.rx_decap_mode = ATH10K_HW_TXRX_RAW; | |
1395 | ||
1396 | /* Workaround: | |
1397 | * | |
1398 | * Firmware A-MSDU aggregation breaks with RAW Tx encap mode | |
1399 | * and causes enormous performance issues (malformed frames, | |
1400 | * etc). | |
1401 | * | |
1402 | * Disabling A-MSDU makes RAW mode stable with heavy traffic | |
1403 | * albeit a bit slower compared to regular operation. | |
1404 | */ | |
1405 | ar->htt.max_num_amsdu = 1; | |
1406 | } | |
1407 | ||
202e86e6 KV |
1408 | /* Backwards compatibility for firmwares without |
1409 | * ATH10K_FW_IE_WMI_OP_VERSION. | |
1410 | */ | |
1411 | if (ar->wmi.op_version == ATH10K_FW_WMI_OP_VERSION_UNSET) { | |
1412 | if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { | |
4a16fbec RM |
1413 | if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, |
1414 | ar->fw_features)) | |
202e86e6 KV |
1415 | ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_10_2; |
1416 | else | |
1417 | ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_10_1; | |
1418 | } else { | |
1419 | ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_MAIN; | |
1420 | } | |
1421 | } | |
1422 | ||
1423 | switch (ar->wmi.op_version) { | |
1424 | case ATH10K_FW_WMI_OP_VERSION_MAIN: | |
cfd1061e MK |
1425 | ar->max_num_peers = TARGET_NUM_PEERS; |
1426 | ar->max_num_stations = TARGET_NUM_STATIONS; | |
30c78167 | 1427 | ar->max_num_vdevs = TARGET_NUM_VDEVS; |
91ad5f56 | 1428 | ar->htt.max_num_pending_tx = TARGET_NUM_MSDU_DESC; |
6274cd41 YL |
1429 | ar->fw_stats_req_mask = WMI_STAT_PDEV | WMI_STAT_VDEV | |
1430 | WMI_STAT_PEER; | |
5c8726ec | 1431 | ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM; |
202e86e6 KV |
1432 | break; |
1433 | case ATH10K_FW_WMI_OP_VERSION_10_1: | |
1434 | case ATH10K_FW_WMI_OP_VERSION_10_2: | |
4a16fbec | 1435 | case ATH10K_FW_WMI_OP_VERSION_10_2_4: |
202e86e6 KV |
1436 | ar->max_num_peers = TARGET_10X_NUM_PEERS; |
1437 | ar->max_num_stations = TARGET_10X_NUM_STATIONS; | |
30c78167 | 1438 | ar->max_num_vdevs = TARGET_10X_NUM_VDEVS; |
91ad5f56 | 1439 | ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC; |
6274cd41 | 1440 | ar->fw_stats_req_mask = WMI_STAT_PEER; |
5c8726ec | 1441 | ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM; |
202e86e6 | 1442 | break; |
ca996ec5 MK |
1443 | case ATH10K_FW_WMI_OP_VERSION_TLV: |
1444 | ar->max_num_peers = TARGET_TLV_NUM_PEERS; | |
1445 | ar->max_num_stations = TARGET_TLV_NUM_STATIONS; | |
49274332 | 1446 | ar->max_num_vdevs = TARGET_TLV_NUM_VDEVS; |
8cca3d60 | 1447 | ar->max_num_tdls_vdevs = TARGET_TLV_NUM_TDLS_VDEVS; |
ca996ec5 | 1448 | ar->htt.max_num_pending_tx = TARGET_TLV_NUM_MSDU_DESC; |
25c86619 | 1449 | ar->wow.max_num_patterns = TARGET_TLV_NUM_WOW_PATTERNS; |
6274cd41 YL |
1450 | ar->fw_stats_req_mask = WMI_STAT_PDEV | WMI_STAT_VDEV | |
1451 | WMI_STAT_PEER; | |
5c8726ec | 1452 | ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM; |
ca996ec5 | 1453 | break; |
9bd21322 | 1454 | case ATH10K_FW_WMI_OP_VERSION_10_4: |
d1e52a8e RM |
1455 | ar->max_num_peers = TARGET_10_4_NUM_PEERS; |
1456 | ar->max_num_stations = TARGET_10_4_NUM_STATIONS; | |
1457 | ar->num_active_peers = TARGET_10_4_ACTIVE_PEERS; | |
1458 | ar->max_num_vdevs = TARGET_10_4_NUM_VDEVS; | |
1459 | ar->num_tids = TARGET_10_4_TGT_NUM_TIDS; | |
721ad3ca | 1460 | ar->htt.max_num_pending_tx = TARGET_10_4_NUM_MSDU_DESC; |
d1e52a8e | 1461 | ar->fw_stats_req_mask = WMI_STAT_PEER; |
5c8726ec | 1462 | ar->max_spatial_stream = WMI_10_4_MAX_SPATIAL_STREAM; |
d1e52a8e | 1463 | break; |
202e86e6 KV |
1464 | case ATH10K_FW_WMI_OP_VERSION_UNSET: |
1465 | case ATH10K_FW_WMI_OP_VERSION_MAX: | |
1466 | WARN_ON(1); | |
1467 | return -EINVAL; | |
cfd1061e | 1468 | } |
5f2144d9 | 1469 | |
dc3632a1 KV |
1470 | /* Backwards compatibility for firmwares without |
1471 | * ATH10K_FW_IE_HTT_OP_VERSION. | |
1472 | */ | |
1473 | if (ar->htt.op_version == ATH10K_FW_HTT_OP_VERSION_UNSET) { | |
1474 | switch (ar->wmi.op_version) { | |
1475 | case ATH10K_FW_WMI_OP_VERSION_MAIN: | |
1476 | ar->htt.op_version = ATH10K_FW_HTT_OP_VERSION_MAIN; | |
1477 | break; | |
1478 | case ATH10K_FW_WMI_OP_VERSION_10_1: | |
1479 | case ATH10K_FW_WMI_OP_VERSION_10_2: | |
1480 | case ATH10K_FW_WMI_OP_VERSION_10_2_4: | |
1481 | ar->htt.op_version = ATH10K_FW_HTT_OP_VERSION_10_1; | |
1482 | break; | |
1483 | case ATH10K_FW_WMI_OP_VERSION_TLV: | |
1484 | ar->htt.op_version = ATH10K_FW_HTT_OP_VERSION_TLV; | |
1485 | break; | |
9bd21322 | 1486 | case ATH10K_FW_WMI_OP_VERSION_10_4: |
dc3632a1 KV |
1487 | case ATH10K_FW_WMI_OP_VERSION_UNSET: |
1488 | case ATH10K_FW_WMI_OP_VERSION_MAX: | |
1489 | WARN_ON(1); | |
1490 | return -EINVAL; | |
1491 | } | |
1492 | } | |
1493 | ||
5f2144d9 | 1494 | return 0; |
cfd1061e MK |
1495 | } |
1496 | ||
43d2a30f | 1497 | int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode) |
5e3dd157 | 1498 | { |
5e3dd157 KV |
1499 | int status; |
1500 | ||
60631c5c KV |
1501 | lockdep_assert_held(&ar->conf_mutex); |
1502 | ||
7962b0d8 MK |
1503 | clear_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags); |
1504 | ||
64d151d4 MK |
1505 | ath10k_bmi_start(ar); |
1506 | ||
5e3dd157 KV |
1507 | if (ath10k_init_configure_target(ar)) { |
1508 | status = -EINVAL; | |
1509 | goto err; | |
1510 | } | |
1511 | ||
83091559 KV |
1512 | status = ath10k_download_cal_data(ar); |
1513 | if (status) | |
1514 | goto err; | |
1515 | ||
163f5264 | 1516 | /* Some of of qca988x solutions are having global reset issue |
617b0f4d KV |
1517 | * during target initialization. Bypassing PLL setting before |
1518 | * downloading firmware and letting the SoC run on REF_CLK is | |
1519 | * fixing the problem. Corresponding firmware change is also needed | |
1520 | * to set the clock source once the target is initialized. | |
163f5264 RM |
1521 | */ |
1522 | if (test_bit(ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT, | |
1523 | ar->fw_features)) { | |
1524 | status = ath10k_bmi_write32(ar, hi_skip_clock_init, 1); | |
1525 | if (status) { | |
1526 | ath10k_err(ar, "could not write to skip_clock_init: %d\n", | |
1527 | status); | |
1528 | goto err; | |
1529 | } | |
1530 | } | |
1531 | ||
83091559 | 1532 | status = ath10k_download_fw(ar, mode); |
5e3dd157 KV |
1533 | if (status) |
1534 | goto err; | |
1535 | ||
1536 | status = ath10k_init_uart(ar); | |
1537 | if (status) | |
1538 | goto err; | |
1539 | ||
cd003fad MK |
1540 | ar->htc.htc_ops.target_send_suspend_complete = |
1541 | ath10k_send_suspend_complete; | |
5e3dd157 | 1542 | |
cd003fad MK |
1543 | status = ath10k_htc_init(ar); |
1544 | if (status) { | |
7aa7a72a | 1545 | ath10k_err(ar, "could not init HTC (%d)\n", status); |
5e3dd157 KV |
1546 | goto err; |
1547 | } | |
1548 | ||
1549 | status = ath10k_bmi_done(ar); | |
1550 | if (status) | |
cd003fad | 1551 | goto err; |
5e3dd157 KV |
1552 | |
1553 | status = ath10k_wmi_attach(ar); | |
1554 | if (status) { | |
7aa7a72a | 1555 | ath10k_err(ar, "WMI attach failed: %d\n", status); |
cd003fad | 1556 | goto err; |
5e3dd157 KV |
1557 | } |
1558 | ||
95bf21f9 MK |
1559 | status = ath10k_htt_init(ar); |
1560 | if (status) { | |
7aa7a72a | 1561 | ath10k_err(ar, "failed to init htt: %d\n", status); |
95bf21f9 MK |
1562 | goto err_wmi_detach; |
1563 | } | |
1564 | ||
1565 | status = ath10k_htt_tx_alloc(&ar->htt); | |
1566 | if (status) { | |
7aa7a72a | 1567 | ath10k_err(ar, "failed to alloc htt tx: %d\n", status); |
95bf21f9 MK |
1568 | goto err_wmi_detach; |
1569 | } | |
1570 | ||
1571 | status = ath10k_htt_rx_alloc(&ar->htt); | |
1572 | if (status) { | |
7aa7a72a | 1573 | ath10k_err(ar, "failed to alloc htt rx: %d\n", status); |
95bf21f9 MK |
1574 | goto err_htt_tx_detach; |
1575 | } | |
1576 | ||
67e3c63f MK |
1577 | status = ath10k_hif_start(ar); |
1578 | if (status) { | |
7aa7a72a | 1579 | ath10k_err(ar, "could not start HIF: %d\n", status); |
95bf21f9 | 1580 | goto err_htt_rx_detach; |
67e3c63f MK |
1581 | } |
1582 | ||
1583 | status = ath10k_htc_wait_target(&ar->htc); | |
1584 | if (status) { | |
7aa7a72a | 1585 | ath10k_err(ar, "failed to connect to HTC: %d\n", status); |
67e3c63f MK |
1586 | goto err_hif_stop; |
1587 | } | |
5e3dd157 | 1588 | |
43d2a30f KV |
1589 | if (mode == ATH10K_FIRMWARE_MODE_NORMAL) { |
1590 | status = ath10k_htt_connect(&ar->htt); | |
1591 | if (status) { | |
1592 | ath10k_err(ar, "failed to connect htt (%d)\n", status); | |
1593 | goto err_hif_stop; | |
1594 | } | |
5e3dd157 KV |
1595 | } |
1596 | ||
95bf21f9 MK |
1597 | status = ath10k_wmi_connect(ar); |
1598 | if (status) { | |
7aa7a72a | 1599 | ath10k_err(ar, "could not connect wmi: %d\n", status); |
95bf21f9 MK |
1600 | goto err_hif_stop; |
1601 | } | |
1602 | ||
1603 | status = ath10k_htc_start(&ar->htc); | |
1604 | if (status) { | |
7aa7a72a | 1605 | ath10k_err(ar, "failed to start htc: %d\n", status); |
95bf21f9 MK |
1606 | goto err_hif_stop; |
1607 | } | |
1608 | ||
43d2a30f KV |
1609 | if (mode == ATH10K_FIRMWARE_MODE_NORMAL) { |
1610 | status = ath10k_wmi_wait_for_service_ready(ar); | |
9eea5689 | 1611 | if (status) { |
43d2a30f | 1612 | ath10k_warn(ar, "wmi service ready event not received"); |
43d2a30f KV |
1613 | goto err_hif_stop; |
1614 | } | |
95bf21f9 | 1615 | } |
5e3dd157 | 1616 | |
7aa7a72a | 1617 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "firmware %s booted\n", |
c8c39afe | 1618 | ar->hw->wiphy->fw_version); |
5e3dd157 | 1619 | |
5e3dd157 KV |
1620 | status = ath10k_wmi_cmd_init(ar); |
1621 | if (status) { | |
7aa7a72a MK |
1622 | ath10k_err(ar, "could not send WMI init command (%d)\n", |
1623 | status); | |
b7967dc7 | 1624 | goto err_hif_stop; |
5e3dd157 KV |
1625 | } |
1626 | ||
1627 | status = ath10k_wmi_wait_for_unified_ready(ar); | |
9eea5689 | 1628 | if (status) { |
7aa7a72a | 1629 | ath10k_err(ar, "wmi unified ready event not received\n"); |
b7967dc7 | 1630 | goto err_hif_stop; |
5e3dd157 KV |
1631 | } |
1632 | ||
c545070e MK |
1633 | /* If firmware indicates Full Rx Reorder support it must be used in a |
1634 | * slightly different manner. Let HTT code know. | |
1635 | */ | |
1636 | ar->htt.rx_ring.in_ord_rx = !!(test_bit(WMI_SERVICE_RX_FULL_REORDER, | |
1637 | ar->wmi.svc_map)); | |
1638 | ||
1639 | status = ath10k_htt_rx_ring_refill(ar); | |
1640 | if (status) { | |
1641 | ath10k_err(ar, "failed to refill htt rx ring: %d\n", status); | |
1642 | goto err_hif_stop; | |
1643 | } | |
1644 | ||
43d2a30f KV |
1645 | /* we don't care about HTT in UTF mode */ |
1646 | if (mode == ATH10K_FIRMWARE_MODE_NORMAL) { | |
1647 | status = ath10k_htt_setup(&ar->htt); | |
1648 | if (status) { | |
1649 | ath10k_err(ar, "failed to setup htt: %d\n", status); | |
1650 | goto err_hif_stop; | |
1651 | } | |
95bf21f9 | 1652 | } |
5e3dd157 | 1653 | |
db66ea04 KV |
1654 | status = ath10k_debug_start(ar); |
1655 | if (status) | |
b7967dc7 | 1656 | goto err_hif_stop; |
db66ea04 | 1657 | |
30c78167 | 1658 | ar->free_vdev_map = (1LL << ar->max_num_vdevs) - 1; |
dfa413de | 1659 | |
0579119f | 1660 | INIT_LIST_HEAD(&ar->arvifs); |
1a1b8a88 | 1661 | |
dd30a36e MK |
1662 | return 0; |
1663 | ||
67e3c63f MK |
1664 | err_hif_stop: |
1665 | ath10k_hif_stop(ar); | |
95bf21f9 MK |
1666 | err_htt_rx_detach: |
1667 | ath10k_htt_rx_free(&ar->htt); | |
1668 | err_htt_tx_detach: | |
1669 | ath10k_htt_tx_free(&ar->htt); | |
dd30a36e MK |
1670 | err_wmi_detach: |
1671 | ath10k_wmi_detach(ar); | |
1672 | err: | |
1673 | return status; | |
1674 | } | |
818bdd16 | 1675 | EXPORT_SYMBOL(ath10k_core_start); |
dd30a36e | 1676 | |
00f5482b MP |
1677 | int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt) |
1678 | { | |
1679 | int ret; | |
a7a42849 | 1680 | unsigned long time_left; |
00f5482b MP |
1681 | |
1682 | reinit_completion(&ar->target_suspend); | |
1683 | ||
1684 | ret = ath10k_wmi_pdev_suspend_target(ar, suspend_opt); | |
1685 | if (ret) { | |
7aa7a72a | 1686 | ath10k_warn(ar, "could not suspend target (%d)\n", ret); |
00f5482b MP |
1687 | return ret; |
1688 | } | |
1689 | ||
a7a42849 | 1690 | time_left = wait_for_completion_timeout(&ar->target_suspend, 1 * HZ); |
00f5482b | 1691 | |
a7a42849 | 1692 | if (!time_left) { |
7aa7a72a | 1693 | ath10k_warn(ar, "suspend timed out - target pause event never came\n"); |
00f5482b MP |
1694 | return -ETIMEDOUT; |
1695 | } | |
1696 | ||
1697 | return 0; | |
1698 | } | |
1699 | ||
dd30a36e MK |
1700 | void ath10k_core_stop(struct ath10k *ar) |
1701 | { | |
60631c5c | 1702 | lockdep_assert_held(&ar->conf_mutex); |
f1ee2682 | 1703 | ath10k_debug_stop(ar); |
60631c5c | 1704 | |
00f5482b | 1705 | /* try to suspend target */ |
43d2a30f KV |
1706 | if (ar->state != ATH10K_STATE_RESTARTING && |
1707 | ar->state != ATH10K_STATE_UTF) | |
216a1836 MK |
1708 | ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND_AND_DISABLE_INTR); |
1709 | ||
95bf21f9 MK |
1710 | ath10k_hif_stop(ar); |
1711 | ath10k_htt_tx_free(&ar->htt); | |
1712 | ath10k_htt_rx_free(&ar->htt); | |
dd30a36e MK |
1713 | ath10k_wmi_detach(ar); |
1714 | } | |
818bdd16 MK |
1715 | EXPORT_SYMBOL(ath10k_core_stop); |
1716 | ||
1717 | /* mac80211 manages fw/hw initialization through start/stop hooks. However in | |
1718 | * order to know what hw capabilities should be advertised to mac80211 it is | |
1719 | * necessary to load the firmware (and tear it down immediately since start | |
1720 | * hook will try to init it again) before registering */ | |
1721 | static int ath10k_core_probe_fw(struct ath10k *ar) | |
1722 | { | |
29385057 MK |
1723 | struct bmi_target_info target_info; |
1724 | int ret = 0; | |
818bdd16 MK |
1725 | |
1726 | ret = ath10k_hif_power_up(ar); | |
1727 | if (ret) { | |
7aa7a72a | 1728 | ath10k_err(ar, "could not start pci hif (%d)\n", ret); |
818bdd16 MK |
1729 | return ret; |
1730 | } | |
1731 | ||
29385057 MK |
1732 | memset(&target_info, 0, sizeof(target_info)); |
1733 | ret = ath10k_bmi_get_target_info(ar, &target_info); | |
1734 | if (ret) { | |
7aa7a72a | 1735 | ath10k_err(ar, "could not get target info (%d)\n", ret); |
c6ce492d | 1736 | goto err_power_down; |
29385057 MK |
1737 | } |
1738 | ||
1739 | ar->target_version = target_info.version; | |
1740 | ar->hw->wiphy->hw_version = target_info.version; | |
1741 | ||
1742 | ret = ath10k_init_hw_params(ar); | |
1743 | if (ret) { | |
7aa7a72a | 1744 | ath10k_err(ar, "could not get hw params (%d)\n", ret); |
c6ce492d | 1745 | goto err_power_down; |
29385057 MK |
1746 | } |
1747 | ||
1748 | ret = ath10k_core_fetch_firmware_files(ar); | |
1749 | if (ret) { | |
7aa7a72a | 1750 | ath10k_err(ar, "could not fetch firmware files (%d)\n", ret); |
c6ce492d | 1751 | goto err_power_down; |
29385057 MK |
1752 | } |
1753 | ||
db0984e5 MP |
1754 | ret = ath10k_core_get_board_id_from_otp(ar); |
1755 | if (ret && ret != -EOPNOTSUPP) { | |
1756 | ath10k_err(ar, "failed to get board id from otp for qca99x0: %d\n", | |
1757 | ret); | |
1758 | return ret; | |
1759 | } | |
1760 | ||
1761 | ret = ath10k_core_fetch_board_file(ar); | |
1762 | if (ret) { | |
1763 | ath10k_err(ar, "failed to fetch board file: %d\n", ret); | |
1764 | goto err_free_firmware_files; | |
1765 | } | |
1766 | ||
5f2144d9 KV |
1767 | ret = ath10k_core_init_firmware_features(ar); |
1768 | if (ret) { | |
1769 | ath10k_err(ar, "fatal problem with firmware features: %d\n", | |
1770 | ret); | |
1771 | goto err_free_firmware_files; | |
1772 | } | |
cfd1061e | 1773 | |
dcb02db1 VT |
1774 | ret = ath10k_swap_code_seg_init(ar); |
1775 | if (ret) { | |
1776 | ath10k_err(ar, "failed to initialize code swap segment: %d\n", | |
1777 | ret); | |
1778 | goto err_free_firmware_files; | |
1779 | } | |
1780 | ||
60631c5c KV |
1781 | mutex_lock(&ar->conf_mutex); |
1782 | ||
43d2a30f | 1783 | ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL); |
818bdd16 | 1784 | if (ret) { |
7aa7a72a | 1785 | ath10k_err(ar, "could not init core (%d)\n", ret); |
c6ce492d | 1786 | goto err_unlock; |
818bdd16 MK |
1787 | } |
1788 | ||
8079de0d | 1789 | ath10k_print_driver_info(ar); |
818bdd16 | 1790 | ath10k_core_stop(ar); |
60631c5c KV |
1791 | |
1792 | mutex_unlock(&ar->conf_mutex); | |
1793 | ||
818bdd16 MK |
1794 | ath10k_hif_power_down(ar); |
1795 | return 0; | |
c6ce492d KV |
1796 | |
1797 | err_unlock: | |
1798 | mutex_unlock(&ar->conf_mutex); | |
1799 | ||
5f2144d9 | 1800 | err_free_firmware_files: |
c6ce492d KV |
1801 | ath10k_core_free_firmware_files(ar); |
1802 | ||
1803 | err_power_down: | |
1804 | ath10k_hif_power_down(ar); | |
1805 | ||
1806 | return ret; | |
818bdd16 | 1807 | } |
dd30a36e | 1808 | |
6782cb69 | 1809 | static void ath10k_core_register_work(struct work_struct *work) |
dd30a36e | 1810 | { |
6782cb69 | 1811 | struct ath10k *ar = container_of(work, struct ath10k, register_work); |
dd30a36e MK |
1812 | int status; |
1813 | ||
818bdd16 MK |
1814 | status = ath10k_core_probe_fw(ar); |
1815 | if (status) { | |
7aa7a72a | 1816 | ath10k_err(ar, "could not probe fw (%d)\n", status); |
6782cb69 | 1817 | goto err; |
818bdd16 | 1818 | } |
dd30a36e | 1819 | |
5e3dd157 | 1820 | status = ath10k_mac_register(ar); |
818bdd16 | 1821 | if (status) { |
7aa7a72a | 1822 | ath10k_err(ar, "could not register to mac80211 (%d)\n", status); |
29385057 | 1823 | goto err_release_fw; |
818bdd16 | 1824 | } |
5e3dd157 | 1825 | |
e13cf7a3 | 1826 | status = ath10k_debug_register(ar); |
5e3dd157 | 1827 | if (status) { |
7aa7a72a | 1828 | ath10k_err(ar, "unable to initialize debugfs\n"); |
5e3dd157 KV |
1829 | goto err_unregister_mac; |
1830 | } | |
1831 | ||
855aed12 SW |
1832 | status = ath10k_spectral_create(ar); |
1833 | if (status) { | |
7aa7a72a | 1834 | ath10k_err(ar, "failed to initialize spectral\n"); |
855aed12 SW |
1835 | goto err_debug_destroy; |
1836 | } | |
1837 | ||
fe6f36d6 RM |
1838 | status = ath10k_thermal_register(ar); |
1839 | if (status) { | |
1840 | ath10k_err(ar, "could not register thermal device: %d\n", | |
1841 | status); | |
1842 | goto err_spectral_destroy; | |
1843 | } | |
1844 | ||
6782cb69 MK |
1845 | set_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags); |
1846 | return; | |
5e3dd157 | 1847 | |
fe6f36d6 RM |
1848 | err_spectral_destroy: |
1849 | ath10k_spectral_destroy(ar); | |
855aed12 SW |
1850 | err_debug_destroy: |
1851 | ath10k_debug_destroy(ar); | |
5e3dd157 KV |
1852 | err_unregister_mac: |
1853 | ath10k_mac_unregister(ar); | |
29385057 MK |
1854 | err_release_fw: |
1855 | ath10k_core_free_firmware_files(ar); | |
6782cb69 | 1856 | err: |
a491a920 MK |
1857 | /* TODO: It's probably a good idea to release device from the driver |
1858 | * but calling device_release_driver() here will cause a deadlock. | |
1859 | */ | |
6782cb69 MK |
1860 | return; |
1861 | } | |
1862 | ||
1863 | int ath10k_core_register(struct ath10k *ar, u32 chip_id) | |
1864 | { | |
6782cb69 | 1865 | ar->chip_id = chip_id; |
6782cb69 MK |
1866 | queue_work(ar->workqueue, &ar->register_work); |
1867 | ||
1868 | return 0; | |
5e3dd157 KV |
1869 | } |
1870 | EXPORT_SYMBOL(ath10k_core_register); | |
1871 | ||
1872 | void ath10k_core_unregister(struct ath10k *ar) | |
1873 | { | |
6782cb69 MK |
1874 | cancel_work_sync(&ar->register_work); |
1875 | ||
1876 | if (!test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags)) | |
1877 | return; | |
1878 | ||
fe6f36d6 | 1879 | ath10k_thermal_unregister(ar); |
804eef14 SW |
1880 | /* Stop spectral before unregistering from mac80211 to remove the |
1881 | * relayfs debugfs file cleanly. Otherwise the parent debugfs tree | |
1882 | * would be already be free'd recursively, leading to a double free. | |
1883 | */ | |
1884 | ath10k_spectral_destroy(ar); | |
1885 | ||
5e3dd157 KV |
1886 | /* We must unregister from mac80211 before we stop HTC and HIF. |
1887 | * Otherwise we will fail to submit commands to FW and mac80211 will be | |
1888 | * unhappy about callback failures. */ | |
1889 | ath10k_mac_unregister(ar); | |
db66ea04 | 1890 | |
43d2a30f KV |
1891 | ath10k_testmode_destroy(ar); |
1892 | ||
29385057 | 1893 | ath10k_core_free_firmware_files(ar); |
0a51b343 | 1894 | ath10k_core_free_board_files(ar); |
6f1f56ea | 1895 | |
e13cf7a3 | 1896 | ath10k_debug_unregister(ar); |
5e3dd157 KV |
1897 | } |
1898 | EXPORT_SYMBOL(ath10k_core_unregister); | |
1899 | ||
e7b54194 | 1900 | struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, |
e07db352 | 1901 | enum ath10k_bus bus, |
d63955b3 | 1902 | enum ath10k_hw_rev hw_rev, |
0d0a6939 MK |
1903 | const struct ath10k_hif_ops *hif_ops) |
1904 | { | |
1905 | struct ath10k *ar; | |
e13cf7a3 | 1906 | int ret; |
0d0a6939 | 1907 | |
e7b54194 | 1908 | ar = ath10k_mac_create(priv_size); |
0d0a6939 MK |
1909 | if (!ar) |
1910 | return NULL; | |
1911 | ||
1912 | ar->ath_common.priv = ar; | |
1913 | ar->ath_common.hw = ar->hw; | |
0d0a6939 | 1914 | ar->dev = dev; |
d63955b3 | 1915 | ar->hw_rev = hw_rev; |
0d0a6939 | 1916 | ar->hif.ops = hif_ops; |
e07db352 | 1917 | ar->hif.bus = bus; |
0d0a6939 | 1918 | |
d63955b3 MK |
1919 | switch (hw_rev) { |
1920 | case ATH10K_HW_QCA988X: | |
1921 | ar->regs = &qca988x_regs; | |
2f2cfc4a | 1922 | ar->hw_values = &qca988x_values; |
d63955b3 MK |
1923 | break; |
1924 | case ATH10K_HW_QCA6174: | |
a226b519 | 1925 | case ATH10K_HW_QCA9377: |
d63955b3 | 1926 | ar->regs = &qca6174_regs; |
2f2cfc4a | 1927 | ar->hw_values = &qca6174_values; |
d63955b3 | 1928 | break; |
8bd47021 VT |
1929 | case ATH10K_HW_QCA99X0: |
1930 | ar->regs = &qca99x0_regs; | |
1931 | ar->hw_values = &qca99x0_values; | |
1932 | break; | |
d63955b3 MK |
1933 | default: |
1934 | ath10k_err(ar, "unsupported core hardware revision %d\n", | |
1935 | hw_rev); | |
1936 | ret = -ENOTSUPP; | |
1937 | goto err_free_mac; | |
1938 | } | |
1939 | ||
0d0a6939 MK |
1940 | init_completion(&ar->scan.started); |
1941 | init_completion(&ar->scan.completed); | |
1942 | init_completion(&ar->scan.on_channel); | |
1943 | init_completion(&ar->target_suspend); | |
5fd3ac3c | 1944 | init_completion(&ar->wow.wakeup_completed); |
0d0a6939 MK |
1945 | |
1946 | init_completion(&ar->install_key_done); | |
1947 | init_completion(&ar->vdev_setup_done); | |
ac2953fc | 1948 | init_completion(&ar->thermal.wmi_sync); |
0d0a6939 | 1949 | |
5c81c7fd | 1950 | INIT_DELAYED_WORK(&ar->scan.timeout, ath10k_scan_timeout_work); |
0d0a6939 MK |
1951 | |
1952 | ar->workqueue = create_singlethread_workqueue("ath10k_wq"); | |
1953 | if (!ar->workqueue) | |
e13cf7a3 | 1954 | goto err_free_mac; |
0d0a6939 | 1955 | |
c8ecfc1c RM |
1956 | ar->workqueue_aux = create_singlethread_workqueue("ath10k_aux_wq"); |
1957 | if (!ar->workqueue_aux) | |
1958 | goto err_free_wq; | |
1959 | ||
0d0a6939 MK |
1960 | mutex_init(&ar->conf_mutex); |
1961 | spin_lock_init(&ar->data_lock); | |
1962 | ||
1963 | INIT_LIST_HEAD(&ar->peers); | |
1964 | init_waitqueue_head(&ar->peer_mapping_wq); | |
7962b0d8 MK |
1965 | init_waitqueue_head(&ar->htt.empty_tx_wq); |
1966 | init_waitqueue_head(&ar->wmi.tx_credits_wq); | |
0d0a6939 MK |
1967 | |
1968 | init_completion(&ar->offchan_tx_completed); | |
1969 | INIT_WORK(&ar->offchan_tx_work, ath10k_offchan_tx_work); | |
1970 | skb_queue_head_init(&ar->offchan_tx_queue); | |
1971 | ||
1972 | INIT_WORK(&ar->wmi_mgmt_tx_work, ath10k_mgmt_over_wmi_tx_work); | |
1973 | skb_queue_head_init(&ar->wmi_mgmt_tx_queue); | |
1974 | ||
6782cb69 | 1975 | INIT_WORK(&ar->register_work, ath10k_core_register_work); |
0d0a6939 MK |
1976 | INIT_WORK(&ar->restart_work, ath10k_core_restart); |
1977 | ||
e13cf7a3 MK |
1978 | ret = ath10k_debug_create(ar); |
1979 | if (ret) | |
c8ecfc1c | 1980 | goto err_free_aux_wq; |
e13cf7a3 | 1981 | |
0d0a6939 MK |
1982 | return ar; |
1983 | ||
c8ecfc1c RM |
1984 | err_free_aux_wq: |
1985 | destroy_workqueue(ar->workqueue_aux); | |
e13cf7a3 MK |
1986 | err_free_wq: |
1987 | destroy_workqueue(ar->workqueue); | |
1988 | ||
1989 | err_free_mac: | |
0d0a6939 | 1990 | ath10k_mac_destroy(ar); |
e13cf7a3 | 1991 | |
0d0a6939 MK |
1992 | return NULL; |
1993 | } | |
1994 | EXPORT_SYMBOL(ath10k_core_create); | |
1995 | ||
1996 | void ath10k_core_destroy(struct ath10k *ar) | |
1997 | { | |
1998 | flush_workqueue(ar->workqueue); | |
1999 | destroy_workqueue(ar->workqueue); | |
2000 | ||
c8ecfc1c RM |
2001 | flush_workqueue(ar->workqueue_aux); |
2002 | destroy_workqueue(ar->workqueue_aux); | |
2003 | ||
e13cf7a3 | 2004 | ath10k_debug_destroy(ar); |
a925a376 | 2005 | ath10k_wmi_free_host_mem(ar); |
0d0a6939 MK |
2006 | ath10k_mac_destroy(ar); |
2007 | } | |
2008 | EXPORT_SYMBOL(ath10k_core_destroy); | |
2009 | ||
5e3dd157 KV |
2010 | MODULE_AUTHOR("Qualcomm Atheros"); |
2011 | MODULE_DESCRIPTION("Core module for QCA988X PCIe devices."); | |
2012 | MODULE_LICENSE("Dual BSD/GPL"); |