瀏覽代碼

qcacmn: Add atomic ref counter for hif_wake_request

Reference count logic to handle concurrent request of hif wake and hif
release operation by multiple contexts

Change-Id: I4626dec9186cd959192582f8903700080534d227
CRs-Fixed: 3391343
Vishal Miskin 2 年之前
父節點
當前提交
6c54bc52ed
共有 3 個文件被更改,包括 78 次插入27 次删除
  1. 1 0
      hif/src/hif_main.h
  2. 76 27
      hif/src/pcie/if_pci.c
  3. 1 0
      hif/src/pcie/if_pci.h

+ 1 - 0
hif/src/hif_main.h

@@ -299,6 +299,7 @@ struct hif_softc {
 	atomic_t active_grp_tasklet_cnt;
 	atomic_t link_suspended;
 	void *vaddr_rri_on_ddr;
+	atomic_t active_wake_req_cnt;
 	qdf_dma_addr_t paddr_rri_on_ddr;
 #ifdef CONFIG_BYPASS_QMI
 	uint32_t *vaddr_qmi_bypass;

+ 76 - 27
hif/src/pcie/if_pci.c

@@ -1157,6 +1157,7 @@ QDF_STATUS hif_pci_open(struct hif_softc *hif_ctx, enum qdf_bus_type bus_type)
 	hif_rtpm_open(hif_ctx);
 
 	qdf_spinlock_create(&sc->irq_lock);
+	qdf_spinlock_create(&sc->force_wake_lock);
 
 	return hif_ce_open(hif_ctx);
 }
@@ -4021,6 +4022,65 @@ bool hif_pci_needs_bmi(struct hif_softc *scn)
  */
 #define HIF_POLL_UMAC_WAKE 0x2
 
