xref: /wlan-driver/qca-wifi-host-cmn/hif/src/ipcie/if_ipci.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
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