Bladeren bron

qcacmn: Add Wake MSI support

Using the same MSI for wake and copy engines has a number of negative
side effects. Instead, set aside a whole MSI just for the wake
notification from firmware.

Change-Id: If871b88ca255ad970dabb4a7773d2b4d3b71c3fe
CRs-Fixed: 2055359
Dustin Brown 7 jaren geleden
bovenliggende
commit
2af3d67336
5 gewijzigde bestanden met toevoegingen van 104 en 85 verwijderingen
  1. 26 35
      hif/src/dispatcher/multibus.c
  2. 20 0
      hif/src/hif_main.c
  3. 11 0
      hif/src/hif_main.h
  4. 23 25
      hif/src/pcie/if_pci.c
  5. 24 25
      hif/src/snoc/if_snoc.c

+ 26 - 35
hif/src/dispatcher/multibus.c

@@ -439,7 +439,6 @@ void hif_set_bundle_mode(struct hif_opaque_softc *scn, bool enabled,
  * Return: int 0 for success, non zero for failure
  */
 int hif_bus_reset_resume(struct hif_opaque_softc *scn)
-
 {
 	struct hif_softc *hif_sc = HIF_GET_SOFTC(scn);
 
@@ -451,14 +450,19 @@ int hif_apps_irqs_disable(struct hif_opaque_softc *hif_ctx)
 	struct hif_softc *scn;
 	int i;
 
+	QDF_BUG(hif_ctx);
 	scn = HIF_GET_SOFTC(hif_ctx);
-	if (!scn) {
-		QDF_BUG(0);
+	if (!scn)
 		return -EINVAL;
-	}
 
-	for (i = 0; i < scn->ce_count; ++i)
-		disable_irq(scn->bus_ops.hif_map_ce_to_irq(scn, i));
+	/* if the wake_irq is shared, don't disable it twice */
+	disable_irq(scn->wake_irq);
+	for (i = 0; i < scn->ce_count; ++i) {
+		int irq = scn->bus_ops.hif_map_ce_to_irq(scn, i);
+
+		if (irq != scn->wake_irq)
+			disable_irq(irq);
+	}
 
 	return 0;
 }
@@ -468,60 +472,47 @@ int hif_apps_irqs_enable(struct hif_opaque_softc *hif_ctx)
 	struct hif_softc *scn;
 	int i;
 
+	QDF_BUG(hif_ctx);
 	scn = HIF_GET_SOFTC(hif_ctx);
-	if (!scn) {
-		QDF_BUG(0);
+	if (!scn)
 		return -EINVAL;
-	}
 
-	for (i = 0; i < scn->ce_count; ++i)
-		enable_irq(scn->bus_ops.hif_map_ce_to_irq(scn, i));
+	/* if the wake_irq is shared, don't enable it twice */
+	enable_irq(scn->wake_irq);
+	for (i = 0; i < scn->ce_count; ++i) {
+		int irq = scn->bus_ops.hif_map_ce_to_irq(scn, i);
+
+		if (irq != scn->wake_irq)
+			enable_irq(irq);
+	}
 
 	return 0;
 }
 
 int hif_apps_wake_irq_disable(struct hif_opaque_softc *hif_ctx)
 {
-	int errno;
 	struct hif_softc *scn;
-	uint8_t wake_ce_id;
 
+	QDF_BUG(hif_ctx);
 	scn = HIF_GET_SOFTC(hif_ctx);
-	if (!scn) {
-		QDF_BUG(0);
+	if (!scn)
 		return -EINVAL;
-	}
-
-	errno = hif_get_wake_ce_id(scn, &wake_ce_id);
-	if (errno) {
-		HIF_ERROR("%s: failed to get wake CE Id: %d", __func__, errno);
-		return errno;
-	}
 
-	disable_irq(scn->bus_ops.hif_map_ce_to_irq(scn, wake_ce_id));
+	disable_irq(scn->wake_irq);
 
 	return 0;
 }
 
 int hif_apps_wake_irq_enable(struct hif_opaque_softc *hif_ctx)
 {
-	int errno;
 	struct hif_softc *scn;
-	uint8_t wake_ce_id;
 
+	QDF_BUG(hif_ctx);
 	scn = HIF_GET_SOFTC(hif_ctx);
-	if (!scn) {
-		QDF_BUG(0);
+	if (!scn)
 		return -EINVAL;
-	}
-
-	errno = hif_get_wake_ce_id(scn, &wake_ce_id);
-	if (errno) {
-		HIF_ERROR("%s: failed to get wake CE Id: %d", __func__, errno);
-		return errno;
-	}
 
-	enable_irq(scn->bus_ops.hif_map_ce_to_irq(scn, wake_ce_id));
+	enable_irq(scn->wake_irq);
 
 	return 0;
 }

