net: drop the weight argument from netif_napi_add
[linux-2.6-block.git] / drivers / net / wireless / ath / ath11k / pcic.c
CommitLineData
bbfdc5a7
MP
1// SPDX-License-Identifier: BSD-3-Clause-Clear
2/*
3 * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
4 * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
5 */
6
bbfdc5a7
MP
7#include "core.h"
8#include "pcic.h"
9#include "debug.h"
10
11static const char *irq_name[ATH11K_IRQ_NUM_MAX] = {
12 "bhi",
13 "mhi-er0",
14 "mhi-er1",
15 "ce0",
16 "ce1",
17 "ce2",
18 "ce3",
19 "ce4",
20 "ce5",
21 "ce6",
22 "ce7",
23 "ce8",
24 "ce9",
25 "ce10",
26 "ce11",
27 "host2wbm-desc-feed",
28 "host2reo-re-injection",
29 "host2reo-command",
30 "host2rxdma-monitor-ring3",
31 "host2rxdma-monitor-ring2",
32 "host2rxdma-monitor-ring1",
33 "reo2ost-exception",
34 "wbm2host-rx-release",
35 "reo2host-status",
36 "reo2host-destination-ring4",
37 "reo2host-destination-ring3",
38 "reo2host-destination-ring2",
39 "reo2host-destination-ring1",
40 "rxdma2host-monitor-destination-mac3",
41 "rxdma2host-monitor-destination-mac2",
42 "rxdma2host-monitor-destination-mac1",
43 "ppdu-end-interrupts-mac3",
44 "ppdu-end-interrupts-mac2",
45 "ppdu-end-interrupts-mac1",
46 "rxdma2host-monitor-status-ring-mac3",
47 "rxdma2host-monitor-status-ring-mac2",
48 "rxdma2host-monitor-status-ring-mac1",
49 "host2rxdma-host-buf-ring-mac3",
50 "host2rxdma-host-buf-ring-mac2",
51 "host2rxdma-host-buf-ring-mac1",
52 "rxdma2host-destination-ring-mac3",
53 "rxdma2host-destination-ring-mac2",
54 "rxdma2host-destination-ring-mac1",
55 "host2tcl-input-ring4",
56 "host2tcl-input-ring3",
57 "host2tcl-input-ring2",
58 "host2tcl-input-ring1",
59 "wbm2host-tx-completions-ring3",
60 "wbm2host-tx-completions-ring2",
61 "wbm2host-tx-completions-ring1",
62 "tcl2host-status-ring",
63};
64
8d06b802
MP
65static const struct ath11k_msi_config ath11k_msi_config[] = {
66 {
67 .total_vectors = 32,
68 .total_users = 4,
69 .users = (struct ath11k_msi_user[]) {
70 { .name = "MHI", .num_vectors = 3, .base_vector = 0 },
71 { .name = "CE", .num_vectors = 10, .base_vector = 3 },
72 { .name = "WAKE", .num_vectors = 1, .base_vector = 13 },
73 { .name = "DP", .num_vectors = 18, .base_vector = 14 },
74 },
75 .hw_rev = ATH11K_HW_QCA6390_HW20,
76 },
77 {
78 .total_vectors = 16,
79 .total_users = 3,
80 .users = (struct ath11k_msi_user[]) {
81 { .name = "MHI", .num_vectors = 3, .base_vector = 0 },
82 { .name = "CE", .num_vectors = 5, .base_vector = 3 },
83 { .name = "DP", .num_vectors = 8, .base_vector = 8 },
84 },
85 .hw_rev = ATH11K_HW_QCN9074_HW10,
86 },
87 {
88 .total_vectors = 32,
89 .total_users = 4,
90 .users = (struct ath11k_msi_user[]) {
91 { .name = "MHI", .num_vectors = 3, .base_vector = 0 },
92 { .name = "CE", .num_vectors = 10, .base_vector = 3 },
93 { .name = "WAKE", .num_vectors = 1, .base_vector = 13 },
94 { .name = "DP", .num_vectors = 18, .base_vector = 14 },
95 },
96 .hw_rev = ATH11K_HW_WCN6855_HW20,
97 },
98 {
99 .total_vectors = 32,
100 .total_users = 4,
101 .users = (struct ath11k_msi_user[]) {
102 { .name = "MHI", .num_vectors = 3, .base_vector = 0 },
103 { .name = "CE", .num_vectors = 10, .base_vector = 3 },
104 { .name = "WAKE", .num_vectors = 1, .base_vector = 13 },
105 { .name = "DP", .num_vectors = 18, .base_vector = 14 },
106 },
107 .hw_rev = ATH11K_HW_WCN6855_HW21,
108 },
00402f49
MP
109 {
110 .total_vectors = 28,
111 .total_users = 2,
112 .users = (struct ath11k_msi_user[]) {
113 { .name = "CE", .num_vectors = 10, .base_vector = 0 },
114 { .name = "DP", .num_vectors = 18, .base_vector = 10 },
115 },
116 .hw_rev = ATH11K_HW_WCN6750_HW10,
117 },
8d06b802
MP
118};
119
120int ath11k_pcic_init_msi_config(struct ath11k_base *ab)
121{
8d06b802
MP
122 const struct ath11k_msi_config *msi_config;
123 int i;
124
125 for (i = 0; i < ARRAY_SIZE(ath11k_msi_config); i++) {
126 msi_config = &ath11k_msi_config[i];
127
128 if (msi_config->hw_rev == ab->hw_rev)
129 break;
130 }
131
132 if (i == ARRAY_SIZE(ath11k_msi_config)) {
133 ath11k_err(ab, "failed to fetch msi config, unsupported hw version: 0x%x\n",
134 ab->hw_rev);
135 return -EINVAL;
136 }
137
0cfaf224 138 ab->pci.msi.config = msi_config;
8d06b802
MP
139 return 0;
140}
141EXPORT_SYMBOL(ath11k_pcic_init_msi_config);
142
bbfdc5a7
MP
143void ath11k_pcic_write32(struct ath11k_base *ab, u32 offset, u32 value)
144{
bbfdc5a7
MP
145 int ret = 0;
146
147 /* for offset beyond BAR + 4K - 32, may
5b32b6dd 148 * need to wakeup the device to access.
bbfdc5a7 149 */
5b32b6dd
MP
150 if (test_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags) &&
151 offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF && ab->pci.ops->wakeup)
152 ret = ab->pci.ops->wakeup(ab);
bbfdc5a7 153
867f4eee 154 if (offset < ATH11K_PCI_WINDOW_START)
bbfdc5a7 155 iowrite32(value, ab->mem + offset);
867f4eee 156 else
56c8ccf3 157 ab->pci.ops->window_write32(ab, offset, value);
bbfdc5a7 158
5b32b6dd
MP
159 if (test_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags) &&
160 offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF && ab->pci.ops->release &&
bbfdc5a7 161 !ret)
5b32b6dd 162 ab->pci.ops->release(ab);
bbfdc5a7 163}
00402f49 164EXPORT_SYMBOL(ath11k_pcic_write32);
bbfdc5a7
MP
165
166u32 ath11k_pcic_read32(struct ath11k_base *ab, u32 offset)
167{
bbfdc5a7 168 int ret = 0;
867f4eee 169 u32 val;
bbfdc5a7
MP
170
171 /* for offset beyond BAR + 4K - 32, may
5b32b6dd 172 * need to wakeup the device to access.
bbfdc5a7 173 */
5b32b6dd
MP
174 if (test_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags) &&
175 offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF && ab->pci.ops->wakeup)
176 ret = ab->pci.ops->wakeup(ab);
bbfdc5a7 177
867f4eee 178 if (offset < ATH11K_PCI_WINDOW_START)
bbfdc5a7 179 val = ioread32(ab->mem + offset);
867f4eee 180 else
56c8ccf3 181 val = ab->pci.ops->window_read32(ab, offset);
bbfdc5a7 182
5b32b6dd
MP
183 if (test_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags) &&
184 offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF && ab->pci.ops->release &&
bbfdc5a7 185 !ret)
5b32b6dd 186 ab->pci.ops->release(ab);
bbfdc5a7
MP
187
188 return val;
189}
00402f49 190EXPORT_SYMBOL(ath11k_pcic_read32);
bbfdc5a7 191
bbfdc5a7
MP
192void ath11k_pcic_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo,
193 u32 *msi_addr_hi)
194{
0cfaf224
MP
195 *msi_addr_lo = ab->pci.msi.addr_lo;
196 *msi_addr_hi = ab->pci.msi.addr_hi;
bbfdc5a7 197}
00402f49 198EXPORT_SYMBOL(ath11k_pcic_get_msi_address);
bbfdc5a7 199
0cfaf224 200int ath11k_pcic_get_user_msi_assignment(struct ath11k_base *ab, char *user_name,
bbfdc5a7
MP
201 int *num_vectors, u32 *user_base_data,
202 u32 *base_vector)
203{
0cfaf224 204 const struct ath11k_msi_config *msi_config = ab->pci.msi.config;
bbfdc5a7
MP
205 int idx;
206
207 for (idx = 0; idx < msi_config->total_users; idx++) {
208 if (strcmp(user_name, msi_config->users[idx].name) == 0) {
209 *num_vectors = msi_config->users[idx].num_vectors;
210 *base_vector = msi_config->users[idx].base_vector;
0cfaf224 211 *user_base_data = *base_vector + ab->pci.msi.ep_base_data;
bbfdc5a7
MP
212
213 ath11k_dbg(ab, ATH11K_DBG_PCI,
214 "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n",
215 user_name, *num_vectors, *user_base_data,
216 *base_vector);
217
218 return 0;
219 }
220 }
221
222 ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name);
223
224 return -EINVAL;
225}
00402f49 226EXPORT_SYMBOL(ath11k_pcic_get_user_msi_assignment);
bbfdc5a7
MP
227
228void ath11k_pcic_get_ce_msi_idx(struct ath11k_base *ab, u32 ce_id, u32 *msi_idx)
229{
230 u32 i, msi_data_idx;
231
232 for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) {
233 if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
234 continue;
235
236 if (ce_id == i)
237 break;
238
239 msi_data_idx++;
240 }
241 *msi_idx = msi_data_idx;
242}
00402f49 243EXPORT_SYMBOL(ath11k_pcic_get_ce_msi_idx);
bbfdc5a7 244
bbfdc5a7
MP
245static void ath11k_pcic_free_ext_irq(struct ath11k_base *ab)
246{
247 int i, j;
248
249 for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
250 struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
251
252 for (j = 0; j < irq_grp->num_irq; j++)
253 free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp);
254
255 netif_napi_del(&irq_grp->napi);
256 }
257}
258
259void ath11k_pcic_free_irq(struct ath11k_base *ab)
260{
261 int i, irq_idx;
262
263 for (i = 0; i < ab->hw_params.ce_count; i++) {
264 if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
265 continue;
266 irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
267 free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]);
268 }
269
270 ath11k_pcic_free_ext_irq(ab);
271}
00402f49 272EXPORT_SYMBOL(ath11k_pcic_free_irq);
bbfdc5a7
MP
273
274static void ath11k_pcic_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
275{
bbfdc5a7
MP
276 u32 irq_idx;
277
278 /* In case of one MSI vector, we handle irq enable/disable in a
279 * uniform way since we only have one irq
280 */
5b32b6dd 281 if (!test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags))
bbfdc5a7
MP
282 return;
283
284 irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
285 enable_irq(ab->irq_num[irq_idx]);
286}
287
288static void ath11k_pcic_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
289{
bbfdc5a7
MP
290 u32 irq_idx;
291
292 /* In case of one MSI vector, we handle irq enable/disable in a
293 * uniform way since we only have one irq
294 */
5b32b6dd 295 if (!test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags))
bbfdc5a7
MP
296 return;
297
298 irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
299 disable_irq_nosync(ab->irq_num[irq_idx]);
300}
301
302static void ath11k_pcic_ce_irqs_disable(struct ath11k_base *ab)
303{
304 int i;
305
306 clear_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags);
307
308 for (i = 0; i < ab->hw_params.ce_count; i++) {
309 if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
310 continue;
311 ath11k_pcic_ce_irq_disable(ab, i);
312 }
313}
314
315static void ath11k_pcic_sync_ce_irqs(struct ath11k_base *ab)
316{
317 int i;
318 int irq_idx;
319
320 for (i = 0; i < ab->hw_params.ce_count; i++) {
321 if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
322 continue;
323
324 irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
325 synchronize_irq(ab->irq_num[irq_idx]);
326 }
327}
328
329static void ath11k_pcic_ce_tasklet(struct tasklet_struct *t)
330{
331 struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq);
332 int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num;
333
334 ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
335
336 enable_irq(ce_pipe->ab->irq_num[irq_idx]);
337}
338
339static irqreturn_t ath11k_pcic_ce_interrupt_handler(int irq, void *arg)
340{
341 struct ath11k_ce_pipe *ce_pipe = arg;
342 struct ath11k_base *ab = ce_pipe->ab;
343 int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num;
344
345 if (!test_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags))
346 return IRQ_HANDLED;
347
348 /* last interrupt received for this CE */
349 ce_pipe->timestamp = jiffies;
350
351 disable_irq_nosync(ab->irq_num[irq_idx]);
352
353 tasklet_schedule(&ce_pipe->intr_tq);
354
355 return IRQ_HANDLED;
356}
357
358static void ath11k_pcic_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
359{
5b32b6dd 360 struct ath11k_base *ab = irq_grp->ab;
bbfdc5a7
MP
361 int i;
362
363 /* In case of one MSI vector, we handle irq enable/disable
364 * in a uniform way since we only have one irq
365 */
5b32b6dd 366 if (!test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags))
bbfdc5a7
MP
367 return;
368
369 for (i = 0; i < irq_grp->num_irq; i++)
370 disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
371}
372
373static void __ath11k_pcic_ext_irq_disable(struct ath11k_base *sc)
374{
375 int i;
376
377 clear_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &sc->dev_flags);
378
379 for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
380 struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i];
381
382 ath11k_pcic_ext_grp_disable(irq_grp);
383
384 if (irq_grp->napi_enabled) {
385 napi_synchronize(&irq_grp->napi);
386 napi_disable(&irq_grp->napi);
387 irq_grp->napi_enabled = false;
388 }
389 }
390}
391
392static void ath11k_pcic_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
393{
5b32b6dd 394 struct ath11k_base *ab = irq_grp->ab;
bbfdc5a7
MP
395 int i;
396
397 /* In case of one MSI vector, we handle irq enable/disable in a
398 * uniform way since we only have one irq
399 */
5b32b6dd 400 if (!test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags))
bbfdc5a7
MP
401 return;
402
403 for (i = 0; i < irq_grp->num_irq; i++)
404 enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
405}
406
407void ath11k_pcic_ext_irq_enable(struct ath11k_base *ab)
408{
409 int i;
410
411 set_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags);
412
413 for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
414 struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
415
416 if (!irq_grp->napi_enabled) {
417 napi_enable(&irq_grp->napi);
418 irq_grp->napi_enabled = true;
419 }
420 ath11k_pcic_ext_grp_enable(irq_grp);
421 }
422}
00402f49 423EXPORT_SYMBOL(ath11k_pcic_ext_irq_enable);
bbfdc5a7
MP
424
425static void ath11k_pcic_sync_ext_irqs(struct ath11k_base *ab)
426{
427 int i, j, irq_idx;
428
429 for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
430 struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
431
432 for (j = 0; j < irq_grp->num_irq; j++) {
433 irq_idx = irq_grp->irqs[j];
434 synchronize_irq(ab->irq_num[irq_idx]);
435 }
436 }
437}
438
439void ath11k_pcic_ext_irq_disable(struct ath11k_base *ab)
440{
441 __ath11k_pcic_ext_irq_disable(ab);
442 ath11k_pcic_sync_ext_irqs(ab);
443}
00402f49 444EXPORT_SYMBOL(ath11k_pcic_ext_irq_disable);
bbfdc5a7
MP
445
446static int ath11k_pcic_ext_grp_napi_poll(struct napi_struct *napi, int budget)
447{
448 struct ath11k_ext_irq_grp *irq_grp = container_of(napi,
449 struct ath11k_ext_irq_grp,
450 napi);
451 struct ath11k_base *ab = irq_grp->ab;
452 int work_done;
453 int i;
454
455 work_done = ath11k_dp_service_srng(ab, irq_grp, budget);
456 if (work_done < budget) {
457 napi_complete_done(napi, work_done);
458 for (i = 0; i < irq_grp->num_irq; i++)
459 enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
460 }
461
462 if (work_done > budget)
463 work_done = budget;
464
465 return work_done;
466}
467
468static irqreturn_t ath11k_pcic_ext_interrupt_handler(int irq, void *arg)
469{
470 struct ath11k_ext_irq_grp *irq_grp = arg;
471 struct ath11k_base *ab = irq_grp->ab;
472 int i;
473
474 if (!test_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags))
475 return IRQ_HANDLED;
476
477 ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq);
478
479 /* last interrupt received for this group */
480 irq_grp->timestamp = jiffies;
481
482 for (i = 0; i < irq_grp->num_irq; i++)
483 disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
484
485 napi_schedule(&irq_grp->napi);
486
487 return IRQ_HANDLED;
488}
489
5b32b6dd
MP
490static int
491ath11k_pcic_get_msi_irq(struct ath11k_base *ab, unsigned int vector)
492{
5b32b6dd
MP
493 return ab->pci.ops->get_msi_irq(ab, vector);
494}
495
bbfdc5a7
MP
496static int ath11k_pcic_ext_irq_config(struct ath11k_base *ab)
497{
bbfdc5a7
MP
498 int i, j, ret, num_vectors = 0;
499 u32 user_base_data = 0, base_vector = 0;
5b32b6dd 500 unsigned long irq_flags;
bbfdc5a7 501
0cfaf224 502 ret = ath11k_pcic_get_user_msi_assignment(ab, "DP", &num_vectors,
bbfdc5a7
MP
503 &user_base_data,
504 &base_vector);
505 if (ret < 0)
506 return ret;
507
5b32b6dd
MP
508 irq_flags = IRQF_SHARED;
509 if (!test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags))
510 irq_flags |= IRQF_NOBALANCING;
511
bbfdc5a7
MP
512 for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
513 struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
514 u32 num_irq = 0;
515
516 irq_grp->ab = ab;
517 irq_grp->grp_id = i;
518 init_dummy_netdev(&irq_grp->napi_ndev);
519 netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi,
b48b89f9 520 ath11k_pcic_ext_grp_napi_poll);
bbfdc5a7
MP
521
522 if (ab->hw_params.ring_mask->tx[i] ||
523 ab->hw_params.ring_mask->rx[i] ||
524 ab->hw_params.ring_mask->rx_err[i] ||
525 ab->hw_params.ring_mask->rx_wbm_rel[i] ||
526 ab->hw_params.ring_mask->reo_status[i] ||
527 ab->hw_params.ring_mask->rxdma2host[i] ||
528 ab->hw_params.ring_mask->host2rxdma[i] ||
529 ab->hw_params.ring_mask->rx_mon_status[i]) {
530 num_irq = 1;
531 }
532
533 irq_grp->num_irq = num_irq;
534 irq_grp->irqs[0] = ATH11K_PCI_IRQ_DP_OFFSET + i;
535
536 for (j = 0; j < irq_grp->num_irq; j++) {
537 int irq_idx = irq_grp->irqs[j];
538 int vector = (i % num_vectors) + base_vector;
5b32b6dd
MP
539 int irq = ath11k_pcic_get_msi_irq(ab, vector);
540
541 if (irq < 0)
542 return irq;
bbfdc5a7
MP
543
544 ab->irq_num[irq_idx] = irq;
545
546 ath11k_dbg(ab, ATH11K_DBG_PCI,
547 "irq:%d group:%d\n", irq, i);
548
549 irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY);
550 ret = request_irq(irq, ath11k_pcic_ext_interrupt_handler,
5b32b6dd 551 irq_flags, "DP_EXT_IRQ", irq_grp);
bbfdc5a7
MP
552 if (ret) {
553 ath11k_err(ab, "failed request irq %d: %d\n",
554 vector, ret);
555 return ret;
556 }
557 }
558 ath11k_pcic_ext_grp_disable(irq_grp);
559 }
560
561 return 0;
562}
563
bbfdc5a7
MP
564int ath11k_pcic_config_irq(struct ath11k_base *ab)
565{
bbfdc5a7
MP
566 struct ath11k_ce_pipe *ce_pipe;
567 u32 msi_data_start;
568 u32 msi_data_count, msi_data_idx;
569 u32 msi_irq_start;
570 unsigned int msi_data;
571 int irq, i, ret, irq_idx;
5b32b6dd 572 unsigned long irq_flags;
bbfdc5a7 573
0cfaf224 574 ret = ath11k_pcic_get_user_msi_assignment(ab, "CE", &msi_data_count,
bbfdc5a7
MP
575 &msi_data_start, &msi_irq_start);
576 if (ret)
577 return ret;
578
5b32b6dd
MP
579 irq_flags = IRQF_SHARED;
580 if (!test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags))
581 irq_flags |= IRQF_NOBALANCING;
bbfdc5a7
MP
582
583 /* Configure CE irqs */
584 for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) {
585 if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
586 continue;
587
588 msi_data = (msi_data_idx % msi_data_count) + msi_irq_start;
5b32b6dd
MP
589 irq = ath11k_pcic_get_msi_irq(ab, msi_data);
590 if (irq < 0)
591 return irq;
592
bbfdc5a7
MP
593 ce_pipe = &ab->ce.ce_pipe[i];
594
595 irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
596
597 tasklet_setup(&ce_pipe->intr_tq, ath11k_pcic_ce_tasklet);
598
599 ret = request_irq(irq, ath11k_pcic_ce_interrupt_handler,
5b32b6dd 600 irq_flags, irq_name[irq_idx], ce_pipe);
bbfdc5a7
MP
601 if (ret) {
602 ath11k_err(ab, "failed to request irq %d: %d\n",
603 irq_idx, ret);
5b32b6dd 604 return ret;
bbfdc5a7
MP
605 }
606
607 ab->irq_num[irq_idx] = irq;
608 msi_data_idx++;
609
610 ath11k_pcic_ce_irq_disable(ab, i);
611 }
612
613 ret = ath11k_pcic_ext_irq_config(ab);
614 if (ret)
5b32b6dd 615 return ret;
bbfdc5a7
MP
616
617 return 0;
bbfdc5a7 618}
00402f49 619EXPORT_SYMBOL(ath11k_pcic_config_irq);
bbfdc5a7
MP
620
621void ath11k_pcic_ce_irqs_enable(struct ath11k_base *ab)
622{
623 int i;
624
625 set_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags);
626
627 for (i = 0; i < ab->hw_params.ce_count; i++) {
628 if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
629 continue;
630 ath11k_pcic_ce_irq_enable(ab, i);
631 }
632}
00402f49 633EXPORT_SYMBOL(ath11k_pcic_ce_irqs_enable);
bbfdc5a7
MP
634
635static void ath11k_pcic_kill_tasklets(struct ath11k_base *ab)
636{
637 int i;
638
639 for (i = 0; i < ab->hw_params.ce_count; i++) {
640 struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
641
642 if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
643 continue;
644
645 tasklet_kill(&ce_pipe->intr_tq);
646 }
647}
648
649void ath11k_pcic_ce_irq_disable_sync(struct ath11k_base *ab)
650{
651 ath11k_pcic_ce_irqs_disable(ab);
652 ath11k_pcic_sync_ce_irqs(ab);
653 ath11k_pcic_kill_tasklets(ab);
654}
00402f49 655EXPORT_SYMBOL(ath11k_pcic_ce_irq_disable_sync);
bbfdc5a7
MP
656
657void ath11k_pcic_stop(struct ath11k_base *ab)
658{
659 ath11k_pcic_ce_irq_disable_sync(ab);
660 ath11k_ce_cleanup_pipes(ab);
661}
00402f49 662EXPORT_SYMBOL(ath11k_pcic_stop);
bbfdc5a7
MP
663
664int ath11k_pcic_start(struct ath11k_base *ab)
665{
5b32b6dd 666 set_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags);
bbfdc5a7
MP
667
668 ath11k_pcic_ce_irqs_enable(ab);
669 ath11k_ce_rx_post_buf(ab);
670
671 return 0;
672}
00402f49 673EXPORT_SYMBOL(ath11k_pcic_start);
bbfdc5a7
MP
674
675int ath11k_pcic_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
676 u8 *ul_pipe, u8 *dl_pipe)
677{
678 const struct service_to_pipe *entry;
679 bool ul_set = false, dl_set = false;
680 int i;
681
682 for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) {
683 entry = &ab->hw_params.svc_to_ce_map[i];
684
685 if (__le32_to_cpu(entry->service_id) != service_id)
686 continue;
687
688 switch (__le32_to_cpu(entry->pipedir)) {
689 case PIPEDIR_NONE:
690 break;
691 case PIPEDIR_IN:
692 WARN_ON(dl_set);
693 *dl_pipe = __le32_to_cpu(entry->pipenum);
694 dl_set = true;
695 break;
696 case PIPEDIR_OUT:
697 WARN_ON(ul_set);
698 *ul_pipe = __le32_to_cpu(entry->pipenum);
699 ul_set = true;
700 break;
701 case PIPEDIR_INOUT:
702 WARN_ON(dl_set);
703 WARN_ON(ul_set);
704 *dl_pipe = __le32_to_cpu(entry->pipenum);
705 *ul_pipe = __le32_to_cpu(entry->pipenum);
706 dl_set = true;
707 ul_set = true;
708 break;
709 }
710 }
711
712 if (WARN_ON(!ul_set || !dl_set))
713 return -ENOENT;
714
715 return 0;
716}
00402f49 717EXPORT_SYMBOL(ath11k_pcic_map_service_to_pipe);
867f4eee
MP
718
719int ath11k_pcic_register_pci_ops(struct ath11k_base *ab,
720 const struct ath11k_pci_ops *pci_ops)
721{
722 if (!pci_ops)
723 return 0;
724
725 /* Return error if mandatory pci_ops callbacks are missing */
726 if (!pci_ops->get_msi_irq || !pci_ops->window_write32 ||
727 !pci_ops->window_read32)
728 return -EINVAL;
729
730 ab->pci.ops = pci_ops;
731 return 0;
732}
733EXPORT_SYMBOL(ath11k_pcic_register_pci_ops);