mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-09 21:59:12 -04:00
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
This commit is contained in:
parent
903165f2ef
commit
2af3d67336
5 changed files with 104 additions and 85 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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__ */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue