qcacmn: Support force wake request

1. Add hif_force_wake_request API to wake the
mhi and umac before reading/writing the memory region
greater than BAR+4K.
2. Add hif_force_wake_release API to release the
PCIE_PCIE_LOCAL_REG_PCIE_SOC_WAKE_PCIE_LOCAL_REG so the
umac can power collapse again at a later point of time.
3. Add pci stats to dump the force wake status.

Change-Id: Ic6d5463ea0cdb28d9144be61da55e43033b53298
CRs-Fixed: 2478052
This commit is contained in:
Venkata Sharath Chandra Manchala
2019-06-18 17:18:47 -07:00
committed by nshrivas
parent a32b831887
commit 2b0d3f38d5
11 changed files with 408 additions and 131 deletions

View File

@@ -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; struct wlan_cfg_dp_soc_ctxt *soc_cfg_ctx;
int nss_cfg; int nss_cfg;
void *sojourn_buf; void *sojourn_buf;
struct dp_soc *soc = (struct dp_soc *)txrx_soc; struct dp_soc *soc = (struct dp_soc *)txrx_soc;
struct dp_pdev *pdev = NULL; struct dp_pdev *pdev = NULL;

View File

@@ -23,6 +23,22 @@
#include "qdf_util.h" #include "qdf_util.h"
#include "qdf_atomic.h" #include "qdf_atomic.h"
#include "hal_internal.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 #define MAX_UNWINDOWED_ADDRESS 0x80000
#if defined(QCA_WIFI_QCA6390) || defined(QCA_WIFI_QCA6490) || \ #if defined(QCA_WIFI_QCA6390) || defined(QCA_WIFI_QCA6490) || \
defined(QCA_WIFI_QCN9000) defined(QCA_WIFI_QCN9000)
@@ -35,21 +51,12 @@
#define WINDOW_VALUE_MASK 0x3F #define WINDOW_VALUE_MASK 0x3F
#define WINDOW_START MAX_UNWINDOWED_ADDRESS #define WINDOW_START MAX_UNWINDOWED_ADDRESS
#define WINDOW_RANGE_MASK 0x7FFFF #define WINDOW_RANGE_MASK 0x7FFFF
/* /*
* BAR + 4K is always accessible, any access outside this * BAR + 4K is always accessible, any access outside this
* space requires force wake procedure. * space requires force wake procedure.
* OFFSET = 4K - 32 bytes = 0x4063 * OFFSET = 4K - 32 bytes = 0xFE0
*/ */
#define MAPPED_REF_OFF 0x4063 #define MAPPED_REF_OFF 0xFE0
#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
/** /**
* hal_ring_desc - opaque handle for DP ring descriptor * 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 #endif
#if !defined(QCA_WIFI_QCA6390) && !defined(QCA_WIFI_QCA6490) #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, static inline void hal_lock_reg_access(struct hal_soc *soc,
unsigned long *flags) 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); qdf_spin_unlock_irqrestore(&soc->register_access_lock);
} }
#else #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, static inline void hal_lock_reg_access(struct hal_soc *soc,
unsigned long *flags) unsigned long *flags)
{ {
@@ -212,10 +179,30 @@ static inline void hal_select_window(struct hal_soc *hal_soc, uint32_t offset,
#endif #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 * note1: WINDOW_RANGE_MASK = (1 << WINDOW_SHIFT) -1
* note2: 1 << WINDOW_SHIFT = MAX_UNWINDOWED_ADDRESS * note2: 1 << WINDOW_SHIFT = MAX_UNWINDOWED_ADDRESS
* note3: WINDOW_VALUE_MASK = big enough that trying to write past that window * note3: WINDOW_VALUE_MASK = big enough that trying to write past
* would be a bug * that window would be a bug
*/ */
#if !defined(QCA_WIFI_QCA6390) && !defined(QCA_WIFI_QCA6490) #if !defined(QCA_WIFI_QCA6390) && !defined(QCA_WIFI_QCA6490)
static inline void hal_write32_mb(struct hal_soc *hal_soc, uint32_t offset, 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; int ret;
unsigned long flags; unsigned long flags;
if (offset > MAPPED_REF_OFF) { /* Region < BAR + 4K can be directly accessed */
ret = hal_force_wake_request(hal_soc); 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) { if (ret) {
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, hal_err("Wake up request failed");
"%s: Wake up request failed %d\n",
__func__, ret);
QDF_BUG(0); QDF_BUG(0);
return; return;
} }
@@ -278,19 +270,23 @@ static inline void hal_write32_mb(struct hal_soc *hal_soc, uint32_t offset,
hal_unlock_reg_access(hal_soc, &flags); hal_unlock_reg_access(hal_soc, &flags);
} }
if ((offset > MAPPED_REF_OFF) && if (!hal_soc->init_phase) {
hal_force_wake_release(hal_soc)) ret = hif_force_wake_release(hal_soc->hif_handle);
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, if (ret) {
"%s: Wake up release failed\n", __func__); hal_err("Wake up request failed");
QDF_BUG(0);
return;
}
}
} }
#endif #endif
/** /**
* hal_write_address_32_mb - write a value to a register * hal_write_address_32_mb - write a value to a register
* *
*/ */
static inline void hal_write_address_32_mb(struct hal_soc *hal_soc, static inline
void hal_write_address_32_mb(struct hal_soc *hal_soc,
void __iomem *addr, uint32_t value) void __iomem *addr, uint32_t value)
{ {
uint32_t offset; 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) #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; uint32_t ret;
unsigned long flags; unsigned long flags;
@@ -321,6 +339,45 @@ static inline uint32_t hal_read32_mb(struct hal_soc *hal_soc, uint32_t offset)
return ret; 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 * hal_read_address_32_mb() - Read 32-bit value from the register
@@ -329,7 +386,8 @@ static inline uint32_t hal_read32_mb(struct hal_soc *hal_soc, uint32_t offset)
* *
* Return: 32-bit value * Return: 32-bit value
*/ */
static inline uint32_t hal_read_address_32_mb(struct hal_soc *soc, static inline
uint32_t hal_read_address_32_mb(struct hal_soc *soc,
void __iomem *addr) void __iomem *addr)
{ {
uint32_t offset; uint32_t offset;
@@ -342,54 +400,6 @@ static inline uint32_t hal_read_address_32_mb(struct hal_soc *soc,
ret = hal_read32_mb(soc, offset); ret = hal_read32_mb(soc, offset);
return ret; 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 * hal_attach - Initialize HAL layer
@@ -455,6 +465,24 @@ enum hal_ring_type {
#define PN_SIZE_48 1 #define PN_SIZE_48 1
#define PN_SIZE_128 2 #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 * 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 * used by callers for calculating the size of memory to be allocated before

View File

@@ -83,13 +83,6 @@
#define HAL_SRNG_REO_ALTERNATE_SELECT 0x7 #define HAL_SRNG_REO_ALTERNATE_SELECT 0x7
#define HAL_NON_QOS_TID 16 #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 */ /* 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_MASK REO_DESTINATION_RING_15_LOOPING_COUNT_MASK
#define SRNG_LOOP_CNT_LSB REO_DESTINATION_RING_15_LOOPING_COUNT_LSB #define SRNG_LOOP_CNT_LSB REO_DESTINATION_RING_15_LOOPING_COUNT_LSB

View File

@@ -502,6 +502,9 @@ struct hal_soc {
struct hal_hw_srng_config *hw_srng_table; struct hal_hw_srng_config *hw_srng_table;
int32_t *hal_hw_reg_offset; int32_t *hal_hw_reg_offset;
struct hal_hw_txrx_ops *ops; struct hal_hw_txrx_ops *ops;
/* Indicate srngs initialization */
bool init_phase;
}; };
void hal_qca6490_attach(struct hal_soc *hal_soc); void hal_qca6490_attach(struct hal_soc *hal_soc);

View File

@@ -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_type = hal_get_target_type(hal_soc_to_hal_soc_handle(hal));
hal_target_based_configure(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; 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]; ring_params->hwreg_base[i] = srng->hwreg_base[i];
} }
qdf_export_symbol(hal_get_srng_params); 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 */

View File

@@ -1128,6 +1128,50 @@ void hif_clear_napi_stats(struct hif_opaque_softc *hif_ctx);
} }
#endif #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); 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; 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_ */ #endif /* _HIF_H_ */

