xref: /freebsd/sys/contrib/dev/athk/ath12k/core.c (revision 5c1def83a4cc2eb3f828600dfd786f8c5788fb7d)
1*5c1def83SBjoern A. Zeeb // SPDX-License-Identifier: BSD-3-Clause-Clear
2*5c1def83SBjoern A. Zeeb /*
3*5c1def83SBjoern A. Zeeb  * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
4*5c1def83SBjoern A. Zeeb  * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
5*5c1def83SBjoern A. Zeeb  */
6*5c1def83SBjoern A. Zeeb 
7*5c1def83SBjoern A. Zeeb #if defined(__FreeBSD__)
8*5c1def83SBjoern A. Zeeb #define	LINUXKPI_PARAM_PREFIX	ath12k_core_
9*5c1def83SBjoern A. Zeeb #endif
10*5c1def83SBjoern A. Zeeb 
11*5c1def83SBjoern A. Zeeb #include <linux/module.h>
12*5c1def83SBjoern A. Zeeb #include <linux/slab.h>
13*5c1def83SBjoern A. Zeeb #include <linux/remoteproc.h>
14*5c1def83SBjoern A. Zeeb #include <linux/firmware.h>
15*5c1def83SBjoern A. Zeeb #include <linux/of.h>
16*5c1def83SBjoern A. Zeeb #if defined(__FreeBSD__)
17*5c1def83SBjoern A. Zeeb #include <linux/delay.h>
18*5c1def83SBjoern A. Zeeb #endif
19*5c1def83SBjoern A. Zeeb #include "core.h"
20*5c1def83SBjoern A. Zeeb #include "dp_tx.h"
21*5c1def83SBjoern A. Zeeb #include "dp_rx.h"
22*5c1def83SBjoern A. Zeeb #include "debug.h"
23*5c1def83SBjoern A. Zeeb #include "hif.h"
24*5c1def83SBjoern A. Zeeb 
25*5c1def83SBjoern A. Zeeb unsigned int ath12k_debug_mask;
26*5c1def83SBjoern A. Zeeb module_param_named(debug_mask, ath12k_debug_mask, uint, 0644);
27*5c1def83SBjoern A. Zeeb MODULE_PARM_DESC(debug_mask, "Debugging mask");
28*5c1def83SBjoern A. Zeeb 
ath12k_core_suspend(struct ath12k_base * ab)29*5c1def83SBjoern A. Zeeb int ath12k_core_suspend(struct ath12k_base *ab)
30*5c1def83SBjoern A. Zeeb {
31*5c1def83SBjoern A. Zeeb 	int ret;
32*5c1def83SBjoern A. Zeeb 
33*5c1def83SBjoern A. Zeeb 	if (!ab->hw_params->supports_suspend)
34*5c1def83SBjoern A. Zeeb 		return -EOPNOTSUPP;
35*5c1def83SBjoern A. Zeeb 
36*5c1def83SBjoern A. Zeeb 	/* TODO: there can frames in queues so for now add delay as a hack.
37*5c1def83SBjoern A. Zeeb 	 * Need to implement to handle and remove this delay.
38*5c1def83SBjoern A. Zeeb 	 */
39*5c1def83SBjoern A. Zeeb #if defined(__linux__)
40*5c1def83SBjoern A. Zeeb 	msleep(500);
41*5c1def83SBjoern A. Zeeb #elif defined(__FreeBSD__)
42*5c1def83SBjoern A. Zeeb 	linux_msleep(500);
43*5c1def83SBjoern A. Zeeb #endif
44*5c1def83SBjoern A. Zeeb 
45*5c1def83SBjoern A. Zeeb 	ret = ath12k_dp_rx_pktlog_stop(ab, true);
46*5c1def83SBjoern A. Zeeb 	if (ret) {
47*5c1def83SBjoern A. Zeeb 		ath12k_warn(ab, "failed to stop dp rx (and timer) pktlog during suspend: %d\n",
48*5c1def83SBjoern A. Zeeb 			    ret);
49*5c1def83SBjoern A. Zeeb 		return ret;
50*5c1def83SBjoern A. Zeeb 	}
51*5c1def83SBjoern A. Zeeb 
52*5c1def83SBjoern A. Zeeb 	ret = ath12k_dp_rx_pktlog_stop(ab, false);
53*5c1def83SBjoern A. Zeeb 	if (ret) {
54*5c1def83SBjoern A. Zeeb 		ath12k_warn(ab, "failed to stop dp rx pktlog during suspend: %d\n",
55*5c1def83SBjoern A. Zeeb 			    ret);
56*5c1def83SBjoern A. Zeeb 		return ret;
57*5c1def83SBjoern A. Zeeb 	}
58*5c1def83SBjoern A. Zeeb 
59*5c1def83SBjoern A. Zeeb 	ath12k_hif_irq_disable(ab);
60*5c1def83SBjoern A. Zeeb 	ath12k_hif_ce_irq_disable(ab);
61*5c1def83SBjoern A. Zeeb 
62*5c1def83SBjoern A. Zeeb 	ret = ath12k_hif_suspend(ab);
63*5c1def83SBjoern A. Zeeb 	if (ret) {
64*5c1def83SBjoern A. Zeeb 		ath12k_warn(ab, "failed to suspend hif: %d\n", ret);
65*5c1def83SBjoern A. Zeeb 		return ret;
66*5c1def83SBjoern A. Zeeb 	}
67*5c1def83SBjoern A. Zeeb 
68*5c1def83SBjoern A. Zeeb 	return 0;
69*5c1def83SBjoern A. Zeeb }
70*5c1def83SBjoern A. Zeeb 
ath12k_core_resume(struct ath12k_base * ab)71*5c1def83SBjoern A. Zeeb int ath12k_core_resume(struct ath12k_base *ab)
72*5c1def83SBjoern A. Zeeb {
73*5c1def83SBjoern A. Zeeb 	int ret;
74*5c1def83SBjoern A. Zeeb 
75*5c1def83SBjoern A. Zeeb 	if (!ab->hw_params->supports_suspend)
76*5c1def83SBjoern A. Zeeb 		return -EOPNOTSUPP;
77*5c1def83SBjoern A. Zeeb 
78*5c1def83SBjoern A. Zeeb 	ret = ath12k_hif_resume(ab);
79*5c1def83SBjoern A. Zeeb 	if (ret) {
80*5c1def83SBjoern A. Zeeb 		ath12k_warn(ab, "failed to resume hif during resume: %d\n", ret);
81*5c1def83SBjoern A. Zeeb 		return ret;
82*5c1def83SBjoern A. Zeeb 	}
83*5c1def83SBjoern A. Zeeb 
84*5c1def83SBjoern A. Zeeb 	ath12k_hif_ce_irq_enable(ab);
85*5c1def83SBjoern A. Zeeb 	ath12k_hif_irq_enable(ab);
86*5c1def83SBjoern A. Zeeb 
87*5c1def83SBjoern A. Zeeb 	ret = ath12k_dp_rx_pktlog_start(ab);
88*5c1def83SBjoern A. Zeeb 	if (ret) {
89*5c1def83SBjoern A. Zeeb 		ath12k_warn(ab, "failed to start rx pktlog during resume: %d\n",
90*5c1def83SBjoern A. Zeeb 			    ret);
91*5c1def83SBjoern A. Zeeb 		return ret;
92*5c1def83SBjoern A. Zeeb 	}
93*5c1def83SBjoern A. Zeeb 
94*5c1def83SBjoern A. Zeeb 	return 0;
95*5c1def83SBjoern A. Zeeb }
96*5c1def83SBjoern A. Zeeb 
ath12k_core_create_board_name(struct ath12k_base * ab,char * name,size_t name_len)97*5c1def83SBjoern A. Zeeb static int ath12k_core_create_board_name(struct ath12k_base *ab, char *name,
98*5c1def83SBjoern A. Zeeb 					 size_t name_len)
99*5c1def83SBjoern A. Zeeb {
100*5c1def83SBjoern A. Zeeb 	/* strlen(',variant=') + strlen(ab->qmi.target.bdf_ext) */
101*5c1def83SBjoern A. Zeeb 	char variant[9 + ATH12K_QMI_BDF_EXT_STR_LENGTH] = { 0 };
102*5c1def83SBjoern A. Zeeb 
103*5c1def83SBjoern A. Zeeb 	if (ab->qmi.target.bdf_ext[0] != '\0')
104*5c1def83SBjoern A. Zeeb 		scnprintf(variant, sizeof(variant), ",variant=%s",
105*5c1def83SBjoern A. Zeeb 			  ab->qmi.target.bdf_ext);
106*5c1def83SBjoern A. Zeeb 
107*5c1def83SBjoern A. Zeeb 	scnprintf(name, name_len,
108*5c1def83SBjoern A. Zeeb 		  "bus=%s,qmi-chip-id=%d,qmi-board-id=%d%s",
109*5c1def83SBjoern A. Zeeb 		  ath12k_bus_str(ab->hif.bus),
110*5c1def83SBjoern A. Zeeb 		  ab->qmi.target.chip_id,
111*5c1def83SBjoern A. Zeeb 		  ab->qmi.target.board_id, variant);
112*5c1def83SBjoern A. Zeeb 
113*5c1def83SBjoern A. Zeeb 	ath12k_dbg(ab, ATH12K_DBG_BOOT, "boot using board name '%s'\n", name);
114*5c1def83SBjoern A. Zeeb 
115*5c1def83SBjoern A. Zeeb 	return 0;
116*5c1def83SBjoern A. Zeeb }
117*5c1def83SBjoern A. Zeeb 
ath12k_core_firmware_request(struct ath12k_base * ab,const char * file)118*5c1def83SBjoern A. Zeeb const struct firmware *ath12k_core_firmware_request(struct ath12k_base *ab,
119*5c1def83SBjoern A. Zeeb 						    const char *file)
120*5c1def83SBjoern A. Zeeb {
121*5c1def83SBjoern A. Zeeb 	const struct firmware *fw;
122*5c1def83SBjoern A. Zeeb 	char path[100];
123*5c1def83SBjoern A. Zeeb 	int ret;
124*5c1def83SBjoern A. Zeeb 
125*5c1def83SBjoern A. Zeeb 	if (!file)
126*5c1def83SBjoern A. Zeeb 		return ERR_PTR(-ENOENT);
127*5c1def83SBjoern A. Zeeb 
128*5c1def83SBjoern A. Zeeb 	ath12k_core_create_firmware_path(ab, file, path, sizeof(path));
129*5c1def83SBjoern A. Zeeb 
130*5c1def83SBjoern A. Zeeb 	ret = firmware_request_nowarn(&fw, path, ab->dev);
131*5c1def83SBjoern A. Zeeb 	if (ret)
132*5c1def83SBjoern A. Zeeb 		return ERR_PTR(ret);
133*5c1def83SBjoern A. Zeeb 
134*5c1def83SBjoern A. Zeeb 	ath12k_dbg(ab, ATH12K_DBG_BOOT, "boot firmware request %s size %zu\n",
135*5c1def83SBjoern A. Zeeb 		   path, fw->size);
136*5c1def83SBjoern A. Zeeb 
137*5c1def83SBjoern A. Zeeb 	return fw;
138*5c1def83SBjoern A. Zeeb }
139*5c1def83SBjoern A. Zeeb 
ath12k_core_free_bdf(struct ath12k_base * ab,struct ath12k_board_data * bd)140*5c1def83SBjoern A. Zeeb void ath12k_core_free_bdf(struct ath12k_base *ab, struct ath12k_board_data *bd)
141*5c1def83SBjoern A. Zeeb {
142*5c1def83SBjoern A. Zeeb 	if (!IS_ERR(bd->fw))
143*5c1def83SBjoern A. Zeeb 		release_firmware(bd->fw);
144*5c1def83SBjoern A. Zeeb 
145*5c1def83SBjoern A. Zeeb 	memset(bd, 0, sizeof(*bd));
146*5c1def83SBjoern A. Zeeb }
147*5c1def83SBjoern A. Zeeb 
ath12k_core_parse_bd_ie_board(struct ath12k_base * ab,struct ath12k_board_data * bd,const void * buf,size_t buf_len,const char * boardname,int bd_ie_type)148*5c1def83SBjoern A. Zeeb static int ath12k_core_parse_bd_ie_board(struct ath12k_base *ab,
149*5c1def83SBjoern A. Zeeb 					 struct ath12k_board_data *bd,
150*5c1def83SBjoern A. Zeeb #if defined(__linux__)
151*5c1def83SBjoern A. Zeeb 					 const void *buf, size_t buf_len,
152*5c1def83SBjoern A. Zeeb #elif defined(__FreeBSD__)
153*5c1def83SBjoern A. Zeeb 					 const u8 *buf, size_t buf_len,
154*5c1def83SBjoern A. Zeeb #endif
155*5c1def83SBjoern A. Zeeb 					 const char *boardname,
156*5c1def83SBjoern A. Zeeb 					 int bd_ie_type)
157*5c1def83SBjoern A. Zeeb {
158*5c1def83SBjoern A. Zeeb 	const struct ath12k_fw_ie *hdr;
159*5c1def83SBjoern A. Zeeb 	bool name_match_found;
160*5c1def83SBjoern A. Zeeb 	int ret, board_ie_id;
161*5c1def83SBjoern A. Zeeb 	size_t board_ie_len;
162*5c1def83SBjoern A. Zeeb 	const void *board_ie_data;
163*5c1def83SBjoern A. Zeeb 
164*5c1def83SBjoern A. Zeeb 	name_match_found = false;
165*5c1def83SBjoern A. Zeeb 
166*5c1def83SBjoern A. Zeeb 	/* go through ATH12K_BD_IE_BOARD_ elements */
167*5c1def83SBjoern A. Zeeb 	while (buf_len > sizeof(struct ath12k_fw_ie)) {
168*5c1def83SBjoern A. Zeeb #if defined(__linux__)
169*5c1def83SBjoern A. Zeeb 		hdr = buf;
170*5c1def83SBjoern A. Zeeb #elif defined(__FreeBSD__)
171*5c1def83SBjoern A. Zeeb 		hdr = (const struct ath12k_fw_ie *)buf;
172*5c1def83SBjoern A. Zeeb #endif
173*5c1def83SBjoern A. Zeeb 		board_ie_id = le32_to_cpu(hdr->id);
174*5c1def83SBjoern A. Zeeb 		board_ie_len = le32_to_cpu(hdr->len);
175*5c1def83SBjoern A. Zeeb 		board_ie_data = hdr->data;
176*5c1def83SBjoern A. Zeeb 
177*5c1def83SBjoern A. Zeeb 		buf_len -= sizeof(*hdr);
178*5c1def83SBjoern A. Zeeb 		buf += sizeof(*hdr);
179*5c1def83SBjoern A. Zeeb 
180*5c1def83SBjoern A. Zeeb 		if (buf_len < ALIGN(board_ie_len, 4)) {
181*5c1def83SBjoern A. Zeeb 			ath12k_err(ab, "invalid ATH12K_BD_IE_BOARD length: %zu < %zu\n",
182*5c1def83SBjoern A. Zeeb 				   buf_len, ALIGN(board_ie_len, 4));
183*5c1def83SBjoern A. Zeeb 			ret = -EINVAL;
184*5c1def83SBjoern A. Zeeb 			goto out;
185*5c1def83SBjoern A. Zeeb 		}
186*5c1def83SBjoern A. Zeeb 
187*5c1def83SBjoern A. Zeeb 		switch (board_ie_id) {
188*5c1def83SBjoern A. Zeeb 		case ATH12K_BD_IE_BOARD_NAME:
189*5c1def83SBjoern A. Zeeb 			ath12k_dbg_dump(ab, ATH12K_DBG_BOOT, "board name", "",
190*5c1def83SBjoern A. Zeeb 					board_ie_data, board_ie_len);
191*5c1def83SBjoern A. Zeeb 
192*5c1def83SBjoern A. Zeeb 			if (board_ie_len != strlen(boardname))
193*5c1def83SBjoern A. Zeeb 				break;
194*5c1def83SBjoern A. Zeeb 
195*5c1def83SBjoern A. Zeeb 			ret = memcmp(board_ie_data, boardname, strlen(boardname));
196*5c1def83SBjoern A. Zeeb 			if (ret)
197*5c1def83SBjoern A. Zeeb 				break;
198*5c1def83SBjoern A. Zeeb 
199*5c1def83SBjoern A. Zeeb 			name_match_found = true;
200*5c1def83SBjoern A. Zeeb 			ath12k_dbg(ab, ATH12K_DBG_BOOT,
201*5c1def83SBjoern A. Zeeb 				   "boot found match for name '%s'",
202*5c1def83SBjoern A. Zeeb 				   boardname);
203*5c1def83SBjoern A. Zeeb 			break;
204*5c1def83SBjoern A. Zeeb 		case ATH12K_BD_IE_BOARD_DATA:
205*5c1def83SBjoern A. Zeeb 			if (!name_match_found)
206*5c1def83SBjoern A. Zeeb 				/* no match found */
207*5c1def83SBjoern A. Zeeb 				break;
208*5c1def83SBjoern A. Zeeb 
209*5c1def83SBjoern A. Zeeb 			ath12k_dbg(ab, ATH12K_DBG_BOOT,
210*5c1def83SBjoern A. Zeeb 				   "boot found board data for '%s'", boardname);
211*5c1def83SBjoern A. Zeeb 
212*5c1def83SBjoern A. Zeeb 			bd->data = board_ie_data;
213*5c1def83SBjoern A. Zeeb 			bd->len = board_ie_len;
214*5c1def83SBjoern A. Zeeb 
215*5c1def83SBjoern A. Zeeb 			ret = 0;
216*5c1def83SBjoern A. Zeeb 			goto out;
217*5c1def83SBjoern A. Zeeb 		default:
218*5c1def83SBjoern A. Zeeb 			ath12k_warn(ab, "unknown ATH12K_BD_IE_BOARD found: %d\n",
219*5c1def83SBjoern A. Zeeb 				    board_ie_id);
220*5c1def83SBjoern A. Zeeb 			break;
221*5c1def83SBjoern A. Zeeb 		}
222*5c1def83SBjoern A. Zeeb 
223*5c1def83SBjoern A. Zeeb 		/* jump over the padding */
224*5c1def83SBjoern A. Zeeb 		board_ie_len = ALIGN(board_ie_len, 4);
225*5c1def83SBjoern A. Zeeb 
226*5c1def83SBjoern A. Zeeb 		buf_len -= board_ie_len;
227*5c1def83SBjoern A. Zeeb 		buf += board_ie_len;
228*5c1def83SBjoern A. Zeeb 	}
229*5c1def83SBjoern A. Zeeb 
230*5c1def83SBjoern A. Zeeb 	/* no match found */
231*5c1def83SBjoern A. Zeeb 	ret = -ENOENT;
232*5c1def83SBjoern A. Zeeb 
233*5c1def83SBjoern A. Zeeb out:
234*5c1def83SBjoern A. Zeeb 	return ret;
235*5c1def83SBjoern A. Zeeb }
236*5c1def83SBjoern A. Zeeb 
ath12k_core_fetch_board_data_api_n(struct ath12k_base * ab,struct ath12k_board_data * bd,const char * boardname)237*5c1def83SBjoern A. Zeeb static int ath12k_core_fetch_board_data_api_n(struct ath12k_base *ab,
238*5c1def83SBjoern A. Zeeb 					      struct ath12k_board_data *bd,
239*5c1def83SBjoern A. Zeeb 					      const char *boardname)
240*5c1def83SBjoern A. Zeeb {
241*5c1def83SBjoern A. Zeeb 	size_t len, magic_len;
242*5c1def83SBjoern A. Zeeb 	const u8 *data;
243*5c1def83SBjoern A. Zeeb 	char *filename, filepath[100];
244*5c1def83SBjoern A. Zeeb 	size_t ie_len;
245*5c1def83SBjoern A. Zeeb #if defined(__linux__)
246*5c1def83SBjoern A. Zeeb 	struct ath12k_fw_ie *hdr;
247*5c1def83SBjoern A. Zeeb #elif defined(__FreeBSD__)
248*5c1def83SBjoern A. Zeeb 	const struct ath12k_fw_ie *hdr;
249*5c1def83SBjoern A. Zeeb #endif
250*5c1def83SBjoern A. Zeeb 	int ret, ie_id;
251*5c1def83SBjoern A. Zeeb 
252*5c1def83SBjoern A. Zeeb 	filename = ATH12K_BOARD_API2_FILE;
253*5c1def83SBjoern A. Zeeb 
254*5c1def83SBjoern A. Zeeb 	if (!bd->fw)
255*5c1def83SBjoern A. Zeeb 		bd->fw = ath12k_core_firmware_request(ab, filename);
256*5c1def83SBjoern A. Zeeb 
257*5c1def83SBjoern A. Zeeb 	if (IS_ERR(bd->fw))
258*5c1def83SBjoern A. Zeeb 		return PTR_ERR(bd->fw);
259*5c1def83SBjoern A. Zeeb 
260*5c1def83SBjoern A. Zeeb 	data = bd->fw->data;
261*5c1def83SBjoern A. Zeeb 	len = bd->fw->size;
262*5c1def83SBjoern A. Zeeb 
263*5c1def83SBjoern A. Zeeb 	ath12k_core_create_firmware_path(ab, filename,
264*5c1def83SBjoern A. Zeeb 					 filepath, sizeof(filepath));
265*5c1def83SBjoern A. Zeeb 
266*5c1def83SBjoern A. Zeeb 	/* magic has extra null byte padded */
267*5c1def83SBjoern A. Zeeb 	magic_len = strlen(ATH12K_BOARD_MAGIC) + 1;
268*5c1def83SBjoern A. Zeeb 	if (len < magic_len) {
269*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed to find magic value in %s, file too short: %zu\n",
270*5c1def83SBjoern A. Zeeb 			   filepath, len);
271*5c1def83SBjoern A. Zeeb 		ret = -EINVAL;
272*5c1def83SBjoern A. Zeeb 		goto err;
273*5c1def83SBjoern A. Zeeb 	}
274*5c1def83SBjoern A. Zeeb 
275*5c1def83SBjoern A. Zeeb 	if (memcmp(data, ATH12K_BOARD_MAGIC, magic_len)) {
276*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "found invalid board magic\n");
277*5c1def83SBjoern A. Zeeb 		ret = -EINVAL;
278*5c1def83SBjoern A. Zeeb 		goto err;
279*5c1def83SBjoern A. Zeeb 	}
280*5c1def83SBjoern A. Zeeb 
281*5c1def83SBjoern A. Zeeb 	/* magic is padded to 4 bytes */
282*5c1def83SBjoern A. Zeeb 	magic_len = ALIGN(magic_len, 4);
283*5c1def83SBjoern A. Zeeb 	if (len < magic_len) {
284*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed: %s too small to contain board data, len: %zu\n",
285*5c1def83SBjoern A. Zeeb 			   filepath, len);
286*5c1def83SBjoern A. Zeeb 		ret = -EINVAL;
287*5c1def83SBjoern A. Zeeb 		goto err;
288*5c1def83SBjoern A. Zeeb 	}
289*5c1def83SBjoern A. Zeeb 
290*5c1def83SBjoern A. Zeeb 	data += magic_len;
291*5c1def83SBjoern A. Zeeb 	len -= magic_len;
292*5c1def83SBjoern A. Zeeb 
293*5c1def83SBjoern A. Zeeb 	while (len > sizeof(struct ath12k_fw_ie)) {
294*5c1def83SBjoern A. Zeeb #if defined(__linux__)
295*5c1def83SBjoern A. Zeeb 		hdr = (struct ath12k_fw_ie *)data;
296*5c1def83SBjoern A. Zeeb #elif defined(__FreeBSD__)
297*5c1def83SBjoern A. Zeeb 		hdr = (const struct ath12k_fw_ie *)data;
298*5c1def83SBjoern A. Zeeb #endif
299*5c1def83SBjoern A. Zeeb 		ie_id = le32_to_cpu(hdr->id);
300*5c1def83SBjoern A. Zeeb 		ie_len = le32_to_cpu(hdr->len);
301*5c1def83SBjoern A. Zeeb 
302*5c1def83SBjoern A. Zeeb 		len -= sizeof(*hdr);
303*5c1def83SBjoern A. Zeeb 		data = hdr->data;
304*5c1def83SBjoern A. Zeeb 
305*5c1def83SBjoern A. Zeeb 		if (len < ALIGN(ie_len, 4)) {
306*5c1def83SBjoern A. Zeeb 			ath12k_err(ab, "invalid length for board ie_id %d ie_len %zu len %zu\n",
307*5c1def83SBjoern A. Zeeb 				   ie_id, ie_len, len);
308*5c1def83SBjoern A. Zeeb 			ret = -EINVAL;
309*5c1def83SBjoern A. Zeeb 			goto err;
310*5c1def83SBjoern A. Zeeb 		}
311*5c1def83SBjoern A. Zeeb 
312*5c1def83SBjoern A. Zeeb 		switch (ie_id) {
313*5c1def83SBjoern A. Zeeb 		case ATH12K_BD_IE_BOARD:
314*5c1def83SBjoern A. Zeeb 			ret = ath12k_core_parse_bd_ie_board(ab, bd, data,
315*5c1def83SBjoern A. Zeeb 							    ie_len,
316*5c1def83SBjoern A. Zeeb 							    boardname,
317*5c1def83SBjoern A. Zeeb 							    ATH12K_BD_IE_BOARD);
318*5c1def83SBjoern A. Zeeb 			if (ret == -ENOENT)
319*5c1def83SBjoern A. Zeeb 				/* no match found, continue */
320*5c1def83SBjoern A. Zeeb 				break;
321*5c1def83SBjoern A. Zeeb 			else if (ret)
322*5c1def83SBjoern A. Zeeb 				/* there was an error, bail out */
323*5c1def83SBjoern A. Zeeb 				goto err;
324*5c1def83SBjoern A. Zeeb 			/* either found or error, so stop searching */
325*5c1def83SBjoern A. Zeeb 			goto out;
326*5c1def83SBjoern A. Zeeb 		}
327*5c1def83SBjoern A. Zeeb 
328*5c1def83SBjoern A. Zeeb 		/* jump over the padding */
329*5c1def83SBjoern A. Zeeb 		ie_len = ALIGN(ie_len, 4);
330*5c1def83SBjoern A. Zeeb 
331*5c1def83SBjoern A. Zeeb 		len -= ie_len;
332*5c1def83SBjoern A. Zeeb 		data += ie_len;
333*5c1def83SBjoern A. Zeeb 	}
334*5c1def83SBjoern A. Zeeb 
335*5c1def83SBjoern A. Zeeb out:
336*5c1def83SBjoern A. Zeeb 	if (!bd->data || !bd->len) {
337*5c1def83SBjoern A. Zeeb 		ath12k_err(ab,
338*5c1def83SBjoern A. Zeeb 			   "failed to fetch board data for %s from %s\n",
339*5c1def83SBjoern A. Zeeb 			   boardname, filepath);
340*5c1def83SBjoern A. Zeeb 		ret = -ENODATA;
341*5c1def83SBjoern A. Zeeb 		goto err;
342*5c1def83SBjoern A. Zeeb 	}
343*5c1def83SBjoern A. Zeeb 
344*5c1def83SBjoern A. Zeeb 	return 0;
345*5c1def83SBjoern A. Zeeb 
346*5c1def83SBjoern A. Zeeb err:
347*5c1def83SBjoern A. Zeeb 	ath12k_core_free_bdf(ab, bd);
348*5c1def83SBjoern A. Zeeb 	return ret;
349*5c1def83SBjoern A. Zeeb }
350*5c1def83SBjoern A. Zeeb 
ath12k_core_fetch_board_data_api_1(struct ath12k_base * ab,struct ath12k_board_data * bd,char * filename)351*5c1def83SBjoern A. Zeeb int ath12k_core_fetch_board_data_api_1(struct ath12k_base *ab,
352*5c1def83SBjoern A. Zeeb 				       struct ath12k_board_data *bd,
353*5c1def83SBjoern A. Zeeb 				       char *filename)
354*5c1def83SBjoern A. Zeeb {
355*5c1def83SBjoern A. Zeeb 	bd->fw = ath12k_core_firmware_request(ab, filename);
356*5c1def83SBjoern A. Zeeb 	if (IS_ERR(bd->fw))
357*5c1def83SBjoern A. Zeeb 		return PTR_ERR(bd->fw);
358*5c1def83SBjoern A. Zeeb 
359*5c1def83SBjoern A. Zeeb 	bd->data = bd->fw->data;
360*5c1def83SBjoern A. Zeeb 	bd->len = bd->fw->size;
361*5c1def83SBjoern A. Zeeb 
362*5c1def83SBjoern A. Zeeb 	return 0;
363*5c1def83SBjoern A. Zeeb }
364*5c1def83SBjoern A. Zeeb 
365*5c1def83SBjoern A. Zeeb #define BOARD_NAME_SIZE 100
ath12k_core_fetch_bdf(struct ath12k_base * ab,struct ath12k_board_data * bd)366*5c1def83SBjoern A. Zeeb int ath12k_core_fetch_bdf(struct ath12k_base *ab, struct ath12k_board_data *bd)
367*5c1def83SBjoern A. Zeeb {
368*5c1def83SBjoern A. Zeeb 	char boardname[BOARD_NAME_SIZE];
369*5c1def83SBjoern A. Zeeb 	int ret;
370*5c1def83SBjoern A. Zeeb 
371*5c1def83SBjoern A. Zeeb 	ret = ath12k_core_create_board_name(ab, boardname, BOARD_NAME_SIZE);
372*5c1def83SBjoern A. Zeeb 	if (ret) {
373*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed to create board name: %d", ret);
374*5c1def83SBjoern A. Zeeb 		return ret;
375*5c1def83SBjoern A. Zeeb 	}
376*5c1def83SBjoern A. Zeeb 
377*5c1def83SBjoern A. Zeeb 	ab->bd_api = 2;
378*5c1def83SBjoern A. Zeeb 	ret = ath12k_core_fetch_board_data_api_n(ab, bd, boardname);
379*5c1def83SBjoern A. Zeeb 	if (!ret)
380*5c1def83SBjoern A. Zeeb 		goto success;
381*5c1def83SBjoern A. Zeeb 
382*5c1def83SBjoern A. Zeeb 	ab->bd_api = 1;
383*5c1def83SBjoern A. Zeeb 	ret = ath12k_core_fetch_board_data_api_1(ab, bd, ATH12K_DEFAULT_BOARD_FILE);
384*5c1def83SBjoern A. Zeeb 	if (ret) {
385*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed to fetch board-2.bin or board.bin from %s\n",
386*5c1def83SBjoern A. Zeeb 			   ab->hw_params->fw.dir);
387*5c1def83SBjoern A. Zeeb 		return ret;
388*5c1def83SBjoern A. Zeeb 	}
389*5c1def83SBjoern A. Zeeb 
390*5c1def83SBjoern A. Zeeb success:
391*5c1def83SBjoern A. Zeeb 	ath12k_dbg(ab, ATH12K_DBG_BOOT, "using board api %d\n", ab->bd_api);
392*5c1def83SBjoern A. Zeeb 	return 0;
393*5c1def83SBjoern A. Zeeb }
394*5c1def83SBjoern A. Zeeb 
ath12k_core_stop(struct ath12k_base * ab)395*5c1def83SBjoern A. Zeeb static void ath12k_core_stop(struct ath12k_base *ab)
396*5c1def83SBjoern A. Zeeb {
397*5c1def83SBjoern A. Zeeb 	if (!test_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags))
398*5c1def83SBjoern A. Zeeb 		ath12k_qmi_firmware_stop(ab);
399*5c1def83SBjoern A. Zeeb 
400*5c1def83SBjoern A. Zeeb 	ath12k_hif_stop(ab);
401*5c1def83SBjoern A. Zeeb 	ath12k_wmi_detach(ab);
402*5c1def83SBjoern A. Zeeb 	ath12k_dp_rx_pdev_reo_cleanup(ab);
403*5c1def83SBjoern A. Zeeb 
404*5c1def83SBjoern A. Zeeb 	/* De-Init of components as needed */
405*5c1def83SBjoern A. Zeeb }
406*5c1def83SBjoern A. Zeeb 
ath12k_core_soc_create(struct ath12k_base * ab)407*5c1def83SBjoern A. Zeeb static int ath12k_core_soc_create(struct ath12k_base *ab)
408*5c1def83SBjoern A. Zeeb {
409*5c1def83SBjoern A. Zeeb 	int ret;
410*5c1def83SBjoern A. Zeeb 
411*5c1def83SBjoern A. Zeeb 	ret = ath12k_qmi_init_service(ab);
412*5c1def83SBjoern A. Zeeb 	if (ret) {
413*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed to initialize qmi :%d\n", ret);
414*5c1def83SBjoern A. Zeeb 		return ret;
415*5c1def83SBjoern A. Zeeb 	}
416*5c1def83SBjoern A. Zeeb 
417*5c1def83SBjoern A. Zeeb 	ret = ath12k_hif_power_up(ab);
418*5c1def83SBjoern A. Zeeb 	if (ret) {
419*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed to power up :%d\n", ret);
420*5c1def83SBjoern A. Zeeb 		goto err_qmi_deinit;
421*5c1def83SBjoern A. Zeeb 	}
422*5c1def83SBjoern A. Zeeb 
423*5c1def83SBjoern A. Zeeb 	return 0;
424*5c1def83SBjoern A. Zeeb 
425*5c1def83SBjoern A. Zeeb err_qmi_deinit:
426*5c1def83SBjoern A. Zeeb 	ath12k_qmi_deinit_service(ab);
427*5c1def83SBjoern A. Zeeb 	return ret;
428*5c1def83SBjoern A. Zeeb }
429*5c1def83SBjoern A. Zeeb 
ath12k_core_soc_destroy(struct ath12k_base * ab)430*5c1def83SBjoern A. Zeeb static void ath12k_core_soc_destroy(struct ath12k_base *ab)
431*5c1def83SBjoern A. Zeeb {
432*5c1def83SBjoern A. Zeeb 	ath12k_dp_free(ab);
433*5c1def83SBjoern A. Zeeb 	ath12k_reg_free(ab);
434*5c1def83SBjoern A. Zeeb 	ath12k_qmi_deinit_service(ab);
435*5c1def83SBjoern A. Zeeb }
436*5c1def83SBjoern A. Zeeb 
ath12k_core_pdev_create(struct ath12k_base * ab)437*5c1def83SBjoern A. Zeeb static int ath12k_core_pdev_create(struct ath12k_base *ab)
438*5c1def83SBjoern A. Zeeb {
439*5c1def83SBjoern A. Zeeb 	int ret;
440*5c1def83SBjoern A. Zeeb 
441*5c1def83SBjoern A. Zeeb 	ret = ath12k_mac_register(ab);
442*5c1def83SBjoern A. Zeeb 	if (ret) {
443*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed register the radio with mac80211: %d\n", ret);
444*5c1def83SBjoern A. Zeeb 		return ret;
445*5c1def83SBjoern A. Zeeb 	}
446*5c1def83SBjoern A. Zeeb 
447*5c1def83SBjoern A. Zeeb 	ret = ath12k_dp_pdev_alloc(ab);
448*5c1def83SBjoern A. Zeeb 	if (ret) {
449*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed to attach DP pdev: %d\n", ret);
450*5c1def83SBjoern A. Zeeb 		goto err_mac_unregister;
451*5c1def83SBjoern A. Zeeb 	}
452*5c1def83SBjoern A. Zeeb 
453*5c1def83SBjoern A. Zeeb 	return 0;
454*5c1def83SBjoern A. Zeeb 
455*5c1def83SBjoern A. Zeeb err_mac_unregister:
456*5c1def83SBjoern A. Zeeb 	ath12k_mac_unregister(ab);
457*5c1def83SBjoern A. Zeeb 
458*5c1def83SBjoern A. Zeeb 	return ret;
459*5c1def83SBjoern A. Zeeb }
460*5c1def83SBjoern A. Zeeb 
ath12k_core_pdev_destroy(struct ath12k_base * ab)461*5c1def83SBjoern A. Zeeb static void ath12k_core_pdev_destroy(struct ath12k_base *ab)
462*5c1def83SBjoern A. Zeeb {
463*5c1def83SBjoern A. Zeeb 	ath12k_mac_unregister(ab);
464*5c1def83SBjoern A. Zeeb 	ath12k_hif_irq_disable(ab);
465*5c1def83SBjoern A. Zeeb 	ath12k_dp_pdev_free(ab);
466*5c1def83SBjoern A. Zeeb }
467*5c1def83SBjoern A. Zeeb 
ath12k_core_start(struct ath12k_base * ab,enum ath12k_firmware_mode mode)468*5c1def83SBjoern A. Zeeb static int ath12k_core_start(struct ath12k_base *ab,
469*5c1def83SBjoern A. Zeeb 			     enum ath12k_firmware_mode mode)
470*5c1def83SBjoern A. Zeeb {
471*5c1def83SBjoern A. Zeeb 	int ret;
472*5c1def83SBjoern A. Zeeb 
473*5c1def83SBjoern A. Zeeb 	ret = ath12k_wmi_attach(ab);
474*5c1def83SBjoern A. Zeeb 	if (ret) {
475*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed to attach wmi: %d\n", ret);
476*5c1def83SBjoern A. Zeeb 		return ret;
477*5c1def83SBjoern A. Zeeb 	}
478*5c1def83SBjoern A. Zeeb 
479*5c1def83SBjoern A. Zeeb 	ret = ath12k_htc_init(ab);
480*5c1def83SBjoern A. Zeeb 	if (ret) {
481*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed to init htc: %d\n", ret);
482*5c1def83SBjoern A. Zeeb 		goto err_wmi_detach;
483*5c1def83SBjoern A. Zeeb 	}
484*5c1def83SBjoern A. Zeeb 
485*5c1def83SBjoern A. Zeeb 	ret = ath12k_hif_start(ab);
486*5c1def83SBjoern A. Zeeb 	if (ret) {
487*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed to start HIF: %d\n", ret);
488*5c1def83SBjoern A. Zeeb 		goto err_wmi_detach;
489*5c1def83SBjoern A. Zeeb 	}
490*5c1def83SBjoern A. Zeeb 
491*5c1def83SBjoern A. Zeeb 	ret = ath12k_htc_wait_target(&ab->htc);
492*5c1def83SBjoern A. Zeeb 	if (ret) {
493*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed to connect to HTC: %d\n", ret);
494*5c1def83SBjoern A. Zeeb 		goto err_hif_stop;
495*5c1def83SBjoern A. Zeeb 	}
496*5c1def83SBjoern A. Zeeb 
497*5c1def83SBjoern A. Zeeb 	ret = ath12k_dp_htt_connect(&ab->dp);
498*5c1def83SBjoern A. Zeeb 	if (ret) {
499*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed to connect to HTT: %d\n", ret);
500*5c1def83SBjoern A. Zeeb 		goto err_hif_stop;
501*5c1def83SBjoern A. Zeeb 	}
502*5c1def83SBjoern A. Zeeb 
503*5c1def83SBjoern A. Zeeb 	ret = ath12k_wmi_connect(ab);
504*5c1def83SBjoern A. Zeeb 	if (ret) {
505*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed to connect wmi: %d\n", ret);
506*5c1def83SBjoern A. Zeeb 		goto err_hif_stop;
507*5c1def83SBjoern A. Zeeb 	}
508*5c1def83SBjoern A. Zeeb 
509*5c1def83SBjoern A. Zeeb 	ret = ath12k_htc_start(&ab->htc);
510*5c1def83SBjoern A. Zeeb 	if (ret) {
511*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed to start HTC: %d\n", ret);
512*5c1def83SBjoern A. Zeeb 		goto err_hif_stop;
513*5c1def83SBjoern A. Zeeb 	}
514*5c1def83SBjoern A. Zeeb 
515*5c1def83SBjoern A. Zeeb 	ret = ath12k_wmi_wait_for_service_ready(ab);
516*5c1def83SBjoern A. Zeeb 	if (ret) {
517*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed to receive wmi service ready event: %d\n",
518*5c1def83SBjoern A. Zeeb 			   ret);
519*5c1def83SBjoern A. Zeeb 		goto err_hif_stop;
520*5c1def83SBjoern A. Zeeb 	}
521*5c1def83SBjoern A. Zeeb 
522*5c1def83SBjoern A. Zeeb 	ret = ath12k_mac_allocate(ab);
523*5c1def83SBjoern A. Zeeb 	if (ret) {
524*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed to create new hw device with mac80211 :%d\n",
525*5c1def83SBjoern A. Zeeb 			   ret);
526*5c1def83SBjoern A. Zeeb 		goto err_hif_stop;
527*5c1def83SBjoern A. Zeeb 	}
528*5c1def83SBjoern A. Zeeb 
529*5c1def83SBjoern A. Zeeb 	ath12k_dp_cc_config(ab);
530*5c1def83SBjoern A. Zeeb 
531*5c1def83SBjoern A. Zeeb 	ath12k_dp_pdev_pre_alloc(ab);
532*5c1def83SBjoern A. Zeeb 
533*5c1def83SBjoern A. Zeeb 	ret = ath12k_dp_rx_pdev_reo_setup(ab);
534*5c1def83SBjoern A. Zeeb 	if (ret) {
535*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed to initialize reo destination rings: %d\n", ret);
536*5c1def83SBjoern A. Zeeb 		goto err_mac_destroy;
537*5c1def83SBjoern A. Zeeb 	}
538*5c1def83SBjoern A. Zeeb 
539*5c1def83SBjoern A. Zeeb 	ret = ath12k_wmi_cmd_init(ab);
540*5c1def83SBjoern A. Zeeb 	if (ret) {
541*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed to send wmi init cmd: %d\n", ret);
542*5c1def83SBjoern A. Zeeb 		goto err_reo_cleanup;
543*5c1def83SBjoern A. Zeeb 	}
544*5c1def83SBjoern A. Zeeb 
545*5c1def83SBjoern A. Zeeb 	ret = ath12k_wmi_wait_for_unified_ready(ab);
546*5c1def83SBjoern A. Zeeb 	if (ret) {
547*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed to receive wmi unified ready event: %d\n",
548*5c1def83SBjoern A. Zeeb 			   ret);
549*5c1def83SBjoern A. Zeeb 		goto err_reo_cleanup;
550*5c1def83SBjoern A. Zeeb 	}
551*5c1def83SBjoern A. Zeeb 
552*5c1def83SBjoern A. Zeeb 	/* put hardware to DBS mode */
553*5c1def83SBjoern A. Zeeb 	if (ab->hw_params->single_pdev_only) {
554*5c1def83SBjoern A. Zeeb 		ret = ath12k_wmi_set_hw_mode(ab, WMI_HOST_HW_MODE_DBS);
555*5c1def83SBjoern A. Zeeb 		if (ret) {
556*5c1def83SBjoern A. Zeeb 			ath12k_err(ab, "failed to send dbs mode: %d\n", ret);
557*5c1def83SBjoern A. Zeeb 			goto err_reo_cleanup;
558*5c1def83SBjoern A. Zeeb 		}
559*5c1def83SBjoern A. Zeeb 	}
560*5c1def83SBjoern A. Zeeb 
561*5c1def83SBjoern A. Zeeb 	ret = ath12k_dp_tx_htt_h2t_ver_req_msg(ab);
562*5c1def83SBjoern A. Zeeb 	if (ret) {
563*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed to send htt version request message: %d\n",
564*5c1def83SBjoern A. Zeeb 			   ret);
565*5c1def83SBjoern A. Zeeb 		goto err_reo_cleanup;
566*5c1def83SBjoern A. Zeeb 	}
567*5c1def83SBjoern A. Zeeb 
568*5c1def83SBjoern A. Zeeb 	return 0;
569*5c1def83SBjoern A. Zeeb 
570*5c1def83SBjoern A. Zeeb err_reo_cleanup:
571*5c1def83SBjoern A. Zeeb 	ath12k_dp_rx_pdev_reo_cleanup(ab);
572*5c1def83SBjoern A. Zeeb err_mac_destroy:
573*5c1def83SBjoern A. Zeeb 	ath12k_mac_destroy(ab);
574*5c1def83SBjoern A. Zeeb err_hif_stop:
575*5c1def83SBjoern A. Zeeb 	ath12k_hif_stop(ab);
576*5c1def83SBjoern A. Zeeb err_wmi_detach:
577*5c1def83SBjoern A. Zeeb 	ath12k_wmi_detach(ab);
578*5c1def83SBjoern A. Zeeb 	return ret;
579*5c1def83SBjoern A. Zeeb }
580*5c1def83SBjoern A. Zeeb 
ath12k_core_start_firmware(struct ath12k_base * ab,enum ath12k_firmware_mode mode)581*5c1def83SBjoern A. Zeeb static int ath12k_core_start_firmware(struct ath12k_base *ab,
582*5c1def83SBjoern A. Zeeb 				      enum ath12k_firmware_mode mode)
583*5c1def83SBjoern A. Zeeb {
584*5c1def83SBjoern A. Zeeb 	int ret;
585*5c1def83SBjoern A. Zeeb 
586*5c1def83SBjoern A. Zeeb 	ath12k_ce_get_shadow_config(ab, &ab->qmi.ce_cfg.shadow_reg_v3,
587*5c1def83SBjoern A. Zeeb 				    &ab->qmi.ce_cfg.shadow_reg_v3_len);
588*5c1def83SBjoern A. Zeeb 
589*5c1def83SBjoern A. Zeeb 	ret = ath12k_qmi_firmware_start(ab, mode);
590*5c1def83SBjoern A. Zeeb 	if (ret) {
591*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed to send firmware start: %d\n", ret);
592*5c1def83SBjoern A. Zeeb 		return ret;
593*5c1def83SBjoern A. Zeeb 	}
594*5c1def83SBjoern A. Zeeb 
595*5c1def83SBjoern A. Zeeb 	return ret;
596*5c1def83SBjoern A. Zeeb }
597*5c1def83SBjoern A. Zeeb 
ath12k_core_qmi_firmware_ready(struct ath12k_base * ab)598*5c1def83SBjoern A. Zeeb int ath12k_core_qmi_firmware_ready(struct ath12k_base *ab)
599*5c1def83SBjoern A. Zeeb {
600*5c1def83SBjoern A. Zeeb 	int ret;
601*5c1def83SBjoern A. Zeeb 
602*5c1def83SBjoern A. Zeeb 	ret = ath12k_core_start_firmware(ab, ATH12K_FIRMWARE_MODE_NORMAL);
603*5c1def83SBjoern A. Zeeb 	if (ret) {
604*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed to start firmware: %d\n", ret);
605*5c1def83SBjoern A. Zeeb 		return ret;
606*5c1def83SBjoern A. Zeeb 	}
607*5c1def83SBjoern A. Zeeb 
608*5c1def83SBjoern A. Zeeb 	ret = ath12k_ce_init_pipes(ab);
609*5c1def83SBjoern A. Zeeb 	if (ret) {
610*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed to initialize CE: %d\n", ret);
611*5c1def83SBjoern A. Zeeb 		goto err_firmware_stop;
612*5c1def83SBjoern A. Zeeb 	}
613*5c1def83SBjoern A. Zeeb 
614*5c1def83SBjoern A. Zeeb 	ret = ath12k_dp_alloc(ab);
615*5c1def83SBjoern A. Zeeb 	if (ret) {
616*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed to init DP: %d\n", ret);
617*5c1def83SBjoern A. Zeeb 		goto err_firmware_stop;
618*5c1def83SBjoern A. Zeeb 	}
619*5c1def83SBjoern A. Zeeb 
620*5c1def83SBjoern A. Zeeb 	mutex_lock(&ab->core_lock);
621*5c1def83SBjoern A. Zeeb 	ret = ath12k_core_start(ab, ATH12K_FIRMWARE_MODE_NORMAL);
622*5c1def83SBjoern A. Zeeb 	if (ret) {
623*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed to start core: %d\n", ret);
624*5c1def83SBjoern A. Zeeb 		goto err_dp_free;
625*5c1def83SBjoern A. Zeeb 	}
626*5c1def83SBjoern A. Zeeb 
627*5c1def83SBjoern A. Zeeb 	ret = ath12k_core_pdev_create(ab);
628*5c1def83SBjoern A. Zeeb 	if (ret) {
629*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed to create pdev core: %d\n", ret);
630*5c1def83SBjoern A. Zeeb 		goto err_core_stop;
631*5c1def83SBjoern A. Zeeb 	}
632*5c1def83SBjoern A. Zeeb 	ath12k_hif_irq_enable(ab);
633*5c1def83SBjoern A. Zeeb 	mutex_unlock(&ab->core_lock);
634*5c1def83SBjoern A. Zeeb 
635*5c1def83SBjoern A. Zeeb 	return 0;
636*5c1def83SBjoern A. Zeeb 
637*5c1def83SBjoern A. Zeeb err_core_stop:
638*5c1def83SBjoern A. Zeeb 	ath12k_core_stop(ab);
639*5c1def83SBjoern A. Zeeb 	ath12k_mac_destroy(ab);
640*5c1def83SBjoern A. Zeeb err_dp_free:
641*5c1def83SBjoern A. Zeeb 	ath12k_dp_free(ab);
642*5c1def83SBjoern A. Zeeb 	mutex_unlock(&ab->core_lock);
643*5c1def83SBjoern A. Zeeb err_firmware_stop:
644*5c1def83SBjoern A. Zeeb 	ath12k_qmi_firmware_stop(ab);
645*5c1def83SBjoern A. Zeeb 
646*5c1def83SBjoern A. Zeeb 	return ret;
647*5c1def83SBjoern A. Zeeb }
648*5c1def83SBjoern A. Zeeb 
ath12k_core_reconfigure_on_crash(struct ath12k_base * ab)649*5c1def83SBjoern A. Zeeb static int ath12k_core_reconfigure_on_crash(struct ath12k_base *ab)
650*5c1def83SBjoern A. Zeeb {
651*5c1def83SBjoern A. Zeeb 	int ret;
652*5c1def83SBjoern A. Zeeb 
653*5c1def83SBjoern A. Zeeb 	mutex_lock(&ab->core_lock);
654*5c1def83SBjoern A. Zeeb 	ath12k_hif_irq_disable(ab);
655*5c1def83SBjoern A. Zeeb 	ath12k_dp_pdev_free(ab);
656*5c1def83SBjoern A. Zeeb 	ath12k_hif_stop(ab);
657*5c1def83SBjoern A. Zeeb 	ath12k_wmi_detach(ab);
658*5c1def83SBjoern A. Zeeb 	ath12k_dp_rx_pdev_reo_cleanup(ab);
659*5c1def83SBjoern A. Zeeb 	mutex_unlock(&ab->core_lock);
660*5c1def83SBjoern A. Zeeb 
661*5c1def83SBjoern A. Zeeb 	ath12k_dp_free(ab);
662*5c1def83SBjoern A. Zeeb 	ath12k_hal_srng_deinit(ab);
663*5c1def83SBjoern A. Zeeb 
664*5c1def83SBjoern A. Zeeb 	ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1;
665*5c1def83SBjoern A. Zeeb 
666*5c1def83SBjoern A. Zeeb 	ret = ath12k_hal_srng_init(ab);
667*5c1def83SBjoern A. Zeeb 	if (ret)
668*5c1def83SBjoern A. Zeeb 		return ret;
669*5c1def83SBjoern A. Zeeb 
670*5c1def83SBjoern A. Zeeb 	clear_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags);
671*5c1def83SBjoern A. Zeeb 
672*5c1def83SBjoern A. Zeeb 	ret = ath12k_core_qmi_firmware_ready(ab);
673*5c1def83SBjoern A. Zeeb 	if (ret)
674*5c1def83SBjoern A. Zeeb 		goto err_hal_srng_deinit;
675*5c1def83SBjoern A. Zeeb 
676*5c1def83SBjoern A. Zeeb 	clear_bit(ATH12K_FLAG_RECOVERY, &ab->dev_flags);
677*5c1def83SBjoern A. Zeeb 
678*5c1def83SBjoern A. Zeeb 	return 0;
679*5c1def83SBjoern A. Zeeb 
680*5c1def83SBjoern A. Zeeb err_hal_srng_deinit:
681*5c1def83SBjoern A. Zeeb 	ath12k_hal_srng_deinit(ab);
682*5c1def83SBjoern A. Zeeb 	return ret;
683*5c1def83SBjoern A. Zeeb }
684*5c1def83SBjoern A. Zeeb 
ath12k_core_halt(struct ath12k * ar)685*5c1def83SBjoern A. Zeeb void ath12k_core_halt(struct ath12k *ar)
686*5c1def83SBjoern A. Zeeb {
687*5c1def83SBjoern A. Zeeb 	struct ath12k_base *ab = ar->ab;
688*5c1def83SBjoern A. Zeeb 
689*5c1def83SBjoern A. Zeeb 	lockdep_assert_held(&ar->conf_mutex);
690*5c1def83SBjoern A. Zeeb 
691*5c1def83SBjoern A. Zeeb 	ar->num_created_vdevs = 0;
692*5c1def83SBjoern A. Zeeb 	ar->allocated_vdev_map = 0;
693*5c1def83SBjoern A. Zeeb 
694*5c1def83SBjoern A. Zeeb 	ath12k_mac_scan_finish(ar);
695*5c1def83SBjoern A. Zeeb 	ath12k_mac_peer_cleanup_all(ar);
696*5c1def83SBjoern A. Zeeb 	cancel_delayed_work_sync(&ar->scan.timeout);
697*5c1def83SBjoern A. Zeeb 	cancel_work_sync(&ar->regd_update_work);
698*5c1def83SBjoern A. Zeeb 
699*5c1def83SBjoern A. Zeeb 	rcu_assign_pointer(ab->pdevs_active[ar->pdev_idx], NULL);
700*5c1def83SBjoern A. Zeeb 	synchronize_rcu();
701*5c1def83SBjoern A. Zeeb 	INIT_LIST_HEAD(&ar->arvifs);
702*5c1def83SBjoern A. Zeeb 	idr_init(&ar->txmgmt_idr);
703*5c1def83SBjoern A. Zeeb }
704*5c1def83SBjoern A. Zeeb 
ath12k_core_pre_reconfigure_recovery(struct ath12k_base * ab)705*5c1def83SBjoern A. Zeeb static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab)
706*5c1def83SBjoern A. Zeeb {
707*5c1def83SBjoern A. Zeeb 	struct ath12k *ar;
708*5c1def83SBjoern A. Zeeb 	struct ath12k_pdev *pdev;
709*5c1def83SBjoern A. Zeeb 	int i;
710*5c1def83SBjoern A. Zeeb 
711*5c1def83SBjoern A. Zeeb 	spin_lock_bh(&ab->base_lock);
712*5c1def83SBjoern A. Zeeb 	ab->stats.fw_crash_counter++;
713*5c1def83SBjoern A. Zeeb 	spin_unlock_bh(&ab->base_lock);
714*5c1def83SBjoern A. Zeeb 
715*5c1def83SBjoern A. Zeeb 	for (i = 0; i < ab->num_radios; i++) {
716*5c1def83SBjoern A. Zeeb 		pdev = &ab->pdevs[i];
717*5c1def83SBjoern A. Zeeb 		ar = pdev->ar;
718*5c1def83SBjoern A. Zeeb 		if (!ar || ar->state == ATH12K_STATE_OFF)
719*5c1def83SBjoern A. Zeeb 			continue;
720*5c1def83SBjoern A. Zeeb 
721*5c1def83SBjoern A. Zeeb 		ieee80211_stop_queues(ar->hw);
722*5c1def83SBjoern A. Zeeb 		ath12k_mac_drain_tx(ar);
723*5c1def83SBjoern A. Zeeb 		complete(&ar->scan.started);
724*5c1def83SBjoern A. Zeeb 		complete(&ar->scan.completed);
725*5c1def83SBjoern A. Zeeb 		complete(&ar->peer_assoc_done);
726*5c1def83SBjoern A. Zeeb 		complete(&ar->peer_delete_done);
727*5c1def83SBjoern A. Zeeb 		complete(&ar->install_key_done);
728*5c1def83SBjoern A. Zeeb 		complete(&ar->vdev_setup_done);
729*5c1def83SBjoern A. Zeeb 		complete(&ar->vdev_delete_done);
730*5c1def83SBjoern A. Zeeb 		complete(&ar->bss_survey_done);
731*5c1def83SBjoern A. Zeeb 
732*5c1def83SBjoern A. Zeeb 		wake_up(&ar->dp.tx_empty_waitq);
733*5c1def83SBjoern A. Zeeb 		idr_for_each(&ar->txmgmt_idr,
734*5c1def83SBjoern A. Zeeb 			     ath12k_mac_tx_mgmt_pending_free, ar);
735*5c1def83SBjoern A. Zeeb 		idr_destroy(&ar->txmgmt_idr);
736*5c1def83SBjoern A. Zeeb 		wake_up(&ar->txmgmt_empty_waitq);
737*5c1def83SBjoern A. Zeeb 	}
738*5c1def83SBjoern A. Zeeb 
739*5c1def83SBjoern A. Zeeb 	wake_up(&ab->wmi_ab.tx_credits_wq);
740*5c1def83SBjoern A. Zeeb 	wake_up(&ab->peer_mapping_wq);
741*5c1def83SBjoern A. Zeeb }
742*5c1def83SBjoern A. Zeeb 
ath12k_core_post_reconfigure_recovery(struct ath12k_base * ab)743*5c1def83SBjoern A. Zeeb static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab)
744*5c1def83SBjoern A. Zeeb {
745*5c1def83SBjoern A. Zeeb 	struct ath12k *ar;
746*5c1def83SBjoern A. Zeeb 	struct ath12k_pdev *pdev;
747*5c1def83SBjoern A. Zeeb 	int i;
748*5c1def83SBjoern A. Zeeb 
749*5c1def83SBjoern A. Zeeb 	for (i = 0; i < ab->num_radios; i++) {
750*5c1def83SBjoern A. Zeeb 		pdev = &ab->pdevs[i];
751*5c1def83SBjoern A. Zeeb 		ar = pdev->ar;
752*5c1def83SBjoern A. Zeeb 		if (!ar || ar->state == ATH12K_STATE_OFF)
753*5c1def83SBjoern A. Zeeb 			continue;
754*5c1def83SBjoern A. Zeeb 
755*5c1def83SBjoern A. Zeeb 		mutex_lock(&ar->conf_mutex);
756*5c1def83SBjoern A. Zeeb 
757*5c1def83SBjoern A. Zeeb 		switch (ar->state) {
758*5c1def83SBjoern A. Zeeb 		case ATH12K_STATE_ON:
759*5c1def83SBjoern A. Zeeb 			ar->state = ATH12K_STATE_RESTARTING;
760*5c1def83SBjoern A. Zeeb 			ath12k_core_halt(ar);
761*5c1def83SBjoern A. Zeeb 			ieee80211_restart_hw(ar->hw);
762*5c1def83SBjoern A. Zeeb 			break;
763*5c1def83SBjoern A. Zeeb 		case ATH12K_STATE_OFF:
764*5c1def83SBjoern A. Zeeb 			ath12k_warn(ab,
765*5c1def83SBjoern A. Zeeb 				    "cannot restart radio %d that hasn't been started\n",
766*5c1def83SBjoern A. Zeeb 				    i);
767*5c1def83SBjoern A. Zeeb 			break;
768*5c1def83SBjoern A. Zeeb 		case ATH12K_STATE_RESTARTING:
769*5c1def83SBjoern A. Zeeb 			break;
770*5c1def83SBjoern A. Zeeb 		case ATH12K_STATE_RESTARTED:
771*5c1def83SBjoern A. Zeeb 			ar->state = ATH12K_STATE_WEDGED;
772*5c1def83SBjoern A. Zeeb 			fallthrough;
773*5c1def83SBjoern A. Zeeb 		case ATH12K_STATE_WEDGED:
774*5c1def83SBjoern A. Zeeb 			ath12k_warn(ab,
775*5c1def83SBjoern A. Zeeb 				    "device is wedged, will not restart radio %d\n", i);
776*5c1def83SBjoern A. Zeeb 			break;
777*5c1def83SBjoern A. Zeeb 		}
778*5c1def83SBjoern A. Zeeb 		mutex_unlock(&ar->conf_mutex);
779*5c1def83SBjoern A. Zeeb 	}
780*5c1def83SBjoern A. Zeeb 	complete(&ab->driver_recovery);
781*5c1def83SBjoern A. Zeeb }
782*5c1def83SBjoern A. Zeeb 
ath12k_core_restart(struct work_struct * work)783*5c1def83SBjoern A. Zeeb static void ath12k_core_restart(struct work_struct *work)
784*5c1def83SBjoern A. Zeeb {
785*5c1def83SBjoern A. Zeeb 	struct ath12k_base *ab = container_of(work, struct ath12k_base, restart_work);
786*5c1def83SBjoern A. Zeeb 	int ret;
787*5c1def83SBjoern A. Zeeb 
788*5c1def83SBjoern A. Zeeb 	if (!ab->is_reset)
789*5c1def83SBjoern A. Zeeb 		ath12k_core_pre_reconfigure_recovery(ab);
790*5c1def83SBjoern A. Zeeb 
791*5c1def83SBjoern A. Zeeb 	ret = ath12k_core_reconfigure_on_crash(ab);
792*5c1def83SBjoern A. Zeeb 	if (ret) {
793*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed to reconfigure driver on crash recovery\n");
794*5c1def83SBjoern A. Zeeb 		return;
795*5c1def83SBjoern A. Zeeb 	}
796*5c1def83SBjoern A. Zeeb 
797*5c1def83SBjoern A. Zeeb 	if (ab->is_reset)
798*5c1def83SBjoern A. Zeeb 		complete_all(&ab->reconfigure_complete);
799*5c1def83SBjoern A. Zeeb 
800*5c1def83SBjoern A. Zeeb 	if (!ab->is_reset)
801*5c1def83SBjoern A. Zeeb 		ath12k_core_post_reconfigure_recovery(ab);
802*5c1def83SBjoern A. Zeeb }
803*5c1def83SBjoern A. Zeeb 
ath12k_core_reset(struct work_struct * work)804*5c1def83SBjoern A. Zeeb static void ath12k_core_reset(struct work_struct *work)
805*5c1def83SBjoern A. Zeeb {
806*5c1def83SBjoern A. Zeeb 	struct ath12k_base *ab = container_of(work, struct ath12k_base, reset_work);
807*5c1def83SBjoern A. Zeeb 	int reset_count, fail_cont_count;
808*5c1def83SBjoern A. Zeeb 	long time_left;
809*5c1def83SBjoern A. Zeeb 
810*5c1def83SBjoern A. Zeeb 	if (!(test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags))) {
811*5c1def83SBjoern A. Zeeb 		ath12k_warn(ab, "ignore reset dev flags 0x%lx\n", ab->dev_flags);
812*5c1def83SBjoern A. Zeeb 		return;
813*5c1def83SBjoern A. Zeeb 	}
814*5c1def83SBjoern A. Zeeb 
815*5c1def83SBjoern A. Zeeb 	/* Sometimes the recovery will fail and then the next all recovery fail,
816*5c1def83SBjoern A. Zeeb 	 * this is to avoid infinite recovery since it can not recovery success
817*5c1def83SBjoern A. Zeeb 	 */
818*5c1def83SBjoern A. Zeeb 	fail_cont_count = atomic_read(&ab->fail_cont_count);
819*5c1def83SBjoern A. Zeeb 
820*5c1def83SBjoern A. Zeeb 	if (fail_cont_count >= ATH12K_RESET_MAX_FAIL_COUNT_FINAL)
821*5c1def83SBjoern A. Zeeb 		return;
822*5c1def83SBjoern A. Zeeb 
823*5c1def83SBjoern A. Zeeb 	if (fail_cont_count >= ATH12K_RESET_MAX_FAIL_COUNT_FIRST &&
824*5c1def83SBjoern A. Zeeb 	    time_before(jiffies, ab->reset_fail_timeout))
825*5c1def83SBjoern A. Zeeb 		return;
826*5c1def83SBjoern A. Zeeb 
827*5c1def83SBjoern A. Zeeb 	reset_count = atomic_inc_return(&ab->reset_count);
828*5c1def83SBjoern A. Zeeb 
829*5c1def83SBjoern A. Zeeb 	if (reset_count > 1) {
830*5c1def83SBjoern A. Zeeb 		/* Sometimes it happened another reset worker before the previous one
831*5c1def83SBjoern A. Zeeb 		 * completed, then the second reset worker will destroy the previous one,
832*5c1def83SBjoern A. Zeeb 		 * thus below is to avoid that.
833*5c1def83SBjoern A. Zeeb 		 */
834*5c1def83SBjoern A. Zeeb 		ath12k_warn(ab, "already resetting count %d\n", reset_count);
835*5c1def83SBjoern A. Zeeb 
836*5c1def83SBjoern A. Zeeb 		reinit_completion(&ab->reset_complete);
837*5c1def83SBjoern A. Zeeb 		time_left = wait_for_completion_timeout(&ab->reset_complete,
838*5c1def83SBjoern A. Zeeb 							ATH12K_RESET_TIMEOUT_HZ);
839*5c1def83SBjoern A. Zeeb 		if (time_left) {
840*5c1def83SBjoern A. Zeeb 			ath12k_dbg(ab, ATH12K_DBG_BOOT, "to skip reset\n");
841*5c1def83SBjoern A. Zeeb 			atomic_dec(&ab->reset_count);
842*5c1def83SBjoern A. Zeeb 			return;
843*5c1def83SBjoern A. Zeeb 		}
844*5c1def83SBjoern A. Zeeb 
845*5c1def83SBjoern A. Zeeb 		ab->reset_fail_timeout = jiffies + ATH12K_RESET_FAIL_TIMEOUT_HZ;
846*5c1def83SBjoern A. Zeeb 		/* Record the continuous recovery fail count when recovery failed*/
847*5c1def83SBjoern A. Zeeb 		fail_cont_count = atomic_inc_return(&ab->fail_cont_count);
848*5c1def83SBjoern A. Zeeb 	}
849*5c1def83SBjoern A. Zeeb 
850*5c1def83SBjoern A. Zeeb 	ath12k_dbg(ab, ATH12K_DBG_BOOT, "reset starting\n");
851*5c1def83SBjoern A. Zeeb 
852*5c1def83SBjoern A. Zeeb 	ab->is_reset = true;
853*5c1def83SBjoern A. Zeeb 	atomic_set(&ab->recovery_count, 0);
854*5c1def83SBjoern A. Zeeb 
855*5c1def83SBjoern A. Zeeb 	ath12k_core_pre_reconfigure_recovery(ab);
856*5c1def83SBjoern A. Zeeb 
857*5c1def83SBjoern A. Zeeb 	reinit_completion(&ab->reconfigure_complete);
858*5c1def83SBjoern A. Zeeb 	ath12k_core_post_reconfigure_recovery(ab);
859*5c1def83SBjoern A. Zeeb 
860*5c1def83SBjoern A. Zeeb 	reinit_completion(&ab->recovery_start);
861*5c1def83SBjoern A. Zeeb 	atomic_set(&ab->recovery_start_count, 0);
862*5c1def83SBjoern A. Zeeb 
863*5c1def83SBjoern A. Zeeb 	ath12k_dbg(ab, ATH12K_DBG_BOOT, "waiting recovery start...\n");
864*5c1def83SBjoern A. Zeeb 
865*5c1def83SBjoern A. Zeeb 	time_left = wait_for_completion_timeout(&ab->recovery_start,
866*5c1def83SBjoern A. Zeeb 						ATH12K_RECOVER_START_TIMEOUT_HZ);
867*5c1def83SBjoern A. Zeeb 
868*5c1def83SBjoern A. Zeeb 	ath12k_hif_power_down(ab);
869*5c1def83SBjoern A. Zeeb 	ath12k_hif_power_up(ab);
870*5c1def83SBjoern A. Zeeb 
871*5c1def83SBjoern A. Zeeb 	ath12k_dbg(ab, ATH12K_DBG_BOOT, "reset started\n");
872*5c1def83SBjoern A. Zeeb }
873*5c1def83SBjoern A. Zeeb 
ath12k_core_pre_init(struct ath12k_base * ab)874*5c1def83SBjoern A. Zeeb int ath12k_core_pre_init(struct ath12k_base *ab)
875*5c1def83SBjoern A. Zeeb {
876*5c1def83SBjoern A. Zeeb 	int ret;
877*5c1def83SBjoern A. Zeeb 
878*5c1def83SBjoern A. Zeeb 	ret = ath12k_hw_init(ab);
879*5c1def83SBjoern A. Zeeb 	if (ret) {
880*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed to init hw params: %d\n", ret);
881*5c1def83SBjoern A. Zeeb 		return ret;
882*5c1def83SBjoern A. Zeeb 	}
883*5c1def83SBjoern A. Zeeb 
884*5c1def83SBjoern A. Zeeb 	return 0;
885*5c1def83SBjoern A. Zeeb }
886*5c1def83SBjoern A. Zeeb 
ath12k_core_init(struct ath12k_base * ab)887*5c1def83SBjoern A. Zeeb int ath12k_core_init(struct ath12k_base *ab)
888*5c1def83SBjoern A. Zeeb {
889*5c1def83SBjoern A. Zeeb 	int ret;
890*5c1def83SBjoern A. Zeeb 
891*5c1def83SBjoern A. Zeeb 	ret = ath12k_core_soc_create(ab);
892*5c1def83SBjoern A. Zeeb 	if (ret) {
893*5c1def83SBjoern A. Zeeb 		ath12k_err(ab, "failed to create soc core: %d\n", ret);
894*5c1def83SBjoern A. Zeeb 		return ret;
895*5c1def83SBjoern A. Zeeb 	}
896*5c1def83SBjoern A. Zeeb 
897*5c1def83SBjoern A. Zeeb 	return 0;
898*5c1def83SBjoern A. Zeeb }
899*5c1def83SBjoern A. Zeeb 
ath12k_core_deinit(struct ath12k_base * ab)900*5c1def83SBjoern A. Zeeb void ath12k_core_deinit(struct ath12k_base *ab)
901*5c1def83SBjoern A. Zeeb {
902*5c1def83SBjoern A. Zeeb 	mutex_lock(&ab->core_lock);
903*5c1def83SBjoern A. Zeeb 
904*5c1def83SBjoern A. Zeeb 	ath12k_core_pdev_destroy(ab);
905*5c1def83SBjoern A. Zeeb 	ath12k_core_stop(ab);
906*5c1def83SBjoern A. Zeeb 
907*5c1def83SBjoern A. Zeeb 	mutex_unlock(&ab->core_lock);
908*5c1def83SBjoern A. Zeeb 
909*5c1def83SBjoern A. Zeeb 	ath12k_hif_power_down(ab);
910*5c1def83SBjoern A. Zeeb 	ath12k_mac_destroy(ab);
911*5c1def83SBjoern A. Zeeb 	ath12k_core_soc_destroy(ab);
912*5c1def83SBjoern A. Zeeb }
913*5c1def83SBjoern A. Zeeb 
ath12k_core_free(struct ath12k_base * ab)914*5c1def83SBjoern A. Zeeb void ath12k_core_free(struct ath12k_base *ab)
915*5c1def83SBjoern A. Zeeb {
916*5c1def83SBjoern A. Zeeb 	timer_delete_sync(&ab->rx_replenish_retry);
917*5c1def83SBjoern A. Zeeb 	destroy_workqueue(ab->workqueue_aux);
918*5c1def83SBjoern A. Zeeb 	destroy_workqueue(ab->workqueue);
919*5c1def83SBjoern A. Zeeb 	kfree(ab);
920*5c1def83SBjoern A. Zeeb }
921*5c1def83SBjoern A. Zeeb 
ath12k_core_alloc(struct device * dev,size_t priv_size,enum ath12k_bus bus)922*5c1def83SBjoern A. Zeeb struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size,
923*5c1def83SBjoern A. Zeeb 				      enum ath12k_bus bus)
924*5c1def83SBjoern A. Zeeb {
925*5c1def83SBjoern A. Zeeb 	struct ath12k_base *ab;
926*5c1def83SBjoern A. Zeeb 
927*5c1def83SBjoern A. Zeeb 	ab = kzalloc(sizeof(*ab) + priv_size, GFP_KERNEL);
928*5c1def83SBjoern A. Zeeb 	if (!ab)
929*5c1def83SBjoern A. Zeeb 		return NULL;
930*5c1def83SBjoern A. Zeeb 
931*5c1def83SBjoern A. Zeeb 	init_completion(&ab->driver_recovery);
932*5c1def83SBjoern A. Zeeb 
933*5c1def83SBjoern A. Zeeb 	ab->workqueue = create_singlethread_workqueue("ath12k_wq");
934*5c1def83SBjoern A. Zeeb 	if (!ab->workqueue)
935*5c1def83SBjoern A. Zeeb 		goto err_sc_free;
936*5c1def83SBjoern A. Zeeb 
937*5c1def83SBjoern A. Zeeb 	ab->workqueue_aux = create_singlethread_workqueue("ath12k_aux_wq");
938*5c1def83SBjoern A. Zeeb 	if (!ab->workqueue_aux)
939*5c1def83SBjoern A. Zeeb 		goto err_free_wq;
940*5c1def83SBjoern A. Zeeb 
941*5c1def83SBjoern A. Zeeb 	mutex_init(&ab->core_lock);
942*5c1def83SBjoern A. Zeeb 	spin_lock_init(&ab->base_lock);
943*5c1def83SBjoern A. Zeeb 	init_completion(&ab->reset_complete);
944*5c1def83SBjoern A. Zeeb 	init_completion(&ab->reconfigure_complete);
945*5c1def83SBjoern A. Zeeb 	init_completion(&ab->recovery_start);
946*5c1def83SBjoern A. Zeeb 
947*5c1def83SBjoern A. Zeeb 	INIT_LIST_HEAD(&ab->peers);
948*5c1def83SBjoern A. Zeeb 	init_waitqueue_head(&ab->peer_mapping_wq);
949*5c1def83SBjoern A. Zeeb 	init_waitqueue_head(&ab->wmi_ab.tx_credits_wq);
950*5c1def83SBjoern A. Zeeb 	INIT_WORK(&ab->restart_work, ath12k_core_restart);
951*5c1def83SBjoern A. Zeeb 	INIT_WORK(&ab->reset_work, ath12k_core_reset);
952*5c1def83SBjoern A. Zeeb 	timer_setup(&ab->rx_replenish_retry, ath12k_ce_rx_replenish_retry, 0);
953*5c1def83SBjoern A. Zeeb 	init_completion(&ab->htc_suspend);
954*5c1def83SBjoern A. Zeeb 
955*5c1def83SBjoern A. Zeeb 	ab->dev = dev;
956*5c1def83SBjoern A. Zeeb 	ab->hif.bus = bus;
957*5c1def83SBjoern A. Zeeb 
958*5c1def83SBjoern A. Zeeb 	return ab;
959*5c1def83SBjoern A. Zeeb 
960*5c1def83SBjoern A. Zeeb err_free_wq:
961*5c1def83SBjoern A. Zeeb 	destroy_workqueue(ab->workqueue);
962*5c1def83SBjoern A. Zeeb err_sc_free:
963*5c1def83SBjoern A. Zeeb 	kfree(ab);
964*5c1def83SBjoern A. Zeeb 	return NULL;
965*5c1def83SBjoern A. Zeeb }
966*5c1def83SBjoern A. Zeeb 
967*5c1def83SBjoern A. Zeeb MODULE_DESCRIPTION("Core module for Qualcomm Atheros 802.11be wireless LAN cards.");
968*5c1def83SBjoern A. Zeeb MODULE_LICENSE("Dual BSD/GPL");
969