root/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nvkm_ioctl_nop
  2. nvkm_ioctl_sclass
  3. nvkm_ioctl_new
  4. nvkm_ioctl_del
  5. nvkm_ioctl_mthd
  6. nvkm_ioctl_rd
  7. nvkm_ioctl_wr
  8. nvkm_ioctl_map
  9. nvkm_ioctl_unmap
  10. nvkm_ioctl_ntfy_new
  11. nvkm_ioctl_ntfy_del
  12. nvkm_ioctl_ntfy_get
  13. nvkm_ioctl_ntfy_put
  14. nvkm_ioctl_path
  15. nvkm_ioctl

   1 /*
   2  * Copyright 2014 Red Hat Inc.
   3  *
   4  * Permission is hereby granted, free of charge, to any person obtaining a
   5  * copy of this software and associated documentation files (the "Software"),
   6  * to deal in the Software without restriction, including without limitation
   7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8  * and/or sell copies of the Software, and to permit persons to whom the
   9  * Software is furnished to do so, subject to the following conditions:
  10  *
  11  * The above copyright notice and this permission notice shall be included in
  12  * all copies or substantial portions of the Software.
  13  *
  14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20  * OTHER DEALINGS IN THE SOFTWARE.
  21  *
  22  * Authors: Ben Skeggs <bskeggs@redhat.com>
  23  */
  24 #include <core/ioctl.h>
  25 #include <core/client.h>
  26 #include <core/engine.h>
  27 
  28 #include <nvif/unpack.h>
  29 #include <nvif/ioctl.h>
  30 
  31 static int
  32 nvkm_ioctl_nop(struct nvkm_client *client,
  33                struct nvkm_object *object, void *data, u32 size)
  34 {
  35         union {
  36                 struct nvif_ioctl_nop_v0 v0;
  37         } *args = data;
  38         int ret = -ENOSYS;
  39 
  40         nvif_ioctl(object, "nop size %d\n", size);
  41         if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
  42                 nvif_ioctl(object, "nop vers %lld\n", args->v0.version);
  43                 args->v0.version = NVIF_VERSION_LATEST;
  44         }
  45 
  46         return ret;
  47 }
  48 
  49 static int
  50 nvkm_ioctl_sclass(struct nvkm_client *client,
  51                   struct nvkm_object *object, void *data, u32 size)
  52 {
  53         union {
  54                 struct nvif_ioctl_sclass_v0 v0;
  55         } *args = data;
  56         struct nvkm_oclass oclass = { .client = client };
  57         int ret = -ENOSYS, i = 0;
  58 
  59         nvif_ioctl(object, "sclass size %d\n", size);
  60         if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
  61                 nvif_ioctl(object, "sclass vers %d count %d\n",
  62                            args->v0.version, args->v0.count);
  63                 if (size != args->v0.count * sizeof(args->v0.oclass[0]))
  64                         return -EINVAL;
  65 
  66                 while (object->func->sclass &&
  67                        object->func->sclass(object, i, &oclass) >= 0) {
  68                         if (i < args->v0.count) {
  69                                 args->v0.oclass[i].oclass = oclass.base.oclass;
  70                                 args->v0.oclass[i].minver = oclass.base.minver;
  71                                 args->v0.oclass[i].maxver = oclass.base.maxver;
  72                         }
  73                         i++;
  74                 }
  75 
  76                 args->v0.count = i;
  77         }
  78 
  79         return ret;
  80 }
  81 
  82 static int
  83 nvkm_ioctl_new(struct nvkm_client *client,
  84                struct nvkm_object *parent, void *data, u32 size)
  85 {
  86         union {
  87                 struct nvif_ioctl_new_v0 v0;
  88         } *args = data;
  89         struct nvkm_object *object = NULL;
  90         struct nvkm_oclass oclass;
  91         int ret = -ENOSYS, i = 0;
  92 
  93         nvif_ioctl(parent, "new size %d\n", size);
  94         if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
  95                 nvif_ioctl(parent, "new vers %d handle %08x class %08x "
  96                                    "route %02x token %llx object %016llx\n",
  97                            args->v0.version, args->v0.handle, args->v0.oclass,
  98                            args->v0.route, args->v0.token, args->v0.object);
  99         } else
 100                 return ret;
 101 
 102         if (!parent->func->sclass) {
 103                 nvif_ioctl(parent, "cannot have children\n");
 104                 return -EINVAL;
 105         }
 106 
 107         do {
 108                 memset(&oclass, 0x00, sizeof(oclass));
 109                 oclass.handle = args->v0.handle;
 110                 oclass.route  = args->v0.route;
 111                 oclass.token  = args->v0.token;
 112                 oclass.object = args->v0.object;
 113                 oclass.client = client;
 114                 oclass.parent = parent;
 115                 ret = parent->func->sclass(parent, i++, &oclass);
 116                 if (ret)
 117                         return ret;
 118         } while (oclass.base.oclass != args->v0.oclass);
 119 
 120         if (oclass.engine) {
 121                 oclass.engine = nvkm_engine_ref(oclass.engine);
 122                 if (IS_ERR(oclass.engine))
 123                         return PTR_ERR(oclass.engine);
 124         }
 125 
 126         ret = oclass.ctor(&oclass, data, size, &object);
 127         nvkm_engine_unref(&oclass.engine);
 128         if (ret == 0) {
 129                 ret = nvkm_object_init(object);
 130                 if (ret == 0) {
 131                         list_add(&object->head, &parent->tree);
 132                         if (nvkm_object_insert(object)) {
 133                                 client->data = object;
 134                                 return 0;
 135                         }
 136                         ret = -EEXIST;
 137                 }
 138                 nvkm_object_fini(object, false);
 139         }
 140 
 141         nvkm_object_del(&object);
 142         return ret;
 143 }
 144 
 145 static int
 146 nvkm_ioctl_del(struct nvkm_client *client,
 147                struct nvkm_object *object, void *data, u32 size)
 148 {
 149         union {
 150                 struct nvif_ioctl_del none;
 151         } *args = data;
 152         int ret = -ENOSYS;
 153 
 154         nvif_ioctl(object, "delete size %d\n", size);
 155         if (!(ret = nvif_unvers(ret, &data, &size, args->none))) {
 156                 nvif_ioctl(object, "delete\n");
 157                 nvkm_object_fini(object, false);
 158                 nvkm_object_del(&object);
 159         }
 160 
 161         return ret ? ret : 1;
 162 }
 163 
 164 static int
 165 nvkm_ioctl_mthd(struct nvkm_client *client,
 166                 struct nvkm_object *object, void *data, u32 size)
 167 {
 168         union {
 169                 struct nvif_ioctl_mthd_v0 v0;
 170         } *args = data;
 171         int ret = -ENOSYS;
 172 
 173         nvif_ioctl(object, "mthd size %d\n", size);
 174         if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
 175                 nvif_ioctl(object, "mthd vers %d mthd %02x\n",
 176                            args->v0.version, args->v0.method);
 177                 ret = nvkm_object_mthd(object, args->v0.method, data, size);
 178         }
 179 
 180         return ret;
 181 }
 182 
 183 
 184 static int
 185 nvkm_ioctl_rd(struct nvkm_client *client,
 186               struct nvkm_object *object, void *data, u32 size)
 187 {
 188         union {
 189                 struct nvif_ioctl_rd_v0 v0;
 190         } *args = data;
 191         union {
 192                 u8  b08;
 193                 u16 b16;
 194                 u32 b32;
 195         } v;
 196         int ret = -ENOSYS;
 197 
 198         nvif_ioctl(object, "rd size %d\n", size);
 199         if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
 200                 nvif_ioctl(object, "rd vers %d size %d addr %016llx\n",
 201                            args->v0.version, args->v0.size, args->v0.addr);
 202                 switch (args->v0.size) {
 203                 case 1:
 204                         ret = nvkm_object_rd08(object, args->v0.addr, &v.b08);
 205                         args->v0.data = v.b08;
 206                         break;
 207                 case 2:
 208                         ret = nvkm_object_rd16(object, args->v0.addr, &v.b16);
 209                         args->v0.data = v.b16;
 210                         break;
 211                 case 4:
 212                         ret = nvkm_object_rd32(object, args->v0.addr, &v.b32);
 213                         args->v0.data = v.b32;
 214                         break;
 215                 default:
 216                         ret = -EINVAL;
 217                         break;
 218                 }
 219         }
 220 
 221         return ret;
 222 }
 223 
 224 static int
 225 nvkm_ioctl_wr(struct nvkm_client *client,
 226               struct nvkm_object *object, void *data, u32 size)
 227 {
 228         union {
 229                 struct nvif_ioctl_wr_v0 v0;
 230         } *args = data;
 231         int ret = -ENOSYS;
 232 
 233         nvif_ioctl(object, "wr size %d\n", size);
 234         if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
 235                 nvif_ioctl(object,
 236                            "wr vers %d size %d addr %016llx data %08x\n",
 237                            args->v0.version, args->v0.size, args->v0.addr,
 238                            args->v0.data);
 239         } else
 240                 return ret;
 241 
 242         switch (args->v0.size) {
 243         case 1: return nvkm_object_wr08(object, args->v0.addr, args->v0.data);
 244         case 2: return nvkm_object_wr16(object, args->v0.addr, args->v0.data);
 245         case 4: return nvkm_object_wr32(object, args->v0.addr, args->v0.data);
 246         default:
 247                 break;
 248         }
 249 
 250         return -EINVAL;
 251 }
 252 
 253 static int
 254 nvkm_ioctl_map(struct nvkm_client *client,
 255                struct nvkm_object *object, void *data, u32 size)
 256 {
 257         union {
 258                 struct nvif_ioctl_map_v0 v0;
 259         } *args = data;
 260         enum nvkm_object_map type;
 261         int ret = -ENOSYS;
 262 
 263         nvif_ioctl(object, "map size %d\n", size);
 264         if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
 265                 nvif_ioctl(object, "map vers %d\n", args->v0.version);
 266                 ret = nvkm_object_map(object, data, size, &type,
 267                                       &args->v0.handle,
 268                                       &args->v0.length);
 269                 if (type == NVKM_OBJECT_MAP_IO)
 270                         args->v0.type = NVIF_IOCTL_MAP_V0_IO;
 271                 else
 272                         args->v0.type = NVIF_IOCTL_MAP_V0_VA;
 273         }
 274 
 275         return ret;
 276 }
 277 
 278 static int
 279 nvkm_ioctl_unmap(struct nvkm_client *client,
 280                  struct nvkm_object *object, void *data, u32 size)
 281 {
 282         union {
 283                 struct nvif_ioctl_unmap none;
 284         } *args = data;
 285         int ret = -ENOSYS;
 286 
 287         nvif_ioctl(object, "unmap size %d\n", size);
 288         if (!(ret = nvif_unvers(ret, &data, &size, args->none))) {
 289                 nvif_ioctl(object, "unmap\n");
 290                 ret = nvkm_object_unmap(object);
 291         }
 292 
 293         return ret;
 294 }
 295 
 296 static int
 297 nvkm_ioctl_ntfy_new(struct nvkm_client *client,
 298                     struct nvkm_object *object, void *data, u32 size)
 299 {
 300         union {
 301                 struct nvif_ioctl_ntfy_new_v0 v0;
 302         } *args = data;
 303         struct nvkm_event *event;
 304         int ret = -ENOSYS;
 305 
 306         nvif_ioctl(object, "ntfy new size %d\n", size);
 307         if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
 308                 nvif_ioctl(object, "ntfy new vers %d event %02x\n",
 309                            args->v0.version, args->v0.event);
 310                 ret = nvkm_object_ntfy(object, args->v0.event, &event);
 311                 if (ret == 0) {
 312                         ret = nvkm_client_notify_new(object, event, data, size);
 313                         if (ret >= 0) {
 314                                 args->v0.index = ret;
 315                                 ret = 0;
 316                         }
 317                 }
 318         }
 319 
 320         return ret;
 321 }
 322 
 323 static int
 324 nvkm_ioctl_ntfy_del(struct nvkm_client *client,
 325                     struct nvkm_object *object, void *data, u32 size)
 326 {
 327         union {
 328                 struct nvif_ioctl_ntfy_del_v0 v0;
 329         } *args = data;
 330         int ret = -ENOSYS;
 331 
 332         nvif_ioctl(object, "ntfy del size %d\n", size);
 333         if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
 334                 nvif_ioctl(object, "ntfy del vers %d index %d\n",
 335                            args->v0.version, args->v0.index);
 336                 ret = nvkm_client_notify_del(client, args->v0.index);
 337         }
 338 
 339         return ret;
 340 }
 341 
 342 static int
 343 nvkm_ioctl_ntfy_get(struct nvkm_client *client,
 344                     struct nvkm_object *object, void *data, u32 size)
 345 {
 346         union {
 347                 struct nvif_ioctl_ntfy_get_v0 v0;
 348         } *args = data;
 349         int ret = -ENOSYS;
 350 
 351         nvif_ioctl(object, "ntfy get size %d\n", size);
 352         if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
 353                 nvif_ioctl(object, "ntfy get vers %d index %d\n",
 354                            args->v0.version, args->v0.index);
 355                 ret = nvkm_client_notify_get(client, args->v0.index);
 356         }
 357 
 358         return ret;
 359 }
 360 
 361 static int
 362 nvkm_ioctl_ntfy_put(struct nvkm_client *client,
 363                     struct nvkm_object *object, void *data, u32 size)
 364 {
 365         union {
 366                 struct nvif_ioctl_ntfy_put_v0 v0;
 367         } *args = data;
 368         int ret = -ENOSYS;
 369 
 370         nvif_ioctl(object, "ntfy put size %d\n", size);
 371         if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
 372                 nvif_ioctl(object, "ntfy put vers %d index %d\n",
 373                            args->v0.version, args->v0.index);
 374                 ret = nvkm_client_notify_put(client, args->v0.index);
 375         }
 376 
 377         return ret;
 378 }
 379 
 380 static struct {
 381         int version;
 382         int (*func)(struct nvkm_client *, struct nvkm_object *, void *, u32);
 383 }
 384 nvkm_ioctl_v0[] = {
 385         { 0x00, nvkm_ioctl_nop },
 386         { 0x00, nvkm_ioctl_sclass },
 387         { 0x00, nvkm_ioctl_new },
 388         { 0x00, nvkm_ioctl_del },
 389         { 0x00, nvkm_ioctl_mthd },
 390         { 0x00, nvkm_ioctl_rd },
 391         { 0x00, nvkm_ioctl_wr },
 392         { 0x00, nvkm_ioctl_map },
 393         { 0x00, nvkm_ioctl_unmap },
 394         { 0x00, nvkm_ioctl_ntfy_new },
 395         { 0x00, nvkm_ioctl_ntfy_del },
 396         { 0x00, nvkm_ioctl_ntfy_get },
 397         { 0x00, nvkm_ioctl_ntfy_put },
 398 };
 399 
 400 static int
 401 nvkm_ioctl_path(struct nvkm_client *client, u64 handle, u32 type,
 402                 void *data, u32 size, u8 owner, u8 *route, u64 *token)
 403 {
 404         struct nvkm_object *object;
 405         int ret;
 406 
 407         object = nvkm_object_search(client, handle, NULL);
 408         if (IS_ERR(object)) {
 409                 nvif_ioctl(&client->object, "object not found\n");
 410                 return PTR_ERR(object);
 411         }
 412 
 413         if (owner != NVIF_IOCTL_V0_OWNER_ANY && owner != object->route) {
 414                 nvif_ioctl(&client->object, "route != owner\n");
 415                 return -EACCES;
 416         }
 417         *route = object->route;
 418         *token = object->token;
 419 
 420         if (ret = -EINVAL, type < ARRAY_SIZE(nvkm_ioctl_v0)) {
 421                 if (nvkm_ioctl_v0[type].version == 0)
 422                         ret = nvkm_ioctl_v0[type].func(client, object, data, size);
 423         }
 424 
 425         return ret;
 426 }
 427 
 428 int
 429 nvkm_ioctl(struct nvkm_client *client, bool supervisor,
 430            void *data, u32 size, void **hack)
 431 {
 432         struct nvkm_object *object = &client->object;
 433         union {
 434                 struct nvif_ioctl_v0 v0;
 435         } *args = data;
 436         int ret = -ENOSYS;
 437 
 438         client->super = supervisor;
 439         nvif_ioctl(object, "size %d\n", size);
 440 
 441         if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
 442                 nvif_ioctl(object,
 443                            "vers %d type %02x object %016llx owner %02x\n",
 444                            args->v0.version, args->v0.type, args->v0.object,
 445                            args->v0.owner);
 446                 ret = nvkm_ioctl_path(client, args->v0.object, args->v0.type,
 447                                       data, size, args->v0.owner,
 448                                       &args->v0.route, &args->v0.token);
 449         }
 450 
 451         if (ret != 1) {
 452                 nvif_ioctl(object, "return %d\n", ret);
 453                 if (hack) {
 454                         *hack = client->data;
 455                         client->data = NULL;
 456                 }
 457         }
 458 
 459         return ret;
 460 }

/* [<][>][^][v][top][bottom][index][help] */