drm/nouveau: expose the full object/event interfaces to userspace
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
		
					parent
					
						
							
								771fa0e4d0
							
						
					
				
			
			
				commit
				
					
						27111a23d0
					
				
			
		
					 9 changed files with 427 additions and 10 deletions
				
			
		| 
						 | 
					@ -340,7 +340,7 @@ nouveau-y += nouveau_drm.o nouveau_chan.o nouveau_dma.o nouveau_fence.o
 | 
				
			||||||
nouveau-y += nouveau_vga.o nouveau_agp.o
 | 
					nouveau-y += nouveau_vga.o nouveau_agp.o
 | 
				
			||||||
nouveau-y += nouveau_ttm.o nouveau_sgdma.o nouveau_bo.o nouveau_gem.o
 | 
					nouveau-y += nouveau_ttm.o nouveau_sgdma.o nouveau_bo.o nouveau_gem.o
 | 
				
			||||||
nouveau-y += nouveau_prime.o nouveau_abi16.o
 | 
					nouveau-y += nouveau_prime.o nouveau_abi16.o
 | 
				
			||||||
nouveau-y += nouveau_nvif.o
 | 
					nouveau-y += nouveau_nvif.o nouveau_usif.o
 | 
				
			||||||
nouveau-y += nv04_fence.o nv10_fence.o nv17_fence.o
 | 
					nouveau-y += nv04_fence.o nv10_fence.o nv17_fence.o
 | 
				
			||||||
nouveau-y += nv50_fence.o nv84_fence.o nvc0_fence.o
 | 
					nouveau-y += nv50_fence.o nv84_fence.o nvc0_fence.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -50,6 +50,7 @@
 | 
				
			||||||
#include "nouveau_fbcon.h"
 | 
					#include "nouveau_fbcon.h"
 | 
				
			||||||
#include "nouveau_fence.h"
 | 
					#include "nouveau_fence.h"
 | 
				
			||||||
#include "nouveau_debugfs.h"
 | 
					#include "nouveau_debugfs.h"
 | 
				
			||||||
 | 
					#include "nouveau_usif.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MODULE_PARM_DESC(config, "option string to pass to driver core");
 | 
					MODULE_PARM_DESC(config, "option string to pass to driver core");
 | 
				
			||||||
static char *nouveau_config;
 | 
					static char *nouveau_config;
 | 
				
			||||||
