linux/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.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 "priv.h"
  25#include "chan.h"
  26
  27#include <core/client.h>
  28#include <core/gpuobj.h>
  29#include <core/notify.h>
  30
  31#include <nvif/event.h>
  32#include <nvif/unpack.h>
  33
  34void
  35nvkm_fifo_pause(struct nvkm_fifo *fifo, unsigned long *flags)
  36{
  37        return fifo->func->pause(fifo, flags);
  38}
  39
  40void
  41nvkm_fifo_start(struct nvkm_fifo *fifo, unsigned long *flags)
  42{
  43        return fifo->func->start(fifo, flags);
  44}
  45
  46void
  47nvkm_fifo_chan_put(struct nvkm_fifo *fifo, unsigned long flags,
  48                   struct nvkm_fifo_chan **pchan)
  49{
  50        struct nvkm_fifo_chan *chan = *pchan;
  51        if (likely(chan)) {
  52                *pchan = NULL;
  53                spin_unlock_irqrestore(&fifo->lock, flags);
  54        }
  55}
  56
  57struct nvkm_fifo_chan *
  58nvkm_fifo_chan_inst(struct nvkm_fifo *fifo, u64 inst, unsigned long *rflags)
  59{
  60        struct nvkm_fifo_chan *chan;
  61        unsigned long flags;
  62        spin_lock_irqsave(&fifo->lock, flags);
  63        list_for_each_entry(chan, &fifo->chan, head) {
  64                if (chan->inst->addr == inst) {
  65                        list_del(&chan->head);
  66                        list_add(&chan->head, &fifo->chan);
  67                        *rflags = flags;
  68                        return chan;
  69                }
  70        }
  71        spin_unlock_irqrestore(&fifo->lock, flags);
  72        return NULL;
  73}
  74
  75struct nvkm_fifo_chan *
  76nvkm_fifo_chan_chid(struct nvkm_fifo *fifo, int chid, unsigned long *rflags)
  77{
  78        struct nvkm_fifo_chan *chan;
  79        unsigned long flags;
  80        spin_lock_irqsave(&fifo->lock, flags);
  81        list_for_each_entry(chan, &fifo->chan, head) {
  82                if (chan->chid == chid) {
  83                        list_del(&chan->head);
  84                        list_add(&chan->head, &fifo->chan);
  85                        *rflags = flags;
  86                        return chan;
  87                }
  88        }
  89        spin_unlock_irqrestore(&fifo->lock, flags);
  90        return NULL;
  91}
  92
  93static int
  94nvkm_fifo_event_ctor(struct nvkm_object *object, void *data, u32 size,
  95                     struct nvkm_notify *notify)
  96{
  97        if (size == 0) {
  98                notify->size  = 0;
  99                notify->types = 1;
 100                notify->index = 0;
 101                return 0;
 102        }
 103        return -ENOSYS;
 104}
 105
 106static const struct nvkm_event_func
 107nvkm_fifo_event_func = {
 108        .ctor = nvkm_fifo_event_ctor,
 109};
 110
 111static void
 112nvkm_fifo_uevent_fini(struct nvkm_event *event, int type, int index)
 113{
 114        struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent);
 115        fifo->func->uevent_fini(fifo);
 116}
 117
 118static void
 119nvkm_fifo_uevent_init(struct nvkm_event *event, int type, int index)
 120{
 121        struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent);
 122        fifo->func->uevent_init(fifo);
 123}
 124
 125static int
 126nvkm_fifo_uevent_ctor(struct nvkm_object *object, void *data, u32 size,
 127                      struct nvkm_notify *notify)
 128{
 129        union {
 130                struct nvif_notify_uevent_req none;
 131        } *req = data;
 132        int ret = -ENOSYS;
 133
 134        if (!(ret = nvif_unvers(ret, &data, &size, req->none))) {
 135                notify->size  = sizeof(struct nvif_notify_uevent_rep);
 136                notify->types = 1;
 137                notify->index = 0;
 138        }
 139
 140        return ret;
 141}
 142
 143static const struct nvkm_event_func
 144nvkm_fifo_uevent_func = {
 145        .ctor = nvkm_fifo_uevent_ctor,
 146        .init = nvkm_fifo_uevent_init,
 147        .fini = nvkm_fifo_uevent_fini,
 148};
 149
 150void
 151nvkm_fifo_uevent(struct nvkm_fifo *fifo)
 152{
 153        struct nvif_notify_uevent_rep rep = {
 154        };
 155        nvkm_event_send(&fifo->uevent, 1, 0, &rep, sizeof(rep));
 156}
 157
 158static int
 159nvkm_fifo_class_new(struct nvkm_device *device,
 160                    const struct nvkm_oclass *oclass, void *data, u32 size,
 161                    struct nvkm_object **pobject)
 162{
 163        const struct nvkm_fifo_chan_oclass *sclass = oclass->engn;
 164        struct nvkm_fifo *fifo = nvkm_fifo(oclass->engine);
 165        return sclass->ctor(fifo, oclass, data, size, pobject);
 166}
 167
 168static const struct nvkm_device_oclass
 169nvkm_fifo_class = {
 170        .ctor = nvkm_fifo_class_new,
 171};
 172
 173static int
 174nvkm_fifo_class_get(struct nvkm_oclass *oclass, int index,
 175                    const struct nvkm_device_oclass **class)
 176{
 177        struct nvkm_fifo *fifo = nvkm_fifo(oclass->engine);
 178        const struct nvkm_fifo_chan_oclass *sclass;
 179        int c = 0;
 180
 181        while ((sclass = fifo->func->chan[c])) {
 182                if (c++ == index) {
 183                        oclass->base = sclass->base;
 184                        oclass->engn = sclass;
 185                        *class = &nvkm_fifo_class;
 186                        return 0;
 187                }
 188        }
 189
 190        return c;
 191}
 192
 193static void
 194nvkm_fifo_intr(struct nvkm_engine *engine)
 195{
 196        struct nvkm_fifo *fifo = nvkm_fifo(engine);
 197        fifo->func->intr(fifo);
 198}
 199
 200static int
 201nvkm_fifo_fini(struct nvkm_engine *engine, bool suspend)
 202{
 203        struct nvkm_fifo *fifo = nvkm_fifo(engine);
 204        if (fifo->func->fini)
 205                fifo->func->fini(fifo);
 206        return 0;
 207}
 208
 209static int
 210nvkm_fifo_oneinit(struct nvkm_engine *engine)
 211{
 212        struct nvkm_fifo *fifo = nvkm_fifo(engine);
 213        if (fifo->func->oneinit)
 214                return fifo->func->oneinit(fifo);
 215        return 0;
 216}
 217
 218static int
 219nvkm_fifo_init(struct nvkm_engine *engine)
 220{
 221        struct nvkm_fifo *fifo = nvkm_fifo(engine);
 222        fifo->func->init(fifo);
 223        return 0;
 224}
 225
 226static void *
 227nvkm_fifo_dtor(struct nvkm_engine *engine)
 228{
 229        struct nvkm_fifo *fifo = nvkm_fifo(engine);
 230        void *data = fifo;
 231        if (fifo->func->dtor)
 232                data = fifo->func->dtor(fifo);
 233        nvkm_event_fini(&fifo->cevent);
 234        nvkm_event_fini(&fifo->uevent);
 235        return data;
 236}
 237
 238static const struct nvkm_engine_func
 239nvkm_fifo = {
 240        .dtor = nvkm_fifo_dtor,
 241        .oneinit = nvkm_fifo_oneinit,
 242        .init = nvkm_fifo_init,
 243        .fini = nvkm_fifo_fini,
 244        .intr = nvkm_fifo_intr,
 245        .base.sclass = nvkm_fifo_class_get,
 246};
 247
 248int
 249nvkm_fifo_ctor(const struct nvkm_fifo_func *func, struct nvkm_device *device,
 250               int index, int nr, struct nvkm_fifo *fifo)
 251{
 252        int ret;
 253
 254        fifo->func = func;
 255        INIT_LIST_HEAD(&fifo->chan);
 256        spin_lock_init(&fifo->lock);
 257
 258        if (WARN_ON(fifo->nr > NVKM_FIFO_CHID_NR))
 259                fifo->nr = NVKM_FIFO_CHID_NR;
 260        else
 261                fifo->nr = nr;
 262        bitmap_clear(fifo->mask, 0, fifo->nr);
 263
 264        ret = nvkm_engine_ctor(&nvkm_fifo, device, index, 0x00000100,
 265                               true, &fifo->engine);
 266        if (ret)
 267                return ret;
 268
 269        if (func->uevent_init) {
 270                ret = nvkm_event_init(&nvkm_fifo_uevent_func, 1, 1,
 271                                      &fifo->uevent);
 272                if (ret)
 273                        return ret;
 274        }
 275
 276        return nvkm_event_init(&nvkm_fifo_event_func, 1, 1, &fifo->cevent);
 277}
 278