Browse Source

qcacmn: Delay 50us when update same shadow reg

Add 50us delay if srng's shadow reg write again within 5us.

Change-Id: I8d48496814e063ebd441db3520e3a5406c5db13e
CRs-Fixed: 2965371
Rakesh Pillai 4 years ago
parent
commit
1104d6d5a7
2 changed files with 68 additions and 5 deletions
  1. 7 0
      hal/wifi3.0/hal_internal.h
  2. 61 5
      hal/wifi3.0/hal_srng.c

+ 7 - 0
hal/wifi3.0/hal_internal.h

@@ -352,12 +352,14 @@ struct hal_reg_write_q_elem {
  * @dequeues: writes dequeued from delayed work (not written yet)
  * @dequeues: writes dequeued from delayed work (not written yet)
  * @coalesces: writes not enqueued since srng is already queued up
  * @coalesces: writes not enqueued since srng is already queued up
  * @direct: writes not enqueued and written to register directly
  * @direct: writes not enqueued and written to register directly
+ * @dequeue_delay: dequeue operation be delayed
  */
  */
 struct hal_reg_write_srng_stats {
 struct hal_reg_write_srng_stats {
 	uint32_t enqueues;
 	uint32_t enqueues;
 	uint32_t dequeues;
 	uint32_t dequeues;
 	uint32_t coalesces;
 	uint32_t coalesces;
 	uint32_t direct;
 	uint32_t direct;
+	uint32_t dequeue_delay;
 };
 };
 
 
 /**
 /**
@@ -386,6 +388,7 @@ enum hal_reg_sched_delay {
  * @q_depth: current queue depth in delayed register write queue
  * @q_depth: current queue depth in delayed register write queue
  * @max_q_depth: maximum queue for delayed register write queue
  * @max_q_depth: maximum queue for delayed register write queue
  * @sched_delay: = kernel work sched delay + bus wakeup delay, histogram
  * @sched_delay: = kernel work sched delay + bus wakeup delay, histogram
+ * @dequeue_delay: dequeue operation be delayed
  */
  */
 struct hal_reg_write_soc_stats {
 struct hal_reg_write_soc_stats {
 	qdf_atomic_t enqueues;
 	qdf_atomic_t enqueues;
@@ -396,6 +399,7 @@ struct hal_reg_write_soc_stats {
 	qdf_atomic_t q_depth;
 	qdf_atomic_t q_depth;
 	uint32_t max_q_depth;
 	uint32_t max_q_depth;
 	uint32_t sched_delay[REG_WRITE_SCHED_DELAY_HIST_MAX];
 	uint32_t sched_delay[REG_WRITE_SCHED_DELAY_HIST_MAX];
+	uint32_t dequeue_delay;
 };
 };
 
 
 #ifdef FEATURE_HAL_DELAYED_REG_WRITE_V2
 #ifdef FEATURE_HAL_DELAYED_REG_WRITE_V2
@@ -549,6 +553,9 @@ struct hal_srng {
 	uint32_t last_reg_wr_val;
 	uint32_t last_reg_wr_val;
 	/* flag to indicate whether srng is already queued for delayed write */
 	/* flag to indicate whether srng is already queued for delayed write */
 	uint8_t reg_write_in_progress;
 	uint8_t reg_write_in_progress;
+	/* last dequeue elem time stamp */
+	qdf_time_t last_dequeue_time;
+
 	/* srng specific delayed write stats */
 	/* srng specific delayed write stats */
 	struct hal_reg_write_srng_stats wstats;
 	struct hal_reg_write_srng_stats wstats;
 #endif
 #endif

+ 61 - 5
hal/wifi3.0/hal_srng.c

@@ -328,9 +328,9 @@ void hal_get_shadow_config(void *hal_soc,
 qdf_export_symbol(hal_get_shadow_config);
 qdf_export_symbol(hal_get_shadow_config);
 
 
 
 
-static void hal_validate_shadow_register(struct hal_soc *hal,
-				  uint32_t *destination,
-				  uint32_t *shadow_address)
+static bool hal_validate_shadow_register(struct hal_soc *hal,
+					 uint32_t *destination,
+					 uint32_t *shadow_address)
 {
 {
 	unsigned int index;
 	unsigned int index;
 	uint32_t *shadow_0_offset = SHADOW_REGISTER(0) + hal->dev_base_addr;
 	uint32_t *shadow_0_offset = SHADOW_REGISTER(0) + hal->dev_base_addr;
@@ -350,13 +350,13 @@ static void hal_validate_shadow_register(struct hal_soc *hal,
 			hal->shadow_config[index].addr);
 			hal->shadow_config[index].addr);
 		goto error;
 		goto error;
 	}
 	}
-	return;
+	return true;
 error:
 error:
 	qdf_print("baddr %pK, desination %pK, shadow_address %pK s0offset %pK index %x",
 	qdf_print("baddr %pK, desination %pK, shadow_address %pK s0offset %pK index %x",
 		  hal->dev_base_addr, destination, shadow_address,
 		  hal->dev_base_addr, destination, shadow_address,
 		  shadow_0_offset, index);
 		  shadow_0_offset, index);
 	QDF_BUG(0);
 	QDF_BUG(0);
-	return;
+	return false;
 }
 }
 
 
 static void hal_target_based_configure(struct hal_soc *hal)
 static void hal_target_based_configure(struct hal_soc *hal)
@@ -675,6 +675,7 @@ hal_process_reg_write_q_elem(struct hal_soc *hal,
 	}
 	}
 
 
 	q_elem->valid = 0;
 	q_elem->valid = 0;
