From a17e5e546fb28b0fe78755f7176faa6a4ba92cc6 Mon Sep 17 00:00:00 2001 From: Kiran Venkatappa Date: Tue, 20 Dec 2016 11:32:06 +0530 Subject: [PATCH] qcacmn: Fix for crash during unload of driver modules Cleanup usage of irq_request_done flag. This flag is set after registering irq. Irq register is skipped for emulation. Setting this flag here causes detach path to release irq even though it was not registered. Add new bitmap ce_register_irq_done to track CE irqs. Change-Id: I84cb4463b8ad51f22cb17c55dab36a398ccbaef0 CRs-Fixed: 1097695 --- hif/src/ce/ce_main.c | 2 -- hif/src/ce/ce_main.h | 1 + hif/src/ce/ce_tasklet.c | 5 +++++ hif/src/pcie/if_pci.c | 4 +++- hif/src/snoc/if_ahb.c | 4 +++- hif/src/snoc/if_snoc.c | 6 ++---- 6 files changed, 14 insertions(+), 8 deletions(-) diff --git a/hif/src/ce/ce_main.c b/hif/src/ce/ce_main.c index 5a960c1e9ed2..74f0bf520b5c 100644 --- a/hif/src/ce/ce_main.c +++ b/hif/src/ce/ce_main.c @@ -2178,7 +2178,6 @@ void hif_unconfig_ce(struct hif_softc *hif_sc) pipe_info = &hif_state->pipe_info[pipe_num]; if (pipe_info->ce_hdl) { ce_unregister_irq(hif_state, (1 << pipe_num)); - hif_sc->request_irq_done = false; ce_fini(pipe_info->ce_hdl); pipe_info->ce_hdl = NULL; pipe_info->buf_sz = 0; @@ -2305,7 +2304,6 @@ int hif_config_ce(struct hif_softc *scn) } ce_tasklet_init(hif_state, (1 << pipe_num)); ce_register_irq(hif_state, (1 << pipe_num)); - scn->request_irq_done = true; } if (athdiag_procfs_init(scn) != 0) { diff --git a/hif/src/ce/ce_main.h b/hif/src/ce/ce_main.h index 9549ea213d98..4b416ccea0d6 100644 --- a/hif/src/ce/ce_main.h +++ b/hif/src/ce/ce_main.h @@ -144,6 +144,7 @@ struct HIF_CE_state { qdf_timer_t sleep_timer; bool sleep_timer_init; qdf_time_t sleep_ticks; + uint32_t ce_register_irq_done; struct CE_pipe_config *target_ce_config; struct CE_attr *host_ce_config; diff --git a/hif/src/ce/ce_tasklet.c b/hif/src/ce/ce_tasklet.c index 52595f289cd8..ef13e4e2d0e1 100644 --- a/hif/src/ce/ce_tasklet.c +++ b/hif/src/ce/ce_tasklet.c @@ -557,6 +557,8 @@ QDF_STATUS ce_unregister_irq(struct HIF_CE_state *hif_ce_state, uint32_t mask) __func__, ret); /* this is not fatal, continue */ + /* filter mask to free only for ce's with irq registered */ + mask &= hif_ce_state->ce_register_irq_done; for (id = 0; id < ce_count; id++) { if ((mask & (1 << id)) && hif_ce_state->tasklets[id].inited) { ret = pld_ce_free_irq(scn->qdf_dev->dev, id, @@ -567,6 +569,8 @@ QDF_STATUS ce_unregister_irq(struct HIF_CE_state *hif_ce_state, uint32_t mask) __func__, id, ret); } } + hif_ce_state->ce_register_irq_done &= ~mask; + return QDF_STATUS_SUCCESS; } /** @@ -607,6 +611,7 @@ QDF_STATUS ce_register_irq(struct HIF_CE_state *hif_ce_state, uint32_t mask) } } } + hif_ce_state->ce_register_irq_done |= done_mask; return QDF_STATUS_SUCCESS; } diff --git a/hif/src/pcie/if_pci.c b/hif/src/pcie/if_pci.c index 2ab29b6f9fca..d5dd28c5edf6 100644 --- a/hif/src/pcie/if_pci.c +++ b/hif/src/pcie/if_pci.c @@ -2593,6 +2593,8 @@ void hif_pci_nointrs(struct hif_softc *scn) struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); + ce_unregister_irq(hif_state, CE_ALL_BITMAP); + if (scn->request_irq_done == false) return; @@ -2609,8 +2611,8 @@ void hif_pci_nointrs(struct hif_softc *scn) platform_device pdev doesn't have an irq field */ free_irq(sc->irq, sc); } - ce_unregister_irq(hif_state, 0xfff); scn->request_irq_done = false; + } /** diff --git a/hif/src/snoc/if_ahb.c b/hif/src/snoc/if_ahb.c index 7dc95b8345a7..a137c1e67b0d 100644 --- a/hif/src/snoc/if_ahb.c +++ b/hif/src/snoc/if_ahb.c @@ -557,6 +557,8 @@ void hif_ahb_nointrs(struct hif_softc *scn) struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); + ce_unregister_irq(hif_state, CE_ALL_BITMAP); + if (scn->request_irq_done == false) return; @@ -576,8 +578,8 @@ void hif_ahb_nointrs(struct hif_softc *scn) } } } - ce_unregister_irq(hif_state, CE_ALL_BITMAP); scn->request_irq_done = false; + } /** diff --git a/hif/src/snoc/if_snoc.c b/hif/src/snoc/if_snoc.c index 22103d4c73fd..3b5e0f6ac5ac 100644 --- a/hif/src/snoc/if_snoc.c +++ b/hif/src/snoc/if_snoc.c @@ -309,10 +309,8 @@ void hif_snoc_disable_bus(struct hif_softc *scn) void hif_snoc_nointrs(struct hif_softc *scn) { struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); - if (scn->request_irq_done) { - ce_unregister_irq(hif_state, 0xfff); - scn->request_irq_done = false; - } + + ce_unregister_irq(hif_state, CE_ALL_BITMAP); } /**