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: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
Ben Skeggs
2012-07-20 08:17:34 +10:00
parent ac1499d957
commit ebb945a94b
146 changed files with 14480 additions and 11360 deletions
+74 -23
View File
@@ -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
# drm/compat - will go away
nouveau-y += nouveau_compat.o nouveau_revcompat.o
nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.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
+58 -255
View File
@@ -1,5 +1,5 @@
/*
* 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;
struct nouveau_bar *bar = nouveau_bar(ramht);
u32 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);
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)
{
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_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;
}
int
nouveau_ramht_new(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
struct nouveau_ramht **pramht)
{
struct nouveau_ramht *ramht;
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);
*pramht = ramht;
return 0;
}
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)
nouveau_ramht_remove(struct nouveau_ramht *ramht, int cookie)
{
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;
struct nouveau_bar *bar = nouveau_bar(ramht);
nv_wo32(ramht, cookie + 0, 0x00000000);
nv_wo32(ramht, cookie + 4, 0x00000000);
if (bar)
bar->flush(bar);
}
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 nouveau_object *parent, struct nouveau_object *pargpu,
u32 size, u32 align, struct nouveau_ramht **pramht)
{
struct nouveau_ramht *ramht;
int ret;
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;
if (ret)
return ret;
ramht->bits = log2i(nv_gpuobj(ramht)->size >> 3);
return 0;
}
+132 -39
View File
@@ -1,5 +1,5 @@
/*
* 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_engine {
struct nouveau_exec_engine base;
struct nv84_bsp_priv {
struct nouveau_bsp base;
};
static int
nv84_bsp_fini(struct drm_device *dev, int engine, bool suspend)
{
if (!(nv_rd32(dev, 0x000200) & 0x00008000))
return 0;
struct nv84_bsp_chan {
struct nouveau_bsp_chan base;
};
nv_mask(dev, 0x000200, 0x00008000, 0x00000000);
return 0;
}
/*******************************************************************************
* BSP object classes
******************************************************************************/
static struct nouveau_oclass
nv84_bsp_sclass[] = {
{},
};
/*******************************************************************************
* BSP context
******************************************************************************/
static int
nv84_bsp_init(struct drm_device *dev, int engine)
nv84_bsp_context_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, 0x00008000, 0x00000000);
nv_mask(dev, 0x000200, 0x00008000, 0x00008000);
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;
return 0;
}
static void
nv84_bsp_destroy(struct drm_device *dev, int engine)
nv84_bsp_context_dtor(struct nouveau_object *object)
{
struct nv84_bsp_engine *pbsp = nv_engine(dev, engine);
NVOBJ_ENGINE_DEL(dev, BSP);
kfree(pbsp);
struct nv84_bsp_chan *priv = (void *)object;
nouveau_bsp_context_destroy(&priv->base);
}
int
nv84_bsp_create(struct drm_device *dev)
static int
nv84_bsp_context_init(struct nouveau_object *object)
{
struct nv84_bsp_engine *pbsp;
struct nv84_bsp_chan *priv = (void *)object;
int ret;
pbsp = kzalloc(sizeof(*pbsp), GFP_KERNEL);
if (!pbsp)
return -ENOMEM;
ret = nouveau_bsp_context_init(&priv->base);
if (ret)
return ret;
pbsp->base.destroy = nv84_bsp_destroy;
pbsp->base.init = nv84_bsp_init;
pbsp->base.fini = nv84_bsp_fini;
NVOBJ_ENGINE_ADD(dev, BSP, &pbsp->base);
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_intr(struct nouveau_subdev *subdev)
{
}
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;
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;
}
static void
nv84_bsp_dtor(struct nouveau_object *object)
{
struct nv84_bsp_priv *priv = (void *)object;
nouveau_bsp_destroy(&priv->base);
}
static int
nv84_bsp_init(struct nouveau_object *object)
{
struct nv84_bsp_priv *priv = (void *)object;
int ret;
ret = nouveau_bsp_init(&priv->base);
if (ret)
return ret;
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,
},
};
+149 -137
View File
@@ -1,5 +1,5 @@
/*
* 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 <core/os.h>
#include <core/enum.h>
#include <core/class.h>
#include <core/engctx.h>
#include <subdev/fb.h>
#include <subdev/vm.h>
#include <engine/copy.h>
#include "fuc/nva3.fuc.h"
struct nva3_copy_engine {
struct nouveau_exec_engine base;
struct nva3_copy_priv {
struct nouveau_copy base;
};
struct nva3_copy_chan {
struct nouveau_copy_chan base;
};
/*******************************************************************************
* Copy object classes
******************************************************************************/
static struct nouveau_oclass
nva3_copy_sclass[] = {
{ 0x85b5, &nouveau_object_ofuncs },
{}
};
/*******************************************************************************
* PCOPY context
******************************************************************************/
static int
nva3_copy_context_new(struct nouveau_channel *chan, 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)
{
struct drm_device *dev = chan->dev;
struct nouveau_gpuobj *ramin = chan->ramin;
struct nouveau_gpuobj *ctx = NULL;
struct nva3_copy_chan *priv;
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_copy_context_create(parent, engine, oclass, NULL, 256, 0,
NVOBJ_FLAG_ZERO_ALLOC, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
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);
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];
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,
/* fuc engine doesn't need an object, our ramht code does.. */
ctx->engine = 3;
ctx->class = class;
return nouveau_ramht_insert(chan, handle, ctx);
}
},
};
static void
nva3_copy_context_del(struct nouveau_channel *chan, int engine)
{
struct nouveau_gpuobj *ctx = chan->engctx[engine];
int i;
for (i = 0xc0; i <= 0xd4; i += 4)
nv_wo32(chan->ramin, i, 0x00000000);
nvvm_engref(chan->vm, engine, -1);
nouveau_gpuobj_ref(NULL, &ctx);
chan->engctx[engine] = ctx;
}
static void
nva3_copy_tlb_flush(struct drm_device *dev, int engine)
{
nv50_vm_flush_engine(dev, 0x0d);
}
static int
nva3_copy_init(struct drm_device *dev, int engine)
{
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]);
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]);
}
/* 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;
}
/*******************************************************************************
* 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);
nouveau_irq_unregister(dev, 22);
NVOBJ_ENGINE_DEL(dev, COPY0);
kfree(pcopy);
}
int
nva3_copy_create(struct drm_device *dev)
{
struct nva3_copy_engine *pcopy;
pcopy = kzalloc(sizeof(*pcopy), GFP_KERNEL);
if (!pcopy)
return -ENOMEM;
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;
nouveau_irq_register(dev, 22, nva3_copy_isr);
NVOBJ_ENGINE_ADD(dev, COPY0, &pcopy->base);
NVOBJ_CLASS(dev, 0x85b5, COPY0);
nv50_vm_flush_engine(&engine->base, 0x0d);
return 0;
}
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;
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;
}
static int
nva3_copy_init(struct nouveau_object *object)
{
struct nva3_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, 0xffffffff);
/* 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]);
}
/* 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,
},
};
+184 -184
View File
@@ -1,5 +1,5 @@
/*
* 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;
};
/*******************************************************************************
* Copy object classes
******************************************************************************/
static struct nouveau_oclass
nvc0_copy0_sclass[] = {
{ 0x90b5, &nouveau_object_ofuncs },
{},
};
static struct nouveau_oclass
nvc0_copy1_sclass[] = {
{ 0x90b8, &nouveau_object_ofuncs },
{},
};
/*******************************************************************************
* PCOPY context
******************************************************************************/
static int
nvc0_copy_context_new(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;
struct drm_device *dev = chan->dev;
struct nouveau_gpuobj *ramin = chan->ramin;
struct nvc0_copy_chan *priv;
int ret;
cctx = chan->engctx[engine] = kzalloc(sizeof(*cctx), GFP_KERNEL);
if (!cctx)
return -ENOMEM;
ret = nouveau_gpuobj_new(dev, NULL, 256, 256,
NVOBJ_FLAG_ZERO_ALLOC, &cctx->mem);
ret = nouveau_copy_context_create(parent, engine, oclass, NULL, 256,
256, NVOBJ_FLAG_ZERO_ALLOC, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
ret = nouveau_gpuobj_map_vm(cctx->mem, chan->vm, NV_MEM_ACCESS_RW,
&cctx->vma);
if (ret)
return ret;
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;
}
static int
nvc0_copy_object_new(struct nouveau_channel *chan, int engine,
u32 handle, u16 class)
{
return 0;
}
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,
};
static void
nvc0_copy_context_del(struct nouveau_channel *chan, int engine)
{
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;
static struct nouveau_oclass
nvc0_copy0_cclass = {
.handle = NV_ENGCTX(COPY0, 0xc0),
.ofuncs = &nvc0_copy_context_ofuncs,
};
inst = (chan->ramin->addr >> 12);
inst |= 0x40000000;
static struct nouveau_oclass
nvc0_copy1_cclass = {
.handle = NV_ENGCTX(COPY1, 0xc0),
.ofuncs = &nvc0_copy_context_ofuncs,
};
/* 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]);
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]);
}
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);
nv_mask(dev, pcopy->fuc + 0x048, 0x00000003, 0x00000000);
/* 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);
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;
static void
nvc0_copy_destroy(struct drm_device *dev, int engine)
{
struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
nouveau_irq_unregister(dev, pcopy->irq);
if (engine == NVOBJ_ENGINE_COPY0)
NVOBJ_ENGINE_DEL(dev, COPY0);
else
NVOBJ_ENGINE_DEL(dev, COPY1);
kfree(pcopy);
}
int
nvc0_copy_create(struct drm_device *dev, int engine)
{
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);
}
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 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_priv *priv;
int ret;
if (nv_rd32(parent, 0x022500) & 0x00000200)
return -ENODEV;
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;
}
static int
nvc0_copy_init(struct nouveau_object *object)
{
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,
},
};
+126 -120
View File
@@ -1,5 +1,5 @@
/*
* 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;
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,
};
inst = (chan->ramin->addr >> 12);
inst |= 0x80000000;
static struct nouveau_oclass
nv84_crypt_sclass[] = {
{ 0x74c1, &nv84_crypt_ofuncs },
{}
};
/* 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;
}
/*******************************************************************************
* 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,
},
};
static struct nouveau_bitfield nv84_crypt_intr[] = {
/*******************************************************************************
* PCRYPT engine/subdev functions
******************************************************************************/
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);
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 (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);
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)
static int
nv84_crypt_init(struct nouveau_object *object)
{
struct nv84_crypt_engine *pcrypt = nv_engine(dev, engine);
struct nv84_crypt_priv *priv = (void *)object;
int ret;
NVOBJ_ENGINE_DEL(dev, CRYPT);
ret = nouveau_crypt_init(&priv->base);
if (ret)
return ret;
nouveau_irq_unregister(dev, 14);
kfree(pcrypt);
}
int
nv84_crypt_create(struct drm_device *dev)
{
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;
nouveau_irq_register(dev, 14, nv84_crypt_isr);
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,
},
};
+129 -144
View File
@@ -1,5 +1,5 @@
/*
* 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;
};
/*******************************************************************************
* Crypt object classes
******************************************************************************/
static struct nouveau_oclass
nv98_crypt_sclass[] = {
{ 0x88b4, &nouveau_object_ofuncs },
{},
};
/*******************************************************************************
* PCRYPT context
******************************************************************************/
static int
nv98_crypt_context_new(struct nouveau_channel *chan, int engine)
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 drm_device *dev = chan->dev;
struct nv98_crypt_priv *priv = nv_engine(dev, engine);
struct nv98_crypt_chan *cctx;
struct nv98_crypt_chan *priv;
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);
ret = nouveau_crypt_context_create(parent, engine, oclass, NULL, 256,
256, NVOBJ_FLAG_ZERO_ALLOC, &priv);
*pobject = nv_object(priv);
if (ret)
goto error;
return ret;
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);
nouveau_gpuobj_ref(NULL, &cctx->mem);
nvvm_engref(chan->vm, engine, -1);
chan->engctx[engine] = NULL;
kfree(cctx);
}
static int
nv98_crypt_object_new(struct nouveau_channel *chan, int engine,
u32 handle, u16 class)
{
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);
}
static void
nv98_crypt_tlb_flush(struct drm_device *dev, int engine)
{
nv50_vm_flush_engine(dev, 0x0a);
}
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;
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,
},
};
/* 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]);
/* 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);
}
int
nv98_crypt_create(struct drm_device *dev)
{
struct nv98_crypt_priv *priv;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
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;
nouveau_irq_register(dev, 14, nv98_crypt_isr);
NVOBJ_ENGINE_ADD(dev, CRYPT, &priv->base);
NVOBJ_CLASS(dev, 0x88b4, CRYPT);
nv50_vm_flush_engine(&engine->base, 0x0a);
return 0;
}
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;
/* wait for exit interrupt to signal */
nv_wait(priv, 0x087008, 0x00000010, 0x00000010);
nv_wr32(priv, 0x087004, 0x00000010);
/* 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]);
nv_wr32(priv, 0x087ff8, 0x00000000);
for (i = 0; i < ARRAY_SIZE(nv98_pcrypt_data); i++)
nv_wr32(priv, 0x087ff4, nv98_pcrypt_data[i]);
/* 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,
},
};
@@ -0,0 +1,90 @@
/*
* 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/disp.h>
struct nv04_disp_priv {
struct nouveau_disp base;
};
static struct nouveau_oclass
nv04_disp_sclass[] = {
{},
};
static void
nv04_disp_intr_vblank(struct nv04_disp_priv *priv, int crtc)
{
struct nouveau_disp *disp = &priv->base;
if (disp->vblank.notify)
disp->vblank.notify(disp->vblank.data, crtc);
}
static void
nv04_disp_intr(struct nouveau_subdev *subdev)
{
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
nv04_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv04_disp_priv *priv;
int ret;
ret = nouveau_disp_create(parent, engine, oclass, "DISPLAY",
"display", &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_engine(priv)->sclass = nv04_disp_sclass;
nv_subdev(priv)->intr = nv04_disp_intr;
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,
},
};
@@ -0,0 +1,125 @@
/*
* 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,
},
};
@@ -0,0 +1,118 @@
/*
* 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,
},
};
@@ -0,0 +1,87 @@
/*
* 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;
}
@@ -0,0 +1,176 @@
/*
* 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,
},
};
@@ -0,0 +1,168 @@
/*
* 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,
},
};
@@ -0,0 +1,99 @@
/*
* 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,
},
};
@@ -0,0 +1,165 @@
/*
* 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;
}
+437 -323
View File
@@ -1,44 +1,45 @@
/*
* 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/namedb.h>
#include <core/handle.h>
#include <core/ramht.h>
#include "nouveau_software.h"
static struct ramfc_desc {
unsigned bits:6;
unsigned ctxs:5;
unsigned ctxp:8;
unsigned regs:5;
unsigned regp;
} nv04_ramfc[] = {
#include <subdev/instmem.h>
#include <subdev/instmem/nv04.h>
#include <subdev/timer.h>
#include <subdev/fb.h>
#include <engine/fifo.h>
#include "nv04.h"
static struct ramfc_desc
nv04_ramfc[] = {
{ 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
{ 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
{ 16, 0, 0x08, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
@@ -50,259 +51,284 @@ static struct ramfc_desc {
{}
};
struct nv04_fifo_priv {
struct nouveau_fifo_priv base;
struct ramfc_desc *ramfc_desc;
struct nouveau_gpuobj *ramro;
struct nouveau_gpuobj *ramfc;
};
/*******************************************************************************
* FIFO channel objects
******************************************************************************/
struct nv04_fifo_chan {
struct nouveau_fifo_chan base;
u32 ramfc;
};
bool
nv04_fifo_cache_pull(struct drm_device *dev, bool enable)
int
nv04_fifo_object_attach(struct nouveau_object *parent,
struct nouveau_object *object, u32 handle)
{
int pull = nv_mask(dev, NV04_PFIFO_CACHE1_PULL0, 1, enable);
struct nv04_fifo_priv *priv = (void *)parent->engine;
struct nv04_fifo_chan *chan = (void *)parent;
u32 context, chid = chan->base.chid;
int ret;
if (!enable) {
/* In some cases the PFIFO puller may be left in an
* inconsistent state if you try to stop it when it's
* busy translating handles. Sometimes you get a
* PFIFO_CACHE_ERROR, sometimes it just fails silently
* sending incorrect instance offsets to PGRAPH after
* it's started up again. To avoid the latter we
* invalidate the most recently calculated instance.
*/
if (!nv_wait(dev, NV04_PFIFO_CACHE1_PULL0,
NV04_PFIFO_CACHE1_PULL0_HASH_BUSY, 0))
NV_ERROR(dev, "Timeout idling the PFIFO puller.\n");
if (nv_iclass(object, NV_GPUOBJ_CLASS))
context = nv_gpuobj(object)->addr >> 4;
else
context = 0x00000004; /* just non-zero */
if (nv_rd32(dev, NV04_PFIFO_CACHE1_PULL0) &
NV04_PFIFO_CACHE1_PULL0_HASH_FAILED)
nv_wr32(dev, NV03_PFIFO_INTR_0,
NV_PFIFO_INTR_CACHE_ERROR);
nv_wr32(dev, NV04_PFIFO_CACHE1_HASH, 0);
switch (nv_engidx(object->engine)) {
case NVDEV_ENGINE_DMAOBJ:
case NVDEV_ENGINE_SW:
context |= 0x00000000;
break;
case NVDEV_ENGINE_GR:
context |= 0x00010000;
break;
case NVDEV_ENGINE_MPEG:
context |= 0x00020000;
break;
default:
return -EINVAL;
}
return pull & 1;
context |= 0x80000000; /* valid */
context |= chid << 24;
mutex_lock(&nv_subdev(priv)->mutex);
ret = nouveau_ramht_insert(priv->ramht, chid, handle, context);
mutex_unlock(&nv_subdev(priv)->mutex);
return ret;
}
void
nv04_fifo_object_detach(struct nouveau_object *parent, int cookie)
{
struct nv04_fifo_priv *priv = (void *)parent->engine;
mutex_lock(&nv_subdev(priv)->mutex);
nouveau_ramht_remove(priv->ramht, cookie);
mutex_unlock(&nv_subdev(priv)->mutex);
}
static int
nv04_fifo_context_new(struct nouveau_channel *chan, int engine)
nv04_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 nv04_fifo_priv *priv = nv_engine(dev, engine);
struct nv04_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;
if (size < sizeof(*args))
return -EINVAL;
fctx->ramfc = chan->id * 32;
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;
/* 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;
}
nv_parent(chan)->object_attach = nv04_fifo_object_attach;
nv_parent(chan)->object_detach = nv04_fifo_object_detach;
chan->ramfc = chan->base.chid * 32;
/* 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 + 0x08, chan->pushbuf->addr >> 4);
nv_wo32(priv->ramfc, fctx->ramfc + 0x10,
nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->offset);
nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->offset);
nv_wo32(priv->ramfc, chan->ramfc + 0x08, chan->base.pushgpu->addr >> 4);
nv_wo32(priv->ramfc, chan->ramfc + 0x10,
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);
/* 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);
error:
if (ret)
priv->base.base.context_del(chan, engine);
return ret;
return 0;
}
void
nv04_fifo_context_del(struct nouveau_channel *chan, int engine)
nv04_fifo_chan_dtor(struct nouveau_object *object)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv04_fifo_priv *priv = nv_engine(chan->dev, engine);
struct nv04_fifo_chan *fctx = chan->engctx[engine];
struct nv04_fifo_priv *priv = (void *)object->engine;
struct nv04_fifo_chan *chan = (void *)object;
struct ramfc_desc *c = priv->ramfc_desc;
unsigned long flags;
int chid;
/* prevent fifo context switches */
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
nv_wr32(dev, NV03_PFIFO_CACHES, 0);
do {
nv_wo32(priv->ramfc, chan->ramfc + c->ctxp, 0x00000000);
} while ((++c)->bits);
/* if this channel is active, replace it with a null context */
chid = nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH1) & priv->base.channels;
if (chid == chan->id) {
nv_mask(dev, NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001, 0);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, 0);
nv_mask(dev, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0);
do {
u32 mask = ((1ULL << c->bits) - 1) << c->regs;
nv_mask(dev, c->regp, mask, 0x00000000);
nv_wo32(priv->ramfc, fctx->ramfc + c->ctxp, 0x00000000);
} while ((++c)->bits);
nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, priv->base.channels);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, 1);
nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
}
/* restore normal operation, after disabling dma mode */
nv_mask(dev, NV04_PFIFO_MODE, 1 << chan->id, 0);
nv_wr32(dev, NV03_PFIFO_CACHES, 1);
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
/* clean up */
nouveau_gpuobj_ref(NULL, &chan->ramfc); /*XXX: nv40 */
if (chan->user) {
iounmap(chan->user);
chan->user = NULL;
}
nouveau_fifo_channel_destroy(&chan->base);
}
int
nv04_fifo_init(struct drm_device *dev, int engine)
nv04_fifo_chan_init(struct nouveau_object *object)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv04_fifo_priv *priv = nv_engine(dev, engine);
int i;
struct nv04_fifo_priv *priv = (void *)object->engine;
struct nv04_fifo_chan *chan = (void *)object;
u32 mask = 1 << chan->base.chid;
unsigned long flags;
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);
nv_wr32(dev, NV04_PFIFO_DELAY_0, 0x000000ff);
nv_wr32(dev, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff);
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, priv->ramfc->addr >> 8);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, priv->base.channels);
nv_wr32(dev, NV03_PFIFO_INTR_0, 0xffffffff);
nv_wr32(dev, NV03_PFIFO_INTR_EN_0, 0xffffffff);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, 1);
nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
nv_wr32(dev, NV03_PFIFO_CACHES, 1);
for (i = 0; i < priv->base.channels; i++) {
if (dev_priv->channels.ptr[i])
nv_mask(dev, NV04_PFIFO_MODE, (1 << i), (1 << i));
}
ret = nouveau_fifo_channel_init(&chan->base);
if (ret)
return ret;
spin_lock_irqsave(&priv->base.lock, flags);
nv_mask(priv, NV04_PFIFO_MODE, mask, mask);
spin_unlock_irqrestore(&priv->base.lock, flags);
return 0;
}
int
nv04_fifo_fini(struct drm_device *dev, int engine, bool suspend)
nv04_fifo_chan_fini(struct nouveau_object *object, bool suspend)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv04_fifo_priv *priv = nv_engine(dev, engine);
struct nouveau_channel *chan;
int chid;
struct nv04_fifo_priv *priv = (void *)object->engine;
struct nv04_fifo_chan *chan = (void *)object;
struct nouveau_gpuobj *fctx = priv->ramfc;
struct ramfc_desc *c;
unsigned long flags;
u32 data = chan->ramfc;
u32 chid;
/* prevent context switches and halt fifo operation */
nv_wr32(dev, NV03_PFIFO_CACHES, 0);
nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, 0);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, 0);
nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 0);
/* prevent fifo context switches */
spin_lock_irqsave(&priv->base.lock, flags);
nv_wr32(priv, NV03_PFIFO_CACHES, 0);
/* store current fifo context in ramfc */
chid = nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH1) & priv->base.channels;
chan = dev_priv->channels.ptr[chid];
if (suspend && chid != priv->base.channels && chan) {
struct nv04_fifo_chan *fctx = chan->engctx[engine];
struct nouveau_gpuobj *ctx = priv->ramfc;
struct ramfc_desc *c = priv->ramfc_desc;
/* if this channel is active, replace it with a null context */
chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max;
if (chid == chan->base.chid) {
nv_mask(priv, NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001, 0);
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 0);
nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0);
c = priv->ramfc_desc;
do {
u32 rm = ((1ULL << c->bits) - 1) << c->regs;
u32 cm = ((1ULL << c->bits) - 1) << c->ctxs;
u32 rv = (nv_rd32(dev, c->regp) & rm) >> c->regs;
u32 cv = (nv_ro32(ctx, c->ctxp + fctx->ramfc) & ~cm);
nv_wo32(ctx, c->ctxp + fctx->ramfc, cv | (rv << c->ctxs));
u32 rv = (nv_rd32(priv, c->regp) & rm) >> c->regs;
u32 cv = (nv_ro32(fctx, c->ctxp + data) & ~cm);
nv_wo32(fctx, c->ctxp + data, cv | (rv << c->ctxs));
} while ((++c)->bits);
c = priv->ramfc_desc;
do {
nv_wr32(priv, c->regp, 0x00000000);
} while ((++c)->bits);
nv_wr32(priv, NV03_PFIFO_CACHE1_GET, 0);
nv_wr32(priv, NV03_PFIFO_CACHE1_PUT, 0);
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
}
nv_wr32(dev, NV03_PFIFO_INTR_EN_0, 0x00000000);
/* restore normal operation, after disabling dma mode */
nv_mask(priv, NV04_PFIFO_MODE, 1 << chan->base.chid, 0);
nv_wr32(priv, NV03_PFIFO_CACHES, 1);
spin_unlock_irqrestore(&priv->base.lock, flags);
return nouveau_fifo_channel_fini(&chan->base, suspend);
}
static struct nouveau_ofuncs
nv04_fifo_ofuncs = {
.ctor = nv04_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,
};
static struct nouveau_oclass
nv04_fifo_sclass[] = {
{ 0x006e, &nv04_fifo_ofuncs },
{}
};
/*******************************************************************************
* FIFO context - basically just the instmem reserved for the channel
******************************************************************************/
int
nv04_fifo_context_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv04_fifo_base *base;
int ret;
ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x1000,
0x1000, NVOBJ_FLAG_HEAP, &base);
*pobject = nv_object(base);
if (ret)
return ret;
return 0;
}
static bool
nouveau_fifo_swmthd(struct drm_device *dev, u32 chid, u32 addr, u32 data)
static struct nouveau_oclass
nv04_fifo_cclass = {
.handle = NV_ENGCTX(FIFO, 0x04),
.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
******************************************************************************/
void
nv04_fifo_pause(struct nouveau_fifo *pfifo, unsigned long *pflags)
__acquires(priv->base.lock)
{
struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = NULL;
struct nouveau_gpuobj *obj;
struct nv04_fifo_priv *priv = (void *)pfifo;
unsigned long flags;
const int subc = (addr >> 13) & 0x7;
const int mthd = addr & 0x1ffc;
bool handled = false;
u32 engine;
spin_lock_irqsave(&dev_priv->channels.lock, flags);
if (likely(chid >= 0 && chid < pfifo->channels))
chan = dev_priv->channels.ptr[chid];
if (unlikely(!chan))
goto out;
spin_lock_irqsave(&priv->base.lock, flags);
*pflags = flags;
switch (mthd) {
case 0x0000: /* bind object to subchannel */
obj = nouveau_ramht_find(chan, data);
if (unlikely(!obj || obj->engine != NVOBJ_ENGINE_SW))
break;
nv_wr32(priv, NV03_PFIFO_CACHES, 0x00000000);
nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000000);
engine = 0x0000000f << (subc * 4);
/* in some cases the puller may be left in an inconsistent state
* if you try to stop it while it's busy translating handles.
* sometimes you get a CACHE_ERROR, sometimes it just fails
* silently; sending incorrect instance offsets to PGRAPH after
* it's started up again.
*
* to avoid this, we invalidate the most recently calculated
* instance.
*/
if (!nv_wait(priv, NV04_PFIFO_CACHE1_PULL0,
NV04_PFIFO_CACHE1_PULL0_HASH_BUSY, 0x00000000))
nv_warn(priv, "timeout idling puller\n");
nv_mask(dev, NV04_PFIFO_CACHE1_ENGINE, engine, 0x00000000);
handled = true;
break;
default:
engine = nv_rd32(dev, NV04_PFIFO_CACHE1_ENGINE);
if (unlikely(((engine >> (subc * 4)) & 0xf) != 0))
break;
if (nv_rd32(priv, NV04_PFIFO_CACHE1_PULL0) &
NV04_PFIFO_CACHE1_PULL0_HASH_FAILED)
nv_wr32(priv, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR);
if (!nouveau_gpuobj_mthd_call(chan, nouveau_software_class(dev),
mthd, data))
handled = true;
break;
}
out:
spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
return handled;
nv_wr32(priv, NV04_PFIFO_CACHE1_HASH, 0x00000000);
}
static const char *nv_dma_state_err(u32 state)
void
nv04_fifo_start(struct nouveau_fifo *pfifo, unsigned long *pflags)
__releases(priv->base.lock)
{
struct nv04_fifo_priv *priv = (void *)pfifo;
unsigned long flags = *pflags;
nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000001);
nv_wr32(priv, NV03_PFIFO_CACHES, 0x00000001);
spin_unlock_irqrestore(&priv->base.lock, flags);
}
static const char *
nv_dma_state_err(u32 state)
{
static const char * const desc[] = {
"NONE", "CALL_SUBR_ACTIVE", "INVALID_MTHD", "RET_SUBR_INACTIVE",
@@ -311,22 +337,74 @@ static const char *nv_dma_state_err(u32 state)
return desc[(state >> 29) & 0x7];
}
void
nv04_fifo_isr(struct drm_device *dev)
static bool
nv04_fifo_swmthd(struct nv04_fifo_priv *priv, u32 chid, u32 addr, u32 data)
{
struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv04_fifo_chan *chan = NULL;
struct nouveau_handle *bind;
const int subc = (addr >> 13) & 0x7;
const int mthd = addr & 0x1ffc;
bool handled = false;
unsigned long flags;
u32 engine;
spin_lock_irqsave(&priv->base.lock, flags);
if (likely(chid >= priv->base.min && chid <= priv->base.max))
chan = (void *)priv->base.channel[chid];
if (unlikely(!chan))
goto out;
switch (mthd) {
case 0x0000:
bind = nouveau_namedb_get(nv_namedb(chan), data);
if (unlikely(!bind))
break;
if (nv_engidx(bind->object->engine) == NVDEV_ENGINE_SW) {
engine = 0x0000000f << (subc * 4);
chan->subc[subc] = data;
handled = true;
nv_mask(priv, NV04_PFIFO_CACHE1_ENGINE, engine, 0);
}
nouveau_namedb_put(bind);
break;
default:
engine = nv_rd32(priv, NV04_PFIFO_CACHE1_ENGINE);
if (unlikely(((engine >> (subc * 4)) & 0xf) != 0))
break;
bind = nouveau_namedb_get(nv_namedb(chan), chan->subc[subc]);
if (likely(bind)) {
if (!nv_call(bind->object, mthd, data))
handled = true;
nouveau_namedb_put(bind);
}
break;
}
out:
spin_unlock_irqrestore(&priv->base.lock, flags);
return handled;
}
void
nv04_fifo_intr(struct nouveau_subdev *subdev)
{
struct nouveau_device *device = nv_device(subdev);
struct nv04_fifo_priv *priv = (void *)subdev;
uint32_t status, reassign;
int cnt = 0;
reassign = nv_rd32(dev, NV03_PFIFO_CACHES) & 1;
while ((status = nv_rd32(dev, NV03_PFIFO_INTR_0)) && (cnt++ < 100)) {
reassign = nv_rd32(priv, NV03_PFIFO_CACHES) & 1;
while ((status = nv_rd32(priv, NV03_PFIFO_INTR_0)) && (cnt++ < 100)) {
uint32_t chid, get;
nv_wr32(dev, NV03_PFIFO_CACHES, 0);
nv_wr32(priv, NV03_PFIFO_CACHES, 0);
chid = nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH1) & pfifo->channels;
get = nv_rd32(dev, NV03_PFIFO_CACHE1_GET);
chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max;
get = nv_rd32(priv, NV03_PFIFO_CACHE1_GET);
if (status & NV_PFIFO_INTR_CACHE_ERROR) {
uint32_t mthd, data;
@@ -340,86 +418,85 @@ nv04_fifo_isr(struct drm_device *dev)
*/
ptr = (get & 0x7ff) >> 2;
if (dev_priv->card_type < NV_40) {
mthd = nv_rd32(dev,
if (device->card_type < NV_40) {
mthd = nv_rd32(priv,
NV04_PFIFO_CACHE1_METHOD(ptr));
data = nv_rd32(dev,
data = nv_rd32(priv,
NV04_PFIFO_CACHE1_DATA(ptr));
} else {
mthd = nv_rd32(dev,
mthd = nv_rd32(priv,
NV40_PFIFO_CACHE1_METHOD(ptr));
data = nv_rd32(dev,
data = nv_rd32(priv,
NV40_PFIFO_CACHE1_DATA(ptr));
}
if (!nouveau_fifo_swmthd(dev, chid, mthd, data)) {
NV_INFO(dev, "PFIFO_CACHE_ERROR - Ch %d/%d "
"Mthd 0x%04x Data 0x%08x\n",
if (!nv04_fifo_swmthd(priv, chid, mthd, data)) {
nv_info(priv, "CACHE_ERROR - Ch %d/%d "
"Mthd 0x%04x Data 0x%08x\n",
chid, (mthd >> 13) & 7, mthd & 0x1ffc,
data);
}
nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, 0);
nv_wr32(dev, NV03_PFIFO_INTR_0,
nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH, 0);
nv_wr32(priv, NV03_PFIFO_INTR_0,
NV_PFIFO_INTR_CACHE_ERROR);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0,
nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH0) & ~1);
nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0,
nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH0) | 1);
nv_wr32(dev, NV04_PFIFO_CACHE1_HASH, 0);
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0,
nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) & ~1);
nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4);
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0,
nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) | 1);
nv_wr32(priv, NV04_PFIFO_CACHE1_HASH, 0);
nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH,
nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUSH) | 1);
nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH,
nv_rd32(priv, NV04_PFIFO_CACHE1_DMA_PUSH) | 1);
nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
status &= ~NV_PFIFO_INTR_CACHE_ERROR;
}
if (status & NV_PFIFO_INTR_DMA_PUSHER) {
u32 dma_get = nv_rd32(dev, 0x003244);
u32 dma_put = nv_rd32(dev, 0x003240);
u32 push = nv_rd32(dev, 0x003220);
u32 state = nv_rd32(dev, 0x003228);
u32 dma_get = nv_rd32(priv, 0x003244);
u32 dma_put = nv_rd32(priv, 0x003240);
u32 push = nv_rd32(priv, 0x003220);
u32 state = nv_rd32(priv, 0x003228);
if (dev_priv->card_type == NV_50) {
u32 ho_get = nv_rd32(dev, 0x003328);
u32 ho_put = nv_rd32(dev, 0x003320);
u32 ib_get = nv_rd32(dev, 0x003334);
u32 ib_put = nv_rd32(dev, 0x003330);
if (device->card_type == NV_50) {
u32 ho_get = nv_rd32(priv, 0x003328);
u32 ho_put = nv_rd32(priv, 0x003320);
u32 ib_get = nv_rd32(priv, 0x003334);
u32 ib_put = nv_rd32(priv, 0x003330);
if (nouveau_ratelimit())
NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x "
"Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x "
"State 0x%08x (err: %s) Push 0x%08x\n",
chid, ho_get, dma_get, ho_put,
dma_put, ib_get, ib_put, state,
nv_dma_state_err(state),
push);
nv_info(priv, "DMA_PUSHER - Ch %d Get 0x%02x%08x "
"Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x "
"State 0x%08x (err: %s) Push 0x%08x\n",
chid, ho_get, dma_get, ho_put,
dma_put, ib_get, ib_put, state,
nv_dma_state_err(state),
push);
/* METHOD_COUNT, in DMA_STATE on earlier chipsets */
nv_wr32(dev, 0x003364, 0x00000000);
nv_wr32(priv, 0x003364, 0x00000000);
if (dma_get != dma_put || ho_get != ho_put) {
nv_wr32(dev, 0x003244, dma_put);
nv_wr32(dev, 0x003328, ho_put);
nv_wr32(priv, 0x003244, dma_put);
nv_wr32(priv, 0x003328, ho_put);
} else
if (ib_get != ib_put) {
nv_wr32(dev, 0x003334, ib_put);
nv_wr32(priv, 0x003334, ib_put);
}
} else {
NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%08x "
nv_info(priv, "DMA_PUSHER - Ch %d Get 0x%08x "
"Put 0x%08x State 0x%08x (err: %s) Push 0x%08x\n",
chid, dma_get, dma_put, state,
nv_dma_state_err(state), push);
if (dma_get != dma_put)
nv_wr32(dev, 0x003244, dma_put);
nv_wr32(priv, 0x003244, dma_put);
}
nv_wr32(dev, 0x003228, 0x00000000);
nv_wr32(dev, 0x003220, 0x00000001);
nv_wr32(dev, 0x002100, NV_PFIFO_INTR_DMA_PUSHER);
nv_wr32(priv, 0x003228, 0x00000000);
nv_wr32(priv, 0x003220, 0x00000001);
nv_wr32(priv, 0x002100, NV_PFIFO_INTR_DMA_PUSHER);
status &= ~NV_PFIFO_INTR_DMA_PUSHER;
}
@@ -427,81 +504,118 @@ nv04_fifo_isr(struct drm_device *dev)
uint32_t sem;
status &= ~NV_PFIFO_INTR_SEMAPHORE;
nv_wr32(dev, NV03_PFIFO_INTR_0,
nv_wr32(priv, NV03_PFIFO_INTR_0,
NV_PFIFO_INTR_SEMAPHORE);
sem = nv_rd32(dev, NV10_PFIFO_CACHE1_SEMAPHORE);
nv_wr32(dev, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1);
sem = nv_rd32(priv, NV10_PFIFO_CACHE1_SEMAPHORE);
nv_wr32(priv, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1);
nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4);
nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4);
nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
}
if (dev_priv->card_type == NV_50) {
if (device->card_type == NV_50) {
if (status & 0x00000010) {
nv50_fb_vm_trap(dev, nouveau_ratelimit());
nv50_fb_trap(nouveau_fb(priv), 1);
status &= ~0x00000010;
nv_wr32(dev, 0x002100, 0x00000010);
nv_wr32(priv, 0x002100, 0x00000010);
}
}
if (status) {
if (nouveau_ratelimit())
NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n",
status, chid);
nv_wr32(dev, NV03_PFIFO_INTR_0, status);
nv_info(priv, "unknown intr 0x%08x, ch %d\n",
status, chid);
nv_wr32(priv, NV03_PFIFO_INTR_0, status);
status = 0;
}
nv_wr32(dev, NV03_PFIFO_CACHES, reassign);
nv_wr32(priv, NV03_PFIFO_CACHES, reassign);
}
if (status) {
NV_INFO(dev, "PFIFO still angry after %d spins, halt\n", cnt);
nv_wr32(dev, 0x2140, 0);
nv_wr32(dev, 0x140, 0);
nv_info(priv, "still angry after %d spins, halt\n", cnt);
nv_wr32(priv, 0x002140, 0);
nv_wr32(priv, 0x000140, 0);
}
nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PFIFO_PENDING);
nv_wr32(priv, 0x000100, 0x00000100);
}
static int
nv04_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv04_instmem_priv *imem = nv04_instmem(parent);
struct nv04_fifo_priv *priv;
int ret;
ret = nouveau_fifo_create(parent, engine, oclass, 0, 15, &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 = &nv04_fifo_cclass;
nv_engine(priv)->sclass = nv04_fifo_sclass;
priv->base.pause = nv04_fifo_pause;
priv->base.start = nv04_fifo_start;
priv->ramfc_desc = nv04_ramfc;
return 0;
}
void
nv04_fifo_destroy(struct drm_device *dev, int engine)
nv04_fifo_dtor(struct nouveau_object *object)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv04_fifo_priv *priv = nv_engine(dev, engine);
nouveau_irq_unregister(dev, 8);
struct nv04_fifo_priv *priv = (void *)object;
nouveau_gpuobj_ref(NULL, &priv->ramfc);
nouveau_gpuobj_ref(NULL, &priv->ramro);
dev_priv->eng[engine] = NULL;
kfree(priv);
nouveau_ramht_ref(NULL, &priv->ramht);
nouveau_fifo_destroy(&priv->base);
}
int
nv04_fifo_create(struct drm_device *dev)
nv04_fifo_init(struct nouveau_object *object)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv04_fifo_priv *priv;
struct nv04_fifo_priv *priv = (void *)object;
int ret;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
ret = nouveau_fifo_init(&priv->base);
if (ret)
return ret;
nouveau_gpuobj_ref(nvimem_ramro(dev), &priv->ramro);
nouveau_gpuobj_ref(nvimem_ramfc(dev), &priv->ramfc);
nv_wr32(priv, NV04_PFIFO_DELAY_0, 0x000000ff);
nv_wr32(priv, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff);
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 = nv04_fifo_context_new;
priv->base.base.context_del = nv04_fifo_context_del;
priv->base.channels = 15;
priv->ramfc_desc = nv04_ramfc;
dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base;
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);
nouveau_irq_register(dev, 8, nv04_fifo_isr);
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
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;
}
struct nouveau_oclass
nv04_fifo_oclass = {
.handle = NV_ENGINE(FIFO, 0x04),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv04_fifo_ctor,
.dtor = nv04_fifo_dtor,
.init = nv04_fifo_init,
.fini = _nouveau_fifo_fini,
},
};
@@ -0,0 +1,178 @@
#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
+133 -99
View File
@@ -1,43 +1,42 @@
/*
* 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;
if (size < sizeof(*args))
return -EINVAL;
fctx->ramfc = chan->id * 32;
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;
/* 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;
}
nv_parent(chan)->object_attach = nv04_fifo_object_attach;
nv_parent(chan)->object_detach = nv04_fifo_object_detach;
chan->ramfc = chan->base.chid * 32;
/* 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,
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);
/* 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);
error:
if (ret)
priv->base.base.context_del(chan, engine);
return ret;
}
int
nv10_fifo_create(struct drm_device *dev)
{
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;
nouveau_irq_register(dev, 8, nv04_fifo_isr);
return 0;
}
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,
};
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
******************************************************************************/
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 nv04_instmem_priv *imem = nv04_instmem(parent);
struct nv04_fifo_priv *priv;
int ret;
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,
},
};
+151 -122
View File
@@ -1,43 +1,42 @@
/*
* 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;
if (size < sizeof(*args))
return -EINVAL;
fctx->ramfc = chan->id * 64;
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;
/* 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;
}
nv_parent(chan)->object_attach = nv04_fifo_object_attach;
nv_parent(chan)->object_detach = nv04_fifo_object_detach;
chan->ramfc = chan->base.chid * 64;
/* 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,
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:
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_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv04_instmem_priv *imem = nv04_instmem(parent);
struct nv04_fifo_priv *priv;
int ret;
ret = nouveau_fifo_create(parent, engine, oclass, 0, 31, &priv);
*pobject = nv_object(priv);
if (ret)
priv->base.base.context_del(chan, engine);
return 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;
}
static int
nv17_fifo_init(struct drm_device *dev, int engine)
nv17_fifo_init(struct nouveau_object *object)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv17_fifo_priv *priv = nv_engine(dev, engine);
int i;
struct nv04_fifo_priv *priv = (void *)object;
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_init(&priv->base);
if (ret)
return ret;
nv_wr32(dev, NV04_PFIFO_DELAY_0, 0x000000ff);
nv_wr32(dev, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff);
nv_wr32(priv, NV04_PFIFO_DELAY_0, 0x000000ff);
nv_wr32(priv, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff);
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);
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_PUSH1, priv->base.channels);
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
nv_wr32(dev, NV03_PFIFO_INTR_0, 0xffffffff);
nv_wr32(dev, NV03_PFIFO_INTR_EN_0, 0xffffffff);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, 1);
nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
nv_wr32(dev, NV03_PFIFO_CACHES, 1);
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,
},
};
+268 -130
View File
@@ -1,43 +1,42 @@
/*
* 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;
} nv40_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
nv40_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 },
@@ -63,148 +62,287 @@ static struct ramfc_desc {
{}
};
struct nv40_fifo_priv {
struct nouveau_fifo_priv base;
struct ramfc_desc *ramfc_desc;
struct nouveau_gpuobj *ramro;
struct nouveau_gpuobj *ramfc;
};
struct nv40_fifo_chan {
struct nouveau_fifo_chan base;
u32 ramfc;
};
/*******************************************************************************
* FIFO channel objects
******************************************************************************/
static int
nv40_fifo_context_new(struct nouveau_channel *chan, int engine)
nv40_fifo_object_attach(struct nouveau_object *parent,
struct nouveau_object *object, u32 handle)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv40_fifo_priv *priv = nv_engine(dev, engine);
struct nv40_fifo_chan *fctx;
unsigned long flags;
struct nv04_fifo_priv *priv = (void *)parent->engine;
struct nv04_fifo_chan *chan = (void *)parent;
u32 context, chid = chan->base.chid;
int ret;
fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL);
if (!fctx)
return -ENOMEM;
if (nv_iclass(object, NV_GPUOBJ_CLASS))
context = nv_gpuobj(object)->addr >> 4;
else
context = 0x00000004; /* just non-zero */
fctx->ramfc = chan->id * 128;
/* 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;
switch (nv_engidx(object->engine)) {
case NVDEV_ENGINE_DMAOBJ:
case NVDEV_ENGINE_SW:
context |= 0x00000000;
break;
case NVDEV_ENGINE_GR:
context |= 0x00100000;
break;
case NVDEV_ENGINE_MPEG:
context |= 0x00200000;
break;
default:
return -EINVAL;
}
/* 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 + 0x18, 0x30000000 |
context |= chid << 23;
mutex_lock(&nv_subdev(priv)->mutex);
ret = nouveau_ramht_insert(priv->ramht, chid, handle, context);
mutex_unlock(&nv_subdev(priv)->mutex);
return ret;
}
static int
nv40_fifo_context_attach(struct nouveau_object *parent,
struct nouveau_object *engctx)
{
struct nv04_fifo_priv *priv = (void *)parent->engine;
struct nv04_fifo_chan *chan = (void *)parent;
unsigned long flags;
u32 reg, ctx;
switch (nv_engidx(engctx->engine)) {
case NVDEV_ENGINE_SW:
return 0;
case NVDEV_ENGINE_GR:
reg = 0x32e0;
ctx = 0x38;
break;
case NVDEV_ENGINE_MPEG:
reg = 0x330c;
ctx = 0x54;
break;
default:
return -EINVAL;
}
spin_lock_irqsave(&priv->base.lock, flags);
nv_mask(priv, 0x002500, 0x00000001, 0x00000000);
if ((nv_rd32(priv, 0x003204) & priv->base.max) == chan->base.chid)
nv_wr32(priv, reg, nv_gpuobj(engctx)->addr >> 4);
nv_wo32(priv->ramfc, chan->ramfc + ctx, nv_gpuobj(engctx)->addr >> 4);
nv_mask(priv, 0x002500, 0x00000001, 0x00000001);
spin_unlock_irqrestore(&priv->base.lock, flags);
return 0;
}
static int
nv40_fifo_context_detach(struct nouveau_object *parent, bool suspend,
struct nouveau_object *engctx)
{
struct nv04_fifo_priv *priv = (void *)parent->engine;
struct nv04_fifo_chan *chan = (void *)parent;
unsigned long flags;
u32 reg, ctx;
switch (nv_engidx(engctx->engine)) {
case NVDEV_ENGINE_SW:
return 0;
case NVDEV_ENGINE_GR:
reg = 0x32e0;
ctx = 0x38;
break;
case NVDEV_ENGINE_MPEG:
reg = 0x330c;
ctx = 0x54;
break;
default:
return -EINVAL;
}
spin_lock_irqsave(&priv->base.lock, flags);
nv_mask(priv, 0x002500, 0x00000001, 0x00000000);
if ((nv_rd32(priv, 0x003204) & priv->base.max) == chan->base.chid)
nv_wr32(priv, reg, 0x00000000);
nv_wo32(priv->ramfc, chan->ramfc + ctx, 0x00000000);
nv_mask(priv, 0x002500, 0x00000001, 0x00000001);
spin_unlock_irqrestore(&priv->base.lock, flags);
return 0;
}
static int
nv40_fifo_chan_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv04_fifo_priv *priv = (void *)engine;
struct nv04_fifo_chan *chan;
struct nv_channel_dma_class *args = data;
int ret;
if (size < sizeof(*args))
return -EINVAL;
ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
0x1000, args->pushbuf,
(1 << NVDEV_ENGINE_DMAOBJ) |
(1 << NVDEV_ENGINE_SW) |
(1 << NVDEV_ENGINE_GR) |
(1 << NVDEV_ENGINE_MPEG), &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
nv_parent(chan)->context_attach = nv40_fifo_context_attach;
nv_parent(chan)->context_detach = nv40_fifo_context_detach;
nv_parent(chan)->object_attach = nv40_fifo_object_attach;
nv_parent(chan)->object_detach = nv04_fifo_object_detach;
chan->ramfc = chan->base.chid * 128;
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 + 0x18, 0x30000000 |
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);
nv_wo32(priv->ramfc, fctx->ramfc + 0x3c, 0x0001ffff);
nv_wo32(priv->ramfc, chan->ramfc + 0x3c, 0x0001ffff);
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
nv40_fifo_ofuncs = {
.ctor = nv40_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,
};
/*XXX: remove this later, need fifo engine context commit hook */
nouveau_gpuobj_ref(priv->ramfc, &chan->ramfc);
static struct nouveau_oclass
nv40_fifo_sclass[] = {
{ 0x006e, &nv40_fifo_ofuncs },
{}
};
error:
/*******************************************************************************
* FIFO context - basically just the instmem reserved for the channel
******************************************************************************/
static struct nouveau_oclass
nv40_fifo_cclass = {
.handle = NV_ENGCTX(FIFO, 0x40),
.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
nv40_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv04_instmem_priv *imem = nv04_instmem(parent);
struct nv04_fifo_priv *priv;
int ret;
ret = nouveau_fifo_create(parent, engine, oclass, 0, 31, &priv);
*pobject = nv_object(priv);
if (ret)
priv->base.base.context_del(chan, engine);
return 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 = &nv40_fifo_cclass;
nv_engine(priv)->sclass = nv40_fifo_sclass;
priv->base.pause = nv04_fifo_pause;
priv->base.start = nv04_fifo_start;
priv->ramfc_desc = nv40_ramfc;
return 0;
}
static int
nv40_fifo_init(struct drm_device *dev, int engine)
nv40_fifo_init(struct nouveau_object *object)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv40_fifo_priv *priv = nv_engine(dev, engine);
int i;
struct nv04_fifo_priv *priv = (void *)object;
struct nouveau_fb *pfb = nouveau_fb(object);
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_init(&priv->base);
if (ret)
return ret;
nv_wr32(dev, 0x002040, 0x000000ff);
nv_wr32(dev, 0x002044, 0x2101ffff);
nv_wr32(dev, 0x002058, 0x00000001);
nv_wr32(priv, 0x002040, 0x000000ff);
nv_wr32(priv, 0x002044, 0x2101ffff);
nv_wr32(priv, 0x002058, 0x00000001);
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(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);
switch (dev_priv->chipset) {
switch (nv_device(priv)->chipset) {
case 0x47:
case 0x49:
case 0x4b:
nv_wr32(dev, 0x002230, 0x00000001);
nv_wr32(priv, 0x002230, 0x00000001);
case 0x40:
case 0x41:
case 0x42:
case 0x43:
case 0x45:
case 0x48:
nv_wr32(dev, 0x002220, 0x00030002);
nv_wr32(priv, 0x002220, 0x00030002);
break;
default:
nv_wr32(dev, 0x002230, 0x00000000);
nv_wr32(dev, 0x002220, ((nvfb_vram_size(dev) - 512 * 1024 +
nv_wr32(priv, 0x002230, 0x00000000);
nv_wr32(priv, 0x002220, ((pfb->ram.size - 512 * 1024 +
priv->ramfc->addr) >> 16) |
0x00030000);
0x00030000);
break;
}
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, priv->base.channels);
nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
nv_wr32(dev, NV03_PFIFO_INTR_0, 0xffffffff);
nv_wr32(dev, NV03_PFIFO_INTR_EN_0, 0xffffffff);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, 1);
nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
nv_wr32(dev, NV03_PFIFO_CACHES, 1);
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
nv40_fifo_create(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv40_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 = nv40_fifo_init;
priv->base.base.fini = nv04_fifo_fini;
priv->base.base.context_new = nv40_fifo_context_new;
priv->base.base.context_del = nv04_fifo_context_del;
priv->base.channels = 31;
priv->ramfc_desc = nv40_ramfc;
dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base;
nouveau_irq_register(dev, 8, nv04_fifo_isr);
return 0;
}
struct nouveau_oclass
nv40_fifo_oclass = {
.handle = NV_ENGINE(FIFO, 0x40),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv40_fifo_ctor,
.dtor = nv04_fifo_dtor,
.init = nv40_fifo_init,
.fini = _nouveau_fifo_fini,
},
};
+349 -203
View File
@@ -1,126 +1,123 @@
/*
* 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 <core/client.h>
#include <core/engctx.h>
#include <core/ramht.h>
#include <core/class.h>
#include <core/math.h>
struct nv50_fifo_priv {
struct nouveau_fifo_priv base;
struct nouveau_gpuobj *playlist[2];
int cur_playlist;
};
#include <subdev/timer.h>
#include <subdev/bar.h>
struct nv50_fifo_chan {
struct nouveau_fifo_chan base;
};
#include <engine/dmaobj.h>
#include <engine/fifo.h>
#include "nv50.h"
/*******************************************************************************
* FIFO channel objects
******************************************************************************/
void
nv50_fifo_playlist_update(struct drm_device *dev)
nv50_fifo_playlist_update(struct nv50_fifo_priv *priv)
{
struct nv50_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO);
struct nouveau_bar *bar = nouveau_bar(priv);
struct nouveau_gpuobj *cur;
int i, p;
cur = priv->playlist[priv->cur_playlist];
priv->cur_playlist = !priv->cur_playlist;
for (i = 0, p = 0; i < priv->base.channels; i++) {
if (nv_rd32(dev, 0x002600 + (i * 4)) & 0x80000000)
for (i = priv->base.min, p = 0; i < priv->base.max; i++) {
if (nv_rd32(priv, 0x002600 + (i * 4)) & 0x80000000)
nv_wo32(cur, p++ * 4, i);
}
nvimem_flush(dev);
bar->flush(bar);
nv_wr32(dev, 0x0032f4, cur->addr >> 12);
nv_wr32(dev, 0x0032ec, p);
nv_wr32(dev, 0x002500, 0x00000101);
nv_wr32(priv, 0x0032f4, cur->addr >> 12);
nv_wr32(priv, 0x0032ec, p);
nv_wr32(priv, 0x002500, 0x00000101);
}
static int
nv50_fifo_context_new(struct nouveau_channel *chan, int engine)
nv50_fifo_context_attach(struct nouveau_object *parent,
struct nouveau_object *object)
{
struct nv50_fifo_priv *priv = nv_engine(chan->dev, engine);
struct nv50_fifo_chan *fctx;
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
u64 ib_offset = chan->pushbuf_base + chan->dma.ib_base * 4;
u64 instance = chan->ramin->addr >> 12;
unsigned long flags;
int ret = 0, i;
struct nouveau_bar *bar = nouveau_bar(parent);
struct nv50_fifo_base *base = (void *)parent->parent;
struct nouveau_gpuobj *ectx = (void *)object;
u64 limit = ectx->addr + ectx->size - 1;
u64 start = ectx->addr;
u32 addr;
fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL);
if (!fctx)
return -ENOMEM;
nvvm_engref(chan->vm, engine, 1);
chan->user = ioremap(pci_resource_start(dev->pdev, 0) +
NV50_USER(chan->id), PAGE_SIZE);
if (!chan->user) {
ret = -ENOMEM;
goto error;
switch (nv_engidx(object->engine)) {
case NVDEV_ENGINE_SW : return 0;
case NVDEV_ENGINE_GR : addr = 0x0000; break;
case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
default:
return -EINVAL;
}
for (i = 0; i < 0x100; i += 4)
nv_wo32(chan->ramin, i, 0x00000000);
nv_wo32(chan->ramin, 0x3c, 0x403f6078);
nv_wo32(chan->ramin, 0x40, 0x00000000);
nv_wo32(chan->ramin, 0x44, 0x01003fff);
nv_wo32(chan->ramin, 0x48, chan->pushbuf->node->offset >> 4);
nv_wo32(chan->ramin, 0x50, lower_32_bits(ib_offset));
nv_wo32(chan->ramin, 0x54, upper_32_bits(ib_offset) |
drm_order(chan->dma.ib_max + 1) << 16);
nv_wo32(chan->ramin, 0x60, 0x7fffffff);
nv_wo32(chan->ramin, 0x78, 0x00000000);
nv_wo32(chan->ramin, 0x7c, 0x30000001);
nv_wo32(chan->ramin, 0x80, ((chan->ramht->bits - 9) << 27) |
(4 << 24) /* SEARCH_FULL */ |
(chan->ramht->gpuobj->node->offset >> 4));
nvimem_flush(dev);
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
nv_wr32(dev, 0x002600 + (chan->id * 4), 0x80000000 | instance);
nv50_fifo_playlist_update(dev);
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
error:
if (ret)
priv->base.base.context_del(chan, engine);
return ret;
nv_wo32(base->eng, addr + 0x00, 0x00190000);
nv_wo32(base->eng, addr + 0x04, lower_32_bits(limit));
nv_wo32(base->eng, addr + 0x08, lower_32_bits(start));
nv_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 |
upper_32_bits(start));
nv_wo32(base->eng, addr + 0x10, 0x00000000);
nv_wo32(base->eng, addr + 0x14, 0x00000000);
bar->flush(bar);
return 0;
}
static bool
nv50_fifo_kickoff(struct nouveau_channel *chan)
static int
nv50_fifo_context_detach(struct nouveau_object *parent, bool suspend,
struct nouveau_object *object)
{
struct drm_device *dev = chan->dev;
bool done = true;
u32 me;
struct nouveau_bar *bar = nouveau_bar(parent);
struct nv50_fifo_priv *priv = (void *)parent->engine;
struct nv50_fifo_base *base = (void *)parent->parent;
struct nv50_fifo_chan *chan = (void *)parent;
u32 addr, me;
int ret = 0;
switch (nv_engidx(object->engine)) {
case NVDEV_ENGINE_SW : return 0;
case NVDEV_ENGINE_GR : addr = 0x0000; break;
case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
default:
return -EINVAL;
}
nv_wo32(base->eng, addr + 0x00, 0x00000000);
nv_wo32(base->eng, addr + 0x04, 0x00000000);
nv_wo32(base->eng, addr + 0x08, 0x00000000);
nv_wo32(base->eng, addr + 0x0c, 0x00000000);
nv_wo32(base->eng, addr + 0x10, 0x00000000);
nv_wo32(base->eng, addr + 0x14, 0x00000000);
bar->flush(bar);
/* HW bug workaround:
*
@@ -134,159 +131,308 @@ nv50_fifo_kickoff(struct nouveau_channel *chan)
* there's also a "ignore these engines" bitmask reg we can use
* if we hit the issue there..
*/
/* PME: make sure engine is enabled */
me = nv_mask(dev, 0x00b860, 0x00000001, 0x00000001);
me = nv_mask(priv, 0x00b860, 0x00000001, 0x00000001);
/* do the kickoff... */
nv_wr32(dev, 0x0032fc, chan->ramin->addr >> 12);
if (!nv_wait_ne(dev, 0x0032fc, 0xffffffff, 0xffffffff)) {
NV_INFO(dev, "PFIFO: channel %d unload timeout\n", chan->id);
done = false;
nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12);
if (!nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff)) {
nv_error(priv, "channel %d unload timeout\n", chan->base.chid);
if (suspend)
ret = -EBUSY;
}
/* restore any engine states we changed, and exit */
nv_wr32(dev, 0x00b860, me);
return done;
}
static void
nv50_fifo_context_del(struct nouveau_channel *chan, int engine)
{
struct nv50_fifo_chan *fctx = chan->engctx[engine];
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
unsigned long flags;
/* remove channel from playlist, will context switch if active */
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
nv_mask(dev, 0x002600 + (chan->id * 4), 0x80000000, 0x00000000);
nv50_fifo_playlist_update(dev);
/* tell any engines on this channel to unload their contexts */
nv50_fifo_kickoff(chan);
nv_wr32(dev, 0x002600 + (chan->id * 4), 0x00000000);
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
/* clean up */
if (chan->user) {
iounmap(chan->user);
chan->user = NULL;
}
nvvm_engref(chan->vm, engine, -1);
chan->engctx[engine] = NULL;
kfree(fctx);
nv_wr32(priv, 0x00b860, me);
return ret;
}
static int
nv50_fifo_init(struct drm_device *dev, int engine)
nv50_fifo_object_attach(struct nouveau_object *parent,
struct nouveau_object *object, u32 handle)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
u32 instance;
int i;
struct nv50_fifo_chan *chan = (void *)parent;
u32 context;
nv_mask(dev, 0x000200, 0x00000100, 0x00000000);
nv_mask(dev, 0x000200, 0x00000100, 0x00000100);
nv_wr32(dev, 0x00250c, 0x6f3cfc34);
nv_wr32(dev, 0x002044, 0x01003fff);
if (nv_iclass(object, NV_GPUOBJ_CLASS))
context = nv_gpuobj(object)->node->offset >> 4;
else
context = 0x00000004; /* just non-zero */
nv_wr32(dev, 0x002100, 0xffffffff);
nv_wr32(dev, 0x002140, 0xffffffff);
for (i = 0; i < 128; i++) {
struct nouveau_channel *chan = dev_priv->channels.ptr[i];
if (chan && chan->engctx[engine])
instance = 0x80000000 | chan->ramin->addr >> 12;
else
instance = 0x00000000;
nv_wr32(dev, 0x002600 + (i * 4), instance);
switch (nv_engidx(object->engine)) {
case NVDEV_ENGINE_DMAOBJ:
case NVDEV_ENGINE_SW : context |= 0x00000000; break;
case NVDEV_ENGINE_GR : context |= 0x00100000; break;
case NVDEV_ENGINE_MPEG : context |= 0x00200000; break;
default:
return -EINVAL;
}
nv50_fifo_playlist_update(dev);
return nouveau_ramht_insert(chan->ramht, 0, handle, context);
}
nv_wr32(dev, 0x003200, 1);
nv_wr32(dev, 0x003250, 1);
nv_wr32(dev, 0x002500, 1);
return 0;
void
nv50_fifo_object_detach(struct nouveau_object *parent, int cookie)
{
struct nv50_fifo_chan *chan = (void *)parent;
nouveau_ramht_remove(chan->ramht, cookie);
}
static int
nv50_fifo_fini(struct drm_device *dev, int engine, bool suspend)
nv50_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_nouveau_private *dev_priv = dev->dev_private;
struct nv50_fifo_priv *priv = nv_engine(dev, engine);
int i;
struct nv_channel_ind_class *args = data;
struct nouveau_bar *bar = nouveau_bar(parent);
struct nv50_fifo_base *base = (void *)parent;
struct nv50_fifo_chan *chan;
u64 ioffset, ilength;
int ret;
/* set playlist length to zero, fifo will unload context */
nv_wr32(dev, 0x0032ec, 0);
if (size < sizeof(*args))
return -EINVAL;
/* tell all connected engines to unload their contexts */
for (i = 0; i < priv->base.channels; i++) {
struct nouveau_channel *chan = dev_priv->channels.ptr[i];
if (chan && !nv50_fifo_kickoff(chan))
return -EBUSY;
}
ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
0x2000, args->pushbuf,
(1 << NVDEV_ENGINE_DMAOBJ) |
(1 << NVDEV_ENGINE_SW) |
(1 << NVDEV_ENGINE_GR) |
(1 << NVDEV_ENGINE_MPEG), &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
nv_wr32(dev, 0x002140, 0);
nv_parent(chan)->context_attach = nv50_fifo_context_attach;
nv_parent(chan)->context_detach = nv50_fifo_context_detach;
nv_parent(chan)->object_attach = nv50_fifo_object_attach;
nv_parent(chan)->object_detach = nv50_fifo_object_detach;
ret = nouveau_ramht_new(parent, parent, 0x8000, 16, &chan->ramht);
if (ret)
return ret;
ioffset = args->ioffset;
ilength = log2i(args->ilength / 8);
nv_wo32(base->ramfc, 0x3c, 0x403f6078);
nv_wo32(base->ramfc, 0x44, 0x01003fff);
nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
nv_wo32(base->ramfc, 0x50, lower_32_bits(ioffset));
nv_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16));
nv_wo32(base->ramfc, 0x60, 0x7fffffff);
nv_wo32(base->ramfc, 0x78, 0x00000000);
nv_wo32(base->ramfc, 0x7c, 0x30000001);
nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
(4 << 24) /* SEARCH_FULL */ |
(chan->ramht->base.node->offset >> 4));
bar->flush(bar);
return 0;
}
void
nv50_fifo_tlb_flush(struct drm_device *dev, int engine)
nv50_fifo_chan_dtor(struct nouveau_object *object)
{
nv50_vm_flush_engine(dev, 5);
struct nv50_fifo_chan *chan = (void *)object;
nouveau_ramht_ref(NULL, &chan->ramht);
nouveau_fifo_channel_destroy(&chan->base);
}
void
nv50_fifo_destroy(struct drm_device *dev, int engine)
static int
nv50_fifo_chan_init(struct nouveau_object *object)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv50_fifo_priv *priv = nv_engine(dev, engine);
struct nv50_fifo_priv *priv = (void *)object->engine;
struct nv50_fifo_base *base = (void *)object->parent;
struct nv50_fifo_chan *chan = (void *)object;
struct nouveau_gpuobj *ramfc = base->ramfc;
u32 chid = chan->base.chid;
int ret;
nouveau_irq_unregister(dev, 8);
ret = nouveau_fifo_channel_init(&chan->base);
if (ret)
return ret;
nouveau_gpuobj_ref(NULL, &priv->playlist[0]);
nouveau_gpuobj_ref(NULL, &priv->playlist[1]);
dev_priv->eng[engine] = NULL;
kfree(priv);
nv_wr32(priv, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 12);
nv50_fifo_playlist_update(priv);
return 0;
}
int
nv50_fifo_create(struct drm_device *dev)
nv50_fifo_chan_fini(struct nouveau_object *object, bool suspend)
{
struct nv50_fifo_priv *priv = (void *)object->engine;
struct nv50_fifo_chan *chan = (void *)object;
u32 chid = chan->base.chid;
/* remove channel from playlist, fifo will unload context */
nv_mask(priv, 0x002600 + (chid * 4), 0x80000000, 0x00000000);
nv50_fifo_playlist_update(priv);
nv_wr32(priv, 0x002600 + (chid * 4), 0x00000000);
return nouveau_fifo_channel_fini(&chan->base, suspend);
}
static struct nouveau_ofuncs
nv50_fifo_ofuncs = {
.ctor = nv50_fifo_chan_ctor,
.dtor = nv50_fifo_chan_dtor,
.init = nv50_fifo_chan_init,
.fini = nv50_fifo_chan_fini,
.rd32 = _nouveau_fifo_channel_rd32,
.wr32 = _nouveau_fifo_channel_wr32,
};
static struct nouveau_oclass
nv50_fifo_sclass[] = {
{ 0x506f, &nv50_fifo_ofuncs },
{}
};
/*******************************************************************************
* FIFO context - basically just the instmem reserved for the channel
******************************************************************************/
static int
nv50_fifo_context_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv50_fifo_base *base;
int ret;
ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x10000,
0x1000, NVOBJ_FLAG_HEAP, &base);
*pobject = nv_object(base);
if (ret)
return ret;
ret = nouveau_gpuobj_new(parent, nv_object(base), 0x0200, 0x1000,
NVOBJ_FLAG_ZERO_ALLOC, &base->ramfc);
if (ret)
return ret;
ret = nouveau_gpuobj_new(parent, nv_object(base), 0x1200, 0,
NVOBJ_FLAG_ZERO_ALLOC, &base->eng);
if (ret)
return ret;
ret = nouveau_gpuobj_new(parent, nv_object(base), 0x4000, 0, 0,
&base->pgd);
if (ret)
return ret;
ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd);
if (ret)
return ret;
return 0;
}
void
nv50_fifo_context_dtor(struct nouveau_object *object)
{
struct nv50_fifo_base *base = (void *)object;
nouveau_vm_ref(NULL, &base->vm, base->pgd);
nouveau_gpuobj_ref(NULL, &base->pgd);
nouveau_gpuobj_ref(NULL, &base->eng);
nouveau_gpuobj_ref(NULL, &base->ramfc);
nouveau_gpuobj_ref(NULL, &base->cache);
nouveau_fifo_context_destroy(&base->base);
}
static struct nouveau_oclass
nv50_fifo_cclass = {
.handle = NV_ENGCTX(FIFO, 0x50),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv50_fifo_context_ctor,
.dtor = nv50_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
nv50_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 nv50_fifo_priv *priv;
int ret;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->base.base.destroy = nv50_fifo_destroy;
priv->base.base.init = nv50_fifo_init;
priv->base.base.fini = nv50_fifo_fini;
priv->base.base.context_new = nv50_fifo_context_new;
priv->base.base.context_del = nv50_fifo_context_del;
priv->base.base.tlb_flush = nv50_fifo_tlb_flush;
priv->base.channels = 127;
dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base;
ret = nouveau_gpuobj_new(dev, NULL, priv->base.channels * 4, 0x1000,
NVOBJ_FLAG_ZERO_ALLOC, &priv->playlist[0]);
ret = nouveau_fifo_create(parent, engine, oclass, 1, 127, &priv);
*pobject = nv_object(priv);
if (ret)
goto error;
return ret;
ret = nouveau_gpuobj_new(dev, NULL, priv->base.channels * 4, 0x1000,
NVOBJ_FLAG_ZERO_ALLOC, &priv->playlist[1]);
ret = nouveau_gpuobj_new(parent, NULL, 128 * 4, 0x1000, 0,
&priv->playlist[0]);
if (ret)
goto error;
return ret;
nouveau_irq_register(dev, 8, nv04_fifo_isr);
error:
ret = nouveau_gpuobj_new(parent, NULL, 128 * 4, 0x1000, 0,
&priv->playlist[1]);
if (ret)
priv->base.base.destroy(dev, NVOBJ_ENGINE_FIFO);
return ret;
return ret;
nv_subdev(priv)->unit = 0x00000100;
nv_subdev(priv)->intr = nv04_fifo_intr;
nv_engine(priv)->cclass = &nv50_fifo_cclass;
nv_engine(priv)->sclass = nv50_fifo_sclass;
return 0;
}
void
nv50_fifo_dtor(struct nouveau_object *object)
{
struct nv50_fifo_priv *priv = (void *)object;
nouveau_gpuobj_ref(NULL, &priv->playlist[1]);
nouveau_gpuobj_ref(NULL, &priv->playlist[0]);
nouveau_fifo_destroy(&priv->base);
}
int
nv50_fifo_init(struct nouveau_object *object)
{
struct nv50_fifo_priv *priv = (void *)object;
int ret, i;
ret = nouveau_fifo_init(&priv->base);
if (ret)
return ret;
nv_mask(priv, 0x000200, 0x00000100, 0x00000000);
nv_mask(priv, 0x000200, 0x00000100, 0x00000100);
nv_wr32(priv, 0x00250c, 0x6f3cfc34);
nv_wr32(priv, 0x002044, 0x01003fff);
nv_wr32(priv, 0x002100, 0xffffffff);
nv_wr32(priv, 0x002140, 0xffffffff);
for (i = 0; i < 128; i++)
nv_wr32(priv, 0x002600 + (i * 4), 0x00000000);
nv50_fifo_playlist_update(priv);
nv_wr32(priv, 0x003200, 0x00000001);
nv_wr32(priv, 0x003250, 0x00000001);
nv_wr32(priv, 0x002500, 0x00000001);
return 0;
}
struct nouveau_oclass
nv50_fifo_oclass = {
.handle = NV_ENGINE(FIFO, 0x50),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv50_fifo_ctor,
.dtor = nv50_fifo_dtor,
.init = nv50_fifo_init,
.fini = _nouveau_fifo_fini,
},
};
@@ -0,0 +1,36 @@
#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
+302 -208
View File
@@ -1,249 +1,343 @@
/*
* 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 <core/os.h>
#include <core/client.h>
#include <core/engctx.h>
#include <core/ramht.h>
#include <core/class.h>
#include <core/math.h>
struct nv84_fifo_priv {
struct nouveau_fifo_priv base;
struct nouveau_gpuobj *playlist[2];
int cur_playlist;
};
#include <subdev/timer.h>
#include <subdev/bar.h>
struct nv84_fifo_chan {
struct nouveau_fifo_chan base;
struct nouveau_gpuobj *ramfc;
struct nouveau_gpuobj *cache;
};
#include <engine/dmaobj.h>
#include <engine/fifo.h>
#include "nv50.h"
/*******************************************************************************
* FIFO channel objects
******************************************************************************/
static int
nv84_fifo_context_new(struct nouveau_channel *chan, int engine)
nv84_fifo_context_attach(struct nouveau_object *parent,
struct nouveau_object *object)
{
struct nv84_fifo_priv *priv = nv_engine(chan->dev, engine);
struct nv84_fifo_chan *fctx;
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
u64 ib_offset = chan->pushbuf_base + chan->dma.ib_base * 4;
u64 instance;
unsigned long flags;
struct nouveau_bar *bar = nouveau_bar(parent);
struct nv50_fifo_base *base = (void *)parent->parent;
struct nouveau_gpuobj *ectx = (void *)object;
u64 limit = ectx->addr + ectx->size - 1;
u64 start = ectx->addr;
u32 addr;
switch (nv_engidx(object->engine)) {
case NVDEV_ENGINE_SW : return 0;
case NVDEV_ENGINE_GR : addr = 0x0020; break;
case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
case NVDEV_ENGINE_CRYPT: addr = 0x00a0; break;
case NVDEV_ENGINE_COPY0: addr = 0x00c0; break;
default:
return -EINVAL;
}
nv_wo32(base->eng, addr + 0x00, 0x00190000);
nv_wo32(base->eng, addr + 0x04, lower_32_bits(limit));
nv_wo32(base->eng, addr + 0x08, lower_32_bits(start));
nv_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 |
upper_32_bits(start));
nv_wo32(base->eng, addr + 0x10, 0x00000000);
nv_wo32(base->eng, addr + 0x14, 0x00000000);
bar->flush(bar);
return 0;
}
static int
nv84_fifo_context_detach(struct nouveau_object *parent, bool suspend,
struct nouveau_object *object)
{
struct nouveau_bar *bar = nouveau_bar(parent);
struct nv50_fifo_priv *priv = (void *)parent->engine;
struct nv50_fifo_base *base = (void *)parent->parent;
struct nv50_fifo_chan *chan = (void *)parent;
u32 addr;
switch (nv_engidx(object->engine)) {
case NVDEV_ENGINE_SW : return 0;
case NVDEV_ENGINE_GR : addr = 0x0020; break;
case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
case NVDEV_ENGINE_CRYPT: addr = 0x00a0; break;
case NVDEV_ENGINE_COPY0: addr = 0x00c0; break;
default:
return -EINVAL;
}
nv_wo32(base->eng, addr + 0x00, 0x00000000);
nv_wo32(base->eng, addr + 0x04, 0x00000000);
nv_wo32(base->eng, addr + 0x08, 0x00000000);
nv_wo32(base->eng, addr + 0x0c, 0x00000000);
nv_wo32(base->eng, addr + 0x10, 0x00000000);
nv_wo32(base->eng, addr + 0x14, 0x00000000);
bar->flush(bar);
nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12);
if (!nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff)) {
nv_error(priv, "channel %d unload timeout\n", chan->base.chid);
if (suspend)
return -EBUSY;
}
return 0;
}
static int
nv84_fifo_object_attach(struct nouveau_object *parent,
struct nouveau_object *object, u32 handle)
{
struct nv50_fifo_chan *chan = (void *)parent;
u32 context;
if (nv_iclass(object, NV_GPUOBJ_CLASS))
context = nv_gpuobj(object)->node->offset >> 4;
else
context = 0x00000004; /* just non-zero */
switch (nv_engidx(object->engine)) {
case NVDEV_ENGINE_DMAOBJ:
case NVDEV_ENGINE_SW : context |= 0x00000000; break;
case NVDEV_ENGINE_GR : context |= 0x00100000; break;
case NVDEV_ENGINE_MPEG :
case NVDEV_ENGINE_PPP : context |= 0x00200000; break;
case NVDEV_ENGINE_ME :
case NVDEV_ENGINE_COPY0 : context |= 0x00300000; break;
case NVDEV_ENGINE_VP : context |= 0x00400000; break;
case NVDEV_ENGINE_CRYPT :
case NVDEV_ENGINE_UNK1C1: context |= 0x00500000; break;
case NVDEV_ENGINE_BSP : context |= 0x00600000; break;
default:
return -EINVAL;
}
return nouveau_ramht_insert(chan->ramht, 0, handle, context);
}
static int
nv84_fifo_chan_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_bar *bar = nouveau_bar(parent);
struct nv50_fifo_base *base = (void *)parent;
struct nv50_fifo_chan *chan;
struct nv_channel_ind_class *args = data;
u64 ioffset, ilength;
int ret;
fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL);
if (!fctx)
return -ENOMEM;
nvvm_engref(chan->vm, engine, 1);
if (size < sizeof(*args))
return -EINVAL;
chan->user = ioremap(pci_resource_start(dev->pdev, 0) +
NV50_USER(chan->id), PAGE_SIZE);
if (!chan->user) {
ret = -ENOMEM;
goto error;
}
ret = nouveau_gpuobj_new(dev, chan, 256, 256, NVOBJ_FLAG_ZERO_ALLOC |
NVOBJ_FLAG_ZERO_FREE, &fctx->ramfc);
ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
0x2000, args->pushbuf,
(1 << NVDEV_ENGINE_DMAOBJ) |
(1 << NVDEV_ENGINE_SW) |
(1 << NVDEV_ENGINE_GR) |
(1 << NVDEV_ENGINE_MPEG) |
(1 << NVDEV_ENGINE_ME) |
(1 << NVDEV_ENGINE_VP) |
(1 << NVDEV_ENGINE_CRYPT) |
(1 << NVDEV_ENGINE_BSP) |
(1 << NVDEV_ENGINE_PPP) |
(1 << NVDEV_ENGINE_COPY0) |
(1 << NVDEV_ENGINE_UNK1C1), &chan);
*pobject = nv_object(chan);
if (ret)
goto error;
return ret;
instance = fctx->ramfc->addr >> 8;
ret = nouveau_gpuobj_new(dev, chan, 4096, 1024, 0, &fctx->cache);
ret = nouveau_ramht_new(parent, parent, 0x8000, 16, &chan->ramht);
if (ret)
goto error;
return ret;
nv_wo32(fctx->ramfc, 0x3c, 0x403f6078);
nv_wo32(fctx->ramfc, 0x40, 0x00000000);
nv_wo32(fctx->ramfc, 0x44, 0x01003fff);
nv_wo32(fctx->ramfc, 0x48, chan->pushbuf->node->offset >> 4);
nv_wo32(fctx->ramfc, 0x50, lower_32_bits(ib_offset));
nv_wo32(fctx->ramfc, 0x54, upper_32_bits(ib_offset) |
drm_order(chan->dma.ib_max + 1) << 16);
nv_wo32(fctx->ramfc, 0x60, 0x7fffffff);
nv_wo32(fctx->ramfc, 0x78, 0x00000000);
nv_wo32(fctx->ramfc, 0x7c, 0x30000001);
nv_wo32(fctx->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
nv_parent(chan)->context_attach = nv84_fifo_context_attach;
nv_parent(chan)->context_detach = nv84_fifo_context_detach;
nv_parent(chan)->object_attach = nv84_fifo_object_attach;
nv_parent(chan)->object_detach = nv50_fifo_object_detach;
ioffset = args->ioffset;
ilength = log2i(args->ilength / 8);
nv_wo32(base->ramfc, 0x3c, 0x403f6078);
nv_wo32(base->ramfc, 0x44, 0x01003fff);
nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
nv_wo32(base->ramfc, 0x50, lower_32_bits(ioffset));
nv_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16));
nv_wo32(base->ramfc, 0x60, 0x7fffffff);
nv_wo32(base->ramfc, 0x78, 0x00000000);
nv_wo32(base->ramfc, 0x7c, 0x30000001);
nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
(4 << 24) /* SEARCH_FULL */ |
(chan->ramht->gpuobj->node->offset >> 4));
nv_wo32(fctx->ramfc, 0x88, fctx->cache->addr >> 10);
nv_wo32(fctx->ramfc, 0x98, chan->ramin->addr >> 12);
(chan->ramht->base.node->offset >> 4));
nv_wo32(base->ramfc, 0x88, base->cache->addr >> 10);
nv_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12);
bar->flush(bar);
return 0;
}
nv_wo32(chan->ramin, 0x00, chan->id);
nv_wo32(chan->ramin, 0x04, fctx->ramfc->addr >> 8);
static int
nv84_fifo_chan_init(struct nouveau_object *object)
{
struct nv50_fifo_priv *priv = (void *)object->engine;
struct nv50_fifo_base *base = (void *)object->parent;
struct nv50_fifo_chan *chan = (void *)object;
struct nouveau_gpuobj *ramfc = base->ramfc;
u32 chid = chan->base.chid;
int ret;
nvimem_flush(dev);
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
nv_wr32(dev, 0x002600 + (chan->id * 4), 0x80000000 | instance);
nv50_fifo_playlist_update(dev);
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
error:
ret = nouveau_fifo_channel_init(&chan->base);
if (ret)
priv->base.base.context_del(chan, engine);
return ret;
}
return ret;
static void
nv84_fifo_context_del(struct nouveau_channel *chan, int engine)
{
struct nv84_fifo_chan *fctx = chan->engctx[engine];
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
unsigned long flags;
u32 save;
/* remove channel from playlist, will context switch if active */
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
nv_mask(dev, 0x002600 + (chan->id * 4), 0x80000000, 0x00000000);
nv50_fifo_playlist_update(dev);
save = nv_mask(dev, 0x002520, 0x0000003f, 0x15);
/* tell any engines on this channel to unload their contexts */
nv_wr32(dev, 0x0032fc, chan->ramin->addr >> 12);
if (!nv_wait_ne(dev, 0x0032fc, 0xffffffff, 0xffffffff))
NV_INFO(dev, "PFIFO: channel %d unload timeout\n", chan->id);
nv_wr32(dev, 0x002520, save);
nv_wr32(dev, 0x002600 + (chan->id * 4), 0x00000000);
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
/* clean up */
if (chan->user) {
iounmap(chan->user);
chan->user = NULL;
}
nouveau_gpuobj_ref(NULL, &fctx->ramfc);
nouveau_gpuobj_ref(NULL, &fctx->cache);
nvvm_engref(chan->vm, engine, -1);
chan->engctx[engine] = NULL;
kfree(fctx);
}
static int
nv84_fifo_init(struct drm_device *dev, int engine)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv84_fifo_chan *fctx;
u32 instance;
int i;
nv_mask(dev, 0x000200, 0x00000100, 0x00000000);
nv_mask(dev, 0x000200, 0x00000100, 0x00000100);
nv_wr32(dev, 0x00250c, 0x6f3cfc34);
nv_wr32(dev, 0x002044, 0x01003fff);
nv_wr32(dev, 0x002100, 0xffffffff);
nv_wr32(dev, 0x002140, 0xffffffff);
for (i = 0; i < 128; i++) {
struct nouveau_channel *chan = dev_priv->channels.ptr[i];
if (chan && (fctx = chan->engctx[engine]))
instance = 0x80000000 | fctx->ramfc->addr >> 8;
else
instance = 0x00000000;
nv_wr32(dev, 0x002600 + (i * 4), instance);
}
nv50_fifo_playlist_update(dev);
nv_wr32(dev, 0x003200, 1);
nv_wr32(dev, 0x003250, 1);
nv_wr32(dev, 0x002500, 1);
nv_wr32(priv, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 8);
nv50_fifo_playlist_update(priv);
return 0;
}
static int
nv84_fifo_fini(struct drm_device *dev, int engine, bool suspend)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv84_fifo_priv *priv = nv_engine(dev, engine);
int i;
u32 save;
static struct nouveau_ofuncs
nv84_fifo_ofuncs = {
.ctor = nv84_fifo_chan_ctor,
.dtor = nv50_fifo_chan_dtor,
.init = nv84_fifo_chan_init,
.fini = nv50_fifo_chan_fini,
.rd32 = _nouveau_fifo_channel_rd32,
.wr32 = _nouveau_fifo_channel_wr32,
};
/* set playlist length to zero, fifo will unload context */
nv_wr32(dev, 0x0032ec, 0);
static struct nouveau_oclass
nv84_fifo_sclass[] = {
{ 0x826f, &nv84_fifo_ofuncs },
{}
};
save = nv_mask(dev, 0x002520, 0x0000003f, 0x15);
/* tell all connected engines to unload their contexts */
for (i = 0; i < priv->base.channels; i++) {
struct nouveau_channel *chan = dev_priv->channels.ptr[i];
if (chan)
nv_wr32(dev, 0x0032fc, chan->ramin->addr >> 12);
if (!nv_wait_ne(dev, 0x0032fc, 0xffffffff, 0xffffffff)) {
NV_INFO(dev, "PFIFO: channel %d unload timeout\n", i);
return -EBUSY;
}
}
nv_wr32(dev, 0x002520, save);
nv_wr32(dev, 0x002140, 0);
return 0;
}
/*******************************************************************************
* FIFO context - basically just the instmem reserved for the channel
******************************************************************************/
int
nv84_fifo_create(struct drm_device *dev)
nv84_fifo_context_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 nv84_fifo_priv *priv;
struct nv50_fifo_base *base;
int ret;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->base.base.destroy = nv50_fifo_destroy;
priv->base.base.init = nv84_fifo_init;
priv->base.base.fini = nv84_fifo_fini;
priv->base.base.context_new = nv84_fifo_context_new;
priv->base.base.context_del = nv84_fifo_context_del;
priv->base.base.tlb_flush = nv50_fifo_tlb_flush;
priv->base.channels = 127;
dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base;
ret = nouveau_gpuobj_new(dev, NULL, priv->base.channels * 4, 0x1000,
NVOBJ_FLAG_ZERO_ALLOC, &priv->playlist[0]);
ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x10000,
0x1000, NVOBJ_FLAG_HEAP, &base);
*pobject = nv_object(base);
if (ret)
goto error;
return ret;
ret = nouveau_gpuobj_new(dev, NULL, priv->base.channels * 4, 0x1000,
NVOBJ_FLAG_ZERO_ALLOC, &priv->playlist[1]);
ret = nouveau_gpuobj_new(parent, nv_object(base), 0x0200, 0,
NVOBJ_FLAG_ZERO_ALLOC, &base->eng);
if (ret)
goto error;
return ret;
nouveau_irq_register(dev, 8, nv04_fifo_isr);
error:
ret = nouveau_gpuobj_new(parent, nv_object(base), 0x4000, 0,
0, &base->pgd);
if (ret)
priv->base.base.destroy(dev, NVOBJ_ENGINE_FIFO);
return ret;
return ret;
ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd);
if (ret)
return ret;
ret = nouveau_gpuobj_new(parent, nv_object(base), 0x1000, 0x400,
NVOBJ_FLAG_ZERO_ALLOC, &base->cache);
if (ret)
return ret;
ret = nouveau_gpuobj_new(parent, nv_object(base), 0x0100, 0x100,
NVOBJ_FLAG_ZERO_ALLOC, &base->ramfc);
if (ret)
return ret;
return 0;
}
static struct nouveau_oclass
nv84_fifo_cclass = {
.handle = NV_ENGCTX(FIFO, 0x84),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv84_fifo_context_ctor,
.dtor = nv50_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
nv84_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv50_fifo_priv *priv;
int ret;
ret = nouveau_fifo_create(parent, engine, oclass, 1, 127, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
ret = nouveau_gpuobj_new(parent, NULL, 128 * 4, 0x1000, 0,
&priv->playlist[0]);
if (ret)
return ret;
ret = nouveau_gpuobj_new(parent, NULL, 128 * 4, 0x1000, 0,
&priv->playlist[1]);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00000100;
nv_subdev(priv)->intr = nv04_fifo_intr;
nv_engine(priv)->cclass = &nv84_fifo_cclass;
nv_engine(priv)->sclass = nv84_fifo_sclass;
return 0;
}
struct nouveau_oclass
nv84_fifo_oclass = {
.handle = NV_ENGINE(FIFO, 0x84),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv84_fifo_ctor,
.dtor = nv50_fifo_dtor,
.init = nv50_fifo_init,
.fini = _nouveau_fifo_fini,
},
};
+404 -250
View File
@@ -1,5 +1,5 @@
/*
* 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,17 +22,24 @@
* Authors: Ben Skeggs
*/
#include "drmP.h"
#include <core/client.h>
#include <core/handle.h>
#include <core/namedb.h>
#include <core/gpuobj.h>
#include <core/engctx.h>
#include <core/class.h>
#include <core/math.h>
#include <core/enum.h>
#include "nouveau_drv.h"
#include <core/mm.h>
#include <subdev/timer.h>
#include <subdev/bar.h>
#include <subdev/vm.h>
#include <engine/dmaobj.h>
#include <engine/fifo.h>
#include "nouveau_software.h"
static void nvc0_fifo_isr(struct drm_device *);
struct nvc0_fifo_priv {
struct nouveau_fifo_priv base;
struct nouveau_fifo base;
struct nouveau_gpuobj *playlist[2];
int cur_playlist;
struct {
@@ -42,14 +49,24 @@ struct nvc0_fifo_priv {
int spoon_nr;
};
struct nvc0_fifo_base {
struct nouveau_fifo_base base;
struct nouveau_gpuobj *pgd;
struct nouveau_vm *vm;
};
struct nvc0_fifo_chan {
struct nouveau_fifo_chan base;
};
/*******************************************************************************
* FIFO channel objects
******************************************************************************/
static void
nvc0_fifo_playlist_update(struct drm_device *dev)
nvc0_fifo_playlist_update(struct nvc0_fifo_priv *priv)
{
struct nvc0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO);
struct nouveau_bar *bar = nouveau_bar(priv);
struct nouveau_gpuobj *cur;
int i, p;
@@ -57,174 +74,253 @@ nvc0_fifo_playlist_update(struct drm_device *dev)
priv->cur_playlist = !priv->cur_playlist;
for (i = 0, p = 0; i < 128; i++) {
if (!(nv_rd32(dev, 0x3004 + (i * 8)) & 1))
if (!(nv_rd32(priv, 0x003004 + (i * 8)) & 1))
continue;
nv_wo32(cur, p + 0, i);
nv_wo32(cur, p + 4, 0x00000004);
p += 8;
}
nvimem_flush(dev);
bar->flush(bar);
nv_wr32(dev, 0x002270, cur->addr >> 12);
nv_wr32(dev, 0x002274, 0x01f00000 | (p >> 3));
if (!nv_wait(dev, 0x00227c, 0x00100000, 0x00000000))
NV_ERROR(dev, "PFIFO - playlist update failed\n");
nv_wr32(priv, 0x002270, cur->addr >> 12);
nv_wr32(priv, 0x002274, 0x01f00000 | (p >> 3));
if (!nv_wait(priv, 0x00227c, 0x00100000, 0x00000000))
nv_error(priv, "playlist update failed\n");
}
static int
nvc0_fifo_context_new(struct nouveau_channel *chan, int engine)
nvc0_fifo_context_attach(struct nouveau_object *parent,
struct nouveau_object *object)
{
struct drm_device *dev = chan->dev;
struct nvc0_fifo_priv *priv = nv_engine(dev, engine);
struct nvc0_fifo_chan *fctx;
u64 usermem = priv->user.mem->addr + chan->id * 0x1000;
u64 ib_virt = chan->pushbuf_base + chan->dma.ib_base * 4;
int ret, i;
struct nouveau_bar *bar = nouveau_bar(parent);
struct nvc0_fifo_base *base = (void *)parent->parent;
struct nouveau_engctx *ectx = (void *)object;
u32 addr;
int ret;
fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL);
if (!fctx)
return -ENOMEM;
chan->user = ioremap_wc(pci_resource_start(dev->pdev, 1) +
priv->user.bar.offset + (chan->id * 0x1000),
PAGE_SIZE);
if (!chan->user) {
ret = -ENOMEM;
goto error;
switch (nv_engidx(object->engine)) {
case NVDEV_ENGINE_SW : return 0;
case NVDEV_ENGINE_GR : addr = 0x0210; break;
case NVDEV_ENGINE_COPY0: addr = 0x0230; break;
case NVDEV_ENGINE_COPY1: addr = 0x0240; break;
default:
return -EINVAL;
}
for (i = 0; i < 0x100; i += 4)
nv_wo32(chan->ramin, i, 0x00000000);
nv_wo32(chan->ramin, 0x08, lower_32_bits(usermem));
nv_wo32(chan->ramin, 0x0c, upper_32_bits(usermem));
nv_wo32(chan->ramin, 0x10, 0x0000face);
nv_wo32(chan->ramin, 0x30, 0xfffff902);
nv_wo32(chan->ramin, 0x48, lower_32_bits(ib_virt));
nv_wo32(chan->ramin, 0x4c, drm_order(chan->dma.ib_max + 1) << 16 |
upper_32_bits(ib_virt));
nv_wo32(chan->ramin, 0x54, 0x00000002);
nv_wo32(chan->ramin, 0x84, 0x20400000);
nv_wo32(chan->ramin, 0x94, 0x30000001);
nv_wo32(chan->ramin, 0x9c, 0x00000100);
nv_wo32(chan->ramin, 0xa4, 0x1f1f1f1f);
nv_wo32(chan->ramin, 0xa8, 0x1f1f1f1f);
nv_wo32(chan->ramin, 0xac, 0x0000001f);
nv_wo32(chan->ramin, 0xb8, 0xf8000000);
nv_wo32(chan->ramin, 0xf8, 0x10003080); /* 0x002310 */
nv_wo32(chan->ramin, 0xfc, 0x10000010); /* 0x002350 */
nvimem_flush(dev);
if (!ectx->vma.node) {
ret = nouveau_gpuobj_map_vm(nv_gpuobj(ectx), base->vm,
NV_MEM_ACCESS_RW, &ectx->vma);
if (ret)
return ret;
}
nv_wr32(dev, 0x003000 + (chan->id * 8), 0xc0000000 |
(chan->ramin->addr >> 12));
nv_wr32(dev, 0x003004 + (chan->id * 8), 0x001f0001);
nvc0_fifo_playlist_update(dev);
nv_wo32(base, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4);
nv_wo32(base, addr + 0x04, upper_32_bits(ectx->vma.offset));
bar->flush(bar);
return 0;
}
error:
static int
nvc0_fifo_context_detach(struct nouveau_object *parent, bool suspend,
struct nouveau_object *object)
{
struct nouveau_bar *bar = nouveau_bar(parent);
struct nvc0_fifo_priv *priv = (void *)parent->engine;
struct nvc0_fifo_base *base = (void *)parent->parent;
struct nvc0_fifo_chan *chan = (void *)parent;
u32 addr;
switch (nv_engidx(object->engine)) {
case NVDEV_ENGINE_SW : return 0;
case NVDEV_ENGINE_GR : addr = 0x0210; break;
case NVDEV_ENGINE_COPY0: addr = 0x0230; break;
case NVDEV_ENGINE_COPY1: addr = 0x0240; break;
default:
return -EINVAL;
}
nv_wo32(base, addr + 0x00, 0x00000000);
nv_wo32(base, addr + 0x04, 0x00000000);
bar->flush(bar);
nv_wr32(priv, 0x002634, chan->base.chid);
if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) {
nv_error(priv, "channel %d kick timeout\n", chan->base.chid);
if (suspend)
return -EBUSY;
}
return 0;
}
static int
nvc0_fifo_chan_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_bar *bar = nouveau_bar(parent);
struct nvc0_fifo_priv *priv = (void *)engine;
struct nvc0_fifo_base *base = (void *)parent;
struct nvc0_fifo_chan *chan;
struct nv_channel_ind_class *args = data;
u64 usermem, ioffset, ilength;
int ret, i;
if (size < sizeof(*args))
return -EINVAL;
ret = nouveau_fifo_channel_create(parent, engine, oclass, 1,
priv->user.bar.offset, 0x1000,
args->pushbuf,
(1 << NVDEV_ENGINE_SW) |
(1 << NVDEV_ENGINE_GR) |
(1 << NVDEV_ENGINE_COPY0) |
(1 << NVDEV_ENGINE_COPY1), &chan);
*pobject = nv_object(chan);
if (ret)
priv->base.base.context_del(chan, engine);
return ret;
return ret;
nv_parent(chan)->context_attach = nvc0_fifo_context_attach;
nv_parent(chan)->context_detach = nvc0_fifo_context_detach;
usermem = chan->base.chid * 0x1000;
ioffset = args->ioffset;
ilength = log2i(args->ilength / 8);
for (i = 0; i < 0x1000; i += 4)
nv_wo32(priv->user.mem, usermem + i, 0x00000000);
nv_wo32(base, 0x08, lower_32_bits(priv->user.mem->addr + usermem));
nv_wo32(base, 0x0c, upper_32_bits(priv->user.mem->addr + usermem));
nv_wo32(base, 0x10, 0x0000face);
nv_wo32(base, 0x30, 0xfffff902);
nv_wo32(base, 0x48, lower_32_bits(ioffset));
nv_wo32(base, 0x4c, upper_32_bits(ioffset) | (ilength << 16));
nv_wo32(base, 0x54, 0x00000002);
nv_wo32(base, 0x84, 0x20400000);
nv_wo32(base, 0x94, 0x30000001);
nv_wo32(base, 0x9c, 0x00000100);
nv_wo32(base, 0xa4, 0x1f1f1f1f);
nv_wo32(base, 0xa8, 0x1f1f1f1f);
nv_wo32(base, 0xac, 0x0000001f);
nv_wo32(base, 0xb8, 0xf8000000);
nv_wo32(base, 0xf8, 0x10003080); /* 0x002310 */
nv_wo32(base, 0xfc, 0x10000010); /* 0x002350 */
bar->flush(bar);
return 0;
}
static int
nvc0_fifo_chan_init(struct nouveau_object *object)
{
struct nouveau_gpuobj *base = nv_gpuobj(object->parent);
struct nvc0_fifo_priv *priv = (void *)object->engine;
struct nvc0_fifo_chan *chan = (void *)object;
u32 chid = chan->base.chid;
int ret;
ret = nouveau_fifo_channel_init(&chan->base);
if (ret)
return ret;
nv_wr32(priv, 0x003000 + (chid * 8), 0xc0000000 | base->addr >> 12);
nv_wr32(priv, 0x003004 + (chid * 8), 0x001f0001);
nvc0_fifo_playlist_update(priv);
return 0;
}
static int
nvc0_fifo_chan_fini(struct nouveau_object *object, bool suspend)
{
struct nvc0_fifo_priv *priv = (void *)object->engine;
struct nvc0_fifo_chan *chan = (void *)object;
u32 chid = chan->base.chid;
nv_mask(priv, 0x003004 + (chid * 8), 0x00000001, 0x00000000);
nvc0_fifo_playlist_update(priv);
nv_wr32(priv, 0x003000 + (chid * 8), 0x00000000);
return nouveau_fifo_channel_fini(&chan->base, suspend);
}
static struct nouveau_ofuncs
nvc0_fifo_ofuncs = {
.ctor = nvc0_fifo_chan_ctor,
.dtor = _nouveau_fifo_channel_dtor,
.init = nvc0_fifo_chan_init,
.fini = nvc0_fifo_chan_fini,
.rd32 = _nouveau_fifo_channel_rd32,
.wr32 = _nouveau_fifo_channel_wr32,
};
static struct nouveau_oclass
nvc0_fifo_sclass[] = {
{ 0x906f, &nvc0_fifo_ofuncs },
{}
};
/*******************************************************************************
* FIFO context - instmem heap and vm setup
******************************************************************************/
static int
nvc0_fifo_context_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nvc0_fifo_base *base;
int ret;
ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x1000,
0x1000, NVOBJ_FLAG_ZERO_ALLOC |
NVOBJ_FLAG_HEAP, &base);
*pobject = nv_object(base);
if (ret)
return ret;
ret = nouveau_gpuobj_new(parent, NULL, 0x10000, 0x1000, 0, &base->pgd);
if (ret)
return ret;
nv_wo32(base, 0x0200, lower_32_bits(base->pgd->addr));
nv_wo32(base, 0x0204, upper_32_bits(base->pgd->addr));
nv_wo32(base, 0x0208, 0xffffffff);
nv_wo32(base, 0x020c, 0x000000ff);
ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd);
if (ret)
return ret;
return 0;
}
static void
nvc0_fifo_context_del(struct nouveau_channel *chan, int engine)
nvc0_fifo_context_dtor(struct nouveau_object *object)
{
struct nvc0_fifo_chan *fctx = chan->engctx[engine];
struct drm_device *dev = chan->dev;
nv_mask(dev, 0x003004 + (chan->id * 8), 0x00000001, 0x00000000);
nv_wr32(dev, 0x002634, chan->id);
if (!nv_wait(dev, 0x0002634, 0xffffffff, chan->id))
NV_WARN(dev, "0x2634 != chid: 0x%08x\n", nv_rd32(dev, 0x2634));
nvc0_fifo_playlist_update(dev);
nv_wr32(dev, 0x003000 + (chan->id * 8), 0x00000000);
if (chan->user) {
iounmap(chan->user);
chan->user = NULL;
}
chan->engctx[engine] = NULL;
kfree(fctx);
struct nvc0_fifo_base *base = (void *)object;
nouveau_vm_ref(NULL, &base->vm, base->pgd);
nouveau_gpuobj_ref(NULL, &base->pgd);
nouveau_fifo_context_destroy(&base->base);
}
static int
nvc0_fifo_init(struct drm_device *dev, int engine)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvc0_fifo_priv *priv = nv_engine(dev, engine);
struct nouveau_channel *chan;
int i;
/* reset PFIFO, enable all available PSUBFIFO areas */
nv_mask(dev, 0x000200, 0x00000100, 0x00000000);
nv_mask(dev, 0x000200, 0x00000100, 0x00000100);
nv_wr32(dev, 0x000204, 0xffffffff);
nv_wr32(dev, 0x002204, 0xffffffff);
priv->spoon_nr = hweight32(nv_rd32(dev, 0x002204));
NV_DEBUG(dev, "PFIFO: %d subfifo(s)\n", priv->spoon_nr);
/* assign engines to subfifos */
if (priv->spoon_nr >= 3) {
nv_wr32(dev, 0x002208, ~(1 << 0)); /* PGRAPH */
nv_wr32(dev, 0x00220c, ~(1 << 1)); /* PVP */
nv_wr32(dev, 0x002210, ~(1 << 1)); /* PPP */
nv_wr32(dev, 0x002214, ~(1 << 1)); /* PBSP */
nv_wr32(dev, 0x002218, ~(1 << 2)); /* PCE0 */
nv_wr32(dev, 0x00221c, ~(1 << 1)); /* PCE1 */
}
/* PSUBFIFO[n] */
for (i = 0; i < priv->spoon_nr; i++) {
nv_mask(dev, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
nv_wr32(dev, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
nv_wr32(dev, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTR_EN */
}
nv_mask(dev, 0x002200, 0x00000001, 0x00000001);
nv_wr32(dev, 0x002254, 0x10000000 | priv->user.bar.offset >> 12);
nv_wr32(dev, 0x002a00, 0xffffffff); /* clears PFIFO.INTR bit 30 */
nv_wr32(dev, 0x002100, 0xffffffff);
nv_wr32(dev, 0x002140, 0xbfffffff);
/* restore PFIFO context table */
for (i = 0; i < 128; i++) {
chan = dev_priv->channels.ptr[i];
if (!chan || !chan->engctx[engine])
continue;
nv_wr32(dev, 0x003000 + (i * 8), 0xc0000000 |
(chan->ramin->addr >> 12));
nv_wr32(dev, 0x003004 + (i * 8), 0x001f0001);
}
nvc0_fifo_playlist_update(dev);
return 0;
}
static int
nvc0_fifo_fini(struct drm_device *dev, int engine, bool suspend)
{
int i;
for (i = 0; i < 128; i++) {
if (!(nv_rd32(dev, 0x003004 + (i * 8)) & 1))
continue;
nv_mask(dev, 0x003004 + (i * 8), 0x00000001, 0x00000000);
nv_wr32(dev, 0x002634, i);
if (!nv_wait(dev, 0x002634, 0xffffffff, i)) {
NV_INFO(dev, "PFIFO: kick ch %d failed: 0x%08x\n",
i, nv_rd32(dev, 0x002634));
return -EBUSY;
}
}
nv_wr32(dev, 0x002140, 0x00000000);
return 0;
}
static struct nouveau_oclass
nvc0_fifo_cclass = {
.handle = NV_ENGCTX(FIFO, 0xc0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nvc0_fifo_context_ctor,
.dtor = nvc0_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
******************************************************************************/
struct nouveau_enum nvc0_fifo_fault_unit[] = {
{ 0x00, "PGRAPH" },
@@ -289,16 +385,16 @@ struct nouveau_bitfield nvc0_fifo_subfifo_intr[] = {
};
static void
nvc0_fifo_isr_vm_fault(struct drm_device *dev, int unit)
nvc0_fifo_isr_vm_fault(struct nvc0_fifo_priv *priv, int unit)
{
u32 inst = nv_rd32(dev, 0x2800 + (unit * 0x10));
u32 valo = nv_rd32(dev, 0x2804 + (unit * 0x10));
u32 vahi = nv_rd32(dev, 0x2808 + (unit * 0x10));
u32 stat = nv_rd32(dev, 0x280c + (unit * 0x10));
u32 inst = nv_rd32(priv, 0x2800 + (unit * 0x10));
u32 valo = nv_rd32(priv, 0x2804 + (unit * 0x10));
u32 vahi = nv_rd32(priv, 0x2808 + (unit * 0x10));
u32 stat = nv_rd32(priv, 0x280c + (unit * 0x10));
u32 client = (stat & 0x00001f00) >> 8;
NV_INFO(dev, "PFIFO: %s fault at 0x%010llx [",
(stat & 0x00000080) ? "write" : "read", (u64)vahi << 32 | valo);
nv_error(priv, "%s fault at 0x%010llx [", (stat & 0x00000080) ?
"write" : "read", (u64)vahi << 32 | valo);
nouveau_enum_print(nvc0_fifo_fault_reason, stat & 0x0000000f);
printk("] from ");
nouveau_enum_print(nvc0_fifo_fault_unit, unit);
@@ -313,165 +409,223 @@ nvc0_fifo_isr_vm_fault(struct drm_device *dev, int unit)
}
static int
nvc0_fifo_page_flip(struct drm_device *dev, u32 chid)
nvc0_fifo_swmthd(struct nvc0_fifo_priv *priv, u32 chid, u32 mthd, u32 data)
{
struct nvc0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO);
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = NULL;
struct nvc0_fifo_chan *chan = NULL;
struct nouveau_handle *bind;
unsigned long flags;
int ret = -EINVAL;
spin_lock_irqsave(&dev_priv->channels.lock, flags);
if (likely(chid >= 0 && chid < priv->base.channels)) {
chan = dev_priv->channels.ptr[chid];
if (likely(chan)) {
struct nouveau_software_chan *swch =
chan->engctx[NVOBJ_ENGINE_SW];
ret = swch->flip(swch->flip_data);
}
spin_lock_irqsave(&priv->base.lock, flags);
if (likely(chid >= priv->base.min && chid <= priv->base.max))
chan = (void *)priv->base.channel[chid];
if (unlikely(!chan))
goto out;
bind = nouveau_namedb_get_class(nv_namedb(chan), 0x906e);
if (likely(bind)) {
if (!mthd || !nv_call(bind->object, mthd, data))
ret = 0;
nouveau_namedb_put(bind);
}
spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
out:
spin_unlock_irqrestore(&priv->base.lock, flags);
return ret;
}
static void
nvc0_fifo_isr_subfifo_intr(struct drm_device *dev, int unit)
nvc0_fifo_isr_subfifo_intr(struct nvc0_fifo_priv *priv, int unit)
{
u32 stat = nv_rd32(dev, 0x040108 + (unit * 0x2000));
u32 addr = nv_rd32(dev, 0x0400c0 + (unit * 0x2000));
u32 data = nv_rd32(dev, 0x0400c4 + (unit * 0x2000));
u32 chid = nv_rd32(dev, 0x040120 + (unit * 0x2000)) & 0x7f;
u32 subc = (addr & 0x00070000);
u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000));
u32 addr = nv_rd32(priv, 0x0400c0 + (unit * 0x2000));
u32 data = nv_rd32(priv, 0x0400c4 + (unit * 0x2000));
u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0x7f;
u32 subc = (addr & 0x00070000) >> 16;
u32 mthd = (addr & 0x00003ffc);
u32 show = stat;
if (stat & 0x00200000) {
if (mthd == 0x0054) {
if (!nvc0_fifo_page_flip(dev, chid))
if (!nvc0_fifo_swmthd(priv, chid, 0x0500, 0x00000000))
show &= ~0x00200000;
}
}
if (show) {
NV_INFO(dev, "PFIFO%d:", unit);
nouveau_bitfield_print(nvc0_fifo_subfifo_intr, show);
NV_INFO(dev, "PFIFO%d: ch %d subc %d mthd 0x%04x data 0x%08x\n",
unit, chid, subc, mthd, data);
if (stat & 0x00800000) {
if (!nvc0_fifo_swmthd(priv, chid, mthd, data))
show &= ~0x00800000;
}
nv_wr32(dev, 0x0400c0 + (unit * 0x2000), 0x80600008);
nv_wr32(dev, 0x040108 + (unit * 0x2000), stat);
if (show) {
nv_error(priv, "SUBFIFO%d:", unit);
nouveau_bitfield_print(nvc0_fifo_subfifo_intr, show);
printk("\n");
nv_error(priv, "SUBFIFO%d: ch %d subc %d mthd 0x%04x "
"data 0x%08x\n",
unit, chid, subc, mthd, data);
}
nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008);
nv_wr32(priv, 0x040108 + (unit * 0x2000), stat);
}
static void
nvc0_fifo_isr(struct drm_device *dev)
nvc0_fifo_intr(struct nouveau_subdev *subdev)
{
u32 mask = nv_rd32(dev, 0x002140);
u32 stat = nv_rd32(dev, 0x002100) & mask;
struct nvc0_fifo_priv *priv = (void *)subdev;
u32 mask = nv_rd32(priv, 0x002140);
u32 stat = nv_rd32(priv, 0x002100) & mask;
if (stat & 0x00000100) {
NV_INFO(dev, "PFIFO: unknown status 0x00000100\n");
nv_wr32(dev, 0x002100, 0x00000100);
nv_info(priv, "unknown status 0x00000100\n");
nv_wr32(priv, 0x002100, 0x00000100);
stat &= ~0x00000100;
}
if (stat & 0x10000000) {
u32 units = nv_rd32(dev, 0x00259c);
u32 units = nv_rd32(priv, 0x00259c);
u32 u = units;
while (u) {
int i = ffs(u) - 1;
nvc0_fifo_isr_vm_fault(dev, i);
nvc0_fifo_isr_vm_fault(priv, i);
u &= ~(1 << i);
}
nv_wr32(dev, 0x00259c, units);
nv_wr32(priv, 0x00259c, units);
stat &= ~0x10000000;
}
if (stat & 0x20000000) {
u32 units = nv_rd32(dev, 0x0025a0);
u32 units = nv_rd32(priv, 0x0025a0);
u32 u = units;
while (u) {
int i = ffs(u) - 1;
nvc0_fifo_isr_subfifo_intr(dev, i);
nvc0_fifo_isr_subfifo_intr(priv, i);
u &= ~(1 << i);
}
nv_wr32(dev, 0x0025a0, units);
nv_wr32(priv, 0x0025a0, units);
stat &= ~0x20000000;
}
if (stat & 0x40000000) {
NV_INFO(dev, "PFIFO: unknown status 0x40000000\n");
nv_mask(dev, 0x002a00, 0x00000000, 0x00000000);
nv_warn(priv, "unknown status 0x40000000\n");
nv_mask(priv, 0x002a00, 0x00000000, 0x00000000);
stat &= ~0x40000000;
}
if (stat) {
NV_INFO(dev, "PFIFO: unhandled status 0x%08x\n", stat);
nv_wr32(dev, 0x002100, stat);
nv_wr32(dev, 0x002140, 0);
nv_fatal(priv, "unhandled status 0x%08x\n", stat);
nv_wr32(priv, 0x002100, stat);
nv_wr32(priv, 0x002140, 0);
}
}
static void
nvc0_fifo_destroy(struct drm_device *dev, int engine)
static int
nvc0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nvc0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO);
struct drm_nouveau_private *dev_priv = dev->dev_private;
nouveau_gpuobj_unmap(&priv->user.bar);
nouveau_gpuobj_ref(NULL, &priv->user.mem);
nouveau_gpuobj_ref(NULL, &priv->playlist[1]);
nouveau_gpuobj_ref(NULL, &priv->playlist[0]);
dev_priv->eng[engine] = NULL;
kfree(priv);
}
int
nvc0_fifo_create(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvc0_fifo_priv *priv;
int ret;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->base.base.destroy = nvc0_fifo_destroy;
priv->base.base.init = nvc0_fifo_init;
priv->base.base.fini = nvc0_fifo_fini;
priv->base.base.context_new = nvc0_fifo_context_new;
priv->base.base.context_del = nvc0_fifo_context_del;
priv->base.channels = 128;
dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base;
ret = nouveau_gpuobj_new(dev, NULL, 4096, 4096, 0, &priv->playlist[0]);
ret = nouveau_fifo_create(parent, engine, oclass, 0, 127, &priv);
*pobject = nv_object(priv);
if (ret)
goto error;
return ret;
ret = nouveau_gpuobj_new(dev, NULL, 4096, 4096, 0, &priv->playlist[1]);
ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 0x1000, 0,
&priv->playlist[0]);
if (ret)
goto error;
return ret;
ret = nouveau_gpuobj_new(dev, NULL, priv->base.channels * 4096, 0x1000,
NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem);
ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 0x1000, 0,
&priv->playlist[1]);
if (ret)
goto error;
return ret;
ret = nouveau_gpuobj_map_bar(priv->user.mem, NV_MEM_ACCESS_RW,
&priv->user.bar);
ret = nouveau_gpuobj_new(parent, NULL, 128 * 0x1000, 0x1000, 0,
&priv->user.mem);
if (ret)
goto error;
return ret;
nouveau_irq_register(dev, 8, nvc0_fifo_isr);
error:
ret = nouveau_gpuobj_map(priv->user.mem, NV_MEM_ACCESS_RW,
&priv->user.bar);
if (ret)
priv->base.base.destroy(dev, NVOBJ_ENGINE_FIFO);
return ret;
return ret;
nv_subdev(priv)->unit = 0x00000100;
nv_subdev(priv)->intr = nvc0_fifo_intr;
nv_engine(priv)->cclass = &nvc0_fifo_cclass;
nv_engine(priv)->sclass = nvc0_fifo_sclass;
return 0;
}
static void
nvc0_fifo_dtor(struct nouveau_object *object)
{
struct nvc0_fifo_priv *priv = (void *)object;
nouveau_gpuobj_unmap(&priv->user.bar);
nouveau_gpuobj_ref(NULL, &priv->user.mem);
nouveau_gpuobj_ref(NULL, &priv->playlist[1]);
nouveau_gpuobj_ref(NULL, &priv->playlist[0]);
nouveau_fifo_destroy(&priv->base);
}
static int
nvc0_fifo_init(struct nouveau_object *object)
{
struct nvc0_fifo_priv *priv = (void *)object;
int ret, i;
ret = nouveau_fifo_init(&priv->base);
if (ret)
return ret;
nv_wr32(priv, 0x000204, 0xffffffff);
nv_wr32(priv, 0x002204, 0xffffffff);
priv->spoon_nr = hweight32(nv_rd32(priv, 0x002204));
nv_debug(priv, "%d subfifo(s)\n", priv->spoon_nr);
/* assign engines to subfifos */
if (priv->spoon_nr >= 3) {
nv_wr32(priv, 0x002208, ~(1 << 0)); /* PGRAPH */
nv_wr32(priv, 0x00220c, ~(1 << 1)); /* PVP */
nv_wr32(priv, 0x002210, ~(1 << 1)); /* PPP */
nv_wr32(priv, 0x002214, ~(1 << 1)); /* PBSP */
nv_wr32(priv, 0x002218, ~(1 << 2)); /* PCE0 */
nv_wr32(priv, 0x00221c, ~(1 << 1)); /* PCE1 */
}
/* PSUBFIFO[n] */
for (i = 0; i < priv->spoon_nr; i++) {
nv_mask(priv, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
nv_wr32(priv, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
nv_wr32(priv, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */
}
nv_mask(priv, 0x002200, 0x00000001, 0x00000001);
nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12);
nv_wr32(priv, 0x002a00, 0xffffffff); /* clears PFIFO.INTR bit 30 */
nv_wr32(priv, 0x002100, 0xffffffff);
nv_wr32(priv, 0x002140, 0xbfffffff);
return 0;
}
struct nouveau_oclass
nvc0_fifo_oclass = {
.handle = NV_ENGINE(FIFO, 0xc0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nvc0_fifo_ctor,
.dtor = nvc0_fifo_dtor,
.init = nvc0_fifo_init,
.fini = _nouveau_fifo_fini,
},
};
+386 -244
View File
@@ -1,5 +1,5 @@
/*
* 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,25 +22,30 @@
* Authors: Ben Skeggs
*/
#include "drmP.h"
#include <core/client.h>
#include <core/handle.h>
#include <core/namedb.h>
#include <core/gpuobj.h>
#include <core/engctx.h>
#include <core/class.h>
#include <core/math.h>
#include <core/enum.h>
#include "nouveau_drv.h"
#include <core/mm.h>
#include <subdev/timer.h>
#include <subdev/bar.h>
#include <subdev/vm.h>
#include <engine/dmaobj.h>
#include <engine/fifo.h>
#include "nouveau_software.h"
#define NVE0_FIFO_ENGINE_NUM 32
static void nve0_fifo_isr(struct drm_device *);
struct nve0_fifo_engine {
struct nve0_fifo_engn {
struct nouveau_gpuobj *playlist[2];
int cur_playlist;
};
struct nve0_fifo_priv {
struct nouveau_fifo_priv base;
struct nve0_fifo_engine engine[NVE0_FIFO_ENGINE_NUM];
struct nouveau_fifo base;
struct nve0_fifo_engn engine[16];
struct {
struct nouveau_gpuobj *mem;
struct nouveau_vma bar;
@@ -48,193 +53,285 @@ struct nve0_fifo_priv {
int spoon_nr;
};
struct nve0_fifo_base {
struct nouveau_fifo_base base;
struct nouveau_gpuobj *pgd;
struct nouveau_vm *vm;
};
struct nve0_fifo_chan {
struct nouveau_fifo_chan base;
u32 engine;
};
/*******************************************************************************
* FIFO channel objects
******************************************************************************/
static void
nve0_fifo_playlist_update(struct drm_device *dev, u32 engine)
nve0_fifo_playlist_update(struct nve0_fifo_priv *priv, u32 engine)
{
struct nve0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO);
struct nve0_fifo_engine *peng = &priv->engine[engine];
struct nouveau_bar *bar = nouveau_bar(priv);
struct nve0_fifo_engn *engn = &priv->engine[engine];
struct nouveau_gpuobj *cur;
u32 match = (engine << 16) | 0x00000001;
int ret, i, p;
int i, p;
cur = peng->playlist[peng->cur_playlist];
cur = engn->playlist[engn->cur_playlist];
if (unlikely(cur == NULL)) {
ret = nouveau_gpuobj_new(dev, NULL, 0x8000, 0x1000, 0, &cur);
int ret = nouveau_gpuobj_new(nv_object(priv)->parent, NULL,
0x8000, 0x1000, 0, &cur);
if (ret) {
NV_ERROR(dev, "PFIFO: playlist alloc failed\n");
nv_error(priv, "playlist alloc failed\n");
return;
}
peng->playlist[peng->cur_playlist] = cur;
engn->playlist[engn->cur_playlist] = cur;
}
peng->cur_playlist = !peng->cur_playlist;
engn->cur_playlist = !engn->cur_playlist;
for (i = 0, p = 0; i < priv->base.channels; i++) {
u32 ctrl = nv_rd32(dev, 0x800004 + (i * 8)) & 0x001f0001;
for (i = 0, p = 0; i < priv->base.max; i++) {
u32 ctrl = nv_rd32(priv, 0x800004 + (i * 8)) & 0x001f0001;
if (ctrl != match)
continue;
nv_wo32(cur, p + 0, i);
nv_wo32(cur, p + 4, 0x00000000);
p += 8;
}
nvimem_flush(dev);
bar->flush(bar);
nv_wr32(dev, 0x002270, cur->addr >> 12);
nv_wr32(dev, 0x002274, (engine << 20) | (p >> 3));
if (!nv_wait(dev, 0x002284 + (engine * 4), 0x00100000, 0x00000000))
NV_ERROR(dev, "PFIFO: playlist %d update timeout\n", engine);
nv_wr32(priv, 0x002270, cur->addr >> 12);
nv_wr32(priv, 0x002274, (engine << 20) | (p >> 3));
if (!nv_wait(priv, 0x002284 + (engine * 4), 0x00100000, 0x00000000))
nv_error(priv, "playlist %d update timeout\n", engine);
}
static int
nve0_fifo_context_new(struct nouveau_channel *chan, int engine)
nve0_fifo_context_attach(struct nouveau_object *parent,
struct nouveau_object *object)
{
struct drm_device *dev = chan->dev;
struct nve0_fifo_priv *priv = nv_engine(dev, engine);
struct nve0_fifo_chan *fctx;
u64 usermem = priv->user.mem->addr + chan->id * 512;
u64 ib_virt = chan->pushbuf_base + chan->dma.ib_base * 4;
int ret = 0, i;
struct nouveau_bar *bar = nouveau_bar(parent);
struct nve0_fifo_base *base = (void *)parent->parent;
struct nouveau_engctx *ectx = (void *)object;
u32 addr;
int ret;
fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL);
if (!fctx)
return -ENOMEM;
fctx->engine = 0; /* PGRAPH */
/* allocate vram for control regs, map into polling area */
chan->user = ioremap_wc(pci_resource_start(dev->pdev, 1) +
priv->user.bar.offset + (chan->id * 512), 512);
if (!chan->user) {
ret = -ENOMEM;
goto error;
switch (nv_engidx(object->engine)) {
case NVDEV_ENGINE_SW : return 0;
case NVDEV_ENGINE_GR : addr = 0x0210; break;
default:
return -EINVAL;
}
for (i = 0; i < 0x100; i += 4)
nv_wo32(chan->ramin, i, 0x00000000);
nv_wo32(chan->ramin, 0x08, lower_32_bits(usermem));
nv_wo32(chan->ramin, 0x0c, upper_32_bits(usermem));
nv_wo32(chan->ramin, 0x10, 0x0000face);
nv_wo32(chan->ramin, 0x30, 0xfffff902);
nv_wo32(chan->ramin, 0x48, lower_32_bits(ib_virt));
nv_wo32(chan->ramin, 0x4c, drm_order(chan->dma.ib_max + 1) << 16 |
upper_32_bits(ib_virt));
nv_wo32(chan->ramin, 0x84, 0x20400000);
nv_wo32(chan->ramin, 0x94, 0x30000001);
nv_wo32(chan->ramin, 0x9c, 0x00000100);
nv_wo32(chan->ramin, 0xac, 0x0000001f);
nv_wo32(chan->ramin, 0xe4, 0x00000000);
nv_wo32(chan->ramin, 0xe8, chan->id);
nv_wo32(chan->ramin, 0xf8, 0x10003080); /* 0x002310 */
nv_wo32(chan->ramin, 0xfc, 0x10000010); /* 0x002350 */
nvimem_flush(dev);
if (!ectx->vma.node) {
ret = nouveau_gpuobj_map_vm(nv_gpuobj(ectx), base->vm,
NV_MEM_ACCESS_RW, &ectx->vma);
if (ret)
return ret;
}
nv_wr32(dev, 0x800000 + (chan->id * 8), 0x80000000 |
(chan->ramin->addr >> 12));
nv_mask(dev, 0x800004 + (chan->id * 8), 0x00000400, 0x00000400);
nve0_fifo_playlist_update(dev, fctx->engine);
nv_mask(dev, 0x800004 + (chan->id * 8), 0x00000400, 0x00000400);
nv_wo32(base, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4);
nv_wo32(base, addr + 0x04, upper_32_bits(ectx->vma.offset));
bar->flush(bar);
return 0;
}
error:
static int
nve0_fifo_context_detach(struct nouveau_object *parent, bool suspend,
struct nouveau_object *object)
{
struct nouveau_bar *bar = nouveau_bar(parent);
struct nve0_fifo_priv *priv = (void *)parent->engine;
struct nve0_fifo_base *base = (void *)parent->parent;
struct nve0_fifo_chan *chan = (void *)parent;
u32 addr;
switch (nv_engidx(object->engine)) {
case NVDEV_ENGINE_SW : return 0;
case NVDEV_ENGINE_GR : addr = 0x0210; break;
default:
return -EINVAL;
}
nv_wo32(base, addr + 0x00, 0x00000000);
nv_wo32(base, addr + 0x04, 0x00000000);
bar->flush(bar);
nv_wr32(priv, 0x002634, chan->base.chid);
if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) {
nv_error(priv, "channel %d kick timeout\n", chan->base.chid);
if (suspend)
return -EBUSY;
}
return 0;
}
static int
nve0_fifo_chan_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_bar *bar = nouveau_bar(parent);
struct nve0_fifo_priv *priv = (void *)engine;
struct nve0_fifo_base *base = (void *)parent;
struct nve0_fifo_chan *chan;
struct nv_channel_ind_class *args = data;
u64 usermem, ioffset, ilength;
int ret, i;
if (size < sizeof(*args))
return -EINVAL;
ret = nouveau_fifo_channel_create(parent, engine, oclass, 1,
priv->user.bar.offset, 0x200,
args->pushbuf,
(1 << NVDEV_ENGINE_SW) |
(1 << NVDEV_ENGINE_GR), &chan);
*pobject = nv_object(chan);
if (ret)
priv->base.base.context_del(chan, engine);
return ret;
return ret;
nv_parent(chan)->context_attach = nve0_fifo_context_attach;
nv_parent(chan)->context_detach = nve0_fifo_context_detach;
usermem = chan->base.chid * 0x200;
ioffset = args->ioffset;
ilength = log2i(args->ilength / 8);
for (i = 0; i < 0x200; i += 4)
nv_wo32(priv->user.mem, usermem + i, 0x00000000);
nv_wo32(base, 0x08, lower_32_bits(priv->user.mem->addr + usermem));
nv_wo32(base, 0x0c, upper_32_bits(priv->user.mem->addr + usermem));
nv_wo32(base, 0x10, 0x0000face);
nv_wo32(base, 0x30, 0xfffff902);
nv_wo32(base, 0x48, lower_32_bits(ioffset));
nv_wo32(base, 0x4c, upper_32_bits(ioffset) | (ilength << 16));
nv_wo32(base, 0x84, 0x20400000);
nv_wo32(base, 0x94, 0x30000001);
nv_wo32(base, 0x9c, 0x00000100);
nv_wo32(base, 0xac, 0x0000001f);
nv_wo32(base, 0xe8, chan->base.chid);
nv_wo32(base, 0xb8, 0xf8000000);
nv_wo32(base, 0xf8, 0x10003080); /* 0x002310 */
nv_wo32(base, 0xfc, 0x10000010); /* 0x002350 */
bar->flush(bar);
return 0;
}
static int
nve0_fifo_chan_init(struct nouveau_object *object)
{
struct nouveau_gpuobj *base = nv_gpuobj(object->parent);
struct nve0_fifo_priv *priv = (void *)object->engine;
struct nve0_fifo_chan *chan = (void *)object;
u32 chid = chan->base.chid;
int ret;
ret = nouveau_fifo_channel_init(&chan->base);
if (ret)
return ret;
nv_wr32(priv, 0x800000 + (chid * 8), 0x80000000 | base->addr >> 12);
nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400);
nve0_fifo_playlist_update(priv, chan->engine);
nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400);
return 0;
}
static int
nve0_fifo_chan_fini(struct nouveau_object *object, bool suspend)
{
struct nve0_fifo_priv *priv = (void *)object->engine;
struct nve0_fifo_chan *chan = (void *)object;
u32 chid = chan->base.chid;
nv_mask(priv, 0x800004 + (chid * 8), 0x00000800, 0x00000800);
nve0_fifo_playlist_update(priv, chan->engine);
nv_wr32(priv, 0x800000 + (chid * 8), 0x00000000);
return nouveau_fifo_channel_fini(&chan->base, suspend);
}
static struct nouveau_ofuncs
nve0_fifo_ofuncs = {
.ctor = nve0_fifo_chan_ctor,
.dtor = _nouveau_fifo_channel_dtor,
.init = nve0_fifo_chan_init,
.fini = nve0_fifo_chan_fini,
.rd32 = _nouveau_fifo_channel_rd32,
.wr32 = _nouveau_fifo_channel_wr32,
};
static struct nouveau_oclass
nve0_fifo_sclass[] = {
{ 0xa06f, &nve0_fifo_ofuncs },
{}
};
/*******************************************************************************
* FIFO context - instmem heap and vm setup
******************************************************************************/
static int
nve0_fifo_context_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nve0_fifo_base *base;
int ret;
ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x1000,
0x1000, NVOBJ_FLAG_ZERO_ALLOC, &base);
*pobject = nv_object(base);
if (ret)
return ret;
ret = nouveau_gpuobj_new(parent, NULL, 0x10000, 0x1000, 0, &base->pgd);
if (ret)
return ret;
nv_wo32(base, 0x0200, lower_32_bits(base->pgd->addr));
nv_wo32(base, 0x0204, upper_32_bits(base->pgd->addr));
nv_wo32(base, 0x0208, 0xffffffff);
nv_wo32(base, 0x020c, 0x000000ff);
ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd);
if (ret)
return ret;
return 0;
}
static void
nve0_fifo_context_del(struct nouveau_channel *chan, int engine)
nve0_fifo_context_dtor(struct nouveau_object *object)
{
struct nve0_fifo_chan *fctx = chan->engctx[engine];
struct drm_device *dev = chan->dev;
nv_mask(dev, 0x800004 + (chan->id * 8), 0x00000800, 0x00000800);
nv_wr32(dev, 0x002634, chan->id);
if (!nv_wait(dev, 0x0002634, 0xffffffff, chan->id))
NV_WARN(dev, "0x2634 != chid: 0x%08x\n", nv_rd32(dev, 0x2634));
nve0_fifo_playlist_update(dev, fctx->engine);
nv_wr32(dev, 0x800000 + (chan->id * 8), 0x00000000);
if (chan->user) {
iounmap(chan->user);
chan->user = NULL;
}
chan->engctx[NVOBJ_ENGINE_FIFO] = NULL;
kfree(fctx);
struct nve0_fifo_base *base = (void *)object;
nouveau_vm_ref(NULL, &base->vm, base->pgd);
nouveau_gpuobj_ref(NULL, &base->pgd);
nouveau_fifo_context_destroy(&base->base);
}
static int
nve0_fifo_init(struct drm_device *dev, int engine)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nve0_fifo_priv *priv = nv_engine(dev, engine);
struct nve0_fifo_chan *fctx;
int i;
static struct nouveau_oclass
nve0_fifo_cclass = {
.handle = NV_ENGCTX(FIFO, 0xe0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nve0_fifo_context_ctor,
.dtor = nve0_fifo_context_dtor,
.init = _nouveau_fifo_context_init,
.fini = _nouveau_fifo_context_fini,
.rd32 = _nouveau_fifo_context_rd32,
.wr32 = _nouveau_fifo_context_wr32,
},
};
/* reset PFIFO, enable all available PSUBFIFO areas */
nv_mask(dev, 0x000200, 0x00000100, 0x00000000);
nv_mask(dev, 0x000200, 0x00000100, 0x00000100);
nv_wr32(dev, 0x000204, 0xffffffff);
priv->spoon_nr = hweight32(nv_rd32(dev, 0x000204));
NV_DEBUG(dev, "PFIFO: %d subfifo(s)\n", priv->spoon_nr);
/* PSUBFIFO[n] */
for (i = 0; i < priv->spoon_nr; i++) {
nv_mask(dev, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
nv_wr32(dev, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
nv_wr32(dev, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTR_EN */
}
nv_wr32(dev, 0x002254, 0x10000000 | priv->user.bar.offset >> 12);
nv_wr32(dev, 0x002a00, 0xffffffff);
nv_wr32(dev, 0x002100, 0xffffffff);
nv_wr32(dev, 0x002140, 0xbfffffff);
/* restore PFIFO context table */
for (i = 0; i < priv->base.channels; i++) {
struct nouveau_channel *chan = dev_priv->channels.ptr[i];
if (!chan || !(fctx = chan->engctx[engine]))
continue;
nv_wr32(dev, 0x800000 + (i * 8), 0x80000000 |
(chan->ramin->addr >> 12));
nv_mask(dev, 0x800004 + (i * 8), 0x00000400, 0x00000400);
nve0_fifo_playlist_update(dev, fctx->engine);
nv_mask(dev, 0x800004 + (i * 8), 0x00000400, 0x00000400);
}
return 0;
}
static int
nve0_fifo_fini(struct drm_device *dev, int engine, bool suspend)
{
struct nve0_fifo_priv *priv = nv_engine(dev, engine);
int i;
for (i = 0; i < priv->base.channels; i++) {
if (!(nv_rd32(dev, 0x800004 + (i * 8)) & 1))
continue;
nv_mask(dev, 0x800004 + (i * 8), 0x00000800, 0x00000800);
nv_wr32(dev, 0x002634, i);
if (!nv_wait(dev, 0x002634, 0xffffffff, i)) {
NV_INFO(dev, "PFIFO: kick ch %d failed: 0x%08x\n",
i, nv_rd32(dev, 0x002634));
return -EBUSY;
}
}
nv_wr32(dev, 0x002140, 0x00000000);
return 0;
}
/*******************************************************************************
* PFIFO engine
******************************************************************************/
struct nouveau_enum nve0_fifo_fault_unit[] = {
{}
@@ -268,16 +365,16 @@ struct nouveau_bitfield nve0_fifo_subfifo_intr[] = {
};
static void
nve0_fifo_isr_vm_fault(struct drm_device *dev, int unit)
nve0_fifo_isr_vm_fault(struct nve0_fifo_priv *priv, int unit)
{
u32 inst = nv_rd32(dev, 0x2800 + (unit * 0x10));
u32 valo = nv_rd32(dev, 0x2804 + (unit * 0x10));
u32 vahi = nv_rd32(dev, 0x2808 + (unit * 0x10));
u32 stat = nv_rd32(dev, 0x280c + (unit * 0x10));
u32 inst = nv_rd32(priv, 0x2800 + (unit * 0x10));
u32 valo = nv_rd32(priv, 0x2804 + (unit * 0x10));
u32 vahi = nv_rd32(priv, 0x2808 + (unit * 0x10));
u32 stat = nv_rd32(priv, 0x280c + (unit * 0x10));
u32 client = (stat & 0x00001f00) >> 8;
NV_INFO(dev, "PFIFO: %s fault at 0x%010llx [",
(stat & 0x00000080) ? "write" : "read", (u64)vahi << 32 | valo);
nv_error(priv, "PFIFO: %s fault at 0x%010llx [", (stat & 0x00000080) ?
"write" : "read", (u64)vahi << 32 | valo);
nouveau_enum_print(nve0_fifo_fault_reason, stat & 0x0000000f);
printk("] from ");
nouveau_enum_print(nve0_fifo_fault_unit, unit);
@@ -292,160 +389,205 @@ nve0_fifo_isr_vm_fault(struct drm_device *dev, int unit)
}
static int
nve0_fifo_page_flip(struct drm_device *dev, u32 chid)
nve0_fifo_swmthd(struct nve0_fifo_priv *priv, u32 chid, u32 mthd, u32 data)
{
struct nve0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO);
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = NULL;
struct nve0_fifo_chan *chan = NULL;
struct nouveau_handle *bind;
unsigned long flags;
int ret = -EINVAL;
spin_lock_irqsave(&dev_priv->channels.lock, flags);
if (likely(chid >= 0 && chid < priv->base.channels)) {
chan = dev_priv->channels.ptr[chid];
if (likely(chan)) {
struct nouveau_software_chan *swch =
chan->engctx[NVOBJ_ENGINE_SW];
ret = swch->flip(swch->flip_data);
}
spin_lock_irqsave(&priv->base.lock, flags);
if (likely(chid >= priv->base.min && chid <= priv->base.max))
chan = (void *)priv->base.channel[chid];
if (unlikely(!chan))
goto out;
bind = nouveau_namedb_get_class(nv_namedb(chan), 0x906e);
if (likely(bind)) {
if (!mthd || !nv_call(bind->object, mthd, data))
ret = 0;
nouveau_namedb_put(bind);
}
spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
out:
spin_unlock_irqrestore(&priv->base.lock, flags);
return ret;
}
static void
nve0_fifo_isr_subfifo_intr(struct drm_device *dev, int unit)
nve0_fifo_isr_subfifo_intr(struct nve0_fifo_priv *priv, int unit)
{
u32 stat = nv_rd32(dev, 0x040108 + (unit * 0x2000));
u32 addr = nv_rd32(dev, 0x0400c0 + (unit * 0x2000));
u32 data = nv_rd32(dev, 0x0400c4 + (unit * 0x2000));
u32 chid = nv_rd32(dev, 0x040120 + (unit * 0x2000)) & 0xfff;
u32 subc = (addr & 0x00070000);
u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000));
u32 addr = nv_rd32(priv, 0x0400c0 + (unit * 0x2000));
u32 data = nv_rd32(priv, 0x0400c4 + (unit * 0x2000));
u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0xfff;
u32 subc = (addr & 0x00070000) >> 16;
u32 mthd = (addr & 0x00003ffc);
u32 show = stat;
if (stat & 0x00200000) {
if (mthd == 0x0054) {
if (!nve0_fifo_page_flip(dev, chid))
if (!nve0_fifo_swmthd(priv, chid, 0x0500, 0x00000000))
show &= ~0x00200000;
}
}
if (show) {
NV_INFO(dev, "PFIFO%d:", unit);
nouveau_bitfield_print(nve0_fifo_subfifo_intr, show);
NV_INFO(dev, "PFIFO%d: ch %d subc %d mthd 0x%04x data 0x%08x\n",
unit, chid, subc, mthd, data);
if (stat & 0x00800000) {
if (!nve0_fifo_swmthd(priv, chid, mthd, data))
show &= ~0x00800000;
}
nv_wr32(dev, 0x0400c0 + (unit * 0x2000), 0x80600008);
nv_wr32(dev, 0x040108 + (unit * 0x2000), stat);
if (show) {
nv_error(priv, "SUBFIFO%d:", unit);
nouveau_bitfield_print(nve0_fifo_subfifo_intr, show);
printk("\n");
nv_error(priv, "SUBFIFO%d: ch %d subc %d mthd 0x%04x "
"data 0x%08x\n",
unit, chid, subc, mthd, data);
}
nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008);
nv_wr32(priv, 0x040108 + (unit * 0x2000), stat);
}
static void
nve0_fifo_isr(struct drm_device *dev)
nve0_fifo_intr(struct nouveau_subdev *subdev)
{
u32 mask = nv_rd32(dev, 0x002140);
u32 stat = nv_rd32(dev, 0x002100) & mask;
struct nve0_fifo_priv *priv = (void *)subdev;
u32 mask = nv_rd32(priv, 0x002140);
u32 stat = nv_rd32(priv, 0x002100) & mask;
if (stat & 0x00000100) {
NV_INFO(dev, "PFIFO: unknown status 0x00000100\n");
nv_wr32(dev, 0x002100, 0x00000100);
nv_warn(priv, "unknown status 0x00000100\n");
nv_wr32(priv, 0x002100, 0x00000100);
stat &= ~0x00000100;
}
if (stat & 0x10000000) {
u32 units = nv_rd32(dev, 0x00259c);
u32 units = nv_rd32(priv, 0x00259c);
u32 u = units;
while (u) {
int i = ffs(u) - 1;
nve0_fifo_isr_vm_fault(dev, i);
nve0_fifo_isr_vm_fault(priv, i);
u &= ~(1 << i);
}
nv_wr32(dev, 0x00259c, units);
nv_wr32(priv, 0x00259c, units);
stat &= ~0x10000000;
}
if (stat & 0x20000000) {
u32 units = nv_rd32(dev, 0x0025a0);
u32 units = nv_rd32(priv, 0x0025a0);
u32 u = units;
while (u) {
int i = ffs(u) - 1;
nve0_fifo_isr_subfifo_intr(dev, i);
nve0_fifo_isr_subfifo_intr(priv, i);
u &= ~(1 << i);
}
nv_wr32(dev, 0x0025a0, units);
nv_wr32(priv, 0x0025a0, units);
stat &= ~0x20000000;
}
if (stat & 0x40000000) {
NV_INFO(dev, "PFIFO: unknown status 0x40000000\n");
nv_mask(dev, 0x002a00, 0x00000000, 0x00000000);
nv_warn(priv, "unknown status 0x40000000\n");
nv_mask(priv, 0x002a00, 0x00000000, 0x00000000);
stat &= ~0x40000000;
}
if (stat) {
NV_INFO(dev, "PFIFO: unhandled status 0x%08x\n", stat);
nv_wr32(dev, 0x002100, stat);
nv_wr32(dev, 0x002140, 0);
nv_fatal(priv, "unhandled status 0x%08x\n", stat);
nv_wr32(priv, 0x002100, stat);
nv_wr32(priv, 0x002140, 0);
}
}
static void
nve0_fifo_destroy(struct drm_device *dev, int engine)
static int
nve0_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 nve0_fifo_priv *priv = nv_engine(dev, engine);
struct nve0_fifo_priv *priv;
int ret;
ret = nouveau_fifo_create(parent, engine, oclass, 0, 4095, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
ret = nouveau_gpuobj_new(parent, NULL, 4096 * 0x200, 0x1000,
NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem);
if (ret)
return ret;
ret = nouveau_gpuobj_map(priv->user.mem, NV_MEM_ACCESS_RW,
&priv->user.bar);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00000100;
nv_subdev(priv)->intr = nve0_fifo_intr;
nv_engine(priv)->cclass = &nve0_fifo_cclass;
nv_engine(priv)->sclass = nve0_fifo_sclass;
return 0;
}
static void
nve0_fifo_dtor(struct nouveau_object *object)
{
struct nve0_fifo_priv *priv = (void *)object;
int i;
nouveau_gpuobj_unmap(&priv->user.bar);
nouveau_gpuobj_ref(NULL, &priv->user.mem);
for (i = 0; i < NVE0_FIFO_ENGINE_NUM; i++) {
nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[0]);
for (i = 0; i < ARRAY_SIZE(priv->engine); i++) {
nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[1]);
nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[0]);
}
dev_priv->eng[engine] = NULL;
kfree(priv);
nouveau_fifo_destroy(&priv->base);
}
int
nve0_fifo_create(struct drm_device *dev)
static int
nve0_fifo_init(struct nouveau_object *object)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nve0_fifo_priv *priv;
int ret;
struct nve0_fifo_priv *priv = (void *)object;
int ret, i;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->base.base.destroy = nve0_fifo_destroy;
priv->base.base.init = nve0_fifo_init;
priv->base.base.fini = nve0_fifo_fini;
priv->base.base.context_new = nve0_fifo_context_new;
priv->base.base.context_del = nve0_fifo_context_del;
priv->base.channels = 4096;
dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base;
ret = nouveau_gpuobj_new(dev, NULL, priv->base.channels * 512, 0x1000,
NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem);
ret = nouveau_fifo_init(&priv->base);
if (ret)
goto error;
return ret;
ret = nouveau_gpuobj_map_bar(priv->user.mem, NV_MEM_ACCESS_RW,
&priv->user.bar);
if (ret)
goto error;
/* enable all available PSUBFIFOs */
nv_wr32(priv, 0x000204, 0xffffffff);
priv->spoon_nr = hweight32(nv_rd32(priv, 0x000204));
nv_debug(priv, "%d subfifo(s)\n", priv->spoon_nr);
nouveau_irq_register(dev, 8, nve0_fifo_isr);
error:
if (ret)
priv->base.base.destroy(dev, NVOBJ_ENGINE_FIFO);
return ret;
/* PSUBFIFO[n] */
for (i = 0; i < priv->spoon_nr; i++) {
nv_mask(priv, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
nv_wr32(priv, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
nv_wr32(priv, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */
}
nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12);
nv_wr32(priv, 0x002a00, 0xffffffff);
nv_wr32(priv, 0x002100, 0xffffffff);
nv_wr32(priv, 0x002140, 0xbfffffff);
return 0;
}
struct nouveau_oclass
nve0_fifo_oclass = {
.handle = NV_ENGINE(FIFO, 0xe0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nve0_fifo_ctor,
.dtor = nve0_fifo_dtor,
.init = nve0_fifo_init,
.fini = _nouveau_fifo_fini,
},
};
+13 -13
View File
@@ -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;
@@ -22,6 +22,8 @@
* Authors: Ben Skeggs
*/
#include <core/gpuobj.h>
/* NVIDIA context programs handle a number of other conditions which are
* not implemented in our versions. It's not clear why NVIDIA context
* programs have this code, nor whether it's strictly necessary for
@@ -109,8 +111,7 @@
#define CP_LOAD_MAGIC_NV44TCL 0x00800029 /* per-vs state (0x4497) */
#define CP_LOAD_MAGIC_NV40TCL 0x00800041 /* per-vs state (0x4097) */
#include "drmP.h"
#include "nouveau_drv.h"
#include "nv40.h"
#include "ctx.h"
/* TODO:
@@ -118,11 +119,10 @@
*/
static int
nv40_graph_vs_count(struct drm_device *dev)
nv40_graph_vs_count(struct nouveau_device *device)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
switch (dev_priv->chipset) {
switch (device->chipset) {
case 0x47:
case 0x49:
case 0x4b:
@@ -160,7 +160,7 @@ enum cp_label {
static void
nv40_graph_construct_general(struct nouveau_grctx *ctx)
{
struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
struct nouveau_device *device = ctx->device;
int i;
cp_ctx(ctx, 0x4000a4, 1);
@@ -187,7 +187,7 @@ nv40_graph_construct_general(struct nouveau_grctx *ctx)
cp_ctx(ctx, 0x400724, 1);
gr_def(ctx, 0x400724, 0x02008821);
cp_ctx(ctx, 0x400770, 3);
if (dev_priv->chipset == 0x40) {
if (device->chipset == 0x40) {
cp_ctx(ctx, 0x400814, 4);
cp_ctx(ctx, 0x400828, 5);
cp_ctx(ctx, 0x400840, 5);
@@ -208,7 +208,7 @@ nv40_graph_construct_general(struct nouveau_grctx *ctx)
gr_def(ctx, 0x4009dc, 0x80000000);
} else {
cp_ctx(ctx, 0x400840, 20);
if (nv44_graph_class(ctx->dev)) {
if (nv44_graph_class(ctx->device)) {
for (i = 0; i < 8; i++)
gr_def(ctx, 0x400860 + (i * 4), 0x00000001);
}
@@ -217,21 +217,21 @@ nv40_graph_construct_general(struct nouveau_grctx *ctx)
gr_def(ctx, 0x400888, 0x00000040);
cp_ctx(ctx, 0x400894, 11);
gr_def(ctx, 0x400894, 0x00000040);
if (!nv44_graph_class(ctx->dev)) {
if (!nv44_graph_class(ctx->device)) {
for (i = 0; i < 8; i++)
gr_def(ctx, 0x4008a0 + (i * 4), 0x80000000);
}
cp_ctx(ctx, 0x4008e0, 2);
cp_ctx(ctx, 0x4008f8, 2);
if (dev_priv->chipset == 0x4c ||
(dev_priv->chipset & 0xf0) == 0x60)
if (device->chipset == 0x4c ||
(device->chipset & 0xf0) == 0x60)
cp_ctx(ctx, 0x4009f8, 1);
}
cp_ctx(ctx, 0x400a00, 73);
gr_def(ctx, 0x400b0c, 0x0b0b0b0c);
cp_ctx(ctx, 0x401000, 4);
cp_ctx(ctx, 0x405004, 1);
switch (dev_priv->chipset) {
switch (device->chipset) {
case 0x47:
case 0x49:
case 0x4b:
@@ -240,7 +240,7 @@ nv40_graph_construct_general(struct nouveau_grctx *ctx)
break;
default:
cp_ctx(ctx, 0x403440, 1);
switch (dev_priv->chipset) {
switch (device->chipset) {
case 0x40:
gr_def(ctx, 0x403440, 0x00000010);
break;
@@ -266,19 +266,19 @@ nv40_graph_construct_general(struct nouveau_grctx *ctx)
static void
nv40_graph_construct_state3d(struct nouveau_grctx *ctx)
{
struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
struct nouveau_device *device = ctx->device;
int i;
if (dev_priv->chipset == 0x40) {
if (device->chipset == 0x40) {
cp_ctx(ctx, 0x401880, 51);
gr_def(ctx, 0x401940, 0x00000100);
} else
if (dev_priv->chipset == 0x46 || dev_priv->chipset == 0x47 ||
dev_priv->chipset == 0x49 || dev_priv->chipset == 0x4b) {
if (device->chipset == 0x46 || device->chipset == 0x47 ||
device->chipset == 0x49 || device->chipset == 0x4b) {
cp_ctx(ctx, 0x401880, 32);
for (i = 0; i < 16; i++)
gr_def(ctx, 0x401880 + (i * 4), 0x00000111);
if (dev_priv->chipset == 0x46)
if (device->chipset == 0x46)
cp_ctx(ctx, 0x401900, 16);
cp_ctx(ctx, 0x401940, 3);
}
@@ -289,7 +289,7 @@ nv40_graph_construct_state3d(struct nouveau_grctx *ctx)
gr_def(ctx, 0x401978, 0xffff0000);
gr_def(ctx, 0x40197c, 0x00000001);
gr_def(ctx, 0x401990, 0x46400000);
if (dev_priv->chipset == 0x40) {
if (device->chipset == 0x40) {
cp_ctx(ctx, 0x4019a0, 2);
cp_ctx(ctx, 0x4019ac, 5);
} else {
@@ -297,7 +297,7 @@ nv40_graph_construct_state3d(struct nouveau_grctx *ctx)
cp_ctx(ctx, 0x4019b4, 3);
}
gr_def(ctx, 0x4019bc, 0xffff0000);
switch (dev_priv->chipset) {
switch (device->chipset) {
case 0x46:
case 0x47:
case 0x49:
@@ -316,7 +316,7 @@ nv40_graph_construct_state3d(struct nouveau_grctx *ctx)
for (i = 0; i < 16; i++)
gr_def(ctx, 0x401a44 + (i * 4), 0x07ff0000);
gr_def(ctx, 0x401a8c, 0x4b7fffff);
if (dev_priv->chipset == 0x40) {
if (device->chipset == 0x40) {
cp_ctx(ctx, 0x401ab8, 3);
} else {
cp_ctx(ctx, 0x401ab8, 1);
@@ -327,10 +327,10 @@ nv40_graph_construct_state3d(struct nouveau_grctx *ctx)
gr_def(ctx, 0x401ad4, 0x70605040);
gr_def(ctx, 0x401ad8, 0xb8a89888);
gr_def(ctx, 0x401adc, 0xf8e8d8c8);
cp_ctx(ctx, 0x401b10, dev_priv->chipset == 0x40 ? 2 : 1);
cp_ctx(ctx, 0x401b10, device->chipset == 0x40 ? 2 : 1);
gr_def(ctx, 0x401b10, 0x40100000);
cp_ctx(ctx, 0x401b18, dev_priv->chipset == 0x40 ? 6 : 5);
gr_def(ctx, 0x401b28, dev_priv->chipset == 0x40 ?
cp_ctx(ctx, 0x401b18, device->chipset == 0x40 ? 6 : 5);
gr_def(ctx, 0x401b28, device->chipset == 0x40 ?
0x00000004 : 0x00000000);
cp_ctx(ctx, 0x401b30, 25);
gr_def(ctx, 0x401b34, 0x0000ffff);
@@ -341,8 +341,8 @@ nv40_graph_construct_state3d(struct nouveau_grctx *ctx)
gr_def(ctx, 0x401b84, 0xffffffff);
gr_def(ctx, 0x401b88, 0x00ff7000);
gr_def(ctx, 0x401b8c, 0x0000ffff);
if (dev_priv->chipset != 0x44 && dev_priv->chipset != 0x4a &&
dev_priv->chipset != 0x4e)
if (device->chipset != 0x44 && device->chipset != 0x4a &&
device->chipset != 0x4e)
cp_ctx(ctx, 0x401b94, 1);
cp_ctx(ctx, 0x401b98, 8);
gr_def(ctx, 0x401b9c, 0x00ff0000);
@@ -371,12 +371,12 @@ nv40_graph_construct_state3d(struct nouveau_grctx *ctx)
static void
nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
{
struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
struct nouveau_device *device = ctx->device;
int i;
cp_ctx(ctx, 0x402000, 1);
cp_ctx(ctx, 0x402404, dev_priv->chipset == 0x40 ? 1 : 2);
switch (dev_priv->chipset) {
cp_ctx(ctx, 0x402404, device->chipset == 0x40 ? 1 : 2);
switch (device->chipset) {
case 0x40:
gr_def(ctx, 0x402404, 0x00000001);
break;
@@ -393,9 +393,9 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
default:
gr_def(ctx, 0x402404, 0x00000021);
}
if (dev_priv->chipset != 0x40)
if (device->chipset != 0x40)
gr_def(ctx, 0x402408, 0x030c30c3);
switch (dev_priv->chipset) {
switch (device->chipset) {
case 0x44:
case 0x46:
case 0x4a:
@@ -408,10 +408,10 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
default:
break;
}
cp_ctx(ctx, 0x402480, dev_priv->chipset == 0x40 ? 8 : 9);
cp_ctx(ctx, 0x402480, device->chipset == 0x40 ? 8 : 9);
gr_def(ctx, 0x402488, 0x3e020200);
gr_def(ctx, 0x40248c, 0x00ffffff);
switch (dev_priv->chipset) {
switch (device->chipset) {
case 0x40:
gr_def(ctx, 0x402490, 0x60103f00);
break;
@@ -428,16 +428,16 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
gr_def(ctx, 0x402490, 0x0c103f00);
break;
}
gr_def(ctx, 0x40249c, dev_priv->chipset <= 0x43 ?
gr_def(ctx, 0x40249c, device->chipset <= 0x43 ?
0x00020000 : 0x00040000);
cp_ctx(ctx, 0x402500, 31);
gr_def(ctx, 0x402530, 0x00008100);
if (dev_priv->chipset == 0x40)
if (device->chipset == 0x40)
cp_ctx(ctx, 0x40257c, 6);
cp_ctx(ctx, 0x402594, 16);
cp_ctx(ctx, 0x402800, 17);
gr_def(ctx, 0x402800, 0x00000001);
switch (dev_priv->chipset) {
switch (device->chipset) {
case 0x47:
case 0x49:
case 0x4b:
@@ -445,7 +445,7 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
gr_def(ctx, 0x402864, 0x00001001);
cp_ctx(ctx, 0x402870, 3);
gr_def(ctx, 0x402878, 0x00000003);
if (dev_priv->chipset != 0x47) { /* belong at end!! */
if (device->chipset != 0x47) { /* belong at end!! */
cp_ctx(ctx, 0x402900, 1);
cp_ctx(ctx, 0x402940, 1);
cp_ctx(ctx, 0x402980, 1);
@@ -470,9 +470,9 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
}
cp_ctx(ctx, 0x402c00, 4);
gr_def(ctx, 0x402c00, dev_priv->chipset == 0x40 ?
gr_def(ctx, 0x402c00, device->chipset == 0x40 ?
0x80800001 : 0x00888001);
switch (dev_priv->chipset) {
switch (device->chipset) {
case 0x47:
case 0x49:
case 0x4b:
@@ -485,30 +485,30 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
break;
default:
cp_ctx(ctx, 0x402c10, 4);
if (dev_priv->chipset == 0x40)
if (device->chipset == 0x40)
cp_ctx(ctx, 0x402c20, 36);
else
if (dev_priv->chipset <= 0x42)
if (device->chipset <= 0x42)
cp_ctx(ctx, 0x402c20, 24);
else
if (dev_priv->chipset <= 0x4a)
if (device->chipset <= 0x4a)
cp_ctx(ctx, 0x402c20, 16);
else
cp_ctx(ctx, 0x402c20, 8);
cp_ctx(ctx, 0x402cb0, dev_priv->chipset == 0x40 ? 12 : 13);
cp_ctx(ctx, 0x402cb0, device->chipset == 0x40 ? 12 : 13);
gr_def(ctx, 0x402cd4, 0x00000005);
if (dev_priv->chipset != 0x40)
if (device->chipset != 0x40)
gr_def(ctx, 0x402ce0, 0x0000ffff);
break;
}
cp_ctx(ctx, 0x403400, dev_priv->chipset == 0x40 ? 4 : 3);
cp_ctx(ctx, 0x403410, dev_priv->chipset == 0x40 ? 4 : 3);
cp_ctx(ctx, 0x403420, nv40_graph_vs_count(ctx->dev));
for (i = 0; i < nv40_graph_vs_count(ctx->dev); i++)
cp_ctx(ctx, 0x403400, device->chipset == 0x40 ? 4 : 3);
cp_ctx(ctx, 0x403410, device->chipset == 0x40 ? 4 : 3);
cp_ctx(ctx, 0x403420, nv40_graph_vs_count(ctx->device));
for (i = 0; i < nv40_graph_vs_count(ctx->device); i++)
gr_def(ctx, 0x403420 + (i * 4), 0x00005555);
if (dev_priv->chipset != 0x40) {
if (device->chipset != 0x40) {
cp_ctx(ctx, 0x403600, 1);
gr_def(ctx, 0x403600, 0x00000001);
}
@@ -516,7 +516,7 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
cp_ctx(ctx, 0x403c18, 1);
gr_def(ctx, 0x403c18, 0x00000001);
switch (dev_priv->chipset) {
switch (device->chipset) {
case 0x46:
case 0x47:
case 0x49:
@@ -527,7 +527,7 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
gr_def(ctx, 0x405c24, 0x000e3000);
break;
}
if (dev_priv->chipset != 0x4e)
if (device->chipset != 0x4e)
cp_ctx(ctx, 0x405800, 11);
cp_ctx(ctx, 0x407000, 1);
}
@@ -535,7 +535,7 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
static void
nv40_graph_construct_state3d_3(struct nouveau_grctx *ctx)
{
int len = nv44_graph_class(ctx->dev) ? 0x0084 : 0x0684;
int len = nv44_graph_class(ctx->device) ? 0x0084 : 0x0684;
cp_out (ctx, 0x300000);
cp_lsr (ctx, len - 4);
@@ -550,32 +550,31 @@ nv40_graph_construct_state3d_3(struct nouveau_grctx *ctx)
static void
nv40_graph_construct_shader(struct nouveau_grctx *ctx)
{
struct drm_device *dev = ctx->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_device *device = ctx->device;
struct nouveau_gpuobj *obj = ctx->data;
int vs, vs_nr, vs_len, vs_nr_b0, vs_nr_b1, b0_offset, b1_offset;
int offset, i;
vs_nr = nv40_graph_vs_count(ctx->dev);
vs_nr = nv40_graph_vs_count(ctx->device);
vs_nr_b0 = 363;
vs_nr_b1 = dev_priv->chipset == 0x40 ? 128 : 64;
if (dev_priv->chipset == 0x40) {
vs_nr_b1 = device->chipset == 0x40 ? 128 : 64;
if (device->chipset == 0x40) {
b0_offset = 0x2200/4; /* 33a0 */
b1_offset = 0x55a0/4; /* 1500 */
vs_len = 0x6aa0/4;
} else
if (dev_priv->chipset == 0x41 || dev_priv->chipset == 0x42) {
if (device->chipset == 0x41 || device->chipset == 0x42) {
b0_offset = 0x2200/4; /* 2200 */
b1_offset = 0x4400/4; /* 0b00 */
vs_len = 0x4f00/4;
} else {
b0_offset = 0x1d40/4; /* 2200 */
b1_offset = 0x3f40/4; /* 0b00 : 0a40 */
vs_len = nv44_graph_class(dev) ? 0x4980/4 : 0x4a40/4;
vs_len = nv44_graph_class(device) ? 0x4980/4 : 0x4a40/4;
}
cp_lsr(ctx, vs_len * vs_nr + 0x300/4);
cp_out(ctx, nv44_graph_class(dev) ? 0x800029 : 0x800041);
cp_out(ctx, nv44_graph_class(device) ? 0x800029 : 0x800041);
offset = ctx->ctxvals_pos;
ctx->ctxvals_pos += (0x0300/4 + (vs_nr * vs_len));
@@ -661,21 +660,21 @@ nv40_grctx_generate(struct nouveau_grctx *ctx)
}
void
nv40_grctx_fill(struct drm_device *dev, struct nouveau_gpuobj *mem)
nv40_grctx_fill(struct nouveau_device *device, struct nouveau_gpuobj *mem)
{
nv40_grctx_generate(&(struct nouveau_grctx) {
.dev = dev,
.device = device,
.mode = NOUVEAU_GRCTX_VALS,
.data = mem,
});
}
void
nv40_grctx_init(struct drm_device *dev, u32 *size)
nv40_grctx_init(struct nouveau_device *device, u32 *size)
{
u32 ctxprog[256], i;
struct nouveau_grctx ctx = {
.dev = dev,
.device = device,
.mode = NOUVEAU_GRCTX_PROG,
.data = ctxprog,
.ctxprog_max = ARRAY_SIZE(ctxprog)
@@ -683,8 +682,8 @@ nv40_grctx_init(struct drm_device *dev, u32 *size)
nv40_grctx_generate(&ctx);
nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
nv_wr32(device, 0x400324, 0);
for (i = 0; i < ctx.ctxprog_len; i++)
nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, ctxprog[i]);
nv_wr32(device, 0x400328, ctxprog[i]);
*size = ctx.ctxvals_pos * 4;
}
File diff suppressed because it is too large Load Diff
@@ -22,13 +22,10 @@
* Authors: Ben Skeggs
*/
#include "drmP.h"
#include "nouveau_drv.h"
#include <core/mm.h>
#include "nvc0.h"
void
nv_icmd(struct drm_device *priv, u32 icmd, u32 data)
nv_icmd(struct nvc0_graph_priv *priv, u32 icmd, u32 data)
{
nv_wr32(priv, 0x400204, data);
nv_wr32(priv, 0x400200, icmd);
@@ -36,21 +33,22 @@ nv_icmd(struct drm_device *priv, u32 icmd, u32 data)
}
int
nvc0_grctx_init(struct drm_device *priv, struct nvc0_graph_priv *oprv,
struct nvc0_grctx *info)
nvc0_grctx_init(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
{
struct nouveau_bar *bar = nouveau_bar(priv);
struct nouveau_object *parent = nv_object(priv);
struct nouveau_gpuobj *chan;
u32 size = (0x80000 + oprv->size + 4095) & ~4095;
u32 size = (0x80000 + priv->size + 4095) & ~4095;
int ret, i;
/* allocate memory to for a "channel", which we'll use to generate
* the default context values
*/
ret = nouveau_gpuobj_new(priv, NULL, size, 0x1000,
ret = nouveau_gpuobj_new(parent, NULL, size, 0x1000,
NVOBJ_FLAG_ZERO_ALLOC, &info->chan);
chan = info->chan;
if (ret) {
NV_ERROR(priv, "failed to allocate channel memory, %d\n", ret);
nv_error(priv, "failed to allocate channel memory, %d\n", ret);
return ret;
}
@@ -75,32 +73,31 @@ nvc0_grctx_init(struct drm_device *priv, struct nvc0_graph_priv *oprv,
nv_wo32(chan, 0x0210, 0x00080004);
nv_wo32(chan, 0x0214, 0x00000000);
nvimem_flush(priv);
bar->flush(bar);
nv_wr32(priv, 0x100cb8, (chan->addr + 0x1000) >> 8);
nv_wr32(priv, 0x100cbc, 0x80000001);
nv_wait(priv, 0x100c80, 0x00008000, 0x00008000);
/* setup default state for mmio list construction */
info->dev = priv;
info->data = oprv->mmio_data;
info->mmio = oprv->mmio_list;
info->data = priv->mmio_data;
info->mmio = priv->mmio_list;
info->addr = 0x2000 + (i * 8);
info->priv = oprv;
info->priv = priv;
info->buffer_nr = 0;
if (oprv->firmware) {
if (priv->firmware) {
nv_wr32(priv, 0x409840, 0x00000030);
nv_wr32(priv, 0x409500, 0x80000000 | chan->addr >> 12);
nv_wr32(priv, 0x409504, 0x00000003);
if (!nv_wait(priv, 0x409800, 0x00000010, 0x00000010))
NV_ERROR(priv, "load_ctx timeout\n");
nv_error(priv, "load_ctx timeout\n");
nv_wo32(chan, 0x8001c, 1);
nv_wo32(chan, 0x80020, 0);
nv_wo32(chan, 0x80028, 0);
nv_wo32(chan, 0x8002c, 0);
nvimem_flush(priv);
bar->flush(bar);
return 0;
}
@@ -109,7 +106,7 @@ nvc0_grctx_init(struct drm_device *priv, struct nvc0_graph_priv *oprv,
nv_wr32(priv, 0x409500, 0x80000000 | chan->addr >> 12);
nv_wr32(priv, 0x409504, 0x00000001);
if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000)) {
NV_ERROR(priv, "HUB_SET_CHAN timeout\n");
nv_error(priv, "HUB_SET_CHAN timeout\n");
nvc0_graph_ctxctl_debug(priv);
nouveau_gpuobj_ref(NULL, &info->chan);
return -EBUSY;
@@ -135,6 +132,8 @@ nvc0_grctx_data(struct nvc0_grctx *info, u32 size, u32 align, u32 access)
void
nvc0_grctx_mmio(struct nvc0_grctx *info, u32 addr, u32 data, u32 shift, u32 buf)
{
struct nvc0_graph_priv *priv = info->priv;
info->mmio->addr = addr;
info->mmio->data = data;
info->mmio->shift = shift;
@@ -143,7 +142,7 @@ nvc0_grctx_mmio(struct nvc0_grctx *info, u32 addr, u32 data, u32 shift, u32 buf)
if (shift)
data |= info->buffer[buf] >> shift;
nv_wr32(info->dev, addr, data);
nv_wr32(priv, addr, data);
}
int
@@ -153,11 +152,11 @@ nvc0_grctx_fini(struct nvc0_grctx *info)
int i;
if (priv->firmware) {
nv_wr32(info->dev, 0x409840, 0x00000003);
nv_wr32(info->dev, 0x409500, 0x80000000 | info->chan->addr >> 12);
nv_wr32(info->dev, 0x409504, 0x00000009);
if (!nv_wait(info->dev, 0x409800, 0x00000001, 0x00000000)) {
NV_ERROR(info->dev, "unload_ctx timeout\n");
nv_wr32(priv, 0x409840, 0x00000003);
nv_wr32(priv, 0x409500, 0x80000000 | info->chan->addr >> 12);
nv_wr32(priv, 0x409504, 0x00000009);
if (!nv_wait(priv, 0x409800, 0x00000001, 0x00000000)) {
nv_error(priv, "unload_ctx timeout\n");
return -EBUSY;
}
@@ -165,12 +164,12 @@ nvc0_grctx_fini(struct nvc0_grctx *info)
}
/* HUB_FUC(CTX_SAVE) */
nv_wr32(info->dev, 0x409840, 0x80000000);
nv_wr32(info->dev, 0x409500, 0x80000000 | info->chan->addr >> 12);
nv_wr32(info->dev, 0x409504, 0x00000002);
if (!nv_wait(info->dev, 0x409800, 0x80000000, 0x80000000)) {
NV_ERROR(info->dev, "HUB_CTX_SAVE timeout\n");
nvc0_graph_ctxctl_debug(info->dev);
nv_wr32(priv, 0x409840, 0x80000000);
nv_wr32(priv, 0x409500, 0x80000000 | info->chan->addr >> 12);
nv_wr32(priv, 0x409504, 0x00000002);
if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000)) {
nv_error(priv, "HUB_CTX_SAVE timeout\n");
nvc0_graph_ctxctl_debug(priv);
return -EBUSY;
}
@@ -186,7 +185,7 @@ save:
}
static void
nvc0_grctx_generate_9097(struct drm_device *priv)
nvc0_grctx_generate_9097(struct nvc0_graph_priv *priv)
{
u32 fermi = nvc0_graph_class(priv);
u32 mthd;
@@ -1343,7 +1342,7 @@ nvc0_grctx_generate_9097(struct drm_device *priv)
}
static void
nvc0_grctx_generate_9197(struct drm_device *priv)
nvc0_grctx_generate_9197(struct nvc0_graph_priv *priv)
{
u32 fermi = nvc0_graph_class(priv);
u32 mthd;
@@ -1356,7 +1355,7 @@ nvc0_grctx_generate_9197(struct drm_device *priv)
}
static void
nvc0_grctx_generate_9297(struct drm_device *priv)
nvc0_grctx_generate_9297(struct nvc0_graph_priv *priv)
{
u32 fermi = nvc0_graph_class(priv);
u32 mthd;
@@ -1374,7 +1373,7 @@ nvc0_grctx_generate_9297(struct drm_device *priv)
}
static void
nvc0_grctx_generate_902d(struct drm_device *priv)
nvc0_grctx_generate_902d(struct nvc0_graph_priv *priv)
{
nv_mthd(priv, 0x902d, 0x0200, 0x000000cf);
nv_mthd(priv, 0x902d, 0x0204, 0x00000001);
@@ -1396,7 +1395,7 @@ nvc0_grctx_generate_902d(struct drm_device *priv)
}
static void
nvc0_grctx_generate_9039(struct drm_device *priv)
nvc0_grctx_generate_9039(struct nvc0_graph_priv *priv)
{
nv_mthd(priv, 0x9039, 0x030c, 0x00000000);
nv_mthd(priv, 0x9039, 0x0310, 0x00000000);
@@ -1409,12 +1408,11 @@ nvc0_grctx_generate_9039(struct drm_device *priv)
}
static void
nvc0_grctx_generate_90c0(struct drm_device *priv)
nvc0_grctx_generate_90c0(struct nvc0_graph_priv *priv)
{
struct drm_nouveau_private *dev_priv = priv->dev_private;
int i;
for (i = 0; dev_priv->chipset == 0xd9 && i < 4; i++) {
for (i = 0; nv_device(priv)->chipset == 0xd9 && i < 4; i++) {
nv_mthd(priv, 0x90c0, 0x2700 + (i * 0x40), 0x00000000);
nv_mthd(priv, 0x90c0, 0x2720 + (i * 0x40), 0x00000000);
nv_mthd(priv, 0x90c0, 0x2704 + (i * 0x40), 0x00000000);
@@ -1430,7 +1428,7 @@ nvc0_grctx_generate_90c0(struct drm_device *priv)
nv_mthd(priv, 0x90c0, 0x27ac, 0x00000000);
nv_mthd(priv, 0x90c0, 0x27cc, 0x00000000);
nv_mthd(priv, 0x90c0, 0x27ec, 0x00000000);
for (i = 0; dev_priv->chipset == 0xd9 && i < 4; i++) {
for (i = 0; nv_device(priv)->chipset == 0xd9 && i < 4; i++) {
nv_mthd(priv, 0x90c0, 0x2710 + (i * 0x40), 0x00014000);
nv_mthd(priv, 0x90c0, 0x2730 + (i * 0x40), 0x00014000);
nv_mthd(priv, 0x90c0, 0x2714 + (i * 0x40), 0x00000040);
@@ -1458,7 +1456,7 @@ nvc0_grctx_generate_90c0(struct drm_device *priv)
}
static void
nvc0_grctx_generate_dispatch(struct drm_device *priv)
nvc0_grctx_generate_dispatch(struct nvc0_graph_priv *priv)
{
int i;
@@ -1511,7 +1509,7 @@ nvc0_grctx_generate_dispatch(struct drm_device *priv)
}
static void
nvc0_grctx_generate_macro(struct drm_device *priv)
nvc0_grctx_generate_macro(struct nvc0_graph_priv *priv)
{
nv_wr32(priv, 0x404404, 0x00000000);
nv_wr32(priv, 0x404408, 0x00000000);
@@ -1536,7 +1534,7 @@ nvc0_grctx_generate_macro(struct drm_device *priv)
}
static void
nvc0_grctx_generate_m2mf(struct drm_device *priv)
nvc0_grctx_generate_m2mf(struct nvc0_graph_priv *priv)
{
nv_wr32(priv, 0x404604, 0x00000015);
nv_wr32(priv, 0x404608, 0x00000000);
@@ -1600,7 +1598,7 @@ nvc0_grctx_generate_m2mf(struct drm_device *priv)
}
static void
nvc0_grctx_generate_unk47xx(struct drm_device *priv)
nvc0_grctx_generate_unk47xx(struct nvc0_graph_priv *priv)
{
nv_wr32(priv, 0x404700, 0x00000000);
nv_wr32(priv, 0x404704, 0x00000000);
@@ -1627,16 +1625,15 @@ nvc0_grctx_generate_unk47xx(struct drm_device *priv)
}
static void
nvc0_grctx_generate_shaders(struct drm_device *priv)
nvc0_grctx_generate_shaders(struct nvc0_graph_priv *priv)
{
struct drm_nouveau_private *dev_priv = priv->dev_private;
if (dev_priv->chipset == 0xd9) {
if (nv_device(priv)->chipset == 0xd9) {
nv_wr32(priv, 0x405800, 0x0f8000bf);
nv_wr32(priv, 0x405830, 0x02180218);
nv_wr32(priv, 0x405834, 0x08000000);
} else
if (dev_priv->chipset == 0xc1) {
if (nv_device(priv)->chipset == 0xc1) {
nv_wr32(priv, 0x405800, 0x0f8000bf);
nv_wr32(priv, 0x405830, 0x02180218);
nv_wr32(priv, 0x405834, 0x00000000);
@@ -1657,7 +1654,7 @@ nvc0_grctx_generate_shaders(struct drm_device *priv)
}
static void
nvc0_grctx_generate_unk60xx(struct drm_device *priv)
nvc0_grctx_generate_unk60xx(struct nvc0_graph_priv *priv)
{
nv_wr32(priv, 0x406020, 0x000103c1);
nv_wr32(priv, 0x406028, 0x00000001);
@@ -1667,25 +1664,24 @@ nvc0_grctx_generate_unk60xx(struct drm_device *priv)
}
static void
nvc0_grctx_generate_unk64xx(struct drm_device *priv)
nvc0_grctx_generate_unk64xx(struct nvc0_graph_priv *priv)
{
struct drm_nouveau_private *dev_priv = priv->dev_private;
nv_wr32(priv, 0x4064a8, 0x00000000);
nv_wr32(priv, 0x4064ac, 0x00003fff);
nv_wr32(priv, 0x4064b4, 0x00000000);
nv_wr32(priv, 0x4064b8, 0x00000000);
if (dev_priv->chipset == 0xd9)
if (nv_device(priv)->chipset == 0xd9)
nv_wr32(priv, 0x4064bc, 0x00000000);
if (dev_priv->chipset == 0xc1 ||
dev_priv->chipset == 0xd9) {
if (nv_device(priv)->chipset == 0xc1 ||
nv_device(priv)->chipset == 0xd9) {
nv_wr32(priv, 0x4064c0, 0x80140078);
nv_wr32(priv, 0x4064c4, 0x0086ffff);
}
}
static void
nvc0_grctx_generate_tpbus(struct drm_device *priv)
nvc0_grctx_generate_tpbus(struct nvc0_graph_priv *priv)
{
nv_wr32(priv, 0x407804, 0x00000023);
nv_wr32(priv, 0x40780c, 0x0a418820);
@@ -1698,7 +1694,7 @@ nvc0_grctx_generate_tpbus(struct drm_device *priv)
}
static void
nvc0_grctx_generate_ccache(struct drm_device *priv)
nvc0_grctx_generate_ccache(struct nvc0_graph_priv *priv)
{
nv_wr32(priv, 0x408000, 0x00000000);
nv_wr32(priv, 0x408004, 0x00000000);
@@ -1711,10 +1707,9 @@ nvc0_grctx_generate_ccache(struct drm_device *priv)
}
static void
nvc0_grctx_generate_rop(struct drm_device *priv)
nvc0_grctx_generate_rop(struct nvc0_graph_priv *priv)
{
struct drm_nouveau_private *dev_priv = priv->dev_private;
int chipset = dev_priv->chipset;
int chipset = nv_device(priv)->chipset;
/* ROPC_BROADCAST */
nv_wr32(priv, 0x408800, 0x02802a3c);
@@ -1741,10 +1736,9 @@ nvc0_grctx_generate_rop(struct drm_device *priv)
}
static void
nvc0_grctx_generate_gpc(struct drm_device *priv)
nvc0_grctx_generate_gpc(struct nvc0_graph_priv *priv)
{
struct drm_nouveau_private *dev_priv = priv->dev_private;
int chipset = dev_priv->chipset;
int chipset = nv_device(priv)->chipset;
int i;
/* GPC_BROADCAST */
@@ -1834,10 +1828,9 @@ nvc0_grctx_generate_gpc(struct drm_device *priv)
}
static void
nvc0_grctx_generate_tp(struct drm_device *priv)
nvc0_grctx_generate_tp(struct nvc0_graph_priv *priv)
{
struct drm_nouveau_private *dev_priv = priv->dev_private;
int chipset = dev_priv->chipset;
int chipset = nv_device(priv)->chipset;
/* GPC_BROADCAST.TP_BROADCAST */
nv_wr32(priv, 0x419818, 0x00000000);
@@ -1876,7 +1869,7 @@ nvc0_grctx_generate_tp(struct drm_device *priv)
nv_wr32(priv, 0x419c04, 0x00000006);
nv_wr32(priv, 0x419c08, 0x00000002);
nv_wr32(priv, 0x419c20, 0x00000000);
if (dev_priv->chipset == 0xd9) {
if (nv_device(priv)->chipset == 0xd9) {
nv_wr32(priv, 0x419c24, 0x00084210);
nv_wr32(priv, 0x419c28, 0x3cf3cf3c);
nv_wr32(priv, 0x419cb0, 0x00020048);
@@ -1929,16 +1922,14 @@ nvc0_grctx_generate_tp(struct drm_device *priv)
}
int
nvc0_grctx_generate(struct drm_device *priv)
nvc0_grctx_generate(struct nvc0_graph_priv *priv)
{
struct drm_nouveau_private *dev_priv = priv->dev_private;
struct nvc0_graph_priv *oprv = nv_engine(priv, NVOBJ_ENGINE_GR);
struct nvc0_grctx info;
int ret, i, gpc, tpc, id;
u32 fermi = nvc0_graph_class(priv);
u32 r000260, tmp;
ret = nvc0_grctx_init(priv, oprv, &info);
ret = nvc0_grctx_init(priv, &info);
if (ret)
return ret;
@@ -1975,11 +1966,11 @@ nvc0_grctx_generate(struct drm_device *priv)
mmio_list(0x419008, 0x00000000, 0, 0);
mmio_list(0x418808, 0x00000000, 8, 0);
mmio_list(0x41880c, 0x80000018, 0, 0);
if (dev_priv->chipset != 0xc1) {
if (nv_device(priv)->chipset != 0xc1) {
tmp = 0x02180000;
mmio_list(0x405830, tmp, 0, 0);
for (gpc = 0; gpc < oprv->gpc_nr; gpc++) {
for (tpc = 0; tpc < oprv->tpc_nr[gpc]; tpc++) {
for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
u32 reg = TPC_UNIT(gpc, tpc, 0x0520);
mmio_list(reg, tmp, 0, 0);
tmp += 0x0324;
@@ -1989,13 +1980,13 @@ nvc0_grctx_generate(struct drm_device *priv)
tmp = 0x02180000;
mmio_list(0x405830, 0x00000218 | tmp, 0, 0);
mmio_list(0x4064c4, 0x0086ffff, 0, 0);
for (gpc = 0; gpc < oprv->gpc_nr; gpc++) {
for (tpc = 0; tpc < oprv->tpc_nr[gpc]; tpc++) {
for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
u32 reg = TPC_UNIT(gpc, tpc, 0x0520);
mmio_list(reg, 0x10000000 | tmp, 0, 0);
tmp += 0x0324;
}
for (tpc = 0; tpc < oprv->tpc_nr[gpc]; tpc++) {
for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
u32 reg = TPC_UNIT(gpc, tpc, 0x0544);
mmio_list(reg, tmp, 0, 0);
tmp += 0x0324;
@@ -2004,8 +1995,8 @@ nvc0_grctx_generate(struct drm_device *priv)
}
for (tpc = 0, id = 0; tpc < 4; tpc++) {
for (gpc = 0; gpc < oprv->gpc_nr; gpc++) {
if (tpc < oprv->tpc_nr[gpc]) {
for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
if (tpc < priv->tpc_nr[gpc]) {
nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x698), id);
nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x4e8), id);
nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id);
@@ -2013,14 +2004,14 @@ nvc0_grctx_generate(struct drm_device *priv)
id++;
}
nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), oprv->tpc_nr[gpc]);
nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), oprv->tpc_nr[gpc]);
nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), priv->tpc_nr[gpc]);
nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), priv->tpc_nr[gpc]);
}
}
tmp = 0;
for (i = 0; i < oprv->gpc_nr; i++)
tmp |= oprv->tpc_nr[i] << (i * 4);
for (i = 0; i < priv->gpc_nr; i++)
tmp |= priv->tpc_nr[i] << (i * 4);
nv_wr32(priv, 0x406028, tmp);
nv_wr32(priv, 0x405870, tmp);
@@ -2034,13 +2025,13 @@ nvc0_grctx_generate(struct drm_device *priv)
if (1) {
u8 tpcnr[GPC_MAX], data[TPC_MAX];
memcpy(tpcnr, oprv->tpc_nr, sizeof(oprv->tpc_nr));
memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
memset(data, 0x1f, sizeof(data));
gpc = -1;
for (tpc = 0; tpc < oprv->tpc_total; tpc++) {
for (tpc = 0; tpc < priv->tpc_total; tpc++) {
do {
gpc = (gpc + 1) % oprv->gpc_nr;
gpc = (gpc + 1) % priv->gpc_nr;
} while (!tpcnr[gpc]);
tpcnr[gpc]--;
data[tpc] = gpc;
@@ -2056,12 +2047,12 @@ nvc0_grctx_generate(struct drm_device *priv)
u8 shift, ntpcv;
/* calculate first set of magics */
memcpy(tpcnr, oprv->tpc_nr, sizeof(oprv->tpc_nr));
memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
gpc = -1;
for (tpc = 0; tpc < oprv->tpc_total; tpc++) {
for (tpc = 0; tpc < priv->tpc_total; tpc++) {
do {
gpc = (gpc + 1) % oprv->gpc_nr;
gpc = (gpc + 1) % priv->gpc_nr;
} while (!tpcnr[gpc]);
tpcnr[gpc]--;
@@ -2073,7 +2064,7 @@ nvc0_grctx_generate(struct drm_device *priv)
/* and the second... */
shift = 0;
ntpcv = oprv->tpc_total;
ntpcv = priv->tpc_total;
while (!(ntpcv & (1 << 4))) {
ntpcv <<= 1;
shift++;
@@ -2086,22 +2077,22 @@ nvc0_grctx_generate(struct drm_device *priv)
data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5);
/* GPC_BROADCAST */
nv_wr32(priv, 0x418bb8, (oprv->tpc_total << 8) |
oprv->magic_not_rop_nr);
nv_wr32(priv, 0x418bb8, (priv->tpc_total << 8) |
priv->magic_not_rop_nr);
for (i = 0; i < 6; i++)
nv_wr32(priv, 0x418b08 + (i * 4), data[i]);
/* GPC_BROADCAST.TP_BROADCAST */
nv_wr32(priv, 0x419bd0, (oprv->tpc_total << 8) |
oprv->magic_not_rop_nr |
nv_wr32(priv, 0x419bd0, (priv->tpc_total << 8) |
priv->magic_not_rop_nr |
data2[0]);
nv_wr32(priv, 0x419be4, data2[1]);
for (i = 0; i < 6; i++)
nv_wr32(priv, 0x419b00 + (i * 4), data[i]);
/* UNK78xx */
nv_wr32(priv, 0x4078bc, (oprv->tpc_total << 8) |
oprv->magic_not_rop_nr);
nv_wr32(priv, 0x4078bc, (priv->tpc_total << 8) |
priv->magic_not_rop_nr);
for (i = 0; i < 6; i++)
nv_wr32(priv, 0x40780c + (i * 4), data[i]);
}
@@ -2110,18 +2101,18 @@ nvc0_grctx_generate(struct drm_device *priv)
u32 tpc_mask = 0, tpc_set = 0;
u8 tpcnr[GPC_MAX], a, b;
memcpy(tpcnr, oprv->tpc_nr, sizeof(oprv->tpc_nr));
for (gpc = 0; gpc < oprv->gpc_nr; gpc++)
tpc_mask |= ((1 << oprv->tpc_nr[gpc]) - 1) << (gpc * 8);
memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
for (gpc = 0; gpc < priv->gpc_nr; gpc++)
tpc_mask |= ((1 << priv->tpc_nr[gpc]) - 1) << (gpc * 8);
for (i = 0, gpc = -1, b = -1; i < 32; i++) {
a = (i * (oprv->tpc_total - 1)) / 32;
a = (i * (priv->tpc_total - 1)) / 32;
if (a != b) {
b = a;
do {
gpc = (gpc + 1) % oprv->gpc_nr;
gpc = (gpc + 1) % priv->gpc_nr;
} while (!tpcnr[gpc]);
tpc = oprv->tpc_nr[gpc] - tpcnr[gpc]--;
tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
tpc_set |= 1 << ((gpc * 8) + tpc);
}
@@ -2232,7 +2223,7 @@ nvc0_grctx_generate(struct drm_device *priv)
nv_icmd(priv, 0x00000215, 0x00000040);
nv_icmd(priv, 0x00000216, 0x00000040);
nv_icmd(priv, 0x00000217, 0x00000040);
if (dev_priv->chipset == 0xd9) {
if (nv_device(priv)->chipset == 0xd9) {
for (i = 0x0400; i <= 0x0417; i++)
nv_icmd(priv, i, 0x00000040);
}
@@ -2244,7 +2235,7 @@ nvc0_grctx_generate(struct drm_device *priv)
nv_icmd(priv, 0x0000021d, 0x0000c080);
nv_icmd(priv, 0x0000021e, 0x0000c080);
nv_icmd(priv, 0x0000021f, 0x0000c080);
if (dev_priv->chipset == 0xd9) {
if (nv_device(priv)->chipset == 0xd9) {
for (i = 0x0440; i <= 0x0457; i++)
nv_icmd(priv, i, 0x0000c080);
}
@@ -2810,8 +2801,8 @@ nvc0_grctx_generate(struct drm_device *priv)
nv_icmd(priv, 0x0000053f, 0xffff0000);
nv_icmd(priv, 0x00000585, 0x0000003f);
nv_icmd(priv, 0x00000576, 0x00000003);
if (dev_priv->chipset == 0xc1 ||
dev_priv->chipset == 0xd9)
if (nv_device(priv)->chipset == 0xc1 ||
nv_device(priv)->chipset == 0xd9)
nv_icmd(priv, 0x0000057b, 0x00000059);
nv_icmd(priv, 0x00000586, 0x00000040);
nv_icmd(priv, 0x00000582, 0x00000080);
@@ -2913,7 +2904,7 @@ nvc0_grctx_generate(struct drm_device *priv)
nv_icmd(priv, 0x00000957, 0x00000003);
nv_icmd(priv, 0x0000095e, 0x20164010);
nv_icmd(priv, 0x0000095f, 0x00000020);
if (dev_priv->chipset == 0xd9)
if (nv_device(priv)->chipset == 0xd9)
nv_icmd(priv, 0x0000097d, 0x00000020);
nv_icmd(priv, 0x00000683, 0x00000006);
nv_icmd(priv, 0x00000685, 0x003fffff);
@@ -3056,5 +3047,6 @@ nvc0_grctx_generate(struct drm_device *priv)
nvc0_grctx_generate_90c0(priv);
nv_wr32(priv, 0x000260, r000260);
return nvc0_grctx_fini(&info);
}
@@ -22,13 +22,10 @@
* Authors: Ben Skeggs
*/
#include "drmP.h"
#include "nouveau_drv.h"
#include <core/mm.h>
#include "nvc0.h"
static void
nve0_grctx_generate_icmd(struct drm_device *priv)
nve0_grctx_generate_icmd(struct nvc0_graph_priv *priv)
{
nv_wr32(priv, 0x400208, 0x80000000);
nv_icmd(priv, 0x001000, 0x00000004);
@@ -916,7 +913,7 @@ nve0_grctx_generate_icmd(struct drm_device *priv)
}
static void
nve0_grctx_generate_a097(struct drm_device *priv)
nve0_grctx_generate_a097(struct nvc0_graph_priv *priv)
{
nv_mthd(priv, 0xa097, 0x0800, 0x00000000);
nv_mthd(priv, 0xa097, 0x0840, 0x00000000);
@@ -2146,7 +2143,7 @@ nve0_grctx_generate_a097(struct drm_device *priv)
}
static void
nve0_grctx_generate_902d(struct drm_device *priv)
nve0_grctx_generate_902d(struct nvc0_graph_priv *priv)
{
nv_mthd(priv, 0x902d, 0x0200, 0x000000cf);
nv_mthd(priv, 0x902d, 0x0204, 0x00000001);
@@ -2169,7 +2166,7 @@ nve0_grctx_generate_902d(struct drm_device *priv)
}
static void
nve0_graph_generate_unk40xx(struct drm_device *priv)
nve0_graph_generate_unk40xx(struct nvc0_graph_priv *priv)
{
nv_wr32(priv, 0x404010, 0x0);
nv_wr32(priv, 0x404014, 0x0);
@@ -2213,7 +2210,7 @@ nve0_graph_generate_unk40xx(struct drm_device *priv)
}
static void
nve0_graph_generate_unk44xx(struct drm_device *priv)
nve0_graph_generate_unk44xx(struct nvc0_graph_priv *priv)
{
nv_wr32(priv, 0x404404, 0x0);
nv_wr32(priv, 0x404408, 0x0);
@@ -2238,7 +2235,7 @@ nve0_graph_generate_unk44xx(struct drm_device *priv)
}
static void
nve0_graph_generate_unk46xx(struct drm_device *priv)
nve0_graph_generate_unk46xx(struct nvc0_graph_priv *priv)
{
nv_wr32(priv, 0x404604, 0x14);
nv_wr32(priv, 0x404608, 0x0);
@@ -2278,7 +2275,7 @@ nve0_graph_generate_unk46xx(struct drm_device *priv)
}
static void
nve0_graph_generate_unk47xx(struct drm_device *priv)
nve0_graph_generate_unk47xx(struct nvc0_graph_priv *priv)
{
nv_wr32(priv, 0x404700, 0x0);
nv_wr32(priv, 0x404704, 0x0);
@@ -2299,7 +2296,7 @@ nve0_graph_generate_unk47xx(struct drm_device *priv)
}
static void
nve0_graph_generate_unk58xx(struct drm_device *priv)
nve0_graph_generate_unk58xx(struct nvc0_graph_priv *priv)
{
nv_wr32(priv, 0x405800, 0xf8000bf);
nv_wr32(priv, 0x405830, 0x2180648);
@@ -2318,7 +2315,7 @@ nve0_graph_generate_unk58xx(struct drm_device *priv)
}
static void
nve0_graph_generate_unk60xx(struct drm_device *priv)
nve0_graph_generate_unk60xx(struct nvc0_graph_priv *priv)
{
nv_wr32(priv, 0x406020, 0x4103c1);
nv_wr32(priv, 0x406028, 0x1);
@@ -2328,7 +2325,7 @@ nve0_graph_generate_unk60xx(struct drm_device *priv)
}
static void
nve0_graph_generate_unk64xx(struct drm_device *priv)
nve0_graph_generate_unk64xx(struct nvc0_graph_priv *priv)
{
nv_wr32(priv, 0x4064a8, 0x0);
nv_wr32(priv, 0x4064ac, 0x3fff);
@@ -2350,13 +2347,13 @@ nve0_graph_generate_unk64xx(struct drm_device *priv)
}
static void
nve0_graph_generate_unk70xx(struct drm_device *priv)
nve0_graph_generate_unk70xx(struct nvc0_graph_priv *priv)
{
nv_wr32(priv, 0x407040, 0x0);
}
static void
nve0_graph_generate_unk78xx(struct drm_device *priv)
nve0_graph_generate_unk78xx(struct nvc0_graph_priv *priv)
{
nv_wr32(priv, 0x407804, 0x23);
nv_wr32(priv, 0x40780c, 0xa418820);
@@ -2369,7 +2366,7 @@ nve0_graph_generate_unk78xx(struct drm_device *priv)
}
static void
nve0_graph_generate_unk80xx(struct drm_device *priv)
nve0_graph_generate_unk80xx(struct nvc0_graph_priv *priv)
{
nv_wr32(priv, 0x408000, 0x0);
nv_wr32(priv, 0x408004, 0x0);
@@ -2382,7 +2379,7 @@ nve0_graph_generate_unk80xx(struct drm_device *priv)
}
static void
nve0_graph_generate_unk88xx(struct drm_device *priv)
nve0_graph_generate_unk88xx(struct nvc0_graph_priv *priv)
{
nv_wr32(priv, 0x408800, 0x2802a3c);
nv_wr32(priv, 0x408804, 0x40);
@@ -2395,7 +2392,7 @@ nve0_graph_generate_unk88xx(struct drm_device *priv)
}
static void
nve0_graph_generate_gpc(struct drm_device *priv)
nve0_graph_generate_gpc(struct nvc0_graph_priv *priv)
{
nv_wr32(priv, 0x418380, 0x16);
nv_wr32(priv, 0x418400, 0x38004e00);
@@ -2521,7 +2518,7 @@ nve0_graph_generate_gpc(struct drm_device *priv)
}
static void
nve0_graph_generate_tpc(struct drm_device *priv)
nve0_graph_generate_tpc(struct nvc0_graph_priv *priv)
{
nv_wr32(priv, 0x419848, 0x0);
nv_wr32(priv, 0x419864, 0x129);
@@ -2586,7 +2583,7 @@ nve0_graph_generate_tpc(struct drm_device *priv)
}
static void
nve0_graph_generate_tpcunk(struct drm_device *priv)
nve0_graph_generate_tpcunk(struct nvc0_graph_priv *priv)
{
nv_wr32(priv, 0x41be24, 0x6);
nv_wr32(priv, 0x41bec0, 0x12180000);
@@ -2604,9 +2601,8 @@ nve0_graph_generate_tpcunk(struct drm_device *priv)
}
int
nve0_grctx_generate(struct drm_device *priv)
nve0_grctx_generate(struct nvc0_graph_priv *priv)
{
struct nvc0_graph_priv *oprv = nv_engine(priv, NVOBJ_ENGINE_GR);
struct nvc0_grctx info;
int ret, i, gpc, tpc, id;
u32 data[6] = {}, data2[2] = {}, tmp;
@@ -2615,7 +2611,7 @@ nve0_grctx_generate(struct drm_device *priv)
u8 tpcnr[GPC_MAX], a, b;
u8 shift, ntpcv;
ret = nvc0_grctx_init(priv, oprv, &info);
ret = nvc0_grctx_init(priv, &info);
if (ret)
return ret;
@@ -2657,17 +2653,17 @@ nve0_grctx_generate(struct drm_device *priv)
mmio_list(0x419848, 0x10000000, 12, 2);
mmio_list(0x405830, 0x02180648, 0, 0);
mmio_list(0x4064c4, 0x0192ffff, 0, 0);
for (gpc = 0, offset = 0; gpc < oprv->gpc_nr; gpc++) {
u16 magic0 = 0x0218 * oprv->tpc_nr[gpc];
u16 magic1 = 0x0648 * oprv->tpc_nr[gpc];
for (gpc = 0, offset = 0; gpc < priv->gpc_nr; gpc++) {
u16 magic0 = 0x0218 * priv->tpc_nr[gpc];
u16 magic1 = 0x0648 * priv->tpc_nr[gpc];
magic[gpc][0] = 0x10000000 | (magic0 << 16) | offset;
magic[gpc][1] = 0x00000000 | (magic1 << 16);
offset += 0x0324 * oprv->tpc_nr[gpc];
offset += 0x0324 * priv->tpc_nr[gpc];
}
for (gpc = 0; gpc < oprv->gpc_nr; gpc++) {
for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
mmio_list(GPC_UNIT(gpc, 0x30c0), magic[gpc][0], 0, 0);
mmio_list(GPC_UNIT(gpc, 0x30e4), magic[gpc][1] | offset, 0, 0);
offset += 0x07ff * oprv->tpc_nr[gpc];
offset += 0x07ff * priv->tpc_nr[gpc];
}
mmio_list(0x17e91c, 0x06060609, 0, 0);
mmio_list(0x17e920, 0x00090a05, 0, 0);
@@ -2680,22 +2676,22 @@ nve0_grctx_generate(struct drm_device *priv)
nv_wr32(priv, 0x419c00, 0xa);
for (tpc = 0, id = 0; tpc < 4; tpc++) {
for (gpc = 0; gpc < oprv->gpc_nr; gpc++) {
if (tpc < oprv->tpc_nr[gpc]) {
for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
if (tpc < priv->tpc_nr[gpc]) {
nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0698), id);
nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x04e8), id);
nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id);
nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0088), id++);
}
nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), oprv->tpc_nr[gpc]);
nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), oprv->tpc_nr[gpc]);
nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), priv->tpc_nr[gpc]);
nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), priv->tpc_nr[gpc]);
}
}
tmp = 0;
for (i = 0; i < oprv->gpc_nr; i++)
tmp |= oprv->tpc_nr[i] << (i * 4);
for (i = 0; i < priv->gpc_nr; i++)
tmp |= priv->tpc_nr[i] << (i * 4);
nv_wr32(priv, 0x406028, tmp);
nv_wr32(priv, 0x405870, tmp);
@@ -2707,12 +2703,12 @@ nve0_grctx_generate(struct drm_device *priv)
nv_wr32(priv, 0x40587c, 0x0);
/* calculate first set of magics */
memcpy(tpcnr, oprv->tpc_nr, sizeof(oprv->tpc_nr));
memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
gpc = -1;
for (tpc = 0; tpc < oprv->tpc_total; tpc++) {
for (tpc = 0; tpc < priv->tpc_total; tpc++) {
do {
gpc = (gpc + 1) % oprv->gpc_nr;
gpc = (gpc + 1) % priv->gpc_nr;
} while (!tpcnr[gpc]);
tpcnr[gpc]--;
@@ -2724,7 +2720,7 @@ nve0_grctx_generate(struct drm_device *priv)
/* and the second... */
shift = 0;
ntpcv = oprv->tpc_total;
ntpcv = priv->tpc_total;
while (!(ntpcv & (1 << 4))) {
ntpcv <<= 1;
shift++;
@@ -2733,13 +2729,13 @@ nve0_grctx_generate(struct drm_device *priv)
data2[0] = ntpcv << 16;
data2[0] |= shift << 21;
data2[0] |= (((1 << (0 + 5)) % ntpcv) << 24);
data2[0] |= oprv->tpc_total << 8;
data2[0] |= oprv->magic_not_rop_nr;
data2[0] |= priv->tpc_total << 8;
data2[0] |= priv->magic_not_rop_nr;
for (i = 1; i < 7; i++)
data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5);
/* and write it all the various parts of PGRAPH */
nv_wr32(priv, 0x418bb8, (oprv->tpc_total << 8) | oprv->magic_not_rop_nr);
nv_wr32(priv, 0x418bb8, (priv->tpc_total << 8) | priv->magic_not_rop_nr);
for (i = 0; i < 6; i++)
nv_wr32(priv, 0x418b08 + (i * 4), data[i]);
@@ -2748,23 +2744,23 @@ nve0_grctx_generate(struct drm_device *priv)
for (i = 0; i < 6; i++)
nv_wr32(priv, 0x41bf00 + (i * 4), data[i]);
nv_wr32(priv, 0x4078bc, (oprv->tpc_total << 8) | oprv->magic_not_rop_nr);
nv_wr32(priv, 0x4078bc, (priv->tpc_total << 8) | priv->magic_not_rop_nr);
for (i = 0; i < 6; i++)
nv_wr32(priv, 0x40780c + (i * 4), data[i]);
memcpy(tpcnr, oprv->tpc_nr, sizeof(oprv->tpc_nr));
for (gpc = 0; gpc < oprv->gpc_nr; gpc++)
tpc_mask |= ((1 << oprv->tpc_nr[gpc]) - 1) << (gpc * 8);
memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
for (gpc = 0; gpc < priv->gpc_nr; gpc++)
tpc_mask |= ((1 << priv->tpc_nr[gpc]) - 1) << (gpc * 8);
for (i = 0, gpc = -1, b = -1; i < 32; i++) {
a = (i * (oprv->tpc_total - 1)) / 32;
a = (i * (priv->tpc_total - 1)) / 32;
if (a != b) {
b = a;
do {
gpc = (gpc + 1) % oprv->gpc_nr;
gpc = (gpc + 1) % priv->gpc_nr;
} while (!tpcnr[gpc]);
tpc = oprv->tpc_nr[gpc] - tpcnr[gpc]--;
tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
tpc_set |= 1 << ((gpc * 8) + tpc);
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,31 @@
#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
@@ -0,0 +1,167 @@
#include <core/os.h>
#include <core/class.h>
#include <core/engctx.h>
#include <core/enum.h>
#include <subdev/timer.h>
#include <subdev/fb.h>
#include <engine/graph.h>
#include "nv20.h"
#include "regs.h"
/*******************************************************************************
* Graphics object classes
******************************************************************************/
struct nouveau_oclass
nv25_graph_sclass[] = {
{ 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */
{ 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */
{ 0x0030, &nv04_graph_ofuncs, NULL }, /* null */
{ 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */
{ 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */
{ 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */
{ 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */
{ 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */
{ 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */
{ 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */
{ 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */
{ 0x0096, &nv04_graph_ofuncs, NULL }, /* celcius */
{ 0x009e, &nv04_graph_ofuncs, NULL }, /* swzsurf */
{ 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */
{ 0x0597, &nv04_graph_ofuncs, NULL }, /* kelvin */
{},
};
/*******************************************************************************
* PGRAPH context
******************************************************************************/
static int
nv25_graph_context_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv20_graph_chan *chan;
int ret, i;
ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x3724,
16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
chan->chid = nouveau_fifo_chan(parent)->chid;
nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
nv_wo32(chan, 0x035c, 0xffff0000);
nv_wo32(chan, 0x03c0, 0x0fff0000);
nv_wo32(chan, 0x03c4, 0x0fff0000);
nv_wo32(chan, 0x049c, 0x00000101);
nv_wo32(chan, 0x04b0, 0x00000111);
nv_wo32(chan, 0x04c8, 0x00000080);
nv_wo32(chan, 0x04cc, 0xffff0000);
nv_wo32(chan, 0x04d0, 0x00000001);
nv_wo32(chan, 0x04e4, 0x44400000);
nv_wo32(chan, 0x04fc, 0x4b800000);
for (i = 0x0510; i <= 0x051c; i += 4)
nv_wo32(chan, i, 0x00030303);
for (i = 0x0530; i <= 0x053c; i += 4)
nv_wo32(chan, i, 0x00080000);
for (i = 0x0548; i <= 0x0554; i += 4)
nv_wo32(chan, i, 0x01012000);
for (i = 0x0558; i <= 0x0564; i += 4)
nv_wo32(chan, i, 0x000105b8);
for (i = 0x0568; i <= 0x0574; i += 4)
nv_wo32(chan, i, 0x00080008);
for (i = 0x0598; i <= 0x05d4; i += 4)
nv_wo32(chan, i, 0x07ff0000);
nv_wo32(chan, 0x05e0, 0x4b7fffff);
nv_wo32(chan, 0x0620, 0x00000080);
nv_wo32(chan, 0x0624, 0x30201000);
nv_wo32(chan, 0x0628, 0x70605040);
nv_wo32(chan, 0x062c, 0xb0a09080);
nv_wo32(chan, 0x0630, 0xf0e0d0c0);
nv_wo32(chan, 0x0664, 0x00000001);
nv_wo32(chan, 0x066c, 0x00004000);
nv_wo32(chan, 0x0678, 0x00000001);
nv_wo32(chan, 0x0680, 0x00040000);
nv_wo32(chan, 0x0684, 0x00010000);
for (i = 0x1b04; i <= 0x2374; i += 16) {
nv_wo32(chan, (i + 0), 0x10700ff9);
nv_wo32(chan, (i + 4), 0x0436086c);
nv_wo32(chan, (i + 8), 0x000c001b);
}
nv_wo32(chan, 0x2704, 0x3f800000);
nv_wo32(chan, 0x2718, 0x3f800000);
nv_wo32(chan, 0x2744, 0x40000000);
nv_wo32(chan, 0x2748, 0x3f800000);
nv_wo32(chan, 0x274c, 0x3f000000);
nv_wo32(chan, 0x2754, 0x40000000);
nv_wo32(chan, 0x2758, 0x3f800000);
nv_wo32(chan, 0x2760, 0xbf800000);
nv_wo32(chan, 0x2768, 0xbf800000);
nv_wo32(chan, 0x308c, 0x000fe000);
nv_wo32(chan, 0x3108, 0x000003f8);
nv_wo32(chan, 0x3468, 0x002fe000);
for (i = 0x3484; i <= 0x34a0; i += 4)
nv_wo32(chan, i, 0x001c527c);
return 0;
}
static struct nouveau_oclass
nv25_graph_cclass = {
.handle = NV_ENGCTX(GR, 0x25),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv25_graph_context_ctor,
.dtor = _nouveau_graph_context_dtor,
.init = nv20_graph_context_init,
.fini = nv20_graph_context_fini,
.rd32 = _nouveau_graph_context_rd32,
.wr32 = _nouveau_graph_context_wr32,
},
};
/*******************************************************************************
* PGRAPH engine/subdev functions
******************************************************************************/
static int
nv25_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv20_graph_priv *priv;
int ret;
ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
ret = nouveau_gpuobj_new(parent, NULL, 32 * 4, 16,
NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00001000;
nv_subdev(priv)->intr = nv20_graph_intr;
nv_engine(priv)->cclass = &nv25_graph_cclass;
nv_engine(priv)->sclass = nv25_graph_sclass;
nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
return 0;
}
struct nouveau_oclass
nv25_graph_oclass = {
.handle = NV_ENGINE(GR, 0x25),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv25_graph_ctor,
.dtor = nv20_graph_dtor,
.init = nv20_graph_init,
.fini = _nouveau_graph_fini,
},
};
@@ -0,0 +1,134 @@
#include <core/os.h>
#include <core/class.h>
#include <core/engctx.h>
#include <core/enum.h>
#include <subdev/timer.h>
#include <subdev/fb.h>
#include <engine/graph.h>
#include "nv20.h"
#include "regs.h"
/*******************************************************************************
* PGRAPH context
******************************************************************************/
static int
nv2a_graph_context_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv20_graph_chan *chan;
int ret, i;
ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x36b0,
16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
chan->chid = nouveau_fifo_chan(parent)->chid;
nv_wo32(chan, 0x0000, 0x00000001 | (chan->chid << 24));
nv_wo32(chan, 0x033c, 0xffff0000);
nv_wo32(chan, 0x03a0, 0x0fff0000);
nv_wo32(chan, 0x03a4, 0x0fff0000);
nv_wo32(chan, 0x047c, 0x00000101);
nv_wo32(chan, 0x0490, 0x00000111);
nv_wo32(chan, 0x04a8, 0x44400000);
for (i = 0x04d4; i <= 0x04e0; i += 4)
nv_wo32(chan, i, 0x00030303);
for (i = 0x04f4; i <= 0x0500; i += 4)
nv_wo32(chan, i, 0x00080000);
for (i = 0x050c; i <= 0x0518; i += 4)
nv_wo32(chan, i, 0x01012000);
for (i = 0x051c; i <= 0x0528; i += 4)
nv_wo32(chan, i, 0x000105b8);
for (i = 0x052c; i <= 0x0538; i += 4)
nv_wo32(chan, i, 0x00080008);
for (i = 0x055c; i <= 0x0598; i += 4)
nv_wo32(chan, i, 0x07ff0000);
nv_wo32(chan, 0x05a4, 0x4b7fffff);
nv_wo32(chan, 0x05fc, 0x00000001);
nv_wo32(chan, 0x0604, 0x00004000);
nv_wo32(chan, 0x0610, 0x00000001);
nv_wo32(chan, 0x0618, 0x00040000);
nv_wo32(chan, 0x061c, 0x00010000);
for (i = 0x1a9c; i <= 0x22fc; i += 16) { /*XXX: check!! */
nv_wo32(chan, (i + 0), 0x10700ff9);
nv_wo32(chan, (i + 4), 0x0436086c);
nv_wo32(chan, (i + 8), 0x000c001b);
}
nv_wo32(chan, 0x269c, 0x3f800000);
nv_wo32(chan, 0x26b0, 0x3f800000);
nv_wo32(chan, 0x26dc, 0x40000000);
nv_wo32(chan, 0x26e0, 0x3f800000);
nv_wo32(chan, 0x26e4, 0x3f000000);
nv_wo32(chan, 0x26ec, 0x40000000);
nv_wo32(chan, 0x26f0, 0x3f800000);
nv_wo32(chan, 0x26f8, 0xbf800000);
nv_wo32(chan, 0x2700, 0xbf800000);
nv_wo32(chan, 0x3024, 0x000fe000);
nv_wo32(chan, 0x30a0, 0x000003f8);
nv_wo32(chan, 0x33fc, 0x002fe000);
for (i = 0x341c; i <= 0x3438; i += 4)
nv_wo32(chan, i, 0x001c527c);
return 0;
}
static struct nouveau_oclass
nv2a_graph_cclass = {
.handle = NV_ENGCTX(GR, 0x2a),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv2a_graph_context_ctor,
.dtor = _nouveau_graph_context_dtor,
.init = nv20_graph_context_init,
.fini = nv20_graph_context_fini,
.rd32 = _nouveau_graph_context_rd32,
.wr32 = _nouveau_graph_context_wr32,
},
};
/*******************************************************************************
* PGRAPH engine/subdev functions
******************************************************************************/
static int
nv2a_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv20_graph_priv *priv;
int ret;
ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
ret = nouveau_gpuobj_new(parent, NULL, 32 * 4, 16,
NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00001000;
nv_subdev(priv)->intr = nv20_graph_intr;
nv_engine(priv)->cclass = &nv2a_graph_cclass;
nv_engine(priv)->sclass = nv25_graph_sclass;
nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
return 0;
}
struct nouveau_oclass
nv2a_graph_oclass = {
.handle = NV_ENGINE(GR, 0x2a),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv2a_graph_ctor,
.dtor = nv20_graph_dtor,
.init = nv20_graph_init,
.fini = _nouveau_graph_fini,
},
};
@@ -0,0 +1,238 @@
#include <core/os.h>
#include <core/class.h>
#include <core/engctx.h>
#include <core/enum.h>
#include <subdev/timer.h>
#include <subdev/fb.h>
#include <engine/graph.h>
#include "nv20.h"
#include "regs.h"
/*******************************************************************************
* Graphics object classes
******************************************************************************/
static struct nouveau_oclass
nv30_graph_sclass[] = {
{ 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */
{ 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */
{ 0x0030, &nv04_graph_ofuncs, NULL }, /* null */
{ 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */
{ 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */
{ 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */
{ 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */
{ 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */
{ 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */
{ 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */
{ 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */
{ 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */
{ 0x0362, &nv04_graph_ofuncs, NULL }, /* surf2d (nv30) */
{ 0x0389, &nv04_graph_ofuncs, NULL }, /* sifm (nv30) */
{ 0x038a, &nv04_graph_ofuncs, NULL }, /* ifc (nv30) */
{ 0x039e, &nv04_graph_ofuncs, NULL }, /* swzsurf (nv30) */
{ 0x0397, &nv04_graph_ofuncs, NULL }, /* rankine */
{},
};
/*******************************************************************************
* PGRAPH context
******************************************************************************/
static int
nv30_graph_context_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv20_graph_chan *chan;
int ret, i;
ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x5f48,
16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
chan->chid = nouveau_fifo_chan(parent)->chid;
nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
nv_wo32(chan, 0x0410, 0x00000101);
nv_wo32(chan, 0x0424, 0x00000111);
nv_wo32(chan, 0x0428, 0x00000060);
nv_wo32(chan, 0x0444, 0x00000080);
nv_wo32(chan, 0x0448, 0xffff0000);
nv_wo32(chan, 0x044c, 0x00000001);
nv_wo32(chan, 0x0460, 0x44400000);
nv_wo32(chan, 0x048c, 0xffff0000);
for (i = 0x04e0; i < 0x04e8; i += 4)
nv_wo32(chan, i, 0x0fff0000);
nv_wo32(chan, 0x04ec, 0x00011100);
for (i = 0x0508; i < 0x0548; i += 4)
nv_wo32(chan, i, 0x07ff0000);
nv_wo32(chan, 0x0550, 0x4b7fffff);
nv_wo32(chan, 0x058c, 0x00000080);
nv_wo32(chan, 0x0590, 0x30201000);
nv_wo32(chan, 0x0594, 0x70605040);
nv_wo32(chan, 0x0598, 0xb8a89888);
nv_wo32(chan, 0x059c, 0xf8e8d8c8);
nv_wo32(chan, 0x05b0, 0xb0000000);
for (i = 0x0600; i < 0x0640; i += 4)
nv_wo32(chan, i, 0x00010588);
for (i = 0x0640; i < 0x0680; i += 4)
nv_wo32(chan, i, 0x00030303);
for (i = 0x06c0; i < 0x0700; i += 4)
nv_wo32(chan, i, 0x0008aae4);
for (i = 0x0700; i < 0x0740; i += 4)
nv_wo32(chan, i, 0x01012000);
for (i = 0x0740; i < 0x0780; i += 4)
nv_wo32(chan, i, 0x00080008);
nv_wo32(chan, 0x085c, 0x00040000);
nv_wo32(chan, 0x0860, 0x00010000);
for (i = 0x0864; i < 0x0874; i += 4)
nv_wo32(chan, i, 0x00040004);
for (i = 0x1f18; i <= 0x3088 ; i += 16) {
nv_wo32(chan, i + 0, 0x10700ff9);
nv_wo32(chan, i + 1, 0x0436086c);
nv_wo32(chan, i + 2, 0x000c001b);
}
for (i = 0x30b8; i < 0x30c8; i += 4)
nv_wo32(chan, i, 0x0000ffff);
nv_wo32(chan, 0x344c, 0x3f800000);
nv_wo32(chan, 0x3808, 0x3f800000);
nv_wo32(chan, 0x381c, 0x3f800000);
nv_wo32(chan, 0x3848, 0x40000000);
nv_wo32(chan, 0x384c, 0x3f800000);
nv_wo32(chan, 0x3850, 0x3f000000);
nv_wo32(chan, 0x3858, 0x40000000);
nv_wo32(chan, 0x385c, 0x3f800000);
nv_wo32(chan, 0x3864, 0xbf800000);
nv_wo32(chan, 0x386c, 0xbf800000);
return 0;
}
static struct nouveau_oclass
nv30_graph_cclass = {
.handle = NV_ENGCTX(GR, 0x30),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv30_graph_context_ctor,
.dtor = _nouveau_graph_context_dtor,
.init = nv20_graph_context_init,
.fini = nv20_graph_context_fini,
.rd32 = _nouveau_graph_context_rd32,
.wr32 = _nouveau_graph_context_wr32,
},
};
/*******************************************************************************
* PGRAPH engine/subdev functions
******************************************************************************/
static int
nv30_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv20_graph_priv *priv;
int ret;
ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
ret = nouveau_gpuobj_new(parent, NULL, 32 * 4, 16,
NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00001000;
nv_subdev(priv)->intr = nv20_graph_intr;
nv_engine(priv)->cclass = &nv30_graph_cclass;
nv_engine(priv)->sclass = nv30_graph_sclass;
nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
return 0;
}
int
nv30_graph_init(struct nouveau_object *object)
{
struct nouveau_engine *engine = nv_engine(object);
struct nv20_graph_priv *priv = (void *)engine;
struct nouveau_fb *pfb = nouveau_fb(object);
int ret, i;
ret = nouveau_graph_init(&priv->base);
if (ret)
return ret;
nv_wr32(priv, NV20_PGRAPH_CHANNEL_CTX_TABLE, priv->ctxtab->addr >> 4);
nv_wr32(priv, NV03_PGRAPH_INTR , 0xFFFFFFFF);
nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000);
nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x401287c0);
nv_wr32(priv, 0x400890, 0x01b463ff);
nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xf2de0475);
nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00008000);
nv_wr32(priv, NV04_PGRAPH_LIMIT_VIOL_PIX, 0xf04bdff6);
nv_wr32(priv, 0x400B80, 0x1003d888);
nv_wr32(priv, 0x400B84, 0x0c000000);
nv_wr32(priv, 0x400098, 0x00000000);
nv_wr32(priv, 0x40009C, 0x0005ad00);
nv_wr32(priv, 0x400B88, 0x62ff00ff); /* suspiciously like PGRAPH_DEBUG_2 */
nv_wr32(priv, 0x4000a0, 0x00000000);
nv_wr32(priv, 0x4000a4, 0x00000008);
nv_wr32(priv, 0x4008a8, 0xb784a400);
nv_wr32(priv, 0x400ba0, 0x002f8685);
nv_wr32(priv, 0x400ba4, 0x00231f3f);
nv_wr32(priv, 0x4008a4, 0x40000020);
if (nv_device(priv)->chipset == 0x34) {
nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0004);
nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00200201);
nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0008);
nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000008);
nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0000);
nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000032);
nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E00004);
nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000002);
}
nv_wr32(priv, 0x4000c0, 0x00000016);
/* Turn all the tiling regions off. */
for (i = 0; i < pfb->tile.regions; i++)
engine->tile_prog(engine, i);
nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
nv_wr32(priv, NV10_PGRAPH_STATE , 0xFFFFFFFF);
nv_wr32(priv, 0x0040075c , 0x00000001);
/* begin RAM config */
/* vramsz = pci_resource_len(priv->dev->pdev, 0) - 1; */
nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200));
nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204));
if (nv_device(priv)->chipset != 0x34) {
nv_wr32(priv, 0x400750, 0x00EA0000);
nv_wr32(priv, 0x400754, nv_rd32(priv, 0x100200));
nv_wr32(priv, 0x400750, 0x00EA0004);
nv_wr32(priv, 0x400754, nv_rd32(priv, 0x100204));
}
return 0;
}
struct nouveau_oclass
nv30_graph_oclass = {
.handle = NV_ENGINE(GR, 0x30),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv30_graph_ctor,
.dtor = nv20_graph_dtor,
.init = nv30_graph_init,
.fini = _nouveau_graph_fini,
},
};
@@ -0,0 +1,168 @@
#include <core/os.h>
#include <core/class.h>
#include <core/engctx.h>
#include <core/enum.h>
#include <subdev/timer.h>
#include <subdev/fb.h>
#include <engine/graph.h>
#include "nv20.h"
#include "regs.h"
/*******************************************************************************
* Graphics object classes
******************************************************************************/
static struct nouveau_oclass
nv34_graph_sclass[] = {
{ 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */
{ 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */
{ 0x0030, &nv04_graph_ofuncs, NULL }, /* null */
{ 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */
{ 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */
{ 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */
{ 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */
{ 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */
{ 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */
{ 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */
{ 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */
{ 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */
{ 0x0362, &nv04_graph_ofuncs, NULL }, /* surf2d (nv30) */
{ 0x0389, &nv04_graph_ofuncs, NULL }, /* sifm (nv30) */
{ 0x038a, &nv04_graph_ofuncs, NULL }, /* ifc (nv30) */
{ 0x039e, &nv04_graph_ofuncs, NULL }, /* swzsurf (nv30) */
{ 0x0697, &nv04_graph_ofuncs, NULL }, /* rankine */
{},
};
/*******************************************************************************
* PGRAPH context
******************************************************************************/
static int
nv34_graph_context_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv20_graph_chan *chan;
int ret, i;
ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x46dc,
16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
chan->chid = nouveau_fifo_chan(parent)->chid;
nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
nv_wo32(chan, 0x040c, 0x01000101);
nv_wo32(chan, 0x0420, 0x00000111);
nv_wo32(chan, 0x0424, 0x00000060);
nv_wo32(chan, 0x0440, 0x00000080);
nv_wo32(chan, 0x0444, 0xffff0000);
nv_wo32(chan, 0x0448, 0x00000001);
nv_wo32(chan, 0x045c, 0x44400000);
nv_wo32(chan, 0x0480, 0xffff0000);
for (i = 0x04d4; i < 0x04dc; i += 4)
nv_wo32(chan, i, 0x0fff0000);
nv_wo32(chan, 0x04e0, 0x00011100);
for (i = 0x04fc; i < 0x053c; i += 4)
nv_wo32(chan, i, 0x07ff0000);
nv_wo32(chan, 0x0544, 0x4b7fffff);
nv_wo32(chan, 0x057c, 0x00000080);
nv_wo32(chan, 0x0580, 0x30201000);
nv_wo32(chan, 0x0584, 0x70605040);
nv_wo32(chan, 0x0588, 0xb8a89888);
nv_wo32(chan, 0x058c, 0xf8e8d8c8);
nv_wo32(chan, 0x05a0, 0xb0000000);
for (i = 0x05f0; i < 0x0630; i += 4)
nv_wo32(chan, i, 0x00010588);
for (i = 0x0630; i < 0x0670; i += 4)
nv_wo32(chan, i, 0x00030303);
for (i = 0x06b0; i < 0x06f0; i += 4)
nv_wo32(chan, i, 0x0008aae4);
for (i = 0x06f0; i < 0x0730; i += 4)
nv_wo32(chan, i, 0x01012000);
for (i = 0x0730; i < 0x0770; i += 4)
nv_wo32(chan, i, 0x00080008);
nv_wo32(chan, 0x0850, 0x00040000);
nv_wo32(chan, 0x0854, 0x00010000);
for (i = 0x0858; i < 0x0868; i += 4)
nv_wo32(chan, i, 0x00040004);
for (i = 0x15ac; i <= 0x271c ; i += 16) {
nv_wo32(chan, i + 0, 0x10700ff9);
nv_wo32(chan, i + 1, 0x0436086c);
nv_wo32(chan, i + 2, 0x000c001b);
}
for (i = 0x274c; i < 0x275c; i += 4)
nv_wo32(chan, i, 0x0000ffff);
nv_wo32(chan, 0x2ae0, 0x3f800000);
nv_wo32(chan, 0x2e9c, 0x3f800000);
nv_wo32(chan, 0x2eb0, 0x3f800000);
nv_wo32(chan, 0x2edc, 0x40000000);
nv_wo32(chan, 0x2ee0, 0x3f800000);
nv_wo32(chan, 0x2ee4, 0x3f000000);
nv_wo32(chan, 0x2eec, 0x40000000);
nv_wo32(chan, 0x2ef0, 0x3f800000);
nv_wo32(chan, 0x2ef8, 0xbf800000);
nv_wo32(chan, 0x2f00, 0xbf800000);
return 0;
}
static struct nouveau_oclass
nv34_graph_cclass = {
.handle = NV_ENGCTX(GR, 0x34),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv34_graph_context_ctor,
.dtor = _nouveau_graph_context_dtor,
.init = nv20_graph_context_init,
.fini = nv20_graph_context_fini,
.rd32 = _nouveau_graph_context_rd32,
.wr32 = _nouveau_graph_context_wr32,
},
};
/*******************************************************************************
* PGRAPH engine/subdev functions
******************************************************************************/
static int
nv34_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv20_graph_priv *priv;
int ret;
ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
ret = nouveau_gpuobj_new(parent, NULL, 32 * 4, 16,
NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00001000;
nv_subdev(priv)->intr = nv20_graph_intr;
nv_engine(priv)->cclass = &nv34_graph_cclass;
nv_engine(priv)->sclass = nv34_graph_sclass;
nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
return 0;
}
struct nouveau_oclass
nv34_graph_oclass = {
.handle = NV_ENGINE(GR, 0x34),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv34_graph_ctor,
.dtor = nv20_graph_dtor,
.init = nv30_graph_init,
.fini = _nouveau_graph_fini,
},
};
@@ -0,0 +1,166 @@
#include <core/os.h>
#include <core/class.h>
#include <core/engctx.h>
#include <core/enum.h>
#include <subdev/timer.h>
#include <subdev/fb.h>
#include "nv20.h"
#include "regs.h"
/*******************************************************************************
* Graphics object classes
******************************************************************************/
static struct nouveau_oclass
nv35_graph_sclass[] = {
{ 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */
{ 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */
{ 0x0030, &nv04_graph_ofuncs, NULL }, /* null */
{ 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */
{ 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */
{ 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */
{ 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */
{ 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */
{ 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */
{ 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */
{ 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */
{ 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */
{ 0x0362, &nv04_graph_ofuncs, NULL }, /* surf2d (nv30) */
{ 0x0389, &nv04_graph_ofuncs, NULL }, /* sifm (nv30) */
{ 0x038a, &nv04_graph_ofuncs, NULL }, /* ifc (nv30) */
{ 0x039e, &nv04_graph_ofuncs, NULL }, /* swzsurf (nv30) */
{ 0x0497, &nv04_graph_ofuncs, NULL }, /* rankine */
{},
};
/*******************************************************************************
* PGRAPH context
******************************************************************************/
static int
nv35_graph_context_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv20_graph_chan *chan;
int ret, i;
ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x577c,
16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
chan->chid = nouveau_fifo_chan(parent)->chid;
nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
nv_wo32(chan, 0x040c, 0x00000101);
nv_wo32(chan, 0x0420, 0x00000111);
nv_wo32(chan, 0x0424, 0x00000060);
nv_wo32(chan, 0x0440, 0x00000080);
nv_wo32(chan, 0x0444, 0xffff0000);
nv_wo32(chan, 0x0448, 0x00000001);
nv_wo32(chan, 0x045c, 0x44400000);
nv_wo32(chan, 0x0488, 0xffff0000);
for (i = 0x04dc; i < 0x04e4; i += 4)
nv_wo32(chan, i, 0x0fff0000);
nv_wo32(chan, 0x04e8, 0x00011100);
for (i = 0x0504; i < 0x0544; i += 4)
nv_wo32(chan, i, 0x07ff0000);
nv_wo32(chan, 0x054c, 0x4b7fffff);
nv_wo32(chan, 0x0588, 0x00000080);
nv_wo32(chan, 0x058c, 0x30201000);
nv_wo32(chan, 0x0590, 0x70605040);
nv_wo32(chan, 0x0594, 0xb8a89888);
nv_wo32(chan, 0x0598, 0xf8e8d8c8);
nv_wo32(chan, 0x05ac, 0xb0000000);
for (i = 0x0604; i < 0x0644; i += 4)
nv_wo32(chan, i, 0x00010588);
for (i = 0x0644; i < 0x0684; i += 4)
nv_wo32(chan, i, 0x00030303);
for (i = 0x06c4; i < 0x0704; i += 4)
nv_wo32(chan, i, 0x0008aae4);
for (i = 0x0704; i < 0x0744; i += 4)
nv_wo32(chan, i, 0x01012000);
for (i = 0x0744; i < 0x0784; i += 4)
nv_wo32(chan, i, 0x00080008);
nv_wo32(chan, 0x0860, 0x00040000);
nv_wo32(chan, 0x0864, 0x00010000);
for (i = 0x0868; i < 0x0878; i += 4)
nv_wo32(chan, i, 0x00040004);
for (i = 0x1f1c; i <= 0x308c ; i += 16) {
nv_wo32(chan, i + 0, 0x10700ff9);
nv_wo32(chan, i + 4, 0x0436086c);
nv_wo32(chan, i + 8, 0x000c001b);
}
for (i = 0x30bc; i < 0x30cc; i += 4)
nv_wo32(chan, i, 0x0000ffff);
nv_wo32(chan, 0x3450, 0x3f800000);
nv_wo32(chan, 0x380c, 0x3f800000);
nv_wo32(chan, 0x3820, 0x3f800000);
nv_wo32(chan, 0x384c, 0x40000000);
nv_wo32(chan, 0x3850, 0x3f800000);
nv_wo32(chan, 0x3854, 0x3f000000);
nv_wo32(chan, 0x385c, 0x40000000);
nv_wo32(chan, 0x3860, 0x3f800000);
nv_wo32(chan, 0x3868, 0xbf800000);
nv_wo32(chan, 0x3870, 0xbf800000);
return 0;
}
static struct nouveau_oclass
nv35_graph_cclass = {
.handle = NV_ENGCTX(GR, 0x35),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv35_graph_context_ctor,
.dtor = _nouveau_graph_context_dtor,
.init = nv20_graph_context_init,
.fini = nv20_graph_context_fini,
.rd32 = _nouveau_graph_context_rd32,
.wr32 = _nouveau_graph_context_wr32,
},
};
/*******************************************************************************
* PGRAPH engine/subdev functions
******************************************************************************/
static int
nv35_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv20_graph_priv *priv;
int ret;
ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
ret = nouveau_gpuobj_new(parent, NULL, 32 * 4, 16,
NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00001000;
nv_subdev(priv)->intr = nv20_graph_intr;
nv_engine(priv)->cclass = &nv35_graph_cclass;
nv_engine(priv)->sclass = nv35_graph_sclass;
nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
return 0;
}
struct nouveau_oclass
nv35_graph_oclass = {
.handle = NV_ENGINE(GR, 0x35),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv35_graph_ctor,
.dtor = nv20_graph_dtor,
.init = nv30_graph_init,
.fini = _nouveau_graph_fini,
},
};
+360 -339
View File
@@ -1,151 +1,238 @@
/*
* Copyright (C) 2007 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 <core/ramht.h>
#include <core/os.h>
#include <core/class.h>
#include <core/handle.h>
#include <core/engctx.h>
struct nv40_graph_engine {
struct nouveau_exec_engine base;
u32 grctx_size;
#include <subdev/fb.h>
#include <subdev/timer.h>
#include <engine/graph.h>
#include <engine/fifo.h>
#include "nv40.h"
#include "regs.h"
struct nv40_graph_priv {
struct nouveau_graph base;
u32 size;
};
struct nv40_graph_chan {
struct nouveau_graph_chan base;
};
/*******************************************************************************
* Graphics object classes
******************************************************************************/
static int
nv40_graph_context_new(struct nouveau_channel *chan, int engine)
nv40_graph_object_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv40_graph_engine *pgraph = nv_engine(chan->dev, engine);
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *grctx = NULL;
unsigned long flags;
struct nouveau_gpuobj *obj;
int ret;
ret = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 16,
NVOBJ_FLAG_ZERO_ALLOC, &grctx);
ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent,
20, 16, 0, &obj);
*pobject = nv_object(obj);
if (ret)
return ret;
/* Initialise default context values */
nv40_grctx_fill(dev, grctx);
nv_wo32(grctx, 0, grctx->addr);
/* init grctx pointer in ramfc, and on PFIFO if channel is
* already active there
*/
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
nv_wo32(chan->ramfc, 0x38, grctx->addr >> 4);
nv_mask(dev, 0x002500, 0x00000001, 0x00000000);
if ((nv_rd32(dev, 0x003204) & 0x0000001f) == chan->id)
nv_wr32(dev, 0x0032e0, grctx->addr >> 4);
nv_mask(dev, 0x002500, 0x00000001, 0x00000001);
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
chan->engctx[engine] = grctx;
return 0;
}
static void
nv40_graph_context_del(struct nouveau_channel *chan, int engine)
{
struct nouveau_gpuobj *grctx = chan->engctx[engine];
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
u32 inst = 0x01000000 | (grctx->addr >> 4);
unsigned long flags;
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
nv_mask(dev, 0x400720, 0x00000000, 0x00000001);
if (nv_rd32(dev, 0x40032c) == inst)
nv_mask(dev, 0x40032c, 0x01000000, 0x00000000);
if (nv_rd32(dev, 0x400330) == inst)
nv_mask(dev, 0x400330, 0x01000000, 0x00000000);
nv_mask(dev, 0x400720, 0x00000001, 0x00000001);
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
/* Free the context resources */
nouveau_gpuobj_ref(NULL, &grctx);
chan->engctx[engine] = NULL;
}
int
nv40_graph_object_new(struct nouveau_channel *chan, int engine,
u32 handle, u16 class)
{
struct drm_device *dev = chan->dev;
struct nouveau_gpuobj *obj = NULL;
int ret;
ret = nouveau_gpuobj_new(dev, chan, 20, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
if (ret)
return ret;
obj->engine = 1;
obj->class = class;
nv_wo32(obj, 0x00, class);
nv_wo32(obj, 0x00, nv_mclass(obj));
nv_wo32(obj, 0x04, 0x00000000);
#ifndef __BIG_ENDIAN
nv_wo32(obj, 0x08, 0x00000000);
#else
nv_wo32(obj, 0x08, 0x01000000);
#ifdef __BIG_ENDIAN
nv_mo32(obj, 0x08, 0x01000000, 0x01000000);
#endif
nv_wo32(obj, 0x0c, 0x00000000);
nv_wo32(obj, 0x10, 0x00000000);
return 0;
}
ret = nouveau_ramht_insert(chan, handle, obj);
nouveau_gpuobj_ref(NULL, &obj);
struct nouveau_ofuncs
nv40_graph_ofuncs = {
.ctor = nv40_graph_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
nv40_graph_sclass[] = {
{ 0x0012, &nv40_graph_ofuncs, NULL }, /* beta1 */
{ 0x0019, &nv40_graph_ofuncs, NULL }, /* clip */
{ 0x0030, &nv40_graph_ofuncs, NULL }, /* null */
{ 0x0039, &nv40_graph_ofuncs, NULL }, /* m2mf */
{ 0x0043, &nv40_graph_ofuncs, NULL }, /* rop */
{ 0x0044, &nv40_graph_ofuncs, NULL }, /* patt */
{ 0x004a, &nv40_graph_ofuncs, NULL }, /* gdi */
{ 0x0062, &nv40_graph_ofuncs, NULL }, /* surf2d */
{ 0x0072, &nv40_graph_ofuncs, NULL }, /* beta4 */
{ 0x0089, &nv40_graph_ofuncs, NULL }, /* sifm */
{ 0x008a, &nv40_graph_ofuncs, NULL }, /* ifc */
{ 0x009f, &nv40_graph_ofuncs, NULL }, /* imageblit */
{ 0x3062, &nv40_graph_ofuncs, NULL }, /* surf2d (nv40) */
{ 0x3089, &nv40_graph_ofuncs, NULL }, /* sifm (nv40) */
{ 0x309e, &nv40_graph_ofuncs, NULL }, /* swzsurf (nv40) */
{ 0x4097, &nv40_graph_ofuncs, NULL }, /* curie */
{},
};
static struct nouveau_oclass
nv44_graph_sclass[] = {
{ 0x0012, &nv40_graph_ofuncs, NULL }, /* beta1 */
{ 0x0019, &nv40_graph_ofuncs, NULL }, /* clip */
{ 0x0030, &nv40_graph_ofuncs, NULL }, /* null */
{ 0x0039, &nv40_graph_ofuncs, NULL }, /* m2mf */
{ 0x0043, &nv40_graph_ofuncs, NULL }, /* rop */
{ 0x0044, &nv40_graph_ofuncs, NULL }, /* patt */
{ 0x004a, &nv40_graph_ofuncs, NULL }, /* gdi */
{ 0x0062, &nv40_graph_ofuncs, NULL }, /* surf2d */
{ 0x0072, &nv40_graph_ofuncs, NULL }, /* beta4 */
{ 0x0089, &nv40_graph_ofuncs, NULL }, /* sifm */
{ 0x008a, &nv40_graph_ofuncs, NULL }, /* ifc */
{ 0x009f, &nv40_graph_ofuncs, NULL }, /* imageblit */
{ 0x3062, &nv40_graph_ofuncs, NULL }, /* surf2d (nv40) */
{ 0x3089, &nv40_graph_ofuncs, NULL }, /* sifm (nv40) */
{ 0x309e, &nv40_graph_ofuncs, NULL }, /* swzsurf (nv40) */
{ 0x4497, &nv40_graph_ofuncs, NULL }, /* curie */
{},
};
/*******************************************************************************
* PGRAPH context
******************************************************************************/
static int
nv40_graph_context_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv40_graph_priv *priv = (void *)engine;
struct nv40_graph_chan *chan;
int ret;
ret = nouveau_graph_context_create(parent, engine, oclass, NULL,
priv->size, 16,
NVOBJ_FLAG_ZERO_ALLOC, &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
nv40_grctx_fill(nv_device(priv), nv_gpuobj(chan));
nv_wo32(chan, 0x00000, nv_gpuobj(chan)->addr >> 4);
return 0;
}
static int
nv40_graph_context_fini(struct nouveau_object *object, bool suspend)
{
struct nv04_graph_priv *priv = (void *)object->engine;
struct nv04_graph_chan *chan = (void *)object;
u32 inst = 0x01000000 | nv_gpuobj(chan)->addr >> 4;
int ret = 0;
nv_mask(priv, 0x400720, 0x00000001, 0x00000000);
if (nv_rd32(priv, 0x40032c) == inst) {
if (suspend) {
nv_wr32(priv, 0x400720, 0x00000000);
nv_wr32(priv, 0x400784, inst);
nv_mask(priv, 0x400310, 0x00000020, 0x00000020);
nv_mask(priv, 0x400304, 0x00000001, 0x00000001);
if (!nv_wait(priv, 0x400300, 0x00000001, 0x00000000)) {
u32 insn = nv_rd32(priv, 0x400308);
nv_warn(priv, "ctxprog timeout 0x%08x\n", insn);
ret = -EBUSY;
}
}
nv_mask(priv, 0x40032c, 0x01000000, 0x00000000);
}
if (nv_rd32(priv, 0x400330) == inst)
nv_mask(priv, 0x400330, 0x01000000, 0x00000000);
nv_mask(priv, 0x400720, 0x00000001, 0x00000001);
return ret;
}
static void
nv40_graph_set_tile_region(struct drm_device *dev, int i)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_fb_tile *tile = nvfb_tile(dev, i);
static struct nouveau_oclass
nv40_graph_cclass = {
.handle = NV_ENGCTX(GR, 0x40),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv40_graph_context_ctor,
.dtor = _nouveau_graph_context_dtor,
.init = _nouveau_graph_context_init,
.fini = nv40_graph_context_fini,
.rd32 = _nouveau_graph_context_rd32,
.wr32 = _nouveau_graph_context_wr32,
},
};
switch (dev_priv->chipset) {
/*******************************************************************************
* PGRAPH engine/subdev functions
******************************************************************************/
static void
nv40_graph_tile_prog(struct nouveau_engine *engine, int i)
{
struct nouveau_fb_tile *tile = &nouveau_fb(engine)->tile.region[i];
struct nouveau_fifo *pfifo = nouveau_fifo(engine);
struct nv40_graph_priv *priv = (void *)engine;
unsigned long flags;
pfifo->pause(pfifo, &flags);
nv04_graph_idle(priv);
switch (nv_device(priv)->chipset) {
case 0x40:
case 0x41: /* guess */
case 0x42:
case 0x43:
case 0x45: /* guess */
case 0x4e:
nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch);
nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit);
nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr);
nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tile->pitch);
nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit);
nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr);
nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch);
nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit);
nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr);
nv_wr32(priv, NV40_PGRAPH_TSIZE1(i), tile->pitch);
nv_wr32(priv, NV40_PGRAPH_TLIMIT1(i), tile->limit);
nv_wr32(priv, NV40_PGRAPH_TILE1(i), tile->addr);
break;
case 0x44:
case 0x4a:
nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch);
nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit);
nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr);
nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch);
nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit);
nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr);
break;
case 0x46:
case 0x47:
@@ -154,149 +241,213 @@ nv40_graph_set_tile_region(struct drm_device *dev, int i)
case 0x4c:
case 0x67:
default:
nv_wr32(dev, NV47_PGRAPH_TSIZE(i), tile->pitch);
nv_wr32(dev, NV47_PGRAPH_TLIMIT(i), tile->limit);
nv_wr32(dev, NV47_PGRAPH_TILE(i), tile->addr);
nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tile->pitch);
nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit);
nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr);
nv_wr32(priv, NV47_PGRAPH_TSIZE(i), tile->pitch);
nv_wr32(priv, NV47_PGRAPH_TLIMIT(i), tile->limit);
nv_wr32(priv, NV47_PGRAPH_TILE(i), tile->addr);
nv_wr32(priv, NV40_PGRAPH_TSIZE1(i), tile->pitch);
nv_wr32(priv, NV40_PGRAPH_TLIMIT1(i), tile->limit);
nv_wr32(priv, NV40_PGRAPH_TILE1(i), tile->addr);
break;
}
pfifo->start(pfifo, &flags);
}
static void
nv40_graph_intr(struct nouveau_subdev *subdev)
{
struct nv40_graph_priv *priv = (void *)subdev;
struct nouveau_engine *engine = nv_engine(subdev);
struct nouveau_handle *handle = NULL;
u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR);
u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE);
u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS);
u32 inst = (nv_rd32(priv, 0x40032c) & 0x000fffff) << 4;
u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR);
u32 subc = (addr & 0x00070000) >> 16;
u32 mthd = (addr & 0x00001ffc);
u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA);
u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xffff;
u32 show = stat;
if (stat & NV_PGRAPH_INTR_ERROR) {
if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
handle = nouveau_engctx_lookup_class(engine, inst, class);
if (handle && !nv_call(handle->object, mthd, data))
show &= ~NV_PGRAPH_INTR_ERROR;
nouveau_engctx_handle_put(handle);
}
if (nsource & NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION) {
nv_mask(priv, 0x402000, 0, 0);
}
}
nv_wr32(priv, NV03_PGRAPH_INTR, stat);
nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
if (show) {
nv_info(priv, "");
nouveau_bitfield_print(nv10_graph_intr_name, show);
printk(" nsource:");
nouveau_bitfield_print(nv04_graph_nsource, nsource);
printk(" nstatus:");
nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
printk("\n");
nv_error(priv, "ch 0x%08x subc %d class 0x%04x "
"mthd 0x%04x data 0x%08x\n",
inst, subc, class, mthd, data);
}
}
/*
* G70 0x47
* G71 0x49
* NV45 0x48
* G72[M] 0x46
* G73 0x4b
* C51_G7X 0x4c
* C51 0x4e
*/
int
nv40_graph_init(struct drm_device *dev, int engine)
static int
nv40_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv40_graph_engine *pgraph = nv_engine(dev, engine);
struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t vramsz;
int i, j;
struct nv40_graph_priv *priv;
int ret;
nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
~NV_PMC_ENABLE_PGRAPH);
nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) |
NV_PMC_ENABLE_PGRAPH);
ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00001000;
nv_subdev(priv)->intr = nv40_graph_intr;
nv_engine(priv)->cclass = &nv40_graph_cclass;
if (nv44_graph_class(priv))
nv_engine(priv)->sclass = nv44_graph_sclass;
else
nv_engine(priv)->sclass = nv40_graph_sclass;
nv_engine(priv)->tile_prog = nv40_graph_tile_prog;
return 0;
}
static int
nv40_graph_init(struct nouveau_object *object)
{
struct nouveau_engine *engine = nv_engine(object);
struct nouveau_fb *pfb = nouveau_fb(object);
struct nv40_graph_priv *priv = (void *)engine;
int ret, i, j;
u32 vramsz;
ret = nouveau_graph_init(&priv->base);
if (ret)
return ret;
/* generate and upload context program */
nv40_grctx_init(dev, &pgraph->grctx_size);
nv40_grctx_init(nv_device(priv), &priv->size);
/* No context present currently */
nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0x00000000);
nv_wr32(priv, NV40_PGRAPH_CTXCTL_CUR, 0x00000000);
nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF);
nv_wr32(dev, NV40_PGRAPH_INTR_EN, 0xFFFFFFFF);
nv_wr32(priv, NV03_PGRAPH_INTR , 0xFFFFFFFF);
nv_wr32(priv, NV40_PGRAPH_INTR_EN, 0xFFFFFFFF);
nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x00000000);
nv_wr32(dev, NV04_PGRAPH_DEBUG_1, 0x401287c0);
nv_wr32(dev, NV04_PGRAPH_DEBUG_3, 0xe0de8055);
nv_wr32(dev, NV10_PGRAPH_DEBUG_4, 0x00008000);
nv_wr32(dev, NV04_PGRAPH_LIMIT_VIOL_PIX, 0x00be3c5f);
nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000);
nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x401287c0);
nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xe0de8055);
nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00008000);
nv_wr32(priv, NV04_PGRAPH_LIMIT_VIOL_PIX, 0x00be3c5f);
nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
nv_wr32(dev, NV10_PGRAPH_STATE , 0xFFFFFFFF);
nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
nv_wr32(priv, NV10_PGRAPH_STATE , 0xFFFFFFFF);
j = nv_rd32(dev, 0x1540) & 0xff;
j = nv_rd32(priv, 0x1540) & 0xff;
if (j) {
for (i = 0; !(j & 1); j >>= 1, i++)
;
nv_wr32(dev, 0x405000, i);
nv_wr32(priv, 0x405000, i);
}
if (dev_priv->chipset == 0x40) {
nv_wr32(dev, 0x4009b0, 0x83280fff);
nv_wr32(dev, 0x4009b4, 0x000000a0);
if (nv_device(priv)->chipset == 0x40) {
nv_wr32(priv, 0x4009b0, 0x83280fff);
nv_wr32(priv, 0x4009b4, 0x000000a0);
} else {
nv_wr32(dev, 0x400820, 0x83280eff);
nv_wr32(dev, 0x400824, 0x000000a0);
nv_wr32(priv, 0x400820, 0x83280eff);
nv_wr32(priv, 0x400824, 0x000000a0);
}
switch (dev_priv->chipset) {
switch (nv_device(priv)->chipset) {
case 0x40:
case 0x45:
nv_wr32(dev, 0x4009b8, 0x0078e366);
nv_wr32(dev, 0x4009bc, 0x0000014c);
nv_wr32(priv, 0x4009b8, 0x0078e366);
nv_wr32(priv, 0x4009bc, 0x0000014c);
break;
case 0x41:
case 0x42: /* pciid also 0x00Cx */
/* case 0x0120: XXX (pciid) */
nv_wr32(dev, 0x400828, 0x007596ff);
nv_wr32(dev, 0x40082c, 0x00000108);
nv_wr32(priv, 0x400828, 0x007596ff);
nv_wr32(priv, 0x40082c, 0x00000108);
break;
case 0x43:
nv_wr32(dev, 0x400828, 0x0072cb77);
nv_wr32(dev, 0x40082c, 0x00000108);
nv_wr32(priv, 0x400828, 0x0072cb77);
nv_wr32(priv, 0x40082c, 0x00000108);
break;
case 0x44:
case 0x46: /* G72 */
case 0x4a:
case 0x4c: /* G7x-based C51 */
case 0x4e:
nv_wr32(dev, 0x400860, 0);
nv_wr32(dev, 0x400864, 0);
nv_wr32(priv, 0x400860, 0);
nv_wr32(priv, 0x400864, 0);
break;
case 0x47: /* G70 */
case 0x49: /* G71 */
case 0x4b: /* G73 */
nv_wr32(dev, 0x400828, 0x07830610);
nv_wr32(dev, 0x40082c, 0x0000016A);
nv_wr32(priv, 0x400828, 0x07830610);
nv_wr32(priv, 0x40082c, 0x0000016A);
break;
default:
break;
}
nv_wr32(dev, 0x400b38, 0x2ffff800);
nv_wr32(dev, 0x400b3c, 0x00006000);
nv_wr32(priv, 0x400b38, 0x2ffff800);
nv_wr32(priv, 0x400b3c, 0x00006000);
/* Tiling related stuff. */
switch (dev_priv->chipset) {
switch (nv_device(priv)->chipset) {
case 0x44:
case 0x4a:
nv_wr32(dev, 0x400bc4, 0x1003d888);
nv_wr32(dev, 0x400bbc, 0xb7a7b500);
nv_wr32(priv, 0x400bc4, 0x1003d888);
nv_wr32(priv, 0x400bbc, 0xb7a7b500);
break;
case 0x46:
nv_wr32(dev, 0x400bc4, 0x0000e024);
nv_wr32(dev, 0x400bbc, 0xb7a7b520);
nv_wr32(priv, 0x400bc4, 0x0000e024);
nv_wr32(priv, 0x400bbc, 0xb7a7b520);
break;
case 0x4c:
case 0x4e:
case 0x67:
nv_wr32(dev, 0x400bc4, 0x1003d888);
nv_wr32(dev, 0x400bbc, 0xb7a7b540);
nv_wr32(priv, 0x400bc4, 0x1003d888);
nv_wr32(priv, 0x400bbc, 0xb7a7b540);
break;
default:
break;
}
/* Turn all the tiling regions off. */
for (i = 0; i < nvfb_tile_nr(dev); i++)
nv40_graph_set_tile_region(dev, i);
for (i = 0; i < pfb->tile.regions; i++)
engine->tile_prog(engine, i);
/* begin RAM config */
vramsz = pci_resource_len(dev->pdev, 0) - 1;
switch (dev_priv->chipset) {
vramsz = pci_resource_len(nv_device(priv)->pdev, 0) - 1;
switch (nv_device(priv)->chipset) {
case 0x40:
nv_wr32(dev, 0x4009A4, nv_rd32(dev, NV04_PFB_CFG0));
nv_wr32(dev, 0x4009A8, nv_rd32(dev, NV04_PFB_CFG1));
nv_wr32(dev, 0x4069A4, nv_rd32(dev, NV04_PFB_CFG0));
nv_wr32(dev, 0x4069A8, nv_rd32(dev, NV04_PFB_CFG1));
nv_wr32(dev, 0x400820, 0);
nv_wr32(dev, 0x400824, 0);
nv_wr32(dev, 0x400864, vramsz);
nv_wr32(dev, 0x400868, vramsz);
nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200));
nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204));
nv_wr32(priv, 0x4069A4, nv_rd32(priv, 0x100200));
nv_wr32(priv, 0x4069A8, nv_rd32(priv, 0x100204));
nv_wr32(priv, 0x400820, 0);
nv_wr32(priv, 0x400824, 0);
nv_wr32(priv, 0x400864, vramsz);
nv_wr32(priv, 0x400868, vramsz);
break;
default:
switch (dev_priv->chipset) {
switch (nv_device(priv)->chipset) {
case 0x41:
case 0x42:
case 0x43:
@@ -304,163 +455,33 @@ nv40_graph_init(struct drm_device *dev, int engine)
case 0x4e:
case 0x44:
case 0x4a:
nv_wr32(dev, 0x4009F0, nv_rd32(dev, NV04_PFB_CFG0));
nv_wr32(dev, 0x4009F4, nv_rd32(dev, NV04_PFB_CFG1));
nv_wr32(priv, 0x4009F0, nv_rd32(priv, 0x100200));
nv_wr32(priv, 0x4009F4, nv_rd32(priv, 0x100204));
break;
default:
nv_wr32(dev, 0x400DF0, nv_rd32(dev, NV04_PFB_CFG0));
nv_wr32(dev, 0x400DF4, nv_rd32(dev, NV04_PFB_CFG1));
nv_wr32(priv, 0x400DF0, nv_rd32(priv, 0x100200));
nv_wr32(priv, 0x400DF4, nv_rd32(priv, 0x100204));
break;
}
nv_wr32(dev, 0x4069F0, nv_rd32(dev, NV04_PFB_CFG0));
nv_wr32(dev, 0x4069F4, nv_rd32(dev, NV04_PFB_CFG1));
nv_wr32(dev, 0x400840, 0);
nv_wr32(dev, 0x400844, 0);
nv_wr32(dev, 0x4008A0, vramsz);
nv_wr32(dev, 0x4008A4, vramsz);
nv_wr32(priv, 0x4069F0, nv_rd32(priv, 0x100200));
nv_wr32(priv, 0x4069F4, nv_rd32(priv, 0x100204));
nv_wr32(priv, 0x400840, 0);
nv_wr32(priv, 0x400844, 0);
nv_wr32(priv, 0x4008A0, vramsz);
nv_wr32(priv, 0x4008A4, vramsz);
break;
}
return 0;
}
static int
nv40_graph_fini(struct drm_device *dev, int engine, bool suspend)
{
u32 inst = nv_rd32(dev, 0x40032c);
if (inst & 0x01000000) {
nv_wr32(dev, 0x400720, 0x00000000);
nv_wr32(dev, 0x400784, inst);
nv_mask(dev, 0x400310, 0x00000020, 0x00000020);
nv_mask(dev, 0x400304, 0x00000001, 0x00000001);
if (!nv_wait(dev, 0x400300, 0x00000001, 0x00000000)) {
u32 insn = nv_rd32(dev, 0x400308);
NV_ERROR(dev, "PGRAPH: ctxprog timeout 0x%08x\n", insn);
}
nv_mask(dev, 0x40032c, 0x01000000, 0x00000000);
}
return 0;
}
static int
nv40_graph_isr_chid(struct drm_device *dev, u32 inst)
{
struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *grctx;
unsigned long flags;
int i;
spin_lock_irqsave(&dev_priv->channels.lock, flags);
for (i = 0; i < pfifo->channels; i++) {
if (!dev_priv->channels.ptr[i])
continue;
grctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_GR];
if (grctx && grctx->addr == inst)
break;
}
spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
return i;
}
static void
nv40_graph_isr(struct drm_device *dev)
{
u32 stat;
while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) {
u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS);
u32 inst = (nv_rd32(dev, 0x40032c) & 0x000fffff) << 4;
u32 chid = nv40_graph_isr_chid(dev, inst);
u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
u32 subc = (addr & 0x00070000) >> 16;
u32 mthd = (addr & 0x00001ffc);
u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
u32 class = nv_rd32(dev, 0x400160 + subc * 4) & 0xffff;
u32 show = stat;
if (stat & NV_PGRAPH_INTR_ERROR) {
if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data))
show &= ~NV_PGRAPH_INTR_ERROR;
} else
if (nsource & NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION) {
nv_mask(dev, 0x402000, 0, 0);
}
}
nv_wr32(dev, NV03_PGRAPH_INTR, stat);
nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001);
if (show && nouveau_ratelimit()) {
NV_INFO(dev, "PGRAPH -");
nouveau_bitfield_print(nv10_graph_intr, show);
printk(" nsource:");
nouveau_bitfield_print(nv04_graph_nsource, nsource);
printk(" nstatus:");
nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
printk("\n");
NV_INFO(dev, "PGRAPH - ch %d (0x%08x) subc %d "
"class 0x%04x mthd 0x%04x data 0x%08x\n",
chid, inst, subc, class, mthd, data);
}
}
}
static void
nv40_graph_destroy(struct drm_device *dev, int engine)
{
struct nv40_graph_engine *pgraph = nv_engine(dev, engine);
nouveau_irq_unregister(dev, 12);
NVOBJ_ENGINE_DEL(dev, GR);
kfree(pgraph);
}
int
nv40_graph_create(struct drm_device *dev)
{
struct nv40_graph_engine *pgraph;
pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
if (!pgraph)
return -ENOMEM;
pgraph->base.destroy = nv40_graph_destroy;
pgraph->base.init = nv40_graph_init;
pgraph->base.fini = nv40_graph_fini;
pgraph->base.context_new = nv40_graph_context_new;
pgraph->base.context_del = nv40_graph_context_del;
pgraph->base.object_new = nv40_graph_object_new;
pgraph->base.set_tile_region = nv40_graph_set_tile_region;
NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
nouveau_irq_register(dev, 12, nv40_graph_isr);
NVOBJ_CLASS(dev, 0x0030, GR); /* null */
NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
NVOBJ_CLASS(dev, 0x3089, GR); /* sifm (nv40) */
NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
NVOBJ_CLASS(dev, 0x3062, GR); /* surf2d (nv40) */
NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
NVOBJ_CLASS(dev, 0x309e, GR); /* swzsurf */
/* curie */
if (nv44_graph_class(dev))
NVOBJ_CLASS(dev, 0x4497, GR);
else
NVOBJ_CLASS(dev, 0x4097, GR);
return 0;
}
struct nouveau_oclass
nv40_graph_oclass = {
.handle = NV_ENGINE(GR, 0x40),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv40_graph_ctor,
.dtor = _nouveau_graph_dtor,
.init = nv40_graph_init,
.fini = _nouveau_graph_fini,
},
};
@@ -0,0 +1,21 @@
#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
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,7 @@
#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
File diff suppressed because it is too large Load Diff
@@ -25,6 +25,18 @@
#ifndef __NVC0_GRAPH_H__
#define __NVC0_GRAPH_H__
#include <core/client.h>
#include <core/handle.h>
#include <core/gpuobj.h>
#include <core/option.h>
#include <subdev/fb.h>
#include <subdev/vm.h>
#include <subdev/bar.h>
#include <subdev/timer.h>
#include <engine/graph.h>
#define GPC_MAX 4
#define TPC_MAX 32
@@ -53,7 +65,7 @@ struct nvc0_graph_fuc {
};
struct nvc0_graph_priv {
struct nouveau_exec_engine base;
struct nouveau_graph base;
struct nvc0_graph_fuc fuc409c;
struct nvc0_graph_fuc fuc409d;
@@ -78,11 +90,10 @@ struct nvc0_graph_priv {
};
struct nvc0_graph_chan {
struct nouveau_gpuobj *grctx;
struct nouveau_vma grctx_vma;
struct nouveau_graph_chan base;
struct nouveau_gpuobj *mmio;
struct nouveau_vma mmio_vma;
struct nouveau_vma mmio_vma;
int mmio_nr;
struct {
struct nouveau_gpuobj *mem;
@@ -91,11 +102,11 @@ struct nvc0_graph_chan {
};
static inline u32
nvc0_graph_class(struct drm_device *priv)
nvc0_graph_class(void *obj)
{
struct drm_nouveau_private *dev_priv = priv->dev_private;
struct nouveau_device *device = nv_device(obj);
switch (dev_priv->chipset) {
switch (device->chipset) {
case 0xc0:
case 0xc3:
case 0xc4:
@@ -115,17 +126,16 @@ nvc0_graph_class(struct drm_device *priv)
}
}
void nv_icmd(struct drm_device *priv, u32 icmd, u32 data);
void nv_icmd(struct nvc0_graph_priv *priv, u32 icmd, u32 data);
static inline void
nv_mthd(struct drm_device *priv, u32 class, u32 mthd, u32 data)
nv_mthd(struct nvc0_graph_priv *priv, u32 class, u32 mthd, u32 data)
{
nv_wr32(priv, 0x40448c, data);
nv_wr32(priv, 0x404488, 0x80000000 | (mthd << 14) | class);
}
struct nvc0_grctx {
struct drm_device *dev;
struct nvc0_graph_priv *priv;
struct nvc0_graph_data *data;
struct nvc0_graph_mmio *mmio;
@@ -135,18 +145,18 @@ struct nvc0_grctx {
u64 addr;
};
int nvc0_grctx_generate(struct drm_device *);
int nvc0_grctx_init(struct drm_device *, struct nvc0_graph_priv *,
struct nvc0_grctx *);
int nvc0_grctx_generate(struct nvc0_graph_priv *);
int nvc0_grctx_init(struct nvc0_graph_priv *, struct nvc0_grctx *);
void nvc0_grctx_data(struct nvc0_grctx *, u32, u32, u32);
void nvc0_grctx_mmio(struct nvc0_grctx *, u32, u32, u32, u32);
int nvc0_grctx_fini(struct nvc0_grctx *);
int nve0_grctx_generate(struct drm_device *);
int nve0_grctx_generate(struct nvc0_graph_priv *);
#define mmio_data(s,a,p) nvc0_grctx_data(&info, (s), (a), (p))
#define mmio_list(r,d,s,b) nvc0_grctx_mmio(&info, (r), (d), (s), (b))
void nvc0_graph_ctxctl_debug(struct nvc0_graph_priv *);
int nvc0_graph_ctor_fw(struct nvc0_graph_priv *, const char *,
struct nvc0_graph_fuc *);
void nvc0_graph_dtor(struct nouveau_object *);
@@ -157,9 +167,4 @@ int nvc0_graph_context_ctor(struct nouveau_object *, struct nouveau_object *,
struct nouveau_object **);
void nvc0_graph_context_dtor(struct nouveau_object *);
void nvc0_graph_ctxctl_debug(struct drm_device *);
int nvc0_graph_context_new(struct nouveau_channel *, int);
void nvc0_graph_context_del(struct nouveau_channel *, int);
#endif
+386 -505
View File
@@ -1,5 +1,5 @@
/*
* 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,586 +22,213 @@
* Authors: Ben Skeggs
*/
#include <linux/firmware.h>
#include <linux/module.h>
#include "drmP.h"
#include "nouveau_drv.h"
#include <core/mm.h>
#include <engine/fifo.h>
#include "nvc0.h"
static void
nve0_graph_ctxctl_debug_unit(struct drm_device *dev, u32 base)
{
NV_INFO(dev, "PGRAPH: %06x - done 0x%08x\n", base,
nv_rd32(dev, base + 0x400));
NV_INFO(dev, "PGRAPH: %06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
nv_rd32(dev, base + 0x800), nv_rd32(dev, base + 0x804),
nv_rd32(dev, base + 0x808), nv_rd32(dev, base + 0x80c));
NV_INFO(dev, "PGRAPH: %06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
nv_rd32(dev, base + 0x810), nv_rd32(dev, base + 0x814),
nv_rd32(dev, base + 0x818), nv_rd32(dev, base + 0x81c));
}
/*******************************************************************************
* Graphics object classes
******************************************************************************/
static struct nouveau_oclass
nve0_graph_sclass[] = {
{ 0x902d, &nouveau_object_ofuncs },
{ 0xa040, &nouveau_object_ofuncs },
{ 0xa097, &nouveau_object_ofuncs },
{ 0xa0c0, &nouveau_object_ofuncs },
{ 0xa0b5, &nouveau_object_ofuncs },
{}
};
/*******************************************************************************
* PGRAPH context
******************************************************************************/
static struct nouveau_oclass
nve0_graph_cclass = {
.handle = NV_ENGCTX(GR, 0xe0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nvc0_graph_context_ctor,
.dtor = nvc0_graph_context_dtor,
.init = _nouveau_graph_context_init,
.fini = _nouveau_graph_context_fini,
.rd32 = _nouveau_graph_context_rd32,
.wr32 = _nouveau_graph_context_wr32,
},
};
/*******************************************************************************
* PGRAPH engine/subdev functions
******************************************************************************/
static void
nve0_graph_ctxctl_debug(struct drm_device *dev)
nve0_graph_ctxctl_isr(struct nvc0_graph_priv *priv)
{
u32 gpcnr = nv_rd32(dev, 0x409604) & 0xffff;
u32 gpc;
nve0_graph_ctxctl_debug_unit(dev, 0x409000);
for (gpc = 0; gpc < gpcnr; gpc++)
nve0_graph_ctxctl_debug_unit(dev, 0x502000 + (gpc * 0x8000));
}
static int
nve0_graph_object_new(struct nouveau_channel *chan, int engine,
u32 handle, u16 class)
{
return 0;
}
static int
nve0_graph_fini(struct drm_device *dev, int engine, bool suspend)
{
return 0;
}
static void
nve0_graph_init_obj418880(struct drm_device *dev)
{
struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
int i;
nv_wr32(dev, GPC_BCAST(0x0880), 0x00000000);
nv_wr32(dev, GPC_BCAST(0x08a4), 0x00000000);
for (i = 0; i < 4; i++)
nv_wr32(dev, GPC_BCAST(0x0888) + (i * 4), 0x00000000);
nv_wr32(dev, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
nv_wr32(dev, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
}
static void
nve0_graph_init_regs(struct drm_device *dev)
{
nv_wr32(dev, 0x400080, 0x003083c2);
nv_wr32(dev, 0x400088, 0x0001ffe7);
nv_wr32(dev, 0x40008c, 0x00000000);
nv_wr32(dev, 0x400090, 0x00000030);
nv_wr32(dev, 0x40013c, 0x003901f7);
nv_wr32(dev, 0x400140, 0x00000100);
nv_wr32(dev, 0x400144, 0x00000000);
nv_wr32(dev, 0x400148, 0x00000110);
nv_wr32(dev, 0x400138, 0x00000000);
nv_wr32(dev, 0x400130, 0x00000000);
nv_wr32(dev, 0x400134, 0x00000000);
nv_wr32(dev, 0x400124, 0x00000002);
}
static void
nve0_graph_init_units(struct drm_device *dev)
{
nv_wr32(dev, 0x409ffc, 0x00000000);
nv_wr32(dev, 0x409c14, 0x00003e3e);
nv_wr32(dev, 0x409c24, 0x000f0000);
nv_wr32(dev, 0x404000, 0xc0000000);
nv_wr32(dev, 0x404600, 0xc0000000);
nv_wr32(dev, 0x408030, 0xc0000000);
nv_wr32(dev, 0x404490, 0xc0000000);
nv_wr32(dev, 0x406018, 0xc0000000);
nv_wr32(dev, 0x407020, 0xc0000000);
nv_wr32(dev, 0x405840, 0xc0000000);
nv_wr32(dev, 0x405844, 0x00ffffff);
nv_mask(dev, 0x419cc0, 0x00000008, 0x00000008);
nv_mask(dev, 0x419eb4, 0x00001000, 0x00001000);
}
static void
nve0_graph_init_gpc_0(struct drm_device *dev)
{
struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
u32 data[TPC_MAX / 8];
u8 tpcnr[GPC_MAX];
int i, gpc, tpc;
nv_wr32(dev, GPC_UNIT(0, 0x3018), 0x00000001);
memset(data, 0x00, sizeof(data));
memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
do {
gpc = (gpc + 1) % priv->gpc_nr;
} while (!tpcnr[gpc]);
tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
data[i / 8] |= tpc << ((i % 8) * 4);
}
nv_wr32(dev, GPC_BCAST(0x0980), data[0]);
nv_wr32(dev, GPC_BCAST(0x0984), data[1]);
nv_wr32(dev, GPC_BCAST(0x0988), data[2]);
nv_wr32(dev, GPC_BCAST(0x098c), data[3]);
for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
nv_wr32(dev, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 |
priv->tpc_nr[gpc]);
nv_wr32(dev, GPC_UNIT(gpc, 0x0910), 0x00040000 | priv->tpc_total);
nv_wr32(dev, GPC_UNIT(gpc, 0x0918), magicgpc918);
}
nv_wr32(dev, GPC_BCAST(0x1bd4), magicgpc918);
nv_wr32(dev, GPC_BCAST(0x08ac), nv_rd32(dev, 0x100800));
}
static void
nve0_graph_init_gpc_1(struct drm_device *dev)
{
struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
int gpc, tpc;
for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
nv_wr32(dev, GPC_UNIT(gpc, 0x3038), 0xc0000000);
nv_wr32(dev, GPC_UNIT(gpc, 0x0420), 0xc0000000);
nv_wr32(dev, GPC_UNIT(gpc, 0x0900), 0xc0000000);
nv_wr32(dev, GPC_UNIT(gpc, 0x1028), 0xc0000000);
nv_wr32(dev, GPC_UNIT(gpc, 0x0824), 0xc0000000);
for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe);
nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f);
}
nv_wr32(dev, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
nv_wr32(dev, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
}
}
static void
nve0_graph_init_rop(struct drm_device *dev)
{
struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
int rop;
for (rop = 0; rop < priv->rop_nr; rop++) {
nv_wr32(dev, ROP_UNIT(rop, 0x144), 0xc0000000);
nv_wr32(dev, ROP_UNIT(rop, 0x070), 0xc0000000);
nv_wr32(dev, ROP_UNIT(rop, 0x204), 0xffffffff);
nv_wr32(dev, ROP_UNIT(rop, 0x208), 0xffffffff);
}
}
static void
nve0_graph_init_fuc(struct drm_device *dev, u32 fuc_base,
struct nvc0_graph_fuc *code, struct nvc0_graph_fuc *data)
{
int i;
nv_wr32(dev, fuc_base + 0x01c0, 0x01000000);
for (i = 0; i < data->size / 4; i++)
nv_wr32(dev, fuc_base + 0x01c4, data->data[i]);
nv_wr32(dev, fuc_base + 0x0180, 0x01000000);
for (i = 0; i < code->size / 4; i++) {
if ((i & 0x3f) == 0)
nv_wr32(dev, fuc_base + 0x0188, i >> 6);
nv_wr32(dev, fuc_base + 0x0184, code->data[i]);
}
}
static int
nve0_graph_init_ctxctl(struct drm_device *dev)
{
struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
u32 r000260;
/* load fuc microcode */
r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000);
nve0_graph_init_fuc(dev, 0x409000, &priv->fuc409c, &priv->fuc409d);
nve0_graph_init_fuc(dev, 0x41a000, &priv->fuc41ac, &priv->fuc41ad);
nv_wr32(dev, 0x000260, r000260);
/* start both of them running */
nv_wr32(dev, 0x409840, 0xffffffff);
nv_wr32(dev, 0x41a10c, 0x00000000);
nv_wr32(dev, 0x40910c, 0x00000000);
nv_wr32(dev, 0x41a100, 0x00000002);
nv_wr32(dev, 0x409100, 0x00000002);
if (!nv_wait(dev, 0x409800, 0x00000001, 0x00000001))
NV_INFO(dev, "0x409800 wait failed\n");
nv_wr32(dev, 0x409840, 0xffffffff);
nv_wr32(dev, 0x409500, 0x7fffffff);
nv_wr32(dev, 0x409504, 0x00000021);
nv_wr32(dev, 0x409840, 0xffffffff);
nv_wr32(dev, 0x409500, 0x00000000);
nv_wr32(dev, 0x409504, 0x00000010);
if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
NV_ERROR(dev, "fuc09 req 0x10 timeout\n");
return -EBUSY;
}
priv->size = nv_rd32(dev, 0x409800);
nv_wr32(dev, 0x409840, 0xffffffff);
nv_wr32(dev, 0x409500, 0x00000000);
nv_wr32(dev, 0x409504, 0x00000016);
if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
NV_ERROR(dev, "fuc09 req 0x16 timeout\n");
return -EBUSY;
}
nv_wr32(dev, 0x409840, 0xffffffff);
nv_wr32(dev, 0x409500, 0x00000000);
nv_wr32(dev, 0x409504, 0x00000025);
if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
NV_ERROR(dev, "fuc09 req 0x25 timeout\n");
return -EBUSY;
}
nv_wr32(dev, 0x409800, 0x00000000);
nv_wr32(dev, 0x409500, 0x00000001);
nv_wr32(dev, 0x409504, 0x00000030);
if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
NV_ERROR(dev, "fuc09 req 0x30 timeout\n");
return -EBUSY;
}
nv_wr32(dev, 0x409810, 0xb00095c8);
nv_wr32(dev, 0x409800, 0x00000000);
nv_wr32(dev, 0x409500, 0x00000001);
nv_wr32(dev, 0x409504, 0x00000031);
if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
NV_ERROR(dev, "fuc09 req 0x31 timeout\n");
return -EBUSY;
}
nv_wr32(dev, 0x409810, 0x00080420);
nv_wr32(dev, 0x409800, 0x00000000);
nv_wr32(dev, 0x409500, 0x00000001);
nv_wr32(dev, 0x409504, 0x00000032);
if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
NV_ERROR(dev, "fuc09 req 0x32 timeout\n");
return -EBUSY;
}
nv_wr32(dev, 0x409614, 0x00000070);
nv_wr32(dev, 0x409614, 0x00000770);
nv_wr32(dev, 0x40802c, 0x00000001);
if (priv->data == NULL) {
int ret = nve0_grctx_generate(dev);
if (ret) {
NV_ERROR(dev, "PGRAPH: failed to construct context\n");
return ret;
}
return 1;
}
return 0;
}
static int
nve0_graph_init(struct drm_device *dev, int engine)
{
int ret;
reset:
nv_mask(dev, 0x000200, 0x18001000, 0x00000000);
nv_mask(dev, 0x000200, 0x18001000, 0x18001000);
nve0_graph_init_obj418880(dev);
nve0_graph_init_regs(dev);
nve0_graph_init_gpc_0(dev);
nv_wr32(dev, 0x400500, 0x00010001);
nv_wr32(dev, 0x400100, 0xffffffff);
nv_wr32(dev, 0x40013c, 0xffffffff);
nve0_graph_init_units(dev);
nve0_graph_init_gpc_1(dev);
nve0_graph_init_rop(dev);
nv_wr32(dev, 0x400108, 0xffffffff);
nv_wr32(dev, 0x400138, 0xffffffff);
nv_wr32(dev, 0x400118, 0xffffffff);
nv_wr32(dev, 0x400130, 0xffffffff);
nv_wr32(dev, 0x40011c, 0xffffffff);
nv_wr32(dev, 0x400134, 0xffffffff);
nv_wr32(dev, 0x400054, 0x34ce3464);
ret = nve0_graph_init_ctxctl(dev);
if (ret) {
if (ret == 1)
goto reset;
return ret;
}
return 0;
}
int
nve0_graph_isr_chid(struct drm_device *dev, u64 inst)
{
struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan;
unsigned long flags;
int i;
spin_lock_irqsave(&dev_priv->channels.lock, flags);
for (i = 0; i < pfifo->channels; i++) {
chan = dev_priv->channels.ptr[i];
if (!chan || !chan->ramin)
continue;
if (inst == chan->ramin->addr)
break;
}
spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
return i;
}
static void
nve0_graph_ctxctl_isr(struct drm_device *dev)
{
u32 ustat = nv_rd32(dev, 0x409c18);
u32 ustat = nv_rd32(priv, 0x409c18);
if (ustat & 0x00000001)
NV_INFO(dev, "PGRAPH: CTXCTRL ucode error\n");
nv_error(priv, "CTXCTRL ucode error\n");
if (ustat & 0x00080000)
NV_INFO(dev, "PGRAPH: CTXCTRL watchdog timeout\n");
nv_error(priv, "CTXCTRL watchdog timeout\n");
if (ustat & ~0x00080001)
NV_INFO(dev, "PGRAPH: CTXCTRL 0x%08x\n", ustat);
nv_error(priv, "CTXCTRL 0x%08x\n", ustat);
nve0_graph_ctxctl_debug(dev);
nv_wr32(dev, 0x409c20, ustat);
nvc0_graph_ctxctl_debug(priv);
nv_wr32(priv, 0x409c20, ustat);
}
static void
nve0_graph_trap_isr(struct drm_device *dev, int chid)
nve0_graph_trap_isr(struct nvc0_graph_priv *priv, u64 inst)
{
struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
u32 trap = nv_rd32(dev, 0x400108);
u32 trap = nv_rd32(priv, 0x400108);
int rop;
if (trap & 0x00000001) {
u32 stat = nv_rd32(dev, 0x404000);
NV_INFO(dev, "PGRAPH: DISPATCH ch %d 0x%08x\n", chid, stat);
nv_wr32(dev, 0x404000, 0xc0000000);
nv_wr32(dev, 0x400108, 0x00000001);
u32 stat = nv_rd32(priv, 0x404000);
nv_error(priv, "DISPATCH ch 0x%010llx 0x%08x\n", inst, stat);
nv_wr32(priv, 0x404000, 0xc0000000);
nv_wr32(priv, 0x400108, 0x00000001);
trap &= ~0x00000001;
}
if (trap & 0x00000010) {
u32 stat = nv_rd32(dev, 0x405840);
NV_INFO(dev, "PGRAPH: SHADER ch %d 0x%08x\n", chid, stat);
nv_wr32(dev, 0x405840, 0xc0000000);
nv_wr32(dev, 0x400108, 0x00000010);
u32 stat = nv_rd32(priv, 0x405840);
nv_error(priv, "SHADER ch 0x%010llx 0x%08x\n", inst, stat);
nv_wr32(priv, 0x405840, 0xc0000000);
nv_wr32(priv, 0x400108, 0x00000010);
trap &= ~0x00000010;
}
if (trap & 0x02000000) {
for (rop = 0; rop < priv->rop_nr; rop++) {
u32 statz = nv_rd32(dev, ROP_UNIT(rop, 0x070));
u32 statc = nv_rd32(dev, ROP_UNIT(rop, 0x144));
NV_INFO(dev, "PGRAPH: ROP%d ch %d 0x%08x 0x%08x\n",
rop, chid, statz, statc);
nv_wr32(dev, ROP_UNIT(rop, 0x070), 0xc0000000);
nv_wr32(dev, ROP_UNIT(rop, 0x144), 0xc0000000);
u32 statz = nv_rd32(priv, ROP_UNIT(rop, 0x070));
u32 statc = nv_rd32(priv, ROP_UNIT(rop, 0x144));
nv_error(priv, "ROP%d ch 0x%010llx 0x%08x 0x%08x\n",
rop, inst, statz, statc);
nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
}
nv_wr32(dev, 0x400108, 0x02000000);
nv_wr32(priv, 0x400108, 0x02000000);
trap &= ~0x02000000;
}
if (trap) {
NV_INFO(dev, "PGRAPH: TRAP ch %d 0x%08x\n", chid, trap);
nv_wr32(dev, 0x400108, trap);
nv_error(priv, "TRAP ch 0x%010llx 0x%08x\n", inst, trap);
nv_wr32(priv, 0x400108, trap);
}
}
static void
nve0_graph_isr(struct drm_device *dev)
nve0_graph_intr(struct nouveau_subdev *subdev)
{
u64 inst = (u64)(nv_rd32(dev, 0x409b00) & 0x0fffffff) << 12;
u32 chid = nve0_graph_isr_chid(dev, inst);
u32 stat = nv_rd32(dev, 0x400100);
u32 addr = nv_rd32(dev, 0x400704);
struct nvc0_graph_priv *priv = (void *)subdev;
struct nouveau_engine *engine = nv_engine(subdev);
struct nouveau_handle *handle = NULL;
u64 inst = (u64)(nv_rd32(priv, 0x409b00) & 0x0fffffff) << 12;
u32 stat = nv_rd32(priv, 0x400100);
u32 addr = nv_rd32(priv, 0x400704);
u32 mthd = (addr & 0x00003ffc);
u32 subc = (addr & 0x00070000) >> 16;
u32 data = nv_rd32(dev, 0x400708);
u32 code = nv_rd32(dev, 0x400110);
u32 class = nv_rd32(dev, 0x404200 + (subc * 4));
u32 data = nv_rd32(priv, 0x400708);
u32 code = nv_rd32(priv, 0x400110);
u32 class = nv_rd32(priv, 0x404200 + (subc * 4));
if (stat & 0x00000010) {
if (nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data)) {
NV_INFO(dev, "PGRAPH: ILLEGAL_MTHD ch %d [0x%010llx] "
handle = nouveau_engctx_lookup_class(engine, inst, class);
if (!handle || nv_call(handle->object, mthd, data)) {
nv_error(priv, "ILLEGAL_MTHD ch 0x%010llx "
"subc %d class 0x%04x mthd 0x%04x "
"data 0x%08x\n",
chid, inst, subc, class, mthd, data);
inst, subc, class, mthd, data);
}
nv_wr32(dev, 0x400100, 0x00000010);
nouveau_engctx_handle_put(handle);
nv_wr32(priv, 0x400100, 0x00000010);
stat &= ~0x00000010;
}
if (stat & 0x00000020) {
NV_INFO(dev, "PGRAPH: ILLEGAL_CLASS ch %d [0x%010llx] subc %d "
nv_error(priv, "ILLEGAL_CLASS ch 0x%010llx subc %d "
"class 0x%04x mthd 0x%04x data 0x%08x\n",
chid, inst, subc, class, mthd, data);
nv_wr32(dev, 0x400100, 0x00000020);
inst, subc, class, mthd, data);
nv_wr32(priv, 0x400100, 0x00000020);
stat &= ~0x00000020;
}
if (stat & 0x00100000) {
NV_INFO(dev, "PGRAPH: DATA_ERROR [");
nv_error(priv, "DATA_ERROR [");
nouveau_enum_print(nv50_data_error_names, code);
printk("] ch %d [0x%010llx] subc %d class 0x%04x "
printk("] ch 0x%010llx subc %d class 0x%04x "
"mthd 0x%04x data 0x%08x\n",
chid, inst, subc, class, mthd, data);
nv_wr32(dev, 0x400100, 0x00100000);
inst, subc, class, mthd, data);
nv_wr32(priv, 0x400100, 0x00100000);
stat &= ~0x00100000;
}
if (stat & 0x00200000) {
nve0_graph_trap_isr(dev, chid);
nv_wr32(dev, 0x400100, 0x00200000);
nve0_graph_trap_isr(priv, inst);
nv_wr32(priv, 0x400100, 0x00200000);
stat &= ~0x00200000;
}
if (stat & 0x00080000) {
nve0_graph_ctxctl_isr(dev);
nv_wr32(dev, 0x400100, 0x00080000);
nve0_graph_ctxctl_isr(priv);
nv_wr32(priv, 0x400100, 0x00080000);
stat &= ~0x00080000;
}
if (stat) {
NV_INFO(dev, "PGRAPH: unknown stat 0x%08x\n", stat);
nv_wr32(dev, 0x400100, stat);
nv_error(priv, "unknown stat 0x%08x\n", stat);
nv_wr32(priv, 0x400100, stat);
}
nv_wr32(dev, 0x400500, 0x00010001);
nv_wr32(priv, 0x400500, 0x00010001);
}
static int
nve0_graph_create_fw(struct drm_device *dev, const char *fwname,
struct nvc0_graph_fuc *fuc)
nve0_graph_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;
const struct firmware *fw;
char f[32];
int ret;
struct nvc0_graph_priv *priv;
int ret, i;
snprintf(f, sizeof(f), "nouveau/nv%02x_%s", dev_priv->chipset, fwname);
ret = request_firmware(&fw, f, &dev->pdev->dev);
ret = nouveau_graph_create(parent, engine, oclass, false, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
fuc->size = fw->size;
fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL);
release_firmware(fw);
return (fuc->data != NULL) ? 0 : -ENOMEM;
}
nv_subdev(priv)->unit = 0x18001000;
nv_subdev(priv)->intr = nve0_graph_intr;
nv_engine(priv)->cclass = &nve0_graph_cclass;
nv_engine(priv)->sclass = nve0_graph_sclass;
static void
nve0_graph_destroy_fw(struct nvc0_graph_fuc *fuc)
{
if (fuc->data) {
kfree(fuc->data);
fuc->data = NULL;
}
}
static void
nve0_graph_destroy(struct drm_device *dev, int engine)
{
struct nvc0_graph_priv *priv = nv_engine(dev, engine);
nve0_graph_destroy_fw(&priv->fuc409c);
nve0_graph_destroy_fw(&priv->fuc409d);
nve0_graph_destroy_fw(&priv->fuc41ac);
nve0_graph_destroy_fw(&priv->fuc41ad);
nouveau_irq_unregister(dev, 12);
nouveau_gpuobj_ref(NULL, &priv->unk4188b8);
nouveau_gpuobj_ref(NULL, &priv->unk4188b4);
if (priv->data)
kfree(priv->data);
NVOBJ_ENGINE_DEL(dev, GR);
kfree(priv);
}
int
nve0_graph_create(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvc0_graph_priv *priv;
int ret, gpc, i;
u32 kepler;
kepler = nvc0_graph_class(dev);
if (!kepler) {
NV_ERROR(dev, "PGRAPH: unsupported chipset, please report!\n");
return 0;
}
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->base.destroy = nve0_graph_destroy;
priv->base.init = nve0_graph_init;
priv->base.fini = nve0_graph_fini;
priv->base.context_new = nvc0_graph_context_new;
priv->base.context_del = nvc0_graph_context_del;
priv->base.object_new = nve0_graph_object_new;
NVOBJ_ENGINE_ADD(dev, GR, &priv->base);
nouveau_irq_register(dev, 12, nve0_graph_isr);
NV_INFO(dev, "PGRAPH: using external firmware\n");
if (nve0_graph_create_fw(dev, "fuc409c", &priv->fuc409c) ||
nve0_graph_create_fw(dev, "fuc409d", &priv->fuc409d) ||
nve0_graph_create_fw(dev, "fuc41ac", &priv->fuc41ac) ||
nve0_graph_create_fw(dev, "fuc41ad", &priv->fuc41ad)) {
ret = 0;
goto error;
}
nv_info(priv, "using external firmware\n");
if (nvc0_graph_ctor_fw(priv, "fuc409c", &priv->fuc409c) ||
nvc0_graph_ctor_fw(priv, "fuc409d", &priv->fuc409d) ||
nvc0_graph_ctor_fw(priv, "fuc41ac", &priv->fuc41ac) ||
nvc0_graph_ctor_fw(priv, "fuc41ad", &priv->fuc41ad))
return -EINVAL;
priv->firmware = true;
ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4);
ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 256, 0, &priv->unk4188b4);
if (ret)
goto error;
return ret;
ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b8);
ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 256, 0, &priv->unk4188b8);
if (ret)
goto error;
return ret;
for (i = 0; i < 0x1000; i += 4) {
nv_wo32(priv->unk4188b4, i, 0x00000010);
nv_wo32(priv->unk4188b8, i, 0x00000010);
}
priv->gpc_nr = nv_rd32(dev, 0x409604) & 0x0000001f;
priv->rop_nr = (nv_rd32(dev, 0x409604) & 0x001f0000) >> 16;
for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
priv->tpc_nr[gpc] = nv_rd32(dev, GPC_UNIT(gpc, 0x2608));
priv->tpc_total += priv->tpc_nr[gpc];
priv->gpc_nr = nv_rd32(priv, 0x409604) & 0x0000001f;
priv->rop_nr = (nv_rd32(priv, 0x409604) & 0x001f0000) >> 16;
for (i = 0; i < priv->gpc_nr; i++) {
priv->tpc_nr[i] = nv_rd32(priv, GPC_UNIT(i, 0x2608));
priv->tpc_total += priv->tpc_nr[i];
}
switch (dev_priv->chipset) {
switch (nv_device(priv)->chipset) {
case 0xe4:
if (priv->tpc_total == 8)
priv->magic_not_rop_nr = 3;
@@ -616,21 +243,275 @@ nve0_graph_create(struct drm_device *dev)
break;
}
if (!priv->magic_not_rop_nr) {
NV_ERROR(dev, "PGRAPH: unknown config: %d/%d/%d/%d, %d\n",
priv->tpc_nr[0], priv->tpc_nr[1], priv->tpc_nr[2],
priv->tpc_nr[3], priv->rop_nr);
priv->magic_not_rop_nr = 0x00;
return 0;
}
static void
nve0_graph_init_obj418880(struct nvc0_graph_priv *priv)
{
int i;
nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000);
nv_wr32(priv, GPC_BCAST(0x08a4), 0x00000000);
for (i = 0; i < 4; i++)
nv_wr32(priv, GPC_BCAST(0x0888) + (i * 4), 0x00000000);
nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
}
static void
nve0_graph_init_regs(struct nvc0_graph_priv *priv)
{
nv_wr32(priv, 0x400080, 0x003083c2);
nv_wr32(priv, 0x400088, 0x0001ffe7);
nv_wr32(priv, 0x40008c, 0x00000000);
nv_wr32(priv, 0x400090, 0x00000030);
nv_wr32(priv, 0x40013c, 0x003901f7);
nv_wr32(priv, 0x400140, 0x00000100);
nv_wr32(priv, 0x400144, 0x00000000);
nv_wr32(priv, 0x400148, 0x00000110);
nv_wr32(priv, 0x400138, 0x00000000);
nv_wr32(priv, 0x400130, 0x00000000);
nv_wr32(priv, 0x400134, 0x00000000);
nv_wr32(priv, 0x400124, 0x00000002);
}
static void
nve0_graph_init_units(struct nvc0_graph_priv *priv)
{
nv_wr32(priv, 0x409ffc, 0x00000000);
nv_wr32(priv, 0x409c14, 0x00003e3e);
nv_wr32(priv, 0x409c24, 0x000f0000);
nv_wr32(priv, 0x404000, 0xc0000000);
nv_wr32(priv, 0x404600, 0xc0000000);
nv_wr32(priv, 0x408030, 0xc0000000);
nv_wr32(priv, 0x404490, 0xc0000000);
nv_wr32(priv, 0x406018, 0xc0000000);
nv_wr32(priv, 0x407020, 0xc0000000);
nv_wr32(priv, 0x405840, 0xc0000000);
nv_wr32(priv, 0x405844, 0x00ffffff);
nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008);
nv_mask(priv, 0x419eb4, 0x00001000, 0x00001000);
}
static void
nve0_graph_init_gpc_0(struct nvc0_graph_priv *priv)
{
const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
u32 data[TPC_MAX / 8];
u8 tpcnr[GPC_MAX];
int i, gpc, tpc;
nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001);
memset(data, 0x00, sizeof(data));
memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
do {
gpc = (gpc + 1) % priv->gpc_nr;
} while (!tpcnr[gpc]);
tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
data[i / 8] |= tpc << ((i % 8) * 4);
}
NVOBJ_CLASS(dev, 0xa097, GR); /* subc 0: 3D */
NVOBJ_CLASS(dev, 0xa0c0, GR); /* subc 1: COMPUTE */
NVOBJ_CLASS(dev, 0xa040, GR); /* subc 2: P2MF */
NVOBJ_CLASS(dev, 0x902d, GR); /* subc 3: 2D */
NVOBJ_CLASS(dev, 0xa0b5, GR); /* subc 4: COPY */
return 0;
nv_wr32(priv, GPC_BCAST(0x0980), data[0]);
nv_wr32(priv, GPC_BCAST(0x0984), data[1]);
nv_wr32(priv, GPC_BCAST(0x0988), data[2]);
nv_wr32(priv, GPC_BCAST(0x098c), data[3]);
error:
nve0_graph_destroy(dev, NVOBJ_ENGINE_GR);
return ret;
for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
nv_wr32(priv, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 |
priv->tpc_nr[gpc]);
nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 | priv->tpc_total);
nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918);
}
nv_wr32(priv, GPC_BCAST(0x1bd4), magicgpc918);
nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800));
}
static void
nve0_graph_init_gpc_1(struct nvc0_graph_priv *priv)
{
int gpc, tpc;
for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
nv_wr32(priv, GPC_UNIT(gpc, 0x3038), 0xc0000000);
nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe);
nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f);
}
nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
}
}
static void
nve0_graph_init_rop(struct nvc0_graph_priv *priv)
{
int rop;
for (rop = 0; rop < priv->rop_nr; rop++) {
nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff);
nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff);
}
}
static int
nve0_graph_init_ctxctl(struct nvc0_graph_priv *priv)
{
u32 r000260;
/* load fuc microcode */
r000260 = nv_mask(priv, 0x000260, 0x00000001, 0x00000000);
nvc0_graph_init_fw(priv, 0x409000, &priv->fuc409c, &priv->fuc409d);
nvc0_graph_init_fw(priv, 0x41a000, &priv->fuc41ac, &priv->fuc41ad);
nv_wr32(priv, 0x000260, r000260);
/* start both of them running */
nv_wr32(priv, 0x409840, 0xffffffff);
nv_wr32(priv, 0x41a10c, 0x00000000);
nv_wr32(priv, 0x40910c, 0x00000000);
nv_wr32(priv, 0x41a100, 0x00000002);
nv_wr32(priv, 0x409100, 0x00000002);
if (!nv_wait(priv, 0x409800, 0x00000001, 0x00000001))
nv_error(priv, "0x409800 wait failed\n");
nv_wr32(priv, 0x409840, 0xffffffff);
nv_wr32(priv, 0x409500, 0x7fffffff);
nv_wr32(priv, 0x409504, 0x00000021);
nv_wr32(priv, 0x409840, 0xffffffff);
nv_wr32(priv, 0x409500, 0x00000000);
nv_wr32(priv, 0x409504, 0x00000010);
if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
nv_error(priv, "fuc09 req 0x10 timeout\n");
return -EBUSY;
}
priv->size = nv_rd32(priv, 0x409800);
nv_wr32(priv, 0x409840, 0xffffffff);
nv_wr32(priv, 0x409500, 0x00000000);
nv_wr32(priv, 0x409504, 0x00000016);
if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
nv_error(priv, "fuc09 req 0x16 timeout\n");
return -EBUSY;
}
nv_wr32(priv, 0x409840, 0xffffffff);
nv_wr32(priv, 0x409500, 0x00000000);
nv_wr32(priv, 0x409504, 0x00000025);
if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
nv_error(priv, "fuc09 req 0x25 timeout\n");
return -EBUSY;
}
nv_wr32(priv, 0x409800, 0x00000000);
nv_wr32(priv, 0x409500, 0x00000001);
nv_wr32(priv, 0x409504, 0x00000030);
if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
nv_error(priv, "fuc09 req 0x30 timeout\n");
return -EBUSY;
}
nv_wr32(priv, 0x409810, 0xb00095c8);
nv_wr32(priv, 0x409800, 0x00000000);
nv_wr32(priv, 0x409500, 0x00000001);
nv_wr32(priv, 0x409504, 0x00000031);
if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
nv_error(priv, "fuc09 req 0x31 timeout\n");
return -EBUSY;
}
nv_wr32(priv, 0x409810, 0x00080420);
nv_wr32(priv, 0x409800, 0x00000000);
nv_wr32(priv, 0x409500, 0x00000001);
nv_wr32(priv, 0x409504, 0x00000032);
if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
nv_error(priv, "fuc09 req 0x32 timeout\n");
return -EBUSY;
}
nv_wr32(priv, 0x409614, 0x00000070);
nv_wr32(priv, 0x409614, 0x00000770);
nv_wr32(priv, 0x40802c, 0x00000001);
if (priv->data == NULL) {
int ret = nve0_grctx_generate(priv);
if (ret) {
nv_error(priv, "failed to construct context\n");
return ret;
}
return 1;
}
return 0;
}
static int
nve0_graph_init(struct nouveau_object *object)
{
struct nvc0_graph_priv *priv = (void *)object;
int ret;
reset:
ret = nouveau_graph_init(&priv->base);
if (ret)
return ret;
nve0_graph_init_obj418880(priv);
nve0_graph_init_regs(priv);
nve0_graph_init_gpc_0(priv);
nv_wr32(priv, 0x400500, 0x00010001);
nv_wr32(priv, 0x400100, 0xffffffff);
nv_wr32(priv, 0x40013c, 0xffffffff);
nve0_graph_init_units(priv);
nve0_graph_init_gpc_1(priv);
nve0_graph_init_rop(priv);
nv_wr32(priv, 0x400108, 0xffffffff);
nv_wr32(priv, 0x400138, 0xffffffff);
nv_wr32(priv, 0x400118, 0xffffffff);
nv_wr32(priv, 0x400130, 0xffffffff);
nv_wr32(priv, 0x40011c, 0xffffffff);
nv_wr32(priv, 0x400134, 0xffffffff);
nv_wr32(priv, 0x400054, 0x34ce3464);
ret = nve0_graph_init_ctxctl(priv);
if (ret) {
if (ret == 1)
goto reset;
return ret;
}
return 0;
}
struct nouveau_oclass
nve0_graph_oclass = {
.handle = NV_ENGINE(GR, 0xe0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nve0_graph_ctor,
.dtor = nvc0_graph_dtor,
.init = nve0_graph_init,
.fini = _nouveau_graph_fini,
},
};
@@ -0,0 +1,269 @@
#ifndef __NOUVEAU_GRAPH_REGS_H__
#define __NOUVEAU_GRAPH_REGS_H__
#define NV04_PGRAPH_DEBUG_0 0x00400080
#define NV04_PGRAPH_DEBUG_1 0x00400084
#define NV04_PGRAPH_DEBUG_2 0x00400088
#define NV04_PGRAPH_DEBUG_3 0x0040008c
#define NV10_PGRAPH_DEBUG_4 0x00400090
#define NV03_PGRAPH_INTR 0x00400100
#define NV03_PGRAPH_NSTATUS 0x00400104
# define NV04_PGRAPH_NSTATUS_STATE_IN_USE (1<<11)
# define NV04_PGRAPH_NSTATUS_INVALID_STATE (1<<12)
# define NV04_PGRAPH_NSTATUS_BAD_ARGUMENT (1<<13)
# define NV04_PGRAPH_NSTATUS_PROTECTION_FAULT (1<<14)
# define NV10_PGRAPH_NSTATUS_STATE_IN_USE (1<<23)
# define NV10_PGRAPH_NSTATUS_INVALID_STATE (1<<24)
# define NV10_PGRAPH_NSTATUS_BAD_ARGUMENT (1<<25)
# define NV10_PGRAPH_NSTATUS_PROTECTION_FAULT (1<<26)
#define NV03_PGRAPH_NSOURCE 0x00400108
# define NV03_PGRAPH_NSOURCE_NOTIFICATION (1<<0)
# define NV03_PGRAPH_NSOURCE_DATA_ERROR (1<<1)
# define NV03_PGRAPH_NSOURCE_PROTECTION_ERROR (1<<2)
# define NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION (1<<3)
# define NV03_PGRAPH_NSOURCE_LIMIT_COLOR (1<<4)
# define NV03_PGRAPH_NSOURCE_LIMIT_ZETA (1<<5)
# define NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD (1<<6)
# define NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION (1<<7)
# define NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION (1<<8)
# define NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION (1<<9)
# define NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION (1<<10)
# define NV03_PGRAPH_NSOURCE_STATE_INVALID (1<<11)
# define NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY (1<<12)
# define NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE (1<<13)
# define NV03_PGRAPH_NSOURCE_METHOD_CNT (1<<14)
# define NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION (1<<15)
# define NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION (1<<16)
# define NV03_PGRAPH_NSOURCE_DMA_WIDTH_A (1<<17)
# define NV03_PGRAPH_NSOURCE_DMA_WIDTH_B (1<<18)
#define NV03_PGRAPH_INTR_EN 0x00400140
#define NV40_PGRAPH_INTR_EN 0x0040013C
# define NV_PGRAPH_INTR_NOTIFY (1<<0)
# define NV_PGRAPH_INTR_MISSING_HW (1<<4)
# define NV_PGRAPH_INTR_CONTEXT_SWITCH (1<<12)
# define NV_PGRAPH_INTR_BUFFER_NOTIFY (1<<16)
# define NV_PGRAPH_INTR_ERROR (1<<20)
#define NV10_PGRAPH_CTX_CONTROL 0x00400144
#define NV10_PGRAPH_CTX_USER 0x00400148
#define NV10_PGRAPH_CTX_SWITCH(i) (0x0040014C + 0x4*(i))
#define NV04_PGRAPH_CTX_SWITCH1 0x00400160
#define NV10_PGRAPH_CTX_CACHE(i, j) (0x00400160 \
+ 0x4*(i) + 0x20*(j))
#define NV04_PGRAPH_CTX_SWITCH2 0x00400164
#define NV04_PGRAPH_CTX_SWITCH3 0x00400168
#define NV04_PGRAPH_CTX_SWITCH4 0x0040016C
#define NV04_PGRAPH_CTX_CONTROL 0x00400170
#define NV04_PGRAPH_CTX_USER 0x00400174
#define NV04_PGRAPH_CTX_CACHE1 0x00400180
#define NV03_PGRAPH_CTX_CONTROL 0x00400190
#define NV03_PGRAPH_CTX_USER 0x00400194
#define NV04_PGRAPH_CTX_CACHE2 0x004001A0
#define NV04_PGRAPH_CTX_CACHE3 0x004001C0
#define NV04_PGRAPH_CTX_CACHE4 0x004001E0
#define NV40_PGRAPH_CTXCTL_0304 0x00400304
#define NV40_PGRAPH_CTXCTL_0304_XFER_CTX 0x00000001
#define NV40_PGRAPH_CTXCTL_UCODE_STAT 0x00400308
#define NV40_PGRAPH_CTXCTL_UCODE_STAT_IP_MASK 0xff000000
#define NV40_PGRAPH_CTXCTL_UCODE_STAT_IP_SHIFT 24
#define NV40_PGRAPH_CTXCTL_UCODE_STAT_OP_MASK 0x00ffffff
#define NV40_PGRAPH_CTXCTL_0310 0x00400310
#define NV40_PGRAPH_CTXCTL_0310_XFER_SAVE 0x00000020
#define NV40_PGRAPH_CTXCTL_0310_XFER_LOAD 0x00000040
#define NV40_PGRAPH_CTXCTL_030C 0x0040030c
#define NV40_PGRAPH_CTXCTL_UCODE_INDEX 0x00400324
#define NV40_PGRAPH_CTXCTL_UCODE_DATA 0x00400328
#define NV40_PGRAPH_CTXCTL_CUR 0x0040032c
#define NV40_PGRAPH_CTXCTL_CUR_LOADED 0x01000000
#define NV40_PGRAPH_CTXCTL_CUR_INSTANCE 0x000FFFFF
#define NV40_PGRAPH_CTXCTL_NEXT 0x00400330
#define NV40_PGRAPH_CTXCTL_NEXT_INSTANCE 0x000fffff
#define NV50_PGRAPH_CTXCTL_CUR 0x0040032c
#define NV50_PGRAPH_CTXCTL_CUR_LOADED 0x80000000
#define NV50_PGRAPH_CTXCTL_CUR_INSTANCE 0x00ffffff
#define NV50_PGRAPH_CTXCTL_NEXT 0x00400330
#define NV50_PGRAPH_CTXCTL_NEXT_INSTANCE 0x00ffffff
#define NV03_PGRAPH_ABS_X_RAM 0x00400400
#define NV03_PGRAPH_ABS_Y_RAM 0x00400480
#define NV03_PGRAPH_X_MISC 0x00400500
#define NV03_PGRAPH_Y_MISC 0x00400504
#define NV04_PGRAPH_VALID1 0x00400508
#define NV04_PGRAPH_SOURCE_COLOR 0x0040050C
#define NV04_PGRAPH_MISC24_0 0x00400510
#define NV03_PGRAPH_XY_LOGIC_MISC0 0x00400514
#define NV03_PGRAPH_XY_LOGIC_MISC1 0x00400518
#define NV03_PGRAPH_XY_LOGIC_MISC2 0x0040051C
#define NV03_PGRAPH_XY_LOGIC_MISC3 0x00400520
#define NV03_PGRAPH_CLIPX_0 0x00400524
#define NV03_PGRAPH_CLIPX_1 0x00400528
#define NV03_PGRAPH_CLIPY_0 0x0040052C
#define NV03_PGRAPH_CLIPY_1 0x00400530
#define NV03_PGRAPH_ABS_ICLIP_XMAX 0x00400534
#define NV03_PGRAPH_ABS_ICLIP_YMAX 0x00400538
#define NV03_PGRAPH_ABS_UCLIP_XMIN 0x0040053C
#define NV03_PGRAPH_ABS_UCLIP_YMIN 0x00400540
#define NV03_PGRAPH_ABS_UCLIP_XMAX 0x00400544
#define NV03_PGRAPH_ABS_UCLIP_YMAX 0x00400548
#define NV03_PGRAPH_ABS_UCLIPA_XMIN 0x00400560
#define NV03_PGRAPH_ABS_UCLIPA_YMIN 0x00400564
#define NV03_PGRAPH_ABS_UCLIPA_XMAX 0x00400568
#define NV03_PGRAPH_ABS_UCLIPA_YMAX 0x0040056C
#define NV04_PGRAPH_MISC24_1 0x00400570
#define NV04_PGRAPH_MISC24_2 0x00400574
#define NV04_PGRAPH_VALID2 0x00400578
#define NV04_PGRAPH_PASSTHRU_0 0x0040057C
#define NV04_PGRAPH_PASSTHRU_1 0x00400580
#define NV04_PGRAPH_PASSTHRU_2 0x00400584
#define NV10_PGRAPH_DIMX_TEXTURE 0x00400588
#define NV10_PGRAPH_WDIMX_TEXTURE 0x0040058C
#define NV04_PGRAPH_COMBINE_0_ALPHA 0x00400590
#define NV04_PGRAPH_COMBINE_0_COLOR 0x00400594
#define NV04_PGRAPH_COMBINE_1_ALPHA 0x00400598
#define NV04_PGRAPH_COMBINE_1_COLOR 0x0040059C
#define NV04_PGRAPH_FORMAT_0 0x004005A8
#define NV04_PGRAPH_FORMAT_1 0x004005AC
#define NV04_PGRAPH_FILTER_0 0x004005B0
#define NV04_PGRAPH_FILTER_1 0x004005B4
#define NV03_PGRAPH_MONO_COLOR0 0x00400600
#define NV04_PGRAPH_ROP3 0x00400604
#define NV04_PGRAPH_BETA_AND 0x00400608
#define NV04_PGRAPH_BETA_PREMULT 0x0040060C
#define NV04_PGRAPH_LIMIT_VIOL_PIX 0x00400610
#define NV04_PGRAPH_FORMATS 0x00400618
#define NV10_PGRAPH_DEBUG_2 0x00400620
#define NV04_PGRAPH_BOFFSET0 0x00400640
#define NV04_PGRAPH_BOFFSET1 0x00400644
#define NV04_PGRAPH_BOFFSET2 0x00400648
#define NV04_PGRAPH_BOFFSET3 0x0040064C
#define NV04_PGRAPH_BOFFSET4 0x00400650
#define NV04_PGRAPH_BOFFSET5 0x00400654
#define NV04_PGRAPH_BBASE0 0x00400658
#define NV04_PGRAPH_BBASE1 0x0040065C
#define NV04_PGRAPH_BBASE2 0x00400660
#define NV04_PGRAPH_BBASE3 0x00400664
#define NV04_PGRAPH_BBASE4 0x00400668
#define NV04_PGRAPH_BBASE5 0x0040066C
#define NV04_PGRAPH_BPITCH0 0x00400670
#define NV04_PGRAPH_BPITCH1 0x00400674
#define NV04_PGRAPH_BPITCH2 0x00400678
#define NV04_PGRAPH_BPITCH3 0x0040067C
#define NV04_PGRAPH_BPITCH4 0x00400680
#define NV04_PGRAPH_BLIMIT0 0x00400684
#define NV04_PGRAPH_BLIMIT1 0x00400688
#define NV04_PGRAPH_BLIMIT2 0x0040068C
#define NV04_PGRAPH_BLIMIT3 0x00400690
#define NV04_PGRAPH_BLIMIT4 0x00400694
#define NV04_PGRAPH_BLIMIT5 0x00400698
#define NV04_PGRAPH_BSWIZZLE2 0x0040069C
#define NV04_PGRAPH_BSWIZZLE5 0x004006A0
#define NV03_PGRAPH_STATUS 0x004006B0
#define NV04_PGRAPH_STATUS 0x00400700
# define NV40_PGRAPH_STATUS_SYNC_STALL 0x00004000
#define NV04_PGRAPH_TRAPPED_ADDR 0x00400704
#define NV04_PGRAPH_TRAPPED_DATA 0x00400708
#define NV04_PGRAPH_SURFACE 0x0040070C
#define NV10_PGRAPH_TRAPPED_DATA_HIGH 0x0040070C
#define NV04_PGRAPH_STATE 0x00400710
#define NV10_PGRAPH_SURFACE 0x00400710
#define NV04_PGRAPH_NOTIFY 0x00400714
#define NV10_PGRAPH_STATE 0x00400714
#define NV10_PGRAPH_NOTIFY 0x00400718
#define NV04_PGRAPH_FIFO 0x00400720
#define NV04_PGRAPH_BPIXEL 0x00400724
#define NV10_PGRAPH_RDI_INDEX 0x00400750
#define NV04_PGRAPH_FFINTFC_ST2 0x00400754
#define NV10_PGRAPH_RDI_DATA 0x00400754
#define NV04_PGRAPH_DMA_PITCH 0x00400760
#define NV10_PGRAPH_FFINTFC_FIFO_PTR 0x00400760
#define NV04_PGRAPH_DVD_COLORFMT 0x00400764
#define NV10_PGRAPH_FFINTFC_ST2 0x00400764
#define NV04_PGRAPH_SCALED_FORMAT 0x00400768
#define NV10_PGRAPH_FFINTFC_ST2_DL 0x00400768
#define NV10_PGRAPH_FFINTFC_ST2_DH 0x0040076c
#define NV10_PGRAPH_DMA_PITCH 0x00400770
#define NV10_PGRAPH_DVD_COLORFMT 0x00400774
#define NV10_PGRAPH_SCALED_FORMAT 0x00400778
#define NV20_PGRAPH_CHANNEL_CTX_TABLE 0x00400780
#define NV20_PGRAPH_CHANNEL_CTX_POINTER 0x00400784
#define NV20_PGRAPH_CHANNEL_CTX_XFER 0x00400788
#define NV20_PGRAPH_CHANNEL_CTX_XFER_LOAD 0x00000001
#define NV20_PGRAPH_CHANNEL_CTX_XFER_SAVE 0x00000002
#define NV04_PGRAPH_PATT_COLOR0 0x00400800
#define NV04_PGRAPH_PATT_COLOR1 0x00400804
#define NV04_PGRAPH_PATTERN 0x00400808
#define NV04_PGRAPH_PATTERN_SHAPE 0x00400810
#define NV04_PGRAPH_CHROMA 0x00400814
#define NV04_PGRAPH_CONTROL0 0x00400818
#define NV04_PGRAPH_CONTROL1 0x0040081C
#define NV04_PGRAPH_CONTROL2 0x00400820
#define NV04_PGRAPH_BLEND 0x00400824
#define NV04_PGRAPH_STORED_FMT 0x00400830
#define NV04_PGRAPH_PATT_COLORRAM 0x00400900
#define NV20_PGRAPH_TILE(i) (0x00400900 + (i*16))
#define NV20_PGRAPH_TLIMIT(i) (0x00400904 + (i*16))
#define NV20_PGRAPH_TSIZE(i) (0x00400908 + (i*16))
#define NV20_PGRAPH_TSTATUS(i) (0x0040090C + (i*16))
#define NV20_PGRAPH_ZCOMP(i) (0x00400980 + 4*(i))
#define NV10_PGRAPH_TILE(i) (0x00400B00 + (i*16))
#define NV10_PGRAPH_TLIMIT(i) (0x00400B04 + (i*16))
#define NV10_PGRAPH_TSIZE(i) (0x00400B08 + (i*16))
#define NV10_PGRAPH_TSTATUS(i) (0x00400B0C + (i*16))
#define NV04_PGRAPH_U_RAM 0x00400D00
#define NV47_PGRAPH_TILE(i) (0x00400D00 + (i*16))
#define NV47_PGRAPH_TLIMIT(i) (0x00400D04 + (i*16))
#define NV47_PGRAPH_TSIZE(i) (0x00400D08 + (i*16))
#define NV47_PGRAPH_TSTATUS(i) (0x00400D0C + (i*16))
#define NV04_PGRAPH_V_RAM 0x00400D40
#define NV04_PGRAPH_W_RAM 0x00400D80
#define NV10_PGRAPH_COMBINER0_IN_ALPHA 0x00400E40
#define NV10_PGRAPH_COMBINER1_IN_ALPHA 0x00400E44
#define NV10_PGRAPH_COMBINER0_IN_RGB 0x00400E48
#define NV10_PGRAPH_COMBINER1_IN_RGB 0x00400E4C
#define NV10_PGRAPH_COMBINER_COLOR0 0x00400E50
#define NV10_PGRAPH_COMBINER_COLOR1 0x00400E54
#define NV10_PGRAPH_COMBINER0_OUT_ALPHA 0x00400E58
#define NV10_PGRAPH_COMBINER1_OUT_ALPHA 0x00400E5C
#define NV10_PGRAPH_COMBINER0_OUT_RGB 0x00400E60
#define NV10_PGRAPH_COMBINER1_OUT_RGB 0x00400E64
#define NV10_PGRAPH_COMBINER_FINAL0 0x00400E68
#define NV10_PGRAPH_COMBINER_FINAL1 0x00400E6C
#define NV10_PGRAPH_WINDOWCLIP_HORIZONTAL 0x00400F00
#define NV10_PGRAPH_WINDOWCLIP_VERTICAL 0x00400F20
#define NV10_PGRAPH_XFMODE0 0x00400F40
#define NV10_PGRAPH_XFMODE1 0x00400F44
#define NV10_PGRAPH_GLOBALSTATE0 0x00400F48
#define NV10_PGRAPH_GLOBALSTATE1 0x00400F4C
#define NV10_PGRAPH_PIPE_ADDRESS 0x00400F50
#define NV10_PGRAPH_PIPE_DATA 0x00400F54
#define NV04_PGRAPH_DMA_START_0 0x00401000
#define NV04_PGRAPH_DMA_START_1 0x00401004
#define NV04_PGRAPH_DMA_LENGTH 0x00401008
#define NV04_PGRAPH_DMA_MISC 0x0040100C
#define NV04_PGRAPH_DMA_DATA_0 0x00401020
#define NV04_PGRAPH_DMA_DATA_1 0x00401024
#define NV04_PGRAPH_DMA_RM 0x00401030
#define NV04_PGRAPH_DMA_A_XLATE_INST 0x00401040
#define NV04_PGRAPH_DMA_A_CONTROL 0x00401044
#define NV04_PGRAPH_DMA_A_LIMIT 0x00401048
#define NV04_PGRAPH_DMA_A_TLB_PTE 0x0040104C
#define NV04_PGRAPH_DMA_A_TLB_TAG 0x00401050
#define NV04_PGRAPH_DMA_A_ADJ_OFFSET 0x00401054
#define NV04_PGRAPH_DMA_A_OFFSET 0x00401058
#define NV04_PGRAPH_DMA_A_SIZE 0x0040105C
#define NV04_PGRAPH_DMA_A_Y_SIZE 0x00401060
#define NV04_PGRAPH_DMA_B_XLATE_INST 0x00401080
#define NV04_PGRAPH_DMA_B_CONTROL 0x00401084
#define NV04_PGRAPH_DMA_B_LIMIT 0x00401088
#define NV04_PGRAPH_DMA_B_TLB_PTE 0x0040108C
#define NV04_PGRAPH_DMA_B_TLB_TAG 0x00401090
#define NV04_PGRAPH_DMA_B_ADJ_OFFSET 0x00401094
#define NV04_PGRAPH_DMA_B_OFFSET 0x00401098
#define NV04_PGRAPH_DMA_B_SIZE 0x0040109C
#define NV04_PGRAPH_DMA_B_Y_SIZE 0x004010A0
#define NV40_PGRAPH_TILE1(i) (0x00406900 + (i*16))
#define NV40_PGRAPH_TLIMIT1(i) (0x00406904 + (i*16))
#define NV40_PGRAPH_TSIZE1(i) (0x00406908 + (i*16))
#define NV40_PGRAPH_TSTATUS1(i) (0x0040690C + (i*16))
#endif
+199 -241
View File
@@ -1,5 +1,5 @@
/*
* 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,159 +22,62 @@
* Authors: Ben Skeggs
*/
#include "drmP.h"
#include "nouveau_drv.h"
#include <engine/fifo.h>
#include <core/ramht.h>
#include <core/os.h>
#include <core/class.h>
#include <core/engctx.h>
#include <core/handle.h>
#include <core/engine/graph/nv40.h>
struct nv31_mpeg_engine {
struct nouveau_exec_engine base;
#include <subdev/fb.h>
#include <subdev/timer.h>
#include <subdev/instmem.h>
#include <engine/mpeg.h>
struct nv31_mpeg_priv {
struct nouveau_mpeg base;
atomic_t refcount;
};
struct nv31_mpeg_chan {
struct nouveau_object base;
};
/*******************************************************************************
* MPEG object classes
******************************************************************************/
static int
nv31_mpeg_context_new(struct nouveau_channel *chan, int engine)
nv31_mpeg_object_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv31_mpeg_engine *pmpeg = nv_engine(chan->dev, engine);
if (!atomic_add_unless(&pmpeg->refcount, 1, 1))
return -EBUSY;
chan->engctx[engine] = (void *)0xdeadcafe;
return 0;
}
static void
nv31_mpeg_context_del(struct nouveau_channel *chan, int engine)
{
struct nv31_mpeg_engine *pmpeg = nv_engine(chan->dev, engine);
atomic_dec(&pmpeg->refcount);
chan->engctx[engine] = NULL;
}
static int
nv40_mpeg_context_new(struct nouveau_channel *chan, int engine)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *ctx = NULL;
unsigned long flags;
struct nouveau_gpuobj *obj;
int ret;
NV_DEBUG(dev, "ch%d\n", chan->id);
ret = nouveau_gpuobj_new(dev, NULL, 264 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC |
NVOBJ_FLAG_ZERO_FREE, &ctx);
ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent,
20, 16, 0, &obj);
*pobject = nv_object(obj);
if (ret)
return ret;
nv_wo32(ctx, 0x78, 0x02001ec1);
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
nv_mask(dev, 0x002500, 0x00000001, 0x00000000);
if ((nv_rd32(dev, 0x003204) & 0x1f) == chan->id)
nv_wr32(dev, 0x00330c, ctx->addr >> 4);
nv_wo32(chan->ramfc, 0x54, ctx->addr >> 4);
nv_mask(dev, 0x002500, 0x00000001, 0x00000001);
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
chan->engctx[engine] = ctx;
return 0;
}
static void
nv40_mpeg_context_del(struct nouveau_channel *chan, int engine)
{
struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
struct nouveau_gpuobj *ctx = chan->engctx[engine];
struct drm_device *dev = chan->dev;
unsigned long flags;
u32 inst = 0x80000000 | (ctx->addr >> 4);
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
if (nv_rd32(dev, 0x00b318) == inst)
nv_mask(dev, 0x00b318, 0x80000000, 0x00000000);
nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
nouveau_gpuobj_ref(NULL, &ctx);
chan->engctx[engine] = NULL;
}
static int
nv31_mpeg_object_new(struct nouveau_channel *chan, int engine,
u32 handle, u16 class)
{
struct drm_device *dev = chan->dev;
struct nouveau_gpuobj *obj = NULL;
int ret;
ret = nouveau_gpuobj_new(dev, chan, 20, 16, NVOBJ_FLAG_ZERO_ALLOC |
NVOBJ_FLAG_ZERO_FREE, &obj);
if (ret)
return ret;
obj->engine = 2;
obj->class = class;
nv_wo32(obj, 0x00, class);
ret = nouveau_ramht_insert(chan, handle, obj);
nouveau_gpuobj_ref(NULL, &obj);
return ret;
}
static int
nv31_mpeg_init(struct drm_device *dev, int engine)
{
struct nv31_mpeg_engine *pmpeg = nv_engine(dev, engine);
int i;
/* VPE init */
nv_mask(dev, 0x000200, 0x00000002, 0x00000000);
nv_mask(dev, 0x000200, 0x00000002, 0x00000002);
nv_wr32(dev, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
nv_wr32(dev, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
for (i = 0; i < nvfb_tile_nr(dev); i++)
pmpeg->base.set_tile_region(dev, i);
/* PMPEG init */
nv_wr32(dev, 0x00b32c, 0x00000000);
nv_wr32(dev, 0x00b314, 0x00000100);
nv_wr32(dev, 0x00b220, nv44_graph_class(dev) ? 0x00000044 : 0x00000031);
nv_wr32(dev, 0x00b300, 0x02001ec1);
nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
nv_wr32(dev, 0x00b100, 0xffffffff);
nv_wr32(dev, 0x00b140, 0xffffffff);
if (!nv_wait(dev, 0x00b200, 0x00000001, 0x00000000)) {
NV_ERROR(dev, "PMPEG init: 0x%08x\n", nv_rd32(dev, 0x00b200));
return -EBUSY;
}
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 int
nv31_mpeg_fini(struct drm_device *dev, int engine, bool suspend)
nv31_mpeg_mthd_dma(struct nouveau_object *object, u32 mthd, void *arg, u32 len)
{
/*XXX: context save? */
nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
nv_wr32(dev, 0x00b140, 0x00000000);
return 0;
}
static int
nv31_mpeg_mthd_dma(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
{
struct drm_device *dev = chan->dev;
u32 inst = data << 4;
u32 dma0 = nv_ri32(dev, inst + 0);
u32 dma1 = nv_ri32(dev, inst + 4);
u32 dma2 = nv_ri32(dev, inst + 8);
struct nouveau_instmem *imem = nouveau_instmem(object);
struct nv31_mpeg_priv *priv = (void *)object->engine;
u32 inst = *(u32 *)arg << 4;
u32 dma0 = nv_ro32(imem, inst + 0);
u32 dma1 = nv_ro32(imem, inst + 4);
u32 dma2 = nv_ro32(imem, inst + 8);
u32 base = (dma2 & 0xfffff000) | (dma0 >> 20);
u32 size = dma1 + 1;
@@ -184,160 +87,215 @@ nv31_mpeg_mthd_dma(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
if (mthd == 0x0190) {
/* DMA_CMD */
nv_mask(dev, 0x00b300, 0x00030000, (dma0 & 0x00030000));
nv_wr32(dev, 0x00b334, base);
nv_wr32(dev, 0x00b324, size);
nv_mask(priv, 0x00b300, 0x00030000, (dma0 & 0x00030000));
nv_wr32(priv, 0x00b334, base);
nv_wr32(priv, 0x00b324, size);
} else
if (mthd == 0x01a0) {
/* DMA_DATA */
nv_mask(dev, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2);
nv_wr32(dev, 0x00b360, base);
nv_wr32(dev, 0x00b364, size);
nv_mask(priv, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2);
nv_wr32(priv, 0x00b360, base);
nv_wr32(priv, 0x00b364, size);
} else {
/* DMA_IMAGE, VRAM only */
if (dma0 & 0x000c0000)
return -EINVAL;
nv_wr32(dev, 0x00b370, base);
nv_wr32(dev, 0x00b374, size);
nv_wr32(priv, 0x00b370, base);
nv_wr32(priv, 0x00b374, size);
}
return 0;
}
struct nouveau_ofuncs
nv31_mpeg_ofuncs = {
.ctor = nv31_mpeg_object_ctor,
.dtor = _nouveau_gpuobj_dtor,
.init = _nouveau_gpuobj_init,
.fini = _nouveau_gpuobj_fini,
.rd32 = _nouveau_gpuobj_rd32,
.wr32 = _nouveau_gpuobj_wr32,
};
struct nouveau_omthds
nv31_mpeg_omthds[] = {
{ 0x0190, nv31_mpeg_mthd_dma },
{ 0x01a0, nv31_mpeg_mthd_dma },
{ 0x01b0, nv31_mpeg_mthd_dma },
{}
};
struct nouveau_oclass
nv31_mpeg_sclass[] = {
{ 0x3174, &nv31_mpeg_ofuncs, nv31_mpeg_omthds },
{}
};
/*******************************************************************************
* PMPEG context
******************************************************************************/
static int
nv31_mpeg_isr_chid(struct drm_device *dev, u32 inst)
nv31_mpeg_context_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *ctx;
unsigned long flags;
int i;
struct nv31_mpeg_priv *priv = (void *)engine;
struct nv31_mpeg_chan *chan;
int ret;
/* hardcode drm channel id on nv3x, so swmthd lookup works */
if (dev_priv->card_type < NV_40)
return 0;
if (!atomic_add_unless(&priv->refcount, 1, 1))
return -EBUSY;
spin_lock_irqsave(&dev_priv->channels.lock, flags);
for (i = 0; i < pfifo->channels; i++) {
if (!dev_priv->channels.ptr[i])
continue;
ret = nouveau_object_create(parent, engine, oclass, 0, &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
ctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_MPEG];
if (ctx && ctx->addr == inst)
break;
}
spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
return i;
return 0;
}
static void
nv31_vpe_set_tile_region(struct drm_device *dev, int i)
nv31_mpeg_context_dtor(struct nouveau_object *object)
{
struct nouveau_fb_tile *tile = nvfb_tile(dev, i);
nv_wr32(dev, 0x00b008 + (i * 0x10), tile->pitch);
nv_wr32(dev, 0x00b004 + (i * 0x10), tile->limit);
nv_wr32(dev, 0x00b000 + (i * 0x10), tile->addr);
struct nv31_mpeg_priv *priv = (void *)object->engine;
struct nv31_mpeg_chan *chan = (void *)object;
atomic_dec(&priv->refcount);
nouveau_object_destroy(&chan->base);
}
static void
nv31_mpeg_isr(struct drm_device *dev)
static struct nouveau_oclass
nv31_mpeg_cclass = {
.handle = NV_ENGCTX(MPEG, 0x31),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv31_mpeg_context_ctor,
.dtor = nv31_mpeg_context_dtor,
.init = nouveau_object_init,
.fini = nouveau_object_fini,
},
};
/*******************************************************************************
* PMPEG engine/subdev functions
******************************************************************************/
void
nv31_mpeg_tile_prog(struct nouveau_engine *engine, int i)
{
u32 inst = (nv_rd32(dev, 0x00b318) & 0x000fffff) << 4;
u32 chid = nv31_mpeg_isr_chid(dev, inst);
u32 stat = nv_rd32(dev, 0x00b100);
u32 type = nv_rd32(dev, 0x00b230);
u32 mthd = nv_rd32(dev, 0x00b234);
u32 data = nv_rd32(dev, 0x00b238);
struct nouveau_fb_tile *tile = &nouveau_fb(engine)->tile.region[i];
struct nv31_mpeg_priv *priv = (void *)engine;
nv_wr32(priv, 0x00b008 + (i * 0x10), tile->pitch);
nv_wr32(priv, 0x00b004 + (i * 0x10), tile->limit);
nv_wr32(priv, 0x00b000 + (i * 0x10), tile->addr);
}
void
nv31_mpeg_intr(struct nouveau_subdev *subdev)
{
struct nv31_mpeg_priv *priv = (void *)subdev;
struct nouveau_engine *engine = nv_engine(subdev);
struct nouveau_handle *handle = NULL;
u32 inst = (nv_rd32(priv, 0x00b318) & 0x000fffff) << 4;
u32 stat = nv_rd32(priv, 0x00b100);
u32 type = nv_rd32(priv, 0x00b230);
u32 mthd = nv_rd32(priv, 0x00b234);
u32 data = nv_rd32(priv, 0x00b238);
u32 show = stat;
if (stat & 0x01000000) {
/* happens on initial binding of the object */
if (type == 0x00000020 && mthd == 0x0000) {
nv_mask(dev, 0x00b308, 0x00000000, 0x00000000);
if (handle && type == 0x00000020 && mthd == 0x0000) {
nv_mask(priv, 0x00b308, 0x00000000, 0x00000000);
show &= ~0x01000000;
}
if (type == 0x00000010) {
if (!nouveau_gpuobj_mthd_call2(dev, chid, 0x3174, mthd, data))
if (handle && type == 0x00000010) {
handle = nouveau_engctx_lookup_class(engine, inst, 0x3174);
if (handle && !nv_call(handle->object, mthd, data)) {
nouveau_engctx_handle_put(handle);
show &= ~0x01000000;
}
}
}
nv_wr32(dev, 0x00b100, stat);
nv_wr32(dev, 0x00b230, 0x00000001);
nv_wr32(priv, 0x00b100, stat);
nv_wr32(priv, 0x00b230, 0x00000001);
if (show && nouveau_ratelimit()) {
NV_INFO(dev, "PMPEG: Ch %d [0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n",
chid, inst, stat, type, mthd, data);
if (show) {
nv_error(priv, "ch %d [0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n",
inst, stat, type, mthd, data);
}
}
static void
nv31_vpe_isr(struct drm_device *dev)
static int
nv31_mpeg_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, 0x00b100))
nv31_mpeg_isr(dev);
struct nv31_mpeg_priv *priv;
int ret;
if (nv_rd32(dev, 0x00b800)) {
u32 stat = nv_rd32(dev, 0x00b800);
NV_INFO(dev, "PMSRCH: 0x%08x\n", stat);
nv_wr32(dev, 0xb800, stat);
}
}
ret = nouveau_mpeg_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
static void
nv31_mpeg_destroy(struct drm_device *dev, int engine)
{
struct nv31_mpeg_engine *pmpeg = nv_engine(dev, engine);
nouveau_irq_unregister(dev, 0);
NVOBJ_ENGINE_DEL(dev, MPEG);
kfree(pmpeg);
nv_subdev(priv)->unit = 0x00000002;
nv_subdev(priv)->intr = nv31_mpeg_intr;
nv_engine(priv)->cclass = &nv31_mpeg_cclass;
nv_engine(priv)->sclass = nv31_mpeg_sclass;
nv_engine(priv)->tile_prog = nv31_mpeg_tile_prog;
return 0;
}
int
nv31_mpeg_create(struct drm_device *dev)
nv31_mpeg_init(struct nouveau_object *object)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv31_mpeg_engine *pmpeg;
struct nouveau_engine *engine = nv_engine(object->engine);
struct nv31_mpeg_priv *priv = (void *)engine;
struct nouveau_fb *pfb = nouveau_fb(object);
int ret, i;
pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL);
if (!pmpeg)
return -ENOMEM;
atomic_set(&pmpeg->refcount, 0);
ret = nouveau_mpeg_init(&priv->base);
if (ret)
return ret;
pmpeg->base.destroy = nv31_mpeg_destroy;
pmpeg->base.init = nv31_mpeg_init;
pmpeg->base.fini = nv31_mpeg_fini;
if (dev_priv->card_type < NV_40) {
pmpeg->base.context_new = nv31_mpeg_context_new;
pmpeg->base.context_del = nv31_mpeg_context_del;
} else {
pmpeg->base.context_new = nv40_mpeg_context_new;
pmpeg->base.context_del = nv40_mpeg_context_del;
/* VPE init */
nv_wr32(priv, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
nv_wr32(priv, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
for (i = 0; i < pfb->tile.regions; i++)
engine->tile_prog(engine, i);
/* PMPEG init */
nv_wr32(priv, 0x00b32c, 0x00000000);
nv_wr32(priv, 0x00b314, 0x00000100);
nv_wr32(priv, 0x00b220, nv44_graph_class(priv) ? 0x00000044 : 0x00000031);
nv_wr32(priv, 0x00b300, 0x02001ec1);
nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001);
nv_wr32(priv, 0x00b100, 0xffffffff);
nv_wr32(priv, 0x00b140, 0xffffffff);
if (!nv_wait(priv, 0x00b200, 0x00000001, 0x00000000)) {
nv_error(priv, "timeout 0x%08x\n", nv_rd32(priv, 0x00b200));
return -EBUSY;
}
pmpeg->base.object_new = nv31_mpeg_object_new;
/* ISR vector, PMC_ENABLE bit, and TILE regs are shared between
* all VPE engines, for this driver's purposes the PMPEG engine
* will be treated as the "master" and handle the global VPE
* bits too
*/
pmpeg->base.set_tile_region = nv31_vpe_set_tile_region;
nouveau_irq_register(dev, 0, nv31_vpe_isr);
NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base);
NVOBJ_CLASS(dev, 0x3174, MPEG);
NVOBJ_MTHD (dev, 0x3174, 0x0190, nv31_mpeg_mthd_dma);
NVOBJ_MTHD (dev, 0x3174, 0x01a0, nv31_mpeg_mthd_dma);
NVOBJ_MTHD (dev, 0x3174, 0x01b0, nv31_mpeg_mthd_dma);
#if 0
NVOBJ_ENGINE_ADD(dev, ME, &pme->base);
NVOBJ_CLASS(dev, 0x4075, ME);
#endif
return 0;
}
struct nouveau_oclass
nv31_mpeg_oclass = {
.handle = NV_ENGINE(MPEG, 0x31),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv31_mpeg_ctor,
.dtor = _nouveau_mpeg_dtor,
.init = nv31_mpeg_init,
.fini = _nouveau_mpeg_fini,
},
};
@@ -0,0 +1,144 @@
/*
* 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/os.h>
#include <core/class.h>
#include <core/engctx.h>
#include <subdev/fb.h>
#include <subdev/timer.h>
#include <subdev/instmem.h>
#include <engine/mpeg.h>
#include <engine/graph/nv40.h>
struct nv40_mpeg_priv {
struct nouveau_mpeg base;
};
struct nv40_mpeg_chan {
struct nouveau_mpeg base;
};
/*******************************************************************************
* PMPEG context
******************************************************************************/
static int
nv40_mpeg_context_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv40_mpeg_chan *chan;
int ret;
ret = nouveau_mpeg_context_create(parent, engine, oclass, NULL,
264 * 4, 16,
NVOBJ_FLAG_ZERO_ALLOC, &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
return 0;
}
static int
nv40_mpeg_context_fini(struct nouveau_object *object, bool suspend)
{
struct nv40_mpeg_priv *priv = (void *)object->engine;
struct nv40_mpeg_chan *chan = (void *)object;
u32 inst = 0x80000000 | nv_gpuobj(chan)->addr >> 4;
nv_mask(priv, 0x00b32c, 0x00000001, 0x00000000);
if (nv_rd32(priv, 0x00b318) == inst)
nv_mask(priv, 0x00b318, 0x80000000, 0x00000000);
nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001);
return 0;
}
static struct nouveau_oclass
nv40_mpeg_cclass = {
.handle = NV_ENGCTX(MPEG, 0x40),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv40_mpeg_context_ctor,
.dtor = _nouveau_mpeg_context_dtor,
.init = _nouveau_mpeg_context_init,
.fini = nv40_mpeg_context_fini,
.rd32 = _nouveau_mpeg_context_rd32,
.wr32 = _nouveau_mpeg_context_wr32,
},
};
/*******************************************************************************
* PMPEG engine/subdev functions
******************************************************************************/
static void
nv40_mpeg_intr(struct nouveau_subdev *subdev)
{
struct nv40_mpeg_priv *priv = (void *)subdev;
u32 stat;
if ((stat = nv_rd32(priv, 0x00b100)))
nv31_mpeg_intr(subdev);
if ((stat = nv_rd32(priv, 0x00b800))) {
nv_error(priv, "PMSRCH 0x%08x\n", stat);
nv_wr32(priv, 0x00b800, stat);
}
}
static int
nv40_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv40_mpeg_priv *priv;
int ret;
ret = nouveau_mpeg_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00000002;
nv_subdev(priv)->intr = nv40_mpeg_intr;
nv_engine(priv)->cclass = &nv40_mpeg_cclass;
nv_engine(priv)->sclass = nv31_mpeg_sclass;
nv_engine(priv)->tile_prog = nv31_mpeg_tile_prog;
return 0;
}
struct nouveau_oclass
nv40_mpeg_oclass = {
.handle = NV_ENGINE(MPEG, 0x40),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv40_mpeg_ctor,
.dtor = _nouveau_mpeg_dtor,
.init = nv31_mpeg_init,
.fini = _nouveau_mpeg_fini,
},
};
+184 -183
View File
@@ -1,5 +1,5 @@
/*
* 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,218 +22,219 @@
* Authors: Ben Skeggs
*/
#include "drmP.h"
#include "nouveau_drv.h"
#include <core/ramht.h>
#include <core/os.h>
#include <core/class.h>
#include <core/engctx.h>
struct nv50_mpeg_engine {
struct nouveau_exec_engine base;
#include <subdev/vm.h>
#include <subdev/bar.h>
#include <subdev/timer.h>
#include <engine/mpeg.h>
struct nv50_mpeg_priv {
struct nouveau_mpeg base;
};
static inline u32
CTX_PTR(struct drm_device *dev, u32 offset)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv50_mpeg_chan {
struct nouveau_mpeg_chan base;
};
if (dev_priv->chipset == 0x50)
offset += 0x0260;
else
offset += 0x0060;
return offset;
}
/*******************************************************************************
* MPEG object classes
******************************************************************************/
static int
nv50_mpeg_context_new(struct nouveau_channel *chan, int engine)
nv50_mpeg_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 = NULL;
struct nouveau_gpuobj *obj;
int ret;
NV_DEBUG(dev, "ch%d\n", chan->id);
ret = nouveau_gpuobj_new(dev, chan, 128 * 4, 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, CTX_PTR(dev, 0x00), 0x80190002);
nv_wo32(ramin, CTX_PTR(dev, 0x04), ctx->addr + ctx->size - 1);
nv_wo32(ramin, CTX_PTR(dev, 0x08), ctx->addr);
nv_wo32(ramin, CTX_PTR(dev, 0x0c), 0);
nv_wo32(ramin, CTX_PTR(dev, 0x10), 0);
nv_wo32(ramin, CTX_PTR(dev, 0x14), 0x00010000);
nv_wo32(ctx, 0x70, 0x00801ec1);
nv_wo32(ctx, 0x7c, 0x0000037c);
nvimem_flush(dev);
chan->engctx[engine] = ctx;
return 0;
}
static void
nv50_mpeg_context_del(struct nouveau_channel *chan, int engine)
{
struct nouveau_gpuobj *ctx = chan->engctx[engine];
struct drm_device *dev = chan->dev;
int i;
for (i = 0x00; i <= 0x14; i += 4)
nv_wo32(chan->ramin, CTX_PTR(dev, i), 0x00000000);
nouveau_gpuobj_ref(NULL, &ctx);
chan->engctx[engine] = NULL;
}
static int
nv50_mpeg_object_new(struct nouveau_channel *chan, int engine,
u32 handle, u16 class)
{
struct drm_device *dev = chan->dev;
struct nouveau_gpuobj *obj = NULL;
int ret;
ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
if (ret)
return ret;
obj->engine = 2;
obj->class = class;
nv_wo32(obj, 0x00, class);
nv_wo32(obj, 0x00, nv_mclass(obj));
nv_wo32(obj, 0x04, 0x00000000);
nv_wo32(obj, 0x08, 0x00000000);
nv_wo32(obj, 0x0c, 0x00000000);
nvimem_flush(dev);
return 0;
}
ret = nouveau_ramht_insert(chan, handle, obj);
nouveau_gpuobj_ref(NULL, &obj);
return ret;
struct nouveau_ofuncs
nv50_mpeg_ofuncs = {
.ctor = nv50_mpeg_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
nv50_mpeg_sclass[] = {
{ 0x3174, &nv50_mpeg_ofuncs },
{}
};
/*******************************************************************************
* PMPEG context
******************************************************************************/
int
nv50_mpeg_context_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_bar *bar = nouveau_bar(parent);
struct nv50_mpeg_chan *chan;
int ret;
ret = nouveau_mpeg_context_create(parent, engine, oclass, NULL, 128 * 4,
0, NVOBJ_FLAG_ZERO_ALLOC, &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
nv_wo32(chan, 0x0070, 0x00801ec1);
nv_wo32(chan, 0x007c, 0x0000037c);
bar->flush(bar);
return 0;
}
static struct nouveau_oclass
nv50_mpeg_cclass = {
.handle = NV_ENGCTX(MPEG, 0x50),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv50_mpeg_context_ctor,
.dtor = _nouveau_mpeg_context_dtor,
.init = _nouveau_mpeg_context_init,
.fini = _nouveau_mpeg_context_fini,
.rd32 = _nouveau_mpeg_context_rd32,
.wr32 = _nouveau_mpeg_context_wr32,
},
};
/*******************************************************************************
* PMPEG engine/subdev functions
******************************************************************************/
int
nv50_mpeg_tlb_flush(struct nouveau_engine *engine)
{
nv50_vm_flush_engine(&engine->base, 0x08);
return 0;
}
void
nv50_mpeg_intr(struct nouveau_subdev *subdev)
{
struct nv50_mpeg_priv *priv = (void *)subdev;
u32 stat = nv_rd32(priv, 0x00b100);
u32 type = nv_rd32(priv, 0x00b230);
u32 mthd = nv_rd32(priv, 0x00b234);
u32 data = nv_rd32(priv, 0x00b238);
u32 show = stat;
if (stat & 0x01000000) {
/* happens on initial binding of the object */
if (type == 0x00000020 && mthd == 0x0000) {
nv_wr32(priv, 0x00b308, 0x00000100);
show &= ~0x01000000;
}
}
if (show) {
nv_info(priv, "0x%08x 0x%08x 0x%08x 0x%08x\n",
stat, type, mthd, data);
}
nv_wr32(priv, 0x00b100, stat);
nv_wr32(priv, 0x00b230, 0x00000001);
nv50_fb_trap(nouveau_fb(priv), 1);
}
static void
nv50_mpeg_tlb_flush(struct drm_device *dev, int engine)
nv50_vpe_intr(struct nouveau_subdev *subdev)
{
nv50_vm_flush_engine(dev, 0x08);
struct nv50_mpeg_priv *priv = (void *)subdev;
if (nv_rd32(priv, 0x00b100))
nv50_mpeg_intr(subdev);
if (nv_rd32(priv, 0x00b800)) {
u32 stat = nv_rd32(priv, 0x00b800);
nv_info(priv, "PMSRCH: 0x%08x\n", stat);
nv_wr32(priv, 0xb800, stat);
}
}
static int
nv50_mpeg_init(struct drm_device *dev, int engine)
nv50_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
nv_wr32(dev, 0x00b32c, 0x00000000);
nv_wr32(dev, 0x00b314, 0x00000100);
nv_wr32(dev, 0x00b0e0, 0x0000001a);
struct nv50_mpeg_priv *priv;
int ret;
nv_wr32(dev, 0x00b220, 0x00000044);
nv_wr32(dev, 0x00b300, 0x00801ec1);
nv_wr32(dev, 0x00b390, 0x00000000);
nv_wr32(dev, 0x00b394, 0x00000000);
nv_wr32(dev, 0x00b398, 0x00000000);
nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
ret = nouveau_mpeg_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_wr32(dev, 0x00b100, 0xffffffff);
nv_wr32(dev, 0x00b140, 0xffffffff);
nv_subdev(priv)->unit = 0x00400002;
nv_subdev(priv)->intr = nv50_vpe_intr;
nv_engine(priv)->cclass = &nv50_mpeg_cclass;
nv_engine(priv)->sclass = nv50_mpeg_sclass;
nv_engine(priv)->tlb_flush = nv50_mpeg_tlb_flush;
return 0;
}
if (!nv_wait(dev, 0x00b200, 0x00000001, 0x00000000)) {
NV_ERROR(dev, "PMPEG init: 0x%08x\n", nv_rd32(dev, 0x00b200));
int
nv50_mpeg_init(struct nouveau_object *object)
{
struct nv50_mpeg_priv *priv = (void *)object;
int ret;
ret = nouveau_mpeg_init(&priv->base);
if (ret)
return ret;
nv_wr32(priv, 0x00b32c, 0x00000000);
nv_wr32(priv, 0x00b314, 0x00000100);
nv_wr32(priv, 0x00b0e0, 0x0000001a);
nv_wr32(priv, 0x00b220, 0x00000044);
nv_wr32(priv, 0x00b300, 0x00801ec1);
nv_wr32(priv, 0x00b390, 0x00000000);
nv_wr32(priv, 0x00b394, 0x00000000);
nv_wr32(priv, 0x00b398, 0x00000000);
nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001);
nv_wr32(priv, 0x00b100, 0xffffffff);
nv_wr32(priv, 0x00b140, 0xffffffff);
if (!nv_wait(priv, 0x00b200, 0x00000001, 0x00000000)) {
nv_error(priv, "timeout 0x%08x\n", nv_rd32(priv, 0x00b200));
return -EBUSY;
}
return 0;
}
static int
nv50_mpeg_fini(struct drm_device *dev, int engine, bool suspend)
{
nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
nv_wr32(dev, 0x00b140, 0x00000000);
return 0;
}
static void
nv50_mpeg_isr(struct drm_device *dev)
{
u32 stat = nv_rd32(dev, 0x00b100);
u32 type = nv_rd32(dev, 0x00b230);
u32 mthd = nv_rd32(dev, 0x00b234);
u32 data = nv_rd32(dev, 0x00b238);
u32 show = stat;
if (stat & 0x01000000) {
/* happens on initial binding of the object */
if (type == 0x00000020 && mthd == 0x0000) {
nv_wr32(dev, 0x00b308, 0x00000100);
show &= ~0x01000000;
}
}
if (show && nouveau_ratelimit()) {
NV_INFO(dev, "PMPEG - 0x%08x 0x%08x 0x%08x 0x%08x\n",
stat, type, mthd, data);
}
nv_wr32(dev, 0x00b100, stat);
nv_wr32(dev, 0x00b230, 0x00000001);
nv50_fb_vm_trap(dev, 1);
}
static void
nv50_vpe_isr(struct drm_device *dev)
{
if (nv_rd32(dev, 0x00b100))
nv50_mpeg_isr(dev);
if (nv_rd32(dev, 0x00b800)) {
u32 stat = nv_rd32(dev, 0x00b800);
NV_INFO(dev, "PMSRCH: 0x%08x\n", stat);
nv_wr32(dev, 0xb800, stat);
}
}
static void
nv50_mpeg_destroy(struct drm_device *dev, int engine)
{
struct nv50_mpeg_engine *pmpeg = nv_engine(dev, engine);
nouveau_irq_unregister(dev, 0);
NVOBJ_ENGINE_DEL(dev, MPEG);
kfree(pmpeg);
}
int
nv50_mpeg_create(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv50_mpeg_engine *pmpeg;
pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL);
if (!pmpeg)
return -ENOMEM;
pmpeg->base.destroy = nv50_mpeg_destroy;
pmpeg->base.init = nv50_mpeg_init;
pmpeg->base.fini = nv50_mpeg_fini;
pmpeg->base.context_new = nv50_mpeg_context_new;
pmpeg->base.context_del = nv50_mpeg_context_del;
pmpeg->base.object_new = nv50_mpeg_object_new;
pmpeg->base.tlb_flush = nv50_mpeg_tlb_flush;
if (dev_priv->chipset == 0x50) {
nouveau_irq_register(dev, 0, nv50_vpe_isr);
NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base);
NVOBJ_CLASS(dev, 0x3174, MPEG);
#if 0
NVOBJ_ENGINE_ADD(dev, ME, &pme->base);
NVOBJ_CLASS(dev, 0x4075, ME);
#endif
} else {
nouveau_irq_register(dev, 0, nv50_mpeg_isr);
NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base);
NVOBJ_CLASS(dev, 0x8274, MPEG);
}
return 0;
}
struct nouveau_oclass
nv50_mpeg_oclass = {
.handle = NV_ENGINE(MPEG, 0x50),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv50_mpeg_ctor,
.dtor = _nouveau_mpeg_dtor,
.init = nv50_mpeg_init,
.fini = _nouveau_mpeg_fini,
},
};
@@ -0,0 +1,104 @@
/*
* 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/os.h>
#include <core/class.h>
#include <core/engctx.h>
#include <subdev/vm.h>
#include <subdev/bar.h>
#include <subdev/timer.h>
#include <engine/mpeg.h>
struct nv84_mpeg_priv {
struct nouveau_mpeg base;
};
struct nv84_mpeg_chan {
struct nouveau_mpeg_chan base;
};
/*******************************************************************************
* MPEG object classes
******************************************************************************/
static struct nouveau_oclass
nv84_mpeg_sclass[] = {
{ 0x8274, &nv50_mpeg_ofuncs },
{}
};
/*******************************************************************************
* PMPEG context
******************************************************************************/
static struct nouveau_oclass
nv84_mpeg_cclass = {
.handle = NV_ENGCTX(MPEG, 0x84),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv50_mpeg_context_ctor,
.dtor = _nouveau_mpeg_context_dtor,
.init = _nouveau_mpeg_context_init,
.fini = _nouveau_mpeg_context_fini,
.rd32 = _nouveau_mpeg_context_rd32,
.wr32 = _nouveau_mpeg_context_wr32,
},
};
/*******************************************************************************
* PMPEG engine/subdev functions
******************************************************************************/
static int
nv84_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv84_mpeg_priv *priv;
int ret;
ret = nouveau_mpeg_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00000002;
nv_subdev(priv)->intr = nv50_mpeg_intr;
nv_engine(priv)->cclass = &nv84_mpeg_cclass;
nv_engine(priv)->sclass = nv84_mpeg_sclass;
nv_engine(priv)->tlb_flush = nv50_mpeg_tlb_flush;
return 0;
}
struct nouveau_oclass
nv84_mpeg_oclass = {
.handle = NV_ENGINE(MPEG, 0x84),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv84_mpeg_ctor,
.dtor = _nouveau_mpeg_dtor,
.init = nv50_mpeg_init,
.fini = _nouveau_mpeg_fini,
},
};
+133 -35
View File
@@ -1,5 +1,5 @@
/*
* 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,56 +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>
struct nv98_ppp_engine {
struct nouveau_exec_engine base;
#include <engine/ppp.h>
struct nv98_ppp_priv {
struct nouveau_ppp base;
};
static int
nv98_ppp_fini(struct drm_device *dev, int engine, bool suspend)
{
if (!(nv_rd32(dev, 0x000200) & 0x00000002))
return 0;
struct nv98_ppp_chan {
struct nouveau_ppp_chan base;
};
nv_mask(dev, 0x000200, 0x00000002, 0x00000000);
return 0;
}
/*******************************************************************************
* PPP object classes
******************************************************************************/
static struct nouveau_oclass
nv98_ppp_sclass[] = {
{},
};
/*******************************************************************************
* PPPP context
******************************************************************************/
static int
nv98_ppp_init(struct drm_device *dev, int engine)
nv98_ppp_context_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, 0x00000002, 0x00000000);
nv_mask(dev, 0x000200, 0x00000002, 0x00000002);
struct nv98_ppp_chan *priv;
int ret;
ret = nouveau_ppp_context_create(parent, engine, oclass, NULL,
0, 0, 0, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
return 0;
}
static void
nv98_ppp_destroy(struct drm_device *dev, int engine)
nv98_ppp_context_dtor(struct nouveau_object *object)
{
struct nv98_ppp_engine *pppp = nv_engine(dev, engine);
NVOBJ_ENGINE_DEL(dev, PPP);
kfree(pppp);
struct nv98_ppp_chan *priv = (void *)object;
nouveau_ppp_context_destroy(&priv->base);
}
int
nv98_ppp_create(struct drm_device *dev)
static int
nv98_ppp_context_init(struct nouveau_object *object)
{
struct nv98_ppp_engine *pppp;
struct nv98_ppp_chan *priv = (void *)object;
int ret;
pppp = kzalloc(sizeof(*pppp), GFP_KERNEL);
if (!pppp)
return -ENOMEM;
ret = nouveau_ppp_context_init(&priv->base);
if (ret)
return ret;
pppp->base.destroy = nv98_ppp_destroy;
pppp->base.init = nv98_ppp_init;
pppp->base.fini = nv98_ppp_fini;
NVOBJ_ENGINE_ADD(dev, PPP, &pppp->base);
return 0;
}
static int
nv98_ppp_context_fini(struct nouveau_object *object, bool suspend)
{
struct nv98_ppp_chan *priv = (void *)object;
return nouveau_ppp_context_fini(&priv->base, suspend);
}
static struct nouveau_oclass
nv98_ppp_cclass = {
.handle = NV_ENGCTX(PPP, 0x98),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv98_ppp_context_ctor,
.dtor = nv98_ppp_context_dtor,
.init = nv98_ppp_context_init,
.fini = nv98_ppp_context_fini,
.rd32 = _nouveau_ppp_context_rd32,
.wr32 = _nouveau_ppp_context_wr32,
},
};
/*******************************************************************************
* PPPP engine/subdev functions
******************************************************************************/
static void
nv98_ppp_intr(struct nouveau_subdev *subdev)
{
}
static int
nv98_ppp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv98_ppp_priv *priv;
int ret;
ret = nouveau_ppp_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x00400002;
nv_subdev(priv)->intr = nv98_ppp_intr;
nv_engine(priv)->cclass = &nv98_ppp_cclass;
nv_engine(priv)->sclass = nv98_ppp_sclass;
return 0;
}
static void
nv98_ppp_dtor(struct nouveau_object *object)
{
struct nv98_ppp_priv *priv = (void *)object;
nouveau_ppp_destroy(&priv->base);
}
static int
nv98_ppp_init(struct nouveau_object *object)
{
struct nv98_ppp_priv *priv = (void *)object;
int ret;
ret = nouveau_ppp_init(&priv->base);
if (ret)
return ret;
return 0;
}
static int
nv98_ppp_fini(struct nouveau_object *object, bool suspend)
{
struct nv98_ppp_priv *priv = (void *)object;
return nouveau_ppp_fini(&priv->base, suspend);
}
struct nouveau_oclass
nv98_ppp_oclass = {
.handle = NV_ENGINE(PPP, 0x98),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv98_ppp_ctor,
.dtor = nv98_ppp_dtor,
.init = nv98_ppp_init,
.fini = nv98_ppp_fini,
},
};
@@ -0,0 +1,140 @@
/*
* 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/os.h>
#include <core/class.h>
#include <core/engctx.h>
#include <engine/software.h>
#include <engine/fifo.h>
struct nv04_software_priv {
struct nouveau_software base;
};
struct nv04_software_chan {
struct nouveau_software_chan base;
};
/*******************************************************************************
* software object classes
******************************************************************************/
static int
nv04_software_set_ref(struct nouveau_object *object, u32 mthd,
void *data, u32 size)
{
struct nouveau_object *channel = (void *)nv_engctx(object->parent);
struct nouveau_fifo_chan *fifo = (void *)channel->parent;
atomic_set(&fifo->refcnt, *(u32*)data);
return 0;
}
static int
nv04_software_flip(struct nouveau_object *object, u32 mthd,
void *args, u32 size)
{
struct nv04_software_chan *chan = (void *)nv_engctx(object->parent);
if (chan->base.flip)
return chan->base.flip(chan->base.flip_data);
return -EINVAL;
}
static struct nouveau_omthds
nv04_software_omthds[] = {
{ 0x0150, nv04_software_set_ref },
{ 0x0500, nv04_software_flip },
{}
};
static struct nouveau_oclass
nv04_software_sclass[] = {
{ 0x006e, &nouveau_object_ofuncs, nv04_software_omthds },
{}
};
/*******************************************************************************
* software context
******************************************************************************/
static int
nv04_software_context_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv04_software_chan *chan;
int ret;
ret = nouveau_software_context_create(parent, engine, oclass, &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
return 0;
}
static struct nouveau_oclass
nv04_software_cclass = {
.handle = NV_ENGCTX(SW, 0x04),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv04_software_context_ctor,
.dtor = _nouveau_software_context_dtor,
.init = _nouveau_software_context_init,
.fini = _nouveau_software_context_fini,
},
};
/*******************************************************************************
* software engine/subdev functions
******************************************************************************/
static int
nv04_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv04_software_priv *priv;
int ret;
ret = nouveau_software_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_engine(priv)->cclass = &nv04_software_cclass;
nv_engine(priv)->sclass = nv04_software_sclass;
return 0;
}
struct nouveau_oclass
nv04_software_oclass = {
.handle = NV_ENGINE(SW, 0x04),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv04_software_ctor,
.dtor = _nouveau_software_dtor,
.init = _nouveau_software_init,
.fini = _nouveau_software_fini,
},
};
@@ -0,0 +1,128 @@
/*
* 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/os.h>
#include <core/class.h>
#include <core/engctx.h>
#include <engine/software.h>
struct nv10_software_priv {
struct nouveau_software base;
};
struct nv10_software_chan {
struct nouveau_software_chan base;
};
/*******************************************************************************
* software object classes
******************************************************************************/
static int
nv10_software_flip(struct nouveau_object *object, u32 mthd,
void *args, u32 size)
{
struct nv10_software_chan *chan = (void *)nv_engctx(object->parent);
if (chan->base.flip)
return chan->base.flip(chan->base.flip_data);
return -EINVAL;
}
static struct nouveau_omthds
nv10_software_omthds[] = {
{ 0x0500, nv10_software_flip },
{}
};
static struct nouveau_oclass
nv10_software_sclass[] = {
{ 0x016e, &nouveau_object_ofuncs, nv10_software_omthds },
{}
};
/*******************************************************************************
* software context
******************************************************************************/
static int
nv10_software_context_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv10_software_chan *chan;
int ret;
ret = nouveau_software_context_create(parent, engine, oclass, &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
return 0;
}
static struct nouveau_oclass
nv10_software_cclass = {
.handle = NV_ENGCTX(SW, 0x04),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv10_software_context_ctor,
.dtor = _nouveau_software_context_dtor,
.init = _nouveau_software_context_init,
.fini = _nouveau_software_context_fini,
},
};
/*******************************************************************************
* software engine/subdev functions
******************************************************************************/
static int
nv10_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv10_software_priv *priv;
int ret;
ret = nouveau_software_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_engine(priv)->cclass = &nv10_software_cclass;
nv_engine(priv)->sclass = nv10_software_sclass;
return 0;
}
struct nouveau_oclass
nv10_software_oclass = {
.handle = NV_ENGINE(SW, 0x10),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv10_software_ctor,
.dtor = _nouveau_software_dtor,
.init = _nouveau_software_init,
.fini = _nouveau_software_fini,
},
};
@@ -0,0 +1,198 @@
/*
* 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/os.h>
#include <core/class.h>
#include <core/engctx.h>
#include <core/namedb.h>
#include <core/handle.h>
#include <core/gpuobj.h>
#include <engine/software.h>
#include <engine/disp.h>
struct nv50_software_priv {
struct nouveau_software base;
};
struct nv50_software_chan {
struct nouveau_software_chan base;
};
/*******************************************************************************
* software object classes
******************************************************************************/
static int
nv50_software_mthd_dma_vblsem(struct nouveau_object *object, u32 mthd,
void *args, u32 size)
{
struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
struct nouveau_fifo_chan *fifo = (void *)nv_object(chan)->parent;
struct nouveau_handle *handle;
int ret = -EINVAL;
handle = nouveau_namedb_get(nv_namedb(fifo), *(u32 *)args);
if (!handle)
return -ENOENT;
if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) {
struct nouveau_gpuobj *gpuobj = nv_gpuobj(handle->object);
chan->base.vblank.ctxdma = gpuobj->node->offset >> 4;
ret = 0;
}
nouveau_namedb_put(handle);
return ret;
}
static int
nv50_software_mthd_vblsem_offset(struct nouveau_object *object, u32 mthd,
void *args, u32 size)
{
struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
chan->base.vblank.offset = *(u32 *)args;
return 0;
}
static int
nv50_software_mthd_vblsem_value(struct nouveau_object *object, u32 mthd,
void *args, u32 size)
{
struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
chan->base.vblank.value = *(u32 *)args;
return 0;
}
static int
nv50_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd,
void *args, u32 size)
{
struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
struct nouveau_disp *disp = nouveau_disp(object);
unsigned long flags;
u32 crtc = *(u32 *)args;
if (crtc > 1)
return -EINVAL;
disp->vblank.get(disp->vblank.data, crtc);
spin_lock_irqsave(&disp->vblank.lock, flags);
list_add(&chan->base.vblank.head, &disp->vblank.list);
chan->base.vblank.crtc = crtc;
spin_unlock_irqrestore(&disp->vblank.lock, flags);
return 0;
}
static int
nv50_software_mthd_flip(struct nouveau_object *object, u32 mthd,
void *args, u32 size)
{
struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
if (chan->base.flip)
return chan->base.flip(chan->base.flip_data);
return -EINVAL;
}
static struct nouveau_omthds
nv50_software_omthds[] = {
{ 0x018c, nv50_software_mthd_dma_vblsem },
{ 0x0400, nv50_software_mthd_vblsem_offset },
{ 0x0404, nv50_software_mthd_vblsem_value },
{ 0x0408, nv50_software_mthd_vblsem_release },
{ 0x0500, nv50_software_mthd_flip },
{}
};
static struct nouveau_oclass
nv50_software_sclass[] = {
{ 0x506e, &nouveau_object_ofuncs, nv50_software_omthds },
{}
};
/*******************************************************************************
* software context
******************************************************************************/
static int
nv50_software_context_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv50_software_chan *chan;
int ret;
ret = nouveau_software_context_create(parent, engine, oclass, &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
chan->base.vblank.channel = nv_gpuobj(parent->parent)->addr >> 12;
return 0;
}
static struct nouveau_oclass
nv50_software_cclass = {
.handle = NV_ENGCTX(SW, 0x50),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv50_software_context_ctor,
.dtor = _nouveau_software_context_dtor,
.init = _nouveau_software_context_init,
.fini = _nouveau_software_context_fini,
},
};
/*******************************************************************************
* software engine/subdev functions
******************************************************************************/
static int
nv50_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv50_software_priv *priv;
int ret;
ret = nouveau_software_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_engine(priv)->cclass = &nv50_software_cclass;
nv_engine(priv)->sclass = nv50_software_sclass;
return 0;
}
struct nouveau_oclass
nv50_software_oclass = {
.handle = NV_ENGINE(SW, 0x50),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv50_software_ctor,
.dtor = _nouveau_software_dtor,
.init = _nouveau_software_init,
.fini = _nouveau_software_fini,
},
};
@@ -0,0 +1,180 @@
/*
* 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/os.h>
#include <core/class.h>
#include <core/engctx.h>
#include <engine/software.h>
#include <engine/disp.h>
struct nvc0_software_priv {
struct nouveau_software base;
};
struct nvc0_software_chan {
struct nouveau_software_chan base;
};
/*******************************************************************************
* software object classes
******************************************************************************/
static int
nvc0_software_mthd_vblsem_offset(struct nouveau_object *object, u32 mthd,
void *args, u32 size)
{
struct nvc0_software_chan *chan = (void *)nv_engctx(object->parent);
u64 data = *(u32 *)args;
if (mthd == 0x0400) {
chan->base.vblank.offset &= 0x00ffffffffULL;
chan->base.vblank.offset |= data << 32;
} else {
chan->base.vblank.offset &= 0xff00000000ULL;
chan->base.vblank.offset |= data;
}
return 0;
}
static int
nvc0_software_mthd_vblsem_value(struct nouveau_object *object, u32 mthd,
void *args, u32 size)
{
struct nvc0_software_chan *chan = (void *)nv_engctx(object->parent);
chan->base.vblank.value = *(u32 *)args;
return 0;
}
static int
nvc0_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd,
void *args, u32 size)
{
struct nvc0_software_chan *chan = (void *)nv_engctx(object->parent);
struct nouveau_disp *disp = nouveau_disp(object);
unsigned long flags;
u32 crtc = *(u32 *)args;
if ((nv_device(object)->card_type < NV_E0 && crtc > 1) || crtc > 3)
return -EINVAL;
disp->vblank.get(disp->vblank.data, crtc);
spin_lock_irqsave(&disp->vblank.lock, flags);
list_add(&chan->base.vblank.head, &disp->vblank.list);
chan->base.vblank.crtc = crtc;
spin_unlock_irqrestore(&disp->vblank.lock, flags);
return 0;
}
static int
nvc0_software_mthd_flip(struct nouveau_object *object, u32 mthd,
void *args, u32 size)
{
struct nvc0_software_chan *chan = (void *)nv_engctx(object->parent);
if (chan->base.flip)
return chan->base.flip(chan->base.flip_data);
return -EINVAL;
}
static struct nouveau_omthds
nvc0_software_omthds[] = {
{ 0x0400, nvc0_software_mthd_vblsem_offset },
{ 0x0404, nvc0_software_mthd_vblsem_offset },
{ 0x0408, nvc0_software_mthd_vblsem_value },
{ 0x040c, nvc0_software_mthd_vblsem_release },
{ 0x0500, nvc0_software_mthd_flip },
{}
};
static struct nouveau_oclass
nvc0_software_sclass[] = {
{ 0x906e, &nouveau_object_ofuncs, nvc0_software_omthds },
{}
};
/*******************************************************************************
* software context
******************************************************************************/
static int
nvc0_software_context_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nvc0_software_chan *chan;
int ret;
ret = nouveau_software_context_create(parent, engine, oclass, &chan);
*pobject = nv_object(chan);
if (ret)
return ret;
chan->base.vblank.channel = nv_gpuobj(parent->parent)->addr >> 12;
return 0;
}
static struct nouveau_oclass
nvc0_software_cclass = {
.handle = NV_ENGCTX(SW, 0xc0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nvc0_software_context_ctor,
.dtor = _nouveau_software_context_dtor,
.init = _nouveau_software_context_init,
.fini = _nouveau_software_context_fini,
},
};
/*******************************************************************************
* software engine/subdev functions
******************************************************************************/
static int
nvc0_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nvc0_software_priv *priv;
int ret;
ret = nouveau_software_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_engine(priv)->cclass = &nvc0_software_cclass;
nv_engine(priv)->sclass = nvc0_software_sclass;
return 0;
}
struct nouveau_oclass
nvc0_software_oclass = {
.handle = NV_ENGINE(SW, 0xc0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nvc0_software_ctor,
.dtor = _nouveau_software_dtor,
.init = _nouveau_software_init,
.fini = _nouveau_software_fini,
},
};
+132 -39
View File
@@ -1,5 +1,5 @@
/*
* 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_vp.c...
*/
#include <engine/vp.h>
struct nv84_vp_engine {
struct nouveau_exec_engine base;
struct nv84_vp_priv {
struct nouveau_vp base;
};
static int
nv84_vp_fini(struct drm_device *dev, int engine, bool suspend)
{
if (!(nv_rd32(dev, 0x000200) & 0x00020000))
return 0;
struct nv84_vp_chan {
struct nouveau_vp_chan base;
};
nv_mask(dev, 0x000200, 0x00020000, 0x00000000);
return 0;
}
/*******************************************************************************
* VP object classes
******************************************************************************/
static struct nouveau_oclass
nv84_vp_sclass[] = {
{},
};
/*******************************************************************************
* PVP context
******************************************************************************/
static int
nv84_vp_init(struct drm_device *dev, int engine)
nv84_vp_context_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, 0x00020000, 0x00000000);
nv_mask(dev, 0x000200, 0x00020000, 0x00020000);
struct nv84_vp_chan *priv;
int ret;
ret = nouveau_vp_context_create(parent, engine, oclass, NULL,
0, 0, 0, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
return 0;
}
static void
nv84_vp_destroy(struct drm_device *dev, int engine)
nv84_vp_context_dtor(struct nouveau_object *object)
{
struct nv84_vp_engine *pvp = nv_engine(dev, engine);
NVOBJ_ENGINE_DEL(dev, VP);
kfree(pvp);
struct nv84_vp_chan *priv = (void *)object;
nouveau_vp_context_destroy(&priv->base);
}
int
nv84_vp_create(struct drm_device *dev)
static int
nv84_vp_context_init(struct nouveau_object *object)
{
struct nv84_vp_engine *pvp;
struct nv84_vp_chan *priv = (void *)object;
int ret;
pvp = kzalloc(sizeof(*pvp), GFP_KERNEL);
if (!pvp)
return -ENOMEM;
ret = nouveau_vp_context_init(&priv->base);
if (ret)
return ret;
pvp->base.destroy = nv84_vp_destroy;
pvp->base.init = nv84_vp_init;
pvp->base.fini = nv84_vp_fini;
NVOBJ_ENGINE_ADD(dev, VP, &pvp->base);
return 0;
}
static int
nv84_vp_context_fini(struct nouveau_object *object, bool suspend)
{
struct nv84_vp_chan *priv = (void *)object;
return nouveau_vp_context_fini(&priv->base, suspend);
}
static struct nouveau_oclass
nv84_vp_cclass = {
.handle = NV_ENGCTX(VP, 0x84),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv84_vp_context_ctor,
.dtor = nv84_vp_context_dtor,
.init = nv84_vp_context_init,
.fini = nv84_vp_context_fini,
.rd32 = _nouveau_vp_context_rd32,
.wr32 = _nouveau_vp_context_wr32,
},
};
/*******************************************************************************
* PVP engine/subdev functions
******************************************************************************/
static void
nv84_vp_intr(struct nouveau_subdev *subdev)
{
}
static int
nv84_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv84_vp_priv *priv;
int ret;
ret = nouveau_vp_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
nv_subdev(priv)->unit = 0x01020000;
nv_subdev(priv)->intr = nv84_vp_intr;
nv_engine(priv)->cclass = &nv84_vp_cclass;
nv_engine(priv)->sclass = nv84_vp_sclass;
return 0;
}
static void
nv84_vp_dtor(struct nouveau_object *object)
{
struct nv84_vp_priv *priv = (void *)object;
nouveau_vp_destroy(&priv->base);
}
static int
nv84_vp_init(struct nouveau_object *object)
{
struct nv84_vp_priv *priv = (void *)object;
int ret;
ret = nouveau_vp_init(&priv->base);
if (ret)
return ret;
return 0;
}
static int
nv84_vp_fini(struct nouveau_object *object, bool suspend)
{
struct nv84_vp_priv *priv = (void *)object;
return nouveau_vp_fini(&priv->base, suspend);
}
struct nouveau_oclass
nv84_vp_oclass = {
.handle = NV_ENGINE(VP, 0x84),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv84_vp_ctor,
.dtor = nv84_vp_dtor,
.init = nv84_vp_init,
.fini = nv84_vp_fini,
},
};
@@ -1,55 +1,23 @@
/*
* Copyright 2010 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
*/
#ifndef __NOUVEAU_RAMHT_H__
#define __NOUVEAU_RAMHT_H__
struct nouveau_ramht_entry {
struct list_head head;
struct nouveau_channel *channel;
struct nouveau_gpuobj *gpuobj;
u32 handle;
};
#include <core/gpuobj.h>
struct nouveau_ramht {
struct drm_device *dev;
struct kref refcount;
spinlock_t lock;
struct nouveau_gpuobj *gpuobj;
struct list_head entries;
struct nouveau_gpuobj base;
int bits;
};
extern int nouveau_ramht_new(struct drm_device *, struct nouveau_gpuobj *,
struct nouveau_ramht **);
extern void nouveau_ramht_ref(struct nouveau_ramht *, struct nouveau_ramht **,
struct nouveau_channel *unref_channel);
int nouveau_ramht_insert(struct nouveau_ramht *, int chid,
u32 handle, u32 context);
void nouveau_ramht_remove(struct nouveau_ramht *, int cookie);
int nouveau_ramht_new(struct nouveau_object *, struct nouveau_object *,
u32 size, u32 align, struct nouveau_ramht **);
extern int nouveau_ramht_insert(struct nouveau_channel *, u32 handle,
struct nouveau_gpuobj *);
extern int nouveau_ramht_remove(struct nouveau_channel *, u32 handle);
extern struct nouveau_gpuobj *
nouveau_ramht_find(struct nouveau_channel *chan, u32 handle);
static inline void
nouveau_ramht_ref(struct nouveau_ramht *obj, struct nouveau_ramht **ref)
{
nouveau_gpuobj_ref(&obj->base, (struct nouveau_gpuobj **)ref);
}
#endif
@@ -0,0 +1,45 @@
#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
@@ -0,0 +1,47 @@
#ifndef __NOUVEAU_COPY_H__
#define __NOUVEAU_COPY_H__
#include <core/engine.h>
#include <core/engctx.h>
struct nouveau_copy_chan {
struct nouveau_engctx base;
};
#define nouveau_copy_context_create(p,e,c,g,s,a,f,d) \
nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
#define nouveau_copy_context_destroy(d) \
nouveau_engctx_destroy(&(d)->base)
#define nouveau_copy_context_init(d) \
nouveau_engctx_init(&(d)->base)
#define nouveau_copy_context_fini(d,s) \
nouveau_engctx_fini(&(d)->base, (s))
#define _nouveau_copy_context_dtor _nouveau_engctx_dtor
#define _nouveau_copy_context_init _nouveau_engctx_init
#define _nouveau_copy_context_fini _nouveau_engctx_fini
#define _nouveau_copy_context_rd32 _nouveau_engctx_rd32
#define _nouveau_copy_context_wr32 _nouveau_engctx_wr32
struct nouveau_copy {
struct nouveau_engine base;
};
#define nouveau_copy_create(p,e,c,y,i,d) \
nouveau_engine_create((p), (e), (c), (y), "PCE"#i, "copy"#i, (d))
#define nouveau_copy_destroy(d) \
nouveau_engine_destroy(&(d)->base)
#define nouveau_copy_init(d) \
nouveau_engine_init(&(d)->base)
#define nouveau_copy_fini(d,s) \
nouveau_engine_fini(&(d)->base, (s))
#define _nouveau_copy_dtor _nouveau_engine_dtor
#define _nouveau_copy_init _nouveau_engine_init
#define _nouveau_copy_fini _nouveau_engine_fini
extern struct nouveau_oclass nva3_copy_oclass;
extern struct nouveau_oclass nvc0_copy0_oclass;
extern struct nouveau_oclass nvc0_copy1_oclass;
#endif
@@ -0,0 +1,46 @@
#ifndef __NOUVEAU_CRYPT_H__
#define __NOUVEAU_CRYPT_H__
#include <core/engine.h>
#include <core/engctx.h>
struct nouveau_crypt_chan {
struct nouveau_engctx base;
};
#define nouveau_crypt_context_create(p,e,c,g,s,a,f,d) \
nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
#define nouveau_crypt_context_destroy(d) \
nouveau_engctx_destroy(&(d)->base)
#define nouveau_crypt_context_init(d) \
nouveau_engctx_init(&(d)->base)
#define nouveau_crypt_context_fini(d,s) \
nouveau_engctx_fini(&(d)->base, (s))
#define _nouveau_crypt_context_dtor _nouveau_engctx_dtor
#define _nouveau_crypt_context_init _nouveau_engctx_init
#define _nouveau_crypt_context_fini _nouveau_engctx_fini
#define _nouveau_crypt_context_rd32 _nouveau_engctx_rd32
#define _nouveau_crypt_context_wr32 _nouveau_engctx_wr32
struct nouveau_crypt {
struct nouveau_engine base;
};
#define nouveau_crypt_create(p,e,c,d) \
nouveau_engine_create((p), (e), (c), true, "PCRYPT", "crypt", (d))
#define nouveau_crypt_destroy(d) \
nouveau_engine_destroy(&(d)->base)
#define nouveau_crypt_init(d) \
nouveau_engine_init(&(d)->base)
#define nouveau_crypt_fini(d,s) \
nouveau_engine_fini(&(d)->base, (s))
#define _nouveau_crypt_dtor _nouveau_engine_dtor
#define _nouveau_crypt_init _nouveau_engine_init
#define _nouveau_crypt_fini _nouveau_engine_fini
extern struct nouveau_oclass nv84_crypt_oclass;
extern struct nouveau_oclass nv98_crypt_oclass;
#endif
@@ -0,0 +1,44 @@
#ifndef __NOUVEAU_DISP_H__
#define __NOUVEAU_DISP_H__
#include <core/object.h>
#include <core/engine.h>
#include <core/device.h>
struct nouveau_disp {
struct nouveau_engine base;
struct {
struct list_head list;
spinlock_t lock;
void (*notify)(void *, int);
void (*get)(void *, int);
void (*put)(void *, int);
void *data;
} vblank;
};
static inline struct nouveau_disp *
nouveau_disp(void *obj)
{
return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_DISP];
}
#define nouveau_disp_create(p,e,c,i,x,d) \
nouveau_engine_create((p), (e), (c), true, (i), (x), (d))
#define nouveau_disp_destroy(d) \
nouveau_engine_destroy(&(d)->base)
#define nouveau_disp_init(d) \
nouveau_engine_init(&(d)->base)
#define nouveau_disp_fini(d,s) \
nouveau_engine_fini(&(d)->base, (s))
#define _nouveau_disp_dtor _nouveau_engine_dtor
#define _nouveau_disp_init _nouveau_engine_init
#define _nouveau_disp_fini _nouveau_engine_fini
extern struct nouveau_oclass nv04_disp_oclass;
extern struct nouveau_oclass nv50_disp_oclass;
extern struct nouveau_oclass nvd0_disp_oclass;
#endif
@@ -0,0 +1,57 @@
#ifndef __NOUVEAU_DMAOBJ_H__
#define __NOUVEAU_DMAOBJ_H__
#include <core/object.h>
#include <core/engine.h>
struct nouveau_gpuobj;
struct nouveau_dmaobj {
struct nouveau_object base;
u32 target;
u32 access;
u64 start;
u64 limit;
};
#define nouveau_dmaobj_create(p,e,c,a,s,d) \
nouveau_dmaobj_create_((p), (e), (c), (a), (s), sizeof(**d), (void **)d)
#define nouveau_dmaobj_destroy(p) \
nouveau_object_destroy(&(p)->base)
#define nouveau_dmaobj_init(p) \
nouveau_object_init(&(p)->base)
#define nouveau_dmaobj_fini(p,s) \
nouveau_object_fini(&(p)->base, (s))
int nouveau_dmaobj_create_(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, void *data, u32 size,
int length, void **);
#define _nouveau_dmaobj_dtor nouveau_object_destroy
#define _nouveau_dmaobj_init nouveau_object_init
#define _nouveau_dmaobj_fini nouveau_object_fini
struct nouveau_dmaeng {
struct nouveau_engine base;
int (*bind)(struct nouveau_dmaeng *, struct nouveau_object *parent,
struct nouveau_dmaobj *, struct nouveau_gpuobj **);
};
#define nouveau_dmaeng_create(p,e,c,d) \
nouveau_engine_create((p), (e), (c), true, "DMAOBJ", "dmaobj", (d))
#define nouveau_dmaeng_destroy(p) \
nouveau_engine_destroy(&(p)->base)
#define nouveau_dmaeng_init(p) \
nouveau_engine_init(&(p)->base)
#define nouveau_dmaeng_fini(p,s) \
nouveau_engine_fini(&(p)->base, (s))
#define _nouveau_dmaeng_dtor _nouveau_engine_dtor
#define _nouveau_dmaeng_init _nouveau_engine_init
#define _nouveau_dmaeng_fini _nouveau_engine_fini
extern struct nouveau_oclass nv04_dmaeng_oclass;
extern struct nouveau_oclass nv50_dmaeng_oclass;
extern struct nouveau_oclass nvc0_dmaeng_oclass;
#endif
@@ -1,32 +1,109 @@
#ifndef __NOUVEAU_FIFO_H__
#define __NOUVEAU_FIFO_H__
struct nouveau_fifo_priv {
struct nouveau_exec_engine base;
u32 channels;
};
#include <core/namedb.h>
#include <core/gpuobj.h>
#include <core/engine.h>
struct nouveau_fifo_chan {
struct nouveau_namedb base;
struct nouveau_dmaobj *pushdma;
struct nouveau_gpuobj *pushgpu;
void __iomem *user;
u32 size;
u16 chid;
atomic_t refcnt; /* NV04_NVSW_SET_REF */
};
bool nv04_fifo_cache_pull(struct drm_device *, bool);
void nv04_fifo_context_del(struct nouveau_channel *, int);
int nv04_fifo_fini(struct drm_device *, int, bool);
int nv04_fifo_init(struct drm_device *, int);
void nv04_fifo_isr(struct drm_device *);
void nv04_fifo_destroy(struct drm_device *, int);
static inline struct nouveau_fifo_chan *
nouveau_fifo_chan(void *obj)
{
return (void *)nv_namedb(obj);
}
void nv50_fifo_playlist_update(struct drm_device *);
void nv50_fifo_destroy(struct drm_device *, int);
void nv50_fifo_tlb_flush(struct drm_device *, int);
#define nouveau_fifo_channel_create(p,e,c,b,a,s,n,m,d) \
nouveau_fifo_channel_create_((p), (e), (c), (b), (a), (s), (n), \
(m), sizeof(**d), (void **)d)
#define nouveau_fifo_channel_init(p) \
nouveau_namedb_init(&(p)->base)
#define nouveau_fifo_channel_fini(p,s) \
nouveau_namedb_fini(&(p)->base, (s))
int nv04_fifo_create(struct drm_device *);
int nv10_fifo_create(struct drm_device *);
int nv17_fifo_create(struct drm_device *);
int nv40_fifo_create(struct drm_device *);
int nv50_fifo_create(struct drm_device *);
int nv84_fifo_create(struct drm_device *);
int nvc0_fifo_create(struct drm_device *);
int nve0_fifo_create(struct drm_device *);
int nouveau_fifo_channel_create_(struct nouveau_object *,
struct nouveau_object *,
struct nouveau_oclass *,
int bar, u32 addr, u32 size, u32 push,
u32 engmask, int len, void **);
void nouveau_fifo_channel_destroy(struct nouveau_fifo_chan *);
#define _nouveau_fifo_channel_init _nouveau_namedb_init
#define _nouveau_fifo_channel_fini _nouveau_namedb_fini
void _nouveau_fifo_channel_dtor(struct nouveau_object *);
u32 _nouveau_fifo_channel_rd32(struct nouveau_object *, u32);
void _nouveau_fifo_channel_wr32(struct nouveau_object *, u32, u32);
struct nouveau_fifo_base {
struct nouveau_gpuobj base;
};
#define nouveau_fifo_context_create(p,e,c,g,s,a,f,d) \
nouveau_gpuobj_create((p), (e), (c), 0, (g), (s), (a), (f), (d))
#define nouveau_fifo_context_destroy(p) \
nouveau_gpuobj_destroy(&(p)->base)
#define nouveau_fifo_context_init(p) \
nouveau_gpuobj_init(&(p)->base)
#define nouveau_fifo_context_fini(p,s) \
nouveau_gpuobj_fini(&(p)->base, (s))
#define _nouveau_fifo_context_dtor _nouveau_gpuobj_dtor
#define _nouveau_fifo_context_init _nouveau_gpuobj_init
#define _nouveau_fifo_context_fini _nouveau_gpuobj_fini
#define _nouveau_fifo_context_rd32 _nouveau_gpuobj_rd32
#define _nouveau_fifo_context_wr32 _nouveau_gpuobj_wr32
struct nouveau_fifo {
struct nouveau_engine base;
struct nouveau_object **channel;
spinlock_t lock;
u16 min;
u16 max;
void (*pause)(struct nouveau_fifo *, unsigned long *);
void (*start)(struct nouveau_fifo *, unsigned long *);
};
static inline struct nouveau_fifo *
nouveau_fifo(void *obj)
{
return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_FIFO];
}
#define nouveau_fifo_create(o,e,c,fc,lc,d) \
nouveau_fifo_create_((o), (e), (c), (fc), (lc), sizeof(**d), (void **)d)
#define nouveau_fifo_init(p) \
nouveau_engine_init(&(p)->base)
#define nouveau_fifo_fini(p,s) \
nouveau_engine_fini(&(p)->base, (s))
int nouveau_fifo_create_(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, int min, int max,
int size, void **);
void nouveau_fifo_destroy(struct nouveau_fifo *);
#define _nouveau_fifo_init _nouveau_engine_init
#define _nouveau_fifo_fini _nouveau_engine_fini
extern struct nouveau_oclass nv04_fifo_oclass;
extern struct nouveau_oclass nv10_fifo_oclass;
extern struct nouveau_oclass nv17_fifo_oclass;
extern struct nouveau_oclass nv40_fifo_oclass;
extern struct nouveau_oclass nv50_fifo_oclass;
extern struct nouveau_oclass nv84_fifo_oclass;
extern struct nouveau_oclass nvc0_fifo_oclass;
extern struct nouveau_oclass nve0_fifo_oclass;
void nv04_fifo_intr(struct nouveau_subdev *);
#endif
@@ -0,0 +1,72 @@
#ifndef __NOUVEAU_GRAPH_H__
#define __NOUVEAU_GRAPH_H__
#include <core/engine.h>
#include <core/engctx.h>
#include <core/enum.h>
struct nouveau_graph_chan {
struct nouveau_engctx base;
};
#define nouveau_graph_context_create(p,e,c,g,s,a,f,d) \
nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
#define nouveau_graph_context_destroy(d) \
nouveau_engctx_destroy(&(d)->base)
#define nouveau_graph_context_init(d) \
nouveau_engctx_init(&(d)->base)
#define nouveau_graph_context_fini(d,s) \
nouveau_engctx_fini(&(d)->base, (s))
#define _nouveau_graph_context_dtor _nouveau_engctx_dtor
#define _nouveau_graph_context_init _nouveau_engctx_init
#define _nouveau_graph_context_fini _nouveau_engctx_fini
#define _nouveau_graph_context_rd32 _nouveau_engctx_rd32
#define _nouveau_graph_context_wr32 _nouveau_engctx_wr32
struct nouveau_graph {
struct nouveau_engine base;
};
static inline struct nouveau_graph *
nouveau_graph(void *obj)
{
return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_GR];
}
#define nouveau_graph_create(p,e,c,y,d) \
nouveau_engine_create((p), (e), (c), (y), "PGRAPH", "graphics", (d))
#define nouveau_graph_destroy(d) \
nouveau_engine_destroy(&(d)->base)
#define nouveau_graph_init(d) \
nouveau_engine_init(&(d)->base)
#define nouveau_graph_fini(d,s) \
nouveau_engine_fini(&(d)->base, (s))
#define _nouveau_graph_dtor _nouveau_engine_dtor
#define _nouveau_graph_init _nouveau_engine_init
#define _nouveau_graph_fini _nouveau_engine_fini
extern struct nouveau_oclass nv04_graph_oclass;
extern struct nouveau_oclass nv10_graph_oclass;
extern struct nouveau_oclass nv20_graph_oclass;
extern struct nouveau_oclass nv25_graph_oclass;
extern struct nouveau_oclass nv2a_graph_oclass;
extern struct nouveau_oclass nv30_graph_oclass;
extern struct nouveau_oclass nv34_graph_oclass;
extern struct nouveau_oclass nv35_graph_oclass;
extern struct nouveau_oclass nv40_graph_oclass;
extern struct nouveau_oclass nv50_graph_oclass;
extern struct nouveau_oclass nvc0_graph_oclass;
extern struct nouveau_oclass nve0_graph_oclass;
extern struct nouveau_bitfield nv04_graph_nsource[];
extern struct nouveau_ofuncs nv04_graph_ofuncs;
bool nv04_graph_idle(void *obj);
extern struct nouveau_bitfield nv10_graph_intr_name[];
extern struct nouveau_bitfield nv10_graph_nstatus[];
extern struct nouveau_enum nv50_data_error_names[];
#endif
@@ -0,0 +1,61 @@
#ifndef __NOUVEAU_MPEG_H__
#define __NOUVEAU_MPEG_H__
#include <core/engine.h>
#include <core/engctx.h>
struct nouveau_mpeg_chan {
struct nouveau_engctx base;
};
#define nouveau_mpeg_context_create(p,e,c,g,s,a,f,d) \
nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
#define nouveau_mpeg_context_destroy(d) \
nouveau_engctx_destroy(&(d)->base)
#define nouveau_mpeg_context_init(d) \
nouveau_engctx_init(&(d)->base)
#define nouveau_mpeg_context_fini(d,s) \
nouveau_engctx_fini(&(d)->base, (s))
#define _nouveau_mpeg_context_dtor _nouveau_engctx_dtor
#define _nouveau_mpeg_context_init _nouveau_engctx_init
#define _nouveau_mpeg_context_fini _nouveau_engctx_fini
#define _nouveau_mpeg_context_rd32 _nouveau_engctx_rd32
#define _nouveau_mpeg_context_wr32 _nouveau_engctx_wr32
struct nouveau_mpeg {
struct nouveau_engine base;
};
#define nouveau_mpeg_create(p,e,c,d) \
nouveau_engine_create((p), (e), (c), true, "PMPEG", "mpeg", (d))
#define nouveau_mpeg_destroy(d) \
nouveau_engine_destroy(&(d)->base)
#define nouveau_mpeg_init(d) \
nouveau_engine_init(&(d)->base)
#define nouveau_mpeg_fini(d,s) \
nouveau_engine_fini(&(d)->base, (s))
#define _nouveau_mpeg_dtor _nouveau_engine_dtor
#define _nouveau_mpeg_init _nouveau_engine_init
#define _nouveau_mpeg_fini _nouveau_engine_fini
extern struct nouveau_oclass nv31_mpeg_oclass;
extern struct nouveau_oclass nv40_mpeg_oclass;
extern struct nouveau_oclass nv50_mpeg_oclass;
extern struct nouveau_oclass nv84_mpeg_oclass;
extern struct nouveau_oclass nv31_mpeg_sclass[];
void nv31_mpeg_intr(struct nouveau_subdev *);
void nv31_mpeg_tile_prog(struct nouveau_engine *, int);
int nv31_mpeg_init(struct nouveau_object *);
extern struct nouveau_ofuncs nv50_mpeg_ofuncs;
int nv50_mpeg_context_ctor(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, void *, u32,
struct nouveau_object **);
int nv50_mpeg_tlb_flush(struct nouveau_engine *);
void nv50_mpeg_intr(struct nouveau_subdev *);
int nv50_mpeg_init(struct nouveau_object *);
#endif
@@ -0,0 +1,45 @@
#ifndef __NOUVEAU_PPP_H__
#define __NOUVEAU_PPP_H__
#include <core/engine.h>
#include <core/engctx.h>
struct nouveau_ppp_chan {
struct nouveau_engctx base;
};
#define nouveau_ppp_context_create(p,e,c,g,s,a,f,d) \
nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
#define nouveau_ppp_context_destroy(d) \
nouveau_engctx_destroy(&(d)->base)
#define nouveau_ppp_context_init(d) \
nouveau_engctx_init(&(d)->base)
#define nouveau_ppp_context_fini(d,s) \
nouveau_engctx_fini(&(d)->base, (s))
#define _nouveau_ppp_context_dtor _nouveau_engctx_dtor
#define _nouveau_ppp_context_init _nouveau_engctx_init
#define _nouveau_ppp_context_fini _nouveau_engctx_fini
#define _nouveau_ppp_context_rd32 _nouveau_engctx_rd32
#define _nouveau_ppp_context_wr32 _nouveau_engctx_wr32
struct nouveau_ppp {
struct nouveau_engine base;
};
#define nouveau_ppp_create(p,e,c,d) \
nouveau_engine_create((p), (e), (c), true, "PPPP", "ppp", (d))
#define nouveau_ppp_destroy(d) \
nouveau_engine_destroy(&(d)->base)
#define nouveau_ppp_init(d) \
nouveau_engine_init(&(d)->base)
#define nouveau_ppp_fini(d,s) \
nouveau_engine_fini(&(d)->base, (s))
#define _nouveau_ppp_dtor _nouveau_engine_dtor
#define _nouveau_ppp_init _nouveau_engine_init
#define _nouveau_ppp_fini _nouveau_engine_fini
extern struct nouveau_oclass nv98_ppp_oclass;
#endif
@@ -0,0 +1,58 @@
#ifndef __NOUVEAU_SOFTWARE_H__
#define __NOUVEAU_SOFTWARE_H__
#include <core/engine.h>
#include <core/engctx.h>
struct nouveau_software_chan {
struct nouveau_engctx base;
struct {
struct list_head head;
u32 channel;
u32 ctxdma;
u64 offset;
u32 value;
u32 crtc;
} vblank;
int (*flip)(void *);
void *flip_data;
};
#define nouveau_software_context_create(p,e,c,d) \
nouveau_engctx_create((p), (e), (c), (p), 0, 0, 0, (d))
#define nouveau_software_context_destroy(d) \
nouveau_engctx_destroy(&(d)->base)
#define nouveau_software_context_init(d) \
nouveau_engctx_init(&(d)->base)
#define nouveau_software_context_fini(d,s) \
nouveau_engctx_fini(&(d)->base, (s))
#define _nouveau_software_context_dtor _nouveau_engctx_dtor
#define _nouveau_software_context_init _nouveau_engctx_init
#define _nouveau_software_context_fini _nouveau_engctx_fini
struct nouveau_software {
struct nouveau_engine base;
};
#define nouveau_software_create(p,e,c,d) \
nouveau_engine_create((p), (e), (c), true, "SW", "software", (d))
#define nouveau_software_destroy(d) \
nouveau_engine_destroy(&(d)->base)
#define nouveau_software_init(d) \
nouveau_engine_init(&(d)->base)
#define nouveau_software_fini(d,s) \
nouveau_engine_fini(&(d)->base, (s))
#define _nouveau_software_dtor _nouveau_engine_dtor
#define _nouveau_software_init _nouveau_engine_init
#define _nouveau_software_fini _nouveau_engine_fini
extern struct nouveau_oclass nv04_software_oclass;
extern struct nouveau_oclass nv10_software_oclass;
extern struct nouveau_oclass nv50_software_oclass;
extern struct nouveau_oclass nvc0_software_oclass;
#endif
@@ -0,0 +1,45 @@
#ifndef __NOUVEAU_VP_H__
#define __NOUVEAU_VP_H__
#include <core/engine.h>
#include <core/engctx.h>
struct nouveau_vp_chan {
struct nouveau_engctx base;
};
#define nouveau_vp_context_create(p,e,c,g,s,a,f,d) \
nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
#define nouveau_vp_context_destroy(d) \
nouveau_engctx_destroy(&(d)->base)
#define nouveau_vp_context_init(d) \
nouveau_engctx_init(&(d)->base)
#define nouveau_vp_context_fini(d,s) \
nouveau_engctx_fini(&(d)->base, (s))
#define _nouveau_vp_context_dtor _nouveau_engctx_dtor
#define _nouveau_vp_context_init _nouveau_engctx_init
#define _nouveau_vp_context_fini _nouveau_engctx_fini
#define _nouveau_vp_context_rd32 _nouveau_engctx_rd32
#define _nouveau_vp_context_wr32 _nouveau_engctx_wr32
struct nouveau_vp {
struct nouveau_engine base;
};
#define nouveau_vp_create(p,e,c,d) \
nouveau_engine_create((p), (e), (c), true, "PVP", "vp", (d))
#define nouveau_vp_destroy(d) \
nouveau_engine_destroy(&(d)->base)
#define nouveau_vp_init(d) \
nouveau_engine_init(&(d)->base)
#define nouveau_vp_fini(d,s) \
nouveau_engine_fini(&(d)->base, (s))
#define _nouveau_vp_dtor _nouveau_engine_dtor
#define _nouveau_vp_init _nouveau_engine_init
#define _nouveau_vp_fini _nouveau_engine_fini
extern struct nouveau_oclass nv84_vp_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 *);
@@ -8,7 +8,6 @@
struct nouveau_instobj {
struct nouveau_object base;
struct list_head head;
struct nouveau_mm heap;
u32 *suspend;
u64 addr;
u32 size;
@@ -73,6 +73,7 @@ struct nouveau_vm {
struct nouveau_vmmgr {
struct nouveau_subdev base;
u64 limit;
u32 pgt_bits;
u8 spg_shift;
u8 lpg_shift;
@@ -241,6 +241,8 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
if (!device->subdev[i]) {
ret = nouveau_object_ctor(nv_object(device), NULL,
oclass, NULL, i, &subdev);
if (ret == -ENODEV)
continue;
if (ret)
return ret;
@@ -404,10 +406,26 @@ nouveau_device_sclass[] = {
{}
};
static void
nouveau_device_dtor(struct nouveau_object *object)
{
struct nouveau_device *device = (void *)object;
mutex_lock(&nv_devices_mutex);
list_del(&device->head);
mutex_unlock(&nv_devices_mutex);
if (device->base.mmio)
iounmap(device->base.mmio);
nouveau_subdev_destroy(&device->base);
}
static struct nouveau_oclass
nouveau_device_oclass = {
.handle = NV_SUBDEV(DEVICE, 0x00),
.ofuncs = &(struct nouveau_ofuncs) {
.dtor = nouveau_device_dtor,
},
};
@@ -444,18 +462,3 @@ done:
mutex_unlock(&nv_devices_mutex);
return ret;
}
void
nouveau_device_destroy(struct nouveau_device **pdevice)
{
struct nouveau_device *device = *pdevice;
if (device) {
mutex_lock(&nv_devices_mutex);
list_del(&device->head);
mutex_unlock(&nv_devices_mutex);
if (device->base.mmio)
iounmap(device->base.mmio);
nouveau_subdev_destroy(&device->base);
}
*pdevice = NULL;
}
@@ -33,6 +33,12 @@
#include <subdev/instmem.h>
#include <subdev/vm.h>
#include <engine/dmaobj.h>
#include <engine/fifo.h>
#include <engine/software.h>
#include <engine/graph.h>
#include <engine/disp.h>
int
nv04_identify(struct nouveau_device *device)
{
@@ -47,6 +53,11 @@ nv04_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv04_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv04_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv04_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv04_graph_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x05:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -58,6 +69,11 @@ nv04_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv04_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv04_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv04_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv04_graph_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
default:
nv_fatal(device, "unknown RIVA chipset\n");
@@ -34,6 +34,12 @@
#include <subdev/instmem.h>
#include <subdev/vm.h>
#include <engine/dmaobj.h>
#include <engine/fifo.h>
#include <engine/software.h>
#include <engine/graph.h>
#include <engine/disp.h>
int
nv10_identify(struct nouveau_device *device)
{
@@ -49,6 +55,9 @@ nv10_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x15:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -61,6 +70,11 @@ nv10_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv10_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x16:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -73,6 +87,11 @@ nv10_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv10_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x1a:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -85,6 +104,11 @@ nv10_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv10_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x11:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -97,6 +121,11 @@ nv10_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv10_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x17:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -109,6 +138,11 @@ nv10_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv17_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x1f:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -121,6 +155,11 @@ nv10_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv17_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x18:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -133,6 +172,11 @@ nv10_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv10_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv17_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
default:
nv_fatal(device, "unknown Celsius chipset\n");
@@ -34,6 +34,12 @@
#include <subdev/instmem.h>
#include <subdev/vm.h>
#include <engine/dmaobj.h>
#include <engine/fifo.h>
#include <engine/software.h>
#include <engine/graph.h>
#include <engine/disp.h>
int
nv20_identify(struct nouveau_device *device)
{
@@ -49,6 +55,11 @@ nv20_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv20_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv17_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv20_graph_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x25:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -61,6 +72,11 @@ nv20_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv20_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv17_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv25_graph_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x28:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -73,6 +89,11 @@ nv20_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv20_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv17_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv25_graph_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x2a:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -85,6 +106,11 @@ nv20_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv20_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv17_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv2a_graph_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
default:
nv_fatal(device, "unknown Kelvin chipset\n");
@@ -34,6 +34,13 @@
#include <subdev/instmem.h>
#include <subdev/vm.h>
#include <engine/dmaobj.h>
#include <engine/fifo.h>
#include <engine/software.h>
#include <engine/graph.h>
#include <engine/mpeg.h>
#include <engine/disp.h>
int
nv30_identify(struct nouveau_device *device)
{
@@ -49,6 +56,11 @@ nv30_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv30_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv17_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv30_graph_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x35:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -61,6 +73,11 @@ nv30_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv30_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv17_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv35_graph_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x31:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -73,6 +90,12 @@ nv30_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv30_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv17_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv30_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x36:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -85,6 +108,12 @@ nv30_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv30_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv17_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv35_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x34:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -97,6 +126,12 @@ nv30_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv30_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv17_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv34_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
default:
nv_fatal(device, "unknown Rankine chipset\n");
@@ -34,6 +34,13 @@
#include <subdev/instmem.h>
#include <subdev/vm.h>
#include <engine/dmaobj.h>
#include <engine/fifo.h>
#include <engine/software.h>
#include <engine/graph.h>
#include <engine/mpeg.h>
#include <engine/disp.h>
int
nv40_identify(struct nouveau_device *device)
{
@@ -49,6 +56,12 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x41:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -61,6 +74,12 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x42:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -73,6 +92,12 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x43:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -85,6 +110,12 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x45:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -97,6 +128,12 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x47:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -109,6 +146,12 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x49:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -121,6 +164,12 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x4b:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -133,6 +182,12 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x44:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -145,6 +200,12 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x46:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -157,6 +218,12 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x4a:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -169,6 +236,12 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x4c:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -181,6 +254,12 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x4e:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -193,6 +272,12 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x63:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -205,6 +290,12 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x67:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -217,6 +308,12 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
case 0x68:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -229,6 +326,12 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass;
break;
default:
nv_fatal(device, "unknown Curie chipset\n");
@@ -35,6 +35,18 @@
#include <subdev/vm.h>
#include <subdev/bar.h>
#include <engine/dmaobj.h>
#include <engine/fifo.h>
#include <engine/software.h>
#include <engine/graph.h>
#include <engine/mpeg.h>
#include <engine/vp.h>
#include <engine/crypt.h>
#include <engine/bsp.h>
#include <engine/ppp.h>
#include <engine/copy.h>
#include <engine/disp.h>
int
nv50_identify(struct nouveau_device *device)
{
@@ -51,6 +63,12 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv50_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv50_mpeg_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0x84:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -64,6 +82,15 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv84_mpeg_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0x86:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -77,6 +104,15 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv84_mpeg_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0x92:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -90,6 +126,15 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv84_mpeg_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0x94:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -103,6 +148,15 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv84_mpeg_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0x96:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -116,6 +170,15 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv84_mpeg_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0x98:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -129,6 +192,15 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
device->oclass[NVDEV_ENGINE_CRYPT ] = &nv98_crypt_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0xa0:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -142,6 +214,15 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv84_mpeg_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0xaa:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -155,6 +236,15 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
device->oclass[NVDEV_ENGINE_CRYPT ] = &nv98_crypt_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0xac:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -168,6 +258,15 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
device->oclass[NVDEV_ENGINE_CRYPT ] = &nv98_crypt_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0xa3:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -181,6 +280,16 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv84_mpeg_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nva3_copy_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0xa5:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -194,6 +303,15 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nva3_copy_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0xa8:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -207,6 +325,15 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nva3_copy_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0xaf:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -220,6 +347,15 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nva3_copy_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
default:
nv_fatal(device, "unknown Tesla chipset\n");
@@ -36,6 +36,16 @@
#include <subdev/vm.h>
#include <subdev/bar.h>
#include <engine/dmaobj.h>
#include <engine/fifo.h>
#include <engine/software.h>
#include <engine/graph.h>
#include <engine/vp.h>
#include <engine/bsp.h>
#include <engine/ppp.h>
#include <engine/copy.h>
#include <engine/disp.h>
int
nvc0_identify(struct nouveau_device *device)
{
@@ -53,6 +63,16 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0xc4:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -67,6 +87,16 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0xc3:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -81,6 +111,16 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0xce:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -95,6 +135,16 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0xcf:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -109,6 +159,16 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0xc1:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -123,6 +183,16 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0xc8:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -137,6 +207,16 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass;
break;
case 0xd9:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -151,6 +231,15 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nvd0_disp_oclass;
break;
default:
nv_fatal(device, "unknown Fermi chipset\n");
@@ -36,6 +36,12 @@
#include <subdev/vm.h>
#include <subdev/bar.h>
#include <engine/dmaobj.h>
#include <engine/fifo.h>
#include <engine/software.h>
#include <engine/graph.h>
#include <engine/disp.h>
int
nve0_identify(struct nouveau_device *device)
{
@@ -53,6 +59,11 @@ nve0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nve0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nve0_graph_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nvd0_disp_oclass;
break;
case 0xe7:
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
@@ -67,6 +78,11 @@ nve0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nve0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nve0_graph_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nvd0_disp_oclass;
break;
default:
nv_fatal(device, "unknown Kepler chipset\n");
@@ -139,8 +139,7 @@ nv04_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return ret;
/* 0x10000-0x18000: reserve for RAMHT */
ret = nouveau_gpuobj_new(parent, NULL, 0x08000, 0,
NVOBJ_FLAG_ZERO_ALLOC, &priv->ramht);
ret = nouveau_ramht_new(parent, NULL, 0x08000, 0, &priv->ramht);
if (ret)
return ret;
@@ -165,7 +164,7 @@ nv04_instmem_dtor(struct nouveau_object *object)
struct nv04_instmem_priv *priv = (void *)object;
nouveau_gpuobj_ref(NULL, &priv->ramfc);
nouveau_gpuobj_ref(NULL, &priv->ramro);
nouveau_gpuobj_ref(NULL, &priv->ramht);
nouveau_ramht_ref(NULL, &priv->ramht);
nouveau_gpuobj_ref(NULL, &priv->vbios);
nouveau_mm_fini(&priv->heap);
if (priv->iomem)
@@ -2,6 +2,7 @@
#define __NV04_INSTMEM_H__
#include <core/gpuobj.h>
#include <core/ramht.h>
#include <core/mm.h>
#include <subdev/instmem.h>
@@ -14,11 +15,17 @@ struct nv04_instmem_priv {
struct nouveau_mm heap;
struct nouveau_gpuobj *vbios;
struct nouveau_gpuobj *ramht;
struct nouveau_ramht *ramht;
struct nouveau_gpuobj *ramro;
struct nouveau_gpuobj *ramfc;
};
static inline struct nv04_instmem_priv *
nv04_instmem(void *obj)
{
return (void *)nouveau_instmem(obj);
}
struct nv04_instobj_priv {
struct nouveau_instobj base;
struct nouveau_mm_node *mem;
@@ -87,8 +87,7 @@ nv40_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return ret;
/* 0x10000-0x18000: reserve for RAMHT */
ret = nouveau_gpuobj_new(parent, NULL, 0x08000, 0,
NVOBJ_FLAG_ZERO_ALLOC, &priv->ramht);
ret = nouveau_ramht_new(parent, NULL, 0x08000, 0, &priv->ramht);
if (ret)
return ret;
@@ -299,6 +299,7 @@ nouveau_vm_get(struct nouveau_vm *vm, u64 size, u32 page_shift,
fpde = (vma->node->offset >> vmm->pgt_bits);
lpde = (vma->node->offset + vma->node->length - 1) >> vmm->pgt_bits;
for (pde = fpde; pde <= lpde; pde++) {
struct nouveau_vm_pgt *vpgt = &vm->pgt[pde - vm->fpde];
int big = (vma->node->type != vmm->spg_shift);
@@ -96,6 +96,7 @@ nv04_vmmgr_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return ret;
priv->base.create = nv04_vm_create;
priv->base.limit = NV04_PDMA_SIZE;
priv->base.pgt_bits = 32 - 12;
priv->base.spg_shift = 12;
priv->base.lpg_shift = 12;
@@ -10,4 +10,10 @@ struct nv04_vmmgr_priv {
dma_addr_t null;
};
static inline struct nv04_vmmgr_priv *
nv04_vmmgr(void *obj)
{
return (void *)nouveau_vmmgr(obj);
}
#endif
@@ -97,6 +97,7 @@ nv41_vmmgr_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return ret;
priv->base.create = nv04_vm_create;
priv->base.limit = NV41_GART_SIZE;
priv->base.pgt_bits = 32 - 12;
priv->base.spg_shift = 12;
priv->base.lpg_shift = 12;
@@ -178,6 +178,7 @@ nv44_vmmgr_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return ret;
priv->base.create = nv04_vm_create;
priv->base.limit = NV44_GART_SIZE;
priv->base.pgt_bits = 32 - 12;
priv->base.spg_shift = 12;
priv->base.lpg_shift = 12;
@@ -154,7 +154,6 @@ nv50_vm_flush(struct nouveau_vm *vm)
struct nouveau_engine *engine;
int i;
#if 0
for (i = 0; i < NVDEV_SUBDEV_NR; i++) {
if (atomic_read(&vm->engref[i])) {
engine = nouveau_engine(vm->vmm, i);
@@ -162,11 +161,6 @@ nv50_vm_flush(struct nouveau_vm *vm)
engine->tlb_flush(engine);
}
}
#else
nv50_vm_flush_engine(nv_subdev(vm->vmm), 0x06); /* bar */
nv50_vm_flush_engine(nv_subdev(vm->vmm), 0x05); /* fifo */
nv50_vm_flush_engine(nv_subdev(vm->vmm), 0x00); /* gr */
#endif
}
void
@@ -206,6 +200,7 @@ nv50_vmmgr_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
priv->base.limit = 1ULL << 40;
priv->base.pgt_bits = 29 - 12;
priv->base.spg_shift = 12;
priv->base.lpg_shift = 16;
@@ -162,6 +162,7 @@ nvc0_vmmgr_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
priv->base.limit = 1ULL << 40;
priv->base.pgt_bits = 27 - 12;
priv->base.spg_shift = 12;
priv->base.lpg_shift = 17;
+325 -96
View File
@@ -21,23 +21,153 @@
*
*/
#include "drmP.h"
#include <core/object.h>
#include <core/client.h>
#include <core/device.h>
#include <core/class.h>
#include <core/mm.h>
#include "nouveau_drv.h"
#include <subdev/fb.h>
#include <subdev/timer.h>
#include <subdev/instmem.h>
#include "nouveau_drm.h"
#include "nouveau_dma.h"
#include "nouveau_gem.h"
#include "nouveau_chan.h"
#include "nouveau_abi16.h"
#include <core/ramht.h>
#include "nouveau_software.h"
struct nouveau_abi16 *
nouveau_abi16_get(struct drm_file *file_priv, struct drm_device *dev)
{
struct nouveau_cli *cli = nouveau_cli(file_priv);
mutex_lock(&cli->mutex);
if (!cli->abi16) {
struct nouveau_abi16 *abi16;
cli->abi16 = abi16 = kzalloc(sizeof(*abi16), GFP_KERNEL);
if (cli->abi16) {
INIT_LIST_HEAD(&abi16->channels);
abi16->client = nv_object(cli);
/* allocate device object targeting client's default
* device (ie. the one that belongs to the fd it
* opened)
*/
if (nouveau_object_new(abi16->client, NVDRM_CLIENT,
NVDRM_DEVICE, 0x0080,
&(struct nv_device_class) {
.device = ~0ULL,
},
sizeof(struct nv_device_class),
&abi16->device) == 0)
return cli->abi16;
kfree(cli->abi16);
cli->abi16 = NULL;
}
mutex_unlock(&cli->mutex);
}
return cli->abi16;
}
int
nouveau_abi16_put(struct nouveau_abi16 *abi16, int ret)
{
struct nouveau_cli *cli = (void *)abi16->client;
mutex_unlock(&cli->mutex);
return ret;
}
u16
nouveau_abi16_swclass(struct nouveau_drm *drm)
{
switch (nv_device(drm->device)->card_type) {
case NV_04:
return 0x006e;
case NV_10:
case NV_20:
case NV_30:
case NV_40:
return 0x016e;
case NV_50:
return 0x506e;
case NV_C0:
case NV_D0:
case NV_E0:
return 0x906e;
}
return 0x0000;
}
static void
nouveau_abi16_ntfy_fini(struct nouveau_abi16_chan *chan,
struct nouveau_abi16_ntfy *ntfy)
{
nouveau_mm_free(&chan->heap, &ntfy->node);
list_del(&ntfy->head);
kfree(ntfy);
}
static void
nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16,
struct nouveau_abi16_chan *chan)
{
struct nouveau_abi16_ntfy *ntfy, *temp;
/* cleanup notifier state */
list_for_each_entry_safe(ntfy, temp, &chan->notifiers, head) {
nouveau_abi16_ntfy_fini(chan, ntfy);
}
if (chan->ntfy) {
nouveau_bo_vma_del(chan->ntfy, &chan->ntfy_vma);
drm_gem_object_unreference_unlocked(chan->ntfy->gem);
}
if (chan->heap.block_size)
nouveau_mm_fini(&chan->heap);
/* destroy channel object, all children will be killed too */
if (chan->chan) {
abi16->handles &= ~(1 << (chan->chan->handle & 0xffff));
nouveau_channel_del(&chan->chan);
}
list_del(&chan->head);
kfree(chan);
}
void
nouveau_abi16_fini(struct nouveau_abi16 *abi16)
{
struct nouveau_cli *cli = (void *)abi16->client;
struct nouveau_abi16_chan *chan, *temp;
/* cleanup channels */
list_for_each_entry_safe(chan, temp, &abi16->channels, head) {
nouveau_abi16_chan_fini(abi16, chan);
}
/* destroy the device object */
nouveau_object_del(abi16->client, NVDRM_CLIENT, NVDRM_DEVICE);
kfree(cli->abi16);
cli->abi16 = NULL;
}
int
nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_device *device = nv_device(drm->device);
struct nouveau_timer *ptimer = nouveau_timer(device);
struct drm_nouveau_getparam *getparam = data;
switch (getparam->param) {
case NOUVEAU_GETPARAM_CHIPSET_ID:
getparam->value = dev_priv->chipset;
getparam->value = device->chipset;
break;
case NOUVEAU_GETPARAM_PCI_VENDOR:
getparam->value = dev->pci_vendor;
@@ -55,16 +185,16 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)
getparam->value = 2;
break;
case NOUVEAU_GETPARAM_FB_SIZE:
getparam->value = dev_priv->fb_available_size;
getparam->value = drm->gem.vram_available;
break;
case NOUVEAU_GETPARAM_AGP_SIZE:
getparam->value = dev_priv->gart_info.aper_size;
getparam->value = drm->gem.gart_available;
break;
case NOUVEAU_GETPARAM_VM_VRAM_BASE:
getparam->value = 0; /* deprecated */
break;
case NOUVEAU_GETPARAM_PTIMER_TIME:
getparam->value = nv_timer_read(dev);
getparam->value = ptimer->read(ptimer);
break;
case NOUVEAU_GETPARAM_HAS_BO_USAGE:
getparam->value = 1;
@@ -76,13 +206,13 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)
/* NV40 and NV50 versions are quite different, but register
* address is the same. User is supposed to know the card
* family anyway... */
if (dev_priv->chipset >= 0x40) {
getparam->value = nv_rd32(dev, NV40_PMC_GRAPH_UNITS);
if (device->chipset >= 0x40) {
getparam->value = nv_rd32(device, 0x001540);
break;
}
/* FALLTHRU */
default:
NV_DEBUG(dev, "unknown parameter %lld\n", getparam->param);
nv_debug(device, "unknown parameter %lld\n", getparam->param);
return -EINVAL;
}
@@ -98,148 +228,247 @@ nouveau_abi16_ioctl_setparam(ABI16_IOCTL_ARGS)
int
nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct drm_nouveau_channel_alloc *init = data;
struct nouveau_channel *chan;
struct nouveau_cli *cli = nouveau_cli(file_priv);
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev);
struct nouveau_abi16_chan *chan;
struct nouveau_client *client;
struct nouveau_device *device;
struct nouveau_instmem *imem;
struct nouveau_fb *pfb;
int ret;
if (!dev_priv->eng[NVOBJ_ENGINE_GR])
return -ENODEV;
if (unlikely(!abi16))
return -ENOMEM;
client = nv_client(abi16->client);
if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0)
return -EINVAL;
return nouveau_abi16_put(abi16, -EINVAL);
ret = nouveau_channel_alloc(dev, &chan, file_priv,
init->fb_ctxdma_handle,
init->tt_ctxdma_handle);
device = nv_device(abi16->device);
imem = nouveau_instmem(device);
pfb = nouveau_fb(device);
/* allocate "abi16 channel" data and make up a handle for it */
init->channel = ffsll(~abi16->handles);
if (!init->channel--)
return nouveau_abi16_put(abi16, -ENOSPC);
chan = kzalloc(sizeof(*chan), GFP_KERNEL);
if (!chan)
return nouveau_abi16_put(abi16, -ENOMEM);
INIT_LIST_HEAD(&chan->notifiers);
list_add(&chan->head, &abi16->channels);
abi16->handles |= (1 << init->channel);
/* create channel object and initialise dma and fence management */
ret = nouveau_channel_new(drm, cli, NVDRM_DEVICE, NVDRM_CHAN |
init->channel, init->fb_ctxdma_handle,
init->tt_ctxdma_handle, &chan->chan);
if (ret)
return ret;
init->channel = chan->id;
goto done;
if (nouveau_vram_pushbuf == 0) {
if (chan->dma.ib_max)
init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM |
NOUVEAU_GEM_DOMAIN_GART;
else if (chan->pushbuf_bo->bo.mem.mem_type == TTM_PL_VRAM)
init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM;
else
init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART;
} else {
if (device->card_type >= NV_50)
init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM |
NOUVEAU_GEM_DOMAIN_GART;
else
if (chan->chan->push.buffer->bo.mem.mem_type == TTM_PL_VRAM)
init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM;
}
else
init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART;
if (dev_priv->card_type < NV_C0) {
if (device->card_type < NV_C0) {
init->subchan[0].handle = 0x00000000;
init->subchan[0].grclass = 0x0000;
init->subchan[1].handle = NvSw;
init->subchan[1].grclass = NV_SW;
init->subchan[1].grclass = 0x506e;
init->nr_subchan = 2;
}
/* Named memory object area */
ret = drm_gem_handle_create(file_priv, chan->notifier_bo->gem,
&init->notifier_handle);
ret = nouveau_gem_new(dev, PAGE_SIZE, 0, NOUVEAU_GEM_DOMAIN_GART,
0, 0, &chan->ntfy);
if (ret == 0)
atomic_inc(&chan->users); /* userspace reference */
nouveau_channel_put(&chan);
return ret;
ret = nouveau_bo_pin(chan->ntfy, TTM_PL_FLAG_TT);
if (ret)
goto done;
if (device->card_type >= NV_50) {
ret = nouveau_bo_vma_add(chan->ntfy, client->vm,
&chan->ntfy_vma);
if (ret)
goto done;
}
ret = drm_gem_handle_create(file_priv, chan->ntfy->gem,
&init->notifier_handle);
if (ret)
goto done;
ret = nouveau_mm_init(&chan->heap, 0, PAGE_SIZE, 1);
done:
if (ret)
nouveau_abi16_chan_fini(abi16, chan);
return nouveau_abi16_put(abi16, ret);
}
int
nouveau_abi16_ioctl_channel_free(ABI16_IOCTL_ARGS)
{
struct drm_nouveau_channel_free *req = data;
struct nouveau_channel *chan;
struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev);
struct nouveau_abi16_chan *chan;
int ret = -ENOENT;
chan = nouveau_channel_get(file_priv, req->channel);
if (IS_ERR(chan))
return PTR_ERR(chan);
if (unlikely(!abi16))
return -ENOMEM;
list_del(&chan->list);
atomic_dec(&chan->users);
nouveau_channel_put(&chan);
return 0;
list_for_each_entry(chan, &abi16->channels, head) {
if (chan->chan->handle == (NVDRM_CHAN | req->channel)) {
nouveau_abi16_chan_fini(abi16, chan);
return nouveau_abi16_put(abi16, 0);
}
}
return nouveau_abi16_put(abi16, ret);
}
int
nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS)
{
struct drm_nouveau_grobj_alloc *init = data;
struct nouveau_channel *chan;
struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev);
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_object *object;
int ret;
if (unlikely(!abi16))
return -ENOMEM;
if (init->handle == ~0)
return -EINVAL;
return nouveau_abi16_put(abi16, -EINVAL);
/* compatibility with userspace that assumes 506e for all chipsets */
if (init->class == 0x506e) {
init->class = nouveau_software_class(dev);
init->class = nouveau_abi16_swclass(drm);
if (init->class == 0x906e)
return 0;
} else
if (init->class == 0x906e) {
NV_DEBUG(dev, "906e not supported yet\n");
return -EINVAL;
return nouveau_abi16_put(abi16, 0);
}
chan = nouveau_channel_get(file_priv, init->channel);
if (IS_ERR(chan))
return PTR_ERR(chan);
if (nouveau_ramht_find(chan, init->handle)) {
ret = -EEXIST;
goto out;
}
ret = nouveau_gpuobj_gr_new(chan, init->handle, init->class);
if (ret) {
NV_ERROR(dev, "Error creating object: %d (%d/0x%08x)\n",
ret, init->channel, init->handle);
}
out:
nouveau_channel_put(&chan);
return ret;
ret = nouveau_object_new(abi16->client, NVDRM_CHAN | init->channel,
init->handle, init->class, NULL, 0, &object);
return nouveau_abi16_put(abi16, ret);
}
int
nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct drm_nouveau_notifierobj_alloc *na = data;
struct nouveau_channel *chan;
struct drm_nouveau_notifierobj_alloc *info = data;
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_device *device = nv_device(drm->device);
struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev);
struct nouveau_abi16_chan *chan, *temp;
struct nouveau_abi16_ntfy *ntfy;
struct nouveau_object *object;
struct nv_dma_class args;
int ret;
if (unlikely(!abi16))
return -ENOMEM;
/* completely unnecessary for these chipsets... */
if (unlikely(dev_priv->card_type >= NV_C0))
return -EINVAL;
if (unlikely(nv_device(abi16->device)->card_type >= NV_C0))
return nouveau_abi16_put(abi16, -EINVAL);
chan = nouveau_channel_get(file_priv, na->channel);
if (IS_ERR(chan))
return PTR_ERR(chan);
list_for_each_entry_safe(chan, temp, &abi16->channels, head) {
if (chan->chan->handle == (NVDRM_CHAN | info->channel))
break;
chan = NULL;
}
ret = nouveau_notifier_alloc(chan, na->handle, na->size, 0, 0x1000,
&na->offset);
nouveau_channel_put(&chan);
return ret;
if (!chan)
return nouveau_abi16_put(abi16, -ENOENT);
ntfy = kzalloc(sizeof(*ntfy), GFP_KERNEL);
if (!ntfy)
return nouveau_abi16_put(abi16, -ENOMEM);
list_add(&ntfy->head, &chan->notifiers);
ntfy->handle = info->handle;
ret = nouveau_mm_head(&chan->heap, 1, info->size, info->size, 1,
&ntfy->node);
if (ret)
goto done;
args.start = ntfy->node->offset;
args.limit = ntfy->node->offset + ntfy->node->length - 1;
if (device->card_type >= NV_50) {
args.flags = NV_DMA_TARGET_VM | NV_DMA_ACCESS_VM;
args.start += chan->ntfy_vma.offset;
args.limit += chan->ntfy_vma.offset;
} else
if (drm->agp.stat == ENABLED) {
args.flags = NV_DMA_TARGET_AGP | NV_DMA_ACCESS_RDWR;
args.start += drm->agp.base + chan->ntfy->bo.offset;
args.limit += drm->agp.base + chan->ntfy->bo.offset;
} else {
args.flags = NV_DMA_TARGET_VM | NV_DMA_ACCESS_RDWR;
args.start += chan->ntfy->bo.offset;
args.limit += chan->ntfy->bo.offset;
}
ret = nouveau_object_new(abi16->client, chan->chan->handle,
ntfy->handle, 0x003d, &args,
sizeof(args), &object);
if (ret)
goto done;
done:
if (ret)
nouveau_abi16_ntfy_fini(chan, ntfy);
return nouveau_abi16_put(abi16, ret);
}
int
nouveau_abi16_ioctl_gpuobj_free(ABI16_IOCTL_ARGS)
{
struct drm_nouveau_gpuobj_free *objfree = data;
struct nouveau_channel *chan;
struct drm_nouveau_gpuobj_free *fini = data;
struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev);
struct nouveau_abi16_chan *chan, *temp;
struct nouveau_abi16_ntfy *ntfy;
int ret;
chan = nouveau_channel_get(file_priv, objfree->channel);
if (IS_ERR(chan))
return PTR_ERR(chan);
if (unlikely(!abi16))
return -ENOMEM;
/* Synchronize with the user channel */
nouveau_channel_idle(chan);
list_for_each_entry_safe(chan, temp, &abi16->channels, head) {
if (chan->chan->handle == (NVDRM_CHAN | fini->channel))
break;
chan = NULL;
}
ret = nouveau_ramht_remove(chan, objfree->handle);
nouveau_channel_put(&chan);
return ret;
if (!chan)
return nouveau_abi16_put(abi16, -ENOENT);
/* synchronize with the user channel and destroy the gpu object */
nouveau_channel_idle(chan->chan);
ret = nouveau_object_del(abi16->client, chan->chan->handle, fini->handle);
if (ret)
return nouveau_abi16_put(abi16, ret);
/* cleanup extra state if this object was a notifier */
list_for_each_entry(ntfy, &chan->notifiers, head) {
if (ntfy->handle == fini->handle) {
nouveau_mm_free(&chan->heap, &ntfy->node);
list_del(&ntfy->head);
break;
}
}
return nouveau_abi16_put(abi16, 0);
}
+32
View File
@@ -3,6 +3,7 @@
#define ABI16_IOCTL_ARGS \
struct drm_device *dev, void *data, struct drm_file *file_priv
int nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS);
int nouveau_abi16_ioctl_setparam(ABI16_IOCTL_ARGS);
int nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS);
@@ -11,6 +12,37 @@ int nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS);
int nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS);
int nouveau_abi16_ioctl_gpuobj_free(ABI16_IOCTL_ARGS);
struct nouveau_abi16_ntfy {
struct list_head head;
struct nouveau_mm_node *node;
u32 handle;
};
struct nouveau_abi16_chan {
struct list_head head;
struct nouveau_channel *chan;
struct list_head notifiers;
struct nouveau_bo *ntfy;
struct nouveau_vma ntfy_vma;
struct nouveau_mm heap;
};
struct nouveau_abi16 {
struct nouveau_object *client;
struct nouveau_object *device;
struct list_head channels;
u64 handles;
};
struct nouveau_drm;
struct nouveau_abi16 *nouveau_abi16_get(struct drm_file *, struct drm_device *);
int nouveau_abi16_put(struct nouveau_abi16 *, int);
void nouveau_abi16_fini(struct nouveau_abi16 *);
u16 nouveau_abi16_swclass(struct nouveau_drm *);
#define NOUVEAU_GEM_DOMAIN_VRAM (1 << 1)
#define NOUVEAU_GEM_DOMAIN_GART (1 << 2)
struct drm_nouveau_channel_alloc {
uint32_t fb_ctxdma_handle;
uint32_t tt_ctxdma_handle;
-1
View File
@@ -13,7 +13,6 @@
#include "drm_crtc_helper.h"
#include "nouveau_drv.h"
#include <nouveau_drm.h>
#include "nv50_display.h"
#include "nouveau_connector.h"
#include <linux/vga_switcheroo.h>
+160 -187
View File
@@ -27,66 +27,57 @@
* Jeremy Kolb <jkolb@brandeis.edu>
*/
#include "drmP.h"
#include "ttm/ttm_page_alloc.h"
#include <core/engine.h>
#include <nouveau_drm.h>
#include "nouveau_drv.h"
#include <subdev/fb.h>
#include <subdev/vm.h>
#include <subdev/bar.h>
#include "nouveau_drm.h"
#include "nouveau_dma.h"
#include <core/mm.h>
#include "nouveau_fence.h"
#include <core/ramht.h>
#include <engine/fifo.h>
#include <linux/log2.h>
#include <linux/slab.h>
#include "nouveau_bo.h"
#include "nouveau_ttm.h"
#include "nouveau_gem.h"
/*
* NV10-NV40 tiling helpers
*/
static void
nv10_bo_update_tile_region(struct drm_device *dev,
struct nouveau_tile_reg *tilereg, uint32_t addr,
uint32_t size, uint32_t pitch, uint32_t flags)
nv10_bo_update_tile_region(struct drm_device *dev, struct nouveau_drm_tile *reg,
u32 addr, u32 size, u32 pitch, u32 flags)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
int i = tilereg - dev_priv->tile.reg, j;
struct nouveau_fb_tile *tile = nvfb_tile(dev, i);
unsigned long save;
struct nouveau_drm *drm = nouveau_newpriv(dev);
int i = reg - drm->tile.reg;
struct nouveau_fb *pfb = nouveau_fb(drm->device);
struct nouveau_fb_tile *tile = &pfb->tile.region[i];
struct nouveau_engine *engine;
nouveau_fence_unref(&tilereg->fence);
nouveau_fence_unref(&reg->fence);
if (tile->pitch)
nvfb_tile_fini(dev, i);
pfb->tile.fini(pfb, i, tile);
if (pitch)
nvfb_tile_init(dev, i, addr, size, pitch, flags);
pfb->tile.init(pfb, i, addr, size, pitch, flags, tile);
spin_lock_irqsave(&dev_priv->context_switch_lock, save);
nv_wr32(dev, NV03_PFIFO_CACHES, 0);
nv04_fifo_cache_pull(dev, false);
pfb->tile.prog(pfb, i, tile);
nouveau_wait_for_idle(dev);
nvfb_tile_prog(dev, i);
for (j = 0; j < NVOBJ_ENGINE_NR; j++) {
if (dev_priv->eng[j] && dev_priv->eng[j]->set_tile_region)
dev_priv->eng[j]->set_tile_region(dev, i);
}
nv04_fifo_cache_pull(dev, true);
nv_wr32(dev, NV03_PFIFO_CACHES, 1);
spin_unlock_irqrestore(&dev_priv->context_switch_lock, save);
if ((engine = nouveau_engine(pfb, NVDEV_ENGINE_GR)))
engine->tile_prog(engine, i);
if ((engine = nouveau_engine(pfb, NVDEV_ENGINE_MPEG)))
engine->tile_prog(engine, i);
}
static struct nouveau_tile_reg *
static struct nouveau_drm_tile *
nv10_bo_get_tile_region(struct drm_device *dev, int i)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
struct nouveau_drm *drm = nouveau_newpriv(dev);
struct nouveau_drm_tile *tile = &drm->tile.reg[i];
spin_lock(&dev_priv->tile.lock);
spin_lock(&drm->tile.lock);
if (!tile->used &&
(!tile->fence || nouveau_fence_done(tile->fence)))
@@ -94,18 +85,18 @@ nv10_bo_get_tile_region(struct drm_device *dev, int i)
else
tile = NULL;
spin_unlock(&dev_priv->tile.lock);
spin_unlock(&drm->tile.lock);
return tile;
}
static void
nv10_bo_put_tile_region(struct drm_device *dev, struct nouveau_tile_reg *tile,
struct nouveau_fence *fence)
nv10_bo_put_tile_region(struct drm_device *dev, struct nouveau_drm_tile *tile,
struct nouveau_fence *fence)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_drm *drm = nouveau_newpriv(dev);
if (tile) {
spin_lock(&dev_priv->tile.lock);
spin_lock(&drm->tile.lock);
if (fence) {
/* Mark it as pending. */
tile->fence = fence;
@@ -113,25 +104,27 @@ nv10_bo_put_tile_region(struct drm_device *dev, struct nouveau_tile_reg *tile,
}
tile->used = false;
spin_unlock(&dev_priv->tile.lock);
spin_unlock(&drm->tile.lock);
}
}
static struct nouveau_tile_reg *
nv10_bo_set_tiling(struct drm_device *dev, uint32_t addr, uint32_t size,
uint32_t pitch, uint32_t flags)
static struct nouveau_drm_tile *
nv10_bo_set_tiling(struct drm_device *dev, u32 addr,
u32 size, u32 pitch, u32 flags)
{
struct nouveau_tile_reg *tile, *found = NULL;
struct nouveau_drm *drm = nouveau_newpriv(dev);
struct nouveau_fb *pfb = nouveau_fb(drm->device);
struct nouveau_drm_tile *tile, *found = NULL;
int i;
for (i = 0; i < nvfb_tile_nr(dev); i++) {
for (i = 0; i < pfb->tile.regions; i++) {
tile = nv10_bo_get_tile_region(dev, i);
if (pitch && !found) {
found = tile;
continue;
} else if (tile && nvfb_tile(dev, i)->pitch) {
} else if (tile && pfb->tile.region[i].pitch) {
/* Kill an unused tile region. */
nv10_bo_update_tile_region(dev, tile, 0, 0, 0, 0);
}
@@ -148,13 +141,12 @@ nv10_bo_set_tiling(struct drm_device *dev, uint32_t addr, uint32_t size,
static void
nouveau_bo_del_ttm(struct ttm_buffer_object *bo)
{
struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev);
struct drm_device *dev = dev_priv->dev;
struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
struct drm_device *dev = drm->dev;
struct nouveau_bo *nvbo = nouveau_bo(bo);
if (unlikely(nvbo->gem))
DRM_ERROR("bo %p still attached to GEM object\n", bo);
nv10_bo_put_tile_region(dev, nvbo->tile, NULL);
kfree(nvbo);
}
@@ -163,23 +155,24 @@ static void
nouveau_bo_fixup_align(struct nouveau_bo *nvbo, u32 flags,
int *align, int *size)
{
struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev);
struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
struct nouveau_device *device = nv_device(drm->device);
if (dev_priv->card_type < NV_50) {
if (device->card_type < NV_50) {
if (nvbo->tile_mode) {
if (dev_priv->chipset >= 0x40) {
if (device->chipset >= 0x40) {
*align = 65536;
*size = roundup(*size, 64 * nvbo->tile_mode);
} else if (dev_priv->chipset >= 0x30) {
} else if (device->chipset >= 0x30) {
*align = 32768;
*size = roundup(*size, 64 * nvbo->tile_mode);
} else if (dev_priv->chipset >= 0x20) {
} else if (device->chipset >= 0x20) {
*align = 16384;
*size = roundup(*size, 64 * nvbo->tile_mode);
} else if (dev_priv->chipset >= 0x10) {
} else if (device->chipset >= 0x10) {
*align = 16384;
*size = roundup(*size, 32 * nvbo->tile_mode);
}
@@ -198,7 +191,7 @@ nouveau_bo_new(struct drm_device *dev, int size, int align,
struct sg_table *sg,
struct nouveau_bo **pnvbo)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_drm *drm = nouveau_newpriv(dev);
struct nouveau_bo *nvbo;
size_t acc_size;
int ret;
@@ -215,22 +208,22 @@ nouveau_bo_new(struct drm_device *dev, int size, int align,
INIT_LIST_HEAD(&nvbo->vma_list);
nvbo->tile_mode = tile_mode;
nvbo->tile_flags = tile_flags;
nvbo->bo.bdev = &dev_priv->ttm.bdev;
nvbo->bo.bdev = &drm->ttm.bdev;
nvbo->page_shift = 12;
if (dev_priv->chan_vm) {
if (drm->client.base.vm) {
if (!(flags & TTM_PL_FLAG_TT) && size > 256 * 1024)
nvbo->page_shift = nvvm_lpg_shift(dev_priv->chan_vm);
nvbo->page_shift = drm->client.base.vm->vmm->lpg_shift;
}
nouveau_bo_fixup_align(nvbo, flags, &align, &size);
nvbo->bo.mem.num_pages = size >> PAGE_SHIFT;
nouveau_bo_placement_set(nvbo, flags, 0);
acc_size = ttm_bo_dma_acc_size(&dev_priv->ttm.bdev, size,
acc_size = ttm_bo_dma_acc_size(&drm->ttm.bdev, size,
sizeof(struct nouveau_bo));
ret = ttm_bo_init(&dev_priv->ttm.bdev, &nvbo->bo, size,
ret = ttm_bo_init(&drm->ttm.bdev, &nvbo->bo, size,
type, &nvbo->placement,
align >> PAGE_SHIFT, 0, false, NULL, acc_size, sg,
nouveau_bo_del_ttm);
@@ -259,10 +252,11 @@ set_placement_list(uint32_t *pl, unsigned *n, uint32_t type, uint32_t flags)
static void
set_placement_range(struct nouveau_bo *nvbo, uint32_t type)
{
struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev);
int vram_pages = nvfb_vram_size(dev_priv->dev) >> PAGE_SHIFT;
struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
struct nouveau_fb *pfb = nouveau_fb(drm->device);
u32 vram_pages = pfb->ram.size >> PAGE_SHIFT;
if (dev_priv->card_type == NV_10 &&
if (nv_device(drm->device)->card_type == NV_10 &&
nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM) &&
nvbo->bo.mem.num_pages < vram_pages / 4) {
/*
@@ -302,13 +296,12 @@ nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t type, uint32_t busy)
int
nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype)
{
struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev);
struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
struct ttm_buffer_object *bo = &nvbo->bo;
int ret;
if (nvbo->pin_refcnt && !(memtype & (1 << bo->mem.mem_type))) {
NV_ERROR(nouveau_bdev(bo->bdev)->dev,
"bo %p pinned elsewhere: 0x%08x vs 0x%08x\n", bo,
NV_ERROR(drm, "bo %p pinned elsewhere: 0x%08x vs 0x%08x\n", bo,
1 << bo->mem.mem_type, memtype);
return -EINVAL;
}
@@ -326,10 +319,10 @@ nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype)
if (ret == 0) {
switch (bo->mem.mem_type) {
case TTM_PL_VRAM:
dev_priv->fb_aper_free -= bo->mem.size;
drm->gem.vram_available -= bo->mem.size;
break;
case TTM_PL_TT:
dev_priv->gart_info.aper_free -= bo->mem.size;
drm->gem.gart_available -= bo->mem.size;
break;
default:
break;
@@ -345,7 +338,7 @@ out:
int
nouveau_bo_unpin(struct nouveau_bo *nvbo)
{
struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev);
struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
struct ttm_buffer_object *bo = &nvbo->bo;
int ret;
@@ -362,10 +355,10 @@ nouveau_bo_unpin(struct nouveau_bo *nvbo)
if (ret == 0) {
switch (bo->mem.mem_type) {
case TTM_PL_VRAM:
dev_priv->fb_aper_free += bo->mem.size;
drm->gem.vram_available += bo->mem.size;
break;
case TTM_PL_TT:
dev_priv->gart_info.aper_free += bo->mem.size;
drm->gem.gart_available += bo->mem.size;
break;
default:
break;
@@ -460,30 +453,18 @@ nouveau_bo_wr32(struct nouveau_bo *nvbo, unsigned index, u32 val)
}
static struct ttm_tt *
nouveau_ttm_tt_create(struct ttm_bo_device *bdev,
unsigned long size, uint32_t page_flags,
struct page *dummy_read_page)
nouveau_ttm_tt_create(struct ttm_bo_device *bdev, unsigned long size,
uint32_t page_flags, struct page *dummy_read)
{
struct drm_nouveau_private *dev_priv = nouveau_bdev(bdev);
struct drm_device *dev = dev_priv->dev;
struct nouveau_drm *drm = nouveau_bdev(bdev);
struct drm_device *dev = drm->dev;
switch (dev_priv->gart_info.type) {
#if __OS_HAS_AGP
case NOUVEAU_GART_AGP:
return ttm_agp_tt_create(bdev, dev->agp->bridge,
size, page_flags, dummy_read_page);
#endif
case NOUVEAU_GART_PDMA:
case NOUVEAU_GART_HW:
return nouveau_sgdma_create_ttm(bdev, size, page_flags,
dummy_read_page);
default:
NV_ERROR(dev, "Unknown GART type %d\n",
dev_priv->gart_info.type);
break;
if (drm->agp.stat == ENABLED) {
return ttm_agp_tt_create(bdev, dev->agp->bridge, size,
page_flags, dummy_read);
}
return NULL;
return nouveau_sgdma_create_ttm(bdev, size, page_flags, dummy_read);
}
static int
@@ -497,8 +478,7 @@ static int
nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
struct ttm_mem_type_manager *man)
{
struct drm_nouveau_private *dev_priv = nouveau_bdev(bdev);
struct drm_device *dev = dev_priv->dev;
struct nouveau_drm *drm = nouveau_bdev(bdev);
switch (type) {
case TTM_PL_SYSTEM:
@@ -507,7 +487,7 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
man->default_caching = TTM_PL_FLAG_CACHED;
break;
case TTM_PL_VRAM:
if (dev_priv->card_type >= NV_50) {
if (nv_device(drm->device)->card_type >= NV_50) {
man->func = &nouveau_vram_manager;
man->io_reserve_fastpath = false;
man->use_io_reserve_lru = true;
@@ -521,35 +501,28 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
man->default_caching = TTM_PL_FLAG_WC;
break;
case TTM_PL_TT:
if (dev_priv->card_type >= NV_50)
if (nv_device(drm->device)->card_type >= NV_50)
man->func = &nouveau_gart_manager;
else
if (dev_priv->gart_info.type != NOUVEAU_GART_AGP)
if (drm->agp.stat != ENABLED)
man->func = &nv04_gart_manager;
else
man->func = &ttm_bo_manager_func;
switch (dev_priv->gart_info.type) {
case NOUVEAU_GART_AGP:
if (drm->agp.stat == ENABLED) {
man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
man->available_caching = TTM_PL_FLAG_UNCACHED |
TTM_PL_FLAG_WC;
man->default_caching = TTM_PL_FLAG_WC;
break;
case NOUVEAU_GART_PDMA:
case NOUVEAU_GART_HW:
} else {
man->flags = TTM_MEMTYPE_FLAG_MAPPABLE |
TTM_MEMTYPE_FLAG_CMA;
man->available_caching = TTM_PL_MASK_CACHING;
man->default_caching = TTM_PL_FLAG_CACHED;
break;
default:
NV_ERROR(dev, "Unknown GART type: %d\n",
dev_priv->gart_info.type);
return -EINVAL;
}
break;
default:
NV_ERROR(dev, "Unsupported memory type %u\n", (unsigned)type);
return -EINVAL;
}
return 0;
@@ -783,20 +756,14 @@ nv84_bo_move_exec(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
static int
nv50_bo_move_init(struct nouveau_channel *chan, u32 handle)
{
int ret = nouveau_notifier_alloc(chan, NvNotify0, 32, 0xfe0, 0x1000,
&chan->m2mf_ntfy);
int ret = RING_SPACE(chan, 6);
if (ret == 0) {
ret = RING_SPACE(chan, 6);
if (ret == 0) {
BEGIN_NV04(chan, NvSubCopy, 0x0000, 1);
OUT_RING (chan, handle);
BEGIN_NV04(chan, NvSubCopy, 0x0180, 3);
OUT_RING (chan, NvNotify0);
OUT_RING (chan, NvDmaFB);
OUT_RING (chan, NvDmaFB);
} else {
nouveau_ramht_remove(chan, NvNotify0);
}
BEGIN_NV04(chan, NvSubCopy, 0x0000, 1);
OUT_RING (chan, handle);
BEGIN_NV04(chan, NvSubCopy, 0x0180, 3);
OUT_RING (chan, NvNotify0);
OUT_RING (chan, NvDmaFB);
OUT_RING (chan, NvDmaFB);
}
return ret;
@@ -895,16 +862,12 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
static int
nv04_bo_move_init(struct nouveau_channel *chan, u32 handle)
{
int ret = nouveau_notifier_alloc(chan, NvNotify0, 32, 0xfe0, 0x1000,
&chan->m2mf_ntfy);
int ret = RING_SPACE(chan, 4);
if (ret == 0) {
ret = RING_SPACE(chan, 4);
if (ret == 0) {
BEGIN_NV04(chan, NvSubCopy, 0x0000, 1);
OUT_RING (chan, handle);
BEGIN_NV04(chan, NvSubCopy, 0x0180, 1);
OUT_RING (chan, NvNotify0);
}
BEGIN_NV04(chan, NvSubCopy, 0x0000, 1);
OUT_RING (chan, handle);
BEGIN_NV04(chan, NvSubCopy, 0x0180, 1);
OUT_RING (chan, NvNotify0);
}
return ret;
@@ -915,8 +878,8 @@ nouveau_bo_mem_ctxdma(struct ttm_buffer_object *bo,
struct nouveau_channel *chan, struct ttm_mem_reg *mem)
{
if (mem->mem_type == TTM_PL_TT)
return chan->gart_handle;
return chan->vram_handle;
return NvDmaTT;
return NvDmaFB;
}
static int
@@ -972,8 +935,9 @@ nouveau_vma_getmap(struct nouveau_channel *chan, struct nouveau_bo *nvbo,
struct nouveau_mem *node = mem->mm_node;
int ret;
ret = nouveau_vm_get(chan->vm, mem->num_pages << PAGE_SHIFT,
node->page_shift, NV_MEM_ACCESS_RO, vma);
ret = nouveau_vm_get(nv_client(chan->cli)->vm, mem->num_pages <<
PAGE_SHIFT, node->page_shift,
NV_MEM_ACCESS_RW, vma);
if (ret)
return ret;
@@ -990,19 +954,19 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr,
bool no_wait_reserve, bool no_wait_gpu,
struct ttm_mem_reg *new_mem)
{
struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev);
struct nouveau_channel *chan = chan = dev_priv->channel;
struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
struct nouveau_channel *chan = chan = drm->channel;
struct nouveau_bo *nvbo = nouveau_bo(bo);
struct ttm_mem_reg *old_mem = &bo->mem;
int ret;
mutex_lock_nested(&chan->mutex, NOUVEAU_KCHANNEL_MUTEX);
mutex_lock(&chan->cli->mutex);
/* create temporary vmas for the transfer and attach them to the
* old nouveau_mem node, these will get cleaned up after ttm has
* destroyed the ttm_mem_reg
*/
if (dev_priv->card_type >= NV_50) {
if (nv_device(drm->device)->card_type >= NV_50) {
struct nouveau_mem *node = old_mem->mm_node;
ret = nouveau_vma_getmap(chan, nvbo, old_mem, &node->vma[0]);
@@ -1014,7 +978,7 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr,
goto out;
}
ret = dev_priv->ttm.move(chan, bo, &bo->mem, new_mem);
ret = drm->ttm.move(chan, bo, &bo->mem, new_mem);
if (ret == 0) {
ret = nouveau_bo_move_accel_cleanup(chan, nvbo, evict,
no_wait_reserve,
@@ -1022,14 +986,15 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr,
}
out:
mutex_unlock(&chan->mutex);
mutex_unlock(&chan->cli->mutex);
return ret;
}
void
nouveau_bo_move_init(struct nouveau_channel *chan)
{
struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
struct nouveau_cli *cli = chan->cli;
struct nouveau_drm *drm = chan->drm;
static const struct {
const char *name;
int engine;
@@ -1054,19 +1019,26 @@ nouveau_bo_move_init(struct nouveau_channel *chan)
int ret;
do {
struct nouveau_object *object;
u32 handle = (mthd->engine << 16) | mthd->oclass;
ret = nouveau_gpuobj_gr_new(chan, handle, mthd->oclass);
ret = nouveau_object_new(nv_object(cli), chan->handle, handle,
mthd->oclass, NULL, 0, &object);
if (ret == 0) {
ret = mthd->init(chan, handle);
if (ret == 0) {
dev_priv->ttm.move = mthd->exec;
name = mthd->name;
break;
if (ret) {
nouveau_object_del(nv_object(cli),
chan->handle, handle);
continue;
}
drm->ttm.move = mthd->exec;
name = mthd->name;
break;
}
} while ((++mthd)->exec);
NV_INFO(chan->dev, "MM: using %s for buffer copies\n", name);
NV_INFO(drm, "MM: using %s for buffer copies\n", name);
}
static int
@@ -1151,7 +1123,7 @@ nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem)
nouveau_vm_map(vma, new_mem->mm_node);
} else
if (new_mem && new_mem->mem_type == TTM_PL_TT &&
nvbo->page_shift == nvvm_spg_shift(vma->vm)) {
nvbo->page_shift == vma->vm->vmm->spg_shift) {
if (((struct nouveau_mem *)new_mem->mm_node)->sg)
nouveau_vm_map_sg_table(vma, 0, new_mem->
num_pages << PAGE_SHIFT,
@@ -1168,10 +1140,10 @@ nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem)
static int
nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem,
struct nouveau_tile_reg **new_tile)
struct nouveau_drm_tile **new_tile)
{
struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev);
struct drm_device *dev = dev_priv->dev;
struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
struct drm_device *dev = drm->dev;
struct nouveau_bo *nvbo = nouveau_bo(bo);
u64 offset = new_mem->start << PAGE_SHIFT;
@@ -1179,7 +1151,7 @@ nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem,
if (new_mem->mem_type != TTM_PL_VRAM)
return 0;
if (dev_priv->card_type >= NV_10) {
if (nv_device(drm->device)->card_type >= NV_10) {
*new_tile = nv10_bo_set_tiling(dev, offset, new_mem->size,
nvbo->tile_mode,
nvbo->tile_flags);
@@ -1190,11 +1162,11 @@ nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem,
static void
nouveau_bo_vm_cleanup(struct ttm_buffer_object *bo,
struct nouveau_tile_reg *new_tile,
struct nouveau_tile_reg **old_tile)
struct nouveau_drm_tile *new_tile,
struct nouveau_drm_tile **old_tile)
{
struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev);
struct drm_device *dev = dev_priv->dev;
struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
struct drm_device *dev = drm->dev;
nv10_bo_put_tile_region(dev, *old_tile, bo->sync_obj);
*old_tile = new_tile;
@@ -1205,13 +1177,13 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr,
bool no_wait_reserve, bool no_wait_gpu,
struct ttm_mem_reg *new_mem)
{
struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev);
struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
struct nouveau_bo *nvbo = nouveau_bo(bo);
struct ttm_mem_reg *old_mem = &bo->mem;
struct nouveau_tile_reg *new_tile = NULL;
struct nouveau_drm_tile *new_tile = NULL;
int ret = 0;
if (dev_priv->card_type < NV_50) {
if (nv_device(drm->device)->card_type < NV_50) {
ret = nouveau_bo_vm_bind(bo, new_mem, &new_tile);
if (ret)
return ret;
@@ -1226,7 +1198,7 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr,
}
/* CPU copy if we have no accelerated method available */
if (!dev_priv->ttm.move) {
if (!drm->ttm.move) {
ret = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem);
goto out;
}
@@ -1246,7 +1218,7 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr,
ret = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem);
out:
if (dev_priv->card_type < NV_50) {
if (nv_device(drm->device)->card_type < NV_50) {
if (ret)
nouveau_bo_vm_cleanup(bo, NULL, &new_tile);
else
@@ -1266,8 +1238,8 @@ static int
nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
{
struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
struct drm_nouveau_private *dev_priv = nouveau_bdev(bdev);
struct drm_device *dev = dev_priv->dev;
struct nouveau_drm *drm = nouveau_bdev(bdev);
struct drm_device *dev = drm->dev;
int ret;
mem->bus.addr = NULL;
@@ -1283,9 +1255,9 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
return 0;
case TTM_PL_TT:
#if __OS_HAS_AGP
if (dev_priv->gart_info.type == NOUVEAU_GART_AGP) {
if (drm->agp.stat == ENABLED) {
mem->bus.offset = mem->start << PAGE_SHIFT;
mem->bus.base = dev_priv->gart_info.aper_base;
mem->bus.base = drm->agp.base;
mem->bus.is_iomem = true;
}
#endif
@@ -1294,10 +1266,11 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
mem->bus.offset = mem->start << PAGE_SHIFT;
mem->bus.base = pci_resource_start(dev->pdev, 1);
mem->bus.is_iomem = true;
if (dev_priv->card_type >= NV_50) {
if (nv_device(drm->device)->card_type >= NV_50) {
struct nouveau_bar *bar = nouveau_bar(drm->device);
struct nouveau_mem *node = mem->mm_node;
ret = nvbar_map(dev, node, NV_MEM_ACCESS_RW,
ret = bar->umap(bar, node, NV_MEM_ACCESS_RW,
&node->bar_vma);
if (ret)
return ret;
@@ -1314,40 +1287,40 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
static void
nouveau_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
{
struct drm_nouveau_private *dev_priv = nouveau_bdev(bdev);
struct nouveau_drm *drm = nouveau_bdev(bdev);
struct nouveau_bar *bar = nouveau_bar(drm->device);
struct nouveau_mem *node = mem->mm_node;
if (mem->mem_type != TTM_PL_VRAM)
return;
if (!node->bar_vma.node)
return;
nvbar_unmap(dev_priv->dev, &node->bar_vma);
bar->unmap(bar, &node->bar_vma);
}
static int
nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
{
struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev);
struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
struct nouveau_bo *nvbo = nouveau_bo(bo);
struct nouveau_device *device = nv_device(drm->device);
u32 mappable = pci_resource_len(device->pdev, 1) >> PAGE_SHIFT;
/* as long as the bo isn't in vram, and isn't tiled, we've got
* nothing to do here.
*/
if (bo->mem.mem_type != TTM_PL_VRAM) {
if (dev_priv->card_type < NV_50 ||
if (nv_device(drm->device)->card_type < NV_50 ||
!nouveau_bo_tile_layout(nvbo))
return 0;
}
/* make sure bo is in mappable vram */
if (bo->mem.start + bo->mem.num_pages < dev_priv->fb_mappable_pages)
if (bo->mem.start + bo->mem.num_pages < mappable)
return 0;
nvbo->placement.fpfn = 0;
nvbo->placement.lpfn = dev_priv->fb_mappable_pages;
nvbo->placement.lpfn = mappable;
nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_VRAM, 0);
return nouveau_bo_validate(nvbo, false, true, false);
}
@@ -1356,7 +1329,7 @@ static int
nouveau_ttm_tt_populate(struct ttm_tt *ttm)
{
struct ttm_dma_tt *ttm_dma = (void *)ttm;
struct drm_nouveau_private *dev_priv;
struct nouveau_drm *drm;
struct drm_device *dev;
unsigned i;
int r;
@@ -1373,11 +1346,11 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm)
return 0;
}
dev_priv = nouveau_bdev(ttm->bdev);
dev = dev_priv->dev;
drm = nouveau_bdev(ttm->bdev);
dev = drm->dev;
#if __OS_HAS_AGP
if (dev_priv->gart_info.type == NOUVEAU_GART_AGP) {
if (drm->agp.stat == ENABLED) {
return ttm_agp_tt_populate(ttm);
}
#endif
@@ -1414,7 +1387,7 @@ static void
nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
{
struct ttm_dma_tt *ttm_dma = (void *)ttm;
struct drm_nouveau_private *dev_priv;
struct nouveau_drm *drm;
struct drm_device *dev;
unsigned i;
bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
@@ -1422,11 +1395,11 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
if (slave)
return;
dev_priv = nouveau_bdev(ttm->bdev);
dev = dev_priv->dev;
drm = nouveau_bdev(ttm->bdev);
dev = drm->dev;
#if __OS_HAS_AGP
if (dev_priv->gart_info.type == NOUVEAU_GART_AGP) {
if (drm->agp.stat == ENABLED) {
ttm_agp_tt_unpopulate(ttm);
return;
}
+13 -6
View File
@@ -2,13 +2,9 @@
#define __NOUVEAU_BO_H__
struct nouveau_channel;
struct nouveau_fence;
struct nouveau_vma;
struct nouveau_tile_reg {
bool used;
struct nouveau_fence *fence;
};
struct nouveau_bo {
struct ttm_buffer_object bo;
struct ttm_placement placement;
@@ -29,7 +25,7 @@ struct nouveau_bo {
u32 tile_mode;
u32 tile_flags;
struct nouveau_tile_reg *tile;
struct nouveau_drm_tile *tile;
struct drm_gem_object *gem;
int pin_refcnt;
@@ -89,4 +85,15 @@ int nouveau_bo_vma_add(struct nouveau_bo *, struct nouveau_vm *,
struct nouveau_vma *);
void nouveau_bo_vma_del(struct nouveau_bo *, struct nouveau_vma *);
/* TODO: submit equivalent to TTM generic API upstream? */
static inline void __iomem *
nvbo_kmap_obj_iovirtual(struct nouveau_bo *nvbo)
{
bool is_iomem;
void __iomem *ioptr = (void __force __iomem *)ttm_kmap_obj_virtual(
&nvbo->kmap, &is_iomem);
WARN_ON_ONCE(ioptr && !is_iomem);
return ioptr;
}
#endif
+387
View File
@@ -0,0 +1,387 @@
/*
* 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/client.h>
#include <core/device.h>
#include <core/class.h>
#include <subdev/fb.h>
#include <subdev/vm.h>
#include <subdev/instmem.h>
#include <engine/software.h>
#include "nouveau_drm.h"
#include "nouveau_dma.h"
#include "nouveau_bo.h"
#include "nouveau_chan.h"
#include "nouveau_fence.h"
#include "nouveau_abi16.h"
MODULE_PARM_DESC(vram_pushbuf, "Create DMA push buffers in VRAM");
static int nouveau_vram_pushbuf;
module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400);
int
nouveau_channel_idle(struct nouveau_channel *chan)
{
struct nouveau_drm *drm = chan->drm;
struct nouveau_fence *fence = NULL;
int ret;
ret = nouveau_fence_new(chan, &fence);
if (!ret) {
ret = nouveau_fence_wait(fence, false, false);
nouveau_fence_unref(&fence);
}
if (ret)
NV_ERROR(drm, "failed to idle channel 0x%08x\n", chan->handle);
return ret;
}
void
nouveau_channel_del(struct nouveau_channel **pchan)
{
struct nouveau_channel *chan = *pchan;
if (chan) {
struct nouveau_object *client = nv_object(chan->cli);
if (chan->fence) {
nouveau_channel_idle(chan);
nouveau_fence(chan->drm)->context_del(chan);
}
nouveau_object_del(client, NVDRM_DEVICE, chan->handle);
nouveau_object_del(client, NVDRM_DEVICE, chan->push.handle);
nouveau_bo_vma_del(chan->push.buffer, &chan->push.vma);
nouveau_bo_unmap(chan->push.buffer);
nouveau_bo_ref(NULL, &chan->push.buffer);
kfree(chan);
}
*pchan = NULL;
}
static int
nouveau_channel_prep(struct nouveau_drm *drm, struct nouveau_cli *cli,
u32 parent, u32 handle, u32 size,
struct nouveau_channel **pchan)
{
struct nouveau_device *device = nv_device(drm->device);
struct nouveau_instmem *imem = nouveau_instmem(device);
struct nouveau_vmmgr *vmm = nouveau_vmmgr(device);
struct nouveau_fb *pfb = nouveau_fb(device);
struct nouveau_client *client = &cli->base;
struct nv_dma_class args = {};
struct nouveau_channel *chan;
struct nouveau_object *push;
u32 target;
int ret;
chan = *pchan = kzalloc(sizeof(*chan), GFP_KERNEL);
if (!chan)
return -ENOMEM;
chan->cli = cli;
chan->drm = drm;
chan->handle = handle;
/* allocate memory for dma push buffer */
target = TTM_PL_FLAG_TT;
if (nouveau_vram_pushbuf)
target = TTM_PL_FLAG_VRAM;
ret = nouveau_bo_new(drm->dev, size, 0, target, 0, 0, NULL,
&chan->push.buffer);
if (ret == 0) {
ret = nouveau_bo_pin(chan->push.buffer, target);
if (ret == 0)
ret = nouveau_bo_map(chan->push.buffer);
}
if (ret) {
nouveau_channel_del(pchan);
return ret;
}
/* create dma object covering the *entire* memory space that the
* pushbuf lives in, this is because the GEM code requires that
* we be able to call out to other (indirect) push buffers
*/
chan->push.vma.offset = chan->push.buffer->bo.offset;
chan->push.handle = NVDRM_PUSH | (handle & 0xffff);
if (device->card_type >= NV_50) {
ret = nouveau_bo_vma_add(chan->push.buffer, client->vm,
&chan->push.vma);
if (ret) {
nouveau_channel_del(pchan);
return ret;
}
args.flags = NV_DMA_TARGET_VM | NV_DMA_ACCESS_VM;
args.start = 0;
args.limit = client->vm->vmm->limit - 1;
} else
if (chan->push.buffer->bo.mem.mem_type == TTM_PL_VRAM) {
u64 limit = pfb->ram.size - imem->reserved - 1;
if (device->card_type == NV_04) {
/* nv04 vram pushbuf hack, retarget to its location in
* the framebuffer bar rather than direct vram access..
* nfi why this exists, it came from the -nv ddx.
*/
args.flags = NV_DMA_TARGET_PCI | NV_DMA_ACCESS_RDWR;
args.start = pci_resource_start(device->pdev, 1);
args.limit = args.start + limit;
} else {
args.flags = NV_DMA_TARGET_VRAM | NV_DMA_ACCESS_RDWR;
args.start = 0;
args.limit = limit;
}
} else {
if (chan->drm->agp.stat == ENABLED) {
args.flags = NV_DMA_TARGET_AGP | NV_DMA_ACCESS_RDWR;
args.start = chan->drm->agp.base;
args.limit = chan->drm->agp.base +
chan->drm->agp.size - 1;
} else {
args.flags = NV_DMA_TARGET_VM | NV_DMA_ACCESS_RDWR;
args.start = 0;
args.limit = vmm->limit - 1;
}
}
ret = nouveau_object_new(nv_object(chan->cli), parent,
chan->push.handle, 0x0002,
&args, sizeof(args), &push);
if (ret) {
nouveau_channel_del(pchan);
return ret;
}
return 0;
}
int
nouveau_channel_ind(struct nouveau_drm *drm, struct nouveau_cli *cli,
u32 parent, u32 handle, struct nouveau_channel **pchan)
{
static const u16 oclasses[] = { 0xa06f, 0x906f, 0x826f, 0x506f, 0 };
const u16 *oclass = oclasses;
struct nv_channel_ind_class args;
struct nouveau_channel *chan;
int ret;
/* allocate dma push buffer */
ret = nouveau_channel_prep(drm, cli, parent, handle, 0x12000, &chan);
*pchan = chan;
if (ret)
return ret;
/* create channel object */
args.pushbuf = chan->push.handle;
args.ioffset = 0x10000 + chan->push.vma.offset;
args.ilength = 0x02000;
do {
ret = nouveau_object_new(nv_object(cli), parent, handle,
*oclass++, &args, sizeof(args),
&chan->object);
if (ret == 0)
return ret;
} while (*oclass);
nouveau_channel_del(pchan);
return ret;
}
static int
nouveau_channel_dma(struct nouveau_drm *drm, struct nouveau_cli *cli,
u32 parent, u32 handle, struct nouveau_channel **pchan)
{
static const u16 oclasses[] = { 0x006e, 0 };
const u16 *oclass = oclasses;
struct nv_channel_dma_class args;
struct nouveau_channel *chan;
int ret;
/* allocate dma push buffer */
ret = nouveau_channel_prep(drm, cli, parent, handle, 0x10000, &chan);
*pchan = chan;
if (ret)
return ret;
/* create channel object */
args.pushbuf = chan->push.handle;
args.offset = chan->push.vma.offset;
do {
ret = nouveau_object_new(nv_object(cli), parent, handle,
*oclass++, &args, sizeof(args),
&chan->object);
if (ret == 0)
return ret;
} while (ret && *oclass);
nouveau_channel_del(pchan);
return ret;
}
static int
nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
{
struct nouveau_client *client = nv_client(chan->cli);
struct nouveau_device *device = nv_device(chan->drm->device);
struct nouveau_instmem *imem = nouveau_instmem(device);
struct nouveau_vmmgr *vmm = nouveau_vmmgr(device);
struct nouveau_fb *pfb = nouveau_fb(device);
struct nouveau_software_chan *swch;
struct nouveau_object *object;
struct nv_dma_class args;
int ret, i;
chan->vram = vram;
chan->gart = gart;
/* allocate dma objects to cover all allowed vram, and gart */
if (device->card_type < NV_C0) {
if (device->card_type >= NV_50) {
args.flags = NV_DMA_TARGET_VM | NV_DMA_ACCESS_VM;
args.start = 0;
args.limit = client->vm->vmm->limit - 1;
} else {
args.flags = NV_DMA_TARGET_VRAM | NV_DMA_ACCESS_RDWR;
args.start = 0;
args.limit = pfb->ram.size - imem->reserved - 1;
}
ret = nouveau_object_new(nv_object(client), chan->handle, vram,
0x003d, &args, sizeof(args), &object);
if (ret)
return ret;
if (device->card_type >= NV_50) {
args.flags = NV_DMA_TARGET_VM | NV_DMA_ACCESS_VM;
args.start = 0;
args.limit = client->vm->vmm->limit - 1;
} else
if (chan->drm->agp.stat == ENABLED) {
args.flags = NV_DMA_TARGET_AGP | NV_DMA_ACCESS_RDWR;
args.start = chan->drm->agp.base;
args.limit = chan->drm->agp.base +
chan->drm->agp.size - 1;
} else {
args.flags = NV_DMA_TARGET_VM | NV_DMA_ACCESS_RDWR;
args.start = 0;
args.limit = vmm->limit - 1;
}
ret = nouveau_object_new(nv_object(client), chan->handle, gart,
0x003d, &args, sizeof(args), &object);
if (ret)
return ret;
}
/* initialise dma tracking parameters */
switch (nv_hclass(chan->object) & 0xffff) {
case 0x006e:
chan->user_put = 0x40;
chan->user_get = 0x44;
chan->dma.max = (0x10000 / 4) - 2;
break;
default:
chan->user_put = 0x40;
chan->user_get = 0x44;
chan->user_get_hi = 0x60;
chan->dma.ib_base = 0x10000 / 4;
chan->dma.ib_max = (0x02000 / 8) - 1;
chan->dma.ib_put = 0;
chan->dma.ib_free = chan->dma.ib_max - chan->dma.ib_put;
chan->dma.max = chan->dma.ib_base;
break;
}
chan->dma.put = 0;
chan->dma.cur = chan->dma.put;
chan->dma.free = chan->dma.max - chan->dma.cur;
ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS);
if (ret)
return ret;
for (i = 0; i < NOUVEAU_DMA_SKIPS; i++)
OUT_RING(chan, 0x00000000);
/* allocate software object class (used for fences on <= nv05, and
* to signal flip completion), bind it to a subchannel.
*/
ret = nouveau_object_new(nv_object(client), chan->handle,
NvSw, nouveau_abi16_swclass(chan->drm),
NULL, 0, &object);
if (ret)
return ret;
swch = (void *)object->parent;
swch->flip = nouveau_flip_complete;
swch->flip_data = chan;
if (device->card_type < NV_C0) {
ret = RING_SPACE(chan, 2);
if (ret)
return ret;
BEGIN_NV04(chan, NvSubSw, 0x0000, 1);
OUT_RING (chan, NvSw);
FIRE_RING (chan);
}
/* initialise synchronisation */
return nouveau_fence(chan->drm)->context_new(chan);
}
int
nouveau_channel_new(struct nouveau_drm *drm, struct nouveau_cli *cli,
u32 parent, u32 handle, u32 vram, u32 gart,
struct nouveau_channel **pchan)
{
int ret;
ret = nouveau_channel_ind(drm, cli, parent, handle, pchan);
if (ret) {
NV_DEBUG(drm, "ib channel create, %d\n", ret);
ret = nouveau_channel_dma(drm, cli, parent, handle, pchan);
if (ret) {
NV_DEBUG(drm, "dma channel create, %d\n", ret);
return ret;
}
}
ret = nouveau_channel_init(*pchan, vram, gart);
if (ret) {
NV_ERROR(drm, "channel failed to initialise, %d\n", ret);
nouveau_channel_del(pchan);
return ret;
}
return 0;
}
+47
View File
@@ -0,0 +1,47 @@
#ifndef __NOUVEAU_CHAN_H__
#define __NOUVEAU_CHAN_H__
struct nouveau_cli;
struct nouveau_channel {
struct nouveau_cli *cli;
struct nouveau_drm *drm;
u32 handle;
u32 vram;
u32 gart;
struct {
struct nouveau_bo *buffer;
struct nouveau_vma vma;
u32 handle;
} push;
/* TODO: this will be reworked in the near future */
bool accel_done;
void *fence;
struct {
int max;
int free;
int cur;
int put;
int ib_base;
int ib_max;
int ib_free;
int ib_put;
} dma;
u32 user_get_hi;
u32 user_get;
u32 user_put;
struct nouveau_object *object;
};
int nouveau_channel_new(struct nouveau_drm *, struct nouveau_cli *,
u32 parent, u32 handle, u32 vram, u32 gart,
struct nouveau_channel **);
void nouveau_channel_del(struct nouveau_channel **);
int nouveau_channel_idle(struct nouveau_channel *);
#endif
-408
View File
@@ -1,408 +0,0 @@
/*
* Copyright 2005-2006 Stephane Marchesin
* All Rights Reserved.
*
* 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 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
* PRECISION INSIGHT 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.
*/
#include "drmP.h"
#include "drm.h"
#include "nouveau_drv.h"
#include <nouveau_drm.h>
#include "nouveau_dma.h"
#include <engine/fifo.h>
#include <core/ramht.h>
#include "nouveau_fence.h"
#include "nouveau_software.h"
MODULE_PARM_DESC(vram_pushbuf, "Force DMA push buffers to be in VRAM");
int nouveau_vram_pushbuf;
module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400);
static int
nouveau_channel_pushbuf_init(struct nouveau_channel *chan)
{
u32 mem = nouveau_vram_pushbuf ? TTM_PL_FLAG_VRAM : TTM_PL_FLAG_TT;
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
int ret;
/* allocate buffer object */
ret = nouveau_bo_new(dev, 65536, 0, mem, 0, 0, NULL, &chan->pushbuf_bo);
if (ret)
goto out;
ret = nouveau_bo_pin(chan->pushbuf_bo, mem);
if (ret)
goto out;
ret = nouveau_bo_map(chan->pushbuf_bo);
if (ret)
goto out;
/* create DMA object covering the entire memtype where the push
* buffer resides, userspace can submit its own push buffers from
* anywhere within the same memtype.
*/
chan->pushbuf_base = chan->pushbuf_bo->bo.offset;
if (dev_priv->card_type >= NV_50) {
ret = nouveau_bo_vma_add(chan->pushbuf_bo, chan->vm,
&chan->pushbuf_vma);
if (ret)
goto out;
if (dev_priv->card_type < NV_C0) {
ret = nouveau_gpuobj_dma_new(chan,
NV_CLASS_DMA_IN_MEMORY, 0,
(1ULL << 40),
NV_MEM_ACCESS_RO,
NV_MEM_TARGET_VM,
&chan->pushbuf);
}
chan->pushbuf_base = chan->pushbuf_vma.offset;
} else
if (chan->pushbuf_bo->bo.mem.mem_type == TTM_PL_TT) {
ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0,
dev_priv->gart_info.aper_size,
NV_MEM_ACCESS_RO,
NV_MEM_TARGET_GART,
&chan->pushbuf);
} else
if (dev_priv->card_type != NV_04) {
ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0,
dev_priv->fb_available_size,
NV_MEM_ACCESS_RO,
NV_MEM_TARGET_VRAM,
&chan->pushbuf);
} else {
/* NV04 cmdbuf hack, from original ddx.. not sure of it's
* exact reason for existing :) PCI access to cmdbuf in
* VRAM.
*/
ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
pci_resource_start(dev->pdev, 1),
dev_priv->fb_available_size,
NV_MEM_ACCESS_RO,
NV_MEM_TARGET_PCI,
&chan->pushbuf);
}
out:
if (ret) {
NV_ERROR(dev, "error initialising pushbuf: %d\n", ret);
nouveau_bo_vma_del(chan->pushbuf_bo, &chan->pushbuf_vma);
nouveau_gpuobj_ref(NULL, &chan->pushbuf);
if (chan->pushbuf_bo) {
nouveau_bo_unmap(chan->pushbuf_bo);
nouveau_bo_ref(NULL, &chan->pushbuf_bo);
}
}
return 0;
}
/* allocates and initializes a fifo for user space consumption */
int
nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret,
struct drm_file *file_priv,
uint32_t vram_handle, uint32_t gart_handle)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
struct nouveau_fence_priv *fence = dev_priv->fence.func;
struct nouveau_fpriv *fpriv = nouveau_fpriv(file_priv);
struct nouveau_channel *chan;
unsigned long flags;
int ret, i;
/* allocate and lock channel structure */
chan = kzalloc(sizeof(*chan), GFP_KERNEL);
if (!chan)
return -ENOMEM;
chan->dev = dev;
chan->file_priv = file_priv;
chan->vram_handle = vram_handle;
chan->gart_handle = gart_handle;
kref_init(&chan->ref);
atomic_set(&chan->users, 1);
mutex_init(&chan->mutex);
mutex_lock(&chan->mutex);
/* allocate hw channel id */
spin_lock_irqsave(&dev_priv->channels.lock, flags);
for (chan->id = 0; chan->id < pfifo->channels; chan->id++) {
if ( dev_priv->card_type == NV_50 && chan->id == 0)
continue;
if (!dev_priv->channels.ptr[chan->id]) {
nouveau_channel_ref(chan, &dev_priv->channels.ptr[chan->id]);
break;
}
}
spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
if (chan->id == pfifo->channels) {
mutex_unlock(&chan->mutex);
kfree(chan);
return -ENODEV;
}
NV_DEBUG(dev, "initialising channel %d\n", chan->id);
/* setup channel's memory and vm */
ret = nouveau_gpuobj_channel_init(chan, vram_handle, gart_handle);
if (ret) {
NV_ERROR(dev, "gpuobj %d\n", ret);
nouveau_channel_put(&chan);
return ret;
}
/* Allocate space for per-channel fixed notifier memory */
ret = nouveau_notifier_init_channel(chan);
if (ret) {
NV_ERROR(dev, "ntfy %d\n", ret);
nouveau_channel_put(&chan);
return ret;
}
/* Allocate DMA push buffer */
ret = nouveau_channel_pushbuf_init(chan);
if (ret) {
NV_ERROR(dev, "pushbuf %d\n", ret);
nouveau_channel_put(&chan);
return ret;
}
nouveau_dma_init(chan);
chan->user_put = 0x40;
chan->user_get = 0x44;
if (dev_priv->card_type >= NV_50)
chan->user_get_hi = 0x60;
/* create fifo context */
ret = pfifo->base.context_new(chan, NVOBJ_ENGINE_FIFO);
if (ret) {
nouveau_channel_put(&chan);
return ret;
}
/* Insert NOPs for NOUVEAU_DMA_SKIPS */
ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS);
if (ret) {
nouveau_channel_put(&chan);
return ret;
}
for (i = 0; i < NOUVEAU_DMA_SKIPS; i++)
OUT_RING (chan, 0x00000000);
ret = nouveau_gpuobj_gr_new(chan, NvSw, nouveau_software_class(dev));
if (ret) {
nouveau_channel_put(&chan);
return ret;
}
if (dev_priv->card_type < NV_C0) {
ret = RING_SPACE(chan, 2);
if (ret) {
nouveau_channel_put(&chan);
return ret;
}
BEGIN_NV04(chan, NvSubSw, NV01_SUBCHAN_OBJECT, 1);
OUT_RING (chan, NvSw);
FIRE_RING (chan);
}
FIRE_RING(chan);
ret = fence->context_new(chan);
if (ret) {
nouveau_channel_put(&chan);
return ret;
}
nouveau_debugfs_channel_init(chan);
NV_DEBUG(dev, "channel %d initialised\n", chan->id);
if (fpriv) {
spin_lock(&fpriv->lock);
list_add(&chan->list, &fpriv->channels);
spin_unlock(&fpriv->lock);
}
*chan_ret = chan;
return 0;
}
struct nouveau_channel *
nouveau_channel_get_unlocked(struct nouveau_channel *ref)
{
struct nouveau_channel *chan = NULL;
if (likely(ref && atomic_inc_not_zero(&ref->users)))
nouveau_channel_ref(ref, &chan);
return chan;
}
struct nouveau_channel *
nouveau_channel_get(struct drm_file *file_priv, int id)
{
struct nouveau_fpriv *fpriv = nouveau_fpriv(file_priv);
struct nouveau_channel *chan;
spin_lock(&fpriv->lock);
list_for_each_entry(chan, &fpriv->channels, list) {
if (chan->id == id) {
chan = nouveau_channel_get_unlocked(chan);
spin_unlock(&fpriv->lock);
mutex_lock(&chan->mutex);
return chan;
}
}
spin_unlock(&fpriv->lock);
return ERR_PTR(-EINVAL);
}
void
nouveau_channel_put_unlocked(struct nouveau_channel **pchan)
{
struct nouveau_channel *chan = *pchan;
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_fence_priv *fence = dev_priv->fence.func;
unsigned long flags;
int i;
/* decrement the refcount, and we're done if there's still refs */
if (likely(!atomic_dec_and_test(&chan->users))) {
nouveau_channel_ref(NULL, pchan);
return;
}
/* no one wants the channel anymore */
NV_DEBUG(dev, "freeing channel %d\n", chan->id);
nouveau_debugfs_channel_fini(chan);
/* give it chance to idle */
nouveau_channel_idle(chan);
/* destroy the engine specific contexts */
for (i = NVOBJ_ENGINE_NR - 1; i >= 0; i--) {
if (chan->engctx[i])
dev_priv->eng[i]->context_del(chan, i);
}
if (chan->fence)
fence->context_del(chan);
/* aside from its resources, the channel should now be dead,
* remove it from the channel list
*/
spin_lock_irqsave(&dev_priv->channels.lock, flags);
nouveau_channel_ref(NULL, &dev_priv->channels.ptr[chan->id]);
spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
/* destroy any resources the channel owned */
nouveau_gpuobj_ref(NULL, &chan->pushbuf);
if (chan->pushbuf_bo) {
nouveau_bo_vma_del(chan->pushbuf_bo, &chan->pushbuf_vma);
nouveau_bo_unmap(chan->pushbuf_bo);
nouveau_bo_unpin(chan->pushbuf_bo);
nouveau_bo_ref(NULL, &chan->pushbuf_bo);
}
nouveau_ramht_ref(NULL, &chan->ramht, chan);
nouveau_notifier_takedown_channel(chan);
nouveau_gpuobj_channel_takedown(chan);
nouveau_channel_ref(NULL, pchan);
}
void
nouveau_channel_put(struct nouveau_channel **pchan)
{
mutex_unlock(&(*pchan)->mutex);
nouveau_channel_put_unlocked(pchan);
}
static void
nouveau_channel_del(struct kref *ref)
{
struct nouveau_channel *chan =
container_of(ref, struct nouveau_channel, ref);
kfree(chan);
}
void
nouveau_channel_ref(struct nouveau_channel *chan,
struct nouveau_channel **pchan)
{
if (chan)
kref_get(&chan->ref);
if (*pchan)
kref_put(&(*pchan)->ref, nouveau_channel_del);
*pchan = chan;
}
int
nouveau_channel_idle(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
struct nouveau_fence *fence = NULL;
int ret;
ret = nouveau_fence_new(chan, &fence);
if (!ret) {
ret = nouveau_fence_wait(fence, false, false);
nouveau_fence_unref(&fence);
}
if (ret)
NV_ERROR(dev, "Failed to idle channel %d.\n", chan->id);
return ret;
}
/* cleans up all the fifos from file_priv */
void
nouveau_channel_cleanup(struct drm_device *dev, struct drm_file *file_priv)
{
struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
struct nouveau_channel *chan;
int i;
if (!pfifo)
return;
NV_DEBUG(dev, "clearing FIFO enables from file_priv\n");
for (i = 0; i < pfifo->channels; i++) {
chan = nouveau_channel_get(file_priv, i);
if (IS_ERR(chan))
continue;
list_del(&chan->list);
atomic_dec(&chan->users);
nouveau_channel_put(&chan);
}
}
+26 -2
View File
@@ -1,4 +1,5 @@
#include "nouveau_drm.h"
#include "nouveau_chan.h"
#include "nouveau_compat.h"
#include <subdev/bios.h>
@@ -14,8 +15,6 @@
#include <subdev/bar.h>
#include <subdev/vm.h>
void *nouveau_newpriv(struct drm_device *);
int
nvdrm_gart_init(struct drm_device *dev, u64 *base, u64 *size)
{
@@ -583,3 +582,28 @@ nvvm_lpg_shift(struct nouveau_vm *vm)
{
return vm->vmm->lpg_shift;
}
u64 nvgpuobj_addr(struct nouveau_object *object)
{
return nv_gpuobj(object)->addr;
}
struct drm_device *
nouveau_drv(void *ptr)
{
struct nouveau_drm *drm = ptr;
return drm->dev;
}
struct nouveau_channel *
nvdrm_channel(struct drm_device *dev)
{
struct nouveau_drm *drm = nouveau_newpriv(dev);
return drm->channel;
}
struct mutex *
nvchan_mutex(struct nouveau_channel *chan)
{
return &chan->cli->mutex;
}

Some files were not shown because too many files have changed in this diff Show More