diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index ac7d574ae4..74407ccf30 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -3422,7 +3422,6 @@ static struct cdp_pdev *dp_pdev_attach_wifi3(struct cdp_soc_t *txrx_soc, struct wlan_cfg_dp_soc_ctxt *soc_cfg_ctx; int nss_cfg; void *sojourn_buf; - struct dp_soc *soc = (struct dp_soc *)txrx_soc; struct dp_pdev *pdev = NULL; diff --git a/hal/wifi3.0/hal_api.h b/hal/wifi3.0/hal_api.h index 1a0340665a..4dee3827fc 100644 --- a/hal/wifi3.0/hal_api.h +++ b/hal/wifi3.0/hal_api.h @@ -23,6 +23,22 @@ #include "qdf_util.h" #include "qdf_atomic.h" #include "hal_internal.h" +#include "hif.h" +#include "hif_io32.h" + +/* calculate the register address offset from bar0 of shadow register x */ +#if defined(QCA_WIFI_QCA6390) || defined(QCA_WIFI_QCA6490) +#define SHADOW_REGISTER_START_ADDRESS_OFFSET 0x000008FC +#define SHADOW_REGISTER_END_ADDRESS_OFFSET \ + ((SHADOW_REGISTER_START_ADDRESS_OFFSET) + (4 * (MAX_SHADOW_REGISTERS))) +#define SHADOW_REGISTER(x) ((SHADOW_REGISTER_START_ADDRESS_OFFSET) + (4 * (x))) +#elif defined(QCA_WIFI_QCA6290) +#define SHADOW_REGISTER_START_ADDRESS_OFFSET 0x00003024 +#define SHADOW_REGISTER_END_ADDRESS_OFFSET \ + ((SHADOW_REGISTER_START_ADDRESS_OFFSET) + (4 * (MAX_SHADOW_REGISTERS))) +#define SHADOW_REGISTER(x) ((SHADOW_REGISTER_START_ADDRESS_OFFSET) + (4 * (x))) +#endif /* QCA_WIFI_QCA6390 || QCA_WIFI_QCA6490 */ + #define MAX_UNWINDOWED_ADDRESS 0x80000 #if defined(QCA_WIFI_QCA6390) || defined(QCA_WIFI_QCA6490) || \ defined(QCA_WIFI_QCN9000) @@ -35,21 +51,12 @@ #define WINDOW_VALUE_MASK 0x3F #define WINDOW_START MAX_UNWINDOWED_ADDRESS #define WINDOW_RANGE_MASK 0x7FFFF - /* * BAR + 4K is always accessible, any access outside this * space requires force wake procedure. - * OFFSET = 4K - 32 bytes = 0x4063 + * OFFSET = 4K - 32 bytes = 0xFE0 */ -#define MAPPED_REF_OFF 0x4063 - -#ifdef HAL_CONFIG_SLUB_DEBUG_ON -#define FORCE_WAKE_DELAY_TIMEOUT 100 -#else -#define FORCE_WAKE_DELAY_TIMEOUT 50 -#endif /* HAL_CONFIG_SLUB_DEBUG_ON */ - -#define FORCE_WAKE_DELAY_MS 5 +#define MAPPED_REF_OFF 0xFE0 /** * hal_ring_desc - opaque handle for DP ring descriptor @@ -113,16 +120,6 @@ static inline void hal_reg_write_result_check(struct hal_soc *hal_soc, #endif #if !defined(QCA_WIFI_QCA6390) && !defined(QCA_WIFI_QCA6490) -static inline int hal_force_wake_request(struct hal_soc *soc) -{ - return 0; -} - -static inline int hal_force_wake_release(struct hal_soc *soc) -{ - return 0; -} - static inline void hal_lock_reg_access(struct hal_soc *soc, unsigned long *flags) { @@ -134,37 +131,7 @@ static inline void hal_unlock_reg_access(struct hal_soc *soc, { qdf_spin_unlock_irqrestore(&soc->register_access_lock); } - #else -static inline int hal_force_wake_request(struct hal_soc *soc) -{ - uint32_t timeout = 0; - int ret; - - ret = pld_force_wake_request(soc->qdf_dev->dev); - if (ret) { - QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, - "%s: Request send failed %d\n", __func__, ret); - return -EINVAL; - } - - while (!pld_is_device_awake(soc->qdf_dev->dev) && - timeout <= FORCE_WAKE_DELAY_TIMEOUT) { - mdelay(FORCE_WAKE_DELAY_MS); - timeout += FORCE_WAKE_DELAY_MS; - } - - if (pld_is_device_awake(soc->qdf_dev->dev) == true) - return 0; - else - return -ETIMEDOUT; -} - -static inline int hal_force_wake_release(struct hal_soc *soc) -{ - return pld_force_wake_release(soc->qdf_dev->dev); -} - static inline void hal_lock_reg_access(struct hal_soc *soc, unsigned long *flags) { @@ -212,10 +179,30 @@ static inline void hal_select_window(struct hal_soc *hal_soc, uint32_t offset, #endif /** + * hal_write32_mb() - Access registers to update configuration + * @hal_soc: hal soc handle + * @offset: offset address from the BAR + * @value: value to write + * + * Return: None + * + * Description: Register address space is split below: + * SHADOW REGION UNWINDOWED REGION WINDOWED REGION + * |--------------------|-------------------|------------------| + * BAR NO FORCE WAKE BAR+4K FORCE WAKE BAR+512K FORCE WAKE + * + * 1. Any access to the shadow region, doesn't need force wake + * and windowing logic to access. + * 2. Any access beyond BAR + 4K: + * If init_phase enabled, no force wake is needed and access + * should be based on windowed or unwindowed access. + * If init_phase disabled, force wake is needed and access + * should be based on windowed or unwindowed access. + * * note1: WINDOW_RANGE_MASK = (1 << WINDOW_SHIFT) -1 * note2: 1 << WINDOW_SHIFT = MAX_UNWINDOWED_ADDRESS - * note3: WINDOW_VALUE_MASK = big enough that trying to write past that window - * would be a bug + * note3: WINDOW_VALUE_MASK = big enough that trying to write past + * that window would be a bug */ #if !defined(QCA_WIFI_QCA6390) && !defined(QCA_WIFI_QCA6490) static inline void hal_write32_mb(struct hal_soc *hal_soc, uint32_t offset, @@ -248,12 +235,17 @@ static inline void hal_write32_mb(struct hal_soc *hal_soc, uint32_t offset, int ret; unsigned long flags; - if (offset > MAPPED_REF_OFF) { - ret = hal_force_wake_request(hal_soc); + /* Region < BAR + 4K can be directly accessed */ + if (offset < MAPPED_REF_OFF) { + qdf_iowrite32(hal_soc->dev_base_addr + offset, value); + return; + } + + /* Region greater than BAR + 4K */ + if (!hal_soc->init_phase) { + ret = hif_force_wake_request(hal_soc->hif_handle); if (ret) { - QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, - "%s: Wake up request failed %d\n", - __func__, ret); + hal_err("Wake up request failed"); QDF_BUG(0); return; } @@ -278,20 +270,24 @@ static inline void hal_write32_mb(struct hal_soc *hal_soc, uint32_t offset, hal_unlock_reg_access(hal_soc, &flags); } - if ((offset > MAPPED_REF_OFF) && - hal_force_wake_release(hal_soc)) - QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, - "%s: Wake up release failed\n", __func__); + if (!hal_soc->init_phase) { + ret = hif_force_wake_release(hal_soc->hif_handle); + if (ret) { + hal_err("Wake up request failed"); + QDF_BUG(0); + return; + } + } } - #endif /** * hal_write_address_32_mb - write a value to a register * */ -static inline void hal_write_address_32_mb(struct hal_soc *hal_soc, - void __iomem *addr, uint32_t value) +static inline +void hal_write_address_32_mb(struct hal_soc *hal_soc, + void __iomem *addr, uint32_t value) { uint32_t offset; @@ -303,7 +299,29 @@ static inline void hal_write_address_32_mb(struct hal_soc *hal_soc, } #if !defined(QCA_WIFI_QCA6390) && !defined(QCA_WIFI_QCA6490) -static inline uint32_t hal_read32_mb(struct hal_soc *hal_soc, uint32_t offset) +/** + * hal_read32_mb() - Access registers to read configuration + * @hal_soc: hal soc handle + * @offset: offset address from the BAR + * @value: value to write + * + * Description: Register address space is split below: + * SHADOW REGION UNWINDOWED REGION WINDOWED REGION + * |--------------------|-------------------|------------------| + * BAR NO FORCE WAKE BAR+4K FORCE WAKE BAR+512K FORCE WAKE + * + * 1. Any access to the shadow region, doesn't need force wake + * and windowing logic to access. + * 2. Any access beyond BAR + 4K: + * If init_phase enabled, no force wake is needed and access + * should be based on windowed or unwindowed access. + * If init_phase disabled, force wake is needed and access + * should be based on windowed or unwindowed access. + * + * Return: < 0 for failure/>= 0 for success + */ +static inline +uint32_t hal_read32_mb(struct hal_soc *hal_soc, uint32_t offset) { uint32_t ret; unsigned long flags; @@ -321,6 +339,45 @@ static inline uint32_t hal_read32_mb(struct hal_soc *hal_soc, uint32_t offset) return ret; } +#else +static +uint32_t hal_read32_mb(struct hal_soc *hal_soc, uint32_t offset) +{ + uint32_t ret; + unsigned long flags; + + /* Region < BAR + 4K can be directly accessed */ + if (offset < MAPPED_REF_OFF) + return qdf_ioread32(hal_soc->dev_base_addr + offset); + + if ((!hal_soc->init_phase) && + hif_force_wake_request(hal_soc->hif_handle)) { + hal_err("Wake up request failed"); + QDF_BUG(0); + return 0; + } + + if (!hal_soc->use_register_windowing || + offset < MAX_UNWINDOWED_ADDRESS) { + ret = qdf_ioread32(hal_soc->dev_base_addr + offset); + } else { + hal_lock_reg_access(hal_soc, &flags); + hal_select_window(hal_soc, offset, false); + ret = qdf_ioread32(hal_soc->dev_base_addr + WINDOW_START + + (offset & WINDOW_RANGE_MASK)); + hal_unlock_reg_access(hal_soc, &flags); + } + + if ((!hal_soc->init_phase) && + hif_force_wake_release(hal_soc->hif_handle)) { + hal_err("Wake up release failed"); + QDF_BUG(0); + return 0; + } + + return ret; +} +#endif /** * hal_read_address_32_mb() - Read 32-bit value from the register @@ -329,8 +386,9 @@ static inline uint32_t hal_read32_mb(struct hal_soc *hal_soc, uint32_t offset) * * Return: 32-bit value */ -static inline uint32_t hal_read_address_32_mb(struct hal_soc *soc, - void __iomem *addr) +static inline +uint32_t hal_read_address_32_mb(struct hal_soc *soc, + void __iomem *addr) { uint32_t offset; uint32_t ret; @@ -342,54 +400,6 @@ static inline uint32_t hal_read_address_32_mb(struct hal_soc *soc, ret = hal_read32_mb(soc, offset); return ret; } -#else -static inline uint32_t hal_read32_mb(struct hal_soc *hal_soc, uint32_t offset) -{ - uint32_t ret; - unsigned long flags; - - if ((offset > MAPPED_REF_OFF) && - hal_force_wake_request(hal_soc)) { - QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, - "%s: Wake up request failed\n", __func__); - return -EINVAL; - } - - if (!hal_soc->use_register_windowing || - offset < MAX_UNWINDOWED_ADDRESS) { - return qdf_ioread32(hal_soc->dev_base_addr + offset); - } - - hal_lock_reg_access(hal_soc, &flags); - hal_select_window(hal_soc, offset, false); - ret = qdf_ioread32(hal_soc->dev_base_addr + WINDOW_START + - (offset & WINDOW_RANGE_MASK)); - hal_unlock_reg_access(hal_soc, &flags); - - if ((offset > MAPPED_REF_OFF) && - hal_force_wake_release(hal_soc)) - QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, - "%s: Wake up release failed\n", __func__); - - return ret; -} - -static inline uint32_t hal_read_address_32_mb(struct hal_soc *soc, - void __iomem *addr) -{ - uint32_t offset; - uint32_t ret; - - if (!soc->use_register_windowing) - return qdf_ioread32(addr); - - offset = addr - soc->dev_base_addr; - ret = hal_read32_mb(soc, offset); - return ret; -} -#endif - -#include "hif_io32.h" /** * hal_attach - Initialize HAL layer @@ -455,6 +465,24 @@ enum hal_ring_type { #define PN_SIZE_48 1 #define PN_SIZE_128 2 +#ifdef FORCE_WAKE +/** + * hal_set_init_phase() - Indicate initialization of + * datapath rings + * @soc: hal_soc handle + * @init_phase: flag to indicate datapath rings + * initialization status + * + * Return: None + */ +void hal_set_init_phase(hal_soc_handle_t soc, bool init_phase); +#else +static inline +void hal_set_init_phase(hal_soc_handle_t soc, bool init_phase) +{ +} +#endif /* FORCE_WAKE */ + /** * hal_srng_get_entrysize - Returns size of ring entry in bytes. Should be * used by callers for calculating the size of memory to be allocated before diff --git a/hal/wifi3.0/hal_hw_headers.h b/hal/wifi3.0/hal_hw_headers.h index d363d1280b..b54d2a1653 100644 --- a/hal/wifi3.0/hal_hw_headers.h +++ b/hal/wifi3.0/hal_hw_headers.h @@ -83,13 +83,6 @@ #define HAL_SRNG_REO_ALTERNATE_SELECT 0x7 #define HAL_NON_QOS_TID 16 -/* calculate the register address offset from bar0 of shadow register x */ -#if defined(QCA_WIFI_QCA6390) || defined(QCA_WIFI_QCA6490) -#define SHADOW_REGISTER(x) (0x000008FC + (4 * (x))) -#else -#define SHADOW_REGISTER(x) (0x00003024 + (4 * (x))) -#endif - /* TODO: Check if the following can be provided directly by HW headers */ #define SRNG_LOOP_CNT_MASK REO_DESTINATION_RING_15_LOOPING_COUNT_MASK #define SRNG_LOOP_CNT_LSB REO_DESTINATION_RING_15_LOOPING_COUNT_LSB diff --git a/hal/wifi3.0/hal_internal.h b/hal/wifi3.0/hal_internal.h index a19771a047..76f4c08233 100644 --- a/hal/wifi3.0/hal_internal.h +++ b/hal/wifi3.0/hal_internal.h @@ -502,6 +502,9 @@ struct hal_soc { struct hal_hw_srng_config *hw_srng_table; int32_t *hal_hw_reg_offset; struct hal_hw_txrx_ops *ops; + + /* Indicate srngs initialization */ + bool init_phase; }; void hal_qca6490_attach(struct hal_soc *hal_soc); diff --git a/hal/wifi3.0/hal_srng.c b/hal/wifi3.0/hal_srng.c index 1234459d56..30836e5fa4 100644 --- a/hal/wifi3.0/hal_srng.c +++ b/hal/wifi3.0/hal_srng.c @@ -355,6 +355,11 @@ void *hal_attach(struct hif_opaque_softc *hif_handle, qdf_device_t qdf_dev) hal->target_type = hal_get_target_type(hal_soc_to_hal_soc_handle(hal)); hal_target_based_configure(hal); + /** + * Indicate Initialization of srngs to avoid force wake + * as umac power collapse is not enabled yet + */ + hal->init_phase = true; return (void *)hal; @@ -849,3 +854,12 @@ extern void hal_get_srng_params(hal_soc_handle_t hal_soc_hdl, ring_params->hwreg_base[i] = srng->hwreg_base[i]; } qdf_export_symbol(hal_get_srng_params); + +#ifdef FORCE_WAKE +void hal_set_init_phase(hal_soc_handle_t soc, bool init_phase) +{ + struct hal_soc *hal_soc = (struct hal_soc *)soc; + + hal_soc->init_phase = init_phase; +} +#endif /* FORCE_WAKE */ diff --git a/hif/inc/hif.h b/hif/inc/hif.h index ae406152ce..17745e32d1 100644 --- a/hif/inc/hif.h +++ b/hif/inc/hif.h @@ -1128,6 +1128,50 @@ void hif_clear_napi_stats(struct hif_opaque_softc *hif_ctx); } #endif +#ifdef FORCE_WAKE +/** + * hif_force_wake_request() - Function to wake from power collapse + * @handle: HIF opaque handle + * + * Description: API to check if the device is awake or not before + * read/write to BAR + 4K registers. If device is awake return + * success otherwise write '1' to + * PCIE_PCIE_LOCAL_REG_PCIE_SOC_WAKE_PCIE_LOCAL_REG which will interrupt + * the device and does wakeup the PCI and MHI within 50ms + * and then the device writes a value to + * PCIE_SOC_PCIE_REG_PCIE_SCRATCH_0_SOC_PCIE_REG to complete the + * handshake process to let the host know the device is awake. + * + * Return: zero - success/non-zero - failure + */ +int hif_force_wake_request(struct hif_opaque_softc *handle); + +/** + * hif_force_wake_release() - API to release/reset the SOC wake register + * from interrupting the device. + * @handle: HIF opaque handle + * + * Description: API to set the + * PCIE_PCIE_LOCAL_REG_PCIE_SOC_WAKE_PCIE_LOCAL_REG to '0' + * to release the interrupt line. + * + * Return: zero - success/non-zero - failure + */ +int hif_force_wake_release(struct hif_opaque_softc *handle); +#else +static inline +int hif_force_wake_request(struct hif_opaque_softc *handle) +{ + return 0; +} + +static inline +int hif_force_wake_release(struct hif_opaque_softc *handle) +{ + return 0; +} +#endif /* FORCE_WAKE */ + void *hif_get_dev_ba(struct hif_opaque_softc *hif_handle); /** @@ -1224,4 +1268,24 @@ hif_softc_to_hif_opaque_softc(struct hif_softc *hif_handle) { return (struct hif_opaque_softc *)hif_handle; } + +#ifdef FORCE_WAKE +/** + * hif_srng_init_phase(): Indicate srng initialization phase + * to avoid force wake as UMAC power collapse is not yet + * enabled + * @hif_ctx: hif opaque handle + * @init_phase: initialization phase + * + * Return: None + */ +void hif_srng_init_phase(struct hif_opaque_softc *hif_ctx, + bool init_phase); +#else +static inline +void hif_srng_init_phase(struct hif_opaque_softc *hif_ctx, + bool init_phase) +{ +} +#endif /* FORCE_WAKE */ #endif /* _HIF_H_ */ diff --git a/hif/src/hif_io32.h b/hif/src/hif_io32.h index 63674e26ff..c0bd583a56 100644 --- a/hif/src/hif_io32.h +++ b/hif/src/hif_io32.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2019 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 @@ -28,10 +28,9 @@ static inline void hif_write32_mb_reg_window(void *sc, void __iomem *addr, uint32_t value); - -static inline uint32_t hif_read32_mb_reg_window(void *sc, - void __iomem *addr); - +static inline +uint32_t hif_read32_mb_reg_window(void *sc, + void __iomem *addr); #define hif_read32_mb(scn, addr) \ hif_read32_mb_reg_window((void *)scn, \ (void __iomem *)addr) @@ -40,11 +39,9 @@ static inline uint32_t hif_read32_mb_reg_window(void *sc, (void __iomem *)addr, value) #else - #define hif_read32_mb(scn, addr) ioread32((void __iomem *)addr) #define hif_write32_mb(scn, addr, value) \ iowrite32((u32)(value), (void __iomem *)(addr)) - #endif #define Q_TARGET_ACCESS_BEGIN(scn) \ diff --git a/hif/src/hif_main.c b/hif/src/hif_main.c index 8a13b69a0e..c2cee5de29 100644 --- a/hif/src/hif_main.c +++ b/hif/src/hif_main.c @@ -77,6 +77,17 @@ void *hif_get_targetdef(struct hif_opaque_softc *hif_ctx) return scn->targetdef; } +#ifdef FORCE_WAKE +void hif_srng_init_phase(struct hif_opaque_softc *hif_ctx, + bool init_phase) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + if (ce_srng_based(scn)) + hal_set_init_phase(scn->hal_soc, init_phase); +} +#endif /* FORCE_WAKE */ + /** * hif_vote_link_down(): unvote for link up * diff --git a/hif/src/hif_main.h b/hif/src/hif_main.h index 9458d06428..8c1d48ef18 100644 --- a/hif/src/hif_main.h +++ b/hif/src/hif_main.h @@ -45,6 +45,11 @@ #define HIF_MAX_BUDGET 0xFFFF +#define HIF_STATS_INC(_handle, _field, _delta) \ +{ \ + (_handle)->stats._field += _delta; \ +} + /* * This macro implementation is exposed for efficiency only. * The implementation may change and callers should diff --git a/hif/src/pcie/if_pci.c b/hif/src/pcie/if_pci.c index 67d547cc9a..dd71b5a81c 100644 --- a/hif/src/pcie/if_pci.c +++ b/hif/src/pcie/if_pci.c @@ -1396,6 +1396,8 @@ void hif_pci_display_stats(struct hif_softc *hif_ctx) return; } hif_display_ce_stats(&pci_ctx->ce_sc); + + hif_print_pci_stats(pci_ctx); } void hif_pci_clear_stats(struct hif_softc *hif_ctx) @@ -4627,3 +4629,110 @@ bool hif_pci_needs_bmi(struct hif_softc *scn) { return !ce_srng_based(scn); } + +#ifdef FORCE_WAKE +int hif_force_wake_request(struct hif_opaque_softc *hif_handle) +{ + uint32_t timeout = 0, value; + struct hif_softc *scn = (struct hif_softc *)hif_handle; + struct hif_pci_softc *pci_scn = HIF_GET_PCI_SOFTC(scn); + + if (pld_force_wake_request(scn->qdf_dev->dev)) { + hif_err("force wake request send failed"); + return -EINVAL; + } + + HIF_STATS_INC(pci_scn, mhi_force_wake_request_vote, 1); + while (!pld_is_device_awake(scn->qdf_dev->dev) && + timeout <= FORCE_WAKE_DELAY_TIMEOUT_MS) { + qdf_mdelay(FORCE_WAKE_DELAY_MS); + timeout += FORCE_WAKE_DELAY_MS; + } + + if (pld_is_device_awake(scn->qdf_dev->dev) <= 0) { + hif_err("Unable to wake up mhi"); + HIF_STATS_INC(pci_scn, mhi_force_wake_failure, 1); + return -EINVAL; + } + HIF_STATS_INC(pci_scn, mhi_force_wake_success, 1); + hif_write32_mb(scn, + scn->mem + + PCIE_SOC_PCIE_REG_PCIE_SCRATCH_0_SOC_PCIE_REG, + 0); + hif_write32_mb(scn, + scn->mem + + PCIE_PCIE_LOCAL_REG_PCIE_SOC_WAKE_PCIE_LOCAL_REG, + 1); + + HIF_STATS_INC(pci_scn, soc_force_wake_register_write_success, 1); + /* + * do not reset the timeout + * total_wake_time = MHI_WAKE_TIME + PCI_WAKE_TIME < 50 ms + */ + do { + value = + hif_read32_mb(scn, + scn->mem + + PCIE_SOC_PCIE_REG_PCIE_SCRATCH_0_SOC_PCIE_REG); + if (value) + break; + qdf_mdelay(FORCE_WAKE_DELAY_MS); + timeout += FORCE_WAKE_DELAY_MS; + } while (timeout <= FORCE_WAKE_DELAY_TIMEOUT_MS); + + if (!value) { + hif_err("failed handshake mechanism"); + HIF_STATS_INC(pci_scn, soc_force_wake_failure, 1); + return -ETIMEDOUT; + } + + HIF_STATS_INC(pci_scn, soc_force_wake_success, 1); + + return 0; +} + +int hif_force_wake_release(struct hif_opaque_softc *hif_handle) +{ + int ret; + struct hif_softc *scn = (struct hif_softc *)hif_handle; + struct hif_pci_softc *pci_scn = HIF_GET_PCI_SOFTC(scn); + + ret = pld_force_wake_release(scn->qdf_dev->dev); + if (ret) { + hif_err("force wake release failure"); + HIF_STATS_INC(pci_scn, mhi_force_wake_release_failure, 1); + return ret; + } + + HIF_STATS_INC(pci_scn, mhi_force_wake_release_success, 1); + hif_write32_mb(scn, + scn->mem + + PCIE_PCIE_LOCAL_REG_PCIE_SOC_WAKE_PCIE_LOCAL_REG, + 0); + HIF_STATS_INC(pci_scn, soc_force_wake_release_success, 1); + return 0; +} + +void hif_print_pci_stats(struct hif_pci_softc *pci_handle) +{ + hif_debug("mhi_force_wake_request_vote: %d", + pci_handle->stats.mhi_force_wake_request_vote); + hif_debug("mhi_force_wake_failure: %d", + pci_handle->stats.mhi_force_wake_failure); + hif_debug("mhi_force_wake_success: %d", + pci_handle->stats.mhi_force_wake_success); + hif_debug("soc_force_wake_register_write_success: %d", + pci_handle->stats.soc_force_wake_register_write_success); + hif_debug("soc_force_wake_failure: %d", + pci_handle->stats.soc_force_wake_failure); + hif_debug("soc_force_wake_success: %d", + pci_handle->stats.soc_force_wake_success); + hif_debug("mhi_force_wake_release_failure: %d", + pci_handle->stats.mhi_force_wake_release_failure); + hif_debug("mhi_force_wake_release_success: %d", + pci_handle->stats.mhi_force_wake_release_success); + hif_debug("oc_force_wake_release_success: %d", + pci_handle->stats.soc_force_wake_release_success); +} +#endif /* FORCE_WAKE */ + diff --git a/hif/src/pcie/if_pci.h b/hif/src/pcie/if_pci.h index 68109291d6..1940a9c33d 100644 --- a/hif/src/pcie/if_pci.h +++ b/hif/src/pcie/if_pci.h @@ -29,6 +29,21 @@ #include "cepci.h" #include "ce_main.h" +#ifdef FORCE_WAKE +/* Register to wake the UMAC from power collapse */ +#define PCIE_SOC_PCIE_REG_PCIE_SCRATCH_0_SOC_PCIE_REG 0x4040 +/* Register used for handshake mechanism to validate UMAC is awake */ +#define PCIE_PCIE_LOCAL_REG_PCIE_SOC_WAKE_PCIE_LOCAL_REG 0x3004 +/* Timeout duration to validate UMAC wake status */ +#ifdef HAL_CONFIG_SLUB_DEBUG_ON +#define FORCE_WAKE_DELAY_TIMEOUT_MS 100 +#else +#define FORCE_WAKE_DELAY_TIMEOUT_MS 50 +#endif /* HAL_CONFIG_SLUB_DEBUG_ON */ +/* Validate UMAC status every 5ms */ +#define FORCE_WAKE_DELAY_MS 5 +#endif /* FORCE_WAKE */ + #ifdef QCA_HIF_HIA_EXTND extern int32_t frac, intval, ar900b_20_targ_clk, qca9888_20_targ_clk; #endif @@ -106,6 +121,29 @@ struct hif_msi_info { OS_DMA_MEM_CONTEXT(dmacontext); }; +/** + * struct hif_pci_stats - Account for hif pci based statistics + * @mhi_force_wake_request_vote: vote for mhi + * @mhi_force_wake_failure: mhi force wake failure + * @mhi_force_wake_success: mhi force wake success + * @soc_force_wake_register_write_success: write to soc wake + * @soc_force_wake_failure: soc force wake failure + * @soc_force_wake_success: soc force wake success + * @mhi_force_wake_release_success: mhi force wake release success + * @soc_force_wake_release_success: soc force wake release + */ +struct hif_pci_stats { + uint32_t mhi_force_wake_request_vote; + uint32_t mhi_force_wake_failure; + uint32_t mhi_force_wake_success; + uint32_t soc_force_wake_register_write_success; + uint32_t soc_force_wake_failure; + uint32_t soc_force_wake_success; + uint32_t mhi_force_wake_release_failure; + uint32_t mhi_force_wake_release_success; + uint32_t soc_force_wake_release_success; +}; + struct hif_pci_softc { struct HIF_CE_state ce_sc; void __iomem *mem; /* PCI address. */ @@ -152,6 +190,7 @@ struct hif_pci_softc { void (*hif_pci_deinit)(struct hif_pci_softc *sc); void (*hif_pci_get_soc_info)(struct hif_pci_softc *sc, struct device *dev); + struct hif_pci_stats stats; }; bool hif_pci_targ_is_present(struct hif_softc *scn, void *__iomem *mem); @@ -196,6 +235,21 @@ int hif_pci_addr_in_boundary(struct hif_softc *scn, uint32_t offset); #define OL_ATH_TX_DRAIN_WAIT_CNT 60 #endif +#ifdef FORCE_WAKE +/** + * hif_print_pci_stats() - Display HIF PCI stats + * @hif_ctx - HIF pci handle + * + * Return: None + */ +void hif_print_pci_stats(struct hif_pci_softc *pci_scn); +#else +static inline +void hif_print_pci_stats(struct hif_pci_softc *pci_scn) +{ +} +#endif /* FORCE_WAKE */ + #ifdef FEATURE_RUNTIME_PM #include