View File

@@ -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 * Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the * any purpose with or without fee is hereby granted, provided that the
@@ -28,10 +28,9 @@
static inline static inline
void hif_write32_mb_reg_window(void *sc, void hif_write32_mb_reg_window(void *sc,
void __iomem *addr, uint32_t value); void __iomem *addr, uint32_t value);
static inline
static inline uint32_t hif_read32_mb_reg_window(void *sc, uint32_t hif_read32_mb_reg_window(void *sc,
void __iomem *addr); void __iomem *addr);
#define hif_read32_mb(scn, addr) \ #define hif_read32_mb(scn, addr) \
hif_read32_mb_reg_window((void *)scn, \ hif_read32_mb_reg_window((void *)scn, \
(void __iomem *)addr) (void __iomem *)addr)
@@ -40,11 +39,9 @@ static inline uint32_t hif_read32_mb_reg_window(void *sc,
(void __iomem *)addr, value) (void __iomem *)addr, value)
#else #else
#define hif_read32_mb(scn, addr) ioread32((void __iomem *)addr) #define hif_read32_mb(scn, addr) ioread32((void __iomem *)addr)
#define hif_write32_mb(scn, addr, value) \ #define hif_write32_mb(scn, addr, value) \
iowrite32((u32)(value), (void __iomem *)(addr)) iowrite32((u32)(value), (void __iomem *)(addr))
#endif #endif
#define Q_TARGET_ACCESS_BEGIN(scn) \ #define Q_TARGET_ACCESS_BEGIN(scn) \