| 
						 | 
					@ -107,8 +108,10 @@ nouveau_cli_create(u64 name, const char *sname,
 | 
				
			||||||
		int ret = nvif_client_init(NULL, NULL, sname, name,
 | 
							int ret = nvif_client_init(NULL, NULL, sname, name,
 | 
				
			||||||
					   nouveau_config, nouveau_debug,
 | 
										   nouveau_config, nouveau_debug,
 | 
				
			||||||
					  &cli->base);
 | 
										  &cli->base);
 | 
				
			||||||
		if (ret == 0)
 | 
							if (ret == 0) {
 | 
				
			||||||
			mutex_init(&cli->mutex);
 | 
								mutex_init(&cli->mutex);
 | 
				
			||||||
 | 
								usif_client_init(cli);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return -ENOMEM;
 | 
						return -ENOMEM;
 | 
				
			||||||
| 
						 | 
					@ -119,6 +122,7 @@ nouveau_cli_destroy(struct nouveau_cli *cli)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	nouveau_vm_ref(NULL, &nvkm_client(&cli->base)->vm, NULL);
 | 
						nouveau_vm_ref(NULL, &nvkm_client(&cli->base)->vm, NULL);
 | 
				
			||||||
	nvif_client_fini(&cli->base);
 | 
						nvif_client_fini(&cli->base);
 | 
				
			||||||
 | 
						usif_client_fini(cli);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
| 
						 | 
					@ -810,24 +814,31 @@ nouveau_ioctls[] = {
 | 
				
			||||||
	DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_INFO, nouveau_gem_ioctl_info, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
 | 
						DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_INFO, nouveau_gem_ioctl_info, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
long nouveau_drm_ioctl(struct file *filp,
 | 
					long
 | 
				
			||||||
		       unsigned int cmd, unsigned long arg)
 | 
					nouveau_drm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct drm_file *file_priv = filp->private_data;
 | 
						struct drm_file *filp = file->private_data;
 | 
				
			||||||
	struct drm_device *dev;
 | 
						struct drm_device *dev = filp->minor->dev;
 | 
				
			||||||
	long ret;
 | 
						long ret;
 | 
				
			||||||
	dev = file_priv->minor->dev;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = pm_runtime_get_sync(dev->dev);
 | 
						ret = pm_runtime_get_sync(dev->dev);
 | 
				
			||||||
	if (ret < 0 && ret != -EACCES)
 | 
						if (ret < 0 && ret != -EACCES)
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = drm_ioctl(filp, cmd, arg);
 | 
						switch (_IOC_NR(cmd) - DRM_COMMAND_BASE) {
 | 
				
			||||||
 | 
						case DRM_NOUVEAU_NVIF:
 | 
				
			||||||
 | 
							ret = usif_ioctl(filp, (void __user *)arg, _IOC_SIZE(cmd));
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							ret = drm_ioctl(file, cmd, arg);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pm_runtime_mark_last_busy(dev->dev);
 | 
						pm_runtime_mark_last_busy(dev->dev);
 | 
				
			||||||
	pm_runtime_put_autosuspend(dev->dev);
 | 
						pm_runtime_put_autosuspend(dev->dev);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct file_operations
 | 
					static const struct file_operations
 | 
				
			||||||
nouveau_driver_fops = {
 | 
					nouveau_driver_fops = {
 | 
				
			||||||
	.owner = THIS_MODULE,
 | 
						.owner = THIS_MODULE,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,8 +9,8 @@
 | 
				
			||||||
#define DRIVER_DATE		"20120801"
 | 
					#define DRIVER_DATE		"20120801"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DRIVER_MAJOR		1
 | 
					#define DRIVER_MAJOR		1
 | 
				
			||||||
#define DRIVER_MINOR		1
 | 
					#define DRIVER_MINOR		2
 | 
				
			||||||
#define DRIVER_PATCHLEVEL	2
 | 
					#define DRIVER_PATCHLEVEL	0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * 1.1.1:
 | 
					 * 1.1.1:
 | 
				
			||||||
| 
						 | 
					@ -23,6 +23,9 @@
 | 
				
			||||||
 *        bounds access to local memory to be silently ignored / return 0).
 | 
					 *        bounds access to local memory to be silently ignored / return 0).
 | 
				
			||||||
 * 1.1.2:
 | 
					 * 1.1.2:
 | 
				
			||||||
 *      - fixes multiple bugs in flip completion events and timestamping
 | 
					 *      - fixes multiple bugs in flip completion events and timestamping
 | 
				
			||||||
 | 
					 * 1.2.0:
 | 
				
			||||||
 | 
					 * 	- object api exposed to userspace
 | 
				
			||||||
 | 
					 * 	- fermi,kepler,maxwell zbc
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <nvif/client.h>
 | 
					#include <nvif/client.h>
 | 
				
			||||||
| 
						 | 
					@ -79,6 +82,8 @@ struct nouveau_cli {
 | 
				
			||||||
	struct list_head head;
 | 
						struct list_head head;
 | 
				
			||||||
	struct mutex mutex;
 | 
						struct mutex mutex;
 | 
				
			||||||
	void *abi16;
 | 
						void *abi16;
 | 
				
			||||||
 | 
						struct list_head objects;
 | 
				
			||||||
 | 
						struct list_head notifys;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline struct nouveau_cli *
 | 
					static inline struct nouveau_cli *
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,6 +37,7 @@
 | 
				
			||||||
#include <nvif/ioctl.h>
 | 
					#include <nvif/ioctl.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "nouveau_drm.h"
 | 
					#include "nouveau_drm.h"
 | 
				
			||||||
 | 
					#include "nouveau_usif.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
nvkm_client_unmap(void *priv, void *ptr, u32 size)
 | 
					nvkm_client_unmap(void *priv, void *ptr, u32 size)
 | 
				
			||||||
| 
						 | 
					@ -95,6 +96,8 @@ nvkm_client_ntfy(const void *header, u32 length, const void *data, u32 size)
 | 
				
			||||||
	switch (route) {
 | 
						switch (route) {
 | 
				
			||||||
	case NVDRM_NOTIFY_NVIF:
 | 
						case NVDRM_NOTIFY_NVIF:
 | 
				
			||||||
		return nvif_notify(header, length, data, size);
 | 
							return nvif_notify(header, length, data, size);
 | 
				
			||||||
 | 
						case NVDRM_NOTIFY_USIF:
 | 
				
			||||||
 | 
							return usif_notify(header, length, data, size);
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		WARN_ON(1);
 | 
							WARN_ON(1);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										384
									
								
								drivers/gpu/drm/nouveau/nouveau_usif.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										384
									
								
								drivers/gpu/drm/nouveau/nouveau_usif.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,384 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright 2014 Red Hat Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Permission is hereby granted, free of charge, to any person obtaining a
 | 
				
			||||||
 | 
					 * copy of this software and associated documentation files (the "Software"),
 | 
				
			||||||
 | 
					 * to deal in the Software without restriction, including without limitation
 | 
				
			||||||
 | 
					 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 | 
				
			||||||
 | 
					 * and/or sell copies of the Software, and to permit persons to whom the
 | 
				
			||||||
 | 
					 * Software is furnished to do so, subject to the following conditions:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The above copyright notice and this permission notice shall be included in
 | 
				
			||||||
 | 
					 * all copies or substantial portions of the Software.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
				
			||||||
 | 
					 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
				
			||||||
 | 
					 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 | 
				
			||||||
 | 
					 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 | 
				
			||||||
 | 
					 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 | 
				
			||||||
 | 
					 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 | 
				
			||||||
 | 
					 * OTHER DEALINGS IN THE SOFTWARE.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Authors: Ben Skeggs <bskeggs@redhat.com>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "nouveau_drm.h"
 | 
				
			||||||
 | 
					#include "nouveau_usif.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <nvif/notify.h>
 | 
				
			||||||
 | 
					#include <nvif/unpack.h>
 | 
				
			||||||
 | 
					#include <nvif/client.h>
 | 
				
			||||||
 | 
					#include <nvif/event.h>
 | 
				
			||||||
 | 
					#include <nvif/ioctl.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct usif_notify_p {
 | 
				
			||||||
 | 
						struct drm_pending_event base;
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct drm_event base;
 | 
				
			||||||
 | 
							u8 data[];
 | 
				
			||||||
 | 
						} e;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct usif_notify {
 | 
				
			||||||
 | 
						struct list_head head;
 | 
				
			||||||
 | 
						atomic_t enabled;
 | 
				
			||||||
 | 
						u32 handle;
 | 
				
			||||||
 | 
						u16 reply;
 | 
				
			||||||
 | 
						u8  route;
 | 
				
			||||||
 | 
						u64 token;
 | 
				
			||||||
 | 
						struct usif_notify_p *p;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline struct usif_notify *
 | 
				
			||||||
 | 
					usif_notify_find(struct drm_file *filp, u32 handle)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct nouveau_cli *cli = nouveau_cli(filp);
 | 
				
			||||||
 | 
						struct usif_notify *ntfy;
 | 
				
			||||||
 | 
						list_for_each_entry(ntfy, &cli->notifys, head) {
 | 
				
			||||||
 | 
							if (ntfy->handle == handle)
 | 
				
			||||||
 | 
								return ntfy;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					usif_notify_dtor(struct usif_notify *ntfy)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						list_del(&ntfy->head);
 | 
				
			||||||
 | 
						kfree(ntfy);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					usif_notify(const void *header, u32 length, const void *data, u32 size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usif_notify *ntfy = NULL;
 | 
				
			||||||
 | 
						const union {
 | 
				
			||||||
 | 
							struct nvif_notify_rep_v0 v0;
 | 
				
			||||||
 | 
						} *rep = header;
 | 
				
			||||||
 | 
						struct drm_device *dev;
 | 
				
			||||||
 | 
						struct drm_file *filp;
 | 
				
			||||||
 | 
						unsigned long flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (length == sizeof(rep->v0) && rep->v0.version == 0) {
 | 
				
			||||||
 | 
							if (WARN_ON(!(ntfy = (void *)(unsigned long)rep->v0.token)))
 | 
				
			||||||
 | 
								return NVIF_NOTIFY_DROP;
 | 
				
			||||||
 | 
							BUG_ON(rep->v0.route != NVDRM_NOTIFY_USIF);
 | 
				
			||||||
 | 
						} else
 | 
				
			||||||
 | 
						if (WARN_ON(1))
 | 
				
			||||||
 | 
							return NVIF_NOTIFY_DROP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (WARN_ON(!ntfy->p || ntfy->reply != (length + size)))
 | 
				
			||||||
 | 
							return NVIF_NOTIFY_DROP;
 | 
				
			||||||
 | 
						filp = ntfy->p->base.file_priv;
 | 
				
			||||||
 | 
						dev = filp->minor->dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memcpy(&ntfy->p->e.data[0], header, length);
 | 
				
			||||||
 | 
						memcpy(&ntfy->p->e.data[length], data, size);
 | 
				
			||||||
 | 
						switch (rep->v0.version) {
 | 
				
			||||||
 | 
						case 0: {
 | 
				
			||||||
 | 
							struct nvif_notify_rep_v0 *rep = (void *)ntfy->p->e.data;
 | 
				
			||||||
 | 
							rep->route = ntfy->route;
 | 
				
			||||||
 | 
							rep->token = ntfy->token;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							BUG_ON(1);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock_irqsave(&dev->event_lock, flags);
 | 
				
			||||||
 | 
						if (!WARN_ON(filp->event_space < ntfy->p->e.base.length)) {
 | 
				
			||||||
 | 
							list_add_tail(&ntfy->p->base.link, &filp->event_list);
 | 
				
			||||||
 | 
							filp->event_space -= ntfy->p->e.base.length;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						wake_up_interruptible(&filp->event_wait);
 | 
				
			||||||
 | 
						spin_unlock_irqrestore(&dev->event_lock, flags);
 | 
				
			||||||
 | 
						atomic_set(&ntfy->enabled, 0);
 | 
				
			||||||
 | 
						return NVIF_NOTIFY_DROP;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					usif_notify_new(struct drm_file *f, void *data, u32 size, void *argv, u32 argc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct nouveau_cli *cli = nouveau_cli(f);
 | 
				
			||||||
 | 
						struct nvif_client *client = &cli->base;
 | 
				
			||||||
 | 
						union {
 | 
				
			||||||
 | 
							struct nvif_ioctl_ntfy_new_v0 v0;
 | 
				
			||||||
 | 
						} *args = data;
 | 
				
			||||||
 | 
						union {
 | 
				
			||||||
 | 
							struct nvif_notify_req_v0 v0;
 | 
				
			||||||
 | 
						} *req;
 | 
				
			||||||
 | 
						struct usif_notify *ntfy;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (nvif_unpack(args->v0, 0, 0, true)) {
 | 
				
			||||||
 | 
							if (usif_notify_find(f, args->v0.index))
 | 
				
			||||||
 | 
								return -EEXIST;
 | 
				
			||||||
 | 
						} else
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						req = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!(ntfy = kmalloc(sizeof(*ntfy), GFP_KERNEL)))
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
						atomic_set(&ntfy->enabled, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (nvif_unpack(req->v0, 0, 0, true)) {
 | 
				
			||||||
 | 
							ntfy->reply = sizeof(struct nvif_notify_rep_v0) + req->v0.reply;
 | 
				
			||||||
 | 
							ntfy->route = req->v0.route;
 | 
				
			||||||
 | 
							ntfy->token = req->v0.token;
 | 
				
			||||||
 | 
							req->v0.route = NVDRM_NOTIFY_USIF;
 | 
				
			||||||
 | 
							req->v0.token = (unsigned long)(void *)ntfy;
 | 
				
			||||||
 | 
							ret = nvif_client_ioctl(client, argv, argc);
 | 
				
			||||||
 | 
							req->v0.token = ntfy->token;
 | 
				
			||||||
 | 
							req->v0.route = ntfy->route;
 | 
				
			||||||
 | 
							ntfy->handle = args->v0.index;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ret == 0)
 | 
				
			||||||
 | 
							list_add(&ntfy->head, &cli->notifys);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							kfree(ntfy);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					usif_notify_del(struct drm_file *f, void *data, u32 size, void *argv, u32 argc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct nouveau_cli *cli = nouveau_cli(f);
 | 
				
			||||||
 | 
						struct nvif_client *client = &cli->base;
 | 
				
			||||||
 | 
						union {
 | 
				
			||||||
 | 
							struct nvif_ioctl_ntfy_del_v0 v0;
 | 
				
			||||||
 | 
						} *args = data;
 | 
				
			||||||
 | 
						struct usif_notify *ntfy;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (nvif_unpack(args->v0, 0, 0, true)) {
 | 
				
			||||||
 | 
							if (!(ntfy = usif_notify_find(f, args->v0.index)))
 | 
				
			||||||
 | 
								return -ENOENT;
 | 
				
			||||||
 | 
						} else
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = nvif_client_ioctl(client, argv, argc);
 | 
				
			||||||
 | 
						if (ret == 0)
 | 
				
			||||||
 | 
							usif_notify_dtor(ntfy);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					usif_notify_get(struct drm_file *f, void *data, u32 size, void *argv, u32 argc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct nouveau_cli *cli = nouveau_cli(f);
 | 
				
			||||||
 | 
						struct nvif_client *client = &cli->base;
 | 
				
			||||||
 | 
						union {
 | 
				
			||||||
 | 
							struct nvif_ioctl_ntfy_del_v0 v0;
 | 
				
			||||||
 | 
						} *args = data;
 | 
				
			||||||
 | 
						struct usif_notify *ntfy;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (nvif_unpack(args->v0, 0, 0, true)) {
 | 
				
			||||||
 | 
							if (!(ntfy = usif_notify_find(f, args->v0.index)))
 | 
				
			||||||
 | 
								return -ENOENT;
 | 
				
			||||||
 | 
						} else
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (atomic_xchg(&ntfy->enabled, 1))
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ntfy->p = kmalloc(sizeof(*ntfy->p) + ntfy->reply, GFP_KERNEL);
 | 
				
			||||||
 | 
						if (ret = -ENOMEM, !ntfy->p)
 | 
				
			||||||
 | 
							goto done;
 | 
				
			||||||
 | 
						ntfy->p->base.event = &ntfy->p->e.base;
 | 
				
			||||||
 | 
						ntfy->p->base.file_priv = f;
 | 
				
			||||||
 | 
						ntfy->p->base.pid = current->pid;
 | 
				
			||||||
 | 
						ntfy->p->base.destroy =(void(*)(struct drm_pending_event *))kfree;
 | 
				
			||||||
 | 
						ntfy->p->e.base.type = DRM_NOUVEAU_EVENT_NVIF;
 | 
				
			||||||
 | 
						ntfy->p->e.base.length = sizeof(ntfy->p->e.base) + ntfy->reply;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = nvif_client_ioctl(client, argv, argc);
 | 
				
			||||||
 | 
					done:
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							atomic_set(&ntfy->enabled, 0);
 | 
				
			||||||
 | 
							kfree(ntfy->p);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					usif_notify_put(struct drm_file *f, void *data, u32 size, void *argv, u32 argc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct nouveau_cli *cli = nouveau_cli(f);
 | 
				
			||||||
 | 
						struct nvif_client *client = &cli->base;
 | 
				
			||||||
 | 
						union {
 | 
				
			||||||
 | 
							struct nvif_ioctl_ntfy_put_v0 v0;
 | 
				
			||||||
 | 
						} *args = data;
 | 
				
			||||||
 | 
						struct usif_notify *ntfy;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (nvif_unpack(args->v0, 0, 0, true)) {
 | 
				
			||||||
 | 
							if (!(ntfy = usif_notify_find(f, args->v0.index)))
 | 
				
			||||||
 | 
								return -ENOENT;
 | 
				
			||||||
 | 
						} else
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = nvif_client_ioctl(client, argv, argc);
 | 
				
			||||||
 | 
						if (ret == 0 && atomic_xchg(&ntfy->enabled, 0))
 | 
				
			||||||
 | 
							kfree(ntfy->p);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct usif_object {
 | 
				
			||||||
 | 
						struct list_head head;
 | 
				
			||||||
 | 
						struct list_head ntfy;
 | 
				
			||||||
 | 
						u8  route;
 | 
				
			||||||
 | 
						u64 token;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					usif_object_dtor(struct usif_object *object)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						list_del(&object->head);
 | 
				
			||||||
 | 
						kfree(object);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					usif_object_new(struct drm_file *f, void *data, u32 size, void *argv, u32 argc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct nouveau_cli *cli = nouveau_cli(f);
 | 
				
			||||||
 | 
						struct nvif_client *client = &cli->base;
 | 
				
			||||||
 | 
						union {
 | 
				
			||||||
 | 
							struct nvif_ioctl_new_v0 v0;
 | 
				
			||||||
 | 
						} *args = data;
 | 
				
			||||||
 | 
						struct usif_object *object;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!(object = kmalloc(sizeof(*object), GFP_KERNEL)))
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
						list_add(&object->head, &cli->objects);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (nvif_unpack(args->v0, 0, 0, true)) {
 | 
				
			||||||
 | 
							object->route = args->v0.route;
 | 
				
			||||||
 | 
							object->token = args->v0.token;
 | 
				
			||||||
 | 
							args->v0.route = NVDRM_OBJECT_USIF;
 | 
				
			||||||
 | 
							args->v0.token = (unsigned long)(void *)object;
 | 
				
			||||||
 | 
							ret = nvif_client_ioctl(client, argv, argc);
 | 
				
			||||||
 | 
							args->v0.token = object->token;
 | 
				
			||||||
 | 
							args->v0.route = object->route;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							usif_object_dtor(object);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					usif_ioctl(struct drm_file *filp, void __user *user, u32 argc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct nouveau_cli *cli = nouveau_cli(filp);
 | 
				
			||||||
 | 
						struct nvif_client *client = &cli->base;
 | 
				
			||||||
 | 
						void *data = kmalloc(argc, GFP_KERNEL);
 | 
				
			||||||
 | 
						u32   size = argc;
 | 
				
			||||||
 | 
						union {
 | 
				
			||||||
 | 
							struct nvif_ioctl_v0 v0;
 | 
				
			||||||
 | 
						} *argv = data;
 | 
				
			||||||
 | 
						struct usif_object *object;
 | 
				
			||||||
 | 
						u8 owner;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ret = -ENOMEM, !argv)
 | 
				
			||||||
 | 
							goto done;
 | 
				
			||||||
 | 
						if (ret = -EFAULT, copy_from_user(argv, user, size))
 | 
				
			||||||
 | 
							goto done;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (nvif_unpack(argv->v0, 0, 0, true)) {
 | 
				
			||||||
 | 
							/* block access to objects not created via this interface */
 | 
				
			||||||
 | 
							owner = argv->v0.owner;
 | 
				
			||||||
 | 
							argv->v0.owner = NVDRM_OBJECT_USIF;
 | 
				
			||||||
 | 
						} else
 | 
				
			||||||
 | 
							goto done;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&cli->mutex);
 | 
				
			||||||
 | 
						switch (argv->v0.type) {
 | 
				
			||||||
 | 
						case NVIF_IOCTL_V0_NEW:
 | 
				
			||||||
 | 
							/* ... except if we're creating children */
 | 
				
			||||||
 | 
							argv->v0.owner = NVIF_IOCTL_V0_OWNER_ANY;
 | 
				
			||||||
 | 
							ret = usif_object_new(filp, data, size, argv, argc);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case NVIF_IOCTL_V0_NTFY_NEW:
 | 
				
			||||||
 | 
							ret = usif_notify_new(filp, data, size, argv, argc);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case NVIF_IOCTL_V0_NTFY_DEL:
 | 
				
			||||||
 | 
							ret = usif_notify_del(filp, data, size, argv, argc);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case NVIF_IOCTL_V0_NTFY_GET:
 | 
				
			||||||
 | 
							ret = usif_notify_get(filp, data, size, argv, argc);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case NVIF_IOCTL_V0_NTFY_PUT:
 | 
				
			||||||
 | 
							ret = usif_notify_put(filp, data, size, argv, argc);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							ret = nvif_client_ioctl(client, argv, argc);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (argv->v0.route == NVDRM_OBJECT_USIF) {
 | 
				
			||||||
 | 
							object = (void *)(unsigned long)argv->v0.token;
 | 
				
			||||||
 | 
							argv->v0.route = object->route;
 | 
				
			||||||
 | 
							argv->v0.token = object->token;
 | 
				
			||||||
 | 
							if (ret == 0 && argv->v0.type == NVIF_IOCTL_V0_DEL) {
 | 
				
			||||||
 | 
								list_del(&object->head);
 | 
				
			||||||
 | 
								kfree(object);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							argv->v0.route = NVIF_IOCTL_V0_ROUTE_HIDDEN;
 | 
				
			||||||
 | 
							argv->v0.token = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						argv->v0.owner = owner;
 | 
				
			||||||
 | 
						mutex_unlock(&cli->mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (copy_to_user(user, argv, argc))
 | 
				
			||||||
 | 
							ret = -EFAULT;
 | 
				
			||||||
 | 
					done:
 | 
				
			||||||
 | 
						kfree(argv);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					usif_client_fini(struct nouveau_cli *cli)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct usif_object *object, *otemp;
 | 
				
			||||||
 | 
						struct usif_notify *notify, *ntemp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list_for_each_entry_safe(notify, ntemp, &cli->notifys, head) {
 | 
				
			||||||
 | 
							usif_notify_dtor(notify);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list_for_each_entry_safe(object, otemp, &cli->objects, head) {
 | 
				
			||||||
 | 
							usif_object_dtor(object);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					usif_client_init(struct nouveau_cli *cli)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						INIT_LIST_HEAD(&cli->objects);
 | 
				
			||||||
 | 
						INIT_LIST_HEAD(&cli->notifys);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										9
									
								
								drivers/gpu/drm/nouveau/nouveau_usif.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								drivers/gpu/drm/nouveau/nouveau_usif.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,9 @@
 | 
				
			||||||
 | 
					#ifndef __NOUVEAU_USIF_H__
 | 
				
			||||||
 | 
					#define __NOUVEAU_USIF_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void usif_client_init(struct nouveau_cli *);
 | 
				
			||||||
 | 
					void usif_client_fini(struct nouveau_cli *);
 | 
				
			||||||
 | 
					int  usif_ioctl(struct drm_file *, void __user *, u32);
 | 
				
			||||||
 | 
					int  usif_notify(const void *, u32, const void *, u32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -60,6 +60,7 @@ nvif_drivers[] = {
 | 
				
			||||||
#ifdef __KERNEL__
 | 
					#ifdef __KERNEL__
 | 
				
			||||||
	&nvif_driver_nvkm,
 | 
						&nvif_driver_nvkm,
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
 | 
						&nvif_driver_drm,
 | 
				
			||||||
	&nvif_driver_lib,
 | 
						&nvif_driver_lib,
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	NULL
 | 
						NULL
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,6 +15,7 @@ struct nvif_driver {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern const struct nvif_driver nvif_driver_nvkm;
 | 
					extern const struct nvif_driver nvif_driver_nvkm;
 | 
				
			||||||
 | 
					extern const struct nvif_driver nvif_driver_drm;
 | 
				
			||||||
extern const struct nvif_driver nvif_driver_lib;
 | 
					extern const struct nvif_driver nvif_driver_lib;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,6 +25,8 @@
 | 
				
			||||||
#ifndef __NOUVEAU_DRM_H__
 | 
					#ifndef __NOUVEAU_DRM_H__
 | 
				
			||||||
#define __NOUVEAU_DRM_H__
 | 
					#define __NOUVEAU_DRM_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DRM_NOUVEAU_EVENT_NVIF                                       0x80000000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* reserved object handles when using deprecated object APIs - these
 | 
					/* reserved object handles when using deprecated object APIs - these
 | 
				
			||||||
 * are here so that libdrm can allow interoperability with the new
 | 
					 * are here so that libdrm can allow interoperability with the new
 | 
				
			||||||
 * object APIs
 | 
					 * object APIs
 | 
				
			||||||
| 
						 | 
					@ -131,6 +133,7 @@ struct drm_nouveau_gem_cpu_fini {
 | 
				
			||||||
#define DRM_NOUVEAU_GROBJ_ALLOC        0x04 /* deprecated */
 | 
					#define DRM_NOUVEAU_GROBJ_ALLOC        0x04 /* deprecated */
 | 
				
			||||||
#define DRM_NOUVEAU_NOTIFIEROBJ_ALLOC  0x05 /* deprecated */
 | 
					#define DRM_NOUVEAU_NOTIFIEROBJ_ALLOC  0x05 /* deprecated */
 | 
				
			||||||
#define DRM_NOUVEAU_GPUOBJ_FREE        0x06 /* deprecated */
 | 
					#define DRM_NOUVEAU_GPUOBJ_FREE        0x06 /* deprecated */
 | 
				
			||||||
 | 
					#define DRM_NOUVEAU_NVIF               0x07
 | 
				
			||||||
#define DRM_NOUVEAU_GEM_NEW            0x40
 | 
					#define DRM_NOUVEAU_GEM_NEW            0x40
 | 
				
			||||||
#define DRM_NOUVEAU_GEM_PUSHBUF        0x41
 | 
					#define DRM_NOUVEAU_GEM_PUSHBUF        0x41
 | 
				
			||||||
#define DRM_NOUVEAU_GEM_CPU_PREP       0x42
 | 
					#define DRM_NOUVEAU_GEM_CPU_PREP       0x42
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue