qcacmn: Force update HP/TP upon delayed register writes
Currently if HP/TP register updates are delayed due to delayed reg write work not getting scheduled, although driver has processed the ring completely, hardware would see HP/TP delta and fires an interrupt based on interrupt threshold configuration until the HP/TP updates reach the hardware. When system is heavily stressed, this delay in HP/TP updates would result in IRQ storm further stressing the system which is bad. Force update HP/TP to the hardware under such scenarios to avoid this problem. Currently doing this just for CE DST SRNGs, this can be scaled to other SRNGs on need. Change-Id: I8a4938dbd4850d7ab6ae5183186237a5e37e1038 CRs-Fixed: 3749078
This commit is contained in:

committed by
Ravindra Konda

parent
e454eb5052
commit
e2e92aa7d6
@@ -877,6 +877,27 @@ static inline int hal_get_reg_write_pending_work(void *hal_soc)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(FEATURE_HAL_DELAYED_REG_WRITE) && defined(QCA_WIFI_QCA6750)
|
||||
/**
|
||||
* hal_srng_check_and_update_hptp() - Check and force update HP/TP
|
||||
* to the hardware
|
||||
* @hal_soc: HAL soc handle
|
||||
* @srng: SRNG handle
|
||||
* @update: Whether or not update is needed
|
||||
*
|
||||
* Returns: void
|
||||
*/
|
||||
void hal_srng_check_and_update_hptp(struct hal_soc *hal_soc,
|
||||
struct hal_srng *srng,
|
||||
bool update);
|
||||
#else
|
||||
static inline void
|
||||
hal_srng_check_and_update_hptp(struct hal_soc *hal_soc, struct hal_srng *srng,
|
||||
bool update)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* hal_read_address_32_mb() - Read 32-bit value from the register
|
||||
* @soc: soc handle
|
||||
|
@@ -868,6 +868,12 @@ struct hal_srng {
|
||||
|
||||
/* srng specific delayed write stats */
|
||||
struct hal_reg_write_srng_stats wstats;
|
||||
|
||||
union {
|
||||
uint32_t updated_hp;
|
||||
uint32_t updated_tp;
|
||||
};
|
||||
uint32_t force_cnt;
|
||||
#endif
|
||||
#ifdef WLAN_DP_SRNG_USAGE_WM_TRACKING
|
||||
struct hal_srng_high_wm_info high_wm;
|
||||
|
@@ -673,6 +673,72 @@ int hal_get_reg_write_pending_work(void *hal_soc)
|
||||
#define HAL_REG_WRITE_QUEUE_LEN 32
|
||||
#endif
|
||||
|
||||
#ifdef QCA_WIFI_QCA6750
|
||||
|
||||
#define HAL_DEL_WRITE_FORCE_UPDATE_THRES 5
|
||||
|
||||
static inline void hal_srng_update_last_hptp(struct hal_srng *srng)
|
||||
{
|
||||
if (srng->ring_dir == HAL_SRNG_SRC_RING)
|
||||
srng->updated_hp = srng->u.src_ring.hp;
|
||||
else
|
||||
srng->updated_tp = srng->u.dst_ring.tp;
|
||||
|
||||
srng->force_cnt = 0;
|
||||
}
|
||||
|
||||
/* If HP/TP register updates are delayed due to delayed reg
|
||||
* write work not getting scheduled, hardware would see HP/TP
|
||||
* delta and will fire interrupts until the HP/TP updates reach
|
||||
* the hardware.
|
||||
*
|
||||
* When system is heavily stressed, this delay in HP/TP updates
|
||||
* would result in IRQ storm further stressing the system. Force
|
||||
* update HP/TP to the hardware under such scenarios to avoid this.
|
||||
*/
|
||||
void hal_srng_check_and_update_hptp(struct hal_soc *hal_soc,
|
||||
struct hal_srng *srng, bool update)
|
||||
{
|
||||
uint32_t value;
|
||||
|
||||
if (!update)
|
||||
return;
|
||||
|
||||
SRNG_LOCK(&srng->lock);
|
||||
if (srng->ring_dir == HAL_SRNG_SRC_RING) {
|
||||
value = srng->u.src_ring.hp;
|
||||
|
||||
if (value == srng->updated_hp ||
|
||||
srng->force_cnt++ < HAL_DEL_WRITE_FORCE_UPDATE_THRES)
|
||||
goto out_unlock;
|
||||
|
||||
hal_write_address_32_mb(hal_soc, srng->u.src_ring.hp_addr,
|
||||
value, false);
|
||||
} else {
|
||||
value = srng->u.dst_ring.tp;
|
||||
|
||||
if (value == srng->updated_tp ||
|
||||
srng->force_cnt++ < HAL_DEL_WRITE_FORCE_UPDATE_THRES)
|
||||
goto out_unlock;
|
||||
|
||||
hal_write_address_32_mb(hal_soc, srng->u.dst_ring.tp_addr,
|
||||
value, false);
|
||||
}
|
||||
|
||||
hal_srng_update_last_hptp(srng);
|
||||
hal_srng_reg_his_add(srng, value);
|
||||
qdf_atomic_inc(&hal_soc->stats.wstats.direct);
|
||||
srng->wstats.direct++;
|
||||
|
||||
out_unlock:
|
||||
SRNG_UNLOCK(&srng->lock);
|
||||
}
|
||||
#else
|
||||
static inline void hal_srng_update_last_hptp(struct hal_srng *srng)
|
||||
{
|
||||
}
|
||||
#endif /* QCA_WIFI_QCA6750 */
|
||||
|
||||
/**
|
||||
* hal_process_reg_write_q_elem() - process a register write queue element
|
||||
* @hal: hal_soc pointer
|
||||
@@ -705,6 +771,8 @@ hal_process_reg_write_q_elem(struct hal_soc *hal,
|
||||
srng->u.dst_ring.tp, false);
|
||||
write_val = srng->u.dst_ring.tp;
|
||||
}
|
||||
|
||||
hal_srng_update_last_hptp(srng);
|
||||
hal_srng_reg_his_add(srng, write_val);
|
||||
|
||||
q_elem->valid = 0;
|
||||
@@ -1100,6 +1168,7 @@ void hal_delayed_reg_write(struct hal_soc *hal_soc,
|
||||
PLD_MHI_STATE_L0 ==
|
||||
pld_get_mhi_state(hal_soc->qdf_dev->dev))) {
|
||||
hal_write_address_32_mb(hal_soc, addr, value, false);
|
||||
hal_srng_update_last_hptp(srng);
|
||||
hal_srng_reg_his_add(srng, value);
|
||||
qdf_atomic_inc(&hal_soc->stats.wstats.direct);
|
||||
srng->wstats.direct++;
|
||||
@@ -1136,6 +1205,7 @@ void hal_delayed_reg_write(struct hal_soc *hal_soc,
|
||||
qdf_atomic_inc(&hal_soc->stats.wstats.direct);
|
||||
srng->wstats.direct++;
|
||||
hal_write_address_32_mb(hal_soc, addr, value, false);
|
||||
hal_srng_update_last_hptp(srng);
|
||||
hal_srng_reg_his_add(srng, value);
|
||||
} else {
|
||||
hal_reg_write_enqueue(hal_soc, srng, addr, value);
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. 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
|
||||
@@ -344,6 +344,12 @@ ce_recv_buf_enqueue_srng(struct CE_handle *copyeng,
|
||||
return QDF_STATUS_E_IO;
|
||||
}
|
||||
|
||||
/* HP/TP update if any should happen only once per interrupt,
|
||||
* therefore checking for CE receive_count.
|
||||
*/
|
||||
hal_srng_check_and_update_hptp(scn->hal_soc, dest_ring->srng_ctx,
|
||||
!CE_state->receive_count);
|
||||
|
||||
if (hal_srng_access_start(scn->hal_soc, dest_ring->srng_ctx)) {
|
||||
qdf_spin_unlock_bh(&CE_state->ce_index_lock);
|
||||
return QDF_STATUS_E_FAILURE;
|
||||
@@ -446,6 +452,12 @@ ce_completed_recv_next_nolock_srng(struct CE_state *CE_state,
|
||||
int nbytes;
|
||||
struct ce_srng_dest_status_desc dest_status_info;
|
||||
|
||||
/* HP/TP update if any should happen only once per interrupt,
|
||||
* therefore checking for CE receive_count.
|
||||
*/
|
||||
hal_srng_check_and_update_hptp(scn->hal_soc, status_ring->srng_ctx,
|
||||
!CE_state->receive_count);
|
||||
|
||||
if (hal_srng_access_start(scn->hal_soc, status_ring->srng_ctx))
|
||||
return QDF_STATUS_E_FAILURE;
|
||||
|
||||
|
Reference in New Issue
Block a user