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        if (fifo->func->class_get) {
 182                int ret = fifo->func->class_get(fifo, index, &sclass);
 183                if (ret == 0) {
 184                        oclass->base = sclass->base;
 185                        oclass->engn = sclass;
 186                        *class = &nvkm_fifo_class;
 187                        return 0;
 188                }
 189                return ret;
 190        }
 191
 192        while ((sclass = fifo->func->chan[c])) {
 193                if (c++ == index) {
 194                        oclass->base = sclass->base;
 195                        oclass->engn = sclass;
 196                        *class = &nvkm_fifo_class;
 197                        return 0;
 198                }
 199        }
 200
 201        return c;
 202}
 203
 204static void
 205nvkm_fifo_intr(struct nvkm_engine *engine)
 206{
 207        struct nvkm_fifo *fifo = nvkm_fifo(engine);
 208        fifo->func->intr(fifo);
 209}
 210
 211static int
 212nvkm_fifo_fini(struct nvkm_engine *engine, bool suspend)
 213{
 214        struct nvkm_fifo *fifo = nvkm_fifo(engine);
 215        if (fifo->func->fini)
 216                fifo->func->fini(fifo);
 217        return 0;
 218}
 219
 220static int
 221nvkm_fifo_oneinit(struct nvkm_engine *engine)
 222{
 223        struct nvkm_fifo *fifo = nvkm_fifo(engine);
 224        if (fifo->func->oneinit)
 225                return fifo->func->oneinit(fifo);
 226        return 0;
 227}
 228
 229static int
 230nvkm_fifo_init(struct nvkm_engine *engine)
 231{
 232        struct nvkm_fifo *fifo = nvkm_fifo(engine);
 233        fifo->func->init(fifo);
 234        return 0;
 235}
 236
 237static void *
 238nvkm_fifo_dtor(struct nvkm_engine *engine)
 239{
 240        struct nvkm_fifo *fifo = nvkm_fifo(engine);
 241        void *data = fifo;
 242        if (fifo->func->dtor)
 243                data = fifo->func->dtor(fifo);
 244        nvkm_event_fini(&fifo->cevent);
 245        nvkm_event_fini(&fifo->uevent);
 246        return data;
 247}
 248
 249static const struct nvkm_engine_func
 250nvkm_fifo = {
 251        .dtor = nvkm_fifo_dtor,
 252        .oneinit = nvkm_fifo_oneinit,
 253        .init = nvkm_fifo_init,
 254        .fini = nvkm_fifo_fini,
 255        .intr = nvkm_fifo_intr,
 256        .base.sclass = nvkm_fifo_class_get,
 257};
 258
 259int
 260nvkm_fifo_ctor(const struct nvkm_fifo_func *func, struct nvkm_device *device,
 261               int index, int nr, struct nvkm_fifo *fifo)
 262{
 263        int ret;
 264
 265        fifo->func = func;
 266        INIT_LIST_HEAD(&fifo->chan);
 267        spin_lock_init(&fifo->lock);
 268
 269        if (WARN_ON(fifo->nr > NVKM_FIFO_CHID_NR))
 270                fifo->nr = NVKM_FIFO_CHID_NR;
 271        else
 272                fifo->nr = nr;
 273        bitmap_clear(fifo->mask, 0, fifo->nr);
 274
 275        ret = nvkm_engine_ctor(&nvkm_fifo, device, index, true, &fifo->engine);
 276        if (ret)
 277                return ret;
 278
 279        if (func->uevent_init) {
 280                ret = nvkm_event_init(&nvkm_fifo_uevent_func, 1, 1,
 281                                      &fifo->uevent);
 282                if (ret)
 283                        return ret;
 284        }
 285
 286        return nvkm_event_init(&nvkm_fifo_event_func, 1, 1, &fifo->cevent);
 287}
 288