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