blob: a137c1e67b0d58c6515c886307b53bbd21628413 [file] [log] [blame]
Houston Hoffman3db96a42016-05-05 19:54:39 -07001/*
2 * Copyright (c) 2013-2016 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 "hif_main.h"
27#include "hif_debug.h"
28#include "hif_io32.h"
29#include "ce_main.h"
30#include "ce_tasklet.h"
31#include "if_ahb.h"
32#include "if_pci.h"
33#include "ahb_api.h"
Aravind Narasimhana1c7d6d2016-06-01 10:21:32 +053034#include "pci_api.h"
Venkateswara Swamy Bandaru31108f32016-08-08 18:04:29 +053035#include "hif_napi.h"
Houston Hoffman3db96a42016-05-05 19:54:39 -070036
37#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
38#define IRQF_DISABLED 0x00000020
39#endif
Venkateswara Swamy Bandaru9fd9af02016-09-20 20:27:31 +053040
41#define HIF_IC_CE0_IRQ_OFFSET 4
42#define HIF_IC_MAX_IRQ 54
43
Venkateswara Swamy Bandaru31108f32016-08-08 18:04:29 +053044static uint8_t ic_irqnum[HIF_IC_MAX_IRQ];
Venkateswara Swamy Bandaru9fd9af02016-09-20 20:27:31 +053045/* integrated chip irq names */
46const char *ic_irqname[HIF_IC_MAX_IRQ] = {
Pamidipati, Vijay30dc8f22016-10-26 21:54:23 +053047"misc-pulse1",
48"misc-latch",
49"sw-exception",
Venkateswara Swamy Bandaru9fd9af02016-09-20 20:27:31 +053050"watchdog",
51"ce0",
52"ce1",
53"ce2",
54"ce3",
55"ce4",
56"ce5",
57"ce6",
58"ce7",
59"ce8",
60"ce9",
61"ce10",
62"ce11",
63"ce12",
64"ce13",
Pamidipati, Vijay30dc8f22016-10-26 21:54:23 +053065"host2wbm-desc-feed",
66"host2reo-re-injection",
67"host2reo-command",
68"host2rxdma-monitor-ring3",
69"host2rxdma-monitor-ring2",
70"host2rxdma-monitor-ring1",
71"reo2ost-exception",
72"wbm2host-rx-release",
73"reo2host-status",
74"reo2host-destination-ring4",
75"reo2host-destination-ring3",
76"reo2host-destination-ring2",
77"reo2host-destination-ring1",
78"rxdma2host-monitor-destination-mac3",
79"rxdma2host-monitor-destination-mac2",
80"rxdma2host-monitor-destination-mac1",
81"ppdu-end-interrupts-mac3",
82"ppdu-end-interrupts-mac2",
83"ppdu-end-interrupts-mac1",
84"rxdma2host-monitor-status-ring-mac3",
85"rxdma2host-monitor-status-ring-mac2",
86"rxdma2host-monitor-status-ring-mac1",
87"host2rxdma-host-buf-ring-mac3",
88"host2rxdma-host-buf-ring-mac2",
89"host2rxdma-host-buf-ring-mac1",
90"rxdma2host-destination-ring-mac3",
91"rxdma2host-destination-ring-mac2",
92"rxdma2host-destination-ring-mac1",
93"host2tcl-input-ring4",
94"host2tcl-input-ring3",
95"host2tcl-input-ring2",
96"host2tcl-input-ring1",
97"wbm2host-tx-completions-ring3",
98"wbm2host-tx-completions-ring2",
99"wbm2host-tx-completions-ring1",
100"tcl2host-status-ring",
Venkateswara Swamy Bandaru9fd9af02016-09-20 20:27:31 +0530101};
102
Houston Hoffman3db96a42016-05-05 19:54:39 -0700103/**
104 * hif_disable_isr() - disable isr
105 *
106 * This function disables isr and kills tasklets
107 *
108 * @hif_ctx: struct hif_softc
109 *
110 * Return: void
111 */
112void hif_ahb_disable_isr(struct hif_softc *scn)
113{
114 struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn);
115
116 hif_nointrs(scn);
117 ce_tasklet_kill(scn);
Venkateswara Swamy Bandaru31108f32016-08-08 18:04:29 +0530118 hif_grp_tasklet_kill(scn);
Houston Hoffman3db96a42016-05-05 19:54:39 -0700119 tasklet_kill(&sc->intr_tq);
120 qdf_atomic_set(&scn->active_tasklet_cnt, 0);
Venkateswara Swamy Bandaru31108f32016-08-08 18:04:29 +0530121 qdf_atomic_set(&scn->active_grp_tasklet_cnt, 0);
Houston Hoffman3db96a42016-05-05 19:54:39 -0700122}
123
124/**
125 * hif_dump_registers() - dump bus debug registers
126 * @scn: struct hif_opaque_softc
127 *
128 * This function dumps hif bus debug registers
129 *
130 * Return: 0 for success or error code
131 */
132int hif_ahb_dump_registers(struct hif_softc *hif_ctx)
133{
134 int status;
135 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
136
137 status = hif_dump_ce_registers(scn);
138 if (status)
139 HIF_ERROR("%s: Dump CE Registers Failed status %d", __func__,
140 status);
141
142 return 0;
143}
144
145/**
146 * hif_ahb_close() - hif_bus_close
147 * @scn: pointer to the hif context.
148 *
149 * This is a callback function for hif_bus_close.
150 *
151 *
152 * Return: n/a
153 */
154void hif_ahb_close(struct hif_softc *scn)
155{
156 hif_ce_close(scn);
157}
158
159/**
160 * hif_bus_open() - hif_ahb open
161 * @hif_ctx: hif context
162 * @bus_type: bus type
163 *
164 * This is a callback function for hif_bus_open.
165 *
166 * Return: n/a
167 */
168QDF_STATUS hif_ahb_open(struct hif_softc *hif_ctx, enum qdf_bus_type bus_type)
169{
170
171 struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(hif_ctx);
172
173 qdf_spinlock_create(&sc->irq_lock);
174 return hif_ce_open(hif_ctx);
175}
176
177/**
178 * hif_bus_configure() - Configure the bus
179 * @scn: pointer to the hif context.
180 *
181 * This function configure the ahb bus
182 *
183 * return: 0 for success. nonzero for failure.
184 */
185int hif_ahb_bus_configure(struct hif_softc *scn)
186{
187 return hif_pci_bus_configure(scn);
188}
189
190/**
191 * hif_configure_msi_ahb - Configure MSI interrupts
192 * @sc : pointer to the hif context
193 *
194 * return: 0 for success. nonzero for failure.
195 */
196
197int hif_configure_msi_ahb(struct hif_pci_softc *sc)
198{
199 return 0;
200}
201
202/**
203 * hif_ahb_configure_legacy_irq() - Configure Legacy IRQ
204 * @sc: pointer to the hif context.
205 *
206 * This function registers the irq handler and enables legacy interrupts
207 *
208 * return: 0 for success. nonzero for failure.
209 */
210int hif_ahb_configure_legacy_irq(struct hif_pci_softc *sc)
211{
212 int ret = 0;
213 struct hif_softc *scn = HIF_GET_SOFTC(sc);
214 struct platform_device *pdev = (struct platform_device *)sc->pdev;
215 int irq = 0;
216
217 /* do not support MSI or MSI IRQ failed */
218 tasklet_init(&sc->intr_tq, wlan_tasklet, (unsigned long)sc);
219 irq = platform_get_irq_byname(pdev, "legacy");
220 if (irq < 0) {
221 dev_err(&pdev->dev, "Unable to get irq\n");
222 ret = -1;
223 goto end;
224 }
225 ret = request_irq(irq, hif_pci_interrupt_handler,
226 IRQF_DISABLED, "wlan_ahb", sc);
227 if (ret) {
228 dev_err(&pdev->dev, "ath_request_irq failed\n");
229 ret = -1;
230 goto end;
231 }
232 sc->irq = irq;
233
234 /* Use Legacy PCI Interrupts */
235 hif_write32_mb(sc->mem+(SOC_CORE_BASE_ADDRESS |
236 PCIE_INTR_ENABLE_ADDRESS),
237 PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL);
238 /* read once to flush */
239 hif_read32_mb(sc->mem+(SOC_CORE_BASE_ADDRESS |
240 PCIE_INTR_ENABLE_ADDRESS)
241 );
242
243end:
244 return ret;
245}
246
Venkateswara Swamy Bandaru9fd9af02016-09-20 20:27:31 +0530247int hif_ahb_configure_irq(struct hif_pci_softc *sc)
248{
249 int ret = 0;
250 struct hif_softc *scn = HIF_GET_SOFTC(sc);
251 struct platform_device *pdev = (struct platform_device *)sc->pdev;
Venkateswara Swamy Bandaru31108f32016-08-08 18:04:29 +0530252 struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
253 struct hif_ext_group_entry *hif_ext_group;
Venkateswara Swamy Bandaru9fd9af02016-09-20 20:27:31 +0530254 int irq = 0;
Venkateswara Swamy Bandaru31108f32016-08-08 18:04:29 +0530255 int i, j;
Venkateswara Swamy Bandaru9fd9af02016-09-20 20:27:31 +0530256
257 /* configure per CE interrupts */
258 for (i = 0; i < scn->ce_count; i++) {
259 irq = platform_get_irq_byname(pdev, ic_irqname[HIF_IC_CE0_IRQ_OFFSET + i]);
Venkateswara Swamy Bandaru31108f32016-08-08 18:04:29 +0530260 ic_irqnum[HIF_IC_CE0_IRQ_OFFSET + i] = irq;
Venkateswara Swamy Bandaru9fd9af02016-09-20 20:27:31 +0530261 ret = request_irq(irq ,
262 hif_ahb_interrupt_handler,
263 IRQF_TRIGGER_RISING, ic_irqname[HIF_IC_CE0_IRQ_OFFSET + i],
Venkateswara Swamy Bandaru31108f32016-08-08 18:04:29 +0530264 &hif_state->tasklets[i]);
Venkateswara Swamy Bandaru9fd9af02016-09-20 20:27:31 +0530265 if (ret) {
266 dev_err(&pdev->dev, "ath_request_irq failed\n");
267 ret = -1;
268 goto end;
269 }
270 hif_ahb_irq_enable(scn, i);
271 }
272
Venkateswara Swamy Bandaru31108f32016-08-08 18:04:29 +0530273 /* configure external interrupts */
274 for (i = 0; i < hif_state->hif_num_extgroup; i++) {
275
276 hif_ext_group = &hif_state->hif_ext_group[i];
277 if (hif_ext_group->configured) {
278
279 tasklet_init(&hif_ext_group->intr_tq,
280 hif_ext_grp_tasklet,
281 (unsigned long)hif_ext_group);
282 hif_ext_group->inited = true;
283
284 for (j = 0; j < hif_ext_group->numirq; j++) {
285 irq = platform_get_irq_byname(pdev,
286 ic_irqname[hif_ext_group->irq[j]]);
287
288 ic_irqnum[hif_ext_group->irq[j]] = irq;
289 ret = request_irq(irq,
290 hif_ext_group_ahb_interrupt_handler,
291 IRQF_TRIGGER_RISING, "wlan_ahb",
292 hif_ext_group);
293 if (ret) {
294 dev_err(&pdev->dev,
295 "ath_request_irq failed\n");
296 ret = -1;
297 goto end;
298 }
299 }
300 }
301 }
302
Venkateswara Swamy Bandaru9fd9af02016-09-20 20:27:31 +0530303end:
304 return ret;
305}
306
307irqreturn_t hif_ahb_interrupt_handler(int irq, void *context)
308{
309 struct ce_tasklet_entry *tasklet_entry = context;
310 return ce_dispatch_interrupt(tasklet_entry->ce_id, tasklet_entry);
311}
312
Venkateswara Swamy Bandaru31108f32016-08-08 18:04:29 +0530313irqreturn_t hif_ext_group_ahb_interrupt_handler(int irq, void *context)
314{
315 struct hif_ext_group_entry *hif_ext_group = context;
316 struct HIF_CE_state *hif_state = hif_ext_group->hif_state;
317 struct hif_softc *scn = HIF_GET_SOFTC(hif_state);
318 struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(scn);
319 uint32_t grp_id = hif_ext_group->grp_id;
320
321 hif_grp_irq_disable(scn, grp_id);
322
323 qdf_atomic_inc(&scn->active_grp_tasklet_cnt);
324
325 if (hif_ext_napi_enabled(hif_hdl, grp_id)) {
326 hif_napi_schedule_grp(hif_hdl, grp_id);
327 } else {
328 tasklet_schedule(&hif_ext_group->intr_tq);
329 }
330
331 return IRQ_HANDLED;
332}
Venkateswara Swamy Bandaru9fd9af02016-09-20 20:27:31 +0530333
Houston Hoffman3db96a42016-05-05 19:54:39 -0700334/**
335 * hif_target_sync() : ensure the target is ready
336 * @scn: hif control structure
337 *
338 * Informs fw that we plan to use legacy interupts so that
339 * it can begin booting. Ensures that the fw finishes booting
340 * before continuing. Should be called before trying to write
341 * to the targets other registers for the first time.
342 *
343 * Return: none
344 */
345int hif_target_sync_ahb(struct hif_softc *scn)
346{
347 hif_write32_mb(scn->mem + FW_INDICATOR_ADDRESS, FW_IND_HOST_READY);
348 if (HAS_FW_INDICATOR) {
349 int wait_limit = 500;
350 int fw_ind = 0;
351
352 while (1) {
353 fw_ind = hif_read32_mb(scn->mem +
354 FW_INDICATOR_ADDRESS);
355 if (fw_ind & FW_IND_INITIALIZED)
356 break;
357 if (wait_limit-- < 0)
358 break;
359 hif_write32_mb(scn->mem+(SOC_CORE_BASE_ADDRESS |
360 PCIE_INTR_ENABLE_ADDRESS),
361 PCIE_INTR_FIRMWARE_MASK);
362 qdf_mdelay(10);
363 }
364 if (wait_limit < 0) {
365 HIF_TRACE("%s: FW signal timed out", __func__);
366 return -EIO;
367 } else {
368 HIF_TRACE("%s: Got FW signal, retries = %x", __func__,
369 500-wait_limit);
370 }
371 }
372
373 return 0;
374}
375
376/**
377 * hif_disable_bus() - Disable the bus
378 * @scn : pointer to the hif context
379 *
380 * This function disables the bus and helds the target in reset state
381 *
382 * Return: none
383 */
384void hif_ahb_disable_bus(struct hif_softc *scn)
385{
386 struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn);
387 void __iomem *mem;
388 struct platform_device *pdev = (struct platform_device *)sc->pdev;
Venkateswara Swamy Bandaru3ca38e22016-08-05 14:51:19 +0530389 struct resource *memres = NULL;
390 int mem_pa_size = 0;
Houston Hoffman3db96a42016-05-05 19:54:39 -0700391
392 /*Disable WIFI clock input*/
Venkateswara Swamy Bandaru3ca38e22016-08-05 14:51:19 +0530393 if (sc->mem) {
394 memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
395 if (!memres) {
396 HIF_INFO("%s: Failed to get IORESOURCE_MEM\n",
397 __func__);
398 return;
399 }
400 mem_pa_size = memres->end - memres->start + 1;
Houston Hoffman3db96a42016-05-05 19:54:39 -0700401
Venkateswara Swamy Bandaru3ca38e22016-08-05 14:51:19 +0530402 hif_ahb_clk_enable_disable(&pdev->dev, 0);
403
404 hif_ahb_device_reset(scn);
405 mem = (void __iomem *)sc->mem;
406 if (mem) {
407 devm_iounmap(&pdev->dev, mem);
408 devm_release_mem_region(&pdev->dev, scn->mem_pa,
409 mem_pa_size);
410 sc->mem = NULL;
411 }
Houston Hoffman3db96a42016-05-05 19:54:39 -0700412 }
413 scn->mem = NULL;
414}
415
416/**
417 * hif_enable_bus() - Enable the bus
418 * @dev: dev
419 * @bdev: bus dev
420 * @bid: bus id
421 * @type: bus type
422 *
423 * This function enables the radio bus by enabling necessary
424 * clocks and waits for the target to get ready to proceed futher
425 *
426 * Return: QDF_STATUS
427 */
428QDF_STATUS hif_ahb_enable_bus(struct hif_softc *ol_sc,
429 struct device *dev, void *bdev,
430 const hif_bus_id *bid,
431 enum hif_enable_type type)
432{
433 int ret = 0;
434 int hif_type;
435 int target_type;
436 const struct platform_device_id *id = (struct platform_device_id *)bid;
437 struct platform_device *pdev = bdev;
438 struct hif_target_info *tgt_info = NULL;
439 struct resource *memres = NULL;
440 void __iomem *mem = NULL;
441 uint32_t revision_id = 0;
442 struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(ol_sc);
443
444 sc->pdev = (struct pci_dev *)pdev;
445 sc->dev = &pdev->dev;
446 sc->devid = id->driver_data;
447
448 ret = hif_get_device_type(id->driver_data, revision_id,
449 &hif_type, &target_type);
450 if (ret < 0) {
451 HIF_ERROR("%s: invalid device ret %d id %d revision_id %d",
452 __func__, ret, (int)id->driver_data, revision_id);
453 return QDF_STATUS_E_FAILURE;
454 }
455
456 memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
457 if (!memres) {
458 HIF_INFO("%s: Failed to get IORESOURCE_MEM\n", __func__);
459 return -EIO;
460 }
461
462 ret = dma_set_mask(dev, DMA_BIT_MASK(32));
463 if (ret) {
464 HIF_INFO("ath: 32-bit DMA not available\n");
465 goto err_cleanup1;
466 }
467
Houston Hoffman6296c3e2016-07-12 18:43:32 -0700468#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
Houston Hoffman3db96a42016-05-05 19:54:39 -0700469 ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
Houston Hoffman6296c3e2016-07-12 18:43:32 -0700470#else
471 ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
472#endif
Houston Hoffman3db96a42016-05-05 19:54:39 -0700473 if (ret) {
474 HIF_ERROR("%s: failed to set dma mask error = %d",
475 __func__, ret);
476 return ret;
477 }
478
479 /* Arrange for access to Target SoC registers. */
Houston Hoffman6296c3e2016-07-12 18:43:32 -0700480#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
Houston Hoffman3db96a42016-05-05 19:54:39 -0700481 mem = devm_ioremap_resource(&pdev->dev, memres);
Houston Hoffman6296c3e2016-07-12 18:43:32 -0700482#else
483 mem = devm_request_and_ioremap(&pdev->dev, memres);
484#endif
Houston Hoffman3db96a42016-05-05 19:54:39 -0700485 if (IS_ERR(mem)) {
486 HIF_INFO("ath: ioremap error\n");
487 ret = PTR_ERR(mem);
488 goto err_cleanup1;
489 }
490
491 sc->mem = mem;
492 ol_sc->mem = mem;
493 ol_sc->mem_pa = memres->start;
Venkateswara Swamy Bandaru3ca38e22016-08-05 14:51:19 +0530494
Houston Hoffman3db96a42016-05-05 19:54:39 -0700495 tgt_info = hif_get_target_info_handle((struct hif_opaque_softc *)ol_sc);
496
497 tgt_info->target_type = target_type;
498 hif_register_tbl_attach(ol_sc, hif_type);
Govind Singh051a8c42016-05-10 12:23:41 +0530499 hif_target_register_tbl_attach(ol_sc, target_type);
Houston Hoffman3db96a42016-05-05 19:54:39 -0700500
Pratik Gandhi815c6d82016-10-19 12:06:32 +0530501 /* QCA_WIFI_QCA8074_VP:Should not be executed on 8074 VP platform */
502 if (tgt_info->target_type != TARGET_TYPE_QCA8074) {
503 if (hif_ahb_enable_radio(sc, pdev, id) != 0) {
504 HIF_INFO("error in enabling soc\n");
505 return -EIO;
506 }
Houston Hoffman3db96a42016-05-05 19:54:39 -0700507
Pratik Gandhi815c6d82016-10-19 12:06:32 +0530508 if (hif_target_sync_ahb(ol_sc) < 0) {
509 ret = -EIO;
510 goto err_target_sync;
511 }
Houston Hoffman3db96a42016-05-05 19:54:39 -0700512 }
513 HIF_TRACE("%s: X - hif_type = 0x%x, target_type = 0x%x",
514 __func__, hif_type, target_type);
515
516 return QDF_STATUS_SUCCESS;
517err_target_sync:
Pratik Gandhi815c6d82016-10-19 12:06:32 +0530518 /* QCA_WIFI_QCA8074_VP:Should not be executed on 8074 VP platform */
519 if (tgt_info->target_type != TARGET_TYPE_QCA8074) {
520 HIF_INFO("Error: Disabling target\n");
521 hif_ahb_disable_bus(ol_sc);
522 }
Houston Hoffman3db96a42016-05-05 19:54:39 -0700523err_cleanup1:
524 return ret;
525}
526
527
528/**
529 * hif_reset_soc() - reset soc
530 *
531 * @hif_ctx: HIF context
532 *
533 * This function resets soc and helds the
534 * target in reset state
535 *
536 * Return: void
537 */
538/* Function to reset SoC */
Venkateswara Swamy Bandaru3ca38e22016-08-05 14:51:19 +0530539void hif_ahb_reset_soc(struct hif_softc *hif_ctx)
Houston Hoffman3db96a42016-05-05 19:54:39 -0700540{
Venkateswara Swamy Bandaru3ca38e22016-08-05 14:51:19 +0530541 hif_ahb_device_reset(hif_ctx);
Houston Hoffman3db96a42016-05-05 19:54:39 -0700542}
543
544
545/**
546 * hif_nointrs() - disable IRQ
547 *
548 * @scn: struct hif_softc
549 *
550 * This function stops interrupt(s)
551 *
552 * Return: none
553 */
554void hif_ahb_nointrs(struct hif_softc *scn)
555{
Venkateswara Swamy Bandaru9fd9af02016-09-20 20:27:31 +0530556 int i;
Venkateswara Swamy Bandaru9fd9af02016-09-20 20:27:31 +0530557 struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn);
Venkateswara Swamy Bandaru9fd9af02016-09-20 20:27:31 +0530558 struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
559
Kiran Venkatappaa17e5e52016-12-20 11:32:06 +0530560 ce_unregister_irq(hif_state, CE_ALL_BITMAP);
561
Venkateswara Swamy Bandaru9fd9af02016-09-20 20:27:31 +0530562 if (scn->request_irq_done == false)
563 return;
564
565 if (sc->num_msi_intrs > 0) {
566 /* MSI interrupt(s) */
567 for (i = 0; i < sc->num_msi_intrs; i++) {
568 free_irq(sc->irq + i, sc);
569 }
570 sc->num_msi_intrs = 0;
571 } else {
572 if (!scn->per_ce_irq) {
573 free_irq(sc->irq, sc);
574 } else {
575 for (i = 0; i < scn->ce_count; i++) {
Venkateswara Swamy Bandaru31108f32016-08-08 18:04:29 +0530576 free_irq(ic_irqnum[HIF_IC_CE0_IRQ_OFFSET + i],
577 sc);
Venkateswara Swamy Bandaru9fd9af02016-09-20 20:27:31 +0530578 }
579 }
580 }
Venkateswara Swamy Bandaru9fd9af02016-09-20 20:27:31 +0530581 scn->request_irq_done = false;
Kiran Venkatappaa17e5e52016-12-20 11:32:06 +0530582
Houston Hoffman3db96a42016-05-05 19:54:39 -0700583}
584
585/**
586 * ce_irq_enable() - enable copy engine IRQ
587 * @scn: struct hif_softc
588 * @ce_id: ce_id
589 *
590 * This function enables the interrupt for the radio.
591 *
592 * Return: N/A
593 */
594void hif_ahb_irq_enable(struct hif_softc *scn, int ce_id)
595{
Venkateswara Swamy Bandaru9fd9af02016-09-20 20:27:31 +0530596 uint32_t regval;
597 uint32_t reg_offset = 0;
598 struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
599 struct CE_pipe_config *target_ce_conf = &hif_state->target_ce_config[ce_id];
600
601 if (scn->per_ce_irq) {
602 if (target_ce_conf->pipedir & PIPEDIR_OUT) {
603 reg_offset = HOST_IE_ADDRESS;
604 qdf_spin_lock_irqsave(&hif_state->irq_reg_lock);
605 regval = hif_read32_mb(scn->mem + reg_offset);
606 regval |= (1 << ce_id);
607 hif_write32_mb(scn->mem + reg_offset, regval);
608 qdf_spin_unlock_irqrestore(&hif_state->irq_reg_lock);
609 }
610 if (target_ce_conf->pipedir & PIPEDIR_IN) {
611 reg_offset = HOST_IE_ADDRESS_2;
612 qdf_spin_lock_irqsave(&hif_state->irq_reg_lock);
613 regval = hif_read32_mb(scn->mem + reg_offset);
614 regval |= (1 << ce_id);
615 hif_write32_mb(scn->mem + reg_offset, regval);
616 qdf_spin_unlock_irqrestore(&hif_state->irq_reg_lock);
617 }
618 } else {
619 hif_pci_irq_enable(scn, ce_id);
620 }
Houston Hoffman3db96a42016-05-05 19:54:39 -0700621}
622
623/**
624 * ce_irq_disable() - disable copy engine IRQ
625 * @scn: struct hif_softc
626 * @ce_id: ce_id
627 *
628 * Return: N/A
629 */
630void hif_ahb_irq_disable(struct hif_softc *scn, int ce_id)
631{
Venkateswara Swamy Bandaru9fd9af02016-09-20 20:27:31 +0530632 uint32_t regval;
633 uint32_t reg_offset = 0;
634 struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
635 struct CE_pipe_config *target_ce_conf = &hif_state->target_ce_config[ce_id];
Houston Hoffman3db96a42016-05-05 19:54:39 -0700636
Venkateswara Swamy Bandaru9fd9af02016-09-20 20:27:31 +0530637 if (scn->per_ce_irq) {
638 if (target_ce_conf->pipedir & PIPEDIR_OUT) {
639 reg_offset = HOST_IE_ADDRESS;
640 qdf_spin_lock_irqsave(&hif_state->irq_reg_lock);
641 regval = hif_read32_mb(scn->mem + reg_offset);
642 regval &= ~(1 << ce_id);
643 hif_write32_mb(scn->mem + reg_offset, regval);
644 qdf_spin_unlock_irqrestore(&hif_state->irq_reg_lock);
645 }
646 if (target_ce_conf->pipedir & PIPEDIR_IN) {
647 reg_offset = HOST_IE_ADDRESS_2;
648 qdf_spin_lock_irqsave(&hif_state->irq_reg_lock);
649 regval = hif_read32_mb(scn->mem + reg_offset);
650 regval &= ~(1 << ce_id);
651 hif_write32_mb(scn->mem + reg_offset, regval);
652 qdf_spin_unlock_irqrestore(&hif_state->irq_reg_lock);
653 }
654 }
Houston Hoffman3db96a42016-05-05 19:54:39 -0700655}
Venkateswara Swamy Bandaru31108f32016-08-08 18:04:29 +0530656
657void hif_ahb_grp_irq_disable(struct hif_softc *scn, uint32_t grp_id)
658{
659 struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
660 struct hif_ext_group_entry *hif_ext_group;
661 uint32_t i;
662
663 hif_ext_group = &hif_state->hif_ext_group[grp_id];
664
665 for (i = 0; i < hif_ext_group->numirq; i++) {
Pamidipati, Vijay30dc8f22016-10-26 21:54:23 +0530666 disable_irq_nosync(ic_irqnum[hif_ext_group->irq[i]]);
Venkateswara Swamy Bandaru31108f32016-08-08 18:04:29 +0530667 }
668}
669
670void hif_ahb_grp_irq_enable(struct hif_softc *scn, uint32_t grp_id)
671{
672 struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
673 struct hif_ext_group_entry *hif_ext_group;
674 uint32_t i;
675
676 hif_ext_group = &hif_state->hif_ext_group[grp_id];
677
678 for (i = 0; i < hif_ext_group->numirq; i++) {
679 enable_irq(ic_irqnum[hif_ext_group->irq[i]]);
680 }
681}