gpu: host1x-fence: fence support for multi-instance host1x

Update host1x-fence driver for handling fences for
multi-instance host1x

Bug 4793553
Jira HOSTX-5413

Signed-off-by: Santosh BS <santoshb@nvidia.com>
Change-Id: Ice32d6f7ffe5bced50e2d50abe71530a5c75928f
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3198410
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
Reviewed-by: Mikko Perttunen <mperttunen@nvidia.com>
This commit is contained in:
Santosh BS
2024-08-22 09:45:13 +00:00
committed by Jon Hunter
parent edf6adc357
commit 98a6db4289
3 changed files with 77 additions and 17 deletions

View File

@@ -18,6 +18,8 @@
#include "include/uapi/linux/host1x-fence.h"
#define HOST1X_INSTANCE_MAX 2
static struct host1x_uapi {
struct class *class;
@@ -30,6 +32,8 @@ static int dev_file_open(struct inode *inode, struct file *file)
{
struct platform_device *host1x_pdev;
struct device_node *np;
int numa_node;
struct host1x **host1xp;
static const struct of_device_id host1x_match[] = {
{ .compatible = "nvidia,tegra186-host1x", },
@@ -38,17 +42,33 @@ static int dev_file_open(struct inode *inode, struct file *file)
{},
};
np = of_find_matching_node(NULL, host1x_match);
if (!np) {
return -ENODEV;
host1xp = kzalloc(HOST1X_INSTANCE_MAX * sizeof(struct host1x *), GFP_KERNEL);
if (!host1xp)
return -ENOMEM;
for_each_matching_node(np, host1x_match) {
host1x_pdev = of_find_device_by_node(np);
if (host1x_pdev) {
numa_node = dev_to_node(&host1x_pdev->dev);
if (numa_node == NUMA_NO_NODE)
host1xp[0] = platform_get_drvdata(host1x_pdev);
else if (numa_node < HOST1X_INSTANCE_MAX && numa_node >= 0)
host1xp[numa_node] = platform_get_drvdata(host1x_pdev);
else
pr_warn("%s: no host1x_fence support for instance %d\n",
__func__, numa_node);
}
}
host1x_pdev = of_find_device_by_node(np);
if (!host1x_pdev) {
return -EAGAIN;
}
file->private_data = host1xp;
file->private_data = platform_get_drvdata(host1x_pdev);
return 0;
}
static int dev_file_release(struct inode *inode, struct file *file)
{
kfree(file->private_data);
file->private_data = NULL;
return 0;
}
@@ -79,12 +99,13 @@ static int host1x_fence_create_fd(struct host1x_syncpt *sp, u32 threshold)
return fd;
}
static int dev_file_ioctl_create_fence(struct host1x *host1x, void __user *data)
static int dev_file_ioctl_create_fence(struct host1x **host1xp, void __user *data)
{
struct host1x_create_fence args;
struct host1x_syncpt *syncpt;
unsigned long copy_err;
int fd;
unsigned int instance, local_id;
copy_err = copy_from_user(&args, data, sizeof(args));
if (copy_err)
@@ -93,7 +114,13 @@ static int dev_file_ioctl_create_fence(struct host1x *host1x, void __user *data)
if (args.reserved[0])
return -EINVAL;
syncpt = host1x_syncpt_get_by_id_noref(host1x, args.id);
instance = HOST1X_INSTANCE_NUM_FROM_GLOBAL_SYNCPOINT(args.id);
local_id = HOST1X_GLOBAL_TO_LOCAL_SYNCPOINT(args.id);
if (instance >= HOST1X_INSTANCE_MAX || !host1xp[instance])
return -EINVAL;
syncpt = host1x_syncpt_get_by_id_noref(host1xp[instance], local_id);
if (!syncpt)
return -EINVAL;
@@ -110,7 +137,7 @@ static int dev_file_ioctl_create_fence(struct host1x *host1x, void __user *data)
return 0;
}
static int dev_file_ioctl_fence_extract(struct host1x *host1x, void __user *data)
static int dev_file_ioctl_fence_extract(struct host1x **host1xp, void __user *data)
{
struct host1x_fence_extract_fence __user *fences_user_ptr;
struct dma_fence *fence, **fences;
@@ -144,6 +171,7 @@ static int dev_file_ioctl_fence_extract(struct host1x *host1x, void __user *data
for (i = 0, j = 0; i < num_fences; i++) {
struct host1x_fence_extract_fence f;
int instance;
err = host1x_fence_extract(fences[i], &f.id, &f.threshold);
if (err == -EINVAL && dma_fence_is_signaled(fences[i])) {
@@ -154,6 +182,11 @@ static int dev_file_ioctl_fence_extract(struct host1x *host1x, void __user *data
}
if (j < args.num_fences) {
/* Convert to global id before giving to userspace */
instance = host1x_fence_get_node(fences[i]);
if (instance < HOST1X_INSTANCE_MAX && instance >= 0)
f.id = HOST1X_LOCAL_TO_GLOBAL_SYNCPOINT(f.id, instance);
copy_err = copy_to_user(fences_user_ptr + j, &f, sizeof(f));
if (copy_err) {
err = -EFAULT;
@@ -266,7 +299,7 @@ static const struct file_operations host1x_pollfd_ops = {
.poll = host1x_pollfd_poll,
};
static int dev_file_ioctl_create_pollfd(struct host1x *host1x, void __user *data)
static int dev_file_ioctl_create_pollfd(struct host1x **host1xp, void __user *data)
{
struct host1x_create_pollfd args;
struct host1x_pollfd *pollfd;
@@ -324,7 +357,7 @@ static void host1x_pollfd_callback(struct dma_fence *fence, struct dma_fence_cb
wake_up_all(pfd_fence->wq);
}
static int dev_file_ioctl_trigger_pollfd(struct host1x *host1x, void __user *data)
static int dev_file_ioctl_trigger_pollfd(struct host1x **host1xp, void __user *data)
{
struct host1x_pollfd_fence *pfd_fence;
struct host1x_trigger_pollfd args;
@@ -334,6 +367,7 @@ static int dev_file_ioctl_trigger_pollfd(struct host1x *host1x, void __user *dat
unsigned long copy_err;
struct file *file;
int err;
unsigned int instance, local_id;
copy_err = copy_from_user(&args, data, sizeof(args));
if (copy_err)
@@ -350,7 +384,13 @@ static int dev_file_ioctl_trigger_pollfd(struct host1x *host1x, void __user *dat
pollfd = file->private_data;
syncpt = host1x_syncpt_get_by_id_noref(host1x, args.id);
instance = HOST1X_INSTANCE_NUM_FROM_GLOBAL_SYNCPOINT(args.id);
local_id = HOST1X_GLOBAL_TO_LOCAL_SYNCPOINT(args.id);
if (instance >= HOST1X_INSTANCE_MAX || !host1xp[instance])
return -EINVAL;
syncpt = host1x_syncpt_get_by_id_noref(host1xp[instance], local_id);
if (!syncpt) {
err = -EINVAL;
goto put_file;
@@ -437,6 +477,7 @@ static long dev_file_ioctl(struct file *file, unsigned int cmd,
static const struct file_operations dev_file_fops = {
.owner = THIS_MODULE,
.open = dev_file_open,
.release = dev_file_release,
.unlocked_ioctl = dev_file_ioctl,
.compat_ioctl = dev_file_ioctl,
};

View File

@@ -2,7 +2,7 @@
/*
* Syncpoint dma_fence implementation
*
* Copyright (c) 2020-2023, NVIDIA Corporation.
* Copyright (c) 2020-2024, NVIDIA Corporation.
*/
#include <linux/dma-fence.h>
@@ -178,6 +178,21 @@ int host1x_fence_extract(struct dma_fence *fence, u32 *id, u32 *threshold)
}
EXPORT_SYMBOL(host1x_fence_extract);
int host1x_fence_get_node(struct dma_fence *fence)
{
struct host1x_syncpt_fence *f;
int node;
if (fence->ops != &host1x_syncpt_fence_ops)
return -EINVAL;
f = container_of(fence, struct host1x_syncpt_fence, base);
node = dev_to_node(f->sp->host->dev);
return node == NUMA_NO_NODE ? 0 : node;
}
EXPORT_SYMBOL(host1x_fence_get_node);
void host1x_fence_cancel(struct dma_fence *f)
{
struct host1x_syncpt_fence *sf = to_host1x_fence(f);

View File

@@ -219,10 +219,13 @@ static inline void host1x_bo_munmap(struct host1x_bo *bo, void *addr)
#define HOST1X_SYNCPT_GPU (1 << 2)
#define HOST1X_GLOBAL_TO_LOCAL_SYNCPOINT(global_syncpoint_id) \
(global_syncpoint_id & 0xFFFFFF)
(global_syncpoint_id & 0xFFFFFF)
#define HOST1X_INSTANCE_NUM_FROM_GLOBAL_SYNCPOINT(global_syncpoint_id) \
((global_syncpoint_id & 0xFF000000) >> 24)
#define HOST1X_LOCAL_TO_GLOBAL_SYNCPOINT(local_syncpoint_id, instance) \
((instance << 24) | (local_syncpoint_id))
((instance << 24) | (local_syncpoint_id))
struct host1x_syncpt_base;
struct host1x_syncpt;
@@ -257,6 +260,7 @@ void host1x_syncpt_release_vblank_reservation(struct host1x_client *client,
struct dma_fence *host1x_fence_create(struct host1x_syncpt *sp, u32 threshold,
bool timeout);
int host1x_fence_extract(struct dma_fence *fence, u32 *id, u32 *threshold);
int host1x_fence_get_node(struct dma_fence *fence);
void host1x_fence_cancel(struct dma_fence *fence);
/*