From 90a054551e00917d7eba14422202a8a0c397bcd4 Mon Sep 17 00:00:00 2001 From: Manikanta Pubbisetty Date: Mon, 1 Mar 2021 13:09:21 +0530 Subject: [PATCH] qcacmn: disable EXT grp irqs and drain TXRX during suspend Any update to the SRNG TP/HP when the device is in low power state would result in system errors. It is recommended to disable EXT grp irqs and drain TXRX before sending power save enter command to the FW. This will ensure that no interrupts are received while in power save mode and as a result there wont be any HP/TP updates. Change-Id: Ibf952bbc2c6d13fb3e4ca6b4845bc9cc887fa694 CRs-Fixed: 2883135 --- dp/inc/cdp_txrx_cmn.h | 21 +++++++++++ dp/inc/cdp_txrx_ops.h | 1 + dp/wifi3.0/dp_main.c | 44 ++++++++++++++++++++++ hif/inc/hif.h | 32 ++++++++++++++++ hif/src/dispatcher/dummy.c | 22 ++++++++++- hif/src/dispatcher/dummy.h | 4 +- hif/src/dispatcher/ipci_api.h | 21 ++++++++++- hif/src/dispatcher/multibus.c | 60 ++++++++++++++++++++++++++++++ hif/src/dispatcher/multibus.h | 4 +- hif/src/dispatcher/multibus_ipci.c | 4 +- hif/src/ipcie/if_ipci.c | 10 +++++ 11 files changed, 218 insertions(+), 5 deletions(-) diff --git a/dp/inc/cdp_txrx_cmn.h b/dp/inc/cdp_txrx_cmn.h index 6ffd5433576c..3fc8d89427dc 100644 --- a/dp/inc/cdp_txrx_cmn.h +++ b/dp/inc/cdp_txrx_cmn.h @@ -2709,4 +2709,25 @@ cdp_wds_ext_set_peer_rx(ol_txrx_soc_handle soc, uint8_t vdev_id, (soc, vdev_id, mac, rx, osif_peer); } #endif /* QCA_SUPPORT_WDS_EXTENDED */ + +/** + * cdp_drain_txrx() - drain TX/RX SRNGs + * @soc: opaque soc handle + */ +static inline void +cdp_drain_txrx(ol_txrx_soc_handle soc) +{ + if (!soc || !soc->ops) { + QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG, + "%s: Invalid Instance", __func__); + QDF_BUG(0); + return; + } + + if (!soc->ops->cmn_drv_ops || + !soc->ops->cmn_drv_ops->txrx_drain) + return; + + return soc->ops->cmn_drv_ops->txrx_drain(soc); +} #endif /* _CDP_TXRX_CMN_H_ */ diff --git a/dp/inc/cdp_txrx_ops.h b/dp/inc/cdp_txrx_ops.h index f208d1951a96..235dc91012a5 100644 --- a/dp/inc/cdp_txrx_ops.h +++ b/dp/inc/cdp_txrx_ops.h @@ -566,6 +566,7 @@ struct cdp_cmn_ops { ol_txrx_rx_fp rx, ol_osif_peer_handle osif_peer); #endif /* QCA_SUPPORT_WDS_EXTENDED */ + void (*txrx_drain)(ol_txrx_soc_handle soc); }; struct cdp_ctrl_ops { diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index 558cf112545a..c2267781e8de 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -9978,11 +9978,25 @@ void dp_update_rx_soft_irq_limit_params(struct dp_soc *soc, soc->wlan_cfg_ctx->rx_enable_eol_data_check, soc->wlan_cfg_ctx->rx_hp_oos_update_limit); } + +static void dp_update_soft_irq_limits(struct dp_soc *soc, uint32_t tx_limit, + uint32_t rx_limit) +{ + soc->wlan_cfg_ctx->tx_comp_loop_pkt_limit = tx_limit; + soc->wlan_cfg_ctx->rx_reap_loop_pkt_limit = rx_limit; +} + #else static inline void dp_update_rx_soft_irq_limit_params(struct dp_soc *soc, struct cdp_config_params *params) { } + +static inline +void dp_update_soft_irq_limits(struct dp_soc *soc, uint32_t tx_limit, + uint32_t rx_limit) +{ +} #endif /* WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT */ /** @@ -11016,6 +11030,32 @@ dp_config_full_mon_mode(struct cdp_soc_t *soc_handle, } #endif +#if defined(FEATURE_RUNTIME_PM) || defined(DP_POWER_SAVE) +static void dp_drain_txrx(struct cdp_soc_t *soc_handle) +{ + struct dp_soc *soc = (struct dp_soc *)soc_handle; + uint32_t cur_tx_limit, cur_rx_limit; + uint32_t budget = 0xffff; + int i; + + cur_tx_limit = soc->wlan_cfg_ctx->tx_comp_loop_pkt_limit; + cur_rx_limit = soc->wlan_cfg_ctx->rx_reap_loop_pkt_limit; + + /* Temporarily increase soft irq limits when going to drain + * the UMAC/LMAC SRNGs and restore them after polling. + * Though the budget is on higher side, the TX/RX reaping loops + * will not execute longer as both TX and RX would be suspended + * by the time this API is called. + */ + dp_update_soft_irq_limits(soc, budget, budget); + + for (i = 0; i < wlan_cfg_get_num_contexts(soc->wlan_cfg_ctx); i++) + dp_service_srngs(&soc->intr_ctx[i], budget); + + dp_update_soft_irq_limits(soc, cur_tx_limit, cur_rx_limit); +} +#endif + static struct cdp_cmn_ops dp_ops_cmn = { .txrx_soc_attach_target = dp_soc_attach_target_wifi3, .txrx_vdev_attach = dp_vdev_attach_wifi3, @@ -11114,6 +11154,10 @@ static struct cdp_cmn_ops dp_ops_cmn = { .get_wds_ext_peer_id = dp_wds_ext_get_peer_id, .set_wds_ext_peer_rx = dp_wds_ext_set_peer_rx, #endif /* QCA_SUPPORT_WDS_EXTENDED */ + +#if defined(FEATURE_RUNTIME_PM) || defined(DP_POWER_SAVE) + .txrx_drain = dp_drain_txrx, +#endif }; static struct cdp_ctrl_ops dp_ops_ctrl = { diff --git a/hif/inc/hif.h b/hif/inc/hif.h index d3c3ff4d5533..9e2d3e16fed1 100644 --- a/hif/inc/hif.h +++ b/hif/inc/hif.h @@ -1698,4 +1698,36 @@ static inline void hif_config_irq_set_perf_affinity_hint( { } #endif + +/** + * hif_apps_grp_irqs_enable() - enable ext grp irqs + * @hif - HIF opaque context + * + * Return: 0 on success. Error code on failure. + */ +int hif_apps_grp_irqs_enable(struct hif_opaque_softc *hif_ctx); + +/** + * hif_apps_grp_irqs_disable() - disable ext grp irqs + * @hif - HIF opaque context + * + * Return: 0 on success. Error code on failure. + */ +int hif_apps_grp_irqs_disable(struct hif_opaque_softc *hif_ctx); + +/** + * hif_disable_grp_irqs() - disable ext grp irqs + * @hif - HIF opaque context + * + * Return: 0 on success. Error code on failure. + */ +int hif_disable_grp_irqs(struct hif_opaque_softc *scn); + +/** + * hif_enable_grp_irqs() - enable ext grp irqs + * @hif - HIF opaque context + * + * Return: 0 on success. Error code on failure. + */ +int hif_enable_grp_irqs(struct hif_opaque_softc *scn); #endif /* _HIF_H_ */ diff --git a/hif/src/dispatcher/dummy.c b/hif/src/dispatcher/dummy.c index b32a18273276..0d8a66b56f79 100644 --- a/hif/src/dispatcher/dummy.c +++ b/hif/src/dispatcher/dummy.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -389,3 +389,23 @@ void hif_dummy_log_bus_info(struct hif_softc *scn, uint8_t *data, unsigned int *offset) { } + +/** + * hif_dummy_enable_grp_irqs - dummy call + * @scn: hif context + * Return: EOPNOTSUPP + */ +int hif_dummy_enable_grp_irqs(struct hif_softc *scn) +{ + return -EOPNOTSUPP; +} + +/** + * hif_dummy_disable_grp_irqs - dummy call + * @scn: hif context + * Return: EOPNOTSUPP + */ +int hif_dummy_disable_grp_irqs(struct hif_softc *scn) +{ + return -EOPNOTSUPP; +} diff --git a/hif/src/dispatcher/dummy.h b/hif/src/dispatcher/dummy.h index d7a28fff7e91..ea66a27a2d00 100644 --- a/hif/src/dispatcher/dummy.h +++ b/hif/src/dispatcher/dummy.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -62,3 +62,5 @@ int hif_dummy_addr_in_boundary(struct hif_softc *scn, uint32_t offset); void hif_dummy_config_irq_affinity(struct hif_softc *scn); void hif_dummy_log_bus_info(struct hif_softc *scn, uint8_t *data, unsigned int *offset); +int hif_dummy_enable_grp_irqs(struct hif_softc *scn); +int hif_dummy_disable_grp_irqs(struct hif_softc *scn); diff --git a/hif/src/dispatcher/ipci_api.h b/hif/src/dispatcher/ipci_api.h index 897e21e4e1d2..7952db3dde6b 100644 --- a/hif/src/dispatcher/ipci_api.h +++ b/hif/src/dispatcher/ipci_api.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -240,4 +240,23 @@ bool hif_ipci_needs_bmi(struct hif_softc *scn); */ const char *hif_ipci_get_irq_name(int irq_no); +/** + * hif_ipci_enable_grp_irqs(): enable grp IRQs + * @scn: struct hif_softc + * + * This function enables grp irqs + * + * Return: 0 if success, error code if failure + */ +int hif_ipci_enable_grp_irqs(struct hif_softc *scn); + +/** + * hif_ipci_disable_grp_irqs(): disable grp IRQs + * @scn: struct hif_softc + * + * This function disables grp irqs + * + * Return: 0 if success, error code if failure + */ +int hif_ipci_disable_grp_irqs(struct hif_softc *scn); #endif /* _IPCI_API_H_ */ diff --git a/hif/src/dispatcher/multibus.c b/hif/src/dispatcher/multibus.c index 0ba0b4db1100..8ca93da4901c 100644 --- a/hif/src/dispatcher/multibus.c +++ b/hif/src/dispatcher/multibus.c @@ -60,6 +60,8 @@ static void hif_initialize_default_ops(struct hif_softc *hif_sc) bus_ops->hif_grp_irq_configure = &hif_dummy_grp_irq_configure; bus_ops->hif_config_irq_affinity = &hif_dummy_config_irq_affinity; + bus_ops->hif_enable_grp_irqs = &hif_dummy_enable_grp_irqs; + bus_ops->hif_disable_grp_irqs = &hif_dummy_enable_grp_irqs; } #define NUM_OPS (sizeof(struct hif_bus_ops) / sizeof(void *)) @@ -617,3 +619,61 @@ void hif_log_bus_info(struct hif_softc *hif_sc, uint8_t *data, hif_sc->bus_ops.hif_log_bus_info(hif_sc, data, offset); } #endif + +int hif_apps_grp_irqs_enable(struct hif_opaque_softc *hif_ctx) +{ + struct hif_exec_context *hif_exec; + struct hif_softc *scn; + int i; + + QDF_BUG(hif_ctx); + scn = HIF_GET_SOFTC(hif_ctx); + if (!scn) + return -EINVAL; + + for (i = 0 ; i < HIF_MAX_GROUP; i++) { + hif_exec = hif_exec_get_ctx(hif_ctx, i); + if (!hif_exec) + continue; + + hif_exec->irq_enable(hif_exec); + } + + return 0; +} + +int hif_apps_grp_irqs_disable(struct hif_opaque_softc *hif_ctx) +{ + struct hif_exec_context *hif_exec; + struct hif_softc *scn; + int i; + + QDF_BUG(hif_ctx); + scn = HIF_GET_SOFTC(hif_ctx); + if (!scn) + return -EINVAL; + + for (i = 0 ; i < HIF_MAX_GROUP; i++) { + hif_exec = hif_exec_get_ctx(hif_ctx, i); + if (!hif_exec) + continue; + + hif_exec->irq_disable(hif_exec); + } + + return 0; +} + +int hif_disable_grp_irqs(struct hif_opaque_softc *scn) +{ + struct hif_softc *hif_sc = HIF_GET_SOFTC(scn); + + return hif_sc->bus_ops.hif_disable_grp_irqs(hif_sc); +} + +int hif_enable_grp_irqs(struct hif_opaque_softc *scn) +{ + struct hif_softc *hif_sc = HIF_GET_SOFTC(scn); + + return hif_sc->bus_ops.hif_enable_grp_irqs(hif_sc); +} diff --git a/hif/src/dispatcher/multibus.h b/hif/src/dispatcher/multibus.h index e797531c391f..3c1f901381b1 100644 --- a/hif/src/dispatcher/multibus.h +++ b/hif/src/dispatcher/multibus.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018, 2020-2021 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -88,6 +88,8 @@ struct hif_bus_ops { void (*hif_config_irq_affinity)(struct hif_softc *hif_sc); void (*hif_log_bus_info)(struct hif_softc *scn, uint8_t *data, unsigned int *offset); + int (*hif_enable_grp_irqs)(struct hif_softc *scn); + int (*hif_disable_grp_irqs)(struct hif_softc *scn); }; #ifdef HIF_SNOC diff --git a/hif/src/dispatcher/multibus_ipci.c b/hif/src/dispatcher/multibus_ipci.c index d30fd74b5d9d..bef2a131bd3f 100644 --- a/hif/src/dispatcher/multibus_ipci.c +++ b/hif/src/dispatcher/multibus_ipci.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -78,6 +78,8 @@ QDF_STATUS hif_initialize_ipci_ops(struct hif_softc *hif_sc) bus_ops->hif_config_irq_affinity = &hif_dummy_config_irq_affinity; bus_ops->hif_log_bus_info = &hif_dummy_log_bus_info; + bus_ops->hif_enable_grp_irqs = hif_ipci_enable_grp_irqs; + bus_ops->hif_disable_grp_irqs = hif_ipci_disable_grp_irqs; return QDF_STATUS_SUCCESS; } diff --git a/hif/src/ipcie/if_ipci.c b/hif/src/ipcie/if_ipci.c index 4d0bc168f89f..f20a3ce59e27 100644 --- a/hif/src/ipcie/if_ipci.c +++ b/hif/src/ipcie/if_ipci.c @@ -826,3 +826,13 @@ void hif_allow_link_low_power_states(struct hif_opaque_softc *hif) { } #endif + +int hif_ipci_enable_grp_irqs(struct hif_softc *scn) +{ + return hif_apps_grp_irqs_enable(GET_HIF_OPAQUE_HDL(scn)); +} + +int hif_ipci_disable_grp_irqs(struct hif_softc *scn) +{ + return hif_apps_grp_irqs_disable(GET_HIF_OPAQUE_HDL(scn)); +}