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