From 2af3d67336b556fc5f0699bfaa764edbaa07083e Mon Sep 17 00:00:00 2001 From: Dustin Brown Date: Tue, 30 May 2017 16:14:01 -0700 Subject: [PATCH] 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 --- hif/src/dispatcher/multibus.c | 61 +++++++++++++++-------------------- hif/src/hif_main.c | 20 ++++++++++++ hif/src/hif_main.h | 11 +++++++ hif/src/pcie/if_pci.c | 48 +++++++++++++-------------- hif/src/snoc/if_snoc.c | 49 ++++++++++++++-------------- 5 files changed, 104 insertions(+), 85 deletions(-) diff --git a/hif/src/dispatcher/multibus.c b/hif/src/dispatcher/multibus.c index 0570df817d28..e22eabe2db72 100644 --- a/hif/src/dispatcher/multibus.c +++ b/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; } diff --git a/hif/src/hif_main.c b/hif/src/hif_main.c index 15259bcb560b..35a2835a8d11 100644 --- a/hif/src/hif_main.c +++ b/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 */ diff --git a/hif/src/hif_main.h b/hif/src/hif_main.h index 24689e15faec..40f7779c7d59 100644 --- a/hif/src/hif_main.h +++ b/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__ */ diff --git a/hif/src/pcie/if_pci.c b/hif/src/pcie/if_pci.c index f01745a5dae0..658511c23f62 100644 --- a/hif/src/pcie/if_pci.c +++ b/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; } diff --git a/hif/src/snoc/if_snoc.c b/hif/src/snoc/if_snoc.c index c633b9b99244..5fa389b0771a 100644 --- a/hif/src/snoc/if_snoc.c +++ b/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 #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; }