/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include <core/client.h>
#include <core/handle.h>
#include <core/namedb.h>
#include <core/gpuobj.h>
#include <core/engctx.h>
#include <core/event.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include <core/enum.h>
#include <subdev/timer.h>
#include <subdev/bar.h>
#include <subdev/fb.h>
#include <subdev/vm.h>
#include <engine/dmaobj.h>
#include <engine/fifo.h>
struct nvc0_fifo_priv {
struct nouveau_fifo base;
struct work_struct fault;
u64 mask;
struct {
struct nouveau_gpuobj *mem[2];
int active;
wait_queue_head_t wait;
} runlist;
struct {
struct nouveau_gpuobj *mem;
struct nouveau_vma bar;
} user;
int spoon_nr;
};
struct nvc0_fifo_base {
struct nouveau_fifo_base base;
struct nouveau_gpuobj *pgd;
struct nouveau_vm *vm;
};
struct nvc0_fifo_chan {
struct nouveau_fifo_chan base;
enum {
STOPPED,
RUNNING,
KILLED
} state;
};
/*******************************************************************************
* FIFO channel objects
******************************************************************************/
static void
nvc0_fifo_runlist_update(struct nvc0_fifo_priv *priv)
{
struct nouveau_bar *bar = nouveau_bar(priv);
struct nouveau_gpuobj *cur;
int i, p;
mutex_lock(&nv_subdev(priv)->mutex);
cur = priv->runlist.mem[priv->runlist.active];
priv->runlist.active = !priv->runlist.active;
for (i = 0, p = 0; i < 128; i++) {
struct nvc0_fifo_chan *chan = (void *)priv->base.channel[i];
if (chan && chan->state == RUNNING) {
nv_wo32(cur, p + 0, i);
nv_wo32(cur, p + 4, 0x00000004);
p += 8;
}
}
bar->flush(bar);
nv_wr32(priv, 0x002270, cur->addr >> 12);
nv_wr32(priv, 0x002274, 0x01f00000 | (p >> 3));
if (wait_event_timeout(priv->runlist.wait,
!(nv_rd32(priv, 0x00227c) & 0x00100000),
msecs_to_jiffies(2000)) == 0)
nv_error(priv, "runlist update timeout\n");
mutex_unlock(&nv_subdev(priv)->mutex);
}
static int
nvc0_fifo_context_attach(struct nouveau_object *parent,
struct nouveau_object *object)
{
struct nouveau_bar *bar = nouveau_bar(parent);
struct nvc0_fifo_base *base = (void *)parent->parent;
struct nouveau_engctx *ectx = (void *)object;
u32 addr;
int ret;
switch (nv_engidx(object->engine)) {
case NVDEV_ENGINE_SW : return 0;
case NVDEV_ENGINE_GR : addr = 0x0210; break;
case NVDEV_ENGINE_COPY0: addr = 0x0230; break;
case NVDEV_ENGINE_COPY1: addr = 0x0240; break;
case NVDEV_ENGINE_BSP : addr = 0x0270; break;
case NVDEV_ENGINE_VP : addr = 0x0250; break;
case NVDEV_ENGINE_PPP : addr = 0x0260; break;
default:
return -EINVAL;
}
if (!ectx->vma.node) {
ret = nouveau_gpuobj_map_vm(nv_gpuobj(ectx), base->vm,
NV_MEM_ACCESS_RW, &ectx->vma);
if (ret)
return ret;
nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
}
nv_wo32(base, addr + 0x00, lower_32_bits(ectx->vma.offset