1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2020 NVIDIA Corporation */
4 #include <linux/host1x.h>
5 #include <linux/iommu.h>
6 #include <linux/list.h>
8 #include <drm/drm_drv.h>
9 #include <drm/drm_file.h>
10 #include <drm/drm_utils.h>
15 static void tegra_drm_mapping_release(struct kref *ref)
17 struct tegra_drm_mapping *mapping =
18 container_of(ref, struct tegra_drm_mapping, ref);
20 host1x_bo_unpin(mapping->map);
21 host1x_bo_put(mapping->bo);
26 void tegra_drm_mapping_put(struct tegra_drm_mapping *mapping)
28 kref_put(&mapping->ref, tegra_drm_mapping_release);
31 static void tegra_drm_channel_context_close(struct tegra_drm_context *context)
33 struct tegra_drm_mapping *mapping;
36 xa_for_each(&context->mappings, id, mapping)
37 tegra_drm_mapping_put(mapping);
39 xa_destroy(&context->mappings);
41 host1x_channel_put(context->channel);
46 void tegra_drm_uapi_close_file(struct tegra_drm_file *file)
48 struct tegra_drm_context *context;
49 struct host1x_syncpt *sp;
52 xa_for_each(&file->contexts, id, context)
53 tegra_drm_channel_context_close(context);
55 xa_for_each(&file->syncpoints, id, sp)
56 host1x_syncpt_put(sp);
58 xa_destroy(&file->contexts);
59 xa_destroy(&file->syncpoints);
62 static struct tegra_drm_client *tegra_drm_find_client(struct tegra_drm *tegra, u32 class)
64 struct tegra_drm_client *client;
66 list_for_each_entry(client, &tegra->clients, list)
67 if (client->base.class == class)
73 int tegra_drm_ioctl_channel_open(struct drm_device *drm, void *data, struct drm_file *file)
75 struct tegra_drm_file *fpriv = file->driver_priv;
76 struct tegra_drm *tegra = drm->dev_private;
77 struct drm_tegra_channel_open *args = data;
78 struct tegra_drm_client *client = NULL;
79 struct tegra_drm_context *context;
85 context = kzalloc(sizeof(*context), GFP_KERNEL);
89 client = tegra_drm_find_client(tegra, args->host1x_class);
95 if (client->shared_channel) {
96 context->channel = host1x_channel_get(client->shared_channel);
98 context->channel = host1x_channel_request(&client->base);
99 if (!context->channel) {
105 err = xa_alloc(&fpriv->contexts, &args->context, context, XA_LIMIT(1, U32_MAX),
110 context->client = client;
111 xa_init_flags(&context->mappings, XA_FLAGS_ALLOC1);
113 args->version = client->version;
114 args->capabilities = 0;
116 if (device_get_dma_attr(client->base.dev) == DEV_DMA_COHERENT)
117 args->capabilities |= DRM_TEGRA_CHANNEL_CAP_CACHE_COHERENT;
122 host1x_channel_put(context->channel);
129 int tegra_drm_ioctl_channel_close(struct drm_device *drm, void *data, struct drm_file *file)
131 struct tegra_drm_file *fpriv = file->driver_priv;
132 struct drm_tegra_channel_close *args = data;
133 struct tegra_drm_context *context;
135 mutex_lock(&fpriv->lock);
137 context = xa_load(&fpriv->contexts, args->context);
139 mutex_unlock(&fpriv->lock);
143 xa_erase(&fpriv->contexts, args->context);
145 mutex_unlock(&fpriv->lock);
147 tegra_drm_channel_context_close(context);
152 int tegra_drm_ioctl_channel_map(struct drm_device *drm, void *data, struct drm_file *file)
154 struct tegra_drm_file *fpriv = file->driver_priv;
155 struct drm_tegra_channel_map *args = data;
156 struct tegra_drm_mapping *mapping;
157 struct tegra_drm_context *context;
158 enum dma_data_direction direction;
161 if (args->flags & ~DRM_TEGRA_CHANNEL_MAP_READ_WRITE)
164 mutex_lock(&fpriv->lock);
166 context = xa_load(&fpriv->contexts, args->context);
168 mutex_unlock(&fpriv->lock);
172 mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
178 kref_init(&mapping->ref);
180 mapping->bo = tegra_gem_lookup(file, args->handle);
186 switch (args->flags & DRM_TEGRA_CHANNEL_MAP_READ_WRITE) {
187 case DRM_TEGRA_CHANNEL_MAP_READ_WRITE:
188 direction = DMA_BIDIRECTIONAL;
191 case DRM_TEGRA_CHANNEL_MAP_WRITE:
192 direction = DMA_FROM_DEVICE;
195 case DRM_TEGRA_CHANNEL_MAP_READ:
196 direction = DMA_TO_DEVICE;
204 mapping->map = host1x_bo_pin(context->client->base.dev, mapping->bo, direction, NULL);
205 if (IS_ERR(mapping->map)) {
206 err = PTR_ERR(mapping->map);
210 mapping->iova = mapping->map->phys;
211 mapping->iova_end = mapping->iova + host1x_to_tegra_bo(mapping->bo)->gem.size;
213 err = xa_alloc(&context->mappings, &args->mapping, mapping, XA_LIMIT(1, U32_MAX),
218 mutex_unlock(&fpriv->lock);
223 host1x_bo_unpin(mapping->map);
225 host1x_bo_put(mapping->bo);
229 mutex_unlock(&fpriv->lock);
233 int tegra_drm_ioctl_channel_unmap(struct drm_device *drm, void *data, struct drm_file *file)
235 struct tegra_drm_file *fpriv = file->driver_priv;
236 struct drm_tegra_channel_unmap *args = data;
237 struct tegra_drm_mapping *mapping;
238 struct tegra_drm_context *context;
240 mutex_lock(&fpriv->lock);
242 context = xa_load(&fpriv->contexts, args->context);
244 mutex_unlock(&fpriv->lock);
248 mapping = xa_erase(&context->mappings, args->mapping);
250 mutex_unlock(&fpriv->lock);
255 tegra_drm_mapping_put(mapping);
259 int tegra_drm_ioctl_syncpoint_allocate(struct drm_device *drm, void *data, struct drm_file *file)
261 struct host1x *host1x = tegra_drm_to_host1x(drm->dev_private);
262 struct tegra_drm_file *fpriv = file->driver_priv;
263 struct drm_tegra_syncpoint_allocate *args = data;
264 struct host1x_syncpt *sp;
270 sp = host1x_syncpt_alloc(host1x, HOST1X_SYNCPT_CLIENT_MANAGED, current->comm);
274 args->id = host1x_syncpt_id(sp);
276 err = xa_insert(&fpriv->syncpoints, args->id, sp, GFP_KERNEL);
278 host1x_syncpt_put(sp);
285 int tegra_drm_ioctl_syncpoint_free(struct drm_device *drm, void *data, struct drm_file *file)
287 struct tegra_drm_file *fpriv = file->driver_priv;
288 struct drm_tegra_syncpoint_allocate *args = data;
289 struct host1x_syncpt *sp;
291 mutex_lock(&fpriv->lock);
292 sp = xa_erase(&fpriv->syncpoints, args->id);
293 mutex_unlock(&fpriv->lock);
298 host1x_syncpt_put(sp);
303 int tegra_drm_ioctl_syncpoint_wait(struct drm_device *drm, void *data, struct drm_file *file)
305 struct host1x *host1x = tegra_drm_to_host1x(drm->dev_private);
306 struct drm_tegra_syncpoint_wait *args = data;
307 signed long timeout_jiffies;
308 struct host1x_syncpt *sp;
310 if (args->padding != 0)
313 sp = host1x_syncpt_get_by_id_noref(host1x, args->id);
317 timeout_jiffies = drm_timeout_abs_to_jiffies(args->timeout_ns);
319 return host1x_syncpt_wait(sp, args->threshold, timeout_jiffies, &args->value);