提交 ebb945a9 编写于 作者: B Ben Skeggs

drm/nouveau: port all engines to new engine module format

This is a HUGE commit, but it's not nearly as bad as it looks - any problems
can be isolated to a particular chipset and engine combination.  It was
simply too difficult to port each one at a time, the compat layers are
*already* ridiculous.

Most of the changes here are simply to the glue, the process for each of the
engine modules was to start with a standard skeleton and copy+paste the old
code into the appropriate places, fixing up variable names etc as needed.

v2: Marcin Slusarz <marcin.slusarz@gmail.com>
- fix find/replace bug in license header

v3: Ben Skeggs <bskeggs@redhat.com>
- bump indirect pushbuf size to 8KiB, 4KiB barely enough for userspace and
  left no space for kernel's requirements during GEM pushbuf submission.
- fix duplicate assignments noticed by clang

v4: Marcin Slusarz <marcin.slusarz@gmail.com>
- add sparse annotations to nv04_fifo_pause/nv04_fifo_start
- use ioread32_native/iowrite32_native for fifo control registers

v5: Ben Skeggs <bskeggs@redhat.com>
- rebase on v3.6-rc4, modified to keep copy engine fix intact
- nv10/fence: unmap fence bo before destroying
- fixed fermi regression when using nvidia gr fuc
- fixed typo in supported dma_mask checking
Signed-off-by: NBen Skeggs <bskeggs@redhat.com>
上级 ac1499d9
......@@ -4,9 +4,11 @@
ccflags-y := -Iinclude/drm -DCONFIG_NOUVEAU_DEBUG=7 -DCONFIG_NOUVEAU_DEBUG_DEFAULT=3
ccflags-y += -I$(src)/core/include
ccflags-y += -I$(src)/core
ccflags-y += -I$(src)
nouveau-y := core/core/client.o
nouveau-y += core/core/engctx.o
nouveau-y += core/core/engine.o
nouveau-y += core/core/enum.o
nouveau-y += core/core/gpuobj.o
......@@ -90,12 +92,20 @@ nouveau-y += core/subdev/vm/nv44.o
nouveau-y += core/subdev/vm/nv50.o
nouveau-y += core/subdev/vm/nvc0.o
nouveau-y += core/engine/dmaobj/base.o
nouveau-y += core/engine/dmaobj/nv04.o
nouveau-y += core/engine/dmaobj/nv50.o
nouveau-y += core/engine/dmaobj/nvc0.o
nouveau-y += core/engine/bsp/nv84.o
nouveau-y += core/engine/copy/nva3.o
nouveau-y += core/engine/copy/nvc0.o
nouveau-y += core/engine/crypt/nv84.o
nouveau-y += core/engine/crypt/nv98.o
nouveau-y += core/engine/disp/nv04.o
nouveau-y += core/engine/disp/nv50.o
nouveau-y += core/engine/disp/nvd0.o
nouveau-y += core/engine/disp/vga.o
nouveau-y += core/engine/fifo/base.o
nouveau-y += core/engine/fifo/nv04.o
nouveau-y += core/engine/fifo/nv10.o
nouveau-y += core/engine/fifo/nv17.o
......@@ -111,41 +121,82 @@ nouveau-y += core/engine/graph/ctxnve0.o
nouveau-y += core/engine/graph/nv04.o
nouveau-y += core/engine/graph/nv10.o
nouveau-y += core/engine/graph/nv20.o
nouveau-y += core/engine/graph/nv25.o
nouveau-y += core/engine/graph/nv2a.o
nouveau-y += core/engine/graph/nv30.o
nouveau-y += core/engine/graph/nv34.o
nouveau-y += core/engine/graph/nv35.o
nouveau-y += core/engine/graph/nv40.o
nouveau-y += core/engine/graph/nv50.o
nouveau-y += core/engine/graph/nvc0.o
nouveau-y += core/engine/graph/nve0.o
nouveau-y += core/engine/mpeg/nv31.o
nouveau-y += core/engine/mpeg/nv40.o
nouveau-y += core/engine/mpeg/nv50.o
nouveau-y += core/engine/mpeg/nv84.o
nouveau-y += core/engine/ppp/nv98.o
nouveau-y += core/engine/software/nv04.o
nouveau-y += core/engine/software/nv10.o
nouveau-y += core/engine/software/nv50.o
nouveau-y += core/engine/software/nvc0.o
nouveau-y += core/engine/vp/nv84.o
nouveau-y += nouveau_drm.o nouveau_compat.o \
nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
nouveau_gpuobj.o nouveau_irq.o nouveau_notifier.o \
nouveau_sgdma.o nouveau_dma.o nouveau_util.o \
nouveau_bo.o nouveau_fence.o nouveau_gem.o nouveau_ttm.o \
nouveau_hw.o nouveau_calc.o \
nouveau_display.o nouveau_connector.o nouveau_fbcon.o \
nouveau_hdmi.o nouveau_dp.o \
nouveau_pm.o nouveau_volt.o nouveau_perf.o nouveau_temp.o \
nouveau_mxm.o nouveau_agp.o \
nouveau_abi16.o \
nouveau_bios.o \
nv04_fence.o nv10_fence.o nv50_fence.o nv84_fence.o nvc0_fence.o \
nv04_software.o nv50_software.o nvc0_software.o \
nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \
nv04_crtc.o nv04_display.o nv04_cursor.o \
nv50_evo.o nv50_crtc.o nv50_dac.o nv50_sor.o \
nv50_cursor.o nv50_display.o \
nvd0_display.o \
nv04_fbcon.o nv50_fbcon.o nvc0_fbcon.o \
nv04_pm.o nv40_pm.o nv50_pm.o nva3_pm.o nvc0_pm.o \
nouveau_prime.o
nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o
# drm/compat - will go away
nouveau-y += nouveau_compat.o nouveau_revcompat.o
# drm/core
nouveau-y += nouveau_drm.o nouveau_chan.o nouveau_dma.o nouveau_fence.o
nouveau-y += nouveau_agp.o
nouveau-y += nouveau_ttm.o nouveau_sgdma.o nouveau_bo.o nouveau_gem.o
nouveau-y += nouveau_abi16.o
nouveau-y += nv04_fence.o nv10_fence.o nv50_fence.o nv84_fence.o nvc0_fence.o
# drm/kms/common
nouveau-y += nouveau_fbcon.o
# drm/kms/nv04:nv50
nouveau-y += nv04_fbcon.o
# drm/kms/nv50:nvd9
nouveau-y += nv50_fbcon.o nvc0_fbcon.o
# drm/kms/nvd9-
##
## unported bits below
##
# drm/core
nouveau-y += nouveau_drv.o nouveau_state.o nouveau_irq.o
nouveau-y += nouveau_prime.o
# drm/kms/bios
nouveau-y += nouveau_mxm.o nouveau_bios.o
# drm/kms/common
nouveau-y += nouveau_display.o nouveau_connector.o
nouveau-y += nouveau_hdmi.o nouveau_dp.o
# drm/kms/nv04:nv50
nouveau-y += nouveau_hw.o nouveau_calc.o
nouveau-y += nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o
nouveau-y += nv04_crtc.o nv04_display.o nv04_cursor.o
# drm/kms/nv50-
nouveau-y += nv50_display.o nvd0_display.o
nouveau-y += nv50_crtc.o nv50_dac.o nv50_sor.o nv50_cursor.o
nouveau-y += nv50_evo.o
# drm/pm
nouveau-y += nouveau_pm.o nouveau_volt.o nouveau_perf.o nouveau_temp.o
nouveau-y += nv04_pm.o nv40_pm.o nv50_pm.o nva3_pm.o nvc0_pm.o
nouveau-y += nouveau_mem.o
# optional stuff
nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
nouveau-$(CONFIG_DRM_NOUVEAU_BACKLIGHT) += nouveau_backlight.o
nouveau-$(CONFIG_ACPI) += nouveau_acpi.o
obj-$(CONFIG_DRM_NOUVEAU)+= nouveau.o
/*
* Copyright 2010 Red Hat Inc.
* 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"),
......@@ -18,289 +18,92 @@
* 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 "drmP.h"
#include "nouveau_drv.h"
#include <core/object.h>
#include <core/ramht.h>
#include <core/math.h>
#include <subdev/bar.h>
static u32
nouveau_ramht_hash_handle(struct nouveau_channel *chan, u32 handle)
nouveau_ramht_hash(struct nouveau_ramht *ramht, int chid, u32 handle)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_ramht *ramht = chan->ramht;
u32 hash = 0;
int i;
NV_DEBUG(dev, "ch%d handle=0x%08x\n", chan->id, handle);
for (i = 32; i > 0; i -= ramht->bits) {
while (handle) {
hash ^= (handle & ((1 << ramht->bits) - 1));
handle >>= ramht->bits;
}
if (dev_priv->card_type < NV_50)
hash ^= chan->id << (ramht->bits - 4);
hash <<= 3;
NV_DEBUG(dev, "hash=0x%08x\n", hash);
hash ^= chid << (ramht->bits - 4);
hash = hash << 3;
return hash;
}
static int
nouveau_ramht_entry_valid(struct drm_device *dev, struct nouveau_gpuobj *ramht,
u32 offset)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
u32 ctx = nv_ro32(ramht, offset + 4);
if (dev_priv->card_type < NV_40)
return ((ctx & NV_RAMHT_CONTEXT_VALID) != 0);
return (ctx != 0);
}
static int
nouveau_ramht_entry_same_channel(struct nouveau_channel *chan,
struct nouveau_gpuobj *ramht, u32 offset)
{
struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
u32 ctx = nv_ro32(ramht, offset + 4);
if (dev_priv->card_type >= NV_50)
return true;
else if (dev_priv->card_type >= NV_40)
return chan->id ==
((ctx >> NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) & 0x1f);
else
return chan->id ==
((ctx >> NV_RAMHT_CONTEXT_CHANNEL_SHIFT) & 0x1f);
}
int
nouveau_ramht_insert(struct nouveau_channel *chan, u32 handle,
struct nouveau_gpuobj *gpuobj)
nouveau_ramht_insert(struct nouveau_ramht *ramht, int chid,
u32 handle, u32 context)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_ramht_entry *entry;
struct nouveau_gpuobj *ramht = chan->ramht->gpuobj;
unsigned long flags;
u32 ctx, co, ho;
if (nouveau_ramht_find(chan, handle))
return -EEXIST;
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
return -ENOMEM;
entry->channel = chan;
entry->gpuobj = NULL;
entry->handle = handle;
nouveau_gpuobj_ref(gpuobj, &entry->gpuobj);
if (dev_priv->card_type < NV_40) {
ctx = NV_RAMHT_CONTEXT_VALID | (gpuobj->addr >> 4) |
(chan->id << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) |
(gpuobj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT);
} else
if (dev_priv->card_type < NV_50) {
ctx = (gpuobj->addr >> 4) |
(chan->id << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) |
(gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT);
} else {
if (gpuobj->engine == NVOBJ_ENGINE_DISPLAY) {
ctx = (gpuobj->node->offset << 10) |
(chan->id << 28) |
chan->id; /* HASH_TAG */
} else {
ctx = (gpuobj->node->offset >> 4) |
((gpuobj->engine <<
NV40_RAMHT_CONTEXT_ENGINE_SHIFT));
}
}
spin_lock_irqsave(&chan->ramht->lock, flags);
list_add(&entry->head, &chan->ramht->entries);
struct nouveau_bar *bar = nouveau_bar(ramht);
u32 co, ho;
co = ho = nouveau_ramht_hash_handle(chan, handle);
co = ho = nouveau_ramht_hash(ramht, chid, handle);
do {
if (!nouveau_ramht_entry_valid(dev, ramht, co)) {
NV_DEBUG(dev,
"insert ch%d 0x%08x: h=0x%08x, c=0x%08x\n",
chan->id, co, handle, ctx);
if (!nv_ro32(ramht, co + 4)) {
nv_wo32(ramht, co + 0, handle);
nv_wo32(ramht, co + 4, ctx);
spin_unlock_irqrestore(&chan->ramht->lock, flags);
nvimem_flush(dev);
return 0;
nv_wo32(ramht, co + 4, context);
if (bar)
bar->flush(bar);
return co;
}
NV_DEBUG(dev, "collision ch%d 0x%08x: h=0x%08x\n",
chan->id, co, nv_ro32(ramht, co));
co += 8;
if (co >= ramht->size)
if (co >= nv_gpuobj(ramht)->size)
co = 0;
} while (co != ho);
NV_ERROR(dev, "RAMHT space exhausted. ch=%d\n", chan->id);
list_del(&entry->head);
spin_unlock_irqrestore(&chan->ramht->lock, flags);
kfree(entry);
return -ENOMEM;
}
static struct nouveau_ramht_entry *
nouveau_ramht_remove_entry(struct nouveau_channel *chan, u32 handle)
{
struct nouveau_ramht *ramht = chan ? chan->ramht : NULL;
struct nouveau_ramht_entry *entry;
unsigned long flags;
if (!ramht)
return NULL;
spin_lock_irqsave(&ramht->lock, flags);
list_for_each_entry(entry, &ramht->entries, head) {
if (entry->channel == chan &&
(!handle || entry->handle == handle)) {
list_del(&entry->head);
spin_unlock_irqrestore(&ramht->lock, flags);
return entry;
}
}
spin_unlock_irqrestore(&ramht->lock, flags);
return NULL;
}
static void
nouveau_ramht_remove_hash(struct nouveau_channel *chan, u32 handle)
{
struct drm_device *dev = chan->dev;
struct nouveau_gpuobj *ramht = chan->ramht->gpuobj;
unsigned long flags;
u32 co, ho;
spin_lock_irqsave(&chan->ramht->lock, flags);
co = ho = nouveau_ramht_hash_handle(chan, handle);
do {
if (nouveau_ramht_entry_valid(dev, ramht, co) &&
nouveau_ramht_entry_same_channel(chan, ramht, co) &&
(handle == nv_ro32(ramht, co))) {
NV_DEBUG(dev,
"remove ch%d 0x%08x: h=0x%08x, c=0x%08x\n",
chan->id, co, handle, nv_ro32(ramht, co + 4));
nv_wo32(ramht, co + 0, 0x00000000);
nv_wo32(ramht, co + 4, 0x00000000);
nvimem_flush(dev);
goto out;
}
co += 8;
if (co >= ramht->size)
co = 0;
} while (co != ho);
NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n",
chan->id, handle);
out:
spin_unlock_irqrestore(&chan->ramht->lock, flags);
}
int
nouveau_ramht_remove(struct nouveau_channel *chan, u32 handle)
void
nouveau_ramht_remove(struct nouveau_ramht *ramht, int cookie)
{
struct nouveau_ramht_entry *entry;
entry = nouveau_ramht_remove_entry(chan, handle);
if (!entry)
return -ENOENT;
nouveau_ramht_remove_hash(chan, entry->handle);
nouveau_gpuobj_ref(NULL, &entry->gpuobj);
kfree(entry);
return 0;
struct nouveau_bar *bar = nouveau_bar(ramht);
nv_wo32(ramht, cookie + 0, 0x00000000);
nv_wo32(ramht, cookie + 4, 0x00000000);
if (bar)
bar->flush(bar);
}
struct nouveau_gpuobj *
nouveau_ramht_find(struct nouveau_channel *chan, u32 handle)
{
struct nouveau_ramht *ramht = chan->ramht;
struct nouveau_ramht_entry *entry;
struct nouveau_gpuobj *gpuobj = NULL;
unsigned long flags;
if (unlikely(!chan->ramht))
return NULL;
spin_lock_irqsave(&ramht->lock, flags);
list_for_each_entry(entry, &chan->ramht->entries, head) {
if (entry->channel == chan && entry->handle == handle) {
gpuobj = entry->gpuobj;
break;
}
}
spin_unlock_irqrestore(&ramht->lock, flags);
return gpuobj;
}
static struct nouveau_oclass
nouveau_ramht_oclass = {
.handle = 0x0000abcd,
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = NULL,
.dtor = _nouveau_gpuobj_dtor,
.init = _nouveau_gpuobj_init,
.fini = _nouveau_gpuobj_fini,
.rd32 = _nouveau_gpuobj_rd32,
.wr32 = _nouveau_gpuobj_wr32,
},
};
int
nouveau_ramht_new(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
struct nouveau_ramht **pramht)
nouveau_ramht_new(struct nouveau_object *parent, struct nouveau_object *pargpu,
u32 size, u32 align, struct nouveau_ramht **pramht)
{
struct nouveau_ramht *ramht;
int ret;
ramht = kzalloc(sizeof(*ramht), GFP_KERNEL);
if (!ramht)
return -ENOMEM;
ramht->dev = dev;
kref_init(&ramht->refcount);
ramht->bits = drm_order(gpuobj->size / 8);
INIT_LIST_HEAD(&ramht->entries);
spin_lock_init(&ramht->lock);
nouveau_gpuobj_ref(gpuobj, &ramht->gpuobj);
ret = nouveau_gpuobj_create(parent, parent->engine ?
parent->engine : parent, /* <nv50 ramht */
&nouveau_ramht_oclass, 0, pargpu, size,
align, NVOBJ_FLAG_ZERO_ALLOC, &ramht);
*pramht = ramht;
return 0;
}
if (ret)
return ret;
static void
nouveau_ramht_del(struct kref *ref)
{
struct nouveau_ramht *ramht =
container_of(ref, struct nouveau_ramht, refcount);
nouveau_gpuobj_ref(NULL, &ramht->gpuobj);
kfree(ramht);
}
void
nouveau_ramht_ref(struct nouveau_ramht *ref, struct nouveau_ramht **ptr,
struct nouveau_channel *chan)
{
struct nouveau_ramht_entry *entry;
struct nouveau_ramht *ramht;
if (ref)
kref_get(&ref->refcount);
ramht = *ptr;
if (ramht) {
while ((entry = nouveau_ramht_remove_entry(chan, 0))) {
nouveau_ramht_remove_hash(chan, entry->handle);
nouveau_gpuobj_ref(NULL, &entry->gpuobj);
kfree(entry);
}
kref_put(&ramht->refcount, nouveau_ramht_del);
}
*ptr = ref;
ramht->bits = log2i(nv_gpuobj(ramht)->size >> 3);
return 0;
}
/*
* Copyright 2011 Red Hat Inc.
* 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"),
......@@ -22,61 +22,154 @@
* Authors: Ben Skeggs
*/
#include "drmP.h"
#include "nouveau_drv.h"
#include "nouveau_util.h"
#include <core/ramht.h>
#include <core/os.h>
#include <core/class.h>
#include <core/engctx.h>
/*XXX: This stub is currently used on NV98+ also, as soon as this becomes
* more than just an enable/disable stub this needs to be split out to
* nv98_bsp.c...
*/
#include <engine/bsp.h>
struct nv84_bsp_priv {
struct nouveau_bsp base;
};
struct nv84_bsp_engine {
struct nouveau_exec_engine base;
struct nv84_bsp_chan {
struct nouveau_bsp_chan base;
};
/*******************************************************************************
* BSP object classes
******************************************************************************/
static struct nouveau_oclass
nv84_bsp_sclass[] = {
{},
};
/*******************************************************************************
* BSP context
******************************************************************************/
static int
nv84_bsp_fini(struct drm_device *dev, int engine, bool suspend)
nv84_bsp_context_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
if (!(nv_rd32(dev, 0x000200) & 0x00008000))
return 0;
struct nv84_bsp_chan *priv;
int ret;
ret = nouveau_bsp_context_create(parent, engine, oclass, NULL,
0, 0, 0, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_mask(dev, 0x000200, 0x00008000, 0x00000000);
return 0;
}
static void
nv84_bsp_context_dtor(struct nouveau_object *object)
{
struct nv84_bsp_chan *priv = (void *)object;
nouveau_bsp_context_destroy(&priv->base);
}
static int
nv84_bsp_init(struct drm_device *dev, int engine)
nv84_bsp_context_init(struct nouveau_object *object)
{
nv_mask(dev, 0x000200, 0x00008000, 0x00000000);
nv_mask(dev, 0x000200, 0x00008000, 0x00008000);
struct nv84_bsp_chan *priv = (void *)object;
int ret;
ret = nouveau_bsp_context_init(&priv->base);
if (ret)
return ret;
return 0;
}
static int
nv84_bsp_context_fini(struct nouveau_object *object, bool suspend)
{
struct nv84_bsp_chan *priv = (void *)object;
return nouveau_bsp_context_fini(&priv->base, suspend);
}
static struct nouveau_oclass
nv84_bsp_cclass = {
.handle = NV_ENGCTX(BSP, 0x84),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv84_bsp_context_ctor,
.dtor = nv84_bsp_context_dtor,
.init = nv84_bsp_context_init,
.fini = nv84_bsp_context_fini,
.rd32 = _nouveau_bsp_context_rd32,
.wr32 = _nouveau_bsp_context_wr32,
},
};
/*******************************************************************************
* BSP engine/subdev functions
******************************************************************************/
static void
nv84_bsp_destroy(struct drm_device *dev, int engine)
nv84_bsp_intr(struct nouveau_subdev *subdev)
{
struct nv84_bsp_engine *pbsp = nv_engine(dev, engine);
}
NVOBJ_ENGINE_DEL(dev, BSP);
static int
nv84_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv84_bsp_priv *priv;
int ret;
ret = nouveau_bsp_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
kfree(pbsp);
nv_subdev(priv)->unit = 0x04008000;
nv_subdev(priv)->intr = nv84_bsp_intr;
nv_engine(priv)->cclass = &nv84_bsp_cclass;
nv_engine(priv)->sclass = nv84_bsp_sclass;
return 0;
}
int
nv84_bsp_create(struct drm_device *dev)
static void
nv84_bsp_dtor(struct nouveau_object *object)
{
struct nv84_bsp_engine *pbsp;
struct nv84_bsp_priv *priv = (void *)object;
nouveau_bsp_destroy(&priv->base);
}
pbsp = kzalloc(sizeof(*pbsp), GFP_KERNEL);
if (!pbsp)
return -ENOMEM;
static int
nv84_bsp_init(struct nouveau_object *object)
{
struct nv84_bsp_priv *priv = (void *)object;
int ret;
pbsp->base.destroy = nv84_bsp_destroy;
pbsp->base.init = nv84_bsp_init;
pbsp->base.fini = nv84_bsp_fini;
ret = nouveau_bsp_init(&priv->base);
if (ret)
return ret;
NVOBJ_ENGINE_ADD(dev, BSP, &pbsp->base);
return 0;
}
static int
nv84_bsp_fini(struct nouveau_object *object, bool suspend)
{
struct nv84_bsp_priv *priv = (void *)object;
return nouveau_bsp_fini(&priv->base, suspend);
}
struct nouveau_oclass
nv84_bsp_oclass = {
.handle = NV_ENGINE(BSP, 0x84),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv84_bsp_ctor,
.dtor = nv84_bsp_dtor,
.init = nv84_bsp_init,
.fini = nv84_bsp_fini,
},
};
/*
* Copyright 2011 Red Hat Inc.
* 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"),
......@@ -22,112 +22,75 @@
* Authors: Ben Skeggs
*/
#include <linux/firmware.h>
#include "drmP.h"
#include "nouveau_drv.h"
#include "nouveau_util.h"
#include <core/ramht.h>
#include "fuc/nva3.fuc.h"
struct nva3_copy_engine {
struct nouveau_exec_engine base;
};
static int
nva3_copy_context_new(struct nouveau_channel *chan, int engine)
{
struct drm_device *dev = chan->dev;
struct nouveau_gpuobj *ramin = chan->ramin;
struct nouveau_gpuobj *ctx = NULL;
int ret;
NV_DEBUG(dev, "ch%d\n", chan->id);
#include <core/os.h>
#include <core/enum.h>
#include <core/class.h>
#include <core/engctx.h>
ret = nouveau_gpuobj_new(dev, chan, 256, 0, NVOBJ_FLAG_ZERO_ALLOC |
NVOBJ_FLAG_ZERO_FREE, &ctx);
if (ret)
return ret;
#include <subdev/fb.h>
#include <subdev/vm.h>
nv_wo32(ramin, 0xc0, 0x00190000);
nv_wo32(ramin, 0xc4, ctx->addr + ctx->size - 1);
nv_wo32(ramin, 0xc8, ctx->addr);
nv_wo32(ramin, 0xcc, 0x00000000);
nv_wo32(ramin, 0xd0, 0x00000000);
nv_wo32(ramin, 0xd4, 0x00000000);
nvimem_flush(dev);
#include <engine/copy.h>
nvvm_engref(chan->vm, engine, 1);
chan->engctx[engine] = ctx;
return 0;
}
static int
nva3_copy_object_new(struct nouveau_channel *chan, int engine,
u32 handle, u16 class)
{
struct nouveau_gpuobj *ctx = chan->engctx[engine];
#include "fuc/nva3.fuc.h"
/* fuc engine doesn't need an object, our ramht code does.. */
ctx->engine = 3;
ctx->class = class;
return nouveau_ramht_insert(chan, handle, ctx);
}
struct nva3_copy_priv {
struct nouveau_copy base;
};
static void
nva3_copy_context_del(struct nouveau_channel *chan, int engine)
{
struct nouveau_gpuobj *ctx = chan->engctx[engine];
int i;
struct nva3_copy_chan {
struct nouveau_copy_chan base;
};
for (i = 0xc0; i <= 0xd4; i += 4)
nv_wo32(chan->ramin, i, 0x00000000);
/*******************************************************************************
* Copy object classes
******************************************************************************/
nvvm_engref(chan->vm, engine, -1);
nouveau_gpuobj_ref(NULL, &ctx);
chan->engctx[engine] = ctx;
}
static struct nouveau_oclass
nva3_copy_sclass[] = {
{ 0x85b5, &nouveau_object_ofuncs },
{}
};
static void
nva3_copy_tlb_flush(struct drm_device *dev, int engine)
{
nv50_vm_flush_engine(dev, 0x0d);
}
/*******************************************************************************
* PCOPY context
******************************************************************************/
static int
nva3_copy_init(struct drm_device *dev, int engine)
nva3_copy_context_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
int i;
nv_mask(dev, 0x000200, 0x00002000, 0x00000000);
nv_mask(dev, 0x000200, 0x00002000, 0x00002000);
nv_wr32(dev, 0x104014, 0xffffffff); /* disable all interrupts */
/* upload ucode */
nv_wr32(dev, 0x1041c0, 0x01000000);
for (i = 0; i < sizeof(nva3_pcopy_data) / 4; i++)
nv_wr32(dev, 0x1041c4, nva3_pcopy_data[i]);
struct nva3_copy_chan *priv;
int ret;
nv_wr32(dev, 0x104180, 0x01000000);
for (i = 0; i < sizeof(nva3_pcopy_code) / 4; i++) {
if ((i & 0x3f) == 0)
nv_wr32(dev, 0x104188, i >> 6);
nv_wr32(dev, 0x104184, nva3_pcopy_code[i]);
}
ret = nouveau_copy_context_create(parent, engine, oclass, NULL, 256, 0,
NVOBJ_FLAG_ZERO_ALLOC, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
/* start it running */
nv_wr32(dev, 0x10410c, 0x00000000);
nv_wr32(dev, 0x104104, 0x00000000); /* ENTRY */
nv_wr32(dev, 0x104100, 0x00000002); /* TRIGGER */
return 0;
}
static int
nva3_copy_fini(struct drm_device *dev, int engine, bool suspend)
{
nv_mask(dev, 0x104048, 0x00000003, 0x00000000);
nv_wr32(dev, 0x104014, 0xffffffff);
return 0;
}
static struct nouveau_oclass
nva3_copy_cclass = {
.handle = NV_ENGCTX(COPY0, 0xa3),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nva3_copy_context_ctor,
.dtor = _nouveau_copy_context_dtor,
.init = _nouveau_copy_context_init,
.fini = _nouveau_copy_context_fini,
.rd32 = _nouveau_copy_context_rd32,
.wr32 = _nouveau_copy_context_wr32,
},
};
/*******************************************************************************
* PCOPY engine/subdev functions
******************************************************************************/
static struct nouveau_enum nva3_copy_isr_error_name[] = {
{ 0x0001, "ILLEGAL_MTHD" },
......@@ -137,65 +100,114 @@ static struct nouveau_enum nva3_copy_isr_error_name[] = {
};
static void
nva3_copy_isr(struct drm_device *dev)
nva3_copy_intr(struct nouveau_subdev *subdev)
{
u32 dispatch = nv_rd32(dev, 0x10401c);
u32 stat = nv_rd32(dev, 0x104008) & dispatch & ~(dispatch >> 16);
u32 inst = nv_rd32(dev, 0x104050) & 0x3fffffff;
u32 ssta = nv_rd32(dev, 0x104040) & 0x0000ffff;
u32 addr = nv_rd32(dev, 0x104040) >> 16;
struct nva3_copy_priv *priv = (void *)subdev;
u32 dispatch = nv_rd32(priv, 0x10401c);
u32 stat = nv_rd32(priv, 0x104008) & dispatch & ~(dispatch >> 16);
u32 inst = nv_rd32(priv, 0x104050) & 0x3fffffff;
u32 ssta = nv_rd32(priv, 0x104040) & 0x0000ffff;
u32 addr = nv_rd32(priv, 0x104040) >> 16;
u32 mthd = (addr & 0x07ff) << 2;
u32 subc = (addr & 0x3800) >> 11;
u32 data = nv_rd32(dev, 0x104044);
int chid = nv50_graph_isr_chid(dev, inst);
u32 data = nv_rd32(priv, 0x104044);
if (stat & 0x00000040) {
NV_INFO(dev, "PCOPY: DISPATCH_ERROR [");
nv_error(priv, "DISPATCH_ERROR [");
nouveau_enum_print(nva3_copy_isr_error_name, ssta);
printk("] ch %d [0x%08x] subc %d mthd 0x%04x data 0x%08x\n",
chid, inst, subc, mthd, data);
nv_wr32(dev, 0x104004, 0x00000040);
printk("] ch 0x%08x subc %d mthd 0x%04x data 0x%08x\n",
inst, subc, mthd, data);
nv_wr32(priv, 0x104004, 0x00000040);
stat &= ~0x00000040;
}
if (stat) {
NV_INFO(dev, "PCOPY: unhandled intr 0x%08x\n", stat);
nv_wr32(dev, 0x104004, stat);
nv_error(priv, "unhandled intr 0x%08x\n", stat);
nv_wr32(priv, 0x104004, stat);
}
nv50_fb_vm_trap(dev, 1);
nv50_fb_trap(nouveau_fb(priv), 1);
}
static void
nva3_copy_destroy(struct drm_device *dev, int engine)
static int
nva3_copy_tlb_flush(struct nouveau_engine *engine)
{
struct nva3_copy_engine *pcopy = nv_engine(dev, engine);
nv50_vm_flush_engine(&engine->base, 0x0d);
return 0;
}
nouveau_irq_unregister(dev, 22);
static int
nva3_copy_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
bool enable = (nv_device(parent)->chipset != 0xaf);
struct nva3_copy_priv *priv;
int ret;
NVOBJ_ENGINE_DEL(dev, COPY0);
kfree(pcopy);
ret = nouveau_copy_create(parent, engine, oclass, enable, 0, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00802000;
nv_subdev(priv)->intr = nva3_copy_intr;
nv_engine(priv)->cclass = &nva3_copy_cclass;
nv_engine(priv)->sclass = nva3_copy_sclass;
nv_engine(priv)->tlb_flush = nva3_copy_tlb_flush;
return 0;
}
int
nva3_copy_create(struct drm_device *dev)
static int
nva3_copy_init(struct nouveau_object *object)
{
struct nva3_copy_engine *pcopy;
struct nva3_copy_priv *priv = (void *)object;
int ret, i;
pcopy = kzalloc(sizeof(*pcopy), GFP_KERNEL);
if (!pcopy)
return -ENOMEM;
ret = nouveau_copy_init(&priv->base);
if (ret)
return ret;
pcopy->base.destroy = nva3_copy_destroy;
pcopy->base.init = nva3_copy_init;
pcopy->base.fini = nva3_copy_fini;
pcopy->base.context_new = nva3_copy_context_new;
pcopy->base.context_del = nva3_copy_context_del;
pcopy->base.object_new = nva3_copy_object_new;
pcopy->base.tlb_flush = nva3_copy_tlb_flush;
/* disable all interrupts */
nv_wr32(priv, 0x104014, 0xffffffff);
nouveau_irq_register(dev, 22, nva3_copy_isr);
/* upload ucode */
nv_wr32(priv, 0x1041c0, 0x01000000);
for (i = 0; i < sizeof(nva3_pcopy_data) / 4; i++)
nv_wr32(priv, 0x1041c4, nva3_pcopy_data[i]);
nv_wr32(priv, 0x104180, 0x01000000);
for (i = 0; i < sizeof(nva3_pcopy_code) / 4; i++) {
if ((i & 0x3f) == 0)
nv_wr32(priv, 0x104188, i >> 6);
nv_wr32(priv, 0x104184, nva3_pcopy_code[i]);
}
NVOBJ_ENGINE_ADD(dev, COPY0, &pcopy->base);
NVOBJ_CLASS(dev, 0x85b5, COPY0);
/* start it running */
nv_wr32(priv, 0x10410c, 0x00000000);
nv_wr32(priv, 0x104104, 0x00000000); /* ENTRY */
nv_wr32(priv, 0x104100, 0x00000002); /* TRIGGER */
return 0;
}
static int
nva3_copy_fini(struct nouveau_object *object, bool suspend)
{
struct nva3_copy_priv *priv = (void *)object;
nv_mask(priv, 0x104048, 0x00000003, 0x00000000);
nv_wr32(priv, 0x104014, 0xffffffff);
return nouveau_copy_fini(&priv->base, suspend);
}
struct nouveau_oclass
nva3_copy_oclass = {
.handle = NV_ENGINE(COPY0, 0xa3),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nva3_copy_ctor,
.dtor = _nouveau_copy_dtor,
.init = nva3_copy_init,
.fini = nva3_copy_fini,
},
};
/*
* Copyright 2011 Red Hat Inc.
* 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"),
......@@ -22,138 +22,86 @@
* Authors: Ben Skeggs
*/
#include <linux/firmware.h>
#include "drmP.h"
#include "nouveau_drv.h"
#include "nouveau_util.h"
#include <core/ramht.h>
#include <core/os.h>
#include <core/enum.h>
#include <core/class.h>
#include <core/engctx.h>
#include <engine/copy.h>
#include "fuc/nvc0.fuc.h"
struct nvc0_copy_engine {
struct nouveau_exec_engine base;
u32 irq;
u32 pmc;
u32 fuc;
u32 ctx;
struct nvc0_copy_priv {
struct nouveau_copy base;
};
struct nvc0_copy_chan {
struct nouveau_gpuobj *mem;
struct nouveau_vma vma;
struct nouveau_copy_chan base;
};
static int
nvc0_copy_context_new(struct nouveau_channel *chan, int engine)
{
struct nvc0_copy_engine *pcopy = nv_engine(chan->dev, engine);
struct nvc0_copy_chan *cctx;
struct drm_device *dev = chan->dev;
struct nouveau_gpuobj *ramin = chan->ramin;
int ret;
cctx = chan->engctx[engine] = kzalloc(sizeof(*cctx), GFP_KERNEL);
if (!cctx)
return -ENOMEM;
/*******************************************************************************
* Copy object classes
******************************************************************************/
ret = nouveau_gpuobj_new(dev, NULL, 256, 256,
NVOBJ_FLAG_ZERO_ALLOC, &cctx->mem);
if (ret)
return ret;
static struct nouveau_oclass
nvc0_copy0_sclass[] = {
{ 0x90b5, &nouveau_object_ofuncs },
{},
};
ret = nouveau_gpuobj_map_vm(cctx->mem, chan->vm, NV_MEM_ACCESS_RW,
&cctx->vma);
if (ret)
return ret;
static struct nouveau_oclass
nvc0_copy1_sclass[] = {
{ 0x90b8, &nouveau_object_ofuncs },
{},
};
nv_wo32(ramin, pcopy->ctx + 0, lower_32_bits(cctx->vma.offset));
nv_wo32(ramin, pcopy->ctx + 4, upper_32_bits(cctx->vma.offset));
nvimem_flush(dev);
return 0;
}
/*******************************************************************************
* PCOPY context
******************************************************************************/
static int
nvc0_copy_object_new(struct nouveau_channel *chan, int engine,
u32 handle, u16 class)
{
return 0;
}
static void
nvc0_copy_context_del(struct nouveau_channel *chan, int engine)
nvc0_copy_context_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nvc0_copy_engine *pcopy = nv_engine(chan->dev, engine);
struct nvc0_copy_chan *cctx = chan->engctx[engine];
struct drm_device *dev = chan->dev;
u32 inst;
inst = (chan->ramin->addr >> 12);
inst |= 0x40000000;
/* disable fifo access */
nv_wr32(dev, pcopy->fuc + 0x048, 0x00000000);
/* mark channel as unloaded if it's currently active */
if (nv_rd32(dev, pcopy->fuc + 0x050) == inst)
nv_mask(dev, pcopy->fuc + 0x050, 0x40000000, 0x00000000);
/* mark next channel as invalid if it's about to be loaded */
if (nv_rd32(dev, pcopy->fuc + 0x054) == inst)
nv_mask(dev, pcopy->fuc + 0x054, 0x40000000, 0x00000000);
/* restore fifo access */
nv_wr32(dev, pcopy->fuc + 0x048, 0x00000003);
nv_wo32(chan->ramin, pcopy->ctx + 0, 0x00000000);
nv_wo32(chan->ramin, pcopy->ctx + 4, 0x00000000);
nouveau_gpuobj_unmap(&cctx->vma);
nouveau_gpuobj_ref(NULL, &cctx->mem);
kfree(cctx);
chan->engctx[engine] = NULL;
}
static int
nvc0_copy_init(struct drm_device *dev, int engine)
{
struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
int i;
nv_mask(dev, 0x000200, pcopy->pmc, 0x00000000);
nv_mask(dev, 0x000200, pcopy->pmc, pcopy->pmc);
nv_wr32(dev, pcopy->fuc + 0x014, 0xffffffff);
nv_wr32(dev, pcopy->fuc + 0x1c0, 0x01000000);
for (i = 0; i < sizeof(nvc0_pcopy_data) / 4; i++)
nv_wr32(dev, pcopy->fuc + 0x1c4, nvc0_pcopy_data[i]);
struct nvc0_copy_chan *priv;
int ret;
nv_wr32(dev, pcopy->fuc + 0x180, 0x01000000);
for (i = 0; i < sizeof(nvc0_pcopy_code) / 4; i++) {
if ((i & 0x3f) == 0)
nv_wr32(dev, pcopy->fuc + 0x188, i >> 6);
nv_wr32(dev, pcopy->fuc + 0x184, nvc0_pcopy_code[i]);
}
ret = nouveau_copy_context_create(parent, engine, oclass, NULL, 256,
256, NVOBJ_FLAG_ZERO_ALLOC, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_wr32(dev, pcopy->fuc + 0x084, engine - NVOBJ_ENGINE_COPY0);
nv_wr32(dev, pcopy->fuc + 0x10c, 0x00000000);
nv_wr32(dev, pcopy->fuc + 0x104, 0x00000000); /* ENTRY */
nv_wr32(dev, pcopy->fuc + 0x100, 0x00000002); /* TRIGGER */
return 0;
}
static int
nvc0_copy_fini(struct drm_device *dev, int engine, bool suspend)
{
struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
static struct nouveau_ofuncs
nvc0_copy_context_ofuncs = {
.ctor = nvc0_copy_context_ctor,
.dtor = _nouveau_copy_context_dtor,
.init = _nouveau_copy_context_init,
.fini = _nouveau_copy_context_fini,
.rd32 = _nouveau_copy_context_rd32,
.wr32 = _nouveau_copy_context_wr32,
};
nv_mask(dev, pcopy->fuc + 0x048, 0x00000003, 0x00000000);
static struct nouveau_oclass
nvc0_copy0_cclass = {
.handle = NV_ENGCTX(COPY0, 0xc0),
.ofuncs = &nvc0_copy_context_ofuncs,
};
/* trigger fuc context unload */
nv_wait(dev, pcopy->fuc + 0x008, 0x0000000c, 0x00000000);
nv_mask(dev, pcopy->fuc + 0x054, 0x40000000, 0x00000000);
nv_wr32(dev, pcopy->fuc + 0x000, 0x00000008);
nv_wait(dev, pcopy->fuc + 0x008, 0x00000008, 0x00000000);
static struct nouveau_oclass
nvc0_copy1_cclass = {
.handle = NV_ENGCTX(COPY1, 0xc0),
.ofuncs = &nvc0_copy_context_ofuncs,
};
nv_wr32(dev, pcopy->fuc + 0x014, 0xffffffff);
return 0;
}
/*******************************************************************************
* PCOPY engine/subdev functions
******************************************************************************/
static struct nouveau_enum nvc0_copy_isr_error_name[] = {
{ 0x0001, "ILLEGAL_MTHD" },
......@@ -163,93 +111,145 @@ static struct nouveau_enum nvc0_copy_isr_error_name[] = {
};
static void
nvc0_copy_isr(struct drm_device *dev, int engine)
nvc0_copy_intr(struct nouveau_subdev *subdev)
{
struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
u32 disp = nv_rd32(dev, pcopy->fuc + 0x01c);
u32 stat = nv_rd32(dev, pcopy->fuc + 0x008) & disp & ~(disp >> 16);
u64 inst = (u64)(nv_rd32(dev, pcopy->fuc + 0x050) & 0x0fffffff) << 12;
u32 chid = nvc0_graph_isr_chid(dev, inst);
u32 ssta = nv_rd32(dev, pcopy->fuc + 0x040) & 0x0000ffff;
u32 addr = nv_rd32(dev, pcopy->fuc + 0x040) >> 16;
int idx = nv_engidx(nv_object(subdev)) - NVDEV_ENGINE_COPY0;
struct nvc0_copy_priv *priv = (void *)subdev;
u32 disp = nv_rd32(priv, 0x10401c + (idx * 0x1000));
u32 intr = nv_rd32(priv, 0x104008 + (idx * 0x1000));
u32 stat = intr & disp & ~(disp >> 16);
u64 inst = nv_rd32(priv, 0x104050 + (idx * 0x1000)) & 0x0fffffff;
u32 ssta = nv_rd32(priv, 0x104040 + (idx * 0x1000)) & 0x0000ffff;
u32 addr = nv_rd32(priv, 0x104040 + (idx * 0x1000)) >> 16;
u32 mthd = (addr & 0x07ff) << 2;
u32 subc = (addr & 0x3800) >> 11;
u32 data = nv_rd32(dev, pcopy->fuc + 0x044);
u32 data = nv_rd32(priv, 0x104044 + (idx * 0x1000));
if (stat & 0x00000040) {
NV_INFO(dev, "PCOPY: DISPATCH_ERROR [");
nv_error(priv, "DISPATCH_ERROR [");
nouveau_enum_print(nvc0_copy_isr_error_name, ssta);
printk("] ch %d [0x%010llx] subc %d mthd 0x%04x data 0x%08x\n",
chid, inst, subc, mthd, data);
nv_wr32(dev, pcopy->fuc + 0x004, 0x00000040);
printk("] ch 0x%010llx subc %d mthd 0x%04x data 0x%08x\n",
(u64)inst << 12, subc, mthd, data);
nv_wr32(priv, 0x104004 + (idx * 0x1000), 0x00000040);
stat &= ~0x00000040;
}
if (stat) {
NV_INFO(dev, "PCOPY: unhandled intr 0x%08x\n", stat);
nv_wr32(dev, pcopy->fuc + 0x004, stat);
nv_error(priv, "unhandled intr 0x%08x\n", stat);
nv_wr32(priv, 0x104004 + (idx * 0x1000), stat);
}
}
static void
nvc0_copy_isr_0(struct drm_device *dev)
static int
nvc0_copy0_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
nvc0_copy_isr(dev, NVOBJ_ENGINE_COPY0);
}
struct nvc0_copy_priv *priv;
int ret;
static void
nvc0_copy_isr_1(struct drm_device *dev)
{
nvc0_copy_isr(dev, NVOBJ_ENGINE_COPY1);
if (nv_rd32(parent, 0x022500) & 0x00000100)
return -ENODEV;
ret = nouveau_copy_create(parent, engine, oclass, true, 0, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00000040;
nv_subdev(priv)->intr = nvc0_copy_intr;
nv_engine(priv)->cclass = &nvc0_copy0_cclass;
nv_engine(priv)->sclass = nvc0_copy0_sclass;
return 0;
}
static void
nvc0_copy_destroy(struct drm_device *dev, int engine)
static int
nvc0_copy1_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
struct nvc0_copy_priv *priv;
int ret;
nouveau_irq_unregister(dev, pcopy->irq);
if (nv_rd32(parent, 0x022500) & 0x00000200)
return -ENODEV;
if (engine == NVOBJ_ENGINE_COPY0)
NVOBJ_ENGINE_DEL(dev, COPY0);
else
NVOBJ_ENGINE_DEL(dev, COPY1);
kfree(pcopy);
ret = nouveau_copy_create(parent, engine, oclass, true, 1, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00000080;
nv_subdev(priv)->intr = nvc0_copy_intr;
nv_engine(priv)->cclass = &nvc0_copy1_cclass;
nv_engine(priv)->sclass = nvc0_copy1_sclass;
return 0;
}
int
nvc0_copy_create(struct drm_device *dev, int engine)
static int
nvc0_copy_init(struct nouveau_object *object)
{
struct nvc0_copy_engine *pcopy;
pcopy = kzalloc(sizeof(*pcopy), GFP_KERNEL);
if (!pcopy)
return -ENOMEM;
pcopy->base.destroy = nvc0_copy_destroy;
pcopy->base.init = nvc0_copy_init;
pcopy->base.fini = nvc0_copy_fini;
pcopy->base.context_new = nvc0_copy_context_new;
pcopy->base.context_del = nvc0_copy_context_del;
pcopy->base.object_new = nvc0_copy_object_new;
if (engine == 0) {
pcopy->irq = 5;
pcopy->pmc = 0x00000040;
pcopy->fuc = 0x104000;
pcopy->ctx = 0x0230;
nouveau_irq_register(dev, pcopy->irq, nvc0_copy_isr_0);
NVOBJ_ENGINE_ADD(dev, COPY0, &pcopy->base);
NVOBJ_CLASS(dev, 0x90b5, COPY0);
} else {
pcopy->irq = 6;
pcopy->pmc = 0x00000080;
pcopy->fuc = 0x105000;
pcopy->ctx = 0x0240;
nouveau_irq_register(dev, pcopy->irq, nvc0_copy_isr_1);
NVOBJ_ENGINE_ADD(dev, COPY1, &pcopy->base);
NVOBJ_CLASS(dev, 0x90b8, COPY1);
int idx = nv_engidx(object) - NVDEV_ENGINE_COPY0;
struct nvc0_copy_priv *priv = (void *)object;
int ret, i;
ret = nouveau_copy_init(&priv->base);
if (ret)
return ret;
/* disable all interrupts */
nv_wr32(priv, 0x104014 + (idx * 0x1000), 0xffffffff);
/* upload ucode */
nv_wr32(priv, 0x1041c0 + (idx * 0x1000), 0x01000000);
for (i = 0; i < sizeof(nvc0_pcopy_data) / 4; i++)
nv_wr32(priv, 0x1041c4 + (idx * 0x1000), nvc0_pcopy_data[i]);
nv_wr32(priv, 0x104180 + (idx * 0x1000), 0x01000000);
for (i = 0; i < sizeof(nvc0_pcopy_code) / 4; i++) {
if ((i & 0x3f) == 0)
nv_wr32(priv, 0x104188 + (idx * 0x1000), i >> 6);
nv_wr32(priv, 0x104184 + (idx * 0x1000), nvc0_pcopy_code[i]);
}
/* start it running */
nv_wr32(priv, 0x104084 + (idx * 0x1000), idx);
nv_wr32(priv, 0x10410c + (idx * 0x1000), 0x00000000);
nv_wr32(priv, 0x104104 + (idx * 0x1000), 0x00000000); /* ENTRY */
nv_wr32(priv, 0x104100 + (idx * 0x1000), 0x00000002); /* TRIGGER */
return 0;
}
static int
nvc0_copy_fini(struct nouveau_object *object, bool suspend)
{
int idx = nv_engidx(object) - NVDEV_ENGINE_COPY0;
struct nvc0_copy_priv *priv = (void *)object;
nv_mask(priv, 0x104048 + (idx * 0x1000), 0x00000003, 0x00000000);
nv_wr32(priv, 0x104014 + (idx * 0x1000), 0xffffffff);
return nouveau_copy_fini(&priv->base, suspend);
}
struct nouveau_oclass
nvc0_copy0_oclass = {
.handle = NV_ENGINE(COPY0, 0xc0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nvc0_copy0_ctor,
.dtor = _nouveau_copy_dtor,
.init = nvc0_copy_init,
.fini = nvc0_copy_fini,
},
};
struct nouveau_oclass
nvc0_copy1_oclass = {
.handle = NV_ENGINE(COPY1, 0xc0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nvc0_copy1_ctor,
.dtor = _nouveau_copy_dtor,
.init = nvc0_copy_init,
.fini = nvc0_copy_fini,
},
};
/*
* Copyright 2010 Red Hat Inc.
* 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"),
......@@ -22,99 +22,106 @@
* Authors: Ben Skeggs
*/
#include "drmP.h"
#include "nouveau_drv.h"
#include "nouveau_util.h"
#include <core/ramht.h>
#include <core/os.h>
#include <core/enum.h>
#include <core/class.h>
#include <core/engctx.h>
#include <core/gpuobj.h>
struct nv84_crypt_engine {
struct nouveau_exec_engine base;
#include <subdev/fb.h>
#include <engine/crypt.h>
struct nv84_crypt_priv {
struct nouveau_crypt base;
};
struct nv84_crypt_chan {
struct nouveau_crypt_chan base;
};
/*******************************************************************************
* Crypt object classes
******************************************************************************/
static int
nv84_crypt_context_new(struct nouveau_channel *chan, int engine)
nv84_crypt_object_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct drm_device *dev = chan->dev;
struct nouveau_gpuobj *ramin = chan->ramin;
struct nouveau_gpuobj *ctx;
struct nouveau_gpuobj *obj;
int ret;
NV_DEBUG(dev, "ch%d\n", chan->id);
ret = nouveau_gpuobj_new(dev, chan, 256, 0, NVOBJ_FLAG_ZERO_ALLOC |
NVOBJ_FLAG_ZERO_FREE, &ctx);
ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent,
16, 16, 0, &obj);
*pobject = nv_object(obj);
if (ret)
return ret;
nv_wo32(ramin, 0xa0, 0x00190000);
nv_wo32(ramin, 0xa4, ctx->addr + ctx->size - 1);
nv_wo32(ramin, 0xa8, ctx->addr);
nv_wo32(ramin, 0xac, 0);
nv_wo32(ramin, 0xb0, 0);
nv_wo32(ramin, 0xb4, 0);
nvimem_flush(dev);
nvvm_engref(chan->vm, engine, 1);
chan->engctx[engine] = ctx;
nv_wo32(obj, 0x00, nv_mclass(obj));
nv_wo32(obj, 0x04, 0x00000000);
nv_wo32(obj, 0x08, 0x00000000);
nv_wo32(obj, 0x0c, 0x00000000);
return 0;
}
static void
nv84_crypt_context_del(struct nouveau_channel *chan, int engine)
{
struct nouveau_gpuobj *ctx = chan->engctx[engine];
struct drm_device *dev = chan->dev;
u32 inst;
inst = (chan->ramin->addr >> 12);
inst |= 0x80000000;
/* mark context as invalid if still on the hardware, not
* doing this causes issues the next time PCRYPT is used,
* unsurprisingly :)
*/
nv_wr32(dev, 0x10200c, 0x00000000);
if (nv_rd32(dev, 0x102188) == inst)
nv_mask(dev, 0x102188, 0x80000000, 0x00000000);
if (nv_rd32(dev, 0x10218c) == inst)
nv_mask(dev, 0x10218c, 0x80000000, 0x00000000);
nv_wr32(dev, 0x10200c, 0x00000010);
nouveau_gpuobj_ref(NULL, &ctx);
nvvm_engref(chan->vm, engine, -1);
chan->engctx[engine] = NULL;
}
static struct nouveau_ofuncs
nv84_crypt_ofuncs = {
.ctor = nv84_crypt_object_ctor,
.dtor = _nouveau_gpuobj_dtor,
.init = _nouveau_gpuobj_init,
.fini = _nouveau_gpuobj_fini,
.rd32 = _nouveau_gpuobj_rd32,
.wr32 = _nouveau_gpuobj_wr32,
};
static struct nouveau_oclass
nv84_crypt_sclass[] = {
{ 0x74c1, &nv84_crypt_ofuncs },
{}
};
/*******************************************************************************
* PCRYPT context
******************************************************************************/
static int
nv84_crypt_object_new(struct nouveau_channel *chan, int engine,
u32 handle, u16 class)
nv84_crypt_context_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct drm_device *dev = chan->dev;
struct nouveau_gpuobj *obj = NULL;
struct nv84_crypt_chan *priv;
int ret;
ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
ret = nouveau_crypt_context_create(parent, engine, oclass, NULL, 256,
0, NVOBJ_FLAG_ZERO_ALLOC, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
obj->engine = 5;
obj->class = class;
nv_wo32(obj, 0x00, class);
nvimem_flush(dev);
ret = nouveau_ramht_insert(chan, handle, obj);
nouveau_gpuobj_ref(NULL, &obj);
return ret;
return 0;
}
static void
nv84_crypt_tlb_flush(struct drm_device *dev, int engine)
{
nv50_vm_flush_engine(dev, 0x0a);
}
static struct nouveau_oclass
nv84_crypt_cclass = {
.handle = NV_ENGCTX(CRYPT, 0x84),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv84_crypt_context_ctor,
.dtor = _nouveau_crypt_context_dtor,
.init = _nouveau_crypt_context_init,
.fini = _nouveau_crypt_context_fini,
.rd32 = _nouveau_crypt_context_rd32,
.wr32 = _nouveau_crypt_context_wr32,
},
};
/*******************************************************************************
* PCRYPT engine/subdev functions
******************************************************************************/
static struct nouveau_bitfield nv84_crypt_intr[] = {
static struct nouveau_bitfield nv84_crypt_intr_mask[] = {
{ 0x00000001, "INVALID_STATE" },
{ 0x00000002, "ILLEGAL_MTHD" },
{ 0x00000004, "ILLEGAL_CLASS" },
......@@ -124,79 +131,78 @@ static struct nouveau_bitfield nv84_crypt_intr[] = {
};
static void
nv84_crypt_isr(struct drm_device *dev)
nv84_crypt_intr(struct nouveau_subdev *subdev)
{
u32 stat = nv_rd32(dev, 0x102130);
u32 mthd = nv_rd32(dev, 0x102190);
u32 data = nv_rd32(dev, 0x102194);
u64 inst = (u64)(nv_rd32(dev, 0x102188) & 0x7fffffff) << 12;
int show = nouveau_ratelimit();
int chid = nv50_graph_isr_chid(dev, inst);
if (show) {
NV_INFO(dev, "PCRYPT:");
nouveau_bitfield_print(nv84_crypt_intr, stat);
printk(KERN_CONT " ch %d (0x%010llx) mthd 0x%04x data 0x%08x\n",
chid, inst, mthd, data);
struct nv84_crypt_priv *priv = (void *)subdev;
u32 stat = nv_rd32(priv, 0x102130);
u32 mthd = nv_rd32(priv, 0x102190);
u32 data = nv_rd32(priv, 0x102194);
u32 inst = nv_rd32(priv, 0x102188) & 0x7fffffff;
if (stat) {
nv_error(priv, "");
nouveau_bitfield_print(nv84_crypt_intr_mask, stat);
printk(" ch 0x%010llx mthd 0x%04x data 0x%08x\n",
(u64)inst << 12, mthd, data);
}
nv_wr32(dev, 0x102130, stat);
nv_wr32(dev, 0x10200c, 0x10);
nv_wr32(priv, 0x102130, stat);
nv_wr32(priv, 0x10200c, 0x10);
nv50_fb_vm_trap(dev, show);
nv50_fb_trap(nouveau_fb(priv), 1);
}
static int
nv84_crypt_fini(struct drm_device *dev, int engine, bool suspend)
nv84_crypt_tlb_flush(struct nouveau_engine *engine)
{
nv_wr32(dev, 0x102140, 0x00000000);
nv50_vm_flush_engine(&engine->base, 0x0a);
return 0;
}
static int
nv84_crypt_init(struct drm_device *dev, int engine)
nv84_crypt_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
nv_mask(dev, 0x000200, 0x00004000, 0x00000000);
nv_mask(dev, 0x000200, 0x00004000, 0x00004000);
struct nv84_crypt_priv *priv;
int ret;
nv_wr32(dev, 0x102130, 0xffffffff);
nv_wr32(dev, 0x102140, 0xffffffbf);
ret = nouveau_crypt_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_wr32(dev, 0x10200c, 0x00000010);
nv_subdev(priv)->unit = 0x00004000;
nv_subdev(priv)->intr = nv84_crypt_intr;
nv_engine(priv)->cclass = &nv84_crypt_cclass;
nv_engine(priv)->sclass = nv84_crypt_sclass;
nv_engine(priv)->tlb_flush = nv84_crypt_tlb_flush;
return 0;
}
static void
nv84_crypt_destroy(struct drm_device *dev, int engine)
{
struct nv84_crypt_engine *pcrypt = nv_engine(dev, engine);
NVOBJ_ENGINE_DEL(dev, CRYPT);
nouveau_irq_unregister(dev, 14);
kfree(pcrypt);
}
int
nv84_crypt_create(struct drm_device *dev)
static int
nv84_crypt_init(struct nouveau_object *object)
{
struct nv84_crypt_engine *pcrypt;
pcrypt = kzalloc(sizeof(*pcrypt), GFP_KERNEL);
if (!pcrypt)
return -ENOMEM;
pcrypt->base.destroy = nv84_crypt_destroy;
pcrypt->base.init = nv84_crypt_init;
pcrypt->base.fini = nv84_crypt_fini;
pcrypt->base.context_new = nv84_crypt_context_new;
pcrypt->base.context_del = nv84_crypt_context_del;
pcrypt->base.object_new = nv84_crypt_object_new;
pcrypt->base.tlb_flush = nv84_crypt_tlb_flush;
struct nv84_crypt_priv *priv = (void *)object;
int ret;
nouveau_irq_register(dev, 14, nv84_crypt_isr);
ret = nouveau_crypt_init(&priv->base);
if (ret)
return ret;
NVOBJ_ENGINE_ADD(dev, CRYPT, &pcrypt->base);
NVOBJ_CLASS (dev, 0x74c1, CRYPT);
nv_wr32(priv, 0x102130, 0xffffffff);
nv_wr32(priv, 0x102140, 0xffffffbf);
nv_wr32(priv, 0x10200c, 0x00000010);
return 0;
}
struct nouveau_oclass
nv84_crypt_oclass = {
.handle = NV_ENGINE(CRYPT, 0x84),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv84_crypt_ctor,
.dtor = _nouveau_crypt_dtor,
.init = nv84_crypt_init,
.fini = _nouveau_crypt_fini,
},
};
/*
* Copyright 2011 Red Hat Inc.
* 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"),
......@@ -22,124 +22,74 @@
* Authors: Ben Skeggs
*/
#include "drmP.h"
#include <core/os.h>
#include <core/enum.h>
#include <core/class.h>
#include <core/engctx.h>
#include "nouveau_drv.h"
#include "nouveau_util.h"
#include <core/ramht.h>
#include <subdev/timer.h>
#include <subdev/fb.h>
#include <engine/crypt.h>
#include "fuc/nv98.fuc.h"
struct nv98_crypt_priv {
struct nouveau_exec_engine base;
struct nouveau_crypt base;
};
struct nv98_crypt_chan {
struct nouveau_gpuobj *mem;
struct nouveau_crypt_chan base;
};
static int
nv98_crypt_context_new(struct nouveau_channel *chan, int engine)
{
struct drm_device *dev = chan->dev;
struct nv98_crypt_priv *priv = nv_engine(dev, engine);
struct nv98_crypt_chan *cctx;
int ret;
cctx = chan->engctx[engine] = kzalloc(sizeof(*cctx), GFP_KERNEL);
if (!cctx)
return -ENOMEM;
nvvm_engref(chan->vm, engine, 1);
ret = nouveau_gpuobj_new(dev, chan, 256, 0, NVOBJ_FLAG_ZERO_ALLOC |
NVOBJ_FLAG_ZERO_FREE, &cctx->mem);
if (ret)
goto error;
nv_wo32(chan->ramin, 0xa0, 0x00190000);
nv_wo32(chan->ramin, 0xa4, cctx->mem->addr + cctx->mem->size - 1);
nv_wo32(chan->ramin, 0xa8, cctx->mem->addr);
nv_wo32(chan->ramin, 0xac, 0x00000000);
nv_wo32(chan->ramin, 0xb0, 0x00000000);
nv_wo32(chan->ramin, 0xb4, 0x00000000);
nvimem_flush(dev);
error:
if (ret)
priv->base.context_del(chan, engine);
return ret;
}
static void
nv98_crypt_context_del(struct nouveau_channel *chan, int engine)
{
struct nv98_crypt_chan *cctx = chan->engctx[engine];
int i;
for (i = 0xa0; i < 0xb4; i += 4)
nv_wo32(chan->ramin, i, 0x00000000);
/*******************************************************************************
* Crypt object classes
******************************************************************************/
nouveau_gpuobj_ref(NULL, &cctx->mem);
static struct nouveau_oclass
nv98_crypt_sclass[] = {
{ 0x88b4, &nouveau_object_ofuncs },
{},
};
nvvm_engref(chan->vm, engine, -1);
chan->engctx[engine] = NULL;
kfree(cctx);
}
/*******************************************************************************
* PCRYPT context
******************************************************************************/
static int
nv98_crypt_object_new(struct nouveau_channel *chan, int engine,
u32 handle, u16 class)
nv98_crypt_context_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv98_crypt_chan *cctx = chan->engctx[engine];
/* fuc engine doesn't need an object, our ramht code does.. */
cctx->mem->engine = 5;
cctx->mem->class = class;
return nouveau_ramht_insert(chan, handle, cctx->mem);
}
struct nv98_crypt_chan *priv;
int ret;
static void
nv98_crypt_tlb_flush(struct drm_device *dev, int engine)
{
nv50_vm_flush_engine(dev, 0x0a);
}
ret = nouveau_crypt_context_create(parent, engine, oclass, NULL, 256,
256, NVOBJ_FLAG_ZERO_ALLOC, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
static int
nv98_crypt_fini(struct drm_device *dev, int engine, bool suspend)
{
nv_mask(dev, 0x000200, 0x00004000, 0x00000000);
return 0;
}
static int
nv98_crypt_init(struct drm_device *dev, int engine)
{
int i;
/* reset! */
nv_mask(dev, 0x000200, 0x00004000, 0x00000000);
nv_mask(dev, 0x000200, 0x00004000, 0x00004000);
/* wait for exit interrupt to signal */
nv_wait(dev, 0x087008, 0x00000010, 0x00000010);
nv_wr32(dev, 0x087004, 0x00000010);
/* upload microcode code and data segments */
nv_wr32(dev, 0x087ff8, 0x00100000);
for (i = 0; i < ARRAY_SIZE(nv98_pcrypt_code); i++)
nv_wr32(dev, 0x087ff4, nv98_pcrypt_code[i]);
nv_wr32(dev, 0x087ff8, 0x00000000);
for (i = 0; i < ARRAY_SIZE(nv98_pcrypt_data); i++)
nv_wr32(dev, 0x087ff4, nv98_pcrypt_data[i]);
static struct nouveau_oclass
nv98_crypt_cclass = {
.handle = NV_ENGCTX(CRYPT, 0x98),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv98_crypt_context_ctor,
.dtor = _nouveau_crypt_context_dtor,
.init = _nouveau_crypt_context_init,
.fini = _nouveau_crypt_context_fini,
.rd32 = _nouveau_crypt_context_rd32,
.wr32 = _nouveau_crypt_context_wr32,
},
};
/* start it running */
nv_wr32(dev, 0x08710c, 0x00000000);
nv_wr32(dev, 0x087104, 0x00000000); /* ENTRY */
nv_wr32(dev, 0x087100, 0x00000002); /* TRIGGER */
return 0;
}
/*******************************************************************************
* PCRYPT engine/subdev functions
******************************************************************************/
static struct nouveau_enum nv98_crypt_isr_error_name[] = {
{ 0x0000, "ILLEGAL_MTHD" },
......@@ -150,65 +100,100 @@ static struct nouveau_enum nv98_crypt_isr_error_name[] = {
};
static void
nv98_crypt_isr(struct drm_device *dev)
nv98_crypt_intr(struct nouveau_subdev *subdev)
{
u32 disp = nv_rd32(dev, 0x08701c);
u32 stat = nv_rd32(dev, 0x087008) & disp & ~(disp >> 16);
u32 inst = nv_rd32(dev, 0x087050) & 0x3fffffff;
u32 ssta = nv_rd32(dev, 0x087040) & 0x0000ffff;
u32 addr = nv_rd32(dev, 0x087040) >> 16;
struct nv98_crypt_priv *priv = (void *)subdev;
u32 disp = nv_rd32(priv, 0x08701c);
u32 stat = nv_rd32(priv, 0x087008) & disp & ~(disp >> 16);
u32 inst = nv_rd32(priv, 0x087050) & 0x3fffffff;
u32 ssta = nv_rd32(priv, 0x087040) & 0x0000ffff;
u32 addr = nv_rd32(priv, 0x087040) >> 16;
u32 mthd = (addr & 0x07ff) << 2;
u32 subc = (addr & 0x3800) >> 11;
u32 data = nv_rd32(dev, 0x087044);
int chid = nv50_graph_isr_chid(dev, inst);
u32 data = nv_rd32(priv, 0x087044);
if (stat & 0x00000040) {
NV_INFO(dev, "PCRYPT: DISPATCH_ERROR [");
nv_error(priv, "DISPATCH_ERROR [");
nouveau_enum_print(nv98_crypt_isr_error_name, ssta);
printk("] ch %d [0x%08x] subc %d mthd 0x%04x data 0x%08x\n",
chid, inst, subc, mthd, data);
nv_wr32(dev, 0x087004, 0x00000040);
printk("] ch 0x%08x subc %d mthd 0x%04x data 0x%08x\n",
inst, subc, mthd, data);
nv_wr32(priv, 0x087004, 0x00000040);
stat &= ~0x00000040;
}
if (stat) {
NV_INFO(dev, "PCRYPT: unhandled intr 0x%08x\n", stat);
nv_wr32(dev, 0x087004, stat);
nv_error(priv, "unhandled intr 0x%08x\n", stat);
nv_wr32(priv, 0x087004, stat);
}
nv50_fb_vm_trap(dev, 1);
nv50_fb_trap(nouveau_fb(priv), 1);
}
static void
nv98_crypt_destroy(struct drm_device *dev, int engine)
static int
nv98_crypt_tlb_flush(struct nouveau_engine *engine)
{
struct nv98_crypt_priv *priv = nv_engine(dev, engine);
nouveau_irq_unregister(dev, 14);
NVOBJ_ENGINE_DEL(dev, CRYPT);
kfree(priv);
nv50_vm_flush_engine(&engine->base, 0x0a);
return 0;
}
int
nv98_crypt_create(struct drm_device *dev)
static int
nv98_crypt_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv98_crypt_priv *priv;
int ret;
ret = nouveau_crypt_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00004000;
nv_subdev(priv)->intr = nv98_crypt_intr;
nv_engine(priv)->cclass = &nv98_crypt_cclass;
nv_engine(priv)->sclass = nv98_crypt_sclass;
nv_engine(priv)->tlb_flush = nv98_crypt_tlb_flush;
return 0;
}
static int
nv98_crypt_init(struct nouveau_object *object)
{
struct nv98_crypt_priv *priv = (void *)object;
int ret, i;
ret = nouveau_crypt_init(&priv->base);
if (ret)
return ret;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
/* wait for exit interrupt to signal */
nv_wait(priv, 0x087008, 0x00000010, 0x00000010);
nv_wr32(priv, 0x087004, 0x00000010);
priv->base.destroy = nv98_crypt_destroy;
priv->base.init = nv98_crypt_init;
priv->base.fini = nv98_crypt_fini;
priv->base.context_new = nv98_crypt_context_new;
priv->base.context_del = nv98_crypt_context_del;
priv->base.object_new = nv98_crypt_object_new;
priv->base.tlb_flush = nv98_crypt_tlb_flush;
/* upload microcode code and data segments */
nv_wr32(priv, 0x087ff8, 0x00100000);
for (i = 0; i < ARRAY_SIZE(nv98_pcrypt_code); i++)
nv_wr32(priv, 0x087ff4, nv98_pcrypt_code[i]);
nouveau_irq_register(dev, 14, nv98_crypt_isr);
nv_wr32(priv, 0x087ff8, 0x00000000);
for (i = 0; i < ARRAY_SIZE(nv98_pcrypt_data); i++)
nv_wr32(priv, 0x087ff4, nv98_pcrypt_data[i]);
NVOBJ_ENGINE_ADD(dev, CRYPT, &priv->base);
NVOBJ_CLASS(dev, 0x88b4, CRYPT);
/* start it running */
nv_wr32(priv, 0x08710c, 0x00000000);
nv_wr32(priv, 0x087104, 0x00000000); /* ENTRY */
nv_wr32(priv, 0x087100, 0x00000002); /* TRIGGER */
return 0;
}
struct nouveau_oclass
nv98_crypt_oclass = {
.handle = NV_ENGINE(CRYPT, 0x98),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv98_crypt_ctor,
.dtor = _nouveau_crypt_dtor,
.init = nv98_crypt_init,
.fini = _nouveau_crypt_fini,
},
};
......@@ -22,88 +22,69 @@
* Authors: Ben Skeggs
*/
#include "drmP.h"
#include <engine/disp.h>
#include "nouveau_drv.h"
#include <core/ramht.h>
#include "nouveau_software.h"
#include "nv50_display.h"
struct nvc0_software_priv {
struct nouveau_software_priv base;
struct nv04_disp_priv {
struct nouveau_disp base;
};
struct nvc0_software_chan {
struct nouveau_software_chan base;
static struct nouveau_oclass
nv04_disp_sclass[] = {
{},
};
static int
nvc0_software_context_new(struct nouveau_channel *chan, int engine)
static void
nv04_disp_intr_vblank(struct nv04_disp_priv *priv, int crtc)
{
struct nvc0_software_chan *pch;
pch = kzalloc(sizeof(*pch), GFP_KERNEL);
if (!pch)
return -ENOMEM;
nouveau_software_context_new(chan, &pch->base);
chan->engctx[engine] = pch;
return 0;
struct nouveau_disp *disp = &priv->base;
if (disp->vblank.notify)
disp->vblank.notify(disp->vblank.data, crtc);
}
static void
nvc0_software_context_del(struct nouveau_channel *chan, int engine)
nv04_disp_intr(struct nouveau_subdev *subdev)
{
struct nvc0_software_chan *pch = chan->engctx[engine];
chan->engctx[engine] = NULL;
kfree(pch);
struct nv04_disp_priv *priv = (void *)subdev;
u32 crtc0 = nv_rd32(priv, 0x600100);
u32 crtc1 = nv_rd32(priv, 0x602100);
if (crtc0 & 0x00000001) {
nv04_disp_intr_vblank(priv, 0);
nv_wr32(priv, 0x600100, 0x00000001);
}
if (crtc1 & 0x00000001) {
nv04_disp_intr_vblank(priv, 1);
nv_wr32(priv, 0x602100, 0x00000001);
}
}
static int
nvc0_software_object_new(struct nouveau_channel *chan, int engine,
u32 handle, u16 class)
nv04_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
return 0;
}
struct nv04_disp_priv *priv;
int ret;
static int
nvc0_software_init(struct drm_device *dev, int engine)
{
return 0;
}
ret = nouveau_disp_create(parent, engine, oclass, "DISPLAY",
"display", &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
static int
nvc0_software_fini(struct drm_device *dev, int engine, bool suspend)
{
nv_engine(priv)->sclass = nv04_disp_sclass;
nv_subdev(priv)->intr = nv04_disp_intr;
return 0;
}
static void
nvc0_software_destroy(struct drm_device *dev, int engine)
{
struct nvc0_software_priv *psw = nv_engine(dev, engine);
NVOBJ_ENGINE_DEL(dev, SW);
kfree(psw);
}
int
nvc0_software_create(struct drm_device *dev)
{
struct nvc0_software_priv *psw = kzalloc(sizeof(*psw), GFP_KERNEL);
if (!psw)
return -ENOMEM;
psw->base.base.destroy = nvc0_software_destroy;
psw->base.base.init = nvc0_software_init;
psw->base.base.fini = nvc0_software_fini;
psw->base.base.context_new = nvc0_software_context_new;
psw->base.base.context_del = nvc0_software_context_del;
psw->base.base.object_new = nvc0_software_object_new;
nouveau_software_create(&psw->base);
NVOBJ_ENGINE_ADD(dev, SW, &psw->base.base);
NVOBJ_CLASS(dev, 0x906e, SW);
return 0;
}
struct nouveau_oclass
nv04_disp_oclass = {
.handle = NV_ENGINE(DISP, 0x04),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv04_disp_ctor,
.dtor = _nouveau_disp_dtor,
.init = _nouveau_disp_init,
.fini = _nouveau_disp_fini,
},
};
/*
* 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 <engine/software.h>
#include <engine/disp.h>
struct nv50_disp_priv {
struct nouveau_disp base;
};
static struct nouveau_oclass
nv50_disp_sclass[] = {
{},
};
static void
nv50_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc)
{
struct nouveau_disp *disp = &priv->base;
struct nouveau_software_chan *chan, *temp;
unsigned long flags;
spin_lock_irqsave(&disp->vblank.lock, flags);
list_for_each_entry_safe(chan, temp, &disp->vblank.list, vblank.head) {
if (chan->vblank.crtc != crtc)
continue;
nv_wr32(priv, 0x001704, chan->vblank.channel);
nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma);
if (nv_device(priv)->chipset == 0x50) {
nv_wr32(priv, 0x001570, chan->vblank.offset);
nv_wr32(priv, 0x001574, chan->vblank.value);
} else {
if (nv_device(priv)->chipset >= 0xc0) {
nv_wr32(priv, 0x06000c,
upper_32_bits(chan->vblank.offset));
}
nv_wr32(priv, 0x060010, chan->vblank.offset);
nv_wr32(priv, 0x060014, chan->vblank.value);
}
list_del(&chan->vblank.head);
if (disp->vblank.put)
disp->vblank.put(disp->vblank.data, crtc);
}
spin_unlock_irqrestore(&disp->vblank.lock, flags);
if (disp->vblank.notify)
disp->vblank.notify(disp->vblank.data, crtc);
}
static void
nv50_disp_intr(struct nouveau_subdev *subdev)
{
struct nv50_disp_priv *priv = (void *)subdev;
u32 stat1 = nv_rd32(priv, 0x610024);
if (stat1 & 0x00000004) {
nv50_disp_intr_vblank(priv, 0);
nv_wr32(priv, 0x610024, 0x00000004);
stat1 &= ~0x00000004;
}
if (stat1 & 0x00000008) {
nv50_disp_intr_vblank(priv, 1);
nv_wr32(priv, 0x610024, 0x00000008);
stat1 &= ~0x00000008;
}
}
static int
nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv50_disp_priv *priv;
int ret;
ret = nouveau_disp_create(parent, engine, oclass, "PDISP",
"display", &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_engine(priv)->sclass = nv50_disp_sclass;
nv_subdev(priv)->intr = nv50_disp_intr;
INIT_LIST_HEAD(&priv->base.vblank.list);
spin_lock_init(&priv->base.vblank.lock);
return 0;
}
struct nouveau_oclass
nv50_disp_oclass = {
.handle = NV_ENGINE(DISP, 0x50),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv50_disp_ctor,
.dtor = _nouveau_disp_dtor,
.init = _nouveau_disp_init,
.fini = _nouveau_disp_fini,
},
};
/*
* 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 <subdev/bar.h>
#include <engine/software.h>
#include <engine/disp.h>
struct nvd0_disp_priv {
struct nouveau_disp base;
};
static struct nouveau_oclass
nvd0_disp_sclass[] = {
{},
};
static void
nvd0_disp_intr_vblank(struct nvd0_disp_priv *priv, int crtc)
{
struct nouveau_bar *bar = nouveau_bar(priv);
struct nouveau_disp *disp = &priv->base;
struct nouveau_software_chan *chan, *temp;
unsigned long flags;
spin_lock_irqsave(&disp->vblank.lock, flags);
list_for_each_entry_safe(chan, temp, &disp->vblank.list, vblank.head) {
if (chan->vblank.crtc != crtc)
continue;
nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel);
bar->flush(bar);
nv_wr32(priv, 0x06000c, upper_32_bits(chan->vblank.offset));
nv_wr32(priv, 0x060010, lower_32_bits(chan->vblank.offset));
nv_wr32(priv, 0x060014, chan->vblank.value);
list_del(&chan->vblank.head);
if (disp->vblank.put)
disp->vblank.put(disp->vblank.data, crtc);
}
spin_unlock_irqrestore(&disp->vblank.lock, flags);
if (disp->vblank.notify)
disp->vblank.notify(disp->vblank.data, crtc);
}
static void
nvd0_disp_intr(struct nouveau_subdev *subdev)
{
struct nvd0_disp_priv *priv = (void *)subdev;
u32 intr = nv_rd32(priv, 0x610088);
int i;
for (i = 0; i < 4; i++) {
u32 mask = 0x01000000 << i;
if (mask & intr) {
u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800));
if (stat & 0x00000001)
nvd0_disp_intr_vblank(priv, i);
nv_mask(priv, 0x6100bc + (i * 0x800), 0, 0);
nv_rd32(priv, 0x6100c0 + (i * 0x800));
}
}
}
static int
nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nvd0_disp_priv *priv;
int ret;
ret = nouveau_disp_create(parent, engine, oclass, "PDISP",
"display", &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_engine(priv)->sclass = nvd0_disp_sclass;
nv_subdev(priv)->intr = nvd0_disp_intr;
INIT_LIST_HEAD(&priv->base.vblank.list);
spin_lock_init(&priv->base.vblank.lock);
return 0;
}
struct nouveau_oclass
nvd0_disp_oclass = {
.handle = NV_ENGINE(DISP, 0xd0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nvd0_disp_ctor,
.dtor = _nouveau_disp_dtor,
.init = _nouveau_disp_init,
.fini = _nouveau_disp_fini,
},
};
/*
* 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/object.h>
#include <core/class.h>
#include <subdev/fb.h>
#include <engine/dmaobj.h>
int
nouveau_dmaobj_create_(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass,
void *data, u32 size, int len, void **pobject)
{
struct nv_dma_class *args = data;
struct nouveau_dmaobj *object;
int ret;
if (size < sizeof(*args))
return -EINVAL;
ret = nouveau_object_create_(parent, engine, oclass, 0, len, pobject);
object = *pobject;
if (ret)
return ret;
switch (args->flags & NV_DMA_TARGET_MASK) {
case NV_DMA_TARGET_VM:
object->target = NV_MEM_TARGET_VM;
break;
case NV_DMA_TARGET_VRAM:
object->target = NV_MEM_TARGET_VRAM;
break;
case NV_DMA_TARGET_PCI:
object->target = NV_MEM_TARGET_PCI;
break;
case NV_DMA_TARGET_PCI_US:
case NV_DMA_TARGET_AGP:
object->target = NV_MEM_TARGET_PCI_NOSNOOP;
break;
default:
return -EINVAL;
}
switch (args->flags & NV_DMA_ACCESS_MASK) {
case NV_DMA_ACCESS_VM:
object->access = NV_MEM_ACCESS_VM;
break;
case NV_DMA_ACCESS_RD:
object->access = NV_MEM_ACCESS_RO;
break;
case NV_DMA_ACCESS_WR:
object->access = NV_MEM_ACCESS_WO;
break;
case NV_DMA_ACCESS_RDWR:
object->access = NV_MEM_ACCESS_RW;
break;
default:
return -EINVAL;
}
object->start = args->start;
object->limit = args->limit;
return 0;
}
/*
* 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/gpuobj.h>
#include <subdev/fb.h>
#include <subdev/vm/nv04.h>
#include <engine/dmaobj.h>
struct nv04_dmaeng_priv {
struct nouveau_dmaeng base;
};
struct nv04_dmaobj_priv {
struct nouveau_dmaobj base;
};
static int
nv04_dmaobj_bind(struct nouveau_dmaeng *dmaeng,
struct nouveau_object *parent,
struct nouveau_dmaobj *dmaobj,
struct nouveau_gpuobj **pgpuobj)
{
struct nouveau_gpuobj *gpuobj;
u32 flags0 = nv_mclass(dmaobj);
u32 flags2 = 0x00000000;
u32 offset = (dmaobj->start & 0xfffff000);
u32 adjust = (dmaobj->start & 0x00000fff);
u32 length = dmaobj->limit - dmaobj->start;
int ret;
if (dmaobj->target == NV_MEM_TARGET_VM) {
gpuobj = nv04_vmmgr(dmaeng)->vm->pgt[0].obj[0];
if (dmaobj->start == 0)
return nouveau_gpuobj_dup(parent, gpuobj, pgpuobj);
offset = nv_ro32(gpuobj, 8 + (offset >> 10));
offset &= 0xfffff000;
dmaobj->target = NV_MEM_TARGET_PCI;
dmaobj->access = NV_MEM_ACCESS_RW;
}
switch (dmaobj->target) {
case NV_MEM_TARGET_VRAM:
flags0 |= 0x00003000;
break;
case NV_MEM_TARGET_PCI:
flags0 |= 0x00023000;
break;
case NV_MEM_TARGET_PCI_NOSNOOP:
flags0 |= 0x00033000;
break;
default:
return -EINVAL;
}
switch (dmaobj->access) {
case NV_MEM_ACCESS_RO:
flags0 |= 0x00004000;
break;
case NV_MEM_ACCESS_WO:
flags0 |= 0x00008000;
case NV_MEM_ACCESS_RW:
flags2 |= 0x00000002;
break;
default:
return -EINVAL;
}
ret = nouveau_gpuobj_new(parent, parent, 16, 16, 0, &gpuobj);
*pgpuobj = gpuobj;
if (ret == 0) {
nv_wo32(*pgpuobj, 0x00, flags0 | (adjust << 20));
nv_wo32(*pgpuobj, 0x04, length);
nv_wo32(*pgpuobj, 0x08, flags2 | offset);
nv_wo32(*pgpuobj, 0x0c, flags2 | offset);
}
return ret;
}
static int
nv04_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_dmaeng *dmaeng = (void *)engine;
struct nv04_dmaobj_priv *dmaobj;
struct nouveau_gpuobj *gpuobj;
int ret;
ret = nouveau_dmaobj_create(parent, engine, oclass,
data, size, &dmaobj);
*pobject = nv_object(dmaobj);
if (ret)
return ret;
switch (nv_mclass(parent)) {
case 0x006e:
ret = dmaeng->bind(dmaeng, *pobject, &dmaobj->base, &gpuobj);
nouveau_object_ref(NULL, pobject);
*pobject = nv_object(gpuobj);
break;
default:
break;
}
return ret;
}
static struct nouveau_ofuncs
nv04_dmaobj_ofuncs = {
.ctor = nv04_dmaobj_ctor,
.dtor = _nouveau_dmaobj_dtor,
.init = _nouveau_dmaobj_init,
.fini = _nouveau_dmaobj_fini,
};
static struct nouveau_oclass
nv04_dmaobj_sclass[] = {
{ 0x0002, &nv04_dmaobj_ofuncs },
{ 0x0003, &nv04_dmaobj_ofuncs },
{ 0x003d, &nv04_dmaobj_ofuncs },
{}
};
static int
nv04_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv04_dmaeng_priv *priv;
int ret;
ret = nouveau_dmaeng_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.base.sclass = nv04_dmaobj_sclass;
priv->base.bind = nv04_dmaobj_bind;
return 0;
}
struct nouveau_oclass
nv04_dmaeng_oclass = {
.handle = NV_ENGINE(DMAOBJ, 0x04),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv04_dmaeng_ctor,
.dtor = _nouveau_dmaeng_dtor,
.init = _nouveau_dmaeng_init,
.fini = _nouveau_dmaeng_fini,
},
};
/*
* 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/gpuobj.h>
#include <subdev/fb.h>
#include <engine/dmaobj.h>
struct nv50_dmaeng_priv {
struct nouveau_dmaeng base;
};
struct nv50_dmaobj_priv {
struct nouveau_dmaobj base;
};
static int
nv50_dmaobj_bind(struct nouveau_dmaeng *dmaeng,
struct nouveau_object *parent,
struct nouveau_dmaobj *dmaobj,
struct nouveau_gpuobj **pgpuobj)
{
u32 flags = nv_mclass(dmaobj);
int ret;
switch (dmaobj->target) {
case NV_MEM_TARGET_VM:
flags |= 0x00000000;
flags |= 0x60000000; /* COMPRESSION_USEVM */
flags |= 0x1fc00000; /* STORAGE_TYPE_USEVM */
break;
case NV_MEM_TARGET_VRAM:
flags |= 0x00010000;
flags |= 0x00100000; /* ACCESSUS_USER_SYSTEM */
break;
case NV_MEM_TARGET_PCI:
flags |= 0x00020000;
flags |= 0x00100000; /* ACCESSUS_USER_SYSTEM */
break;
case NV_MEM_TARGET_PCI_NOSNOOP:
flags |= 0x00030000;
flags |= 0x00100000; /* ACCESSUS_USER_SYSTEM */
break;
default:
return -EINVAL;
}
switch (dmaobj->access) {
case NV_MEM_ACCESS_VM:
break;
case NV_MEM_ACCESS_RO:
flags |= 0x00040000;
break;
case NV_MEM_ACCESS_WO:
case NV_MEM_ACCESS_RW:
flags |= 0x00080000;
break;
}
ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
if (ret == 0) {
nv_wo32(*pgpuobj, 0x00, flags);
nv_wo32(*pgpuobj, 0x04, lower_32_bits(dmaobj->limit));
nv_wo32(*pgpuobj, 0x08, lower_32_bits(dmaobj->start));
nv_wo32(*pgpuobj, 0x0c, upper_32_bits(dmaobj->limit) << 24 |
upper_32_bits(dmaobj->start));
nv_wo32(*pgpuobj, 0x10, 0x00000000);
nv_wo32(*pgpuobj, 0x14, 0x00000000);
}
return ret;
}
static int
nv50_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_dmaeng *dmaeng = (void *)engine;
struct nv50_dmaobj_priv *dmaobj;
struct nouveau_gpuobj *gpuobj;
int ret;
ret = nouveau_dmaobj_create(parent, engine, oclass,
data, size, &dmaobj);
*pobject = nv_object(dmaobj);
if (ret)
return ret;
switch (nv_mclass(parent)) {
case 0x506f:
case 0x826f:
ret = dmaeng->bind(dmaeng, *pobject, &dmaobj->base, &gpuobj);
nouveau_object_ref(NULL, pobject);
*pobject = nv_object(gpuobj);
break;
default:
break;
}
return ret;
}
static struct nouveau_ofuncs
nv50_dmaobj_ofuncs = {
.ctor = nv50_dmaobj_ctor,
.dtor = _nouveau_dmaobj_dtor,
.init = _nouveau_dmaobj_init,
.fini = _nouveau_dmaobj_fini,
};
static struct nouveau_oclass
nv50_dmaobj_sclass[] = {
{ 0x0002, &nv50_dmaobj_ofuncs },
{ 0x0003, &nv50_dmaobj_ofuncs },
{ 0x003d, &nv50_dmaobj_ofuncs },
{}
};
static int
nv50_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv50_dmaeng_priv *priv;
int ret;
ret = nouveau_dmaeng_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.base.sclass = nv50_dmaobj_sclass;
priv->base.bind = nv50_dmaobj_bind;
return 0;
}
struct nouveau_oclass
nv50_dmaeng_oclass = {
.handle = NV_ENGINE(DMAOBJ, 0x50),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv50_dmaeng_ctor,
.dtor = _nouveau_dmaeng_dtor,
.init = _nouveau_dmaeng_init,
.fini = _nouveau_dmaeng_fini,
},
};
/*
* 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/gpuobj.h>
#include <subdev/fb.h>
#include <engine/dmaobj.h>
struct nvc0_dmaeng_priv {
struct nouveau_dmaeng base;
};
struct nvc0_dmaobj_priv {
struct nouveau_dmaobj base;
};
static int
nvc0_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nvc0_dmaobj_priv *dmaobj;
int ret;
ret = nouveau_dmaobj_create(parent, engine, oclass, data, size, &dmaobj);
*pobject = nv_object(dmaobj);
if (ret)
return ret;
if (dmaobj->base.target != NV_MEM_TARGET_VM || dmaobj->base.start)
return -EINVAL;
return 0;
}
static struct nouveau_ofuncs
nvc0_dmaobj_ofuncs = {
.ctor = nvc0_dmaobj_ctor,
.dtor = _nouveau_dmaobj_dtor,
.init = _nouveau_dmaobj_init,
.fini = _nouveau_dmaobj_fini,
};
static struct nouveau_oclass
nvc0_dmaobj_sclass[] = {
{ 0x0002, &nvc0_dmaobj_ofuncs },
{ 0x0003, &nvc0_dmaobj_ofuncs },
{ 0x003d, &nvc0_dmaobj_ofuncs },
{}
};
static int
nvc0_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nvc0_dmaeng_priv *priv;
int ret;
ret = nouveau_dmaeng_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.base.sclass = nvc0_dmaobj_sclass;
return 0;
}
struct nouveau_oclass
nvc0_dmaeng_oclass = {
.handle = NV_ENGINE(DMAOBJ, 0xc0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nvc0_dmaeng_ctor,
.dtor = _nouveau_dmaeng_dtor,
.init = _nouveau_dmaeng_init,
.fini = _nouveau_dmaeng_fini,
},
};
/*
* 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/object.h>
#include <core/handle.h>
#include <engine/dmaobj.h>
#include <engine/fifo.h>
int
nouveau_fifo_channel_create_(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass,
int bar, u32 addr, u32 size, u32 pushbuf,
u32 engmask, int len, void **ptr)
{
struct nouveau_device *device = nv_device(engine);
struct nouveau_fifo *priv = (void *)engine;
struct nouveau_fifo_chan *chan;
struct nouveau_dmaeng *dmaeng;
unsigned long flags;
int ret;
/* create base object class */
ret = nouveau_namedb_create_(parent, engine, oclass, 0, NULL,
engmask, len, ptr);
chan = *ptr;
if (ret)
return ret;
/* validate dma object representing push buffer */
chan->pushdma = (void *)nouveau_handle_ref(parent, pushbuf);
if (!chan->pushdma)
return -ENOENT;
dmaeng = (void *)chan->pushdma->base.engine;
switch (chan->pushdma->base.oclass->handle) {
case 0x0002:
case 0x003d:
break;
default:
return -EINVAL;
}
if (dmaeng->bind) {
ret = dmaeng->bind(dmaeng, parent, chan->pushdma, &chan->pushgpu);
if (ret)
return ret;
}
/* find a free fifo channel */
spin_lock_irqsave(&priv->lock, flags);
for (chan->chid = priv->min; chan->chid < priv->max; chan->chid++) {
if (!priv->channel[chan->chid]) {
priv->channel[chan->chid] = nv_object(chan);
break;
}
}
spin_unlock_irqrestore(&priv->lock, flags);
if (chan->chid == priv->max) {
nv_error(priv, "no free channels\n");
return -ENOSPC;
}
/* map fifo control registers */
chan->user = ioremap(pci_resource_start(device->pdev, bar) + addr +
(chan->chid * size), size);
if (!chan->user)
return -EFAULT;
chan->size = size;
return 0;
}
void
nouveau_fifo_channel_destroy(struct nouveau_fifo_chan *chan)
{
struct nouveau_fifo *priv = (void *)nv_object(chan)->engine;
unsigned long flags;
iounmap(chan->user);
spin_lock_irqsave(&priv->lock, flags);
priv->channel[chan->chid] = NULL;
spin_unlock_irqrestore(&priv->lock, flags);
nouveau_gpuobj_ref(NULL, &chan->pushgpu);
nouveau_object_ref(NULL, (struct nouveau_object **)&chan->pushdma);
nouveau_namedb_destroy(&chan->base);
}
void
_nouveau_fifo_channel_dtor(struct nouveau_object *object)
{
struct nouveau_fifo_chan *chan = (void *)object;
nouveau_fifo_channel_destroy(chan);
}
u32
_nouveau_fifo_channel_rd32(struct nouveau_object *object, u32 addr)
{
struct nouveau_fifo_chan *chan = (void *)object;
return ioread32_native(chan->user + addr);
}
void
_nouveau_fifo_channel_wr32(struct nouveau_object *object, u32 addr, u32 data)
{
struct nouveau_fifo_chan *chan = (void *)object;
iowrite32_native(data, chan->user + addr);
}
void
nouveau_fifo_destroy(struct nouveau_fifo *priv)
{
kfree(priv->channel);
nouveau_engine_destroy(&priv->base);
}
int
nouveau_fifo_create_(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass,
int min, int max, int length, void **pobject)
{
struct nouveau_fifo *priv;
int ret;
ret = nouveau_engine_create_(parent, engine, oclass, true, "PFIFO",
"fifo", length, pobject);
priv = *pobject;
if (ret)
return ret;
priv->min = min;
priv->max = max;
priv->channel = kzalloc(sizeof(*priv->channel) * (max + 1), GFP_KERNEL);
if (!priv->channel)
return -ENOMEM;
spin_lock_init(&priv->lock);
return 0;
}
#ifndef __NV04_FIFO_H__
#define __NV04_FIFO_H__
#include <engine/fifo.h>
#define NV04_PFIFO_DELAY_0 0x00002040
#define NV04_PFIFO_DMA_TIMESLICE 0x00002044
#define NV04_PFIFO_NEXT_CHANNEL 0x00002050
#define NV03_PFIFO_INTR_0 0x00002100
#define NV03_PFIFO_INTR_EN_0 0x00002140
# define NV_PFIFO_INTR_CACHE_ERROR (1<<0)
# define NV_PFIFO_INTR_RUNOUT (1<<4)
# define NV_PFIFO_INTR_RUNOUT_OVERFLOW (1<<8)
# define NV_PFIFO_INTR_DMA_PUSHER (1<<12)
# define NV_PFIFO_INTR_DMA_PT (1<<16)
# define NV_PFIFO_INTR_SEMAPHORE (1<<20)
# define NV_PFIFO_INTR_ACQUIRE_TIMEOUT (1<<24)
#define NV03_PFIFO_RAMHT 0x00002210
#define NV03_PFIFO_RAMFC 0x00002214
#define NV03_PFIFO_RAMRO 0x00002218
#define NV40_PFIFO_RAMFC 0x00002220
#define NV03_PFIFO_CACHES 0x00002500
#define NV04_PFIFO_MODE 0x00002504
#define NV04_PFIFO_DMA 0x00002508
#define NV04_PFIFO_SIZE 0x0000250c
#define NV50_PFIFO_CTX_TABLE(c) (0x2600+(c)*4)
#define NV50_PFIFO_CTX_TABLE__SIZE 128
#define NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED (1<<31)
#define NV50_PFIFO_CTX_TABLE_UNK30_BAD (1<<30)
#define NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G80 0x0FFFFFFF
#define NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G84 0x00FFFFFF
#define NV03_PFIFO_CACHE0_PUSH0 0x00003000
#define NV03_PFIFO_CACHE0_PULL0 0x00003040
#define NV04_PFIFO_CACHE0_PULL0 0x00003050
#define NV04_PFIFO_CACHE0_PULL1 0x00003054
#define NV03_PFIFO_CACHE1_PUSH0 0x00003200
#define NV03_PFIFO_CACHE1_PUSH1 0x00003204
#define NV03_PFIFO_CACHE1_PUSH1_DMA (1<<8)
#define NV40_PFIFO_CACHE1_PUSH1_DMA (1<<16)
#define NV03_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000000f
#define NV10_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000001f
#define NV50_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000007f
#define NV03_PFIFO_CACHE1_PUT 0x00003210
#define NV04_PFIFO_CACHE1_DMA_PUSH 0x00003220
#define NV04_PFIFO_CACHE1_DMA_FETCH 0x00003224
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_8_BYTES 0x00000000
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_16_BYTES 0x00000008
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_24_BYTES 0x00000010
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_32_BYTES 0x00000018
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_40_BYTES 0x00000020
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_48_BYTES 0x00000028
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_56_BYTES 0x00000030
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_64_BYTES 0x00000038
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_72_BYTES 0x00000040
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_80_BYTES 0x00000048
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_88_BYTES 0x00000050
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_96_BYTES 0x00000058
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_104_BYTES 0x00000060
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_112_BYTES 0x00000068
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_120_BYTES 0x00000070
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES 0x00000078
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_136_BYTES 0x00000080
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_144_BYTES 0x00000088
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_152_BYTES 0x00000090
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_160_BYTES 0x00000098
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_168_BYTES 0x000000A0
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_176_BYTES 0x000000A8
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_184_BYTES 0x000000B0
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_192_BYTES 0x000000B8
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_200_BYTES 0x000000C0
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_208_BYTES 0x000000C8
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_216_BYTES 0x000000D0
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_224_BYTES 0x000000D8
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_232_BYTES 0x000000E0
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_240_BYTES 0x000000E8
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_248_BYTES 0x000000F0
# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_256_BYTES 0x000000F8
# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE 0x0000E000
# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_32_BYTES 0x00000000
# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_64_BYTES 0x00002000
# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_96_BYTES 0x00004000
# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES 0x00006000
# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_160_BYTES 0x00008000
# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_192_BYTES 0x0000A000
# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_224_BYTES 0x0000C000
# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_256_BYTES 0x0000E000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS 0x001F0000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_0 0x00000000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_1 0x00010000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_2 0x00020000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_3 0x00030000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_4 0x00040000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_5 0x00050000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_6 0x00060000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_7 0x00070000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 0x00080000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_9 0x00090000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_10 0x000A0000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_11 0x000B0000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_12 0x000C0000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_13 0x000D0000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_14 0x000E0000
# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_15 0x000F0000
# define NV_PFIFO_CACHE1_ENDIAN 0x80000000
# define NV_PFIFO_CACHE1_LITTLE_ENDIAN 0x7FFFFFFF
# define NV_PFIFO_CACHE1_BIG_ENDIAN 0x80000000
#define NV04_PFIFO_CACHE1_DMA_STATE 0x00003228
#define NV04_PFIFO_CACHE1_DMA_INSTANCE 0x0000322c
#define NV04_PFIFO_CACHE1_DMA_CTL 0x00003230
#define NV04_PFIFO_CACHE1_DMA_PUT 0x00003240
#define NV04_PFIFO_CACHE1_DMA_GET 0x00003244
#define NV10_PFIFO_CACHE1_REF_CNT 0x00003248
#define NV10_PFIFO_CACHE1_DMA_SUBROUTINE 0x0000324C
#define NV03_PFIFO_CACHE1_PULL0 0x00003240
#define NV04_PFIFO_CACHE1_PULL0 0x00003250
# define NV04_PFIFO_CACHE1_PULL0_HASH_FAILED 0x00000010
# define NV04_PFIFO_CACHE1_PULL0_HASH_BUSY 0x00001000
#define NV03_PFIFO_CACHE1_PULL1 0x00003250
#define NV04_PFIFO_CACHE1_PULL1 0x00003254
#define NV04_PFIFO_CACHE1_HASH 0x00003258
#define NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT 0x00003260
#define NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP 0x00003264
#define NV10_PFIFO_CACHE1_ACQUIRE_VALUE 0x00003268
#define NV10_PFIFO_CACHE1_SEMAPHORE 0x0000326C
#define NV03_PFIFO_CACHE1_GET 0x00003270
#define NV04_PFIFO_CACHE1_ENGINE 0x00003280
#define NV04_PFIFO_CACHE1_DMA_DCOUNT 0x000032A0
#define NV40_PFIFO_GRCTX_INSTANCE 0x000032E0
#define NV40_PFIFO_UNK32E4 0x000032E4
#define NV04_PFIFO_CACHE1_METHOD(i) (0x00003800+(i*8))
#define NV04_PFIFO_CACHE1_DATA(i) (0x00003804+(i*8))
#define NV40_PFIFO_CACHE1_METHOD(i) (0x00090000+(i*8))
#define NV40_PFIFO_CACHE1_DATA(i) (0x00090004+(i*8))
struct ramfc_desc {
unsigned bits:6;
unsigned ctxs:5;
unsigned ctxp:8;
unsigned regs:5;
unsigned regp;
};
struct nv04_fifo_priv {
struct nouveau_fifo base;
struct ramfc_desc *ramfc_desc;
struct nouveau_ramht *ramht;
struct nouveau_gpuobj *ramro;
struct nouveau_gpuobj *ramfc;
};
struct nv04_fifo_base {
struct nouveau_fifo_base base;
};
struct nv04_fifo_chan {
struct nouveau_fifo_chan base;
u32 subc[8];
u32 ramfc;
};
int nv04_fifo_object_attach(struct nouveau_object *,
struct nouveau_object *, u32);
void nv04_fifo_object_detach(struct nouveau_object *, int);
void nv04_fifo_chan_dtor(struct nouveau_object *);
int nv04_fifo_chan_init(struct nouveau_object *);
int nv04_fifo_chan_fini(struct nouveau_object *, bool suspend);
int nv04_fifo_context_ctor(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, void *, u32,
struct nouveau_object **);
void nv04_fifo_dtor(struct nouveau_object *);
int nv04_fifo_init(struct nouveau_object *);
void nv04_fifo_pause(struct nouveau_fifo *, unsigned long *);
void nv04_fifo_start(struct nouveau_fifo *, unsigned long *);
#endif
/*
* Copyright (C) 2012 Ben Skeggs.
* All Rights Reserved.
* 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:
* 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 (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
* 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
* 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 "drmP.h"
#include "drm.h"
#include "nouveau_drv.h"
#include <engine/fifo.h>
#include "nouveau_util.h"
#include <core/os.h>
#include <core/class.h>
#include <core/engctx.h>
#include <core/ramht.h>
static struct ramfc_desc {
unsigned bits:6;
unsigned ctxs:5;
unsigned ctxp:8;
unsigned regs:5;
unsigned regp;
} nv10_ramfc[] = {
#include <subdev/instmem.h>
#include <subdev/instmem/nv04.h>
#include <subdev/fb.h>
#include <engine/fifo.h>
#include "nv04.h"
static struct ramfc_desc
nv10_ramfc[] = {
{ 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
{ 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
{ 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT },
......@@ -50,87 +49,122 @@ static struct ramfc_desc {
{}
};
struct nv10_fifo_priv {
struct nouveau_fifo_priv base;
struct ramfc_desc *ramfc_desc;
struct nouveau_gpuobj *ramro;
struct nouveau_gpuobj *ramfc;
};
struct nv10_fifo_chan {
struct nouveau_fifo_chan base;
u32 ramfc;
};
/*******************************************************************************
* FIFO channel objects
******************************************************************************/
static int
nv10_fifo_context_new(struct nouveau_channel *chan, int engine)
nv10_fifo_chan_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv10_fifo_priv *priv = nv_engine(dev, engine);
struct nv10_fifo_chan *fctx;
unsigned long flags;
struct nv04_fifo_priv *priv = (void *)engine;
struct nv04_fifo_chan *chan;
struct nv_channel_dma_class *args = data;
int ret;
fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL);
if (!fctx)
return -ENOMEM;
fctx->ramfc = chan->id * 32;
/* map channel control registers */
chan->user = ioremap(pci_resource_start(dev->pdev, 0) +
NV03_USER(chan->id), PAGE_SIZE);
if (!chan->user) {
ret = -ENOMEM;
goto error;
}
/* initialise default fifo context */
nv_wo32(priv->ramfc, fctx->ramfc + 0x00, chan->pushbuf_base);
nv_wo32(priv->ramfc, fctx->ramfc + 0x04, chan->pushbuf_base);
nv_wo32(priv->ramfc, fctx->ramfc + 0x0c, chan->pushbuf->addr >> 4);
nv_wo32(priv->ramfc, fctx->ramfc + 0x14,
if (size < sizeof(*args))
return -EINVAL;
ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0x800000,
0x10000, args->pushbuf,
(1 << NVDEV_ENGINE_DMAOBJ) |
(1 << NVDEV_ENGINE_SW) |
(1 << NVDEV_ENGINE_GR), &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
nv_parent(chan)->object_attach = nv04_fifo_object_attach;
nv_parent(chan)->object_detach = nv04_fifo_object_detach;
chan->ramfc = chan->base.chid * 32;
nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->offset);
nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->offset);
nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4);
nv_wo32(priv->ramfc, chan->ramfc + 0x14,
NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
#ifdef __BIG_ENDIAN
NV_PFIFO_CACHE1_BIG_ENDIAN |
#endif
NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
return 0;
}
/* enable dma mode on the channel */
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
nv_mask(dev, NV04_PFIFO_MODE, (1 << chan->id), (1 << chan->id));
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
static struct nouveau_ofuncs
nv10_fifo_ofuncs = {
.ctor = nv10_fifo_chan_ctor,
.dtor = nv04_fifo_chan_dtor,
.init = nv04_fifo_chan_init,
.fini = nv04_fifo_chan_fini,
.rd32 = _nouveau_fifo_channel_rd32,
.wr32 = _nouveau_fifo_channel_wr32,
};
error:
if (ret)
priv->base.base.context_del(chan, engine);
return ret;
}
static struct nouveau_oclass
nv10_fifo_sclass[] = {
{ 0x006e, &nv10_fifo_ofuncs },
{}
};
/*******************************************************************************
* FIFO context - basically just the instmem reserved for the channel
******************************************************************************/
static struct nouveau_oclass
nv10_fifo_cclass = {
.handle = NV_ENGCTX(FIFO, 0x10),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv04_fifo_context_ctor,
.dtor = _nouveau_fifo_context_dtor,
.init = _nouveau_fifo_context_init,
.fini = _nouveau_fifo_context_fini,
.rd32 = _nouveau_fifo_context_rd32,
.wr32 = _nouveau_fifo_context_wr32,
},
};
/*******************************************************************************
* PFIFO engine
******************************************************************************/
int
nv10_fifo_create(struct drm_device *dev)
static int
nv10_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv10_fifo_priv *priv;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
nouveau_gpuobj_ref(nvimem_ramro(dev), &priv->ramro);
nouveau_gpuobj_ref(nvimem_ramfc(dev), &priv->ramfc);
priv->base.base.destroy = nv04_fifo_destroy;
priv->base.base.init = nv04_fifo_init;
priv->base.base.fini = nv04_fifo_fini;
priv->base.base.context_new = nv10_fifo_context_new;
priv->base.base.context_del = nv04_fifo_context_del;
priv->base.channels = 31;
priv->ramfc_desc = nv10_ramfc;
dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base;
struct nv04_instmem_priv *imem = nv04_instmem(parent);
struct nv04_fifo_priv *priv;
int ret;
nouveau_irq_register(dev, 8, nv04_fifo_isr);
ret = nouveau_fifo_create(parent, engine, oclass, 0, 31, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nouveau_ramht_ref(imem->ramht, &priv->ramht);
nouveau_gpuobj_ref(imem->ramro, &priv->ramro);
nouveau_gpuobj_ref(imem->ramfc, &priv->ramfc);
nv_subdev(priv)->unit = 0x00000100;
nv_subdev(priv)->intr = nv04_fifo_intr;
nv_engine(priv)->cclass = &nv10_fifo_cclass;
nv_engine(priv)->sclass = nv10_fifo_sclass;
priv->base.pause = nv04_fifo_pause;
priv->base.start = nv04_fifo_start;
priv->ramfc_desc = nv10_ramfc;
return 0;
}
struct nouveau_oclass
nv10_fifo_oclass = {
.handle = NV_ENGINE(FIFO, 0x10),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv10_fifo_ctor,
.dtor = nv04_fifo_dtor,
.init = nv04_fifo_init,
.fini = _nouveau_fifo_fini,
},
};
/*
* Copyright (C) 2012 Ben Skeggs.
* All Rights Reserved.
* 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:
* 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 (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
* 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
* 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 "drmP.h"
#include "drm.h"
#include "nouveau_drv.h"
#include <engine/fifo.h>
#include "nouveau_util.h"
#include <core/os.h>
#include <core/class.h>
#include <core/engctx.h>
#include <core/ramht.h>
static struct ramfc_desc {
unsigned bits:6;
unsigned ctxs:5;
unsigned ctxp:8;
unsigned regs:5;
unsigned regp;
} nv17_ramfc[] = {
#include <subdev/instmem.h>
#include <subdev/instmem/nv04.h>
#include <subdev/fb.h>
#include <engine/fifo.h>
#include "nv04.h"
static struct ramfc_desc
nv17_ramfc[] = {
{ 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
{ 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
{ 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT },
......@@ -55,124 +54,154 @@ static struct ramfc_desc {
{}
};
struct nv17_fifo_priv {
struct nouveau_fifo_priv base;
struct ramfc_desc *ramfc_desc;
struct nouveau_gpuobj *ramro;
struct nouveau_gpuobj *ramfc;
};
struct nv17_fifo_chan {
struct nouveau_fifo_chan base;
u32 ramfc;
};
/*******************************************************************************
* FIFO channel objects
******************************************************************************/
static int
nv17_fifo_context_new(struct nouveau_channel *chan, int engine)
nv17_fifo_chan_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv17_fifo_priv *priv = nv_engine(dev, engine);
struct nv17_fifo_chan *fctx;
unsigned long flags;
struct nv04_fifo_priv *priv = (void *)engine;
struct nv04_fifo_chan *chan;
struct nv_channel_dma_class *args = data;
int ret;
fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL);
if (!fctx)
return -ENOMEM;
fctx->ramfc = chan->id * 64;
/* map channel control registers */
chan->user = ioremap(pci_resource_start(dev->pdev, 0) +
NV03_USER(chan->id), PAGE_SIZE);
if (!chan->user) {
ret = -ENOMEM;
goto error;
}
/* initialise default fifo context */
nv_wo32(priv->ramfc, fctx->ramfc + 0x00, chan->pushbuf_base);
nv_wo32(priv->ramfc, fctx->ramfc + 0x04, chan->pushbuf_base);
nv_wo32(priv->ramfc, fctx->ramfc + 0x0c, chan->pushbuf->addr >> 4);
nv_wo32(priv->ramfc, fctx->ramfc + 0x14,
if (size < sizeof(*args))
return -EINVAL;
ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0x800000,
0x10000, args->pushbuf,
(1 << NVDEV_ENGINE_DMAOBJ) |
(1 << NVDEV_ENGINE_SW) |
(1 << NVDEV_ENGINE_GR) |
(1 << NVDEV_ENGINE_MPEG), /* NV31- */
&chan);
*pobject = nv_object(chan);
if (ret)
return ret;
nv_parent(chan)->object_attach = nv04_fifo_object_attach;
nv_parent(chan)->object_detach = nv04_fifo_object_detach;
chan->ramfc = chan->base.chid * 64;
nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->offset);
nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->offset);
nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4);
nv_wo32(priv->ramfc, chan->ramfc + 0x14,
NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
#ifdef __BIG_ENDIAN
NV_PFIFO_CACHE1_BIG_ENDIAN |
#endif
NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
return 0;
}
/* enable dma mode on the channel */
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
nv_mask(dev, NV04_PFIFO_MODE, (1 << chan->id), (1 << chan->id));
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
static struct nouveau_ofuncs
nv17_fifo_ofuncs = {
.ctor = nv17_fifo_chan_ctor,
.dtor = nv04_fifo_chan_dtor,
.init = nv04_fifo_chan_init,
.fini = nv04_fifo_chan_fini,
.rd32 = _nouveau_fifo_channel_rd32,
.wr32 = _nouveau_fifo_channel_wr32,
};
error:
if (ret)
priv->base.base.context_del(chan, engine);
return ret;
}
static struct nouveau_oclass
nv17_fifo_sclass[] = {
{ 0x006e, &nv17_fifo_ofuncs },
{}
};
/*******************************************************************************
* FIFO context - basically just the instmem reserved for the channel
******************************************************************************/
static struct nouveau_oclass
nv17_fifo_cclass = {
.handle = NV_ENGCTX(FIFO, 0x17),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv04_fifo_context_ctor,
.dtor = _nouveau_fifo_context_dtor,
.init = _nouveau_fifo_context_init,
.fini = _nouveau_fifo_context_fini,
.rd32 = _nouveau_fifo_context_rd32,
.wr32 = _nouveau_fifo_context_wr32,
},
};
/*******************************************************************************
* PFIFO engine
******************************************************************************/
static int
nv17_fifo_init(struct drm_device *dev, int engine)
nv17_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv17_fifo_priv *priv = nv_engine(dev, engine);
int i;
struct nv04_instmem_priv *imem = nv04_instmem(parent);
struct nv04_fifo_priv *priv;
int ret;
nv_mask(dev, NV03_PMC_ENABLE, NV_PMC_ENABLE_PFIFO, 0);
nv_mask(dev, NV03_PMC_ENABLE, NV_PMC_ENABLE_PFIFO, NV_PMC_ENABLE_PFIFO);
ret = nouveau_fifo_create(parent, engine, oclass, 0, 31, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nouveau_ramht_ref(imem->ramht, &priv->ramht);
nouveau_gpuobj_ref(imem->ramro, &priv->ramro);
nouveau_gpuobj_ref(imem->ramfc, &priv->ramfc);
nv_subdev(priv)->unit = 0x00000100;
nv_subdev(priv)->intr = nv04_fifo_intr;
nv_engine(priv)->cclass = &nv17_fifo_cclass;
nv_engine(priv)->sclass = nv17_fifo_sclass;
priv->base.pause = nv04_fifo_pause;
priv->base.start = nv04_fifo_start;
priv->ramfc_desc = nv17_ramfc;
return 0;
}
nv_wr32(dev, NV04_PFIFO_DELAY_0, 0x000000ff);
nv_wr32(dev, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff);
static int
nv17_fifo_init(struct nouveau_object *object)
{
struct nv04_fifo_priv *priv = (void *)object;
int ret;
nv_wr32(dev, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
((dev_priv->ramht->bits - 9) << 16) |
(dev_priv->ramht->gpuobj->addr >> 8));
nv_wr32(dev, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8);
nv_wr32(dev, NV03_PFIFO_RAMFC, 0x00010000 |
priv->ramfc->addr >> 8);
ret = nouveau_fifo_init(&priv->base);
if (ret)
return ret;
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, priv->base.channels);
nv_wr32(priv, NV04_PFIFO_DELAY_0, 0x000000ff);
nv_wr32(priv, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff);
nv_wr32(dev, NV03_PFIFO_INTR_0, 0xffffffff);
nv_wr32(dev, NV03_PFIFO_INTR_EN_0, 0xffffffff);
nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
((priv->ramht->bits - 9) << 16) |
(priv->ramht->base.addr >> 8));
nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8);
nv_wr32(priv, NV03_PFIFO_RAMFC, priv->ramfc->addr >> 8 | 0x00010000);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, 1);
nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
nv_wr32(dev, NV03_PFIFO_CACHES, 1);
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
for (i = 0; i < priv->base.channels; i++) {
if (dev_priv->channels.ptr[i])
nv_mask(dev, NV04_PFIFO_MODE, (1 << i), (1 << i));
}
nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff);
nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff);
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
nv_wr32(priv, NV03_PFIFO_CACHES, 1);
return 0;
}
int
nv17_fifo_create(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv17_fifo_priv *priv;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
nouveau_gpuobj_ref(nvimem_ramro(dev), &priv->ramro);
nouveau_gpuobj_ref(nvimem_ramfc(dev), &priv->ramfc);
priv->base.base.destroy = nv04_fifo_destroy;
priv->base.base.init = nv17_fifo_init;
priv->base.base.fini = nv04_fifo_fini;
priv->base.base.context_new = nv17_fifo_context_new;
priv->base.base.context_del = nv04_fifo_context_del;
priv->base.channels = 31;
priv->ramfc_desc = nv17_ramfc;
dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base;
nouveau_irq_register(dev, 8, nv04_fifo_isr);
return 0;
}
struct nouveau_oclass
nv17_fifo_oclass = {
.handle = NV_ENGINE(FIFO, 0x17),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv17_fifo_ctor,
.dtor = nv04_fifo_dtor,
.init = nv17_fifo_init,
.fini = _nouveau_fifo_fini,
},
};
#ifndef __NV50_FIFO_H__
#define __NV50_FIFO_H__
struct nv50_fifo_priv {
struct nouveau_fifo base;
struct nouveau_gpuobj *playlist[2];
int cur_playlist;
};
struct nv50_fifo_base {
struct nouveau_fifo_base base;
struct nouveau_gpuobj *ramfc;
struct nouveau_gpuobj *cache;
struct nouveau_gpuobj *eng;
struct nouveau_gpuobj *pgd;
struct nouveau_vm *vm;
};
struct nv50_fifo_chan {
struct nouveau_fifo_chan base;
u32 subc[8];
struct nouveau_ramht *ramht;
};
void nv50_fifo_playlist_update(struct nv50_fifo_priv *);
void nv50_fifo_object_detach(struct nouveau_object *, int);
void nv50_fifo_chan_dtor(struct nouveau_object *);
int nv50_fifo_chan_fini(struct nouveau_object *, bool);
void nv50_fifo_context_dtor(struct nouveau_object *);
void nv50_fifo_dtor(struct nouveau_object *);
int nv50_fifo_init(struct nouveau_object *);
#endif
......@@ -2,7 +2,7 @@
#define __NOUVEAU_GRCTX_H__
struct nouveau_grctx {
struct drm_device *dev;
struct nouveau_device *device;
enum {
NOUVEAU_GRCTX_PROG,
......@@ -10,18 +10,18 @@ struct nouveau_grctx {
} mode;
void *data;
uint32_t ctxprog_max;
uint32_t ctxprog_len;
uint32_t ctxprog_reg;
int ctxprog_label[32];
uint32_t ctxvals_pos;
uint32_t ctxvals_base;
u32 ctxprog_max;
u32 ctxprog_len;
u32 ctxprog_reg;
int ctxprog_label[32];
u32 ctxvals_pos;
u32 ctxvals_base;
};
static inline void
cp_out(struct nouveau_grctx *ctx, uint32_t inst)
cp_out(struct nouveau_grctx *ctx, u32 inst)
{
uint32_t *ctxprog = ctx->data;
u32 *ctxprog = ctx->data;
if (ctx->mode != NOUVEAU_GRCTX_PROG)
return;
......@@ -31,13 +31,13 @@ cp_out(struct nouveau_grctx *ctx, uint32_t inst)
}
static inline void
cp_lsr(struct nouveau_grctx *ctx, uint32_t val)
cp_lsr(struct nouveau_grctx *ctx, u32 val)
{
cp_out(ctx, CP_LOAD_SR | val);
}
static inline void
cp_ctx(struct nouveau_grctx *ctx, uint32_t reg, uint32_t length)
cp_ctx(struct nouveau_grctx *ctx, u32 reg, u32 length)
{
ctx->ctxprog_reg = (reg - 0x00400000) >> 2;
......@@ -55,7 +55,7 @@ cp_ctx(struct nouveau_grctx *ctx, uint32_t reg, uint32_t length)
static inline void
cp_name(struct nouveau_grctx *ctx, int name)
{
uint32_t *ctxprog = ctx->data;
u32 *ctxprog = ctx->data;
int i;
if (ctx->mode != NOUVEAU_GRCTX_PROG)
......@@ -115,7 +115,7 @@ cp_pos(struct nouveau_grctx *ctx, int offset)
}
static inline void
gr_def(struct nouveau_grctx *ctx, uint32_t reg, uint32_t val)
gr_def(struct nouveau_grctx *ctx, u32 reg, u32 val)
{
if (ctx->mode != NOUVEAU_GRCTX_VALS)
return;
......
#ifndef __NV20_GRAPH_H__
#define __NV20_GRAPH_H__
#include <core/enum.h>
#include <engine/graph.h>
#include <engine/fifo.h>
struct nv20_graph_priv {
struct nouveau_graph base;
struct nouveau_gpuobj *ctxtab;
};
struct nv20_graph_chan {
struct nouveau_graph_chan base;
int chid;
};
extern struct nouveau_oclass nv25_graph_sclass[];
int nv20_graph_context_init(struct nouveau_object *);
int nv20_graph_context_fini(struct nouveau_object *, bool);
void nv20_graph_tile_prog(struct nouveau_engine *, int);
void nv20_graph_intr(struct nouveau_subdev *);
void nv20_graph_dtor(struct nouveau_object *);
int nv20_graph_init(struct nouveau_object *);
int nv30_graph_init(struct nouveau_object *);
#endif
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
#ifndef __NV40_GRAPH_H__
#define __NV40_GRAPH_H__
/* returns 1 if device is one of the nv4x using the 0x4497 object class,
* helpful to determine a number of other hardware features
*/
static inline int
nv44_graph_class(void *priv)
{
struct nouveau_device *device = nv_device(priv);
if ((device->chipset & 0xf0) == 0x60)
return 1;
return !(0x0baf & (1 << (device->chipset & 0x0f)));
}
void nv40_grctx_init(struct nouveau_device *, u32 *size);
void nv40_grctx_fill(struct nouveau_device *, struct nouveau_gpuobj *);
#endif
#ifndef __NV50_GRAPH_H__
#define __NV50_GRAPH_H__
int nv50_grctx_init(struct nouveau_device *, u32 *size);
void nv50_grctx_fill(struct nouveau_device *, struct nouveau_gpuobj *);
#endif
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
#ifndef __NOUVEAU_BSP_H__
#define __NOUVEAU_BSP_H__
#include <core/engine.h>
#include <core/engctx.h>
struct nouveau_bsp_chan {
struct nouveau_engctx base;
};
#define nouveau_bsp_context_create(p,e,c,g,s,a,f,d) \
nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
#define nouveau_bsp_context_destroy(d) \
nouveau_engctx_destroy(&(d)->base)
#define nouveau_bsp_context_init(d) \
nouveau_engctx_init(&(d)->base)
#define nouveau_bsp_context_fini(d,s) \
nouveau_engctx_fini(&(d)->base, (s))
#define _nouveau_bsp_context_dtor _nouveau_engctx_dtor
#define _nouveau_bsp_context_init _nouveau_engctx_init
#define _nouveau_bsp_context_fini _nouveau_engctx_fini
#define _nouveau_bsp_context_rd32 _nouveau_engctx_rd32
#define _nouveau_bsp_context_wr32 _nouveau_engctx_wr32
struct nouveau_bsp {
struct nouveau_engine base;
};
#define nouveau_bsp_create(p,e,c,d) \
nouveau_engine_create((p), (e), (c), true, "PBSP", "bsp", (d))
#define nouveau_bsp_destroy(d) \
nouveau_engine_destroy(&(d)->base)
#define nouveau_bsp_init(d) \
nouveau_engine_init(&(d)->base)
#define nouveau_bsp_fini(d,s) \
nouveau_engine_fini(&(d)->base, (s))
#define _nouveau_bsp_dtor _nouveau_engine_dtor
#define _nouveau_bsp_init _nouveau_engine_init
#define _nouveau_bsp_fini _nouveau_engine_fini
extern struct nouveau_oclass nv84_bsp_oclass;
#endif
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -8,7 +8,6 @@
int nouveau_device_create_(struct pci_dev *, u64 name, const char *sname,
const char *cfg, const char *dbg, int, void **);
void nouveau_device_destroy(struct nouveau_device **);
int nv04_identify(struct nouveau_device *);
int nv10_identify(struct nouveau_device *);
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册