Reset firmware

Reset the firmware if it becomes unresponsive. Use ping to send
keep alive requests.

Only monitor ping and inference request messages. The other messages
pass no resources to the firmware and can be cancelled without
resetting the firmware.

Change-Id: Ifbcc370f02d79a64f25598f11376a1dc84a7a066
diff --git a/kernel/ethosu_inference.c b/kernel/ethosu_inference.c
index ad31f06..3c18bbd 100644
--- a/kernel/ethosu_inference.c
+++ b/kernel/ethosu_inference.c
@@ -28,7 +28,6 @@
 #include "ethosu_core_interface.h"
 #include "ethosu_device.h"
 #include "ethosu_network.h"
-#include "uapi/ethosu.h"
 
 #include <linux/anon_inodes.h>
 #include <linux/file.h>
@@ -81,9 +80,6 @@
 {
 	int ret;
 
-	if (inf->pending)
-		return -EINVAL;
-
 	inf->status = ETHOSU_UAPI_STATUS_ERROR;
 
 	ret = ethosu_mailbox_inference(&inf->edev->mailbox, inf,
@@ -97,24 +93,51 @@
 	if (ret)
 		return ret;
 
-	inf->pending = true;
-
 	ethosu_inference_get(inf);
 
 	return 0;
 }
 
-static int ethosu_inference_find(struct ethosu_inference *inf,
-				 struct list_head *inference_list)
+static void ethosu_inference_fail(struct ethosu_mailbox_msg *msg)
 {
-	struct ethosu_inference *cur;
+	struct ethosu_inference *inf =
+		container_of(msg, typeof(*inf), msg);
+	int ret;
 
-	list_for_each_entry(cur, inference_list, list) {
-		if (cur == inf)
-			return 0;
+	/* Decrement reference count if inference was pending reponse */
+	if (!inf->done) {
+		ret = ethosu_inference_put(inf);
+		if (ret)
+			return;
 	}
 
-	return -EINVAL;
+	/* Fail inference and wake up any waiting process */
+	inf->status = ETHOSU_UAPI_STATUS_ERROR;
+	inf->done = true;
+	wake_up_interruptible(&inf->waitq);
+}
+
+static int ethosu_inference_resend(struct ethosu_mailbox_msg *msg)
+{
+	struct ethosu_inference *inf =
+		container_of(msg, typeof(*inf), msg);
+	int ret;
+
+	/* Don't resend request if response has already been received */
+	if (inf->done)
+		return 0;
+
+	/* Decrement reference count for pending request */
+	ret = ethosu_inference_put(inf);
+	if (ret)
+		return 0;
+
+	/* Resend request */
+	ret = ethosu_inference_send(inf);
+	if (ret)
+		return ret;
+
+	return 0;
 }
 
 static bool ethosu_inference_verify(struct file *file)
@@ -131,7 +154,7 @@
 		 "Inference destroy. handle=0x%pK, status=%d\n",
 		 inf, inf->status);
 
-	list_del(&inf->list);
+	list_del(&inf->msg.list);
 
 	while (inf->ifm_count-- > 0)
 		ethosu_buffer_put(inf->ifm[inf->ifm_count]);
@@ -165,7 +188,7 @@
 
 	poll_wait(file, &inf->waitq, wait);
 
-	if (!inf->pending)
+	if (inf->done)
 		ret |= POLLIN;
 
 	return ret;
@@ -237,10 +260,12 @@
 
 	inf->edev = edev;
 	inf->net = net;
-	inf->pending = false;
+	inf->done = false;
 	inf->status = ETHOSU_UAPI_STATUS_ERROR;
 	kref_init(&inf->kref);
 	init_waitqueue_head(&inf->waitq);
+	inf->msg.fail = ethosu_inference_fail;
+	inf->msg.resend = ethosu_inference_resend;
 
 	/* Get pointer to IFM buffers */
 	for (i = 0; i < uapi->ifm_count; i++) {
@@ -296,8 +321,8 @@
 	inf->file = fget(ret);
 	fput(inf->file);
 
-	/* Add inference to inference list */
-	list_add(&inf->list, &edev->inference_list);
+	/* Add inference to pending list */
+	list_add(&inf->msg.list, &edev->mailbox.pending_list);
 
 	/* Send inference request to Arm Ethos-U subsystem */
 	(void)ethosu_inference_send(inf);
@@ -350,9 +375,9 @@
 	kref_get(&inf->kref);
 }
 
-void ethosu_inference_put(struct ethosu_inference *inf)
+int ethosu_inference_put(struct ethosu_inference *inf)
 {
-	kref_put(&inf->kref, &ethosu_inference_kref_destroy);
+	return kref_put(&inf->kref, &ethosu_inference_kref_destroy);
 }
 
 void ethosu_inference_rsp(struct ethosu_device *edev,
@@ -363,7 +388,7 @@
 	int ret;
 	int i;
 
-	ret = ethosu_inference_find(inf, &edev->inference_list);
+	ret = ethosu_mailbox_find(&edev->mailbox, &inf->msg);
 	if (ret) {
 		dev_warn(edev->dev,
 			 "Handle not found in inference list. handle=0x%p\n",
@@ -372,8 +397,6 @@
 		return;
 	}
 
-	inf->pending = false;
-
 	if (rsp->status == ETHOSU_CORE_STATUS_OK &&
 	    inf->ofm_count <= ETHOSU_CORE_BUFFER_MAX) {
 		uint32_t i;
@@ -412,6 +435,8 @@
 		 "PMU cycle counter. enable=%u, count=%llu\n",
 		 inf->pmu_cycle_counter_enable,
 		 inf->pmu_cycle_counter_count);
+
+	inf->done = true;
 	wake_up_interruptible(&inf->waitq);
 
 	ethosu_inference_put(inf);