diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2012-07-20 08:17:34 +1000 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2012-10-03 13:12:56 +1000 |
commit | ebb945a94bba2ce8dff7b0942ff2b3f2a52a0a69 (patch) | |
tree | 07cad59be501458e6ae1304b7c0352e322ac3387 /drivers/gpu/drm/nouveau/core/engine/graph/nve0.c | |
parent | ac1499d9573f4aadd1d2beac11fe23af8ce90c24 (diff) | |
download | op-kernel-dev-ebb945a94bba2ce8dff7b0942ff2b3f2a52a0a69.zip op-kernel-dev-ebb945a94bba2ce8dff7b0942ff2b3f2a52a0a69.tar.gz |
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>
Diffstat (limited to 'drivers/gpu/drm/nouveau/core/engine/graph/nve0.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/graph/nve0.c | 843 |
1 files changed, 362 insertions, 481 deletions
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c index a3a4ee7..c79748a 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c @@ -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,116 +22,290 @@ * 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" +/******************************************************************************* + * 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_unit(struct drm_device *dev, u32 base) +nve0_graph_ctxctl_isr(struct nvc0_graph_priv *priv) { - 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)); + u32 ustat = nv_rd32(priv, 0x409c18); + + if (ustat & 0x00000001) + nv_error(priv, "CTXCTRL ucode error\n"); + if (ustat & 0x00080000) + nv_error(priv, "CTXCTRL watchdog timeout\n"); + if (ustat & ~0x00080001) + nv_error(priv, "CTXCTRL 0x%08x\n", ustat); + + nvc0_graph_ctxctl_debug(priv); + nv_wr32(priv, 0x409c20, ustat); } static void -nve0_graph_ctxctl_debug(struct drm_device *dev) +nve0_graph_trap_isr(struct nvc0_graph_priv *priv, u64 inst) { - u32 gpcnr = nv_rd32(dev, 0x409604) & 0xffff; - u32 gpc; + u32 trap = nv_rd32(priv, 0x400108); + int rop; + + if (trap & 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; + } - nve0_graph_ctxctl_debug_unit(dev, 0x409000); - for (gpc = 0; gpc < gpcnr; gpc++) - nve0_graph_ctxctl_debug_unit(dev, 0x502000 + (gpc * 0x8000)); + if (trap & 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(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(priv, 0x400108, 0x02000000); + trap &= ~0x02000000; + } + + if (trap) { + nv_error(priv, "TRAP ch 0x%010llx 0x%08x\n", inst, trap); + nv_wr32(priv, 0x400108, trap); + } } -static int -nve0_graph_object_new(struct nouveau_channel *chan, int engine, - u32 handle, u16 class) +static void +nve0_graph_intr(struct nouveau_subdev *subdev) { - return 0; + 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(priv, 0x400708); + u32 code = nv_rd32(priv, 0x400110); + u32 class = nv_rd32(priv, 0x404200 + (subc * 4)); + + if (stat & 0x00000010) { + 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", + inst, subc, class, mthd, data); + } + nouveau_engctx_handle_put(handle); + nv_wr32(priv, 0x400100, 0x00000010); + stat &= ~0x00000010; + } + + if (stat & 0x00000020) { + nv_error(priv, "ILLEGAL_CLASS ch 0x%010llx subc %d " + "class 0x%04x mthd 0x%04x data 0x%08x\n", + inst, subc, class, mthd, data); + nv_wr32(priv, 0x400100, 0x00000020); + stat &= ~0x00000020; + } + + if (stat & 0x00100000) { + nv_error(priv, "DATA_ERROR ["); + nouveau_enum_print(nv50_data_error_names, code); + printk("] ch 0x%010llx subc %d class 0x%04x " + "mthd 0x%04x data 0x%08x\n", + inst, subc, class, mthd, data); + nv_wr32(priv, 0x400100, 0x00100000); + stat &= ~0x00100000; + } + + if (stat & 0x00200000) { + nve0_graph_trap_isr(priv, inst); + nv_wr32(priv, 0x400100, 0x00200000); + stat &= ~0x00200000; + } + + if (stat & 0x00080000) { + nve0_graph_ctxctl_isr(priv); + nv_wr32(priv, 0x400100, 0x00080000); + stat &= ~0x00080000; + } + + if (stat) { + nv_error(priv, "unknown stat 0x%08x\n", stat); + nv_wr32(priv, 0x400100, stat); + } + + nv_wr32(priv, 0x400500, 0x00010001); } static int -nve0_graph_fini(struct drm_device *dev, int engine, bool suspend) +nve0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { + struct nvc0_graph_priv *priv; + int ret, i; + + ret = nouveau_graph_create(parent, engine, oclass, false, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + 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; + + 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(parent, NULL, 0x1000, 256, 0, &priv->unk4188b4); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 256, 0, &priv->unk4188b8); + if (ret) + 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(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 (nv_device(priv)->chipset) { + case 0xe4: + if (priv->tpc_total == 8) + priv->magic_not_rop_nr = 3; + else + if (priv->tpc_total == 7) + priv->magic_not_rop_nr = 1; + break; + case 0xe7: + priv->magic_not_rop_nr = 1; + break; + default: + break; + } + return 0; } static void -nve0_graph_init_obj418880(struct drm_device *dev) +nve0_graph_init_obj418880(struct nvc0_graph_priv *priv) { - 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); + nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000); + nv_wr32(priv, 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); + 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 drm_device *dev) +nve0_graph_init_regs(struct nvc0_graph_priv *priv) { - 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); + 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 drm_device *dev) +nve0_graph_init_units(struct nvc0_graph_priv *priv) { - 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); + 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 drm_device *dev) +nve0_graph_init_gpc_0(struct nvc0_graph_priv *priv) { - 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); + nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001); memset(data, 0x00, sizeof(data)); memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); @@ -144,164 +318,143 @@ nve0_graph_init_gpc_0(struct drm_device *dev) 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]); + 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]); for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - nv_wr32(dev, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 | + nv_wr32(priv, 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(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 | priv->tpc_total); + nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918); } - nv_wr32(dev, GPC_BCAST(0x1bd4), magicgpc918); - nv_wr32(dev, GPC_BCAST(0x08ac), nv_rd32(dev, 0x100800)); + 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 drm_device *dev) +nve0_graph_init_gpc_1(struct nvc0_graph_priv *priv) { - 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); + 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(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(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(dev, GPC_UNIT(gpc, 0x2c90), 0xffffffff); - nv_wr32(dev, GPC_UNIT(gpc, 0x2c94), 0xffffffff); + nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff); + nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff); } } static void -nve0_graph_init_rop(struct drm_device *dev) +nve0_graph_init_rop(struct nvc0_graph_priv *priv) { - 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]); + 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 drm_device *dev) +nve0_graph_init_ctxctl(struct nvc0_graph_priv *priv) { - 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); + 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(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"); + 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(dev, 0x409800); + priv->size = nv_rd32(priv, 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"); + 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(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"); + 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(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"); + 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(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"); + 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(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"); + 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(dev, 0x409614, 0x00000070); - nv_wr32(dev, 0x409614, 0x00000770); - nv_wr32(dev, 0x40802c, 0x00000001); + nv_wr32(priv, 0x409614, 0x00000070); + nv_wr32(priv, 0x409614, 0x00000770); + nv_wr32(priv, 0x40802c, 0x00000001); if (priv->data == NULL) { - int ret = nve0_grctx_generate(dev); + int ret = nve0_grctx_generate(priv); if (ret) { - NV_ERROR(dev, "PGRAPH: failed to construct context\n"); + nv_error(priv, "failed to construct context\n"); return ret; } @@ -312,325 +465,53 @@ nve0_graph_init_ctxctl(struct drm_device *dev) } static int -nve0_graph_init(struct drm_device *dev, int engine) +nve0_graph_init(struct nouveau_object *object) { + struct nvc0_graph_priv *priv = (void *)object; 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); - - if (ustat & 0x00000001) - NV_INFO(dev, "PGRAPH: CTXCTRL ucode error\n"); - if (ustat & 0x00080000) - NV_INFO(dev, "PGRAPH: CTXCTRL watchdog timeout\n"); - if (ustat & ~0x00080001) - NV_INFO(dev, "PGRAPH: CTXCTRL 0x%08x\n", ustat); - - nve0_graph_ctxctl_debug(dev); - nv_wr32(dev, 0x409c20, ustat); -} - -static void -nve0_graph_trap_isr(struct drm_device *dev, int chid) -{ - struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR); - u32 trap = nv_rd32(dev, 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); - 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); - 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); - } - nv_wr32(dev, 0x400108, 0x02000000); - trap &= ~0x02000000; - } - - if (trap) { - NV_INFO(dev, "PGRAPH: TRAP ch %d 0x%08x\n", chid, trap); - nv_wr32(dev, 0x400108, trap); - } -} - -static void -nve0_graph_isr(struct drm_device *dev) -{ - 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); - 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)); - - if (stat & 0x00000010) { - if (nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data)) { - NV_INFO(dev, "PGRAPH: ILLEGAL_MTHD ch %d [0x%010llx] " - "subc %d class 0x%04x mthd 0x%04x " - "data 0x%08x\n", - chid, inst, subc, class, mthd, data); - } - nv_wr32(dev, 0x400100, 0x00000010); - stat &= ~0x00000010; - } - - if (stat & 0x00000020) { - NV_INFO(dev, "PGRAPH: ILLEGAL_CLASS ch %d [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); - stat &= ~0x00000020; - } - - if (stat & 0x00100000) { - NV_INFO(dev, "PGRAPH: DATA_ERROR ["); - nouveau_enum_print(nv50_data_error_names, code); - printk("] ch %d [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); - stat &= ~0x00100000; - } - - if (stat & 0x00200000) { - nve0_graph_trap_isr(dev, chid); - nv_wr32(dev, 0x400100, 0x00200000); - stat &= ~0x00200000; - } - - if (stat & 0x00080000) { - nve0_graph_ctxctl_isr(dev); - nv_wr32(dev, 0x400100, 0x00080000); - stat &= ~0x00080000; - } - - if (stat) { - NV_INFO(dev, "PGRAPH: unknown stat 0x%08x\n", stat); - nv_wr32(dev, 0x400100, stat); - } - - nv_wr32(dev, 0x400500, 0x00010001); -} - -static int -nve0_graph_create_fw(struct drm_device *dev, const char *fwname, - struct nvc0_graph_fuc *fuc) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - const struct firmware *fw; - char f[32]; - int ret; - - snprintf(f, sizeof(f), "nouveau/nv%02x_%s", dev_priv->chipset, fwname); - ret = request_firmware(&fw, f, &dev->pdev->dev); + ret = nouveau_graph_init(&priv->base); 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; -} - -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; - } - priv->firmware = true; - - ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4); - if (ret) - goto error; + nve0_graph_init_obj418880(priv); + nve0_graph_init_regs(priv); + nve0_graph_init_gpc_0(priv); - ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b8); - if (ret) - goto error; + nv_wr32(priv, 0x400500, 0x00010001); + nv_wr32(priv, 0x400100, 0xffffffff); + nv_wr32(priv, 0x40013c, 0xffffffff); - for (i = 0; i < 0x1000; i += 4) { - nv_wo32(priv->unk4188b4, i, 0x00000010); - nv_wo32(priv->unk4188b8, i, 0x00000010); - } + nve0_graph_init_units(priv); + nve0_graph_init_gpc_1(priv); + nve0_graph_init_rop(priv); - 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]; - } - - switch (dev_priv->chipset) { - case 0xe4: - if (priv->tpc_total == 8) - priv->magic_not_rop_nr = 3; - else - if (priv->tpc_total == 7) - priv->magic_not_rop_nr = 1; - break; - case 0xe7: - priv->magic_not_rop_nr = 1; - break; - default: - break; - } + 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); - 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; + ret = nve0_graph_init_ctxctl(priv); + if (ret) { + if (ret == 1) + goto reset; + return ret; } - 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; - -error: - nve0_graph_destroy(dev, NVOBJ_ENGINE_GR); - return ret; } + +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, + }, +}; |