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