Converting Ethos-U driver to rpmsg

The Ethos-U kernel driver has been converted from a
platform driver with a custom firmware interface into a
rpmsg driver.

Change-Id: I9ae449f5e79eb02924e6630611d0893e5fec86be
diff --git a/kernel/ethosu_device.c b/kernel/ethosu_device.c
index 36b776f..004b26f 100644
--- a/kernel/ethosu_device.c
+++ b/kernel/ethosu_device.c
@@ -25,7 +25,7 @@
 #include "ethosu_device.h"
 
 #include "ethosu_buffer.h"
-#include "ethosu_core_interface.h"
+#include "ethosu_core_rpmsg.h"
 #include "ethosu_capabilities.h"
 #include "ethosu_inference.h"
 #include "ethosu_cancel_inference.h"
@@ -46,102 +46,98 @@
  * Defines
  ****************************************************************************/
 
-#define DMA_ADDR_BITS 32 /* Number of address bits */
-
 /****************************************************************************
  * Functions
  ****************************************************************************/
 
 /* Incoming messages */
-static int ethosu_handle_msg(struct ethosu_device *edev)
+static int ethosu_handle_msg(struct rpmsg_device *rpdev,
+			     void *data,
+			     int len,
+			     void *priv,
+			     u32 src)
 {
+	struct ethosu_device *edev = dev_get_drvdata(&rpdev->dev);
+	struct device *dev = &rpdev->dev;
+	struct ethosu_core_rpmsg *rpmsg = data;
+	int length = len - sizeof(rpmsg->header);
 	int ret;
-	struct ethosu_core_msg header;
 
-	union {
-		struct ethosu_core_msg_err              error;
-		struct ethosu_core_inference_rsp        inf;
-		struct ethosu_core_msg_version          version;
-		struct ethosu_core_msg_capabilities_rsp capabilities;
-		struct ethosu_core_network_info_rsp     network_info;
-		struct ethosu_core_cancel_inference_rsp cancellation;
-	} data;
+	dev_info(dev,
+		 "Msg: magic=0x%08x, type=%u, msg_id=%llu",
+		 rpmsg->header.magic, rpmsg->header.type, rpmsg->header.msg_id);
 
-	/* Read message */
-	ret = ethosu_mailbox_read(&edev->mailbox, &header, &data, sizeof(data));
-	if (ret)
-		return ret;
-
-	switch (header.type) {
+	switch (rpmsg->header.type) {
 	case ETHOSU_CORE_MSG_ERR:
-		if (header.length != sizeof(data.error)) {
-			dev_warn(edev->dev,
-				 "Msg: Error message of incorrect size. size=%u, expected=%zu\n", header.length,
-				 sizeof(data.error));
+		if (length != sizeof(rpmsg->error)) {
+			dev_warn(dev,
+				 "Msg: Error message of incorrect size. size=%u, expected=%zu", length,
+				 sizeof(rpmsg->error));
 			ret = -EBADMSG;
 			break;
 		}
 
-		data.error.msg[sizeof(data.error.msg) - 1] = '\0';
-		dev_warn(edev->dev, "Msg: Error. type=%u, msg=\"%s\"\n",
-			 data.error.type, data.error.msg);
+		rpmsg->error.msg[sizeof(rpmsg->error.msg) - 1] = '\0';
+		dev_warn(dev, "Msg: Error. type=%u, msg=\"%s\"",
+			 rpmsg->error.type, rpmsg->error.msg);
 		ret = -EBADMSG;
 		break;
 	case ETHOSU_CORE_MSG_PING:
-		dev_info(edev->dev, "Msg: Ping\n");
+		dev_info(dev, "Msg: Ping");
 		ret = ethosu_mailbox_pong(&edev->mailbox);
 		break;
 	case ETHOSU_CORE_MSG_PONG:
-		dev_info(edev->dev, "Msg: Pong\n");
+		dev_info(dev, "Msg: Pong");
 		break;
 	case ETHOSU_CORE_MSG_INFERENCE_RSP:
-		if (header.length != sizeof(data.inf)) {
-			dev_warn(edev->dev,
-				 "Msg: Inference response of incorrect size. size=%u, expected=%zu\n", header.length,
-				 sizeof(data.inf));
+		if (length != sizeof(rpmsg->inf_rsp)) {
+			dev_warn(dev,
+				 "Msg: Inference response of incorrect size. size=%u, expected=%zu", length,
+				 sizeof(rpmsg->inf_rsp));
 			ret = -EBADMSG;
 			break;
 		}
 
-		dev_info(edev->dev,
-			 "Msg: Inference response. user_arg=0x%llx, ofm_count=%u, status=%u\n",
-			 data.inf.user_arg, data.inf.ofm_count,
-			 data.inf.status);
+		dev_info(dev,
+			 "Msg: Inference response. ofm_count=%u, status=%u",
+			 rpmsg->inf_rsp.ofm_count, rpmsg->inf_rsp.status);
 
-		ethosu_inference_rsp(edev, &data.inf);
+		ethosu_inference_rsp(edev, rpmsg->header.msg_id,
+				     &rpmsg->inf_rsp);
 		break;
 	case ETHOSU_CORE_MSG_CANCEL_INFERENCE_RSP:
-		if (header.length != sizeof(data.cancellation)) {
-			dev_warn(edev->dev,
-				 "Msg: Cancel Inference response of incorrect size. size=%u, expected=%zu\n", header.length,
-				 sizeof(data.cancellation));
+		if (length != sizeof(rpmsg->cancel_rsp)) {
+			dev_warn(dev,
+				 "Msg: Cancel Inference response of incorrect size. size=%u, expected=%zu", length,
+				 sizeof(rpmsg->cancel_rsp));
 			ret = -EBADMSG;
 			break;
 		}
 
-		dev_info(edev->dev,
-			 "Msg: Cancel Inference response. user_arg=0x%llx, status=%u\n",
-			 data.cancellation.user_arg, data.cancellation.status);
-		ethosu_cancel_inference_rsp(edev, &data.cancellation);
+		dev_info(dev,
+			 "Msg: Cancel Inference response. status=%u",
+			 rpmsg->cancel_rsp.status);
+		ethosu_cancel_inference_rsp(edev, rpmsg->header.msg_id,
+					    &rpmsg->cancel_rsp);
 		break;
 	case ETHOSU_CORE_MSG_VERSION_RSP:
-		if (header.length != sizeof(data.version)) {
-			dev_warn(edev->dev,
-				 "Msg: Version response of incorrect size. size=%u, expected=%zu\n", header.length,
-				 sizeof(data.version));
+		if (length != sizeof(rpmsg->version_rsp)) {
+			dev_warn(dev,
+				 "Msg: Version response of incorrect size. size=%u, expected=%zu", length,
+				 sizeof(rpmsg->version_rsp));
 			ret = -EBADMSG;
 			break;
 		}
 
-		dev_info(edev->dev, "Msg: Version response v%u.%u.%u\n",
-			 data.version.major, data.version.minor,
-			 data.version.patch);
+		dev_info(dev, "Msg: Version response v%u.%u.%u",
+			 rpmsg->version_rsp.major, rpmsg->version_rsp.minor,
+			 rpmsg->version_rsp.patch);
 
 		/* Check major and minor version match, else return error */
-		if (data.version.major != ETHOSU_CORE_MSG_VERSION_MAJOR ||
-		    data.version.minor != ETHOSU_CORE_MSG_VERSION_MINOR) {
-			dev_warn(edev->dev, "Msg: Version mismatch detected! ");
-			dev_warn(edev->dev, "Local version: v%u.%u.%u\n",
+		if (rpmsg->version_rsp.major != ETHOSU_CORE_MSG_VERSION_MAJOR ||
+		    rpmsg->version_rsp.minor != ETHOSU_CORE_MSG_VERSION_MINOR) {
+			dev_warn(dev, "Msg: Version mismatch detected! ");
+			dev_warn(dev, "Local version: v%u.%u.%u",
 				 ETHOSU_CORE_MSG_VERSION_MAJOR,
 				 ETHOSU_CORE_MSG_VERSION_MINOR,
 				 ETHOSU_CORE_MSG_VERSION_PATCH);
@@ -149,53 +145,54 @@
 
 		break;
 	case ETHOSU_CORE_MSG_CAPABILITIES_RSP:
-		if (header.length != sizeof(data.capabilities)) {
-			dev_warn(edev->dev,
-				 "Msg: Capabilities response of incorrect size. size=%u, expected=%zu\n", header.length,
-				 sizeof(data.capabilities));
+		if (length != sizeof(rpmsg->cap_rsp)) {
+			dev_warn(dev,
+				 "Msg: Capabilities response of incorrect size. size=%u, expected=%zu", length,
+				 sizeof(rpmsg->cap_rsp));
 			ret = -EBADMSG;
 			break;
 		}
 
-		dev_info(edev->dev,
-			 "Msg: Capabilities response ua%llx vs%hhu v%hhu.%hhu p%hhu av%hhu.%hhu.%hhu dv%hhu.%hhu.%hhu mcc%hhu csv%hhu cd%hhu\n",
-			 data.capabilities.user_arg,
-			 data.capabilities.version_status,
-			 data.capabilities.version_major,
-			 data.capabilities.version_minor,
-			 data.capabilities.product_major,
-			 data.capabilities.arch_major_rev,
-			 data.capabilities.arch_minor_rev,
-			 data.capabilities.arch_patch_rev,
-			 data.capabilities.driver_major_rev,
-			 data.capabilities.driver_minor_rev,
-			 data.capabilities.driver_patch_rev,
-			 data.capabilities.macs_per_cc,
-			 data.capabilities.cmd_stream_version,
-			 data.capabilities.custom_dma);
+		dev_info(dev,
+			 "Msg: Capabilities response vs%hhu v%hhu.%hhu p%hhu av%hhu.%hhu.%hhu dv%hhu.%hhu.%hhu mcc%hhu csv%hhu cd%hhu",
+			 rpmsg->cap_rsp.version_status,
+			 rpmsg->cap_rsp.version_major,
+			 rpmsg->cap_rsp.version_minor,
+			 rpmsg->cap_rsp.product_major,
+			 rpmsg->cap_rsp.arch_major_rev,
+			 rpmsg->cap_rsp.arch_minor_rev,
+			 rpmsg->cap_rsp.arch_patch_rev,
+			 rpmsg->cap_rsp.driver_major_rev,
+			 rpmsg->cap_rsp.driver_minor_rev,
+			 rpmsg->cap_rsp.driver_patch_rev,
+			 rpmsg->cap_rsp.macs_per_cc,
+			 rpmsg->cap_rsp.cmd_stream_version,
+			 rpmsg->cap_rsp.custom_dma);
 
-		ethosu_capability_rsp(edev, &data.capabilities);
+		ethosu_capability_rsp(edev, rpmsg->header.msg_id,
+				      &rpmsg->cap_rsp);
 		break;
 	case ETHOSU_CORE_MSG_NETWORK_INFO_RSP:
-		if (header.length != sizeof(data.network_info)) {
-			dev_warn(edev->dev,
-				 "Msg: Network info response of incorrect size. size=%u, expected=%zu\n", header.length,
-				 sizeof(data.network_info));
+		if (length != sizeof(rpmsg->net_info_rsp)) {
+			dev_warn(dev,
+				 "Msg: Network info response of incorrect size. size=%u, expected=%zu", length,
+				 sizeof(rpmsg->net_info_rsp));
 			ret = -EBADMSG;
 			break;
 		}
 
-		dev_info(edev->dev,
-			 "Msg: Network info response. user_arg=0x%llx, status=%u",
-			 data.network_info.user_arg,
-			 data.network_info.status);
+		dev_info(dev,
+			 "Msg: Network info response. status=%u",
+			 rpmsg->net_info_rsp.status);
 
-		ethosu_network_info_rsp(edev, &data.network_info);
+		ethosu_network_info_rsp(edev, rpmsg->header.msg_id,
+					&rpmsg->net_info_rsp);
 
 		break;
 	default:
 		/* This should not happen due to version checks */
-		dev_warn(edev->dev, "Msg: Protocol error\n");
+		dev_warn(dev, "Msg: Protocol error. type=%u",
+			 rpmsg->header.type);
 		ret = -EPROTO;
 		break;
 	}
@@ -211,7 +208,7 @@
 
 	file->private_data = edev;
 
-	dev_info(edev->dev, "Device open. file=0x%pK\n", file);
+	dev_info(edev->dev, "Device open. file=0x%pK", file);
 
 	return nonseekable_open(inode, file);
 }
@@ -228,19 +225,19 @@
 	if (ret)
 		return ret;
 
-	dev_info(edev->dev, "Device ioctl. file=0x%pK, cmd=0x%x, arg=0x%lx\n",
+	dev_info(edev->dev, "Device ioctl. file=0x%pK, cmd=0x%x, arg=0x%lx",
 		 file, cmd, arg);
 
 	switch (cmd) {
 	case ETHOSU_IOCTL_VERSION_REQ:
-		dev_info(edev->dev, "Device ioctl: Send version request\n");
+		dev_info(edev->dev, "Device ioctl: Send version request");
 		ret = ethosu_mailbox_version_request(&edev->mailbox);
 		break;
 	case ETHOSU_IOCTL_CAPABILITIES_REQ: {
 		struct ethosu_uapi_device_capabilities uapi;
 
 		dev_info(edev->dev,
-			 "Device ioctl: Send capabilities request\n");
+			 "Device ioctl: Send capabilities request");
 
 		ret = ethosu_capabilities_request(edev, &uapi);
 		if (ret)
@@ -250,7 +247,7 @@
 		break;
 	}
 	case ETHOSU_IOCTL_PING: {
-		dev_info(edev->dev, "Device ioctl: Send ping\n");
+		dev_info(edev->dev, "Device ioctl: Send ping");
 		ret = ethosu_mailbox_ping(&edev->mailbox);
 		break;
 	}
@@ -261,7 +258,7 @@
 			break;
 
 		dev_info(edev->dev,
-			 "Device ioctl: Buffer create. capacity=%u\n",
+			 "Device ioctl: Buffer create. capacity=%u",
 			 uapi.capacity);
 
 		ret = ethosu_buffer_create(edev, uapi.capacity);
@@ -274,7 +271,7 @@
 			break;
 
 		dev_info(edev->dev,
-			 "Device ioctl: Network create. type=%u, fd/index=%u\n",
+			 "Device ioctl: Network create. type=%u, fd/index=%u",
 			 uapi.type, uapi.fd);
 
 		ret = ethosu_network_create(edev, &uapi);
@@ -292,31 +289,34 @@
 	return ret;
 }
 
-static void ethosu_mbox_rx(void *user_arg)
+static struct rpmsg_endpoint *ethosu_create_ept(struct rpmsg_device *rpdev)
 {
-	struct ethosu_device *edev = user_arg;
-	int ret;
+	struct device *dev = &rpdev->dev;
+	struct rpmsg_channel_info info;
+	struct rpmsg_endpoint *ept;
 
-	mutex_lock(&edev->mutex);
+	/* Create rpmsg endpoint */
+	strncpy(info.name, rpdev->id.name, sizeof(info.name));
+	info.src = 0;
+	info.dst = rpdev->dst;
 
-	do {
-		ret = ethosu_handle_msg(edev);
-		if (ret && ret != -ENOMSG)
-			/* Need to start over in case of error, empty the queue
-			 * by fast-forwarding read position to write position.
-			 * */
-			ethosu_mailbox_reset(&edev->mailbox);
-	} while (ret == 0);
+	dev_info(dev, "Creating rpmsg endpoint. name=%s, src=%u, dst=%u",
+		 info.name, info.src, info.dst);
 
-	mutex_unlock(&edev->mutex);
+	ept = rpmsg_create_ept(rpdev, ethosu_handle_msg, NULL, info);
+	if (!ept) {
+		dev_err(&rpdev->dev, "Failed to create endpoint");
+
+		return ERR_PTR(-EINVAL);
+	}
+
+	return ept;
 }
 
 int ethosu_dev_init(struct ethosu_device *edev,
-		    struct device *dev,
+		    struct rpmsg_device *rpdev,
 		    struct class *class,
-		    dev_t devt,
-		    struct resource *in_queue,
-		    struct resource *out_queue)
+		    dev_t devt)
 {
 	static const struct file_operations fops = {
 		.owner          = THIS_MODULE,
@@ -329,43 +329,43 @@
 	struct device *sysdev;
 	int ret;
 
-	edev->dev = dev;
+	edev->dev = &rpdev->dev;
+	edev->rpdev = rpdev;
 	edev->class = class;
 	edev->devt = devt;
 	mutex_init(&edev->mutex);
 
-	ret = of_reserved_mem_device_init(edev->dev);
+	edev->ept = ethosu_create_ept(rpdev);
+	if (IS_ERR(edev->ept))
+		return PTR_ERR(edev->ept);
+
+	ret = ethosu_mailbox_init(&edev->mailbox, edev->dev, edev->ept);
 	if (ret)
 		return ret;
 
-	dma_set_mask_and_coherent(edev->dev, DMA_BIT_MASK(DMA_ADDR_BITS));
-
-	ret = ethosu_mailbox_init(&edev->mailbox, dev, in_queue, out_queue,
-				  ethosu_mbox_rx, edev);
-	if (ret)
-		goto release_reserved_mem;
-
 	cdev_init(&edev->cdev, &fops);
 	edev->cdev.owner = THIS_MODULE;
 
 	ret = cdev_add(&edev->cdev, edev->devt, 1);
 	if (ret) {
-		dev_err(edev->dev, "Failed to add character device.\n");
+		dev_err(edev->dev, "Failed to add character device.");
 		goto deinit_mailbox;
 	}
 
 	sysdev = device_create(edev->class, NULL, edev->devt, edev,
 			       "ethosu%d", MINOR(edev->devt));
 	if (IS_ERR(sysdev)) {
-		dev_err(edev->dev, "Failed to create device.\n");
+		dev_err(edev->dev, "Failed to create device.");
 		ret = PTR_ERR(sysdev);
 		goto del_cdev;
 	}
 
 	dev_info(edev->dev,
-		 "Created Arm Ethos-U device. name=%s, major=%d, minor=%d\n",
+		 "Created Arm Ethos-U device. name=%s, major=%d, minor=%d",
 		 dev_name(sysdev), MAJOR(edev->devt), MINOR(edev->devt));
 
+	ethosu_mailbox_ping(&edev->mailbox);
+
 	return 0;
 
 del_cdev:
@@ -374,18 +374,15 @@
 deinit_mailbox:
 	ethosu_mailbox_deinit(&edev->mailbox);
 
-release_reserved_mem:
-	of_reserved_mem_device_release(edev->dev);
-
 	return ret;
 }
 
 void ethosu_dev_deinit(struct ethosu_device *edev)
 {
+	dev_info(edev->dev, "%s\n", __FUNCTION__);
+
 	ethosu_mailbox_deinit(&edev->mailbox);
+	rpmsg_destroy_ept(edev->ept);
 	device_destroy(edev->class, edev->cdev.dev);
 	cdev_del(&edev->cdev);
-	of_reserved_mem_device_release(edev->dev);
-
-	dev_info(edev->dev, "%s\n", __FUNCTION__);
 }