aboutsummaryrefslogtreecommitdiff
path: root/kernel/ethosu_device.c
diff options
context:
space:
mode:
authorDavide Grohmann <davide.grohmann@arm.com>2021-06-01 15:03:51 +0200
committerKristofer Jonsson <kristofer.jonsson@arm.com>2021-06-10 14:58:49 +0000
commit35ce6c809ccf637c6bb8a00ad14b051b87d9884a (patch)
treee999250ca985ac5b00ba9162ee1782de02983c03 /kernel/ethosu_device.c
parent0c79f896caf1a0ac16dd92810c4b15bfff00bdb3 (diff)
downloadethos-u-linux-driver-stack-35ce6c809ccf637c6bb8a00ad14b051b87d9884a.tar.gz
Add support for handling capabilities requests
Change-Id: Id5aa197312c88b0c448dc085d8477ed67da24724
Diffstat (limited to 'kernel/ethosu_device.c')
-rw-r--r--kernel/ethosu_device.c166
1 files changed, 163 insertions, 3 deletions
diff --git a/kernel/ethosu_device.c b/kernel/ethosu_device.c
index e82b4c0..7adc7a6 100644
--- a/kernel/ethosu_device.c
+++ b/kernel/ethosu_device.c
@@ -38,6 +38,7 @@
#include <linux/io.h>
#include <linux/of_reserved_mem.h>
#include <linux/uaccess.h>
+#include <linux/slab.h>
/****************************************************************************
* Defines
@@ -47,6 +48,8 @@
#define MINOR_COUNT 1 /* Allocate 1 minor version */
#define DMA_ADDR_BITS 32 /* Number of address bits */
+#define CAPABILITIES_RESP_TIMEOUT_MS 50
+
/****************************************************************************
* Types
****************************************************************************/
@@ -55,6 +58,71 @@
* Functions
****************************************************************************/
+static void ethosu_capabilities_destroy(struct kref *kref)
+{
+ struct ethosu_capabilities *cap =
+ container_of(kref, struct ethosu_capabilities, refcount);
+
+ list_del(&cap->list);
+
+ devm_kfree(cap->edev->dev, cap);
+}
+
+static int ethosu_capabilities_find(struct ethosu_capabilities *cap,
+ struct list_head *capabilties_list)
+{
+ struct ethosu_capabilities *cur;
+
+ list_for_each_entry(cur, capabilties_list, list) {
+ if (cur == cap)
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int ethosu_capability_rsp(struct ethosu_device *edev,
+ struct ethosu_core_msg_capabilities_rsp *msg)
+{
+ struct ethosu_capabilities *cap;
+ struct ethosu_uapi_device_capabilities *capabilities;
+ int ret;
+
+ cap = (struct ethosu_capabilities *)msg->user_arg;
+ ret = ethosu_capabilities_find(cap, &edev->capabilities_list);
+ if (0 != ret) {
+ dev_warn(edev->dev,
+ "Handle not found in capabilities list. handle=0x%p\n",
+ cap);
+
+ /* NOTE: do not call complete or kref_put on invalid data! */
+ return ret;
+ }
+
+ capabilities = cap->capabilities;
+
+ capabilities->hw_id.version_status = msg->version_status;
+ capabilities->hw_id.version_minor = msg->version_minor;
+ capabilities->hw_id.version_major = msg->version_major;
+ capabilities->hw_id.product_major = msg->product_major;
+ capabilities->hw_id.arch_patch_rev = msg->arch_patch_rev;
+ capabilities->hw_id.arch_minor_rev = msg->arch_minor_rev;
+ capabilities->hw_id.arch_major_rev = msg->arch_major_rev;
+ capabilities->driver_patch_rev = msg->driver_patch_rev;
+ capabilities->driver_minor_rev = msg->driver_minor_rev;
+ capabilities->driver_major_rev = msg->driver_major_rev;
+ capabilities->hw_cfg.macs_per_cc = msg->macs_per_cc;
+ capabilities->hw_cfg.cmd_stream_version = msg->cmd_stream_version;
+ capabilities->hw_cfg.shram_size = msg->shram_size;
+ capabilities->hw_cfg.custom_dma = msg->custom_dma;
+
+ complete(&cap->done);
+
+ kref_put(&cap->refcount, ethosu_capabilities_destroy);
+
+ return 0;
+}
+
/* Incoming messages */
static int ethosu_handle_msg(struct ethosu_device *edev)
{
@@ -62,9 +130,10 @@ static int ethosu_handle_msg(struct ethosu_device *edev)
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_err error;
+ struct ethosu_core_inference_rsp inf;
+ struct ethosu_core_msg_version version;
+ struct ethosu_core_msg_capabilities_rsp capabilities;
} data;
/* Read message */
@@ -133,7 +202,35 @@ static int ethosu_handle_msg(struct ethosu_device *edev)
}
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));
+ 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 ss%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.shram_size,
+ data.capabilities.custom_dma);
+
+ ret = ethosu_capability_rsp(edev, &data.capabilities);
+ break;
default:
/* This should not happen due to version checks */
dev_warn(edev->dev, "Msg: Protocol error\n");
@@ -157,6 +254,64 @@ static int ethosu_open(struct inode *inode,
return nonseekable_open(inode, file);
}
+static int ethosu_send_capabilities_request(struct ethosu_device *edev,
+ void __user *udata)
+{
+ struct ethosu_uapi_device_capabilities uapi;
+ struct ethosu_capabilities *cap;
+ int ret;
+ int timeout;
+
+ cap = devm_kzalloc(edev->dev, sizeof(struct ethosu_capabilities),
+ GFP_KERNEL);
+ if (!cap)
+ return -ENOMEM;
+
+ cap->edev = edev;
+ cap->capabilities = &uapi;
+ kref_init(&cap->refcount);
+ init_completion(&cap->done);
+ list_add(&cap->list, &edev->capabilities_list);
+
+ ret = ethosu_mailbox_capabilities_request(&edev->mailbox, cap);
+ if (0 != ret)
+ goto put_kref;
+
+ /*
+ * Increase ref counter since we sent the pointer out to
+ * response handler thread. That thread is responsible to
+ * decrease the ref counter before exiting. So the memory
+ * can be freed.
+ *
+ * NOTE: if no response is received back, the memory is leaked.
+ */
+ kref_get(&cap->refcount);
+ /* Unlock the mutex before going to block on the condition */
+ mutex_unlock(&edev->mutex);
+ /* wait for response to arrive back */
+ timeout = wait_for_completion_timeout(&cap->done,
+ msecs_to_jiffies(
+ CAPABILITIES_RESP_TIMEOUT_MS));
+ /* take back the mutex before resuming to do anything */
+ ret = mutex_lock_interruptible(&edev->mutex);
+ if (0 != ret)
+ goto put_kref;
+
+ if (0 == timeout /* timed out*/) {
+ dev_warn(edev->dev,
+ "Msg: Capabilities response lost - timeout\n");
+ ret = -EIO;
+ goto put_kref;
+ }
+
+ ret = copy_to_user(udata, &uapi, sizeof(uapi)) ? -EFAULT : 0;
+
+put_kref:
+ kref_put(&cap->refcount, ethosu_capabilities_destroy);
+
+ return ret;
+}
+
static long ethosu_ioctl(struct file *file,
unsigned int cmd,
unsigned long arg)
@@ -176,6 +331,10 @@ static long ethosu_ioctl(struct file *file,
dev_info(edev->dev, "Ioctl: Send version request\n");
ret = ethosu_mailbox_version_request(&edev->mailbox);
break;
+ case ETHOSU_IOCTL_CAPABILITIES_REQ:
+ dev_info(edev->dev, "Ioctl: Send capabilities request\n");
+ ret = ethosu_send_capabilities_request(edev, udata);
+ break;
case ETHOSU_IOCTL_PING: {
dev_info(edev->dev, "Ioctl: Send ping\n");
ret = ethosu_mailbox_ping(&edev->mailbox);
@@ -257,6 +416,7 @@ int ethosu_dev_init(struct ethosu_device *edev,
edev->dev = dev;
edev->class = class;
mutex_init(&edev->mutex);
+ INIT_LIST_HEAD(&edev->capabilities_list);
INIT_LIST_HEAD(&edev->inference_list);
ret = of_reserved_mem_device_init(edev->dev);