+ 20 - 0
hif/src/hif_main.c

@@ -1186,3 +1186,23 @@ void hif_ramdump_handler(struct hif_opaque_softc *scn)
 }
 #endif
 
+#ifdef WLAN_SUSPEND_RESUME_TEST
+irqreturn_t hif_wake_interrupt_handler(int irq, void *context)
+{
+	struct hif_softc *scn = context;
+
+	HIF_INFO("wake interrupt received on irq %d", irq);
+
+	if (hif_is_ut_suspended(scn))
+		hif_ut_fw_resume(scn);
+
+	return IRQ_HANDLED;
+}
+#else /* WLAN_SUSPEND_RESUME_TEST */
+irqreturn_t hif_wake_interrupt_handler(int irq, void *context)
+{
+	HIF_INFO("wake interrupt received on irq %d", irq);
+
+	return IRQ_HANDLED;
+}
+#endif /* WLAN_SUSPEND_RESUME_TEST */

+ 11 - 0
hif/src/hif_main.h

@@ -167,6 +167,7 @@ struct hif_softc {
 	void *hal_soc;
 	struct hif_ut_suspend_context ut_suspend_ctx;
 	uint32_t hif_attribute;
+	int wake_irq;
 };
 
 static inline void *hif_get_hal_handle(void *hif_hdl)
@@ -247,4 +248,14 @@ void hif_ramdump_handler(struct hif_opaque_softc *scn);
 static inline void hif_usb_get_hw_info(struct hif_softc *scn) {}
 static inline void hif_ramdump_handler(struct hif_opaque_softc *scn) {}
 #endif
+
+/**
+ * hif_wake_interrupt_handler() - interrupt handler for standalone wake irq
+ * @irq: the irq number that fired
+ * @context: the opaque pointer passed to request_irq()
+ *
+ * Return: an irq return type
+ */
+irqreturn_t hif_wake_interrupt_handler(int irq, void *context);
+
 #endif /* __HIF_MAIN_H__ */

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

@@ -2498,6 +2498,7 @@ static int hif_pci_configure_legacy_irq(struct hif_pci_softc *sc)
 		HIF_ERROR("%s: request_irq failed, ret = %d", __func__, ret);
 		goto end;
 	}
+	scn->wake_irq = sc->pdev->irq;
 	/* Use sc->irq instead of sc->pdev-irq
 	 * platform_device pdev doesn't have an irq field
 	 */
