xref: /wlan-dirver/qca-wifi-host-cmn/hif/src/snoc/if_ahb.c (revision 302a1d9701784af5f4797b1a9fe07ae820b51907)
1 /*
2  * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /**
20  * DOC: if_ahb.c
21  *
22  * c file for ahb specific implementations.
23  */
24 
25 #include "hif.h"
26 #include "target_type.h"
27 #include "hif_main.h"
28 #include "hif_debug.h"
29 #include "hif_io32.h"
30 #include "ce_main.h"
31 #include "ce_api.h"
32 #include "ce_tasklet.h"
33 #include "if_ahb.h"
34 #include "if_pci.h"
35 #include "ahb_api.h"
36 #include "pci_api.h"
37 #include "hif_napi.h"
38 #include "qal_vbus_dev.h"
39 
40 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
41 #define IRQF_DISABLED 0x00000020
42 #endif
43 
44 #define HIF_IC_CE0_IRQ_OFFSET 4
45 #define HIF_IC_MAX_IRQ 54
46 
47 static uint8_t ic_irqnum[HIF_IC_MAX_IRQ];
48 /* integrated chip irq names */
49 const char *ic_irqname[HIF_IC_MAX_IRQ] = {
50 "misc-pulse1",
51 "misc-latch",
52 "sw-exception",
53 "watchdog",
54 "ce0",
55 "ce1",
56 "ce2",
57 "ce3",
58 "ce4",
59 "ce5",
60 "ce6",
61 "ce7",
62 "ce8",
63 "ce9",
64 "ce10",
65 "ce11",
66 "ce12",
67 "ce13",
68 "host2wbm-desc-feed",
69 "host2reo-re-injection",
70 "host2reo-command",
71 "host2rxdma-monitor-ring3",
72 "host2rxdma-monitor-ring2",
73 "host2rxdma-monitor-ring1",
74 "reo2ost-exception",
75 "wbm2host-rx-release",
76 "reo2host-status",
77 "reo2host-destination-ring4",
78 "reo2host-destination-ring3",
79 "reo2host-destination-ring2",
80 "reo2host-destination-ring1",
81 "rxdma2host-monitor-destination-mac3",
82 "rxdma2host-monitor-destination-mac2",
83 "rxdma2host-monitor-destination-mac1",
84 "ppdu-end-interrupts-mac3",
85 "ppdu-end-interrupts-mac2",
86 "ppdu-end-interrupts-mac1",
87 "rxdma2host-monitor-status-ring-mac3",
88 "rxdma2host-monitor-status-ring-mac2",
89 "rxdma2host-monitor-status-ring-mac1",
90 "host2rxdma-host-buf-ring-mac3",
91 "host2rxdma-host-buf-ring-mac2",
92 "host2rxdma-host-buf-ring-mac1",
93 "rxdma2host-destination-ring-mac3",
94 "rxdma2host-destination-ring-mac2",
95 "rxdma2host-destination-ring-mac1",
96 "host2tcl-input-ring4",
97 "host2tcl-input-ring3",
98 "host2tcl-input-ring2",
99 "host2tcl-input-ring1",
100 "wbm2host-tx-completions-ring3",
101 "wbm2host-tx-completions-ring2",
102 "wbm2host-tx-completions-ring1",
103 "tcl2host-status-ring",
104 };
105 
106 /**
107  * hif_disable_isr() - disable isr
108  *
109  * This function disables isr and kills tasklets
110  *
111  * @hif_ctx: struct hif_softc
112  *
113  * Return: void
114  */
115 void hif_ahb_disable_isr(struct hif_softc *scn)
116 {
117 	struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn);
118 
119 	hif_exec_kill(&scn->osc);
120 	hif_nointrs(scn);
121 	ce_tasklet_kill(scn);
122 	tasklet_kill(&sc->intr_tq);
123 	qdf_atomic_set(&scn->active_tasklet_cnt, 0);
124 	qdf_atomic_set(&scn->active_grp_tasklet_cnt, 0);
125 }
126 
127 /**
128  * hif_dump_registers() - dump bus debug registers
129  * @scn: struct hif_opaque_softc
130  *
131  * This function dumps hif bus debug registers
132  *
133  * Return: 0 for success or error code
134  */
135 int hif_ahb_dump_registers(struct hif_softc *hif_ctx)
136 {
137 	int status;
138 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
139 
140 	status = hif_dump_ce_registers(scn);
141 	if (status)
142 		HIF_ERROR("%s: Dump CE Registers Failed status %d", __func__,
143 							status);
144 
145 	return 0;
146 }
147 
148 /**
149  * hif_ahb_close() - hif_bus_close
150  * @scn: pointer to the hif context.
151  *
152  * This is a callback function for hif_bus_close.
153  *
154  *
155  * Return: n/a
156  */
157 void hif_ahb_close(struct hif_softc *scn)
158 {
159 	hif_ce_close(scn);
160 }
161 
162 /**
163  * hif_bus_open() - hif_ahb open
164  * @hif_ctx: hif context
165  * @bus_type: bus type
166  *
167  * This is a callback function for hif_bus_open.
168  *
169  * Return: n/a
170  */
171 QDF_STATUS hif_ahb_open(struct hif_softc *hif_ctx, enum qdf_bus_type bus_type)
172 {
173 
174 	struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(hif_ctx);
175 
176 	qdf_spinlock_create(&sc->irq_lock);
177 	return hif_ce_open(hif_ctx);
178 }
179 
180 /**
181  * hif_bus_configure() - Configure the bus
182  * @scn: pointer to the hif context.
183  *
184  * This function configure the ahb bus
185  *
186  * return: 0 for success. nonzero for failure.
187  */
188 int hif_ahb_bus_configure(struct hif_softc *scn)
189 {
190 	return hif_pci_bus_configure(scn);
191 }
192 
193 /**
194  * hif_configure_msi_ahb - Configure MSI interrupts
195  * @sc : pointer to the hif context
196  *
197  * return: 0 for success. nonzero for failure.
198  */
199 
200 int hif_configure_msi_ahb(struct hif_pci_softc *sc)
201 {
202 	return 0;
203 }
204 
205 /**
206  * hif_ahb_configure_legacy_irq() - Configure Legacy IRQ
207  * @sc: pointer to the hif context.
208  *
209  * This function registers the irq handler and enables legacy interrupts
210  *
211  * return: 0 for success. nonzero for failure.
212  */
213 int hif_ahb_configure_legacy_irq(struct hif_pci_softc *sc)
214 {
215 	int ret = 0;
216 	struct hif_softc *scn = HIF_GET_SOFTC(sc);
217 	struct platform_device *pdev = (struct platform_device *)sc->pdev;
218 	int irq = 0;
219 
220 	/* do not support MSI or MSI IRQ failed */
221 	tasklet_init(&sc->intr_tq, wlan_tasklet, (unsigned long)sc);
222 	qal_vbus_get_irq((struct qdf_pfm_hndl *)pdev, "legacy", &irq);
223 	if (irq < 0) {
224 		dev_err(&pdev->dev, "Unable to get irq\n");
225 		ret = -1;
226 		goto end;
227 	}
228 	ret = request_irq(irq, hif_pci_legacy_ce_interrupt_handler,
229 				IRQF_DISABLED, "wlan_ahb", sc);
230 	if (ret) {
231 		dev_err(&pdev->dev, "ath_request_irq failed\n");
232 		ret = -1;
233 		goto end;
234 	}
235 	sc->irq = irq;
236 
237 	/* Use Legacy PCI Interrupts */
238 	hif_write32_mb(sc, sc->mem + (SOC_CORE_BASE_ADDRESS |
239 				PCIE_INTR_ENABLE_ADDRESS),
240 			PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL);
241 	/* read once to flush */
242 	hif_read32_mb(sc, sc->mem + (SOC_CORE_BASE_ADDRESS |
243 				PCIE_INTR_ENABLE_ADDRESS));
244 
245 end:
246 	return ret;
247 }
248 
249 int hif_ahb_configure_irq(struct hif_pci_softc *sc)
250 {
251 	int ret = 0;
252 	struct hif_softc *scn = HIF_GET_SOFTC(sc);
253 	struct platform_device *pdev = (struct platform_device *)sc->pdev;
254 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
255 	struct CE_attr *host_ce_conf = hif_state->host_ce_config;
256 	int irq = 0;
257 	int i;
258 
259 	/* configure per CE interrupts */
260 	for (i = 0; i < scn->ce_count; i++) {
261 		if (host_ce_conf[i].flags & CE_ATTR_DISABLE_INTR)
262 			continue;
263 		qal_vbus_get_irq((struct qdf_pfm_hndl *)pdev,
264 				 ic_irqname[HIF_IC_CE0_IRQ_OFFSET + i], &irq);
265 		ic_irqnum[HIF_IC_CE0_IRQ_OFFSET + i] = irq;
266 		ret = request_irq(irq ,
267 				hif_ahb_interrupt_handler,
268 				IRQF_TRIGGER_RISING, ic_irqname[HIF_IC_CE0_IRQ_OFFSET + i],
269 				&hif_state->tasklets[i]);
270 		if (ret) {
271 			dev_err(&pdev->dev, "ath_request_irq failed\n");
272 			ret = -1;
273 			goto end;
274 		}
275 		hif_ahb_irq_enable(scn, i);
276 	}
277 
278 end:
279 	return ret;
280 }
281 
282 int hif_ahb_configure_grp_irq(struct hif_softc *scn,
283 			      struct hif_exec_context *hif_ext_group)
284 {
285 	int ret = 0;
286 	struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn);
287 	struct platform_device *pdev = (struct platform_device *)sc->pdev;
288 	int irq = 0;
289 	int j;
290 
291 	/* configure external interrupts */
292 	hif_ext_group->irq_enable = &hif_ahb_exec_grp_irq_enable;
293 	hif_ext_group->irq_disable = &hif_ahb_exec_grp_irq_disable;
294 	hif_ext_group->work_complete = &hif_dummy_grp_done;
295 
296 	qdf_spin_lock_irqsave(&hif_ext_group->irq_lock);
297 
298 	for (j = 0; j < hif_ext_group->numirq; j++) {
299 		qal_vbus_get_irq((struct qdf_pfm_hndl *)pdev,
300 				 ic_irqname[hif_ext_group->irq[j]], &irq);
301 
302 		ic_irqnum[hif_ext_group->irq[j]] = irq;
303 		irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY);
304 		ret = request_irq(irq, hif_ext_group_interrupt_handler,
305 				  IRQF_TRIGGER_RISING,
306 				  ic_irqname[hif_ext_group->irq[j]],
307 				  hif_ext_group);
308 		if (ret) {
309 			dev_err(&pdev->dev,
310 				"ath_request_irq failed\n");
311 			ret = -1;
312 			goto end;
313 		}
314 		hif_ext_group->os_irq[j] = irq;
315 	}
316 	qdf_spin_unlock_irqrestore(&hif_ext_group->irq_lock);
317 
318 	qdf_spin_lock_irqsave(&hif_ext_group->irq_lock);
319 	hif_ext_group->irq_requested = true;
320 
321 end:
322 	qdf_spin_unlock_irqrestore(&hif_ext_group->irq_lock);
323 	return ret;
324 }
325 
326 void hif_ahb_deconfigure_grp_irq(struct hif_softc *scn)
327 {
328 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
329 	struct hif_exec_context *hif_ext_group;
330 	int i, j;
331 	int irq = 0;
332 
333 	/* configure external interrupts */
334 	for (i = 0; i < hif_state->hif_num_extgroup; i++) {
335 		hif_ext_group = hif_state->hif_ext_group[i];
336 		if (hif_ext_group->irq_requested == true) {
337 			qdf_spin_lock_irqsave(&hif_ext_group->irq_lock);
338 			hif_ext_group->irq_requested = false;
339 			for (j = 0; j < hif_ext_group->numirq; j++) {
340 				irq = hif_ext_group->os_irq[j];
341 				irq_clear_status_flags(irq,
342 						       IRQ_DISABLE_UNLAZY);
343 				free_irq(irq, hif_ext_group);
344 			}
345 			qdf_spin_unlock_irqrestore(&hif_ext_group->irq_lock);
346 		}
347 	}
348 }
349 
350 irqreturn_t hif_ahb_interrupt_handler(int irq, void *context)
351 {
352 	struct ce_tasklet_entry *tasklet_entry = context;
353 	return ce_dispatch_interrupt(tasklet_entry->ce_id, tasklet_entry);
354 }
355 
356 /**
357  * hif_target_sync() : ensure the target is ready
358  * @scn: hif control structure
359  *
360  * Informs fw that we plan to use legacy interupts so that
361  * it can begin booting. Ensures that the fw finishes booting
362  * before continuing. Should be called before trying to write
363  * to the targets other registers for the first time.
364  *
365  * Return: none
366  */
367 int hif_target_sync_ahb(struct hif_softc *scn)
368 {
369 	int val = 0;
370 	int limit = 0;
371 
372 	while (limit < 50) {
373 		hif_write32_mb(scn, scn->mem +
374 			(SOC_CORE_BASE_ADDRESS | PCIE_INTR_ENABLE_ADDRESS),
375 			PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL);
376 		qdf_mdelay(10);
377 		val = hif_read32_mb(scn, scn->mem +
378 			(SOC_CORE_BASE_ADDRESS | PCIE_INTR_ENABLE_ADDRESS));
379 		if (val == 0)
380 			break;
381 		limit++;
382 	}
383 	hif_write32_mb(scn, scn->mem +
384 		(SOC_CORE_BASE_ADDRESS | PCIE_INTR_ENABLE_ADDRESS),
385 		PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL);
386 	hif_write32_mb(scn, scn->mem + FW_INDICATOR_ADDRESS, FW_IND_HOST_READY);
387 	if (HAS_FW_INDICATOR) {
388 		int wait_limit = 500;
389 		int fw_ind = 0;
390 
391 		while (1) {
392 			fw_ind = hif_read32_mb(scn, scn->mem +
393 					FW_INDICATOR_ADDRESS);
394 			if (fw_ind & FW_IND_INITIALIZED)
395 				break;
396 			if (wait_limit-- < 0)
397 				break;
398 			hif_write32_mb(scn, scn->mem + (SOC_CORE_BASE_ADDRESS |
399 				PCIE_INTR_ENABLE_ADDRESS),
400 				PCIE_INTR_FIRMWARE_MASK);
401 			qdf_mdelay(10);
402 		}
403 		if (wait_limit < 0) {
404 			HIF_TRACE("%s: FW signal timed out", __func__);
405 			return -EIO;
406 		}
407 		HIF_TRACE("%s: Got FW signal, retries = %x", __func__,
408 							500-wait_limit);
409 	}
410 
411 	return 0;
412 }
413 
414 /**
415  * hif_disable_bus() - Disable the bus
416  * @scn : pointer to the hif context
417  *
418  * This function disables the bus and helds the target in reset state
419  *
420  * Return: none
421  */
422 void hif_ahb_disable_bus(struct hif_softc *scn)
423 {
424 	struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn);
425 	void __iomem *mem;
426 	struct platform_device *pdev = (struct platform_device *)sc->pdev;
427 	struct resource *memres = NULL;
428 	int mem_pa_size = 0;
429 	struct hif_target_info *tgt_info = NULL;
430 	struct qdf_vbus_resource *vmres = NULL;
431 
432 	tgt_info = &scn->target_info;
433 	/*Disable WIFI clock input*/
434 	if (sc->mem) {
435 		qal_vbus_get_resource((struct qdf_pfm_hndl *)pdev, &vmres,
436 				      IORESOURCE_MEM, 0);
437 		memres = (struct resource *)vmres;
438 		if (!memres) {
439 			HIF_INFO("%s: Failed to get IORESOURCE_MEM\n",
440 								__func__);
441 			return;
442 		}
443 		mem_pa_size = memres->end - memres->start + 1;
444 
445 		/* Should not be executed on 8074 platform */
446 		if ((tgt_info->target_type != TARGET_TYPE_QCA8074) &&
447 		    (tgt_info->target_type != TARGET_TYPE_QCA8074V2)) {
448 			hif_ahb_clk_enable_disable(&pdev->dev, 0);
449 
450 			hif_ahb_device_reset(scn);
451 		}
452 		mem = (void __iomem *)sc->mem;
453 		if (mem) {
454 			devm_iounmap(&pdev->dev, mem);
455 			devm_release_mem_region(&pdev->dev, scn->mem_pa,
456 								mem_pa_size);
457 			sc->mem = NULL;
458 		}
459 	}
460 	scn->mem = NULL;
461 }
462 
463 /**
464  * hif_enable_bus() - Enable the bus
465  * @dev: dev
466  * @bdev: bus dev
467  * @bid: bus id
468  * @type: bus type
469  *
470  * This function enables the radio bus by enabling necessary
471  * clocks and waits for the target to get ready to proceed futher
472  *
473  * Return: QDF_STATUS
474  */
475 QDF_STATUS hif_ahb_enable_bus(struct hif_softc *ol_sc,
476 		struct device *dev, void *bdev,
477 		const struct hif_bus_id *bid,
478 		enum hif_enable_type type)
479 {
480 	int ret = 0;
481 	int hif_type;
482 	int target_type;
483 	const struct platform_device_id *id = (struct platform_device_id *)bid;
484 	struct platform_device *pdev = bdev;
485 	struct hif_target_info *tgt_info = NULL;
486 	struct resource *memres = NULL;
487 	void __iomem *mem = NULL;
488 	uint32_t revision_id = 0;
489 	struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(ol_sc);
490 
491 	sc->pdev = (struct pci_dev *)pdev;
492 	sc->dev = &pdev->dev;
493 	sc->devid = id->driver_data;
494 
495 	ret = hif_get_device_type(id->driver_data, revision_id,
496 			&hif_type, &target_type);
497 	if (ret < 0) {
498 		HIF_ERROR("%s: invalid device  ret %d id %d revision_id %d",
499 			__func__, ret, (int)id->driver_data, revision_id);
500 		return QDF_STATUS_E_FAILURE;
501 	}
502 
503 	memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
504 	if (!memres) {
505 		HIF_INFO("%s: Failed to get IORESOURCE_MEM\n", __func__);
506 		return -EIO;
507 	}
508 
509 	ret = dma_set_mask(dev, DMA_BIT_MASK(32));
510 	if (ret) {
511 		HIF_INFO("ath: 32-bit DMA not available\n");
512 		goto err_cleanup1;
513 	}
514 
515 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
516 	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
517 #else
518 	ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
519 #endif
520 	if (ret) {
521 		HIF_ERROR("%s: failed to set dma mask error = %d",
522 				__func__, ret);
523 		return ret;
524 	}
525 
526 	/* Arrange for access to Target SoC registers. */
527 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
528 	mem = devm_ioremap_resource(&pdev->dev, memres);
529 #else
530 	mem = devm_request_and_ioremap(&pdev->dev, memres);
531 #endif
532 	if (IS_ERR(mem)) {
533 		HIF_INFO("ath: ioremap error\n");
534 		ret = PTR_ERR(mem);
535 		goto err_cleanup1;
536 	}
537 
538 	sc->mem = mem;
539 	ol_sc->mem = mem;
540 	ol_sc->mem_pa = memres->start;
541 
542 	tgt_info = hif_get_target_info_handle((struct hif_opaque_softc *)ol_sc);
543 
544 	tgt_info->target_type = target_type;
545 	hif_register_tbl_attach(ol_sc, hif_type);
546 	hif_target_register_tbl_attach(ol_sc, target_type);
547 
548 	/* QCA_WIFI_QCA8074_VP:Should not be executed on 8074 VP platform */
549 	if ((tgt_info->target_type != TARGET_TYPE_QCA8074) &&
550 	    (tgt_info->target_type != TARGET_TYPE_QCA8074V2)) {
551 		if (hif_ahb_enable_radio(sc, pdev, id) != 0) {
552 			HIF_INFO("error in enabling soc\n");
553 			return -EIO;
554 		}
555 
556 		if (hif_target_sync_ahb(ol_sc) < 0) {
557 			ret = -EIO;
558 			goto err_target_sync;
559 		}
560 	}
561 	HIF_TRACE("%s: X - hif_type = 0x%x, target_type = 0x%x",
562 			__func__, hif_type, target_type);
563 
564 	return QDF_STATUS_SUCCESS;
565 err_target_sync:
566 	/* QCA_WIFI_QCA8074_VP:Should not be executed on 8074 VP platform */
567 	if ((tgt_info->target_type != TARGET_TYPE_QCA8074) &&
568 	    (tgt_info->target_type != TARGET_TYPE_QCA8074V2)) {
569 		HIF_INFO("Error: Disabling target\n");
570 		hif_ahb_disable_bus(ol_sc);
571 	}
572 err_cleanup1:
573 	return ret;
574 }
575 
576 
577 /**
578  * hif_reset_soc() - reset soc
579  *
580  * @hif_ctx: HIF context
581  *
582  * This function resets soc and helds the
583  * target in reset state
584  *
585  * Return: void
586  */
587 /* Function to reset SoC */
588 void hif_ahb_reset_soc(struct hif_softc *hif_ctx)
589 {
590 	hif_ahb_device_reset(hif_ctx);
591 }
592 
593 
594 /**
595  * hif_nointrs() - disable IRQ
596  *
597  * @scn: struct hif_softc
598  *
599  * This function stops interrupt(s)
600  *
601  * Return: none
602  */
603 void hif_ahb_nointrs(struct hif_softc *scn)
604 {
605 	int i;
606 	struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn);
607 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
608 	struct CE_attr *host_ce_conf = hif_state->host_ce_config;
609 
610 	ce_unregister_irq(hif_state, CE_ALL_BITMAP);
611 
612 	if (scn->request_irq_done == false)
613 		return;
614 
615 	if (sc->num_msi_intrs > 0) {
616 		/* MSI interrupt(s) */
617 		for (i = 0; i < sc->num_msi_intrs; i++) {
618 			free_irq(sc->irq + i, sc);
619 		}
620 		sc->num_msi_intrs = 0;
621 	} else {
622 		if (!scn->per_ce_irq) {
623 			free_irq(sc->irq, sc);
624 		} else {
625 			for (i = 0; i < scn->ce_count; i++) {
626 				if (host_ce_conf[i].flags
627 						& CE_ATTR_DISABLE_INTR)
628 					continue;
629 
630 				free_irq(ic_irqnum[HIF_IC_CE0_IRQ_OFFSET + i],
631 						&hif_state->tasklets[i]);
632 			}
633 			hif_ahb_deconfigure_grp_irq(scn);
634 		}
635 	}
636 	scn->request_irq_done = false;
637 
638 }
639 
640 /**
641  * ce_irq_enable() - enable copy engine IRQ
642  * @scn: struct hif_softc
643  * @ce_id: ce_id
644  *
645  * This function enables the interrupt for the radio.
646  *
647  * Return: N/A
648  */
649 void hif_ahb_irq_enable(struct hif_softc *scn, int ce_id)
650 {
651 	uint32_t regval;
652 	uint32_t reg_offset = 0;
653 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
654 	struct CE_pipe_config *target_ce_conf = &hif_state->target_ce_config[ce_id];
655 	struct hif_target_info *tgt_info = &scn->target_info;
656 
657 	if (scn->per_ce_irq) {
658 		if (target_ce_conf->pipedir & PIPEDIR_OUT) {
659 			reg_offset = HOST_IE_ADDRESS;
660 			qdf_spin_lock_irqsave(&hif_state->irq_reg_lock);
661 			regval = hif_read32_mb(scn, scn->mem + reg_offset);
662 			regval |= HOST_IE_REG1_CE_BIT(ce_id);
663 			hif_write32_mb(scn, scn->mem + reg_offset, regval);
664 			qdf_spin_unlock_irqrestore(&hif_state->irq_reg_lock);
665 		}
666 		if (target_ce_conf->pipedir & PIPEDIR_IN) {
667 			reg_offset = HOST_IE_ADDRESS_2;
668 			qdf_spin_lock_irqsave(&hif_state->irq_reg_lock);
669 			regval = hif_read32_mb(scn, scn->mem + reg_offset);
670 			regval |= HOST_IE_REG2_CE_BIT(ce_id);
671 			hif_write32_mb(scn, scn->mem + reg_offset, regval);
672 			if (tgt_info->target_type == TARGET_TYPE_QCA8074) {
673 				/* Enable destination ring interrupts for 8074
674 				 * TODO: To be removed in 2.0 HW */
675 				regval = hif_read32_mb(scn, scn->mem +
676 					HOST_IE_ADDRESS_3);
677 				regval |= HOST_IE_REG3_CE_BIT(ce_id);
678 			}
679 			hif_write32_mb(scn, scn->mem + HOST_IE_ADDRESS_3,
680 				       regval);
681 			qdf_spin_unlock_irqrestore(&hif_state->irq_reg_lock);
682 		}
683 	} else {
684 		hif_pci_irq_enable(scn, ce_id);
685 	}
686 }
687 
688 /**
689  * ce_irq_disable() - disable copy engine IRQ
690  * @scn: struct hif_softc
691  * @ce_id: ce_id
692  *
693  * Return: N/A
694  */
695 void hif_ahb_irq_disable(struct hif_softc *scn, int ce_id)
696 {
697 	uint32_t regval;
698 	uint32_t reg_offset = 0;
699 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
700 	struct CE_pipe_config *target_ce_conf = &hif_state->target_ce_config[ce_id];
701 	struct hif_target_info *tgt_info = &scn->target_info;
702 
703 	if (scn->per_ce_irq) {
704 		if (target_ce_conf->pipedir & PIPEDIR_OUT) {
705 			reg_offset = HOST_IE_ADDRESS;
706 			qdf_spin_lock_irqsave(&hif_state->irq_reg_lock);
707 			regval = hif_read32_mb(scn, scn->mem + reg_offset);
708 			regval &= ~HOST_IE_REG1_CE_BIT(ce_id);
709 			hif_write32_mb(scn, scn->mem + reg_offset, regval);
710 			qdf_spin_unlock_irqrestore(&hif_state->irq_reg_lock);
711 		}
712 		if (target_ce_conf->pipedir & PIPEDIR_IN) {
713 			reg_offset = HOST_IE_ADDRESS_2;
714 			qdf_spin_lock_irqsave(&hif_state->irq_reg_lock);
715 			regval = hif_read32_mb(scn, scn->mem + reg_offset);
716 			regval &= ~HOST_IE_REG2_CE_BIT(ce_id);
717 			hif_write32_mb(scn, scn->mem + reg_offset, regval);
718 			if (tgt_info->target_type == TARGET_TYPE_QCA8074) {
719 				/* Disable destination ring interrupts for 8074
720 				 * TODO: To be removed in 2.0 HW */
721 				regval = hif_read32_mb(scn, scn->mem +
722 					HOST_IE_ADDRESS_3);
723 				regval &= ~HOST_IE_REG3_CE_BIT(ce_id);
724 			}
725 			hif_write32_mb(scn, scn->mem + HOST_IE_ADDRESS_3,
726 				       regval);
727 			qdf_spin_unlock_irqrestore(&hif_state->irq_reg_lock);
728 		}
729 	}
730 }
731 
732 void hif_ahb_exec_grp_irq_disable(struct hif_exec_context *hif_ext_group)
733 {
734 	int i;
735 
736 	qdf_spin_lock_irqsave(&hif_ext_group->irq_lock);
737 	if (hif_ext_group->irq_enabled) {
738 		for (i = 0; i < hif_ext_group->numirq; i++) {
739 			disable_irq_nosync(hif_ext_group->os_irq[i]);
740 		}
741 		hif_ext_group->irq_enabled = false;
742 	}
743 	qdf_spin_unlock_irqrestore(&hif_ext_group->irq_lock);
744 }
745 
746 void hif_ahb_exec_grp_irq_enable(struct hif_exec_context *hif_ext_group)
747 {
748 	int i;
749 
750 	qdf_spin_lock_irqsave(&hif_ext_group->irq_lock);
751 	if (!hif_ext_group->irq_enabled) {
752 		for (i = 0; i < hif_ext_group->numirq; i++) {
753 			enable_irq(hif_ext_group->os_irq[i]);
754 		}
755 		hif_ext_group->irq_enabled = true;
756 	}
757 	qdf_spin_unlock_irqrestore(&hif_ext_group->irq_lock);
758 }
759 
760 /**
761  * hif_ahb_needs_bmi() - return true if the soc needs bmi through the driver
762  * @scn: hif context
763  *
764  * Return: true if soc needs driver bmi otherwise false
765  */
766 bool hif_ahb_needs_bmi(struct hif_softc *scn)
767 {
768 	return !ce_srng_based(scn);
769 }
770