diff --git a/hif/src/snoc/if_snoc.c b/hif/src/snoc/if_snoc.c index be5d06ce281c..ab0bda16b323 100644 --- a/hif/src/snoc/if_snoc.c +++ b/hif/src/snoc/if_snoc.c @@ -376,22 +376,107 @@ QDF_STATUS hif_snoc_setup_wakeup_sources(struct hif_softc *scn, bool enable) return QDF_STATUS_SUCCESS; } +/** + * __hif_snoc_irq_state_vote() - enable/disable all the ce interrupts + * @scn: hif context pointer + * @enble: true to enable the interrupts false to disable + * + * takes care of unwinding partial successes. + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS __hif_snoc_irq_state_vote(struct hif_softc *scn, bool enable) +{ + int num_ce = scn->ce_count; + int ce_id = 0; + int irq; + + while (ce_id < num_ce) { + irq = icnss_get_irq(ce_id); + if (irq < 0) + goto error; + + if (enable) + enable_irq(irq); + else + disable_irq(irq); + + ce_id++; + } + + return QDF_STATUS_SUCCESS; + +error: + HIF_ERROR("%s: failed to map ce to irq", __func__); + + while (--ce_id >= 0) { + irq = icnss_get_irq(ce_id); + if (irq < 0) + continue; + + if (enable) + disable_irq(irq); + else + enable_irq(irq); + } + return QDF_STATUS_E_FAULT; +} + +/** + * hif_snoc_enable_irqs() - enable the ce irqs + * @scn: hif context + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS hif_snoc_enable_irqs(struct hif_softc *scn) +{ + return __hif_snoc_irq_state_vote(scn, true); +} + +/** + * hif_snoc_enable_irqs() - enable the ce irqs + * @scn: hif context + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS hif_snoc_disable_irqs(struct hif_softc *scn) +{ + return __hif_snoc_irq_state_vote(scn, false); +} /** * hif_snoc_bus_suspend() - prepare to suspend the bus * @scn: hif context * * Setup wakeup interrupt configuration. + * Disable CE interrupts (wakeup interrupt will still wake apps) + * Drain tasklets. - make sure that we don't suspend while processing + * the wakeup message. * * Return: 0 on success. */ int hif_snoc_bus_suspend(struct hif_softc *scn) { if (hif_snoc_setup_wakeup_sources(scn, true) != QDF_STATUS_SUCCESS) - return -EFAULT; + goto error; + if (hif_snoc_disable_irqs(scn) != QDF_STATUS_SUCCESS) + goto wakeup_sources; + + if (hif_drain_tasklets(scn) != 0) + goto enable_irqs; return 0; + +enable_irqs: + if (hif_snoc_enable_irqs(scn) != QDF_STATUS_SUCCESS) + QDF_BUG(0); +wakeup_sources: + if (hif_snoc_setup_wakeup_sources(scn, false) != QDF_STATUS_SUCCESS) + QDF_BUG(0); +error: + return -EFAULT; + } /** @@ -399,6 +484,7 @@ int hif_snoc_bus_suspend(struct hif_softc *scn) * @scn: hif context * * Clear wakeup interrupt configuration. + * Reenable ce interrupts * * Return: 0 on success */ @@ -407,5 +493,8 @@ int hif_snoc_bus_resume(struct hif_softc *scn) if (hif_snoc_setup_wakeup_sources(scn, false) != QDF_STATUS_SUCCESS) QDF_BUG(0); + if (hif_snoc_enable_irqs(scn) != QDF_STATUS_SUCCESS) + QDF_BUG(0); + return 0; }