Browse Source

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
Kiran Venkatappa 8 năm trước cách đây
mục cha
commit
a17e5e546f

+ 0 - 2
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) {

+ 1 - 0
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;

+ 5 - 0
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;
 }

+ 3 - 1
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;
+
 }
 
 /**

+ 3 - 1
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;
+
 }
 
 /**

+ 2 - 4
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);
 }
 
 /**