linux/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.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 <core/client.h>
  26#include <core/engctx.h>
  27#include <core/ramht.h>
  28#include <core/class.h>
  29
  30#include <subdev/timer.h>
  31#include <subdev/bar.h>
  32
  33#include <engine/dmaobj.h>
  34#include <engine/fifo.h>
  35
  36#include "nv04.h"
  37#include "nv50.h"
  38
  39/*******************************************************************************
  40 * FIFO channel objects
  41 ******************************************************************************/
  42
  43static void
  44nv50_fifo_playlist_update_locked(struct nv50_fifo_priv *priv)
  45{
  46        struct nouveau_bar *bar = nouveau_bar(priv);
  47        struct nouveau_gpuobj *cur;
  48        int i, p;
  49
  50        cur = priv->playlist[priv->cur_playlist];
  51        priv->cur_playlist = !priv->cur_playlist;
  52
  53        for (i = priv->base.min, p = 0; i < priv->base.max; i++) {
  54                if (nv_rd32(priv, 0x002600 + (i * 4)) & 0x80000000)
  55                        nv_wo32(cur, p++ * 4, i);
  56        }
  57
  58        bar->flush(bar);
  59
  60        nv_wr32(priv, 0x0032f4, cur->addr >> 12);
  61        nv_wr32(priv, 0x0032ec, p);
  62        nv_wr32(priv, 0x002500, 0x00000101);
  63}
  64
  65void
  66nv50_fifo_playlist_update(struct nv50_fifo_priv *priv)
  67{
  68        mutex_lock(&nv_subdev(priv)->mutex);
  69        nv50_fifo_playlist_update_locked(priv);
  70        mutex_unlock(&nv_subdev(priv)->mutex);
  71}
  72
  73static int
  74nv50_fifo_context_attach(struct nouveau_object *parent,
  75                         struct nouveau_object *object)
  76{
  77        struct nouveau_bar *bar = nouveau_bar(parent);
  78        struct nv50_fifo_base *base = (void *)parent->parent;
  79        struct nouveau_gpuobj *ectx = (void *)object;
  80        u64 limit = ectx->addr + ectx->size - 1;
  81        u64 start = ectx->addr;
  82        u32 addr;
  83
  84        switch (nv_engidx(object->engine)) {
  85        case NVDEV_ENGINE_SW   : return 0;
  86        case NVDEV_ENGINE_GR   : addr = 0x0000; break;
  87        case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
  88        default:
  89                return -EINVAL;
  90        }
  91
  92        nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
  93        nv_wo32(base->eng, addr + 0x00, 0x00190000);
  94        nv_wo32(base->eng, addr + 0x04, lower_32_bits(limit));
  95        nv_wo32(base->eng, addr + 0x08, lower_32_bits(start));
  96        nv_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 |
  97                                        upper_32_bits(start));
  98        nv_wo32(base->eng, addr + 0x10, 0x00000000);
  99        nv_wo32(base->eng, addr + 0x14, 0x00000000);
 100        bar->flush(bar);
 101        return 0;
 102}
 103
 104static int
 105nv50_fifo_context_detach(struct nouveau_object *parent, bool suspend,
 106                         struct nouveau_object *object)
 107{
 108        struct nouveau_bar *bar = nouveau_bar(parent);
 109        struct nv50_fifo_priv *priv = (void *)parent->engine;
 110        struct nv50_fifo_base *base = (void *)parent->parent;
 111        struct nv50_fifo_chan *chan = (void *)parent;
 112        u32 addr, me;
 113        int ret = 0;
 114
 115        switch (nv_engidx(object->engine)) {
 116        case NVDEV_ENGINE_SW   : return 0;
 117        case NVDEV_ENGINE_GR   : addr = 0x0000; break;
 118        case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
 119        default:
 120                return -EINVAL;
 121        }
 122
 123        /* HW bug workaround:
 124         *
 125         * PFIFO will hang forever if the connected engines don't report
 126         * that they've processed the context switch request.
 127         *
 128         * In order for the kickoff to work, we need to ensure all the
 129         * connected engines are in a state where they can answer.
 130         *
 131         * Newer chipsets don't seem to suffer from this issue, and well,
 132         * there's also a "ignore these engines" bitmask reg we can use
 133         * if we hit the issue there..
 134         */
 135        me = nv_mask(priv, 0x00b860, 0x00000001, 0x00000001);
 136
 137        /* do the kickoff... */
 138        nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12);
 139        if (!nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff)) {
 140                nv_error(priv, "channel %d [%s] unload timeout\n",
 141                         chan->base.chid, nouveau_client_name(chan));
 142                if (suspend)
 143                        ret = -EBUSY;
 144        }
 145        nv_wr32(priv, 0x00b860, me);
 146
 147        if (ret == 0) {
 148                nv_wo32(base->eng, addr + 0x00, 0x00000000);
 149                nv_wo32(base->eng, addr + 0x04, 0x00000000);
 150                nv_wo32(base->eng, addr + 0x08, 0x00000000);
 151                nv_wo32(base->eng, addr + 0x0c, 0x00000000);
 152                nv_wo32(base->eng, addr + 0x10, 0x00000000);
 153                nv_wo32(base->eng, addr + 0x14, 0x00000000);
 154                bar->flush(bar);
 155        }
 156
 157        return ret;
 158}
 159
 160static int
 161nv50_fifo_object_attach(struct nouveau_object *parent,
 162                        struct nouveau_object *object, u32 handle)
 163{
 164        struct nv50_fifo_chan *chan = (void *)parent;
 165        u32 context;
 166
 167        if (nv_iclass(object, NV_GPUOBJ_CLASS))
 168                context = nv_gpuobj(object)->node->offset >> 4;
 169        else
 170                context = 0x00000004; /* just non-zero */
 171
 172        switch (nv_engidx(object->engine)) {
 173        case NVDEV_ENGINE_DMAOBJ:
 174        case NVDEV_ENGINE_SW    : context |= 0x00000000; break;
 175        case NVDEV_ENGINE_GR    : context |= 0x00100000; break;
 176        case NVDEV_ENGINE_MPEG  : context |= 0x00200000; break;
 177        default:
 178                return -EINVAL;
 179        }
 180
 181        return nouveau_ramht_insert(chan->ramht, 0, handle, context);
 182}
 183
 184void
 185nv50_fifo_object_detach(struct nouveau_object *parent, int cookie)
 186{
 187        struct nv50_fifo_chan *chan = (void *)parent;
 188        nouveau_ramht_remove(chan->ramht, cookie);
 189}
 190
 191static int
 192nv50_fifo_chan_ctor_dma(struct nouveau_object *parent,
 193                        struct nouveau_object *engine,
 194                        struct nouveau_oclass *oclass, void *data, u32 size,
 195                        struct nouveau_object **pobject)
 196{
 197        struct nouveau_bar *bar = nouveau_bar(parent);
 198        struct nv50_fifo_base *base = (void *)parent;
 199        struct nv50_fifo_chan *chan;
 200        struct nv03_channel_dma_class *args = data;
 201        int ret;
 202
 203        if (size < sizeof(*args))
 204                return -EINVAL;
 205
 206        ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
 207                                          0x2000, args->pushbuf,
 208                                          (1ULL << NVDEV_ENGINE_DMAOBJ) |
 209                                          (1ULL << NVDEV_ENGINE_SW) |
 210                                          (1ULL << NVDEV_ENGINE_GR) |
 211                                          (1ULL << NVDEV_ENGINE_MPEG), &chan);
 212        *pobject = nv_object(chan);
 213        if (ret)
 214                return ret;
 215
 216        nv_parent(chan)->context_attach = nv50_fifo_context_attach;
 217        nv_parent(chan)->context_detach = nv50_fifo_context_detach;
 218        nv_parent(chan)->object_attach = nv50_fifo_object_attach;
 219        nv_parent(chan)->object_detach = nv50_fifo_object_detach;
 220
 221        ret = nouveau_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16,
 222                                &chan->ramht);
 223        if (ret)
 224                return ret;
 225
 226        nv_wo32(base->ramfc, 0x08, lower_32_bits(args->offset));
 227        nv_wo32(base->ramfc, 0x0c, upper_32_bits(args->offset));
 228        nv_wo32(base->ramfc, 0x10, lower_32_bits(args->offset));
 229        nv_wo32(base->ramfc, 0x14, upper_32_bits(args->offset));
 230        nv_wo32(base->ramfc, 0x3c, 0x003f6078);
 231        nv_wo32(base->ramfc, 0x44, 0x01003fff);
 232        nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
 233        nv_wo32(base->ramfc, 0x4c, 0xffffffff);
 234        nv_wo32(base->ramfc, 0x60, 0x7fffffff);
 235        nv_wo32(base->ramfc, 0x78, 0x00000000);
 236        nv_wo32(base->ramfc, 0x7c, 0x30000001);
 237        nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
 238                                   (4 << 24) /* SEARCH_FULL */ |
 239                                   (chan->ramht->base.node->offset >> 4));
 240        bar->flush(bar);
 241        return 0;
 242}
 243
 244static int
 245nv50_fifo_chan_ctor_ind(struct nouveau_object *parent,
 246                        struct nouveau_object *engine,
 247                        struct nouveau_oclass *oclass, void *data, u32 size,
 248                        struct nouveau_object **pobject)
 249{
 250        struct nv50_channel_ind_class *args = data;
 251        struct nouveau_bar *bar = nouveau_bar(parent);
 252        struct nv50_fifo_base *base = (void *)parent;
 253        struct nv50_fifo_chan *chan;
 254        u64 ioffset, ilength;
 255        int ret;
 256
 257        if (size < sizeof(*args))
 258                return -EINVAL;
 259
 260        ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
 261                                          0x2000, args->pushbuf,
 262                                          (1ULL << NVDEV_ENGINE_DMAOBJ) |
 263                                          (1ULL << NVDEV_ENGINE_SW) |
 264                                          (1ULL << NVDEV_ENGINE_GR) |
 265                                          (1ULL << NVDEV_ENGINE_MPEG), &chan);
 266        *pobject = nv_object(chan);
 267        if (ret)
 268                return ret;
 269
 270        nv_parent(chan)->context_attach = nv50_fifo_context_attach;
 271        nv_parent(chan)->context_detach = nv50_fifo_context_detach;
 272        nv_parent(chan)->object_attach = nv50_fifo_object_attach;
 273        nv_parent(chan)->object_detach = nv50_fifo_object_detach;
 274
 275        ret = nouveau_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16,
 276                               &chan->ramht);
 277        if (ret)
 278                return ret;
 279
 280        ioffset = args->ioffset;
 281        ilength = order_base_2(args->ilength / 8);
 282
 283        nv_wo32(base->ramfc, 0x3c, 0x403f6078);
 284        nv_wo32(base->ramfc, 0x44, 0x01003fff);
 285        nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
 286        nv_wo32(base->ramfc, 0x50, lower_32_bits(ioffset));
 287        nv_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16));
 288        nv_wo32(base->ramfc, 0x60, 0x7fffffff);
 289        nv_wo32(base->ramfc, 0x78, 0x00000000);
 290        nv_wo32(base->ramfc, 0x7c, 0x30000001);
 291        nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
 292                                   (4 << 24) /* SEARCH_FULL */ |
 293                                   (chan->ramht->base.node->offset >> 4));
 294        bar->flush(bar);
 295        return 0;
 296}
 297
 298void
 299nv50_fifo_chan_dtor(struct nouveau_object *object)
 300{
 301        struct nv50_fifo_chan *chan = (void *)object;
 302        nouveau_ramht_ref(NULL, &chan->ramht);
 303        nouveau_fifo_channel_destroy(&chan->base);
 304}
 305
 306static int
 307nv50_fifo_chan_init(struct nouveau_object *object)
 308{
 309        struct nv50_fifo_priv *priv = (void *)object->engine;
 310        struct nv50_fifo_base *base = (void *)object->parent;
 311        struct nv50_fifo_chan *chan = (void *)object;
 312        struct nouveau_gpuobj *ramfc = base->ramfc;
 313        u32 chid = chan->base.chid;
 314        int ret;
 315
 316        ret = nouveau_fifo_channel_init(&chan->base);
 317        if (ret)
 318                return ret;
 319
 320        nv_wr32(priv, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 12);
 321        nv50_fifo_playlist_update(priv);
 322        return 0;
 323}
 324
 325int
 326nv50_fifo_chan_fini(struct nouveau_object *object, bool suspend)
 327{
 328        struct nv50_fifo_priv *priv = (void *)object->engine;
 329        struct nv50_fifo_chan *chan = (void *)object;
 330        u32 chid = chan->base.chid;
 331
 332        /* remove channel from playlist, fifo will unload context */
 333        nv_mask(priv, 0x002600 + (chid * 4), 0x80000000, 0x00000000);
 334        nv50_fifo_playlist_update(priv);
 335        nv_wr32(priv, 0x002600 + (chid * 4), 0x00000000);
 336
 337        return nouveau_fifo_channel_fini(&chan->base, suspend);
 338}
 339
 340static struct nouveau_ofuncs
 341nv50_fifo_ofuncs_dma = {
 342        .ctor = nv50_fifo_chan_ctor_dma,
 343        .dtor = nv50_fifo_chan_dtor,
 344        .init = nv50_fifo_chan_init,
 345        .fini = nv50_fifo_chan_fini,
 346        .rd32 = _nouveau_fifo_channel_rd32,
 347        .wr32 = _nouveau_fifo_channel_wr32,
 348};
 349
 350static struct nouveau_ofuncs
 351nv50_fifo_ofuncs_ind = {
 352        .ctor = nv50_fifo_chan_ctor_ind,
 353        .dtor = nv50_fifo_chan_dtor,
 354        .init = nv50_fifo_chan_init,
 355        .fini = nv50_fifo_chan_fini,
 356        .rd32 = _nouveau_fifo_channel_rd32,
 357        .wr32 = _nouveau_fifo_channel_wr32,
 358};
 359
 360static struct nouveau_oclass
 361nv50_fifo_sclass[] = {
 362        { NV50_CHANNEL_DMA_CLASS, &nv50_fifo_ofuncs_dma },
 363        { NV50_CHANNEL_IND_CLASS, &nv50_fifo_ofuncs_ind },
 364        {}
 365};
 366
 367/*******************************************************************************
 368 * FIFO context - basically just the instmem reserved for the channel
 369 ******************************************************************************/
 370
 371static int
 372nv50_fifo_context_ctor(struct nouveau_object *parent,
 373                       struct nouveau_object *engine,
 374                       struct nouveau_oclass *oclass, void *data, u32 size,
 375                       struct nouveau_object **pobject)
 376{
 377        struct nv50_fifo_base *base;
 378        int ret;
 379
 380        ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x10000,
 381                                          0x1000, NVOBJ_FLAG_HEAP, &base);
 382        *pobject = nv_object(base);
 383        if (ret)
 384                return ret;
 385
 386        ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x0200,
 387                                 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &base->ramfc);
 388        if (ret)
 389                return ret;
 390
 391        ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x1200, 0,
 392                                 NVOBJ_FLAG_ZERO_ALLOC, &base->eng);
 393        if (ret)
 394                return ret;
 395
 396        ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x4000, 0, 0,
 397                                &base->pgd);
 398        if (ret)
 399                return ret;
 400
 401        ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd);
 402        if (ret)
 403                return ret;
 404
 405        return 0;
 406}
 407
 408void
 409nv50_fifo_context_dtor(struct nouveau_object *object)
 410{
 411        struct nv50_fifo_base *base = (void *)object;
 412        nouveau_vm_ref(NULL, &base->vm, base->pgd);
 413        nouveau_gpuobj_ref(NULL, &base->pgd);
 414        nouveau_gpuobj_ref(NULL, &base->eng);
 415        nouveau_gpuobj_ref(NULL, &base->ramfc);
 416        nouveau_gpuobj_ref(NULL, &base->cache);
 417        nouveau_fifo_context_destroy(&base->base);
 418}
 419
 420static struct nouveau_oclass
 421nv50_fifo_cclass = {
 422        .handle = NV_ENGCTX(FIFO, 0x50),
 423        .ofuncs = &(struct nouveau_ofuncs) {
 424                .ctor = nv50_fifo_context_ctor,
 425                .dtor = nv50_fifo_context_dtor,
 426                .init = _nouveau_fifo_context_init,
 427                .fini = _nouveau_fifo_context_fini,
 428                .rd32 = _nouveau_fifo_context_rd32,
 429                .wr32 = _nouveau_fifo_context_wr32,
 430        },
 431};
 432
 433/*******************************************************************************
 434 * PFIFO engine
 435 ******************************************************************************/
 436
 437static int
 438nv50_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 439               struct nouveau_oclass *oclass, void *data, u32 size,
 440               struct nouveau_object **pobject)
 441{
 442        struct nv50_fifo_priv *priv;
 443        int ret;
 444
 445        ret = nouveau_fifo_create(parent, engine, oclass, 1, 127, &priv);
 446        *pobject = nv_object(priv);
 447        if (ret)
 448                return ret;
 449
 450        ret = nouveau_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0,
 451                                &priv->playlist[0]);
 452        if (ret)
 453                return ret;
 454
 455        ret = nouveau_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0,
 456                                &priv->playlist[1]);
 457        if (ret)
 458                return ret;
 459
 460        nv_subdev(priv)->unit = 0x00000100;
 461        nv_subdev(priv)->intr = nv04_fifo_intr;
 462        nv_engine(priv)->cclass = &nv50_fifo_cclass;
 463        nv_engine(priv)->sclass = nv50_fifo_sclass;
 464        priv->base.pause = nv04_fifo_pause;
 465        priv->base.start = nv04_fifo_start;
 466        return 0;
 467}
 468
 469void
 470nv50_fifo_dtor(struct nouveau_object *object)
 471{
 472        struct nv50_fifo_priv *priv = (void *)object;
 473
 474        nouveau_gpuobj_ref(NULL, &priv->playlist[1]);
 475        nouveau_gpuobj_ref(NULL, &priv->playlist[0]);
 476
 477        nouveau_fifo_destroy(&priv->base);
 478}
 479
 480int
 481nv50_fifo_init(struct nouveau_object *object)
 482{
 483        struct nv50_fifo_priv *priv = (void *)object;
 484        int ret, i;
 485
 486        ret = nouveau_fifo_init(&priv->base);
 487        if (ret)
 488                return ret;
 489
 490        nv_mask(priv, 0x000200, 0x00000100, 0x00000000);
 491        nv_mask(priv, 0x000200, 0x00000100, 0x00000100);
 492        nv_wr32(priv, 0x00250c, 0x6f3cfc34);
 493        nv_wr32(priv, 0x002044, 0x01003fff);
 494
 495        nv_wr32(priv, 0x002100, 0xffffffff);
 496        nv_wr32(priv, 0x002140, 0xbfffffff);
 497
 498        for (i = 0; i < 128; i++)
 499                nv_wr32(priv, 0x002600 + (i * 4), 0x00000000);
 500        nv50_fifo_playlist_update_locked(priv);
 501
 502        nv_wr32(priv, 0x003200, 0x00000001);
 503        nv_wr32(priv, 0x003250, 0x00000001);
 504        nv_wr32(priv, 0x002500, 0x00000001);
 505        return 0;
 506}
 507
 508struct nouveau_oclass *
 509nv50_fifo_oclass = &(struct nouveau_oclass) {
 510        .handle = NV_ENGINE(FIFO, 0x50),
 511        .ofuncs = &(struct nouveau_ofuncs) {
 512                .ctor = nv50_fifo_ctor,
 513                .dtor = nv50_fifo_dtor,
 514                .init = nv50_fifo_init,
 515                .fini = _nouveau_fifo_fini,
 516        },
 517};
 518