linux/drivers/gpu/drm/nouveau/nouveau_abi16.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 */
  23
  24#include <nvif/client.h>
  25#include <nvif/driver.h>
  26#include <nvif/ioctl.h>
  27#include <nvif/class.h>
  28#include <nvif/cl0002.h>
  29#include <nvif/cla06f.h>
  30#include <nvif/unpack.h>
  31
  32#include "nouveau_drm.h"
  33#include "nouveau_dma.h"
  34#include "nouveau_gem.h"
  35#include "nouveau_chan.h"
  36#include "nouveau_abi16.h"
  37
  38static struct nouveau_abi16 *
  39nouveau_abi16(struct drm_file *file_priv)
  40{
  41        struct nouveau_cli *cli = nouveau_cli(file_priv);
  42        if (!cli->abi16) {
  43                struct nouveau_abi16 *abi16;
  44                cli->abi16 = abi16 = kzalloc(sizeof(*abi16), GFP_KERNEL);
  45                if (cli->abi16) {
  46                        struct nv_device_v0 args = {
  47                                .device = ~0ULL,
  48                        };
  49
  50                        INIT_LIST_HEAD(&abi16->channels);
  51
  52                        /* allocate device object targeting client's default
  53                         * device (ie. the one that belongs to the fd it
  54                         * opened)
  55                         */
  56                        if (nvif_device_init(&cli->base.object, 0, NV_DEVICE,
  57                                             &args, sizeof(args),
  58                                             &abi16->device) == 0)
  59                                return cli->abi16;
  60
  61                        kfree(cli->abi16);
  62                        cli->abi16 = NULL;
  63                }
  64        }
  65        return cli->abi16;
  66}
  67
  68struct nouveau_abi16 *
  69nouveau_abi16_get(struct drm_file *file_priv)
  70{
  71        struct nouveau_cli *cli = nouveau_cli(file_priv);
  72        mutex_lock(&cli->mutex);
  73        if (nouveau_abi16(file_priv))
  74                return cli->abi16;
  75        mutex_unlock(&cli->mutex);
  76        return NULL;
  77}
  78
  79int
  80nouveau_abi16_put(struct nouveau_abi16 *abi16, int ret)
  81{
  82        struct nouveau_cli *cli = (void *)abi16->device.object.client;
  83        mutex_unlock(&cli->mutex);
  84        return ret;
  85}
  86
  87s32
  88nouveau_abi16_swclass(struct nouveau_drm *drm)
  89{
  90        switch (drm->device.info.family) {
  91        case NV_DEVICE_INFO_V0_TNT:
  92                return NVIF_CLASS_SW_NV04;
  93        case NV_DEVICE_INFO_V0_CELSIUS:
  94        case NV_DEVICE_INFO_V0_KELVIN:
  95        case NV_DEVICE_INFO_V0_RANKINE:
  96        case NV_DEVICE_INFO_V0_CURIE:
  97                return NVIF_CLASS_SW_NV10;
  98        case NV_DEVICE_INFO_V0_TESLA:
  99                return NVIF_CLASS_SW_NV50;
 100        case NV_DEVICE_INFO_V0_FERMI:
 101        case NV_DEVICE_INFO_V0_KEPLER:
 102        case NV_DEVICE_INFO_V0_MAXWELL:
 103                return NVIF_CLASS_SW_GF100;
 104        }
 105
 106        return 0x0000;
 107}
 108
 109static void
 110nouveau_abi16_ntfy_fini(struct nouveau_abi16_chan *chan,
 111                        struct nouveau_abi16_ntfy *ntfy)
 112{
 113        nvif_object_fini(&ntfy->object);
 114        nvkm_mm_free(&chan->heap, &ntfy->node);
 115        list_del(&ntfy->head);
 116        kfree(ntfy);
 117}
 118
 119static void
 120nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16,
 121                        struct nouveau_abi16_chan *chan)
 122{
 123        struct nouveau_abi16_ntfy *ntfy, *temp;
 124
 125        /* wait for all activity to stop before releasing notify object, which
 126         * may be still in use */
 127        if (chan->chan && chan->ntfy)
 128                nouveau_channel_idle(chan->chan);
 129
 130        /* cleanup notifier state */
 131        list_for_each_entry_safe(ntfy, temp, &chan->notifiers, head) {
 132                nouveau_abi16_ntfy_fini(chan, ntfy);
 133        }
 134
 135        if (chan->ntfy) {
 136                nouveau_bo_vma_del(chan->ntfy, &chan->ntfy_vma);
 137                nouveau_bo_unpin(chan->ntfy);
 138                drm_gem_object_unreference_unlocked(&chan->ntfy->gem);
 139        }
 140
 141        if (chan->heap.block_size)
 142                nvkm_mm_fini(&chan->heap);
 143
 144        /* destroy channel object, all children will be killed too */
 145        if (chan->chan) {
 146                nouveau_channel_idle(chan->chan);
 147                nouveau_channel_del(&chan->chan);
 148        }
 149
 150        list_del(&chan->head);
 151        kfree(chan);
 152}
 153
 154void
 155nouveau_abi16_fini(struct nouveau_abi16 *abi16)
 156{
 157        struct nouveau_cli *cli = (void *)abi16->device.object.client;
 158        struct nouveau_abi16_chan *chan, *temp;
 159
 160        /* cleanup channels */
 161        list_for_each_entry_safe(chan, temp, &abi16->channels, head) {
 162                nouveau_abi16_chan_fini(abi16, chan);
 163        }
 164
 165        /* destroy the device object */
 166        nvif_device_fini(&abi16->device);
 167
 168        kfree(cli->abi16);
 169        cli->abi16 = NULL;
 170}
 171
 172int
 173nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)
 174{
 175        struct nouveau_cli *cli = nouveau_cli(file_priv);
 176        struct nouveau_drm *drm = nouveau_drm(dev);
 177        struct nvif_device *device = &drm->device;
 178        struct nvkm_gr *gr = nvxx_gr(device);
 179        struct drm_nouveau_getparam *getparam = data;
 180
 181        switch (getparam->param) {
 182        case NOUVEAU_GETPARAM_CHIPSET_ID:
 183                getparam->value = device->info.chipset;
 184                break;
 185        case NOUVEAU_GETPARAM_PCI_VENDOR:
 186                if (nvxx_device(device)->func->pci)
 187                        getparam->value = dev->pdev->vendor;
 188                else
 189                        getparam->value = 0;
 190                break;
 191        case NOUVEAU_GETPARAM_PCI_DEVICE:
 192                if (nvxx_device(device)->func->pci)
 193                        getparam->value = dev->pdev->device;
 194                else
 195                        getparam->value = 0;
 196                break;
 197        case NOUVEAU_GETPARAM_BUS_TYPE:
 198                if (!nvxx_device(device)->func->pci)
 199                        getparam->value = 3;
 200                else
 201                if (drm_pci_device_is_agp(dev))
 202                        getparam->value = 0;
 203                else
 204                if (!pci_is_pcie(dev->pdev))
 205                        getparam->value = 1;
 206                else
 207                        getparam->value = 2;
 208                break;
 209        case NOUVEAU_GETPARAM_FB_SIZE:
 210                getparam->value = drm->gem.vram_available;
 211                break;
 212        case NOUVEAU_GETPARAM_AGP_SIZE:
 213                getparam->value = drm->gem.gart_available;
 214                break;
 215        case NOUVEAU_GETPARAM_VM_VRAM_BASE:
 216                getparam->value = 0; /* deprecated */
 217                break;
 218        case NOUVEAU_GETPARAM_PTIMER_TIME:
 219                getparam->value = nvif_device_time(device);
 220                break;
 221        case NOUVEAU_GETPARAM_HAS_BO_USAGE:
 222                getparam->value = 1;
 223                break;
 224        case NOUVEAU_GETPARAM_HAS_PAGEFLIP:
 225                getparam->value = 1;
 226                break;
 227        case NOUVEAU_GETPARAM_GRAPH_UNITS:
 228                getparam->value = nvkm_gr_units(gr);
 229                break;
 230        default:
 231                NV_PRINTK(dbg, cli, "unknown parameter %lld\n", getparam->param);
 232                return -EINVAL;
 233        }
 234
 235        return 0;
 236}
 237
 238int
 239nouveau_abi16_ioctl_setparam(ABI16_IOCTL_ARGS)
 240{
 241        return -EINVAL;
 242}
 243
 244int
 245nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
 246{
 247        struct drm_nouveau_channel_alloc *init = data;
 248        struct nouveau_cli *cli = nouveau_cli(file_priv);
 249        struct nouveau_drm *drm = nouveau_drm(dev);
 250        struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
 251        struct nouveau_abi16_chan *chan;
 252        struct nvif_device *device;
 253        int ret;
 254
 255        if (unlikely(!abi16))
 256                return -ENOMEM;
 257
 258        if (!drm->channel)
 259                return nouveau_abi16_put(abi16, -ENODEV);
 260
 261        device = &abi16->device;
 262
 263        /* hack to allow channel engine type specification on kepler */
 264        if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) {
 265                if (init->fb_ctxdma_handle != ~0)
 266                        init->fb_ctxdma_handle = KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_GR;
 267                else
 268                        init->fb_ctxdma_handle = init->tt_ctxdma_handle;
 269
 270                /* allow flips to be executed if this is a graphics channel */
 271                init->tt_ctxdma_handle = 0;
 272                if (init->fb_ctxdma_handle == KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_GR)
 273                        init->tt_ctxdma_handle = 1;
 274        }
 275
 276        if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0)
 277                return nouveau_abi16_put(abi16, -EINVAL);
 278
 279        /* allocate "abi16 channel" data and make up a handle for it */
 280        chan = kzalloc(sizeof(*chan), GFP_KERNEL);
 281        if (!chan)
 282                return nouveau_abi16_put(abi16, -ENOMEM);
 283
 284        INIT_LIST_HEAD(&chan->notifiers);
 285        list_add(&chan->head, &abi16->channels);
 286
 287        /* create channel object and initialise dma and fence management */
 288        ret = nouveau_channel_new(drm, device, init->fb_ctxdma_handle,
 289                                  init->tt_ctxdma_handle, &chan->chan);
 290        if (ret)
 291                goto done;
 292
 293        init->channel = chan->chan->chid;
 294
 295        if (device->info.family >= NV_DEVICE_INFO_V0_TESLA)
 296                init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM |
 297                                        NOUVEAU_GEM_DOMAIN_GART;
 298        else
 299        if (chan->chan->push.buffer->bo.mem.mem_type == TTM_PL_VRAM)
 300                init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM;
 301        else
 302                init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART;
 303
 304        if (device->info.family < NV_DEVICE_INFO_V0_CELSIUS) {
 305                init->subchan[0].handle = 0x00000000;
 306                init->subchan[0].grclass = 0x0000;
 307                init->subchan[1].handle = chan->chan->nvsw.handle;
 308                init->subchan[1].grclass = 0x506e;
 309                init->nr_subchan = 2;
 310        }
 311
 312        /* Named memory object area */
 313        ret = nouveau_gem_new(dev, PAGE_SIZE, 0, NOUVEAU_GEM_DOMAIN_GART,
 314                              0, 0, &chan->ntfy);
 315        if (ret == 0)
 316                ret = nouveau_bo_pin(chan->ntfy, TTM_PL_FLAG_TT, false);
 317        if (ret)
 318                goto done;
 319
 320        if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) {
 321                ret = nouveau_bo_vma_add(chan->ntfy, cli->vm,
 322                                        &chan->ntfy_vma);
 323                if (ret)
 324                        goto done;
 325        }
 326
 327        ret = drm_gem_handle_create(file_priv, &chan->ntfy->gem,
 328                                    &init->notifier_handle);
 329        if (ret)
 330                goto done;
 331
 332        ret = nvkm_mm_init(&chan->heap, 0, PAGE_SIZE, 1);
 333done:
 334        if (ret)
 335                nouveau_abi16_chan_fini(abi16, chan);
 336        return nouveau_abi16_put(abi16, ret);
 337}
 338
 339static struct nouveau_abi16_chan *
 340nouveau_abi16_chan(struct nouveau_abi16 *abi16, int channel)
 341{
 342        struct nouveau_abi16_chan *chan;
 343
 344        list_for_each_entry(chan, &abi16->channels, head) {
 345                if (chan->chan->chid == channel)
 346                        return chan;
 347        }
 348
 349        return NULL;
 350}
 351
 352int
 353nouveau_abi16_usif(struct drm_file *file_priv, void *data, u32 size)
 354{
 355        union {
 356                struct nvif_ioctl_v0 v0;
 357        } *args = data;
 358        struct nouveau_abi16_chan *chan;
 359        struct nouveau_abi16 *abi16;
 360        int ret = -ENOSYS;
 361
 362        if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
 363                switch (args->v0.type) {
 364                case NVIF_IOCTL_V0_NEW:
 365                case NVIF_IOCTL_V0_MTHD:
 366                case NVIF_IOCTL_V0_SCLASS:
 367                        break;
 368                default:
 369                        return -EACCES;
 370                }
 371        } else
 372                return ret;
 373
 374        if (!(abi16 = nouveau_abi16(file_priv)))
 375                return -ENOMEM;
 376
 377        if (args->v0.token != ~0ULL) {
 378                if (!(chan = nouveau_abi16_chan(abi16, args->v0.token)))
 379                        return -EINVAL;
 380                args->v0.object = nvif_handle(&chan->chan->user);
 381                args->v0.owner  = NVIF_IOCTL_V0_OWNER_ANY;
 382                return 0;
 383        }
 384
 385        args->v0.object = nvif_handle(&abi16->device.object);
 386        args->v0.owner  = NVIF_IOCTL_V0_OWNER_ANY;
 387        return 0;
 388}
 389
 390int
 391nouveau_abi16_ioctl_channel_free(ABI16_IOCTL_ARGS)
 392{
 393        struct drm_nouveau_channel_free *req = data;
 394        struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
 395        struct nouveau_abi16_chan *chan;
 396
 397        if (unlikely(!abi16))
 398                return -ENOMEM;
 399
 400        chan = nouveau_abi16_chan(abi16, req->channel);
 401        if (!chan)
 402                return nouveau_abi16_put(abi16, -ENOENT);
 403        nouveau_abi16_chan_fini(abi16, chan);
 404        return nouveau_abi16_put(abi16, 0);
 405}
 406
 407int
 408nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS)
 409{
 410        struct drm_nouveau_grobj_alloc *init = data;
 411        struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
 412        struct nouveau_abi16_chan *chan;
 413        struct nouveau_abi16_ntfy *ntfy;
 414        struct nvif_client *client;
 415        struct nvif_sclass *sclass;
 416        s32 oclass = 0;
 417        int ret, i;
 418
 419        if (unlikely(!abi16))
 420                return -ENOMEM;
 421
 422        if (init->handle == ~0)
 423                return nouveau_abi16_put(abi16, -EINVAL);
 424        client = abi16->device.object.client;
 425
 426        chan = nouveau_abi16_chan(abi16, init->channel);
 427        if (!chan)
 428                return nouveau_abi16_put(abi16, -ENOENT);
 429
 430        ret = nvif_object_sclass_get(&chan->chan->user, &sclass);
 431        if (ret < 0)
 432                return nouveau_abi16_put(abi16, ret);
 433
 434        if ((init->class & 0x00ff) == 0x006e) {
 435                /* nvsw: compatibility with older 0x*6e class identifier */
 436                for (i = 0; !oclass && i < ret; i++) {
 437                        switch (sclass[i].oclass) {
 438                        case NVIF_CLASS_SW_NV04:
 439                        case NVIF_CLASS_SW_NV10:
 440                        case NVIF_CLASS_SW_NV50:
 441                        case NVIF_CLASS_SW_GF100:
 442                                oclass = sclass[i].oclass;
 443                                break;
 444                        default:
 445                                break;
 446                        }
 447                }
 448        } else
 449        if ((init->class & 0x00ff) == 0x00b1) {
 450                /* msvld: compatibility with incorrect version exposure */
 451                for (i = 0; i < ret; i++) {
 452                        if ((sclass[i].oclass & 0x00ff) == 0x00b1) {
 453                                oclass = sclass[i].oclass;
 454                                break;
 455                        }
 456                }
 457        } else
 458        if ((init->class & 0x00ff) == 0x00b2) { /* mspdec */
 459                /* mspdec: compatibility with incorrect version exposure */
 460                for (i = 0; i < ret; i++) {
 461                        if ((sclass[i].oclass & 0x00ff) == 0x00b2) {
 462                                oclass = sclass[i].oclass;
 463                                break;
 464                        }
 465                }
 466        } else
 467        if ((init->class & 0x00ff) == 0x00b3) { /* msppp */
 468                /* msppp: compatibility with incorrect version exposure */
 469                for (i = 0; i < ret; i++) {
 470                        if ((sclass[i].oclass & 0x00ff) == 0x00b3) {
 471                                oclass = sclass[i].oclass;
 472                                break;
 473                        }
 474                }
 475        } else {
 476                oclass = init->class;
 477        }
 478
 479        nvif_object_sclass_put(&sclass);
 480        if (!oclass)
 481                return nouveau_abi16_put(abi16, -EINVAL);
 482
 483        ntfy = kzalloc(sizeof(*ntfy), GFP_KERNEL);
 484        if (!ntfy)
 485                return nouveau_abi16_put(abi16, -ENOMEM);
 486
 487        list_add(&ntfy->head, &chan->notifiers);
 488
 489        client->route = NVDRM_OBJECT_ABI16;
 490        ret = nvif_object_init(&chan->chan->user, init->handle, oclass,
 491                               NULL, 0, &ntfy->object);
 492        client->route = NVDRM_OBJECT_NVIF;
 493
 494        if (ret)
 495                nouveau_abi16_ntfy_fini(chan, ntfy);
 496        return nouveau_abi16_put(abi16, ret);
 497}
 498
 499int
 500nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS)
 501{
 502        struct drm_nouveau_notifierobj_alloc *info = data;
 503        struct nouveau_drm *drm = nouveau_drm(dev);
 504        struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
 505        struct nouveau_abi16_chan *chan;
 506        struct nouveau_abi16_ntfy *ntfy;
 507        struct nvif_device *device = &abi16->device;
 508        struct nvif_client *client;
 509        struct nv_dma_v0 args = {};
 510        int ret;
 511
 512        if (unlikely(!abi16))
 513                return -ENOMEM;
 514
 515        /* completely unnecessary for these chipsets... */
 516        if (unlikely(device->info.family >= NV_DEVICE_INFO_V0_FERMI))
 517                return nouveau_abi16_put(abi16, -EINVAL);
 518        client = abi16->device.object.client;
 519
 520        chan = nouveau_abi16_chan(abi16, info->channel);
 521        if (!chan)
 522                return nouveau_abi16_put(abi16, -ENOENT);
 523
 524        ntfy = kzalloc(sizeof(*ntfy), GFP_KERNEL);
 525        if (!ntfy)
 526                return nouveau_abi16_put(abi16, -ENOMEM);
 527
 528        list_add(&ntfy->head, &chan->notifiers);
 529
 530        ret = nvkm_mm_head(&chan->heap, 0, 1, info->size, info->size, 1,
 531                           &ntfy->node);
 532        if (ret)
 533                goto done;
 534
 535        args.start = ntfy->node->offset;
 536        args.limit = ntfy->node->offset + ntfy->node->length - 1;
 537        if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) {
 538                args.target = NV_DMA_V0_TARGET_VM;
 539                args.access = NV_DMA_V0_ACCESS_VM;
 540                args.start += chan->ntfy_vma.offset;
 541                args.limit += chan->ntfy_vma.offset;
 542        } else
 543        if (drm->agp.bridge) {
 544                args.target = NV_DMA_V0_TARGET_AGP;
 545                args.access = NV_DMA_V0_ACCESS_RDWR;
 546                args.start += drm->agp.base + chan->ntfy->bo.offset;
 547                args.limit += drm->agp.base + chan->ntfy->bo.offset;
 548        } else {
 549                args.target = NV_DMA_V0_TARGET_VM;
 550                args.access = NV_DMA_V0_ACCESS_RDWR;
 551                args.start += chan->ntfy->bo.offset;
 552                args.limit += chan->ntfy->bo.offset;
 553        }
 554
 555        client->route = NVDRM_OBJECT_ABI16;
 556        client->super = true;
 557        ret = nvif_object_init(&chan->chan->user, info->handle,
 558                               NV_DMA_IN_MEMORY, &args, sizeof(args),
 559                               &ntfy->object);
 560        client->super = false;
 561        client->route = NVDRM_OBJECT_NVIF;
 562        if (ret)
 563                goto done;
 564
 565        info->offset = ntfy->node->offset;
 566done:
 567        if (ret)
 568                nouveau_abi16_ntfy_fini(chan, ntfy);
 569        return nouveau_abi16_put(abi16, ret);
 570}
 571
 572int
 573nouveau_abi16_ioctl_gpuobj_free(ABI16_IOCTL_ARGS)
 574{
 575        struct drm_nouveau_gpuobj_free *fini = data;
 576        struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
 577        struct nouveau_abi16_chan *chan;
 578        struct nouveau_abi16_ntfy *ntfy;
 579        int ret = -ENOENT;
 580
 581        if (unlikely(!abi16))
 582                return -ENOMEM;
 583
 584        chan = nouveau_abi16_chan(abi16, fini->channel);
 585        if (!chan)
 586                return nouveau_abi16_put(abi16, -EINVAL);
 587
 588        /* synchronize with the user channel and destroy the gpu object */
 589        nouveau_channel_idle(chan->chan);
 590
 591        list_for_each_entry(ntfy, &chan->notifiers, head) {
 592                if (ntfy->object.handle == fini->handle) {
 593                        nouveau_abi16_ntfy_fini(chan, ntfy);
 594                        ret = 0;
 595                        break;
 596                }
 597        }
 598
 599        return nouveau_abi16_put(abi16, ret);
 600}
 601