1*5113495bSYour Name /*
2*5113495bSYour Name * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved.
3*5113495bSYour Name * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4*5113495bSYour Name *
5*5113495bSYour Name * Permission to use, copy, modify, and/or distribute this software for any
6*5113495bSYour Name * purpose with or without fee is hereby granted, provided that the above
7*5113495bSYour Name * copyright notice and this permission notice appear in all copies.
8*5113495bSYour Name
9*5113495bSYour Name * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10*5113495bSYour Name * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11*5113495bSYour Name * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12*5113495bSYour Name * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13*5113495bSYour Name * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14*5113495bSYour Name * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15*5113495bSYour Name * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16*5113495bSYour Name */
17*5113495bSYour Name
18*5113495bSYour Name #include <linux/slab.h>
19*5113495bSYour Name #include <linux/interrupt.h>
20*5113495bSYour Name #include <linux/if_arp.h>
21*5113495bSYour Name #include "hif_io32.h"
22*5113495bSYour Name #include "if_ipci.h"
23*5113495bSYour Name #include "hif.h"
24*5113495bSYour Name #include "target_type.h"
25*5113495bSYour Name #include "hif_main.h"
26*5113495bSYour Name #include "ce_main.h"
27*5113495bSYour Name #include "ce_api.h"
28*5113495bSYour Name #include "ce_internal.h"
29*5113495bSYour Name #include "ce_reg.h"
30*5113495bSYour Name #include "ce_bmi.h"
31*5113495bSYour Name #include "regtable.h"
32*5113495bSYour Name #include "hif_hw_version.h"
33*5113495bSYour Name #include <linux/debugfs.h>
34*5113495bSYour Name #include <linux/seq_file.h>
35*5113495bSYour Name #include "qdf_status.h"
36*5113495bSYour Name #include "qdf_atomic.h"
37*5113495bSYour Name #include "pld_common.h"
38*5113495bSYour Name #include "mp_dev.h"
39*5113495bSYour Name #include "hif_debug.h"
40*5113495bSYour Name
41*5113495bSYour Name #include "ce_tasklet.h"
42*5113495bSYour Name #include "targaddrs.h"
43*5113495bSYour Name #include "hif_exec.h"
44*5113495bSYour Name
45*5113495bSYour Name #include "ipci_api.h"
46*5113495bSYour Name
hif_ipci_enable_power_management(struct hif_softc * hif_sc,bool is_packet_log_enabled)47*5113495bSYour Name void hif_ipci_enable_power_management(struct hif_softc *hif_sc,
48*5113495bSYour Name bool is_packet_log_enabled)
49*5113495bSYour Name {
50*5113495bSYour Name hif_rtpm_start(hif_sc);
51*5113495bSYour Name }
52*5113495bSYour Name
hif_ipci_disable_power_management(struct hif_softc * hif_ctx)53*5113495bSYour Name void hif_ipci_disable_power_management(struct hif_softc *hif_ctx)
54*5113495bSYour Name {
55*5113495bSYour Name hif_rtpm_stop(hif_ctx);
56*5113495bSYour Name }
57*5113495bSYour Name
hif_ipci_display_stats(struct hif_softc * hif_ctx)58*5113495bSYour Name void hif_ipci_display_stats(struct hif_softc *hif_ctx)
59*5113495bSYour Name {
60*5113495bSYour Name hif_display_ce_stats(hif_ctx);
61*5113495bSYour Name }
62*5113495bSYour Name
hif_ipci_clear_stats(struct hif_softc * hif_ctx)63*5113495bSYour Name void hif_ipci_clear_stats(struct hif_softc *hif_ctx)
64*5113495bSYour Name {
65*5113495bSYour Name struct hif_ipci_softc *ipci_ctx = HIF_GET_IPCI_SOFTC(hif_ctx);
66*5113495bSYour Name
67*5113495bSYour Name if (!ipci_ctx) {
68*5113495bSYour Name hif_err("hif_ctx null");
69*5113495bSYour Name return;
70*5113495bSYour Name }
71*5113495bSYour Name hif_clear_ce_stats(&ipci_ctx->ce_sc);
72*5113495bSYour Name }
73*5113495bSYour Name
hif_ipci_open(struct hif_softc * hif_ctx,enum qdf_bus_type bus_type)74*5113495bSYour Name QDF_STATUS hif_ipci_open(struct hif_softc *hif_ctx, enum qdf_bus_type bus_type)
75*5113495bSYour Name {
76*5113495bSYour Name struct hif_ipci_softc *sc = HIF_GET_IPCI_SOFTC(hif_ctx);
77*5113495bSYour Name
78*5113495bSYour Name hif_ctx->bus_type = bus_type;
79*5113495bSYour Name hif_rtpm_open(hif_ctx);
80*5113495bSYour Name
81*5113495bSYour Name qdf_spinlock_create(&sc->irq_lock);
82*5113495bSYour Name
83*5113495bSYour Name return hif_ce_open(hif_ctx);
84*5113495bSYour Name }
85*5113495bSYour Name
86*5113495bSYour Name /**
87*5113495bSYour Name * hif_ce_msi_map_ce_to_irq() - map CE to IRQ
88*5113495bSYour Name * @scn: hif context
89*5113495bSYour Name * @ce_id: CE Id
90*5113495bSYour Name *
91*5113495bSYour Name * Return: IRQ number
92*5113495bSYour Name */
hif_ce_msi_map_ce_to_irq(struct hif_softc * scn,int ce_id)93*5113495bSYour Name static int hif_ce_msi_map_ce_to_irq(struct hif_softc *scn, int ce_id)
94*5113495bSYour Name {
95*5113495bSYour Name struct hif_ipci_softc *ipci_scn = HIF_GET_IPCI_SOFTC(scn);
96*5113495bSYour Name
97*5113495bSYour Name return ipci_scn->ce_msi_irq_num[ce_id];
98*5113495bSYour Name }
99*5113495bSYour Name
hif_ipci_bus_configure(struct hif_softc * hif_sc)100*5113495bSYour Name int hif_ipci_bus_configure(struct hif_softc *hif_sc)
101*5113495bSYour Name {
102*5113495bSYour Name int status = 0;
103*5113495bSYour Name uint8_t wake_ce_id;
104*5113495bSYour Name
105*5113495bSYour Name hif_ce_prepare_config(hif_sc);
106*5113495bSYour Name
107*5113495bSYour Name status = hif_wlan_enable(hif_sc);
108*5113495bSYour Name if (status) {
109*5113495bSYour Name hif_err("hif_wlan_enable error = %d", status);
110*5113495bSYour Name return status;
111*5113495bSYour Name }
112*5113495bSYour Name
113*5113495bSYour Name A_TARGET_ACCESS_LIKELY(hif_sc);
114*5113495bSYour Name
115*5113495bSYour Name status = hif_config_ce(hif_sc);
116*5113495bSYour Name if (status)
117*5113495bSYour Name goto disable_wlan;
118*5113495bSYour Name
119*5113495bSYour Name status = hif_get_wake_ce_id(hif_sc, &wake_ce_id);
120*5113495bSYour Name if (status)
121*5113495bSYour Name goto unconfig_ce;
122*5113495bSYour Name
123*5113495bSYour Name status = hif_configure_irq(hif_sc);
124*5113495bSYour Name if (status < 0)
125*5113495bSYour Name goto unconfig_ce;
126*5113495bSYour Name
127*5113495bSYour Name hif_sc->wake_irq = hif_ce_msi_map_ce_to_irq(hif_sc, wake_ce_id);
128*5113495bSYour Name hif_sc->wake_irq_type = HIF_PM_CE_WAKE;
129*5113495bSYour Name
130*5113495bSYour Name hif_info("expecting wake from ce %d, irq %d",
131*5113495bSYour Name wake_ce_id, hif_sc->wake_irq);
132*5113495bSYour Name
133*5113495bSYour Name A_TARGET_ACCESS_UNLIKELY(hif_sc);
134*5113495bSYour Name
135*5113495bSYour Name return status;
136*5113495bSYour Name
137*5113495bSYour Name unconfig_ce:
138*5113495bSYour Name hif_unconfig_ce(hif_sc);
139*5113495bSYour Name disable_wlan:
140*5113495bSYour Name A_TARGET_ACCESS_UNLIKELY(hif_sc);
141*5113495bSYour Name hif_wlan_disable(hif_sc);
142*5113495bSYour Name
143*5113495bSYour Name hif_err("Failed, status = %d", status);
144*5113495bSYour Name return status;
145*5113495bSYour Name }
146*5113495bSYour Name
hif_ipci_close(struct hif_softc * hif_sc)147*5113495bSYour Name void hif_ipci_close(struct hif_softc *hif_sc)
148*5113495bSYour Name {
149*5113495bSYour Name hif_rtpm_close(hif_sc);
150*5113495bSYour Name hif_ce_close(hif_sc);
151*5113495bSYour Name }
152*5113495bSYour Name
153*5113495bSYour Name /**
154*5113495bSYour Name * hif_ce_srng_msi_free_irq(): free CE msi IRQ
155*5113495bSYour Name * @scn: struct hif_softc
156*5113495bSYour Name *
157*5113495bSYour Name * Return: ErrorNo
158*5113495bSYour Name */
hif_ce_srng_msi_free_irq(struct hif_softc * scn)159*5113495bSYour Name static int hif_ce_srng_msi_free_irq(struct hif_softc *scn)
160*5113495bSYour Name {
161*5113495bSYour Name int ret;
162*5113495bSYour Name int ce_id, irq;
163*5113495bSYour Name uint32_t msi_data_start;
164*5113495bSYour Name uint32_t msi_data_count;
165*5113495bSYour Name uint32_t msi_irq_start;
166*5113495bSYour Name struct HIF_CE_state *ce_sc = HIF_GET_CE_STATE(scn);
167*5113495bSYour Name
168*5113495bSYour Name ret = pld_get_user_msi_assignment(scn->qdf_dev->dev, "CE",
169*5113495bSYour Name &msi_data_count, &msi_data_start,
170*5113495bSYour Name &msi_irq_start);
171*5113495bSYour Name if (ret)
172*5113495bSYour Name return ret;
173*5113495bSYour Name
174*5113495bSYour Name /* needs to match the ce_id -> irq data mapping
175*5113495bSYour Name * used in the srng parameter configuration
176*5113495bSYour Name */
177*5113495bSYour Name for (ce_id = 0; ce_id < scn->ce_count; ce_id++) {
178*5113495bSYour Name unsigned int msi_data;
179*5113495bSYour Name
180*5113495bSYour Name if (!ce_sc->tasklets[ce_id].inited)
181*5113495bSYour Name continue;
182*5113495bSYour Name
183*5113495bSYour Name msi_data = (ce_id % msi_data_count) + msi_irq_start;
184*5113495bSYour Name irq = pld_get_msi_irq(scn->qdf_dev->dev, msi_data);
185*5113495bSYour Name
186*5113495bSYour Name hif_ce_irq_remove_affinity_hint(irq);
187*5113495bSYour Name
188*5113495bSYour Name hif_debug("%s: (ce_id %d, msi_data %d, irq %d)", __func__,
189*5113495bSYour Name ce_id, msi_data, irq);
190*5113495bSYour Name
191*5113495bSYour Name pfrm_free_irq(scn->qdf_dev->dev, irq, &ce_sc->tasklets[ce_id]);
192*5113495bSYour Name }
193*5113495bSYour Name
194*5113495bSYour Name return ret;
195*5113495bSYour Name }
196*5113495bSYour Name
197*5113495bSYour Name /**
198*5113495bSYour Name * hif_ipci_deconfigure_grp_irq(): deconfigure HW block IRQ
199*5113495bSYour Name * @scn: struct hif_softc
200*5113495bSYour Name *
201*5113495bSYour Name * Return: none
202*5113495bSYour Name */
hif_ipci_deconfigure_grp_irq(struct hif_softc * scn)203*5113495bSYour Name void hif_ipci_deconfigure_grp_irq(struct hif_softc *scn)
204*5113495bSYour Name {
205*5113495bSYour Name int i, j, irq;
206*5113495bSYour Name struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
207*5113495bSYour Name struct hif_exec_context *hif_ext_group;
208*5113495bSYour Name
209*5113495bSYour Name for (i = 0; i < hif_state->hif_num_extgroup; i++) {
210*5113495bSYour Name hif_ext_group = hif_state->hif_ext_group[i];
211*5113495bSYour Name if (hif_ext_group->irq_requested) {
212*5113495bSYour Name hif_ext_group->irq_requested = false;
213*5113495bSYour Name for (j = 0; j < hif_ext_group->numirq; j++) {
214*5113495bSYour Name irq = hif_ext_group->os_irq[j];
215*5113495bSYour Name pfrm_free_irq(scn->qdf_dev->dev,
216*5113495bSYour Name irq, hif_ext_group);
217*5113495bSYour Name }
218*5113495bSYour Name hif_ext_group->numirq = 0;
219*5113495bSYour Name }
220*5113495bSYour Name }
221*5113495bSYour Name }
222*5113495bSYour Name
hif_ipci_nointrs(struct hif_softc * scn)223*5113495bSYour Name void hif_ipci_nointrs(struct hif_softc *scn)
224*5113495bSYour Name {
225*5113495bSYour Name int ret;
226*5113495bSYour Name struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
227*5113495bSYour Name
228*5113495bSYour Name scn->free_irq_done = true;
229*5113495bSYour Name ce_unregister_irq(hif_state, CE_ALL_BITMAP);
230*5113495bSYour Name
231*5113495bSYour Name if (scn->request_irq_done == false)
232*5113495bSYour Name return;
233*5113495bSYour Name
234*5113495bSYour Name hif_ipci_deconfigure_grp_irq(scn);
235*5113495bSYour Name
236*5113495bSYour Name ret = hif_ce_srng_msi_free_irq(scn);
237*5113495bSYour Name
238*5113495bSYour Name scn->request_irq_done = false;
239*5113495bSYour Name }
240*5113495bSYour Name
hif_ipci_disable_bus(struct hif_softc * scn)241*5113495bSYour Name void hif_ipci_disable_bus(struct hif_softc *scn)
242*5113495bSYour Name {
243*5113495bSYour Name struct hif_ipci_softc *sc = HIF_GET_IPCI_SOFTC(scn);
244*5113495bSYour Name void __iomem *mem;
245*5113495bSYour Name
246*5113495bSYour Name /* Attach did not succeed, all resources have been
247*5113495bSYour Name * freed in error handler
248*5113495bSYour Name */
249*5113495bSYour Name if (!sc)
250*5113495bSYour Name return;
251*5113495bSYour Name
252*5113495bSYour Name mem = (void __iomem *)sc->mem;
253*5113495bSYour Name if (mem) {
254*5113495bSYour Name hif_dump_pipe_debug_count(scn);
255*5113495bSYour Name if (scn->athdiag_procfs_inited) {
256*5113495bSYour Name athdiag_procfs_remove();
257*5113495bSYour Name scn->athdiag_procfs_inited = false;
258*5113495bSYour Name }
259*5113495bSYour Name scn->mem = NULL;
260*5113495bSYour Name }
261*5113495bSYour Name hif_info("X");
262*5113495bSYour Name }
263*5113495bSYour Name
264*5113495bSYour Name #ifdef CONFIG_PLD_PCIE_CNSS
hif_ipci_prevent_linkdown(struct hif_softc * scn,bool flag)265*5113495bSYour Name void hif_ipci_prevent_linkdown(struct hif_softc *scn, bool flag)
266*5113495bSYour Name {
267*5113495bSYour Name int errno;
268*5113495bSYour Name
269*5113495bSYour Name hif_info("wlan: %s pcie power collapse", flag ? "disable" : "enable");
270*5113495bSYour Name hif_runtime_prevent_linkdown(scn, flag);
271*5113495bSYour Name
272*5113495bSYour Name errno = pld_wlan_pm_control(scn->qdf_dev->dev, flag);
273*5113495bSYour Name if (errno)
274*5113495bSYour Name hif_err("Failed pld_wlan_pm_control; errno %d", errno);
275*5113495bSYour Name }
276*5113495bSYour Name #else
hif_ipci_prevent_linkdown(struct hif_softc * scn,bool flag)277*5113495bSYour Name void hif_ipci_prevent_linkdown(struct hif_softc *scn, bool flag)
278*5113495bSYour Name {
279*5113495bSYour Name }
280*5113495bSYour Name #endif
281*5113495bSYour Name
hif_ipci_bus_suspend(struct hif_softc * scn)282*5113495bSYour Name int hif_ipci_bus_suspend(struct hif_softc *scn)
283*5113495bSYour Name {
284*5113495bSYour Name int ret;
285*5113495bSYour Name
286*5113495bSYour Name ret = hif_apps_disable_irqs_except_wake_irq(GET_HIF_OPAQUE_HDL(scn));
287*5113495bSYour Name if (ret) {
288*5113495bSYour Name hif_err("Failed to disable IRQs");
289*5113495bSYour Name goto disable_irq_fail;
290*5113495bSYour Name }
291*5113495bSYour Name
292*5113495bSYour Name ret = hif_apps_enable_irq_wake(GET_HIF_OPAQUE_HDL(scn));
293*5113495bSYour Name if (ret) {
294*5113495bSYour Name hif_err("Failed to enable Wake-IRQ");
295*5113495bSYour Name goto enable_wake_irq_fail;
296*5113495bSYour Name }
297*5113495bSYour Name
298*5113495bSYour Name if (QDF_IS_STATUS_ERROR(hif_try_complete_tasks(scn))) {
299*5113495bSYour Name hif_err("hif_try_complete_tasks timed-out, so abort suspend");
300*5113495bSYour Name ret = -EBUSY;
301*5113495bSYour Name goto drain_tasks_fail;
302*5113495bSYour Name }
303*5113495bSYour Name
304*5113495bSYour Name /*
305*5113495bSYour Name * In an unlikely case, if draining becomes infinite loop,
306*5113495bSYour Name * it returns an error, shall abort the bus suspend.
307*5113495bSYour Name */
308*5113495bSYour Name ret = hif_drain_fw_diag_ce(scn);
309*5113495bSYour Name if (ret) {
310*5113495bSYour Name hif_err("draining fw_diag_ce goes infinite, so abort suspend");
311*5113495bSYour Name goto drain_tasks_fail;
312*5113495bSYour Name }
313*5113495bSYour Name
314*5113495bSYour Name scn->bus_suspended = true;
315*5113495bSYour Name
316*5113495bSYour Name return 0;
317*5113495bSYour Name
318*5113495bSYour Name drain_tasks_fail:
319*5113495bSYour Name hif_apps_disable_irq_wake(GET_HIF_OPAQUE_HDL(scn));
320*5113495bSYour Name
321*5113495bSYour Name enable_wake_irq_fail:
322*5113495bSYour Name hif_apps_enable_irqs_except_wake_irq(GET_HIF_OPAQUE_HDL(scn));
323*5113495bSYour Name
324*5113495bSYour Name disable_irq_fail:
325*5113495bSYour Name return ret;
326*5113495bSYour Name }
327*5113495bSYour Name
hif_ipci_bus_resume(struct hif_softc * scn)328*5113495bSYour Name int hif_ipci_bus_resume(struct hif_softc *scn)
329*5113495bSYour Name {
330*5113495bSYour Name int ret = 0;
331*5113495bSYour Name
332*5113495bSYour Name ret = hif_apps_disable_irq_wake(GET_HIF_OPAQUE_HDL(scn));
333*5113495bSYour Name if (ret) {
334*5113495bSYour Name hif_err("Failed to disable Wake-IRQ");
335*5113495bSYour Name goto fail;
336*5113495bSYour Name }
337*5113495bSYour Name
338*5113495bSYour Name ret = hif_apps_enable_irqs_except_wake_irq(GET_HIF_OPAQUE_HDL(scn));
339*5113495bSYour Name if (ret)
340*5113495bSYour Name hif_err("Failed to enable IRQs");
341*5113495bSYour Name
342*5113495bSYour Name scn->bus_suspended = false;
343*5113495bSYour Name
344*5113495bSYour Name fail:
345*5113495bSYour Name return ret;
346*5113495bSYour Name }
347*5113495bSYour Name
hif_ipci_bus_suspend_noirq(struct hif_softc * scn)348*5113495bSYour Name int hif_ipci_bus_suspend_noirq(struct hif_softc *scn)
349*5113495bSYour Name {
350*5113495bSYour Name /*
351*5113495bSYour Name * If it is system suspend case and wake-IRQ received
352*5113495bSYour Name * just before Kernel issuing suspend_noirq, that must
353*5113495bSYour Name * have scheduled CE2 tasklet, so suspend activity can
354*5113495bSYour Name * be aborted.
355*5113495bSYour Name * Similar scenario for runtime suspend case, would be
356*5113495bSYour Name * handled by hif_rtpm_check_and_request_resume
357*5113495bSYour Name * in hif_ce_interrupt_handler.
358*5113495bSYour Name *
359*5113495bSYour Name */
360*5113495bSYour Name if (!hif_rtpm_get_monitor_wake_intr() &&
361*5113495bSYour Name hif_get_num_active_tasklets(scn)) {
362*5113495bSYour Name hif_err("Tasklets are pending, abort sys suspend_noirq");
363*5113495bSYour Name return -EBUSY;
364*5113495bSYour Name }
365*5113495bSYour Name
366*5113495bSYour Name return 0;
367*5113495bSYour Name }
368*5113495bSYour Name
hif_ipci_bus_resume_noirq(struct hif_softc * scn)369*5113495bSYour Name int hif_ipci_bus_resume_noirq(struct hif_softc *scn)
370*5113495bSYour Name {
371*5113495bSYour Name return 0;
372*5113495bSYour Name }
373*5113495bSYour Name
hif_ipci_disable_isr(struct hif_softc * scn)374*5113495bSYour Name void hif_ipci_disable_isr(struct hif_softc *scn)
375*5113495bSYour Name {
376*5113495bSYour Name struct hif_ipci_softc *sc = HIF_GET_IPCI_SOFTC(scn);
377*5113495bSYour Name
378*5113495bSYour Name hif_exec_kill(&scn->osc);
379*5113495bSYour Name hif_nointrs(scn);
380*5113495bSYour Name /* Cancel the pending tasklet */
381*5113495bSYour Name ce_tasklet_kill(scn);
382*5113495bSYour Name tasklet_kill(&sc->intr_tq);
383*5113495bSYour Name qdf_atomic_set(&scn->active_tasklet_cnt, 0);
384*5113495bSYour Name qdf_atomic_set(&scn->active_grp_tasklet_cnt, 0);
385*5113495bSYour Name }
386*5113495bSYour Name
hif_ipci_dump_registers(struct hif_softc * hif_ctx)387*5113495bSYour Name int hif_ipci_dump_registers(struct hif_softc *hif_ctx)
388*5113495bSYour Name {
389*5113495bSYour Name int status;
390*5113495bSYour Name struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
391*5113495bSYour Name
392*5113495bSYour Name status = hif_dump_ce_registers(scn);
393*5113495bSYour Name
394*5113495bSYour Name if (status)
395*5113495bSYour Name hif_err("Dump CE Registers Failed");
396*5113495bSYour Name
397*5113495bSYour Name return 0;
398*5113495bSYour Name }
399*5113495bSYour Name
400*5113495bSYour Name /**
401*5113495bSYour Name * hif_ce_interrupt_handler() - interrupt handler for copy engine
402*5113495bSYour Name * @irq: irq number
403*5113495bSYour Name * @context: tasklet context
404*5113495bSYour Name *
405*5113495bSYour Name * Return: irqreturn_t
406*5113495bSYour Name */
hif_ce_interrupt_handler(int irq,void * context)407*5113495bSYour Name static irqreturn_t hif_ce_interrupt_handler(int irq, void *context)
408*5113495bSYour Name {
409*5113495bSYour Name struct ce_tasklet_entry *tasklet_entry = context;
410*5113495bSYour Name
411*5113495bSYour Name hif_rtpm_check_and_request_resume(false);
412*5113495bSYour Name return ce_dispatch_interrupt(tasklet_entry->ce_id, tasklet_entry);
413*5113495bSYour Name }
414*5113495bSYour Name
415*5113495bSYour Name extern const char *ce_name[];
416*5113495bSYour Name
417*5113495bSYour Name /* hif_ce_srng_msi_irq_disable() - disable the irq for msi
418*5113495bSYour Name * @hif_sc: hif context
419*5113495bSYour Name * @ce_id: which ce to disable copy complete interrupts for
420*5113495bSYour Name *
421*5113495bSYour Name * @Return: none
422*5113495bSYour Name */
hif_ce_srng_msi_irq_disable(struct hif_softc * hif_sc,int ce_id)423*5113495bSYour Name static void hif_ce_srng_msi_irq_disable(struct hif_softc *hif_sc, int ce_id)
424*5113495bSYour Name {
425*5113495bSYour Name pfrm_disable_irq_nosync(hif_sc->qdf_dev->dev,
426*5113495bSYour Name hif_ce_msi_map_ce_to_irq(hif_sc, ce_id));
427*5113495bSYour Name
428*5113495bSYour Name }
429*5113495bSYour Name
430*5113495bSYour Name /* hif_ce_srng_msi_irq_enable() - enable the irq for msi
431*5113495bSYour Name * @hif_sc: hif context
432*5113495bSYour Name * @ce_id: which ce to enable copy complete interrupts for
433*5113495bSYour Name *
434*5113495bSYour Name * @Return: none
435*5113495bSYour Name */
hif_ce_srng_msi_irq_enable(struct hif_softc * hif_sc,int ce_id)436*5113495bSYour Name static void hif_ce_srng_msi_irq_enable(struct hif_softc *hif_sc, int ce_id)
437*5113495bSYour Name {
438*5113495bSYour Name pfrm_enable_irq(hif_sc->qdf_dev->dev,
439*5113495bSYour Name hif_ce_msi_map_ce_to_irq(hif_sc, ce_id));
440*5113495bSYour Name
441*5113495bSYour Name }
442*5113495bSYour Name
443*5113495bSYour Name /* hif_ce_msi_configure_irq() - configure the irq
444*5113495bSYour Name * @scn: hif context
445*5113495bSYour Name *
446*5113495bSYour Name * @Return: none
447*5113495bSYour Name */
hif_ce_msi_configure_irq(struct hif_softc * scn)448*5113495bSYour Name static int hif_ce_msi_configure_irq(struct hif_softc *scn)
449*5113495bSYour Name {
450*5113495bSYour Name int ret;
451*5113495bSYour Name int ce_id, irq;
452*5113495bSYour Name uint32_t msi_data_start;
453*5113495bSYour Name uint32_t msi_data_count;
454*5113495bSYour Name uint32_t msi_irq_start;
455*5113495bSYour Name struct HIF_CE_state *ce_sc = HIF_GET_CE_STATE(scn);
456*5113495bSYour Name struct hif_ipci_softc *ipci_sc = HIF_GET_IPCI_SOFTC(scn);
457*5113495bSYour Name uint8_t wake_ce_id;
458*5113495bSYour Name
459*5113495bSYour Name ret = hif_get_wake_ce_id(scn, &wake_ce_id);
460*5113495bSYour Name if (ret)
461*5113495bSYour Name return ret;
462*5113495bSYour Name
463*5113495bSYour Name /* do ce irq assignments */
464*5113495bSYour Name ret = pld_get_user_msi_assignment(scn->qdf_dev->dev, "CE",
465*5113495bSYour Name &msi_data_count, &msi_data_start,
466*5113495bSYour Name &msi_irq_start);
467*5113495bSYour Name if (ret)
468*5113495bSYour Name return ret;
469*5113495bSYour Name
470*5113495bSYour Name scn->bus_ops.hif_irq_disable = &hif_ce_srng_msi_irq_disable;
471*5113495bSYour Name scn->bus_ops.hif_irq_enable = &hif_ce_srng_msi_irq_enable;
472*5113495bSYour Name scn->bus_ops.hif_map_ce_to_irq = &hif_ce_msi_map_ce_to_irq;
473*5113495bSYour Name
474*5113495bSYour Name /* needs to match the ce_id -> irq data mapping
475*5113495bSYour Name * used in the srng parameter configuration
476*5113495bSYour Name */
477*5113495bSYour Name for (ce_id = 0; ce_id < scn->ce_count; ce_id++) {
478*5113495bSYour Name unsigned long irqflags = IRQF_SHARED;
479*5113495bSYour Name unsigned int msi_data = (ce_id % msi_data_count) +
480*5113495bSYour Name msi_irq_start;
481*5113495bSYour Name irq = pld_get_msi_irq(scn->qdf_dev->dev, msi_data);
482*5113495bSYour Name hif_debug("(ce_id %d, msi_data %d, irq %d tasklet %pK)",
483*5113495bSYour Name ce_id, msi_data, irq,
484*5113495bSYour Name &ce_sc->tasklets[ce_id]);
485*5113495bSYour Name
486*5113495bSYour Name /* implies the ce is also initialized */
487*5113495bSYour Name if (!ce_sc->tasklets[ce_id].inited)
488*5113495bSYour Name continue;
489*5113495bSYour Name
490*5113495bSYour Name ipci_sc->ce_msi_irq_num[ce_id] = irq;
491*5113495bSYour Name ret = pfrm_request_irq(scn->qdf_dev->dev,
492*5113495bSYour Name irq, hif_ce_interrupt_handler,
493*5113495bSYour Name irqflags,
494*5113495bSYour Name ce_name[ce_id],
495*5113495bSYour Name &ce_sc->tasklets[ce_id]);
496*5113495bSYour Name if (ret)
497*5113495bSYour Name goto free_irq;
498*5113495bSYour Name }
499*5113495bSYour Name
500*5113495bSYour Name return ret;
501*5113495bSYour Name
502*5113495bSYour Name free_irq:
503*5113495bSYour Name /* the request_irq for the last ce_id failed so skip it. */
504*5113495bSYour Name while (ce_id > 0 && ce_id < scn->ce_count) {
505*5113495bSYour Name unsigned int msi_data;
506*5113495bSYour Name
507*5113495bSYour Name ce_id--;
508*5113495bSYour Name msi_data = (ce_id % msi_data_count) + msi_irq_start;
509*5113495bSYour Name irq = pld_get_msi_irq(scn->qdf_dev->dev, msi_data);
510*5113495bSYour Name pfrm_free_irq(scn->qdf_dev->dev, irq, &ce_sc->tasklets[ce_id]);
511*5113495bSYour Name }
512*5113495bSYour Name
513*5113495bSYour Name return ret;
514*5113495bSYour Name }
515*5113495bSYour Name
516*5113495bSYour Name /**
517*5113495bSYour Name * hif_exec_grp_irq_disable() - disable the irq for group
518*5113495bSYour Name * @hif_ext_group: hif exec context
519*5113495bSYour Name *
520*5113495bSYour Name * Return: none
521*5113495bSYour Name */
hif_exec_grp_irq_disable(struct hif_exec_context * hif_ext_group)522*5113495bSYour Name static void hif_exec_grp_irq_disable(struct hif_exec_context *hif_ext_group)
523*5113495bSYour Name {
524*5113495bSYour Name int i;
525*5113495bSYour Name struct hif_softc *scn = HIF_GET_SOFTC(hif_ext_group->hif);
526*5113495bSYour Name
527*5113495bSYour Name for (i = 0; i < hif_ext_group->numirq; i++)
528*5113495bSYour Name pfrm_disable_irq_nosync(scn->qdf_dev->dev,
529*5113495bSYour Name hif_ext_group->os_irq[i]);
530*5113495bSYour Name }
531*5113495bSYour Name
532*5113495bSYour Name /**
533*5113495bSYour Name * hif_exec_grp_irq_enable() - enable the irq for group
534*5113495bSYour Name * @hif_ext_group: hif exec context
535*5113495bSYour Name *
536*5113495bSYour Name * Return: none
537*5113495bSYour Name */
hif_exec_grp_irq_enable(struct hif_exec_context * hif_ext_group)538*5113495bSYour Name static void hif_exec_grp_irq_enable(struct hif_exec_context *hif_ext_group)
539*5113495bSYour Name {
540*5113495bSYour Name int i;
541*5113495bSYour Name struct hif_softc *scn = HIF_GET_SOFTC(hif_ext_group->hif);
542*5113495bSYour Name
543*5113495bSYour Name for (i = 0; i < hif_ext_group->numirq; i++)
544*5113495bSYour Name pfrm_enable_irq(scn->qdf_dev->dev, hif_ext_group->os_irq[i]);
545*5113495bSYour Name }
546*5113495bSYour Name
hif_ipci_get_irq_name(int irq_no)547*5113495bSYour Name const char *hif_ipci_get_irq_name(int irq_no)
548*5113495bSYour Name {
549*5113495bSYour Name return "pci-dummy";
550*5113495bSYour Name }
551*5113495bSYour Name
552*5113495bSYour Name #ifdef FEATURE_IRQ_AFFINITY
553*5113495bSYour Name static
hif_ipci_irq_set_affinity_hint(struct hif_exec_context * hif_ext_group,bool perf)554*5113495bSYour Name void hif_ipci_irq_set_affinity_hint(struct hif_exec_context *hif_ext_group,
555*5113495bSYour Name bool perf)
556*5113495bSYour Name {
557*5113495bSYour Name int i, ret;
558*5113495bSYour Name unsigned int cpus;
559*5113495bSYour Name bool mask_set = false;
560*5113495bSYour Name int package_id;
561*5113495bSYour Name int cpu_cluster = perf ? hif_get_perf_cluster_bitmap() :
562*5113495bSYour Name BIT(CPU_CLUSTER_TYPE_LITTLE);
563*5113495bSYour Name
564*5113495bSYour Name for (i = 0; i < hif_ext_group->numirq; i++)
565*5113495bSYour Name qdf_cpumask_clear(&hif_ext_group->new_cpu_mask[i]);
566*5113495bSYour Name
567*5113495bSYour Name for (i = 0; i < hif_ext_group->numirq; i++) {
568*5113495bSYour Name qdf_for_each_online_cpu(cpus) {
569*5113495bSYour Name package_id = qdf_topology_physical_package_id(cpus);
570*5113495bSYour Name if (package_id >= 0 && BIT(package_id) & cpu_cluster) {
571*5113495bSYour Name qdf_cpumask_set_cpu(cpus,
572*5113495bSYour Name &hif_ext_group->
573*5113495bSYour Name new_cpu_mask[i]);
574*5113495bSYour Name mask_set = true;
575*5113495bSYour Name }
576*5113495bSYour Name }
577*5113495bSYour Name }
578*5113495bSYour Name for (i = 0; i < hif_ext_group->numirq && i < HIF_MAX_GRP_IRQ; i++) {
579*5113495bSYour Name if (mask_set) {
580*5113495bSYour Name ret = hif_affinity_mgr_set_qrg_irq_affinity((struct hif_softc *)hif_ext_group->hif,
581*5113495bSYour Name hif_ext_group->os_irq[i],
582*5113495bSYour Name hif_ext_group->grp_id, i,
583*5113495bSYour Name &hif_ext_group->new_cpu_mask[i]);
584*5113495bSYour Name if (ret)
585*5113495bSYour Name qdf_debug("Set affinity %*pbl fails for IRQ %d ",
586*5113495bSYour Name qdf_cpumask_pr_args(&hif_ext_group->
587*5113495bSYour Name new_cpu_mask[i]),
588*5113495bSYour Name hif_ext_group->os_irq[i]);
589*5113495bSYour Name } else {
590*5113495bSYour Name qdf_err("Offline CPU: Set affinity fails for IRQ: %d",
591*5113495bSYour Name hif_ext_group->os_irq[i]);
592*5113495bSYour Name }
593*5113495bSYour Name }
594*5113495bSYour Name }
595*5113495bSYour Name
hif_ipci_set_grp_intr_affinity(struct hif_softc * scn,uint32_t grp_intr_bitmask,bool perf)596*5113495bSYour Name void hif_ipci_set_grp_intr_affinity(struct hif_softc *scn,
597*5113495bSYour Name uint32_t grp_intr_bitmask, bool perf)
598*5113495bSYour Name {
599*5113495bSYour Name int i;
600*5113495bSYour Name struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
601*5113495bSYour Name struct hif_exec_context *hif_ext_group;
602*5113495bSYour Name
603*5113495bSYour Name for (i = 0; i < hif_state->hif_num_extgroup; i++) {
604*5113495bSYour Name if (!(grp_intr_bitmask & BIT(i)))
605*5113495bSYour Name continue;
606*5113495bSYour Name
607*5113495bSYour Name hif_ext_group = hif_state->hif_ext_group[i];
608*5113495bSYour Name hif_ipci_irq_set_affinity_hint(hif_ext_group, perf);
609*5113495bSYour Name qdf_atomic_set(&hif_ext_group->force_napi_complete, -1);
610*5113495bSYour Name }
611*5113495bSYour Name }
612*5113495bSYour Name #endif
613*5113495bSYour Name
614*5113495bSYour Name #ifdef HIF_CPU_PERF_AFFINE_MASK
hif_ipci_ce_irq_set_affinity_hint(struct hif_softc * scn)615*5113495bSYour Name static void hif_ipci_ce_irq_set_affinity_hint(struct hif_softc *scn)
616*5113495bSYour Name {
617*5113495bSYour Name int ret;
618*5113495bSYour Name unsigned int cpus;
619*5113495bSYour Name struct HIF_CE_state *ce_sc = HIF_GET_CE_STATE(scn);
620*5113495bSYour Name struct hif_ipci_softc *ipci_sc = HIF_GET_IPCI_SOFTC(scn);
621*5113495bSYour Name struct CE_attr *host_ce_conf;
622*5113495bSYour Name int ce_id;
623*5113495bSYour Name qdf_cpu_mask ce_cpu_mask, updated_mask;
624*5113495bSYour Name int perf_cpu_cluster = hif_get_perf_cluster_bitmap();
625*5113495bSYour Name int package_id;
626*5113495bSYour Name
627*5113495bSYour Name host_ce_conf = ce_sc->host_ce_config;
628*5113495bSYour Name qdf_cpumask_clear(&ce_cpu_mask);
629*5113495bSYour Name
630*5113495bSYour Name qdf_for_each_online_cpu(cpus) {
631*5113495bSYour Name package_id = qdf_topology_physical_package_id(cpus);
632*5113495bSYour Name if (package_id >= 0 && BIT(package_id) & perf_cpu_cluster) {
633*5113495bSYour Name qdf_cpumask_set_cpu(cpus,
634*5113495bSYour Name &ce_cpu_mask);
635*5113495bSYour Name }
636*5113495bSYour Name }
637*5113495bSYour Name if (qdf_cpumask_empty(&ce_cpu_mask)) {
638*5113495bSYour Name hif_err_rl("Empty cpu_mask, unable to set CE IRQ affinity");
639*5113495bSYour Name return;
640*5113495bSYour Name }
641*5113495bSYour Name for (ce_id = 0; ce_id < scn->ce_count; ce_id++) {
642*5113495bSYour Name if (host_ce_conf[ce_id].flags & CE_ATTR_DISABLE_INTR)
643*5113495bSYour Name continue;
644*5113495bSYour Name qdf_cpumask_copy(&updated_mask, &ce_cpu_mask);
645*5113495bSYour Name ret = hif_affinity_mgr_set_ce_irq_affinity(scn, ipci_sc->ce_msi_irq_num[ce_id],
646*5113495bSYour Name ce_id,
647*5113495bSYour Name &updated_mask);
648*5113495bSYour Name qdf_cpumask_clear(&ipci_sc->ce_irq_cpu_mask[ce_id]);
649*5113495bSYour Name qdf_cpumask_copy(&ipci_sc->ce_irq_cpu_mask[ce_id],
650*5113495bSYour Name &updated_mask);
651*5113495bSYour Name if (ret)
652*5113495bSYour Name hif_err_rl("Set affinity %*pbl fails for CE IRQ %d",
653*5113495bSYour Name qdf_cpumask_pr_args(
654*5113495bSYour Name &ipci_sc->ce_irq_cpu_mask[ce_id]),
655*5113495bSYour Name ipci_sc->ce_msi_irq_num[ce_id]);
656*5113495bSYour Name else
657*5113495bSYour Name hif_debug_rl("Set affinity %*pbl for CE IRQ: %d",
658*5113495bSYour Name qdf_cpumask_pr_args(
659*5113495bSYour Name &ipci_sc->ce_irq_cpu_mask[ce_id]),
660*5113495bSYour Name ipci_sc->ce_msi_irq_num[ce_id]);
661*5113495bSYour Name }
662*5113495bSYour Name }
663*5113495bSYour Name
hif_ipci_config_irq_affinity(struct hif_softc * scn)664*5113495bSYour Name void hif_ipci_config_irq_affinity(struct hif_softc *scn)
665*5113495bSYour Name {
666*5113495bSYour Name hif_core_ctl_set_boost(true);
667*5113495bSYour Name /* Set IRQ affinity for CE interrupts*/
668*5113495bSYour Name hif_ipci_ce_irq_set_affinity_hint(scn);
669*5113495bSYour Name }
670*5113495bSYour Name #endif /* #ifdef HIF_CPU_PERF_AFFINE_MASK */
671*5113495bSYour Name
672*5113495bSYour Name #ifdef HIF_CPU_CLEAR_AFFINITY
hif_ipci_config_irq_clear_cpu_affinity(struct hif_softc * scn,int intr_ctxt_id,int cpu)673*5113495bSYour Name void hif_ipci_config_irq_clear_cpu_affinity(struct hif_softc *scn,
674*5113495bSYour Name int intr_ctxt_id, int cpu)
675*5113495bSYour Name {
676*5113495bSYour Name struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
677*5113495bSYour Name struct hif_exec_context *hif_ext_group;
678*5113495bSYour Name int i, ret;
679*5113495bSYour Name
680*5113495bSYour Name if (intr_ctxt_id < hif_state->hif_num_extgroup) {
681*5113495bSYour Name hif_ext_group = hif_state->hif_ext_group[intr_ctxt_id];
682*5113495bSYour Name for (i = 0; i < hif_ext_group->numirq; i++) {
683*5113495bSYour Name qdf_cpumask_setall(&hif_ext_group->new_cpu_mask[i]);
684*5113495bSYour Name qdf_cpumask_clear_cpu(cpu,
685*5113495bSYour Name &hif_ext_group->new_cpu_mask[i]);
686*5113495bSYour Name ret = hif_affinity_mgr_set_qrg_irq_affinity((struct hif_softc *)hif_ext_group->hif,
687*5113495bSYour Name hif_ext_group->os_irq[i],
688*5113495bSYour Name hif_ext_group->grp_id, i,
689*5113495bSYour Name &hif_ext_group->new_cpu_mask[i]);
690*5113495bSYour Name if (ret)
691*5113495bSYour Name hif_err("Set affinity %*pbl fails for IRQ %d ",
692*5113495bSYour Name qdf_cpumask_pr_args(&hif_ext_group->
693*5113495bSYour Name new_cpu_mask[i]),
694*5113495bSYour Name hif_ext_group->os_irq[i]);
695*5113495bSYour Name else
696*5113495bSYour Name hif_debug("Set affinity %*pbl for IRQ: %d",
697*5113495bSYour Name qdf_cpumask_pr_args(&hif_ext_group->
698*5113495bSYour Name new_cpu_mask[i]),
699*5113495bSYour Name hif_ext_group->os_irq[0]);
700*5113495bSYour Name }
701*5113495bSYour Name }
702*5113495bSYour Name }
703*5113495bSYour Name #endif
704*5113495bSYour Name
hif_ipci_configure_grp_irq(struct hif_softc * scn,struct hif_exec_context * hif_ext_group)705*5113495bSYour Name int hif_ipci_configure_grp_irq(struct hif_softc *scn,
706*5113495bSYour Name struct hif_exec_context *hif_ext_group)
707*5113495bSYour Name {
708*5113495bSYour Name int ret = 0;
709*5113495bSYour Name int irq = 0;
710*5113495bSYour Name int j;
711*5113495bSYour Name
712*5113495bSYour Name hif_ext_group->irq_enable = &hif_exec_grp_irq_enable;
713*5113495bSYour Name hif_ext_group->irq_disable = &hif_exec_grp_irq_disable;
714*5113495bSYour Name hif_ext_group->irq_name = &hif_ipci_get_irq_name;
715*5113495bSYour Name hif_ext_group->work_complete = &hif_dummy_grp_done;
716*5113495bSYour Name
717*5113495bSYour Name for (j = 0; j < hif_ext_group->numirq; j++) {
718*5113495bSYour Name irq = hif_ext_group->irq[j];
719*5113495bSYour Name
720*5113495bSYour Name hif_info("request_irq = %d for grp %d",
721*5113495bSYour Name irq, hif_ext_group->grp_id);
722*5113495bSYour Name ret = pfrm_request_irq(scn->qdf_dev->dev, irq,
723*5113495bSYour Name hif_ext_group_interrupt_handler,
724*5113495bSYour Name IRQF_SHARED | IRQF_NO_SUSPEND,
725*5113495bSYour Name "wlan_EXT_GRP",
726*5113495bSYour Name hif_ext_group);
727*5113495bSYour Name if (ret) {
728*5113495bSYour Name hif_err("request_irq failed ret = %d", ret);
729*5113495bSYour Name return -EFAULT;
730*5113495bSYour Name }
731*5113495bSYour Name hif_ext_group->os_irq[j] = irq;
732*5113495bSYour Name }
733*5113495bSYour Name hif_ext_group->irq_requested = true;
734*5113495bSYour Name return 0;
735*5113495bSYour Name }
736*5113495bSYour Name
hif_configure_irq(struct hif_softc * scn)737*5113495bSYour Name int hif_configure_irq(struct hif_softc *scn)
738*5113495bSYour Name {
739*5113495bSYour Name int ret = 0;
740*5113495bSYour Name
741*5113495bSYour Name if (hif_is_polled_mode_enabled(GET_HIF_OPAQUE_HDL(scn))) {
742*5113495bSYour Name scn->request_irq_done = false;
743*5113495bSYour Name return 0;
744*5113495bSYour Name }
745*5113495bSYour Name
746*5113495bSYour Name ret = hif_ce_msi_configure_irq(scn);
747*5113495bSYour Name if (ret == 0)
748*5113495bSYour Name goto end;
749*5113495bSYour Name
750*5113495bSYour Name if (ret < 0) {
751*5113495bSYour Name hif_err("hif_ipci_configure_irq error = %d", ret);
752*5113495bSYour Name return ret;
753*5113495bSYour Name }
754*5113495bSYour Name end:
755*5113495bSYour Name scn->request_irq_done = true;
756*5113495bSYour Name return 0;
757*5113495bSYour Name }
758*5113495bSYour Name
759*5113495bSYour Name /**
760*5113495bSYour Name * hif_ipci_get_soc_info_pld() - get soc info for ipcie bus from pld target
761*5113495bSYour Name * @sc: ipci context
762*5113495bSYour Name * @dev: device structure
763*5113495bSYour Name *
764*5113495bSYour Name * Return: none
765*5113495bSYour Name */
hif_ipci_get_soc_info_pld(struct hif_ipci_softc * sc,struct device * dev)766*5113495bSYour Name static void hif_ipci_get_soc_info_pld(struct hif_ipci_softc *sc,
767*5113495bSYour Name struct device *dev)
768*5113495bSYour Name {
769*5113495bSYour Name struct pld_soc_info info;
770*5113495bSYour Name struct hif_softc *scn = HIF_GET_SOFTC(sc);
771*5113495bSYour Name
772*5113495bSYour Name pld_get_soc_info(dev, &info);
773*5113495bSYour Name sc->mem = info.v_addr;
774*5113495bSYour Name sc->ce_sc.ol_sc.mem = info.v_addr;
775*5113495bSYour Name sc->ce_sc.ol_sc.mem_pa = info.p_addr;
776*5113495bSYour Name
777*5113495bSYour Name scn->target_info.target_version = info.soc_id;
778*5113495bSYour Name scn->target_info.target_revision = 0;
779*5113495bSYour Name }
780*5113495bSYour Name
781*5113495bSYour Name /**
782*5113495bSYour Name * hif_ipci_get_soc_info_nopld() - get soc info for ipcie bus for non pld target
783*5113495bSYour Name * @sc: ipci context
784*5113495bSYour Name * @dev: device structure
785*5113495bSYour Name *
786*5113495bSYour Name * Return: none
787*5113495bSYour Name */
hif_ipci_get_soc_info_nopld(struct hif_ipci_softc * sc,struct device * dev)788*5113495bSYour Name static void hif_ipci_get_soc_info_nopld(struct hif_ipci_softc *sc,
789*5113495bSYour Name struct device *dev)
790*5113495bSYour Name {}
791*5113495bSYour Name
792*5113495bSYour Name /**
793*5113495bSYour Name * hif_is_pld_based_target() - verify if the target is pld based
794*5113495bSYour Name * @sc: ipci context
795*5113495bSYour Name * @device_id: device id
796*5113495bSYour Name *
797*5113495bSYour Name * Return: none
798*5113495bSYour Name */
hif_is_pld_based_target(struct hif_ipci_softc * sc,int device_id)799*5113495bSYour Name static bool hif_is_pld_based_target(struct hif_ipci_softc *sc,
800*5113495bSYour Name int device_id)
801*5113495bSYour Name {
802*5113495bSYour Name if (!pld_have_platform_driver_support(sc->dev))
803*5113495bSYour Name return false;
804*5113495bSYour Name
805*5113495bSYour Name switch (device_id) {
806*5113495bSYour Name #ifdef QCA_WIFI_QCA6750
807*5113495bSYour Name case QCA6750_DEVICE_ID:
808*5113495bSYour Name #endif
809*5113495bSYour Name case WCN6450_DEVICE_ID:
810*5113495bSYour Name return true;
811*5113495bSYour Name }
812*5113495bSYour Name return false;
813*5113495bSYour Name }
814*5113495bSYour Name
815*5113495bSYour Name /**
816*5113495bSYour Name * hif_ipci_init_deinit_ops_attach() - attach ops for ipci
817*5113495bSYour Name * @sc: ipci context
818*5113495bSYour Name * @device_id: device id
819*5113495bSYour Name *
820*5113495bSYour Name * Return: none
821*5113495bSYour Name */
hif_ipci_init_deinit_ops_attach(struct hif_ipci_softc * sc,int device_id)822*5113495bSYour Name static void hif_ipci_init_deinit_ops_attach(struct hif_ipci_softc *sc,
823*5113495bSYour Name int device_id)
824*5113495bSYour Name {
825*5113495bSYour Name if (hif_is_pld_based_target(sc, device_id))
826*5113495bSYour Name sc->hif_ipci_get_soc_info = hif_ipci_get_soc_info_pld;
827*5113495bSYour Name else
828*5113495bSYour Name sc->hif_ipci_get_soc_info = hif_ipci_get_soc_info_nopld;
829*5113495bSYour Name }
830*5113495bSYour Name
hif_ipci_enable_bus(struct hif_softc * ol_sc,struct device * dev,void * bdev,const struct hif_bus_id * bid,enum hif_enable_type type)831*5113495bSYour Name QDF_STATUS hif_ipci_enable_bus(struct hif_softc *ol_sc,
832*5113495bSYour Name struct device *dev, void *bdev,
833*5113495bSYour Name const struct hif_bus_id *bid,
834*5113495bSYour Name enum hif_enable_type type)
835*5113495bSYour Name {
836*5113495bSYour Name int ret = 0;
837*5113495bSYour Name uint32_t hif_type, target_type;
838*5113495bSYour Name struct hif_ipci_softc *sc = HIF_GET_IPCI_SOFTC(ol_sc);
839*5113495bSYour Name struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(ol_sc);
840*5113495bSYour Name uint16_t revision_id = 0;
841*5113495bSYour Name struct hif_target_info *tgt_info;
842*5113495bSYour Name int device_id = HIF_IPCI_DEVICE_ID;
843*5113495bSYour Name
844*5113495bSYour Name if (!ol_sc) {
845*5113495bSYour Name hif_err("hif_ctx is NULL");
846*5113495bSYour Name return QDF_STATUS_E_NOMEM;
847*5113495bSYour Name }
848*5113495bSYour Name
849*5113495bSYour Name ret = qdf_set_dma_coherent_mask(dev,
850*5113495bSYour Name DMA_COHERENT_MASK_DEFAULT);
851*5113495bSYour Name if (ret) {
852*5113495bSYour Name hif_err("Failed to set dma mask error = %d", ret);
853*5113495bSYour Name return qdf_status_from_os_return(ret);
854*5113495bSYour Name }
855*5113495bSYour Name
856*5113495bSYour Name sc->dev = dev;
857*5113495bSYour Name tgt_info = hif_get_target_info_handle(hif_hdl);
858*5113495bSYour Name hif_ipci_init_deinit_ops_attach(sc, device_id);
859*5113495bSYour Name sc->hif_ipci_get_soc_info(sc, dev);
860*5113495bSYour Name hif_debug("hif_enable_pci done");
861*5113495bSYour Name
862*5113495bSYour Name ret = hif_get_device_type(device_id, revision_id,
863*5113495bSYour Name &hif_type, &target_type);
864*5113495bSYour Name if (ret < 0) {
865*5113495bSYour Name hif_err("Invalid device id/revision_id");
866*5113495bSYour Name return QDF_STATUS_E_ABORTED;
867*5113495bSYour Name }
868*5113495bSYour Name hif_debug("hif_type = 0x%x, target_type = 0x%x",
869*5113495bSYour Name hif_type, target_type);
870*5113495bSYour Name
871*5113495bSYour Name hif_register_tbl_attach(ol_sc, hif_type);
872*5113495bSYour Name hif_target_register_tbl_attach(ol_sc, target_type);
873*5113495bSYour Name sc->use_register_windowing = false;
874*5113495bSYour Name tgt_info->target_type = target_type;
875*5113495bSYour Name
876*5113495bSYour Name if (!ol_sc->mem_pa) {
877*5113495bSYour Name hif_err("BAR0 uninitialized");
878*5113495bSYour Name return QDF_STATUS_E_ABORTED;
879*5113495bSYour Name }
880*5113495bSYour Name
881*5113495bSYour Name return QDF_STATUS_SUCCESS;
882*5113495bSYour Name }
883*5113495bSYour Name
hif_ipci_needs_bmi(struct hif_softc * scn)884*5113495bSYour Name bool hif_ipci_needs_bmi(struct hif_softc *scn)
885*5113495bSYour Name {
886*5113495bSYour Name return !ce_srng_based(scn);
887*5113495bSYour Name }
888*5113495bSYour Name
889*5113495bSYour Name #ifdef FORCE_WAKE
hif_force_wake_request(struct hif_opaque_softc * hif_handle)890*5113495bSYour Name int hif_force_wake_request(struct hif_opaque_softc *hif_handle)
891*5113495bSYour Name {
892*5113495bSYour Name uint32_t timeout = 0;
893*5113495bSYour Name struct hif_softc *scn = (struct hif_softc *)hif_handle;
894*5113495bSYour Name struct hif_ipci_softc *ipci_scn = HIF_GET_IPCI_SOFTC(scn);
895*5113495bSYour Name
896*5113495bSYour Name if (pld_force_wake_request(scn->qdf_dev->dev)) {
897*5113495bSYour Name hif_err_rl("force wake request send failed");
898*5113495bSYour Name return -EINVAL;
899*5113495bSYour Name }
900*5113495bSYour Name
901*5113495bSYour Name HIF_STATS_INC(ipci_scn, mhi_force_wake_request_vote, 1);
902*5113495bSYour Name while (!pld_is_device_awake(scn->qdf_dev->dev) &&
903*5113495bSYour Name timeout <= FORCE_WAKE_DELAY_TIMEOUT_MS) {
904*5113495bSYour Name if (qdf_in_interrupt())
905*5113495bSYour Name qdf_mdelay(FORCE_WAKE_DELAY_MS);
906*5113495bSYour Name else
907*5113495bSYour Name qdf_sleep(FORCE_WAKE_DELAY_MS);
908*5113495bSYour Name
909*5113495bSYour Name timeout += FORCE_WAKE_DELAY_MS;
910*5113495bSYour Name }
911*5113495bSYour Name
912*5113495bSYour Name if (pld_is_device_awake(scn->qdf_dev->dev) <= 0) {
913*5113495bSYour Name hif_err("Unable to wake up mhi");
914*5113495bSYour Name HIF_STATS_INC(ipci_scn, mhi_force_wake_failure, 1);
915*5113495bSYour Name hif_force_wake_release(hif_handle);
916*5113495bSYour Name return -EINVAL;
917*5113495bSYour Name }
918*5113495bSYour Name HIF_STATS_INC(ipci_scn, mhi_force_wake_success, 1);
919*5113495bSYour Name
920*5113495bSYour Name HIF_STATS_INC(ipci_scn, soc_force_wake_success, 1);
921*5113495bSYour Name
922*5113495bSYour Name return 0;
923*5113495bSYour Name }
924*5113495bSYour Name
hif_force_wake_release(struct hif_opaque_softc * hif_handle)925*5113495bSYour Name int hif_force_wake_release(struct hif_opaque_softc *hif_handle)
926*5113495bSYour Name {
927*5113495bSYour Name int ret;
928*5113495bSYour Name struct hif_softc *scn = (struct hif_softc *)hif_handle;
929*5113495bSYour Name struct hif_ipci_softc *ipci_scn = HIF_GET_IPCI_SOFTC(scn);
930*5113495bSYour Name
931*5113495bSYour Name ret = pld_force_wake_release(scn->qdf_dev->dev);
932*5113495bSYour Name if (ret) {
933*5113495bSYour Name hif_err("force wake release failure");
934*5113495bSYour Name HIF_STATS_INC(ipci_scn, mhi_force_wake_release_failure, 1);
935*5113495bSYour Name return ret;
936*5113495bSYour Name }
937*5113495bSYour Name
938*5113495bSYour Name HIF_STATS_INC(ipci_scn, mhi_force_wake_release_success, 1);
939*5113495bSYour Name
940*5113495bSYour Name HIF_STATS_INC(ipci_scn, soc_force_wake_release_success, 1);
941*5113495bSYour Name return 0;
942*5113495bSYour Name }
943*5113495bSYour Name
hif_print_ipci_stats(struct hif_ipci_softc * ipci_handle)944*5113495bSYour Name void hif_print_ipci_stats(struct hif_ipci_softc *ipci_handle)
945*5113495bSYour Name {
946*5113495bSYour Name hif_debug("mhi_force_wake_request_vote: %d",
947*5113495bSYour Name ipci_handle->stats.mhi_force_wake_request_vote);
948*5113495bSYour Name hif_debug("mhi_force_wake_failure: %d",
949*5113495bSYour Name ipci_handle->stats.mhi_force_wake_failure);
950*5113495bSYour Name hif_debug("mhi_force_wake_success: %d",
951*5113495bSYour Name ipci_handle->stats.mhi_force_wake_success);
952*5113495bSYour Name hif_debug("soc_force_wake_register_write_success: %d",
953*5113495bSYour Name ipci_handle->stats.soc_force_wake_register_write_success);
954*5113495bSYour Name hif_debug("soc_force_wake_failure: %d",
955*5113495bSYour Name ipci_handle->stats.soc_force_wake_failure);
956*5113495bSYour Name hif_debug("soc_force_wake_success: %d",
957*5113495bSYour Name ipci_handle->stats.soc_force_wake_success);
958*5113495bSYour Name hif_debug("mhi_force_wake_release_failure: %d",
959*5113495bSYour Name ipci_handle->stats.mhi_force_wake_release_failure);
960*5113495bSYour Name hif_debug("mhi_force_wake_release_success: %d",
961*5113495bSYour Name ipci_handle->stats.mhi_force_wake_release_success);
962*5113495bSYour Name hif_debug("oc_force_wake_release_success: %d",
963*5113495bSYour Name ipci_handle->stats.soc_force_wake_release_success);
964*5113495bSYour Name }
965*5113495bSYour Name #endif /* FORCE_WAKE */
966*5113495bSYour Name
967*5113495bSYour Name #if defined(FEATURE_HAL_DELAYED_REG_WRITE) || \
968*5113495bSYour Name defined(FEATURE_HIF_DELAYED_REG_WRITE)
hif_prevent_link_low_power_states(struct hif_opaque_softc * hif)969*5113495bSYour Name int hif_prevent_link_low_power_states(struct hif_opaque_softc *hif)
970*5113495bSYour Name {
971*5113495bSYour Name struct hif_softc *scn = HIF_GET_SOFTC(hif);
972*5113495bSYour Name struct hif_ipci_softc *ipci_scn = HIF_GET_IPCI_SOFTC(scn);
973*5113495bSYour Name uint32_t start_time = 0, curr_time = 0;
974*5113495bSYour Name uint32_t count = 0;
975*5113495bSYour Name
976*5113495bSYour Name if (pld_is_pci_ep_awake(scn->qdf_dev->dev) == -ENOTSUPP)
977*5113495bSYour Name return 0;
978*5113495bSYour Name
979*5113495bSYour Name if (hif_is_ep_vote_access_disabled(scn)) {
980*5113495bSYour Name hif_info_high("EP access disabled in flight skip vote");
981*5113495bSYour Name return 0;
982*5113495bSYour Name }
983*5113495bSYour Name
984*5113495bSYour Name start_time = curr_time = qdf_system_ticks_to_msecs(qdf_system_ticks());
985*5113495bSYour Name while (pld_is_pci_ep_awake(scn->qdf_dev->dev) &&
986*5113495bSYour Name curr_time <= start_time + EP_WAKE_RESET_DELAY_TIMEOUT_MS) {
987*5113495bSYour Name if (count < EP_VOTE_POLL_TIME_CNT) {
988*5113495bSYour Name qdf_udelay(EP_VOTE_POLL_TIME_US);
989*5113495bSYour Name count++;
990*5113495bSYour Name } else {
991*5113495bSYour Name qdf_sleep_us(EP_WAKE_RESET_DELAY_US);
992*5113495bSYour Name }
993*5113495bSYour Name curr_time = qdf_system_ticks_to_msecs(qdf_system_ticks());
994*5113495bSYour Name }
995*5113495bSYour Name
996*5113495bSYour Name
997*5113495bSYour Name if (pld_is_pci_ep_awake(scn->qdf_dev->dev)) {
998*5113495bSYour Name hif_err_rl(" EP state reset is not done to prevent l1");
999*5113495bSYour Name ipci_scn->ep_awake_reset_fail++;
1000*5113495bSYour Name return 0;
1001*5113495bSYour Name }
1002*5113495bSYour Name
1003*5113495bSYour Name if (pld_prevent_l1(scn->qdf_dev->dev)) {
1004*5113495bSYour Name hif_err_rl("pld prevent l1 failed");
1005*5113495bSYour Name ipci_scn->prevent_l1_fail++;
1006*5113495bSYour Name return 0;
1007*5113495bSYour Name }
1008*5113495bSYour Name
1009*5113495bSYour Name count = 0;
1010*5113495bSYour Name ipci_scn->prevent_l1 = true;
1011*5113495bSYour Name start_time = curr_time = qdf_system_ticks_to_msecs(qdf_system_ticks());
1012*5113495bSYour Name while (!pld_is_pci_ep_awake(scn->qdf_dev->dev) &&
1013*5113495bSYour Name curr_time <= start_time + EP_WAKE_DELAY_TIMEOUT_MS) {
1014*5113495bSYour Name if (count < EP_VOTE_POLL_TIME_CNT) {
1015*5113495bSYour Name qdf_udelay(EP_WAKE_RESET_DELAY_US);
1016*5113495bSYour Name count++;
1017*5113495bSYour Name } else {
1018*5113495bSYour Name qdf_sleep_us(EP_WAKE_DELAY_US);
1019*5113495bSYour Name }
1020*5113495bSYour Name
1021*5113495bSYour Name curr_time = qdf_system_ticks_to_msecs(qdf_system_ticks());
1022*5113495bSYour Name }
1023*5113495bSYour Name
1024*5113495bSYour Name if (pld_is_pci_ep_awake(scn->qdf_dev->dev) <= 0) {
1025*5113495bSYour Name hif_err_rl("Unable to wakeup pci ep");
1026*5113495bSYour Name ipci_scn->ep_awake_set_fail++;
1027*5113495bSYour Name return 0;
1028*5113495bSYour Name }
1029*5113495bSYour Name
1030*5113495bSYour Name return 0;
1031*5113495bSYour Name }
1032*5113495bSYour Name
hif_allow_link_low_power_states(struct hif_opaque_softc * hif)1033*5113495bSYour Name void hif_allow_link_low_power_states(struct hif_opaque_softc *hif)
1034*5113495bSYour Name {
1035*5113495bSYour Name struct hif_softc *scn = HIF_GET_SOFTC(hif);
1036*5113495bSYour Name struct hif_ipci_softc *ipci_scn = HIF_GET_IPCI_SOFTC(scn);
1037*5113495bSYour Name
1038*5113495bSYour Name if (qdf_likely(ipci_scn->prevent_l1)) {
1039*5113495bSYour Name pld_allow_l1(scn->qdf_dev->dev);
1040*5113495bSYour Name ipci_scn->prevent_l1 = false;
1041*5113495bSYour Name }
1042*5113495bSYour Name }
1043*5113495bSYour Name #endif
1044*5113495bSYour Name
1045*5113495bSYour Name #ifndef QCA_WIFI_WCN6450
hif_ipci_enable_grp_irqs(struct hif_softc * scn)1046*5113495bSYour Name int hif_ipci_enable_grp_irqs(struct hif_softc *scn)
1047*5113495bSYour Name {
1048*5113495bSYour Name struct hif_ipci_softc *ipci_scn = HIF_GET_IPCI_SOFTC(scn);
1049*5113495bSYour Name int status;
1050*5113495bSYour Name
1051*5113495bSYour Name if (!ipci_scn->grp_irqs_disabled) {
1052*5113495bSYour Name hif_err("Unbalanced group IRQs Enable called");
1053*5113495bSYour Name qdf_assert_always(0);
1054*5113495bSYour Name }
1055*5113495bSYour Name
1056*5113495bSYour Name status = hif_apps_grp_irqs_enable(GET_HIF_OPAQUE_HDL(scn));
1057*5113495bSYour Name if (!status)
1058*5113495bSYour Name ipci_scn->grp_irqs_disabled = false;
1059*5113495bSYour Name
1060*5113495bSYour Name return status;
1061*5113495bSYour Name }
1062*5113495bSYour Name
hif_ipci_disable_grp_irqs(struct hif_softc * scn)1063*5113495bSYour Name int hif_ipci_disable_grp_irqs(struct hif_softc *scn)
1064*5113495bSYour Name {
1065*5113495bSYour Name struct hif_ipci_softc *ipci_scn = HIF_GET_IPCI_SOFTC(scn);
1066*5113495bSYour Name int status;
1067*5113495bSYour Name
1068*5113495bSYour Name if (ipci_scn->grp_irqs_disabled) {
1069*5113495bSYour Name hif_err("Unbalanced group IRQs disable called");
1070*5113495bSYour Name qdf_assert_always(0);
1071*5113495bSYour Name }
1072*5113495bSYour Name
1073*5113495bSYour Name status = hif_apps_grp_irqs_disable(GET_HIF_OPAQUE_HDL(scn));
1074*5113495bSYour Name if (!status)
1075*5113495bSYour Name ipci_scn->grp_irqs_disabled = true;
1076*5113495bSYour Name
1077*5113495bSYour Name return status;
1078*5113495bSYour Name }
1079*5113495bSYour Name #endif
1080