Commit 6dfdd7a6 authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/nouveau: working towards a common way to represent engines



There's lots of more-or-less independant engines present on NVIDIA GPUs
these days, and we generally want to perform the same operations on them.
Implementing new ones requires hooking into lots of different places,
the aim of this work is to make this simpler and cleaner.

NV84:NV98 PCRYPT moved over as a test.

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 2d7b919c
......@@ -269,8 +269,8 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan)
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
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))) {
......@@ -305,8 +305,10 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan)
/* destroy the engine specific contexts */
pfifo->destroy_context(chan);
pgraph->destroy_context(chan);
if (pcrypt->destroy_context)
pcrypt->destroy_context(chan);
for (i = 0; i < NVOBJ_ENGINE_NR; i++) {
if (chan->engctx[i])
dev_priv->eng[i]->context_del(chan, i);
}
pfifo->reassign(dev, true);
......
......@@ -208,6 +208,12 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
pgraph->fifo_access(dev, false);
nouveau_wait_for_idle(dev);
for (i = NVOBJ_ENGINE_NR - 1; i >= 0; i--) {
if (dev_priv->eng[i])
dev_priv->eng[i]->fini(dev, i);
}
pfifo->reassign(dev, false);
pfifo->disable(dev);
pfifo->unload_context(dev);
......@@ -299,8 +305,11 @@ nouveau_pci_resume(struct pci_dev *pdev)
engine->mc.init(dev);
engine->timer.init(dev);
engine->fb.init(dev);
for (i = 0; i < NVOBJ_ENGINE_NR; i++) {
if (dev_priv->eng[i])
dev_priv->eng[i]->init(dev, i);
}
engine->graph.init(dev);
engine->crypt.init(dev);
engine->fifo.init(dev);
nouveau_irq_postinstall(dev);
......
......@@ -150,13 +150,9 @@ enum nouveau_flags {
#define NVOBJ_ENGINE_SW 0
#define NVOBJ_ENGINE_GR 1
#define NVOBJ_ENGINE_PPP 2
#define NVOBJ_ENGINE_COPY 3
#define NVOBJ_ENGINE_VP 4
#define NVOBJ_ENGINE_CRYPT 5
#define NVOBJ_ENGINE_BSP 6
#define NVOBJ_ENGINE_DISPLAY 0xcafe0001
#define NVOBJ_ENGINE_INT 0xdeadbeef
#define NVOBJ_ENGINE_CRYPT 2
#define NVOBJ_ENGINE_DISPLAY 15
#define NVOBJ_ENGINE_NR 16
#define NVOBJ_FLAG_DONT_MAP (1 << 0)
#define NVOBJ_FLAG_ZERO_ALLOC (1 << 1)
......@@ -248,8 +244,8 @@ struct nouveau_channel {
/* PGRAPH context */
/* XXX may be merge 2 pointers as private data ??? */
struct nouveau_gpuobj *ramin_grctx;
struct nouveau_gpuobj *crypt_ctx;
void *pgraph_ctx;
void *engctx[NVOBJ_ENGINE_NR];
/* NV50 VM */
struct nouveau_vm *vm;
......@@ -298,6 +294,17 @@ struct nouveau_channel {
} debugfs;
};
struct nouveau_exec_engine {
void (*destroy)(struct drm_device *, int engine);
int (*init)(struct drm_device *, int engine);
int (*fini)(struct drm_device *, int engine);
int (*context_new)(struct nouveau_channel *, int engine);
void (*context_del)(struct nouveau_channel *, int engine);
int (*object_new)(struct nouveau_channel *, int engine,
u32 handle, u16 class);
void (*tlb_flush)(struct drm_device *, int engine);
};
struct nouveau_instmem_engine {
void *priv;
......@@ -501,17 +508,6 @@ struct nouveau_pm_engine {
int (*temp_get)(struct drm_device *);
};
struct nouveau_crypt_engine {
bool registered;
int (*init)(struct drm_device *);
void (*takedown)(struct drm_device *);
int (*create_context)(struct nouveau_channel *);
void (*destroy_context)(struct nouveau_channel *);
int (*object_new)(struct nouveau_channel *, u32 handle, u16 class);
void (*tlb_flush)(struct drm_device *dev);
};
struct nouveau_vram_engine {
int (*init)(struct drm_device *);
int (*get)(struct drm_device *, u64, u32 align, u32 size_nc,
......@@ -531,7 +527,6 @@ struct nouveau_engine {
struct nouveau_display_engine display;
struct nouveau_gpio_engine gpio;
struct nouveau_pm_engine pm;
struct nouveau_crypt_engine crypt;
struct nouveau_vram_engine vram;
};
......@@ -651,6 +646,7 @@ struct drm_nouveau_private {
u32 ramin_base;
bool ramin_available;
struct drm_mm ramin_heap;
struct nouveau_exec_engine *eng[NVOBJ_ENGINE_NR];
struct list_head gpuobj_list;
struct list_head classes;
......@@ -881,6 +877,16 @@ extern void nouveau_channel_ref(struct nouveau_channel *chan,
extern void nouveau_channel_idle(struct nouveau_channel *chan);
/* nouveau_object.c */
#define NVOBJ_ENGINE_ADD(d, e, p) do { \
struct drm_nouveau_private *dev_priv = (d)->dev_private; \
dev_priv->eng[NVOBJ_ENGINE_##e] = (p); \
} while (0)
#define NVOBJ_ENGINE_DEL(d, e) do { \
struct drm_nouveau_private *dev_priv = (d)->dev_private; \
dev_priv->eng[NVOBJ_ENGINE_##e] = NULL; \
} while (0)
#define NVOBJ_CLASS(d, c, e) do { \
int ret = nouveau_gpuobj_class_new((d), (c), NVOBJ_ENGINE_##e); \
if (ret) \
......@@ -1209,12 +1215,7 @@ extern int nvc0_graph_unload_context(struct drm_device *);
extern int nvc0_graph_object_new(struct nouveau_channel *, u32, u16);
/* nv84_crypt.c */
extern int nv84_crypt_init(struct drm_device *dev);
extern void nv84_crypt_fini(struct drm_device *dev);
extern int nv84_crypt_create_context(struct nouveau_channel *);
extern void nv84_crypt_destroy_context(struct nouveau_channel *);
extern void nv84_crypt_tlb_flush(struct drm_device *dev);
extern int nv84_crypt_object_new(struct nouveau_channel *, u32, u16);
extern int nv84_crypt_create(struct drm_device *);
/* nv04_instmem.c */
extern int nv04_instmem_init(struct drm_device *);
......@@ -1582,6 +1583,13 @@ nv_match_device(struct drm_device *dev, unsigned device,
dev->pdev->subsystem_device == sub_device;
}
static inline void *
nv_engine(struct drm_device *dev, int engine)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
return (void *)dev_priv->eng[engine];
}
/* returns 1 if device is one of the nv4x using the 0x4497 object class,
* helpful to determine a number of other hardware features
*/
......
......@@ -621,7 +621,6 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, u32 handle, int class)
{
struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
struct drm_device *dev = chan->dev;
struct nouveau_gpuobj_class *oc;
int ret;
......@@ -649,17 +648,15 @@ found:
}
return pgraph->object_new(chan, handle, class);
case NVOBJ_ENGINE_CRYPT:
if (!chan->crypt_ctx) {
ret = pcrypt->create_context(chan);
if (ret)
return ret;
}
}
return pcrypt->object_new(chan, handle, class);
if (!chan->engctx[oc->engine]) {
ret = dev_priv->eng[oc->engine]->context_new(chan, oc->engine);
if (ret)
return ret;
}
BUG_ON(1);
return dev_priv->eng[oc->engine]->object_new(chan, oc->engine, handle, class);
}
static int
......
......@@ -99,8 +99,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.clock_get = nv04_pm_clock_get;
engine->pm.clock_pre = nv04_pm_clock_pre;
engine->pm.clock_set = nv04_pm_clock_set;
engine->crypt.init = nouveau_stub_init;
engine->crypt.takedown = nouveau_stub_takedown;
engine->vram.init = nouveau_mem_detect;
engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
......@@ -159,8 +157,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.clock_get = nv04_pm_clock_get;
engine->pm.clock_pre = nv04_pm_clock_pre;
engine->pm.clock_set = nv04_pm_clock_set;
engine->crypt.init = nouveau_stub_init;
engine->crypt.takedown = nouveau_stub_takedown;
engine->vram.init = nouveau_mem_detect;
engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
......@@ -219,8 +215,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.clock_get = nv04_pm_clock_get;
engine->pm.clock_pre = nv04_pm_clock_pre;
engine->pm.clock_set = nv04_pm_clock_set;
engine->crypt.init = nouveau_stub_init;
engine->crypt.takedown = nouveau_stub_takedown;
engine->vram.init = nouveau_mem_detect;
engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
......@@ -281,8 +275,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.clock_set = nv04_pm_clock_set;
engine->pm.voltage_get = nouveau_voltage_gpio_get;
engine->pm.voltage_set = nouveau_voltage_gpio_set;
engine->crypt.init = nouveau_stub_init;
engine->crypt.takedown = nouveau_stub_takedown;
engine->vram.init = nouveau_mem_detect;
engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
......@@ -345,8 +337,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.voltage_get = nouveau_voltage_gpio_get;
engine->pm.voltage_set = nouveau_voltage_gpio_set;
engine->pm.temp_get = nv40_temp_get;
engine->crypt.init = nouveau_stub_init;
engine->crypt.takedown = nouveau_stub_takedown;
engine->vram.init = nouveau_mem_detect;
engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
......@@ -438,25 +428,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.temp_get = nv84_temp_get;
else
engine->pm.temp_get = nv40_temp_get;
switch (dev_priv->chipset) {
case 0x84:
case 0x86:
case 0x92:
case 0x94:
case 0x96:
case 0xa0:
engine->crypt.init = nv84_crypt_init;
engine->crypt.takedown = nv84_crypt_fini;
engine->crypt.create_context = nv84_crypt_create_context;
engine->crypt.destroy_context = nv84_crypt_destroy_context;
engine->crypt.object_new = nv84_crypt_object_new;
engine->crypt.tlb_flush = nv84_crypt_tlb_flush;
break;
default:
engine->crypt.init = nouveau_stub_init;
engine->crypt.takedown = nouveau_stub_takedown;
break;
}
engine->vram.init = nv50_vram_init;
engine->vram.get = nv50_vram_new;
engine->vram.put = nv50_vram_del;
......@@ -511,8 +482,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->gpio.irq_register = nv50_gpio_irq_register;
engine->gpio.irq_unregister = nv50_gpio_irq_unregister;
engine->gpio.irq_enable = nv50_gpio_irq_enable;
engine->crypt.init = nouveau_stub_init;
engine->crypt.takedown = nouveau_stub_takedown;
engine->vram.init = nvc0_vram_init;
engine->vram.get = nvc0_vram_new;
engine->vram.put = nv50_vram_del;
......@@ -601,7 +570,7 @@ nouveau_card_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_engine *engine;
int ret;
int ret, e;
vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode);
vga_switcheroo_register_client(dev->pdev, nouveau_switcheroo_set_state,
......@@ -666,23 +635,37 @@ nouveau_card_init(struct drm_device *dev)
if (ret)
goto out_timer;
switch (dev_priv->chipset) {
case 0x84:
case 0x86:
case 0x92:
case 0x94:
case 0x96:
case 0xa0:
nv84_crypt_create(dev);
break;
}
if (nouveau_noaccel)
engine->graph.accel_blocked = true;
else {
for (e = 0; e < NVOBJ_ENGINE_NR; e++) {
if (dev_priv->eng[e]) {
ret = dev_priv->eng[e]->init(dev, e);
if (ret)
goto out_engine;
}
}
/* PGRAPH */
ret = engine->graph.init(dev);
if (ret)
goto out_fb;
/* PCRYPT */
ret = engine->crypt.init(dev);
if (ret)
goto out_graph;
goto out_engine;
/* PFIFO */
ret = engine->fifo.init(dev);
if (ret)
goto out_crypt;
goto out_graph;
}
ret = engine->display.create(dev);
......@@ -723,13 +706,17 @@ out_vblank:
out_fifo:
if (!nouveau_noaccel)
engine->fifo.takedown(dev);
out_crypt:
if (!nouveau_noaccel)
engine->crypt.takedown(dev);
out_graph:
if (!nouveau_noaccel)
engine->graph.takedown(dev);
out_fb:
out_engine:
if (!nouveau_noaccel) {
for (e = e - 1; e >= 0; e--) {
dev_priv->eng[e]->fini(dev, e);
dev_priv->eng[e]->destroy(dev, e);
}
}
engine->fb.takedown(dev);
out_timer:
engine->timer.takedown(dev);
......@@ -759,6 +746,7 @@ static void nouveau_card_takedown(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_engine *engine = &dev_priv->engine;
int e;
if (!engine->graph.accel_blocked) {
nouveau_fence_fini(dev);
......@@ -767,8 +755,13 @@ static void nouveau_card_takedown(struct drm_device *dev)
if (!nouveau_noaccel) {
engine->fifo.takedown(dev);
engine->crypt.takedown(dev);
engine->graph.takedown(dev);
for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) {
if (dev_priv->eng[e]) {
dev_priv->eng[e]->fini(dev, e);
dev_priv->eng[e]->destroy(dev,e );
}
}
}
engine->fb.takedown(dev);
engine->timer.takedown(dev);
......
......@@ -54,7 +54,7 @@ struct nouveau_vm {
struct list_head pgd_list;
atomic_t pgraph_refs;
atomic_t pcrypt_refs;
atomic_t engref[16];
struct nouveau_vm_pgt *pgt;
u32 fpde;
......
......@@ -152,7 +152,7 @@ nv50_vm_flush(struct nouveau_vm *vm)
struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
int i;
pinstmem->flush(vm->dev);
......@@ -166,8 +166,10 @@ nv50_vm_flush(struct nouveau_vm *vm)
if (atomic_read(&vm->pgraph_refs))
pgraph->tlb_flush(vm->dev);
if (atomic_read(&vm->pcrypt_refs))
pcrypt->tlb_flush(vm->dev);
for (i = 0; i < NVOBJ_ENGINE_NR; i++) {
if (atomic_read(&vm->engref[i]))
dev_priv->eng[i]->tlb_flush(vm->dev, i);
}
}
void
......
......@@ -28,45 +28,46 @@
#include "nouveau_vm.h"
#include "nouveau_ramht.h"
static void nv84_crypt_isr(struct drm_device *);
struct nv84_crypt_engine {
struct nouveau_exec_engine base;
};
int
nv84_crypt_create_context(struct nouveau_channel *chan)
static int
nv84_crypt_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 *ramin = chan->ramin;
struct nouveau_gpuobj *ctx;
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,
&chan->crypt_ctx);
ret = nouveau_gpuobj_new(dev, chan, 256, 0, NVOBJ_FLAG_ZERO_ALLOC |
NVOBJ_FLAG_ZERO_FREE, &ctx);
if (ret)
return ret;
nv_wo32(ramin, 0xa0, 0x00190000);
nv_wo32(ramin, 0xa4, chan->crypt_ctx->vinst + 0xff);
nv_wo32(ramin, 0xa8, chan->crypt_ctx->vinst);
nv_wo32(ramin, 0xa4, ctx->vinst + ctx->size - 1);
nv_wo32(ramin, 0xa8, ctx->vinst);
nv_wo32(ramin, 0xac, 0);
nv_wo32(ramin, 0xb0, 0);
nv_wo32(ramin, 0xb4, 0);
dev_priv->engine.instmem.flush(dev);
atomic_inc(&chan->vm->pcrypt_refs);
atomic_inc(&chan->vm->engref[engine]);
chan->engctx[engine] = ctx;
return 0;
}
void
nv84_crypt_destroy_context(struct nouveau_channel *chan)
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;
if (!chan->crypt_ctx)
return;
inst = (chan->ramin->vinst >> 12);
inst |= 0x80000000;
......@@ -81,12 +82,15 @@ nv84_crypt_destroy_context(struct nouveau_channel *chan)
nv_mask(dev, 0x10218c, 0x80000000, 0x00000000);
nv_wr32(dev, 0x10200c, 0x00000010);
nouveau_gpuobj_ref(NULL, &chan->crypt_ctx);
atomic_dec(&chan->vm->pcrypt_refs);
nouveau_gpuobj_ref(NULL, &ctx);
atomic_dec(&chan->vm->engref[engine]);
chan->engctx[engine] = NULL;
}
int
nv84_crypt_object_new(struct nouveau_channel *chan, u32 handle, u16 class)
static int
nv84_crypt_object_new(struct nouveau_channel *chan, int engine,
u32 handle, u16 class)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
......@@ -107,27 +111,45 @@ nv84_crypt_object_new(struct nouveau_channel *chan, u32 handle, u16 class)
return ret;
}
void
nv84_crypt_tlb_flush(struct drm_device *dev)
static void
nv84_crypt_tlb_flush(struct drm_device *dev, int engine)
{
nv50_vm_flush_engine(dev, 0x0a);
}
int
nv84_crypt_init(struct drm_device *dev)
static void
nv84_crypt_isr(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
u32 stat = nv_rd32(dev, 0x102130);
u32 mthd = nv_rd32(dev, 0x102190);
u32 data = nv_rd32(dev, 0x102194);
u32 inst = nv_rd32(dev, 0x102188) & 0x7fffffff;
int show = nouveau_ratelimit();
if (!pcrypt->registered) {
NVOBJ_CLASS(dev, 0x74c1, CRYPT);
pcrypt->registered = true;
if (show) {
NV_INFO(dev, "PCRYPT_INTR: 0x%08x 0x%08x 0x%08x 0x%08x\n",
stat, mthd, data, inst);
}
nv_wr32(dev, 0x102130, stat);
nv_wr32(dev, 0x10200c, 0x10);
nv50_fb_vm_trap(dev, show);
}
static int
nv84_crypt_fini(struct drm_device *dev, int engine)
{
nv_wr32(dev, 0x102140, 0x00000000);
return 0;
}
static int
nv84_crypt_init(struct drm_device *dev, int engine)
{
nv_mask(dev, 0x000200, 0x00004000, 0x00000000);
nv_mask(dev, 0x000200, 0x00004000, 0x00004000);
nouveau_irq_register(dev, 14, nv84_crypt_isr);
nv_wr32(dev, 0x102130, 0xffffffff);
nv_wr32(dev, 0x102140, 0xffffffbf);
......@@ -135,29 +157,37 @@ nv84_crypt_init(struct drm_device *dev)
return 0;
}
void
nv84_crypt_fini(struct drm_device *dev)
static void
nv84_crypt_destroy(struct drm_device *dev, int engine)
{
nv_wr32(dev, 0x102140, 0x00000000);
struct nv84_crypt_engine *pcrypt = nv_engine(dev, engine);
NVOBJ_ENGINE_DEL(dev, CRYPT);
nouveau_irq_unregister(dev, 14);
kfree(pcrypt);
}
static void
nv84_crypt_isr(struct drm_device *dev)
int
nv84_crypt_create(struct drm_device *dev)
{
u32 stat = nv_rd32(dev, 0x102130);
u32 mthd = nv_rd32(dev, 0x102190);
u32 data = nv_rd32(dev, 0x102194);
u32 inst = nv_rd32(dev, 0x102188) & 0x7fffffff;
int show = nouveau_ratelimit();
struct nv84_crypt_engine *pcrypt;
if (show) {
NV_INFO(dev, "PCRYPT_INTR: 0x%08x 0x%08x 0x%08x 0x%08x\n",
stat, mthd, data, inst);
}
pcrypt = kzalloc(sizeof(*pcrypt), GFP_KERNEL);
if (!pcrypt)
return -ENOMEM;
nv_wr32(dev, 0x102130, stat);
nv_wr32(dev, 0x10200c, 0x10);
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;
nv50_fb_vm_trap(dev, show);
nouveau_irq_register(dev, 14, nv84_crypt_isr);
NVOBJ_ENGINE_ADD(dev, CRYPT, &pcrypt->base);
NVOBJ_CLASS (dev, 0x74c1, CRYPT);
return 0;
}