瀏覽代碼

qcacmn: Add delayed reg write support based on EP power state

Even though HP/TP updates are posted writes at CPU level, they
are getting blocked until soc comes out retention which is hogging
CPU.

To avoid this if EP is in low power state update HP/TP writes from
delayed work context. In delayed work vote for EP awake wait till it
comes out low power state and then proceed to HP/TP update.

Change-Id: I61d5795f58f25f850b5a9ad4d30e3181dba23713
CRs-Fixed: 2913495
Karthik Kantamneni 4 年之前
父節點
當前提交
ad0f442d8f
共有 3 個文件被更改,包括 100 次插入0 次删除
  1. 39 0
      hal/wifi3.0/hal_srng.c
  2. 43 0
      hif/src/ipcie/if_ipci.c
  3. 18 0
      hif/src/ipcie/if_ipci.h

+ 39 - 0
hal/wifi3.0/hal_srng.c

@@ -1277,6 +1277,44 @@ void hal_delayed_reg_write(struct hal_soc *hal_soc,
 
 #else
 #ifdef FEATURE_HAL_DELAYED_REG_WRITE
+#ifdef QCA_WIFI_QCA6750
+void hal_delayed_reg_write(struct hal_soc *hal_soc,
+			   struct hal_srng *srng,
+			   void __iomem *addr,
+			   uint32_t value)
+{
+	switch (srng->ring_type) {
+	case CE_SRC:
+	case CE_DST:
+	case CE_DST_STATUS:
+		if (hif_get_ep_vote_access(hal_soc->hif_handle,
+					   HIF_EP_VOTE_NONDP_ACCESS) ==
+					   HIF_EP_VOTE_ACCESS_DISABLE) {
+			hal_write_address_32_mb(hal_soc, addr, value, false);
+			qdf_atomic_inc(&hal_soc->stats.wstats.direct);
+			srng->wstats.direct++;
+		} else {
+			hal_reg_write_enqueue(hal_soc, srng, addr, value);
+		}
+		break;
+	default:
+		if (hif_get_ep_vote_access(hal_soc->hif_handle,
+		    HIF_EP_VOTE_DP_ACCESS) ==
+		    HIF_EP_VOTE_ACCESS_DISABLE ||
+		    hal_is_reg_write_tput_level_high(hal_soc) ||
+		    PLD_MHI_STATE_L0 ==
+		    pld_get_mhi_state(hal_soc->qdf_dev->dev)) {
+			hal_write_address_32_mb(hal_soc, addr, value, false);
+			qdf_atomic_inc(&hal_soc->stats.wstats.direct);
+			srng->wstats.direct++;
+		} else {
+			hal_reg_write_enqueue(hal_soc, srng, addr, value);
+		}
+
+		break;
+	}
+}
+#else
 void hal_delayed_reg_write(struct hal_soc *hal_soc,
 			   struct hal_srng *srng,
 			   void __iomem *addr,
@@ -1293,6 +1331,7 @@ void hal_delayed_reg_write(struct hal_soc *hal_soc,
 }
 #endif
 #endif
+#endif
 
 /**
  * hal_attach - Initialize HAL layer

+ 43 - 0
hif/src/ipcie/if_ipci.c

@@ -878,11 +878,54 @@ void hif_print_ipci_stats(struct hif_ipci_softc *ipci_handle)
 #ifdef FEATURE_HAL_DELAYED_REG_WRITE
 int hif_prevent_link_low_power_states(struct hif_opaque_softc *hif)
 {
+	struct hif_softc *scn = HIF_GET_SOFTC(hif);
+	struct hif_ipci_softc *ipci_scn = HIF_GET_IPCI_SOFTC(scn);
+	uint32_t timeout = 0;
+
+	while (pld_is_pci_ep_awake(scn->qdf_dev->dev) &&
+	       timeout <= EP_WAKE_RESET_DELAY_TIMEOUT_US) {
+		qdf_sleep_us(EP_WAKE_RESET_DELAY_US);
+		timeout += EP_WAKE_RESET_DELAY_US;
+	}
+
+	if (pld_is_pci_ep_awake(scn->qdf_dev->dev)) {
+		hif_err_rl(" EP state reset is not done to prevent l1");
+		ipci_scn->ep_awake_reset_fail++;
+		return 0;
+	}
+
+	if (pld_prevent_l1(scn->qdf_dev->dev)) {
+		hif_err_rl("pld prevent l1 failed");
+		ipci_scn->prevent_l1_fail++;
+		return 0;
+	}
+
+	ipci_scn->prevent_l1 = true;
+	timeout = 0;
+	while (!pld_is_pci_ep_awake(scn->qdf_dev->dev) &&
+	       timeout <= EP_WAKE_DELAY_TIMEOUT_US) {
+		qdf_sleep_us(EP_WAKE_DELAY_US);
+		timeout += EP_WAKE_DELAY_US;
+	}
+
+	if (pld_is_pci_ep_awake(scn->qdf_dev->dev) <= 0) {
+		hif_err_rl("Unable to wakeup pci ep");
+		ipci_scn->ep_awake_set_fail++;
+		return  0;
+	}
+
 	return 0;
 }
 
 void hif_allow_link_low_power_states(struct hif_opaque_softc *hif)
 {
+	struct hif_softc *scn = HIF_GET_SOFTC(hif);
+	struct hif_ipci_softc *ipci_scn = HIF_GET_IPCI_SOFTC(scn);
+
+	if (qdf_likely(ipci_scn->prevent_l1)) {
+		pld_allow_l1(scn->qdf_dev->dev);
+		ipci_scn->prevent_l1 = false;
+	}
 }
 #endif
 

+ 18 - 0
hif/src/ipcie/if_ipci.h

@@ -66,6 +66,18 @@ struct hif_ipci_stats {
 #define FORCE_WAKE_DELAY_MS 5
 #endif /* FORCE_WAKE */
 
+#ifdef FEATURE_HAL_DELAYED_REG_WRITE
+#ifdef HAL_CONFIG_SLUB_DEBUG_ON
+#define EP_WAKE_RESET_DELAY_TIMEOUT_US 3000
+#define EP_WAKE_DELAY_TIMEOUT_US 7000
+#else
+#define EP_WAKE_RESET_DELAY_TIMEOUT_US 10000
+#define EP_WAKE_DELAY_TIMEOUT_US 10000
+#endif
+#define EP_WAKE_RESET_DELAY_US 50
+#define EP_WAKE_DELAY_US 200
+#endif
+
 struct hif_ipci_softc {
 	struct HIF_CE_state ce_sc;
 	void __iomem *mem;      /* PCI address. */
@@ -83,6 +95,12 @@ struct hif_ipci_softc {
 
 	void (*hif_ipci_get_soc_info)(struct hif_ipci_softc *sc,
 				      struct device *dev);
+#ifdef FEATURE_HAL_DELAYED_REG_WRITE
+	uint32_t ep_awake_reset_fail;
+	uint32_t prevent_l1_fail;
+	uint32_t ep_awake_set_fail;
+	bool prevent_l1;
+#endif
 #ifdef FORCE_WAKE
 	struct hif_ipci_stats stats;
 #endif