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