linux/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c
<<
>>
Prefs
   1/*
   2 * Copyright 2012 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
  23 */
  24#define nvkm_udevice(p) container_of((p), struct nvkm_udevice, object)
  25#include "priv.h"
  26#include "ctrl.h"
  27
  28#include <core/client.h>
  29#include <subdev/fb.h>
  30#include <subdev/instmem.h>
  31#include <subdev/timer.h>
  32
  33#include <nvif/class.h>
  34#include <nvif/cl0080.h>
  35#include <nvif/unpack.h>
  36
  37struct nvkm_udevice {
  38        struct nvkm_object object;
  39        struct nvkm_device *device;
  40};
  41
  42static int
  43nvkm_udevice_info_subdev(struct nvkm_device *device, u64 mthd, u64 *data)
  44{
  45        struct nvkm_subdev *subdev;
  46        enum nvkm_subdev_type type;
  47
  48        switch (mthd & NV_DEVICE_INFO_UNIT) {
  49        case NV_DEVICE_HOST(0): type = NVKM_ENGINE_FIFO; break;
  50        default:
  51                return -EINVAL;
  52        }
  53
  54        subdev = nvkm_device_subdev(device, type, 0);
  55        if (subdev)
  56                return nvkm_subdev_info(subdev, mthd, data);
  57        return -ENODEV;
  58}
  59
  60static void
  61nvkm_udevice_info_v1(struct nvkm_device *device,
  62                     struct nv_device_info_v1_data *args)
  63{
  64        if (args->mthd & NV_DEVICE_INFO_UNIT) {
  65                if (nvkm_udevice_info_subdev(device, args->mthd, &args->data))
  66                        args->mthd = NV_DEVICE_INFO_INVALID;
  67                return;
  68        }
  69        args->mthd = NV_DEVICE_INFO_INVALID;
  70}
  71
  72static int
  73nvkm_udevice_info(struct nvkm_udevice *udev, void *data, u32 size)
  74{
  75        struct nvkm_object *object = &udev->object;
  76        struct nvkm_device *device = udev->device;
  77        struct nvkm_fb *fb = device->fb;
  78        struct nvkm_instmem *imem = device->imem;
  79        union {
  80                struct nv_device_info_v0 v0;
  81                struct nv_device_info_v1 v1;
  82        } *args = data;
  83        int ret = -ENOSYS, i;
  84
  85        nvif_ioctl(object, "device info size %d\n", size);
  86        if (!(ret = nvif_unpack(ret, &data, &size, args->v1, 1, 1, true))) {
  87                nvif_ioctl(object, "device info vers %d count %d\n",
  88                           args->v1.version, args->v1.count);
  89                if (args->v1.count * sizeof(args->v1.data[0]) == size) {
  90                        for (i = 0; i < args->v1.count; i++)
  91                                nvkm_udevice_info_v1(device, &args->v1.data[i]);
  92                        return 0;
  93                }
  94                return -EINVAL;
  95        } else
  96        if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
  97                nvif_ioctl(object, "device info vers %d\n", args->v0.version);
  98        } else
  99                return ret;
 100
 101        switch (device->chipset) {
 102        case 0x01a:
 103        case 0x01f:
 104        case 0x04c:
 105        case 0x04e:
 106        case 0x063:
 107        case 0x067:
 108        case 0x068:
 109        case 0x0aa:
 110        case 0x0ac:
 111        case 0x0af:
 112                args->v0.platform = NV_DEVICE_INFO_V0_IGP;
 113                break;
 114        default:
 115                switch (device->type) {
 116                case NVKM_DEVICE_PCI:
 117                        args->v0.platform = NV_DEVICE_INFO_V0_PCI;
 118                        break;
 119                case NVKM_DEVICE_AGP:
 120                        args->v0.platform = NV_DEVICE_INFO_V0_AGP;
 121                        break;
 122                case NVKM_DEVICE_PCIE:
 123                        args->v0.platform = NV_DEVICE_INFO_V0_PCIE;
 124                        break;
 125                case NVKM_DEVICE_TEGRA:
 126                        args->v0.platform = NV_DEVICE_INFO_V0_SOC;
 127                        break;
 128                default:
 129                        WARN_ON(1);
 130                        break;
 131                }
 132                break;
 133        }
 134
 135        switch (device->card_type) {
 136        case NV_04: args->v0.family = NV_DEVICE_INFO_V0_TNT; break;
 137        case NV_10:
 138        case NV_11: args->v0.family = NV_DEVICE_INFO_V0_CELSIUS; break;
 139        case NV_20: args->v0.family = NV_DEVICE_INFO_V0_KELVIN; break;
 140        case NV_30: args->v0.family = NV_DEVICE_INFO_V0_RANKINE; break;
 141        case NV_40: args->v0.family = NV_DEVICE_INFO_V0_CURIE; break;
 142        case NV_50: args->v0.family = NV_DEVICE_INFO_V0_TESLA; break;
 143        case NV_C0: args->v0.family = NV_DEVICE_INFO_V0_FERMI; break;
 144        case NV_E0: args->v0.family = NV_DEVICE_INFO_V0_KEPLER; break;
 145        case GM100: args->v0.family = NV_DEVICE_INFO_V0_MAXWELL; break;
 146        case GP100: args->v0.family = NV_DEVICE_INFO_V0_PASCAL; break;
 147        case GV100: args->v0.family = NV_DEVICE_INFO_V0_VOLTA; break;
 148        case TU100: args->v0.family = NV_DEVICE_INFO_V0_TURING; break;
 149        case GA100: args->v0.family = NV_DEVICE_INFO_V0_AMPERE; break;
 150        default:
 151                args->v0.family = 0;
 152                break;
 153        }
 154
 155        args->v0.chipset  = device->chipset;
 156        args->v0.revision = device->chiprev;
 157        if (fb && fb->ram)
 158                args->v0.ram_size = args->v0.ram_user = fb->ram->size;
 159        else
 160                args->v0.ram_size = args->v0.ram_user = 0;
 161        if (imem && args->v0.ram_size > 0)
 162                args->v0.ram_user = args->v0.ram_user - imem->reserved;
 163
 164        strncpy(args->v0.chip, device->chip->name, sizeof(args->v0.chip));
 165        strncpy(args->v0.name, device->name, sizeof(args->v0.name));
 166        return 0;
 167}
 168
 169static int
 170nvkm_udevice_time(struct nvkm_udevice *udev, void *data, u32 size)
 171{
 172        struct nvkm_object *object = &udev->object;
 173        struct nvkm_device *device = udev->device;
 174        union {
 175                struct nv_device_time_v0 v0;
 176        } *args = data;
 177        int ret = -ENOSYS;
 178
 179        nvif_ioctl(object, "device time size %d\n", size);
 180        if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
 181                nvif_ioctl(object, "device time vers %d\n", args->v0.version);
 182                args->v0.time = nvkm_timer_read(device->timer);
 183        }
 184
 185        return ret;
 186}
 187
 188static int
 189nvkm_udevice_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
 190{
 191        struct nvkm_udevice *udev = nvkm_udevice(object);
 192        nvif_ioctl(object, "device mthd %08x\n", mthd);
 193        switch (mthd) {
 194        case NV_DEVICE_V0_INFO:
 195                return nvkm_udevice_info(udev, data, size);
 196        case NV_DEVICE_V0_TIME:
 197                return nvkm_udevice_time(udev, data, size);
 198        default:
 199                break;
 200        }
 201        return -EINVAL;
 202}
 203
 204static int
 205nvkm_udevice_rd08(struct nvkm_object *object, u64 addr, u8 *data)
 206{
 207        struct nvkm_udevice *udev = nvkm_udevice(object);
 208        *data = nvkm_rd08(udev->device, addr);
 209        return 0;
 210}
 211
 212static int
 213nvkm_udevice_rd16(struct nvkm_object *object, u64 addr, u16 *data)
 214{
 215        struct nvkm_udevice *udev = nvkm_udevice(object);
 216        *data = nvkm_rd16(udev->device, addr);
 217        return 0;
 218}
 219
 220static int
 221nvkm_udevice_rd32(struct nvkm_object *object, u64 addr, u32 *data)
 222{
 223        struct nvkm_udevice *udev = nvkm_udevice(object);
 224        *data = nvkm_rd32(udev->device, addr);
 225        return 0;
 226}
 227
 228static int
 229nvkm_udevice_wr08(struct nvkm_object *object, u64 addr, u8 data)
 230{
 231        struct nvkm_udevice *udev = nvkm_udevice(object);
 232        nvkm_wr08(udev->device, addr, data);
 233        return 0;
 234}
 235
 236static int
 237nvkm_udevice_wr16(struct nvkm_object *object, u64 addr, u16 data)
 238{
 239        struct nvkm_udevice *udev = nvkm_udevice(object);
 240        nvkm_wr16(udev->device, addr, data);
 241        return 0;
 242}
 243
 244static int
 245nvkm_udevice_wr32(struct nvkm_object *object, u64 addr, u32 data)
 246{
 247        struct nvkm_udevice *udev = nvkm_udevice(object);
 248        nvkm_wr32(udev->device, addr, data);
 249        return 0;
 250}
 251
 252static int
 253nvkm_udevice_map(struct nvkm_object *object, void *argv, u32 argc,
 254                 enum nvkm_object_map *type, u64 *addr, u64 *size)
 255{
 256        struct nvkm_udevice *udev = nvkm_udevice(object);
 257        struct nvkm_device *device = udev->device;
 258        *type = NVKM_OBJECT_MAP_IO;
 259        *addr = device->func->resource_addr(device, 0);
 260        *size = device->func->resource_size(device, 0);
 261        return 0;
 262}
 263
 264static int
 265nvkm_udevice_fini(struct nvkm_object *object, bool suspend)
 266{
 267        struct nvkm_udevice *udev = nvkm_udevice(object);
 268        struct nvkm_device *device = udev->device;
 269        int ret = 0;
 270
 271        mutex_lock(&device->mutex);
 272        if (!--device->refcount) {
 273                ret = nvkm_device_fini(device, suspend);
 274                if (ret && suspend) {
 275                        device->refcount++;
 276                        goto done;
 277                }
 278        }
 279
 280done:
 281        mutex_unlock(&device->mutex);
 282        return ret;
 283}
 284
 285static int
 286nvkm_udevice_init(struct nvkm_object *object)
 287{
 288        struct nvkm_udevice *udev = nvkm_udevice(object);
 289        struct nvkm_device *device = udev->device;
 290        int ret = 0;
 291
 292        mutex_lock(&device->mutex);
 293        if (!device->refcount++) {
 294                ret = nvkm_device_init(device);
 295                if (ret) {
 296                        device->refcount--;
 297                        goto done;
 298                }
 299        }
 300
 301done:
 302        mutex_unlock(&device->mutex);
 303        return ret;
 304}
 305
 306static int
 307nvkm_udevice_child_new(const struct nvkm_oclass *oclass,
 308                       void *data, u32 size, struct nvkm_object **pobject)
 309{
 310        struct nvkm_udevice *udev = nvkm_udevice(oclass->parent);
 311        const struct nvkm_device_oclass *sclass = oclass->priv;
 312        return sclass->ctor(udev->device, oclass, data, size, pobject);
 313}
 314
 315static int
 316nvkm_udevice_child_get(struct nvkm_object *object, int index,
 317                       struct nvkm_oclass *oclass)
 318{
 319        struct nvkm_udevice *udev = nvkm_udevice(object);
 320        struct nvkm_device *device = udev->device;
 321        struct nvkm_engine *engine;
 322        u64 mask = (1ULL << NVKM_ENGINE_DMAOBJ) |
 323                   (1ULL << NVKM_ENGINE_FIFO) |
 324                   (1ULL << NVKM_ENGINE_DISP) |
 325                   (1ULL << NVKM_ENGINE_PM);
 326        const struct nvkm_device_oclass *sclass = NULL;
 327        int i;
 328
 329        for (; i = __ffs64(mask), mask && !sclass; mask &= ~(1ULL << i)) {
 330                if (!(engine = nvkm_device_engine(device, i, 0)) ||
 331                    !(engine->func->base.sclass))
 332                        continue;
 333                oclass->engine = engine;
 334
 335                index -= engine->func->base.sclass(oclass, index, &sclass);
 336        }
 337
 338        if (!sclass) {
 339                if (index-- == 0)
 340                        sclass = &nvkm_control_oclass;
 341                else if (device->mmu && index-- == 0)
 342                        sclass = &device->mmu->user;
 343                else if (device->fault && index-- == 0)
 344                        sclass = &device->fault->user;
 345                else
 346                        return -EINVAL;
 347
 348                oclass->base = sclass->base;
 349        }
 350
 351        oclass->ctor = nvkm_udevice_child_new;
 352        oclass->priv = sclass;
 353        return 0;
 354}
 355
 356static const struct nvkm_object_func
 357nvkm_udevice_super = {
 358        .init = nvkm_udevice_init,
 359        .fini = nvkm_udevice_fini,
 360        .mthd = nvkm_udevice_mthd,
 361        .map = nvkm_udevice_map,
 362        .rd08 = nvkm_udevice_rd08,
 363        .rd16 = nvkm_udevice_rd16,
 364        .rd32 = nvkm_udevice_rd32,
 365        .wr08 = nvkm_udevice_wr08,
 366        .wr16 = nvkm_udevice_wr16,
 367        .wr32 = nvkm_udevice_wr32,
 368        .sclass = nvkm_udevice_child_get,
 369};
 370
 371static const struct nvkm_object_func
 372nvkm_udevice = {
 373        .init = nvkm_udevice_init,
 374        .fini = nvkm_udevice_fini,
 375        .mthd = nvkm_udevice_mthd,
 376        .sclass = nvkm_udevice_child_get,
 377};
 378
 379static int
 380nvkm_udevice_new(const struct nvkm_oclass *oclass, void *data, u32 size,
 381                 struct nvkm_object **pobject)
 382{
 383        union {
 384                struct nv_device_v0 v0;
 385        } *args = data;
 386        struct nvkm_client *client = oclass->client;
 387        struct nvkm_object *parent = &client->object;
 388        const struct nvkm_object_func *func;
 389        struct nvkm_udevice *udev;
 390        int ret = -ENOSYS;
 391
 392        nvif_ioctl(parent, "create device size %d\n", size);
 393        if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
 394                nvif_ioctl(parent, "create device v%d device %016llx\n",
 395                           args->v0.version, args->v0.device);
 396        } else
 397                return ret;
 398
 399        /* give priviledged clients register access */
 400        if (args->v0.priv)
 401                func = &nvkm_udevice_super;
 402        else
 403                func = &nvkm_udevice;
 404
 405        if (!(udev = kzalloc(sizeof(*udev), GFP_KERNEL)))
 406                return -ENOMEM;
 407        nvkm_object_ctor(func, oclass, &udev->object);
 408        *pobject = &udev->object;
 409
 410        /* find the device that matches what the client requested */
 411        if (args->v0.device != ~0)
 412                udev->device = nvkm_device_find(args->v0.device);
 413        else
 414                udev->device = nvkm_device_find(client->device);
 415        if (!udev->device)
 416                return -ENODEV;
 417
 418        return 0;
 419}
 420
 421const struct nvkm_sclass
 422nvkm_udevice_sclass = {
 423        .oclass = NV_DEVICE,
 424        .minver = 0,
 425        .maxver = 0,
 426        .ctor = nvkm_udevice_new,
 427};
 428