@@ -2732,15 +2733,8 @@ void hif_pci_prevent_linkdown(struct hif_softc *scn, bool flag)
 static int hif_mark_wake_irq_wakeable(struct hif_softc *scn)
 {
 	int errno;
-	uint8_t ce_id;
 
-	errno = hif_get_wake_ce_id(scn, &ce_id);
-	if (errno) {
-		HIF_ERROR("%s: failed to get wake CE Id: %d", __func__, errno);
-		return errno;
-	}
-
-	errno = enable_irq_wake(scn->bus_ops.hif_map_ce_to_irq(scn, ce_id));
+	errno = enable_irq_wake(scn->wake_irq);
 	if (errno) {
 		HIF_ERROR("%s: Failed to mark wake IRQ: %d", __func__, errno);
 		return errno;
@@ -2758,14 +2752,6 @@ static int hif_mark_wake_irq_wakeable(struct hif_softc *scn)
  */
 int hif_pci_bus_suspend(struct hif_softc *scn)
 {
-	/*
-	 * This is a workaround to a spurious wake interrupt issue. The
-	 * proper fix is being worked on, and this should be removed as
-	 * soon as possible.
-	 */
-	HIF_ERROR("%s: Pausing bus suspend for 200ms", __func__);
-	msleep(200);
-
 	if (hif_can_suspend_link(GET_HIF_OPAQUE_HDL(scn)))
 		return 0;
 
@@ -2815,15 +2801,8 @@ static int __hif_check_link_status(struct hif_softc *scn)
 static int hif_unmark_wake_irq_wakeable(struct hif_softc *scn)
 {
 	int errno;
-	uint8_t ce_id;
-
-	errno = hif_get_wake_ce_id(scn, &ce_id);
-	if (errno) {
-		HIF_ERROR("%s: failed to get wake CE Id: %d", __func__, errno);
-		return errno;
-	}
 
-	errno = disable_irq_wake(scn->bus_ops.hif_map_ce_to_irq(scn, ce_id));
+	errno = disable_irq_wake(scn->wake_irq);
 	if (errno) {
 		HIF_ERROR("%s: Failed to unmark wake IRQ: %d", __func__, errno);
 		return errno;
@@ -3586,11 +3565,25 @@ static int hif_ce_msi_configure_irq(struct hif_softc *scn)
 	struct HIF_CE_state *ce_sc = HIF_GET_CE_STATE(scn);
 	struct hif_pci_softc *pci_sc = HIF_GET_PCI_SOFTC(scn);
 
+	/* do wake irq assignment */
+	ret = pld_get_user_msi_assignment(scn->qdf_dev->dev, "WAKE",
+					  &msi_data_count, &msi_data_start,
+					  &msi_irq_start);
+	if (ret)
+		return ret;
+
+	scn->wake_irq = pld_get_msi_irq(scn->qdf_dev->dev, msi_irq_start);
+	ret = request_irq(scn->wake_irq, hif_wake_interrupt_handler, 0,
+			  "wlan_wake_irq", scn);
+	if (ret)
+		return ret;
+
+	/* do ce irq assignments */
 	ret = pld_get_user_msi_assignment(scn->qdf_dev->dev, "CE",
 					    &msi_data_count, &msi_data_start,
 					    &msi_irq_start);
 	if (ret)
-		return ret;
+		goto free_wake_irq;
 
 	if (ce_srng_based(scn)) {
 		scn->bus_ops.hif_irq_disable = &hif_ce_srng_msi_irq_disable;
@@ -3638,6 +3631,11 @@ free_irq:
 		irq = pld_get_msi_irq(scn->qdf_dev->dev, msi_data);
 		free_irq(irq, &ce_sc->tasklets[ce_id]);
 	}
+
+free_wake_irq:
+	free_irq(scn->wake_irq, scn->qdf_dev->dev);
+	scn->wake_irq = 0;
+
 	return ret;
 }
 

+ 24 - 25
hif/src/snoc/if_snoc.c

@@ -37,6 +37,8 @@
 #include "hif_io32.h"
 #include "ce_main.h"
 #include "ce_tasklet.h"
+#include "ce_api.h"
+#include "ce_internal.h"
 #include "snoc_api.h"
 #include <soc/qcom/icnss.h>
 #include "pld_common.h"
@@ -166,6 +168,7 @@ static QDF_STATUS hif_snoc_get_soc_info(struct hif_softc *scn)
 int hif_snoc_bus_configure(struct hif_softc *scn)
 {
 	int ret;
+	uint8_t wake_ce_id;
 
 	ret = hif_snoc_get_soc_info(scn);
 	if (ret)
@@ -182,7 +185,25 @@ int hif_snoc_bus_configure(struct hif_softc *scn)
 
 	ret = hif_config_ce(scn);
 	if (ret)
-		hif_wlan_disable(scn);
+		goto wlan_disable;
+
+	ret = hif_get_wake_ce_id(scn, &wake_ce_id);
+	if (ret)
+		goto unconfig_ce;
+
+	scn->wake_irq = icnss_get_irq(wake_ce_id);
+
+	HIF_INFO(FL("expecting wake from ce %d, irq %d"),
+		 wake_ce_id, scn->wake_irq);
+
+	return 0;
+
+unconfig_ce:
+	hif_unconfig_ce(scn);
+
+wlan_disable:
+	hif_wlan_disable(scn);
+
 	return ret;
 }
 
@@ -369,40 +390,18 @@ void hif_snoc_irq_disable(struct hif_softc *scn, int ce_id)
 static
 QDF_STATUS hif_snoc_setup_wakeup_sources(struct hif_softc *scn, bool enable)
 {
-	struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(scn);
-	uint8_t ul_pipe, dl_pipe;
-	int ul_is_polled, dl_is_polled;
-	int irq_to_wake_on;
-
-	QDF_STATUS status;
 	int ret;
 
-	status = hif_map_service_to_pipe(hif_hdl, HTC_CTRL_RSVD_SVC,
-					 &ul_pipe, &dl_pipe,
-					 &ul_is_polled, &dl_is_polled);
-	if (status) {
-		HIF_ERROR("%s: pipe_mapping failure", __func__);
-		return status;
-	}
-
-	irq_to_wake_on = icnss_get_irq(dl_pipe);
-	if (irq_to_wake_on < 0) {
-		HIF_ERROR("%s: failed to map ce to irq", __func__);
-		return QDF_STATUS_E_RESOURCES;
-	}
-
 	if (enable)
-		ret = enable_irq_wake(irq_to_wake_on);
+		ret = enable_irq_wake(scn->wake_irq);
 	else
-		ret = disable_irq_wake(irq_to_wake_on);
+		ret = disable_irq_wake(scn->wake_irq);
 
 	if (ret) {
 		HIF_ERROR("%s: Fail to setup wake IRQ!", __func__);
 		return QDF_STATUS_E_RESOURCES;
 	}
 
-	HIF_INFO("%s: expecting wake from ce %d, irq %d enable %d",
-		  __func__, dl_pipe, irq_to_wake_on, enable);
 	return QDF_STATUS_SUCCESS;
 }