All of lore.kernel.org
 help / color / mirror / Atom feed
From: Mikko Perttunen <cyndis@kapsi.fi>
To: Thierry Reding <thierry.reding@gmail.com>,
	Mikko Perttunen <mperttunen@nvidia.com>
Cc: jonathanh@nvidia.com, digetx@gmail.com, airlied@linux.ie,
	daniel@ffwll.ch, linux-tegra@vger.kernel.org,
	dri-devel@lists.freedesktop.org, talho@nvidia.com,
	bhuntsman@nvidia.com
Subject: Re: [PATCH v5 19/21] drm/tegra: Implement new UAPI
Date: Tue, 23 Mar 2021 16:43:03 +0200	[thread overview]
Message-ID: <494e3858-5b29-0b44-f2eb-7a7cc16ff325@kapsi.fi> (raw)
In-Reply-To: <YFnsQNiLg/5I/qKA@orome.fritz.box>

On 3/23/21 3:25 PM, Thierry Reding wrote:
> On Mon, Jan 11, 2021 at 03:00:17PM +0200, Mikko Perttunen wrote:
>> Implement the non-submission parts of the new UAPI, including
>> channel management and memory mapping. The UAPI is under the
>> CONFIG_DRM_TEGRA_STAGING config flag for now.
>>
>> Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
>> ---
>> v5:
>> * Set iova_end in both mapping paths
>> v4:
>> * New patch, split out from combined UAPI + submit patch.
>> ---
>>   drivers/gpu/drm/tegra/Makefile    |   1 +
>>   drivers/gpu/drm/tegra/drm.c       |  41 ++--
>>   drivers/gpu/drm/tegra/drm.h       |   5 +
>>   drivers/gpu/drm/tegra/uapi.h      |  63 ++++++
>>   drivers/gpu/drm/tegra/uapi/uapi.c | 307 ++++++++++++++++++++++++++++++
> 
> I'd prefer if we kept the directory structure flat. There's something
> like 19 pairs of files in the top-level directory, which is reasonably
> manageable. Also, it looks like there's going to be a couple more files
> in this new subdirectory. I'd prefer if that was all merged into the
> single uapi.c source file to keep things simpler. These are all really
> small files, so there's no need to aggressively split things up. Helps
> with compilation time, too.

Will do, although I think having plenty of subdirectories makes things 
more organized :)

> 
> FWIW, I would've been fine with stashing all of this into drm.c as well
> since the rest of the UAPI is in that already. The churn in this patch
> is reasonably small, but it would've been even less if this was just all
> in drm.c.

I think we shouldn't have the uapi in drm.c -- it just makes the file a 
bit of a dumping ground. I think drm.c should have the code that relates 
to initialization and initial registration with DRM.