+	srng->last_dequeue_time = q_elem->dequeue_time;
 	SRNG_UNLOCK(&srng->lock);
 	SRNG_UNLOCK(&srng->lock);
 
 
 	return write_val;
 	return write_val;
@@ -705,6 +706,57 @@ static inline void hal_reg_write_fill_sched_delay_hist(struct hal_soc *hal,
 		hist[REG_WRITE_SCHED_DELAY_GT_5000us]++;
 		hist[REG_WRITE_SCHED_DELAY_GT_5000us]++;
 }
 }
 
 
+#ifdef SHADOW_WRITE_DELAY
+
+#define SHADOW_WRITE_MIN_DELTA_US	5
+#define SHADOW_WRITE_DELAY_US		50
+
+/*
+ * Never add those srngs which are performance relate.
+ * The delay itself will hit performance heavily.
+ */
+#define IS_SRNG_MATCH(s)	((s)->ring_id == HAL_SRNG_CE_1_DST_STATUS || \
+				 (s)->ring_id == HAL_SRNG_CE_1_DST)
+
+static inline bool hal_reg_write_need_delay(struct hal_reg_write_q_elem *elem)
+{
+	struct hal_srng *srng = elem->srng;
+	struct hal_soc *hal = srng->hal_soc;
+	qdf_time_t now;
+	qdf_iomem_t real_addr;
+
+	/* Check if it is target srng, and valid shadow reg */
+	if (qdf_likely(!IS_SRNG_MATCH(srng)))
+		return false;
+
+	if (srng->ring_dir == HAL_SRNG_SRC_RING)
+		real_addr = SRNG_SRC_ADDR(srng, HP);
+	else
+		real_addr = SRNG_DST_ADDR(srng, TP);
+	if (!hal_validate_shadow_register(hal, real_addr, elem->addr))
+		return false;
+
+	/* Check the time delta from last write of same srng */
+	now = qdf_get_log_timestamp();
+	if (qdf_log_timestamp_to_usecs(now - srng->last_dequeue_time) >
+		SHADOW_WRITE_MIN_DELTA_US)
+		return false;
+
+	/* Delay dequeue, and record */
+	qdf_udelay(SHADOW_WRITE_DELAY_US);
+
+	srng->wstats.dequeue_delay++;
+	hal->stats.wstats.dequeue_delay++;
+
+	return true;
+}
+#else
+static inline bool hal_reg_write_need_delay(struct hal_reg_write_q_elem *elem)
+{
+	return false;
+}
+#endif
+
 /**
 /**
  * hal_reg_write_work() - Worker to process delayed writes
  * hal_reg_write_work() - Worker to process delayed writes
  * @arg: hal_soc pointer
  * @arg: hal_soc pointer
@@ -743,6 +795,10 @@ static void hal_reg_write_work(void *arg)
 		if (!q_elem->valid)
 		if (!q_elem->valid)
 			break;
 			break;
 
 
+		if (hal_reg_write_need_delay(q_elem))
+			hal_verbose_debug("Delay reg writer for srng 0x%x, addr 0x%pK",
+					  q_elem->srng->ring_id, q_elem->addr);
+
 		q_elem->dequeue_time = qdf_get_log_timestamp();
 		q_elem->dequeue_time = qdf_get_log_timestamp();
 		ring_id = q_elem->srng->ring_id;
 		ring_id = q_elem->srng->ring_id;
 		addr = q_elem->addr;
 		addr = q_elem->addr;