ANDROID: trusty-log: Refactor logging state to support concurrent sinks

Bug: 190143735
Change-Id: I01aa0c31b3dec53bdbabebcbb631c0b8c7b84a2d
Signed-off-by: Armelle Laine <[email protected]>
diff --git a/drivers/trusty/trusty-log.c b/drivers/trusty/trusty-log.c
index dd7721c..87982db 100644
--- a/drivers/trusty/trusty-log.c
+++ b/drivers/trusty/trusty-log.c
@@ -37,6 +37,24 @@
 static struct ratelimit_state trusty_log_rate_limit =
 	RATELIMIT_STATE_INIT("trusty_log", 1 * HZ, 100);
 
+/**
+ * struct trusty_log_sink_state - trusty log sink state
+ *
+ * @get:              current read unwrapped index
+ * @last_successful_next:
+ *                    index for the next line after the last successful get
+ * @trusty_panicked:  trusty panic status at the start of the sink interation
+ *
+ * A sink state structure is used for each log sink (e.g. the kernel log sink
+ * and later virtual file sinks).
+ *
+ */
+struct trusty_log_sink_state {
+	u32 get;
+	u32 last_successful_next;
+	bool trusty_panicked;
+};
+
 struct trusty_log_state {
 	struct device *dev;
 	struct device *trusty_dev;
@@ -47,9 +65,7 @@
 	 */
 	spinlock_t lock;
 	struct log_rb *log;
-	u32 get;
-	/* index for the next line after the last successful get */
-	u32 last_successful_next;
+	struct trusty_log_sink_state klog_sink;
 
 	struct page *log_pages;
 	struct scatterlist sg;
@@ -109,15 +125,57 @@
 	return i;
 }
 
-static void trusty_dump_logs(struct trusty_log_state *s)
+/**
+ * trusty_log_has_data() - returns true when more data is available to sink
+ * @s:         Current log state.
+ * @sink:      trusty_log_sink_state holding the get index on a given sink
+ *
+ * Return: true if data is available.
+ */
+static bool trusty_log_has_data(struct trusty_log_state *s,
+				struct trusty_log_sink_state *sink)
 {
 	struct log_rb *log = s->log;
-	u32 get, put, alloc;
-	int read_chars;
-	bool trusty_panicked = trusty_get_panic_status(s->trusty_dev);
 
+	return (log->put != sink->get);
+}
+
+/**
+ * trusty_log_start() - initialize the sink iteration
+ * @s:         Current log state.
+ * @sink:      trusty_log_sink_state holding the get index on a given sink
+ * @index:     Unwrapped ring buffer index from where iteration shall start
+ *
+ * Return: 0 if successful, negative error code otherwise
+ */
+static int trusty_log_start(struct trusty_log_state *s,
+			    struct trusty_log_sink_state *sink,
+			    u32 index)
+{
+	struct log_rb *log;
+
+	if (WARN_ON(!s))
+		return -EINVAL;
+
+	log = s->log;
 	if (WARN_ON(!is_power_of_2(log->sz)))
-		return;
+		return -EINVAL;
+
+	sink->get = index;
+	return 0;
+}
+
+/**
+ * trusty_log_show() - sink log entry at current iteration
+ * @s:         Current log state.
+ * @sink:      trusty_log_sink_state holding the get index on a given sink
+ */
+static void trusty_log_show(struct trusty_log_state *s,
+			    struct trusty_log_sink_state *sink)
+{
+	struct log_rb *log = s->log;
+	u32 alloc, put, get;
+	int read_chars;
 
 	/*
 	 * For this ring buffer, at any given point, alloc >= put >= get.
@@ -126,36 +184,56 @@
 	 * that the above condition is maintained. A read barrier is needed
 	 * to make sure the hardware and compiler keep the reads ordered.
 	 */
-	get = trusty_panicked ? s->last_successful_next : s->get;
-	while ((put = log->put) != get) {
-		/* Make sure that the read of put occurs before the read of log data */
-		rmb();
+	get = sink->get;
+	put = log->put;
 
-		/* Read a line from the log */
-		read_chars = log_read_line(s, put, get);
+	/* Make sure that the read of put occurs before the read of log data */
+	rmb();
 
-		/* Force the loads from log_read_line to complete. */
-		rmb();
-		alloc = log->alloc;
+	/* Read a line from the log */
+	read_chars = log_read_line(s, put, get);
 
-		/*
-		 * Discard the line that was just read if the data could
-		 * have been corrupted by the producer.
-		 */
-		if (u32_sub_overflow(alloc, get) > log->sz) {
-			dev_err(s->dev, "log overflow.");
-			get = u32_sub_overflow(alloc, log->sz);
-			continue;
-		}
-		/* compute next line index */
-		get = u32_add_overflow(get, read_chars);
-		if (trusty_panicked || __ratelimit(&trusty_log_rate_limit)) {
-			dev_info(s->dev, "%s", s->line_buffer);
-			/* next line after last successful get */
-			s->last_successful_next = get;
-		}
+	/* Force the loads from log_read_line to complete. */
+	rmb();
+	alloc = log->alloc;
+
+	/*
+	 * Discard the line that was just read if the data could
+	 * have been corrupted by the producer.
+	 */
+	if (u32_sub_overflow(alloc, get) > log->sz) {
+		dev_err(s->dev, "log overflow.\n");
+		sink->get = u32_sub_overflow(alloc, log->sz);
+		return;
 	}
-	s->get = get;
+	/* compute next line index */
+	sink->get = u32_add_overflow(get, read_chars);
+	if (sink->trusty_panicked || __ratelimit(&trusty_log_rate_limit)) {
+		dev_info(s->dev, "%s", s->line_buffer);
+		/* next line after last successful get */
+		sink->last_successful_next = sink->get;
+	}
+}
+
+static void trusty_dump_logs(struct trusty_log_state *s)
+{
+	u32 start;
+	int rc;
+	/*
+	 * note: klopg_sink.get and last_successful_next
+	 * initialized to zero by kzalloc
+	 */
+	s->klog_sink.trusty_panicked = trusty_get_panic_status(s->trusty_dev);
+
+	start = s->klog_sink.trusty_panicked ?
+			s->klog_sink.last_successful_next :
+			s->klog_sink.get;
+	rc = trusty_log_start(s, &s->klog_sink, start);
+	if (rc < 0)
+		return;
+
+	while (trusty_log_has_data(s, &s->klog_sink))
+		trusty_log_show(s, &s->klog_sink);
 }
 
 static int trusty_log_call_notify(struct notifier_block *nb,
@@ -232,7 +310,6 @@
 	spin_lock_init(&s->lock);
 	s->dev = &pdev->dev;
 	s->trusty_dev = s->dev->parent;
-	s->get = 0;
 	s->log_pages = alloc_pages(GFP_KERNEL | __GFP_ZERO,
 				   get_order(TRUSTY_LOG_SIZE));
 	if (!s->log_pages) {