View File

@@ -77,6 +77,17 @@ void *hif_get_targetdef(struct hif_opaque_softc *hif_ctx)
return scn->targetdef; 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 * hif_vote_link_down(): unvote for link up
* *

View File

@@ -45,6 +45,11 @@
#define HIF_MAX_BUDGET 0xFFFF #define HIF_MAX_BUDGET 0xFFFF
#define HIF_STATS_INC(_handle, _field, _delta) \
{ \
(_handle)->stats._field += _delta; \
}
/* /*
* This macro implementation is exposed for efficiency only. * This macro implementation is exposed for efficiency only.
* The implementation may change and callers should * The implementation may change and callers should

View File

@@ -1396,6 +1396,8 @@ void hif_pci_display_stats(struct hif_softc *hif_ctx)
return; return;
} }
hif_display_ce_stats(&pci_ctx->ce_sc); hif_display_ce_stats(&pci_ctx->ce_sc);
hif_print_pci_stats(pci_ctx);
} }
void hif_pci_clear_stats(struct hif_softc *hif_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); 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 */

View File

@@ -29,6 +29,21 @@
#include "cepci.h" #include "cepci.h"
#include "ce_main.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 #ifdef QCA_HIF_HIA_EXTND
extern int32_t frac, intval, ar900b_20_targ_clk, qca9888_20_targ_clk; extern int32_t frac, intval, ar900b_20_targ_clk, qca9888_20_targ_clk;
#endif #endif
@@ -106,6 +121,29 @@ struct hif_msi_info {
OS_DMA_MEM_CONTEXT(dmacontext); 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_pci_softc {
struct HIF_CE_state ce_sc; struct HIF_CE_state ce_sc;
void __iomem *mem; /* PCI address. */ 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_deinit)(struct hif_pci_softc *sc);
void (*hif_pci_get_soc_info)(struct hif_pci_softc *sc, void (*hif_pci_get_soc_info)(struct hif_pci_softc *sc,
struct device *dev); struct device *dev);
struct hif_pci_stats stats;
}; };
bool hif_pci_targ_is_present(struct hif_softc *scn, void *__iomem *mem); 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 #define OL_ATH_TX_DRAIN_WAIT_CNT 60
#endif #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 #ifdef FEATURE_RUNTIME_PM
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>