ath11k: start a timer to update TCL HP
The timer is to check if TCL HP isn't updated to target. The timer will postpone itself if there are TX operations during the interval, otherwise the timer handler updates the HP again so the index value in HP register will be forwarded to target register, and the timer stops afterwards. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Signed-off-by: Carl Huang <cjhuang@codeaurora.org> Signed-off-by: Kalle Valo <kvalo@codeaurora.org> Link: https://lore.kernel.org/r/1601544890-13450-5-git-send-email-kvalo@codeaurora.org
This commit is contained in:
@@ -304,11 +304,23 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath11k_dp_stop_shadow_timers(struct ath11k_base *ab)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!ab->hw_params.supports_shadow_regs)
|
||||
return;
|
||||
|
||||
for (i = 0; i < DP_TCL_NUM_RING_MAX; i++)
|
||||
ath11k_dp_shadow_stop_timer(ab, &ab->dp.tx_ring_timer[i]);
|
||||
}
|
||||
|
||||
static void ath11k_dp_srng_common_cleanup(struct ath11k_base *ab)
|
||||
{
|
||||
struct ath11k_dp *dp = &ab->dp;
|
||||
int i;
|
||||
|
||||
ath11k_dp_stop_shadow_timers(ab);
|
||||
ath11k_dp_srng_cleanup(ab, &dp->wbm_desc_rel_ring);
|
||||
ath11k_dp_srng_cleanup(ab, &dp->tcl_cmd_ring);
|
||||
ath11k_dp_srng_cleanup(ab, &dp->tcl_status_ring);
|
||||
@@ -374,6 +386,10 @@ static int ath11k_dp_srng_common_setup(struct ath11k_base *ab)
|
||||
|
||||
srng = &ab->hal.srng_list[dp->tx_ring[i].tcl_data_ring.ring_id];
|
||||
ath11k_hal_tx_init_data_ring(ab, srng);
|
||||
|
||||
ath11k_dp_shadow_init_timer(ab, &dp->tx_ring_timer[i],
|
||||
ATH11K_SHADOW_DP_TIMER_INTERVAL,
|
||||
dp->tx_ring[i].tcl_data_ring.ring_id);
|
||||
}
|
||||
|
||||
ret = ath11k_dp_srng_setup(ab, &dp->reo_reinject_ring, HAL_REO_REINJECT,
|
||||
@@ -1066,3 +1082,78 @@ fail_link_desc_cleanup:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ath11k_dp_shadow_timer_handler(struct timer_list *t)
|
||||
{
|
||||
struct ath11k_hp_update_timer *update_timer = from_timer(update_timer,
|
||||
t, timer);
|
||||
struct ath11k_base *ab = update_timer->ab;
|
||||
struct hal_srng *srng = &ab->hal.srng_list[update_timer->ring_id];
|
||||
|
||||
spin_lock_bh(&srng->lock);
|
||||
|
||||
/* when the timer is fired, the handler checks whether there
|
||||
* are new TX happened. The handler updates HP only when there
|
||||
* are no TX operations during the timeout interval, and stop
|
||||
* the timer. Timer will be started again when TX happens again.
|
||||
*/
|
||||
if (update_timer->timer_tx_num != update_timer->tx_num) {
|
||||
update_timer->timer_tx_num = update_timer->tx_num;
|
||||
mod_timer(&update_timer->timer, jiffies +
|
||||
msecs_to_jiffies(update_timer->interval));
|
||||
} else {
|
||||
update_timer->started = false;
|
||||
ath11k_hal_srng_shadow_update_hp_tp(ab, srng);
|
||||
}
|
||||
|
||||
spin_unlock_bh(&srng->lock);
|
||||
}
|
||||
|
||||
void ath11k_dp_shadow_start_timer(struct ath11k_base *ab,
|
||||
struct hal_srng *srng,
|
||||
struct ath11k_hp_update_timer *update_timer)
|
||||
{
|
||||
lockdep_assert_held(&srng->lock);
|
||||
|
||||
if (!ab->hw_params.supports_shadow_regs)
|
||||
return;
|
||||
|
||||
update_timer->tx_num++;
|
||||
|
||||
if (update_timer->started)
|
||||
return;
|
||||
|
||||
update_timer->started = true;
|
||||
update_timer->timer_tx_num = update_timer->tx_num;
|
||||
mod_timer(&update_timer->timer, jiffies +
|
||||
msecs_to_jiffies(update_timer->interval));
|
||||
}
|
||||
|
||||
void ath11k_dp_shadow_stop_timer(struct ath11k_base *ab,
|
||||
struct ath11k_hp_update_timer *update_timer)
|
||||
{
|
||||
if (!ab->hw_params.supports_shadow_regs)
|
||||
return;
|
||||
|
||||
if (!update_timer->init)
|
||||
return;
|
||||
|
||||
del_timer_sync(&update_timer->timer);
|
||||
}
|
||||
|
||||
void ath11k_dp_shadow_init_timer(struct ath11k_base *ab,
|
||||
struct ath11k_hp_update_timer *update_timer,
|
||||
u32 interval, u32 ring_id)
|
||||
{
|
||||
if (!ab->hw_params.supports_shadow_regs)
|
||||
return;
|
||||
|
||||
update_timer->tx_num = 0;
|
||||
update_timer->timer_tx_num = 0;
|
||||
update_timer->ab = ab;
|
||||
update_timer->ring_id = ring_id;
|
||||
update_timer->interval = interval;
|
||||
update_timer->init = true;
|
||||
timer_setup(&update_timer->timer,
|
||||
ath11k_dp_shadow_timer_handler, 0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user