qcacmn: Fix long ping delay after enable RTPM
Issue1: Driver RTPM state is ON/NONE, Kernel state is RESUMING. cdp_runtime_resume is already complete, hif_pm_runtime_get return -E_INPROGRESS, dp_tx_hw_enqueue will set the flush event, but cdp_runtime_resume is already done, this flush event will be handled only on next pkt tx. Issue2: Driver RTPM state: Resuming hif_pm_runtime_get returns -EBUSY, dp_tx_hw_enqueue is interrupted by any IRQ, cdp_runtime_resume is completed, dp_tx_hw_enqueue will set the flush event, This flush event will be handled only on next pkt tx. Fix: Introduce a link_state_up atomic variable in hif to track the link state change by pld_cb. Set atomic variable link_state_up=1 in pmo_core_psoc_bus_runtime_resume just after pld_cb. pld_cb brings the PCIe bus out of suspend state. Set atomic variable link_state_up=0 in pmo_core_psoc_bus_runtime_suspend just before pld_cb. pld_cb puts the PCIe bus into suspend state. Introduce dp_runtime_get and dp_runtime_put. dp_runtime_get get refcount with increment of an atomic variable. dp_runtime_put return refcount with decrement of this atomic variable. If hif_pm_runtime_get returns -EBUSY or -EINPROGRESS, take the dp runtime refcount using dp_runtime_get, check if the link state is up, write TX ring HP, return the dp runtime refcount using dp_runtime_put. cdp_runtime_suspend should reject the suspend, if dp_runtime_get is non zero. cdp_runtime_resume should wait until dp_runtime_get becomes zero or time out, then flush pending tx for runtime suspend. Change-Id: I5b97d50cba710082f117f3845f7830712b86cda7 CRs-Fixed: 2844888
This commit is contained in:
@@ -2633,4 +2633,73 @@ void dp_desc_multi_pages_mem_free(struct dp_soc *soc,
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FEATURE_RUNTIME_PM
|
||||
/**
|
||||
* dp_runtime_get() - Get dp runtime refcount
|
||||
* @soc: Datapath soc handle
|
||||
*
|
||||
* Get dp runtime refcount by increment of an atomic variable, which can block
|
||||
* dp runtime resume to wait to flush pending tx by runtime suspend.
|
||||
*
|
||||
* Return: Current refcount
|
||||
*/
|
||||
static inline int32_t dp_runtime_get(struct dp_soc *soc)
|
||||
{
|
||||
return qdf_atomic_inc_return(&soc->dp_runtime_refcount);
|
||||
}
|
||||
|
||||
/**
|
||||
* dp_runtime_put() - Return dp runtime refcount
|
||||
* @soc: Datapath soc handle
|
||||
*
|
||||
* Return dp runtime refcount by decrement of an atomic variable, allow dp
|
||||
* runtime resume finish.
|
||||
*
|
||||
* Return: Current refcount
|
||||
*/
|
||||
static inline int32_t dp_runtime_put(struct dp_soc *soc)
|
||||
{
|
||||
return qdf_atomic_dec_return(&soc->dp_runtime_refcount);
|
||||
}
|
||||
|
||||
/**
|
||||
* dp_runtime_get_refcount() - Get dp runtime refcount
|
||||
* @soc: Datapath soc handle
|
||||
*
|
||||
* Get dp runtime refcount by returning an atomic variable
|
||||
*
|
||||
* Return: Current refcount
|
||||
*/
|
||||
static inline int32_t dp_runtime_get_refcount(struct dp_soc *soc)
|
||||
{
|
||||
return qdf_atomic_read(&soc->dp_runtime_refcount);
|
||||
}
|
||||
|
||||
/**
|
||||
* dp_runtime_init() - Init dp runtime refcount when dp soc init
|
||||
* @soc: Datapath soc handle
|
||||
*
|
||||
* Return: QDF_STATUS
|
||||
*/
|
||||
static inline QDF_STATUS dp_runtime_init(struct dp_soc *soc)
|
||||
{
|
||||
return qdf_atomic_init(&soc->dp_runtime_refcount);
|
||||
}
|
||||
#else
|
||||
static inline int32_t dp_runtime_get(struct dp_soc *soc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int32_t dp_runtime_put(struct dp_soc *soc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline QDF_STATUS dp_runtime_init(struct dp_soc *soc)
|
||||
{
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* #ifndef _DP_INTERNAL_H_ */
|
||||
|
@@ -5375,6 +5375,8 @@ dp_soc_attach_target_wifi3(struct cdp_soc_t *cdp_soc)
|
||||
|
||||
DP_STATS_INIT(soc);
|
||||
|
||||
dp_runtime_init(soc);
|
||||
|
||||
/* initialize work queue for stats processing */
|
||||
qdf_create_work(0, &soc->htt_stats.work, htt_t2h_stats_handler, soc);
|
||||
|
||||
@@ -11422,6 +11424,12 @@ static QDF_STATUS dp_runtime_suspend(struct cdp_soc_t *soc_hdl, uint8_t pdev_id)
|
||||
return QDF_STATUS_E_AGAIN;
|
||||
}
|
||||
|
||||
if (dp_runtime_get_refcount(soc)) {
|
||||
dp_init_info("refcount: %d", dp_runtime_get_refcount(soc));
|
||||
|
||||
return QDF_STATUS_E_AGAIN;
|
||||
}
|
||||
|
||||
if (soc->intr_mode == DP_INTR_POLL)
|
||||
qdf_timer_stop(&soc->int_timer);
|
||||
|
||||
@@ -11449,9 +11457,12 @@ void dp_flush_ring_hptp(struct dp_soc *soc, hal_ring_handle_t hal_srng)
|
||||
hal_srng_access_end(soc->hal_soc, hal_srng);
|
||||
|
||||
hal_srng_set_flush_last_ts(hal_srng);
|
||||
dp_debug("flushed");
|
||||
}
|
||||
}
|
||||
|
||||
#define DP_FLUSH_WAIT_CNT 10
|
||||
#define DP_RUNTIME_SUSPEND_WAIT_MS 10
|
||||
/**
|
||||
* dp_runtime_resume() - ensure DP is ready to runtime resume
|
||||
* @soc_hdl: Datapath soc handle
|
||||
@@ -11464,11 +11475,21 @@ void dp_flush_ring_hptp(struct dp_soc *soc, hal_ring_handle_t hal_srng)
|
||||
static QDF_STATUS dp_runtime_resume(struct cdp_soc_t *soc_hdl, uint8_t pdev_id)
|
||||
{
|
||||
struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl);
|
||||
int i;
|
||||
int i, suspend_wait = 0;
|
||||
|
||||
if (soc->intr_mode == DP_INTR_POLL)
|
||||
qdf_timer_mod(&soc->int_timer, DP_INTR_POLL_TIMER_MS);
|
||||
|
||||
/*
|
||||
* Wait until dp runtime refcount becomes zero or time out, then flush
|
||||
* pending tx for runtime suspend.
|
||||
*/
|
||||
while (dp_runtime_get_refcount(soc) &&
|
||||
suspend_wait < DP_FLUSH_WAIT_CNT) {
|
||||
qdf_sleep(DP_RUNTIME_SUSPEND_WAIT_MS);
|
||||
suspend_wait++;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_TCL_DATA_RINGS; i++) {
|
||||
dp_flush_ring_hptp(soc, soc->tcl_data_ring[i].hal_srng);
|
||||
}
|
||||
|
@@ -1295,8 +1295,73 @@ dp_tx_ring_access_end(struct dp_soc *soc, hal_ring_handle_t hal_ring_hdl,
|
||||
{
|
||||
dp_tx_hal_ring_access_end(soc, hal_ring_hdl);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef FEATURE_RUNTIME_PM
|
||||
/**
|
||||
* dp_tx_ring_access_end_wrapper() - Wrapper for ring access end
|
||||
* @soc: Datapath soc handle
|
||||
* @hal_ring_hdl: HAL ring handle
|
||||
* @coalesce: Coalesce the current write or not
|
||||
*
|
||||
* Wrapper for HAL ring access end for data transmission for
|
||||
* FEATURE_RUNTIME_PM
|
||||
*
|
||||
* Returns: none
|
||||
*/
|
||||
static inline void
|
||||
dp_tx_ring_access_end_wrapper(struct dp_soc *soc,
|
||||
hal_ring_handle_t hal_ring_hdl,
|
||||
int coalesce)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = hif_pm_runtime_get(soc->hif_handle,
|
||||
RTPM_ID_DW_TX_HW_ENQUEUE, true);
|
||||
switch (ret) {
|
||||
case 0:
|
||||
dp_tx_ring_access_end(soc, hal_ring_hdl, coalesce);
|
||||
hif_pm_runtime_put(soc->hif_handle,
|
||||
RTPM_ID_DW_TX_HW_ENQUEUE);
|
||||
break;
|
||||
/*
|
||||
* If hif_pm_runtime_get returns -EBUSY or -EINPROGRESS,
|
||||
* take the dp runtime refcount using dp_runtime_get,
|
||||
* check link state,if up, write TX ring HP, else just set flush event.
|
||||
* In dp_runtime_resume, wait until dp runtime refcount becomes
|
||||
* zero or time out, then flush pending tx.
|
||||
*/
|
||||
case -EBUSY:
|
||||
case -EINPROGRESS:
|
||||
dp_runtime_get(soc);
|
||||
if (hif_pm_get_link_state(soc->hif_handle) ==
|
||||
HIF_PM_LINK_STATE_UP) {
|
||||
dp_tx_ring_access_end(soc, hal_ring_hdl, coalesce);
|
||||
} else {
|
||||
dp_tx_hal_ring_access_end_reap(soc, hal_ring_hdl);
|
||||
hal_srng_set_event(hal_ring_hdl, HAL_SRNG_FLUSH_EVENT);
|
||||
hal_srng_inc_flush_cnt(hal_ring_hdl);
|
||||
}
|
||||
dp_runtime_put(soc);
|
||||
break;
|
||||
default:
|
||||
dp_runtime_get(soc);
|
||||
dp_tx_hal_ring_access_end_reap(soc, hal_ring_hdl);
|
||||
hal_srng_set_event(hal_ring_hdl, HAL_SRNG_FLUSH_EVENT);
|
||||
hal_srng_inc_flush_cnt(hal_ring_hdl);
|
||||
dp_runtime_put(soc);
|
||||
}
|
||||
}
|
||||
#else
|
||||
static inline void
|
||||
dp_tx_ring_access_end_wrapper(struct dp_soc *soc,
|
||||
hal_ring_handle_t hal_ring_hdl,
|
||||
int coalesce)
|
||||
{
|
||||
dp_tx_ring_access_end(soc, hal_ring_hdl, coalesce);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* dp_tx_hw_enqueue() - Enqueue to TCL HW for transmit
|
||||
* @soc: DP Soc Handle
|
||||
@@ -1432,16 +1497,7 @@ dp_tx_hw_enqueue(struct dp_soc *soc, struct dp_vdev *vdev,
|
||||
status = QDF_STATUS_SUCCESS;
|
||||
|
||||
ring_access_fail:
|
||||
if (hif_pm_runtime_get(soc->hif_handle,
|
||||
RTPM_ID_DW_TX_HW_ENQUEUE, true) == 0) {
|
||||
dp_tx_ring_access_end(soc, hal_ring_hdl, coalesce);
|
||||
hif_pm_runtime_put(soc->hif_handle,
|
||||
RTPM_ID_DW_TX_HW_ENQUEUE);
|
||||
} else {
|
||||
dp_tx_hal_ring_access_end_reap(soc, hal_ring_hdl);
|
||||
hal_srng_set_event(hal_ring_hdl, HAL_SRNG_FLUSH_EVENT);
|
||||
hal_srng_inc_flush_cnt(hal_ring_hdl);
|
||||
}
|
||||
dp_tx_ring_access_end_wrapper(soc, hal_ring_hdl, coalesce);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
@@ -1719,6 +1719,10 @@ struct dp_soc {
|
||||
#ifdef WLAN_DP_FEATURE_SW_LATENCY_MGR
|
||||
struct dp_swlm swlm;
|
||||
#endif
|
||||
#ifdef FEATURE_RUNTIME_PM
|
||||
/* Dp runtime refcount */
|
||||
qdf_atomic_t dp_runtime_refcount;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef IPA_OFFLOAD
|
||||
|
@@ -1022,8 +1022,19 @@ static inline char *rtpm_string_from_dbgid(wlan_rtpm_dbgid id)
|
||||
return (char *)strings[id];
|
||||
}
|
||||
|
||||
/**
|
||||
* enum hif_pm_link_state - hif link state
|
||||
* HIF_PM_LINK_STATE_DOWN: hif link state is down
|
||||
* HIF_PM_LINK_STATE_UP: hif link state is up
|
||||
*/
|
||||
enum hif_pm_link_state {
|
||||
HIF_PM_LINK_STATE_DOWN,
|
||||
HIF_PM_LINK_STATE_UP
|
||||
};
|
||||
|
||||
#ifdef FEATURE_RUNTIME_PM
|
||||
struct hif_pm_runtime_lock;
|
||||
|
||||
void hif_fastpath_resume(struct hif_opaque_softc *hif_ctx);
|
||||
int hif_pm_runtime_get_sync(struct hif_opaque_softc *hif_ctx,
|
||||
wlan_rtpm_dbgid rtpm_dbgid);
|
||||
@@ -1058,6 +1069,22 @@ void hif_pm_runtime_mark_dp_rx_busy(struct hif_opaque_softc *hif_ctx);
|
||||
int hif_pm_runtime_is_dp_rx_busy(struct hif_opaque_softc *hif_ctx);
|
||||
qdf_time_t hif_pm_runtime_get_dp_rx_busy_mark(struct hif_opaque_softc *hif_ctx);
|
||||
int hif_pm_runtime_sync_resume(struct hif_opaque_softc *hif_ctx);
|
||||
|
||||
/**
|
||||
* hif_pm_set_link_state() - set link state during RTPM
|
||||
* @hif_sc: HIF Context
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
void hif_pm_set_link_state(struct hif_opaque_softc *hif_handle, uint8_t val);
|
||||
|
||||
/**
|
||||
* hif_is_link_state_up() - Is link state up
|
||||
* @hif_sc: HIF Context
|
||||
*
|
||||
* Return: 1 link is up, 0 link is down
|
||||
*/
|
||||
uint8_t hif_pm_get_link_state(struct hif_opaque_softc *hif_handle);
|
||||
#else
|
||||
struct hif_pm_runtime_lock {
|
||||
const char *name;
|
||||
@@ -1132,6 +1159,10 @@ hif_pm_runtime_get_dp_rx_busy_mark(struct hif_opaque_softc *hif_ctx)
|
||||
{ return 0; }
|
||||
static inline int hif_pm_runtime_sync_resume(struct hif_opaque_softc *hif_ctx)
|
||||
{ return 0; }
|
||||
static inline
|
||||
void hif_pm_set_link_state(struct hif_opaque_softc *hif_handle, uint8_t val)
|
||||
{}
|
||||
|
||||
#endif
|
||||
|
||||
void hif_enable_power_management(struct hif_opaque_softc *hif_ctx,
|
||||
|
@@ -669,6 +669,7 @@ struct hif_opaque_softc *hif_open(qdf_device_t qdf_ctx,
|
||||
sizeof(struct hif_driver_state_callbacks));
|
||||
scn->bus_type = bus_type;
|
||||
|
||||
hif_pm_set_link_state(GET_HIF_OPAQUE_HDL(scn), HIF_PM_LINK_STATE_DOWN);
|
||||
hif_get_cfg_from_psoc(scn, psoc);
|
||||
|
||||
hif_set_event_hist_mask(GET_HIF_OPAQUE_HDL(scn));
|
||||
@@ -896,6 +897,7 @@ QDF_STATUS hif_enable(struct hif_opaque_softc *hif_ctx, struct device *dev,
|
||||
return status;
|
||||
}
|
||||
|
||||
hif_pm_set_link_state(GET_HIF_OPAQUE_HDL(scn), HIF_PM_LINK_STATE_UP);
|
||||
status = hif_hal_attach(scn);
|
||||
if (status != QDF_STATUS_SUCCESS) {
|
||||
hif_err("hal attach failed");
|
||||
@@ -949,6 +951,7 @@ void hif_disable(struct hif_opaque_softc *hif_ctx, enum hif_disable_type type)
|
||||
|
||||
hif_hal_detach(scn);
|
||||
|
||||
hif_pm_set_link_state(hif_ctx, HIF_PM_LINK_STATE_DOWN);
|
||||
hif_disable_bus(scn);
|
||||
|
||||
hif_wlan_disable(scn);
|
||||
|
@@ -265,6 +265,10 @@ struct hif_softc {
|
||||
/* Flag to indicate whether bus is suspended */
|
||||
bool bus_suspended;
|
||||
bool pktlog_init;
|
||||
#ifdef FEATURE_RUNTIME_PM
|
||||
/* Variable to track the link state change in RTPM */
|
||||
qdf_atomic_t pm_link_state;
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline
|
||||
|
@@ -1775,4 +1775,18 @@ qdf_time_t hif_pm_runtime_get_dp_rx_busy_mark(struct hif_opaque_softc *hif_ctx)
|
||||
rpm_ctx = hif_bus_get_rpm_ctx(scn);
|
||||
return rpm_ctx->dp_last_busy_timestamp;
|
||||
}
|
||||
|
||||
void hif_pm_set_link_state(struct hif_opaque_softc *hif_handle, uint8_t val)
|
||||
{
|
||||
struct hif_softc *scn = HIF_GET_SOFTC(hif_handle);
|
||||
|
||||
qdf_atomic_set(&scn->pm_link_state, val);
|
||||
}
|
||||
|
||||
uint8_t hif_pm_get_link_state(struct hif_opaque_softc *hif_handle)
|
||||
{
|
||||
struct hif_softc *scn = HIF_GET_SOFTC(hif_handle);
|
||||
|
||||
return qdf_atomic_read(&scn->pm_link_state);
|
||||
}
|
||||
#endif /* FEATURE_RUNTIME_PM */
|
||||
|
Reference in New Issue
Block a user