Ver Fonte

qcacmn: Avoid logging few hif events in case of IRQ storm

In IRQ storm scenario, the events are logged to hif
event desc history even though the SRNG is empty
resulting in overwriting of older entries useful for
debugging.

Fix is to avoid recording hif events if the SRNG is
empty in IRQ storm scenario.

Change-Id: Id4161198c60f5fae31123c936f0f4acc1082a78b
CRs-Fixed: 2753675
Yeshwanth Sriram Guntuka há 4 anos atrás
pai
commit
32a9cc93a8
5 ficheiros alterados com 106 adições e 0 exclusões
  1. 12 0
      hif/inc/hif.h
  2. 1 0
      hif/src/ce/ce_internal.h
  3. 1 0
      hif/src/ce/ce_service.c
  4. 1 0
      hif/src/ce/ce_service_srng.c
  5. 91 0
      hif/src/hif_exec.c

+ 12 - 0
hif/inc/hif.h

@@ -328,6 +328,7 @@ enum hif_event_type {
 	HIF_EVENT_BH_SCHED,
 	HIF_EVENT_SRNG_ACCESS_START,
 	HIF_EVENT_SRNG_ACCESS_END,
+	/* Do check hif_hist_skip_event_record when adding new events */
 };
 
 #ifdef WLAN_FEATURE_DP_EVENT_HISTORY
@@ -358,6 +359,16 @@ struct hif_event_record {
 	enum hif_event_type type;
 };
 
+/**
+ * struct hif_event_misc - history related misc info
+ * @last_irq_index: last irq event index in history
+ * @last_irq_ts: last irq timestamp
+ */
+struct hif_event_misc {
+	int32_t last_irq_index;
+	uint64_t last_irq_ts;
+};
+
 /**
  * struct hif_event_history - history for one interrupt group
  * @index: index to store new event
@@ -368,6 +379,7 @@ struct hif_event_record {
  */
 struct hif_event_history {
 	qdf_atomic_t index;
+	struct hif_event_misc misc;
 	struct hif_event_record event[HIF_EVENT_HIST_MAX];
 };
 

+ 1 - 0
hif/src/ce/ce_internal.h

@@ -573,6 +573,7 @@ struct hif_ce_desc_event {
 	int index;
 	enum hif_ce_event_type type;
 	uint64_t time;
+	int cpu_id;
 #ifdef HELIUMPLUS
 	union ce_desc descriptor;
 #else

+ 1 - 0
hif/src/ce/ce_service.c

@@ -210,6 +210,7 @@ void hif_record_ce_desc_event(struct hif_softc *scn, int ce_id,
 
 	event->type = type;
 	event->time = qdf_get_log_timestamp();
+	event->cpu_id = qdf_get_cpu();
 
 	if (descriptor)
 		qdf_mem_copy(&event->descriptor, descriptor,

+ 1 - 0
hif/src/ce/ce_service_srng.c

@@ -112,6 +112,7 @@ void hif_record_ce_srng_desc_event(struct hif_softc *scn, int ce_id,
 
 	event->type = type;
 	event->time = qdf_get_log_timestamp();
+	event->cpu_id = qdf_get_cpu();
 
 	if (descriptor)
 		qdf_mem_copy(&event->descriptor, descriptor,

+ 91 - 0
hif/src/hif_exec.c

@@ -43,6 +43,89 @@ int hif_get_next_record_index(qdf_atomic_t *table_index,
 	return record_index & (array_size - 1);
 }
 
+/**
+ * hif_hist_is_prev_record() - Check if index is the immediate
+ *  previous record wrt curr_index
+ * @curr_index: curr index in the event history
+ * @index: index to be checked
+ * @hist_size: history size
+ *
+ * Return: true if index is immediately behind curr_index else false
+ */
+static inline
+bool hif_hist_is_prev_record(int32_t curr_index, int32_t index,
+			     uint32_t hist_size)
+{
+	return (((index + 1) & (hist_size - 1)) == curr_index) ?
+			true : false;
+}
+
+/**
+ * hif_hist_skip_event_record() - Check if current event needs to be
+ *  recorded or not
+ * @hist_ev: HIF event history
+ * @event: DP event entry
+ *
+ * Return: true if current event needs to be skipped else false
+ */
+static bool
+hif_hist_skip_event_record(struct hif_event_history *hist_ev,
+			   struct hif_event_record *event)
+{
+	struct hif_event_record *rec;
+	struct hif_event_record *last_irq_rec;
+	int32_t index;
+
+	index = qdf_atomic_read(&hist_ev->index);
+	if (index < 0)
+		return false;
+
+	index &= (HIF_EVENT_HIST_MAX - 1);
+	rec = &hist_ev->event[index];
+
+	switch (event->type) {
+	case HIF_EVENT_IRQ_TRIGGER:
+		/*
+		 * The prev record check is to prevent skipping the IRQ event
+		 * record in case where BH got re-scheduled due to force_break
+		 * but there are no entries to be reaped in the rings.
+		 */
+		if (rec->type == HIF_EVENT_BH_SCHED &&
+		    hif_hist_is_prev_record(index,
+					    hist_ev->misc.last_irq_index,
+					    HIF_EVENT_HIST_MAX)) {
+			last_irq_rec =
+				&hist_ev->event[hist_ev->misc.last_irq_index];
+			last_irq_rec->timestamp = qdf_get_log_timestamp();
+			last_irq_rec->cpu_id = qdf_get_cpu();
+			last_irq_rec->hp++;
+			last_irq_rec->tp = last_irq_rec->timestamp -
+						hist_ev->misc.last_irq_ts;
+			return true;
+		}
+		break;
+	case HIF_EVENT_BH_SCHED:
+		if (rec->type == HIF_EVENT_BH_SCHED) {
+			rec->timestamp = qdf_get_log_timestamp();
+			rec->cpu_id = qdf_get_cpu();
+			return true;
+		}
+		break;
+	case HIF_EVENT_SRNG_ACCESS_START:
+		if (event->hp == event->tp)
+			return true;
+		break;
+	case HIF_EVENT_SRNG_ACCESS_END:
+		if (rec->type != HIF_EVENT_SRNG_ACCESS_START)
+			return true;
+		break;
+	default:
+		break;
+	}
+
+	return false;
+}
+
 void hif_hist_record_event(struct hif_opaque_softc *hif_ctx,
 			   struct hif_event_record *event, uint8_t intr_grp_id)
 {
@@ -63,11 +146,19 @@ void hif_hist_record_event(struct hif_opaque_softc *hif_ctx,
 	if (qdf_unlikely(!hist_ev))
 		return;
 
+	if (hif_hist_skip_event_record(hist_ev, event))
+		return;
+
 	record_index = hif_get_next_record_index(
 			&hist_ev->index, HIF_EVENT_HIST_MAX);
 
 	record = &hist_ev->event[record_index];
 
+	if (event->type == HIF_EVENT_IRQ_TRIGGER) {
+		hist_ev->misc.last_irq_index = record_index;
+		hist_ev->misc.last_irq_ts = qdf_get_log_timestamp();
+	}
+
 	record->hal_ring_id = event->hal_ring_id;
 	record->hp = event->hp;
 	record->tp = event->tp;