0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024 #include <core/ioctl.h>
0025 #include <core/client.h>
0026 #include <core/engine.h>
0027 #include <core/event.h>
0028
0029 #include <nvif/unpack.h>
0030 #include <nvif/ioctl.h>
0031
0032 static int
0033 nvkm_ioctl_nop(struct nvkm_client *client,
0034 struct nvkm_object *object, void *data, u32 size)
0035 {
0036 union {
0037 struct nvif_ioctl_nop_v0 v0;
0038 } *args = data;
0039 int ret = -ENOSYS;
0040
0041 nvif_ioctl(object, "nop size %d\n", size);
0042 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
0043 nvif_ioctl(object, "nop vers %lld\n", args->v0.version);
0044 args->v0.version = NVIF_VERSION_LATEST;
0045 }
0046
0047 return ret;
0048 }
0049
0050 static int
0051 nvkm_ioctl_sclass(struct nvkm_client *client,
0052 struct nvkm_object *object, void *data, u32 size)
0053 {
0054 union {
0055 struct nvif_ioctl_sclass_v0 v0;
0056 } *args = data;
0057 struct nvkm_oclass oclass = { .client = client };
0058 int ret = -ENOSYS, i = 0;
0059
0060 nvif_ioctl(object, "sclass size %d\n", size);
0061 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
0062 nvif_ioctl(object, "sclass vers %d count %d\n",
0063 args->v0.version, args->v0.count);
0064 if (size != args->v0.count * sizeof(args->v0.oclass[0]))
0065 return -EINVAL;
0066
0067 while (object->func->sclass &&
0068 object->func->sclass(object, i, &oclass) >= 0) {
0069 if (i < args->v0.count) {
0070 args->v0.oclass[i].oclass = oclass.base.oclass;
0071 args->v0.oclass[i].minver = oclass.base.minver;
0072 args->v0.oclass[i].maxver = oclass.base.maxver;
0073 }
0074 i++;
0075 }
0076
0077 args->v0.count = i;
0078 }
0079
0080 return ret;
0081 }
0082
0083 static int
0084 nvkm_ioctl_new(struct nvkm_client *client,
0085 struct nvkm_object *parent, void *data, u32 size)
0086 {
0087 union {
0088 struct nvif_ioctl_new_v0 v0;
0089 } *args = data;
0090 struct nvkm_object *object = NULL;
0091 struct nvkm_oclass oclass;
0092 int ret = -ENOSYS, i = 0;
0093
0094 nvif_ioctl(parent, "new size %d\n", size);
0095 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
0096 nvif_ioctl(parent, "new vers %d handle %08x class %08x "
0097 "route %02x token %llx object %016llx\n",
0098 args->v0.version, args->v0.handle, args->v0.oclass,
0099 args->v0.route, args->v0.token, args->v0.object);
0100 } else
0101 return ret;
0102
0103 if (!parent->func->sclass) {
0104 nvif_ioctl(parent, "cannot have children\n");
0105 return -EINVAL;
0106 }
0107
0108 do {
0109 memset(&oclass, 0x00, sizeof(oclass));
0110 oclass.handle = args->v0.handle;
0111 oclass.route = args->v0.route;
0112 oclass.token = args->v0.token;
0113 oclass.object = args->v0.object;
0114 oclass.client = client;
0115 oclass.parent = parent;
0116 ret = parent->func->sclass(parent, i++, &oclass);
0117 if (ret)
0118 return ret;
0119 } while (oclass.base.oclass != args->v0.oclass);
0120
0121 if (oclass.engine) {
0122 oclass.engine = nvkm_engine_ref(oclass.engine);
0123 if (IS_ERR(oclass.engine))
0124 return PTR_ERR(oclass.engine);
0125 }
0126
0127 ret = oclass.ctor(&oclass, data, size, &object);
0128 nvkm_engine_unref(&oclass.engine);
0129 if (ret == 0) {
0130 ret = nvkm_object_init(object);
0131 if (ret == 0) {
0132 list_add_tail(&object->head, &parent->tree);
0133 if (nvkm_object_insert(object)) {
0134 client->data = object;
0135 return 0;
0136 }
0137 ret = -EEXIST;
0138 }
0139 nvkm_object_fini(object, false);
0140 }
0141
0142 nvkm_object_del(&object);
0143 return ret;
0144 }
0145
0146 static int
0147 nvkm_ioctl_del(struct nvkm_client *client,
0148 struct nvkm_object *object, void *data, u32 size)
0149 {
0150 union {
0151 struct nvif_ioctl_del none;
0152 } *args = data;
0153 int ret = -ENOSYS;
0154
0155 nvif_ioctl(object, "delete size %d\n", size);
0156 if (!(ret = nvif_unvers(ret, &data, &size, args->none))) {
0157 nvif_ioctl(object, "delete\n");
0158 nvkm_object_fini(object, false);
0159 nvkm_object_del(&object);
0160 }
0161
0162 return ret ? ret : 1;
0163 }
0164
0165 static int
0166 nvkm_ioctl_mthd(struct nvkm_client *client,
0167 struct nvkm_object *object, void *data, u32 size)
0168 {
0169 union {
0170 struct nvif_ioctl_mthd_v0 v0;
0171 } *args = data;
0172 int ret = -ENOSYS;
0173
0174 nvif_ioctl(object, "mthd size %d\n", size);
0175 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
0176 nvif_ioctl(object, "mthd vers %d mthd %02x\n",
0177 args->v0.version, args->v0.method);
0178 ret = nvkm_object_mthd(object, args->v0.method, data, size);
0179 }
0180
0181 return ret;
0182 }
0183
0184
0185 static int
0186 nvkm_ioctl_rd(struct nvkm_client *client,
0187 struct nvkm_object *object, void *data, u32 size)
0188 {
0189 union {
0190 struct nvif_ioctl_rd_v0 v0;
0191 } *args = data;
0192 union {
0193 u8 b08;
0194 u16 b16;
0195 u32 b32;
0196 } v;
0197 int ret = -ENOSYS;
0198
0199 nvif_ioctl(object, "rd size %d\n", size);
0200 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
0201 nvif_ioctl(object, "rd vers %d size %d addr %016llx\n",
0202 args->v0.version, args->v0.size, args->v0.addr);
0203 switch (args->v0.size) {
0204 case 1:
0205 ret = nvkm_object_rd08(object, args->v0.addr, &v.b08);
0206 args->v0.data = v.b08;
0207 break;
0208 case 2:
0209 ret = nvkm_object_rd16(object, args->v0.addr, &v.b16);
0210 args->v0.data = v.b16;
0211 break;
0212 case 4:
0213 ret = nvkm_object_rd32(object, args->v0.addr, &v.b32);
0214 args->v0.data = v.b32;
0215 break;
0216 default:
0217 ret = -EINVAL;
0218 break;
0219 }
0220 }
0221
0222 return ret;
0223 }
0224
0225 static int
0226 nvkm_ioctl_wr(struct nvkm_client *client,
0227 struct nvkm_object *object, void *data, u32 size)
0228 {
0229 union {
0230 struct nvif_ioctl_wr_v0 v0;
0231 } *args = data;
0232 int ret = -ENOSYS;
0233
0234 nvif_ioctl(object, "wr size %d\n", size);
0235 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
0236 nvif_ioctl(object,
0237 "wr vers %d size %d addr %016llx data %08x\n",
0238 args->v0.version, args->v0.size, args->v0.addr,
0239 args->v0.data);
0240 } else
0241 return ret;
0242
0243 switch (args->v0.size) {
0244 case 1: return nvkm_object_wr08(object, args->v0.addr, args->v0.data);
0245 case 2: return nvkm_object_wr16(object, args->v0.addr, args->v0.data);
0246 case 4: return nvkm_object_wr32(object, args->v0.addr, args->v0.data);
0247 default:
0248 break;
0249 }
0250
0251 return -EINVAL;
0252 }
0253
0254 static int
0255 nvkm_ioctl_map(struct nvkm_client *client,
0256 struct nvkm_object *object, void *data, u32 size)
0257 {
0258 union {
0259 struct nvif_ioctl_map_v0 v0;
0260 } *args = data;
0261 enum nvkm_object_map type;
0262 int ret = -ENOSYS;
0263
0264 nvif_ioctl(object, "map size %d\n", size);
0265 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
0266 nvif_ioctl(object, "map vers %d\n", args->v0.version);
0267 ret = nvkm_object_map(object, data, size, &type,
0268 &args->v0.handle,
0269 &args->v0.length);
0270 if (type == NVKM_OBJECT_MAP_IO)
0271 args->v0.type = NVIF_IOCTL_MAP_V0_IO;
0272 else
0273 args->v0.type = NVIF_IOCTL_MAP_V0_VA;
0274 }
0275
0276 return ret;
0277 }
0278
0279 static int
0280 nvkm_ioctl_unmap(struct nvkm_client *client,
0281 struct nvkm_object *object, void *data, u32 size)
0282 {
0283 union {
0284 struct nvif_ioctl_unmap none;
0285 } *args = data;
0286 int ret = -ENOSYS;
0287
0288 nvif_ioctl(object, "unmap size %d\n", size);
0289 if (!(ret = nvif_unvers(ret, &data, &size, args->none))) {
0290 nvif_ioctl(object, "unmap\n");
0291 ret = nvkm_object_unmap(object);
0292 }
0293
0294 return ret;
0295 }
0296
0297 static int
0298 nvkm_ioctl_ntfy_new(struct nvkm_client *client,
0299 struct nvkm_object *object, void *data, u32 size)
0300 {
0301 union {
0302 struct nvif_ioctl_ntfy_new_v0 v0;
0303 } *args = data;
0304 struct nvkm_event *event;
0305 int ret = -ENOSYS;
0306
0307 nvif_ioctl(object, "ntfy new size %d\n", size);
0308 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
0309 nvif_ioctl(object, "ntfy new vers %d event %02x\n",
0310 args->v0.version, args->v0.event);
0311 ret = nvkm_object_ntfy(object, args->v0.event, &event);
0312 if (ret == 0) {
0313 ret = nvkm_client_notify_new(object, event, data, size);
0314 if (ret >= 0) {
0315 args->v0.index = ret;
0316 ret = 0;
0317 }
0318 }
0319 }
0320
0321 return ret;
0322 }
0323
0324 static int
0325 nvkm_ioctl_ntfy_del(struct nvkm_client *client,
0326 struct nvkm_object *object, void *data, u32 size)
0327 {
0328 union {
0329 struct nvif_ioctl_ntfy_del_v0 v0;
0330 } *args = data;
0331 int ret = -ENOSYS;
0332
0333 nvif_ioctl(object, "ntfy del size %d\n", size);
0334 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
0335 nvif_ioctl(object, "ntfy del vers %d index %d\n",
0336 args->v0.version, args->v0.index);
0337 ret = nvkm_client_notify_del(client, args->v0.index);
0338 }
0339
0340 return ret;
0341 }
0342
0343 static int
0344 nvkm_ioctl_ntfy_get(struct nvkm_client *client,
0345 struct nvkm_object *object, void *data, u32 size)
0346 {
0347 union {
0348 struct nvif_ioctl_ntfy_get_v0 v0;
0349 } *args = data;
0350 int ret = -ENOSYS;
0351
0352 nvif_ioctl(object, "ntfy get size %d\n", size);
0353 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
0354 nvif_ioctl(object, "ntfy get vers %d index %d\n",
0355 args->v0.version, args->v0.index);
0356 ret = nvkm_client_notify_get(client, args->v0.index);
0357 }
0358
0359 return ret;
0360 }
0361
0362 static int
0363 nvkm_ioctl_ntfy_put(struct nvkm_client *client,
0364 struct nvkm_object *object, void *data, u32 size)
0365 {
0366 union {
0367 struct nvif_ioctl_ntfy_put_v0 v0;
0368 } *args = data;
0369 int ret = -ENOSYS;
0370
0371 nvif_ioctl(object, "ntfy put size %d\n", size);
0372 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
0373 nvif_ioctl(object, "ntfy put vers %d index %d\n",
0374 args->v0.version, args->v0.index);
0375 ret = nvkm_client_notify_put(client, args->v0.index);
0376 }
0377
0378 return ret;
0379 }
0380
0381 static struct {
0382 int version;
0383 int (*func)(struct nvkm_client *, struct nvkm_object *, void *, u32);
0384 }
0385 nvkm_ioctl_v0[] = {
0386 { 0x00, nvkm_ioctl_nop },
0387 { 0x00, nvkm_ioctl_sclass },
0388 { 0x00, nvkm_ioctl_new },
0389 { 0x00, nvkm_ioctl_del },
0390 { 0x00, nvkm_ioctl_mthd },
0391 { 0x00, nvkm_ioctl_rd },
0392 { 0x00, nvkm_ioctl_wr },
0393 { 0x00, nvkm_ioctl_map },
0394 { 0x00, nvkm_ioctl_unmap },
0395 { 0x00, nvkm_ioctl_ntfy_new },
0396 { 0x00, nvkm_ioctl_ntfy_del },
0397 { 0x00, nvkm_ioctl_ntfy_get },
0398 { 0x00, nvkm_ioctl_ntfy_put },
0399 };
0400
0401 static int
0402 nvkm_ioctl_path(struct nvkm_client *client, u64 handle, u32 type,
0403 void *data, u32 size, u8 owner, u8 *route, u64 *token)
0404 {
0405 struct nvkm_object *object;
0406 int ret;
0407
0408 object = nvkm_object_search(client, handle, NULL);
0409 if (IS_ERR(object)) {
0410 nvif_ioctl(&client->object, "object not found\n");
0411 return PTR_ERR(object);
0412 }
0413
0414 if (owner != NVIF_IOCTL_V0_OWNER_ANY && owner != object->route) {
0415 nvif_ioctl(&client->object, "route != owner\n");
0416 return -EACCES;
0417 }
0418 *route = object->route;
0419 *token = object->token;
0420
0421 if (ret = -EINVAL, type < ARRAY_SIZE(nvkm_ioctl_v0)) {
0422 if (nvkm_ioctl_v0[type].version == 0)
0423 ret = nvkm_ioctl_v0[type].func(client, object, data, size);
0424 }
0425
0426 return ret;
0427 }
0428
0429 int
0430 nvkm_ioctl(struct nvkm_client *client, void *data, u32 size, void **hack)
0431 {
0432 struct nvkm_object *object = &client->object;
0433 union {
0434 struct nvif_ioctl_v0 v0;
0435 } *args = data;
0436 int ret = -ENOSYS;
0437
0438 nvif_ioctl(object, "size %d\n", size);
0439
0440 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
0441 nvif_ioctl(object,
0442 "vers %d type %02x object %016llx owner %02x\n",
0443 args->v0.version, args->v0.type, args->v0.object,
0444 args->v0.owner);
0445 ret = nvkm_ioctl_path(client, args->v0.object, args->v0.type,
0446 data, size, args->v0.owner,
0447 &args->v0.route, &args->v0.token);
0448 }
0449
0450 if (ret != 1) {
0451 nvif_ioctl(object, "return %d\n", ret);
0452 if (hack) {
0453 *hack = client->data;
0454 client->data = NULL;
0455 }
0456 }
0457
0458 return ret;
0459 }