linux/drivers/gpu/drm/nouveau/nouveau_chan.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#include <nvif/push006c.h>
  25
  26#include <nvif/class.h>
  27#include <nvif/cl0002.h>
  28#include <nvif/cl006b.h>
  29#include <nvif/cl506f.h>
  30#include <nvif/cl906f.h>
  31#include <nvif/cla06f.h>
  32#include <nvif/clc36f.h>
  33#include <nvif/ioctl.h>
  34
  35#include "nouveau_drv.h"
  36#include "nouveau_dma.h"
  37#include "nouveau_bo.h"
  38#include "nouveau_chan.h"
  39#include "nouveau_fence.h"
  40#include "nouveau_abi16.h"
  41#include "nouveau_vmm.h"
  42#include "nouveau_svm.h"
  43
  44MODULE_PARM_DESC(vram_pushbuf, "Create DMA push buffers in VRAM");
  45int nouveau_vram_pushbuf;
  46module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400);
  47
  48static int
  49nouveau_channel_killed(struct nvif_notify *ntfy)
  50{
  51        struct nouveau_channel *chan = container_of(ntfy, typeof(*chan), kill);
  52        struct nouveau_cli *cli = (void *)chan->user.client;
  53        NV_PRINTK(warn, cli, "channel %d killed!\n", chan->chid);
  54        atomic_set(&chan->killed, 1);
  55        if (chan->fence)
  56                nouveau_fence_context_kill(chan->fence, -ENODEV);
  57        return NVIF_NOTIFY_DROP;
  58}
  59
  60int
  61nouveau_channel_idle(struct nouveau_channel *chan)
  62{
  63        if (likely(chan && chan->fence && !atomic_read(&chan->killed))) {
  64                struct nouveau_cli *cli = (void *)chan->user.client;
  65                struct nouveau_fence *fence = NULL;
  66                int ret;
  67
  68                ret = nouveau_fence_new(chan, false, &fence);
  69                if (!ret) {
  70                        ret = nouveau_fence_wait(fence, false, false);
  71                        nouveau_fence_unref(&fence);
  72                }
  73
  74                if (ret) {
  75                        NV_PRINTK(err, cli, "failed to idle channel %d [%s]\n",
  76                                  chan->chid, nvxx_client(&cli->base)->name);
  77                        return ret;
  78                }
  79        }
  80        return 0;
  81}
  82
  83void
  84nouveau_channel_del(struct nouveau_channel **pchan)
  85{
  86        struct nouveau_channel *chan = *pchan;
  87        if (chan) {
  88                struct nouveau_cli *cli = (void *)chan->user.client;
  89
  90                if (chan->fence)
  91                        nouveau_fence(chan->drm)->context_del(chan);
  92
  93                if (cli)
  94                        nouveau_svmm_part(chan->vmm->svmm, chan->inst);
  95
  96                nvif_object_dtor(&chan->nvsw);
  97                nvif_object_dtor(&chan->gart);
  98                nvif_object_dtor(&chan->vram);
  99                nvif_notify_dtor(&chan->kill);
 100                nvif_object_dtor(&chan->user);
 101                nvif_object_dtor(&chan->push.ctxdma);
 102                nouveau_vma_del(&chan->push.vma);
 103                nouveau_bo_unmap(chan->push.buffer);
 104                if (chan->push.buffer && chan->push.buffer->bo.pin_count)
 105                        nouveau_bo_unpin(chan->push.buffer);
 106                nouveau_bo_ref(NULL, &chan->push.buffer);
 107                kfree(chan);
 108        }
 109        *pchan = NULL;
 110}
 111
 112static void
 113nouveau_channel_kick(struct nvif_push *push)
 114{
 115        struct nouveau_channel *chan = container_of(push, typeof(*chan), chan._push);
 116        chan->dma.cur = chan->dma.cur + (chan->chan._push.cur - chan->chan._push.bgn);
 117        FIRE_RING(chan);
 118        chan->chan._push.bgn = chan->chan._push.cur;
 119}
 120
 121static int
 122nouveau_channel_wait(struct nvif_push *push, u32 size)
 123{
 124        struct nouveau_channel *chan = container_of(push, typeof(*chan), chan._push);
 125        int ret;
 126        chan->dma.cur = chan->dma.cur + (chan->chan._push.cur - chan->chan._push.bgn);
 127        ret = RING_SPACE(chan, size);
 128        if (ret == 0) {
 129                chan->chan._push.bgn = chan->chan._push.mem.object.map.ptr;
 130                chan->chan._push.bgn = chan->chan._push.bgn + chan->dma.cur;
 131                chan->chan._push.cur = chan->chan._push.bgn;
 132                chan->chan._push.end = chan->chan._push.bgn + size;
 133        }
 134        return ret;
 135}
 136
 137static int
 138nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device,
 139                     u32 size, struct nouveau_channel **pchan)
 140{
 141        struct nouveau_cli *cli = (void *)device->object.client;
 142        struct nv_dma_v0 args = {};
 143        struct nouveau_channel *chan;
 144        u32 target;
 145        int ret;
 146
 147        chan = *pchan = kzalloc(sizeof(*chan), GFP_KERNEL);
 148        if (!chan)
 149                return -ENOMEM;
 150
 151        chan->device = device;
 152        chan->drm = drm;
 153        chan->vmm = cli->svm.cli ? &cli->svm : &cli->vmm;
 154        atomic_set(&chan->killed, 0);
 155
 156        /* allocate memory for dma push buffer */
 157        target = NOUVEAU_GEM_DOMAIN_GART | NOUVEAU_GEM_DOMAIN_COHERENT;
 158        if (nouveau_vram_pushbuf)
 159                target = NOUVEAU_GEM_DOMAIN_VRAM;
 160
 161        ret = nouveau_bo_new(cli, size, 0, target, 0, 0, NULL, NULL,
 162                            &chan->push.buffer);
 163        if (ret == 0) {
 164                ret = nouveau_bo_pin(chan->push.buffer, target, false);
 165                if (ret == 0)
 166                        ret = nouveau_bo_map(chan->push.buffer);
 167        }
 168
 169        if (ret) {
 170                nouveau_channel_del(pchan);
 171                return ret;
 172        }
 173
 174        chan->chan._push.mem.object.parent = cli->base.object.parent;
 175        chan->chan._push.mem.object.client = &cli->base;
 176        chan->chan._push.mem.object.name = "chanPush";
 177        chan->chan._push.mem.object.map.ptr = chan->push.buffer->kmap.virtual;
 178        chan->chan._push.wait = nouveau_channel_wait;
 179        chan->chan._push.kick = nouveau_channel_kick;
 180        chan->chan.push = &chan->chan._push;
 181
 182        /* create dma object covering the *entire* memory space that the
 183         * pushbuf lives in, this is because the GEM code requires that
 184         * we be able to call out to other (indirect) push buffers
 185         */
 186        chan->push.addr = chan->push.buffer->offset;
 187
 188        if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) {
 189                ret = nouveau_vma_new(chan->push.buffer, chan->vmm,
 190                                      &chan->push.vma);
 191                if (ret) {
 192                        nouveau_channel_del(pchan);
 193                        return ret;
 194                }
 195
 196                chan->push.addr = chan->push.vma->addr;
 197
 198                if (device->info.family >= NV_DEVICE_INFO_V0_FERMI)
 199                        return 0;
 200
 201                args.target = NV_DMA_V0_TARGET_VM;
 202                args.access = NV_DMA_V0_ACCESS_VM;
 203                args.start = 0;
 204                args.limit = chan->vmm->vmm.limit - 1;
 205        } else
 206        if (chan->push.buffer->bo.resource->mem_type == TTM_PL_VRAM) {
 207                if (device->info.family == NV_DEVICE_INFO_V0_TNT) {
 208                        /* nv04 vram pushbuf hack, retarget to its location in
 209                         * the framebuffer bar rather than direct vram access..
 210                         * nfi why this exists, it came from the -nv ddx.
 211                         */
 212                        args.target = NV_DMA_V0_TARGET_PCI;
 213                        args.access = NV_DMA_V0_ACCESS_RDWR;
 214                        args.start = nvxx_device(device)->func->
 215                                resource_addr(nvxx_device(device), 1);
 216                        args.limit = args.start + device->info.ram_user - 1;
 217                } else {
 218                        args.target = NV_DMA_V0_TARGET_VRAM;
 219                        args.access = NV_DMA_V0_ACCESS_RDWR;
 220                        args.start = 0;
 221                        args.limit = device->info.ram_user - 1;
 222                }
 223        } else {
 224                if (chan->drm->agp.bridge) {
 225                        args.target = NV_DMA_V0_TARGET_AGP;
 226                        args.access = NV_DMA_V0_ACCESS_RDWR;
 227                        args.start = chan->drm->agp.base;
 228                        args.limit = chan->drm->agp.base +
 229                                     chan->drm->agp.size - 1;
 230                } else {
 231                        args.target = NV_DMA_V0_TARGET_VM;
 232                        args.access = NV_DMA_V0_ACCESS_RDWR;
 233                        args.start = 0;
 234                        args.limit = chan->vmm->vmm.limit - 1;
 235                }
 236        }
 237
 238        ret = nvif_object_ctor(&device->object, "abi16PushCtxDma", 0,
 239                               NV_DMA_FROM_MEMORY, &args, sizeof(args),
 240                               &chan->push.ctxdma);
 241        if (ret) {
 242                nouveau_channel_del(pchan);
 243                return ret;
 244        }
 245
 246        return 0;
 247}
 248
 249static int
 250nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device,
 251                    u64 runlist, bool priv, struct nouveau_channel **pchan)
 252{
 253        static const u16 oclasses[] = { TURING_CHANNEL_GPFIFO_A,
 254                                        VOLTA_CHANNEL_GPFIFO_A,
 255                                        PASCAL_CHANNEL_GPFIFO_A,
 256                                        MAXWELL_CHANNEL_GPFIFO_A,
 257                                        KEPLER_CHANNEL_GPFIFO_B,
 258                                        KEPLER_CHANNEL_GPFIFO_A,
 259                                        FERMI_CHANNEL_GPFIFO,
 260                                        G82_CHANNEL_GPFIFO,
 261                                        NV50_CHANNEL_GPFIFO,
 262                                        0 };
 263        const u16 *oclass = oclasses;
 264        union {
 265                struct nv50_channel_gpfifo_v0 nv50;
 266                struct fermi_channel_gpfifo_v0 fermi;
 267                struct kepler_channel_gpfifo_a_v0 kepler;
 268                struct volta_channel_gpfifo_a_v0 volta;
 269        } args;
 270        struct nouveau_channel *chan;
 271        u32 size;
 272        int ret;
 273
 274        /* allocate dma push buffer */
 275        ret = nouveau_channel_prep(drm, device, 0x12000, &chan);
 276        *pchan = chan;
 277        if (ret)
 278                return ret;
 279
 280        /* create channel object */
 281        do {
 282                if (oclass[0] >= VOLTA_CHANNEL_GPFIFO_A) {
 283                        args.volta.version = 0;
 284                        args.volta.ilength = 0x02000;
 285                        args.volta.ioffset = 0x10000 + chan->push.addr;
 286                        args.volta.runlist = runlist;
 287                        args.volta.vmm = nvif_handle(&chan->vmm->vmm.object);
 288                        args.volta.priv = priv;
 289                        size = sizeof(args.volta);
 290                } else
 291                if (oclass[0] >= KEPLER_CHANNEL_GPFIFO_A) {
 292                        args.kepler.version = 0;
 293                        args.kepler.ilength = 0x02000;
 294                        args.kepler.ioffset = 0x10000 + chan->push.addr;
 295                        args.kepler.runlist = runlist;
 296                        args.kepler.vmm = nvif_handle(&chan->vmm->vmm.object);
 297                        args.kepler.priv = priv;
 298                        size = sizeof(args.kepler);
 299                } else
 300                if (oclass[0] >= FERMI_CHANNEL_GPFIFO) {
 301                        args.fermi.version = 0;
 302                        args.fermi.ilength = 0x02000;
 303                        args.fermi.ioffset = 0x10000 + chan->push.addr;
 304                        args.fermi.vmm = nvif_handle(&chan->vmm->vmm.object);
 305                        size = sizeof(args.fermi);
 306                } else {
 307                        args.nv50.version = 0;
 308                        args.nv50.ilength = 0x02000;
 309                        args.nv50.ioffset = 0x10000 + chan->push.addr;
 310                        args.nv50.pushbuf = nvif_handle(&chan->push.ctxdma);
 311                        args.nv50.vmm = nvif_handle(&chan->vmm->vmm.object);
 312                        size = sizeof(args.nv50);
 313                }
 314
 315                ret = nvif_object_ctor(&device->object, "abi16ChanUser", 0,
 316                                       *oclass++, &args, size, &chan->user);
 317                if (ret == 0) {
 318                        if (chan->user.oclass >= VOLTA_CHANNEL_GPFIFO_A) {
 319                                chan->chid = args.volta.chid;
 320                                chan->inst = args.volta.inst;
 321                                chan->token = args.volta.token;
 322                        } else
 323                        if (chan->user.oclass >= KEPLER_CHANNEL_GPFIFO_A) {
 324                                chan->chid = args.kepler.chid;
 325                                chan->inst = args.kepler.inst;
 326                        } else
 327                        if (chan->user.oclass >= FERMI_CHANNEL_GPFIFO) {
 328                                chan->chid = args.fermi.chid;
 329                        } else {
 330                                chan->chid = args.nv50.chid;
 331                        }
 332                        return ret;
 333                }
 334        } while (*oclass);
 335
 336        nouveau_channel_del(pchan);
 337        return ret;
 338}
 339
 340static int
 341nouveau_channel_dma(struct nouveau_drm *drm, struct nvif_device *device,
 342                    struct nouveau_channel **pchan)
 343{
 344        static const u16 oclasses[] = { NV40_CHANNEL_DMA,
 345                                        NV17_CHANNEL_DMA,
 346                                        NV10_CHANNEL_DMA,
 347                                        NV03_CHANNEL_DMA,
 348                                        0 };
 349        const u16 *oclass = oclasses;
 350        struct nv03_channel_dma_v0 args;
 351        struct nouveau_channel *chan;
 352        int ret;
 353
 354        /* allocate dma push buffer */
 355        ret = nouveau_channel_prep(drm, device, 0x10000, &chan);
 356        *pchan = chan;
 357        if (ret)
 358                return ret;
 359
 360        /* create channel object */
 361        args.version = 0;
 362        args.pushbuf = nvif_handle(&chan->push.ctxdma);
 363        args.offset = chan->push.addr;
 364
 365        do {
 366                ret = nvif_object_ctor(&device->object, "abi16ChanUser", 0,
 367                                       *oclass++, &args, sizeof(args),
 368                                       &chan->user);
 369                if (ret == 0) {
 370                        chan->chid = args.chid;
 371                        return ret;
 372                }
 373        } while (ret && *oclass);
 374
 375        nouveau_channel_del(pchan);
 376        return ret;
 377}
 378
 379static int
 380nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
 381{
 382        struct nvif_device *device = chan->device;
 383        struct nouveau_drm *drm = chan->drm;
 384        struct nv_dma_v0 args = {};
 385        int ret, i;
 386
 387        nvif_object_map(&chan->user, NULL, 0);
 388
 389        if (chan->user.oclass >= FERMI_CHANNEL_GPFIFO) {
 390                ret = nvif_notify_ctor(&chan->user, "abi16ChanKilled",
 391                                       nouveau_channel_killed,
 392                                       true, NV906F_V0_NTFY_KILLED,
 393                                       NULL, 0, 0, &chan->kill);
 394                if (ret == 0)
 395                        ret = nvif_notify_get(&chan->kill);
 396                if (ret) {
 397                        NV_ERROR(drm, "Failed to request channel kill "
 398                                      "notification: %d\n", ret);
 399                        return ret;
 400                }
 401        }
 402
 403        /* allocate dma objects to cover all allowed vram, and gart */
 404        if (device->info.family < NV_DEVICE_INFO_V0_FERMI) {
 405                if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) {
 406                        args.target = NV_DMA_V0_TARGET_VM;
 407                        args.access = NV_DMA_V0_ACCESS_VM;
 408                        args.start = 0;
 409                        args.limit = chan->vmm->vmm.limit - 1;
 410                } else {
 411                        args.target = NV_DMA_V0_TARGET_VRAM;
 412                        args.access = NV_DMA_V0_ACCESS_RDWR;
 413                        args.start = 0;
 414                        args.limit = device->info.ram_user - 1;
 415                }
 416
 417                ret = nvif_object_ctor(&chan->user, "abi16ChanVramCtxDma", vram,
 418                                       NV_DMA_IN_MEMORY, &args, sizeof(args),
 419                                       &chan->vram);
 420                if (ret)
 421                        return ret;
 422
 423                if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) {
 424                        args.target = NV_DMA_V0_TARGET_VM;
 425                        args.access = NV_DMA_V0_ACCESS_VM;
 426                        args.start = 0;
 427                        args.limit = chan->vmm->vmm.limit - 1;
 428                } else
 429                if (chan->drm->agp.bridge) {
 430                        args.target = NV_DMA_V0_TARGET_AGP;
 431                        args.access = NV_DMA_V0_ACCESS_RDWR;
 432                        args.start = chan->drm->agp.base;
 433                        args.limit = chan->drm->agp.base +
 434                                     chan->drm->agp.size - 1;
 435                } else {
 436                        args.target = NV_DMA_V0_TARGET_VM;
 437                        args.access = NV_DMA_V0_ACCESS_RDWR;
 438                        args.start = 0;
 439                        args.limit = chan->vmm->vmm.limit - 1;
 440                }
 441
 442                ret = nvif_object_ctor(&chan->user, "abi16ChanGartCtxDma", gart,
 443                                       NV_DMA_IN_MEMORY, &args, sizeof(args),
 444                                       &chan->gart);
 445                if (ret)
 446                        return ret;
 447        }
 448
 449        /* initialise dma tracking parameters */
 450        switch (chan->user.oclass & 0x00ff) {
 451        case 0x006b:
 452        case 0x006e:
 453                chan->user_put = 0x40;
 454                chan->user_get = 0x44;
 455                chan->dma.max = (0x10000 / 4) - 2;
 456                break;
 457        default:
 458                chan->user_put = 0x40;
 459                chan->user_get = 0x44;
 460                chan->user_get_hi = 0x60;
 461                chan->dma.ib_base =  0x10000 / 4;
 462                chan->dma.ib_max  = (0x02000 / 8) - 1;
 463                chan->dma.ib_put  = 0;
 464                chan->dma.ib_free = chan->dma.ib_max - chan->dma.ib_put;
 465                chan->dma.max = chan->dma.ib_base;
 466                break;
 467        }
 468
 469        chan->dma.put = 0;
 470        chan->dma.cur = chan->dma.put;
 471        chan->dma.free = chan->dma.max - chan->dma.cur;
 472
 473        ret = PUSH_WAIT(chan->chan.push, NOUVEAU_DMA_SKIPS);
 474        if (ret)
 475                return ret;
 476
 477        for (i = 0; i < NOUVEAU_DMA_SKIPS; i++)
 478                PUSH_DATA(chan->chan.push, 0x00000000);
 479
 480        /* allocate software object class (used for fences on <= nv05) */
 481        if (device->info.family < NV_DEVICE_INFO_V0_CELSIUS) {
 482                ret = nvif_object_ctor(&chan->user, "abi16NvswFence", 0x006e,
 483                                       NVIF_CLASS_SW_NV04,
 484                                       NULL, 0, &chan->nvsw);
 485                if (ret)
 486                        return ret;
 487
 488                ret = PUSH_WAIT(chan->chan.push, 2);
 489                if (ret)
 490                        return ret;
 491
 492                PUSH_NVSQ(chan->chan.push, NV_SW, 0x0000, chan->nvsw.handle);
 493                PUSH_KICK(chan->chan.push);
 494        }
 495
 496        /* initialise synchronisation */
 497        return nouveau_fence(chan->drm)->context_new(chan);
 498}
 499
 500int
 501nouveau_channel_new(struct nouveau_drm *drm, struct nvif_device *device,
 502                    u32 arg0, u32 arg1, bool priv,
 503                    struct nouveau_channel **pchan)
 504{
 505        struct nouveau_cli *cli = (void *)device->object.client;
 506        int ret;
 507
 508        /* hack until fencenv50 is fixed, and agp access relaxed */
 509        ret = nouveau_channel_ind(drm, device, arg0, priv, pchan);
 510        if (ret) {
 511                NV_PRINTK(dbg, cli, "ib channel create, %d\n", ret);
 512                ret = nouveau_channel_dma(drm, device, pchan);
 513                if (ret) {
 514                        NV_PRINTK(dbg, cli, "dma channel create, %d\n", ret);
 515                        return ret;
 516                }
 517        }
 518
 519        ret = nouveau_channel_init(*pchan, arg0, arg1);
 520        if (ret) {
 521                NV_PRINTK(err, cli, "channel failed to initialise, %d\n", ret);
 522                nouveau_channel_del(pchan);
 523                return ret;
 524        }
 525
 526        ret = nouveau_svmm_join((*pchan)->vmm->svmm, (*pchan)->inst);
 527        if (ret)
 528                nouveau_channel_del(pchan);
 529
 530        return ret;
 531}
 532
 533int
 534nouveau_channels_init(struct nouveau_drm *drm)
 535{
 536        struct {
 537                struct nv_device_info_v1 m;
 538                struct {
 539                        struct nv_device_info_v1_data channels;
 540                } v;
 541        } args = {
 542                .m.version = 1,
 543                .m.count = sizeof(args.v) / sizeof(args.v.channels),
 544                .v.channels.mthd = NV_DEVICE_HOST_CHANNELS,
 545        };
 546        struct nvif_object *device = &drm->client.device.object;
 547        int ret;
 548
 549        ret = nvif_object_mthd(device, NV_DEVICE_V0_INFO, &args, sizeof(args));
 550        if (ret || args.v.channels.mthd == NV_DEVICE_INFO_INVALID)
 551                return -ENODEV;
 552
 553        drm->chan.nr = args.v.channels.data;
 554        drm->chan.context_base = dma_fence_context_alloc(drm->chan.nr);
 555        return 0;
 556}
 557