diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index 749a0472ae94c0244cd260568ca4712b16a3e59e..dfab376466a1e64cb3720f6a3a25d3b8b3b3c412 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile @@ -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 diff --git a/drivers/gpu/drm/nouveau/core/core/client.c b/drivers/gpu/drm/nouveau/core/core/client.c index 9079c0ac58e6ba071fed5d2f6005af46b21911dc..b30fe2014ecbaca4cb8e21afb257fa672ac79545 100644 --- a/drivers/gpu/drm/nouveau/core/core/client.c +++ b/drivers/gpu/drm/nouveau/core/core/client.c @@ -27,12 +27,124 @@ #include #include +#include +#include + #include +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(¬ify->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, ¬ify->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 index 0000000000000000000000000000000000000000..f7e19bfb489c6920ae6ea6d4231b1affc8fab86c --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/core/ioctl.c @@ -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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +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; +} diff --git a/drivers/gpu/drm/nouveau/core/core/notify.c b/drivers/gpu/drm/nouveau/core/core/notify.c index 460f4ec25bc892e3e0afeaaa695c4d6c22f2060f..76adb81bdea21d2fc2c6f22fd30686a8395bfd03 100644 --- a/drivers/gpu/drm/nouveau/core/core/notify.c +++ b/drivers/gpu/drm/nouveau/core/core/notify.c @@ -22,10 +22,13 @@ * Authors: Ben Skeggs */ -#include +#include #include #include +#include +#include + static inline void nvkm_notify_put_locked(struct nvkm_notify *notify) { diff --git a/drivers/gpu/drm/nouveau/core/include/core/client.h b/drivers/gpu/drm/nouveau/core/include/core/client.h index c66eac5138038cdf3c15d1b54dc6cfe0a8383770..4fc6ab12382d9774694e05d3e664014dc7650cc2 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/client.h +++ b/drivers/gpu/drm/nouveau/core/include/core/client.h @@ -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 diff --git a/drivers/gpu/drm/nouveau/core/include/core/handle.h b/drivers/gpu/drm/nouveau/core/include/core/handle.h index b4789a2e5859feac801fd531be1c26fced642fc8..ceb67d77087522cba3394837a7a2e18336db2872 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/handle.h +++ b/drivers/gpu/drm/nouveau/core/include/core/handle.h @@ -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 index 0000000000000000000000000000000000000000..ac7935c2474eddd826218ce6890b74378aaa5944 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/core/ioctl.h @@ -0,0 +1,6 @@ +#ifndef __NVKM_IOCTL_H__ +#define __NVKM_IOCTL_H__ + +int nvkm_ioctl(struct nouveau_client *, bool, void *, u32, void **); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/notify.h b/drivers/gpu/drm/nouveau/core/include/core/notify.h index 5df2cba43ec7bc8f2e8d750ced8176038a40915d..1262d8f020f377920e260e7c3b25c4dd4334a0e2 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/notify.h +++ b/drivers/gpu/drm/nouveau/core/include/core/notify.h @@ -15,7 +15,7 @@ struct nvkm_notify { /* set by nvkm_event ctor */ u32 types; int index; - u8 size; + u32 size; struct work_struct work; /* this is const for a *very* good reason - the data might be on the diff --git a/drivers/gpu/drm/nouveau/core/include/core/object.h b/drivers/gpu/drm/nouveau/core/include/core/object.h index c04143b4f7794198ccfb66c2b9df6564197818f5..b22e8fd4005e0f0e8e84d2360f2e9eadcaf516cb 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/object.h +++ b/drivers/gpu/drm/nouveau/core/include/core/object.h @@ -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); diff --git a/drivers/gpu/drm/nouveau/core/include/core/printk.h b/drivers/gpu/drm/nouveau/core/include/core/printk.h index 0f9a37bd32b079138ef1122ea749ca55d5b673a7..451b6ed20b7e4c8a704cb9be0d6318371d3d0a74 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/printk.h +++ b/drivers/gpu/drm/nouveau/core/include/core/printk.h @@ -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 index 0000000000000000000000000000000000000000..8569c86907c54c08f9e94e916d62cbd91eff7385 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/nvif/ioctl.h @@ -0,0 +1 @@ +../../../nvif/ioctl.h \ No newline at end of file diff --git a/drivers/gpu/drm/nouveau/nvif/event.h b/drivers/gpu/drm/nouveau/nvif/event.h index 6daced0988930f8caab64444b539ad2c333d15f3..cef3ef103be598b7683756d83b0d375448c8aa33 100644 --- a/drivers/gpu/drm/nouveau/nvif/event.h +++ b/drivers/gpu/drm/nouveau/nvif/event.h @@ -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 index 0000000000000000000000000000000000000000..38f24d1e9f60d745b38eef5cfd787206b23509af --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/ioctl.h @@ -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