linux/drivers/gpu/drm/nouveau/nvif/object.c
<<
>>
Prefs
   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
  25#include <nvif/object.h>
  26#include <nvif/client.h>
  27#include <nvif/driver.h>
  28#include <nvif/ioctl.h>
  29
  30int
  31nvif_object_ioctl(struct nvif_object *object, void *data, u32 size, void **hack)
  32{
  33        struct nvif_client *client = object->client;
  34        union {
  35                struct nvif_ioctl_v0 v0;
  36        } *args = data;
  37
  38        if (size >= sizeof(*args) && args->v0.version == 0) {
  39                if (object != &client->object)
  40                        args->v0.object = nvif_handle(object);
  41                else
  42                        args->v0.object = 0;
  43                args->v0.owner = NVIF_IOCTL_V0_OWNER_ANY;
  44        } else
  45                return -ENOSYS;
  46
  47        return client->driver->ioctl(client->object.priv, client->super,
  48                                     data, size, hack);
  49}
  50
  51void
  52nvif_object_sclass_put(struct nvif_sclass **psclass)
  53{
  54        kfree(*psclass);
  55        *psclass = NULL;
  56}
  57
  58int
  59nvif_object_sclass_get(struct nvif_object *object, struct nvif_sclass **psclass)
  60{
  61        struct {
  62                struct nvif_ioctl_v0 ioctl;
  63                struct nvif_ioctl_sclass_v0 sclass;
  64        } *args = NULL;
  65        int ret, cnt = 0, i;
  66        u32 size;
  67
  68        while (1) {
  69                size = sizeof(*args) + cnt * sizeof(args->sclass.oclass[0]);
  70                if (!(args = kmalloc(size, GFP_KERNEL)))
  71                        return -ENOMEM;
  72                args->ioctl.version = 0;
  73                args->ioctl.type = NVIF_IOCTL_V0_SCLASS;
  74                args->sclass.version = 0;
  75                args->sclass.count = cnt;
  76
  77                ret = nvif_object_ioctl(object, args, size, NULL);
  78                if (ret == 0 && args->sclass.count <= cnt)
  79                        break;
  80                cnt = args->sclass.count;
  81                kfree(args);
  82                if (ret != 0)
  83                        return ret;
  84        }
  85
  86        *psclass = kcalloc(args->sclass.count, sizeof(**psclass), GFP_KERNEL);
  87        if (*psclass) {
  88                for (i = 0; i < args->sclass.count; i++) {
  89                        (*psclass)[i].oclass = args->sclass.oclass[i].oclass;
  90                        (*psclass)[i].minver = args->sclass.oclass[i].minver;
  91                        (*psclass)[i].maxver = args->sclass.oclass[i].maxver;
  92                }
  93                ret = args->sclass.count;
  94        } else {
  95                ret = -ENOMEM;
  96        }
  97
  98        kfree(args);
  99        return ret;
 100}
 101
 102u32
 103nvif_object_rd(struct nvif_object *object, int size, u64 addr)
 104{
 105        struct {
 106                struct nvif_ioctl_v0 ioctl;
 107                struct nvif_ioctl_rd_v0 rd;
 108        } args = {
 109                .ioctl.type = NVIF_IOCTL_V0_RD,
 110                .rd.size = size,
 111                .rd.addr = addr,
 112        };
 113        int ret = nvif_object_ioctl(object, &args, sizeof(args), NULL);
 114        if (ret) {
 115                /*XXX: warn? */
 116                return 0;
 117        }
 118        return args.rd.data;
 119}
 120
 121void
 122nvif_object_wr(struct nvif_object *object, int size, u64 addr, u32 data)
 123{
 124        struct {
 125                struct nvif_ioctl_v0 ioctl;
 126                struct nvif_ioctl_wr_v0 wr;
 127        } args = {
 128                .ioctl.type = NVIF_IOCTL_V0_WR,
 129                .wr.size = size,
 130                .wr.addr = addr,
 131                .wr.data = data,
 132        };
 133        int ret = nvif_object_ioctl(object, &args, sizeof(args), NULL);
 134        if (ret) {
 135                /*XXX: warn? */
 136        }
 137}
 138
 139int
 140nvif_object_mthd(struct nvif_object *object, u32 mthd, void *data, u32 size)
 141{
 142        struct {
 143                struct nvif_ioctl_v0 ioctl;
 144                struct nvif_ioctl_mthd_v0 mthd;
 145        } *args;
 146        u8 stack[128];
 147        int ret;
 148
 149        if (sizeof(*args) + size > sizeof(stack)) {
 150                if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL)))
 151                        return -ENOMEM;
 152        } else {
 153                args = (void *)stack;
 154        }
 155        args->ioctl.version = 0;
 156        args->ioctl.type = NVIF_IOCTL_V0_MTHD;
 157        args->mthd.version = 0;
 158        args->mthd.method = mthd;
 159
 160        memcpy(args->mthd.data, data, size);
 161        ret = nvif_object_ioctl(object, args, sizeof(*args) + size, NULL);
 162        memcpy(data, args->mthd.data, size);
 163        if (args != (void *)stack)
 164                kfree(args);
 165        return ret;
 166}
 167
 168void
 169nvif_object_unmap_handle(struct nvif_object *object)
 170{
 171        struct {
 172                struct nvif_ioctl_v0 ioctl;
 173                struct nvif_ioctl_unmap unmap;
 174        } args = {
 175                .ioctl.type = NVIF_IOCTL_V0_UNMAP,
 176        };
 177
 178        nvif_object_ioctl(object, &args, sizeof(args), NULL);
 179}
 180
 181int
 182nvif_object_map_handle(struct nvif_object *object, void *argv, u32 argc,
 183                       u64 *handle, u64 *length)
 184{
 185        struct {
 186                struct nvif_ioctl_v0 ioctl;
 187                struct nvif_ioctl_map_v0 map;
 188        } *args;
 189        u32 argn = sizeof(*args) + argc;
 190        int ret, maptype;
 191
 192        if (!(args = kzalloc(argn, GFP_KERNEL)))
 193                return -ENOMEM;
 194        args->ioctl.type = NVIF_IOCTL_V0_MAP;
 195        memcpy(args->map.data, argv, argc);
 196
 197        ret = nvif_object_ioctl(object, args, argn, NULL);
 198        *handle = args->map.handle;
 199        *length = args->map.length;
 200        maptype = args->map.type;
 201        kfree(args);
 202        return ret ? ret : (maptype == NVIF_IOCTL_MAP_V0_IO);
 203}
 204
 205void
 206nvif_object_unmap(struct nvif_object *object)
 207{
 208        struct nvif_client *client = object->client;
 209        if (object->map.ptr) {
 210                if (object->map.size) {
 211                        client->driver->unmap(client, object->map.ptr,
 212                                                      object->map.size);
 213                        object->map.size = 0;
 214                }
 215                object->map.ptr = NULL;
 216                nvif_object_unmap_handle(object);
 217        }
 218}
 219
 220int
 221nvif_object_map(struct nvif_object *object, void *argv, u32 argc)
 222{
 223        struct nvif_client *client = object->client;
 224        u64 handle, length;
 225        int ret = nvif_object_map_handle(object, argv, argc, &handle, &length);
 226        if (ret >= 0) {
 227                if (ret) {
 228                        object->map.ptr = client->driver->map(client,
 229                                                              handle,
 230                                                              length);
 231                        if (ret = -ENOMEM, object->map.ptr) {
 232                                object->map.size = length;
 233                                return 0;
 234                        }
 235                } else {
 236                        object->map.ptr = (void *)(unsigned long)handle;
 237                        return 0;
 238                }
 239                nvif_object_unmap_handle(object);
 240        }
 241        return ret;
 242}
 243
 244void
 245nvif_object_fini(struct nvif_object *object)
 246{
 247        struct {
 248                struct nvif_ioctl_v0 ioctl;
 249                struct nvif_ioctl_del del;
 250        } args = {
 251                .ioctl.type = NVIF_IOCTL_V0_DEL,
 252        };
 253
 254        if (!object->client)
 255                return;
 256
 257        nvif_object_unmap(object);
 258        nvif_object_ioctl(object, &args, sizeof(args), NULL);
 259        object->client = NULL;
 260}
 261
 262int
 263nvif_object_init(struct nvif_object *parent, u32 handle, s32 oclass,
 264                 void *data, u32 size, struct nvif_object *object)
 265{
 266        struct {
 267                struct nvif_ioctl_v0 ioctl;
 268                struct nvif_ioctl_new_v0 new;
 269        } *args;
 270        int ret = 0;
 271
 272        object->client = NULL;
 273        object->handle = handle;
 274        object->oclass = oclass;
 275        object->map.ptr = NULL;
 276        object->map.size = 0;
 277
 278        if (parent) {
 279                if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL))) {
 280                        nvif_object_fini(object);
 281                        return -ENOMEM;
 282                }
 283
 284                args->ioctl.version = 0;
 285                args->ioctl.type = NVIF_IOCTL_V0_NEW;
 286                args->new.version = 0;
 287                args->new.route = parent->client->route;
 288                args->new.token = nvif_handle(object);
 289                args->new.object = nvif_handle(object);
 290                args->new.handle = handle;
 291                args->new.oclass = oclass;
 292
 293                memcpy(args->new.data, data, size);
 294                ret = nvif_object_ioctl(parent, args, sizeof(*args) + size,
 295                                        &object->priv);
 296                memcpy(data, args->new.data, size);
 297                kfree(args);
 298                if (ret == 0)
 299                        object->client = parent->client;
 300        }
 301
 302        if (ret)
 303                nvif_object_fini(object);
 304        return ret;
 305}
 306