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:
Jianmin Zhu
2021-01-09 13:01:37 +08:00
committed by snandini
parent 1e157ef978
commit 6ef2047d56
8 changed files with 214 additions and 12 deletions

View File

@@ -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;
}