xref: /wlan-dirver/qca-wifi-host-cmn/hif/src/ipcie/if_ipci.c (revision cc9cfde56b108942f9ccfc4fa51aaa0d3a4f00cd)
1 /*
2  * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7 
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include <linux/slab.h>
18 #include <linux/interrupt.h>
19 #include <linux/if_arp.h>
20 #include "hif_io32.h"
21 #include "if_ipci.h"
22 #include "hif.h"
23 #include "target_type.h"
24 #include "hif_main.h"
25 #include "ce_main.h"
26 #include "ce_api.h"
27 #include "ce_internal.h"
28 #include "ce_reg.h"
29 #include "ce_bmi.h"
30 #include "regtable.h"
31 #include "hif_hw_version.h"
32 #include <linux/debugfs.h>
33 #include <linux/seq_file.h>
34 #include "qdf_status.h"
35 #include "qdf_atomic.h"
36 #include "pld_common.h"
37 #include "mp_dev.h"
38 #include "hif_debug.h"
39 
40 #include "ce_tasklet.h"
41 #include "targaddrs.h"
42 #include "hif_exec.h"
43 
44 #include "ipci_api.h"
45 
46 #ifdef FEATURE_RUNTIME_PM
47 inline struct hif_runtime_pm_ctx *hif_ipci_get_rpm_ctx(struct hif_softc *scn)
48 {
49 	struct hif_ipci_softc *sc = HIF_GET_IPCI_SOFTC(scn);
50 
51 	return &sc->rpm_ctx;
52 }
53 
54 inline struct device *hif_ipci_get_dev(struct hif_softc *scn)
55 {
56 	struct hif_ipci_softc *sc = HIF_GET_IPCI_SOFTC(scn);
57 
58 	return sc->dev;
59 }
60 #endif
61 
62 void hif_ipci_enable_power_management(struct hif_softc *hif_sc,
63 				      bool is_packet_log_enabled)
64 {
65 	hif_pm_runtime_start(hif_sc);
66 }
67 
68 void hif_ipci_disable_power_management(struct hif_softc *hif_ctx)
69 {
70 	hif_pm_runtime_stop(hif_ctx);
71 }
72 
73 void hif_ipci_display_stats(struct hif_softc *hif_ctx)
74 {
75 	hif_display_ce_stats(hif_ctx);
76 }
77 
78 void hif_ipci_clear_stats(struct hif_softc *hif_ctx)
79 {
80 	struct hif_ipci_softc *ipci_ctx = HIF_GET_IPCI_SOFTC(hif_ctx);
81 
82 	if (!ipci_ctx) {
83 		hif_err("hif_ctx null");
84 		return;
85 	}
86 	hif_clear_ce_stats(&ipci_ctx->ce_sc);
87 }
88 
89 QDF_STATUS hif_ipci_open(struct hif_softc *hif_ctx, enum qdf_bus_type bus_type)
90 {
91 	struct hif_ipci_softc *sc = HIF_GET_IPCI_SOFTC(hif_ctx);
92 
93 	hif_ctx->bus_type = bus_type;
94 	hif_pm_runtime_open(hif_ctx);
95 
96 	qdf_spinlock_create(&sc->irq_lock);
97 
98 	return hif_ce_open(hif_ctx);
99 }
100 
101 /**
102  * hif_ce_msi_map_ce_to_irq() - map CE to IRQ
103  * @scn: hif context
104  * @ce_id: CE Id
105  *
106  * Return: IRQ number
107  */
108 static int hif_ce_msi_map_ce_to_irq(struct hif_softc *scn, int ce_id)
109 {
110 	struct hif_ipci_softc *ipci_scn = HIF_GET_IPCI_SOFTC(scn);
111 
112 	return ipci_scn->ce_msi_irq_num[ce_id];
113 }
114 
115 int hif_ipci_bus_configure(struct hif_softc *hif_sc)
116 {
117 	int status = 0;
118 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_sc);
119 	uint8_t wake_ce_id;
120 
121 	hif_ce_prepare_config(hif_sc);
122 
123 	/* initialize sleep state adjust variables */
124 	hif_state->sleep_timer_init = true;
125 	hif_state->keep_awake_count = 0;
126 	hif_state->fake_sleep = false;
127 	hif_state->sleep_ticks = 0;
128 
129 	status = hif_wlan_enable(hif_sc);
130 	if (status) {
131 		hif_err("hif_wlan_enable error = %d", status);
132 		goto timer_free;
133 	}
134 
135 	A_TARGET_ACCESS_LIKELY(hif_sc);
136 
137 	status = hif_config_ce(hif_sc);
138 	if (status)
139 		goto disable_wlan;
140 
141 	status = hif_get_wake_ce_id(hif_sc, &wake_ce_id);
142 	if (status)
143 		goto unconfig_ce;
144 
145 	status = hif_configure_irq(hif_sc);
146 	if (status < 0)
147 		goto unconfig_ce;
148 
149 	hif_sc->wake_irq = hif_ce_msi_map_ce_to_irq(hif_sc, wake_ce_id);
150 	hif_sc->wake_irq_type = HIF_PM_CE_WAKE;
151 
152 	hif_info("expecting wake from ce %d, irq %d",
153 		 wake_ce_id, hif_sc->wake_irq);
154 
155 	A_TARGET_ACCESS_UNLIKELY(hif_sc);
156 
157 	return status;
158 
159 unconfig_ce:
160 	hif_unconfig_ce(hif_sc);
161 disable_wlan:
162 	A_TARGET_ACCESS_UNLIKELY(hif_sc);
163 	hif_wlan_disable(hif_sc);
164 
165 timer_free:
166 	qdf_timer_stop(&hif_state->sleep_timer);
167 	qdf_timer_free(&hif_state->sleep_timer);
168 	hif_state->sleep_timer_init = false;
169 
170 	hif_err("Failed, status = %d", status);
171 	return status;
172 }
173 
174 void hif_ipci_close(struct hif_softc *hif_sc)
175 {
176 	hif_pm_runtime_close(hif_sc);
177 	hif_ce_close(hif_sc);
178 }
179 
180 /**
181  * hif_ce_srng_msi_free_irq(): free CE msi IRQ
182  * @scn: struct hif_softc
183  *
184  * Return: ErrorNo
185  */
186 static int hif_ce_srng_msi_free_irq(struct hif_softc *scn)
187 {
188 	int ret;
189 	int ce_id, irq;
190 	uint32_t msi_data_start;
191 	uint32_t msi_data_count;
192 	uint32_t msi_irq_start;
193 	struct HIF_CE_state *ce_sc = HIF_GET_CE_STATE(scn);
194 
195 	ret = pld_get_user_msi_assignment(scn->qdf_dev->dev, "CE",
196 					  &msi_data_count, &msi_data_start,
197 					  &msi_irq_start);
198 	if (ret)
199 		return ret;
200 
201 	/* needs to match the ce_id -> irq data mapping
202 	 * used in the srng parameter configuration
203 	 */
204 	for (ce_id = 0; ce_id < scn->ce_count; ce_id++) {
205 		unsigned int msi_data;
206 
207 		if (!ce_sc->tasklets[ce_id].inited)
208 			continue;
209 
210 		msi_data = (ce_id % msi_data_count) + msi_irq_start;
211 		irq = pld_get_msi_irq(scn->qdf_dev->dev, msi_data);
212 
213 		hif_debug("%s: (ce_id %d, msi_data %d, irq %d)", __func__,
214 			  ce_id, msi_data, irq);
215 
216 		pfrm_free_irq(scn->qdf_dev->dev, irq, &ce_sc->tasklets[ce_id]);
217 	}
218 
219 	return ret;
220 }
221 
222 /**
223  * hif_ipci_deconfigure_grp_irq(): deconfigure HW block IRQ
224  * @scn: struct hif_softc
225  *
226  * Return: none
227  */
228 static void hif_ipci_deconfigure_grp_irq(struct hif_softc *scn)
229 {
230 	int i, j, irq;
231 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
232 	struct hif_exec_context *hif_ext_group;
233 
234 	for (i = 0; i < hif_state->hif_num_extgroup; i++) {
235 		hif_ext_group = hif_state->hif_ext_group[i];
236 		if (hif_ext_group->irq_requested) {
237 			hif_ext_group->irq_requested = false;
238 			for (j = 0; j < hif_ext_group->numirq; j++) {
239 				irq = hif_ext_group->os_irq[j];
240 				pfrm_free_irq(scn->qdf_dev->dev,
241 					      irq, hif_ext_group);
242 			}
243 			hif_ext_group->numirq = 0;
244 		}
245 	}
246 }
247 
248 void hif_ipci_nointrs(struct hif_softc *scn)
249 {
250 	int ret;
251 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
252 
253 	ce_unregister_irq(hif_state, CE_ALL_BITMAP);
254 
255 	if (scn->request_irq_done == false)
256 		return;
257 
258 	hif_ipci_deconfigure_grp_irq(scn);
259 
260 	ret = hif_ce_srng_msi_free_irq(scn);
261 
262 	scn->request_irq_done = false;
263 }
264 
265 void hif_ipci_disable_bus(struct hif_softc *scn)
266 {
267 	struct hif_ipci_softc *sc = HIF_GET_IPCI_SOFTC(scn);
268 	void __iomem *mem;
269 
270 	/* Attach did not succeed, all resources have been
271 	 * freed in error handler
272 	 */
273 	if (!sc)
274 		return;
275 
276 	mem = (void __iomem *)sc->mem;
277 	if (mem) {
278 		hif_dump_pipe_debug_count(scn);
279 		if (scn->athdiag_procfs_inited) {
280 			athdiag_procfs_remove();
281 			scn->athdiag_procfs_inited = false;
282 		}
283 		scn->mem = NULL;
284 	}
285 	hif_info("X");
286 }
287 
288 #ifdef CONFIG_PLD_PCIE_CNSS
289 void hif_ipci_prevent_linkdown(struct hif_softc *scn, bool flag)
290 {
291 	int errno;
292 
293 	hif_info("wlan: %s pcie power collapse", flag ? "disable" : "enable");
294 	hif_runtime_prevent_linkdown(scn, flag);
295 
296 	errno = pld_wlan_pm_control(scn->qdf_dev->dev, flag);
297 	if (errno)
298 		hif_err("Failed pld_wlan_pm_control; errno %d", errno);
299 }
300 #else
301 void hif_ipci_prevent_linkdown(struct hif_softc *scn, bool flag)
302 {
303 }
304 #endif
305 
306 int hif_ipci_bus_suspend(struct hif_softc *scn)
307 {
308 	int ret;
309 
310 	ret = hif_apps_enable_irq_wake(GET_HIF_OPAQUE_HDL(scn));
311 
312 	if (!ret)
313 		scn->bus_suspended = true;
314 
315 	return ret;
316 }
317 
318 int hif_ipci_bus_resume(struct hif_softc *scn)
319 {
320 	scn->bus_suspended = false;
321 
322 	return hif_apps_disable_irq_wake(GET_HIF_OPAQUE_HDL(scn));
323 }
324 
325 int hif_ipci_bus_suspend_noirq(struct hif_softc *scn)
326 {
327 	QDF_STATUS ret;
328 
329 	ret = hif_try_complete_tasks(scn);
330 	if (QDF_IS_STATUS_ERROR(ret))
331 		return -EBUSY;
332 
333 	return 0;
334 }
335 
336 int hif_ipci_bus_resume_noirq(struct hif_softc *scn)
337 {
338 	return 0;
339 }
340 
341 void hif_ipci_disable_isr(struct hif_softc *scn)
342 {
343 	struct hif_ipci_softc *sc = HIF_GET_IPCI_SOFTC(scn);
344 
345 	hif_exec_kill(&scn->osc);
346 	hif_nointrs(scn);
347 	/* Cancel the pending tasklet */
348 	ce_tasklet_kill(scn);
349 	tasklet_kill(&sc->intr_tq);
350 	qdf_atomic_set(&scn->active_tasklet_cnt, 0);
351 	qdf_atomic_set(&scn->active_grp_tasklet_cnt, 0);
352 }
353 
354 int hif_ipci_dump_registers(struct hif_softc *hif_ctx)
355 {
356 	int status;
357 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
358 
359 	status = hif_dump_ce_registers(scn);
360 
361 	if (status)
362 		hif_err("Dump CE Registers Failed");
363 
364 	return 0;
365 }
366 
367 /**
368  * hif_ce_interrupt_handler() - interrupt handler for copy engine
369  * @irq: irq number
370  * @context: tasklet context
371  *
372  * Return: irqreturn_t
373  */
374 static irqreturn_t hif_ce_interrupt_handler(int irq, void *context)
375 {
376 	struct ce_tasklet_entry *tasklet_entry = context;
377 
378 	hif_pm_runtime_check_and_request_resume(
379 			GET_HIF_OPAQUE_HDL(tasklet_entry->hif_ce_state));
380 	return ce_dispatch_interrupt(tasklet_entry->ce_id, tasklet_entry);
381 }
382 
383 extern const char *ce_name[];
384 
385 /* hif_ce_srng_msi_irq_disable() - disable the irq for msi
386  * @hif_sc: hif context
387  * @ce_id: which ce to disable copy complete interrupts for
388  *
389  * @Return: none
390  */
391 static void hif_ce_srng_msi_irq_disable(struct hif_softc *hif_sc, int ce_id)
392 {
393 	pfrm_disable_irq_nosync(hif_sc->qdf_dev->dev,
394 				hif_ce_msi_map_ce_to_irq(hif_sc, ce_id));
395 
396 }
397 
398 /* hif_ce_srng_msi_irq_enable() - enable the irq for msi
399  * @hif_sc: hif context
400  * @ce_id: which ce to enable copy complete interrupts for
401  *
402  * @Return: none
403  */
404 static void hif_ce_srng_msi_irq_enable(struct hif_softc *hif_sc, int ce_id)
405 {
406 	pfrm_enable_irq(hif_sc->qdf_dev->dev,
407 			hif_ce_msi_map_ce_to_irq(hif_sc, ce_id));
408 
409 }
410 
411 /* hif_ce_msi_configure_irq() - configure the irq
412  * @scn: hif context
413  *
414  * @Return: none
415  */
416 static int hif_ce_msi_configure_irq(struct hif_softc *scn)
417 {
418 	int ret;
419 	int ce_id, irq;
420 	uint32_t msi_data_start;
421 	uint32_t msi_data_count;
422 	uint32_t msi_irq_start;
423 	struct HIF_CE_state *ce_sc = HIF_GET_CE_STATE(scn);
424 	struct hif_ipci_softc *ipci_sc = HIF_GET_IPCI_SOFTC(scn);
425 	uint8_t wake_ce_id;
426 
427 	ret = hif_get_wake_ce_id(scn, &wake_ce_id);
428 	if (ret)
429 		return ret;
430 
431 	/* do ce irq assignments */
432 	ret = pld_get_user_msi_assignment(scn->qdf_dev->dev, "CE",
433 					  &msi_data_count, &msi_data_start,
434 					  &msi_irq_start);
435 	if (ret)
436 		return ret;
437 
438 	scn->bus_ops.hif_irq_disable = &hif_ce_srng_msi_irq_disable;
439 	scn->bus_ops.hif_irq_enable = &hif_ce_srng_msi_irq_enable;
440 	scn->bus_ops.hif_map_ce_to_irq = &hif_ce_msi_map_ce_to_irq;
441 
442 	/* needs to match the ce_id -> irq data mapping
443 	 * used in the srng parameter configuration
444 	 */
445 	for (ce_id = 0; ce_id < scn->ce_count; ce_id++) {
446 		unsigned long irqflags = IRQF_SHARED;
447 		unsigned int msi_data = (ce_id % msi_data_count) +
448 			msi_irq_start;
449 		irq = pld_get_msi_irq(scn->qdf_dev->dev, msi_data);
450 		hif_debug("(ce_id %d, msi_data %d, irq %d tasklet %pK)",
451 			 ce_id, msi_data, irq,
452 			 &ce_sc->tasklets[ce_id]);
453 
454 		/* implies the ce is also initialized */
455 		if (!ce_sc->tasklets[ce_id].inited)
456 			continue;
457 
458 		ipci_sc->ce_msi_irq_num[ce_id] = irq;
459 		ret = pfrm_request_irq(scn->qdf_dev->dev,
460 				       irq, hif_ce_interrupt_handler,
461 				       irqflags,
462 				       ce_name[ce_id],
463 				       &ce_sc->tasklets[ce_id]);
464 		if (ret)
465 			goto free_irq;
466 	}
467 
468 	return ret;
469 
470 free_irq:
471 	/* the request_irq for the last ce_id failed so skip it. */
472 	while (ce_id > 0 && ce_id < scn->ce_count) {
473 		unsigned int msi_data;
474 
475 		ce_id--;
476 		msi_data = (ce_id % msi_data_count) + msi_irq_start;
477 		irq = pld_get_msi_irq(scn->qdf_dev->dev, msi_data);
478 		pfrm_free_irq(scn->qdf_dev->dev, irq, &ce_sc->tasklets[ce_id]);
479 	}
480 
481 	return ret;
482 }
483 
484 /**
485  * hif_exec_grp_irq_disable() - disable the irq for group
486  * @hif_ext_group: hif exec context
487  *
488  * Return: none
489  */
490 static void hif_exec_grp_irq_disable(struct hif_exec_context *hif_ext_group)
491 {
492 	int i;
493 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ext_group->hif);
494 
495 	for (i = 0; i < hif_ext_group->numirq; i++)
496 		pfrm_disable_irq_nosync(scn->qdf_dev->dev,
497 					hif_ext_group->os_irq[i]);
498 }
499 
500 /**
501  * hif_exec_grp_irq_enable() - enable the irq for group
502  * @hif_ext_group: hif exec context
503  *
504  * Return: none
505  */
506 static void hif_exec_grp_irq_enable(struct hif_exec_context *hif_ext_group)
507 {
508 	int i;
509 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ext_group->hif);
510 
511 	for (i = 0; i < hif_ext_group->numirq; i++)
512 		pfrm_enable_irq(scn->qdf_dev->dev, hif_ext_group->os_irq[i]);
513 }
514 
515 const char *hif_ipci_get_irq_name(int irq_no)
516 {
517 	return "pci-dummy";
518 }
519 
520 int hif_ipci_configure_grp_irq(struct hif_softc *scn,
521 			       struct hif_exec_context *hif_ext_group)
522 {
523 	int ret = 0;
524 	int irq = 0;
525 	int j;
526 
527 	hif_ext_group->irq_enable = &hif_exec_grp_irq_enable;
528 	hif_ext_group->irq_disable = &hif_exec_grp_irq_disable;
529 	hif_ext_group->irq_name = &hif_ipci_get_irq_name;
530 	hif_ext_group->work_complete = &hif_dummy_grp_done;
531 
532 	for (j = 0; j < hif_ext_group->numirq; j++) {
533 		irq = hif_ext_group->irq[j];
534 
535 		hif_info("request_irq = %d for grp %d",
536 			 irq, hif_ext_group->grp_id);
537 		ret = pfrm_request_irq(scn->qdf_dev->dev, irq,
538 				       hif_ext_group_interrupt_handler,
539 				       IRQF_SHARED | IRQF_NO_SUSPEND,
540 				       "wlan_EXT_GRP",
541 				       hif_ext_group);
542 		if (ret) {
543 			hif_err("request_irq failed ret = %d", ret);
544 			return -EFAULT;
545 		}
546 		hif_ext_group->os_irq[j] = irq;
547 	}
548 	hif_ext_group->irq_requested = true;
549 	return 0;
550 }
551 
552 int hif_configure_irq(struct hif_softc *scn)
553 {
554 	int ret = 0;
555 
556 	hif_info("E");
557 
558 	if (hif_is_polled_mode_enabled(GET_HIF_OPAQUE_HDL(scn))) {
559 		scn->request_irq_done = false;
560 		return 0;
561 	}
562 
563 	ret = hif_ce_msi_configure_irq(scn);
564 	if (ret == 0)
565 		goto end;
566 
567 	if (ret < 0) {
568 		hif_err("hif_ipci_configure_irq error = %d", ret);
569 		return ret;
570 	}
571 end:
572 	scn->request_irq_done = true;
573 	return 0;
574 }
575 
576 /**
577  * hif_ipci_get_soc_info_pld() - get soc info for ipcie bus from pld target
578  * @sc: ipci context
579  * @dev: device structure
580  *
581  * Return: none
582  */
583 static void hif_ipci_get_soc_info_pld(struct hif_ipci_softc *sc,
584 				      struct device *dev)
585 {
586 	struct pld_soc_info info;
587 
588 	pld_get_soc_info(dev, &info);
589 	sc->mem = info.v_addr;
590 	sc->ce_sc.ol_sc.mem    = info.v_addr;
591 	sc->ce_sc.ol_sc.mem_pa = info.p_addr;
592 }
593 
594 /**
595  * hif_ipci_get_soc_info_nopld() - get soc info for ipcie bus for non pld target
596  * @sc: ipci context
597  * @dev: device structure
598  *
599  * Return: none
600  */
601 static void hif_ipci_get_soc_info_nopld(struct hif_ipci_softc *sc,
602 					struct device *dev)
603 {}
604 
605 /**
606  * hif_is_pld_based_target() - verify if the target is pld based
607  * @sc: ipci context
608  * @device_id: device id
609  *
610  * Return: none
611  */
612 static bool hif_is_pld_based_target(struct hif_ipci_softc *sc,
613 				    int device_id)
614 {
615 	if (!pld_have_platform_driver_support(sc->dev))
616 		return false;
617 
618 	switch (device_id) {
619 #ifdef QCA_WIFI_QCA6750
620 	case QCA6750_DEVICE_ID:
621 #endif
622 		return true;
623 	}
624 	return false;
625 }
626 
627 /**
628  * hif_ipci_init_deinit_ops_attach() - attach ops for ipci
629  * @sc: ipci context
630  * @device_id: device id
631  *
632  * Return: none
633  */
634 static void hif_ipci_init_deinit_ops_attach(struct hif_ipci_softc *sc,
635 					    int device_id)
636 {
637 	if (hif_is_pld_based_target(sc, device_id))
638 		sc->hif_ipci_get_soc_info = hif_ipci_get_soc_info_pld;
639 	else
640 		sc->hif_ipci_get_soc_info = hif_ipci_get_soc_info_nopld;
641 }
642 
643 QDF_STATUS hif_ipci_enable_bus(struct hif_softc *ol_sc,
644 			       struct device *dev, void *bdev,
645 			       const struct hif_bus_id *bid,
646 			       enum hif_enable_type type)
647 {
648 	int ret = 0;
649 	uint32_t hif_type, target_type;
650 	struct hif_ipci_softc *sc = HIF_GET_IPCI_SOFTC(ol_sc);
651 	struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(ol_sc);
652 	uint16_t revision_id = 0;
653 	struct hif_target_info *tgt_info;
654 	int device_id = QCA6750_DEVICE_ID;
655 
656 	if (!ol_sc) {
657 		hif_err("hif_ctx is NULL");
658 		return QDF_STATUS_E_NOMEM;
659 	}
660 
661 	ret = qdf_set_dma_coherent_mask(dev,
662 					DMA_COHERENT_MASK_DEFAULT);
663 	if (ret) {
664 		hif_err("Failed to set dma mask error = %d", ret);
665 		return qdf_status_from_os_return(ret);
666 	}
667 
668 	sc->dev = dev;
669 	tgt_info = hif_get_target_info_handle(hif_hdl);
670 	hif_ipci_init_deinit_ops_attach(sc, device_id);
671 	sc->hif_ipci_get_soc_info(sc, dev);
672 	hif_debug("hif_enable_pci done");
673 
674 	ret = hif_get_device_type(device_id, revision_id,
675 				  &hif_type, &target_type);
676 	if (ret < 0) {
677 		hif_err("Invalid device id/revision_id");
678 		return QDF_STATUS_E_ABORTED;
679 	}
680 	hif_debug("hif_type = 0x%x, target_type = 0x%x",
681 		 hif_type, target_type);
682 
683 	hif_register_tbl_attach(ol_sc, hif_type);
684 	hif_target_register_tbl_attach(ol_sc, target_type);
685 	sc->use_register_windowing = false;
686 	tgt_info->target_type = target_type;
687 
688 	if (!ol_sc->mem_pa) {
689 		hif_err("BAR0 uninitialized");
690 		return QDF_STATUS_E_ABORTED;
691 	}
692 
693 	return QDF_STATUS_SUCCESS;
694 }
695 
696 bool hif_ipci_needs_bmi(struct hif_softc *scn)
697 {
698 	return !ce_srng_based(scn);
699 }
700 
701 #ifdef FORCE_WAKE
702 int hif_force_wake_request(struct hif_opaque_softc *hif_handle)
703 {
704 	uint32_t timeout = 0;
705 	struct hif_softc *scn = (struct hif_softc *)hif_handle;
706 	struct hif_ipci_softc *ipci_scn = HIF_GET_IPCI_SOFTC(scn);
707 
708 	if (pld_force_wake_request(scn->qdf_dev->dev)) {
709 		hif_err_rl("force wake request send failed");
710 		return -EINVAL;
711 	}
712 
713 	HIF_STATS_INC(ipci_scn, mhi_force_wake_request_vote, 1);
714 	while (!pld_is_device_awake(scn->qdf_dev->dev) &&
715 	       timeout <= FORCE_WAKE_DELAY_TIMEOUT_MS) {
716 		qdf_mdelay(FORCE_WAKE_DELAY_MS);
717 		timeout += FORCE_WAKE_DELAY_MS;
718 	}
719 
720 	if (pld_is_device_awake(scn->qdf_dev->dev) <= 0) {
721 		hif_err("Unable to wake up mhi");
722 		HIF_STATS_INC(ipci_scn, mhi_force_wake_failure, 1);
723 		return -EINVAL;
724 	}
725 	HIF_STATS_INC(ipci_scn, mhi_force_wake_success, 1);
726 
727 	HIF_STATS_INC(ipci_scn, soc_force_wake_success, 1);
728 
729 	return 0;
730 }
731 
732 int hif_force_wake_release(struct hif_opaque_softc *hif_handle)
733 {
734 	int ret;
735 	struct hif_softc *scn = (struct hif_softc *)hif_handle;
736 	struct hif_ipci_softc *ipci_scn = HIF_GET_IPCI_SOFTC(scn);
737 
738 	ret = pld_force_wake_release(scn->qdf_dev->dev);
739 	if (ret) {
740 		hif_err("force wake release failure");
741 		HIF_STATS_INC(ipci_scn, mhi_force_wake_release_failure, 1);
742 		return ret;
743 	}
744 
745 	HIF_STATS_INC(ipci_scn, mhi_force_wake_release_success, 1);
746 
747 	HIF_STATS_INC(ipci_scn, soc_force_wake_release_success, 1);
748 	return 0;
749 }
750 
751 void hif_print_ipci_stats(struct hif_ipci_softc *ipci_handle)
752 {
753 	hif_debug("mhi_force_wake_request_vote: %d",
754 		  ipci_handle->stats.mhi_force_wake_request_vote);
755 	hif_debug("mhi_force_wake_failure: %d",
756 		  ipci_handle->stats.mhi_force_wake_failure);
757 	hif_debug("mhi_force_wake_success: %d",
758 		  ipci_handle->stats.mhi_force_wake_success);
759 	hif_debug("soc_force_wake_register_write_success: %d",
760 		  ipci_handle->stats.soc_force_wake_register_write_success);
761 	hif_debug("soc_force_wake_failure: %d",
762 		  ipci_handle->stats.soc_force_wake_failure);
763 	hif_debug("soc_force_wake_success: %d",
764 		  ipci_handle->stats.soc_force_wake_success);
765 	hif_debug("mhi_force_wake_release_failure: %d",
766 		  ipci_handle->stats.mhi_force_wake_release_failure);
767 	hif_debug("mhi_force_wake_release_success: %d",
768 		  ipci_handle->stats.mhi_force_wake_release_success);
769 	hif_debug("oc_force_wake_release_success: %d",
770 		  ipci_handle->stats.soc_force_wake_release_success);
771 }
772 #endif /* FORCE_WAKE */
773