xref: /openbmc/linux/drivers/net/wireless/ath/ath11k/ahb.c (revision 31858805)
1d5c65159SKalle Valo // SPDX-License-Identifier: BSD-3-Clause-Clear
2d5c65159SKalle Valo /*
3d5c65159SKalle Valo  * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
4d5c65159SKalle Valo  */
5d5c65159SKalle Valo 
6d5c65159SKalle Valo #include <linux/module.h>
7d5c65159SKalle Valo #include <linux/platform_device.h>
8d5c65159SKalle Valo #include <linux/of_device.h>
9d5c65159SKalle Valo #include <linux/of.h>
10d5c65159SKalle Valo #include <linux/dma-mapping.h>
11d5c65159SKalle Valo #include "ahb.h"
12d5c65159SKalle Valo #include "debug.h"
1331858805SGovind Singh #include "hif.h"
14d5c65159SKalle Valo #include <linux/remoteproc.h>
15d5c65159SKalle Valo 
16d5c65159SKalle Valo static const struct of_device_id ath11k_ahb_of_match[] = {
17d5c65159SKalle Valo 	/* TODO: Should we change the compatible string to something similar
18d5c65159SKalle Valo 	 * to one that ath10k uses?
19d5c65159SKalle Valo 	 */
20d5c65159SKalle Valo 	{ .compatible = "qcom,ipq8074-wifi",
21d5c65159SKalle Valo 	  .data = (void *)ATH11K_HW_IPQ8074,
22d5c65159SKalle Valo 	},
23d5c65159SKalle Valo 	{ }
24d5c65159SKalle Valo };
25d5c65159SKalle Valo 
26d5c65159SKalle Valo MODULE_DEVICE_TABLE(of, ath11k_ahb_of_match);
27d5c65159SKalle Valo 
28d5c65159SKalle Valo /* Target firmware's Copy Engine configuration. */
29d5c65159SKalle Valo static const struct ce_pipe_config target_ce_config_wlan[] = {
30d5c65159SKalle Valo 	/* CE0: host->target HTC control and raw streams */
31d5c65159SKalle Valo 	{
32d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(0),
33d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_OUT),
34d5c65159SKalle Valo 		.nentries = __cpu_to_le32(32),
35d5c65159SKalle Valo 		.nbytes_max = __cpu_to_le32(2048),
36d5c65159SKalle Valo 		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
37d5c65159SKalle Valo 		.reserved = __cpu_to_le32(0),
38d5c65159SKalle Valo 	},
39d5c65159SKalle Valo 
40d5c65159SKalle Valo 	/* CE1: target->host HTT + HTC control */
41d5c65159SKalle Valo 	{
42d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(1),
43d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_IN),
44d5c65159SKalle Valo 		.nentries = __cpu_to_le32(32),
45d5c65159SKalle Valo 		.nbytes_max = __cpu_to_le32(2048),
46d5c65159SKalle Valo 		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
47d5c65159SKalle Valo 		.reserved = __cpu_to_le32(0),
48d5c65159SKalle Valo 	},
49d5c65159SKalle Valo 
50d5c65159SKalle Valo 	/* CE2: target->host WMI */
51d5c65159SKalle Valo 	{
52d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(2),
53d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_IN),
54d5c65159SKalle Valo 		.nentries = __cpu_to_le32(32),
55d5c65159SKalle Valo 		.nbytes_max = __cpu_to_le32(2048),
56d5c65159SKalle Valo 		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
57d5c65159SKalle Valo 		.reserved = __cpu_to_le32(0),
58d5c65159SKalle Valo 	},
59d5c65159SKalle Valo 
60d5c65159SKalle Valo 	/* CE3: host->target WMI */
61d5c65159SKalle Valo 	{
62d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(3),
63d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_OUT),
64d5c65159SKalle Valo 		.nentries = __cpu_to_le32(32),
65d5c65159SKalle Valo 		.nbytes_max = __cpu_to_le32(2048),
66d5c65159SKalle Valo 		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
67d5c65159SKalle Valo 		.reserved = __cpu_to_le32(0),
68d5c65159SKalle Valo 	},
69d5c65159SKalle Valo 
70d5c65159SKalle Valo 	/* CE4: host->target HTT */
71d5c65159SKalle Valo 	{
72d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(4),
73d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_OUT),
74d5c65159SKalle Valo 		.nentries = __cpu_to_le32(256),
75d5c65159SKalle Valo 		.nbytes_max = __cpu_to_le32(256),
76d5c65159SKalle Valo 		.flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
77d5c65159SKalle Valo 		.reserved = __cpu_to_le32(0),
78d5c65159SKalle Valo 	},
79d5c65159SKalle Valo 
80d5c65159SKalle Valo 	/* CE5: target->host Pktlog */
81d5c65159SKalle Valo 	{
82d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(5),
83d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_IN),
84d5c65159SKalle Valo 		.nentries = __cpu_to_le32(32),
85d5c65159SKalle Valo 		.nbytes_max = __cpu_to_le32(2048),
86d5c65159SKalle Valo 		.flags = __cpu_to_le32(0),
87d5c65159SKalle Valo 		.reserved = __cpu_to_le32(0),
88d5c65159SKalle Valo 	},
89d5c65159SKalle Valo 
90d5c65159SKalle Valo 	/* CE6: Reserved for target autonomous hif_memcpy */
91d5c65159SKalle Valo 	{
92d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(6),
93d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_INOUT),
94d5c65159SKalle Valo 		.nentries = __cpu_to_le32(32),
95d5c65159SKalle Valo 		.nbytes_max = __cpu_to_le32(65535),
96d5c65159SKalle Valo 		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
97d5c65159SKalle Valo 		.reserved = __cpu_to_le32(0),
98d5c65159SKalle Valo 	},
99d5c65159SKalle Valo 
100d5c65159SKalle Valo 	/* CE7 used only by Host */
101d5c65159SKalle Valo 	{
102d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(7),
103d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_OUT),
104d5c65159SKalle Valo 		.nentries = __cpu_to_le32(32),
105d5c65159SKalle Valo 		.nbytes_max = __cpu_to_le32(2048),
106d5c65159SKalle Valo 		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
107d5c65159SKalle Valo 		.reserved = __cpu_to_le32(0),
108d5c65159SKalle Valo 	},
109d5c65159SKalle Valo 
110d5c65159SKalle Valo 	/* CE8 target->host used only by IPA */
111d5c65159SKalle Valo 	{
112d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(8),
113d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_INOUT),
114d5c65159SKalle Valo 		.nentries = __cpu_to_le32(32),
115d5c65159SKalle Valo 		.nbytes_max = __cpu_to_le32(65535),
116d5c65159SKalle Valo 		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
117d5c65159SKalle Valo 		.reserved = __cpu_to_le32(0),
118d5c65159SKalle Valo 	},
119d5c65159SKalle Valo 
120d5c65159SKalle Valo 	/* CE9 host->target HTT */
121d5c65159SKalle Valo 	{
122d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(9),
123d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_OUT),
124d5c65159SKalle Valo 		.nentries = __cpu_to_le32(32),
125d5c65159SKalle Valo 		.nbytes_max = __cpu_to_le32(2048),
126d5c65159SKalle Valo 		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
127d5c65159SKalle Valo 		.reserved = __cpu_to_le32(0),
128d5c65159SKalle Valo 	},
129d5c65159SKalle Valo 
130d5c65159SKalle Valo 	/* CE10 target->host HTT */
131d5c65159SKalle Valo 	{
132d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(10),
133d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_INOUT_H2H),
134d5c65159SKalle Valo 		.nentries = __cpu_to_le32(0),
135d5c65159SKalle Valo 		.nbytes_max = __cpu_to_le32(0),
136d5c65159SKalle Valo 		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
137d5c65159SKalle Valo 		.reserved = __cpu_to_le32(0),
138d5c65159SKalle Valo 	},
139d5c65159SKalle Valo 
140d5c65159SKalle Valo 	/* CE11 Not used */
141d5c65159SKalle Valo 	{
142d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(0),
143d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(0),
144d5c65159SKalle Valo 		.nentries = __cpu_to_le32(0),
145d5c65159SKalle Valo 		.nbytes_max = __cpu_to_le32(0),
146d5c65159SKalle Valo 		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
147d5c65159SKalle Valo 		.reserved = __cpu_to_le32(0),
148d5c65159SKalle Valo 	},
149d5c65159SKalle Valo };
150d5c65159SKalle Valo 
151d5c65159SKalle Valo /* Map from service/endpoint to Copy Engine.
152d5c65159SKalle Valo  * This table is derived from the CE_PCI TABLE, above.
153d5c65159SKalle Valo  * It is passed to the Target at startup for use by firmware.
154d5c65159SKalle Valo  */
155d5c65159SKalle Valo static const struct service_to_pipe target_service_to_ce_map_wlan[] = {
156d5c65159SKalle Valo 	{
157d5c65159SKalle Valo 		.service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_VO),
158d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
159d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(3),
160d5c65159SKalle Valo 	},
161d5c65159SKalle Valo 	{
162d5c65159SKalle Valo 		.service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_VO),
163d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
164d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(2),
165d5c65159SKalle Valo 	},
166d5c65159SKalle Valo 	{
167d5c65159SKalle Valo 		.service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_BK),
168d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
169d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(3),
170d5c65159SKalle Valo 	},
171d5c65159SKalle Valo 	{
172d5c65159SKalle Valo 		.service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_BK),
173d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
174d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(2),
175d5c65159SKalle Valo 	},
176d5c65159SKalle Valo 	{
177d5c65159SKalle Valo 		.service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_BE),
178d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
179d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(3),
180d5c65159SKalle Valo 	},
181d5c65159SKalle Valo 	{
182d5c65159SKalle Valo 		.service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_BE),
183d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
184d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(2),
185d5c65159SKalle Valo 	},
186d5c65159SKalle Valo 	{
187d5c65159SKalle Valo 		.service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_VI),
188d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
189d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(3),
190d5c65159SKalle Valo 	},
191d5c65159SKalle Valo 	{
192d5c65159SKalle Valo 		.service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_VI),
193d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
194d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(2),
195d5c65159SKalle Valo 	},
196d5c65159SKalle Valo 	{
197d5c65159SKalle Valo 		.service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_CONTROL),
198d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
199d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(3),
200d5c65159SKalle Valo 	},
201d5c65159SKalle Valo 	{
202d5c65159SKalle Valo 		.service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_CONTROL),
203d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
204d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(2),
205d5c65159SKalle Valo 	},
206d5c65159SKalle Valo 	{
207d5c65159SKalle Valo 		.service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC1),
208d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
209d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(7),
210d5c65159SKalle Valo 	},
211d5c65159SKalle Valo 	{
212d5c65159SKalle Valo 		.service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC1),
213d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
214d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(2),
215d5c65159SKalle Valo 	},
216d5c65159SKalle Valo 	{
217d5c65159SKalle Valo 		.service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC2),
218d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
219d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(9),
220d5c65159SKalle Valo 	},
221d5c65159SKalle Valo 	{
222d5c65159SKalle Valo 		.service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC2),
223d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
224d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(2),
225d5c65159SKalle Valo 	},
226d5c65159SKalle Valo 	{
227d5c65159SKalle Valo 		.service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_RSVD_CTRL),
228d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
229d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(0),
230d5c65159SKalle Valo 	},
231d5c65159SKalle Valo 	{
232d5c65159SKalle Valo 		.service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_RSVD_CTRL),
233d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
234d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(1),
235d5c65159SKalle Valo 	},
236d5c65159SKalle Valo 	{ /* not used */
237d5c65159SKalle Valo 		.service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_TEST_RAW_STREAMS),
238d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
239d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(0),
240d5c65159SKalle Valo 	},
241d5c65159SKalle Valo 	{ /* not used */
242d5c65159SKalle Valo 		.service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_TEST_RAW_STREAMS),
243d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
244d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(1),
245d5c65159SKalle Valo 	},
246d5c65159SKalle Valo 	{
247d5c65159SKalle Valo 		.service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_HTT_DATA_MSG),
248d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
249d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(4),
250d5c65159SKalle Valo 	},
251d5c65159SKalle Valo 	{
252d5c65159SKalle Valo 		.service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_HTT_DATA_MSG),
253d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
254d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(1),
255d5c65159SKalle Valo 	},
256d5c65159SKalle Valo 	{
257d5c65159SKalle Valo 		.service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_PKT_LOG),
258d5c65159SKalle Valo 		.pipedir = __cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
259d5c65159SKalle Valo 		.pipenum = __cpu_to_le32(5),
260d5c65159SKalle Valo 	},
261d5c65159SKalle Valo 
262d5c65159SKalle Valo 	/* (Additions here) */
263d5c65159SKalle Valo 
264d5c65159SKalle Valo 	{ /* terminator entry */ }
265d5c65159SKalle Valo };
266d5c65159SKalle Valo 
267d5c65159SKalle Valo #define ATH11K_IRQ_CE0_OFFSET 4
268d5c65159SKalle Valo 
269d5c65159SKalle Valo static const char *irq_name[ATH11K_IRQ_NUM_MAX] = {
270d5c65159SKalle Valo 	"misc-pulse1",
271d5c65159SKalle Valo 	"misc-latch",
272d5c65159SKalle Valo 	"sw-exception",
273d5c65159SKalle Valo 	"watchdog",
274d5c65159SKalle Valo 	"ce0",
275d5c65159SKalle Valo 	"ce1",
276d5c65159SKalle Valo 	"ce2",
277d5c65159SKalle Valo 	"ce3",
278d5c65159SKalle Valo 	"ce4",
279d5c65159SKalle Valo 	"ce5",
280d5c65159SKalle Valo 	"ce6",
281d5c65159SKalle Valo 	"ce7",
282d5c65159SKalle Valo 	"ce8",
283d5c65159SKalle Valo 	"ce9",
284d5c65159SKalle Valo 	"ce10",
285d5c65159SKalle Valo 	"ce11",
286d5c65159SKalle Valo 	"host2wbm-desc-feed",
287d5c65159SKalle Valo 	"host2reo-re-injection",
288d5c65159SKalle Valo 	"host2reo-command",
289d5c65159SKalle Valo 	"host2rxdma-monitor-ring3",
290d5c65159SKalle Valo 	"host2rxdma-monitor-ring2",
291d5c65159SKalle Valo 	"host2rxdma-monitor-ring1",
292d5c65159SKalle Valo 	"reo2ost-exception",
293d5c65159SKalle Valo 	"wbm2host-rx-release",
294d5c65159SKalle Valo 	"reo2host-status",
295d5c65159SKalle Valo 	"reo2host-destination-ring4",
296d5c65159SKalle Valo 	"reo2host-destination-ring3",
297d5c65159SKalle Valo 	"reo2host-destination-ring2",
298d5c65159SKalle Valo 	"reo2host-destination-ring1",
299d5c65159SKalle Valo 	"rxdma2host-monitor-destination-mac3",
300d5c65159SKalle Valo 	"rxdma2host-monitor-destination-mac2",
301d5c65159SKalle Valo 	"rxdma2host-monitor-destination-mac1",
302d5c65159SKalle Valo 	"ppdu-end-interrupts-mac3",
303d5c65159SKalle Valo 	"ppdu-end-interrupts-mac2",
304d5c65159SKalle Valo 	"ppdu-end-interrupts-mac1",
305d5c65159SKalle Valo 	"rxdma2host-monitor-status-ring-mac3",
306d5c65159SKalle Valo 	"rxdma2host-monitor-status-ring-mac2",
307d5c65159SKalle Valo 	"rxdma2host-monitor-status-ring-mac1",
308d5c65159SKalle Valo 	"host2rxdma-host-buf-ring-mac3",
309d5c65159SKalle Valo 	"host2rxdma-host-buf-ring-mac2",
310d5c65159SKalle Valo 	"host2rxdma-host-buf-ring-mac1",
311d5c65159SKalle Valo 	"rxdma2host-destination-ring-mac3",
312d5c65159SKalle Valo 	"rxdma2host-destination-ring-mac2",
313d5c65159SKalle Valo 	"rxdma2host-destination-ring-mac1",
314d5c65159SKalle Valo 	"host2tcl-input-ring4",
315d5c65159SKalle Valo 	"host2tcl-input-ring3",
316d5c65159SKalle Valo 	"host2tcl-input-ring2",
317d5c65159SKalle Valo 	"host2tcl-input-ring1",
318d5c65159SKalle Valo 	"wbm2host-tx-completions-ring3",
319d5c65159SKalle Valo 	"wbm2host-tx-completions-ring2",
320d5c65159SKalle Valo 	"wbm2host-tx-completions-ring1",
321d5c65159SKalle Valo 	"tcl2host-status-ring",
322d5c65159SKalle Valo };
323d5c65159SKalle Valo 
324d5c65159SKalle Valo #define ATH11K_TX_RING_MASK_0 0x1
325d5c65159SKalle Valo #define ATH11K_TX_RING_MASK_1 0x2
326d5c65159SKalle Valo #define ATH11K_TX_RING_MASK_2 0x4
327d5c65159SKalle Valo 
328d5c65159SKalle Valo #define ATH11K_RX_RING_MASK_0 0x1
329d5c65159SKalle Valo #define ATH11K_RX_RING_MASK_1 0x2
330d5c65159SKalle Valo #define ATH11K_RX_RING_MASK_2 0x4
331d5c65159SKalle Valo #define ATH11K_RX_RING_MASK_3 0x8
332d5c65159SKalle Valo 
333d5c65159SKalle Valo #define ATH11K_RX_ERR_RING_MASK_0 0x1
334d5c65159SKalle Valo 
335d5c65159SKalle Valo #define ATH11K_RX_WBM_REL_RING_MASK_0 0x1
336d5c65159SKalle Valo 
337d5c65159SKalle Valo #define ATH11K_REO_STATUS_RING_MASK_0 0x1
338d5c65159SKalle Valo 
339d5c65159SKalle Valo #define ATH11K_RXDMA2HOST_RING_MASK_0 0x1
340d5c65159SKalle Valo #define ATH11K_RXDMA2HOST_RING_MASK_1 0x2
341d5c65159SKalle Valo #define ATH11K_RXDMA2HOST_RING_MASK_2 0x4
342d5c65159SKalle Valo 
343d5c65159SKalle Valo #define ATH11K_HOST2RXDMA_RING_MASK_0 0x1
344d5c65159SKalle Valo #define ATH11K_HOST2RXDMA_RING_MASK_1 0x2
345d5c65159SKalle Valo #define ATH11K_HOST2RXDMA_RING_MASK_2 0x4
346d5c65159SKalle Valo 
347d5c65159SKalle Valo #define ATH11K_RX_MON_STATUS_RING_MASK_0 0x1
348d5c65159SKalle Valo #define ATH11K_RX_MON_STATUS_RING_MASK_1 0x2
349d5c65159SKalle Valo #define ATH11K_RX_MON_STATUS_RING_MASK_2 0x4
350d5c65159SKalle Valo 
351d5c65159SKalle Valo const u8 ath11k_tx_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
352d5c65159SKalle Valo 	ATH11K_TX_RING_MASK_0,
353d5c65159SKalle Valo 	ATH11K_TX_RING_MASK_1,
354d5c65159SKalle Valo 	ATH11K_TX_RING_MASK_2,
355d5c65159SKalle Valo };
356d5c65159SKalle Valo 
357d5c65159SKalle Valo const u8 rx_mon_status_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
358d5c65159SKalle Valo 	0, 0, 0, 0,
359d5c65159SKalle Valo 	ATH11K_RX_MON_STATUS_RING_MASK_0,
360d5c65159SKalle Valo 	ATH11K_RX_MON_STATUS_RING_MASK_1,
361d5c65159SKalle Valo 	ATH11K_RX_MON_STATUS_RING_MASK_2,
362d5c65159SKalle Valo };
363d5c65159SKalle Valo 
364d5c65159SKalle Valo const u8 ath11k_rx_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
365d5c65159SKalle Valo 	0, 0, 0, 0, 0, 0, 0,
366d5c65159SKalle Valo 	ATH11K_RX_RING_MASK_0,
367d5c65159SKalle Valo 	ATH11K_RX_RING_MASK_1,
368d5c65159SKalle Valo 	ATH11K_RX_RING_MASK_2,
369d5c65159SKalle Valo 	ATH11K_RX_RING_MASK_3,
370d5c65159SKalle Valo };
371d5c65159SKalle Valo 
372d5c65159SKalle Valo const u8 ath11k_rx_err_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
373d5c65159SKalle Valo 	ATH11K_RX_ERR_RING_MASK_0,
374d5c65159SKalle Valo };
375d5c65159SKalle Valo 
376d5c65159SKalle Valo const u8 ath11k_rx_wbm_rel_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
377d5c65159SKalle Valo 	ATH11K_RX_WBM_REL_RING_MASK_0,
378d5c65159SKalle Valo };
379d5c65159SKalle Valo 
380d5c65159SKalle Valo const u8 ath11k_reo_status_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
381d5c65159SKalle Valo 	ATH11K_REO_STATUS_RING_MASK_0,
382d5c65159SKalle Valo };
383d5c65159SKalle Valo 
384d5c65159SKalle Valo const u8 ath11k_rxdma2host_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
385d5c65159SKalle Valo 	ATH11K_RXDMA2HOST_RING_MASK_0,
386d5c65159SKalle Valo 	ATH11K_RXDMA2HOST_RING_MASK_1,
387d5c65159SKalle Valo 	ATH11K_RXDMA2HOST_RING_MASK_2,
388d5c65159SKalle Valo };
389d5c65159SKalle Valo 
390d5c65159SKalle Valo const u8 ath11k_host2rxdma_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
391d5c65159SKalle Valo 	ATH11K_HOST2RXDMA_RING_MASK_0,
392d5c65159SKalle Valo 	ATH11K_HOST2RXDMA_RING_MASK_1,
393d5c65159SKalle Valo 	ATH11K_HOST2RXDMA_RING_MASK_2,
394d5c65159SKalle Valo };
395d5c65159SKalle Valo 
396d5c65159SKalle Valo /* enum ext_irq_num - irq numbers that can be used by external modules
397d5c65159SKalle Valo  * like datapath
398d5c65159SKalle Valo  */
399d5c65159SKalle Valo enum ext_irq_num {
400d5c65159SKalle Valo 	host2wbm_desc_feed = 16,
401d5c65159SKalle Valo 	host2reo_re_injection,
402d5c65159SKalle Valo 	host2reo_command,
403d5c65159SKalle Valo 	host2rxdma_monitor_ring3,
404d5c65159SKalle Valo 	host2rxdma_monitor_ring2,
405d5c65159SKalle Valo 	host2rxdma_monitor_ring1,
406d5c65159SKalle Valo 	reo2host_exception,
407d5c65159SKalle Valo 	wbm2host_rx_release,
408d5c65159SKalle Valo 	reo2host_status,
409d5c65159SKalle Valo 	reo2host_destination_ring4,
410d5c65159SKalle Valo 	reo2host_destination_ring3,
411d5c65159SKalle Valo 	reo2host_destination_ring2,
412d5c65159SKalle Valo 	reo2host_destination_ring1,
413d5c65159SKalle Valo 	rxdma2host_monitor_destination_mac3,
414d5c65159SKalle Valo 	rxdma2host_monitor_destination_mac2,
415d5c65159SKalle Valo 	rxdma2host_monitor_destination_mac1,
416d5c65159SKalle Valo 	ppdu_end_interrupts_mac3,
417d5c65159SKalle Valo 	ppdu_end_interrupts_mac2,
418d5c65159SKalle Valo 	ppdu_end_interrupts_mac1,
419d5c65159SKalle Valo 	rxdma2host_monitor_status_ring_mac3,
420d5c65159SKalle Valo 	rxdma2host_monitor_status_ring_mac2,
421d5c65159SKalle Valo 	rxdma2host_monitor_status_ring_mac1,
422d5c65159SKalle Valo 	host2rxdma_host_buf_ring_mac3,
423d5c65159SKalle Valo 	host2rxdma_host_buf_ring_mac2,
424d5c65159SKalle Valo 	host2rxdma_host_buf_ring_mac1,
425d5c65159SKalle Valo 	rxdma2host_destination_ring_mac3,
426d5c65159SKalle Valo 	rxdma2host_destination_ring_mac2,
427d5c65159SKalle Valo 	rxdma2host_destination_ring_mac1,
428d5c65159SKalle Valo 	host2tcl_input_ring4,
429d5c65159SKalle Valo 	host2tcl_input_ring3,
430d5c65159SKalle Valo 	host2tcl_input_ring2,
431d5c65159SKalle Valo 	host2tcl_input_ring1,
432d5c65159SKalle Valo 	wbm2host_tx_completions_ring3,
433d5c65159SKalle Valo 	wbm2host_tx_completions_ring2,
434d5c65159SKalle Valo 	wbm2host_tx_completions_ring1,
435d5c65159SKalle Valo 	tcl2host_status_ring,
436d5c65159SKalle Valo };
437d5c65159SKalle Valo 
43831858805SGovind Singh static inline u32 ath11k_ahb_read32(struct ath11k_base *ab, u32 offset)
43931858805SGovind Singh {
44031858805SGovind Singh 	return ioread32(ab->mem + offset);
44131858805SGovind Singh }
44231858805SGovind Singh 
44331858805SGovind Singh static inline void ath11k_ahb_write32(struct ath11k_base *ab, u32 offset, u32 value)
44431858805SGovind Singh {
44531858805SGovind Singh 	iowrite32(value, ab->mem + offset);
44631858805SGovind Singh }
44731858805SGovind Singh 
448d5c65159SKalle Valo static void ath11k_ahb_kill_tasklets(struct ath11k_base *ab)
449d5c65159SKalle Valo {
450d5c65159SKalle Valo 	int i;
451d5c65159SKalle Valo 
452d5c65159SKalle Valo 	for (i = 0; i < CE_COUNT; i++) {
453d5c65159SKalle Valo 		struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
454d5c65159SKalle Valo 
455d5c65159SKalle Valo 		if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR)
456d5c65159SKalle Valo 			continue;
457d5c65159SKalle Valo 
458d5c65159SKalle Valo 		tasklet_kill(&ce_pipe->intr_tq);
459d5c65159SKalle Valo 	}
460d5c65159SKalle Valo }
461d5c65159SKalle Valo 
462d5c65159SKalle Valo static void ath11k_ahb_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
463d5c65159SKalle Valo {
464d5c65159SKalle Valo 	int i;
465d5c65159SKalle Valo 
466d5c65159SKalle Valo 	for (i = 0; i < irq_grp->num_irq; i++)
467d5c65159SKalle Valo 		disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
468d5c65159SKalle Valo }
469d5c65159SKalle Valo 
470d5c65159SKalle Valo static void __ath11k_ahb_ext_irq_disable(struct ath11k_base *ab)
471d5c65159SKalle Valo {
472d5c65159SKalle Valo 	int i;
473d5c65159SKalle Valo 
474d5c65159SKalle Valo 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
475d5c65159SKalle Valo 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
476d5c65159SKalle Valo 
477d5c65159SKalle Valo 		ath11k_ahb_ext_grp_disable(irq_grp);
478d5c65159SKalle Valo 
479d5c65159SKalle Valo 		napi_synchronize(&irq_grp->napi);
480d5c65159SKalle Valo 		napi_disable(&irq_grp->napi);
481d5c65159SKalle Valo 	}
482d5c65159SKalle Valo }
483d5c65159SKalle Valo 
484d5c65159SKalle Valo static void ath11k_ahb_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
485d5c65159SKalle Valo {
486d5c65159SKalle Valo 	int i;
487d5c65159SKalle Valo 
488d5c65159SKalle Valo 	for (i = 0; i < irq_grp->num_irq; i++)
489d5c65159SKalle Valo 		enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
490d5c65159SKalle Valo }
491d5c65159SKalle Valo 
492d5c65159SKalle Valo static void ath11k_ahb_setbit32(struct ath11k_base *ab, u8 bit, u32 offset)
493d5c65159SKalle Valo {
494d5c65159SKalle Valo 	u32 val;
495d5c65159SKalle Valo 
496d5c65159SKalle Valo 	val = ath11k_ahb_read32(ab, offset);
497d5c65159SKalle Valo 	ath11k_ahb_write32(ab, offset, val | BIT(bit));
498d5c65159SKalle Valo }
499d5c65159SKalle Valo 
500d5c65159SKalle Valo static void ath11k_ahb_clearbit32(struct ath11k_base *ab, u8 bit, u32 offset)
501d5c65159SKalle Valo {
502d5c65159SKalle Valo 	u32 val;
503d5c65159SKalle Valo 
504d5c65159SKalle Valo 	val = ath11k_ahb_read32(ab, offset);
505d5c65159SKalle Valo 	ath11k_ahb_write32(ab, offset, val & ~BIT(bit));
506d5c65159SKalle Valo }
507d5c65159SKalle Valo 
508d5c65159SKalle Valo static void ath11k_ahb_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
509d5c65159SKalle Valo {
510d5c65159SKalle Valo 	const struct ce_pipe_config *ce_config;
511d5c65159SKalle Valo 
512d5c65159SKalle Valo 	ce_config = &target_ce_config_wlan[ce_id];
513d5c65159SKalle Valo 	if (__le32_to_cpu(ce_config->pipedir) & PIPEDIR_OUT)
514d5c65159SKalle Valo 		ath11k_ahb_setbit32(ab, ce_id, CE_HOST_IE_ADDRESS);
515d5c65159SKalle Valo 
516d5c65159SKalle Valo 	if (__le32_to_cpu(ce_config->pipedir) & PIPEDIR_IN) {
517d5c65159SKalle Valo 		ath11k_ahb_setbit32(ab, ce_id, CE_HOST_IE_2_ADDRESS);
518d5c65159SKalle Valo 		ath11k_ahb_setbit32(ab, ce_id + CE_HOST_IE_3_SHIFT,
519d5c65159SKalle Valo 				    CE_HOST_IE_3_ADDRESS);
520d5c65159SKalle Valo 	}
521d5c65159SKalle Valo }
522d5c65159SKalle Valo 
523d5c65159SKalle Valo static void ath11k_ahb_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
524d5c65159SKalle Valo {
525d5c65159SKalle Valo 	const struct ce_pipe_config *ce_config;
526d5c65159SKalle Valo 
527d5c65159SKalle Valo 	ce_config = &target_ce_config_wlan[ce_id];
528d5c65159SKalle Valo 	if (__le32_to_cpu(ce_config->pipedir) & PIPEDIR_OUT)
529d5c65159SKalle Valo 		ath11k_ahb_clearbit32(ab, ce_id, CE_HOST_IE_ADDRESS);
530d5c65159SKalle Valo 
531d5c65159SKalle Valo 	if (__le32_to_cpu(ce_config->pipedir) & PIPEDIR_IN) {
532d5c65159SKalle Valo 		ath11k_ahb_clearbit32(ab, ce_id, CE_HOST_IE_2_ADDRESS);
533d5c65159SKalle Valo 		ath11k_ahb_clearbit32(ab, ce_id + CE_HOST_IE_3_SHIFT,
534d5c65159SKalle Valo 				      CE_HOST_IE_3_ADDRESS);
535d5c65159SKalle Valo 	}
536d5c65159SKalle Valo }
537d5c65159SKalle Valo 
538d5c65159SKalle Valo static void ath11k_ahb_sync_ce_irqs(struct ath11k_base *ab)
539d5c65159SKalle Valo {
540d5c65159SKalle Valo 	int i;
541d5c65159SKalle Valo 	int irq_idx;
542d5c65159SKalle Valo 
543d5c65159SKalle Valo 	for (i = 0; i < CE_COUNT; i++) {
544d5c65159SKalle Valo 		if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR)
545d5c65159SKalle Valo 			continue;
546d5c65159SKalle Valo 
547d5c65159SKalle Valo 		irq_idx = ATH11K_IRQ_CE0_OFFSET + i;
548d5c65159SKalle Valo 		synchronize_irq(ab->irq_num[irq_idx]);
549d5c65159SKalle Valo 	}
550d5c65159SKalle Valo }
551d5c65159SKalle Valo 
552d5c65159SKalle Valo static void ath11k_ahb_sync_ext_irqs(struct ath11k_base *ab)
553d5c65159SKalle Valo {
554d5c65159SKalle Valo 	int i, j;
555d5c65159SKalle Valo 	int irq_idx;
556d5c65159SKalle Valo 
557d5c65159SKalle Valo 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
558d5c65159SKalle Valo 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
559d5c65159SKalle Valo 
560d5c65159SKalle Valo 		for (j = 0; j < irq_grp->num_irq; j++) {
561d5c65159SKalle Valo 			irq_idx = irq_grp->irqs[j];
562d5c65159SKalle Valo 			synchronize_irq(ab->irq_num[irq_idx]);
563d5c65159SKalle Valo 		}
564d5c65159SKalle Valo 	}
565d5c65159SKalle Valo }
566d5c65159SKalle Valo 
567d5c65159SKalle Valo static void ath11k_ahb_ce_irqs_enable(struct ath11k_base *ab)
568d5c65159SKalle Valo {
569d5c65159SKalle Valo 	int i;
570d5c65159SKalle Valo 
571d5c65159SKalle Valo 	for (i = 0; i < CE_COUNT; i++) {
572d5c65159SKalle Valo 		if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR)
573d5c65159SKalle Valo 			continue;
574d5c65159SKalle Valo 		ath11k_ahb_ce_irq_enable(ab, i);
575d5c65159SKalle Valo 	}
576d5c65159SKalle Valo }
577d5c65159SKalle Valo 
578d5c65159SKalle Valo static void ath11k_ahb_ce_irqs_disable(struct ath11k_base *ab)
579d5c65159SKalle Valo {
580d5c65159SKalle Valo 	int i;
581d5c65159SKalle Valo 
582d5c65159SKalle Valo 	for (i = 0; i < CE_COUNT; i++) {
583d5c65159SKalle Valo 		if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR)
584d5c65159SKalle Valo 			continue;
585d5c65159SKalle Valo 		ath11k_ahb_ce_irq_disable(ab, i);
586d5c65159SKalle Valo 	}
587d5c65159SKalle Valo }
588d5c65159SKalle Valo 
58931858805SGovind Singh static int ath11k_ahb_start(struct ath11k_base *ab)
590d5c65159SKalle Valo {
591d5c65159SKalle Valo 	ath11k_ahb_ce_irqs_enable(ab);
592d5c65159SKalle Valo 	ath11k_ce_rx_post_buf(ab);
593d5c65159SKalle Valo 
594d5c65159SKalle Valo 	return 0;
595d5c65159SKalle Valo }
596d5c65159SKalle Valo 
59731858805SGovind Singh static void ath11k_ahb_ext_irq_enable(struct ath11k_base *ab)
598d5c65159SKalle Valo {
599d5c65159SKalle Valo 	int i;
600d5c65159SKalle Valo 
601d5c65159SKalle Valo 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
602d5c65159SKalle Valo 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
603d5c65159SKalle Valo 
604d5c65159SKalle Valo 		napi_enable(&irq_grp->napi);
605d5c65159SKalle Valo 		ath11k_ahb_ext_grp_enable(irq_grp);
606d5c65159SKalle Valo 	}
607d5c65159SKalle Valo }
608d5c65159SKalle Valo 
60931858805SGovind Singh static void ath11k_ahb_ext_irq_disable(struct ath11k_base *ab)
610d5c65159SKalle Valo {
611d5c65159SKalle Valo 	__ath11k_ahb_ext_irq_disable(ab);
612d5c65159SKalle Valo 	ath11k_ahb_sync_ext_irqs(ab);
613d5c65159SKalle Valo }
614d5c65159SKalle Valo 
61531858805SGovind Singh static void ath11k_ahb_stop(struct ath11k_base *ab)
616d5c65159SKalle Valo {
617d5c65159SKalle Valo 	if (!test_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags))
618d5c65159SKalle Valo 		ath11k_ahb_ce_irqs_disable(ab);
619d5c65159SKalle Valo 	ath11k_ahb_sync_ce_irqs(ab);
620d5c65159SKalle Valo 	ath11k_ahb_kill_tasklets(ab);
621d5c65159SKalle Valo 	del_timer_sync(&ab->rx_replenish_retry);
622d5c65159SKalle Valo 	ath11k_ce_cleanup_pipes(ab);
623d5c65159SKalle Valo }
624d5c65159SKalle Valo 
62531858805SGovind Singh static int ath11k_ahb_power_up(struct ath11k_base *ab)
626d5c65159SKalle Valo {
627d5c65159SKalle Valo 	int ret;
628d5c65159SKalle Valo 
629d5c65159SKalle Valo 	ret = rproc_boot(ab->tgt_rproc);
630d5c65159SKalle Valo 	if (ret)
631d5c65159SKalle Valo 		ath11k_err(ab, "failed to boot the remote processor Q6\n");
632d5c65159SKalle Valo 
633d5c65159SKalle Valo 	return ret;
634d5c65159SKalle Valo }
635d5c65159SKalle Valo 
63631858805SGovind Singh static void ath11k_ahb_power_down(struct ath11k_base *ab)
637d5c65159SKalle Valo {
638d5c65159SKalle Valo 	rproc_shutdown(ab->tgt_rproc);
639d5c65159SKalle Valo }
640d5c65159SKalle Valo 
641d5c65159SKalle Valo static void ath11k_ahb_init_qmi_ce_config(struct ath11k_base *ab)
642d5c65159SKalle Valo {
643d5c65159SKalle Valo 	struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
644d5c65159SKalle Valo 
645d6af906dSAnilkumar Kolli 	cfg->tgt_ce_len = ARRAY_SIZE(target_ce_config_wlan) - 1;
646d6af906dSAnilkumar Kolli 	cfg->tgt_ce = target_ce_config_wlan;
647d6af906dSAnilkumar Kolli 	cfg->svc_to_ce_map_len = ARRAY_SIZE(target_service_to_ce_map_wlan);
648d6af906dSAnilkumar Kolli 	cfg->svc_to_ce_map = target_service_to_ce_map_wlan;
649d5c65159SKalle Valo }
650d5c65159SKalle Valo 
651d5c65159SKalle Valo static void ath11k_ahb_free_ext_irq(struct ath11k_base *ab)
652d5c65159SKalle Valo {
653d5c65159SKalle Valo 	int i, j;
654d5c65159SKalle Valo 
655d5c65159SKalle Valo 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
656d5c65159SKalle Valo 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
657d5c65159SKalle Valo 
658d5c65159SKalle Valo 		for (j = 0; j < irq_grp->num_irq; j++)
659d5c65159SKalle Valo 			free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp);
660d5c65159SKalle Valo 	}
661d5c65159SKalle Valo }
662d5c65159SKalle Valo 
663d5c65159SKalle Valo static void ath11k_ahb_free_irq(struct ath11k_base *ab)
664d5c65159SKalle Valo {
665d5c65159SKalle Valo 	int irq_idx;
666d5c65159SKalle Valo 	int i;
667d5c65159SKalle Valo 
668d5c65159SKalle Valo 	for (i = 0; i < CE_COUNT; i++) {
669d5c65159SKalle Valo 		if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR)
670d5c65159SKalle Valo 			continue;
671d5c65159SKalle Valo 		irq_idx = ATH11K_IRQ_CE0_OFFSET + i;
672d5c65159SKalle Valo 		free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]);
673d5c65159SKalle Valo 	}
674d5c65159SKalle Valo 
675d5c65159SKalle Valo 	ath11k_ahb_free_ext_irq(ab);
676d5c65159SKalle Valo }
677d5c65159SKalle Valo 
678d5c65159SKalle Valo static void ath11k_ahb_ce_tasklet(unsigned long data)
679d5c65159SKalle Valo {
680d5c65159SKalle Valo 	struct ath11k_ce_pipe *ce_pipe = (struct ath11k_ce_pipe *)data;
681d5c65159SKalle Valo 
682d5c65159SKalle Valo 	ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
683d5c65159SKalle Valo 
684d5c65159SKalle Valo 	ath11k_ahb_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num);
685d5c65159SKalle Valo }
686d5c65159SKalle Valo 
687d5c65159SKalle Valo static irqreturn_t ath11k_ahb_ce_interrupt_handler(int irq, void *arg)
688d5c65159SKalle Valo {
689d5c65159SKalle Valo 	struct ath11k_ce_pipe *ce_pipe = arg;
690d5c65159SKalle Valo 
6915118935bSManikanta Pubbisetty 	/* last interrupt received for this CE */
6925118935bSManikanta Pubbisetty 	ce_pipe->timestamp = jiffies;
6935118935bSManikanta Pubbisetty 
694d5c65159SKalle Valo 	ath11k_ahb_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);
695d5c65159SKalle Valo 
696d5c65159SKalle Valo 	tasklet_schedule(&ce_pipe->intr_tq);
697d5c65159SKalle Valo 
698d5c65159SKalle Valo 	return IRQ_HANDLED;
699d5c65159SKalle Valo }
700d5c65159SKalle Valo 
701d5c65159SKalle Valo static int ath11k_ahb_ext_grp_napi_poll(struct napi_struct *napi, int budget)
702d5c65159SKalle Valo {
703d5c65159SKalle Valo 	struct ath11k_ext_irq_grp *irq_grp = container_of(napi,
704d5c65159SKalle Valo 						struct ath11k_ext_irq_grp,
705d5c65159SKalle Valo 						napi);
706d5c65159SKalle Valo 	struct ath11k_base *ab = irq_grp->ab;
707d5c65159SKalle Valo 	int work_done;
708d5c65159SKalle Valo 
709d5c65159SKalle Valo 	work_done = ath11k_dp_service_srng(ab, irq_grp, budget);
710d5c65159SKalle Valo 	if (work_done < budget) {
711d5c65159SKalle Valo 		napi_complete_done(napi, work_done);
712d5c65159SKalle Valo 		ath11k_ahb_ext_grp_enable(irq_grp);
713d5c65159SKalle Valo 	}
714d5c65159SKalle Valo 
715d5c65159SKalle Valo 	if (work_done > budget)
716d5c65159SKalle Valo 		work_done = budget;
717d5c65159SKalle Valo 
718d5c65159SKalle Valo 	return work_done;
719d5c65159SKalle Valo }
720d5c65159SKalle Valo 
721d5c65159SKalle Valo static irqreturn_t ath11k_ahb_ext_interrupt_handler(int irq, void *arg)
722d5c65159SKalle Valo {
723d5c65159SKalle Valo 	struct ath11k_ext_irq_grp *irq_grp = arg;
724d5c65159SKalle Valo 
7255118935bSManikanta Pubbisetty 	/* last interrupt received for this group */
7265118935bSManikanta Pubbisetty 	irq_grp->timestamp = jiffies;
7275118935bSManikanta Pubbisetty 
728d5c65159SKalle Valo 	ath11k_ahb_ext_grp_disable(irq_grp);
729d5c65159SKalle Valo 
730d5c65159SKalle Valo 	napi_schedule(&irq_grp->napi);
731d5c65159SKalle Valo 
732d5c65159SKalle Valo 	return IRQ_HANDLED;
733d5c65159SKalle Valo }
734d5c65159SKalle Valo 
735d5c65159SKalle Valo static int ath11k_ahb_ext_irq_config(struct ath11k_base *ab)
736d5c65159SKalle Valo {
737d5c65159SKalle Valo 	int i, j;
738d5c65159SKalle Valo 	int irq;
739d5c65159SKalle Valo 	int ret;
740d5c65159SKalle Valo 
741d5c65159SKalle Valo 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
742d5c65159SKalle Valo 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
743d5c65159SKalle Valo 		u32 num_irq = 0;
744d5c65159SKalle Valo 
745d5c65159SKalle Valo 		irq_grp->ab = ab;
746d5c65159SKalle Valo 		irq_grp->grp_id = i;
747d5c65159SKalle Valo 		init_dummy_netdev(&irq_grp->napi_ndev);
748d5c65159SKalle Valo 		netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi,
749d5c65159SKalle Valo 			       ath11k_ahb_ext_grp_napi_poll, NAPI_POLL_WEIGHT);
750d5c65159SKalle Valo 
751d5c65159SKalle Valo 		for (j = 0; j < ATH11K_EXT_IRQ_NUM_MAX; j++) {
752d5c65159SKalle Valo 			if (ath11k_tx_ring_mask[i] & BIT(j)) {
753d5c65159SKalle Valo 				irq_grp->irqs[num_irq++] =
754d5c65159SKalle Valo 					wbm2host_tx_completions_ring1 - j;
755d5c65159SKalle Valo 			}
756d5c65159SKalle Valo 
757d5c65159SKalle Valo 			if (ath11k_rx_ring_mask[i] & BIT(j)) {
758d5c65159SKalle Valo 				irq_grp->irqs[num_irq++] =
759d5c65159SKalle Valo 					reo2host_destination_ring1 - j;
760d5c65159SKalle Valo 			}
761d5c65159SKalle Valo 
762d5c65159SKalle Valo 			if (ath11k_rx_err_ring_mask[i] & BIT(j))
763d5c65159SKalle Valo 				irq_grp->irqs[num_irq++] = reo2host_exception;
764d5c65159SKalle Valo 
765d5c65159SKalle Valo 			if (ath11k_rx_wbm_rel_ring_mask[i] & BIT(j))
766d5c65159SKalle Valo 				irq_grp->irqs[num_irq++] = wbm2host_rx_release;
767d5c65159SKalle Valo 
768d5c65159SKalle Valo 			if (ath11k_reo_status_ring_mask[i] & BIT(j))
769d5c65159SKalle Valo 				irq_grp->irqs[num_irq++] = reo2host_status;
770d5c65159SKalle Valo 
771d5c65159SKalle Valo 			if (j < MAX_RADIOS) {
772d5c65159SKalle Valo 				if (ath11k_rxdma2host_ring_mask[i] & BIT(j)) {
773d5c65159SKalle Valo 					irq_grp->irqs[num_irq++] =
774d5c65159SKalle Valo 						rxdma2host_destination_ring_mac1
775d5c65159SKalle Valo 						- ath11k_core_get_hw_mac_id(ab, j);
776d5c65159SKalle Valo 				}
777d5c65159SKalle Valo 
778d5c65159SKalle Valo 				if (ath11k_host2rxdma_ring_mask[i] & BIT(j)) {
779d5c65159SKalle Valo 					irq_grp->irqs[num_irq++] =
780d5c65159SKalle Valo 						host2rxdma_host_buf_ring_mac1
781d5c65159SKalle Valo 						- ath11k_core_get_hw_mac_id(ab, j);
782d5c65159SKalle Valo 				}
783d5c65159SKalle Valo 
784d5c65159SKalle Valo 				if (rx_mon_status_ring_mask[i] & BIT(j)) {
785d5c65159SKalle Valo 					irq_grp->irqs[num_irq++] =
786d5c65159SKalle Valo 						ppdu_end_interrupts_mac1 -
787d5c65159SKalle Valo 						ath11k_core_get_hw_mac_id(ab, j);
788d5c65159SKalle Valo 					irq_grp->irqs[num_irq++] =
789d5c65159SKalle Valo 						rxdma2host_monitor_status_ring_mac1 -
790d5c65159SKalle Valo 						ath11k_core_get_hw_mac_id(ab, j);
791d5c65159SKalle Valo 				}
792d5c65159SKalle Valo 			}
793d5c65159SKalle Valo 		}
794d5c65159SKalle Valo 		irq_grp->num_irq = num_irq;
795d5c65159SKalle Valo 
796d5c65159SKalle Valo 		for (j = 0; j < irq_grp->num_irq; j++) {
797d5c65159SKalle Valo 			int irq_idx = irq_grp->irqs[j];
798d5c65159SKalle Valo 
799d5c65159SKalle Valo 			irq = platform_get_irq_byname(ab->pdev,
800d5c65159SKalle Valo 						      irq_name[irq_idx]);
801d5c65159SKalle Valo 			ab->irq_num[irq_idx] = irq;
80205090864SManikanta Pubbisetty 			irq_set_status_flags(irq, IRQ_NOAUTOEN | IRQ_DISABLE_UNLAZY);
803d5c65159SKalle Valo 			ret = request_irq(irq, ath11k_ahb_ext_interrupt_handler,
804d5c65159SKalle Valo 					  IRQF_TRIGGER_RISING,
805d5c65159SKalle Valo 					  irq_name[irq_idx], irq_grp);
806d5c65159SKalle Valo 			if (ret) {
807d5c65159SKalle Valo 				ath11k_err(ab, "failed request_irq for %d\n",
808d5c65159SKalle Valo 					   irq);
809d5c65159SKalle Valo 			}
810d5c65159SKalle Valo 		}
811d5c65159SKalle Valo 	}
812d5c65159SKalle Valo 
813d5c65159SKalle Valo 	return 0;
814d5c65159SKalle Valo }
815d5c65159SKalle Valo 
816d5c65159SKalle Valo static int ath11k_ahb_config_irq(struct ath11k_base *ab)
817d5c65159SKalle Valo {
818d5c65159SKalle Valo 	int irq, irq_idx, i;
819d5c65159SKalle Valo 	int ret;
820d5c65159SKalle Valo 
821d5c65159SKalle Valo 	/* Configure CE irqs */
822d5c65159SKalle Valo 	for (i = 0; i < CE_COUNT; i++) {
823d5c65159SKalle Valo 		struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
824d5c65159SKalle Valo 
825d5c65159SKalle Valo 		if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR)
826d5c65159SKalle Valo 			continue;
827d5c65159SKalle Valo 
828d5c65159SKalle Valo 		irq_idx = ATH11K_IRQ_CE0_OFFSET + i;
829d5c65159SKalle Valo 
830d5c65159SKalle Valo 		tasklet_init(&ce_pipe->intr_tq, ath11k_ahb_ce_tasklet,
831d5c65159SKalle Valo 			     (unsigned long)ce_pipe);
832d5c65159SKalle Valo 		irq = platform_get_irq_byname(ab->pdev, irq_name[irq_idx]);
833d5c65159SKalle Valo 		ret = request_irq(irq, ath11k_ahb_ce_interrupt_handler,
834d5c65159SKalle Valo 				  IRQF_TRIGGER_RISING, irq_name[irq_idx],
835d5c65159SKalle Valo 				  ce_pipe);
836d5c65159SKalle Valo 		if (ret)
837d5c65159SKalle Valo 			return ret;
838d5c65159SKalle Valo 
839d5c65159SKalle Valo 		ab->irq_num[irq_idx] = irq;
840d5c65159SKalle Valo 	}
841d5c65159SKalle Valo 
842d5c65159SKalle Valo 	/* Configure external interrupts */
843d5c65159SKalle Valo 	ret = ath11k_ahb_ext_irq_config(ab);
844d5c65159SKalle Valo 
845d5c65159SKalle Valo 	return ret;
846d5c65159SKalle Valo }
847d5c65159SKalle Valo 
84831858805SGovind Singh static int ath11k_ahb_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
849d5c65159SKalle Valo 					  u8 *ul_pipe, u8 *dl_pipe)
850d5c65159SKalle Valo {
851d5c65159SKalle Valo 	const struct service_to_pipe *entry;
852d5c65159SKalle Valo 	bool ul_set = false, dl_set = false;
853d5c65159SKalle Valo 	int i;
854d5c65159SKalle Valo 
855d5c65159SKalle Valo 	for (i = 0; i < ARRAY_SIZE(target_service_to_ce_map_wlan); i++) {
856d5c65159SKalle Valo 		entry = &target_service_to_ce_map_wlan[i];
857d5c65159SKalle Valo 
858d5c65159SKalle Valo 		if (__le32_to_cpu(entry->service_id) != service_id)
859d5c65159SKalle Valo 			continue;
860d5c65159SKalle Valo 
861d5c65159SKalle Valo 		switch (__le32_to_cpu(entry->pipedir)) {
862d5c65159SKalle Valo 		case PIPEDIR_NONE:
863d5c65159SKalle Valo 			break;
864d5c65159SKalle Valo 		case PIPEDIR_IN:
865d5c65159SKalle Valo 			WARN_ON(dl_set);
866d5c65159SKalle Valo 			*dl_pipe = __le32_to_cpu(entry->pipenum);
867d5c65159SKalle Valo 			dl_set = true;
868d5c65159SKalle Valo 			break;
869d5c65159SKalle Valo 		case PIPEDIR_OUT:
870d5c65159SKalle Valo 			WARN_ON(ul_set);
871d5c65159SKalle Valo 			*ul_pipe = __le32_to_cpu(entry->pipenum);
872d5c65159SKalle Valo 			ul_set = true;
873d5c65159SKalle Valo 			break;
874d5c65159SKalle Valo 		case PIPEDIR_INOUT:
875d5c65159SKalle Valo 			WARN_ON(dl_set);
876d5c65159SKalle Valo 			WARN_ON(ul_set);
877d5c65159SKalle Valo 			*dl_pipe = __le32_to_cpu(entry->pipenum);
878d5c65159SKalle Valo 			*ul_pipe = __le32_to_cpu(entry->pipenum);
879d5c65159SKalle Valo 			dl_set = true;
880d5c65159SKalle Valo 			ul_set = true;
881d5c65159SKalle Valo 			break;
882d5c65159SKalle Valo 		}
883d5c65159SKalle Valo 	}
884d5c65159SKalle Valo 
885d5c65159SKalle Valo 	if (WARN_ON(!ul_set || !dl_set))
886d5c65159SKalle Valo 		return -ENOENT;
887d5c65159SKalle Valo 
888d5c65159SKalle Valo 	return 0;
889d5c65159SKalle Valo }
890d5c65159SKalle Valo 
89131858805SGovind Singh static const struct ath11k_hif_ops ath11k_ahb_hif_ops = {
89231858805SGovind Singh 	.start = ath11k_ahb_start,
89331858805SGovind Singh 	.stop = ath11k_ahb_stop,
89431858805SGovind Singh 	.read32 = ath11k_ahb_read32,
89531858805SGovind Singh 	.write32 = ath11k_ahb_write32,
89631858805SGovind Singh 	.irq_enable = ath11k_ahb_ext_irq_enable,
89731858805SGovind Singh 	.irq_disable = ath11k_ahb_ext_irq_disable,
89831858805SGovind Singh 	.map_service_to_pipe = ath11k_ahb_map_service_to_pipe,
89931858805SGovind Singh 	.power_down = ath11k_ahb_power_down,
90031858805SGovind Singh 	.power_up = ath11k_ahb_power_up,
90131858805SGovind Singh };
90231858805SGovind Singh 
903d5c65159SKalle Valo static int ath11k_ahb_probe(struct platform_device *pdev)
904d5c65159SKalle Valo {
905d5c65159SKalle Valo 	struct ath11k_base *ab;
906d5c65159SKalle Valo 	const struct of_device_id *of_id;
907d5c65159SKalle Valo 	struct resource *mem_res;
908d5c65159SKalle Valo 	void __iomem *mem;
909d5c65159SKalle Valo 	int ret;
910d5c65159SKalle Valo 
911d5c65159SKalle Valo 	of_id = of_match_device(ath11k_ahb_of_match, &pdev->dev);
912d5c65159SKalle Valo 	if (!of_id) {
913d5c65159SKalle Valo 		dev_err(&pdev->dev, "failed to find matching device tree id\n");
914d5c65159SKalle Valo 		return -EINVAL;
915d5c65159SKalle Valo 	}
916d5c65159SKalle Valo 
917d5c65159SKalle Valo 	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
918d5c65159SKalle Valo 	if (!mem_res) {
919d5c65159SKalle Valo 		dev_err(&pdev->dev, "failed to get IO memory resource\n");
920d5c65159SKalle Valo 		return -ENXIO;
921d5c65159SKalle Valo 	}
922d5c65159SKalle Valo 
923d5c65159SKalle Valo 	mem = devm_ioremap_resource(&pdev->dev, mem_res);
924d5c65159SKalle Valo 	if (IS_ERR(mem)) {
925d5c65159SKalle Valo 		dev_err(&pdev->dev, "ioremap error\n");
926d5c65159SKalle Valo 		return PTR_ERR(mem);
927d5c65159SKalle Valo 	}
928d5c65159SKalle Valo 
929d5c65159SKalle Valo 	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
930d5c65159SKalle Valo 	if (ret) {
931d5c65159SKalle Valo 		dev_err(&pdev->dev, "failed to set 32-bit consistent dma\n");
932d5c65159SKalle Valo 		return ret;
933d5c65159SKalle Valo 	}
934d5c65159SKalle Valo 
935d5c65159SKalle Valo 	ab = ath11k_core_alloc(&pdev->dev);
936d5c65159SKalle Valo 	if (!ab) {
937d5c65159SKalle Valo 		dev_err(&pdev->dev, "failed to allocate ath11k base\n");
938d5c65159SKalle Valo 		return -ENOMEM;
939d5c65159SKalle Valo 	}
940d5c65159SKalle Valo 
94131858805SGovind Singh 	ab->hif.ops = &ath11k_ahb_hif_ops;
942d5c65159SKalle Valo 	ab->pdev = pdev;
943d5c65159SKalle Valo 	ab->hw_rev = (enum ath11k_hw_rev)of_id->data;
944d5c65159SKalle Valo 	ab->mem = mem;
945d5c65159SKalle Valo 	ab->mem_len = resource_size(mem_res);
946d5c65159SKalle Valo 	platform_set_drvdata(pdev, ab);
947d5c65159SKalle Valo 
948d5c65159SKalle Valo 	ret = ath11k_hal_srng_init(ab);
949d5c65159SKalle Valo 	if (ret)
950d5c65159SKalle Valo 		goto err_core_free;
951d5c65159SKalle Valo 
952d5c65159SKalle Valo 	ret = ath11k_ce_alloc_pipes(ab);
953d5c65159SKalle Valo 	if (ret) {
954d5c65159SKalle Valo 		ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
955d5c65159SKalle Valo 		goto err_hal_srng_deinit;
956d5c65159SKalle Valo 	}
957d5c65159SKalle Valo 
958d5c65159SKalle Valo 	ath11k_ahb_init_qmi_ce_config(ab);
959d5c65159SKalle Valo 
960d5c65159SKalle Valo 	ret = ath11k_ahb_config_irq(ab);
961d5c65159SKalle Valo 	if (ret) {
962d5c65159SKalle Valo 		ath11k_err(ab, "failed to configure irq: %d\n", ret);
963d5c65159SKalle Valo 		goto err_ce_free;
964d5c65159SKalle Valo 	}
965d5c65159SKalle Valo 
966d5c65159SKalle Valo 	ret = ath11k_core_init(ab);
967d5c65159SKalle Valo 	if (ret) {
968d5c65159SKalle Valo 		ath11k_err(ab, "failed to init core: %d\n", ret);
969d5c65159SKalle Valo 		goto err_ce_free;
970d5c65159SKalle Valo 	}
971d5c65159SKalle Valo 
972d5c65159SKalle Valo 	return 0;
973d5c65159SKalle Valo 
974d5c65159SKalle Valo err_ce_free:
975d5c65159SKalle Valo 	ath11k_ce_free_pipes(ab);
976d5c65159SKalle Valo 
977d5c65159SKalle Valo err_hal_srng_deinit:
978d5c65159SKalle Valo 	ath11k_hal_srng_deinit(ab);
979d5c65159SKalle Valo 
980d5c65159SKalle Valo err_core_free:
981d5c65159SKalle Valo 	ath11k_core_free(ab);
982d5c65159SKalle Valo 	platform_set_drvdata(pdev, NULL);
983d5c65159SKalle Valo 
984d5c65159SKalle Valo 	return ret;
985d5c65159SKalle Valo }
986d5c65159SKalle Valo 
987d5c65159SKalle Valo static int ath11k_ahb_remove(struct platform_device *pdev)
988d5c65159SKalle Valo {
989d5c65159SKalle Valo 	struct ath11k_base *ab = platform_get_drvdata(pdev);
990d5c65159SKalle Valo 
991d5c65159SKalle Valo 	reinit_completion(&ab->driver_recovery);
992d5c65159SKalle Valo 
993d5c65159SKalle Valo 	if (test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags))
994d5c65159SKalle Valo 		wait_for_completion_timeout(&ab->driver_recovery,
995d5c65159SKalle Valo 					    ATH11K_AHB_RECOVERY_TIMEOUT);
996d5c65159SKalle Valo 
997d5c65159SKalle Valo 	set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
998d5c65159SKalle Valo 	cancel_work_sync(&ab->restart_work);
999d5c65159SKalle Valo 
1000d5c65159SKalle Valo 	ath11k_core_deinit(ab);
1001d5c65159SKalle Valo 	ath11k_ahb_free_irq(ab);
1002d5c65159SKalle Valo 
1003d5c65159SKalle Valo 	ath11k_hal_srng_deinit(ab);
1004d5c65159SKalle Valo 	ath11k_ce_free_pipes(ab);
1005d5c65159SKalle Valo 	ath11k_core_free(ab);
1006d5c65159SKalle Valo 	platform_set_drvdata(pdev, NULL);
1007d5c65159SKalle Valo 
1008d5c65159SKalle Valo 	return 0;
1009d5c65159SKalle Valo }
1010d5c65159SKalle Valo 
1011d5c65159SKalle Valo static struct platform_driver ath11k_ahb_driver = {
1012d5c65159SKalle Valo 	.driver         = {
1013d5c65159SKalle Valo 		.name   = "ath11k",
1014d5c65159SKalle Valo 		.of_match_table = ath11k_ahb_of_match,
1015d5c65159SKalle Valo 	},
1016d5c65159SKalle Valo 	.probe  = ath11k_ahb_probe,
1017d5c65159SKalle Valo 	.remove = ath11k_ahb_remove,
1018d5c65159SKalle Valo };
1019d5c65159SKalle Valo 
102031858805SGovind Singh static int ath11k_ahb_init(void)
1021d5c65159SKalle Valo {
1022d5c65159SKalle Valo 	return platform_driver_register(&ath11k_ahb_driver);
1023d5c65159SKalle Valo }
102431858805SGovind Singh module_init(ath11k_ahb_init);
1025d5c65159SKalle Valo 
102631858805SGovind Singh static void ath11k_ahb_exit(void)
1027d5c65159SKalle Valo {
1028d5c65159SKalle Valo 	platform_driver_unregister(&ath11k_ahb_driver);
1029d5c65159SKalle Valo }
103031858805SGovind Singh module_exit(ath11k_ahb_exit);
103131858805SGovind Singh 
103231858805SGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax wireless chip");
103331858805SGovind Singh MODULE_LICENSE("Dual BSD/GPL");
1034