qcacmn: Fix ce ring timeout interrupt hw work arround

Interrupt was constantly firing because the low_threshold was
improperly configured.  The low threshold needs to be 1 less than
the number of buffers posted when the CE is fully posted.  The
srng backed CE's are setup with nentries - 2 buffers as the fully
posted amount, therefore the threshold needs to be nentries - 3.

Also fixes a bug where a reused variable is not cleared.  This
bug could result in the threshold being set to a garbages value.

Change-Id: Iac840bfd6677683bf2feb42d8bdbd050f42e895d
CRs-Fixed: 2090603
This commit is contained in:
Houston Hoffman
2017-08-07 14:26:35 -07:00
committed by snandini
parent 1fecd15636
commit 9b55b5fbb9
2 changed files with 32 additions and 5 deletions

View File

@@ -882,6 +882,7 @@ static inline void hal_srng_src_hw_init(struct hal_soc *hal,
}
SRNG_SRC_REG_WRITE(srng, CONSUMER_INT_SETUP_IX0, reg_val);
reg_val = 0;
if (srng->flags & HAL_SRNG_LOW_THRES_INTR_ENABLE) {
reg_val |= SRNG_SM(SRNG_SRC_FLD(CONSUMER_INT_SETUP_IX1,
LOW_THRESHOLD), srng->u.src_ring.low_threshold);

View File

@@ -625,6 +625,35 @@ static void ce_srng_src_ring_setup(struct hif_softc *scn, uint32_t ce_id,
&ring_params);
}
/**
* ce_srng_initialize_dest_timer_interrupt_war() - war initialization
* @dest_ring: ring being initialized
* @ring_params: pointer to initialized parameters
*
* For Napier & Hawkeye v1, the status ring timer interrupts do not work
* As a work arround host configures the destination rings to be a proxy for
* work needing to be done.
*
* The interrupts are setup such that if the destination ring is less than fully
* posted, there is likely undone work for the status ring that the host should
* process.
*
* There is a timing bug in srng based copy engines such that a fully posted
* srng based copy engine has 2 empty entries instead of just one. The copy
* engine data sturctures work with 1 empty entry, but the software frequently
* fails to post the last entry due to the race condition.
*/
static void ce_srng_initialize_dest_timer_interrupt_war(
struct CE_ring_state *dest_ring,
struct hal_srng_params *ring_params) {
int num_buffers_when_fully_posted = dest_ring->nentries - 2;
ring_params->low_threshold = num_buffers_when_fully_posted - 1;
ring_params->intr_timer_thres_us = 1024;
ring_params->intr_batch_cntr_thres_entries = 0;
ring_params->flags |= HAL_SRNG_LOW_THRES_INTR_ENABLE;
}
static void ce_srng_dest_ring_setup(struct hif_softc *scn, uint32_t ce_id,
struct CE_ring_state *dest_ring,
struct CE_attr *attr)
@@ -642,11 +671,8 @@ static void ce_srng_dest_ring_setup(struct hif_softc *scn, uint32_t ce_id,
if (!(CE_ATTR_DISABLE_INTR & attr->flags)) {
ce_srng_msi_ring_params_setup(scn, ce_id, &ring_params);
if (status_ring_timer_thresh_work_arround) {
/* hw bug work arround*/
ring_params.low_threshold = dest_ring->nentries - 1;
ring_params.intr_timer_thres_us = 1024;
ring_params.intr_batch_cntr_thres_entries = 0;
ring_params.flags |= HAL_SRNG_LOW_THRES_INTR_ENABLE;
ce_srng_initialize_dest_timer_interrupt_war(
dest_ring, &ring_params);
} else {
/* normal behavior for future chips */
ring_params.low_threshold = dest_ring->nentries >> 3;