> 
>>   5 files changed, 401 insertions(+), 16 deletions(-)
>>   create mode 100644 drivers/gpu/drm/tegra/uapi.h
>>   create mode 100644 drivers/gpu/drm/tegra/uapi/uapi.c
>>
>> diff --git a/drivers/gpu/drm/tegra/Makefile b/drivers/gpu/drm/tegra/Makefile
>> index d6cf202414f0..0abdb21b38b9 100644
>> --- a/drivers/gpu/drm/tegra/Makefile
>> +++ b/drivers/gpu/drm/tegra/Makefile
>> @@ -3,6 +3,7 @@ ccflags-$(CONFIG_DRM_TEGRA_DEBUG) += -DDEBUG
>>   
>>   tegra-drm-y := \
>>   	drm.o \
>> +	uapi/uapi.o \
>>   	gem.o \
>>   	fb.o \
>>   	dp.o \
>> diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
>> index afd3f143c5e0..6a51035ce33f 100644
>> --- a/drivers/gpu/drm/tegra/drm.c
>> +++ b/drivers/gpu/drm/tegra/drm.c
>> @@ -20,6 +20,7 @@
>>   #include <drm/drm_prime.h>
>>   #include <drm/drm_vblank.h>
>>   
>> +#include "uapi.h"
>>   #include "drm.h"
>>   #include "gem.h"
>>   
>> @@ -33,11 +34,6 @@
>>   #define CARVEOUT_SZ SZ_64M
>>   #define CDMA_GATHER_FETCHES_MAX_NB 16383
>>   
>> -struct tegra_drm_file {
>> -	struct idr contexts;
>> -	struct mutex lock;
>> -};
>> -
>>   static int tegra_atomic_check(struct drm_device *drm,
>>   			      struct drm_atomic_state *state)
>>   {
>> @@ -90,7 +86,8 @@ static int tegra_drm_open(struct drm_device *drm, struct drm_file *filp)
>>   	if (!fpriv)
>>   		return -ENOMEM;
>>   
>> -	idr_init_base(&fpriv->contexts, 1);
>> +	idr_init_base(&fpriv->legacy_contexts, 1);
>> +	xa_init_flags(&fpriv->contexts, XA_FLAGS_ALLOC1);
>>   	mutex_init(&fpriv->lock);
>>   	filp->driver_priv = fpriv;
>>   
>> @@ -429,7 +426,7 @@ static int tegra_client_open(struct tegra_drm_file *fpriv,
>>   	if (err < 0)
>>   		return err;
>>   
>> -	err = idr_alloc(&fpriv->contexts, context, 1, 0, GFP_KERNEL);
>> +	err = idr_alloc(&fpriv->legacy_contexts, context, 1, 0, GFP_KERNEL);
>>   	if (err < 0) {
>>   		client->ops->close_channel(context);
>>   		return err;
>> @@ -484,13 +481,13 @@ static int tegra_close_channel(struct drm_device *drm, void *data,
>>   
>>   	mutex_lock(&fpriv->lock);
>>   
>> -	context = idr_find(&fpriv->contexts, args->context);
>> +	context = idr_find(&fpriv->legacy_contexts, args->context);
>>   	if (!context) {
>>   		err = -EINVAL;
>>   		goto unlock;
>>   	}
>>   
>> -	idr_remove(&fpriv->contexts, context->id);
>> +	idr_remove(&fpriv->legacy_contexts, context->id);
>>   	tegra_drm_context_free(context);
>>   
>>   unlock:
>> @@ -509,7 +506,7 @@ static int tegra_get_syncpt(struct drm_device *drm, void *data,
>>   
>>   	mutex_lock(&fpriv->lock);
>>   
>> -	context = idr_find(&fpriv->contexts, args->context);
>> +	context = idr_find(&fpriv->legacy_contexts, args->context);
>>   	if (!context) {
>>   		err = -ENODEV;
>>   		goto unlock;
>> @@ -538,7 +535,7 @@ static int tegra_submit(struct drm_device *drm, void *data,
>>   
>>   	mutex_lock(&fpriv->lock);
>>   
>> -	context = idr_find(&fpriv->contexts, args->context);
>> +	context = idr_find(&fpriv->legacy_contexts, args->context);
>>   	if (!context) {
>>   		err = -ENODEV;
>>   		goto unlock;
>> @@ -563,7 +560,7 @@ static int tegra_get_syncpt_base(struct drm_device *drm, void *data,
>>   
>>   	mutex_lock(&fpriv->lock);
>>   
>> -	context = idr_find(&fpriv->contexts, args->context);
>> +	context = idr_find(&fpriv->legacy_contexts, args->context);
>>   	if (!context) {
>>   		err = -ENODEV;
>>   		goto unlock;
>> @@ -732,10 +729,21 @@ static int tegra_gem_get_flags(struct drm_device *drm, void *data,
>>   
>>   static const struct drm_ioctl_desc tegra_drm_ioctls[] = {
>>   #ifdef CONFIG_DRM_TEGRA_STAGING
>> -	DRM_IOCTL_DEF_DRV(TEGRA_GEM_CREATE, tegra_gem_create,
>> +	DRM_IOCTL_DEF_DRV(TEGRA_CHANNEL_OPEN, tegra_drm_ioctl_channel_open,
>> +			  DRM_RENDER_ALLOW),
>> +	DRM_IOCTL_DEF_DRV(TEGRA_CHANNEL_CLOSE, tegra_drm_ioctl_channel_close,
>> +			  DRM_RENDER_ALLOW),
> 
> I'd prefer to keep call these TEGRA_OPEN_CHANNEL and TEGRA_CLOSE_CHANNEL
> because I find that easier to think of. My reasoning goes: the TEGRA_
> prefix means we're operating at a global context and then we perform the
> OPEN_CHANNEL and CLOSE_CHANNEL operations. Whereas by the same reasoning
> TEGRA_CHANNEL_OPEN and TEGRA_CHANNEL_CLOSE suggest we're operating at
> the channel context and perform OPEN and CLOSE operations. For close you
> could make the argument that it makes sense, but you can't open a
> channel that you don't have yet.

I go by the same argument but consider TEGRA_CHANNEL_OPEN a bit of a 
"static method" of channels, and as such acceptable :p But I do see your 
point -- I can change it.

> 
> And if that doesn't convince you, I think appending _LEGACY here like we
> do for CREATE and MMAP would be more consistent. Who's going to remember
> which one is new: TEGRA_CHANNEL_OPEN or TEGRA_OPEN_CHANNEL?
> 
>> +	DRM_IOCTL_DEF_DRV(TEGRA_CHANNEL_MAP, tegra_drm_ioctl_channel_map,
>>   			  DRM_RENDER_ALLOW),
>> -	DRM_IOCTL_DEF_DRV(TEGRA_GEM_MMAP, tegra_gem_mmap,
>> +	DRM_IOCTL_DEF_DRV(TEGRA_CHANNEL_UNMAP, tegra_drm_ioctl_channel_unmap,
>>   			  DRM_RENDER_ALLOW),
>> +	DRM_IOCTL_DEF_DRV(TEGRA_GEM_CREATE, tegra_drm_ioctl_gem_create,
>> +			  DRM_RENDER_ALLOW),
>> +	DRM_IOCTL_DEF_DRV(TEGRA_GEM_MMAP, tegra_drm_ioctl_gem_mmap,
>> +			  DRM_RENDER_ALLOW),
>> +
>> +	DRM_IOCTL_DEF_DRV(TEGRA_GEM_CREATE_LEGACY, tegra_gem_create, DRM_RENDER_ALLOW),
>> +	DRM_IOCTL_DEF_DRV(TEGRA_GEM_MMAP_LEGACY, tegra_gem_mmap, DRM_RENDER_ALLOW),
>>   	DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_READ, tegra_syncpt_read,
>>   			  DRM_RENDER_ALLOW),
>>   	DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_INCR, tegra_syncpt_incr,
>> @@ -789,10 +797,11 @@ static void tegra_drm_postclose(struct drm_device *drm, struct drm_file *file)
>>   	struct tegra_drm_file *fpriv = file->driver_priv;
>>   
>>   	mutex_lock(&fpriv->lock);
>> -	idr_for_each(&fpriv->contexts, tegra_drm_context_cleanup, NULL);
>> +	idr_for_each(&fpriv->legacy_contexts, tegra_drm_context_cleanup, NULL);
>> +	tegra_drm_uapi_close_file(fpriv);
>>   	mutex_unlock(&fpriv->lock);
>>   
>> -	idr_destroy(&fpriv->contexts);
>> +	idr_destroy(&fpriv->legacy_contexts);
>>   	mutex_destroy(&fpriv->lock);
>>   	kfree(fpriv);
>>   }
>> diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h
>> index 0f38f159aa8e..1af57c2016eb 100644
>> --- a/drivers/gpu/drm/tegra/drm.h
>> +++ b/drivers/gpu/drm/tegra/drm.h
>> @@ -59,6 +59,11 @@ struct tegra_drm {
>>   	struct tegra_display_hub *hub;
>>   };
>>   
>> +static inline struct host1x *tegra_drm_to_host1x(struct tegra_drm *tegra)
>> +{
>> +	return dev_get_drvdata(tegra->drm->dev->parent);
>> +}
>> +
>>   struct tegra_drm_client;
>>   
>>   struct tegra_drm_context {
>> diff --git a/drivers/gpu/drm/tegra/uapi.h b/drivers/gpu/drm/tegra/uapi.h
>> new file mode 100644
>> index 000000000000..5c422607e8fa
>> --- /dev/null
>> +++ b/drivers/gpu/drm/tegra/uapi.h
>> @@ -0,0 +1,63 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/* Copyright (c) 2020 NVIDIA Corporation */
>> +
>> +#ifndef _TEGRA_DRM_UAPI_H
>> +#define _TEGRA_DRM_UAPI_H
>> +
>> +#include <linux/dma-mapping.h>
>> +#include <linux/idr.h>
>> +#include <linux/kref.h>
>> +#include <linux/xarray.h>
>> +
>> +#include <drm/drm.h>
>> +
>> +struct drm_file;
>> +struct drm_device;
>> +
>> +struct tegra_drm_file {
>> +	/* Legacy UAPI state */
>> +	struct idr legacy_contexts;
>> +	struct mutex lock;
>> +
>> +	/* New UAPI state */
>> +	struct xarray contexts;
>> +};
>> +
>> +struct tegra_drm_channel_ctx {
>> +	struct tegra_drm_client *client;
>> +	struct host1x_channel *channel;
>> +	struct xarray mappings;
>> +};
> 
> This is mostly the same as tegra_drm_context, so can't we just merge the
> two? There's going to be slight overlap, but overall things are going to
> be less confusing to follow.
> 
> Even more so because I think we should consider phasing out the old UAPI
> eventually and then we can just remove the unneeded fields from this.

Okay.

> 
>> +
>> +struct tegra_drm_mapping {
>> +	struct kref ref;
>> +
>> +	struct device *dev;
>> +	struct host1x_bo *bo;
>> +	struct sg_table *sgt;
>> +	enum dma_data_direction direction;
>> +	dma_addr_t iova;
>> +	dma_addr_t iova_end;
> 
> iova_end seems to never be used. Do we need it?

It is used in the firewall.

> 
>> +};
>> +
>> +int tegra_drm_ioctl_channel_open(struct drm_device *drm, void *data,
>> +				 struct drm_file *file);
>> +int tegra_drm_ioctl_channel_close(struct drm_device *drm, void *data,
>> +				  struct drm_file *file);
>> +int tegra_drm_ioctl_channel_map(struct drm_device *drm, void *data,
>> +				struct drm_file *file);
>> +int tegra_drm_ioctl_channel_unmap(struct drm_device *drm, void *data,
>> +				struct drm_file *file);
>> +int tegra_drm_ioctl_channel_submit(struct drm_device *drm, void *data,
>> +				   struct drm_file *file);
>> +int tegra_drm_ioctl_gem_create(struct drm_device *drm, void *data,
>> +				struct drm_file *file);
>> +int tegra_drm_ioctl_gem_mmap(struct drm_device *drm, void *data,
>> +				struct drm_file *file);
>> +
>> +void tegra_drm_uapi_close_file(struct tegra_drm_file *file);
>> +void tegra_drm_mapping_put(struct tegra_drm_mapping *mapping);
>> +struct tegra_drm_channel_ctx *
>> +tegra_drm_channel_ctx_lock(struct tegra_drm_file *file, u32 id);
>> +
>> +#endif
>> diff --git a/drivers/gpu/drm/tegra/uapi/uapi.c b/drivers/gpu/drm/tegra/uapi/uapi.c
>> new file mode 100644
>> index 000000000000..d503b5e817c4
>> --- /dev/null
>> +++ b/drivers/gpu/drm/tegra/uapi/uapi.c
>> @@ -0,0 +1,307 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/* Copyright (c) 2020 NVIDIA Corporation */
>> +
>> +#include <linux/host1x.h>
>> +#include <linux/iommu.h>
>> +#include <linux/list.h>
>> +
>> +#include <drm/drm_drv.h>
>> +#include <drm/drm_file.h>
>> +
>> +#include "../uapi.h"
>> +#include "../drm.h"
>> +
>> +struct tegra_drm_channel_ctx *
>> +tegra_drm_channel_ctx_lock(struct tegra_drm_file *file, u32 id)
>> +{
>> +	struct tegra_drm_channel_ctx *ctx;
>> +
>> +	mutex_lock(&file->lock);
>> +	ctx = xa_load(&file->contexts, id);
>> +	if (!ctx)
>> +		mutex_unlock(&file->lock);
>> +
>> +	return ctx;
>> +}
> 
> This interface seems slightly odd. Looking at how this is used I see how
> doing it this way saves a couple of lines. However, it also make this
> difficult to understand, so I wonder if it wouldn't be better to just
> open-code this in the three callsites to make the code flow a bit more
> idiomatic.

Ok, will do. (Another option may be to add a 
tegra_drm_channel_ctx_unlock that just unlocks file->lock -- that'd 
abstract it out even better, which I quite like -- but I'll go with your 
preference)

> 
>> +
>> +static void tegra_drm_mapping_release(struct kref *ref)
>> +{
>> +	struct tegra_drm_mapping *mapping =
>> +		container_of(ref, struct tegra_drm_mapping, ref);
>> +
>> +	if (mapping->sgt)
>> +		dma_unmap_sgtable(mapping->dev, mapping->sgt,
>> +				  mapping->direction, DMA_ATTR_SKIP_CPU_SYNC);
>> +
>> +	host1x_bo_unpin(mapping->dev, mapping->bo, mapping->sgt);
>> +	host1x_bo_put(mapping->bo);
>> +
>> +	kfree(mapping);
>> +}
>> +
>> +void tegra_drm_mapping_put(struct tegra_drm_mapping *mapping)
>> +{
>> +	kref_put(&mapping->ref, tegra_drm_mapping_release);
>> +}
>> +
>> +static void tegra_drm_channel_ctx_close(struct tegra_drm_channel_ctx *ctx)
> 
> Yeah, the more often I read it, the more I'm in favour of just
> collapsing tegra_drm_channel_ctx into tegra_drm_channel if for nothing
> else but to get rid of that annoying _ctx suffix that's there for no
> other reason than to differentiate it from "legacy" contexts.
> 
>> +{
>> +	unsigned long mapping_id;
> 
> It's clear from the context that this is a mapping ID, so I think you
> can just leave out the "mapping_" prefix to save a bit on screen space.

Sure.

> 
>> +	struct tegra_drm_mapping *mapping;
>> +
>> +	xa_for_each(&ctx->mappings, mapping_id, mapping)
>> +		tegra_drm_mapping_put(mapping);
>> +
>> +	xa_destroy(&ctx->mappings);
>> +
>> +	host1x_channel_put(ctx->channel);
>> +
>> +	kfree(ctx);
>> +}
>> +
>> +int close_channel_ctx(int id, void *p, void *data)
>> +{
>> +	struct tegra_drm_channel_ctx *ctx = p;
>> +
>> +	tegra_drm_channel_ctx_close(ctx);
>> +
>> +	return 0;
>> +}
> 
> The signature looked strange, so I went looking for where this is called
> from and turns out I can't find any place where this is used. Do we need
> it?

Ah, maybe I have left it from some previous version. Will fix.

> 
>> +
>> +void tegra_drm_uapi_close_file(struct tegra_drm_file *file)
>> +{
>> +	unsigned long ctx_id;
> 
> Just like for mappings above, I think it's fine to leave out the ctx_
> prefix here.

Yep.

> 
>> +	struct tegra_drm_channel_ctx *ctx;
>> +
>> +	xa_for_each(&file->contexts, ctx_id, ctx)
>> +		tegra_drm_channel_ctx_close(ctx);
>> +
>> +	xa_destroy(&file->contexts);
>> +}
>> +
>> +int tegra_drm_ioctl_channel_open(struct drm_device *drm, void *data,
>> +				 struct drm_file *file)
>> +{
>> +	struct tegra_drm_file *fpriv = file->driver_priv;
>> +	struct tegra_drm *tegra = drm->dev_private;
>> +	struct drm_tegra_channel_open *args = data;
>> +	struct tegra_drm_client *client = NULL;
>> +	struct tegra_drm_channel_ctx *ctx;
>> +	int err;
>> +
>> +	if (args->flags)
>> +		return -EINVAL;
>> +
>> +	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
>> +	if (!ctx)
>> +		return -ENOMEM;
>> +
>> +	err = -ENODEV;
>> +	list_for_each_entry(client, &tegra->clients, list) {
>> +		if (client->base.class == args->host1x_class) {
>> +			err = 0;
>> +			break;
>> +		}
>> +	}
>> +	if (err)
>> +		goto free_ctx;
> 
> This type of construct looks weird. I found that a good way around this
> is to split this off into a separate function that does the lookup and
> just returns NULL when it doesn't find one, which is very elegant:
> 
> 	struct tegra_drm_client *tegra_drm_find_client(struct tegra_drm *tegra, u32 class)
> 	{
> 		struct tegra_drm_client *client;
> 
> 		list_for_each_entry(client, &tegra->clients, list)
> 			if (client->base.class == class)
> 				return client;
> 
> 		return NULL;
> 	}
> 
> and then all of a sudden, the very cumbersome construct above becomes
> this pretty piece of code:
> 
> 	client = tegra_drm_find_client(tegra, args->host1x_class);
> 	if (!client) {
> 		err = -ENODEV;
> 		goto free_ctx;
> 	}
> 
> No need for initializing client to NULL or preventatively setting err =
> -ENODEV or anything.

Yep.

> 
>> +
>> +	if (client->shared_channel) {
>> +		ctx->channel = host1x_channel_get(client->shared_channel);
>> +	} else {
>> +		ctx->channel = host1x_channel_request(&client->base);
>> +		if (!ctx->channel) {
>> +			err = -EBUSY;
> 
> I -EBUSY really appropriate here? Can host1x_channel_request() fail for
> other reasons?

It could also fail due to being out of memory (failing to allocate space 
for CDMA) - I guess we should plumb the error code here. But -EBUSY is 
really the most likely thing to happen anyway. Perhaps that can be done 
separately.

> 
>> +			goto free_ctx;
>> +		}
>> +	}
>> +
>> +	err = xa_alloc(&fpriv->contexts, &args->channel_ctx, ctx,
>> +		       XA_LIMIT(1, U32_MAX), GFP_KERNEL);
>> +	if (err < 0)
>> +		goto put_channel;
>> +
>> +	ctx->client = client;
>> +	xa_init_flags(&ctx->mappings, XA_FLAGS_ALLOC1);
>> +
>> +	args->hardware_version = client->version;
>> +
>> +	return 0;
>> +
>> +put_channel:
>> +	host1x_channel_put(ctx->channel);
>> +free_ctx:
>> +	kfree(ctx);
>> +
>> +	return err;
>> +}
>> +
>> +int tegra_drm_ioctl_channel_close(struct drm_device *drm, void *data,
>> +				  struct drm_file *file)
>> +{
>> +	struct tegra_drm_file *fpriv = file->driver_priv;
>> +	struct drm_tegra_channel_close *args = data;
>> +	struct tegra_drm_channel_ctx *ctx;
>> +
>> +	ctx = tegra_drm_channel_ctx_lock(fpriv, args->channel_ctx);
>> +	if (!ctx)
>> +		return -EINVAL;
>> +
>> +	xa_erase(&fpriv->contexts, args->channel_ctx);
>> +
>> +	mutex_unlock(&fpriv->lock);
>> +
>> +	tegra_drm_channel_ctx_close(ctx);
>> +
>> +	return 0;
>> +}
>> +
>> +int tegra_drm_ioctl_channel_map(struct drm_device *drm, void *data,
>> +				struct drm_file *file)
>> +{
>> +	struct tegra_drm_file *fpriv = file->driver_priv;
>> +	struct drm_tegra_channel_map *args = data;
>> +	struct tegra_drm_channel_ctx *ctx;
>> +	struct tegra_drm_mapping *mapping;
>> +	struct drm_gem_object *gem;
>> +	u32 mapping_id;
>> +	int err = 0;
>> +
>> +	if (args->flags & ~DRM_TEGRA_CHANNEL_MAP_READWRITE)
>> +		return -EINVAL;
>> +
>> +	ctx = tegra_drm_channel_ctx_lock(fpriv, args->channel_ctx);
>> +	if (!ctx)
>> +		return -EINVAL;
>> +
>> +	mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
>> +	if (!mapping) {
>> +		err = -ENOMEM;
>> +		goto unlock;
>> +	}
>> +
>> +	kref_init(&mapping->ref);
>> +
>> +	gem = drm_gem_object_lookup(file, args->handle);
>> +	if (!gem) {
>> +		err = -EINVAL;
>> +		goto unlock;
>> +	}
>> +
>> +	mapping->dev = ctx->client->base.dev;
>> +	mapping->bo = &container_of(gem, struct tegra_bo, gem)->base;
> 
> We already have host1x_bo_lookup() in drm.c that you can use to avoid
> this strange cast.

Okay, will fix.

> 
>> +
>> +	if (!iommu_get_domain_for_dev(mapping->dev) ||
>> +	    ctx->client->base.group) {
> 
> This expression is now used in at least two places, so I wonder if we
> should have a helper for it along with some documentation about why this
> is the right thing to do. I have a local patch that adds a comment to
> the other instance of this because I had forgotten why this was correct,
> so I can pick that up and refactor later on.

Actually, just last week I found out that the condition here is wrong 
(at least for this particular instance) -- with the current condition, 
if IOMMU is disabled we end up in the first branch, but if the BO in 
question was imported through DMA-BUF the iova will be NULL - 
host1x_bo_pin returns an SGT instead, so we need to go to the else path, 
which works fine. (If ctx->client->base.group is set, this is not a 
problem since import will IOMMU map the BO and set iova). I have a local 
fix for this which I'll add to v6.

> 
>> +		host1x_bo_pin(mapping->dev, mapping->bo,
>> +			      &mapping->iova);
>> +	} else {
>> +		mapping->direction = DMA_TO_DEVICE;
>> +		if (args->flags & DRM_TEGRA_CHANNEL_MAP_READWRITE)
>> +			mapping->direction = DMA_BIDIRECTIONAL;
>> +
>> +		mapping->sgt =
>> +			host1x_bo_pin(mapping->dev, mapping->bo, NULL);
>> +		if (IS_ERR(mapping->sgt)) {
>> +			err = PTR_ERR(mapping->sgt);
>> +			goto put_gem;
>> +		}
>> +
>> +		err = dma_map_sgtable(mapping->dev, mapping->sgt,
>> +				      mapping->direction,
>> +				      DMA_ATTR_SKIP_CPU_SYNC);
>> +		if (err)
>> +			goto unpin;
>> +
>> +		/* TODO only map the requested part */
>> +		mapping->iova = sg_dma_address(mapping->sgt->sgl);
> 
> That comment seems misplaced here since the mapping already happens
> above. Also, wouldn't the same TODO apply to the host1x_bo_pin() path in
> the if block? Maybe the TODO should be at the top of the function?
> 
> Alternatively, if this isn't implemented in this patch anyway, maybe
> just drop the comment altogether. In order to implement this, wouldn't
> the UAPI have to change as well? In that case it might be better to add
> the TODO somewhere in the UAPI header, or in a separate TODO file in the
> driver's directory.

Yeah, I'll drop the comment. The UAPI originally had support for this 
but I dropped it upon Dmitry's objection.

> 
>> +	}
>> +
>> +	mapping->iova_end = mapping->iova + gem->size;
>> +
>> +	mutex_unlock(&fpriv->lock);
>> +
>> +	err = xa_alloc(&ctx->mappings, &mapping_id, mapping,
>> +		       XA_LIMIT(1, U32_MAX), GFP_KERNEL);
>> +	if (err < 0)
>> +		goto unmap;
>> +
>> +	args->mapping_id = mapping_id;
>> +
>> +	return 0;
>> +
>> +unmap:
>> +	if (mapping->sgt) {
>> +		dma_unmap_sgtable(mapping->dev, mapping->sgt,
>> +				  mapping->direction, DMA_ATTR_SKIP_CPU_SYNC);
>> +	}
>> +unpin:
>> +	host1x_bo_unpin(mapping->dev, mapping->bo, mapping->sgt);
>> +put_gem:
>> +	drm_gem_object_put(gem);
>> +	kfree(mapping);
>> +unlock:
>> +	mutex_unlock(&fpriv->lock);
>> +	return err;
>> +}
>> +
>> +int tegra_drm_ioctl_channel_unmap(struct drm_device *drm, void *data,
>> +				  struct drm_file *file)
>> +{
>> +	struct tegra_drm_file *fpriv = file->driver_priv;
>> +	struct drm_tegra_channel_unmap *args = data;
>> +	struct tegra_drm_channel_ctx *ctx;
>> +	struct tegra_drm_mapping *mapping;
>> +
>> +	ctx = tegra_drm_channel_ctx_lock(fpriv, args->channel_ctx);
>> +	if (!ctx)
>> +		return -EINVAL;
>> +
>> +	mapping = xa_erase(&ctx->mappings, args->mapping_id);
>> +
>> +	mutex_unlock(&fpriv->lock);
>> +
>> +	if (mapping) {
>> +		tegra_drm_mapping_put(mapping);
>> +		return 0;
>> +	} else {
>> +		return -EINVAL;
>> +	}
>> +}
>> +
>> +int tegra_drm_ioctl_gem_create(struct drm_device *drm, void *data,
>> +			       struct drm_file *file)
>> +{
>> +	struct drm_tegra_gem_create *args = data;
>> +	struct tegra_bo *bo;
>> +
>> +	if (args->flags)
>> +		return -EINVAL;
> 
> I'm not sure it's worth doing this, especially because this is now a new
> IOCTL that's actually a subset of the original. I think we should just
> keep the original and if we want to deprecate the flags, or replace them
> with new ones, let's just try and phase out the deprecated ones.

Ok, I'll look into it.

> 
> Thierry

Thanks,
Mikko

> 
>> +
>> +	bo = tegra_bo_create_with_handle(file, drm, args->size, args->flags,
>> +					 &args->handle);
>> +	if (IS_ERR(bo))
>> +		return PTR_ERR(bo);
>> +
>> +	return 0;
>> +}
>> +
>> +int tegra_drm_ioctl_gem_mmap(struct drm_device *drm, void *data,
>> +			     struct drm_file *file)
>> +{
>> +	struct drm_tegra_gem_mmap *args = data;
>> +	struct drm_gem_object *gem;
>> +	struct tegra_bo *bo;
>> +
>> +	gem = drm_gem_object_lookup(file, args->handle);
>> +	if (!gem)
>> +		return -EINVAL;
>> +
>> +	bo = to_tegra_bo(gem);
>> +
>> +	args->offset = drm_vma_node_offset_addr(&bo->gem.vma_node);
>> +
>> +	drm_gem_object_put(gem);
>> +
>> +	return 0;
>> +}
>> -- 
>> 2.30.0
>>

WARNING: multiple messages have this Message-ID (diff)
From: Mikko Perttunen <cyndis@kapsi.fi>
To: Thierry Reding <thierry.reding@gmail.com>,
	Mikko Perttunen <mperttunen@nvidia.com>
Cc: airlied@linux.ie, dri-devel@lists.freedesktop.org,
	jonathanh@nvidia.com, talho@nvidia.com, bhuntsman@nvidia.com,
	linux-tegra@vger.kernel.org, digetx@gmail.com
Subject: Re: [PATCH v5 19/21] drm/tegra: Implement new UAPI
Date: Tue, 23 Mar 2021 16:43:03 +0200	[thread overview]
Message-ID: <494e3858-5b29-0b44-f2eb-7a7cc16ff325@kapsi.fi> (raw)
In-Reply-To: <YFnsQNiLg/5I/qKA@orome.fritz.box>

On 3/23/21 3:25 PM, Thierry Reding wrote:
> On Mon, Jan 11, 2021 at 03:00:17PM +0200, Mikko Perttunen wrote:
>> Implement the non-submission parts of the new UAPI, including
>> channel management and memory mapping. The UAPI is under the
>> CONFIG_DRM_TEGRA_STAGING config flag for now.
>>
>> Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
>> ---
>> v5:
>> * Set iova_end in both mapping paths
>> v4:
>> * New patch, split out from combined UAPI + submit patch.
>> ---
>>   drivers/gpu/drm/tegra/Makefile    |   1 +
>>   drivers/gpu/drm/tegra/drm.c       |  41 ++--
>>   drivers/gpu/drm/tegra/drm.h       |   5 +
>>   drivers/gpu/drm/tegra/uapi.h      |  63 ++++++
>>   drivers/gpu/drm/tegra/uapi/uapi.c | 307 ++++++++++++++++++++++++++++++
> 
> I'd prefer if we kept the directory structure flat. There's something
> like 19 pairs of files in the top-level directory, which is reasonably
> manageable. Also, it looks like there's going to be a couple more files
> in this new subdirectory. I'd prefer if that was all merged into the
> single uapi.c source file to keep things simpler. These are all really
> small files, so there's no need to aggressively split things up. Helps
> with compilation time, too.

Will do, although I think having plenty of subdirectories makes things 
more organized :)

> 
> FWIW, I would've been fine with stashing all of this into drm.c as well
> since the rest of the UAPI is in that already. The churn in this patch
> is reasonably small, but it would've been even less if this was just all
> in drm.c.

I think we shouldn't have the uapi in drm.c -- it just makes the file a 
bit of a dumping ground. I think drm.c should have the code that relates 
to initialization and initial registration with DRM.

> 
>>   5 files changed, 401 insertions(+), 16 deletions(-)
>>   create mode 100644 drivers/gpu/drm/tegra/uapi.h
>>   create mode 100644 drivers/gpu/drm/tegra/uapi/uapi.c
>>
>> diff --git a/drivers/gpu/drm/tegra/Makefile b/drivers/gpu/drm/tegra/Makefile
>> index d6cf202414f0..0abdb21b38b9 100644
>> --- a/drivers/gpu/drm/tegra/Makefile
>> +++ b/drivers/gpu/drm/tegra/Makefile
>> @@ -3,6 +3,7 @@ ccflags-$(CONFIG_DRM_TEGRA_DEBUG) += -DDEBUG
>>   
>>   tegra-drm-y := \
>>   	drm.o \
>> +	uapi/uapi.o \
>>   	gem.o \
>>   	fb.o \
>>   	dp.o \
>> diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
>> index afd3f143c5e0..6a51035ce33f 100644
>> --- a/drivers/gpu/drm/tegra/drm.c
>> +++ b/drivers/gpu/drm/tegra/drm.c
>> @@ -20,6 +20,7 @@
>>   #include <drm/drm_prime.h>
>>   #include <drm/drm_vblank.h>
>>   
>> +#include "uapi.h"
>>   #include "drm.h"
>>   #include "gem.h"
>>   
>> @@ -33,11 +34,6 @@
>>   #define CARVEOUT_SZ SZ_64M
>>   #define CDMA_GATHER_FETCHES_MAX_NB 16383
>>   
>> -struct tegra_drm_file {
>> -	struct idr contexts;
>> -	struct mutex lock;
>> -};
>> -
>>   static int tegra_atomic_check(struct drm_device *drm,
>>   			      struct drm_atomic_state *state)
>>   {
>> @@ -90,7 +86,8 @@ static int tegra_drm_open(struct drm_device *drm, struct drm_file *filp)
>>   	if (!fpriv)
>>   		return -ENOMEM;
>>   
>> -	idr_init_base(&fpriv->contexts, 1);
>> +	idr_init_base(&fpriv->legacy_contexts, 1);
>> +	xa_init_flags(&fpriv->contexts, XA_FLAGS_ALLOC1);
>>   	mutex_init(&fpriv->lock);
>>   	filp->driver_priv = fpriv;
>>   
>> @@ -429,7 +426,7 @@ static int tegra_client_open(struct tegra_drm_file *fpriv,
>>   	if (err < 0)
>>   		return err;
>>   
>> -	err = idr_alloc(&fpriv->contexts, context, 1, 0, GFP_KERNEL);
>> +	err = idr_alloc(&fpriv->legacy_contexts, context, 1, 0, GFP_KERNEL);
>>   	if (err < 0) {
>>   		client->ops->close_channel(context);
>>   		return err;
>> @@ -484,13 +481,13 @@ static int tegra_close_channel(struct drm_device *drm, void *data,
>>   
>>   	mutex_lock(&fpriv->lock);
>>   
>> -	context = idr_find(&fpriv->contexts, args->context);
>> +	context = idr_find(&fpriv->legacy_contexts, args->context);
>>   	if (!context) {
>>   		err = -EINVAL;
>>   		goto unlock;
>>   	}
>>   
>> -	idr_remove(&fpriv->contexts, context->id);
>> +	idr_remove(&fpriv->legacy_contexts, context->id);
>>   	tegra_drm_context_free(context);
>>   
>>   unlock:
>> @@ -509,7 +506,7 @@ static int tegra_get_syncpt(struct drm_device *drm, void *data,
>>   
>>   	mutex_lock(&fpriv->lock);
>>   
>> -	context = idr_find(&fpriv->contexts, args->context);
>> +	context = idr_find(&fpriv->legacy_contexts, args->context);
>>   	if (!context) {
>>   		err = -ENODEV;
>>   		goto unlock;
>> @@ -538,7 +535,7 @@ static int tegra_submit(struct drm_device *drm, void *data,
>>   
>>   	mutex_lock(&fpriv->lock);
>>   
>> -	context = idr_find(&fpriv->contexts, args->context);
>> +	context = idr_find(&fpriv->legacy_contexts, args->context);
>>   	if (!context) {
>>   		err = -ENODEV;
>>   		goto unlock;
>> @@ -563,7 +560,7 @@ static int tegra_get_syncpt_base(struct drm_device *drm, void *data,
>>   
>>   	mutex_lock(&fpriv->lock);
>>   
>> -	context = idr_find(&fpriv->contexts, args->context);
>> +	context = idr_find(&fpriv->legacy_contexts, args->context);
>>   	if (!context) {
>>   		err = -ENODEV;
>>   		goto unlock;
>> @@ -732,10 +729,21 @@ static int tegra_gem_get_flags(struct drm_device *drm, void *data,
>>   
>>   static const struct drm_ioctl_desc tegra_drm_ioctls[] = {
>>   #ifdef CONFIG_DRM_TEGRA_STAGING
>> -	DRM_IOCTL_DEF_DRV(TEGRA_GEM_CREATE, tegra_gem_create,
>> +	DRM_IOCTL_DEF_DRV(TEGRA_CHANNEL_OPEN, tegra_drm_ioctl_channel_open,
>> +			  DRM_RENDER_ALLOW),
>> +	DRM_IOCTL_DEF_DRV(TEGRA_CHANNEL_CLOSE, tegra_drm_ioctl_channel_close,
>> +			  DRM_RENDER_ALLOW),
> 
> I'd prefer to keep call these TEGRA_OPEN_CHANNEL and TEGRA_CLOSE_CHANNEL
> because I find that easier to think of. My reasoning goes: the TEGRA_
> prefix means we're operating at a global context and then we perform the
> OPEN_CHANNEL and CLOSE_CHANNEL operations. Whereas by the same reasoning
> TEGRA_CHANNEL_OPEN and TEGRA_CHANNEL_CLOSE suggest we're operating at
> the channel context and perform OPEN and CLOSE operations. For close you
> could make the argument that it makes sense, but you can't open a
> channel that you don't have yet.

I go by the same argument but consider TEGRA_CHANNEL_OPEN a bit of a 
"static method" of channels, and as such acceptable :p But I do see your 
point -- I can change it.

> 
> And if that doesn't convince you, I think appending _LEGACY here like we
> do for CREATE and MMAP would be more consistent. Who's going to remember
> which one is new: TEGRA_CHANNEL_OPEN or TEGRA_OPEN_CHANNEL?
> 
>> +	DRM_IOCTL_DEF_DRV(TEGRA_CHANNEL_MAP, tegra_drm_ioctl_channel_map,
>>   			  DRM_RENDER_ALLOW),
>> -	DRM_IOCTL_DEF_DRV(TEGRA_GEM_MMAP, tegra_gem_mmap,
>> +	DRM_IOCTL_DEF_DRV(TEGRA_CHANNEL_UNMAP, tegra_drm_ioctl_channel_unmap,
>>   			  DRM_RENDER_ALLOW),
>> +	DRM_IOCTL_DEF_DRV(TEGRA_GEM_CREATE, tegra_drm_ioctl_gem_create,
>> +			  DRM_RENDER_ALLOW),
>> +	DRM_IOCTL_DEF_DRV(TEGRA_GEM_MMAP, tegra_drm_ioctl_gem_mmap,
>> +			  DRM_RENDER_ALLOW),
>> +
>> +	DRM_IOCTL_DEF_DRV(TEGRA_GEM_CREATE_LEGACY, tegra_gem_create, DRM_RENDER_ALLOW),
>> +	DRM_IOCTL_DEF_DRV(TEGRA_GEM_MMAP_LEGACY, tegra_gem_mmap, DRM_RENDER_ALLOW),
>>   	DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_READ, tegra_syncpt_read,
>>   			  DRM_RENDER_ALLOW),
>>   	DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_INCR, tegra_syncpt_incr,
>> @@ -789,10 +797,11 @@ static void tegra_drm_postclose(struct drm_device *drm, struct drm_file *file)
>>   	struct tegra_drm_file *fpriv = file->driver_priv;
>>   
>>   	mutex_lock(&fpriv->lock);
>> -	idr_for_each(&fpriv->contexts, tegra_drm_context_cleanup, NULL);
>> +	idr_for_each(&fpriv->legacy_contexts, tegra_drm_context_cleanup, NULL);
>> +	tegra_drm_uapi_close_file(fpriv);
>>   	mutex_unlock(&fpriv->lock);
>>   
>> -	idr_destroy(&fpriv->contexts);
>> +	idr_destroy(&fpriv->legacy_contexts);
>>   	mutex_destroy(&fpriv->lock);
>>   	kfree(fpriv);
>>   }
>> diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h
>> index 0f38f159aa8e..1af57c2016eb 100644
>> --- a/drivers/gpu/drm/tegra/drm.h
>> +++ b/drivers/gpu/drm/tegra/drm.h
>> @@ -59,6 +59,11 @@ struct tegra_drm {
>>   	struct tegra_display_hub *hub;
>>   };
>>   
>> +static inline struct host1x *tegra_drm_to_host1x(struct tegra_drm *tegra)
>> +{
>> +	return dev_get_drvdata(tegra->drm->dev->parent);
>> +}
>> +
>>   struct tegra_drm_client;
>>   
>>   struct tegra_drm_context {
>> diff --git a/drivers/gpu/drm/tegra/uapi.h b/drivers/gpu/drm/tegra/uapi.h
>> new file mode 100644
>> index 000000000000..5c422607e8fa
>> --- /dev/null
>> +++ b/drivers/gpu/drm/tegra/uapi.h
>> @@ -0,0 +1,63 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/* Copyright (c) 2020 NVIDIA Corporation */
>> +
>> +#ifndef _TEGRA_DRM_UAPI_H
>> +#define _TEGRA_DRM_UAPI_H
>> +
>> +#include <linux/dma-mapping.h>
>> +#include <linux/idr.h>
>> +#include <linux/kref.h>
>> +#include <linux/xarray.h>
>> +
>> +#include <drm/drm.h>
>> +
>> +struct drm_file;
>> +struct drm_device;
>> +
>> +struct tegra_drm_file {
>> +	/* Legacy UAPI state */
>> +	struct idr legacy_contexts;
>> +	struct mutex lock;
>> +
>> +	/* New UAPI state */
>> +	struct xarray contexts;
>> +};
>> +
>> +struct tegra_drm_channel_ctx {
>> +	struct tegra_drm_client *client;
>> +	struct host1x_channel *channel;
>> +	struct xarray mappings;
>> +};
> 
> This is mostly the same as tegra_drm_context, so can't we just merge the
> two? There's going to be slight overlap, but overall things are going to
> be less confusing to follow.
> 
> Even more so because I think we should consider phasing out the old UAPI
> eventually and then we can just remove the unneeded fields from this.

Okay.

> 
>> +
>> +struct tegra_drm_mapping {
>> +	struct kref ref;
>> +
>> +	struct device *dev;
>> +	struct host1x_bo *bo;
>> +	struct sg_table *sgt;
>> +	enum dma_data_direction direction;
>> +	dma_addr_t iova;
>> +	dma_addr_t iova_end;
> 
> iova_end seems to never be used. Do we need it?

It is used in the firewall.

> 
>> +};
>> +
>> +int tegra_drm_ioctl_channel_open(struct drm_device *drm, void *data,
>> +				 struct drm_file *file);
>> +int tegra_drm_ioctl_channel_close(struct drm_device *drm, void *data,
>> +				  struct drm_file *file);
>> +int tegra_drm_ioctl_channel_map(struct drm_device *drm, void *data,
>> +				struct drm_file *file);
>> +int tegra_drm_ioctl_channel_unmap(struct drm_device *drm, void *data,
>> +				struct drm_file *file);
>> +int tegra_drm_ioctl_channel_submit(struct drm_device *drm, void *data,
>> +				   struct drm_file *file);
>> +int tegra_drm_ioctl_gem_create(struct drm_device *drm, void *data,
>> +				struct drm_file *file);
>> +int tegra_drm_ioctl_gem_mmap(struct drm_device *drm, void *data,
>> +				struct drm_file *file);
>> +
>> +void tegra_drm_uapi_close_file(struct tegra_drm_file *file);
>> +void tegra_drm_mapping_put(struct tegra_drm_mapping *mapping);
>> +struct tegra_drm_channel_ctx *
>> +tegra_drm_channel_ctx_lock(struct tegra_drm_file *file, u32 id);
>> +
>> +#endif
>> diff --git a/drivers/gpu/drm/tegra/uapi/uapi.c b/drivers/gpu/drm/tegra/uapi/uapi.c
>> new file mode 100644
>> index 000000000000..d503b5e817c4
>> --- /dev/null
>> +++ b/drivers/gpu/drm/tegra/uapi/uapi.c
>> @@ -0,0 +1,307 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/* Copyright (c) 2020 NVIDIA Corporation */
>> +
>> +#include <linux/host1x.h>
>> +#include <linux/iommu.h>
>> +#include <linux/list.h>
>> +
>> +#include <drm/drm_drv.h>
>> +#include <drm/drm_file.h>
>> +
>> +#include "../uapi.h"
>> +#include "../drm.h"
>> +
>> +struct tegra_drm_channel_ctx *
>> +tegra_drm_channel_ctx_lock(struct tegra_drm_file *file, u32 id)
>> +{
>> +	struct tegra_drm_channel_ctx *ctx;
>> +
>> +	mutex_lock(&file->lock);
>> +	ctx = xa_load(&file->contexts, id);
>> +	if (!ctx)
>> +		mutex_unlock(&file->lock);
>> +
>> +	return ctx;
>> +}
> 
> This interface seems slightly odd. Looking at how this is used I see how
> doing it this way saves a couple of lines. However, it also make this
> difficult to understand, so I wonder if it wouldn't be better to just
> open-code this in the three callsites to make the code flow a bit more
> idiomatic.

Ok, will do. (Another option may be to add a 
tegra_drm_channel_ctx_unlock that just unlocks file->lock -- that'd 
abstract it out even better, which I quite like -- but I'll go with your 
preference)

> 
>> +
>> +static void tegra_drm_mapping_release(struct kref *ref)
>> +{
>> +	struct tegra_drm_mapping *mapping =
>> +		container_of(ref, struct tegra_drm_mapping, ref);
>> +
>> +	if (mapping->sgt)
>> +		dma_unmap_sgtable(mapping->dev, mapping->sgt,
>> +				  mapping->direction, DMA_ATTR_SKIP_CPU_SYNC);
>> +
>> +	host1x_bo_unpin(mapping->dev, mapping->bo, mapping->sgt);
>> +	host1x_bo_put(mapping->bo);
>> +
>> +	kfree(mapping);
>> +}
>> +
>> +void tegra_drm_mapping_put(struct tegra_drm_mapping *mapping)
>> +{
>> +	kref_put(&mapping->ref, tegra_drm_mapping_release);
>> +}
>> +
>> +static void tegra_drm_channel_ctx_close(struct tegra_drm_channel_ctx *ctx)
> 
> Yeah, the more often I read it, the more I'm in favour of just
> collapsing tegra_drm_channel_ctx into tegra_drm_channel if for nothing
> else but to get rid of that annoying _ctx suffix that's there for no
> other reason than to differentiate it from "legacy" contexts.
> 
>> +{
>> +	unsigned long mapping_id;
> 
> It's clear from the context that this is a mapping ID, so I think you
> can just leave out the "mapping_" prefix to save a bit on screen space.

Sure.

> 
>> +	struct tegra_drm_mapping *mapping;
>> +
>> +	xa_for_each(&ctx->mappings, mapping_id, mapping)
>> +		tegra_drm_mapping_put(mapping);
>> +
>> +	xa_destroy(&ctx->mappings);
>> +
>> +	host1x_channel_put(ctx->channel);
>> +
>> +	kfree(ctx);
>> +}
>> +
>> +int close_channel_ctx(int id, void *p, void *data)
>> +{
>> +	struct tegra_drm_channel_ctx *ctx = p;
>> +
>> +	tegra_drm_channel_ctx_close(ctx);
>> +
>> +	return 0;
>> +}
> 
> The signature looked strange, so I went looking for where this is called
> from and turns out I can't find any place where this is used. Do we need
> it?

Ah, maybe I have left it from some previous version. Will fix.

> 
>> +
>> +void tegra_drm_uapi_close_file(struct tegra_drm_file *file)
>> +{
>> +	unsigned long ctx_id;
> 
> Just like for mappings above, I think it's fine to leave out the ctx_
> prefix here.

Yep.

> 
>> +	struct tegra_drm_channel_ctx *ctx;
>> +
>> +	xa_for_each(&file->contexts, ctx_id, ctx)
>> +		tegra_drm_channel_ctx_close(ctx);
>> +
>> +	xa_destroy(&file->contexts);
>> +}
>> +
>> +int tegra_drm_ioctl_channel_open(struct drm_device *drm, void *data,
>> +				 struct drm_file *file)
>> +{
>> +	struct tegra_drm_file *fpriv = file->driver_priv;
>> +	struct tegra_drm *tegra = drm->dev_private;
>> +	struct drm_tegra_channel_open *args = data;
>> +	struct tegra_drm_client *client = NULL;
>> +	struct tegra_drm_channel_ctx *ctx;
>> +	int err;
>> +
>> +	if (args->flags)
>> +		return -EINVAL;
>> +
>> +	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
>> +	if (!ctx)
>> +		return -ENOMEM;
>> +
>> +	err = -ENODEV;
>> +	list_for_each_entry(client, &tegra->clients, list) {
>> +		if (client->base.class == args->host1x_class) {
>> +			err = 0;
>> +			break;
>> +		}
>> +	}
>> +	if (err)
>> +		goto free_ctx;
> 
> This type of construct looks weird. I found that a good way around this
> is to split this off into a separate function that does the lookup and
> just returns NULL when it doesn't find one, which is very elegant:
> 
> 	struct tegra_drm_client *tegra_drm_find_client(struct tegra_drm *tegra, u32 class)
> 	{
> 		struct tegra_drm_client *client;
> 
> 		list_for_each_entry(client, &tegra->clients, list)
> 			if (client->base.class == class)
> 				return client;
> 
> 		return NULL;
> 	}
> 
> and then all of a sudden, the very cumbersome construct above becomes
> this pretty piece of code:
> 
> 	client = tegra_drm_find_client(tegra, args->host1x_class);
> 	if (!client) {
> 		err = -ENODEV;
> 		goto free_ctx;
> 	}
> 
> No need for initializing client to NULL or preventatively setting err =
> -ENODEV or anything.

Yep.

> 
>> +
>> +	if (client->shared_channel) {
>> +		ctx->channel = host1x_channel_get(client->shared_channel);
>> +	} else {
>> +		ctx->channel = host1x_channel_request(&client->base);
>> +		if (!ctx->channel) {
>> +			err = -EBUSY;
> 
> I -EBUSY really appropriate here? Can host1x_channel_request() fail for
> other reasons?

It could also fail due to being out of memory (failing to allocate space 
for CDMA) - I guess we should plumb the error code here. But -EBUSY is 
really the most likely thing to happen anyway. Perhaps that can be done 
separately.

> 
>> +			goto free_ctx;
>> +		}
>> +	}
>> +
>> +	err = xa_alloc(&fpriv->contexts, &args->channel_ctx, ctx,
>> +		       XA_LIMIT(1, U32_MAX), GFP_KERNEL);
>> +	if (err < 0)
>> +		goto put_channel;
>> +
>> +	ctx->client = client;
>> +	xa_init_flags(&ctx->mappings, XA_FLAGS_ALLOC1);
>> +
>> +	args->hardware_version = client->version;
>> +
>> +	return 0;
>> +
>> +put_channel:
>> +	host1x_channel_put(ctx->channel);
>> +free_ctx:
>> +	kfree(ctx);
>> +
>> +	return err;
>> +}
>> +
>> +int tegra_drm_ioctl_channel_close(struct drm_device *drm, void *data,
>> +				  struct drm_file *file)
>> +{
>> +	struct tegra_drm_file *fpriv = file->driver_priv;
>> +	struct drm_tegra_channel_close *args = data;
>> +	struct tegra_drm_channel_ctx *ctx;
>> +
>> +	ctx = tegra_drm_channel_ctx_lock(fpriv, args->channel_ctx);
>> +	if (!ctx)
>> +		return -EINVAL;
>> +
>> +	xa_erase(&fpriv->contexts, args->channel_ctx);
>> +
>> +	mutex_unlock(&fpriv->lock);
>> +
>> +	tegra_drm_channel_ctx_close(ctx);
>> +
>> +	return 0;
>> +}
>> +
>> +int tegra_drm_ioctl_channel_map(struct drm_device *drm, void *data,
>> +				struct drm_file *file)
>> +{
>> +	struct tegra_drm_file *fpriv = file->driver_priv;
>> +	struct drm_tegra_channel_map *args = data;
>> +	struct tegra_drm_channel_ctx *ctx;
>> +	struct tegra_drm_mapping *mapping;
>> +	struct drm_gem_object *gem;
>> +	u32 mapping_id;
>> +	int err = 0;
>> +
>> +	if (args->flags & ~DRM_TEGRA_CHANNEL_MAP_READWRITE)
>> +		return -EINVAL;
>> +
>> +	ctx = tegra_drm_channel_ctx_lock(fpriv, args->channel_ctx);
>> +	if (!ctx)
>> +		return -EINVAL;
>> +
>> +	mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
>> +	if (!mapping) {
>> +		err = -ENOMEM;
>> +		goto unlock;
>> +	}
>> +
>> +	kref_init(&mapping->ref);
>> +
>> +	gem = drm_gem_object_lookup(file, args->handle);
>> +	if (!gem) {
>> +		err = -EINVAL;
>> +		goto unlock;
>> +	}
>> +
>> +	mapping->dev = ctx->client->base.dev;
>> +	mapping->bo = &container_of(gem, struct tegra_bo, gem)->base;
> 
> We already have host1x_bo_lookup() in drm.c that you can use to avoid
> this strange cast.

Okay, will fix.

> 
>> +
>> +	if (!iommu_get_domain_for_dev(mapping->dev) ||
>> +	    ctx->client->base.group) {
> 
> This expression is now used in at least two places, so I wonder if we
> should have a helper for it along with some documentation about why this
> is the right thing to do. I have a local patch that adds a comment to
> the other instance of this because I had forgotten why this was correct,
> so I can pick that up and refactor later on.

Actually, just last week I found out that the condition here is wrong 
(at least for this particular instance) -- with the current condition, 
if IOMMU is disabled we end up in the first branch, but if the BO in 
question was imported through DMA-BUF the iova will be NULL - 
host1x_bo_pin returns an SGT instead, so we need to go to the else path, 
which works fine. (If ctx->client->base.group is set, this is not a 
problem since import will IOMMU map the BO and set iova). I have a local 
fix for this which I'll add to v6.

> 
>> +		host1x_bo_pin(mapping->dev, mapping->bo,
>> +			      &mapping->iova);
>> +	} else {
>> +		mapping->direction = DMA_TO_DEVICE;
>> +		if (args->flags & DRM_TEGRA_CHANNEL_MAP_READWRITE)
>> +			mapping->direction = DMA_BIDIRECTIONAL;
>> +
>> +		mapping->sgt =
>> +			host1x_bo_pin(mapping->dev, mapping->bo, NULL);
>> +		if (IS_ERR(mapping->sgt)) {
>> +			err = PTR_ERR(mapping->sgt);
>> +			goto put_gem;
>> +		}
>> +
>> +		err = dma_map_sgtable(mapping->dev, mapping->sgt,
>> +				      mapping->direction,
>> +				      DMA_ATTR_SKIP_CPU_SYNC);
>> +		if (err)
>> +			goto unpin;
>> +
>> +		/* TODO only map the requested part */
>> +		mapping->iova = sg_dma_address(mapping->sgt->sgl);
> 
> That comment seems misplaced here since the mapping already happens
> above. Also, wouldn't the same TODO apply to the host1x_bo_pin() path in
> the if block? Maybe the TODO should be at the top of the function?
> 
> Alternatively, if this isn't implemented in this patch anyway, maybe
> just drop the comment altogether. In order to implement this, wouldn't
> the UAPI have to change as well? In that case it might be better to add
> the TODO somewhere in the UAPI header, or in a separate TODO file in the
> driver's directory.

Yeah, I'll drop the comment. The UAPI originally had support for this 
but I dropped it upon Dmitry's objection.

> 
>> +	}
>> +
>> +	mapping->iova_end = mapping->iova + gem->size;
>> +
>> +	mutex_unlock(&fpriv->lock);
>> +
>> +	err = xa_alloc(&ctx->mappings, &mapping_id, mapping,
>> +		       XA_LIMIT(1, U32_MAX), GFP_KERNEL);
>> +	if (err < 0)
>> +		goto unmap;
>> +
>> +	args->mapping_id = mapping_id;
>> +
>> +	return 0;
>> +
>> +unmap:
>> +	if (mapping->sgt) {
>> +		dma_unmap_sgtable(mapping->dev, mapping->sgt,
>> +				  mapping->direction, DMA_ATTR_SKIP_CPU_SYNC);
>> +	}
>> +unpin:
>> +	host1x_bo_unpin(mapping->dev, mapping->bo, mapping->sgt);
>> +put_gem:
>> +	drm_gem_object_put(gem);
>> +	kfree(mapping);
>> +unlock:
>> +	mutex_unlock(&fpriv->lock);
>> +	return err;
>> +}
>> +
>> +int tegra_drm_ioctl_channel_unmap(struct drm_device *drm, void *data,
>> +				  struct drm_file *file)
>> +{
>> +	struct tegra_drm_file *fpriv = file->driver_priv;
>> +	struct drm_tegra_channel_unmap *args = data;
>> +	struct tegra_drm_channel_ctx *ctx;
>> +	struct tegra_drm_mapping *mapping;
>> +
>> +	ctx = tegra_drm_channel_ctx_lock(fpriv, args->channel_ctx);
>> +	if (!ctx)
>> +		return -EINVAL;
>> +
>> +	mapping = xa_erase(&ctx->mappings, args->mapping_id);
>> +
>> +	mutex_unlock(&fpriv->lock);
>> +
>> +	if (mapping) {
>> +		tegra_drm_mapping_put(mapping);
>> +		return 0;
>> +	} else {
>> +		return -EINVAL;
>> +	}
>> +}
>> +
>> +int tegra_drm_ioctl_gem_create(struct drm_device *drm, void *data,
>> +			       struct drm_file *file)
>> +{
>> +	struct drm_tegra_gem_create *args = data;
>> +	struct tegra_bo *bo;
>> +
>> +	if (args->flags)
>> +		return -EINVAL;
> 
> I'm not sure it's worth doing this, especially because this is now a new
> IOCTL that's actually a subset of the original. I think we should just
> keep the original and if we want to deprecate the flags, or replace them
> with new ones, let's just try and phase out the deprecated ones.

Ok, I'll look into it.

> 
> Thierry

Thanks,
Mikko

> 
>> +
>> +	bo = tegra_bo_create_with_handle(file, drm, args->size, args->flags,
>> +					 &args->handle);
>> +	if (IS_ERR(bo))
>> +		return PTR_ERR(bo);
>> +
>> +	return 0;
>> +}
>> +
>> +int tegra_drm_ioctl_gem_mmap(struct drm_device *drm, void *data,
>> +			     struct drm_file *file)
>> +{
>> +	struct drm_tegra_gem_mmap *args = data;
>> +	struct drm_gem_object *gem;
>> +	struct tegra_bo *bo;
>> +
>> +	gem = drm_gem_object_lookup(file, args->handle);
>> +	if (!gem)
>> +		return -EINVAL;
>> +
>> +	bo = to_tegra_bo(gem);
>> +
>> +	args->offset = drm_vma_node_offset_addr(&bo->gem.vma_node);
>> +
>> +	drm_gem_object_put(gem);
>> +
>> +	return 0;
>> +}
>> -- 
>> 2.30.0
>>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

  reply	other threads:[~2021-03-23 14:44 UTC|newest]

Thread overview: 195+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-01-11 12:59 [PATCH v5 00/21] Host1x/TegraDRM UAPI Mikko Perttunen
2021-01-11 12:59 ` Mikko Perttunen
2021-01-11 12:59 ` [PATCH v5 01/21] gpu: host1x: Use different lock classes for each client Mikko Perttunen
2021-01-11 12:59   ` Mikko Perttunen
2021-03-22 14:46   ` Thierry Reding
2021-03-22 14:46     ` Thierry Reding
2021-03-22 14:48     ` Dmitry Osipenko
2021-03-22 14:48       ` Dmitry Osipenko
2021-03-22 15:19       ` Mikko Perttunen
2021-03-22 15:19         ` Mikko Perttunen
2021-03-22 16:01         ` Dmitry Osipenko
2021-03-22 16:01           ` Dmitry Osipenko
2021-03-23 10:20           ` Thierry Reding
2021-03-23 10:20             ` Thierry Reding
2021-03-23 13:25             ` Dmitry Osipenko
2021-03-23 13:25               ` Dmitry Osipenko
2021-03-26 14:54         ` Mikko Perttunen
2021-03-26 14:54           ` Mikko Perttunen
2021-03-26 18:31           ` Dmitry Osipenko
2021-03-26 18:31             ` Dmitry Osipenko
2021-03-26 19:10             ` Mikko Perttunen
2021-03-26 19:10               ` Mikko Perttunen
2021-03-26 22:47               ` Dmitry Osipenko
2021-03-26 22:47                 ` Dmitry Osipenko
2021-01-11 13:00 ` [PATCH v5 02/21] gpu: host1x: Allow syncpoints without associated client Mikko Perttunen
2021-01-11 13:00   ` Mikko Perttunen
2021-03-23 10:10   ` Thierry Reding
2021-03-23 10:10     ` Thierry Reding
2021-03-23 10:32     ` Mikko Perttunen
2021-03-23 10:32       ` Mikko Perttunen
2021-01-11 13:00 ` [PATCH v5 03/21] gpu: host1x: Show number of pending waiters in debugfs Mikko Perttunen
2021-01-11 13:00   ` Mikko Perttunen
2021-03-23 10:16   ` Thierry Reding
2021-03-23 10:16     ` Thierry Reding
2021-03-26 14:34     ` Mikko Perttunen
2021-03-26 14:34       ` Mikko Perttunen
2021-04-01 21:19       ` Michał Mirosław
2021-04-01 21:19         ` Michał Mirosław
2021-04-02 16:02         ` Dmitry Osipenko
2021-04-02 16:02           ` Dmitry Osipenko
2021-04-08  4:13           ` Michał Mirosław
2021-04-08  4:13             ` Michał Mirosław
2021-04-08  4:25             ` Michał Mirosław
2021-04-08  4:25               ` Michał Mirosław
2021-04-08 11:58               ` Mikko Perttunen
2021-04-08 11:58                 ` Mikko Perttunen
2021-01-11 13:00 ` [PATCH v5 04/21] gpu: host1x: Remove cancelled waiters immediately Mikko Perttunen
2021-01-11 13:00   ` Mikko Perttunen
2021-01-12 22:07   ` Dmitry Osipenko
2021-01-12 22:07     ` Dmitry Osipenko
2021-01-12 22:20     ` Mikko Perttunen
2021-01-12 22:20       ` Mikko Perttunen
2021-01-13 16:29       ` Dmitry Osipenko
2021-01-13 16:29         ` Dmitry Osipenko
2021-01-13 18:16         ` Mikko Perttunen
2021-01-13 18:16           ` Mikko Perttunen
2021-03-23 10:23       ` Thierry Reding
2021-03-23 10:23         ` Thierry Reding
2021-01-11 13:00 ` [PATCH v5 05/21] gpu: host1x: Use HW-equivalent syncpoint expiration check Mikko Perttunen
2021-01-11 13:00   ` Mikko Perttunen
2021-03-23 10:26   ` Thierry Reding
2021-03-23 10:26     ` Thierry Reding
2021-01-11 13:00 ` [PATCH v5 06/21] gpu: host1x: Cleanup and refcounting for syncpoints Mikko Perttunen
2021-01-11 13:00   ` Mikko Perttunen
2021-03-23 10:36   ` Thierry Reding
2021-03-23 10:36     ` Thierry Reding
2021-03-23 10:44     ` Mikko Perttunen
2021-03-23 10:44       ` Mikko Perttunen
2021-03-23 11:21       ` Thierry Reding
2021-03-23 11:21         ` Thierry Reding
2021-01-11 13:00 ` [PATCH v5 07/21] gpu: host1x: Introduce UAPI header Mikko Perttunen
2021-01-11 13:00   ` Mikko Perttunen
2021-03-23 10:52   ` Thierry Reding
2021-03-23 10:52     ` Thierry Reding
2021-03-23 11:12     ` Mikko Perttunen
2021-03-23 11:12       ` Mikko Perttunen
2021-03-23 11:43       ` Thierry Reding
2021-03-23 11:43         ` Thierry Reding
2021-01-11 13:00 ` [PATCH v5 08/21] gpu: host1x: Implement /dev/host1x device node Mikko Perttunen
2021-01-11 13:00   ` Mikko Perttunen
2021-03-23 11:02   ` Thierry Reding
2021-03-23 11:02     ` Thierry Reding
2021-03-23 11:15     ` Mikko Perttunen
2021-03-23 11:15       ` Mikko Perttunen
2021-01-11 13:00 ` [PATCH v5 09/21] gpu: host1x: DMA fences and userspace fence creation Mikko Perttunen
2021-01-11 13:00   ` Mikko Perttunen
2021-03-23 11:15   ` Thierry Reding
2021-03-23 11:15     ` Thierry Reding
2021-01-11 13:00 ` [PATCH v5 10/21] gpu: host1x: Add no-recovery mode Mikko Perttunen
2021-01-11 13:00   ` Mikko Perttunen
2021-01-11 13:00 ` [PATCH v5 11/21] gpu: host1x: Add job release callback Mikko Perttunen
2021-01-11 13:00   ` Mikko Perttunen
2021-03-23 11:55   ` Thierry Reding
2021-03-23 11:55     ` Thierry Reding
2021-01-11 13:00 ` [PATCH v5 12/21] gpu: host1x: Add support for syncpoint waits in CDMA pushbuffer Mikko Perttunen
2021-01-11 13:00   ` Mikko Perttunen
2021-01-11 13:00 ` [PATCH v5 13/21] gpu: host1x: Reset max value when freeing a syncpoint Mikko Perttunen
2021-01-11 13:00   ` Mikko Perttunen
2021-01-11 13:00 ` [PATCH v5 14/21] gpu: host1x: Reserve VBLANK syncpoints at initialization Mikko Perttunen
2021-01-11 13:00   ` Mikko Perttunen
2021-01-11 13:00 ` [PATCH v5 15/21] drm/tegra: Add new UAPI to header Mikko Perttunen
2021-01-11 13:00   ` Mikko Perttunen
2021-01-13 18:14   ` Dmitry Osipenko
2021-01-13 18:14     ` Dmitry Osipenko
2021-01-13 18:56     ` Mikko Perttunen
2021-01-13 18:56       ` Mikko Perttunen
2021-01-14  8:36       ` Dmitry Osipenko
2021-01-14  8:36         ` Dmitry Osipenko
2021-01-14 10:34         ` Mikko Perttunen
2021-01-14 10:34           ` Mikko Perttunen
2021-03-23 12:30           ` Thierry Reding
2021-03-23 12:30             ` Thierry Reding
2021-03-23 14:00             ` Dmitry Osipenko
2021-03-23 14:00               ` Dmitry Osipenko
2021-03-23 16:44               ` Thierry Reding
2021-03-23 16:44                 ` Thierry Reding
2021-03-23 17:32                 ` Dmitry Osipenko
2021-03-23 17:32                   ` Dmitry Osipenko
2021-03-23 17:57                   ` Thierry Reding
2021-03-23 17:57                     ` Thierry Reding
2021-01-11 13:00 ` [PATCH v5 16/21] drm/tegra: Boot VIC during runtime PM resume Mikko Perttunen
2021-01-11 13:00   ` Mikko Perttunen
2021-01-11 13:00 ` [PATCH v5 17/21] drm/tegra: Set resv fields when importing/exporting GEMs Mikko Perttunen
2021-01-11 13:00   ` Mikko Perttunen
2021-01-11 13:00 ` [PATCH v5 18/21] drm/tegra: Allocate per-engine channel in core code Mikko Perttunen
2021-01-11 13:00   ` Mikko Perttunen
2021-03-23 12:35   ` Thierry Reding
2021-03-23 12:35     ` Thierry Reding
2021-03-23 13:15     ` Mikko Perttunen
2021-03-23 13:15       ` Mikko Perttunen
2021-01-11 13:00 ` [PATCH v5 19/21] drm/tegra: Implement new UAPI Mikko Perttunen
2021-01-11 13:00   ` Mikko Perttunen
2021-01-11 17:37   ` kernel test robot
2021-01-11 17:37     ` kernel test robot
2021-01-11 17:37     ` kernel test robot
2021-01-12 22:27   ` Dmitry Osipenko
2021-01-12 22:27     ` Dmitry Osipenko
2021-03-23 13:25   ` Thierry Reding
2021-03-23 13:25     ` Thierry Reding
2021-03-23 14:43     ` Mikko Perttunen [this message]
2021-03-23 14:43       ` Mikko Perttunen
2021-03-23 15:00       ` Dmitry Osipenko
2021-03-23 15:00         ` Dmitry Osipenko
2021-03-23 16:59         ` Thierry Reding
2021-03-23 16:59           ` Thierry Reding
2021-01-11 13:00 ` [PATCH v5 20/21] drm/tegra: Implement job submission part of " Mikko Perttunen
2021-01-11 13:00   ` Mikko Perttunen
2021-03-23 13:38   ` Thierry Reding
2021-03-23 13:38     ` Thierry Reding
2021-03-23 14:16     ` Mikko Perttunen
2021-03-23 14:16       ` Mikko Perttunen
2021-03-23 17:04       ` Thierry Reding
2021-03-23 17:04         ` Thierry Reding
2021-01-11 13:00 ` [PATCH v5 21/21] drm/tegra: Add job firewall Mikko Perttunen
2021-01-11 13:00   ` Mikko Perttunen
2021-01-19 22:29 ` [PATCH v5 00/21] Host1x/TegraDRM UAPI Dmitry Osipenko
2021-01-19 22:29   ` Dmitry Osipenko
2021-01-26  2:45   ` Mikko Perttunen
2021-01-26  2:45     ` Mikko Perttunen
2021-01-27 21:20     ` [PATCH v5 00/21] Host1x sync point UAPI should not be used for tracking DRM jobs Dmitry Osipenko
2021-01-27 21:20       ` Dmitry Osipenko
2021-01-28 11:08       ` Mikko Perttunen
2021-01-28 11:08         ` Mikko Perttunen
2021-01-28 16:58         ` Thierry Reding
2021-01-28 16:58           ` Thierry Reding
2021-01-29 17:30           ` Dmitry Osipenko
2021-01-29 17:30             ` Dmitry Osipenko
2021-02-03 11:18             ` Mikko Perttunen
2021-02-03 11:18               ` Mikko Perttunen
2021-02-27 11:19               ` Dmitry Osipenko
2021-02-27 11:19                 ` Dmitry Osipenko
2021-03-01  8:19                 ` Mikko Perttunen
2021-03-01  8:19                   ` Mikko Perttunen
2021-03-23 18:21                 ` Thierry Reding
2021-03-23 18:21                   ` Thierry Reding
2021-03-23 19:57                   ` Dmitry Osipenko
2021-03-23 19:57                     ` Dmitry Osipenko
2021-03-23 20:13                     ` Dmitry Osipenko
2021-03-23 20:13                       ` Dmitry Osipenko
2021-01-27 21:26     ` [PATCH v5 00/21] Host1x/TegraDRM UAPI Dmitry Osipenko
2021-01-27 21:26       ` Dmitry Osipenko
2021-01-27 21:57       ` Mikko Perttunen
2021-01-27 21:57         ` Mikko Perttunen
2021-01-27 22:06         ` Dmitry Osipenko
2021-01-27 22:06           ` Dmitry Osipenko
2021-01-28 11:46           ` Mikko Perttunen
2021-01-28 11:46             ` Mikko Perttunen
2021-01-27 21:35     ` [PATCH v5 00/21] sync_file API is not very suitable for DRM Dmitry Osipenko
2021-01-27 21:35       ` Dmitry Osipenko
2021-01-27 21:53       ` Mikko Perttunen
2021-01-27 21:53         ` Mikko Perttunen
2021-01-27 22:26         ` Dmitry Osipenko
2021-01-27 22:26           ` Dmitry Osipenko
2021-01-27 21:52     ` [PATCH v5 00/21] support option where all commands are collected into a single,dedicated cmdstream Dmitry Osipenko
2021-01-27 21:52       ` Dmitry Osipenko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=494e3858-5b29-0b44-f2eb-7a7cc16ff325@kapsi.fi \
    --to=cyndis@kapsi.fi \
    --cc=airlied@linux.ie \
    --cc=bhuntsman@nvidia.com \
    --cc=daniel@ffwll.ch \
    --cc=digetx@gmail.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=jonathanh@nvidia.com \
    --cc=linux-tegra@vger.kernel.org \
    --cc=mperttunen@nvidia.com \
    --cc=talho@nvidia.com \
    --cc=thierry.reding@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.