From de0a5c2c113b518bd22fd8961e93a54f2729ef69 Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Thu, 8 Dec 2022 12:31:41 +0200 Subject: [PATCH] gpu: host1x: Support for syncpoint pools Add support for syncpoint pools. These are configuration-dependent subsets of syncpoints that can only be allocated by specifying an allocation specifically from that pool. In this patch, we add support for the GPU pool. On certain systems, the GPU is for safety purposes limited to accessing a specific set of syncpoints. Therefore, syncpoints allocated for GPU use need to come from this pool. Signed-off-by: Mikko Perttunen Change-Id: I385b8bdfdac8573b26f0b1a0feaf05de071148a1 Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2826198 Reviewed-by: svc_kernel_abi Reviewed-by: Arto Merilainen Reviewed-by: Sanif Veeras Reviewed-by: Raghavendra Vishnu Kumar GVS: Gerrit_Virtual_Submit Tested-by: Sanif Veeras --- drivers/gpu/host1x/dev.c | 44 +++++++++++++++++++ drivers/gpu/host1x/dev.h | 10 +++++ .../gpu/host1x/include/linux/host1x-next.h | 1 + drivers/gpu/host1x/syncpt.c | 36 ++++++++++++--- drivers/gpu/host1x/syncpt.h | 1 + 5 files changed, 86 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index 4b90f58f..424c8a67 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c @@ -706,6 +706,46 @@ static int host1x_get_assigned_resources(struct host1x *host) return 0; } +static int host1x_get_syncpt_pools(struct host1x *host) +{ + struct device_node *np = host->dev->of_node; + int err, i; + + err = of_property_count_strings(np, "nvidia,syncpoint-pool-names"); + if (err == -EINVAL) + return 0; + if (err < 0) { + dev_err(host->dev, "invalid nvidia,syncpoint-pool-names property: %d\n", err); + return err; + } + + host->num_pools = err; + host->pools = devm_kcalloc(host->dev, host->num_pools, sizeof(struct host1x_syncpt_pool), + GFP_KERNEL); + if (!host->pools) + return -ENOMEM; + + for (i = 0; i < host->num_pools; i++) { + struct host1x_syncpt_pool *pool = &host->pools[i]; + + err = of_property_read_string_index(np, "nvidia,syncpoint-pool-names", i, &pool->name); + if (err) + return err; + + err = of_property_read_u32_index(np, "nvidia,syncpoint-pools", i*2+0, &pool->base); + if (!err) + err = of_property_read_u32_index(np, "nvidia,syncpoint-pools", i*2+1, &pool->end); + if (err) { + dev_err(host->dev, "invalid nvidia,syncpoint-pools property: %d\n", err); + return err; + } + + pool->end = pool->base + pool->end; + } + + return 0; +} + static int host1x_probe(struct platform_device *pdev) { struct host1x *host; @@ -768,6 +808,10 @@ static int host1x_probe(struct platform_device *pdev) if (err) return err; + err = host1x_get_syncpt_pools(host); + if (err) + return err; + host->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(host->clk)) { err = PTR_ERR(host->clk); diff --git a/drivers/gpu/host1x/dev.h b/drivers/gpu/host1x/dev.h index 87e8c273..25e3f770 100644 --- a/drivers/gpu/host1x/dev.h +++ b/drivers/gpu/host1x/dev.h @@ -118,6 +118,12 @@ struct host1x_info { bool reserve_vblank_syncpts; }; +struct host1x_syncpt_pool { + const char *name; + unsigned int base; + unsigned int end; +}; + struct host1x { const struct host1x_info *info; @@ -136,6 +142,10 @@ struct host1x { unsigned int syncpt_base, syncpt_end; unsigned int channel_base, num_channels; + /* Restricted syncpoint pools */ + struct host1x_syncpt_pool *pools; + unsigned int num_pools; + struct iommu_group *group; struct iommu_domain *domain; struct iova_domain iova; diff --git a/drivers/gpu/host1x/include/linux/host1x-next.h b/drivers/gpu/host1x/include/linux/host1x-next.h index 69a4044e..3e67ed56 100644 --- a/drivers/gpu/host1x/include/linux/host1x-next.h +++ b/drivers/gpu/host1x/include/linux/host1x-next.h @@ -198,6 +198,7 @@ static inline void host1x_bo_munmap(struct host1x_bo *bo, void *addr) #define HOST1X_SYNCPT_CLIENT_MANAGED (1 << 0) #define HOST1X_SYNCPT_HAS_BASE (1 << 1) +#define HOST1X_SYNCPT_GPU (1 << 2) struct host1x_syncpt_base; struct host1x_syncpt; diff --git a/drivers/gpu/host1x/syncpt.c b/drivers/gpu/host1x/syncpt.c index 26b59b31..9375000f 100644 --- a/drivers/gpu/host1x/syncpt.c +++ b/drivers/gpu/host1x/syncpt.c @@ -60,17 +60,34 @@ struct host1x_syncpt *host1x_syncpt_alloc(struct host1x *host, unsigned long flags, const char *name) { - struct host1x_syncpt *sp = host->syncpt; + struct host1x_syncpt *sp = host->syncpt + host->syncpt_base; + struct host1x_syncpt_pool *pool = NULL; char *full_name; unsigned int i; if (!name) return NULL; + if (flags & HOST1X_SYNCPT_GPU) { + for (i = 0; i < host->num_pools; i++) { + if (!strcmp(host->pools[i].name, "gpu")) { + pool = &host->pools[i]; + break; + } + } + + /* If no GPU pool configured, any syncpoint is OK. */ + } + mutex_lock(&host->syncpt_mutex); - for (i = host->syncpt_base; i < host->syncpt_end && kref_read(&sp->ref); i++, sp++) - ; + for (i = host->syncpt_base; i < host->syncpt_end; i++, sp++) { + if (sp->pool != pool) + continue; + + if (kref_read(&sp->ref) == 0) + break; + } if (i >= host->syncpt_end) goto unlock; @@ -322,6 +339,14 @@ int host1x_syncpt_init(struct host1x *host) for (i = 0; i < host->info->nb_bases; i++) bases[i].id = i; + for (i = 0; i < host->num_pools; i++) { + struct host1x_syncpt_pool *pool = &host->pools[i]; + unsigned int j; + + for (j = pool->base; j < pool->end; j++) + syncpt[j].pool = pool; + } + mutex_init(&host->syncpt_mutex); host->syncpt = syncpt; host->bases = bases; @@ -332,9 +357,8 @@ int host1x_syncpt_init(struct host1x *host) * this for anything. */ if (host->syncpt_base == 0) { - host->nop_sp = host1x_syncpt_alloc(host, 0, "reserved-nop"); - if (!host->nop_sp) - return -ENOMEM; + kref_init(&syncpt[0].ref); + syncpt[0].name = kstrdup("reserved", GFP_KERNEL); } if (host->info->reserve_vblank_syncpts) { diff --git a/drivers/gpu/host1x/syncpt.h b/drivers/gpu/host1x/syncpt.h index 76e12137..03a686f1 100644 --- a/drivers/gpu/host1x/syncpt.h +++ b/drivers/gpu/host1x/syncpt.h @@ -38,6 +38,7 @@ struct host1x_syncpt { bool client_managed; struct host1x *host; struct host1x_syncpt_base *base; + struct host1x_syncpt_pool *pool; /* interrupt data */ struct host1x_fence_list fences;