diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h index dd0db88f8213f14cbc4e33f78676ded24a04fcea..ff6331d7e9e67506c1536515221feb4bd06e8444 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h @@ -23,13 +23,12 @@ void nvkm_client_remove(struct nvkm_client *, struct nvkm_handle *); struct nvkm_handle *nvkm_client_search(struct nvkm_client *, u64 handle); static inline struct nvkm_client * -nvkm_client(void *obj) +nvkm_client(struct nvkm_object *object) { - struct nvkm_object *client = nv_object(obj); - while (client && client->parent) - client = client->parent; - if (client && nv_iclass(client, NV_CLIENT_CLASS)) - return (void *)client; + while (object && object->parent) + object = object->parent; + if (object && nv_iclass(object, NV_CLIENT_CLASS)) + return container_of(object, struct nvkm_client, namedb.parent.object); return NULL; } diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/handle.h b/drivers/gpu/drm/nouveau/include/nvkm/core/handle.h index 64f9e62168ff219a97f08d94dec06a43b7aba1cc..88e8bb17a280ccec46f2cb653fb6e628d2956c43 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/handle.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/handle.h @@ -22,7 +22,7 @@ struct nvkm_handle { u64 handle; }; -int nvkm_handle_create(struct nvkm_object *, u32 parent, u32 handle, +int nvkm_handle_create(struct nvkm_handle *, u32 handle, struct nvkm_object *, struct nvkm_handle **); void nvkm_handle_destroy(struct nvkm_handle *); int nvkm_handle_init(struct nvkm_handle *); diff --git a/drivers/gpu/drm/nouveau/nvkm/core/client.c b/drivers/gpu/drm/nouveau/nvkm/core/client.c index bfe5357d7334836209958c4320a72818a6edd67a..9a7c4bc24a767b53bb80521f59858c94738cddd7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/client.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/client.c @@ -294,8 +294,7 @@ nvkm_client_new(const char *name, u64 device, const char *cfg, if (ret) return ret; - ret = nvkm_handle_create(nv_object(client), ~0, ~0, nv_object(client), - &client->root); + ret = nvkm_handle_create(NULL, ~0, nv_object(client), &client->root); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/core/engctx.c b/drivers/gpu/drm/nouveau/nvkm/core/engctx.c index c9c57874933824484c7f8877451d847201d3a151..be640fd24f77b5dc64c480103c0cde782f216404 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/engctx.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/engctx.c @@ -104,7 +104,7 @@ void nvkm_engctx_destroy(struct nvkm_engctx *engctx) { struct nvkm_engine *engine = engctx->gpuobj.object.engine; - struct nvkm_client *client = nvkm_client(engctx); + struct nvkm_client *client = nvkm_client(&engctx->gpuobj.object); unsigned long save; nvkm_gpuobj_unmap(&engctx->vma); diff --git a/drivers/gpu/drm/nouveau/nvkm/core/handle.c b/drivers/gpu/drm/nouveau/nvkm/core/handle.c index a12ab800170187aea5e1958595776174ca7f651a..0c7cde900df608e998ed30c259fe483dd3a5fa3e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/handle.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/handle.c @@ -94,15 +94,15 @@ nvkm_handle_fini(struct nvkm_handle *handle, bool suspend) } int -nvkm_handle_create(struct nvkm_object *parent, u32 _parent, u32 _handle, +nvkm_handle_create(struct nvkm_handle *parent, u32 _handle, struct nvkm_object *object, struct nvkm_handle **phandle) { struct nvkm_object *namedb; struct nvkm_handle *handle; int ret; - namedb = parent; - while (!nv_iclass(namedb, NV_NAMEDB_CLASS)) + namedb = parent ? parent->object : NULL; + while (namedb && !nv_iclass(namedb, NV_NAMEDB_CLASS)) namedb = namedb->parent; handle = kzalloc(sizeof(*handle), GFP_KERNEL); @@ -114,32 +114,32 @@ nvkm_handle_create(struct nvkm_object *parent, u32 _parent, u32 _handle, handle->name = _handle; handle->priv = ~0; RB_CLEAR_NODE(&handle->rb); - - ret = nvkm_namedb_insert(nv_namedb(namedb), _handle, object, handle); - if (ret) { - kfree(handle); - return ret; - } - - if (nv_parent(parent)->object_attach) { - ret = nv_parent(parent)->object_attach(parent, object, _handle); - if (ret < 0) { - nvkm_handle_destroy(handle); + handle->parent = parent; + nvkm_object_ref(object, &handle->object); + + if (namedb) { + ret = nvkm_namedb_insert(nv_namedb(namedb), _handle, + object, handle); + if (ret) { + kfree(handle); return ret; } - - handle->priv = ret; } - if (object != namedb) { - while (!nv_iclass(namedb, NV_CLIENT_CLASS)) - namedb = namedb->parent; - - handle->parent = nvkm_namedb_get(nv_namedb(namedb), _parent); - if (handle->parent) { - list_add(&handle->head, &handle->parent->tree); - nvkm_namedb_put(handle->parent); + if (parent) { + if (nv_iclass(parent->object, NV_PARENT_CLASS) && + nv_parent(parent->object)->object_attach) { + ret = nv_parent(parent->object)-> + object_attach(parent->object, object, _handle); + if (ret < 0) { + nvkm_handle_destroy(handle); + return ret; + } + + handle->priv = ret; } + + list_add(&handle->head, &handle->parent->tree); } hprintk(handle, TRACE, "created\n"); diff --git a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c index d9c26e40ae320b33a44787baa7c17eeeb737404a..b9c81369043384ed6f35ce2972ea85decdd5bb5b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c @@ -55,34 +55,45 @@ nvkm_ioctl_sclass(struct nvkm_handle *handle, void *data, u32 size) union { struct nvif_ioctl_sclass_v0 v0; } *args = data; - int ret; + struct nvkm_oclass oclass; + int ret, i = 0; nvif_ioctl(object, "sclass size %d\n", size); if (nvif_unpack(args->v0, 0, 0, true)) { nvif_ioctl(object, "sclass vers %d count %d\n", args->v0.version, args->v0.count); - if (size == args->v0.count * sizeof(args->v0.oclass[0])) { + if (size != args->v0.count * sizeof(args->v0.oclass[0])) + return -EINVAL; + + if (object->oclass) { if (nv_iclass(object, NV_PARENT_CLASS)) { ret = nvkm_parent_lclass(object, args->v0.oclass, args->v0.count); - } else { - ret = 0; } - if (ret >= 0) { - args->v0.count = ret; - ret = 0; + + args->v0.count = ret; + return 0; + } + + while (object->func->sclass && + object->func->sclass(object, i, &oclass) >= 0) { + if (i < args->v0.count) { + args->v0.oclass[i].oclass = oclass.base.oclass; + args->v0.oclass[i].minver = oclass.base.minver; + args->v0.oclass[i].maxver = oclass.base.maxver; } - } else { - ret = -EINVAL; + i++; } + + args->v0.count = i; } return ret; } static int -nvkm_ioctl_new(struct nvkm_handle *handle, void *data, u32 size) +nvkm_ioctl_new_old(struct nvkm_handle *handle, void *data, u32 size) { union { struct nvif_ioctl_new_v0 v0; @@ -152,7 +163,6 @@ nvkm_ioctl_new(struct nvkm_handle *handle, void *data, u32 size) /* finally, create new object and bind it to its handle */ ret = nvkm_object_old(engctx, &engine->subdev.object, oclass, data, size, &object); - client->data = object; if (ret) goto fail_ctor; @@ -162,8 +172,7 @@ nvkm_ioctl_new(struct nvkm_handle *handle, void *data, u32 size) if (ret) goto fail_init; - ret = nvkm_handle_create(&parent->object, handle->name, - _handle, object, &handle); + ret = nvkm_handle_create(handle, _handle, object, &handle); if (ret) goto fail_handle; @@ -175,6 +184,7 @@ nvkm_ioctl_new(struct nvkm_handle *handle, void *data, u32 size) handle->handle = args->v0.object; nvkm_client_insert(client, handle); + client->data = object; fail_handle: nvkm_object_dec(object, false); fail_init: @@ -187,6 +197,81 @@ nvkm_ioctl_new(struct nvkm_handle *handle, void *data, u32 size) return ret; } +static int +nvkm_ioctl_new(struct nvkm_handle *handle, void *data, u32 size) +{ + union { + struct nvif_ioctl_new_v0 v0; + } *args = data; + struct nvkm_client *client = handle->object->client; + struct nvkm_object *parent = handle->object; + struct nvkm_object *object = NULL; + struct nvkm_oclass oclass; + int ret, i = 0; + + if (parent->oclass) + return nvkm_ioctl_new_old(handle, data, size); + + nvif_ioctl(parent, "new size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, true)) { + nvif_ioctl(parent, "new vers %d handle %08x class %08x " + "route %02x token %llx object %016llx\n", + args->v0.version, args->v0.handle, args->v0.oclass, + args->v0.route, args->v0.token, args->v0.object); + } else + return ret; + + if (!parent->func->sclass) { + nvif_ioctl(parent, "cannot have children\n"); + return -EINVAL; + } + + do { + memset(&oclass, 0x00, sizeof(oclass)); + oclass.client = client; + oclass.handle = args->v0.handle; + oclass.object = args->v0.object; + oclass.parent = parent; + ret = parent->func->sclass(parent, i++, &oclass); + if (ret) + return ret; + } while (oclass.base.oclass != args->v0.oclass); + + if (oclass.engine) { + oclass.engine = nvkm_engine_ref(oclass.engine); + if (IS_ERR(oclass.engine)) + return PTR_ERR(oclass.engine); + } + + ret = oclass.ctor(&oclass, data, size, &object); + if (ret) + goto fail_object; + + ret = nvkm_object_inc(object); + if (ret) + goto fail_object; + + ret = nvkm_handle_create(handle, args->v0.handle, object, &handle); + if (ret) + goto fail_handle; + + ret = nvkm_handle_init(handle); + handle->route = args->v0.route; + handle->token = args->v0.token; + if (ret) + nvkm_handle_destroy(handle); + + handle->handle = args->v0.object; + nvkm_client_insert(client, handle); + client->data = object; +fail_handle: + nvkm_object_dec(object, false); +fail_object: + nvkm_object_ref(NULL, &object); + nvkm_engine_unref(&oclass.engine); + return ret; +} + static int nvkm_ioctl_del(struct nvkm_handle *handle, void *data, u32 size) { diff --git a/drivers/gpu/drm/nouveau/nvkm/core/namedb.c b/drivers/gpu/drm/nouveau/nvkm/core/namedb.c index ca625c527c57ad7a155ad9627fc248925f58c02d..9be1ce9670346aaf3ad5dac78cda14a42419e463 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/namedb.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/namedb.c @@ -104,9 +104,11 @@ nvkm_namedb_remove(struct nvkm_handle *handle) { struct nvkm_namedb *namedb = handle->namedb; struct nvkm_object *object = handle->object; - write_lock_irq(&namedb->lock); - list_del(&handle->node); - write_unlock_irq(&namedb->lock); + if (handle->namedb) { + write_lock_irq(&namedb->lock); + list_del(&handle->node); + write_unlock_irq(&namedb->lock); + } nvkm_object_ref(NULL, &object); }