Add device capabilities caching in kernel driver

To not have to fetch the capabilities from the device for each time they
are requested with the UAPI, the kernel driver will now fetch and save
the capabilities during the device initialization and use the saved copy
for the UAPI requests.

With this change, the character device creation in the device
initialization has been moved to be the last step so the capabilities
are fetched and saved before the character device is created.

Change-Id: I57956aedb983fbc1765d45906a1c6182e2cd5b96
diff --git a/kernel/ethosu_device.c b/kernel/ethosu_device.c
index e1dde65..0b6fdfa 100644
--- a/kernel/ethosu_device.c
+++ b/kernel/ethosu_device.c
@@ -264,16 +264,10 @@
 		ret = ethosu_mailbox_version_request(&edev->mailbox);
 		break;
 	case ETHOSU_IOCTL_CAPABILITIES_REQ: {
-		struct ethosu_uapi_device_capabilities uapi;
+		dev_info(dev, "Device ioctl: Capabilities request");
 
-		dev_info(dev,
-			 "Device ioctl: Send capabilities request");
-
-		ret = ethosu_capabilities_request(dev, &edev->mailbox, &uapi);
-		if (ret)
-			break;
-
-		ret = copy_to_user(udata, &uapi, sizeof(uapi)) ? -EFAULT : 0;
+		ret = copy_to_user(udata, &edev->capabilities,
+				   sizeof(edev->capabilities)) ? -EFAULT : 0;
 		break;
 	}
 	case ETHOSU_IOCTL_PING: {
@@ -464,6 +458,17 @@
 	if (ret)
 		goto device_unregister;
 
+	ethosu_mailbox_ping(&edev->mailbox);
+
+	device_lock(dev);
+	ret = ethosu_capabilities_request(dev, &edev->mailbox,
+					  &edev->capabilities);
+	device_unlock(dev);
+	if (ret) {
+		dev_err(dev, "Failed to get device capabilities: %d", ret);
+		goto deinit_mailbox;
+	}
+
 	/* Create device node */
 	cdev_init(&edev->cdev, &fops);
 	edev->cdev.owner = THIS_MODULE;
@@ -490,8 +495,6 @@
 		 "Created Arm Ethos-U device. name=%s, major=%d, minor=%d",
 		 dev_name(sysdev), MAJOR(devt), MINOR(devt));
 
-	ethosu_mailbox_ping(&edev->mailbox);
-
 	return 0;
 
 del_cdev:
diff --git a/kernel/ethosu_device.h b/kernel/ethosu_device.h
index bcf973d..af14c85 100644
--- a/kernel/ethosu_device.h
+++ b/kernel/ethosu_device.h
@@ -42,12 +42,13 @@
  * struct ethosu_device - Device structure
  */
 struct ethosu_device {
-	struct device         dev;
-	struct rpmsg_device   *rpdev;
-	struct rpmsg_endpoint *ept;
-	struct cdev           cdev;
-	struct class          *class;
-	struct ethosu_mailbox mailbox;
+	struct device                          dev;
+	struct rpmsg_device                    *rpdev;
+	struct rpmsg_endpoint                  *ept;
+	struct cdev                            cdev;
+	struct class                           *class;
+	struct ethosu_mailbox                  mailbox;
+	struct ethosu_uapi_device_capabilities capabilities;
 };
 
 /****************************************************************************