Просмотр исходного кода

qcacmn: Use disable_irq_nosync for ce srng msi mode

Implement interrupt mitigation for copy engines.
Implementation is not good if the CE msi vectors are shared,
since disable_irq_nosync will block all users of the given msi
vector.

When processing multiple CE interrupts while the tasklet is scheduled,
the the interrupts will increments the active_tasklet_cnt without
schduleing the tasklet (since it is allready scheduled).  This leads
to an imballance between the number of irq's processed and the number
of tasklets run.  This imballance leaks active_tasklet_cnt, and prevents
suspend from succeding.

interrupt mitigation fixes this problem by preventing the interrupt
from being processed untill its tasklet is finishing runing.

Change-Id: Idb3168d543481843b92327d302e7536e994e341e
CRs-Fixed: 1104481
Houston Hoffman 8 лет назад
Родитель
Сommit
5caa32f957
2 измененных файлов с 26 добавлено и 18 удалено
  1. 25 17
      hif/src/pcie/if_pci.c
  2. 1 1
      hif/src/pcie/if_pci.h

+ 25 - 17
hif/src/pcie/if_pci.c

@@ -3585,10 +3585,18 @@ extern const char *ce_name[];
  * added here for better system performance.
  */
 static void hif_ce_srng_msi_irq_disable(struct hif_softc *hif_sc, int ce_id)
-{}
+{
+	struct hif_pci_softc *pci_sc = HIF_GET_PCI_SOFTC(hif_sc);
+
+	disable_irq_nosync(pci_sc->ce_msi_irq_num[ce_id]);
+}
 
 static void hif_ce_srng_msi_irq_enable(struct hif_softc *hif_sc, int ce_id)
-{}
+{
+	struct hif_pci_softc *pci_sc = HIF_GET_PCI_SOFTC(hif_sc);
+
+	enable_irq(pci_sc->ce_msi_irq_num[ce_id]);
+}
 
 static void hif_ce_legacy_msi_irq_disable(struct hif_softc *hif_sc, int ce_id)
 {}
@@ -3604,14 +3612,26 @@ static int hif_ce_msi_configure_irq(struct hif_softc *scn)
 	uint32_t msi_data_count;
 	uint32_t msi_irq_start;
 	struct HIF_CE_state *ce_sc = HIF_GET_CE_STATE(scn);
+	struct hif_pci_softc *pci_sc = HIF_GET_PCI_SOFTC(scn);
 
 	ret = pld_get_user_msi_assignment(scn->qdf_dev->dev, "CE",
 					    &msi_data_count, &msi_data_start,
 					    &msi_irq_start);
-
 	if (ret)
 		return ret;
 
+	if (ce_srng_based(scn)) {
+		scn->bus_ops.hif_irq_disable =
+			&hif_ce_srng_msi_irq_disable;
+		scn->bus_ops.hif_irq_enable =
+			&hif_ce_srng_msi_irq_enable;
+	} else {
+		scn->bus_ops.hif_irq_disable =
+			&hif_ce_legacy_msi_irq_disable;
+		scn->bus_ops.hif_irq_enable =
+			&hif_ce_legacy_msi_irq_enable;
+	}
+
 	/* needs to match the ce_id -> irq data mapping
 	 * used in the srng parameter configuration
 	 */
@@ -3623,6 +3643,8 @@ static int hif_ce_msi_configure_irq(struct hif_softc *scn)
 		HIF_INFO("%s: (ce_id %d, msi_data %d, irq %d tasklet %p)",
 			 __func__, ce_id, msi_data, irq,
 			 &ce_sc->tasklets[ce_id]);
+
+		pci_sc->ce_msi_irq_num[ce_id] = irq;
 		ret = request_irq(irq, hif_ce_interrupt_handler,
 				  IRQF_SHARED,
 				  ce_name[ce_id],
@@ -3631,20 +3653,6 @@ static int hif_ce_msi_configure_irq(struct hif_softc *scn)
 			goto free_irq;
 	}
 
-	if (ce_srng_based(scn)) {
-		scn->bus_ops.hif_irq_disable =
-			&hif_ce_srng_msi_irq_disable;
-		scn->bus_ops.hif_irq_enable =
-			&hif_ce_srng_msi_irq_enable;
-	} else {
-		scn->bus_ops.hif_irq_disable =
-			&hif_ce_legacy_msi_irq_disable;
-		scn->bus_ops.hif_irq_enable =
-			&hif_ce_legacy_msi_irq_enable;
-	}
-
-
-
 	return ret;
 
 free_irq:

+ 1 - 1
hif/src/pcie/if_pci.h

@@ -116,8 +116,8 @@ struct hif_pci_softc {
 	int num_msi_intrs;      /* number of MSI interrupts granted */
 	/* 0 --> using legacy PCI line interrupts */
 	struct tasklet_struct intr_tq;  /* tasklet */
-
 	struct hif_msi_info msi_info;
+	int ce_msi_irq_num[CE_COUNT_MAX];
 	int irq;
 	int irq_event;
 	int cacheline_sz;