+static inline int hif_soc_wake_request(struct hif_opaque_softc *hif_handle)
+{
+	uint32_t timeout, value;
+	struct hif_softc *scn = (struct hif_softc *)hif_handle;
+	struct hif_pci_softc *pci_scn = HIF_GET_PCI_SOFTC(scn);
+
+	qdf_spin_lock_bh(&pci_scn->force_wake_lock);
+	if ((qdf_atomic_inc_return(&scn->active_wake_req_cnt) > 1)) {
+		qdf_spin_unlock_bh(&pci_scn->force_wake_lock);
+		return 0;
+	}
+
+	hif_write32_mb(scn, scn->mem + PCIE_REG_WAKE_UMAC_OFFSET, 1);
+	HIF_STATS_INC(pci_scn, soc_force_wake_register_write_success, 1);
+	/*
+	 * do not reset the timeout
+	 * total_wake_time = MHI_WAKE_TIME + PCI_WAKE_TIME < 50 ms
+	 */
+	timeout = 0;
+	do {
+		value = hif_read32_mb(
+				scn, scn->mem +
+				PCIE_SOC_PCIE_REG_PCIE_SCRATCH_0_SOC_PCIE_REG);
+		if (value == HIF_POLL_UMAC_WAKE)
+			break;
+		qdf_mdelay(FORCE_WAKE_DELAY_MS);
+		timeout += FORCE_WAKE_DELAY_MS;
+	} while (timeout <= FORCE_WAKE_DELAY_TIMEOUT_MS);
+
+	if (value != HIF_POLL_UMAC_WAKE) {
+		hif_err("force wake handshake failed, reg value = 0x%x",
+			value);
+		HIF_STATS_INC(pci_scn, soc_force_wake_failure, 1);
+		qdf_atomic_dec(&scn->active_wake_req_cnt);
+		qdf_spin_unlock_bh(&pci_scn->force_wake_lock);
+		return -ETIMEDOUT;
+	}
+
+	HIF_STATS_INC(pci_scn, soc_force_wake_success, 1);
+	qdf_spin_unlock_bh(&pci_scn->force_wake_lock);
+	return 0;
+}
+
+static inline void hif_soc_wake_release(struct hif_opaque_softc *hif_handle)
+{
+	struct hif_softc *scn = (struct hif_softc *)hif_handle;
+	struct hif_pci_softc *pci_scn = HIF_GET_PCI_SOFTC(scn);
+
+	qdf_spin_lock_bh(&pci_scn->force_wake_lock);
+	if (!qdf_atomic_dec_and_test(&scn->active_wake_req_cnt)) {
+		qdf_spin_unlock_bh(&pci_scn->force_wake_lock);
+		return;
+	}
+
+	/* Release umac force wake */
+	hif_write32_mb(scn, scn->mem + PCIE_REG_WAKE_UMAC_OFFSET, 0);
+	qdf_spin_unlock_bh(&pci_scn->force_wake_lock);
+}
+
 /**
  * hif_force_wake_request(): Enable the force wake recipe
  * @hif_handle: HIF handle
@@ -4034,7 +4094,7 @@ bool hif_pci_needs_bmi(struct hif_softc *scn)
  */
 int hif_force_wake_request(struct hif_opaque_softc *hif_handle)
 {
-	uint32_t timeout, value;
+	uint32_t timeout;
 	struct hif_softc *scn = (struct hif_softc *)hif_handle;
 	struct hif_pci_softc *pci_scn = HIF_GET_PCI_SOFTC(scn);
 	int ret, status = 0;
@@ -4068,34 +4128,24 @@ int hif_force_wake_request(struct hif_opaque_softc *hif_handle)
 		hif_info("state-change event races, ignore");
 
 	HIF_STATS_INC(pci_scn, mhi_force_wake_success, 1);
-	hif_write32_mb(scn, scn->mem + PCIE_REG_WAKE_UMAC_OFFSET, 1);
-	HIF_STATS_INC(pci_scn, soc_force_wake_register_write_success, 1);
-	/*
-	 * do not reset the timeout
-	 * total_wake_time = MHI_WAKE_TIME + PCI_WAKE_TIME < 50 ms
-	 */
-	timeout = 0;
-	do {
-		value = hif_read32_mb(
-				scn, scn->mem +
-				PCIE_SOC_PCIE_REG_PCIE_SCRATCH_0_SOC_PCIE_REG);
-		if (value == HIF_POLL_UMAC_WAKE)
-			break;
-		qdf_mdelay(FORCE_WAKE_DELAY_MS);
-		timeout += FORCE_WAKE_DELAY_MS;
-	} while (timeout <= FORCE_WAKE_DELAY_TIMEOUT_MS);
 
-	if (value != HIF_POLL_UMAC_WAKE) {
-		hif_err("force wake handshake failed, reg value = 0x%x",
-			value);
-		HIF_STATS_INC(pci_scn, soc_force_wake_failure, 1);
-		status = -ETIMEDOUT;
-		goto release_rtpm_ref;
+	ret = hif_soc_wake_request(hif_handle);
+	if (ret) {
+		hif_err("soc force wake failed: %d", ret);
+		status = ret;
+		goto release_mhi_wake;
 	}
-
-	HIF_STATS_INC(pci_scn, soc_force_wake_success, 1);
 	return 0;
 
+release_mhi_wake:
+	/* Release MHI force wake */
+	ret = pld_force_wake_release(scn->qdf_dev->dev);
+	if (ret) {
+		hif_err("pld force wake release failure");
+		HIF_STATS_INC(pci_scn, mhi_force_wake_release_failure, 1);
+		return ret;
+	}
+	HIF_STATS_INC(pci_scn, mhi_force_wake_release_success, 1);
 release_rtpm_ref:
 	/* Release runtime PM force wake */
 	ret = hif_rtpm_put(HIF_RTPM_PUT_ASYNC, HIF_RTPM_ID_FORCE_WAKE);
@@ -4113,8 +4163,7 @@ int hif_force_wake_release(struct hif_opaque_softc *hif_handle)
 	struct hif_softc *scn = (struct hif_softc *)hif_handle;
 	struct hif_pci_softc *pci_scn = HIF_GET_PCI_SOFTC(scn);
 
-	/* Release umac force wake */
-	hif_write32_mb(scn, scn->mem + PCIE_REG_WAKE_UMAC_OFFSET, 0);
+	hif_soc_wake_release(hif_handle);
 
 	/* Release MHI force wake */
 	ret = pld_force_wake_release(scn->qdf_dev->dev);

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

@@ -157,6 +157,7 @@ struct hif_pci_softc {
 	qdf_cpu_mask ce_irq_cpu_mask[CE_COUNT_MAX];
 #endif
 	struct hif_soc_info device_version;
+	qdf_spinlock_t force_wake_lock;
 };
 
 bool hif_pci_targ_is_present(struct hif_softc *scn, void *__iomem *mem);