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