summaryrefslogtreecommitdiffstats
path: root/drivers/misc/bcm-vk/bcm_vk_msg.c
diff options
context:
space:
mode:
authorScott Branden <scott.branden@broadcom.com>2021-01-20 09:58:20 -0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2021-01-25 18:44:44 +0100
commit22c30607d1e0c604b2450a7aa5bc90a63e24f088 (patch)
treea00d5473b154ae4f10829ab2c80b4d5a7831cfb5 /drivers/misc/bcm-vk/bcm_vk_msg.c
parentaf22527e82d12f9d0b5afb39f25926a91d5fa7e7 (diff)
downloadlinux-22c30607d1e0c604b2450a7aa5bc90a63e24f088.tar.gz
linux-22c30607d1e0c604b2450a7aa5bc90a63e24f088.tar.bz2
linux-22c30607d1e0c604b2450a7aa5bc90a63e24f088.zip
misc: bcm-vk: add open/release
Add open/release to replace private data with context for other methods to use. Reason for the context is because it is allowed for multiple sessions to open sysfs. For each file open, when upper layer queries the response, only those that are tied to a specified open should be returned. Co-developed-by: Desmond Yan <desmond.yan@broadcom.com> Acked-by: Olof Johansson <olof@lixom.net> Signed-off-by: Desmond Yan <desmond.yan@broadcom.com> Signed-off-by: Scott Branden <scott.branden@broadcom.com> Link: https://lore.kernel.org/r/20210120175827.14820-7-scott.branden@broadcom.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/misc/bcm-vk/bcm_vk_msg.c')
-rw-r--r--drivers/misc/bcm-vk/bcm_vk_msg.c127
1 files changed, 127 insertions, 0 deletions
diff --git a/drivers/misc/bcm-vk/bcm_vk_msg.c b/drivers/misc/bcm-vk/bcm_vk_msg.c
new file mode 100644
index 000000000000..2d9a6b4e5f61
--- /dev/null
+++ b/drivers/misc/bcm-vk/bcm_vk_msg.c
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2018-2020 Broadcom.
+ */
+
+#include "bcm_vk.h"
+#include "bcm_vk_msg.h"
+
+/*
+ * allocate a ctx per file struct
+ */
+static struct bcm_vk_ctx *bcm_vk_get_ctx(struct bcm_vk *vk, const pid_t pid)
+{
+ u32 i;
+ struct bcm_vk_ctx *ctx = NULL;
+ u32 hash_idx = hash_32(pid, VK_PID_HT_SHIFT_BIT);
+
+ spin_lock(&vk->ctx_lock);
+
+ for (i = 0; i < ARRAY_SIZE(vk->ctx); i++) {
+ if (!vk->ctx[i].in_use) {
+ vk->ctx[i].in_use = true;
+ ctx = &vk->ctx[i];
+ break;
+ }
+ }
+
+ if (!ctx) {
+ dev_err(&vk->pdev->dev, "All context in use\n");
+
+ goto all_in_use_exit;
+ }
+
+ /* set the pid and insert it to hash table */
+ ctx->pid = pid;
+ ctx->hash_idx = hash_idx;
+ list_add_tail(&ctx->node, &vk->pid_ht[hash_idx].head);
+
+ /* increase kref */
+ kref_get(&vk->kref);
+
+all_in_use_exit:
+ spin_unlock(&vk->ctx_lock);
+
+ return ctx;
+}
+
+static int bcm_vk_free_ctx(struct bcm_vk *vk, struct bcm_vk_ctx *ctx)
+{
+ u32 idx;
+ u32 hash_idx;
+ pid_t pid;
+ struct bcm_vk_ctx *entry;
+ int count = 0;
+
+ if (!ctx) {
+ dev_err(&vk->pdev->dev, "NULL context detected\n");
+ return -EINVAL;
+ }
+ idx = ctx->idx;
+ pid = ctx->pid;
+
+ spin_lock(&vk->ctx_lock);
+
+ if (!vk->ctx[idx].in_use) {
+ dev_err(&vk->pdev->dev, "context[%d] not in use!\n", idx);
+ } else {
+ vk->ctx[idx].in_use = false;
+ vk->ctx[idx].miscdev = NULL;
+
+ /* Remove it from hash list and see if it is the last one. */
+ list_del(&ctx->node);
+ hash_idx = ctx->hash_idx;
+ list_for_each_entry(entry, &vk->pid_ht[hash_idx].head, node) {
+ if (entry->pid == pid)
+ count++;
+ }
+ }
+
+ spin_unlock(&vk->ctx_lock);
+
+ return count;
+}
+
+int bcm_vk_open(struct inode *inode, struct file *p_file)
+{
+ struct bcm_vk_ctx *ctx;
+ struct miscdevice *miscdev = (struct miscdevice *)p_file->private_data;
+ struct bcm_vk *vk = container_of(miscdev, struct bcm_vk, miscdev);
+ struct device *dev = &vk->pdev->dev;
+ int rc = 0;
+
+ /* get a context and set it up for file */
+ ctx = bcm_vk_get_ctx(vk, task_tgid_nr(current));
+ if (!ctx) {
+ dev_err(dev, "Error allocating context\n");
+ rc = -ENOMEM;
+ } else {
+ /*
+ * set up context and replace private data with context for
+ * other methods to use. Reason for the context is because
+ * it is allowed for multiple sessions to open the sysfs, and
+ * for each file open, when upper layer query the response,
+ * only those that are tied to a specific open should be
+ * returned. The context->idx will be used for such binding
+ */
+ ctx->miscdev = miscdev;
+ p_file->private_data = ctx;
+ dev_dbg(dev, "ctx_returned with idx %d, pid %d\n",
+ ctx->idx, ctx->pid);
+ }
+ return rc;
+}
+
+int bcm_vk_release(struct inode *inode, struct file *p_file)
+{
+ int ret;
+ struct bcm_vk_ctx *ctx = p_file->private_data;
+ struct bcm_vk *vk = container_of(ctx->miscdev, struct bcm_vk, miscdev);
+
+ ret = bcm_vk_free_ctx(vk, ctx);
+
+ kref_put(&vk->kref, bcm_vk_release_data);
+
+ return ret;
+}
+