}
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);
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");
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;
/* 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;
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;
handle->handle = args->v0.object;
nvkm_client_insert(client, handle);
+ client->data = object;
fail_handle:
nvkm_object_dec(object, false);
fail_init:
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)
{