/*
* 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 <core/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 "nve0.h"
#define _(a,b) { (a), ((1ULL << (a)) | (b)) }
static const struct {
u64 subdev;
u64 mask;
} fifo_engine[] = {
_(NVDEV_ENGINE_GR , (1ULL << NVDEV_ENGINE_SW) |
(1ULL << NVDEV_ENGINE_COPY2)),
_(NVDEV_ENGINE_VP , 0),
_(NVDEV_ENGINE_PPP , 0),
_(NVDEV_ENGINE_BSP , 0),
_(NVDEV_ENGINE_COPY0 , 0),
_(NVDEV_ENGINE_COPY1 , 0),
_(NVDEV_ENGINE_VENC , 0),
};
#undef _
#define FIFO_ENGINE_NR ARRAY_SIZE(fifo_engine)
struct nve0_fifo_engn {
struct nouveau_gpuobj *runlist[2];
int cur_runlist;
wait_queue_head_t wait;
};
struct nve0_fifo_priv {
struct nouveau_fifo base;
struct work_struct fault;
u64 mask;
struct nve0_fifo_engn engine[FIFO_ENGINE_NR];
struct {
struct nouveau_gpuobj *mem;
struct nouveau_vma bar;
} user;
int spoon_nr;
};
struct nve0_fifo_base {
struct nouveau_fifo_base base;
struct nouveau_gpuobj *pgd;
struct nouveau_vm *vm;
};
struct nve0_fifo_chan {
struct nouveau_fifo_chan base;
u32 engine;
enum {
STOPPED,
RUNNING,
KILLED
} state;
};
/*******************************************************************************
* FIFO channel objects
******************************************************************************/
static void
nve0_fifo_runlist_update(struct nve0_fifo_priv *priv, u32 engine)
{
struct nouveau_bar *bar = nouveau_bar(priv);
struct nve0_fifo_engn *engn = &priv->engine[engine];
struct nouveau_gpuobj *cur;
int i, p;
mutex_lock(&nv_subdev(priv)->mutex);
cur = engn->runlist[engn->cur_runlist];
engn->cur_runlist = !engn->cur_runlist;
for (i = 0, p = 0; i < priv->base.max; i++) {
struct nve0_fifo_chan *chan = (void *)priv->base.channel[i];
if (chan && chan->state == RUNNING && chan->engine == engine) {
nv_wo32(cur, p + 0, i);
nv_wo32(cur, p + 4, 0x00000000);
p += 8;
}
}
bar->flush(bar);
nv_wr32(priv, 0x002270, cur->addr >> 12);
nv_wr32(priv, 0x002274, (engine << 20) | (p >> 3));
if (wait_event_timeout(engn->wait, !(nv_rd32(priv, 0x002284 +
(engine * 0x08)) & 0x00100000),
msecs_to_jiffies(2000)) == 0)
nv_error(priv, "runlist %d update timeout\n", engine);
mutex_unlock(&nv_subdev(priv)->mutex);
}
static int
nve0_fifo_context_attach(struct nouveau_object *parent,
struct nouveau_object *object)
{