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