|
@@ -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 @@ fail_class:
|
|
|
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)
|
|
|
{
|