drm/nouveau/core: import ioctl/event interfaces
authorBen Skeggs <bskeggs@redhat.com>
Sat, 9 Aug 2014 18:10:20 +0000 (04:10 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Sat, 9 Aug 2014 19:13:04 +0000 (05:13 +1000)
This forms the basis for the new APIs that will be exposed to userspace,
giving it access to:

- Object method calls, the immediately useful of which is performance
  counters and the abiity to manipulate the ZBC tables.
- Information on the child classes an object supports, in order to avoid
  having to try all supported classes until successful.
- Notifications, which will be used in the future to inform the client
  if its channel was killed due to a lockup, etc.

This commit imports the interfaces, but are not currently used.  The DRM
portion of the driver will be ported to speak to the core using these
interfaces as much as possible.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
13 files changed:
drivers/gpu/drm/nouveau/Makefile
drivers/gpu/drm/nouveau/core/core/client.c
drivers/gpu/drm/nouveau/core/core/ioctl.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/core/notify.c
drivers/gpu/drm/nouveau/core/include/core/client.h
drivers/gpu/drm/nouveau/core/include/core/handle.h
drivers/gpu/drm/nouveau/core/include/core/ioctl.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/include/core/notify.h
drivers/gpu/drm/nouveau/core/include/core/object.h
drivers/gpu/drm/nouveau/core/include/core/printk.h
drivers/gpu/drm/nouveau/core/include/nvif/ioctl.h [new symlink]
drivers/gpu/drm/nouveau/nvif/event.h
drivers/gpu/drm/nouveau/nvif/ioctl.h [new file with mode: 0644]

index 749a047..dfab376 100644 (file)
@@ -14,6 +14,7 @@ nouveau-y += core/core/enum.o
 nouveau-y += core/core/event.o
 nouveau-y += core/core/gpuobj.o
 nouveau-y += core/core/handle.o
+nouveau-y += core/core/ioctl.o
 nouveau-y += core/core/mm.o
 nouveau-y += core/core/namedb.o
 nouveau-y += core/core/notify.o
index 9079c0a..b30fe20 100644 (file)
 #include <core/handle.h>
 #include <core/option.h>
 
+#include <nvif/unpack.h>
+#include <nvif/event.h>
+
 #include <engine/device.h>
 
+struct nvkm_client_notify {
+       struct nouveau_client *client;
+       struct nvkm_notify n;
+       u8 version;
+       u8 size;
+       union {
+               struct nvif_notify_rep_v0 v0;
+       } rep;
+};
+
+static int
+nvkm_client_notify(struct nvkm_notify *n)
+{
+       struct nvkm_client_notify *notify = container_of(n, typeof(*notify), n);
+       struct nouveau_client *client = notify->client;
+       return client->ntfy(&notify->rep, notify->size, n->data, n->size);
+}
+
+int
+nvkm_client_notify_put(struct nouveau_client *client, int index)
+{
+       if (index < ARRAY_SIZE(client->notify)) {
+               if (client->notify[index]) {
+                       nvkm_notify_put(&client->notify[index]->n);
+                       return 0;
+               }
+       }
+       return -ENOENT;
+}
+
+int
+nvkm_client_notify_get(struct nouveau_client *client, int index)
+{
+       if (index < ARRAY_SIZE(client->notify)) {
+               if (client->notify[index]) {
+                       nvkm_notify_get(&client->notify[index]->n);
+                       return 0;
+               }
+       }
+       return -ENOENT;
+}
+
+int
+nvkm_client_notify_del(struct nouveau_client *client, int index)
+{
+       if (index < ARRAY_SIZE(client->notify)) {
+               if (client->notify[index]) {
+                       nvkm_notify_fini(&client->notify[index]->n);
+                       kfree(client->notify[index]);
+                       client->notify[index] = NULL;
+                       return 0;
+               }
+       }
+       return -ENOENT;
+}
+
+int
+nvkm_client_notify_new(struct nouveau_client *client,
+                      struct nvkm_event *event, void *data, u32 size)
+{
+       struct nvkm_client_notify *notify;
+       union {
+               struct nvif_notify_req_v0 v0;
+       } *req = data;
+       u8  index, reply;
+       int ret;
+
+       for (index = 0; index < ARRAY_SIZE(client->notify); index++) {
+               if (!client->notify[index])
+                       break;
+       }
+
+       if (index == ARRAY_SIZE(client->notify))
+               return -ENOSPC;
+
+       notify = kzalloc(sizeof(*notify), GFP_KERNEL);
+       if (!notify)
+               return -ENOMEM;
+
+       nv_ioctl(client, "notify new size %d\n", size);
+       if (nvif_unpack(req->v0, 0, 0, true)) {
+               nv_ioctl(client, "notify new vers %d reply %d route %02x "
+                                "token %llx\n", req->v0.version,
+                        req->v0.reply, req->v0.route, req->v0.token);
+               notify->version = req->v0.version;
+               notify->size = sizeof(notify->rep.v0);
+               notify->rep.v0.version = req->v0.version;
+               notify->rep.v0.route = req->v0.route;
+               notify->rep.v0.token = req->v0.token;
+               reply = req->v0.reply;
+       }
+
+       if (ret == 0) {
+               ret = nvkm_notify_init(event, nvkm_client_notify, false,
+                                      data, size, reply, &notify->n);
+               if (ret == 0) {
+                       client->notify[index] = notify;
+                       notify->client = client;
+                       return 0;
+               }
+       }
+
+       kfree(notify);
+       return 0;
+}
+
 static void
 nouveau_client_dtor(struct nouveau_object *object)
 {
        struct nouveau_client *client = (void *)object;
+       int i;
+       for (i = 0; i < ARRAY_SIZE(client->notify); i++)
+               nvkm_client_notify_del(client, i);
        nouveau_object_ref(NULL, &client->device);
        nouveau_handle_destroy(client->root);
        nouveau_namedb_destroy(&client->base);
@@ -93,9 +205,12 @@ int
 nouveau_client_fini(struct nouveau_client *client, bool suspend)
 {
        const char *name[2] = { "fini", "suspend" };
-       int ret;
-
+       int ret, i;
        nv_debug(client, "%s running\n", name[suspend]);
+       nv_debug(client, "%s notify\n", name[suspend]);
+       for (i = 0; i < ARRAY_SIZE(client->notify); i++)
+               nvkm_client_notify_put(client, i);
+       nv_debug(client, "%s object\n", name[suspend]);
        ret = nouveau_handle_fini(client->root, suspend);
        nv_debug(client, "%s completed with %d\n", name[suspend], ret);
        return ret;
diff --git a/drivers/gpu/drm/nouveau/core/core/ioctl.c b/drivers/gpu/drm/nouveau/core/core/ioctl.c
new file mode 100644 (file)
index 0000000..f7e19bf
--- /dev/null
@@ -0,0 +1,531 @@
+/*
+ * 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 <core/object.h>
+#include <core/parent.h>
+#include <core/handle.h>
+#include <core/namedb.h>
+#include <core/client.h>
+#include <core/device.h>
+#include <core/ioctl.h>
+#include <core/event.h>
+
+#include <nvif/unpack.h>
+#include <nvif/ioctl.h>
+
+static int
+nvkm_ioctl_nop(struct nouveau_handle *handle, void *data, u32 size)
+{
+       struct nouveau_object *object = handle->object;
+       union {
+               struct nvif_ioctl_nop none;
+       } *args = data;
+       int ret;
+
+       nv_ioctl(object, "nop size %d\n", size);
+       if (nvif_unvers(args->none)) {
+               nv_ioctl(object, "nop\n");
+       }
+
+       return ret;
+}
+
+static int
+nvkm_ioctl_sclass(struct nouveau_handle *handle, void *data, u32 size)
+{
+       struct nouveau_object *object = handle->object;
+       union {
+               struct nvif_ioctl_sclass_v0 v0;
+       } *args = data;
+       int ret;
+
+       if (!nv_iclass(object, NV_PARENT_CLASS)) {
+               nv_debug(object, "cannot have children (sclass)\n");
+               return -ENODEV;
+       }
+
+       nv_ioctl(object, "sclass size %d\n", size);
+       if (nvif_unpack(args->v0, 0, 0, true)) {
+               nv_ioctl(object, "sclass vers %d count %d\n",
+                        args->v0.version, args->v0.count);
+               if (size == args->v0.count * sizeof(args->v0.oclass[0])) {
+                       ret = nouveau_parent_lclass(object, args->v0.oclass,
+                                                           args->v0.count);
+                       if (ret >= 0) {
+                               args->v0.count = ret;
+                               ret = 0;
+                       }
+               } else {
+                       ret = -EINVAL;
+               }
+       }
+
+       return ret;
+}
+
+static int
+nvkm_ioctl_new(struct nouveau_handle *parent, void *data, u32 size)
+{
+       union {
+               struct nvif_ioctl_new_v0 v0;
+       } *args = data;
+       struct nouveau_client *client = nouveau_client(parent->object);
+       struct nouveau_object *engctx = NULL;
+       struct nouveau_object *object = NULL;
+       struct nouveau_object *engine;
+       struct nouveau_oclass *oclass;
+       struct nouveau_handle *handle;
+       u32 _handle, _oclass;
+       int ret;
+
+       nv_ioctl(client, "new size %d\n", size);
+       if (nvif_unpack(args->v0, 0, 0, true)) {
+               _handle = args->v0.handle;
+               _oclass = args->v0.oclass;
+       } else
+               return ret;
+
+       nv_ioctl(client, "new vers %d handle %08x class %08x "
+                        "route %02x token %llx\n",
+               args->v0.version, _handle, _oclass,
+               args->v0.route, args->v0.token);
+
+       if (!nv_iclass(parent->object, NV_PARENT_CLASS)) {
+               nv_debug(parent->object, "cannot have children (ctor)\n");
+               ret = -ENODEV;
+               goto fail_class;
+       }
+
+       /* check that parent supports the requested subclass */
+       ret = nouveau_parent_sclass(parent->object, _oclass, &engine, &oclass);
+       if (ret) {
+               nv_debug(parent->object, "illegal class 0x%04x\n", _oclass);
+               goto fail_class;
+       }
+
+       /* make sure engine init has been completed *before* any objects
+        * it controls are created - the constructors may depend on
+        * state calculated at init (ie. default context construction)
+        */
+       if (engine) {
+               ret = nouveau_object_inc(engine);
+               if (ret)
+                       goto fail_class;
+       }
+
+       /* if engine requires it, create a context object to insert
+        * between the parent and its children (eg. PGRAPH context)
+        */
+       if (engine && nv_engine(engine)->cclass) {
+               ret = nouveau_object_ctor(parent->object, engine,
+                                         nv_engine(engine)->cclass,
+                                         data, size, &engctx);
+               if (ret)
+                       goto fail_engctx;
+       } else {
+               nouveau_object_ref(parent->object, &engctx);
+       }
+
+       /* finally, create new object and bind it to its handle */
+       ret = nouveau_object_ctor(engctx, engine, oclass, data, size, &object);
+       client->data = object;
+       if (ret)
+               goto fail_ctor;
+
+       ret = nouveau_object_inc(object);
+       if (ret)
+               goto fail_init;
+
+       ret = nouveau_handle_create(parent->object, parent->name,
+                                   _handle, object, &handle);
+       if (ret)
+               goto fail_handle;
+
+       ret = nouveau_handle_init(handle);
+       handle->route = args->v0.route;
+       handle->token = args->v0.token;
+       if (ret)
+               nouveau_handle_destroy(handle);
+
+fail_handle:
+       nouveau_object_dec(object, false);
+fail_init:
+       nouveau_object_ref(NULL, &object);
+fail_ctor:
+       nouveau_object_ref(NULL, &engctx);
+fail_engctx:
+       if (engine)
+               nouveau_object_dec(engine, false);
+fail_class:
+       return ret;
+}
+
+static int
+nvkm_ioctl_del(struct nouveau_handle *handle, void *data, u32 size)
+{
+       struct nouveau_object *object = handle->object;
+       union {
+               struct nvif_ioctl_del none;
+       } *args = data;
+       int ret;
+
+       nv_ioctl(object, "delete size %d\n", size);
+       if (nvif_unvers(args->none)) {
+               nv_ioctl(object, "delete\n");
+               nouveau_handle_fini(handle, false);
+               nouveau_handle_destroy(handle);
+       }
+
+       return ret;
+}
+
+static int
+nvkm_ioctl_mthd(struct nouveau_handle *handle, void *data, u32 size)
+{
+       struct nouveau_object *object = handle->object;
+       struct nouveau_ofuncs *ofuncs = object->oclass->ofuncs;
+       union {
+               struct nvif_ioctl_mthd_v0 v0;
+       } *args = data;
+       int ret;
+
+       nv_ioctl(object, "mthd size %d\n", size);
+       if (nvif_unpack(args->v0, 0, 0, true)) {
+               nv_ioctl(object, "mthd vers %d mthd %02x\n",
+                        args->v0.version, args->v0.method);
+               if (ret = -ENODEV, ofuncs->mthd)
+                       ret = ofuncs->mthd(object, args->v0.method, data, size);
+       }
+
+       return ret;
+}
+
+
+static int
+nvkm_ioctl_rd(struct nouveau_handle *handle, void *data, u32 size)
+{
+       struct nouveau_object *object = handle->object;
+       struct nouveau_ofuncs *ofuncs = object->oclass->ofuncs;
+       union {
+               struct nvif_ioctl_rd_v0 v0;
+       } *args = data;
+       int ret;
+
+       nv_ioctl(object, "rd size %d\n", size);
+       if (nvif_unpack(args->v0, 0, 0, false)) {
+               nv_ioctl(object, "rd vers %d size %d addr %016llx\n",
+                       args->v0.version, args->v0.size, args->v0.addr);
+               switch (args->v0.size) {
+               case 1:
+                       if (ret = -ENODEV, ofuncs->rd08) {
+                               args->v0.data = nv_ro08(object, args->v0.addr);
+                               ret = 0;
+                       }
+                       break;
+               case 2:
+                       if (ret = -ENODEV, ofuncs->rd16) {
+                               args->v0.data = nv_ro16(object, args->v0.addr);
+                               ret = 0;
+                       }
+                       break;
+               case 4:
+                       if (ret = -ENODEV, ofuncs->rd32) {
+                               args->v0.data = nv_ro32(object, args->v0.addr);
+                               ret = 0;
+                       }
+                       break;
+               default:
+                       ret = -EINVAL;
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+static int
+nvkm_ioctl_wr(struct nouveau_handle *handle, void *data, u32 size)
+{
+       struct nouveau_object *object = handle->object;
+       struct nouveau_ofuncs *ofuncs = object->oclass->ofuncs;
+       union {
+               struct nvif_ioctl_wr_v0 v0;
+       } *args = data;
+       int ret;
+
+       nv_ioctl(object, "wr size %d\n", size);
+       if (nvif_unpack(args->v0, 0, 0, false)) {
+               nv_ioctl(object, "wr vers %d size %d addr %016llx data %08x\n",
+                        args->v0.version, args->v0.size, args->v0.addr,
+                        args->v0.data);
+               switch (args->v0.size) {
+               case 1:
+                       if (ret = -ENODEV, ofuncs->wr08) {
+                               nv_wo08(object, args->v0.addr, args->v0.data);
+                               ret = 0;
+                       }
+                       break;
+               case 2:
+                       if (ret = -ENODEV, ofuncs->wr16) {
+                               nv_wo16(object, args->v0.addr, args->v0.data);
+                               ret = 0;
+                       }
+                       break;
+               case 4:
+                       if (ret = -ENODEV, ofuncs->wr32) {
+                               nv_wo32(object, args->v0.addr, args->v0.data);
+                               ret = 0;
+                       }
+                       break;
+               default:
+                       ret = -EINVAL;
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+static int
+nvkm_ioctl_map(struct nouveau_handle *handle, void *data, u32 size)
+{
+       struct nouveau_object *object = handle->object;
+       struct nouveau_ofuncs *ofuncs = object->oclass->ofuncs;
+       union {
+               struct nvif_ioctl_map_v0 v0;
+       } *args = data;
+       int ret;
+
+       nv_ioctl(object, "map size %d\n", size);
+       if (nvif_unpack(args->v0, 0, 0, false)) {
+               nv_ioctl(object, "map vers %d\n", args->v0.version);
+               if (ret = -ENODEV, ofuncs->map) {
+                       ret = ofuncs->map(object, &args->v0.handle,
+                                                 &args->v0.length);
+               }
+       }
+
+       return ret;
+}
+
+static int
+nvkm_ioctl_unmap(struct nouveau_handle *handle, void *data, u32 size)
+{
+       struct nouveau_object *object = handle->object;
+       union {
+               struct nvif_ioctl_unmap none;
+       } *args = data;
+       int ret;
+
+       nv_ioctl(object, "unmap size %d\n", size);
+       if (nvif_unvers(args->none)) {
+               nv_ioctl(object, "unmap\n");
+       }
+
+       return ret;
+}
+
+static int
+nvkm_ioctl_ntfy_new(struct nouveau_handle *handle, void *data, u32 size)
+{
+       struct nouveau_client *client = nouveau_client(handle->object);
+       struct nouveau_object *object = handle->object;
+       struct nouveau_ofuncs *ofuncs = object->oclass->ofuncs;
+       union {
+               struct nvif_ioctl_ntfy_new_v0 v0;
+       } *args = data;
+       struct nvkm_event *event;
+       int ret;
+
+       nv_ioctl(object, "ntfy new size %d\n", size);
+       if (nvif_unpack(args->v0, 0, 0, true)) {
+               nv_ioctl(object, "ntfy new vers %d event %02x\n",
+                        args->v0.version, args->v0.event);
+               if (ret = -ENODEV, ofuncs->ntfy)
+                       ret = ofuncs->ntfy(object, args->v0.event, &event);
+               if (ret == 0) {
+                       ret = nvkm_client_notify_new(client, event, data, size);
+                       if (ret >= 0) {
+                               args->v0.index = ret;
+                               ret = 0;
+                       }
+               }
+       }
+
+       return ret;
+}
+
+static int
+nvkm_ioctl_ntfy_del(struct nouveau_handle *handle, void *data, u32 size)
+{
+       struct nouveau_client *client = nouveau_client(handle->object);
+       struct nouveau_object *object = handle->object;
+       union {
+               struct nvif_ioctl_ntfy_del_v0 v0;
+       } *args = data;
+       int ret;
+
+       nv_ioctl(object, "ntfy del size %d\n", size);
+       if (nvif_unpack(args->v0, 0, 0, false)) {
+               nv_ioctl(object, "ntfy del vers %d index %d\n",
+                        args->v0.version, args->v0.index);
+               ret = nvkm_client_notify_del(client, args->v0.index);
+       }
+
+       return ret;
+}
+
+static int
+nvkm_ioctl_ntfy_get(struct nouveau_handle *handle, void *data, u32 size)
+{
+       struct nouveau_client *client = nouveau_client(handle->object);
+       struct nouveau_object *object = handle->object;
+       union {
+               struct nvif_ioctl_ntfy_get_v0 v0;
+       } *args = data;
+       int ret;
+
+       nv_ioctl(object, "ntfy get size %d\n", size);
+       if (nvif_unpack(args->v0, 0, 0, false)) {
+               nv_ioctl(object, "ntfy get vers %d index %d\n",
+                        args->v0.version, args->v0.index);
+               ret = nvkm_client_notify_get(client, args->v0.index);
+       }
+
+       return ret;
+}
+
+static int
+nvkm_ioctl_ntfy_put(struct nouveau_handle *handle, void *data, u32 size)
+{
+       struct nouveau_client *client = nouveau_client(handle->object);
+       struct nouveau_object *object = handle->object;
+       union {
+               struct nvif_ioctl_ntfy_put_v0 v0;
+       } *args = data;
+       int ret;
+
+       nv_ioctl(object, "ntfy put size %d\n", size);
+       if (nvif_unpack(args->v0, 0, 0, false)) {
+               nv_ioctl(object, "ntfy put vers %d index %d\n",
+                        args->v0.version, args->v0.index);
+               ret = nvkm_client_notify_put(client, args->v0.index);
+       }
+
+       return ret;
+}
+
+static struct {
+       int version;
+       int (*func)(struct nouveau_handle *, void *, u32);
+}
+nvkm_ioctl_v0[] = {
+       { 0x00, nvkm_ioctl_nop },
+       { 0x00, nvkm_ioctl_sclass },
+       { 0x00, nvkm_ioctl_new },
+       { 0x00, nvkm_ioctl_del },
+       { 0x00, nvkm_ioctl_mthd },
+       { 0x00, nvkm_ioctl_rd },
+       { 0x00, nvkm_ioctl_wr },
+       { 0x00, nvkm_ioctl_map },
+       { 0x00, nvkm_ioctl_unmap },
+       { 0x00, nvkm_ioctl_ntfy_new },
+       { 0x00, nvkm_ioctl_ntfy_del },
+       { 0x00, nvkm_ioctl_ntfy_get },
+       { 0x00, nvkm_ioctl_ntfy_put },
+};
+
+static int
+nvkm_ioctl_path(struct nouveau_handle *parent, u32 type, u32 nr,
+                 u32 *path, void *data, u32 size,
+                 u8 owner, u8 *route, u64 *token)
+{
+       struct nouveau_handle *handle = parent;
+       struct nouveau_namedb *namedb;
+       struct nouveau_object *object;
+       int ret;
+
+       while ((object = parent->object), nr--) {
+               nv_ioctl(object, "path 0x%08x\n", path[nr]);
+               if (!nv_iclass(object, NV_PARENT_CLASS)) {
+                       nv_debug(object, "cannot have children (path)\n");
+                       return -EINVAL;
+               }
+
+               if (!(namedb = (void *)nv_pclass(object, NV_NAMEDB_CLASS)) ||
+                   !(handle = nouveau_namedb_get(namedb, path[nr]))) {
+                       nv_debug(object, "handle 0x%08x not found\n", path[nr]);
+                       return -ENOENT;
+               }
+               nouveau_namedb_put(handle);
+               parent = handle;
+       }
+
+       if (owner != NVIF_IOCTL_V0_OWNER_ANY &&
+           owner != handle->route) {
+               nv_ioctl(object, "object route != owner\n");
+               return -EACCES;
+       }
+       *route = handle->route;
+       *token = handle->token;
+
+       if (ret = -EINVAL, type < ARRAY_SIZE(nvkm_ioctl_v0)) {
+               if (nvkm_ioctl_v0[type].version == 0) {
+                       ret = nvkm_ioctl_v0[type].func(handle, data, size);
+               }
+       }
+
+       return ret;
+}
+
+int
+nvkm_ioctl(struct nouveau_client *client, bool supervisor,
+          void *data, u32 size, void **hack)
+{
+       union {
+               struct nvif_ioctl_v0 v0;
+       } *args = data;
+       int ret;
+
+       client->super = supervisor;
+       nv_ioctl(client, "size %d\n", size);
+
+       if (nvif_unpack(args->v0, 0, 0, true)) {
+               nv_ioctl(client, "vers %d type %02x path %d owner %02x\n",
+                        args->v0.version, args->v0.type, args->v0.path_nr,
+                        args->v0.owner);
+               ret = nvkm_ioctl_path(client->root, args->v0.type,
+                                     args->v0.path_nr, args->v0.path,
+                                     data, size, args->v0.owner,
+                                    &args->v0.route, &args->v0.token);
+       }
+
+       nv_ioctl(client, "return %d\n", ret);
+       if (hack) {
+               *hack = client->data;
+               client->data = NULL;
+       }
+       client->super = false;
+       return ret;
+}
index 460f4ec..76adb81 100644 (file)
  * Authors: Ben Skeggs <bskeggs@redhat.com>
  */
 
-#include <core/os.h>
+#include <core/client.h>
 #include <core/event.h>
 #include <core/notify.h>
 
+#include <nvif/unpack.h>
+#include <nvif/event.h>
+
 static inline void
 nvkm_notify_put_locked(struct nvkm_notify *notify)
 {
index c66eac5..4fc6ab1 100644 (file)
@@ -10,6 +10,11 @@ struct nouveau_client {
        char name[32];
        u32 debug;
        struct nouveau_vm *vm;
+       bool super;
+       void *data;
+
+       int (*ntfy)(const void *, u32, const void *, u32);
+       struct nvkm_client_notify *notify[8];
 };
 
 static inline struct nouveau_client *
@@ -43,4 +48,10 @@ int  nouveau_client_init(struct nouveau_client *);
 int  nouveau_client_fini(struct nouveau_client *, bool suspend);
 const char *nouveau_client_name(void *obj);
 
+int nvkm_client_notify_new(struct nouveau_client *, struct nvkm_event *,
+                          void *data, u32 size);
+int nvkm_client_notify_del(struct nouveau_client *, int index);
+int nvkm_client_notify_get(struct nouveau_client *, int index);
+int nvkm_client_notify_put(struct nouveau_client *, int index);
+
 #endif
index b4789a2..ceb67d7 100644 (file)
@@ -10,6 +10,9 @@ struct nouveau_handle {
        u32 name;
        u32 priv;
 
+       u8  route;
+       u64 token;
+
        struct nouveau_handle *parent;
        struct nouveau_object *object;
 };
diff --git a/drivers/gpu/drm/nouveau/core/include/core/ioctl.h b/drivers/gpu/drm/nouveau/core/include/core/ioctl.h
new file mode 100644 (file)
index 0000000..ac7935c
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __NVKM_IOCTL_H__
+#define __NVKM_IOCTL_H__
+
+int nvkm_ioctl(struct nouveau_client *, bool, void *, u32, void **);
+
+#endif
index 5df2cba..1262d8f 100644 (file)
@@ -15,7 +15,7 @@ struct nvkm_notify {
        /* set by nvkm_event ctor */
        u32 types;
        int index;
-       u size;
+       u32 size;
 
        struct work_struct work;
        /* this is const for a *very* good reason - the data might be on the
index c04143b..b22e8fd 100644 (file)
@@ -78,6 +78,7 @@ struct nouveau_omthds {
        int (*call)(struct nouveau_object *, u32, void *, u32);
 };
 
+struct nvkm_event;
 struct nouveau_ofuncs {
        int  (*ctor)(struct nouveau_object *, struct nouveau_object *,
                     struct nouveau_oclass *, void *data, u32 size,
@@ -85,6 +86,9 @@ struct nouveau_ofuncs {
        void (*dtor)(struct nouveau_object *);
        int  (*init)(struct nouveau_object *);
        int  (*fini)(struct nouveau_object *, bool suspend);
+       int  (*mthd)(struct nouveau_object *, u32, void *, u32);
+       int  (*ntfy)(struct nouveau_object *, u32, struct nvkm_event **);
+       int  (* map)(struct nouveau_object *, u64 *, u32 *);
        u8   (*rd08)(struct nouveau_object *, u64 offset);
        u16  (*rd16)(struct nouveau_object *, u64 offset);
        u32  (*rd32)(struct nouveau_object *, u64 offset);
index 0f9a37b..451b6ed 100644 (file)
@@ -21,6 +21,7 @@ nv_printk_(struct nouveau_object *, int, const char *, ...);
 #define nv_debug(o,f,a...) nv_printk((o), DEBUG, f, ##a)
 #define nv_trace(o,f,a...) nv_printk((o), TRACE, f, ##a)
 #define nv_spam(o,f,a...) nv_printk((o), SPAM, f, ##a)
+#define nv_ioctl(o,f,a...) nv_trace(nouveau_client(o), "ioctl: "f, ##a)
 
 #define nv_assert(f,a...) do {                                                 \
        if (NV_DBG_FATAL <= CONFIG_NOUVEAU_DEBUG)                              \
diff --git a/drivers/gpu/drm/nouveau/core/include/nvif/ioctl.h b/drivers/gpu/drm/nouveau/core/include/nvif/ioctl.h
new file mode 120000 (symlink)
index 0000000..8569c86
--- /dev/null
@@ -0,0 +1 @@
+../../../nvif/ioctl.h
\ No newline at end of file
index 6daced0..cef3ef1 100644 (file)
@@ -1,16 +1,39 @@
 #ifndef __NVIF_EVENT_H__
 #define __NVIF_EVENT_H__
 
+struct nvif_notify_req_v0 {
+       __u8  version;
+       __u8  reply;
+       __u8  pad02[5];
+#define NVIF_NOTIFY_V0_ROUTE_NVIF                                          0x00
+       __u8  route;
+       __u64 token;    /* must be unique */
+       __u8  data[];   /* request data (below) */
+};
+
+struct nvif_notify_rep_v0 {
+       __u8  version;
+       __u8  pad01[6];
+       __u8  route;
+       __u64 token;
+       __u8  data[];   /* reply data (below) */
+};
+
 struct nvif_notify_head_req_v0 {
+       /* nvif_notify_req ... */
        __u8  version;
        __u8  head;
+       __u8  pad02[6];
 };
 
 struct nvif_notify_head_rep_v0 {
+       /* nvif_notify_rep ... */
        __u8  version;
+       __u8  pad01[7];
 };
 
 struct nvif_notify_conn_req_v0 {
+       /* nvif_notify_req ... */
        __u8  version;
 #define NVIF_NOTIFY_CONN_V0_PLUG                                           0x01
 #define NVIF_NOTIFY_CONN_V0_UNPLUG                                         0x02
@@ -18,11 +41,14 @@ struct nvif_notify_conn_req_v0 {
 #define NVIF_NOTIFY_CONN_V0_ANY                                            0x07
        __u8  mask;
        __u8  conn;
+       __u8  pad03[5];
 };
 
 struct nvif_notify_conn_rep_v0 {
+       /* nvif_notify_rep ... */
        __u8  version;
        __u8  mask;
+       __u8  pad02[6];
 };
 
 #endif
diff --git a/drivers/gpu/drm/nouveau/nvif/ioctl.h b/drivers/gpu/drm/nouveau/nvif/ioctl.h
new file mode 100644 (file)
index 0000000..38f24d1
--- /dev/null
@@ -0,0 +1,125 @@
+#ifndef __NVIF_IOCTL_H__
+#define __NVIF_IOCTL_H__
+
+struct nvif_ioctl_v0 {
+       __u8  version;
+#define NVIF_IOCTL_V0_OWNER_NVIF                                           0x00
+#define NVIF_IOCTL_V0_OWNER_ANY                                            0xff
+       __u8  owner;
+#define NVIF_IOCTL_V0_NOP                                                  0x00
+#define NVIF_IOCTL_V0_SCLASS                                               0x01
+#define NVIF_IOCTL_V0_NEW                                                  0x02
+#define NVIF_IOCTL_V0_DEL                                                  0x03
+#define NVIF_IOCTL_V0_MTHD                                                 0x04
+#define NVIF_IOCTL_V0_RD                                                   0x05
+#define NVIF_IOCTL_V0_WR                                                   0x06
+#define NVIF_IOCTL_V0_MAP                                                  0x07
+#define NVIF_IOCTL_V0_UNMAP                                                0x08
+#define NVIF_IOCTL_V0_NTFY_NEW                                             0x09
+#define NVIF_IOCTL_V0_NTFY_DEL                                             0x0a
+#define NVIF_IOCTL_V0_NTFY_GET                                             0x0b
+#define NVIF_IOCTL_V0_NTFY_PUT                                             0x0c
+       __u8  type;
+       __u8  path_nr;
+#define NVIF_IOCTL_V0_ROUTE_NVIF                                           0x00
+#define NVIF_IOCTL_V0_ROUTE_HIDDEN                                         0xff
+       __u8  pad04[3];
+       __u8  route;
+       __u64 token;
+       __u32 path[8];          /* in reverse */
+       __u8  data[];           /* ioctl data (below) */
+};
+
+struct nvif_ioctl_nop {
+};
+
+struct nvif_ioctl_sclass_v0 {
+       /* nvif_ioctl ... */
+       __u8  version;
+       __u8  count;
+       __u8  pad02[6];
+       __u32 oclass[];
+};
+
+struct nvif_ioctl_new_v0 {
+       /* nvif_ioctl ... */
+       __u8  version;
+       __u8  pad01[6];
+       __u8  route;
+       __u64 token;
+       __u32 handle;
+       __u32 oclass;
+       __u8  data[];           /* class data (class.h) */
+};
+
+struct nvif_ioctl_del {
+};
+
+struct nvif_ioctl_rd_v0 {
+       /* nvif_ioctl ... */
+       __u8  version;
+       __u8  size;
+       __u8  pad02[2];
+       __u32 data;
+       __u64 addr;
+};
+
+struct nvif_ioctl_wr_v0 {
+       /* nvif_ioctl ... */
+       __u8  version;
+       __u8  size;
+       __u8  pad02[2];
+       __u32 data;
+       __u64 addr;
+};
+
+struct nvif_ioctl_map_v0 {
+       /* nvif_ioctl ... */
+       __u8  version;
+       __u8  pad01[3];
+       __u32 length;
+       __u64 handle;
+};
+
+struct nvif_ioctl_unmap {
+};
+
+struct nvif_ioctl_ntfy_new_v0 {
+       /* nvif_ioctl ... */
+       __u8  version;
+       __u8  event;
+       __u8  index;
+       __u8  pad03[5];
+       __u8  data[];           /* event request data (event.h) */
+};
+
+struct nvif_ioctl_ntfy_del_v0 {
+       /* nvif_ioctl ... */
+       __u8  version;
+       __u8  index;
+       __u8  pad02[6];
+};
+
+struct nvif_ioctl_ntfy_get_v0 {
+       /* nvif_ioctl ... */
+       __u8  version;
+       __u8  index;
+       __u8  pad02[6];
+};
+
+struct nvif_ioctl_ntfy_put_v0 {
+       /* nvif_ioctl ... */
+       __u8  version;
+       __u8  index;
+       __u8  pad02[6];
+};
+
+struct nvif_ioctl_mthd_v0 {
+       /* nvif_ioctl ... */
+       __u8  version;
+       __u8  method;
+       __u8  pad02[6];
+       __u8  data[];           /* method data (class.h) */
+};
+
+#endif