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