From 213732af4381819113756d6d920794cf0dc30dd6 Mon Sep 17 00:00:00 2001 From: Oliver McFadden Date: Thu, 21 Jun 2007 14:32:58 +0000 Subject: r300: Allow writes to R300_VAP_PVS_WAITIDLE. --- shared-core/r300_cmdbuf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/shared-core/r300_cmdbuf.c b/shared-core/r300_cmdbuf.c index c02334a2..0cd5d7e2 100644 --- a/shared-core/r300_cmdbuf.c +++ b/shared-core/r300_cmdbuf.c @@ -156,6 +156,7 @@ void r300_init_reg_flags(void) ADD_RANGE(0x21DC, 1); ADD_RANGE(R300_VAP_UNKNOWN_221C, 1); ADD_RANGE(R300_VAP_CLIP_X_0, 4); + ADD_RANGE(R300_VAP_PVS_WAITIDLE, 1); ADD_RANGE(R300_VAP_UNKNOWN_2288, 1); ADD_RANGE(R300_VAP_OUTPUT_VTX_FMT_0, 2); ADD_RANGE(R300_VAP_PVS_CNTL_1, 3); -- cgit v1.2.3 From 40f6a696cb22ffa064f78198a7a241015d365967 Mon Sep 17 00:00:00 2001 From: Oliver McFadden Date: Thu, 21 Jun 2007 14:35:11 +0000 Subject: r300: Synchronized the register defines file; documentation changes. --- shared-core/r300_reg.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/shared-core/r300_reg.h b/shared-core/r300_reg.h index 3ce09c16..e59919be 100644 --- a/shared-core/r300_reg.h +++ b/shared-core/r300_reg.h @@ -336,13 +336,15 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. * The meaning of the two UNKNOWN fields is obviously not known. However, * experiments so far have shown that both *must* point to an instruction * inside the vertex program, otherwise the GPU locks up. + * * fglrx usually sets CNTL_3_UNKNOWN to the end of the program and - * CNTL_1_UNKNOWN points to instruction where last write to position takes - * place. + * R300_PVS_CNTL_1_POS_END_SHIFT points to instruction where last write to + * position takes place. + * * Most likely this is used to ignore rest of the program in cases * where group of verts arent visible. For some reason this "section" * is sometimes accepted other instruction that have no relationship with - *position calculations. + * position calculations. */ #define R300_VAP_PVS_CNTL_1 0x22D0 # define R300_PVS_CNTL_1_PROGRAM_START_SHIFT 0 -- cgit v1.2.3 From 068ffc1e1bf5607f836839a1fc621a95547251e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 22 Jun 2007 11:55:26 +0200 Subject: radeon: Acknowledge all interrupts we're interested in. Failure to do so was probably the root cause of fd.o bug 11287. --- shared-core/radeon_irq.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/shared-core/radeon_irq.c b/shared-core/radeon_irq.c index 5151b4d6..a4be86e3 100644 --- a/shared-core/radeon_irq.c +++ b/shared-core/radeon_irq.c @@ -72,10 +72,14 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS) /* Only consider the bits we're interested in - others could be used * outside the DRM */ - stat = radeon_acknowledge_irqs(dev_priv, dev_priv->irq_enable_reg); + stat = radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK | + RADEON_CRTC_VBLANK_STAT | + RADEON_CRTC2_VBLANK_STAT)); if (!stat) return IRQ_NONE; + stat &= dev_priv->irq_enable_reg; + /* SW interrupt */ if (stat & RADEON_SW_INT_TEST) { DRM_WAKEUP(&dev_priv->swi_queue); @@ -265,7 +269,8 @@ void radeon_driver_irq_preinstall(drm_device_t * dev) /* Clear bits if they're already high */ radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK | - RADEON_CRTC_VBLANK_STAT)); + RADEON_CRTC_VBLANK_STAT | + RADEON_CRTC2_VBLANK_STAT)); } void radeon_driver_irq_postinstall(drm_device_t * dev) -- cgit v1.2.3 From 5c7c07fd49b154623f9dfdab1fe1f2cda8508036 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sun, 24 Jun 2007 18:54:36 +1000 Subject: nouveau: rename engtab functions --- shared-core/nouveau_drv.h | 30 ++++++------ shared-core/nouveau_state.c | 110 ++++++++++++++++++++++---------------------- 2 files changed, 70 insertions(+), 70 deletions(-) diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index debee8e4..89b284c3 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -101,29 +101,29 @@ struct nouveau_config { struct nouveau_engine_func { struct { - int (*Init)(drm_device_t *dev); - void (*Takedown)(drm_device_t *dev); - } Mc; + int (*init)(drm_device_t *dev); + void (*takedown)(drm_device_t *dev); + } mc; struct { - int (*Init)(drm_device_t *dev); - void (*Takedown)(drm_device_t *dev); - } Timer; + int (*init)(drm_device_t *dev); + void (*takedown)(drm_device_t *dev); + } timer; struct { - int (*Init)(drm_device_t *dev); - void (*Takedown)(drm_device_t *dev); - } Fb; + int (*init)(drm_device_t *dev); + void (*takedown)(drm_device_t *dev); + } fb; struct { - int (*Init)(drm_device_t *dev); - void (*Takedown)(drm_device_t *dev); - } Graph; + int (*init)(drm_device_t *dev); + void (*takedown)(drm_device_t *dev); + } graph; struct { - int (*Init)(drm_device_t *dev); - void (*Takedown)(drm_device_t *dev); - } Fifo; + int (*init)(drm_device_t *dev); + void (*takedown)(drm_device_t *dev); + } fifo; }; typedef struct drm_nouveau_private { diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c index e7930b9e..592797c3 100644 --- a/shared-core/nouveau_state.c +++ b/shared-core/nouveau_state.c @@ -80,64 +80,64 @@ static int nouveau_init_engine_ptrs(drm_device_t *dev) switch (dev_priv->chipset & 0xf0) { case 0x00: - engine->Mc.Init = nv04_mc_init; - engine->Mc.Takedown = nv04_mc_takedown; - engine->Timer.Init = nv04_timer_init; - engine->Timer.Takedown = nv04_timer_takedown; - engine->Fb.Init = nv04_fb_init; - engine->Fb.Takedown = nv04_fb_takedown; - engine->Graph.Init = nv04_graph_init; - engine->Graph.Takedown = nv04_graph_takedown; - engine->Fifo.Init = nouveau_fifo_init; - engine->Fifo.Takedown = nouveau_stub_takedown; + engine->mc.init = nv04_mc_init; + engine->mc.takedown = nv04_mc_takedown; + engine->timer.init = nv04_timer_init; + engine->timer.takedown = nv04_timer_takedown; + engine->fb.init = nv04_fb_init; + engine->fb.takedown = nv04_fb_takedown; + engine->graph.init = nv04_graph_init; + engine->graph.takedown = nv04_graph_takedown; + engine->fifo.init = nouveau_fifo_init; + engine->fifo.takedown = nouveau_stub_takedown; break; case 0x10: - engine->Mc.Init = nv04_mc_init; - engine->Mc.Takedown = nv04_mc_takedown; - engine->Timer.Init = nv04_timer_init; - engine->Timer.Takedown = nv04_timer_takedown; - engine->Fb.Init = nv10_fb_init; - engine->Fb.Takedown = nv10_fb_takedown; - engine->Graph.Init = nv10_graph_init; - engine->Graph.Takedown = nv10_graph_takedown; - engine->Fifo.Init = nouveau_fifo_init; - engine->Fifo.Takedown = nouveau_stub_takedown; + engine->mc.init = nv04_mc_init; + engine->mc.takedown = nv04_mc_takedown; + engine->timer.init = nv04_timer_init; + engine->timer.takedown = nv04_timer_takedown; + engine->fb.init = nv10_fb_init; + engine->fb.takedown = nv10_fb_takedown; + engine->graph.init = nv10_graph_init; + engine->graph.takedown = nv10_graph_takedown; + engine->fifo.init = nouveau_fifo_init; + engine->fifo.takedown = nouveau_stub_takedown; break; case 0x20: - engine->Mc.Init = nv04_mc_init; - engine->Mc.Takedown = nv04_mc_takedown; - engine->Timer.Init = nv04_timer_init; - engine->Timer.Takedown = nv04_timer_takedown; - engine->Fb.Init = nv10_fb_init; - engine->Fb.Takedown = nv10_fb_takedown; - engine->Graph.Init = nv20_graph_init; - engine->Graph.Takedown = nv20_graph_takedown; - engine->Fifo.Init = nouveau_fifo_init; - engine->Fifo.Takedown = nouveau_stub_takedown; + engine->mc.init = nv04_mc_init; + engine->mc.takedown = nv04_mc_takedown; + engine->timer.init = nv04_timer_init; + engine->timer.takedown = nv04_timer_takedown; + engine->fb.init = nv10_fb_init; + engine->fb.takedown = nv10_fb_takedown; + engine->graph.init = nv20_graph_init; + engine->graph.takedown = nv20_graph_takedown; + engine->fifo.init = nouveau_fifo_init; + engine->fifo.takedown = nouveau_stub_takedown; break; case 0x30: - engine->Mc.Init = nv04_mc_init; - engine->Mc.Takedown = nv04_mc_takedown; - engine->Timer.Init = nv04_timer_init; - engine->Timer.Takedown = nv04_timer_takedown; - engine->Fb.Init = nv10_fb_init; - engine->Fb.Takedown = nv10_fb_takedown; - engine->Graph.Init = nv30_graph_init; - engine->Graph.Takedown = nv30_graph_takedown; - engine->Fifo.Init = nouveau_fifo_init; - engine->Fifo.Takedown = nouveau_stub_takedown; + engine->mc.init = nv04_mc_init; + engine->mc.takedown = nv04_mc_takedown; + engine->timer.init = nv04_timer_init; + engine->timer.takedown = nv04_timer_takedown; + engine->fb.init = nv10_fb_init; + engine->fb.takedown = nv10_fb_takedown; + engine->graph.init = nv30_graph_init; + engine->graph.takedown = nv30_graph_takedown; + engine->fifo.init = nouveau_fifo_init; + engine->fifo.takedown = nouveau_stub_takedown; break; case 0x40: - engine->Mc.Init = nv40_mc_init; - engine->Mc.Takedown = nv40_mc_takedown; - engine->Timer.Init = nv04_timer_init; - engine->Timer.Takedown = nv04_timer_takedown; - engine->Fb.Init = nv40_fb_init; - engine->Fb.Takedown = nv40_fb_takedown; - engine->Graph.Init = nv40_graph_init; - engine->Graph.Takedown = nv40_graph_takedown; - engine->Fifo.Init = nouveau_fifo_init; - engine->Fifo.Takedown = nouveau_stub_takedown; + engine->mc.init = nv40_mc_init; + engine->mc.takedown = nv40_mc_takedown; + engine->timer.init = nv04_timer_init; + engine->timer.takedown = nv04_timer_takedown; + engine->fb.init = nv40_fb_init; + engine->fb.takedown = nv40_fb_takedown; + engine->graph.init = nv40_graph_init; + engine->graph.takedown = nv40_graph_takedown; + engine->fifo.init = nouveau_fifo_init; + engine->fifo.takedown = nouveau_stub_takedown; break; case 0x50: default: @@ -184,23 +184,23 @@ static int nouveau_card_init(drm_device_t *dev) /* Parse BIOS tables / Run init tables? */ /* PMC */ - ret = engine->Mc.Init(dev); + ret = engine->mc.init(dev); if (ret) return ret; /* PTIMER */ - ret = engine->Timer.Init(dev); + ret = engine->timer.init(dev); if (ret) return ret; /* PFB */ - ret = engine->Fb.Init(dev); + ret = engine->fb.init(dev); if (ret) return ret; /* PGRAPH */ - ret = engine->Graph.Init(dev); + ret = engine->graph.init(dev); if (ret) return ret; /* PFIFO */ - ret = engine->Fifo.Init(dev); + ret = engine->fifo.init(dev); if (ret) return ret; /* what about PVIDEO/PCRTC/PRAMDAC etc? */ -- cgit v1.2.3 From 24b71c318a00dfbb18b2bbf6652e3b781175c430 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sun, 24 Jun 2007 18:54:51 +1000 Subject: nouveau: prototype PFIFO/PGRAPH engtab API --- shared-core/nouveau_drv.h | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index 89b284c3..093a93c5 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -116,13 +116,23 @@ struct nouveau_engine_func { } fb; struct { - int (*init)(drm_device_t *dev); - void (*takedown)(drm_device_t *dev); + int (*init)(drm_device_t *); + void (*takedown)(drm_device_t *); + + int (*create_context)(drm_device_t *, int channel); + void (*destroy_context)(drm_device_t *, int channel); + int (*load_context)(drm_device_t *, int channel); + int (*save_context)(drm_device_t *, int channel); } graph; struct { - int (*init)(drm_device_t *dev); - void (*takedown)(drm_device_t *dev); + int (*init)(drm_device_t *); + void (*takedown)(drm_device_t *); + + int (*create_context)(drm_device_t *, int channel); + void (*destroy_context)(drm_device_t *, int channel); + int (*load_context)(drm_device_t *, int channel); + int (*save_context)(drm_device_t *, int channel); } fifo; }; -- cgit v1.2.3 From 9dbf322d26642f9e671f144b34e7cd7d295e9b8e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sun, 24 Jun 2007 18:55:06 +1000 Subject: nouveau: (mostly) hook up put_base again --- shared-core/nouveau_drv.h | 1 + shared-core/nouveau_fifo.c | 21 ++++++++++----------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index 093a93c5..da604d37 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -83,6 +83,7 @@ struct nouveau_fifo /* dma object for the command buffer itself */ struct mem_block *cmdbuf_mem; struct nouveau_object *cmdbuf_obj; + uint32_t pushbuf_base; /* PGRAPH context, for cards that keep it in RAMIN */ struct mem_block *ramin_grctx; /* objects belonging to this fifo */ diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c index 8e66ca2e..cc4ff127 100644 --- a/shared-core/nouveau_fifo.c +++ b/shared-core/nouveau_fifo.c @@ -232,6 +232,7 @@ nouveau_fifo_cmdbuf_alloc(struct drm_device *dev, int channel) return DRM_ERR(ENOMEM); } + dev_priv->fifos[channel].pushbuf_base = 0; dev_priv->fifos[channel].cmdbuf_mem = cb; dev_priv->fifos[channel].cmdbuf_obj = cb_dma; return 0; @@ -460,7 +461,7 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp) { int ret; drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_object *cb_obj; + struct nouveau_fifo *chan; int channel; /* @@ -478,14 +479,16 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp) if (channel==nouveau_fifo_number(dev)) return DRM_ERR(EINVAL); (*chan_ret) = channel; + chan = &dev_priv->fifos[channel]; DRM_INFO("Allocating FIFO number %d\n", channel); /* that fifo is used */ - dev_priv->fifos[channel].used = 1; - dev_priv->fifos[channel].filp = filp; + chan->used = 1; + chan->filp = filp; + /* FIFO has no objects yet */ - dev_priv->fifos[channel].objs = NULL; + chan->objs = NULL; /* allocate a command buffer, and create a dma object for the gpu */ ret = nouveau_fifo_cmdbuf_alloc(dev, channel); @@ -493,7 +496,6 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp) nouveau_fifo_free(dev, channel); return ret; } - cb_obj = dev_priv->fifos[channel].cmdbuf_obj; nouveau_wait_for_idle(dev); @@ -548,8 +550,8 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp) NV_WRITE(NV04_PFIFO_MODE,NV_READ(NV04_PFIFO_MODE)|(1<pushbuf_base); + NV_WRITE(NV03_FIFO_REGS_DMAGET(channel), chan->pushbuf_base); /* If this is the first channel, setup PFIFO ourselves. For any * other case, the GPU will handle this when it switches contexts. @@ -557,10 +559,8 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp) if (dev_priv->fifo_alloc_count == 0) { nouveau_fifo_context_restore(dev, channel); if (dev_priv->card_type >= NV_30) { - struct nouveau_fifo *chan; uint32_t inst; - chan = &dev_priv->fifos[channel]; inst = nouveau_chip_instance_get(dev, chan->ramin_grctx); @@ -679,8 +679,7 @@ static int nouveau_ioctl_fifo_alloc(DRM_IOCTL_ARGS) if (res) return res; - /* this should probably disappear in the next abi break? */ - init.put_base = 0; + init.put_base = dev_priv->fifos[init.channel].pushbuf_base; /* make the fifo available to user space */ /* first, the fifo control regs */ -- cgit v1.2.3 From 0afb3b518e1ece820b01f3eea64b25cff01c97bc Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sun, 24 Jun 2007 18:55:23 +1000 Subject: nouveau: split PFIFO/PGRAPH context creation --- shared-core/nouveau_fifo.c | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c index cc4ff127..5bbd1c02 100644 --- a/shared-core/nouveau_fifo.c +++ b/shared-core/nouveau_fifo.c @@ -505,18 +505,16 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp) NV_WRITE(NV03_PFIFO_CACHE1_PUSH0, 0x00000000); NV_WRITE(NV04_PFIFO_CACHE1_PULL0, 0x00000000); - /* Construct inital RAMFC for new channel */ + /* Create a graphics context for new channel */ switch(dev_priv->card_type) { case NV_04: case NV_05: nv04_graph_context_create(dev, channel); - nouveau_nv04_context_init(dev, channel); break; case NV_10: case NV_17: nv10_graph_context_create(dev, channel); - nouveau_nv10_context_init(dev, channel); break; case NV_20: ret = nv20_graph_context_create(dev, channel); @@ -524,7 +522,6 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp) nouveau_fifo_free(dev, channel); return ret; } - nouveau_nv10_context_init(dev, channel); break; case NV_30: ret = nv30_graph_context_create(dev, channel); @@ -532,18 +529,45 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp) nouveau_fifo_free(dev, channel); return ret; } - nouveau_nv30_context_init(dev, channel); break; case NV_40: case NV_44: - case NV_50: ret = nv40_graph_context_create(dev, channel); if (ret) { nouveau_fifo_free(dev, channel); return ret; } - nouveau_nv40_context_init(dev, channel); break; + default: + DRM_ERROR("grctx: unknown card type\n"); + nouveau_fifo_free(dev, channel); + return DRM_ERR(EINVAL); + } + + /* Construct inital RAMFC for new channel */ + switch (dev_priv->card_type) { + case NV_04: + case NV_05: + nouveau_nv04_context_init(dev, channel); + break; + case NV_10: + case NV_17: + nouveau_nv10_context_init(dev, channel); + break; + case NV_20: + nouveau_nv10_context_init(dev, channel); + break; + case NV_30: + nouveau_nv30_context_init(dev, channel); + break; + case NV_40: + case NV_44: + nouveau_nv40_context_init(dev, channel); + break; + default: + DRM_ERROR("fifoctx: unknown card type\n"); + nouveau_fifo_free(dev, channel); + return DRM_ERR(EINVAL); } /* enable the fifo dma operation */ -- cgit v1.2.3 From f2e64d527699751d6b64698495ae1d48eeee6cf7 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sun, 24 Jun 2007 18:56:01 +1000 Subject: nouveau: NV4X PFIFO engtab functions --- linux-core/Makefile.kernel | 1 + linux-core/nv40_fifo.c | 1 + shared-core/nouveau_drv.h | 10 ++- shared-core/nouveau_fifo.c | 100 +++++++---------------- shared-core/nouveau_reg.h | 4 +- shared-core/nouveau_state.c | 4 + shared-core/nv40_fifo.c | 193 ++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 237 insertions(+), 76 deletions(-) create mode 120000 linux-core/nv40_fifo.c create mode 100644 shared-core/nv40_fifo.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 6f5b021b..3e78b6d7 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -25,6 +25,7 @@ nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ nv04_timer.o \ nv04_mc.o nv40_mc.o \ nv04_fb.o nv10_fb.o nv40_fb.o \ + nv40_fifo.o \ nv04_graph.o nv10_graph.o nv20_graph.o nv30_graph.o \ nv40_graph.o radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o diff --git a/linux-core/nv40_fifo.c b/linux-core/nv40_fifo.c new file mode 120000 index 00000000..cc71e7a4 --- /dev/null +++ b/linux-core/nv40_fifo.c @@ -0,0 +1 @@ +../shared-core/nv40_fifo.c \ No newline at end of file diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index da604d37..7c29a882 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -100,7 +100,7 @@ struct nouveau_config { } cmdbuf; }; -struct nouveau_engine_func { +typedef struct nouveau_engine_func { struct { int (*init)(drm_device_t *dev); void (*takedown)(drm_device_t *dev); @@ -135,7 +135,7 @@ struct nouveau_engine_func { int (*load_context)(drm_device_t *, int channel); int (*save_context)(drm_device_t *, int channel); } fifo; -}; +} nouveau_engine_func_t; typedef struct drm_nouveau_private { /* the card type, takes NV_* as values */ @@ -255,6 +255,12 @@ extern void nv10_fb_takedown(drm_device_t *dev); extern int nv40_fb_init(drm_device_t *dev); extern void nv40_fb_takedown(drm_device_t *dev); +/* nv40_fifo.c */ +extern int nv40_fifo_create_context(drm_device_t *, int channel); +extern void nv40_fifo_destroy_context(drm_device_t *, int channel); +extern int nv40_fifo_load_context(drm_device_t *, int channel); +extern int nv40_fifo_save_context(drm_device_t *, int channel); + /* nv04_graph.c */ extern void nouveau_nv04_context_switch(drm_device_t *dev); extern int nv04_graph_init(drm_device_t *dev); diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c index 5bbd1c02..50f094b9 100644 --- a/shared-core/nouveau_fifo.c +++ b/shared-core/nouveau_fifo.c @@ -358,64 +358,6 @@ static void nouveau_nv10_context_save(drm_device_t *dev) #endif #undef RAMFC_WR -#define RAMFC_WR(offset, val) NV_WRITE(fifoctx + NV40_RAMFC_##offset, (val)) -static void nouveau_nv40_context_init(drm_device_t *dev, int channel) -{ - drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; - uint32_t fifoctx, cb_inst, grctx_inst; - int i; - - cb_inst = nouveau_chip_instance_get(dev, chan->cmdbuf_obj->instance); - grctx_inst = nouveau_chip_instance_get(dev, chan->ramin_grctx); - fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel*128; - for (i=0;i<128;i+=4) - NV_WRITE(fifoctx + i, 0); - - /* Fill entries that are seen filled in dumps of nvidia driver just - * after channel's is put into DMA mode - */ - RAMFC_WR(DMA_INSTANCE , cb_inst); - RAMFC_WR(DMA_FETCH , NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | - NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | - NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 | -#ifdef __BIG_ENDIAN - NV_PFIFO_CACHE1_BIG_ENDIAN | -#endif - 0x30000000 /* no idea.. */); - RAMFC_WR(GRCTX_INSTANCE, grctx_inst); - RAMFC_WR(DMA_TIMESLICE , 0x0001FFFF); -} - -static void nouveau_nv40_context_save(drm_device_t *dev) -{ - drm_nouveau_private_t *dev_priv = dev->dev_private; - uint32_t fifoctx; - int channel; - - channel = NV_READ(NV03_PFIFO_CACHE1_PUSH1) & (nouveau_fifo_number(dev)-1); - fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel*128; - - RAMFC_WR(DMA_PUT , NV_READ(NV04_PFIFO_CACHE1_DMA_PUT)); - RAMFC_WR(DMA_GET , NV_READ(NV04_PFIFO_CACHE1_DMA_GET)); - RAMFC_WR(REF_CNT , NV_READ(NV10_PFIFO_CACHE1_REF_CNT)); - RAMFC_WR(DMA_INSTANCE , NV_READ(NV04_PFIFO_CACHE1_DMA_INSTANCE)); - RAMFC_WR(DMA_DCOUNT , NV_READ(NV10_PFIFO_CACHE1_DMA_DCOUNT)); - RAMFC_WR(DMA_STATE , NV_READ(NV04_PFIFO_CACHE1_DMA_STATE)); - RAMFC_WR(DMA_FETCH , NV_READ(NV04_PFIFO_CACHE1_DMA_FETCH)); - RAMFC_WR(ENGINE , NV_READ(NV04_PFIFO_CACHE1_ENGINE)); - RAMFC_WR(PULL1_ENGINE , NV_READ(NV04_PFIFO_CACHE1_PULL1)); - RAMFC_WR(ACQUIRE_VALUE , NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_VALUE)); - RAMFC_WR(ACQUIRE_TIMESTAMP, NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP)); - RAMFC_WR(ACQUIRE_TIMEOUT , NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT)); - RAMFC_WR(SEMAPHORE , NV_READ(NV10_PFIFO_CACHE1_SEMAPHORE)); - RAMFC_WR(DMA_SUBROUTINE , NV_READ(NV04_PFIFO_CACHE1_DMA_GET)); - RAMFC_WR(GRCTX_INSTANCE , NV_READ(NV40_PFIFO_GRCTX_INSTANCE)); - RAMFC_WR(DMA_TIMESLICE , NV_READ(NV04_PFIFO_DMA_TIMESLICE) & 0x1FFFF); - RAMFC_WR(UNK_40 , NV_READ(NV40_PFIFO_UNK32E4)); -} -#undef RAMFC_WR - /* This function should load values from RAMFC into PFIFO, but for now * it just clobbers PFIFO with what nouveau_fifo_alloc used to setup * unconditionally. @@ -461,6 +403,7 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp) { int ret; drm_nouveau_private_t *dev_priv = dev->dev_private; + nouveau_engine_func_t *engine = &dev_priv->Engine; struct nouveau_fifo *chan; int channel; @@ -560,14 +503,17 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp) case NV_30: nouveau_nv30_context_init(dev, channel); break; - case NV_40: - case NV_44: - nouveau_nv40_context_init(dev, channel); - break; default: - DRM_ERROR("fifoctx: unknown card type\n"); - nouveau_fifo_free(dev, channel); - return DRM_ERR(EINVAL); + if (!engine->fifo.create_context) { + DRM_ERROR("fifo.create_context == NULL\n"); + return DRM_ERR(EINVAL); + } + + ret = engine->fifo.create_context(dev, channel); + if (ret) { + nouveau_fifo_free(dev, channel); + return ret; + } } /* enable the fifo dma operation */ @@ -581,7 +527,11 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp) * other case, the GPU will handle this when it switches contexts. */ if (dev_priv->fifo_alloc_count == 0) { - nouveau_fifo_context_restore(dev, channel); + if (engine->fifo.load_context) + engine->fifo.load_context(dev, channel); + else + nouveau_fifo_context_restore(dev, channel); + if (dev_priv->card_type >= NV_30) { uint32_t inst; @@ -615,6 +565,7 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp) void nouveau_fifo_free(drm_device_t* dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; + nouveau_engine_func_t *engine = &dev_priv->Engine; struct nouveau_fifo *chan = &dev_priv->fifos[channel]; int i; int ctx_size = nouveau_fifo_ctx_size(dev); @@ -629,12 +580,17 @@ void nouveau_fifo_free(drm_device_t* dev, int channel) // FIXME XXX needs more code /* Clean RAMFC */ - for (i=0;iramfc_offset + - channel*ctx_size + i)); - NV_WRITE(NV_RAMIN + dev_priv->ramfc_offset + - channel*ctx_size + i, 0); + if (engine->fifo.destroy_context) + engine->fifo.destroy_context(dev, channel); + else { + for (i=0;iramfc_offset + + channel*ctx_size + i)); + NV_WRITE(NV_RAMIN + dev_priv->ramfc_offset + + channel*ctx_size + i, 0); + } } /* Cleanup PGRAPH state */ diff --git a/shared-core/nouveau_reg.h b/shared-core/nouveau_reg.h index ea4a2f6b..07c54a92 100644 --- a/shared-core/nouveau_reg.h +++ b/shared-core/nouveau_reg.h @@ -462,6 +462,6 @@ #define NV40_RAMFC_UNK_40 0x40 #define NV40_RAMFC_UNK_44 0x44 #define NV40_RAMFC_UNK_48 0x48 -#define NV40_RAMFC_2088 0x4C -#define NV40_RAMFC_3300 0x50 +#define NV40_RAMFC_UNK_4C 0x4C +#define NV40_RAMFC_UNK_50 0x50 diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c index 592797c3..42860e9a 100644 --- a/shared-core/nouveau_state.c +++ b/shared-core/nouveau_state.c @@ -138,6 +138,10 @@ static int nouveau_init_engine_ptrs(drm_device_t *dev) engine->graph.takedown = nv40_graph_takedown; engine->fifo.init = nouveau_fifo_init; engine->fifo.takedown = nouveau_stub_takedown; + engine->fifo.create_context = nv40_fifo_create_context; + engine->fifo.destroy_context = nv40_fifo_destroy_context; + engine->fifo.load_context = nv40_fifo_load_context; + engine->fifo.save_context = nv40_fifo_save_context; break; case 0x50: default: diff --git a/shared-core/nv40_fifo.c b/shared-core/nv40_fifo.c new file mode 100644 index 00000000..b67a7e58 --- /dev/null +++ b/shared-core/nv40_fifo.c @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2007 Ben Skeggs. + * 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 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. + * + */ + +#include "drmP.h" +#include "nouveau_drv.h" +#include "nouveau_drm.h" + +#define RAMFC_WR(offset, val) NV_WRITE(fifoctx + NV40_RAMFC_##offset, (val)) +#define RAMFC_RD(offset) NV_READ (fifoctx + NV40_RAMFC_##offset) + +int +nv40_fifo_create_context(drm_device_t *dev, int channel) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + uint32_t fifoctx, grctx, pushbuf; + int i; + + fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel*128; + for (i=0;i<128;i+=4) + NV_WRITE(fifoctx + i, 0); + + grctx = nouveau_chip_instance_get(dev, chan->ramin_grctx); + pushbuf = nouveau_chip_instance_get(dev, chan->cmdbuf_obj->instance); + + /* Fill entries that are seen filled in dumps of nvidia driver just + * after channel's is put into DMA mode + */ + RAMFC_WR(DMA_PUT , chan->pushbuf_base); + RAMFC_WR(DMA_GET , chan->pushbuf_base); + RAMFC_WR(DMA_INSTANCE , pushbuf); + RAMFC_WR(DMA_FETCH , NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | + NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | + NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 | +#ifdef __BIG_ENDIAN + NV_PFIFO_CACHE1_BIG_ENDIAN | +#endif + 0x30000000 /* no idea.. */); + RAMFC_WR(DMA_SUBROUTINE, 0); + RAMFC_WR(GRCTX_INSTANCE, grctx); + RAMFC_WR(DMA_TIMESLICE , 0x0001FFFF); + + return 0; +} + +void +nv40_fifo_destroy_context(drm_device_t *dev, int channel) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + uint32_t fifoctx; + int i; + + fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel*128; + for (i=0;i<128;i+=4) + NV_WRITE(fifoctx + i, 0); +} + +int +nv40_fifo_load_context(drm_device_t *dev, int channel) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + uint32_t fifoctx; + uint32_t tmp, tmp2; + + fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel*128; + + NV_WRITE(NV04_PFIFO_CACHE1_DMA_GET , RAMFC_RD(DMA_GET)); + NV_WRITE(NV04_PFIFO_CACHE1_DMA_PUT , RAMFC_RD(DMA_PUT)); + NV_WRITE(NV10_PFIFO_CACHE1_REF_CNT , RAMFC_RD(REF_CNT)); + NV_WRITE(NV04_PFIFO_CACHE1_DMA_INSTANCE , RAMFC_RD(DMA_INSTANCE)); + NV_WRITE(NV10_PFIFO_CACHE1_DMA_DCOUNT , RAMFC_RD(DMA_DCOUNT)); + NV_WRITE(NV04_PFIFO_CACHE1_DMA_STATE , RAMFC_RD(DMA_STATE)); + + /* No idea what 0x2058 is.. */ + tmp = RAMFC_RD(DMA_FETCH); + tmp2 = NV_READ(0x2058) & 0xFFF; + tmp2 |= (tmp & 0x30000000); + NV_WRITE(0x2058, tmp2); + tmp &= ~0x30000000; + NV_WRITE(NV04_PFIFO_CACHE1_DMA_FETCH , tmp); + + NV_WRITE(NV04_PFIFO_CACHE1_ENGINE , RAMFC_RD(ENGINE)); + NV_WRITE(NV04_PFIFO_CACHE1_PULL1 , RAMFC_RD(PULL1_ENGINE)); + NV_WRITE(NV10_PFIFO_CACHE1_ACQUIRE_VALUE , RAMFC_RD(ACQUIRE_VALUE)); + NV_WRITE(NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP, RAMFC_RD(ACQUIRE_TIMESTAMP)); + NV_WRITE(NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT , RAMFC_RD(ACQUIRE_TIMEOUT)); + NV_WRITE(NV10_PFIFO_CACHE1_SEMAPHORE , RAMFC_RD(SEMAPHORE)); + NV_WRITE(NV10_PFIFO_CACHE1_DMA_SUBROUTINE , RAMFC_RD(DMA_SUBROUTINE)); + NV_WRITE(NV40_PFIFO_GRCTX_INSTANCE , RAMFC_RD(GRCTX_INSTANCE)); + NV_WRITE(0x32e4, RAMFC_RD(UNK_40)); + /* NVIDIA does this next line twice... */ + NV_WRITE(0x32e8, RAMFC_RD(UNK_44)); + NV_WRITE(0x2088, RAMFC_RD(UNK_4C)); + NV_WRITE(0x3300, RAMFC_RD(UNK_50)); + + /* not sure what part is PUT, and which is GET.. never seen a non-zero + * value appear in a mmio-trace yet.. + */ +#if 0 + tmp = NV_READ(UNK_84); + NV_WRITE(NV_PFIFO_CACHE1_GET, tmp ???); + NV_WRITE(NV_PFIFO_CACHE1_PUT, tmp ???); +#endif + + /* Don't clobber the TIMEOUT_ENABLED flag when restoring from RAMFC */ + tmp = NV_READ(NV04_PFIFO_DMA_TIMESLICE) & ~0x1FFFF; + tmp |= RAMFC_RD(DMA_TIMESLICE) & 0x1FFFF; + NV_WRITE(NV04_PFIFO_DMA_TIMESLICE, tmp); + + /* Set channel active, and in DMA mode */ + NV_WRITE(NV03_PFIFO_CACHE1_PUSH1 , 0x00010000 | channel); + /* Reset DMA_CTL_AT_INFO to INVALID */ + tmp = NV_READ(NV04_PFIFO_CACHE1_DMA_CTL) & ~(1<<31); + NV_WRITE(NV04_PFIFO_CACHE1_DMA_CTL, tmp); + + return 0; +} + +int +nv40_fifo_save_context(drm_device_t *dev, int channel) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + uint32_t fifoctx; + uint32_t tmp; + + fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel*128; + + RAMFC_WR(DMA_PUT , NV_READ(NV04_PFIFO_CACHE1_DMA_PUT)); + RAMFC_WR(DMA_GET , NV_READ(NV04_PFIFO_CACHE1_DMA_GET)); + RAMFC_WR(REF_CNT , NV_READ(NV10_PFIFO_CACHE1_REF_CNT)); + RAMFC_WR(DMA_INSTANCE , NV_READ(NV04_PFIFO_CACHE1_DMA_INSTANCE)); + RAMFC_WR(DMA_DCOUNT , NV_READ(NV10_PFIFO_CACHE1_DMA_DCOUNT)); + RAMFC_WR(DMA_STATE , NV_READ(NV04_PFIFO_CACHE1_DMA_STATE)); + + tmp = NV_READ(NV04_PFIFO_CACHE1_DMA_FETCH); + tmp |= NV_READ(0x2058) & 0x30000000; + RAMFC_WR(DMA_FETCH , tmp); + + RAMFC_WR(ENGINE , NV_READ(NV04_PFIFO_CACHE1_ENGINE)); + RAMFC_WR(PULL1_ENGINE , NV_READ(NV04_PFIFO_CACHE1_PULL1)); + RAMFC_WR(ACQUIRE_VALUE , NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_VALUE)); + tmp = NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP); + RAMFC_WR(ACQUIRE_TIMESTAMP, tmp); + RAMFC_WR(ACQUIRE_TIMEOUT , NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT)); + RAMFC_WR(SEMAPHORE , NV_READ(NV10_PFIFO_CACHE1_SEMAPHORE)); + + /* NVIDIA read 0x3228 first, then write DMA_GET here.. maybe something + * more involved depending on the value of 0x3228? + */ + RAMFC_WR(DMA_SUBROUTINE , NV_READ(NV04_PFIFO_CACHE1_DMA_GET)); + + RAMFC_WR(GRCTX_INSTANCE , NV_READ(NV40_PFIFO_GRCTX_INSTANCE)); + + /* No idea what the below is for exactly, ripped from a mmio-trace */ + RAMFC_WR(UNK_40 , NV_READ(NV40_PFIFO_UNK32E4)); + + /* NVIDIA do this next line twice.. bug? */ + RAMFC_WR(UNK_44 , NV_READ(0x32e8)); + RAMFC_WR(UNK_4C , NV_READ(0x2088)); + RAMFC_WR(UNK_50 , NV_READ(0x3300)); + +#if 0 /* no real idea which is PUT/GET in UNK_48.. */ + tmp = NV_READ(NV04_PFIFO_CACHE1_GET); + tmp |= (NV_READ(NV04_PFIFO_CACHE1_PUT) << 16); + RAMFC_WR(UNK_48 , tmp); +#endif + + return 0; +} + -- cgit v1.2.3 From acb710d1a59788a0205cd0daf0859864e683fbd2 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sun, 24 Jun 2007 18:56:40 +1000 Subject: nouveau: NV4X PGRAPH engtab functions --- shared-core/nouveau_drv.h | 11 ++-- shared-core/nouveau_fifo.c | 24 +++++--- shared-core/nouveau_state.c | 4 ++ shared-core/nv40_graph.c | 142 +++++++++++++++++++++++++++----------------- 4 files changed, 111 insertions(+), 70 deletions(-) diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index 7c29a882..07c40107 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -285,11 +285,12 @@ extern void nv30_graph_takedown(drm_device_t *dev); extern int nv30_graph_context_create(drm_device_t *dev, int channel); /* nv40_graph.c */ -extern int nv40_graph_init(drm_device_t *dev); -extern void nv40_graph_takedown(drm_device_t *dev); -extern int nv40_graph_context_create(drm_device_t *dev, int channel); -extern void nv40_graph_context_save_current(drm_device_t *dev); -extern void nv40_graph_context_restore(drm_device_t *dev, int channel); +extern int nv40_graph_init(drm_device_t *); +extern void nv40_graph_takedown(drm_device_t *); +extern int nv40_graph_create_context(drm_device_t *, int channel); +extern void nv40_graph_destroy_context(drm_device_t *, int channel); +extern int nv40_graph_load_context(drm_device_t *, int channel); +extern int nv40_graph_save_context(drm_device_t *, int channel); /* nv04_mc.c */ extern int nv04_mc_init(drm_device_t *dev); diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c index 50f094b9..527a71ae 100644 --- a/shared-core/nouveau_fifo.c +++ b/shared-core/nouveau_fifo.c @@ -473,18 +473,17 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp) return ret; } break; - case NV_40: - case NV_44: - ret = nv40_graph_context_create(dev, channel); + default: + if (!engine->graph.create_context) { + DRM_ERROR("graph.create_context == NULL\n"); + return DRM_ERR(EINVAL); + } + ret = engine->graph.create_context(dev, channel); if (ret) { nouveau_fifo_free(dev, channel); return ret; } break; - default: - DRM_ERROR("grctx: unknown card type\n"); - nouveau_fifo_free(dev, channel); - return DRM_ERR(EINVAL); } /* Construct inital RAMFC for new channel */ @@ -532,6 +531,13 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp) else nouveau_fifo_context_restore(dev, channel); + if (engine->graph.load_context) { + ret = engine->graph.load_context(dev, channel); + if (ret) { + nouveau_fifo_free(dev, channel); + return ret; + } + } else if (dev_priv->card_type >= NV_30) { uint32_t inst; @@ -594,8 +600,8 @@ void nouveau_fifo_free(drm_device_t* dev, int channel) } /* Cleanup PGRAPH state */ - if (dev_priv->card_type >= NV_40) - nouveau_instmem_free(dev, chan->ramin_grctx); + if (engine->graph.destroy_context) + engine->graph.destroy_context(dev, channel); else if (dev_priv->card_type >= NV_30) { } else if (dev_priv->card_type >= NV_20) { diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c index 42860e9a..d113f234 100644 --- a/shared-core/nouveau_state.c +++ b/shared-core/nouveau_state.c @@ -136,6 +136,10 @@ static int nouveau_init_engine_ptrs(drm_device_t *dev) engine->fb.takedown = nv40_fb_takedown; engine->graph.init = nv40_graph_init; engine->graph.takedown = nv40_graph_takedown; + engine->graph.create_context = nv40_graph_create_context; + engine->graph.destroy_context = nv40_graph_destroy_context; + engine->graph.load_context = nv40_graph_load_context; + engine->graph.save_context = nv40_graph_save_context; engine->fifo.init = nouveau_fifo_init; engine->fifo.takedown = nouveau_stub_takedown; engine->fifo.create_context = nv40_fifo_create_context; diff --git a/shared-core/nv40_graph.c b/shared-core/nv40_graph.c index 792734ed..245da54d 100644 --- a/shared-core/nv40_graph.c +++ b/shared-core/nv40_graph.c @@ -1,7 +1,32 @@ +/* + * Copyright (C) 2007 Ben Skeggs. + * 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 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. + * + */ + #include "drmP.h" #include "drm.h" #include "nouveau_drv.h" -#include "nouveau_drm.h" /* The sizes are taken from the difference between the start of two * grctx addresses while running the nvidia driver. Probably slightly @@ -755,7 +780,7 @@ static void nv4e_graph_context_init(drm_device_t *dev, struct mem_block *ctx) } int -nv40_graph_context_create(drm_device_t *dev, int channel) +nv40_graph_create_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = (drm_nouveau_private_t *)dev->dev_private; @@ -808,89 +833,94 @@ nv40_graph_context_create(drm_device_t *dev, int channel) return 0; } -/* Save current context (from PGRAPH) into the channel's context - *XXX: fails sometimes, not sure why.. - */ void -nv40_graph_context_save_current(drm_device_t *dev) +nv40_graph_destroy_context(drm_device_t *dev, int channel) { - drm_nouveau_private_t *dev_priv = - (drm_nouveau_private_t *)dev->dev_private; - uint32_t instance; - int i; - - NV_WRITE(NV04_PGRAPH_FIFO, 0); + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; - instance = NV_READ(0x40032C) & 0xFFFFF; - if (!instance) { - NV_WRITE(NV04_PGRAPH_FIFO, 1); - return; + if (chan->ramin_grctx) { + nouveau_instmem_free(dev, chan->ramin_grctx); + chan->ramin_grctx = NULL; } +} + +static int +nv40_graph_transfer_context(drm_device_t *dev, uint32_t inst, int save) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + uint32_t old_cp, tv = 1000; + int i; - NV_WRITE(0x400784, instance); - NV_WRITE(0x400310, NV_READ(0x400310) | 0x20); + old_cp = NV_READ(0x400784); + NV_WRITE(0x400784, inst); + NV_WRITE(0x400310, save ? 0x20 : 0x40); NV_WRITE(0x400304, 1); - /* just in case, we don't want to spin in-kernel forever */ - for (i=0; i<1000; i++) { - if (NV_READ(0x40030C) == 0) + + for (i = 0; i < tv; i++) { + if (NV_READ(0x40030c) == 0) break; } - if (i==1000) { - DRM_ERROR("failed to save current grctx to ramin\n"); - DRM_ERROR("instance = 0x%08x\n", NV_READ(0x40032C)); - DRM_ERROR("0x40030C = 0x%08x\n", NV_READ(0x40030C)); - NV_WRITE(NV04_PGRAPH_FIFO, 1); - return; + NV_WRITE(0x400784, old_cp); + + if (i == tv) { + DRM_ERROR("failed: inst=0x%08x save=%d\n", inst, save); + DRM_ERROR("0x40030C = 0x%08x\n", NV_READ(0x40030c)); + return DRM_ERR(EBUSY); } - NV_WRITE(NV04_PGRAPH_FIFO, 1); + return 0; +} + +/* Save current context (from PGRAPH) into the channel's context + *XXX: fails sometimes, not sure why.. + */ +int +nv40_graph_save_context(drm_device_t *dev, int channel) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + uint32_t inst; + + if (!chan->ramin_grctx) + return DRM_ERR(EINVAL); + inst = nouveau_chip_instance_get(dev, chan->ramin_grctx); + + return nv40_graph_transfer_context(dev, inst, 1); } /* Restore the context for a specific channel into PGRAPH * XXX: fails sometimes.. not sure why */ -void -nv40_graph_context_restore(drm_device_t *dev, int channel) +int +nv40_graph_load_context(drm_device_t *dev, int channel) { - drm_nouveau_private_t *dev_priv = - (drm_nouveau_private_t *)dev->dev_private; + drm_nouveau_private_t *dev_priv = dev->dev_private; struct nouveau_fifo *chan = &dev_priv->fifos[channel]; - uint32_t instance; - int i; - - instance = nouveau_chip_instance_get(dev, chan->ramin_grctx); + uint32_t inst; + int ret; - NV_WRITE(NV04_PGRAPH_FIFO, 0); - NV_WRITE(0x400784, instance); - NV_WRITE(0x400310, NV_READ(0x400310) | 0x40); - NV_WRITE(0x400304, 1); - /* just in case, we don't want to spin in-kernel forever */ - for (i=0; i<1000; i++) { - if (NV_READ(0x40030C) == 0) - break; - } - if (i==1000) { - DRM_ERROR("failed to restore grctx for ch%d to PGRAPH\n", - channel); - DRM_ERROR("instance = 0x%08x\n", instance); - DRM_ERROR("0x40030C = 0x%08x\n", NV_READ(0x40030C)); - NV_WRITE(NV04_PGRAPH_FIFO, 1); - return; - } + if (!chan->ramin_grctx) + return DRM_ERR(EINVAL); + inst = nouveau_chip_instance_get(dev, chan->ramin_grctx); + ret = nv40_graph_transfer_context(dev, inst, 0); + if (ret) + return ret; /* 0x40032C, no idea of it's exact function. Could simply be a * record of the currently active PGRAPH context. It's currently * unknown as to what bit 24 does. The nv ddx has it set, so we will * set it here too. */ - NV_WRITE(0x40032C, instance | 0x01000000); + NV_WRITE(0x400784, inst); + NV_WRITE(0x40032C, inst | 0x01000000); /* 0x32E0 records the instance address of the active FIFO's PGRAPH * context. If at any time this doesn't match 0x40032C, you will * recieve PGRAPH_INTR_CONTEXT_SWITCH */ - NV_WRITE(NV40_PFIFO_GRCTX_INSTANCE, instance); - NV_WRITE(NV04_PGRAPH_FIFO, 1); + NV_WRITE(NV40_PFIFO_GRCTX_INSTANCE, inst); + return 0; } /* Some voodoo that makes context switching work without the binary driver -- cgit v1.2.3 From 05d86d950a10b77ffaa708e9d89b2a87c11fed01 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sun, 24 Jun 2007 18:57:09 +1000 Subject: nouveau: NV04 PFIFO engtab functions --- linux-core/Makefile.kernel | 2 +- linux-core/nv04_fifo.c | 1 + shared-core/nouveau_drv.h | 6 +++ shared-core/nouveau_fifo.c | 32 ----------- shared-core/nouveau_reg.h | 5 +- shared-core/nouveau_state.c | 4 ++ shared-core/nv04_fifo.c | 126 ++++++++++++++++++++++++++++++++++++++++++++ shared-core/nv40_fifo.c | 4 +- 8 files changed, 144 insertions(+), 36 deletions(-) create mode 120000 linux-core/nv04_fifo.c create mode 100644 shared-core/nv04_fifo.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 3e78b6d7..45d2dc46 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -25,7 +25,7 @@ nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ nv04_timer.o \ nv04_mc.o nv40_mc.o \ nv04_fb.o nv10_fb.o nv40_fb.o \ - nv40_fifo.o \ + nv04_fifo.o nv40_fifo.o \ nv04_graph.o nv10_graph.o nv20_graph.o nv30_graph.o \ nv40_graph.o radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o diff --git a/linux-core/nv04_fifo.c b/linux-core/nv04_fifo.c new file mode 120000 index 00000000..d10beb19 --- /dev/null +++ b/linux-core/nv04_fifo.c @@ -0,0 +1 @@ +../shared-core/nv04_fifo.c \ No newline at end of file diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index 07c40107..3e32c2db 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -255,6 +255,12 @@ extern void nv10_fb_takedown(drm_device_t *dev); extern int nv40_fb_init(drm_device_t *dev); extern void nv40_fb_takedown(drm_device_t *dev); +/* nv04_fifo.c */ +extern int nv04_fifo_create_context(drm_device_t *dev, int channel); +extern void nv04_fifo_destroy_context(drm_device_t *dev, int channel); +extern int nv04_fifo_load_context(drm_device_t *dev, int channel); +extern int nv04_fifo_save_context(drm_device_t *dev, int channel); + /* nv40_fifo.c */ extern int nv40_fifo_create_context(drm_device_t *, int channel); extern void nv40_fifo_destroy_context(drm_device_t *, int channel); diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c index 527a71ae..58408a1e 100644 --- a/shared-core/nouveau_fifo.c +++ b/shared-core/nouveau_fifo.c @@ -238,34 +238,6 @@ nouveau_fifo_cmdbuf_alloc(struct drm_device *dev, int channel) return 0; } -#define RAMFC_WR(offset, val) NV_WRITE(fifoctx + NV04_RAMFC_##offset, (val)) -static void nouveau_nv04_context_init(drm_device_t *dev, int channel) -{ - drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_object *cb_obj; - uint32_t fifoctx, ctx_size = 32; - int i; - - cb_obj = dev_priv->fifos[channel].cmdbuf_obj; - - fifoctx=NV_RAMIN+dev_priv->ramfc_offset+channel*ctx_size; - - // clear the fifo context - for(i=0;iinstance)); - - RAMFC_WR(DMA_FETCH, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_112_BYTES | - NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | - NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_4 | -#ifdef __BIG_ENDIAN - NV_PFIFO_CACHE1_BIG_ENDIAN | -#endif - 0x00000000); -} -#undef RAMFC_WR - #define RAMFC_WR(offset, val) NV_WRITE(fifoctx + NV10_RAMFC_##offset, (val)) static void nouveau_nv10_context_init(drm_device_t *dev, int channel) { @@ -488,10 +460,6 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp) /* Construct inital RAMFC for new channel */ switch (dev_priv->card_type) { - case NV_04: - case NV_05: - nouveau_nv04_context_init(dev, channel); - break; case NV_10: case NV_17: nouveau_nv10_context_init(dev, channel); diff --git a/shared-core/nouveau_reg.h b/shared-core/nouveau_reg.h index 07c54a92..ba61f997 100644 --- a/shared-core/nouveau_reg.h +++ b/shared-core/nouveau_reg.h @@ -404,7 +404,7 @@ #define NV10_PFIFO_CACHE1_SEMAPHORE 0x0000326C #define NV03_PFIFO_CACHE1_GET 0x00003270 #define NV04_PFIFO_CACHE1_ENGINE 0x00003280 -#define NV10_PFIFO_CACHE1_DMA_DCOUNT 0x000032A0 +#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)) @@ -427,7 +427,10 @@ #define NV04_RAMFC_DMA_PUT 0x00 #define NV04_RAMFC_DMA_GET 0x04 #define NV04_RAMFC_DMA_INSTANCE 0x08 +#define NV04_RAMFC_DMA_STATE 0x0C #define NV04_RAMFC_DMA_FETCH 0x10 +#define NV04_RAMFC_ENGINE 0x14 +#define NV04_RAMFC_PULL1_ENGINE 0x18 #define NV10_RAMFC_DMA_PUT 0x00 #define NV10_RAMFC_DMA_GET 0x04 diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c index d113f234..ed200e85 100644 --- a/shared-core/nouveau_state.c +++ b/shared-core/nouveau_state.c @@ -90,6 +90,10 @@ static int nouveau_init_engine_ptrs(drm_device_t *dev) engine->graph.takedown = nv04_graph_takedown; engine->fifo.init = nouveau_fifo_init; engine->fifo.takedown = nouveau_stub_takedown; + engine->fifo.create_context = nv04_fifo_create_context; + engine->fifo.destroy_context = nv04_fifo_destroy_context; + engine->fifo.load_context = nv04_fifo_load_context; + engine->fifo.save_context = nv04_fifo_save_context; break; case 0x10: engine->mc.init = nv04_mc_init; diff --git a/shared-core/nv04_fifo.c b/shared-core/nv04_fifo.c new file mode 100644 index 00000000..34a497b7 --- /dev/null +++ b/shared-core/nv04_fifo.c @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2007 Ben Skeggs. + * 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 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. + * + */ + +#include "drmP.h" +#include "drm.h" +#include "nouveau_drv.h" + +#define NV04_RAMFC (NV_RAMIN + dev_priv->ramfc_offset) +#define RAMFC_WR(offset, val) NV_WRITE(fifoctx + NV04_RAMFC_##offset, (val)) +#define RAMFC_RD(offset) NV_READ(fifoctx + NV04_RAMFC_##offset) +#define NV04_FIFO_CONTEXT_SIZE 32 + +int +nv04_fifo_create_context(drm_device_t *dev, int channel) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_object *pb = chan->cmdbuf_obj; + int fifoctx = NV04_RAMFC + (channel * NV04_FIFO_CONTEXT_SIZE); + int i; + + if (!pb || !pb->instance) + return DRM_ERR(EINVAL); + + /* Clear RAMFC */ + for (i=0; ipushbuf_base); + RAMFC_WR(DMA_GET, chan->pushbuf_base); + RAMFC_WR(DMA_INSTANCE, nouveau_chip_instance_get(dev, pb->instance)); + /* NOTE: nvidia use TRIG_128/SIZE_128/MAX_REQS_8 */ + RAMFC_WR(DMA_FETCH, (NV_PFIFO_CACHE1_DMA_FETCH_TRIG_112_BYTES | + NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | + NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_4 | +#ifdef __BIG_ENDIAN + NV_PFIFO_CACHE1_BIG_ENDIAN | +#endif + 0)); + return 0; +} + +void +nv04_fifo_destroy_context(drm_device_t *dev, int channel) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + uint32_t fifoctx; + int i; + + fifoctx = NV04_RAMFC + (channel * NV04_FIFO_CONTEXT_SIZE); + for (i=0; idev_private; + int fifoctx = NV04_RAMFC + (channel * NV04_FIFO_CONTEXT_SIZE); + uint32_t tmp; + + NV_WRITE(NV04_PFIFO_CACHE1_DMA_PUT, RAMFC_RD(DMA_PUT)); + NV_WRITE(NV04_PFIFO_CACHE1_DMA_GET, RAMFC_RD(DMA_GET)); + + tmp = RAMFC_RD(DMA_INSTANCE); + NV_WRITE(NV04_PFIFO_CACHE1_DMA_INSTANCE, tmp & 0xFFFF); + NV_WRITE(NV04_PFIFO_CACHE1_DMA_DCOUNT, tmp >> 16); + + NV_WRITE(NV04_PFIFO_CACHE1_DMA_STATE, RAMFC_RD(DMA_STATE)); + NV_WRITE(NV04_PFIFO_CACHE1_DMA_FETCH, RAMFC_RD(DMA_FETCH)); + NV_WRITE(NV04_PFIFO_CACHE1_ENGINE, RAMFC_RD(ENGINE)); + NV_WRITE(NV04_PFIFO_CACHE1_PULL1, RAMFC_RD(PULL1_ENGINE)); + + /* Reset NV04_PFIFO_CACHE1_DMA_CTL_AT_INFO to INVALID */ + tmp = NV_READ(NV04_PFIFO_CACHE1_DMA_CTL) & ~(1<<31); + NV_WRITE(NV04_PFIFO_CACHE1_DMA_CTL, tmp); + + return 0; +} + +int +nv04_fifo_save_context(drm_device_t *dev, int channel) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + int fifoctx = NV04_RAMFC + (channel * NV04_FIFO_CONTEXT_SIZE); + uint32_t tmp; + + RAMFC_WR(DMA_PUT, NV04_PFIFO_CACHE1_DMA_PUT); + RAMFC_WR(DMA_GET, NV04_PFIFO_CACHE1_DMA_GET); + + tmp = NV_READ(NV04_PFIFO_CACHE1_DMA_DCOUNT) << 16; + tmp |= NV_READ(NV04_PFIFO_CACHE1_DMA_INSTANCE); + RAMFC_WR(DMA_INSTANCE, tmp); + + RAMFC_WR(DMA_STATE, NV_READ(NV04_PFIFO_CACHE1_DMA_STATE)); + RAMFC_WR(DMA_FETCH, NV_READ(NV04_PFIFO_CACHE1_DMA_FETCH)); + RAMFC_WR(ENGINE, NV_READ(NV04_PFIFO_CACHE1_ENGINE)); + RAMFC_WR(PULL1_ENGINE, NV_READ(NV04_PFIFO_CACHE1_PULL1)); + + return 0; +} + diff --git a/shared-core/nv40_fifo.c b/shared-core/nv40_fifo.c index b67a7e58..9d7afbe5 100644 --- a/shared-core/nv40_fifo.c +++ b/shared-core/nv40_fifo.c @@ -91,7 +91,7 @@ nv40_fifo_load_context(drm_device_t *dev, int channel) NV_WRITE(NV04_PFIFO_CACHE1_DMA_PUT , RAMFC_RD(DMA_PUT)); NV_WRITE(NV10_PFIFO_CACHE1_REF_CNT , RAMFC_RD(REF_CNT)); NV_WRITE(NV04_PFIFO_CACHE1_DMA_INSTANCE , RAMFC_RD(DMA_INSTANCE)); - NV_WRITE(NV10_PFIFO_CACHE1_DMA_DCOUNT , RAMFC_RD(DMA_DCOUNT)); + NV_WRITE(NV04_PFIFO_CACHE1_DMA_DCOUNT , RAMFC_RD(DMA_DCOUNT)); NV_WRITE(NV04_PFIFO_CACHE1_DMA_STATE , RAMFC_RD(DMA_STATE)); /* No idea what 0x2058 is.. */ @@ -152,7 +152,7 @@ nv40_fifo_save_context(drm_device_t *dev, int channel) RAMFC_WR(DMA_GET , NV_READ(NV04_PFIFO_CACHE1_DMA_GET)); RAMFC_WR(REF_CNT , NV_READ(NV10_PFIFO_CACHE1_REF_CNT)); RAMFC_WR(DMA_INSTANCE , NV_READ(NV04_PFIFO_CACHE1_DMA_INSTANCE)); - RAMFC_WR(DMA_DCOUNT , NV_READ(NV10_PFIFO_CACHE1_DMA_DCOUNT)); + RAMFC_WR(DMA_DCOUNT , NV_READ(NV04_PFIFO_CACHE1_DMA_DCOUNT)); RAMFC_WR(DMA_STATE , NV_READ(NV04_PFIFO_CACHE1_DMA_STATE)); tmp = NV_READ(NV04_PFIFO_CACHE1_DMA_FETCH); -- cgit v1.2.3 From 341bc7820749024e09275de6e689b10c2908689a Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sun, 24 Jun 2007 18:58:14 +1000 Subject: nouveau: NV1X/2X/3X PFIFO engtab functions Earlier NV1X chips use the NV04 code, see previous commits about NV10 RAMFC entry size. --- linux-core/Makefile.kernel | 2 +- linux-core/nv10_fifo.c | 1 + shared-core/nouveau_drv.h | 6 ++ shared-core/nouveau_fifo.c | 177 ++------------------------------------------ shared-core/nouveau_state.c | 19 +++++ shared-core/nv10_fifo.c | 143 +++++++++++++++++++++++++++++++++++ 6 files changed, 176 insertions(+), 172 deletions(-) create mode 120000 linux-core/nv10_fifo.c create mode 100644 shared-core/nv10_fifo.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 45d2dc46..9427a04b 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -25,7 +25,7 @@ nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ nv04_timer.o \ nv04_mc.o nv40_mc.o \ nv04_fb.o nv10_fb.o nv40_fb.o \ - nv04_fifo.o nv40_fifo.o \ + nv04_fifo.o nv10_fifo.o nv40_fifo.o \ nv04_graph.o nv10_graph.o nv20_graph.o nv30_graph.o \ nv40_graph.o radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o diff --git a/linux-core/nv10_fifo.c b/linux-core/nv10_fifo.c new file mode 120000 index 00000000..8630ad04 --- /dev/null +++ b/linux-core/nv10_fifo.c @@ -0,0 +1 @@ +../shared-core/nv10_fifo.c \ No newline at end of file diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index 3e32c2db..c7872c33 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -261,6 +261,12 @@ extern void nv04_fifo_destroy_context(drm_device_t *dev, int channel); extern int nv04_fifo_load_context(drm_device_t *dev, int channel); extern int nv04_fifo_save_context(drm_device_t *dev, int channel); +/* nv10_fifo.c */ +extern int nv10_fifo_create_context(drm_device_t *dev, int channel); +extern void nv10_fifo_destroy_context(drm_device_t *dev, int channel); +extern int nv10_fifo_load_context(drm_device_t *dev, int channel); +extern int nv10_fifo_save_context(drm_device_t *dev, int channel); + /* nv40_fifo.c */ extern int nv40_fifo_create_context(drm_device_t *, int channel); extern void nv40_fifo_destroy_context(drm_device_t *, int channel); diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c index 58408a1e..0a883647 100644 --- a/shared-core/nouveau_fifo.c +++ b/shared-core/nouveau_fifo.c @@ -238,138 +238,6 @@ nouveau_fifo_cmdbuf_alloc(struct drm_device *dev, int channel) return 0; } -#define RAMFC_WR(offset, val) NV_WRITE(fifoctx + NV10_RAMFC_##offset, (val)) -static void nouveau_nv10_context_init(drm_device_t *dev, int channel) -{ - drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_object *cb_obj; - uint32_t fifoctx; - int ctx_size = nouveau_fifo_ctx_size(dev); - int i; - cb_obj = dev_priv->fifos[channel].cmdbuf_obj; - fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel*ctx_size; - - for (i=0;iinstance)); - - RAMFC_WR(DMA_FETCH, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_112_BYTES | - NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | - NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_4 | -#ifdef __BIG_ENDIAN - NV_PFIFO_CACHE1_BIG_ENDIAN | -#endif - 0x00000000); -} - -static void nouveau_nv30_context_init(drm_device_t *dev, int channel) -{ - drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; - struct nouveau_object *cb_obj; - uint32_t fifoctx, grctx_inst, cb_inst, ctx_size = 64; - int i; - - cb_obj = dev_priv->fifos[channel].cmdbuf_obj; - cb_inst = nouveau_chip_instance_get(dev, chan->cmdbuf_obj->instance); - grctx_inst = nouveau_chip_instance_get(dev, chan->ramin_grctx); - fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel * ctx_size; - - for (i = 0; i < ctx_size; i += 4) - NV_WRITE(fifoctx + i, 0); - - RAMFC_WR(REF_CNT, NV_READ(NV10_PFIFO_CACHE1_REF_CNT)); - RAMFC_WR(DMA_INSTANCE, cb_inst); - RAMFC_WR(DMA_STATE, NV_READ(NV04_PFIFO_CACHE1_DMA_STATE)); - RAMFC_WR(DMA_FETCH, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | - NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | - NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 | -#ifdef __BIG_ENDIAN - NV_PFIFO_CACHE1_BIG_ENDIAN | -#endif - 0x00000000); - - RAMFC_WR(ENGINE, NV_READ(NV04_PFIFO_CACHE1_ENGINE)); - RAMFC_WR(PULL1_ENGINE, NV_READ(NV04_PFIFO_CACHE1_PULL1)); - RAMFC_WR(ACQUIRE_VALUE, NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_VALUE)); - RAMFC_WR(ACQUIRE_TIMESTAMP, NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP)); - RAMFC_WR(ACQUIRE_TIMEOUT, NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT)); - RAMFC_WR(SEMAPHORE, NV_READ(NV10_PFIFO_CACHE1_SEMAPHORE)); -} - -#if 0 -static void nouveau_nv10_context_save(drm_device_t *dev) -{ - drm_nouveau_private_t *dev_priv = dev->dev_private; - uint32_t fifoctx; - int channel; - - channel = NV_READ(NV03_PFIFO_CACHE1_PUSH1) & (nouveau_fifo_number(dev)-1); - fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel*64; - - RAMFC_WR(DMA_PUT , NV_READ(NV04_PFIFO_CACHE1_DMA_PUT)); - RAMFC_WR(DMA_GET , NV_READ(NV04_PFIFO_CACHE1_DMA_GET)); - RAMFC_WR(REF_CNT , NV_READ(NV10_PFIFO_CACHE1_REF_CNT)); - RAMFC_WR(DMA_INSTANCE , NV_READ(NV04_PFIFO_CACHE1_DMA_INSTANCE)); - RAMFC_WR(DMA_STATE , NV_READ(NV04_PFIFO_CACHE1_DMA_STATE)); - RAMFC_WR(DMA_FETCH , NV_READ(NV04_PFIFO_CACHE1_DMA_FETCH)); - RAMFC_WR(ENGINE , NV_READ(NV04_PFIFO_CACHE1_ENGINE)); - RAMFC_WR(PULL1_ENGINE , NV_READ(NV04_PFIFO_CACHE1_PULL1)); - RAMFC_WR(ACQUIRE_VALUE , NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_VALUE)); - RAMFC_WR(ACQUIRE_TIMESTAMP, NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP)); - RAMFC_WR(ACQUIRE_TIMEOUT , NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT)); - RAMFC_WR(SEMAPHORE , NV_READ(NV10_PFIFO_CACHE1_SEMAPHORE)); - RAMFC_WR(DMA_SUBROUTINE , NV_READ(NV10_PFIFO_CACHE1_DMA_SUBROUTINE)); -} -#endif -#undef RAMFC_WR - -/* This function should load values from RAMFC into PFIFO, but for now - * it just clobbers PFIFO with what nouveau_fifo_alloc used to setup - * unconditionally. - */ -static void -nouveau_fifo_context_restore(drm_device_t *dev, int channel) -{ - drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; - uint32_t cb_inst; - - cb_inst = nouveau_chip_instance_get(dev, chan->cmdbuf_obj->instance); - - // FIXME check if we need to refill the time quota with something like NV_WRITE(0x204C, 0x0003FFFF); - - if (dev_priv->card_type >= NV_40) - NV_WRITE(NV03_PFIFO_CACHE1_PUSH1, 0x00010000|channel); - else - NV_WRITE(NV03_PFIFO_CACHE1_PUSH1, 0x00000100|channel); - - NV_WRITE(NV04_PFIFO_CACHE1_DMA_PUT, 0 /*RAMFC_DMA_PUT*/); - NV_WRITE(NV04_PFIFO_CACHE1_DMA_GET, 0 /*RAMFC_DMA_GET*/); - NV_WRITE(NV04_PFIFO_CACHE1_DMA_INSTANCE, cb_inst); - NV_WRITE(NV04_PFIFO_SIZE , 0x0000FFFF); - NV_WRITE(NV04_PFIFO_CACHE1_HASH, 0x0000FFFF); - - NV_WRITE(NV04_PFIFO_CACHE0_PULL1, 0x00000001); - NV_WRITE(NV04_PFIFO_CACHE1_DMA_CTL, 0x00000000); - NV_WRITE(NV04_PFIFO_CACHE1_DMA_STATE, 0x00000000); - NV_WRITE(NV04_PFIFO_CACHE1_ENGINE, 0x00000000); - - NV_WRITE(NV04_PFIFO_CACHE1_DMA_FETCH, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_112_BYTES | - NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | - NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_4 | -#ifdef __BIG_ENDIAN - NV_PFIFO_CACHE1_BIG_ENDIAN | -#endif - 0x00000000); -} - /* allocates and initializes a fifo for user space consumption */ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp) { @@ -459,28 +327,10 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp) } /* Construct inital RAMFC for new channel */ - switch (dev_priv->card_type) { - case NV_10: - case NV_17: - nouveau_nv10_context_init(dev, channel); - break; - case NV_20: - nouveau_nv10_context_init(dev, channel); - break; - case NV_30: - nouveau_nv30_context_init(dev, channel); - break; - default: - if (!engine->fifo.create_context) { - DRM_ERROR("fifo.create_context == NULL\n"); - return DRM_ERR(EINVAL); - } - - ret = engine->fifo.create_context(dev, channel); - if (ret) { - nouveau_fifo_free(dev, channel); - return ret; - } + ret = engine->fifo.create_context(dev, channel); + if (ret) { + nouveau_fifo_free(dev, channel); + return ret; } /* enable the fifo dma operation */ @@ -494,10 +344,7 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp) * other case, the GPU will handle this when it switches contexts. */ if (dev_priv->fifo_alloc_count == 0) { - if (engine->fifo.load_context) - engine->fifo.load_context(dev, channel); - else - nouveau_fifo_context_restore(dev, channel); + engine->fifo.load_context(dev, channel); if (engine->graph.load_context) { ret = engine->graph.load_context(dev, channel); @@ -553,19 +400,7 @@ void nouveau_fifo_free(drm_device_t* dev, int channel) NV_WRITE(NV04_PFIFO_MODE, NV_READ(NV04_PFIFO_MODE)&~(1<fifo.destroy_context) - engine->fifo.destroy_context(dev, channel); - else { - for (i=0;iramfc_offset + - channel*ctx_size + i)); - NV_WRITE(NV_RAMIN + dev_priv->ramfc_offset + - channel*ctx_size + i, 0); - } - } + engine->fifo.destroy_context(dev, channel); /* Cleanup PGRAPH state */ if (engine->graph.destroy_context) diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c index ed200e85..55d10b8c 100644 --- a/shared-core/nouveau_state.c +++ b/shared-core/nouveau_state.c @@ -106,6 +106,17 @@ static int nouveau_init_engine_ptrs(drm_device_t *dev) engine->graph.takedown = nv10_graph_takedown; engine->fifo.init = nouveau_fifo_init; engine->fifo.takedown = nouveau_stub_takedown; + if (dev_priv->chipset < 0x17) { + engine->fifo.create_context = nv04_fifo_create_context; + engine->fifo.destroy_context = nv04_fifo_destroy_context; + engine->fifo.load_context = nv04_fifo_load_context; + engine->fifo.save_context = nv04_fifo_save_context; + } else { + engine->fifo.create_context = nv10_fifo_create_context; + engine->fifo.destroy_context = nv10_fifo_destroy_context; + engine->fifo.load_context = nv10_fifo_load_context; + engine->fifo.save_context = nv10_fifo_save_context; + } break; case 0x20: engine->mc.init = nv04_mc_init; @@ -118,6 +129,10 @@ static int nouveau_init_engine_ptrs(drm_device_t *dev) engine->graph.takedown = nv20_graph_takedown; engine->fifo.init = nouveau_fifo_init; engine->fifo.takedown = nouveau_stub_takedown; + engine->fifo.create_context = nv10_fifo_create_context; + engine->fifo.destroy_context = nv10_fifo_destroy_context; + engine->fifo.load_context = nv10_fifo_load_context; + engine->fifo.save_context = nv10_fifo_save_context; break; case 0x30: engine->mc.init = nv04_mc_init; @@ -130,6 +145,10 @@ static int nouveau_init_engine_ptrs(drm_device_t *dev) engine->graph.takedown = nv30_graph_takedown; engine->fifo.init = nouveau_fifo_init; engine->fifo.takedown = nouveau_stub_takedown; + engine->fifo.create_context = nv10_fifo_create_context; + engine->fifo.destroy_context = nv10_fifo_destroy_context; + engine->fifo.load_context = nv10_fifo_load_context; + engine->fifo.save_context = nv10_fifo_save_context; break; case 0x40: engine->mc.init = nv40_mc_init; diff --git a/shared-core/nv10_fifo.c b/shared-core/nv10_fifo.c new file mode 100644 index 00000000..8dad45aa --- /dev/null +++ b/shared-core/nv10_fifo.c @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2007 Ben Skeggs. + * 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 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. + * + */ + +#include "drmP.h" +#include "drm.h" +#include "nouveau_drv.h" + +#define RAMFC_WR(offset, val) NV_WRITE(fifoctx + NV10_RAMFC_##offset, (val)) +#define RAMFC_RD(offset) NV_READ (fifoctx + NV10_RAMFC_##offset) +#define NV10_FIFO_CONTEXT_SIZE 64 + +int +nv10_fifo_create_context(drm_device_t *dev, int channel) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + uint32_t fifoctx, pushbuf; + int i; + + pushbuf = nouveau_chip_instance_get(dev, chan->cmdbuf_obj->instance); + + fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel*64; + for (i=0; ipushbuf_base); + RAMFC_WR(DMA_GET , chan->pushbuf_base); + RAMFC_WR(DMA_INSTANCE , pushbuf); + RAMFC_WR(DMA_FETCH , NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | + NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | + NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 | +#ifdef __BIG_ENDIAN + NV_PFIFO_CACHE1_BIG_ENDIAN | +#endif + 0); + + return 0; +} + +void +nv10_fifo_destroy_context(drm_device_t *dev, int channel) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + uint32_t fifoctx; + int i; + + fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel*64; + for (i=0; idev_private; + uint32_t fifoctx; + uint32_t tmp; + + fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel*64; + + NV_WRITE(NV03_PFIFO_CACHE1_PUSH1 , 0x00000100 | channel); + + NV_WRITE(NV04_PFIFO_CACHE1_DMA_GET , RAMFC_RD(DMA_GET)); + NV_WRITE(NV04_PFIFO_CACHE1_DMA_PUT , RAMFC_RD(DMA_PUT)); + NV_WRITE(NV10_PFIFO_CACHE1_REF_CNT , RAMFC_RD(REF_CNT)); + + tmp = RAMFC_RD(DMA_INSTANCE); + NV_WRITE(NV04_PFIFO_CACHE1_DMA_INSTANCE , tmp & 0xFFFF); + NV_WRITE(NV04_PFIFO_CACHE1_DMA_DCOUNT , tmp >> 16); + + NV_WRITE(NV04_PFIFO_CACHE1_DMA_STATE , RAMFC_RD(DMA_STATE)); + NV_WRITE(NV04_PFIFO_CACHE1_DMA_FETCH , RAMFC_RD(DMA_FETCH)); + NV_WRITE(NV04_PFIFO_CACHE1_ENGINE , RAMFC_RD(ENGINE)); + NV_WRITE(NV04_PFIFO_CACHE1_PULL1 , RAMFC_RD(PULL1_ENGINE)); + NV_WRITE(NV10_PFIFO_CACHE1_ACQUIRE_VALUE , RAMFC_RD(ACQUIRE_VALUE)); + NV_WRITE(NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP, RAMFC_RD(ACQUIRE_TIMESTAMP)); + NV_WRITE(NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT , RAMFC_RD(ACQUIRE_TIMEOUT)); + NV_WRITE(NV10_PFIFO_CACHE1_SEMAPHORE , RAMFC_RD(SEMAPHORE)); + NV_WRITE(NV10_PFIFO_CACHE1_DMA_SUBROUTINE , RAMFC_RD(DMA_SUBROUTINE)); + + /* Reset NV04_PFIFO_CACHE1_DMA_CTL_AT_INFO to INVALID */ + tmp = NV_READ(NV04_PFIFO_CACHE1_DMA_CTL) & ~(1<<31); + NV_WRITE(NV04_PFIFO_CACHE1_DMA_CTL, tmp); + + return 0; +} + +int +nv10_fifo_save_context(drm_device_t *dev, int channel) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + uint32_t fifoctx; + uint32_t tmp; + + fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel*64; + + RAMFC_WR(DMA_PUT , NV_READ(NV04_PFIFO_CACHE1_DMA_PUT)); + RAMFC_WR(DMA_GET , NV_READ(NV04_PFIFO_CACHE1_DMA_GET)); + RAMFC_WR(REF_CNT , NV_READ(NV10_PFIFO_CACHE1_REF_CNT)); + + tmp = NV_READ(NV04_PFIFO_CACHE1_DMA_INSTANCE) & 0xFFFF; + tmp |= (NV_READ(NV04_PFIFO_CACHE1_DMA_DCOUNT) << 16); + RAMFC_WR(DMA_INSTANCE , tmp); + + RAMFC_WR(DMA_STATE , NV_READ(NV04_PFIFO_CACHE1_DMA_STATE)); + RAMFC_WR(DMA_FETCH , NV_READ(NV04_PFIFO_CACHE1_DMA_FETCH)); + RAMFC_WR(ENGINE , NV_READ(NV04_PFIFO_CACHE1_ENGINE)); + RAMFC_WR(PULL1_ENGINE , NV_READ(NV04_PFIFO_CACHE1_PULL1)); + RAMFC_WR(ACQUIRE_VALUE , NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_VALUE)); + RAMFC_WR(ACQUIRE_TIMESTAMP, NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP)); + RAMFC_WR(ACQUIRE_TIMEOUT , NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT)); + RAMFC_WR(SEMAPHORE , NV_READ(NV10_PFIFO_CACHE1_SEMAPHORE)); + RAMFC_WR(DMA_SUBROUTINE , NV_READ(NV04_PFIFO_CACHE1_DMA_GET)); + + return 0; +} + -- cgit v1.2.3 From 5d55b0655cb480b7d6ab4cf2467dac6dc6d8df25 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sun, 24 Jun 2007 18:58:38 +1000 Subject: nouveau: NV3X PGRAPH engtab functions --- shared-core/nouveau_drv.h | 7 +++-- shared-core/nouveau_fifo.c | 9 ------- shared-core/nouveau_state.c | 4 +++ shared-core/nv30_graph.c | 66 ++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 74 insertions(+), 12 deletions(-) diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index c7872c33..a4a37648 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -292,9 +292,12 @@ extern void nv20_graph_takedown(drm_device_t *dev); extern int nv20_graph_context_create(drm_device_t *dev, int channel); /* nv30_graph.c */ -extern int nv30_graph_init(drm_device_t *dev); +extern int nv30_graph_init(drm_device_t *dev); extern void nv30_graph_takedown(drm_device_t *dev); -extern int nv30_graph_context_create(drm_device_t *dev, int channel); +extern int nv30_graph_create_context(drm_device_t *, int channel); +extern void nv30_graph_destroy_context(drm_device_t *, int channel); +extern int nv30_graph_load_context(drm_device_t *, int channel); +extern int nv30_graph_save_context(drm_device_t *, int channel); /* nv40_graph.c */ extern int nv40_graph_init(drm_device_t *); diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c index 0a883647..1ef5a425 100644 --- a/shared-core/nouveau_fifo.c +++ b/shared-core/nouveau_fifo.c @@ -306,13 +306,6 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp) return ret; } break; - case NV_30: - ret = nv30_graph_context_create(dev, channel); - if (ret) { - nouveau_fifo_free(dev, channel); - return ret; - } - break; default: if (!engine->graph.create_context) { DRM_ERROR("graph.create_context == NULL\n"); @@ -388,8 +381,6 @@ void nouveau_fifo_free(drm_device_t* dev, int channel) drm_nouveau_private_t *dev_priv = dev->dev_private; nouveau_engine_func_t *engine = &dev_priv->Engine; struct nouveau_fifo *chan = &dev_priv->fifos[channel]; - int i; - int ctx_size = nouveau_fifo_ctx_size(dev); chan->used = 0; DRM_INFO("%s: freeing fifo %d\n", __func__, channel); diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c index 55d10b8c..a997b075 100644 --- a/shared-core/nouveau_state.c +++ b/shared-core/nouveau_state.c @@ -143,6 +143,10 @@ static int nouveau_init_engine_ptrs(drm_device_t *dev) engine->fb.takedown = nv10_fb_takedown; engine->graph.init = nv30_graph_init; engine->graph.takedown = nv30_graph_takedown; + engine->graph.create_context = nv30_graph_create_context; + engine->graph.destroy_context = nv30_graph_destroy_context; + engine->graph.load_context = nv30_graph_load_context; + engine->graph.save_context = nv30_graph_save_context; engine->fifo.init = nouveau_fifo_init; engine->fifo.takedown = nouveau_stub_takedown; engine->fifo.create_context = nv10_fifo_create_context; diff --git a/shared-core/nv30_graph.c b/shared-core/nv30_graph.c index f4faadd8..9f064a0a 100644 --- a/shared-core/nv30_graph.c +++ b/shared-core/nv30_graph.c @@ -100,7 +100,7 @@ static void nv30_graph_context_init(drm_device_t *dev, struct mem_block *ctx) } -int nv30_graph_context_create(drm_device_t *dev, int channel) +int nv30_graph_create_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = (drm_nouveau_private_t *)dev->dev_private; @@ -132,6 +132,70 @@ int nv30_graph_context_create(drm_device_t *dev, int channel) return 0; } +void nv30_graph_destroy_context(drm_device_t *dev, int channel) +{ + drm_nouveau_private_t *dev_priv = + (drm_nouveau_private_t *)dev->dev_private; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + + if (chan->ramin_grctx) { + nouveau_instmem_free(dev, chan->ramin_grctx); + chan->ramin_grctx = NULL; + } + + INSTANCE_WR(dev_priv->ctx_table, channel, 0); +} + +static int +nouveau_graph_wait_idle(drm_device_t *dev) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + int tv = 1000; + + while (tv--) { + if (NV_READ(0x400700) == 0) + break; + } + + if (NV_READ(0x400700)) { + DRM_ERROR("timeout!\n"); + return DRM_ERR(EBUSY); + } + return 0; +} + +int nv30_graph_load_context(drm_device_t *dev, int channel) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + uint32_t inst; + + if (!chan->ramin_grctx) + return DRM_ERR(EINVAL); + inst = nouveau_chip_instance_get(dev, chan->ramin_grctx); + + NV_WRITE(0x400784, inst); + NV_WRITE(0x400788, 1); + + return nouveau_graph_wait_idle(dev); +} + +int nv30_graph_save_context(drm_device_t *dev, int channel) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + uint32_t inst; + + if (!chan->ramin_grctx) + return DRM_ERR(EINVAL); + inst = nouveau_chip_instance_get(dev, chan->ramin_grctx); + + NV_WRITE(0x400784, inst); + NV_WRITE(0x400788, 2); + + return nouveau_graph_wait_idle(dev); +} + int nv30_graph_init(drm_device_t *dev) { drm_nouveau_private_t *dev_priv = -- cgit v1.2.3 From 5f05cd7086c54bccf1c2f0b003b78a08dc55472a Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sun, 24 Jun 2007 19:00:26 +1000 Subject: nouveau: NV04/NV10/NV20 PGRAPH engtab functions NV04/NV10 load_context()/save_context() are stubs. I don't know enough about how they work to implement them sanely. The "old" context_switch() code remains hooked up, so it shouldn't break anything. NV20 will probably break if load_context() works. No inital context values are filled in, so when the first channel is created PGRAPH will probably end up having its state zeroed. Some setup from nv20_graph_init() will probably need to be moved to the per-channel context setup. --- shared-core/nouveau_drv.h | 21 +++++++++++++++------ shared-core/nouveau_fifo.c | 32 ++++---------------------------- shared-core/nouveau_state.c | 12 ++++++++++++ shared-core/nv04_graph.c | 17 ++++++++++++++++- shared-core/nv10_graph.c | 17 ++++++++++++++++- shared-core/nv20_graph.c | 33 +++++++++++++++++++++++---------- 6 files changed, 86 insertions(+), 46 deletions(-) diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index a4a37648..b3122d8a 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -275,21 +275,30 @@ extern int nv40_fifo_save_context(drm_device_t *, int channel); /* nv04_graph.c */ extern void nouveau_nv04_context_switch(drm_device_t *dev); -extern int nv04_graph_init(drm_device_t *dev); +extern int nv04_graph_init(drm_device_t *dev); extern void nv04_graph_takedown(drm_device_t *dev); -extern int nv04_graph_context_create(drm_device_t *dev, int channel); +extern int nv04_graph_create_context(drm_device_t *dev, int channel); +extern void nv04_graph_destroy_context(drm_device_t *dev, int channel); +extern int nv04_graph_load_context(drm_device_t *dev, int channel); +extern int nv04_graph_save_context(drm_device_t *dev, int channel); /* nv10_graph.c */ extern void nouveau_nv10_context_switch(drm_device_t *dev); -extern int nv10_graph_init(drm_device_t *dev); +extern int nv10_graph_init(drm_device_t *dev); extern void nv10_graph_takedown(drm_device_t *dev); -extern int nv10_graph_context_create(drm_device_t *dev, int channel); +extern int nv10_graph_create_context(drm_device_t *dev, int channel); +extern void nv10_graph_destroy_context(drm_device_t *dev, int channel); +extern int nv10_graph_load_context(drm_device_t *dev, int channel); +extern int nv10_graph_save_context(drm_device_t *dev, int channel); /* nv20_graph.c */ extern void nouveau_nv20_context_switch(drm_device_t *dev); -extern int nv20_graph_init(drm_device_t *dev); +extern int nv20_graph_init(drm_device_t *dev); extern void nv20_graph_takedown(drm_device_t *dev); -extern int nv20_graph_context_create(drm_device_t *dev, int channel); +extern int nv20_graph_create_context(drm_device_t *dev, int channel); +extern void nv20_graph_destroy_context(drm_device_t *dev, int channel); +extern int nv20_graph_load_context(drm_device_t *dev, int channel); +extern int nv20_graph_save_context(drm_device_t *dev, int channel); /* nv30_graph.c */ extern int nv30_graph_init(drm_device_t *dev); diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c index 1ef5a425..b47d4e0c 100644 --- a/shared-core/nouveau_fifo.c +++ b/shared-core/nouveau_fifo.c @@ -289,34 +289,10 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp) NV_WRITE(NV04_PFIFO_CACHE1_PULL0, 0x00000000); /* Create a graphics context for new channel */ - switch(dev_priv->card_type) - { - case NV_04: - case NV_05: - nv04_graph_context_create(dev, channel); - break; - case NV_10: - case NV_17: - nv10_graph_context_create(dev, channel); - break; - case NV_20: - ret = nv20_graph_context_create(dev, channel); - if (ret) { - nouveau_fifo_free(dev, channel); - return ret; - } - break; - default: - if (!engine->graph.create_context) { - DRM_ERROR("graph.create_context == NULL\n"); - return DRM_ERR(EINVAL); - } - ret = engine->graph.create_context(dev, channel); - if (ret) { - nouveau_fifo_free(dev, channel); - return ret; - } - break; + ret = engine->graph.create_context(dev, channel); + if (ret) { + nouveau_fifo_free(dev, channel); + return ret; } /* Construct inital RAMFC for new channel */ diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c index a997b075..b3562e2f 100644 --- a/shared-core/nouveau_state.c +++ b/shared-core/nouveau_state.c @@ -88,6 +88,10 @@ static int nouveau_init_engine_ptrs(drm_device_t *dev) engine->fb.takedown = nv04_fb_takedown; engine->graph.init = nv04_graph_init; engine->graph.takedown = nv04_graph_takedown; + engine->graph.create_context = nv04_graph_create_context; + engine->graph.destroy_context = nv04_graph_destroy_context; + engine->graph.load_context = nv04_graph_load_context; + engine->graph.save_context = nv04_graph_save_context; engine->fifo.init = nouveau_fifo_init; engine->fifo.takedown = nouveau_stub_takedown; engine->fifo.create_context = nv04_fifo_create_context; @@ -104,6 +108,10 @@ static int nouveau_init_engine_ptrs(drm_device_t *dev) engine->fb.takedown = nv10_fb_takedown; engine->graph.init = nv10_graph_init; engine->graph.takedown = nv10_graph_takedown; + engine->graph.create_context = nv10_graph_create_context; + engine->graph.destroy_context = nv10_graph_destroy_context; + engine->graph.load_context = nv10_graph_load_context; + engine->graph.save_context = nv10_graph_save_context; engine->fifo.init = nouveau_fifo_init; engine->fifo.takedown = nouveau_stub_takedown; if (dev_priv->chipset < 0x17) { @@ -127,6 +135,10 @@ static int nouveau_init_engine_ptrs(drm_device_t *dev) engine->fb.takedown = nv10_fb_takedown; engine->graph.init = nv20_graph_init; engine->graph.takedown = nv20_graph_takedown; + engine->graph.create_context = nv20_graph_create_context; + engine->graph.destroy_context = nv20_graph_destroy_context; + engine->graph.load_context = nv20_graph_load_context; + engine->graph.save_context = nv20_graph_save_context; engine->fifo.init = nouveau_fifo_init; engine->fifo.takedown = nouveau_stub_takedown; engine->fifo.create_context = nv10_fifo_create_context; diff --git a/shared-core/nv04_graph.c b/shared-core/nv04_graph.c index 0cd4d3b8..1aaae33c 100644 --- a/shared-core/nv04_graph.c +++ b/shared-core/nv04_graph.c @@ -336,7 +336,7 @@ void nouveau_nv04_context_switch(drm_device_t *dev) NV_WRITE(NV04_PGRAPH_FIFO,0x1); } -int nv04_graph_context_create(drm_device_t *dev, int channel) { +int nv04_graph_create_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; DRM_DEBUG("nv04_graph_context_create %d\n", channel); @@ -351,6 +351,21 @@ int nv04_graph_context_create(drm_device_t *dev, int channel) { return 0; } +void nv04_graph_destroy_context(drm_device_t *dev, int channel) +{ +} + +int nv04_graph_load_context(drm_device_t *dev, int channel) +{ + DRM_ERROR("stub!\n"); + return 0; +} + +int nv04_graph_save_context(drm_device_t *dev, int channel) +{ + DRM_ERROR("stub!\n"); + return 0; +} int nv04_graph_init(drm_device_t *dev) { drm_nouveau_private_t *dev_priv = dev->dev_private; diff --git a/shared-core/nv10_graph.c b/shared-core/nv10_graph.c index fb189709..d1fe0a54 100644 --- a/shared-core/nv10_graph.c +++ b/shared-core/nv10_graph.c @@ -611,7 +611,7 @@ void nouveau_nv10_context_switch(drm_device_t *dev) if (offset > 0) \ fifo->pgraph_ctx[offset] = val; \ } while (0) -int nv10_graph_context_create(drm_device_t *dev, int channel) { +int nv10_graph_create_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; struct nouveau_fifo *fifo = &dev_priv->fifos[channel]; uint32_t tmp, vramsz; @@ -663,6 +663,21 @@ int nv10_graph_context_create(drm_device_t *dev, int channel) { return 0; } +void nv10_graph_destroy_context(drm_device_t *dev, int channel) +{ +} + +int nv10_graph_load_context(drm_device_t *dev, int channel) +{ + DRM_ERROR("stub!\n"); + return 0; +} + +int nv10_graph_save_context(drm_device_t *dev, int channel) +{ + DRM_ERROR("stub!\n"); + return 0; +} int nv10_graph_init(drm_device_t *dev) { drm_nouveau_private_t *dev_priv = dev->dev_private; diff --git a/shared-core/nv20_graph.c b/shared-core/nv20_graph.c index 7190fc84..1b8a6727 100644 --- a/shared-core/nv20_graph.c +++ b/shared-core/nv20_graph.c @@ -29,7 +29,7 @@ #define NV20_GRCTX_SIZE (3529*4) -int nv20_graph_context_create(drm_device_t *dev, int channel) { +int nv20_graph_create_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = (drm_nouveau_private_t *)dev->dev_private; struct nouveau_fifo *chan = &dev_priv->fifos[channel]; @@ -47,10 +47,21 @@ int nv20_graph_context_create(drm_device_t *dev, int channel) { INSTANCE_WR(chan->ramin_grctx, 10, channel << 24); /* CTX_USER */ INSTANCE_WR(dev_priv->ctx_table, channel, nouveau_chip_instance_get(dev, chan->ramin_grctx)); - return 0; } +void nv20_graph_destroy_context(drm_device_t *dev, int channel) { + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + + if (chan->ramin_grctx) { + nouveau_instmem_free(dev, chan->ramin_grctx); + chan->ramin_grctx = NULL; + } + + INSTANCE_WR(dev_priv->ctx_table, channel, 0); +} + static void nv20_graph_rdi(drm_device_t *dev) { drm_nouveau_private_t *dev_priv = (drm_nouveau_private_t *)dev->dev_private; @@ -65,40 +76,42 @@ static void nv20_graph_rdi(drm_device_t *dev) { /* Save current context (from PGRAPH) into the channel's context */ -static void nv20_graph_context_save_current(drm_device_t *dev, int channel) { +int nv20_graph_save_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = (drm_nouveau_private_t *)dev->dev_private; uint32_t instance; instance = INSTANCE_RD(dev_priv->ctx_table, channel); if (!instance) { - return; + return DRM_ERR(EINVAL); } if (instance != nouveau_chip_instance_get(dev, dev_priv->fifos[channel].ramin_grctx)) - DRM_ERROR("nv20_graph_context_save_current : bad instance\n"); + DRM_ERROR("nv20_graph_save_context : bad instance\n"); NV_WRITE(NV10_PGRAPH_CHANNEL_CTX_SIZE, instance); NV_WRITE(NV10_PGRAPH_CHANNEL_CTX_POINTER, 2 /* save ctx */); + return 0; } /* Restore the context for a specific channel into PGRAPH */ -static void nv20_graph_context_restore(drm_device_t *dev, int channel) { +int nv20_graph_load_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = (drm_nouveau_private_t *)dev->dev_private; uint32_t instance; instance = INSTANCE_RD(dev_priv->ctx_table, channel); if (!instance) { - return; + return DRM_ERR(EINVAL); } if (instance != nouveau_chip_instance_get(dev, dev_priv->fifos[channel].ramin_grctx)) - DRM_ERROR("nv20_graph_context_restore_current : bad instance\n"); + DRM_ERROR("nv20_graph_load_context_current : bad instance\n"); NV_WRITE(NV10_PGRAPH_CTX_USER, channel << 24); NV_WRITE(NV10_PGRAPH_CHANNEL_CTX_SIZE, instance); NV_WRITE(NV10_PGRAPH_CHANNEL_CTX_POINTER, 1 /* restore ctx */); + return 0; } void nouveau_nv20_context_switch(drm_device_t *dev) @@ -113,13 +126,13 @@ void nouveau_nv20_context_switch(drm_device_t *dev) NV_WRITE(NV04_PGRAPH_FIFO,0x0); - nv20_graph_context_save_current(dev, channel_old); + nv20_graph_save_context(dev, channel_old); nouveau_wait_for_idle(dev); NV_WRITE(NV10_PGRAPH_CTX_CONTROL, 0x10000000); - nv20_graph_context_restore(dev, channel); + nv20_graph_load_context(dev, channel); nouveau_wait_for_idle(dev); -- cgit v1.2.3 From 3dfc13e2da10e86051c7106feb5683542907acdc Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sun, 24 Jun 2007 19:00:44 +1000 Subject: nouveau: kill some dead code --- shared-core/nouveau_fifo.c | 41 +++++++++++------------------------------ 1 file changed, 11 insertions(+), 30 deletions(-) diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c index b47d4e0c..3c07b0da 100644 --- a/shared-core/nouveau_fifo.c +++ b/shared-core/nouveau_fifo.c @@ -313,27 +313,16 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp) * other case, the GPU will handle this when it switches contexts. */ if (dev_priv->fifo_alloc_count == 0) { - engine->fifo.load_context(dev, channel); - - if (engine->graph.load_context) { - ret = engine->graph.load_context(dev, channel); - if (ret) { - nouveau_fifo_free(dev, channel); - return ret; - } - } else - if (dev_priv->card_type >= NV_30) { - uint32_t inst; - - inst = nouveau_chip_instance_get(dev, - chan->ramin_grctx); - - /* see comments in nv40_graph_context_restore() */ - NV_WRITE(NV10_PGRAPH_CHANNEL_CTX_SIZE, inst); - if (dev_priv->card_type >= NV_40) { - NV_WRITE(0x40032C, inst | 0x01000000); - NV_WRITE(NV40_PFIFO_GRCTX_INSTANCE, inst); - } + ret = engine->fifo.load_context(dev, channel); + if (ret) { + nouveau_fifo_free(dev, channel); + return ret; + } + + ret = engine->graph.load_context(dev, channel); + if (ret) { + nouveau_fifo_free(dev, channel); + return ret; } } @@ -370,15 +359,7 @@ void nouveau_fifo_free(drm_device_t* dev, int channel) engine->fifo.destroy_context(dev, channel); /* Cleanup PGRAPH state */ - if (engine->graph.destroy_context) - engine->graph.destroy_context(dev, channel); - else if (dev_priv->card_type >= NV_30) { - } - else if (dev_priv->card_type >= NV_20) { - /* clear ctx table */ - INSTANCE_WR(dev_priv->ctx_table, channel, 0); - nouveau_instmem_free(dev, chan->ramin_grctx); - } + engine->graph.destroy_context(dev, channel); /* reenable the fifo caches */ NV_WRITE(NV03_PFIFO_CACHES, 0x00000001); -- cgit v1.2.3 From 9f617522d9cb8cd33e588d12a13f427dbe5171c2 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 25 Jun 2007 01:57:57 +1000 Subject: nouveau: NV49/NV4B PGRAPH setup from jb17bsome and stephan_2303 --- shared-core/nouveau_fifo.c | 2 + shared-core/nv40_graph.c | 497 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 494 insertions(+), 5 deletions(-) diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c index 3c07b0da..1a06f913 100644 --- a/shared-core/nouveau_fifo.c +++ b/shared-core/nouveau_fifo.c @@ -83,6 +83,8 @@ static int nouveau_fifo_instmem_configure(drm_device_t *dev) case NV_50: case NV_40: NV_WRITE(NV40_PFIFO_RAMFC, 0x30002); + if((dev_priv->chipset == 0x49) || (dev_priv->chipset == 0x4b)) + NV_WRITE(0x2230,0x00000001); break; case NV_44: NV_WRITE(NV40_PFIFO_RAMFC, ((nouveau_mem_fb_amount(dev)-512*1024+dev_priv->ramfc_offset)>>16) | diff --git a/shared-core/nv40_graph.c b/shared-core/nv40_graph.c index 245da54d..acd0cb0f 100644 --- a/shared-core/nv40_graph.c +++ b/shared-core/nv40_graph.c @@ -36,7 +36,9 @@ #define NV40_GRCTX_SIZE (175*1024) #define NV43_GRCTX_SIZE (70*1024) #define NV46_GRCTX_SIZE (70*1024) /* probably ~64KiB */ +#define NV49_GRCTX_SIZE (164640) #define NV4A_GRCTX_SIZE (64*1024) +#define NV4B_GRCTX_SIZE (164640) #define NV4C_GRCTX_SIZE (25*1024) #define NV4E_GRCTX_SIZE (25*1024) @@ -44,7 +46,8 @@ * contexts are taken from dumps just after the 3D object is * created. */ -static void nv40_graph_context_init(drm_device_t *dev, struct mem_block *ctx) +static void +nv40_graph_context_init(drm_device_t *dev, struct mem_block *ctx) { drm_nouveau_private_t *dev_priv = dev->dev_private; int i; @@ -300,7 +303,8 @@ nv43_graph_context_init(drm_device_t *dev, struct mem_block *ctx) INSTANCE_WR(ctx, i/4, 0x3f800000); }; -static void nv46_graph_context_init(drm_device_t *dev, struct mem_block *ctx) +static void +nv46_graph_context_init(drm_device_t *dev, struct mem_block *ctx) { drm_nouveau_private_t *dev_priv = dev->dev_private; int i; @@ -450,7 +454,231 @@ static void nv46_graph_context_init(drm_device_t *dev, struct mem_block *ctx) INSTANCE_WR(ctx, i/4, 0x3f800000); } -static void nv4a_graph_context_init(drm_device_t *dev, struct mem_block *ctx) +static void +nv49_graph_context_init(drm_device_t *dev, struct mem_block *ctx) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + int i; + + INSTANCE_WR(ctx, 0x00000/4, nouveau_chip_instance_get(dev, ctx)); + INSTANCE_WR(ctx, 0x00004/4, 0x0000c040); + INSTANCE_WR(ctx, 0x00008/4, 0x0000c040); + INSTANCE_WR(ctx, 0x0000c/4, 0x0000c040); + INSTANCE_WR(ctx, 0x00010/4, 0x0000c040); + INSTANCE_WR(ctx, 0x00014/4, 0x0000c040); + INSTANCE_WR(ctx, 0x00018/4, 0x0000c040); + INSTANCE_WR(ctx, 0x0001c/4, 0x0000c040); + INSTANCE_WR(ctx, 0x00020/4, 0x0000c040); + INSTANCE_WR(ctx, 0x000c4/4, 0x0000ffff); + INSTANCE_WR(ctx, 0x000c8/4, 0x0000ffff); + INSTANCE_WR(ctx, 0x000d0/4, 0x00000001); + INSTANCE_WR(ctx, 0x001bc/4, 0x20010001); + INSTANCE_WR(ctx, 0x001c0/4, 0x0f73ef00); + INSTANCE_WR(ctx, 0x001c8/4, 0x02008821); + INSTANCE_WR(ctx, 0x00218/4, 0x00000040); + INSTANCE_WR(ctx, 0x0021c/4, 0x00000040); + INSTANCE_WR(ctx, 0x00220/4, 0x00000040); + INSTANCE_WR(ctx, 0x00228/4, 0x00000040); + INSTANCE_WR(ctx, 0x00234/4, 0x80000000); + INSTANCE_WR(ctx, 0x00238/4, 0x80000000); + INSTANCE_WR(ctx, 0x0023c/4, 0x80000000); + INSTANCE_WR(ctx, 0x00240/4, 0x80000000); + INSTANCE_WR(ctx, 0x00244/4, 0x80000000); + INSTANCE_WR(ctx, 0x00248/4, 0x80000000); + INSTANCE_WR(ctx, 0x0024c/4, 0x80000000); + INSTANCE_WR(ctx, 0x00250/4, 0x80000000); + INSTANCE_WR(ctx, 0x00270/4, 0x0b0b0b0c); + INSTANCE_WR(ctx, 0x003e0/4, 0x00040000); + INSTANCE_WR(ctx, 0x003f0/4, 0x55555555); + INSTANCE_WR(ctx, 0x003f4/4, 0x55555555); + INSTANCE_WR(ctx, 0x003f8/4, 0x55555555); + INSTANCE_WR(ctx, 0x003fc/4, 0x55555555); + INSTANCE_WR(ctx, 0x00428/4, 0x00000008); + INSTANCE_WR(ctx, 0x0043c/4, 0x00001010); + INSTANCE_WR(ctx, 0x00460/4, 0x00000111); + INSTANCE_WR(ctx, 0x00464/4, 0x00000111); + INSTANCE_WR(ctx, 0x00468/4, 0x00000111); + INSTANCE_WR(ctx, 0x0046c/4, 0x00000111); + INSTANCE_WR(ctx, 0x00470/4, 0x00000111); + INSTANCE_WR(ctx, 0x00474/4, 0x00000111); + INSTANCE_WR(ctx, 0x00478/4, 0x00000111); + INSTANCE_WR(ctx, 0x0047c/4, 0x00000111); + INSTANCE_WR(ctx, 0x00480/4, 0x00000111); + INSTANCE_WR(ctx, 0x00484/4, 0x00000111); + INSTANCE_WR(ctx, 0x00488/4, 0x00000111); + INSTANCE_WR(ctx, 0x0048c/4, 0x00000111); + INSTANCE_WR(ctx, 0x00490/4, 0x00000111); + INSTANCE_WR(ctx, 0x00494/4, 0x00000111); + INSTANCE_WR(ctx, 0x00498/4, 0x00000111); + INSTANCE_WR(ctx, 0x0049c/4, 0x00000111); + INSTANCE_WR(ctx, 0x004f4/4, 0x00000111); + INSTANCE_WR(ctx, 0x004f8/4, 0x00080060); + INSTANCE_WR(ctx, 0x00514/4, 0x00000080); + INSTANCE_WR(ctx, 0x00518/4, 0xffff0000); + INSTANCE_WR(ctx, 0x0051c/4, 0x00000001); + INSTANCE_WR(ctx, 0x00530/4, 0x46400000); + INSTANCE_WR(ctx, 0x00540/4, 0xffff0000); + INSTANCE_WR(ctx, 0x00544/4, 0x88888888); + INSTANCE_WR(ctx, 0x00548/4, 0x88888888); + INSTANCE_WR(ctx, 0x0054c/4, 0x88888888); + INSTANCE_WR(ctx, 0x00550/4, 0x88888888); + INSTANCE_WR(ctx, 0x00554/4, 0x88888888); + INSTANCE_WR(ctx, 0x00558/4, 0x88888888); + INSTANCE_WR(ctx, 0x0055c/4, 0x88888888); + INSTANCE_WR(ctx, 0x00560/4, 0x88888888); + INSTANCE_WR(ctx, 0x00564/4, 0x88888888); + INSTANCE_WR(ctx, 0x00568/4, 0x88888888); + INSTANCE_WR(ctx, 0x0056c/4, 0x88888888); + INSTANCE_WR(ctx, 0x00570/4, 0x88888888); + INSTANCE_WR(ctx, 0x00574/4, 0x88888888); + INSTANCE_WR(ctx, 0x00578/4, 0x88888888); + INSTANCE_WR(ctx, 0x0057c/4, 0x88888888); + INSTANCE_WR(ctx, 0x00580/4, 0x88888888); + INSTANCE_WR(ctx, 0x00594/4, 0x0fff0000); + INSTANCE_WR(ctx, 0x00598/4, 0x0fff0000); + INSTANCE_WR(ctx, 0x005a0/4, 0x00011100); + INSTANCE_WR(ctx, 0x005bc/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005c0/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005c4/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005c8/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005cc/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005d0/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005d4/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005d8/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005dc/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005e0/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005e4/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005e8/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005ec/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005f0/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005f4/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005f8/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x00604/4, 0x4b7fffff); + INSTANCE_WR(ctx, 0x0062c/4, 0x30201000); + INSTANCE_WR(ctx, 0x00630/4, 0x70605040); + INSTANCE_WR(ctx, 0x00634/4, 0xb8a89888); + INSTANCE_WR(ctx, 0x00638/4, 0xf8e8d8c8); + INSTANCE_WR(ctx, 0x0064c/4, 0x40100000); + INSTANCE_WR(ctx, 0x00668/4, 0x0000ffff); + INSTANCE_WR(ctx, 0x0069c/4, 0x435185d6); + INSTANCE_WR(ctx, 0x006a0/4, 0x2155b699); + INSTANCE_WR(ctx, 0x006a4/4, 0xfedcba98); + INSTANCE_WR(ctx, 0x006a8/4, 0x00000098); + INSTANCE_WR(ctx, 0x006b8/4, 0xffffffff); + INSTANCE_WR(ctx, 0x006bc/4, 0x00ff7000); + INSTANCE_WR(ctx, 0x006c0/4, 0x0000ffff); + INSTANCE_WR(ctx, 0x006d0/4, 0x00ff0000); + INSTANCE_WR(ctx, 0x0070c/4, 0x00ffff00); + for (i=0x00750; i<=0x0078c; i+=4) + INSTANCE_WR(ctx, i/4, 0x00018488); + for (i=0x00790; i<=0x007cc; i+=4) + INSTANCE_WR(ctx, i/4, 0x00028202); + for (i=0x00810; i<=0x0084c; i+=4) + INSTANCE_WR(ctx, i/4, 0x0000aae4); + for (i=0x00850; i<=0x0088c; i+=4) + INSTANCE_WR(ctx, i/4, 0x01012000); + for (i=0x00890; i<=0x008cc; i+=4) + INSTANCE_WR(ctx, i/4, 0x00080008); + for (i=0x00910; i<=0x0094c; i+=4) + INSTANCE_WR(ctx, i/4, 0x00100008); + for (i=0x009a0; i<=0x009ac; i+=4) + INSTANCE_WR(ctx, i/4, 0x0001bc80); + for (i=0x009b0; i<=0x009bc; i+=4) + INSTANCE_WR(ctx, i/4, 0x00000202); + for (i=0x009d0; i<=0x009dc; i+=4) + INSTANCE_WR(ctx, i/4, 0x00000008); + for (i=0x009f0; i<=0x009fc; i+=4) + INSTANCE_WR(ctx, i/4, 0x00080008); + INSTANCE_WR(ctx, 0x00a10/4, 0x00000002); + INSTANCE_WR(ctx, 0x00a44/4, 0x00000421); + INSTANCE_WR(ctx, 0x00a48/4, 0x030c30c3); + INSTANCE_WR(ctx, 0x00a54/4, 0x3e020200); + INSTANCE_WR(ctx, 0x00a58/4, 0x00ffffff); + INSTANCE_WR(ctx, 0x00a5c/4, 0x20103f00); + INSTANCE_WR(ctx, 0x00a68/4, 0x00040000); + INSTANCE_WR(ctx, 0x00aa0/4, 0x00008100); + INSTANCE_WR(ctx, 0x00b2c/4, 0x00000001); + INSTANCE_WR(ctx, 0x00b70/4, 0x00001001); + INSTANCE_WR(ctx, 0x00b7c/4, 0x00000003); + INSTANCE_WR(ctx, 0x00b80/4, 0x00888001); + INSTANCE_WR(ctx, 0x00bb0/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bb4/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bb8/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bbc/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bc0/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bc4/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bc8/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bcc/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bd0/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bd4/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bd8/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bdc/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00be0/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00be4/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00be8/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bec/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bf0/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bf4/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bf8/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bfc/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00c00/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00c04/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00c08/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00c0c/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00c10/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00c14/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00c18/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00c1c/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00c20/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00c24/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00c28/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00c2c/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00c54/4, 0x00000005); + INSTANCE_WR(ctx, 0x00c60/4, 0x0000ffff); + INSTANCE_WR(ctx, 0x00c7c/4, 0x00005555); + INSTANCE_WR(ctx, 0x00c80/4, 0x00005555); + INSTANCE_WR(ctx, 0x00c84/4, 0x00005555); + INSTANCE_WR(ctx, 0x00c88/4, 0x00005555); + INSTANCE_WR(ctx, 0x00c8c/4, 0x00005555); + INSTANCE_WR(ctx, 0x00c90/4, 0x00005555); + INSTANCE_WR(ctx, 0x00c94/4, 0x00005555); + INSTANCE_WR(ctx, 0x00c98/4, 0x00005555); + INSTANCE_WR(ctx, 0x00c9c/4, 0x00000001); + INSTANCE_WR(ctx, 0x00cd4/4, 0x00000001); + INSTANCE_WR(ctx, 0x00cd8/4, 0x08e00001); + INSTANCE_WR(ctx, 0x00cdc/4, 0x000e3000); + for(i=0x030a0; i<=0x03118; i+=8) + INSTANCE_WR(ctx, i/4, 0x3f800000); + for(i=0x098a0; i<=0x0ba90; i+=24) + INSTANCE_WR(ctx, i/4, 0x00000001); + for(i=0x0baa0; i<=0x0be90; i+=16) + INSTANCE_WR(ctx, i/4, 0x3f800000); + for(i=0x0e2e0; i<=0x0fff0; i+=24) + INSTANCE_WR(ctx, i/4, 0x00000001); + for(i=0x10008; i<=0x104d0; i+=24) + INSTANCE_WR(ctx, i/4, 0x00000001); + for(i=0x104e0; i<=0x108d0; i+=16) + INSTANCE_WR(ctx, i/4, 0x3f800000); + for(i=0x12d20; i<=0x14f10; i+=24) + INSTANCE_WR(ctx, i/4, 0x00000001); + for(i=0x14f20; i<=0x15310; i+=16) + INSTANCE_WR(ctx, i/4, 0x3f800000); + for(i=0x17760; i<=0x19950; i+=24) + INSTANCE_WR(ctx, i/4, 0x00000001); + for(i=0x19960; i<=0x19d50; i+=16) + INSTANCE_WR(ctx, i/4, 0x3f800000); + for(i=0x1c1a0; i<=0x1e390; i+=24) + INSTANCE_WR(ctx, i/4, 0x00000001); + for(i=0x1e3a0; i<=0x1e790; i+=16) + INSTANCE_WR(ctx, i/4, 0x3f800000); + for(i=0x20be0; i<=0x22dd0; i+=24) + INSTANCE_WR(ctx, i/4, 0x00000001); + for(i=0x22de0; i<=0x231d0; i+=16) + INSTANCE_WR(ctx, i/4, 0x3f800000); +} + +static void +nv4a_graph_context_init(drm_device_t *dev, struct mem_block *ctx) { drm_nouveau_private_t *dev_priv = dev->dev_private; int i; @@ -566,8 +794,223 @@ static void nv4a_graph_context_init(drm_device_t *dev, struct mem_block *ctx) INSTANCE_WR(ctx, i/4, 0x3f800000); } +static void +nv4b_graph_context_init(drm_device_t *dev, struct mem_block *ctx) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + int i; + + INSTANCE_WR(ctx, 0x00000/4, nouveau_chip_instance_get(dev, ctx)); + INSTANCE_WR(ctx, 0x00004/4, 0x0000c040); + INSTANCE_WR(ctx, 0x00008/4, 0x0000c040); + INSTANCE_WR(ctx, 0x0000c/4, 0x0000c040); + INSTANCE_WR(ctx, 0x00010/4, 0x0000c040); + INSTANCE_WR(ctx, 0x00014/4, 0x0000c040); + INSTANCE_WR(ctx, 0x00018/4, 0x0000c040); + INSTANCE_WR(ctx, 0x0001c/4, 0x0000c040); + INSTANCE_WR(ctx, 0x00020/4, 0x0000c040); + INSTANCE_WR(ctx, 0x000c4/4, 0x0000ffff); + INSTANCE_WR(ctx, 0x000c8/4, 0x0000ffff); + INSTANCE_WR(ctx, 0x000d0/4, 0x00000001); + INSTANCE_WR(ctx, 0x001bc/4, 0x20010001); + INSTANCE_WR(ctx, 0x001c0/4, 0x0f73ef00); + INSTANCE_WR(ctx, 0x001c8/4, 0x02008821); + INSTANCE_WR(ctx, 0x00218/4, 0x00000040); + INSTANCE_WR(ctx, 0x0021c/4, 0x00000040); + INSTANCE_WR(ctx, 0x00220/4, 0x00000040); + INSTANCE_WR(ctx, 0x00228/4, 0x00000040); + INSTANCE_WR(ctx, 0x00234/4, 0x80000000); + INSTANCE_WR(ctx, 0x00238/4, 0x80000000); + INSTANCE_WR(ctx, 0x0023c/4, 0x80000000); + INSTANCE_WR(ctx, 0x00240/4, 0x80000000); + INSTANCE_WR(ctx, 0x00244/4, 0x80000000); + INSTANCE_WR(ctx, 0x00248/4, 0x80000000); + INSTANCE_WR(ctx, 0x0024c/4, 0x80000000); + INSTANCE_WR(ctx, 0x00250/4, 0x80000000); + INSTANCE_WR(ctx, 0x00270/4, 0x0b0b0b0c); + INSTANCE_WR(ctx, 0x003e0/4, 0x00040000); + INSTANCE_WR(ctx, 0x003f0/4, 0x55555555); + INSTANCE_WR(ctx, 0x003f4/4, 0x55555555); + INSTANCE_WR(ctx, 0x003f8/4, 0x55555555); + INSTANCE_WR(ctx, 0x003fc/4, 0x55555555); + INSTANCE_WR(ctx, 0x00428/4, 0x00000008); + INSTANCE_WR(ctx, 0x0043c/4, 0x00001010); + INSTANCE_WR(ctx, 0x00460/4, 0x00000111); + INSTANCE_WR(ctx, 0x00464/4, 0x00000111); + INSTANCE_WR(ctx, 0x00468/4, 0x00000111); + INSTANCE_WR(ctx, 0x0046c/4, 0x00000111); + INSTANCE_WR(ctx, 0x00470/4, 0x00000111); + INSTANCE_WR(ctx, 0x00474/4, 0x00000111); + INSTANCE_WR(ctx, 0x00478/4, 0x00000111); + INSTANCE_WR(ctx, 0x0047c/4, 0x00000111); + INSTANCE_WR(ctx, 0x00480/4, 0x00000111); + INSTANCE_WR(ctx, 0x00484/4, 0x00000111); + INSTANCE_WR(ctx, 0x00488/4, 0x00000111); + INSTANCE_WR(ctx, 0x0048c/4, 0x00000111); + INSTANCE_WR(ctx, 0x00490/4, 0x00000111); + INSTANCE_WR(ctx, 0x00494/4, 0x00000111); + INSTANCE_WR(ctx, 0x00498/4, 0x00000111); + INSTANCE_WR(ctx, 0x0049c/4, 0x00000111); + INSTANCE_WR(ctx, 0x004f4/4, 0x00000111); + INSTANCE_WR(ctx, 0x004f8/4, 0x00080060); + INSTANCE_WR(ctx, 0x00514/4, 0x00000080); + INSTANCE_WR(ctx, 0x00518/4, 0xffff0000); + INSTANCE_WR(ctx, 0x0051c/4, 0x00000001); + INSTANCE_WR(ctx, 0x00530/4, 0x46400000); + INSTANCE_WR(ctx, 0x00540/4, 0xffff0000); + INSTANCE_WR(ctx, 0x00544/4, 0x88888888); + INSTANCE_WR(ctx, 0x00548/4, 0x88888888); + INSTANCE_WR(ctx, 0x0054c/4, 0x88888888); + INSTANCE_WR(ctx, 0x00550/4, 0x88888888); + INSTANCE_WR(ctx, 0x00554/4, 0x88888888); + INSTANCE_WR(ctx, 0x00558/4, 0x88888888); + INSTANCE_WR(ctx, 0x0055c/4, 0x88888888); + INSTANCE_WR(ctx, 0x00560/4, 0x88888888); + INSTANCE_WR(ctx, 0x00564/4, 0x88888888); + INSTANCE_WR(ctx, 0x00568/4, 0x88888888); + INSTANCE_WR(ctx, 0x0056c/4, 0x88888888); + INSTANCE_WR(ctx, 0x00570/4, 0x88888888); + INSTANCE_WR(ctx, 0x00574/4, 0x88888888); + INSTANCE_WR(ctx, 0x00578/4, 0x88888888); + INSTANCE_WR(ctx, 0x0057c/4, 0x88888888); + INSTANCE_WR(ctx, 0x00580/4, 0x88888888); + INSTANCE_WR(ctx, 0x00594/4, 0x0fff0000); + INSTANCE_WR(ctx, 0x00598/4, 0x0fff0000); + INSTANCE_WR(ctx, 0x005a0/4, 0x00011100); + INSTANCE_WR(ctx, 0x005bc/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005c0/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005c4/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005c8/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005cc/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005d0/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005d4/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005d8/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005dc/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005e0/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005e4/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005e8/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005ec/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005f0/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005f4/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x005f8/4, 0x07ff0000); + INSTANCE_WR(ctx, 0x00604/4, 0x4b7fffff); + INSTANCE_WR(ctx, 0x0062c/4, 0x30201000); + INSTANCE_WR(ctx, 0x00630/4, 0x70605040); + INSTANCE_WR(ctx, 0x00634/4, 0xb8a89888); + INSTANCE_WR(ctx, 0x00638/4, 0xf8e8d8c8); + INSTANCE_WR(ctx, 0x0064c/4, 0x40100000); + INSTANCE_WR(ctx, 0x00668/4, 0x0000ffff); + INSTANCE_WR(ctx, 0x0069c/4, 0x435185d6); + INSTANCE_WR(ctx, 0x006a0/4, 0x2155b699); + INSTANCE_WR(ctx, 0x006a4/4, 0xfedcba98); + INSTANCE_WR(ctx, 0x006a8/4, 0x00000098); + INSTANCE_WR(ctx, 0x006b8/4, 0xffffffff); + INSTANCE_WR(ctx, 0x006bc/4, 0x00ff7000); + INSTANCE_WR(ctx, 0x006c0/4, 0x0000ffff); + INSTANCE_WR(ctx, 0x006d0/4, 0x00ff0000); + INSTANCE_WR(ctx, 0x0070c/4, 0x00ffff00); + for (i=0x00750; i<=0x0078c; i+=4) + INSTANCE_WR(ctx, i/4, 0x00018488); + for (i=0x00790; i<=0x007cc; i+=4) + INSTANCE_WR(ctx, i/4, 0x00028202); + for (i=0x00810; i<=0x0084c; i+=4) + INSTANCE_WR(ctx, i/4, 0x0000aae4); + for (i=0x00850; i<=0x0088c; i+=4) + INSTANCE_WR(ctx, i/4, 0x01012000); + for (i=0x00890; i<=0x008cc; i+=4) + INSTANCE_WR(ctx, i/4, 0x00080008); + for (i=0x00910; i<=0x0094c; i+=4) + INSTANCE_WR(ctx, i/4, 0x00100008); + for (i=0x009a0; i<=0x009ac; i+=4) + INSTANCE_WR(ctx, i/4, 0x0001bc80); + for (i=0x009b0; i<=0x009bc; i+=4) + INSTANCE_WR(ctx, i/4, 0x00000202); + for (i=0x009d0; i<=0x009dc; i+=4) + INSTANCE_WR(ctx, i/4, 0x00000008); + for (i=0x009f0; i<=0x009fc; i+=4) + INSTANCE_WR(ctx, i/4, 0x00080008); + INSTANCE_WR(ctx, 0x00a10/4, 0x00000002); + INSTANCE_WR(ctx, 0x00a44/4, 0x00000421); + INSTANCE_WR(ctx, 0x00a48/4, 0x030c30c3); + INSTANCE_WR(ctx, 0x00a54/4, 0x3e020200); + INSTANCE_WR(ctx, 0x00a58/4, 0x00ffffff); + INSTANCE_WR(ctx, 0x00a5c/4, 0x20103f00); + INSTANCE_WR(ctx, 0x00a68/4, 0x00040000); + INSTANCE_WR(ctx, 0x00aa0/4, 0x00008100); + INSTANCE_WR(ctx, 0x00b2c/4, 0x00000001); + INSTANCE_WR(ctx, 0x00b70/4, 0x00001001); + INSTANCE_WR(ctx, 0x00b7c/4, 0x00000003); + INSTANCE_WR(ctx, 0x00b80/4, 0x00888001); + INSTANCE_WR(ctx, 0x00bb0/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bb4/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bb8/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bbc/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bc0/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bc4/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bc8/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bcc/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bd0/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bd4/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bd8/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bdc/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00be0/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00be4/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00be8/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bec/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bf0/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bf4/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bf8/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00bfc/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00c00/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00c04/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00c08/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00c0c/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00c10/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00c14/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00c18/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00c1c/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00c20/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00c24/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00c28/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00c2c/4, 0xffffffff); + INSTANCE_WR(ctx, 0x00c54/4, 0x00000005); + INSTANCE_WR(ctx, 0x00c60/4, 0x0000ffff); + INSTANCE_WR(ctx, 0x00c7c/4, 0x00005555); + INSTANCE_WR(ctx, 0x00c80/4, 0x00005555); + INSTANCE_WR(ctx, 0x00c84/4, 0x00005555); + INSTANCE_WR(ctx, 0x00c88/4, 0x00005555); + INSTANCE_WR(ctx, 0x00c8c/4, 0x00005555); + INSTANCE_WR(ctx, 0x00c90/4, 0x00005555); + INSTANCE_WR(ctx, 0x00c94/4, 0x00005555); + INSTANCE_WR(ctx, 0x00c98/4, 0x00005555); + INSTANCE_WR(ctx, 0x00c9c/4, 0x00000001); + INSTANCE_WR(ctx, 0x00cd4/4, 0x00000001); + INSTANCE_WR(ctx, 0x00cd8/4, 0x08e00001); + INSTANCE_WR(ctx, 0x00cdc/4, 0x000e3000); + for(i=0x030a0; i<=0x03118; i+=8) + INSTANCE_WR(ctx, i/4, 0x3f800000); + for(i=0x098a0; i<=0x0ba90; i+=24) + INSTANCE_WR(ctx, i/4, 0x00000001); + for(i=0x0baa0; i<=0x0be90; i+=16) + INSTANCE_WR(ctx, i/4, 0x3f800000); + for(i=0x0e2e0; i<=0x0fff0; i+=24) + INSTANCE_WR(ctx, i/4, 0x00000001); + for(i=0x10008; i<=0x104d0; i+=24) + INSTANCE_WR(ctx, i/4, 0x00000001); + for(i=0x104e0; i<=0x108d0; i+=16) + INSTANCE_WR(ctx, i/4, 0x3f800000); + for(i=0x12d20; i<=0x14f10; i+=24) + INSTANCE_WR(ctx, i/4, 0x00000001); + for(i=0x14f20; i<=0x15310; i+=16) + INSTANCE_WR(ctx, i/4, 0x3f800000); + for(i=0x17760; i<=0x19950; i+=24) + INSTANCE_WR(ctx, i/4, 0x00000001); + for(i=0x19960; i<=0x19d50; i+=16) + INSTANCE_WR(ctx, i/4, 0x3f800000); +} -static void nv4c_graph_context_init(drm_device_t *dev, struct mem_block *ctx) +static void +nv4c_graph_context_init(drm_device_t *dev, struct mem_block *ctx) { drm_nouveau_private_t *dev_priv = dev->dev_private; int i; @@ -673,7 +1116,8 @@ static void nv4c_graph_context_init(drm_device_t *dev, struct mem_block *ctx) INSTANCE_WR(ctx, i/4, 0x3f800000); } -static void nv4e_graph_context_init(drm_device_t *dev, struct mem_block *ctx) +static void +nv4e_graph_context_init(drm_device_t *dev, struct mem_block *ctx) { drm_nouveau_private_t *dev_priv = dev->dev_private; int i; @@ -802,10 +1246,18 @@ nv40_graph_create_context(drm_device_t *dev, int channel) ctx_size = NV46_GRCTX_SIZE; ctx_init = nv46_graph_context_init; break; + case 0x49: + ctx_size = NV49_GRCTX_SIZE; + ctx_init = nv49_graph_context_init; + break; case 0x4a: ctx_size = NV4A_GRCTX_SIZE; ctx_init = nv4a_graph_context_init; break; + case 0x4b: + ctx_size = NV4B_GRCTX_SIZE; + ctx_init = nv4b_graph_context_init; + break; case 0x4c: ctx_size = NV4C_GRCTX_SIZE; ctx_init = nv4c_graph_context_init; @@ -1037,6 +1489,39 @@ static uint32_t nv46_ctx_voodoo[] = { 0x00600009, 0x00700005, 0x00700006, 0x0060000e, ~0 }; +//this is used for nv49 and nv4b +static uint32_t nv49_4b_ctx_voodoo[] ={ + 0x00400564, 0x00400505, 0x00408165, 0x00408206, 0x00409e68, 0x00200020, + 0x0060000a, 0x00700080, 0x00104042, 0x00200020, 0x0060000a, 0x00700000, + 0x001040c5, 0x00400f26, 0x00401068, 0x0060000d, 0x0070008f, 0x0070000e, + 0x00408d68, 0x004015e6, 0x007000a0, 0x00700080, 0x0040180f, 0x00700000, + 0x00200029, 0x0060000a, 0x0011814d, 0x00110158, 0x00105401, 0x0020003a, + 0x00100051, 0x001040c5, 0x0010c1c4, 0x001041c9, 0x0010c1dc, 0x00150210, + 0x0012c225, 0x00108238, 0x0010823e, 0x001242c0, 0x00200040, 0x00100280, + 0x00128100, 0x00128120, 0x00128143, 0x0011415f, 0x0010815c, 0x0010c140, + 0x00104029, 0x00110400, 0x00104d12, 0x00500060, 0x004071e6, 0x00200118, + 0x0060000a, 0x00200020, 0x00100620, 0x00154650, 0x00104668, 0x0017466d, + 0x0011068b, 0x00168691, 0x001046ae, 0x001046b0, 0x001206b4, 0x001046c4, + 0x001146c6, 0x00200022, 0x001006cc, 0x001246f0, 0x002000c0, 0x00100700, + 0x0010c3d7, 0x001043e1, 0x00500060, 0x00200290, 0x0060000a, 0x00104800, + 0x00108901, 0x00124920, 0x0020001f, 0x00100940, 0x00140965, 0x00144a00, + 0x00104a19, 0x0010ca1c, 0x00110b00, 0x00200028, 0x00100b08, 0x00134c2e, + 0x0010cd00, 0x0010cd04, 0x00120d08, 0x00104d80, 0x00104e00, 0x0012d600, + 0x00105c00, 0x00104f06, 0x00105406, 0x00105709, 0x00200340, 0x0060000a, + 0x00300000, 0x00200680, 0x00406a0f, 0x00200684, 0x00800001, 0x00200b88, + 0x0060000a, 0x00209540, 0x0040708a, 0x00201350, 0x00800041, 0x00407c0f, + 0x00600006, 0x00407ce6, 0x00700080, 0x002000a2, 0x0060000a, 0x00104280, + 0x00200340, 0x0060000a, 0x00200004, 0x00800001, 0x0070008e, 0x00408d68, + 0x0040020f, 0x00600006, 0x00409e68, 0x00600007, 0x0070000f, 0x0070000e, + 0x00408d68, 0x0091a880, 0x00901ffe, 0x10940000, 0x00200020, 0x0060000b, + 0x00500069, 0x0060000c, 0x00401568, 0x00700000, 0x00200001, 0x0040910e, + 0x00200021, 0x0060000a, 0x00409b0d, 0x00104a40, 0x00104a50, 0x00104a60, + 0x00104a70, 0x00104a80, 0x00104a90, 0x00104aa0, 0x00104ab0, 0x00407e0e, + 0x0040130f, 0x00408568, 0x0040a006, 0x0040a105, 0x00600009, 0x00700005, + 0x00700006, 0x0060000e, ~0 +}; + + static uint32_t nv4a_ctx_voodoo[] = { 0x00400889, 0x00200000, 0x0060000a, 0x00200000, 0x00300000, 0x00800001, 0x00700009, 0x0060000e, 0x00400d64, 0x00400d05, 0x00409965, 0x00409e06, @@ -1130,7 +1615,9 @@ nv40_graph_init(drm_device_t *dev) case 0x40: ctx_voodoo = nv40_ctx_voodoo; break; case 0x43: ctx_voodoo = nv43_ctx_voodoo; break; case 0x46: ctx_voodoo = nv46_ctx_voodoo; break; + case 0x49: ctx_voodoo = nv49_4b_ctx_voodoo; break; case 0x4a: ctx_voodoo = nv4a_ctx_voodoo; break; + case 0x4b: ctx_voodoo = nv49_4b_ctx_voodoo; break; case 0x4e: ctx_voodoo = nv4e_ctx_voodoo; break; default: DRM_ERROR("Unknown ctx_voodoo for chipset 0x%02x\n", -- cgit v1.2.3 From 5c27f8a70e6e3684d8d58661a9cc918a3514fd14 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Tue, 26 Jun 2007 09:51:55 -0700 Subject: Add support SiS based XGI chips to SiS DRM. --- shared-core/drm_pciids.txt | 2 ++ shared-core/sis_drv.h | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/shared-core/drm_pciids.txt b/shared-core/drm_pciids.txt index ba02aa89..ad9994ec 100644 --- a/shared-core/drm_pciids.txt +++ b/shared-core/drm_pciids.txt @@ -211,6 +211,8 @@ 0x1039 0x6300 0 "SiS 630" 0x1039 0x6330 SIS_CHIP_315 "SiS 661" 0x1039 0x7300 0 "SiS 730" +0x18CA 0x0040 SIS_CHIP_315 "Volari V3XT/V5/V8" +0x18CA 0x0042 SIS_CHIP_315 "Volari Unknown" [tdfx] 0x121a 0x0003 0 "3dfx Voodoo Banshee" diff --git a/shared-core/sis_drv.h b/shared-core/sis_drv.h index 006d148c..ec572ad4 100644 --- a/shared-core/sis_drv.h +++ b/shared-core/sis_drv.h @@ -33,11 +33,11 @@ #define DRIVER_AUTHOR "SIS, Tungsten Graphics" #define DRIVER_NAME "sis" -#define DRIVER_DESC "SIS 300/630/540" -#define DRIVER_DATE "20060619" +#define DRIVER_DESC "SIS 300/630/540 and XGI V3XE/V5/V8" +#define DRIVER_DATE "20070626" #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 2 -#define DRIVER_PATCHLEVEL 1 +#define DRIVER_MINOR 3 +#define DRIVER_PATCHLEVEL 0 enum sis_family { SIS_OTHER = 0, -- cgit v1.2.3 From 4f2dd78ff3b6efeee97b72cca6bbfaef485a08d9 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 28 Jun 2007 02:56:30 +1000 Subject: nouveau/nv04: Set NV_PFIFO_CACHE1_PUSH1 correctly + small tweaks --- shared-core/nv04_fifo.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/shared-core/nv04_fifo.c b/shared-core/nv04_fifo.c index 34a497b7..783514a7 100644 --- a/shared-core/nv04_fifo.c +++ b/shared-core/nv04_fifo.c @@ -53,10 +53,9 @@ nv04_fifo_create_context(drm_device_t *dev, int channel) RAMFC_WR(DMA_PUT, chan->pushbuf_base); RAMFC_WR(DMA_GET, chan->pushbuf_base); RAMFC_WR(DMA_INSTANCE, nouveau_chip_instance_get(dev, pb->instance)); - /* NOTE: nvidia use TRIG_128/SIZE_128/MAX_REQS_8 */ - RAMFC_WR(DMA_FETCH, (NV_PFIFO_CACHE1_DMA_FETCH_TRIG_112_BYTES | + RAMFC_WR(DMA_FETCH, (NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | - NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_4 | + NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 | #ifdef __BIG_ENDIAN NV_PFIFO_CACHE1_BIG_ENDIAN | #endif @@ -83,8 +82,10 @@ nv04_fifo_load_context(drm_device_t *dev, int channel) int fifoctx = NV04_RAMFC + (channel * NV04_FIFO_CONTEXT_SIZE); uint32_t tmp; - NV_WRITE(NV04_PFIFO_CACHE1_DMA_PUT, RAMFC_RD(DMA_PUT)); + NV_WRITE(NV03_PFIFO_CACHE1_PUSH1, (1<<8) | channel); + NV_WRITE(NV04_PFIFO_CACHE1_DMA_GET, RAMFC_RD(DMA_GET)); + NV_WRITE(NV04_PFIFO_CACHE1_DMA_PUT, RAMFC_RD(DMA_PUT)); tmp = RAMFC_RD(DMA_INSTANCE); NV_WRITE(NV04_PFIFO_CACHE1_DMA_INSTANCE, tmp & 0xFFFF); -- cgit v1.2.3 From 695599f18d907bb277805581bbe208b0e083e7d9 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sun, 24 Jun 2007 19:03:35 +1000 Subject: nouveau: Nuke DMA_OBJECT_INIT ioctl (bumps interface to 0.0.7) For various reasons, this ioctl was a bad idea. At channel creation we now automatically create DMA objects covering available VRAM and GART memory, where the client used to do this themselves. However, there is still a need to be able to create DMA objects pointing at specific areas of memory (ie. notifiers). Each channel is now allocated a small amount of memory from which a client can suballocate things (such as notifiers), and have a DMA object created which covers the suballocated area. The NOTIFIER_ALLOC ioctl exposes this functionality. --- linux-core/Makefile.kernel | 2 +- linux-core/nouveau_notifier.c | 1 + shared-core/nouveau_drm.h | 28 ++++---- shared-core/nouveau_drv.h | 28 +++++++- shared-core/nouveau_fifo.c | 45 +++++++++--- shared-core/nouveau_mem.c | 51 +++++++++----- shared-core/nouveau_notifier.c | 154 +++++++++++++++++++++++++++++++++++++++++ shared-core/nouveau_object.c | 143 +++++++++++++------------------------- shared-core/nouveau_state.c | 3 +- 9 files changed, 315 insertions(+), 140 deletions(-) create mode 120000 linux-core/nouveau_notifier.c create mode 100644 shared-core/nouveau_notifier.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 9427a04b..6ab17a49 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -21,7 +21,7 @@ i810-objs := i810_drv.o i810_dma.o i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o \ i915_buffer.o nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ - nouveau_object.o nouveau_irq.o \ + nouveau_object.o nouveau_irq.o nouveau_notifier.o \ nv04_timer.o \ nv04_mc.o nv40_mc.o \ nv04_fb.o nv10_fb.o nv40_fb.o \ diff --git a/linux-core/nouveau_notifier.c b/linux-core/nouveau_notifier.c new file mode 120000 index 00000000..285469c5 --- /dev/null +++ b/linux-core/nouveau_notifier.c @@ -0,0 +1 @@ +../shared-core/nouveau_notifier.c \ No newline at end of file diff --git a/shared-core/nouveau_drm.h b/shared-core/nouveau_drm.h index 1e7322e0..0758991a 100644 --- a/shared-core/nouveau_drm.h +++ b/shared-core/nouveau_drm.h @@ -25,9 +25,12 @@ #ifndef __NOUVEAU_DRM_H__ #define __NOUVEAU_DRM_H__ -#define NOUVEAU_DRM_HEADER_PATCHLEVEL 6 +#define NOUVEAU_DRM_HEADER_PATCHLEVEL 7 typedef struct drm_nouveau_fifo_alloc { + uint32_t fb_ctxdma_handle; + uint32_t tt_ctxdma_handle; + int channel; uint32_t put_base; /* FIFO control regs */ @@ -36,29 +39,30 @@ typedef struct drm_nouveau_fifo_alloc { /* DMA command buffer */ drm_handle_t cmdbuf; int cmdbuf_size; + /* Notifier memory */ + drm_handle_t notifier; + int notifier_size; } drm_nouveau_fifo_alloc_t; -typedef struct drm_nouveau_object_init { +typedef struct drm_nouveau_grobj_alloc { int channel; uint32_t handle; int class; } -drm_nouveau_object_init_t; +drm_nouveau_grobj_alloc_t; #define NOUVEAU_MEM_ACCESS_RO 1 #define NOUVEAU_MEM_ACCESS_WO 2 #define NOUVEAU_MEM_ACCESS_RW 3 -typedef struct drm_nouveau_dma_object_init { +typedef struct drm_nouveau_notifier_alloc { int channel; uint32_t handle; - int class; - int access; - int target; + int count; + uint32_t offset; - int size; } -drm_nouveau_dma_object_init_t; +drm_nouveau_notifier_alloc_t; #define NOUVEAU_MEM_FB 0x00000001 #define NOUVEAU_MEM_AGP 0x00000002 @@ -68,7 +72,7 @@ drm_nouveau_dma_object_init_t; #define NOUVEAU_MEM_USER_BACKED 0x00000020 #define NOUVEAU_MEM_MAPPED 0x00000040 #define NOUVEAU_MEM_INSTANCE 0x00000080 /* internal */ - +#define NOUVEAU_MEM_NOTIFIER 0x00000100 /* internal */ typedef struct drm_nouveau_mem_alloc { int flags; int alignment; @@ -141,8 +145,8 @@ typedef struct drm_nouveau_sarea { drm_nouveau_sarea_t; #define DRM_NOUVEAU_FIFO_ALLOC 0x00 -#define DRM_NOUVEAU_OBJECT_INIT 0x01 -#define DRM_NOUVEAU_DMA_OBJECT_INIT 0x02 +#define DRM_NOUVEAU_GROBJ_ALLOC 0x01 +#define DRM_NOUVEAU_NOTIFIER_ALLOC 0x02 #define DRM_NOUVEAU_MEM_ALLOC 0x03 #define DRM_NOUVEAU_MEM_FREE 0x04 #define DRM_NOUVEAU_GETPARAM 0x05 diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index b3122d8a..7a1ca3d5 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -34,7 +34,7 @@ #define DRIVER_MAJOR 0 #define DRIVER_MINOR 0 -#define DRIVER_PATCHLEVEL 6 +#define DRIVER_PATCHLEVEL 7 #define NOUVEAU_FAMILY 0x0000FFFF #define NOUVEAU_FLAGS 0xFFFF0000 @@ -84,6 +84,10 @@ struct nouveau_fifo struct mem_block *cmdbuf_mem; struct nouveau_object *cmdbuf_obj; uint32_t pushbuf_base; + /* notifier memory */ + struct mem_block *notifier_block; + struct mem_block *notifier_heap; + drm_local_map_t *notifier_map; /* PGRAPH context, for cards that keep it in RAMIN */ struct mem_block *ramin_grctx; /* objects belonging to this fifo */ @@ -197,6 +201,12 @@ extern void nouveau_wait_for_idle(struct drm_device *dev); extern int nouveau_ioctl_card_init(DRM_IOCTL_ARGS); /* nouveau_mem.c */ +extern int nouveau_mem_init_heap(struct mem_block **, + uint64_t start, uint64_t size); +extern struct mem_block *nouveau_mem_alloc_block(struct mem_block *, + uint64_t size, int align2, + DRMFILE); +extern void nouveau_mem_free_block(struct mem_block *); extern uint64_t nouveau_mem_fb_amount(struct drm_device *dev); extern void nouveau_mem_release(DRMFILE filp, struct mem_block *heap); extern int nouveau_ioctl_mem_alloc(DRM_IOCTL_ARGS); @@ -216,6 +226,13 @@ extern void nouveau_instmem_w32(drm_nouveau_private_t *dev_priv, struct mem_block *mem, int index, uint32_t val); +/* nouveau_notifier.c */ +extern int nouveau_notifier_init_channel(drm_device_t *, int channel, DRMFILE); +extern void nouveau_notifier_takedown_channel(drm_device_t *, int channel); +extern int nouveau_notifier_alloc(drm_device_t *, int channel, + uint32_t handle, int cout, uint32_t *offset); +extern int nouveau_ioctl_notifier_alloc(DRM_IOCTL_ARGS); + /* nouveau_fifo.c */ extern int nouveau_fifo_init(drm_device_t *dev); extern int nouveau_fifo_number(drm_device_t *dev); @@ -225,7 +242,13 @@ extern int nouveau_fifo_owner(drm_device_t *dev, DRMFILE filp, int channel); extern void nouveau_fifo_free(drm_device_t *dev, int channel); /* nouveau_object.c */ +extern int nouveau_object_init_channel(drm_device_t *, int channel, + uint32_t vram_handle, + uint32_t tt_handle); +extern void nouveau_object_takedown_channel(drm_device_t *dev, int channel); extern void nouveau_object_cleanup(drm_device_t *dev, int channel); +extern int nouveau_ht_object_insert(drm_device_t *, int channel, + uint32_t handle, struct nouveau_object *); extern struct nouveau_object * nouveau_object_gr_create(drm_device_t *dev, int channel, int class); extern struct nouveau_object * @@ -233,8 +256,7 @@ nouveau_object_dma_create(drm_device_t *dev, int channel, int class, uint32_t offset, uint32_t size, int access, int target); extern void nouveau_object_free(drm_device_t *dev, struct nouveau_object *obj); -extern int nouveau_ioctl_object_init(DRM_IOCTL_ARGS); -extern int nouveau_ioctl_dma_object_init(DRM_IOCTL_ARGS); +extern int nouveau_ioctl_grobj_alloc(DRM_IOCTL_ARGS); extern uint32_t nouveau_chip_instance_get(drm_device_t *dev, struct mem_block *mem); /* nouveau_irq.c */ diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c index 1a06f913..f179af63 100644 --- a/shared-core/nouveau_fifo.c +++ b/shared-core/nouveau_fifo.c @@ -241,7 +241,8 @@ nouveau_fifo_cmdbuf_alloc(struct drm_device *dev, int channel) } /* allocates and initializes a fifo for user space consumption */ -static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp) +int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp, + uint32_t vram_handle, uint32_t tt_handle) { int ret; drm_nouveau_private_t *dev_priv = dev->dev_private; @@ -282,6 +283,20 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp) return ret; } + /* Setup channel's default objects */ + ret = nouveau_object_init_channel(dev, channel, vram_handle, tt_handle); + if (ret) { + nouveau_fifo_free(dev, channel); + return ret; + } + + /* Allocate space for per-channel fixed notifier memory */ + ret = nouveau_notifier_init_channel(dev, channel, filp); + if (ret) { + nouveau_fifo_free(dev, channel); + return ret; + } + nouveau_wait_for_idle(dev); /* disable the fifo caches */ @@ -370,6 +385,8 @@ void nouveau_fifo_free(drm_device_t* dev, int channel) if (chan->cmdbuf_mem) nouveau_mem_free(dev, chan->cmdbuf_mem); + nouveau_notifier_takedown_channel(dev, channel); + /* Destroy objects belonging to the channel */ nouveau_object_cleanup(dev, channel); @@ -408,30 +425,42 @@ static int nouveau_ioctl_fifo_alloc(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan; drm_nouveau_fifo_alloc_t init; int res; DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_fifo_alloc_t __user *) data, sizeof(init)); - res = nouveau_fifo_alloc(dev, &init.channel, filp); + res = nouveau_fifo_alloc(dev, &init.channel, filp, + init.fb_ctxdma_handle, + init.tt_ctxdma_handle); if (res) return res; + chan = &dev_priv->fifos[init.channel]; - init.put_base = dev_priv->fifos[init.channel].pushbuf_base; + init.put_base = chan->pushbuf_base; /* make the fifo available to user space */ /* first, the fifo control regs */ init.ctrl = dev_priv->mmio->offset + NV03_FIFO_REGS(init.channel); init.ctrl_size = NV03_FIFO_REGS_SIZE; res = drm_addmap(dev, init.ctrl, init.ctrl_size, _DRM_REGISTERS, - 0, &dev_priv->fifos[init.channel].regs); + 0, &chan->regs); if (res != 0) return res; /* pass back FIFO map info to the caller */ - init.cmdbuf = dev_priv->fifos[init.channel].cmdbuf_mem->start; - init.cmdbuf_size = dev_priv->fifos[init.channel].cmdbuf_mem->size; + init.cmdbuf = chan->cmdbuf_mem->start; + init.cmdbuf_size = chan->cmdbuf_mem->size; + + /* and the notifier block */ + init.notifier = chan->notifier_block->start; + init.notifier_size = chan->notifier_block->size; + res = drm_addmap(dev, init.notifier, init.notifier_size, _DRM_REGISTERS, + 0, &chan->notifier_map); + if (res != 0) + return res; DRM_COPY_TO_USER_IOCTL((drm_nouveau_fifo_alloc_t __user *)data, init, sizeof(init)); @@ -444,8 +473,8 @@ static int nouveau_ioctl_fifo_alloc(DRM_IOCTL_ARGS) drm_ioctl_desc_t nouveau_ioctls[] = { [DRM_IOCTL_NR(DRM_NOUVEAU_FIFO_ALLOC)] = {nouveau_ioctl_fifo_alloc, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_NOUVEAU_OBJECT_INIT)] = {nouveau_ioctl_object_init, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_NOUVEAU_DMA_OBJECT_INIT)] = {nouveau_ioctl_dma_object_init, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_NOUVEAU_GROBJ_ALLOC)] = {nouveau_ioctl_grobj_alloc, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_NOUVEAU_NOTIFIER_ALLOC)] = {nouveau_ioctl_notifier_alloc, DRM_AUTH}, [DRM_IOCTL_NR(DRM_NOUVEAU_MEM_ALLOC)] = {nouveau_ioctl_mem_alloc, DRM_AUTH}, [DRM_IOCTL_NR(DRM_NOUVEAU_MEM_FREE)] = {nouveau_ioctl_mem_free, DRM_AUTH}, [DRM_IOCTL_NR(DRM_NOUVEAU_GETPARAM)] = {nouveau_ioctl_getparam, DRM_AUTH}, diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index a5343b99..edfc9d3f 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -77,8 +77,8 @@ out: return p; } -static struct mem_block *alloc_block(struct mem_block *heap, uint64_t size, - int align2, DRMFILE filp) +struct mem_block *nouveau_mem_alloc_block(struct mem_block *heap, uint64_t size, + int align2, DRMFILE filp) { struct mem_block *p; uint64_t mask = (1 << align2) - 1; @@ -106,7 +106,7 @@ static struct mem_block *find_block(struct mem_block *heap, uint64_t start) return NULL; } -static void free_block(struct mem_block *p) +void nouveau_mem_free_block(struct mem_block *p) { p->filp = NULL; @@ -132,7 +132,8 @@ static void free_block(struct mem_block *p) /* Initialize. How to check for an uninitialized heap? */ -static int init_heap(struct mem_block **heap, uint64_t start, uint64_t size) +int nouveau_mem_init_heap(struct mem_block **heap, uint64_t start, + uint64_t size) { struct mem_block *blocks = drm_alloc(sizeof(*blocks), DRM_MEM_BUFS); @@ -331,7 +332,9 @@ int nouveau_mem_init(struct drm_device *dev) goto no_agp; } - if (init_heap(&dev_priv->agp_heap, info.aperture_base, info.aperture_size)) + if (nouveau_mem_init_heap(&dev_priv->agp_heap, + info.aperture_base, + info.aperture_size)) goto no_agp; dev_priv->agp_phys = info.aperture_base; @@ -357,12 +360,19 @@ no_agp: if (fb_size>256*1024*1024) { /* On cards with > 256Mb, you can't map everything. * So we create a second FB heap for that type of memory */ - if (init_heap(&dev_priv->fb_heap, drm_get_resource_start(dev,1), 256*1024*1024)) + if (nouveau_mem_init_heap(&dev_priv->fb_heap, + drm_get_resource_start(dev,1), + 256*1024*1024)) return DRM_ERR(ENOMEM); - if (init_heap(&dev_priv->fb_nomap_heap, drm_get_resource_start(dev,1)+256*1024*1024, fb_size-256*1024*1024)) + if (nouveau_mem_init_heap(&dev_priv->fb_nomap_heap, + drm_get_resource_start(dev,1) + + 256*1024*1024, + fb_size-256*1024*1024)) return DRM_ERR(ENOMEM); } else { - if (init_heap(&dev_priv->fb_heap, drm_get_resource_start(dev,1), fb_size)) + if (nouveau_mem_init_heap(&dev_priv->fb_heap, + drm_get_resource_start(dev,1), + fb_size)) return DRM_ERR(ENOMEM); dev_priv->fb_nomap_heap=NULL; } @@ -397,21 +407,25 @@ struct mem_block* nouveau_mem_alloc(struct drm_device *dev, int alignment, uint6 if (flags&NOUVEAU_MEM_AGP) { type=NOUVEAU_MEM_AGP; - block = alloc_block(dev_priv->agp_heap, size, alignment, filp); + block = nouveau_mem_alloc_block(dev_priv->agp_heap, size, + alignment, filp); if (block) goto alloc_ok; } if (flags&(NOUVEAU_MEM_FB|NOUVEAU_MEM_FB_ACCEPTABLE)) { type=NOUVEAU_MEM_FB; if (!(flags&NOUVEAU_MEM_MAPPED)) { - block = alloc_block(dev_priv->fb_nomap_heap, size, alignment, filp); + block = nouveau_mem_alloc_block(dev_priv->fb_nomap_heap, + size, alignment, filp); if (block) goto alloc_ok; } - block = alloc_block(dev_priv->fb_heap, size, alignment, filp); + block = nouveau_mem_alloc_block(dev_priv->fb_heap, size, + alignment, filp); if (block) goto alloc_ok; } if (flags&NOUVEAU_MEM_AGP_ACCEPTABLE) { type=NOUVEAU_MEM_AGP; - block = alloc_block(dev_priv->agp_heap, size, alignment, filp); + block = nouveau_mem_alloc_block(dev_priv->agp_heap, size, + alignment, filp); if (block) goto alloc_ok; } @@ -432,7 +446,7 @@ alloc_ok: ret = drm_addmap(dev, block->start, block->size, _DRM_FRAME_BUFFER, 0, &block->map); if (ret) { - free_block(block); + nouveau_mem_free_block(block); return NULL; } } @@ -446,7 +460,7 @@ void nouveau_mem_free(struct drm_device* dev, struct mem_block* block) DRM_INFO("freeing 0x%llx\n", block->start); if (block->flags&NOUVEAU_MEM_MAPPED) drm_rmmap(dev, block->map); - free_block(block); + nouveau_mem_free_block(block); } static void @@ -549,8 +563,8 @@ int nouveau_instmem_init(struct drm_device *dev) * the space that was reserved for RAMHT/FC/RO. */ offset = dev_priv->ramfc_offset + dev_priv->ramfc_size; - ret = init_heap(&dev_priv->ramin_heap, - offset, dev_priv->ramin_size - offset); + ret = nouveau_mem_init_heap(&dev_priv->ramin_heap, + offset, dev_priv->ramin_size - offset); if (ret) { dev_priv->ramin_heap = NULL; DRM_ERROR("Failed to init RAMIN heap\n"); @@ -570,7 +584,8 @@ struct mem_block *nouveau_instmem_alloc(struct drm_device *dev, return NULL; } - block = alloc_block(dev_priv->ramin_heap, size, align, (DRMFILE)-2); + block = nouveau_mem_alloc_block(dev_priv->ramin_heap, size, align, + (DRMFILE)-2); if (block) { block->flags = NOUVEAU_MEM_INSTANCE; DRM_DEBUG("instance(size=%d, align=%d) alloc'd at 0x%08x\n", @@ -583,7 +598,7 @@ struct mem_block *nouveau_instmem_alloc(struct drm_device *dev, void nouveau_instmem_free(struct drm_device *dev, struct mem_block *block) { if (dev && block) { - free_block(block); + nouveau_mem_free_block(block); } } diff --git a/shared-core/nouveau_notifier.c b/shared-core/nouveau_notifier.c new file mode 100644 index 00000000..ab6f8c2d --- /dev/null +++ b/shared-core/nouveau_notifier.c @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2007 Ben Skeggs. + * + * 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 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. + * + */ + +#include "drmP.h" +#include "drm.h" +#include "nouveau_drv.h" + +int +nouveau_notifier_init_channel(drm_device_t *dev, int channel, DRMFILE filp) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + int flags, ret; + + /*TODO: PCI notifier blocks */ + if (dev_priv->agp_heap) + flags = NOUVEAU_MEM_AGP | NOUVEAU_MEM_FB_ACCEPTABLE; + else + flags = NOUVEAU_MEM_FB; + + chan->notifier_block = nouveau_mem_alloc(dev, 0, PAGE_SIZE, flags,filp); + if (!chan->notifier_block) + return DRM_ERR(ENOMEM); + + ret = nouveau_mem_init_heap(&chan->notifier_heap, + 0, chan->notifier_block->size); + if (ret) + return ret; + + return 0; +} + +void +nouveau_notifier_takedown_channel(drm_device_t *dev, int channel) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + + if (chan->notifier_block) { + nouveau_mem_free(dev, chan->notifier_block); + chan->notifier_block = NULL; + } + + /*XXX: heap destroy */ +} + +int +nouveau_notifier_alloc(drm_device_t *dev, int channel, uint32_t handle, + int count, uint32_t *b_offset) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_object *obj; + struct mem_block *mem; + uint32_t offset; + int target; + + if (!chan->notifier_heap) { + DRM_ERROR("Channel %d doesn't have a notifier heap!\n", + channel); + return DRM_ERR(EINVAL); + } + + mem = nouveau_mem_alloc_block(chan->notifier_heap, 32, 0, chan->filp); + if (!mem) { + DRM_ERROR("Channel %d notifier block full\n", channel); + return DRM_ERR(ENOMEM); + } + mem->flags = NOUVEAU_MEM_NOTIFIER; + + offset = chan->notifier_block->start + mem->start; + if (chan->notifier_block->flags & NOUVEAU_MEM_FB) { + offset -= drm_get_resource_start(dev, 1); + target = NV_DMA_TARGET_VIDMEM; + } else if (chan->notifier_block->flags & NOUVEAU_MEM_AGP) { + offset -= dev_priv->agp_phys; + target = NV_DMA_TARGET_AGP; + } else { + DRM_ERROR("Bad DMA target, flags 0x%08x!\n", + chan->notifier_block->flags); + return DRM_ERR(EINVAL); + } + + obj = nouveau_object_dma_create(dev, channel, NV_CLASS_DMA_IN_MEMORY, + offset, mem->size, NV_DMA_ACCESS_RW, + target); + if (!obj) { + nouveau_mem_free_block(mem); + DRM_ERROR("Error creating notifier ctxdma\n"); + return DRM_ERR(ENOMEM); + } + + obj->handle = handle; + if (nouveau_ht_object_insert(dev, channel, handle, obj)) { + nouveau_object_free(dev, obj); + nouveau_mem_free_block(mem); + DRM_ERROR("Error inserting notifier ctxdma into RAMHT\n"); + return DRM_ERR(ENOMEM); + } + + *b_offset = mem->start; + return 0; +} + +int +nouveau_ioctl_notifier_alloc(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_nouveau_notifier_alloc_t na; + int ret; + + DRM_COPY_FROM_USER_IOCTL(na, (drm_nouveau_notifier_alloc_t __user*)data, + sizeof(na)); + + if (!nouveau_fifo_owner(dev, filp, na.channel)) { + DRM_ERROR("pid %d doesn't own channel %d\n", + DRM_CURRENTPID, na.channel); + return DRM_ERR(EPERM); + } + + ret = nouveau_notifier_alloc(dev, na.channel, na.handle, + na.count, &na.offset); + if (ret) + return ret; + + DRM_COPY_TO_USER_IOCTL((drm_nouveau_notifier_alloc_t __user*)data, + na, sizeof(na)); + return 0; +} + diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index e36568c6..e7528e23 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -153,13 +153,13 @@ nouveau_ht_handle_hash(drm_device_t *dev, int channel, uint32_t handle) return hash << 3; } -static int +int nouveau_ht_object_insert(drm_device_t* dev, int channel, uint32_t handle, struct nouveau_object *obj) { drm_nouveau_private_t *dev_priv=dev->dev_private; int ht_base = NV_RAMIN + dev_priv->ramht_offset; - int ht_end = ht_base + dev_priv->ramht_size; +/* int ht_end = ht_base + dev_priv->ramht_size; */ int o_ofs, ofs; obj->handle = handle; @@ -461,115 +461,70 @@ nouveau_object_free(drm_device_t *dev, struct nouveau_object *obj) drm_free(obj, sizeof(struct nouveau_object), DRM_MEM_DRIVER); } -void nouveau_object_cleanup(drm_device_t *dev, int channel) -{ - drm_nouveau_private_t *dev_priv=dev->dev_private; - - while (dev_priv->fifos[channel].objs) { - nouveau_object_free(dev, dev_priv->fifos[channel].objs); - } -} - -int nouveau_ioctl_object_init(DRM_IOCTL_ARGS) +int +nouveau_object_init_channel(drm_device_t *dev, int channel, + uint32_t vram_handle, + uint32_t tt_handle) { - DRM_DEVICE; - drm_nouveau_object_init_t init; - struct nouveau_object *obj; - - DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_object_init_t __user *) - data, sizeof(init)); - - if (!nouveau_fifo_owner(dev, filp, init.channel)) { - DRM_ERROR("pid %d doesn't own channel %d\n", - DRM_CURRENTPID, init.channel); - return DRM_ERR(EINVAL); + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_object *gpuobj; + int ret; + + /* VRAM ctxdma */ + gpuobj = nouveau_object_dma_create(dev, channel, NV_CLASS_DMA_IN_MEMORY, + 0, dev_priv->fb_available_size, + NV_DMA_ACCESS_RW, + NV_DMA_TARGET_VIDMEM); + if (!gpuobj) { + DRM_ERROR("Error creating VRAM ctxdma: %d\n", DRM_ERR(ENOMEM)); + return DRM_ERR(ENOMEM); } - //FIXME: check args, only allow trusted objects to be created - - if (nouveau_object_handle_find(dev, init.channel, init.handle)) { - DRM_ERROR("Channel %d: handle 0x%08x already exists\n", - init.channel, init.handle); - return DRM_ERR(EINVAL); + ret = nouveau_ht_object_insert(dev, channel, vram_handle, gpuobj); + if (ret) { + DRM_ERROR("Error referencing VRAM ctxdma: %d\n", ret); + return ret; } - obj = nouveau_object_gr_create(dev, init.channel, init.class); - if (!obj) + /* non-AGP unimplemented */ + if (dev_priv->agp_heap == NULL) + return 0; + + /* GART ctxdma */ + gpuobj = nouveau_object_dma_create(dev, channel, NV_CLASS_DMA_IN_MEMORY, + 0, dev_priv->agp_available_size, + NV_DMA_ACCESS_RW, + NV_DMA_TARGET_AGP); + if (!gpuobj) { + DRM_ERROR("Error creating TT ctxdma: %d\n", DRM_ERR(ENOMEM)); return DRM_ERR(ENOMEM); + } - if (nouveau_ht_object_insert(dev, init.channel, init.handle, obj)) { - nouveau_object_free(dev, obj); - return DRM_ERR(ENOMEM); + ret = nouveau_ht_object_insert(dev, channel, tt_handle, gpuobj); + if (ret) { + DRM_ERROR("Error referencing TT ctxdma: %d\n", ret); + return ret; } return 0; } -static int -nouveau_dma_object_check_access(drm_device_t *dev, - drm_nouveau_dma_object_init_t *init) +void nouveau_object_cleanup(drm_device_t *dev, int channel) { - drm_nouveau_private_t *dev_priv = dev->dev_private; - uint64_t limit; - - /* Check for known DMA object classes */ - switch (init->class) { - case NV_CLASS_DMA_IN_MEMORY: - case NV_CLASS_DMA_FROM_MEMORY: - case NV_CLASS_DMA_TO_MEMORY: - break; - default: - DRM_ERROR("invalid class = 0x%x\n", init->class); - return DRM_ERR(EPERM); - } - - /* Check access mode, and translate to NV_DMA_ACCESS_* */ - switch (init->access) { - case NOUVEAU_MEM_ACCESS_RO: - init->access = NV_DMA_ACCESS_RO; - break; - case NOUVEAU_MEM_ACCESS_WO: - init->access = NV_DMA_ACCESS_WO; - break; - case NOUVEAU_MEM_ACCESS_RW: - init->access = NV_DMA_ACCESS_RW; - break; - default: - DRM_ERROR("invalid access mode = %d\n", init->access); - return DRM_ERR(EPERM); - } - - /* Check that request is within the allowed limits of "target" */ - switch (init->target) { - case NOUVEAU_MEM_FB: - limit = dev_priv->fb_available_size; - init->target = NV_DMA_TARGET_VIDMEM; - break; - case NOUVEAU_MEM_AGP: - limit = dev_priv->agp_available_size; - init->target = NV_DMA_TARGET_AGP; - break; - default: - DRM_ERROR("invalid target = 0x%x\n", init->target); - return DRM_ERR(EPERM); - } + drm_nouveau_private_t *dev_priv=dev->dev_private; - if ((init->offset > limit) || (init->offset + init->size) > limit) { - DRM_ERROR("access out of allowed range (%d,0x%08x,0x%08x)\n", - init->target, init->offset, init->size); - return DRM_ERR(EPERM); + while (dev_priv->fifos[channel].objs) { + nouveau_object_free(dev, dev_priv->fifos[channel].objs); } - - return 0; } -int nouveau_ioctl_dma_object_init(DRM_IOCTL_ARGS) +int nouveau_ioctl_grobj_alloc(DRM_IOCTL_ARGS) { DRM_DEVICE; - drm_nouveau_dma_object_init_t init; + drm_nouveau_grobj_alloc_t init; struct nouveau_object *obj; - DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_dma_object_init_t __user *) + DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_grobj_alloc_t __user *) data, sizeof(init)); if (!nouveau_fifo_owner(dev, filp, init.channel)) { @@ -578,8 +533,7 @@ int nouveau_ioctl_dma_object_init(DRM_IOCTL_ARGS) return DRM_ERR(EINVAL); } - if (nouveau_dma_object_check_access(dev, &init)) - return DRM_ERR(EPERM); + //FIXME: check args, only allow trusted objects to be created if (nouveau_object_handle_find(dev, init.channel, init.handle)) { DRM_ERROR("Channel %d: handle 0x%08x already exists\n", @@ -587,13 +541,10 @@ int nouveau_ioctl_dma_object_init(DRM_IOCTL_ARGS) return DRM_ERR(EINVAL); } - obj = nouveau_object_dma_create(dev, init.channel, init.class, - init.offset, init.size, - init.access, init.target); + obj = nouveau_object_gr_create(dev, init.channel, init.class); if (!obj) return DRM_ERR(ENOMEM); - obj->handle = init.handle; if (nouveau_ht_object_insert(dev, init.channel, init.handle, obj)) { nouveau_object_free(dev, obj); return DRM_ERR(ENOMEM); diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c index b3562e2f..68392c3a 100644 --- a/shared-core/nouveau_state.c +++ b/shared-core/nouveau_state.c @@ -260,9 +260,9 @@ void nouveau_preclose(drm_device_t * dev, DRMFILE filp) { drm_nouveau_private_t *dev_priv = dev->dev_private; + nouveau_fifo_cleanup(dev, filp); nouveau_mem_release(filp,dev_priv->fb_heap); nouveau_mem_release(filp,dev_priv->agp_heap); - nouveau_fifo_cleanup(dev, filp); } /* first module load, setup the mmio/fb mapping */ @@ -282,7 +282,6 @@ int nouveau_firstopen(struct drm_device *dev) int nouveau_load(struct drm_device *dev, unsigned long flags) { drm_nouveau_private_t *dev_priv; - int ret; if (flags==NV_UNKNOWN) return DRM_ERR(EINVAL); -- cgit v1.2.3 From ce0d528d3ca78348a7c1ad7c402757824fb6cf95 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sun, 24 Jun 2007 20:49:19 +1000 Subject: nouveau/nv50: skeletal backend --- linux-core/Makefile.kernel | 6 ++-- linux-core/nv50_fifo.c | 1 + linux-core/nv50_graph.c | 1 + linux-core/nv50_mc.c | 1 + shared-core/drm_pciids.txt | 8 +++++ shared-core/nouveau_drv.h | 20 +++++++++++ shared-core/nouveau_state.c | 21 ++++++++++++ shared-core/nv50_fifo.c | 83 ++++++++++++++++++++++++++++++++++++++++++++ shared-core/nv50_graph.c | 84 +++++++++++++++++++++++++++++++++++++++++++++ shared-core/nv50_mc.c | 42 +++++++++++++++++++++++ 10 files changed, 264 insertions(+), 3 deletions(-) create mode 120000 linux-core/nv50_fifo.c create mode 120000 linux-core/nv50_graph.c create mode 120000 linux-core/nv50_mc.c create mode 100644 shared-core/nv50_fifo.c create mode 100644 shared-core/nv50_graph.c create mode 100644 shared-core/nv50_mc.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 6ab17a49..478c4df0 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -23,11 +23,11 @@ i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o \ nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ nouveau_object.o nouveau_irq.o nouveau_notifier.o \ nv04_timer.o \ - nv04_mc.o nv40_mc.o \ + nv04_mc.o nv40_mc.o nv50_mc.o \ nv04_fb.o nv10_fb.o nv40_fb.o \ - nv04_fifo.o nv10_fifo.o nv40_fifo.o \ + nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o \ nv04_graph.o nv10_graph.o nv20_graph.o nv30_graph.o \ - nv40_graph.o + nv40_graph.o nv50_graph.o radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o sis-objs := sis_drv.o sis_mm.o ffb-objs := ffb_drv.o ffb_context.o diff --git a/linux-core/nv50_fifo.c b/linux-core/nv50_fifo.c new file mode 120000 index 00000000..4c9990a9 --- /dev/null +++ b/linux-core/nv50_fifo.c @@ -0,0 +1 @@ +../shared-core/nv50_fifo.c \ No newline at end of file diff --git a/linux-core/nv50_graph.c b/linux-core/nv50_graph.c new file mode 120000 index 00000000..03f69e68 --- /dev/null +++ b/linux-core/nv50_graph.c @@ -0,0 +1 @@ +../shared-core/nv50_graph.c \ No newline at end of file diff --git a/linux-core/nv50_mc.c b/linux-core/nv50_mc.c new file mode 120000 index 00000000..f4bb369e --- /dev/null +++ b/linux-core/nv50_mc.c @@ -0,0 +1 @@ +../shared-core/nv50_mc.c \ No newline at end of file diff --git a/shared-core/drm_pciids.txt b/shared-core/drm_pciids.txt index ad9994ec..126974d0 100644 --- a/shared-core/drm_pciids.txt +++ b/shared-core/drm_pciids.txt @@ -596,6 +596,9 @@ 0x10de 0x018d NV_17 "GeForce4 448 Go" 0x10de 0x0191 NV_50 "GeForce 8800 GTX" 0x10de 0x0193 NV_50 "GeForce 8800 GTS" +0x10de 0x0194 NV_50 "GeForce 8800 Ultra" +0x10de 0x019d NV_50 "Quadro FX 5600" +0x10de 0x019e NV_50 "Quadro FX 4600" 0x10de 0x01a0 NV_11|NV_NFORCE "GeForce2 MX Integrated Graphics" 0x10de 0x01d1 NV_44 "GeForce 7300 LE" 0x10de 0x01d6 NV_44 "GeForce Go 7200" @@ -702,6 +705,11 @@ 0x10de 0x03d1 NV_44 "GeForce 6100 nForce 405" 0x10de 0x03d2 NV_44 "GeForce 6100 nForce 400" 0x10de 0x03d5 NV_44 "GeForce 6100 nForce 420" +0x10de 0x0400 NV_50 "GeForce 8600 GTS" +0x10de 0x0402 NV_50 "GeForce 8600 GT" +0x10de 0x0421 NV_50 "GeForce 8500 GT" +0x10de 0x0422 NV_50 "GeForce 8400 GS" +0x10de 0x0423 NV_50 "GeForce 8300 GS" 0x12d2 0x0008 NV_03 "NV1" 0x12d2 0x0009 NV_03 "DAC64" 0x12d2 0x0018 NV_03 "Riva128" diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index 7a1ca3d5..f549e600 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -295,6 +295,14 @@ extern void nv40_fifo_destroy_context(drm_device_t *, int channel); extern int nv40_fifo_load_context(drm_device_t *, int channel); extern int nv40_fifo_save_context(drm_device_t *, int channel); +/* nv50_fifo.c */ +extern int nv50_fifo_init(drm_device_t *); +extern void nv50_fifo_takedown(drm_device_t *); +extern int nv50_fifo_create_context(drm_device_t *, int channel); +extern void nv50_fifo_destroy_context(drm_device_t *, int channel); +extern int nv50_fifo_load_context(drm_device_t *, int channel); +extern int nv50_fifo_save_context(drm_device_t *, int channel); + /* nv04_graph.c */ extern void nouveau_nv04_context_switch(drm_device_t *dev); extern int nv04_graph_init(drm_device_t *dev); @@ -338,6 +346,14 @@ extern void nv40_graph_destroy_context(drm_device_t *, int channel); extern int nv40_graph_load_context(drm_device_t *, int channel); extern int nv40_graph_save_context(drm_device_t *, int channel); +/* nv50_graph.c */ +extern int nv50_graph_init(drm_device_t *); +extern void nv50_graph_takedown(drm_device_t *); +extern int nv50_graph_create_context(drm_device_t *, int channel); +extern void nv50_graph_destroy_context(drm_device_t *, int channel); +extern int nv50_graph_load_context(drm_device_t *, int channel); +extern int nv50_graph_save_context(drm_device_t *, int channel); + /* nv04_mc.c */ extern int nv04_mc_init(drm_device_t *dev); extern void nv04_mc_takedown(drm_device_t *dev); @@ -346,6 +362,10 @@ extern void nv04_mc_takedown(drm_device_t *dev); extern int nv40_mc_init(drm_device_t *dev); extern void nv40_mc_takedown(drm_device_t *dev); +/* nv50_mc.c */ +extern int nv50_mc_init(drm_device_t *dev); +extern void nv50_mc_takedown(drm_device_t *dev); + /* nv04_timer.c */ extern int nv04_timer_init(drm_device_t *dev); extern void nv04_timer_takedown(drm_device_t *dev); diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c index 68392c3a..0cb82355 100644 --- a/shared-core/nouveau_state.c +++ b/shared-core/nouveau_state.c @@ -72,6 +72,7 @@ static int nouveau_init_card_mappings(drm_device_t *dev) return 0; } +static int nouveau_stub_init(drm_device_t *dev) { return 0; } static void nouveau_stub_takedown(drm_device_t *dev) {} static int nouveau_init_engine_ptrs(drm_device_t *dev) { @@ -187,6 +188,26 @@ static int nouveau_init_engine_ptrs(drm_device_t *dev) engine->fifo.save_context = nv40_fifo_save_context; break; case 0x50: + case 0x80: /* gotta love NVIDIA's consistency.. */ + engine->mc.init = nv50_mc_init; + engine->mc.takedown = nv50_mc_takedown; + engine->timer.init = nouveau_stub_init; + engine->timer.takedown = nouveau_stub_takedown; + engine->fb.init = nouveau_stub_init; + engine->fb.takedown = nouveau_stub_takedown; + engine->graph.init = nv50_graph_init; + engine->graph.takedown = nv50_graph_takedown; + engine->graph.create_context = nv50_graph_create_context; + engine->graph.destroy_context = nv50_graph_destroy_context; + engine->graph.load_context = nv50_graph_load_context; + engine->graph.save_context = nv50_graph_save_context; + engine->fifo.init = nv50_fifo_init; + engine->fifo.takedown = nv50_fifo_takedown; + engine->fifo.create_context = nv50_fifo_create_context; + engine->fifo.destroy_context = nv50_fifo_destroy_context; + engine->fifo.load_context = nv50_fifo_load_context; + engine->fifo.save_context = nv50_fifo_save_context; + break; default: DRM_ERROR("NV%02x unsupported\n", dev_priv->chipset); return 1; diff --git a/shared-core/nv50_fifo.c b/shared-core/nv50_fifo.c new file mode 100644 index 00000000..e5d37949 --- /dev/null +++ b/shared-core/nv50_fifo.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2007 Ben Skeggs. + * 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 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. + * + */ + +#include "drmP.h" +#include "drm.h" +#include "nouveau_drv.h" + +static void +nv50_fifo_init_reset(drm_device_t *dev) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + uint32_t pmc_e; + + pmc_e = NV_READ(NV03_PMC_ENABLE); + NV_WRITE(NV03_PMC_ENABLE, pmc_e & ~NV_PMC_ENABLE_PFIFO); + pmc_e = NV_READ(NV03_PMC_ENABLE); + NV_WRITE(NV03_PMC_ENABLE, pmc_e | NV_PMC_ENABLE_PFIFO); +} + +int +nv50_fifo_init(drm_device_t *dev) +{ + nv50_fifo_init_reset(dev); + + DRM_ERROR("stub!\n"); + return 0; +} + +void +nv50_fifo_takedown(drm_device_t *dev) +{ + DRM_ERROR("stub!\n"); +} + +int +nv50_fifo_create_context(drm_device_t *dev, int channel) +{ + DRM_ERROR("stub!\n"); + return 0; +} + +void +nv50_fifo_destroy_context(drm_device_t *dev, int channel) +{ +} + +int +nv50_fifo_load_context(drm_device_t *dev, int channel) +{ + DRM_ERROR("stub!\n"); + return 0; +} + +int +nv50_fifo_save_context(drm_device_t *dev, int channel) +{ + DRM_ERROR("stub!\n"); + return 0; +} + diff --git a/shared-core/nv50_graph.c b/shared-core/nv50_graph.c new file mode 100644 index 00000000..8c3e2b9b --- /dev/null +++ b/shared-core/nv50_graph.c @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2007 Ben Skeggs. + * 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 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. + * + */ + +#include "drmP.h" +#include "drm.h" +#include "nouveau_drv.h" + +static void +nv50_graph_init_reset(drm_device_t *dev) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + uint32_t pmc_e; + + pmc_e = NV_READ(NV03_PMC_ENABLE); + NV_WRITE(NV03_PMC_ENABLE, pmc_e & ~NV_PMC_ENABLE_PGRAPH); + pmc_e = NV_READ(NV03_PMC_ENABLE); + NV_WRITE(NV03_PMC_ENABLE, pmc_e | NV_PMC_ENABLE_PGRAPH); +} + +int +nv50_graph_init(drm_device_t *dev) +{ + nv50_graph_init_reset(dev); + + DRM_ERROR("stub!\n"); + return 0; +} + +void +nv50_graph_takedown(drm_device_t *dev) +{ + DRM_ERROR("stub!\n"); +} + +int +nv50_graph_create_context(drm_device_t *dev, int channel) +{ + DRM_ERROR("stub!\n"); + return 0; +} + +void +nv50_graph_destroy_context(drm_device_t *dev, int channel) +{ + DRM_ERROR("stub!\n"); +} + +int +nv50_graph_load_context(drm_device_t *dev, int channel) +{ + DRM_ERROR("stub!\n"); + return 0; +} + +int +nv50_graph_save_context(drm_device_t *dev, int channel) +{ + DRM_ERROR("stub!\n"); + return 0; +} + diff --git a/shared-core/nv50_mc.c b/shared-core/nv50_mc.c new file mode 100644 index 00000000..7f7537f0 --- /dev/null +++ b/shared-core/nv50_mc.c @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2007 Ben Skeggs. + * 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 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. + * + */ + +#include "drmP.h" +#include "drm.h" +#include "nouveau_drv.h" + +int +nv50_mc_init(drm_device_t *dev) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + + NV_WRITE(NV03_PMC_ENABLE, 0xFFFFFFFF); + return 0; +} + +void nv50_mc_takedown(drm_device_t *dev) +{ +} -- cgit v1.2.3 From 38617b6a26d893bbd7b235019159e609f6cdd84b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 25 Jun 2007 03:52:06 +1000 Subject: nouveau: name some regs --- shared-core/nouveau_reg.h | 15 +++++++++++++++ shared-core/nv30_graph.c | 10 ++++++---- shared-core/nv40_graph.c | 29 +++++++++++++++++------------ 3 files changed, 38 insertions(+), 16 deletions(-) diff --git a/shared-core/nouveau_reg.h b/shared-core/nouveau_reg.h index ba61f997..4c013c53 100644 --- a/shared-core/nouveau_reg.h +++ b/shared-core/nouveau_reg.h @@ -135,6 +135,17 @@ #define NV10_PGRAPH_CTX_CACHE4 0x004001C0 #define NV04_PGRAPH_CTX_CACHE4 0x004001E0 #define NV10_PGRAPH_CTX_CACHE5 0x004001E0 +#define NV40_PGRAPH_CTXCTL_0304 0x00400304 +#define NV40_PGRAPH_CTXCTL_0304_XFER_CTX 0x00000001 +#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_INST_MASK 0x000FFFFF #define NV03_PGRAPH_ABS_X_RAM 0x00400400 #define NV03_PGRAPH_ABS_Y_RAM 0x00400480 #define NV03_PGRAPH_X_MISC 0x00400500 @@ -230,7 +241,11 @@ #define NV10_PGRAPH_SCALED_FORMAT 0x00400778 #define NV10_PGRAPH_CHANNEL_CTX_TABLE 0x00400780 #define NV10_PGRAPH_CHANNEL_CTX_SIZE 0x00400784 +#define NV20_PGRAPH_CHANNEL_CTX_POINTER 0x00400784 #define NV10_PGRAPH_CHANNEL_CTX_POINTER 0x00400788 +#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 diff --git a/shared-core/nv30_graph.c b/shared-core/nv30_graph.c index 9f064a0a..7a87990a 100644 --- a/shared-core/nv30_graph.c +++ b/shared-core/nv30_graph.c @@ -174,8 +174,9 @@ int nv30_graph_load_context(drm_device_t *dev, int channel) return DRM_ERR(EINVAL); inst = nouveau_chip_instance_get(dev, chan->ramin_grctx); - NV_WRITE(0x400784, inst); - NV_WRITE(0x400788, 1); + NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_POINTER, inst); + NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_XFER, + NV20_PGRAPH_CHANNEL_CTX_XFER_LOAD); return nouveau_graph_wait_idle(dev); } @@ -190,8 +191,9 @@ int nv30_graph_save_context(drm_device_t *dev, int channel) return DRM_ERR(EINVAL); inst = nouveau_chip_instance_get(dev, chan->ramin_grctx); - NV_WRITE(0x400784, inst); - NV_WRITE(0x400788, 2); + NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_POINTER, inst); + NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_XFER, + NV20_PGRAPH_CHANNEL_CTX_XFER_SAVE); return nouveau_graph_wait_idle(dev); } diff --git a/shared-core/nv40_graph.c b/shared-core/nv40_graph.c index acd0cb0f..6fb575db 100644 --- a/shared-core/nv40_graph.c +++ b/shared-core/nv40_graph.c @@ -1304,20 +1304,23 @@ nv40_graph_transfer_context(drm_device_t *dev, uint32_t inst, int save) uint32_t old_cp, tv = 1000; int i; - old_cp = NV_READ(0x400784); - NV_WRITE(0x400784, inst); - NV_WRITE(0x400310, save ? 0x20 : 0x40); - NV_WRITE(0x400304, 1); + old_cp = NV_READ(NV20_PGRAPH_CHANNEL_CTX_POINTER); + NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_POINTER, inst); + NV_WRITE(NV40_PGRAPH_CTXCTL_0310, + save ? NV40_PGRAPH_CTXCTL_0310_XFER_SAVE : + NV40_PGRAPH_CTXCTL_0310_XFER_LOAD); + NV_WRITE(NV40_PGRAPH_CTXCTL_0304, NV40_PGRAPH_CTXCTL_0304_XFER_CTX); for (i = 0; i < tv; i++) { - if (NV_READ(0x40030c) == 0) + if (NV_READ(NV40_PGRAPH_CTXCTL_030C) == 0) break; } - NV_WRITE(0x400784, old_cp); + NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_POINTER, old_cp); if (i == tv) { DRM_ERROR("failed: inst=0x%08x save=%d\n", inst, save); - DRM_ERROR("0x40030C = 0x%08x\n", NV_READ(0x40030c)); + DRM_ERROR("0x40030C = 0x%08x\n", + NV_READ(NV40_PGRAPH_CTXCTL_030C)); return DRM_ERR(EBUSY); } @@ -1365,8 +1368,10 @@ nv40_graph_load_context(drm_device_t *dev, int channel) * unknown as to what bit 24 does. The nv ddx has it set, so we will * set it here too. */ - NV_WRITE(0x400784, inst); - NV_WRITE(0x40032C, inst | 0x01000000); + NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_POINTER, inst); + NV_WRITE(NV40_PGRAPH_CTXCTL_CUR, + (inst & NV40_PGRAPH_CTXCTL_CUR_INST_MASK) | + NV40_PGRAPH_CTXCTL_CUR_LOADED); /* 0x32E0 records the instance address of the active FIFO's PGRAPH * context. If at any time this doesn't match 0x40032C, you will * recieve PGRAPH_INTR_CONTEXT_SWITCH @@ -1631,15 +1636,15 @@ nv40_graph_init(drm_device_t *dev) DRM_DEBUG("Loading context-switch voodoo\n"); i = 0; - NV_WRITE(0x400324, 0); + NV_WRITE(NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0); while (ctx_voodoo[i] != ~0) { - NV_WRITE(0x400328, ctx_voodoo[i]); + NV_WRITE(NV40_PGRAPH_CTXCTL_UCODE_DATA, ctx_voodoo[i]); i++; } } /* No context present currently */ - NV_WRITE(0x40032C, 0x00000000); + NV_WRITE(NV40_PGRAPH_CTXCTL_CUR, 0x00000000); NV_WRITE(NV03_PGRAPH_INTR_EN, 0x00000000); NV_WRITE(NV03_PGRAPH_INTR , 0xFFFFFFFF); -- cgit v1.2.3 From 18a6d1c9c380b6b19524f654d9173a79e19aa1df Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 25 Jun 2007 15:16:19 +1000 Subject: nouveau: simplify PRAMIN access --- shared-core/nouveau_drv.h | 18 +++++++++++------- shared-core/nouveau_mem.c | 32 -------------------------------- shared-core/nouveau_state.c | 18 ++++++++++++++++-- 3 files changed, 27 insertions(+), 41 deletions(-) diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index f549e600..b2ddf0a6 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -220,11 +220,6 @@ extern struct mem_block* nouveau_instmem_alloc(struct drm_device *dev, uint32_t size, uint32_t align); extern void nouveau_instmem_free(struct drm_device *dev, struct mem_block *block); -extern uint32_t nouveau_instmem_r32(drm_nouveau_private_t *dev_priv, - struct mem_block *mem, int index); -extern void nouveau_instmem_w32(drm_nouveau_private_t *dev_priv, - struct mem_block *mem, int index, - uint32_t val); /* nouveau_notifier.c */ extern int nouveau_notifier_init_channel(drm_device_t *, int channel, DRMFILE); @@ -381,8 +376,17 @@ extern long nouveau_compat_ioctl(struct file *filp, unsigned int cmd, #define NV_WRITE(reg,val) DRM_WRITE32( dev_priv->mmio, (reg), (val) ) #endif -#define INSTANCE_WR(mem,ofs,val) nouveau_instmem_w32(dev_priv,(mem),(ofs),(val)) -#define INSTANCE_RD(mem,ofs) nouveau_instmem_r32(dev_priv,(mem),(ofs)) +/* PRAMIN access */ +#if defined(__powerpc__) +#define NV_RI32(o) in_be32((void __iomem *)(dev_priv->ramin)->handle+(o)) +#define NV_WI32(o,v) out_be32((void __iomem*)(dev_priv->ramin)->handle+(o), (v)) +#else +#define NV_RI32(o) DRM_READ32(dev_priv->ramin, (o)) +#define NV_WI32(o,v) DRM_WRITE32(dev_priv->ramin, (o), (v)) +#endif + +#define INSTANCE_RD(o,i) NV_RI32((o)->start + ((i)<<2)) +#define INSTANCE_WR(o,i,v) NV_WI32((o)->start + ((i)<<2), (v)) #endif /* __NOUVEAU_DRV_H__ */ diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index edfc9d3f..4c6d0d5c 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -602,38 +602,6 @@ void nouveau_instmem_free(struct drm_device *dev, struct mem_block *block) } } -uint32_t nouveau_instmem_r32(drm_nouveau_private_t *dev_priv, - struct mem_block *mem, int index) -{ - uint32_t ofs = (uint32_t)mem->start + (index<<2); - - if (dev_priv->ramin) { -#if defined(__powerpc__) - return in_be32((void __iomem *)(dev_priv->ramin)->handle + ofs); -#else - return DRM_READ32(dev_priv->ramin, ofs); -#endif - } else { - return NV_READ(NV_RAMIN+ofs); - } -} - -void nouveau_instmem_w32(drm_nouveau_private_t *dev_priv, - struct mem_block *mem, int index, uint32_t val) -{ - uint32_t ofs = (uint32_t)mem->start + (index<<2); - - if (dev_priv->ramin) { -#if defined(__powerpc__) - out_be32((void __iomem *)(dev_priv->ramin)->handle + ofs, val); -#else - DRM_WRITE32(dev_priv->ramin, ofs, val); -#endif - } else { - NV_WRITE(NV_RAMIN+ofs, val); - } -} - /* * Ioctls */ diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c index 0cb82355..94d8081c 100644 --- a/shared-core/nouveau_state.c +++ b/shared-core/nouveau_state.c @@ -51,6 +51,7 @@ static int nouveau_init_card_mappings(drm_device_t *dev) DRM_DEBUG("regs mapped ok at 0x%lx\n", dev_priv->mmio->offset); /* map larger RAMIN aperture on NV40 cards */ + dev_priv->ramin = NULL; if (dev_priv->card_type >= NV_40) { int ramin_resource = 2; if (drm_get_resource_len(dev, ramin_resource) == 0) @@ -66,8 +67,21 @@ static int nouveau_init_card_mappings(drm_device_t *dev) "limited instance memory available\n"); dev_priv->ramin = NULL; } - } else - dev_priv->ramin = NULL; + } + + /* On older cards (or if the above failed), create a map covering + * the BAR0 PRAMIN aperture */ + if (!dev_priv->ramin) { + ret = drm_addmap(dev, + drm_get_resource_start(dev, 0) + NV_RAMIN, + (1*1024*1024), + _DRM_REGISTERS, _DRM_READ_ONLY, + &dev_priv->ramin); + if (ret) { + DRM_ERROR("Failed to map BAR0 PRAMIN: %d\n", ret); + return ret; + } + } return 0; } -- cgit v1.2.3 From 68ecf61647e9ec16d59cc8f50550d11478eb3118 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 25 Jun 2007 15:42:55 +1000 Subject: nouveau: never touch PRAMIN with NV_WRITE, cleanup RAMHT code a bit --- shared-core/nouveau_drv.h | 5 +- shared-core/nouveau_mem.c | 9 +-- shared-core/nouveau_notifier.c | 2 +- shared-core/nouveau_object.c | 133 +++++++++++++++++++++++++---------------- shared-core/nv04_fifo.c | 10 ++-- shared-core/nv10_fifo.c | 16 ++--- shared-core/nv40_fifo.c | 16 ++--- 7 files changed, 106 insertions(+), 85 deletions(-) diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index b2ddf0a6..3cca07fc 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -64,7 +64,6 @@ struct nouveau_object int channel; struct mem_block *instance; - uint32_t ht_loc; uint32_t handle; int class; @@ -242,8 +241,8 @@ extern int nouveau_object_init_channel(drm_device_t *, int channel, uint32_t tt_handle); extern void nouveau_object_takedown_channel(drm_device_t *dev, int channel); extern void nouveau_object_cleanup(drm_device_t *dev, int channel); -extern int nouveau_ht_object_insert(drm_device_t *, int channel, - uint32_t handle, struct nouveau_object *); +extern int nouveau_ramht_insert(drm_device_t *, int channel, + uint32_t handle, struct nouveau_object *); extern struct nouveau_object * nouveau_object_gr_create(drm_device_t *dev, int channel, int class); extern struct nouveau_object * diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index 4c6d0d5c..d8ae52b7 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -489,13 +489,8 @@ nouveau_instmem_determine_amount(struct drm_device *dev) DRM_DEBUG("RAMIN size: %dKiB\n", dev_priv->ramin_size>>10); /* Clear all of it, except the BIOS image that's in the first 64KiB */ - if (dev_priv->ramin) { - for (i=(64*1024); iramin_size; i+=4) - DRM_WRITE32(dev_priv->ramin, i, 0x00000000); - } else { - for (i=(64*1024); iramin_size; i+=4) - DRM_WRITE32(dev_priv->mmio, NV_RAMIN + i, 0x00000000); - } + for (i=(64*1024); iramin_size; i+=4) + NV_WI32(i, 0x00000000); } static void diff --git a/shared-core/nouveau_notifier.c b/shared-core/nouveau_notifier.c index ab6f8c2d..0cfe733e 100644 --- a/shared-core/nouveau_notifier.c +++ b/shared-core/nouveau_notifier.c @@ -115,7 +115,7 @@ nouveau_notifier_alloc(drm_device_t *dev, int channel, uint32_t handle, } obj->handle = handle; - if (nouveau_ht_object_insert(dev, channel, handle, obj)) { + if (nouveau_ramht_insert(dev, channel, handle, obj)) { nouveau_object_free(dev, obj); nouveau_mem_free_block(mem); DRM_ERROR("Error inserting notifier ctxdma into RAMHT\n"); diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index e7528e23..dac08df4 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -139,7 +139,7 @@ nouveau_object_handle_find(drm_device_t *dev, int channel, uint32_t handle) is given as: */ static uint32_t -nouveau_ht_handle_hash(drm_device_t *dev, int channel, uint32_t handle) +nouveau_ramht_hash_handle(drm_device_t *dev, int channel, uint32_t handle) { drm_nouveau_private_t *dev_priv=dev->dev_private; uint32_t hash = 0; @@ -153,63 +153,90 @@ nouveau_ht_handle_hash(drm_device_t *dev, int channel, uint32_t handle) return hash << 3; } +static int +nouveau_ramht_entry_valid(drm_device_t *dev, uint32_t ramht, uint32_t offset) +{ + drm_nouveau_private_t *dev_priv=dev->dev_private; + uint32_t ctx = NV_RI32(ramht + offset + 4); + + if (dev_priv->card_type < NV_40) + return ((ctx & NV_RAMHT_CONTEXT_VALID) != 0); + return (ctx != 0); +} + int -nouveau_ht_object_insert(drm_device_t* dev, int channel, uint32_t handle, - struct nouveau_object *obj) +nouveau_ramht_insert(drm_device_t* dev, int channel, uint32_t handle, + struct nouveau_object *obj) { drm_nouveau_private_t *dev_priv=dev->dev_private; - int ht_base = NV_RAMIN + dev_priv->ramht_offset; -/* int ht_end = ht_base + dev_priv->ramht_size; */ - int o_ofs, ofs; - - obj->handle = handle; - o_ofs = ofs = nouveau_ht_handle_hash(dev, channel, obj->handle); - - while (NV_READ(ht_base + ofs) || NV_READ(ht_base + ofs + 4)) { - ofs += 8; - if (ofs == dev_priv->ramht_size) ofs = 0; - if (ofs == o_ofs) { - DRM_ERROR("no free hash table entries\n"); - return 1; - } + uint32_t ramht = dev_priv->ramht_offset; + uint32_t ctx, co, ho; + uint32_t inst; + + inst = nouveau_chip_instance_get(dev, obj->instance); + if (dev_priv->card_type < NV_40) { + ctx = NV_RAMHT_CONTEXT_VALID | inst | + (channel << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) | + (obj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT); + } else + if (dev_priv->card_type < NV_50) { + ctx = inst | + (channel << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) | + (obj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT); + } else { + ctx = inst | + (obj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT); } - ofs += ht_base; - - DRM_DEBUG("Channel %d - Handle 0x%08x at 0x%08x\n", - channel, obj->handle, ofs); - - NV_WRITE(NV_RAMHT_HANDLE_OFFSET + ofs, obj->handle); - if (dev_priv->card_type >= NV_40) - NV_WRITE(NV_RAMHT_CONTEXT_OFFSET + ofs, - (channel << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) | - (obj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT) | - nouveau_chip_instance_get(dev, obj->instance) - ); - else - NV_WRITE(NV_RAMHT_CONTEXT_OFFSET + ofs, - NV_RAMHT_CONTEXT_VALID | - (channel << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) | - (obj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT) | - nouveau_chip_instance_get(dev, obj->instance) - ); - - obj->ht_loc = ofs; - return 0; + + co = ho = nouveau_ramht_hash_handle(dev, channel, handle); + do { + if (!nouveau_ramht_entry_valid(dev, ramht, co)) { + DRM_DEBUG("insert ch%d 0x%08x: h=0x%08x, c=0x%08x\n", + channel, co, handle, ctx); + NV_WI32(ramht + co + 0, handle); + NV_WI32(ramht + co + 4, ctx); + obj->handle = handle; + return 0; + } + DRM_DEBUG("collision ch%d 0x%08x: h=0x%08x\n", + channel, co, NV_RI32(ramht + co)); + + co += 8; + if (co == dev_priv->ramht_size) + co = 0; + } while (co != ho); + + DRM_ERROR("RAMHT space exhausted. ch=%d\n", channel); + return DRM_ERR(ENOMEM); } -static void nouveau_hash_table_remove(drm_device_t* dev, - struct nouveau_object *obj) +static void +nouveau_ramht_remove(drm_device_t* dev, struct nouveau_object *obj) { drm_nouveau_private_t *dev_priv = dev->dev_private; + uint32_t ramht = dev_priv->ramht_offset; + uint32_t co, ho; + + co = ho = nouveau_ramht_hash_handle(dev, obj->channel, obj->handle); + do { + if (nouveau_ramht_entry_valid(dev, ramht, co) && + (obj->handle == NV_RI32(ramht + co))) { + DRM_DEBUG("remove ch%d 0x%08x: h=0x%08x, c=0x%08x\n", + obj->channel, co, obj->handle, + NV_RI32(ramht + co + 4)); + NV_WI32(ramht + co + 0, 0x00000000); + NV_WI32(ramht + co + 4, 0x00000000); + obj->handle = ~0; + return; + } - DRM_DEBUG("Remove handle 0x%08x at 0x%08x from HT\n", - obj->handle, obj->ht_loc); - if (obj->ht_loc) { - DRM_DEBUG("... HT entry was: 0x%08x/0x%08x\n", - NV_READ(obj->ht_loc), NV_READ(obj->ht_loc+4)); - NV_WRITE(obj->ht_loc , 0x00000000); - NV_WRITE(obj->ht_loc+4, 0x00000000); - } + co += 8; + if (co == dev_priv->ramht_size) + co = 0; + } while (co != ho); + + DRM_ERROR("RAMHT entry not found. ch=%d, handle=0x%08x\n", + obj->channel, obj->handle); } static struct nouveau_object * @@ -457,7 +484,7 @@ nouveau_object_free(drm_device_t *dev, struct nouveau_object *obj) { nouveau_object_instance_free(dev, obj); if (obj->handle != ~0) - nouveau_hash_table_remove(dev, obj); + nouveau_ramht_remove(dev, obj); drm_free(obj, sizeof(struct nouveau_object), DRM_MEM_DRIVER); } @@ -480,7 +507,7 @@ nouveau_object_init_channel(drm_device_t *dev, int channel, return DRM_ERR(ENOMEM); } - ret = nouveau_ht_object_insert(dev, channel, vram_handle, gpuobj); + ret = nouveau_ramht_insert(dev, channel, vram_handle, gpuobj); if (ret) { DRM_ERROR("Error referencing VRAM ctxdma: %d\n", ret); return ret; @@ -500,7 +527,7 @@ nouveau_object_init_channel(drm_device_t *dev, int channel, return DRM_ERR(ENOMEM); } - ret = nouveau_ht_object_insert(dev, channel, tt_handle, gpuobj); + ret = nouveau_ramht_insert(dev, channel, tt_handle, gpuobj); if (ret) { DRM_ERROR("Error referencing TT ctxdma: %d\n", ret); return ret; @@ -545,7 +572,7 @@ int nouveau_ioctl_grobj_alloc(DRM_IOCTL_ARGS) if (!obj) return DRM_ERR(ENOMEM); - if (nouveau_ht_object_insert(dev, init.channel, init.handle, obj)) { + if (nouveau_ramht_insert(dev, init.channel, init.handle, obj)) { nouveau_object_free(dev, obj); return DRM_ERR(ENOMEM); } diff --git a/shared-core/nv04_fifo.c b/shared-core/nv04_fifo.c index 783514a7..57010182 100644 --- a/shared-core/nv04_fifo.c +++ b/shared-core/nv04_fifo.c @@ -28,9 +28,9 @@ #include "drm.h" #include "nouveau_drv.h" -#define NV04_RAMFC (NV_RAMIN + dev_priv->ramfc_offset) -#define RAMFC_WR(offset, val) NV_WRITE(fifoctx + NV04_RAMFC_##offset, (val)) -#define RAMFC_RD(offset) NV_READ(fifoctx + NV04_RAMFC_##offset) +#define NV04_RAMFC dev_priv->ramfc_offset +#define RAMFC_WR(offset, val) NV_WI32(fifoctx + NV04_RAMFC_##offset, (val)) +#define RAMFC_RD(offset) NV_RI32(fifoctx + NV04_RAMFC_##offset) #define NV04_FIFO_CONTEXT_SIZE 32 int @@ -47,7 +47,7 @@ nv04_fifo_create_context(drm_device_t *dev, int channel) /* Clear RAMFC */ for (i=0; ipushbuf_base); @@ -72,7 +72,7 @@ nv04_fifo_destroy_context(drm_device_t *dev, int channel) fifoctx = NV04_RAMFC + (channel * NV04_FIFO_CONTEXT_SIZE); for (i=0; icmdbuf_obj->instance); - fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel*64; + fifoctx = dev_priv->ramfc_offset + channel*64; for (i=0; iramfc_offset + channel*64; + fifoctx = dev_priv->ramfc_offset + channel*64; for (i=0; iramfc_offset + channel*64; + fifoctx = dev_priv->ramfc_offset + channel*64; NV_WRITE(NV03_PFIFO_CACHE1_PUSH1 , 0x00000100 | channel); @@ -118,7 +118,7 @@ nv10_fifo_save_context(drm_device_t *dev, int channel) uint32_t fifoctx; uint32_t tmp; - fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel*64; + fifoctx = dev_priv->ramfc_offset + channel*64; RAMFC_WR(DMA_PUT , NV_READ(NV04_PFIFO_CACHE1_DMA_PUT)); RAMFC_WR(DMA_GET , NV_READ(NV04_PFIFO_CACHE1_DMA_GET)); diff --git a/shared-core/nv40_fifo.c b/shared-core/nv40_fifo.c index 9d7afbe5..945fe228 100644 --- a/shared-core/nv40_fifo.c +++ b/shared-core/nv40_fifo.c @@ -28,8 +28,8 @@ #include "nouveau_drv.h" #include "nouveau_drm.h" -#define RAMFC_WR(offset, val) NV_WRITE(fifoctx + NV40_RAMFC_##offset, (val)) -#define RAMFC_RD(offset) NV_READ (fifoctx + NV40_RAMFC_##offset) +#define RAMFC_WR(offset, val) NV_WI32(fifoctx + NV40_RAMFC_##offset, (val)) +#define RAMFC_RD(offset) NV_RI32(fifoctx + NV40_RAMFC_##offset) int nv40_fifo_create_context(drm_device_t *dev, int channel) @@ -39,9 +39,9 @@ nv40_fifo_create_context(drm_device_t *dev, int channel) uint32_t fifoctx, grctx, pushbuf; int i; - fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel*128; + fifoctx = dev_priv->ramfc_offset + channel*128; for (i=0;i<128;i+=4) - NV_WRITE(fifoctx + i, 0); + NV_WI32(fifoctx + i, 0); grctx = nouveau_chip_instance_get(dev, chan->ramin_grctx); pushbuf = nouveau_chip_instance_get(dev, chan->cmdbuf_obj->instance); @@ -73,9 +73,9 @@ nv40_fifo_destroy_context(drm_device_t *dev, int channel) uint32_t fifoctx; int i; - fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel*128; + fifoctx = dev_priv->ramfc_offset + channel*128; for (i=0;i<128;i+=4) - NV_WRITE(fifoctx + i, 0); + NV_WI32(fifoctx + i, 0); } int @@ -85,7 +85,7 @@ nv40_fifo_load_context(drm_device_t *dev, int channel) uint32_t fifoctx; uint32_t tmp, tmp2; - fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel*128; + fifoctx = dev_priv->ramfc_offset + channel*128; NV_WRITE(NV04_PFIFO_CACHE1_DMA_GET , RAMFC_RD(DMA_GET)); NV_WRITE(NV04_PFIFO_CACHE1_DMA_PUT , RAMFC_RD(DMA_PUT)); @@ -146,7 +146,7 @@ nv40_fifo_save_context(drm_device_t *dev, int channel) uint32_t fifoctx; uint32_t tmp; - fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel*128; + fifoctx = dev_priv->ramfc_offset + channel*128; RAMFC_WR(DMA_PUT , NV_READ(NV04_PFIFO_CACHE1_DMA_PUT)); RAMFC_WR(DMA_GET , NV_READ(NV04_PFIFO_CACHE1_DMA_GET)); -- cgit v1.2.3 From 2dd85772aa4e134730f294d77b4ff030a175a4ab Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 28 Jun 2007 04:23:17 +1000 Subject: nouveau/nv10: Fix earlier NV1x chips Can't use nv04 code for them, since an extra field was inserted into RAMFC after DMA_PUT/GET. --- shared-core/nouveau_state.c | 7 ------ shared-core/nv10_fifo.c | 57 +++++++++++++++++++++++++++------------------ 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c index 94d8081c..fa773d28 100644 --- a/shared-core/nouveau_state.c +++ b/shared-core/nouveau_state.c @@ -129,17 +129,10 @@ static int nouveau_init_engine_ptrs(drm_device_t *dev) engine->graph.save_context = nv10_graph_save_context; engine->fifo.init = nouveau_fifo_init; engine->fifo.takedown = nouveau_stub_takedown; - if (dev_priv->chipset < 0x17) { - engine->fifo.create_context = nv04_fifo_create_context; - engine->fifo.destroy_context = nv04_fifo_destroy_context; - engine->fifo.load_context = nv04_fifo_load_context; - engine->fifo.save_context = nv04_fifo_save_context; - } else { engine->fifo.create_context = nv10_fifo_create_context; engine->fifo.destroy_context = nv10_fifo_destroy_context; engine->fifo.load_context = nv10_fifo_load_context; engine->fifo.save_context = nv10_fifo_save_context; - } break; case 0x20: engine->mc.init = nv04_mc_init; diff --git a/shared-core/nv10_fifo.c b/shared-core/nv10_fifo.c index 710a47f7..b84971de 100644 --- a/shared-core/nv10_fifo.c +++ b/shared-core/nv10_fifo.c @@ -30,20 +30,20 @@ #define RAMFC_WR(offset, val) NV_WI32(fifoctx + NV10_RAMFC_##offset, (val)) #define RAMFC_RD(offset) NV_RI32(fifoctx + NV10_RAMFC_##offset) -#define NV10_FIFO_CONTEXT_SIZE 64 +#define NV10_RAMFC(c) (dev_priv->ramfc_offset + NV10_RAMFC__SIZE) +#define NV10_RAMFC__SIZE ((dev_priv->chipset) >= 0x17 ? 64 : 32) int nv10_fifo_create_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; struct nouveau_fifo *chan = &dev_priv->fifos[channel]; - uint32_t fifoctx, pushbuf; + uint32_t fifoctx = NV10_RAMFC(channel), pushbuf; int i; pushbuf = nouveau_chip_instance_get(dev, chan->cmdbuf_obj->instance); - fifoctx = dev_priv->ramfc_offset + channel*64; - for (i=0; idev_private; - uint32_t fifoctx; + uint32_t fifoctx = NV10_RAMFC(channel); int i; - fifoctx = dev_priv->ramfc_offset + channel*64; - for (i=0; idev_private; - uint32_t fifoctx; + uint32_t fifoctx = NV10_RAMFC(channel); uint32_t tmp; - fifoctx = dev_priv->ramfc_offset + channel*64; - NV_WRITE(NV03_PFIFO_CACHE1_PUSH1 , 0x00000100 | channel); NV_WRITE(NV04_PFIFO_CACHE1_DMA_GET , RAMFC_RD(DMA_GET)); @@ -98,11 +95,19 @@ nv10_fifo_load_context(drm_device_t *dev, int channel) NV_WRITE(NV04_PFIFO_CACHE1_DMA_FETCH , RAMFC_RD(DMA_FETCH)); NV_WRITE(NV04_PFIFO_CACHE1_ENGINE , RAMFC_RD(ENGINE)); NV_WRITE(NV04_PFIFO_CACHE1_PULL1 , RAMFC_RD(PULL1_ENGINE)); - NV_WRITE(NV10_PFIFO_CACHE1_ACQUIRE_VALUE , RAMFC_RD(ACQUIRE_VALUE)); - NV_WRITE(NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP, RAMFC_RD(ACQUIRE_TIMESTAMP)); - NV_WRITE(NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT , RAMFC_RD(ACQUIRE_TIMEOUT)); - NV_WRITE(NV10_PFIFO_CACHE1_SEMAPHORE , RAMFC_RD(SEMAPHORE)); - NV_WRITE(NV10_PFIFO_CACHE1_DMA_SUBROUTINE , RAMFC_RD(DMA_SUBROUTINE)); + + if (dev_priv->chipset >= 0x17) { + NV_WRITE(NV10_PFIFO_CACHE1_ACQUIRE_VALUE, + RAMFC_RD(ACQUIRE_VALUE)); + NV_WRITE(NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP, + RAMFC_RD(ACQUIRE_TIMESTAMP)); + NV_WRITE(NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT, + RAMFC_RD(ACQUIRE_TIMEOUT)); + NV_WRITE(NV10_PFIFO_CACHE1_SEMAPHORE, + RAMFC_RD(SEMAPHORE)); + NV_WRITE(NV10_PFIFO_CACHE1_DMA_SUBROUTINE, + RAMFC_RD(DMA_SUBROUTINE)); + } /* Reset NV04_PFIFO_CACHE1_DMA_CTL_AT_INFO to INVALID */ tmp = NV_READ(NV04_PFIFO_CACHE1_DMA_CTL) & ~(1<<31); @@ -115,11 +120,9 @@ int nv10_fifo_save_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - uint32_t fifoctx; + uint32_t fifoctx = NV10_RAMFC(channel); uint32_t tmp; - fifoctx = dev_priv->ramfc_offset + channel*64; - RAMFC_WR(DMA_PUT , NV_READ(NV04_PFIFO_CACHE1_DMA_PUT)); RAMFC_WR(DMA_GET , NV_READ(NV04_PFIFO_CACHE1_DMA_GET)); RAMFC_WR(REF_CNT , NV_READ(NV10_PFIFO_CACHE1_REF_CNT)); @@ -132,11 +135,19 @@ nv10_fifo_save_context(drm_device_t *dev, int channel) RAMFC_WR(DMA_FETCH , NV_READ(NV04_PFIFO_CACHE1_DMA_FETCH)); RAMFC_WR(ENGINE , NV_READ(NV04_PFIFO_CACHE1_ENGINE)); RAMFC_WR(PULL1_ENGINE , NV_READ(NV04_PFIFO_CACHE1_PULL1)); - RAMFC_WR(ACQUIRE_VALUE , NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_VALUE)); - RAMFC_WR(ACQUIRE_TIMESTAMP, NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP)); - RAMFC_WR(ACQUIRE_TIMEOUT , NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT)); - RAMFC_WR(SEMAPHORE , NV_READ(NV10_PFIFO_CACHE1_SEMAPHORE)); - RAMFC_WR(DMA_SUBROUTINE , NV_READ(NV04_PFIFO_CACHE1_DMA_GET)); + + if (dev_priv->chipset >= 0x17) { + RAMFC_WR(ACQUIRE_VALUE, + NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_VALUE)); + RAMFC_WR(ACQUIRE_TIMESTAMP, + NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP)); + RAMFC_WR(ACQUIRE_TIMEOUT, + NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT)); + RAMFC_WR(SEMAPHORE, + NV_READ(NV10_PFIFO_CACHE1_SEMAPHORE)); + RAMFC_WR(DMA_SUBROUTINE, + NV_READ(NV04_PFIFO_CACHE1_DMA_GET)); + } return 0; } -- cgit v1.2.3 From 1c32fecd6d2286af075976167c4887b9096e8312 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 28 Jun 2007 21:01:17 +1000 Subject: nouveau: Hack around possible Xv blit adaptor breakage --- shared-core/nouveau_fifo.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c index f179af63..81dbfcda 100644 --- a/shared-core/nouveau_fifo.c +++ b/shared-core/nouveau_fifo.c @@ -341,6 +341,19 @@ int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp, nouveau_fifo_free(dev, channel); return ret; } + + /* Temporary hack, to avoid breaking Xv on cards where the + * initial context value for 0x400710 doesn't have these bits + * set. Proper fix would be to find which object+method is + * responsible for modifying this state. + */ + if (dev_priv->chipset >= 0x10) { + uint32_t tmp; + tmp = NV_READ(NV10_PGRAPH_SURFACE) & 0x0007ff00; + NV_WRITE(NV10_PGRAPH_SURFACE, tmp); + tmp = NV_READ(NV10_PGRAPH_SURFACE) | 0x00020100; + NV_WRITE(NV10_PGRAPH_SURFACE, tmp); + } } NV_WRITE(NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001); -- cgit v1.2.3 From e26ec51146e77eec2a45f61c9506e9800fc2fba2 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 29 Jun 2007 13:52:55 +1000 Subject: nouveau: small RAMFC cleanups --- shared-core/nv04_fifo.c | 17 ++++++++--------- shared-core/nv40_fifo.c | 20 ++++++++------------ 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/shared-core/nv04_fifo.c b/shared-core/nv04_fifo.c index 57010182..bfae432e 100644 --- a/shared-core/nv04_fifo.c +++ b/shared-core/nv04_fifo.c @@ -28,10 +28,10 @@ #include "drm.h" #include "nouveau_drv.h" -#define NV04_RAMFC dev_priv->ramfc_offset #define RAMFC_WR(offset, val) NV_WI32(fifoctx + NV04_RAMFC_##offset, (val)) #define RAMFC_RD(offset) NV_RI32(fifoctx + NV04_RAMFC_##offset) -#define NV04_FIFO_CONTEXT_SIZE 32 +#define NV04_RAMFC(c) (dev_priv->ramfc_offset + ((c) * NV04_RAMFC__SIZE)) +#define NV04_RAMFC__SIZE 32 int nv04_fifo_create_context(drm_device_t *dev, int channel) @@ -39,14 +39,14 @@ nv04_fifo_create_context(drm_device_t *dev, int channel) drm_nouveau_private_t *dev_priv = dev->dev_private; struct nouveau_fifo *chan = &dev_priv->fifos[channel]; struct nouveau_object *pb = chan->cmdbuf_obj; - int fifoctx = NV04_RAMFC + (channel * NV04_FIFO_CONTEXT_SIZE); + uint32_t fifoctx = NV04_RAMFC(channel); int i; if (!pb || !pb->instance) return DRM_ERR(EINVAL); /* Clear RAMFC */ - for (i=0; idev_private; - uint32_t fifoctx; + uint32_t fifoctx = NV04_RAMFC(channel); int i; - fifoctx = NV04_RAMFC + (channel * NV04_FIFO_CONTEXT_SIZE); - for (i=0; idev_private; - int fifoctx = NV04_RAMFC + (channel * NV04_FIFO_CONTEXT_SIZE); + uint32_t fifoctx = NV04_RAMFC(channel); uint32_t tmp; NV_WRITE(NV03_PFIFO_CACHE1_PUSH1, (1<<8) | channel); @@ -107,7 +106,7 @@ int nv04_fifo_save_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - int fifoctx = NV04_RAMFC + (channel * NV04_FIFO_CONTEXT_SIZE); + uint32_t fifoctx = NV04_RAMFC(channel); uint32_t tmp; RAMFC_WR(DMA_PUT, NV04_PFIFO_CACHE1_DMA_PUT); diff --git a/shared-core/nv40_fifo.c b/shared-core/nv40_fifo.c index 945fe228..6f25349c 100644 --- a/shared-core/nv40_fifo.c +++ b/shared-core/nv40_fifo.c @@ -30,17 +30,18 @@ #define RAMFC_WR(offset, val) NV_WI32(fifoctx + NV40_RAMFC_##offset, (val)) #define RAMFC_RD(offset) NV_RI32(fifoctx + NV40_RAMFC_##offset) +#define NV40_RAMFC(c) (dev_priv->ramfc_offset + ((c)*NV40_RAMFC__SIZE)) +#define NV40_RAMFC__SIZE 128 int nv40_fifo_create_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; struct nouveau_fifo *chan = &dev_priv->fifos[channel]; - uint32_t fifoctx, grctx, pushbuf; + uint32_t fifoctx = NV40_RAMFC(channel), grctx, pushbuf; int i; - fifoctx = dev_priv->ramfc_offset + channel*128; - for (i=0;i<128;i+=4) + for (i = 0; i < NV40_RAMFC__SIZE; i+=4) NV_WI32(fifoctx + i, 0); grctx = nouveau_chip_instance_get(dev, chan->ramin_grctx); @@ -70,11 +71,10 @@ void nv40_fifo_destroy_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - uint32_t fifoctx; + uint32_t fifoctx = NV40_RAMFC(channel); int i; - fifoctx = dev_priv->ramfc_offset + channel*128; - for (i=0;i<128;i+=4) + for (i = 0; i < NV40_RAMFC__SIZE; i+=4) NV_WI32(fifoctx + i, 0); } @@ -82,11 +82,9 @@ int nv40_fifo_load_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - uint32_t fifoctx; + uint32_t fifoctx = NV40_RAMFC(channel); uint32_t tmp, tmp2; - fifoctx = dev_priv->ramfc_offset + channel*128; - NV_WRITE(NV04_PFIFO_CACHE1_DMA_GET , RAMFC_RD(DMA_GET)); NV_WRITE(NV04_PFIFO_CACHE1_DMA_PUT , RAMFC_RD(DMA_PUT)); NV_WRITE(NV10_PFIFO_CACHE1_REF_CNT , RAMFC_RD(REF_CNT)); @@ -143,11 +141,9 @@ int nv40_fifo_save_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - uint32_t fifoctx; + uint32_t fifoctx = NV40_RAMFC(channel); uint32_t tmp; - fifoctx = dev_priv->ramfc_offset + channel*128; - RAMFC_WR(DMA_PUT , NV_READ(NV04_PFIFO_CACHE1_DMA_PUT)); RAMFC_WR(DMA_GET , NV_READ(NV04_PFIFO_CACHE1_DMA_GET)); RAMFC_WR(REF_CNT , NV_READ(NV10_PFIFO_CACHE1_REF_CNT)); -- cgit v1.2.3 From 00f1a66f22d52c212bb9334a0103a4785af69bc1 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 29 Jun 2007 12:50:12 +0200 Subject: Fence object reference / dereference cleanup. Buffer object dereference cleanup. Add a struct drm_device member to fence objects: This can simplify code, particularly in drivers. --- linux-core/drm_bo.c | 109 +++++++++++++++++++----------------------- linux-core/drm_bo_move.c | 6 +-- linux-core/drm_fence.c | 122 +++++++++++++++++++++++++++-------------------- linux-core/drm_objects.h | 21 ++++---- linux-core/drm_vm.c | 3 +- 5 files changed, 134 insertions(+), 127 deletions(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index f1ca0b44..ab257825 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -269,31 +269,25 @@ static int drm_bo_handle_move_mem(drm_buffer_object_t * bo, int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, int no_wait) { - - drm_fence_object_t *fence = bo->fence; int ret; DRM_ASSERT_LOCKED(&bo->mutex); - if (fence) { - drm_device_t *dev = bo->dev; - if (drm_fence_object_signaled(dev, fence, bo->fence_type, 0)) { - drm_fence_usage_deref_unlocked(dev, fence); - bo->fence = NULL; + if (bo->fence) { + if (drm_fence_object_signaled(bo->fence, bo->fence_type, 0)) { + drm_fence_usage_deref_unlocked(&bo->fence); return 0; } if (no_wait) { return -EBUSY; } ret = - drm_fence_object_wait(dev, fence, lazy, ignore_signals, + drm_fence_object_wait(bo->fence, lazy, ignore_signals, bo->fence_type); if (ret) return ret; - drm_fence_usage_deref_unlocked(dev, fence); - bo->fence = NULL; - + drm_fence_usage_deref_unlocked(&bo->fence); } return 0; } @@ -321,10 +315,8 @@ static int drm_bo_expire_fence(drm_buffer_object_t * bo, int allow_errors) "Evicting buffer.\n"); } } - if (bo->fence) { - drm_fence_usage_deref_unlocked(dev, bo->fence); - bo->fence = NULL; - } + if (bo->fence) + drm_fence_usage_deref_unlocked(&bo->fence); } return 0; } @@ -348,11 +340,9 @@ static void drm_bo_cleanup_refs(drm_buffer_object_t * bo, int remove_all) DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); - if (bo->fence && drm_fence_object_signaled(dev, bo->fence, - bo->fence_type, 0)) { - drm_fence_usage_deref_unlocked(dev, bo->fence); - bo->fence = NULL; - } + if (bo->fence && drm_fence_object_signaled(bo->fence, + bo->fence_type, 0)) + drm_fence_usage_deref_unlocked(&bo->fence); if (bo->fence && remove_all) (void)drm_bo_expire_fence(bo, 0); @@ -383,7 +373,7 @@ static void drm_bo_cleanup_refs(drm_buffer_object_t * bo, int remove_all) } if (list_empty(&bo->ddestroy)) { - drm_fence_object_flush(dev, bo->fence, bo->fence_type); + drm_fence_object_flush(bo->fence, bo->fence_type); list_add_tail(&bo->ddestroy, &bm->ddestroy); schedule_delayed_work(&bm->wq, ((DRM_HZ / 100) < 1) ? 1 : DRM_HZ / 100); @@ -503,12 +493,15 @@ static void drm_bo_delayed_workqueue(struct work_struct *work) mutex_unlock(&dev->struct_mutex); } -void drm_bo_usage_deref_locked(drm_buffer_object_t * bo) +void drm_bo_usage_deref_locked(drm_buffer_object_t ** bo) { - DRM_ASSERT_LOCKED(&bo->dev->struct_mutex); + struct drm_buffer_object *tmp_bo = *bo; + bo = NULL; - if (atomic_dec_and_test(&bo->usage)) { - drm_bo_destroy_locked(bo); + DRM_ASSERT_LOCKED(&tmp_bo->dev->struct_mutex); + + if (atomic_dec_and_test(&tmp_bo->usage)) { + drm_bo_destroy_locked(tmp_bo); } } @@ -520,17 +513,19 @@ static void drm_bo_base_deref_locked(drm_file_t * priv, drm_user_object_t * uo) DRM_ASSERT_LOCKED(&bo->dev->struct_mutex); drm_bo_takedown_vm_locked(bo); - drm_bo_usage_deref_locked(bo); + drm_bo_usage_deref_locked(&bo); } -static void drm_bo_usage_deref_unlocked(drm_buffer_object_t * bo) +static void drm_bo_usage_deref_unlocked(drm_buffer_object_t ** bo) { - drm_device_t *dev = bo->dev; + struct drm_buffer_object *tmp_bo = *bo; + drm_device_t *dev = tmp_bo->dev; - if (atomic_dec_and_test(&bo->usage)) { + *bo = NULL; + if (atomic_dec_and_test(&tmp_bo->usage)) { mutex_lock(&dev->struct_mutex); - if (atomic_read(&bo->usage) == 0) - drm_bo_destroy_locked(bo); + if (atomic_read(&tmp_bo->usage) == 0) + drm_bo_destroy_locked(tmp_bo); mutex_unlock(&dev->struct_mutex); } } @@ -616,16 +611,15 @@ int drm_fence_buffer_objects(drm_file_t * priv, if (entry->priv_flags & _DRM_BO_FLAG_UNFENCED) { count++; if (entry->fence) - drm_fence_usage_deref_locked(dev, entry->fence); - entry->fence = fence; - atomic_inc(&fence->usage); + drm_fence_usage_deref_locked(&entry->fence); + entry->fence = drm_fence_reference_locked(fence); DRM_FLAG_MASKED(entry->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); DRM_WAKEUP(&entry->event_queue); drm_bo_add_to_lru(entry); } mutex_unlock(&entry->mutex); - drm_bo_usage_deref_locked(entry); + drm_bo_usage_deref_locked(&entry); l = f_list.next; } DRM_DEBUG("Fenced %d buffers\n", count); @@ -742,7 +736,7 @@ static int drm_bo_mem_force_space(drm_device_t * dev, ret = drm_bo_evict(entry, mem_type, no_wait); mutex_unlock(&entry->mutex); - drm_bo_usage_deref_unlocked(entry); + drm_bo_usage_deref_unlocked(&entry); if (ret) return ret; mutex_lock(&dev->struct_mutex); @@ -962,10 +956,8 @@ static int drm_bo_quick_busy(drm_buffer_object_t * bo) BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); if (fence) { - drm_device_t *dev = bo->dev; - if (drm_fence_object_signaled(dev, fence, bo->fence_type, 0)) { - drm_fence_usage_deref_unlocked(dev, fence); - bo->fence = NULL; + if (drm_fence_object_signaled(fence, bo->fence_type, 0)) { + drm_fence_usage_deref_unlocked(&bo->fence); return 0; } return 1; @@ -984,16 +976,13 @@ static int drm_bo_busy(drm_buffer_object_t * bo) BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); if (fence) { - drm_device_t *dev = bo->dev; - if (drm_fence_object_signaled(dev, fence, bo->fence_type, 0)) { - drm_fence_usage_deref_unlocked(dev, fence); - bo->fence = NULL; + if (drm_fence_object_signaled(fence, bo->fence_type, 0)) { + drm_fence_usage_deref_unlocked(&bo->fence); return 0; } - drm_fence_object_flush(dev, fence, DRM_FENCE_TYPE_EXE); - if (drm_fence_object_signaled(dev, fence, bo->fence_type, 0)) { - drm_fence_usage_deref_unlocked(dev, fence); - bo->fence = NULL; + drm_fence_object_flush(fence, DRM_FENCE_TYPE_EXE); + if (drm_fence_object_signaled(fence, bo->fence_type, 0)) { + drm_fence_usage_deref_unlocked(&bo->fence); return 0; } return 1; @@ -1190,7 +1179,7 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, drm_bo_fill_rep_arg(bo, rep); out: mutex_unlock(&bo->mutex); - drm_bo_usage_deref_unlocked(bo); + drm_bo_usage_deref_unlocked(&bo); return ret; } @@ -1216,7 +1205,7 @@ static int drm_buffer_object_unmap(drm_file_t * priv, uint32_t handle) } drm_remove_ref_object(priv, ro); - drm_bo_usage_deref_locked(bo); + drm_bo_usage_deref_locked(&bo); out: mutex_unlock(&dev->struct_mutex); return ret; @@ -1512,7 +1501,7 @@ static int drm_bo_handle_validate(drm_file_t * priv, uint32_t handle, mutex_unlock(&bo->mutex); - drm_bo_usage_deref_unlocked(bo); + drm_bo_usage_deref_unlocked(&bo); return ret; } @@ -1534,7 +1523,7 @@ static int drm_bo_handle_info(drm_file_t * priv, uint32_t handle, (void)drm_bo_busy(bo); drm_bo_fill_rep_arg(bo, rep); mutex_unlock(&bo->mutex); - drm_bo_usage_deref_unlocked(bo); + drm_bo_usage_deref_unlocked(&bo); return 0; } @@ -1566,7 +1555,7 @@ static int drm_bo_handle_wait(drm_file_t * priv, uint32_t handle, out: mutex_unlock(&bo->mutex); - drm_bo_usage_deref_unlocked(bo); + drm_bo_usage_deref_unlocked(&bo); return ret; } @@ -1651,7 +1640,7 @@ int drm_buffer_object_create(drm_device_t *dev, out_err: mutex_unlock(&bo->mutex); - drm_bo_usage_deref_unlocked(bo); + drm_bo_usage_deref_unlocked(&bo); return ret; } @@ -1728,7 +1717,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) mask & DRM_BO_FLAG_SHAREABLE); if (rep.ret) - drm_bo_usage_deref_unlocked(entry); + drm_bo_usage_deref_unlocked(&entry); if (rep.ret) break; @@ -1957,7 +1946,7 @@ restart: allow_errors); mutex_lock(&dev->struct_mutex); - drm_bo_usage_deref_locked(entry); + drm_bo_usage_deref_locked(&entry); if (ret) return ret; @@ -1967,10 +1956,8 @@ restart: do_restart = ((next->prev != list) && (next->prev != prev)); - if (nentry != NULL && do_restart) { - drm_bo_usage_deref_locked(nentry); - nentry = NULL; - } + if (nentry != NULL && do_restart) + drm_bo_usage_deref_locked(&nentry); if (do_restart) goto restart; @@ -2365,7 +2352,7 @@ static void drm_bo_takedown_vm_locked(drm_buffer_object_t * bo) drm_ctl_free(map, sizeof(*map), DRM_MEM_BUFOBJ); list->map = NULL; list->user_token = 0ULL; - drm_bo_usage_deref_locked(bo); + drm_bo_usage_deref_locked(&bo); } static int drm_bo_setup_vm_locked(drm_buffer_object_t * bo) diff --git a/linux-core/drm_bo_move.c b/linux-core/drm_bo_move.c index 4f752065..8ef2a8ff 100644 --- a/linux-core/drm_bo_move.c +++ b/linux-core/drm_bo_move.c @@ -306,7 +306,7 @@ int drm_buffer_object_transfer(drm_buffer_object_t * bo, INIT_LIST_HEAD(&fbo->p_mm_list); #endif - atomic_inc(&bo->fence->usage); + drm_fence_reference_unlocked(&fbo->fence, bo->fence); fbo->pinned_node = NULL; fbo->mem.mm_node->private = (void *)fbo; atomic_set(&fbo->usage, 1); @@ -339,7 +339,7 @@ int drm_bo_move_accel_cleanup(drm_buffer_object_t * bo, drm_buffer_object_t *old_obj; if (bo->fence) - drm_fence_usage_deref_unlocked(dev, bo->fence); + drm_fence_usage_deref_unlocked(&bo->fence); ret = drm_fence_object_create(dev, fence_class, fence_type, fence_flags | DRM_FENCE_FLAG_EMIT, &bo->fence); @@ -396,7 +396,7 @@ int drm_bo_move_accel_cleanup(drm_buffer_object_t * bo, DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); drm_bo_add_to_lru(old_obj); - drm_bo_usage_deref_locked(old_obj); + drm_bo_usage_deref_locked(&old_obj); mutex_unlock(&dev->struct_mutex); } diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index b5fc2235..ace70d51 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -124,56 +124,76 @@ static void drm_fence_unring(drm_device_t * dev, struct list_head *ring) write_unlock_irqrestore(&fm->lock, flags); } -void drm_fence_usage_deref_locked(drm_device_t * dev, - drm_fence_object_t * fence) +void drm_fence_usage_deref_locked(drm_fence_object_t ** fence) { + struct drm_fence_object *tmp_fence = *fence; + struct drm_device *dev = tmp_fence->dev; drm_fence_manager_t *fm = &dev->fm; DRM_ASSERT_LOCKED(&dev->struct_mutex); - - if (atomic_dec_and_test(&fence->usage)) { - drm_fence_unring(dev, &fence->ring); + *fence = NULL; + if (atomic_dec_and_test(&tmp_fence->usage)) { + drm_fence_unring(dev, &tmp_fence->ring); DRM_DEBUG("Destroyed a fence object 0x%08lx\n", - fence->base.hash.key); + tmp_fence->base.hash.key); atomic_dec(&fm->count); - BUG_ON(!list_empty(&fence->base.list)); - drm_ctl_free(fence, sizeof(*fence), DRM_MEM_FENCE); + BUG_ON(!list_empty(&tmp_fence->base.list)); + drm_ctl_free(tmp_fence, sizeof(*tmp_fence), DRM_MEM_FENCE); } } -void drm_fence_usage_deref_unlocked(drm_device_t * dev, - drm_fence_object_t * fence) +void drm_fence_usage_deref_unlocked(drm_fence_object_t ** fence) { + struct drm_fence_object *tmp_fence = *fence; + struct drm_device *dev = tmp_fence->dev; drm_fence_manager_t *fm = &dev->fm; - if (atomic_dec_and_test(&fence->usage)) { + *fence = NULL; + if (atomic_dec_and_test(&tmp_fence->usage)) { mutex_lock(&dev->struct_mutex); - if (atomic_read(&fence->usage) == 0) { - drm_fence_unring(dev, &fence->ring); + if (atomic_read(&tmp_fence->usage) == 0) { + drm_fence_unring(dev, &tmp_fence->ring); atomic_dec(&fm->count); - BUG_ON(!list_empty(&fence->base.list)); - drm_ctl_free(fence, sizeof(*fence), DRM_MEM_FENCE); + BUG_ON(!list_empty(&tmp_fence->base.list)); + drm_ctl_free(tmp_fence, sizeof(*tmp_fence), DRM_MEM_FENCE); } mutex_unlock(&dev->struct_mutex); } } -static void drm_fence_object_destroy(drm_file_t * priv, - drm_user_object_t * base) +struct drm_fence_object +*drm_fence_reference_locked(struct drm_fence_object *src) +{ + DRM_ASSERT_LOCKED(&src->dev->struct_mutex); + + atomic_inc(&src->usage); + return src; +} + +void drm_fence_reference_unlocked(struct drm_fence_object **dst, + struct drm_fence_object *src) +{ + mutex_lock(&src->dev->struct_mutex); + *dst = src; + atomic_inc(&src->usage); + mutex_unlock(&src->dev->struct_mutex); +} + + +static void drm_fence_object_destroy(drm_file_t *priv, drm_user_object_t * base) { - drm_device_t *dev = priv->head->dev; drm_fence_object_t *fence = drm_user_object_entry(base, drm_fence_object_t, base); - drm_fence_usage_deref_locked(dev, fence); + drm_fence_usage_deref_locked(&fence); } -int drm_fence_object_signaled(drm_device_t * dev, - drm_fence_object_t * fence, - uint32_t mask, int poke_flush) +int drm_fence_object_signaled(drm_fence_object_t * fence, + uint32_t mask, int poke_flush) { unsigned long flags; int signaled; + struct drm_device *dev = fence->dev; drm_fence_manager_t *fm = &dev->fm; drm_fence_driver_t *driver = dev->driver->fence_driver; @@ -204,10 +224,10 @@ static void drm_fence_flush_exe(drm_fence_class_manager_t * fc, } } -int drm_fence_object_flush(drm_device_t * dev, - drm_fence_object_t * fence, +int drm_fence_object_flush(drm_fence_object_t * fence, uint32_t type) { + struct drm_device *dev = fence->dev; drm_fence_manager_t *fm = &dev->fm; drm_fence_class_manager_t *fc = &fm->class[fence->class]; drm_fence_driver_t *driver = dev->driver->fence_driver; @@ -270,24 +290,23 @@ void drm_fence_flush_old(drm_device_t * dev, uint32_t class, uint32_t sequence) mutex_unlock(&dev->struct_mutex); return; } - fence = list_entry(fc->ring.next, drm_fence_object_t, ring); - atomic_inc(&fence->usage); + fence = drm_fence_reference_locked(list_entry(fc->ring.next, drm_fence_object_t, ring)); mutex_unlock(&dev->struct_mutex); diff = (old_sequence - fence->sequence) & driver->sequence_mask; read_unlock_irqrestore(&fm->lock, flags); if (diff < driver->wrap_diff) { - drm_fence_object_flush(dev, fence, fence->type); + drm_fence_object_flush(fence, fence->type); } - drm_fence_usage_deref_unlocked(dev, fence); + drm_fence_usage_deref_unlocked(&fence); } EXPORT_SYMBOL(drm_fence_flush_old); -static int drm_fence_lazy_wait(drm_device_t *dev, - drm_fence_object_t *fence, +static int drm_fence_lazy_wait(drm_fence_object_t *fence, int ignore_signals, uint32_t mask) { + struct drm_device *dev = fence->dev; drm_fence_manager_t *fm = &dev->fm; drm_fence_class_manager_t *fc = &fm->class[fence->class]; int signaled; @@ -296,13 +315,13 @@ static int drm_fence_lazy_wait(drm_device_t *dev, do { DRM_WAIT_ON(ret, fc->fence_queue, 3 * DRM_HZ, - (signaled = drm_fence_object_signaled(dev, fence, mask, 1))); + (signaled = drm_fence_object_signaled(fence, mask, 1))); if (signaled) return 0; if (time_after_eq(jiffies, _end)) break; } while (ret == -EINTR && ignore_signals); - if (drm_fence_object_signaled(dev, fence, mask, 0)) + if (drm_fence_object_signaled(fence, mask, 0)) return 0; if (time_after_eq(jiffies, _end)) ret = -EBUSY; @@ -317,10 +336,10 @@ static int drm_fence_lazy_wait(drm_device_t *dev, return 0; } -int drm_fence_object_wait(drm_device_t * dev, - drm_fence_object_t * fence, +int drm_fence_object_wait(drm_fence_object_t * fence, int lazy, int ignore_signals, uint32_t mask) { + struct drm_device *dev = fence->dev; drm_fence_driver_t *driver = dev->driver->fence_driver; int ret = 0; unsigned long _end; @@ -332,16 +351,16 @@ int drm_fence_object_wait(drm_device_t * dev, return -EINVAL; } - if (drm_fence_object_signaled(dev, fence, mask, 0)) + if (drm_fence_object_signaled(fence, mask, 0)) return 0; _end = jiffies + 3 * DRM_HZ; - drm_fence_object_flush(dev, fence, mask); + drm_fence_object_flush(fence, mask); if (lazy && driver->lazy_capable) { - ret = drm_fence_lazy_wait(dev, fence, ignore_signals, mask); + ret = drm_fence_lazy_wait(fence, ignore_signals, mask); if (ret) return ret; @@ -349,7 +368,7 @@ int drm_fence_object_wait(drm_device_t * dev, if (driver->has_irq(dev, fence->class, DRM_FENCE_TYPE_EXE)) { - ret = drm_fence_lazy_wait(dev, fence, ignore_signals, + ret = drm_fence_lazy_wait(fence, ignore_signals, DRM_FENCE_TYPE_EXE); if (ret) return ret; @@ -357,13 +376,13 @@ int drm_fence_object_wait(drm_device_t * dev, if (driver->has_irq(dev, fence->class, mask & ~DRM_FENCE_TYPE_EXE)) { - ret = drm_fence_lazy_wait(dev, fence, ignore_signals, + ret = drm_fence_lazy_wait(fence, ignore_signals, mask); if (ret) return ret; } } - if (drm_fence_object_signaled(dev, fence, mask, 0)) + if (drm_fence_object_signaled(fence, mask, 0)) return 0; /* @@ -375,7 +394,7 @@ int drm_fence_object_wait(drm_device_t * dev, #endif do { schedule(); - signaled = drm_fence_object_signaled(dev, fence, mask, 1); + signaled = drm_fence_object_signaled(fence, mask, 1); } while (!signaled && !time_after_eq(jiffies, _end)); if (!signaled) @@ -384,9 +403,10 @@ int drm_fence_object_wait(drm_device_t * dev, return 0; } -int drm_fence_object_emit(drm_device_t * dev, drm_fence_object_t * fence, +int drm_fence_object_emit(drm_fence_object_t * fence, uint32_t fence_flags, uint32_t class, uint32_t type) { + struct drm_device *dev = fence->dev; drm_fence_manager_t *fm = &dev->fm; drm_fence_driver_t *driver = dev->driver->fence_driver; drm_fence_class_manager_t *fc = &fm->class[fence->class]; @@ -436,9 +456,10 @@ static int drm_fence_object_init(drm_device_t * dev, uint32_t class, fence->submitted_flush = 0; fence->signaled = 0; fence->sequence = 0; + fence->dev = dev; write_unlock_irqrestore(&fm->lock, flags); if (fence_flags & DRM_FENCE_FLAG_EMIT) { - ret = drm_fence_object_emit(dev, fence, fence_flags, + ret = drm_fence_object_emit(fence, fence_flags, fence->class, type); } return ret; @@ -476,7 +497,7 @@ int drm_fence_object_create(drm_device_t * dev, uint32_t class, uint32_t type, return -ENOMEM; ret = drm_fence_object_init(dev, class, type, flags, fence); if (ret) { - drm_fence_usage_deref_unlocked(dev, fence); + drm_fence_usage_deref_unlocked(&fence); return ret; } *c_fence = fence; @@ -533,8 +554,7 @@ drm_fence_object_t *drm_lookup_fence_object(drm_file_t * priv, uint32_t handle) mutex_unlock(&dev->struct_mutex); return NULL; } - fence = drm_user_object_entry(uo, drm_fence_object_t, base); - atomic_inc(&fence->usage); + fence = drm_fence_reference_locked(drm_user_object_entry(uo, drm_fence_object_t, base)); mutex_unlock(&dev->struct_mutex); return fence; } @@ -568,7 +588,7 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS) arg.flags & DRM_FENCE_FLAG_SHAREABLE); if (ret) { - drm_fence_usage_deref_unlocked(dev, fence); + drm_fence_usage_deref_unlocked(&fence); return ret; } arg.handle = fence->base.hash.key; @@ -603,14 +623,14 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS) fence = drm_lookup_fence_object(priv, arg.handle); if (!fence) return -EINVAL; - ret = drm_fence_object_flush(dev, fence, arg.type); + ret = drm_fence_object_flush(fence, arg.type); break; case drm_fence_wait: fence = drm_lookup_fence_object(priv, arg.handle); if (!fence) return -EINVAL; ret = - drm_fence_object_wait(dev, fence, + drm_fence_object_wait(fence, arg.flags & DRM_FENCE_FLAG_WAIT_LAZY, 0, arg.type); break; @@ -619,7 +639,7 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS) fence = drm_lookup_fence_object(priv, arg.handle); if (!fence) return -EINVAL; - ret = drm_fence_object_emit(dev, fence, arg.flags, arg.class, + ret = drm_fence_object_emit(fence, arg.flags, arg.class, arg.type); break; case drm_fence_buffers: @@ -647,7 +667,7 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS) arg.type = fence->type; arg.signaled = fence->signaled; read_unlock_irqrestore(&fm->lock, flags); - drm_fence_usage_deref_unlocked(dev, fence); + drm_fence_usage_deref_unlocked(&fence); DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); return ret; diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index 59c8902d..f82d6628 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -141,6 +141,7 @@ extern int drm_user_object_unref(drm_file_t * priv, uint32_t user_token, typedef struct drm_fence_object { drm_user_object_t base; + struct drm_device *dev; atomic_t usage; /* @@ -196,17 +197,15 @@ extern void drm_fence_manager_init(struct drm_device *dev); extern void drm_fence_manager_takedown(struct drm_device *dev); extern void drm_fence_flush_old(struct drm_device *dev, uint32_t class, uint32_t sequence); -extern int drm_fence_object_flush(struct drm_device *dev, - drm_fence_object_t * fence, uint32_t type); -extern int drm_fence_object_signaled(struct drm_device *dev, - drm_fence_object_t * fence, +extern int drm_fence_object_flush(drm_fence_object_t * fence, uint32_t type); +extern int drm_fence_object_signaled(drm_fence_object_t * fence, uint32_t type, int flush); -extern void drm_fence_usage_deref_locked(struct drm_device *dev, - drm_fence_object_t * fence); -extern void drm_fence_usage_deref_unlocked(struct drm_device *dev, - drm_fence_object_t * fence); -extern int drm_fence_object_wait(struct drm_device *dev, - drm_fence_object_t * fence, +extern void drm_fence_usage_deref_locked(drm_fence_object_t ** fence); +extern void drm_fence_usage_deref_unlocked(drm_fence_object_t ** fence); +extern struct drm_fence_object *drm_fence_reference_locked(struct drm_fence_object *src); +extern void drm_fence_reference_unlocked(struct drm_fence_object **dst, + struct drm_fence_object *src); +extern int drm_fence_object_wait(drm_fence_object_t * fence, int lazy, int ignore_signals, uint32_t mask); extern int drm_fence_object_create(struct drm_device *dev, uint32_t type, uint32_t fence_flags, uint32_t class, @@ -441,7 +440,7 @@ extern int drm_bo_pci_offset(struct drm_device *dev, unsigned long *bus_size); extern int drm_mem_reg_is_pci(struct drm_device *dev, drm_bo_mem_reg_t * mem); -extern void drm_bo_usage_deref_locked(drm_buffer_object_t * bo); +extern void drm_bo_usage_deref_locked(drm_buffer_object_t ** bo); extern int drm_fence_buffer_objects(drm_file_t * priv, struct list_head *list, uint32_t fence_flags, diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index f2c43508..72d63c10 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -840,7 +840,8 @@ static void drm_bo_vm_close(struct vm_area_struct *vma) #ifdef DRM_ODD_MM_COMPAT drm_bo_delete_vma(bo, vma); #endif - drm_bo_usage_deref_locked(bo); + drm_bo_usage_deref_locked((struct drm_buffer_object **) + &vma->vm_private_data); mutex_unlock(&dev->struct_mutex); } return; -- cgit v1.2.3 From a27af4c4a665864df09123f177ca7269e48f6171 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 29 Jun 2007 15:22:28 +0200 Subject: Avoid hitting BUG() for kernel-only fence objects. --- linux-core/drm_fence.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index ace70d51..5215feb6 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -450,6 +450,12 @@ static int drm_fence_object_init(drm_device_t * dev, uint32_t class, write_lock_irqsave(&fm->lock, flags); INIT_LIST_HEAD(&fence->ring); + + /* + * Avoid hitting BUG() for kernel-only fence objects. + */ + + INIT_LIST_HEAD(&fence->base.list); fence->class = class; fence->type = type; fence->flush_mask = 0; -- cgit v1.2.3 From b323ab52aa9ccbfb06dd723ece361a5242d067b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Thu, 28 Jun 2007 14:45:26 -0400 Subject: Drop drm_drawable_list and add drm_drawable_info directly to the idr. --- linux-core/drmP.h | 4 ---- linux-core/drm_drawable.c | 41 +++++++++++++++++++++-------------------- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index dd3a69df..7bcd095a 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -598,10 +598,6 @@ typedef struct ati_pcigart_info { int table_size; } drm_ati_pcigart_info; -struct drm_drawable_list { - drm_drawable_info_t info; -}; - #include "drm_objects.h" /** diff --git a/linux-core/drm_drawable.c b/linux-core/drm_drawable.c index eb44a189..74f0bb5d 100644 --- a/linux-core/drm_drawable.c +++ b/linux-core/drm_drawable.c @@ -44,19 +44,19 @@ int drm_adddraw(DRM_IOCTL_ARGS) { DRM_DEVICE; unsigned long irqflags; - struct drm_drawable_list *draw_info; + struct drm_drawable_info *draw_info; drm_draw_t draw; int new_id = 0; int ret; - draw_info = drm_calloc(1, sizeof(struct drm_drawable_list), DRM_MEM_BUFS); + draw_info = drm_calloc(1, sizeof(*draw_info), DRM_MEM_BUFS); if (!draw_info) return -ENOMEM; again: if (idr_pre_get(&dev->drw_idr, GFP_KERNEL) == 0) { DRM_ERROR("Out of memory expanding drawable idr\n"); - drm_free(draw_info, sizeof(struct drm_drawable_list), DRM_MEM_BUFS); + drm_free(draw_info, sizeof(struct drm_drawable_info), DRM_MEM_BUFS); return -ENOMEM; } @@ -86,7 +86,7 @@ int drm_rmdraw(DRM_IOCTL_ARGS) DRM_DEVICE; drm_draw_t draw; unsigned long irqflags; - struct drm_drawable_list *draw_info; + struct drm_drawable_info *draw_info; DRM_COPY_FROM_USER_IOCTL(draw, (drm_draw_t __user *) data, sizeof(draw)); @@ -100,33 +100,31 @@ int drm_rmdraw(DRM_IOCTL_ARGS) spin_lock_irqsave(&dev->drw_lock, irqflags); idr_remove(&dev->drw_idr, draw.handle); - drm_free(draw_info, sizeof(struct drm_drawable_list), DRM_MEM_BUFS); + drm_free(draw_info, sizeof(struct drm_drawable_info), DRM_MEM_BUFS); spin_unlock_irqrestore(&dev->drw_lock, irqflags); DRM_DEBUG("%d\n", draw.handle); return 0; } -int drm_update_drawable_info(DRM_IOCTL_ARGS) { +int drm_update_drawable_info(DRM_IOCTL_ARGS) +{ DRM_DEVICE; drm_update_draw_t update; unsigned long irqflags; - drm_drawable_info_t *info; drm_clip_rect_t *rects; - struct drm_drawable_list *draw_info; + struct drm_drawable_info *info; int err; DRM_COPY_FROM_USER_IOCTL(update, (drm_update_draw_t __user *) data, sizeof(update)); - draw_info = idr_find(&dev->drw_idr, update.handle); - if (!draw_info) { + info = idr_find(&dev->drw_idr, update.handle); + if (!info) { DRM_ERROR("No such drawable %d\n", update.handle); return DRM_ERR(EINVAL); } - info = &draw_info->info; - switch (update.type) { case DRM_DRAWABLE_CLIPRECTS: if (update.num != info->num_rects) { @@ -184,24 +182,27 @@ error: /** * Caller must hold the drawable spinlock! */ -drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) { - struct drm_drawable_list *draw_info; - draw_info = idr_find(&dev->drw_idr, id); - if (!draw_info) { +drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) +{ + struct drm_drawable_info *info; + + info = idr_find(&dev->drw_idr, id); + if (!info) { DRM_DEBUG("No such drawable %d\n", id); return NULL; } - return &draw_info->info; + return info; } EXPORT_SYMBOL(drm_get_drawable_info); static int drm_drawable_free(int idr, void *p, void *data) { - struct drm_drawable_list *drw_entry = p; - drm_free(drw_entry->info.rects, drw_entry->info.num_rects * + struct drm_drawable_info *info = p; + + drm_free(info->rects, info->num_rects * sizeof(drm_clip_rect_t), DRM_MEM_BUFS); - drm_free(drw_entry, sizeof(struct drm_drawable_list), DRM_MEM_BUFS); + drm_free(info, sizeof(struct drm_drawable_info), DRM_MEM_BUFS); return 0; } -- cgit v1.2.3 From c9d752ff4fb2b6eee2fef636193fc9ca29abba37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Mon, 2 Jul 2007 17:52:07 -0400 Subject: Fix must-check warnings and implement a few error paths. --- linux-core/drm_drv.c | 2 +- linux-core/drm_stub.c | 26 +++++++++++++++++--------- linux-core/drm_sysfs.c | 31 +++++++++++++++++++++++++------ 3 files changed, 43 insertions(+), 16 deletions(-) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index d5eb9713..6bbe7fca 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -311,7 +311,7 @@ int drm_init(struct drm_driver *driver, } if (!drm_fb_loaded) - pci_register_driver(&driver->pci_driver); + return pci_register_driver(&driver->pci_driver); else { for (i = 0; pciidlist[i].vendor != 0; i++) { pid = &pciidlist[i]; diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index f57ed9cc..b96408ab 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -232,18 +232,22 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, if (!drm_fb_loaded) { pci_set_drvdata(pdev, dev); - pci_request_regions(pdev, driver->pci_driver.name); + ret = pci_request_regions(pdev, driver->pci_driver.name); + if (ret) + goto err_g1; } - pci_enable_device(pdev); + ret = pci_enable_device(pdev); + if (ret) + goto err_g2; pci_set_master(pdev); if ((ret = drm_fill_in_dev(dev, pdev, ent, driver))) { printk(KERN_ERR "DRM: fill_in_dev failed\n"); - goto err_g1; + goto err_g3; } if ((ret = drm_get_head(dev, &dev->primary))) - goto err_g1; + goto err_g3; DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", driver->name, driver->major, driver->minor, driver->patchlevel, @@ -251,12 +255,16 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, return 0; -err_g1: - if (!drm_fb_loaded) { - pci_set_drvdata(pdev, NULL); - pci_release_regions(pdev); + err_g3: + if (!drm_fb_loaded) pci_disable_device(pdev); - } + err_g2: + if (!drm_fb_loaded) + pci_release_regions(pdev); + err_g1: + if (!drm_fb_loaded) + pci_set_drvdata(pdev, NULL); + drm_free(dev, sizeof(*dev), DRM_MEM_STUB); printk(KERN_ERR "DRM: drm_get_dev failed.\n"); return ret; diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index ace0778b..9b2f5dce 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -93,11 +93,15 @@ struct drm_sysfs_class *drm_sysfs_create(struct module *owner, char *name) retval = class_register(&cs->class); if (retval) goto error; - class_create_file(&cs->class, &class_attr_version); + retval = class_create_file(&cs->class, &class_attr_version); + if (retval) + goto error_with_class; return cs; - error: + error_with_class: + class_unregister(&cs->class); + error: kfree(cs); return ERR_PTR(retval); } @@ -170,16 +174,31 @@ struct class_device *drm_sysfs_device_add(struct drm_sysfs_class *cs, if (retval) goto error; - class_device_create_file(&s_dev->class_dev, &cs->attr); + retval = class_device_create_file(&s_dev->class_dev, &cs->attr); + if (retval) + goto error_with_device; + class_set_devdata(&s_dev->class_dev, head); - for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) - class_device_create_file(&s_dev->class_dev, &class_device_attrs[i]); + for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) { + retval = class_device_create_file(&s_dev->class_dev, + &class_device_attrs[i]); + if (retval) + goto error_with_files; + } return &s_dev->class_dev; -error: + error_with_files: + while (i > 0) + class_device_remove_file(&s_dev->class_dev, + &class_device_attrs[--i]); + class_device_remove_file(&s_dev->class_dev, &cs->attr); + error_with_device: + class_device_unregister(&s_dev->class_dev); + error: kfree(s_dev); + return ERR_PTR(retval); } -- cgit v1.2.3 From 8d96ba9805316b29e948d7594344feebb17042f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Tue, 3 Jul 2007 11:41:44 +0200 Subject: Restore pre-idr semantics for drawable information. There's a difference between a drawable ID not having valid drawable information and not being allocated at all. Not making the distinction would break i915 DRM swap scheduling with older X servers that don't push drawable cliprect information to the DRM. --- linux-core/drm_drawable.c | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/linux-core/drm_drawable.c b/linux-core/drm_drawable.c index 74f0bb5d..7657e954 100644 --- a/linux-core/drm_drawable.c +++ b/linux-core/drm_drawable.c @@ -37,6 +37,8 @@ #include "drmP.h" +#define NO_DRW_INFO (void*)1 + /** * Allocate drawable ID and memory to store information about it. */ @@ -44,24 +46,18 @@ int drm_adddraw(DRM_IOCTL_ARGS) { DRM_DEVICE; unsigned long irqflags; - struct drm_drawable_info *draw_info; drm_draw_t draw; int new_id = 0; int ret; - draw_info = drm_calloc(1, sizeof(*draw_info), DRM_MEM_BUFS); - if (!draw_info) - return -ENOMEM; - again: if (idr_pre_get(&dev->drw_idr, GFP_KERNEL) == 0) { DRM_ERROR("Out of memory expanding drawable idr\n"); - drm_free(draw_info, sizeof(struct drm_drawable_info), DRM_MEM_BUFS); return -ENOMEM; } spin_lock_irqsave(&dev->drw_lock, irqflags); - ret = idr_get_new_above(&dev->drw_idr, draw_info, 1, &new_id); + ret = idr_get_new_above(&dev->drw_idr, NO_DRW_INFO, 1, &new_id); if (ret == -EAGAIN) { spin_unlock_irqrestore(&dev->drw_lock, irqflags); goto again; @@ -86,21 +82,16 @@ int drm_rmdraw(DRM_IOCTL_ARGS) DRM_DEVICE; drm_draw_t draw; unsigned long irqflags; - struct drm_drawable_info *draw_info; DRM_COPY_FROM_USER_IOCTL(draw, (drm_draw_t __user *) data, sizeof(draw)); - draw_info = idr_find(&dev->drw_idr, draw.handle); - if (!draw_info) { - DRM_DEBUG("No such drawable %d\n", draw.handle); - return -EINVAL; - } - spin_lock_irqsave(&dev->drw_lock, irqflags); + drm_free(drm_get_drawable_info(dev, draw.handle), + sizeof(struct drm_drawable_info), DRM_MEM_BUFS); + idr_remove(&dev->drw_idr, draw.handle); - drm_free(draw_info, sizeof(struct drm_drawable_info), DRM_MEM_BUFS); spin_unlock_irqrestore(&dev->drw_lock, irqflags); DRM_DEBUG("%d\n", draw.handle); @@ -125,6 +116,13 @@ int drm_update_drawable_info(DRM_IOCTL_ARGS) return DRM_ERR(EINVAL); } + if (info == NO_DRW_INFO) { + info = drm_calloc(1, sizeof(*info), DRM_MEM_BUFS); + if (!info) + return -ENOMEM; + idr_replace(&dev->drw_idr, info, update.handle); + } + switch (update.type) { case DRM_DRAWABLE_CLIPRECTS: if (update.num != info->num_rects) { @@ -187,11 +185,17 @@ drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) struct drm_drawable_info *info; info = idr_find(&dev->drw_idr, id); + if (!info) { DRM_DEBUG("No such drawable %d\n", id); return NULL; } + if (info == NO_DRW_INFO) { + DRM_DEBUG("No information for drawable %d\n", id); + return NULL; + } + return info; } EXPORT_SYMBOL(drm_get_drawable_info); @@ -200,9 +204,12 @@ static int drm_drawable_free(int idr, void *p, void *data) { struct drm_drawable_info *info = p; - drm_free(info->rects, info->num_rects * - sizeof(drm_clip_rect_t), DRM_MEM_BUFS); - drm_free(info, sizeof(struct drm_drawable_info), DRM_MEM_BUFS); + if (info != NO_DRW_INFO) { + drm_free(info->rects, info->num_rects * + sizeof(drm_clip_rect_t), DRM_MEM_BUFS); + drm_free(info, sizeof(*info), DRM_MEM_BUFS); + } + return 0; } -- cgit v1.2.3 From ea832a8e555c9e1f90830b55cbd970d0eca0e2cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Tue, 3 Jul 2007 12:15:15 +0200 Subject: Simplification for previous commit. Dave Airlie pointed out on IRC that idr_replace lets us know if the ID hasn't been allocated, so we don't need a special pointer value for allocated IDs that don't have valid information yet. --- linux-core/drm_drawable.c | 34 +++++++++------------------------- 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/linux-core/drm_drawable.c b/linux-core/drm_drawable.c index 7657e954..57b62ca4 100644 --- a/linux-core/drm_drawable.c +++ b/linux-core/drm_drawable.c @@ -37,8 +37,6 @@ #include "drmP.h" -#define NO_DRW_INFO (void*)1 - /** * Allocate drawable ID and memory to store information about it. */ @@ -57,7 +55,7 @@ again: } spin_lock_irqsave(&dev->drw_lock, irqflags); - ret = idr_get_new_above(&dev->drw_idr, NO_DRW_INFO, 1, &new_id); + ret = idr_get_new_above(&dev->drw_idr, NULL, 1, &new_id); if (ret == -EAGAIN) { spin_unlock_irqrestore(&dev->drw_lock, irqflags); goto again; @@ -112,15 +110,15 @@ int drm_update_drawable_info(DRM_IOCTL_ARGS) info = idr_find(&dev->drw_idr, update.handle); if (!info) { - DRM_ERROR("No such drawable %d\n", update.handle); - return DRM_ERR(EINVAL); - } - - if (info == NO_DRW_INFO) { info = drm_calloc(1, sizeof(*info), DRM_MEM_BUFS); if (!info) return -ENOMEM; - idr_replace(&dev->drw_idr, info, update.handle); + if (idr_replace(&dev->drw_idr, info, update.handle) == + (void*)-ENOENT) { + DRM_ERROR("No such drawable %d\n", update.handle); + drm_free(info, sizeof(*info), DRM_MEM_BUFS); + return -EINVAL; + } } switch (update.type) { @@ -182,21 +180,7 @@ error: */ drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) { - struct drm_drawable_info *info; - - info = idr_find(&dev->drw_idr, id); - - if (!info) { - DRM_DEBUG("No such drawable %d\n", id); - return NULL; - } - - if (info == NO_DRW_INFO) { - DRM_DEBUG("No information for drawable %d\n", id); - return NULL; - } - - return info; + return idr_find(&dev->drw_idr, id); } EXPORT_SYMBOL(drm_get_drawable_info); @@ -204,7 +188,7 @@ static int drm_drawable_free(int idr, void *p, void *data) { struct drm_drawable_info *info = p; - if (info != NO_DRW_INFO) { + if (info) { drm_free(info->rects, info->num_rects * sizeof(drm_clip_rect_t), DRM_MEM_BUFS); drm_free(info, sizeof(*info), DRM_MEM_BUFS); -- cgit v1.2.3 From 91990946fa3f7e8e725af18d1f3a63e0c7892308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Tue, 3 Jul 2007 12:33:51 +0200 Subject: One more spinlock initializer cleanup. --- shared-core/i915_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index dc00f983..2f6a6b95 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -719,7 +719,7 @@ void i915_driver_irq_postinstall(drm_device_t * dev) INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); dev_priv->swaps_pending = 0; - dev_priv->user_irq_lock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&dev_priv->user_irq_lock); dev_priv->user_irq_refcount = 0; i915_enable_interrupt(dev); -- cgit v1.2.3 From 1814a829eb65ee53a14fa9b53fc6f3a4196dcaa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 3 Jul 2007 10:31:46 -0400 Subject: Don't take dev->struct_mutex twice in drm_setsareactx. --- linux-core/drm_context.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/linux-core/drm_context.c b/linux-core/drm_context.c index 101a298c..ff08e809 100644 --- a/linux-core/drm_context.c +++ b/linux-core/drm_context.c @@ -245,8 +245,6 @@ int drm_setsareactx(struct inode *inode, struct file *filp, if (!map) goto bad; - mutex_lock(&dev->struct_mutex); - ctx_sarea = idr_find(&dev->ctx_idr, request.ctx_id); if (!ctx_sarea) goto bad; -- cgit v1.2.3 From d57b7f02d2e525e5600e5d77370d7ad2b4c9b265 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 3 Jul 2007 10:41:48 -0400 Subject: Use idr_replace trick to eliminate struct drm_ctx_sarea_list. --- linux-core/drmP.h | 4 ---- linux-core/drm_context.c | 41 +++++++---------------------------------- linux-core/drm_drawable.c | 3 +-- 3 files changed, 8 insertions(+), 40 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 7bcd095a..c992c8d9 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -570,10 +570,6 @@ typedef struct drm_ctx_list { drm_file_t *tag; /**< associated fd private data */ } drm_ctx_list_t; -struct drm_ctx_sarea_list { - drm_map_t *map; -}; - typedef struct drm_vbl_sig { struct list_head head; unsigned int sequence; diff --git a/linux-core/drm_context.c b/linux-core/drm_context.c index ff08e809..195c7fb5 100644 --- a/linux-core/drm_context.c +++ b/linux-core/drm_context.c @@ -58,17 +58,9 @@ */ void drm_ctxbitmap_free(drm_device_t * dev, int ctx_handle) { - struct drm_ctx_sarea_list *ctx; - mutex_lock(&dev->struct_mutex); - ctx = idr_find(&dev->ctx_idr, ctx_handle); - if (ctx) { - idr_remove(&dev->ctx_idr, ctx_handle); - drm_free(ctx, sizeof(struct drm_ctx_sarea_list), DRM_MEM_CTXLIST); - } else - DRM_ERROR("Attempt to free invalid context handle: %d\n", ctx_handle); + idr_remove(&dev->ctx_idr, ctx_handle); mutex_unlock(&dev->struct_mutex); - return; } /** @@ -84,20 +76,15 @@ static int drm_ctxbitmap_next(drm_device_t * dev) { int new_id; int ret; - struct drm_ctx_sarea_list *new_ctx; - - new_ctx = drm_calloc(1, sizeof(struct drm_ctx_sarea_list), DRM_MEM_CTXLIST); - if (!new_ctx) - return -1; again: if (idr_pre_get(&dev->ctx_idr, GFP_KERNEL) == 0) { DRM_ERROR("Out of memory expanding drawable idr\n"); - drm_free(new_ctx, sizeof(struct drm_ctx_sarea_list), DRM_MEM_CTXLIST); return -ENOMEM; } mutex_lock(&dev->struct_mutex); - ret = idr_get_new_above(&dev->ctx_idr, new_ctx, DRM_RESERVED_CONTEXTS, &new_id); + ret = idr_get_new_above(&dev->ctx_idr, NULL, + DRM_RESERVED_CONTEXTS, &new_id); if (ret == -EAGAIN) { mutex_unlock(&dev->struct_mutex); goto again; @@ -120,15 +107,6 @@ int drm_ctxbitmap_init(drm_device_t * dev) return 0; } - - -static int drm_ctx_sarea_free(int id, void *p, void *data) -{ - struct drm_ctx_sarea_list *ctx_entry = p; - drm_free(ctx_entry, sizeof(struct drm_ctx_sarea_list), DRM_MEM_CTXLIST); - return 0; -} - /** * Context bitmap cleanup. * @@ -140,7 +118,6 @@ static int drm_ctx_sarea_free(int id, void *p, void *data) void drm_ctxbitmap_cleanup(drm_device_t * dev) { mutex_lock(&dev->struct_mutex); - idr_for_each(&dev->ctx_idr, drm_ctx_sarea_free, NULL); idr_remove_all(&dev->ctx_idr); mutex_unlock(&dev->struct_mutex); } @@ -172,19 +149,17 @@ int drm_getsareactx(struct inode *inode, struct file *filp, drm_ctx_priv_map_t request; drm_map_t *map; drm_map_list_t *_entry; - struct drm_ctx_sarea_list *ctx_sarea; if (copy_from_user(&request, argp, sizeof(request))) return -EFAULT; mutex_lock(&dev->struct_mutex); - ctx_sarea = idr_find(&dev->ctx_idr, request.ctx_id); - if (!ctx_sarea) { + map = idr_find(&dev->ctx_idr, request.ctx_id); + if (!map) { mutex_unlock(&dev->struct_mutex); return -EINVAL; } - map = ctx_sarea->map; mutex_unlock(&dev->struct_mutex); @@ -224,7 +199,6 @@ int drm_setsareactx(struct inode *inode, struct file *filp, drm_ctx_priv_map_t request; drm_map_t *map = NULL; drm_map_list_t *r_list = NULL; - struct drm_ctx_sarea_list *ctx_sarea; if (copy_from_user(&request, (drm_ctx_priv_map_t __user *) arg, sizeof(request))) @@ -245,12 +219,11 @@ int drm_setsareactx(struct inode *inode, struct file *filp, if (!map) goto bad; - ctx_sarea = idr_find(&dev->ctx_idr, request.ctx_id); - if (!ctx_sarea) + if (IS_ERR(idr_replace(&dev->ctx_idr, map, request.ctx_id))) goto bad; - ctx_sarea->map = map; mutex_unlock(&dev->struct_mutex); + return 0; } diff --git a/linux-core/drm_drawable.c b/linux-core/drm_drawable.c index 57b62ca4..7129980b 100644 --- a/linux-core/drm_drawable.c +++ b/linux-core/drm_drawable.c @@ -113,8 +113,7 @@ int drm_update_drawable_info(DRM_IOCTL_ARGS) info = drm_calloc(1, sizeof(*info), DRM_MEM_BUFS); if (!info) return -ENOMEM; - if (idr_replace(&dev->drw_idr, info, update.handle) == - (void*)-ENOENT) { + if (IS_ERR(idr_replace(&dev->drw_idr, info, update.handle))) { DRM_ERROR("No such drawable %d\n", update.handle); drm_free(info, sizeof(*info), DRM_MEM_BUFS); return -EINVAL; -- cgit v1.2.3 From 163f8526123ffa38783fc911b5f7a19debce7f73 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 2 Jul 2007 19:31:18 +1000 Subject: nouveau: rewrite gpu object code Allows multiple references to a single object, needed to support PCI(E)GART scatter-gather DMA objects which would quickly fill PRAMIN if each channel had its own. Handle per-channel private instmem areas. This is needed to support NV50, but might be something we want to do on earlier chipsets at some point? Everything that touches PRAMIN is a GPU object. --- shared-core/nouveau_drv.h | 118 ++++-- shared-core/nouveau_fifo.c | 66 ++-- shared-core/nouveau_mem.c | 9 +- shared-core/nouveau_notifier.c | 24 +- shared-core/nouveau_object.c | 827 ++++++++++++++++++++++++++++------------- shared-core/nouveau_state.c | 20 +- shared-core/nv04_fifo.c | 35 +- shared-core/nv10_fifo.c | 33 +- shared-core/nv20_graph.c | 53 ++- shared-core/nv30_graph.c | 53 ++- shared-core/nv40_fifo.c | 36 +- shared-core/nv40_graph.c | 58 ++- 12 files changed, 844 insertions(+), 488 deletions(-) diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index 3cca07fc..73793b34 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -57,18 +57,38 @@ enum nouveau_flags { NV_NFORCE2 =0x20000000 }; -struct nouveau_object -{ - struct nouveau_object *next; - struct nouveau_object *prev; - int channel; +#define NVOBJ_ENGINE_SW 0 +#define NVOBJ_ENGINE_GR 1 +#define NVOBJ_ENGINE_INT 0xdeadbeef - struct mem_block *instance; +#define NVOBJ_FLAG_ALLOW_NO_REFS (1 << 0) +#define NVOBJ_FLAG_ZERO_ALLOC (1 << 1) +#define NVOBJ_FLAG_ZERO_FREE (1 << 2) +#define NVOBJ_FLAG_FAKE (1 << 3) +typedef struct nouveau_gpuobj { + struct nouveau_gpuobj *next; + struct nouveau_gpuobj *prev; - uint32_t handle; - int class; - int engine; -}; + int im_channel; + struct mem_block *im_pramin; + struct mem_block *im_backing; + + uint32_t flags; + int refcount; + + uint32_t engine; + uint32_t class; +} nouveau_gpuobj_t; + +typedef struct nouveau_gpuobj_ref { + struct nouveau_gpuobj_ref *next; + + nouveau_gpuobj_t *gpuobj; + uint32_t instance; + + int channel; + int handle; +} nouveau_gpuobj_ref_t; struct nouveau_fifo { @@ -79,21 +99,29 @@ struct nouveau_fifo drm_local_map_t *map; /* mapping of the regs controling the fifo */ drm_local_map_t *regs; - /* dma object for the command buffer itself */ - struct mem_block *cmdbuf_mem; - struct nouveau_object *cmdbuf_obj; - uint32_t pushbuf_base; - /* notifier memory */ + + /* DMA push buffer */ + struct mem_block *cmdbuf_mem; + nouveau_gpuobj_ref_t *pushbuf; + uint32_t pushbuf_base; + + /* Notifier memory */ struct mem_block *notifier_block; struct mem_block *notifier_heap; drm_local_map_t *notifier_map; - /* PGRAPH context, for cards that keep it in RAMIN */ - struct mem_block *ramin_grctx; - /* objects belonging to this fifo */ - struct nouveau_object *objs; - /* XXX dynamic alloc ? */ - uint32_t pgraph_ctx [340]; + /* PFIFO context */ + nouveau_gpuobj_ref_t *ramfc; + + /* PGRAPH context */ + nouveau_gpuobj_ref_t *ramin_grctx; + uint32_t pgraph_ctx [340]; /* XXX dynamic alloc ? */ + + /* Objects */ + nouveau_gpuobj_ref_t *ramin; /* Private instmem */ + struct mem_block *ramin_heap; /* Private PRAMIN heap */ + nouveau_gpuobj_ref_t *ramht; /* Hash table */ + nouveau_gpuobj_ref_t *ramht_refs; /* Objects referenced by RAMHT */ }; struct nouveau_config { @@ -157,6 +185,7 @@ typedef struct drm_nouveau_private { struct nouveau_engine_func Engine; /* RAMIN configuration, RAMFC, RAMHT and RAMRO offsets */ + nouveau_gpuobj_t *ramht; uint32_t ramin_size; uint32_t ramht_offset; uint32_t ramht_size; @@ -182,9 +211,11 @@ typedef struct drm_nouveau_private { /* context table pointed to be NV_PGRAPH_CHANNEL_CTX_TABLE (0x400780) */ uint32_t ctx_table_size; - struct mem_block *ctx_table; + nouveau_gpuobj_ref_t *ctx_table; struct nouveau_config config; + + nouveau_gpuobj_t *gpuobj_all; } drm_nouveau_private_t; @@ -205,6 +236,7 @@ extern int nouveau_mem_init_heap(struct mem_block **, extern struct mem_block *nouveau_mem_alloc_block(struct mem_block *, uint64_t size, int align2, DRMFILE); +extern void nouveau_mem_takedown(struct mem_block **heap); extern void nouveau_mem_free_block(struct mem_block *); extern uint64_t nouveau_mem_fb_amount(struct drm_device *dev); extern void nouveau_mem_release(DRMFILE filp, struct mem_block *heap); @@ -236,22 +268,28 @@ extern int nouveau_fifo_owner(drm_device_t *dev, DRMFILE filp, int channel); extern void nouveau_fifo_free(drm_device_t *dev, int channel); /* nouveau_object.c */ -extern int nouveau_object_init_channel(drm_device_t *, int channel, - uint32_t vram_handle, - uint32_t tt_handle); -extern void nouveau_object_takedown_channel(drm_device_t *dev, int channel); -extern void nouveau_object_cleanup(drm_device_t *dev, int channel); -extern int nouveau_ramht_insert(drm_device_t *, int channel, - uint32_t handle, struct nouveau_object *); -extern struct nouveau_object * -nouveau_object_gr_create(drm_device_t *dev, int channel, int class); -extern struct nouveau_object * -nouveau_object_dma_create(drm_device_t *dev, int channel, int class, - uint32_t offset, uint32_t size, - int access, int target); -extern void nouveau_object_free(drm_device_t *dev, struct nouveau_object *obj); -extern int nouveau_ioctl_grobj_alloc(DRM_IOCTL_ARGS); -extern uint32_t nouveau_chip_instance_get(drm_device_t *dev, struct mem_block *mem); +extern void nouveau_gpuobj_takedown(drm_device_t *dev); +extern int nouveau_gpuobj_channel_init(drm_device_t *, int channel, + uint32_t vram_h, uint32_t tt_h); +extern void nouveau_gpuobj_channel_takedown(drm_device_t *, int channel); +extern int nouveau_gpuobj_new(drm_device_t *, int channel, int size, int align, + uint32_t flags, nouveau_gpuobj_t **); +extern int nouveau_gpuobj_del(drm_device_t *, nouveau_gpuobj_t **); +extern int nouveau_gpuobj_ref_add(drm_device_t *, int channel, uint32_t handle, + nouveau_gpuobj_t *, nouveau_gpuobj_ref_t **); +extern int nouveau_gpuobj_ref_del(drm_device_t *, nouveau_gpuobj_ref_t **); +extern int nouveau_gpuobj_new_ref(drm_device_t *, int chan_obj, int chan_ref, + uint32_t handle, int size, int align, + uint32_t flags, nouveau_gpuobj_ref_t **); +extern int nouveau_gpuobj_new_fake(drm_device_t *, uint32_t offset, + uint32_t size, uint32_t flags, + nouveau_gpuobj_t**, nouveau_gpuobj_ref_t**); +extern int nouveau_gpuobj_dma_new(drm_device_t *, int channel, int class, + uint64_t offset, uint64_t size, + int access, int target, nouveau_gpuobj_t **); +extern int nouveau_gpuobj_gr_new(drm_device_t *, int channel, int class, + nouveau_gpuobj_t **); +extern int nouveau_ioctl_grobj_alloc(DRM_IOCTL_ARGS); /* nouveau_irq.c */ extern irqreturn_t nouveau_irq_handler(DRM_IRQ_ARGS); @@ -384,8 +422,8 @@ extern long nouveau_compat_ioctl(struct file *filp, unsigned int cmd, #define NV_WI32(o,v) DRM_WRITE32(dev_priv->ramin, (o), (v)) #endif -#define INSTANCE_RD(o,i) NV_RI32((o)->start + ((i)<<2)) -#define INSTANCE_WR(o,i,v) NV_WI32((o)->start + ((i)<<2), (v)) +#define INSTANCE_RD(o,i) NV_RI32((o)->im_pramin->start + ((i)<<2)) +#define INSTANCE_WR(o,i,v) NV_WI32((o)->im_pramin->start + ((i)<<2), (v)) #endif /* __NOUVEAU_DRV_H__ */ diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c index 81dbfcda..9f916307 100644 --- a/shared-core/nouveau_fifo.c +++ b/shared-core/nouveau_fifo.c @@ -186,10 +186,12 @@ static int nouveau_fifo_cmdbuf_alloc(struct drm_device *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; struct nouveau_config *config = &dev_priv->config; struct mem_block *cb; - struct nouveau_object *cb_dma = NULL; int cb_min_size = max(NV03_FIFO_SIZE,PAGE_SIZE); + nouveau_gpuobj_t *pushbuf = NULL; + int ret; /* Defaults for unconfigured values */ if (!config->cmdbuf.location) @@ -206,37 +208,42 @@ nouveau_fifo_cmdbuf_alloc(struct drm_device *dev, int channel) } if (cb->flags & NOUVEAU_MEM_AGP) { - cb_dma = nouveau_object_dma_create(dev, channel, - NV_CLASS_DMA_IN_MEMORY, - cb->start - dev_priv->agp_phys, - cb->size, - NV_DMA_ACCESS_RO, NV_DMA_TARGET_AGP); + ret = nouveau_gpuobj_dma_new + (dev, channel, NV_CLASS_DMA_IN_MEMORY, + cb->start - dev_priv->agp_phys, + cb->size, NV_DMA_ACCESS_RO, NV_DMA_TARGET_AGP, + &pushbuf); } else if (dev_priv->card_type != NV_04) { - cb_dma = nouveau_object_dma_create(dev, channel, - NV_CLASS_DMA_IN_MEMORY, - cb->start - drm_get_resource_start(dev, 1), - cb->size, - NV_DMA_ACCESS_RO, NV_DMA_TARGET_VIDMEM); + ret = nouveau_gpuobj_dma_new + (dev, channel, NV_CLASS_DMA_IN_MEMORY, + cb->start - drm_get_resource_start(dev, 1), + cb->size, NV_DMA_ACCESS_RO, NV_DMA_TARGET_VIDMEM, + &pushbuf); } else { /* NV04 cmdbuf hack, from original ddx.. not sure of it's * exact reason for existing :) PCI access to cmdbuf in * VRAM. */ - cb_dma = nouveau_object_dma_create(dev, channel, - NV_CLASS_DMA_IN_MEMORY, - cb->start, cb->size, - NV_DMA_ACCESS_RO, NV_DMA_TARGET_PCI); + ret = nouveau_gpuobj_dma_new + (dev, channel, NV_CLASS_DMA_IN_MEMORY, + cb->start, cb->size, NV_DMA_ACCESS_RO, + NV_DMA_TARGET_PCI, &pushbuf); } - if (!cb_dma) { + if (ret) { nouveau_mem_free(dev, cb); - DRM_ERROR("Failed to alloc DMA object for command buffer\n"); - return DRM_ERR(ENOMEM); + DRM_ERROR("Error creating push buffer ctxdma: %d\n", ret); + return ret; + } + + if ((ret = nouveau_gpuobj_ref_add(dev, channel, 0, pushbuf, + &chan->pushbuf))) { + DRM_ERROR("Error referencing push buffer ctxdma: %d\n", ret); + return ret; } dev_priv->fifos[channel].pushbuf_base = 0; dev_priv->fifos[channel].cmdbuf_mem = cb; - dev_priv->fifos[channel].cmdbuf_obj = cb_dma; return 0; } @@ -266,6 +273,7 @@ int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp, return DRM_ERR(EINVAL); (*chan_ret) = channel; chan = &dev_priv->fifos[channel]; + memset(chan, sizeof(*chan), 0); DRM_INFO("Allocating FIFO number %d\n", channel); @@ -273,18 +281,15 @@ int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp, chan->used = 1; chan->filp = filp; - /* FIFO has no objects yet */ - chan->objs = NULL; - - /* allocate a command buffer, and create a dma object for the gpu */ - ret = nouveau_fifo_cmdbuf_alloc(dev, channel); + /* Setup channel's default objects */ + ret = nouveau_gpuobj_channel_init(dev, channel, vram_handle, tt_handle); if (ret) { nouveau_fifo_free(dev, channel); return ret; } - /* Setup channel's default objects */ - ret = nouveau_object_init_channel(dev, channel, vram_handle, tt_handle); + /* allocate a command buffer, and create a dma object for the gpu */ + ret = nouveau_fifo_cmdbuf_alloc(dev, channel); if (ret) { nouveau_fifo_free(dev, channel); return ret; @@ -395,13 +400,18 @@ void nouveau_fifo_free(drm_device_t* dev, int channel) NV_WRITE(NV03_PFIFO_CACHES, 0x00000001); /* Deallocate command buffer */ - if (chan->cmdbuf_mem) + if (chan->pushbuf) + nouveau_gpuobj_ref_del(dev, &chan->pushbuf); + + if (chan->cmdbuf_mem) { nouveau_mem_free(dev, chan->cmdbuf_mem); + chan->cmdbuf_mem = NULL; + } nouveau_notifier_takedown_channel(dev, channel); /* Destroy objects belonging to the channel */ - nouveau_object_cleanup(dev, channel); + nouveau_gpuobj_channel_takedown(dev, channel); dev_priv->fifo_alloc_count--; } diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index d8ae52b7..49041862 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -189,7 +189,7 @@ void nouveau_mem_release(DRMFILE filp, struct mem_block *heap) /* * Cleanup everything */ -static void nouveau_mem_takedown(struct mem_block **heap) +void nouveau_mem_takedown(struct mem_block **heap) { struct mem_block *p; @@ -554,6 +554,13 @@ int nouveau_instmem_init(struct drm_device *dev) nouveau_instmem_determine_amount(dev); nouveau_instmem_configure_fixed_tables(dev); + if ((ret = nouveau_gpuobj_new_fake(dev, dev_priv->ramht_offset, + dev_priv->ramht_size, + NVOBJ_FLAG_ZERO_ALLOC | + NVOBJ_FLAG_ALLOW_NO_REFS, + &dev_priv->ramht, NULL))) + return ret; + /* Create a heap to manage RAMIN allocations, we don't allocate * the space that was reserved for RAMHT/FC/RO. */ diff --git a/shared-core/nouveau_notifier.c b/shared-core/nouveau_notifier.c index 0cfe733e..4d5e26ab 100644 --- a/shared-core/nouveau_notifier.c +++ b/shared-core/nouveau_notifier.c @@ -74,10 +74,10 @@ nouveau_notifier_alloc(drm_device_t *dev, int channel, uint32_t handle, { drm_nouveau_private_t *dev_priv = dev->dev_private; struct nouveau_fifo *chan = &dev_priv->fifos[channel]; - struct nouveau_object *obj; + nouveau_gpuobj_t *nobj = NULL; struct mem_block *mem; uint32_t offset; - int target; + int target, ret; if (!chan->notifier_heap) { DRM_ERROR("Channel %d doesn't have a notifier heap!\n", @@ -105,21 +105,19 @@ nouveau_notifier_alloc(drm_device_t *dev, int channel, uint32_t handle, return DRM_ERR(EINVAL); } - obj = nouveau_object_dma_create(dev, channel, NV_CLASS_DMA_IN_MEMORY, - offset, mem->size, NV_DMA_ACCESS_RW, - target); - if (!obj) { + if ((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY, + offset, mem->size, + NV_DMA_ACCESS_RW, target, &nobj))) { nouveau_mem_free_block(mem); - DRM_ERROR("Error creating notifier ctxdma\n"); - return DRM_ERR(ENOMEM); + DRM_ERROR("Error creating notifier ctxdma: %d\n", ret); + return ret; } - obj->handle = handle; - if (nouveau_ramht_insert(dev, channel, handle, obj)) { - nouveau_object_free(dev, obj); + if ((ret = nouveau_gpuobj_ref_add(dev, channel, handle, nobj, NULL))) { + nouveau_gpuobj_del(dev, &nobj); nouveau_mem_free_block(mem); - DRM_ERROR("Error inserting notifier ctxdma into RAMHT\n"); - return DRM_ERR(ENOMEM); + DRM_ERROR("Error referencing notifier ctxdma: %d\n", ret); + return ret; } *b_offset = mem->start; diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index dac08df4..79875ca1 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -35,79 +35,6 @@ #include "nouveau_drv.h" #include "nouveau_drm.h" -/* TODO - * - Check object class, deny unsafe objects (add card-specific versioning?) - * - Get rid of DMA object creation, this should be wrapped by MM routines. - */ - -/* Translate a RAMIN offset into a value the card understands, will be useful - * in the future when we can access more instance ram which isn't mapped into - * the PRAMIN aperture - */ -uint32_t -nouveau_chip_instance_get(drm_device_t *dev, struct mem_block *mem) -{ - uint32_t inst = (uint32_t)mem->start >> 4; - DRM_DEBUG("****** on-chip instance for 0x%016llx = 0x%08x\n", - mem->start, inst); - return inst; -} - -static void -nouveau_object_link(drm_device_t *dev, struct nouveau_object *obj) -{ - drm_nouveau_private_t *dev_priv=dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[obj->channel]; - - if (!chan->objs) { - chan->objs = obj; - return; - } - - obj->prev = NULL; - obj->next = chan->objs; - - chan->objs->prev = obj; - chan->objs = obj; -} - -static void -nouveau_object_unlink(drm_device_t *dev, struct nouveau_object *obj) -{ - drm_nouveau_private_t *dev_priv=dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[obj->channel]; - - if (obj->prev == NULL) { - if (obj->next) - obj->next->prev = NULL; - chan->objs = obj->next; - } else if (obj->next == NULL) { - if (obj->prev) - obj->prev->next = NULL; - } else { - obj->prev->next = obj->next; - obj->next->prev = obj->prev; - } -} - -static struct nouveau_object * -nouveau_object_handle_find(drm_device_t *dev, int channel, uint32_t handle) -{ - drm_nouveau_private_t *dev_priv=dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; - struct nouveau_object *obj = chan->objs; - - DRM_DEBUG("Looking for handle 0x%08x\n", handle); - while (obj) { - if (obj->handle == handle) - return obj; - obj = obj->next; - } - - DRM_DEBUG("...couldn't find handle\n"); - return NULL; -} - /* NVidia uses context objects to drive drawing operations. Context objects can be selected into 8 subchannels in the FIFO, @@ -150,146 +77,439 @@ nouveau_ramht_hash_handle(drm_device_t *dev, int channel, uint32_t handle) handle >>= dev_priv->ramht_bits; } hash ^= channel << (dev_priv->ramht_bits - 4); - return hash << 3; + hash <<= 3; + + DRM_DEBUG("ch%d handle=0x%08x hash=0x%08x\n", channel, handle, hash); + return hash; } static int -nouveau_ramht_entry_valid(drm_device_t *dev, uint32_t ramht, uint32_t offset) +nouveau_ramht_entry_valid(drm_device_t *dev, nouveau_gpuobj_t *ramht, + uint32_t offset) { drm_nouveau_private_t *dev_priv=dev->dev_private; - uint32_t ctx = NV_RI32(ramht + offset + 4); + uint32_t ctx = INSTANCE_RD(ramht, (offset + 4)/4); if (dev_priv->card_type < NV_40) return ((ctx & NV_RAMHT_CONTEXT_VALID) != 0); return (ctx != 0); } -int -nouveau_ramht_insert(drm_device_t* dev, int channel, uint32_t handle, - struct nouveau_object *obj) +static int +nouveau_ramht_insert(drm_device_t* dev, nouveau_gpuobj_ref_t *ref) { drm_nouveau_private_t *dev_priv=dev->dev_private; - uint32_t ramht = dev_priv->ramht_offset; + struct nouveau_fifo *chan = &dev_priv->fifos[ref->channel]; + nouveau_gpuobj_t *ramht = chan->ramht ? chan->ramht->gpuobj : NULL; + nouveau_gpuobj_t *gpuobj = ref->gpuobj; uint32_t ctx, co, ho; - uint32_t inst; - inst = nouveau_chip_instance_get(dev, obj->instance); + if (!ramht) { + DRM_ERROR("No hash table!\n"); + return DRM_ERR(EINVAL); + } + if (dev_priv->card_type < NV_40) { - ctx = NV_RAMHT_CONTEXT_VALID | inst | - (channel << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) | - (obj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT); + ctx = NV_RAMHT_CONTEXT_VALID | (ref->instance >> 4) | + (ref->channel << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) | + (gpuobj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT); } else if (dev_priv->card_type < NV_50) { - ctx = inst | - (channel << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) | - (obj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT); + ctx = (ref->instance >> 4) | + (ref->channel << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) | + (gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT); } else { - ctx = inst | - (obj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT); + ctx = (ref->instance >> 4) | + (gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT); } - co = ho = nouveau_ramht_hash_handle(dev, channel, handle); + co = ho = nouveau_ramht_hash_handle(dev, ref->channel, ref->handle); do { if (!nouveau_ramht_entry_valid(dev, ramht, co)) { DRM_DEBUG("insert ch%d 0x%08x: h=0x%08x, c=0x%08x\n", - channel, co, handle, ctx); - NV_WI32(ramht + co + 0, handle); - NV_WI32(ramht + co + 4, ctx); - obj->handle = handle; + ref->channel, co, ref->handle, ctx); + INSTANCE_WR(ramht, (co + 0)/4, ref->handle); + INSTANCE_WR(ramht, (co + 4)/4, ctx); return 0; } DRM_DEBUG("collision ch%d 0x%08x: h=0x%08x\n", - channel, co, NV_RI32(ramht + co)); + ref->channel, co, INSTANCE_RD(ramht, co/4)); co += 8; - if (co == dev_priv->ramht_size) + if (co >= dev_priv->ramht_size) co = 0; } while (co != ho); - DRM_ERROR("RAMHT space exhausted. ch=%d\n", channel); + DRM_ERROR("RAMHT space exhausted. ch=%d\n", ref->channel); return DRM_ERR(ENOMEM); } static void -nouveau_ramht_remove(drm_device_t* dev, struct nouveau_object *obj) +nouveau_ramht_remove(drm_device_t* dev, nouveau_gpuobj_ref_t *ref) { drm_nouveau_private_t *dev_priv = dev->dev_private; - uint32_t ramht = dev_priv->ramht_offset; + struct nouveau_fifo *chan = &dev_priv->fifos[ref->channel]; + nouveau_gpuobj_t *ramht = chan->ramht ? chan->ramht->gpuobj : NULL; uint32_t co, ho; - co = ho = nouveau_ramht_hash_handle(dev, obj->channel, obj->handle); + if (!ramht) { + DRM_ERROR("No hash table!\n"); + return; + } + + co = ho = nouveau_ramht_hash_handle(dev, ref->channel, ref->handle); do { if (nouveau_ramht_entry_valid(dev, ramht, co) && - (obj->handle == NV_RI32(ramht + co))) { + (ref->handle == INSTANCE_RD(ramht, (co/4)))) { DRM_DEBUG("remove ch%d 0x%08x: h=0x%08x, c=0x%08x\n", - obj->channel, co, obj->handle, - NV_RI32(ramht + co + 4)); - NV_WI32(ramht + co + 0, 0x00000000); - NV_WI32(ramht + co + 4, 0x00000000); - obj->handle = ~0; + ref->channel, co, ref->handle, + INSTANCE_RD(ramht, (co + 4))); + INSTANCE_WR(ramht, (co + 0)/4, 0x00000000); + INSTANCE_WR(ramht, (co + 4)/4, 0x00000000); return; } co += 8; - if (co == dev_priv->ramht_size) + if (co >= dev_priv->ramht_size) co = 0; } while (co != ho); DRM_ERROR("RAMHT entry not found. ch=%d, handle=0x%08x\n", - obj->channel, obj->handle); + ref->channel, ref->handle); } -static struct nouveau_object * -nouveau_object_instance_alloc(drm_device_t* dev, int channel) +int +nouveau_gpuobj_new(drm_device_t *dev, int channel, int size, int align, + uint32_t flags, nouveau_gpuobj_t **gpuobj_ret) { - drm_nouveau_private_t *dev_priv=dev->dev_private; - struct nouveau_object *obj; + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = NULL; + nouveau_gpuobj_t *gpuobj; + struct mem_block *pramin = NULL; + + DRM_DEBUG("ch%d size=%d align=%d flags=0x%08x\n", + channel, size, align, flags); - /* Create object struct */ - obj = drm_calloc(1, sizeof(struct nouveau_object), DRM_MEM_DRIVER); - if (!obj) { - DRM_ERROR("couldn't alloc memory for object\n"); - return NULL; + if (!dev_priv || !gpuobj_ret || *gpuobj_ret != NULL) + return DRM_ERR(EINVAL); + + if (channel >= 0) { + if (channel > nouveau_fifo_number(dev)) + return DRM_ERR(EINVAL); + chan = &dev_priv->fifos[channel]; } - /* Allocate instance memory */ - obj->instance = nouveau_instmem_alloc(dev, - (dev_priv->card_type >= NV_40 ? 32 : 16), 4); - if (!obj->instance) { - DRM_ERROR("couldn't alloc RAMIN for object\n"); - drm_free(obj, sizeof(struct nouveau_object), DRM_MEM_DRIVER); - return NULL; + gpuobj = drm_calloc(1, sizeof(*gpuobj), DRM_MEM_DRIVER); + if (!gpuobj) + return DRM_ERR(ENOMEM); + DRM_DEBUG("gpuobj %p\n", gpuobj); + gpuobj->flags = flags; + gpuobj->im_channel = channel; + + /* Choose between global instmem heap, and per-channel private + * instmem heap. On ramin_heap) { + DRM_DEBUG("private heap\n"); + pramin = chan->ramin_heap; + } else + if (dev_priv->card_type < NV_50) { + DRM_DEBUG("global heap fallback\n"); + pramin = dev_priv->ramin_heap; + } + } else { + DRM_DEBUG("global heap\n"); + pramin = dev_priv->ramin_heap; + } + + if (!pramin) { + DRM_ERROR("No PRAMIN heap!\n"); + return DRM_ERR(EINVAL); } - /* Bind object to channel */ - obj->channel = channel; - obj->handle = ~0; - nouveau_object_link(dev, obj); + /* Allocate a chunk of the PRAMIN aperture */ + gpuobj->im_pramin = nouveau_mem_alloc_block(pramin, size, + drm_order(align), + (DRMFILE)-2); + if (!gpuobj->im_pramin) { + nouveau_gpuobj_del(dev, &gpuobj); + return DRM_ERR(ENOMEM); + } + gpuobj->im_pramin->flags = NOUVEAU_MEM_INSTANCE; + + /* On NV50 the PRAMIN aperture is paged. When allocating from the + * global instmem heap, alloc and bind VRAM pages into the PRAMIN + * aperture. + */ + if (!chan && dev_priv->card_type >= NV_50) { + DRM_ERROR("back aperture with vram pages\n"); + nouveau_gpuobj_del(dev, &gpuobj); + return DRM_ERR(EINVAL); + } - return obj; + if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) { + int i; + + for (i = 0; i < gpuobj->im_pramin->size; i += 4) + INSTANCE_WR(gpuobj, i/4, 0); + } + + if (dev_priv->gpuobj_all) { + gpuobj->next = dev_priv->gpuobj_all; + gpuobj->next->prev = gpuobj; + } + dev_priv->gpuobj_all = gpuobj; + + *gpuobj_ret = gpuobj; + return 0; } -static void -nouveau_object_instance_free(drm_device_t *dev, struct nouveau_object *obj) +void nouveau_gpuobj_takedown(drm_device_t *dev) { - drm_nouveau_private_t *dev_priv=dev->dev_private; + drm_nouveau_private_t *dev_priv = dev->dev_private; + nouveau_gpuobj_t *gpuobj = NULL; + + DRM_DEBUG("\n"); + + while ((gpuobj = dev_priv->gpuobj_all)) { + DRM_ERROR("gpuobj %p still exists at takedown, refs=%d\n", + gpuobj, gpuobj->refcount); + gpuobj->refcount = 0; + nouveau_gpuobj_del(dev, &gpuobj); + } +} + +int nouveau_gpuobj_del(drm_device_t *dev, nouveau_gpuobj_t **pgpuobj) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + nouveau_gpuobj_t *gpuobj; + + DRM_DEBUG("gpuobj %p\n", pgpuobj ? *pgpuobj : NULL); + + if (!dev_priv || !pgpuobj || !(*pgpuobj)) + return DRM_ERR(EINVAL); + gpuobj = *pgpuobj; + + if (gpuobj->refcount != 0) { + DRM_ERROR("gpuobj refcount is %d\n", gpuobj->refcount); + return DRM_ERR(EINVAL); + } + + if (gpuobj->im_pramin) { + if (gpuobj->flags & NVOBJ_FLAG_FAKE) + drm_free(gpuobj->im_pramin, sizeof(*gpuobj->im_pramin), + DRM_MEM_DRIVER); + else + nouveau_mem_free_block(gpuobj->im_pramin); + } + + if (gpuobj->im_backing) + nouveau_mem_free(dev, gpuobj->im_backing); + + if (gpuobj->next) + gpuobj->next->prev = gpuobj->prev; + if (gpuobj->prev) + gpuobj->prev->next = gpuobj->next; + else + dev_priv->gpuobj_all = gpuobj->next; + + *pgpuobj = NULL; + drm_free(gpuobj, sizeof(*gpuobj), DRM_MEM_DRIVER); + return 0; +} + +static int +nouveau_gpuobj_instance_get(drm_device_t *dev, int channel, + nouveau_gpuobj_t *gpuobj, uint32_t *inst) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + nouveau_gpuobj_t *cpramin; + + if ((channel > 0) && gpuobj->im_channel != channel) { + DRM_ERROR("Channel mismatch: obj %d, ref %d\n", + gpuobj->im_channel, channel); + return DRM_ERR(EINVAL); + } + + /* card_type < NV_50) { + *inst = gpuobj->im_pramin->start; + return 0; + } + + /* NV50 channel-local instance */ + if (channel > 0) { + cpramin = dev_priv->fifos[channel].ramin->gpuobj; + *inst = gpuobj->im_pramin->start - cpramin->im_pramin->start; + return 0; + } + + /* NV50 global (VRAM) instance */ + if (gpuobj->im_channel < 0) { + /* ...from global heap */ + if (!gpuobj->im_backing) { + DRM_ERROR("AII, no VRAM backing gpuobj\n"); + return DRM_ERR(EINVAL); + } + *inst = gpuobj->im_backing->start - dev_priv->fb_phys; + return 0; + } else { + /* ...from local heap */ + cpramin = dev_priv->fifos[gpuobj->im_channel].ramin->gpuobj; + *inst = (cpramin->im_backing->start - dev_priv->fb_phys) + + (gpuobj->im_pramin->start - cpramin->im_pramin->start); + return 0; + } + + return DRM_ERR(EINVAL); +} + +int +nouveau_gpuobj_ref_add(drm_device_t *dev, int channel, uint32_t handle, + nouveau_gpuobj_t *gpuobj, nouveau_gpuobj_ref_t **ref_ret) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = NULL; + nouveau_gpuobj_ref_t *ref; + uint32_t instance; + int ret; + + DRM_DEBUG("ch%d h=0x%08x gpuobj=%p\n", channel, handle, gpuobj); + + if (!dev_priv || !gpuobj || (ref_ret && *ref_ret != NULL)) + return DRM_ERR(EINVAL); + + if (channel >= 0) { + if (channel > nouveau_fifo_number(dev)) + return DRM_ERR(EINVAL); + chan = &dev_priv->fifos[channel]; + } else + if (!ref_ret) + return DRM_ERR(EINVAL); + + ret = nouveau_gpuobj_instance_get(dev, channel, gpuobj, &instance); + if (ret) + return ret; + + ref = drm_calloc(1, sizeof(*ref), DRM_MEM_DRIVER); + if (!ref) + return DRM_ERR(ENOMEM); + ref->gpuobj = gpuobj; + ref->channel = channel; + ref->instance = instance; + + if (!ref_ret) { + ref->handle = handle; + + ret = nouveau_ramht_insert(dev, ref); + if (ret) { + drm_free(ref, sizeof(*ref), DRM_MEM_DRIVER); + return ret; + } + + ref->next = chan->ramht_refs; + chan->ramht_refs = ref; + } else { + ref->handle = ~0; + *ref_ret = ref; + } + + ref->gpuobj->refcount++; + return 0; +} + +int nouveau_gpuobj_ref_del(drm_device_t *dev, nouveau_gpuobj_ref_t **pref) +{ + nouveau_gpuobj_ref_t *ref; + + DRM_DEBUG("ref %p\n", pref ? *pref : NULL); + + if (!dev || !pref || *pref == NULL) + return DRM_ERR(EINVAL); + ref = *pref; + + if (ref->handle != ~0) + nouveau_ramht_remove(dev, ref); + + if (ref->gpuobj) { + ref->gpuobj->refcount--; + + if (ref->gpuobj->refcount == 0) { + if (!(ref->gpuobj->flags & NVOBJ_FLAG_ALLOW_NO_REFS)) + nouveau_gpuobj_del(dev, &ref->gpuobj); + } + } + + *pref = NULL; + drm_free(ref, sizeof(ref), DRM_MEM_DRIVER); + return 0; +} + +int +nouveau_gpuobj_new_ref(drm_device_t *dev, int oc, int rc, uint32_t handle, + int size, int align, uint32_t flags, + nouveau_gpuobj_ref_t **ref) +{ + nouveau_gpuobj_t *gpuobj = NULL; + int ret; + + if ((ret = nouveau_gpuobj_new(dev, oc, size, align, flags, &gpuobj))) + return ret; + + if ((ret = nouveau_gpuobj_ref_add(dev, rc, handle, gpuobj, ref))) { + nouveau_gpuobj_del(dev, &gpuobj); + return ret; + } + + return 0; +} + +int +nouveau_gpuobj_new_fake(drm_device_t *dev, uint32_t offset, uint32_t size, + uint32_t flags, nouveau_gpuobj_t **pgpuobj, + nouveau_gpuobj_ref_t **pref) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + nouveau_gpuobj_t *gpuobj = NULL; int i; - /* Unbind object from channel */ - nouveau_object_unlink(dev, obj); + DRM_DEBUG("offset=0x%08x size=0x%08x flags=0x%08x\n", + offset, size, flags); + + gpuobj = drm_calloc(1, sizeof(*gpuobj), DRM_MEM_DRIVER); + if (!gpuobj) + return DRM_ERR(ENOMEM); + DRM_DEBUG("gpuobj %p\n", gpuobj); + gpuobj->im_channel = -1; + gpuobj->flags = flags | NVOBJ_FLAG_FAKE; + + gpuobj->im_pramin = drm_calloc(1, sizeof(struct mem_block), + DRM_MEM_DRIVER); + if (!gpuobj->im_pramin) { + nouveau_gpuobj_del(dev, &gpuobj); + return DRM_ERR(ENOMEM); + } + gpuobj->im_pramin->start = offset; + gpuobj->im_pramin->size = size; + + if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) { + for (i = 0; i < gpuobj->im_pramin->size; i += 4) + INSTANCE_WR(gpuobj, i/4, 0); + } - /* Clean RAMIN entry */ - DRM_DEBUG("Instance entry for 0x%08x" - "(engine %d, class 0x%x) before destroy:\n", - obj->handle, obj->engine, obj->class); - for (i=0; i<(obj->instance->size/4); i++) { - DRM_DEBUG(" +0x%02x: 0x%08x\n", (i*4), - INSTANCE_RD(obj->instance, i)); - INSTANCE_WR(obj->instance, i, 0x00000000); + if (pref) { + if ((i = nouveau_gpuobj_ref_add(dev, -1, 0, gpuobj, pref))) { + nouveau_gpuobj_del(dev, &gpuobj); + return i; + } } - /* Free RAMIN */ - nouveau_instmem_free(dev, obj->instance); + if (pgpuobj) + *pgpuobj = gpuobj; + return 0; } /* @@ -317,64 +537,70 @@ nouveau_object_instance_free(drm_device_t *dev, struct nouveau_object *obj) to it that can be used to set up context objects. */ -struct nouveau_object * -nouveau_object_dma_create(drm_device_t* dev, int channel, int class, - uint32_t offset, uint32_t size, - int access, int target) +static int +nouveau_gpuobj_class_instmem_size(drm_device_t *dev, int class) { - drm_nouveau_private_t *dev_priv=dev->dev_private; - struct nouveau_object *obj; - uint32_t frame, adjust; - uint32_t pte_flags = 0; - - DRM_DEBUG("offset:0x%08x, size:0x%08x, target:%d, access:%d\n", - offset, size, target, access); + drm_nouveau_private_t *dev_priv = dev->dev_private; - switch (target) { - case NV_DMA_TARGET_AGP: - offset += dev_priv->agp_phys; - break; - default: - break; - } + /*XXX: dodgy hack for now */ + if (dev_priv->card_type >= NV_50) + return 24; + if (dev_priv->card_type >= NV_40) + return 32; + return 16; +} - switch (access) { - case NV_DMA_ACCESS_RO: - break; - case NV_DMA_ACCESS_WO: - case NV_DMA_ACCESS_RW: - pte_flags |= (1 << 1); - break; - default: - DRM_ERROR("invalid access mode=%d\n", access); - return NULL; - } +int +nouveau_gpuobj_dma_new(drm_device_t *dev, int channel, int class, + uint64_t offset, uint64_t size, int access, int target, + nouveau_gpuobj_t **gpuobj) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + int ret; - frame = offset & ~0x00000FFF; - adjust = offset & 0x00000FFF; + DRM_DEBUG("ch%d class=0x%04x offset=0x%llx size=0x%llx\n", + channel, class, offset, size); + DRM_DEBUG("access=%d target=%d\n", access, target); - obj = nouveau_object_instance_alloc(dev, channel); - if (!obj) { - DRM_ERROR("couldn't allocate DMA object\n"); - return obj; + ret = nouveau_gpuobj_new(dev, channel, + nouveau_gpuobj_class_instmem_size(dev, class), + 16, + NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE, + gpuobj); + if (ret) { + DRM_ERROR("Error creating gpuobj: %d\n", ret); + return ret; } - obj->engine = 0; - obj->class = class; - - INSTANCE_WR(obj->instance, 0, ((1<<12) | (1<<13) | - (adjust << 20) | - (access << 14) | - (target << 16) | - class)); - INSTANCE_WR(obj->instance, 1, size-1); - INSTANCE_WR(obj->instance, 2, frame | pte_flags); - INSTANCE_WR(obj->instance, 3, frame | pte_flags); + if (dev_priv->card_type < NV_50) { + uint32_t frame, adjust, pte_flags = 0; + + if (target == NV_DMA_TARGET_AGP) + offset += dev_priv->agp_phys; + if (access != NV_DMA_ACCESS_RO) + pte_flags |= (1<<1); + frame = offset & ~0x00000fff; + adjust = offset & 0x00000fff; + + INSTANCE_WR(*gpuobj, 0, ((1<<12) | (1<<13) | + (adjust << 20) | + (access << 14) | + (target << 16) | + class)); + INSTANCE_WR(*gpuobj, 1, size - 1); + INSTANCE_WR(*gpuobj, 2, frame | pte_flags); + INSTANCE_WR(*gpuobj, 3, frame | pte_flags); + } else { + nouveau_gpuobj_del(dev, gpuobj); + DRM_ERROR("stub\n"); + return DRM_ERR(EINVAL); + } - return obj; + (*gpuobj)->engine = NVOBJ_ENGINE_SW; + (*gpuobj)->class = class; + return 0; } - /* Context objects in the instance RAM have the following structure. * On NV40 they are 32 byte long, on NV30 and smaller 16 bytes. @@ -426,89 +652,142 @@ nouveau_object_dma_create(drm_device_t* dev, int channel, int class, entry[5]: set to 0? */ -struct nouveau_object * -nouveau_object_gr_create(drm_device_t* dev, int channel, int class) +int +nouveau_gpuobj_gr_new(drm_device_t *dev, int channel, int class, + nouveau_gpuobj_t **gpuobj) { - drm_nouveau_private_t *dev_priv=dev->dev_private; - struct nouveau_object *obj; + drm_nouveau_private_t *dev_priv = dev->dev_private; + int ret; - DRM_DEBUG("class=%x\n", class); + DRM_DEBUG("ch%d class=0x%04x\n", channel, class); - obj = nouveau_object_instance_alloc(dev, channel); - if (!obj) { - DRM_ERROR("couldn't allocate context object\n"); - return obj; + ret = nouveau_gpuobj_new(dev, channel, + nouveau_gpuobj_class_instmem_size(dev, class), + 16, + NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE, + gpuobj); + if (ret) { + DRM_ERROR("Error creating gpuobj: %d\n", ret); + return ret; } - obj->engine = 1; - obj->class = class; + if (dev_priv->card_type >= NV_50) { + nouveau_gpuobj_del(dev, gpuobj); + DRM_ERROR("stub!\n"); + return DRM_ERR(EINVAL); + } switch (class) { case NV_CLASS_NULL: - INSTANCE_WR(obj->instance, 0, 0x00001030); - INSTANCE_WR(obj->instance, 1, 0xFFFFFFFF); - INSTANCE_WR(obj->instance, 2, 0x00000000); - INSTANCE_WR(obj->instance, 2, 0x00000000); + INSTANCE_WR(*gpuobj, 0, 0x00001030); + INSTANCE_WR(*gpuobj, 1, 0xFFFFFFFF); break; default: if (dev_priv->card_type >= NV_40) { - INSTANCE_WR(obj->instance, 0, obj->class); - INSTANCE_WR(obj->instance, 1, 0x00000000); + INSTANCE_WR(*gpuobj, 0, class); #ifdef __BIG_ENDIAN - INSTANCE_WR(obj->instance, 2, 0x01000000); -#else - INSTANCE_WR(obj->instance, 2, 0x00000000); + INSTANCE_WR(*gpuobj, 2, 0x01000000); #endif - INSTANCE_WR(obj->instance, 3, 0x00000000); - INSTANCE_WR(obj->instance, 4, 0x00000000); - INSTANCE_WR(obj->instance, 5, 0x00000000); - INSTANCE_WR(obj->instance, 6, 0x00000000); - INSTANCE_WR(obj->instance, 7, 0x00000000); } else { #ifdef __BIG_ENDIAN - INSTANCE_WR(obj->instance, 0, obj->class | 0x00080000); + INSTANCE_WR(*gpuobj, 0, class | 0x00080000); #else - INSTANCE_WR(obj->instance, 0, obj->class); + INSTANCE_WR(*gpuobj, 0, class); #endif - INSTANCE_WR(obj->instance, 1, 0x00000000); - INSTANCE_WR(obj->instance, 2, 0x00000000); - INSTANCE_WR(obj->instance, 3, 0x00000000); } } - return obj; + (*gpuobj)->engine = NVOBJ_ENGINE_GR; + (*gpuobj)->class = class; + return 0; } -void -nouveau_object_free(drm_device_t *dev, struct nouveau_object *obj) +static int +nouveau_gpuobj_channel_init_pramin(drm_device_t *dev, int channel) { - nouveau_object_instance_free(dev, obj); - if (obj->handle != ~0) - nouveau_ramht_remove(dev, obj); - drm_free(obj, sizeof(struct nouveau_object), DRM_MEM_DRIVER); + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + nouveau_gpuobj_t *pramin = NULL; + int size, base, ret; + + DRM_DEBUG("ch%d\n", channel); + + /* Base amount for object storage (4KiB enough?) */ + size = 0x1000; + base = 0; + + /* PGRAPH context */ + + if (dev_priv->card_type == NV_50) { + /* RAMHT, RAMFC, PD, funny header thingo */ + } + + DRM_DEBUG("ch%d PRAMIN size: 0x%08x bytes, base alloc=0x%08x\n", + channel, size, base); + ret = nouveau_gpuobj_new_ref(dev, -1, -1, 0, size, 0x1000, 0, + &chan->ramin); + if (ret) { + DRM_ERROR("Error allocating channel PRAMIN: %d\n", ret); + return ret; + } + pramin = chan->ramin->gpuobj; + + ret = nouveau_mem_init_heap(&chan->ramin_heap, + pramin->im_pramin->start + base, size); + if (ret) { + DRM_ERROR("Error creating PRAMIN heap: %d\n", ret); + nouveau_gpuobj_ref_del(dev, &chan->ramin); + return ret; + } + + return 0; } int -nouveau_object_init_channel(drm_device_t *dev, int channel, - uint32_t vram_handle, - uint32_t tt_handle) +nouveau_gpuobj_channel_init(drm_device_t *dev, int channel, + uint32_t vram_h, uint32_t tt_h) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_object *gpuobj; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + nouveau_gpuobj_t *vram = NULL, *tt = NULL; int ret; + DRM_DEBUG("ch%d vram=0x%08x tt=0x%08x\n", channel, vram_h, tt_h); + + /* Reserve a block of PRAMIN for the channel + *XXX: maybe on card_type == NV_50) { + ret = nouveau_gpuobj_channel_init_pramin(dev, channel); + if (ret) + return ret; + } + + /* RAMHT */ + if (dev_priv->card_type < NV_50) { + ret = nouveau_gpuobj_ref_add(dev, -1, 0, dev_priv->ramht, + &chan->ramht); + if (ret) + return ret; + } else { + ret = nouveau_gpuobj_new_ref(dev, channel, channel, 0, + 0x8000, 16, + NVOBJ_FLAG_ZERO_ALLOC, + &chan->ramht); + if (ret) + return ret; + } + /* VRAM ctxdma */ - gpuobj = nouveau_object_dma_create(dev, channel, NV_CLASS_DMA_IN_MEMORY, - 0, dev_priv->fb_available_size, - NV_DMA_ACCESS_RW, - NV_DMA_TARGET_VIDMEM); - if (!gpuobj) { - DRM_ERROR("Error creating VRAM ctxdma: %d\n", DRM_ERR(ENOMEM)); - return DRM_ERR(ENOMEM); + if ((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY, + 0, dev_priv->fb_available_size, + NV_DMA_ACCESS_RW, + NV_DMA_TARGET_VIDMEM, &vram))) { + DRM_ERROR("Error creating VRAM ctxdma: %d\n", ret); + return ret; } - ret = nouveau_ramht_insert(dev, channel, vram_handle, gpuobj); - if (ret) { + if ((ret = nouveau_gpuobj_ref_add(dev, channel, vram_h, vram, NULL))) { DRM_ERROR("Error referencing VRAM ctxdma: %d\n", ret); return ret; } @@ -518,17 +797,15 @@ nouveau_object_init_channel(drm_device_t *dev, int channel, return 0; /* GART ctxdma */ - gpuobj = nouveau_object_dma_create(dev, channel, NV_CLASS_DMA_IN_MEMORY, - 0, dev_priv->agp_available_size, - NV_DMA_ACCESS_RW, - NV_DMA_TARGET_AGP); - if (!gpuobj) { - DRM_ERROR("Error creating TT ctxdma: %d\n", DRM_ERR(ENOMEM)); - return DRM_ERR(ENOMEM); + if ((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY, + 0, dev_priv->agp_available_size, + NV_DMA_ACCESS_RW, NV_DMA_TARGET_AGP, + &tt))) { + DRM_ERROR("Error creating TT ctxdma: %d\n", ret); + return ret; } - ret = nouveau_ramht_insert(dev, channel, tt_handle, gpuobj); - if (ret) { + if ((ret = nouveau_gpuobj_ref_add(dev, channel, tt_h, tt, NULL))) { DRM_ERROR("Error referencing TT ctxdma: %d\n", ret); return ret; } @@ -536,20 +813,34 @@ nouveau_object_init_channel(drm_device_t *dev, int channel, return 0; } -void nouveau_object_cleanup(drm_device_t *dev, int channel) +void +nouveau_gpuobj_channel_takedown(drm_device_t *dev, int channel) { - drm_nouveau_private_t *dev_priv=dev->dev_private; + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + nouveau_gpuobj_ref_t *ref; + + DRM_DEBUG("ch%d\n", channel); - while (dev_priv->fifos[channel].objs) { - nouveau_object_free(dev, dev_priv->fifos[channel].objs); + while ((ref = chan->ramht_refs)) { + chan->ramht_refs = ref->next; + nouveau_gpuobj_ref_del(dev, &ref); } + nouveau_gpuobj_ref_del(dev, &chan->ramht); + + if (chan->ramin_heap) + nouveau_mem_takedown(&chan->ramin_heap); + if (chan->ramin) + nouveau_gpuobj_ref_del(dev, &chan->ramin); + } int nouveau_ioctl_grobj_alloc(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_nouveau_grobj_alloc_t init; - struct nouveau_object *obj; + nouveau_gpuobj_t *gr = NULL; + int ret; DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_grobj_alloc_t __user *) data, sizeof(init)); @@ -561,20 +852,20 @@ int nouveau_ioctl_grobj_alloc(DRM_IOCTL_ARGS) } //FIXME: check args, only allow trusted objects to be created + //FIXME: check for pre-existing handle - if (nouveau_object_handle_find(dev, init.channel, init.handle)) { - DRM_ERROR("Channel %d: handle 0x%08x already exists\n", - init.channel, init.handle); - return DRM_ERR(EINVAL); + if ((ret = nouveau_gpuobj_gr_new(dev, init.channel, init.class, &gr))) { + DRM_ERROR("Error creating gr object: %d (%d/0x%08x)\n", + ret, init.channel, init.handle); + return ret; } - obj = nouveau_object_gr_create(dev, init.channel, init.class); - if (!obj) - return DRM_ERR(ENOMEM); - - if (nouveau_ramht_insert(dev, init.channel, init.handle, obj)) { - nouveau_object_free(dev, obj); - return DRM_ERR(ENOMEM); + if ((ret = nouveau_gpuobj_ref_add(dev, init.channel, init.handle, + gr, NULL))) { + DRM_ERROR("Error referencing gr object: %d (%d/0x%08x\n)", + ret, init.channel, init.handle); + nouveau_gpuobj_del(dev, &gr); + return ret; } return 0; diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c index fa773d28..13bc930a 100644 --- a/shared-core/nouveau_state.c +++ b/shared-core/nouveau_state.c @@ -283,6 +283,20 @@ static int nouveau_card_init(drm_device_t *dev) return 0; } +static void nouveau_card_takedown(drm_device_t *dev) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + nouveau_engine_func_t *engine = &dev_priv->Engine; + + engine->fifo.takedown(dev); + engine->graph.takedown(dev); + engine->fb.takedown(dev); + engine->timer.takedown(dev); + engine->mc.takedown(dev); + nouveau_gpuobj_takedown(dev); + nouveau_mem_close(dev); +} + /* here a client dies, release the stuff that was allocated for its filp */ void nouveau_preclose(drm_device_t * dev, DRMFILE filp) { @@ -314,11 +328,10 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) if (flags==NV_UNKNOWN) return DRM_ERR(EINVAL); - dev_priv = drm_alloc(sizeof(drm_nouveau_private_t), DRM_MEM_DRIVER); + dev_priv = drm_calloc(1, sizeof(*dev_priv), DRM_MEM_DRIVER); if (!dev_priv) return DRM_ERR(ENOMEM); - memset(dev_priv, 0, sizeof(drm_nouveau_private_t)); dev_priv->card_type=flags&NOUVEAU_FAMILY; dev_priv->flags=flags&NOUVEAU_FLAGS; @@ -338,6 +351,9 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) void nouveau_lastclose(struct drm_device *dev) { drm_nouveau_private_t *dev_priv = dev->dev_private; + + nouveau_card_takedown(dev); + if(dev_priv->fb_mtrr>0) { drm_mtrr_del(dev_priv->fb_mtrr, drm_get_resource_start(dev, 1),nouveau_mem_fb_amount(dev), DRM_MTRR_WC); diff --git a/shared-core/nv04_fifo.c b/shared-core/nv04_fifo.c index bfae432e..b84f74c1 100644 --- a/shared-core/nv04_fifo.c +++ b/shared-core/nv04_fifo.c @@ -28,8 +28,10 @@ #include "drm.h" #include "nouveau_drv.h" -#define RAMFC_WR(offset, val) NV_WI32(fifoctx + NV04_RAMFC_##offset, (val)) -#define RAMFC_RD(offset) NV_RI32(fifoctx + NV04_RAMFC_##offset) +#define RAMFC_WR(offset,val) INSTANCE_WR(chan->ramfc->gpuobj, \ + NV04_RAMFC_##offset/4, (val)) +#define RAMFC_RD(offset) INSTANCE_RD(chan->ramfc->gpuobj, \ + NV04_RAMFC_##offset/4) #define NV04_RAMFC(c) (dev_priv->ramfc_offset + ((c) * NV04_RAMFC__SIZE)) #define NV04_RAMFC__SIZE 32 @@ -38,21 +40,19 @@ nv04_fifo_create_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; struct nouveau_fifo *chan = &dev_priv->fifos[channel]; - struct nouveau_object *pb = chan->cmdbuf_obj; - uint32_t fifoctx = NV04_RAMFC(channel); - int i; + int ret; - if (!pb || !pb->instance) - return DRM_ERR(EINVAL); + if ((ret = nouveau_gpuobj_new_fake(dev, NV04_RAMFC(channel), + NV04_RAMFC__SIZE, + NVOBJ_FLAG_ZERO_ALLOC | + NVOBJ_FLAG_ZERO_FREE, + NULL, &chan->ramfc))) + return ret; - /* Clear RAMFC */ - for (i=0; ipushbuf_base); RAMFC_WR(DMA_GET, chan->pushbuf_base); - RAMFC_WR(DMA_INSTANCE, nouveau_chip_instance_get(dev, pb->instance)); + RAMFC_WR(DMA_INSTANCE, chan->pushbuf->instance >> 4); RAMFC_WR(DMA_FETCH, (NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 | @@ -67,18 +67,17 @@ void nv04_fifo_destroy_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - uint32_t fifoctx = NV04_RAMFC(channel); - int i; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; - for (i=0; iramfc) + nouveau_gpuobj_ref_del(dev, &chan->ramfc); } int nv04_fifo_load_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - uint32_t fifoctx = NV04_RAMFC(channel); + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; uint32_t tmp; NV_WRITE(NV03_PFIFO_CACHE1_PUSH1, (1<<8) | channel); @@ -106,7 +105,7 @@ int nv04_fifo_save_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - uint32_t fifoctx = NV04_RAMFC(channel); + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; uint32_t tmp; RAMFC_WR(DMA_PUT, NV04_PFIFO_CACHE1_DMA_PUT); diff --git a/shared-core/nv10_fifo.c b/shared-core/nv10_fifo.c index b84971de..07ec4635 100644 --- a/shared-core/nv10_fifo.c +++ b/shared-core/nv10_fifo.c @@ -28,8 +28,11 @@ #include "drm.h" #include "nouveau_drv.h" -#define RAMFC_WR(offset, val) NV_WI32(fifoctx + NV10_RAMFC_##offset, (val)) -#define RAMFC_RD(offset) NV_RI32(fifoctx + NV10_RAMFC_##offset) + +#define RAMFC_WR(offset,val) INSTANCE_WR(chan->ramfc->gpuobj, \ + NV10_RAMFC_##offset/4, (val)) +#define RAMFC_RD(offset) INSTANCE_RD(chan->ramfc->gpuobj, \ + NV10_RAMFC_##offset/4) #define NV10_RAMFC(c) (dev_priv->ramfc_offset + NV10_RAMFC__SIZE) #define NV10_RAMFC__SIZE ((dev_priv->chipset) >= 0x17 ? 64 : 32) @@ -38,20 +41,21 @@ nv10_fifo_create_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; struct nouveau_fifo *chan = &dev_priv->fifos[channel]; - uint32_t fifoctx = NV10_RAMFC(channel), pushbuf; - int i; - - pushbuf = nouveau_chip_instance_get(dev, chan->cmdbuf_obj->instance); + int ret; - for (i=0; iramfc))) + return ret; /* Fill entries that are seen filled in dumps of nvidia driver just * after channel's is put into DMA mode */ RAMFC_WR(DMA_PUT , chan->pushbuf_base); RAMFC_WR(DMA_GET , chan->pushbuf_base); - RAMFC_WR(DMA_INSTANCE , pushbuf); + RAMFC_WR(DMA_INSTANCE , chan->pushbuf->instance >> 4); RAMFC_WR(DMA_FETCH , NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 | @@ -67,18 +71,17 @@ void nv10_fifo_destroy_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - uint32_t fifoctx = NV10_RAMFC(channel); - int i; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; - for (i=0; iramfc) + nouveau_gpuobj_ref_del(dev, &chan->ramfc); } int nv10_fifo_load_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - uint32_t fifoctx = NV10_RAMFC(channel); + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; uint32_t tmp; NV_WRITE(NV03_PFIFO_CACHE1_PUSH1 , 0x00000100 | channel); @@ -120,7 +123,7 @@ int nv10_fifo_save_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - uint32_t fifoctx = NV10_RAMFC(channel); + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; uint32_t tmp; RAMFC_WR(DMA_PUT , NV_READ(NV04_PFIFO_CACHE1_DMA_PUT)); diff --git a/shared-core/nv20_graph.c b/shared-core/nv20_graph.c index 1b8a6727..13271051 100644 --- a/shared-core/nv20_graph.c +++ b/shared-core/nv20_graph.c @@ -34,19 +34,18 @@ int nv20_graph_create_context(drm_device_t *dev, int channel) { (drm_nouveau_private_t *)dev->dev_private; struct nouveau_fifo *chan = &dev_priv->fifos[channel]; unsigned int ctx_size = NV20_GRCTX_SIZE; - int i; + int ret; - /* Alloc and clear RAMIN to store the context */ - chan->ramin_grctx = nouveau_instmem_alloc(dev, ctx_size, 4); - if (!chan->ramin_grctx) - return DRM_ERR(ENOMEM); - for (i=0; iramin_grctx, i/4, 0x00000000); + if ((ret = nouveau_gpuobj_new_ref(dev, channel, -1, 0, ctx_size, 16, + NVOBJ_FLAG_ZERO_ALLOC, + &chan->ramin_grctx))) + return ret; /* Initialise default context values */ - INSTANCE_WR(chan->ramin_grctx, 10, channel << 24); /* CTX_USER */ + INSTANCE_WR(chan->ramin_grctx->gpuobj, 10, channel<<24); /* CTX_USER */ - INSTANCE_WR(dev_priv->ctx_table, channel, nouveau_chip_instance_get(dev, chan->ramin_grctx)); + INSTANCE_WR(dev_priv->ctx_table->gpuobj, channel, + chan->ramin_grctx->instance >> 4); return 0; } @@ -54,12 +53,10 @@ void nv20_graph_destroy_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; struct nouveau_fifo *chan = &dev_priv->fifos[channel]; - if (chan->ramin_grctx) { - nouveau_instmem_free(dev, chan->ramin_grctx); - chan->ramin_grctx = NULL; - } + if (chan->ramin_grctx) + nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx); - INSTANCE_WR(dev_priv->ctx_table, channel, 0); + INSTANCE_WR(dev_priv->ctx_table->gpuobj, channel, 0); } static void nv20_graph_rdi(drm_device_t *dev) { @@ -79,13 +76,14 @@ static void nv20_graph_rdi(drm_device_t *dev) { int nv20_graph_save_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = (drm_nouveau_private_t *)dev->dev_private; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; uint32_t instance; - instance = INSTANCE_RD(dev_priv->ctx_table, channel); + instance = INSTANCE_RD(dev_priv->ctx_table->gpuobj, channel); if (!instance) { return DRM_ERR(EINVAL); } - if (instance != nouveau_chip_instance_get(dev, dev_priv->fifos[channel].ramin_grctx)) + if (instance != (chan->ramin_grctx->instance >> 4)) DRM_ERROR("nv20_graph_save_context : bad instance\n"); NV_WRITE(NV10_PGRAPH_CHANNEL_CTX_SIZE, instance); @@ -99,13 +97,14 @@ int nv20_graph_save_context(drm_device_t *dev, int channel) { int nv20_graph_load_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = (drm_nouveau_private_t *)dev->dev_private; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; uint32_t instance; - instance = INSTANCE_RD(dev_priv->ctx_table, channel); + instance = INSTANCE_RD(dev_priv->ctx_table->gpuobj, channel); if (!instance) { return DRM_ERR(EINVAL); } - if (instance != nouveau_chip_instance_get(dev, dev_priv->fifos[channel].ramin_grctx)) + if (instance != (chan->ramin_grctx->instance >> 4)) DRM_ERROR("nv20_graph_load_context_current : bad instance\n"); NV_WRITE(NV10_PGRAPH_CTX_USER, channel << 24); @@ -148,8 +147,8 @@ void nouveau_nv20_context_switch(drm_device_t *dev) int nv20_graph_init(drm_device_t *dev) { drm_nouveau_private_t *dev_priv = (drm_nouveau_private_t *)dev->dev_private; - int i; uint32_t tmp, vramsz; + int ret, i; NV_WRITE(NV03_PMC_ENABLE, NV_READ(NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH); @@ -158,14 +157,14 @@ int nv20_graph_init(drm_device_t *dev) { /* Create Context Pointer Table */ dev_priv->ctx_table_size = 32 * 4; - dev_priv->ctx_table = nouveau_instmem_alloc(dev, dev_priv->ctx_table_size, 4); - if (!dev_priv->ctx_table) - return DRM_ERR(ENOMEM); - - for (i=0; i< dev_priv->ctx_table_size; i+=4) - INSTANCE_WR(dev_priv->ctx_table, i/4, 0x00000000); - - NV_WRITE(NV10_PGRAPH_CHANNEL_CTX_TABLE, nouveau_chip_instance_get(dev, dev_priv->ctx_table)); + if ((ret = nouveau_gpuobj_new_ref(dev, -1, -1, 0, + dev_priv->ctx_table_size, 16, + NVOBJ_FLAG_ZERO_ALLOC, + &dev_priv->ctx_table))) + return ret; + + NV_WRITE(NV10_PGRAPH_CHANNEL_CTX_TABLE, + dev_priv->ctx_table->instance >> 4); //XXX need to be done and save/restore for each fifo ??? nv20_graph_rdi(dev); diff --git a/shared-core/nv30_graph.c b/shared-core/nv30_graph.c index 7a87990a..65f4f868 100644 --- a/shared-core/nv30_graph.c +++ b/shared-core/nv30_graph.c @@ -16,7 +16,7 @@ * contexts are taken from dumps just after the 3D object is * created. */ -static void nv30_graph_context_init(drm_device_t *dev, struct mem_block *ctx) +static void nv30_graph_context_init(drm_device_t *dev, nouveau_gpuobj_t *ctx) { drm_nouveau_private_t *dev_priv = dev->dev_private; int i; @@ -105,9 +105,9 @@ int nv30_graph_create_context(drm_device_t *dev, int channel) drm_nouveau_private_t *dev_priv = (drm_nouveau_private_t *)dev->dev_private; struct nouveau_fifo *chan = &dev_priv->fifos[channel]; - void (*ctx_init)(drm_device_t *, struct mem_block *); + void (*ctx_init)(drm_device_t *, nouveau_gpuobj_t *); unsigned int ctx_size; - int i; + int ret; switch (dev_priv->chipset) { default: @@ -116,18 +116,17 @@ int nv30_graph_create_context(drm_device_t *dev, int channel) break; } - /* Alloc and clear RAMIN to store the context */ - chan->ramin_grctx = nouveau_instmem_alloc(dev, ctx_size, 4); - if (!chan->ramin_grctx) - return DRM_ERR(ENOMEM); - for (i=0; iramin_grctx, i/4, 0x00000000); + if ((ret = nouveau_gpuobj_new_ref(dev, channel, -1, 0, ctx_size, 16, + NVOBJ_FLAG_ZERO_ALLOC, + &chan->ramin_grctx))) + return ret; /* Initialise default context values */ - ctx_init(dev, chan->ramin_grctx); + ctx_init(dev, chan->ramin_grctx->gpuobj); - INSTANCE_WR(chan->ramin_grctx, 10, channel << 24); /* CTX_USER */ - INSTANCE_WR(dev_priv->ctx_table, channel, nouveau_chip_instance_get(dev, chan->ramin_grctx)); + INSTANCE_WR(chan->ramin_grctx->gpuobj, 10, channel<<24); /* CTX_USER */ + INSTANCE_WR(dev_priv->ctx_table->gpuobj, channel, + chan->ramin_grctx->instance >> 4); return 0; } @@ -138,12 +137,10 @@ void nv30_graph_destroy_context(drm_device_t *dev, int channel) (drm_nouveau_private_t *)dev->dev_private; struct nouveau_fifo *chan = &dev_priv->fifos[channel]; - if (chan->ramin_grctx) { - nouveau_instmem_free(dev, chan->ramin_grctx); - chan->ramin_grctx = NULL; - } + if (chan->ramin_grctx) + nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx); - INSTANCE_WR(dev_priv->ctx_table, channel, 0); + INSTANCE_WR(dev_priv->ctx_table->gpuobj, channel, 0); } static int @@ -172,7 +169,7 @@ int nv30_graph_load_context(drm_device_t *dev, int channel) if (!chan->ramin_grctx) return DRM_ERR(EINVAL); - inst = nouveau_chip_instance_get(dev, chan->ramin_grctx); + inst = chan->ramin_grctx->instance >> 4; NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_POINTER, inst); NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_XFER, @@ -189,7 +186,7 @@ int nv30_graph_save_context(drm_device_t *dev, int channel) if (!chan->ramin_grctx) return DRM_ERR(EINVAL); - inst = nouveau_chip_instance_get(dev, chan->ramin_grctx); + inst = chan->ramin_grctx->instance >> 4; NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_POINTER, inst); NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_XFER, @@ -203,7 +200,7 @@ int nv30_graph_init(drm_device_t *dev) drm_nouveau_private_t *dev_priv = (drm_nouveau_private_t *)dev->dev_private; uint32_t vramsz, tmp; - int i; + int ret, i; NV_WRITE(NV03_PMC_ENABLE, NV_READ(NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH); @@ -212,14 +209,14 @@ int nv30_graph_init(drm_device_t *dev) /* Create Context Pointer Table */ dev_priv->ctx_table_size = 32 * 4; - dev_priv->ctx_table = nouveau_instmem_alloc(dev, dev_priv->ctx_table_size, 4); - if (!dev_priv->ctx_table) - return DRM_ERR(ENOMEM); - - for (i=0; i< dev_priv->ctx_table_size; i+=4) - INSTANCE_WR(dev_priv->ctx_table, i/4, 0x00000000); - - NV_WRITE(NV10_PGRAPH_CHANNEL_CTX_TABLE, nouveau_chip_instance_get(dev, dev_priv->ctx_table)); + if ((ret = nouveau_gpuobj_new_ref(dev, -1, -1, 0, + dev_priv->ctx_table_size, 16, + NVOBJ_FLAG_ZERO_ALLOC, + &dev_priv->ctx_table))) + return ret; + + NV_WRITE(NV10_PGRAPH_CHANNEL_CTX_TABLE, + dev_priv->ctx_table->instance >> 4); NV_WRITE(NV03_PGRAPH_INTR_EN, 0x00000000); NV_WRITE(NV03_PGRAPH_INTR , 0xFFFFFFFF); diff --git a/shared-core/nv40_fifo.c b/shared-core/nv40_fifo.c index 6f25349c..eed3e45b 100644 --- a/shared-core/nv40_fifo.c +++ b/shared-core/nv40_fifo.c @@ -28,8 +28,11 @@ #include "nouveau_drv.h" #include "nouveau_drm.h" -#define RAMFC_WR(offset, val) NV_WI32(fifoctx + NV40_RAMFC_##offset, (val)) -#define RAMFC_RD(offset) NV_RI32(fifoctx + NV40_RAMFC_##offset) + +#define RAMFC_WR(offset,val) INSTANCE_WR(chan->ramfc->gpuobj, \ + NV40_RAMFC_##offset/4, (val)) +#define RAMFC_RD(offset) INSTANCE_RD(chan->ramfc->gpuobj, \ + NV40_RAMFC_##offset/4) #define NV40_RAMFC(c) (dev_priv->ramfc_offset + ((c)*NV40_RAMFC__SIZE)) #define NV40_RAMFC__SIZE 128 @@ -38,21 +41,21 @@ nv40_fifo_create_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; struct nouveau_fifo *chan = &dev_priv->fifos[channel]; - uint32_t fifoctx = NV40_RAMFC(channel), grctx, pushbuf; - int i; - - for (i = 0; i < NV40_RAMFC__SIZE; i+=4) - NV_WI32(fifoctx + i, 0); + int ret; - grctx = nouveau_chip_instance_get(dev, chan->ramin_grctx); - pushbuf = nouveau_chip_instance_get(dev, chan->cmdbuf_obj->instance); + if ((ret = nouveau_gpuobj_new_fake(dev, NV40_RAMFC(channel), + NV40_RAMFC__SIZE, + NVOBJ_FLAG_ZERO_ALLOC | + NVOBJ_FLAG_ZERO_FREE, + NULL, &chan->ramfc))) + return ret; /* Fill entries that are seen filled in dumps of nvidia driver just * after channel's is put into DMA mode */ RAMFC_WR(DMA_PUT , chan->pushbuf_base); RAMFC_WR(DMA_GET , chan->pushbuf_base); - RAMFC_WR(DMA_INSTANCE , pushbuf); + RAMFC_WR(DMA_INSTANCE , chan->pushbuf->instance >> 4); RAMFC_WR(DMA_FETCH , NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 | @@ -61,7 +64,7 @@ nv40_fifo_create_context(drm_device_t *dev, int channel) #endif 0x30000000 /* no idea.. */); RAMFC_WR(DMA_SUBROUTINE, 0); - RAMFC_WR(GRCTX_INSTANCE, grctx); + RAMFC_WR(GRCTX_INSTANCE, chan->ramin_grctx->instance >> 4); RAMFC_WR(DMA_TIMESLICE , 0x0001FFFF); return 0; @@ -71,18 +74,17 @@ void nv40_fifo_destroy_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - uint32_t fifoctx = NV40_RAMFC(channel); - int i; + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; - for (i = 0; i < NV40_RAMFC__SIZE; i+=4) - NV_WI32(fifoctx + i, 0); + if (chan->ramfc) + nouveau_gpuobj_ref_del(dev, &chan->ramfc); } int nv40_fifo_load_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - uint32_t fifoctx = NV40_RAMFC(channel); + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; uint32_t tmp, tmp2; NV_WRITE(NV04_PFIFO_CACHE1_DMA_GET , RAMFC_RD(DMA_GET)); @@ -141,7 +143,7 @@ int nv40_fifo_save_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - uint32_t fifoctx = NV40_RAMFC(channel); + struct nouveau_fifo *chan = &dev_priv->fifos[channel]; uint32_t tmp; RAMFC_WR(DMA_PUT , NV_READ(NV04_PFIFO_CACHE1_DMA_PUT)); diff --git a/shared-core/nv40_graph.c b/shared-core/nv40_graph.c index 6fb575db..3f33cee6 100644 --- a/shared-core/nv40_graph.c +++ b/shared-core/nv40_graph.c @@ -47,13 +47,13 @@ * created. */ static void -nv40_graph_context_init(drm_device_t *dev, struct mem_block *ctx) +nv40_graph_context_init(drm_device_t *dev, nouveau_gpuobj_t *ctx) { drm_nouveau_private_t *dev_priv = dev->dev_private; int i; /* Always has the "instance address" of itself at offset 0 */ - INSTANCE_WR(ctx, 0x00000/4, nouveau_chip_instance_get(dev, ctx)); + INSTANCE_WR(ctx, 0x00000/4, ctx->im_pramin->start); /* unknown */ INSTANCE_WR(ctx, 0x00024/4, 0x0000ffff); INSTANCE_WR(ctx, 0x00028/4, 0x0000ffff); @@ -188,12 +188,12 @@ nv40_graph_context_init(drm_device_t *dev, struct mem_block *ctx) } static void -nv43_graph_context_init(drm_device_t *dev, struct mem_block *ctx) +nv43_graph_context_init(drm_device_t *dev, nouveau_gpuobj_t *ctx) { drm_nouveau_private_t *dev_priv = dev->dev_private; int i; - INSTANCE_WR(ctx, 0x00000/4, nouveau_chip_instance_get(dev, ctx)); + INSTANCE_WR(ctx, 0x00000/4, ctx->im_pramin->start); INSTANCE_WR(ctx, 0x00024/4, 0x0000ffff); INSTANCE_WR(ctx, 0x00028/4, 0x0000ffff); INSTANCE_WR(ctx, 0x00030/4, 0x00000001); @@ -304,12 +304,12 @@ nv43_graph_context_init(drm_device_t *dev, struct mem_block *ctx) }; static void -nv46_graph_context_init(drm_device_t *dev, struct mem_block *ctx) +nv46_graph_context_init(drm_device_t *dev, nouveau_gpuobj_t *ctx) { drm_nouveau_private_t *dev_priv = dev->dev_private; int i; - INSTANCE_WR(ctx, 0x00000/4, nouveau_chip_instance_get(dev, ctx)); + INSTANCE_WR(ctx, 0x00000/4, ctx->im_pramin->start); INSTANCE_WR(ctx, 0x00040/4, 0x0000ffff); INSTANCE_WR(ctx, 0x00044/4, 0x0000ffff); INSTANCE_WR(ctx, 0x0004c/4, 0x00000001); @@ -455,12 +455,12 @@ nv46_graph_context_init(drm_device_t *dev, struct mem_block *ctx) } static void -nv49_graph_context_init(drm_device_t *dev, struct mem_block *ctx) +nv49_graph_context_init(drm_device_t *dev, nouveau_gpuobj_t *ctx) { drm_nouveau_private_t *dev_priv = dev->dev_private; int i; - INSTANCE_WR(ctx, 0x00000/4, nouveau_chip_instance_get(dev, ctx)); + INSTANCE_WR(ctx, 0x00000/4, ctx->im_pramin->start); INSTANCE_WR(ctx, 0x00004/4, 0x0000c040); INSTANCE_WR(ctx, 0x00008/4, 0x0000c040); INSTANCE_WR(ctx, 0x0000c/4, 0x0000c040); @@ -678,12 +678,12 @@ nv49_graph_context_init(drm_device_t *dev, struct mem_block *ctx) } static void -nv4a_graph_context_init(drm_device_t *dev, struct mem_block *ctx) +nv4a_graph_context_init(drm_device_t *dev, nouveau_gpuobj_t *ctx) { drm_nouveau_private_t *dev_priv = dev->dev_private; int i; - INSTANCE_WR(ctx, 0x00000/4, nouveau_chip_instance_get(dev, ctx)); + INSTANCE_WR(ctx, 0x00000/4, ctx->im_pramin->start); INSTANCE_WR(ctx, 0x00024/4, 0x0000ffff); INSTANCE_WR(ctx, 0x00028/4, 0x0000ffff); INSTANCE_WR(ctx, 0x00030/4, 0x00000001); @@ -795,12 +795,12 @@ nv4a_graph_context_init(drm_device_t *dev, struct mem_block *ctx) } static void -nv4b_graph_context_init(drm_device_t *dev, struct mem_block *ctx) +nv4b_graph_context_init(drm_device_t *dev, nouveau_gpuobj_t *ctx) { drm_nouveau_private_t *dev_priv = dev->dev_private; int i; - INSTANCE_WR(ctx, 0x00000/4, nouveau_chip_instance_get(dev, ctx)); + INSTANCE_WR(ctx, 0x00000/4, ctx->im_pramin->start); INSTANCE_WR(ctx, 0x00004/4, 0x0000c040); INSTANCE_WR(ctx, 0x00008/4, 0x0000c040); INSTANCE_WR(ctx, 0x0000c/4, 0x0000c040); @@ -1010,12 +1010,12 @@ nv4b_graph_context_init(drm_device_t *dev, struct mem_block *ctx) } static void -nv4c_graph_context_init(drm_device_t *dev, struct mem_block *ctx) +nv4c_graph_context_init(drm_device_t *dev, nouveau_gpuobj_t *ctx) { drm_nouveau_private_t *dev_priv = dev->dev_private; int i; - INSTANCE_WR(ctx, 0x00000/4, nouveau_chip_instance_get(dev, ctx)); + INSTANCE_WR(ctx, 0x00000/4, ctx->im_pramin->start); INSTANCE_WR(ctx, 0x00024/4, 0x0000ffff); INSTANCE_WR(ctx, 0x00028/4, 0x0000ffff); INSTANCE_WR(ctx, 0x00030/4, 0x00000001); @@ -1117,12 +1117,12 @@ nv4c_graph_context_init(drm_device_t *dev, struct mem_block *ctx) } static void -nv4e_graph_context_init(drm_device_t *dev, struct mem_block *ctx) +nv4e_graph_context_init(drm_device_t *dev, nouveau_gpuobj_t *ctx) { drm_nouveau_private_t *dev_priv = dev->dev_private; int i; - INSTANCE_WR(ctx, 0x00000/4, nouveau_chip_instance_get(dev, ctx)); + INSTANCE_WR(ctx, 0x00000/4, ctx->im_pramin->start); INSTANCE_WR(ctx, 0x00024/4, 0x0000ffff); INSTANCE_WR(ctx, 0x00028/4, 0x0000ffff); INSTANCE_WR(ctx, 0x00030/4, 0x00000001); @@ -1229,9 +1229,9 @@ nv40_graph_create_context(drm_device_t *dev, int channel) drm_nouveau_private_t *dev_priv = (drm_nouveau_private_t *)dev->dev_private; struct nouveau_fifo *chan = &dev_priv->fifos[channel]; - void (*ctx_init)(drm_device_t *, struct mem_block *); + void (*ctx_init)(drm_device_t *, nouveau_gpuobj_t *); unsigned int ctx_size; - int i; + int ret; switch (dev_priv->chipset) { case 0x40: @@ -1272,15 +1272,13 @@ nv40_graph_create_context(drm_device_t *dev, int channel) break; } - /* Alloc and clear RAMIN to store the context */ - chan->ramin_grctx = nouveau_instmem_alloc(dev, ctx_size, 4); - if (!chan->ramin_grctx) - return DRM_ERR(ENOMEM); - for (i=0; iramin_grctx, i/4, 0x00000000); + if ((ret = nouveau_gpuobj_new_ref(dev, channel, -1, 0, ctx_size, 16, + NVOBJ_FLAG_ZERO_ALLOC, + &chan->ramin_grctx))) + return ret; /* Initialise default context values */ - ctx_init(dev, chan->ramin_grctx); + ctx_init(dev, chan->ramin_grctx->gpuobj); return 0; } @@ -1291,10 +1289,8 @@ nv40_graph_destroy_context(drm_device_t *dev, int channel) drm_nouveau_private_t *dev_priv = dev->dev_private; struct nouveau_fifo *chan = &dev_priv->fifos[channel]; - if (chan->ramin_grctx) { - nouveau_instmem_free(dev, chan->ramin_grctx); - chan->ramin_grctx = NULL; - } + if (chan->ramin_grctx) + nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx); } static int @@ -1339,7 +1335,7 @@ nv40_graph_save_context(drm_device_t *dev, int channel) if (!chan->ramin_grctx) return DRM_ERR(EINVAL); - inst = nouveau_chip_instance_get(dev, chan->ramin_grctx); + inst = chan->ramin_grctx->instance >> 4; return nv40_graph_transfer_context(dev, inst, 1); } @@ -1357,7 +1353,7 @@ nv40_graph_load_context(drm_device_t *dev, int channel) if (!chan->ramin_grctx) return DRM_ERR(EINVAL); - inst = nouveau_chip_instance_get(dev, chan->ramin_grctx); + inst = chan->ramin_grctx->instance >> 4; ret = nv40_graph_transfer_context(dev, inst, 0); if (ret) -- cgit v1.2.3 From 3324342e42b78aef8e90e11273776dd2b3b92074 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 4 Jul 2007 15:31:01 +1000 Subject: nouveau: enable reporting for all PFIFO/PGRAPH irqs --- shared-core/nouveau_irq.c | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/shared-core/nouveau_irq.c b/shared-core/nouveau_irq.c index 8de6e705..72b12e0c 100644 --- a/shared-core/nouveau_irq.c +++ b/shared-core/nouveau_irq.c @@ -87,34 +87,14 @@ void nouveau_irq_postinstall(drm_device_t *dev) DRM_DEBUG("IRQ: postinst\n"); /* Enable PFIFO error reporting */ - NV_WRITE(NV03_PFIFO_INTR_EN_0 , - NV_PFIFO_INTR_CACHE_ERROR | - NV_PFIFO_INTR_RUNOUT | - NV_PFIFO_INTR_RUNOUT_OVERFLOW | - NV_PFIFO_INTR_DMA_PUSHER | - NV_PFIFO_INTR_DMA_PT | - NV_PFIFO_INTR_SEMAPHORE | - NV_PFIFO_INTR_ACQUIRE_TIMEOUT - ); + NV_WRITE(NV03_PFIFO_INTR_EN_0, 0xFFFFFFFF); NV_WRITE(NV03_PFIFO_INTR_0, 0xFFFFFFFF); /* Enable PGRAPH interrupts */ if (dev_priv->card_type Date: Thu, 5 Jul 2007 00:12:33 +1000 Subject: nouveau/nv50: Initial channel/object support Should be OK on G84 for a single channel, multiple channels *almost* work. Untested on G80. --- linux-core/Makefile.kernel | 3 +- linux-core/nv04_instmem.c | 1 + linux-core/nv50_instmem.c | 1 + shared-core/nouveau_drv.h | 46 ++++++-- shared-core/nouveau_fifo.c | 99 +++++++++------- shared-core/nouveau_irq.c | 15 ++- shared-core/nouveau_mem.c | 143 +--------------------- shared-core/nouveau_notifier.c | 6 +- shared-core/nouveau_object.c | 70 ++++++----- shared-core/nouveau_reg.h | 12 +- shared-core/nouveau_state.c | 41 ++++++- shared-core/nv04_fifo.c | 13 +- shared-core/nv04_graph.c | 10 +- shared-core/nv04_instmem.c | 165 ++++++++++++++++++++++++++ shared-core/nv10_fifo.c | 12 +- shared-core/nv10_graph.c | 8 +- shared-core/nv20_graph.c | 8 +- shared-core/nv30_graph.c | 8 +- shared-core/nv40_fifo.c | 12 +- shared-core/nv40_graph.c | 8 +- shared-core/nv50_fifo.c | 259 +++++++++++++++++++++++++++++++++++++++- shared-core/nv50_graph.c | 231 ++++++++++++++++++++++++++++++++++-- shared-core/nv50_instmem.c | 262 +++++++++++++++++++++++++++++++++++++++++ 23 files changed, 1156 insertions(+), 277 deletions(-) create mode 120000 linux-core/nv04_instmem.c create mode 120000 linux-core/nv50_instmem.c create mode 100644 shared-core/nv04_instmem.c create mode 100644 shared-core/nv50_instmem.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 478c4df0..be2641c8 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -27,7 +27,8 @@ nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ nv04_fb.o nv10_fb.o nv40_fb.o \ nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o \ nv04_graph.o nv10_graph.o nv20_graph.o nv30_graph.o \ - nv40_graph.o nv50_graph.o + nv40_graph.o nv50_graph.o \ + nv04_instmem.o nv50_instmem.o radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o sis-objs := sis_drv.o sis_mm.o ffb-objs := ffb_drv.o ffb_context.o diff --git a/linux-core/nv04_instmem.c b/linux-core/nv04_instmem.c new file mode 120000 index 00000000..e720fb5b --- /dev/null +++ b/linux-core/nv04_instmem.c @@ -0,0 +1 @@ +../shared-core/nv04_instmem.c \ No newline at end of file diff --git a/linux-core/nv50_instmem.c b/linux-core/nv50_instmem.c new file mode 120000 index 00000000..4e45344a --- /dev/null +++ b/linux-core/nv50_instmem.c @@ -0,0 +1 @@ +../shared-core/nv50_instmem.c \ No newline at end of file diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index 73793b34..81972db5 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -72,6 +72,7 @@ typedef struct nouveau_gpuobj { int im_channel; struct mem_block *im_pramin; struct mem_block *im_backing; + int im_bound; uint32_t flags; int refcount; @@ -92,7 +93,6 @@ typedef struct nouveau_gpuobj_ref { struct nouveau_fifo { - int used; /* owner of this fifo */ DRMFILE filp; /* mapping of the fifo itself */ @@ -101,8 +101,8 @@ struct nouveau_fifo drm_local_map_t *regs; /* DMA push buffer */ - struct mem_block *cmdbuf_mem; nouveau_gpuobj_ref_t *pushbuf; + struct mem_block *pushbuf_mem; uint32_t pushbuf_base; /* Notifier memory */ @@ -132,6 +132,19 @@ struct nouveau_config { }; typedef struct nouveau_engine_func { + struct { + void *priv; + + int (*init)(drm_device_t *dev); + void (*takedown)(drm_device_t *dev); + + int (*populate)(drm_device_t *, nouveau_gpuobj_t *, + uint32_t *size); + void (*clear)(drm_device_t *, nouveau_gpuobj_t *); + int (*bind)(drm_device_t *, nouveau_gpuobj_t *); + int (*unbind)(drm_device_t *, nouveau_gpuobj_t *); + } instmem; + struct { int (*init)(drm_device_t *dev); void (*takedown)(drm_device_t *dev); @@ -158,6 +171,8 @@ typedef struct nouveau_engine_func { } graph; struct { + void *priv; + int (*init)(drm_device_t *); void (*takedown)(drm_device_t *); @@ -180,13 +195,13 @@ typedef struct drm_nouveau_private { drm_local_map_t *ramin; /* NV40 onwards */ int fifo_alloc_count; - struct nouveau_fifo fifos[NV_MAX_FIFO_NUMBER]; + struct nouveau_fifo *fifos[NV_MAX_FIFO_NUMBER]; struct nouveau_engine_func Engine; /* RAMIN configuration, RAMFC, RAMHT and RAMRO offsets */ nouveau_gpuobj_t *ramht; - uint32_t ramin_size; + uint32_t ramin_rsvd_vram; uint32_t ramht_offset; uint32_t ramht_size; uint32_t ramht_bits; @@ -246,11 +261,6 @@ extern struct mem_block* nouveau_mem_alloc(struct drm_device *dev, int alignment extern void nouveau_mem_free(struct drm_device* dev, struct mem_block*); extern int nouveau_mem_init(struct drm_device *dev); extern void nouveau_mem_close(struct drm_device *dev); -extern int nouveau_instmem_init(struct drm_device *dev); -extern struct mem_block* nouveau_instmem_alloc(struct drm_device *dev, - uint32_t size, uint32_t align); -extern void nouveau_instmem_free(struct drm_device *dev, - struct mem_block *block); /* nouveau_notifier.c */ extern int nouveau_notifier_init_channel(drm_device_t *, int channel, DRMFILE); @@ -386,6 +396,24 @@ extern void nv50_graph_destroy_context(drm_device_t *, int channel); extern int nv50_graph_load_context(drm_device_t *, int channel); extern int nv50_graph_save_context(drm_device_t *, int channel); +/* nv04_instmem.c */ +extern int nv04_instmem_init(drm_device_t *dev); +extern void nv04_instmem_takedown(drm_device_t *dev); +extern int nv04_instmem_populate(drm_device_t*, nouveau_gpuobj_t*, + uint32_t *size); +extern void nv04_instmem_clear(drm_device_t*, nouveau_gpuobj_t*); +extern int nv04_instmem_bind(drm_device_t*, nouveau_gpuobj_t*); +extern int nv04_instmem_unbind(drm_device_t*, nouveau_gpuobj_t*); + +/* nv50_instmem.c */ +extern int nv50_instmem_init(drm_device_t *dev); +extern void nv50_instmem_takedown(drm_device_t *dev); +extern int nv50_instmem_populate(drm_device_t*, nouveau_gpuobj_t*, + uint32_t *size); +extern void nv50_instmem_clear(drm_device_t*, nouveau_gpuobj_t*); +extern int nv50_instmem_bind(drm_device_t*, nouveau_gpuobj_t*); +extern int nv50_instmem_unbind(drm_device_t*, nouveau_gpuobj_t*); + /* nv04_mc.c */ extern int nv04_mc_init(drm_device_t *dev); extern void nv04_mc_takedown(drm_device_t *dev); diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c index 9f916307..c140a634 100644 --- a/shared-core/nouveau_fifo.c +++ b/shared-core/nouveau_fifo.c @@ -39,6 +39,8 @@ int nouveau_fifo_number(drm_device_t* dev) case NV_04: case NV_05: return 16; + case NV_50: + return 128; default: return 32; } @@ -186,7 +188,7 @@ static int nouveau_fifo_cmdbuf_alloc(struct drm_device *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; struct nouveau_config *config = &dev_priv->config; struct mem_block *cb; int cb_min_size = max(NV03_FIFO_SIZE,PAGE_SIZE); @@ -242,8 +244,8 @@ nouveau_fifo_cmdbuf_alloc(struct drm_device *dev, int channel) return ret; } - dev_priv->fifos[channel].pushbuf_base = 0; - dev_priv->fifos[channel].cmdbuf_mem = cb; + dev_priv->fifos[channel]->pushbuf_base = 0; + dev_priv->fifos[channel]->pushbuf_mem = cb; return 0; } @@ -265,22 +267,27 @@ int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp, * (woo, full userspace command submission !) * When there are no more contexts, you lost */ - for(channel=0; channelfifos[channel].used==0) + for(channel=0; channelcard_type == NV_50) && (channel == 0)) + continue; + if (dev_priv->fifos[channel] == NULL) break; + } /* no more fifos. you lost. */ if (channel==nouveau_fifo_number(dev)) return DRM_ERR(EINVAL); (*chan_ret) = channel; - chan = &dev_priv->fifos[channel]; - memset(chan, sizeof(*chan), 0); - - DRM_INFO("Allocating FIFO number %d\n", channel); - /* that fifo is used */ - chan->used = 1; + dev_priv->fifos[channel] = drm_calloc(1, sizeof(struct nouveau_fifo), + DRM_MEM_DRIVER); + if (!dev_priv->fifos[channel]) + return DRM_ERR(ENOMEM); + dev_priv->fifo_alloc_count++; + chan = dev_priv->fifos[channel]; chan->filp = filp; + DRM_INFO("Allocating FIFO number %d\n", channel); + /* Setup channel's default objects */ ret = nouveau_gpuobj_channel_init(dev, channel, vram_handle, tt_handle); if (ret) { @@ -324,17 +331,19 @@ int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp, return ret; } - /* enable the fifo dma operation */ - NV_WRITE(NV04_PFIFO_MODE,NV_READ(NV04_PFIFO_MODE)|(1<pushbuf_base); - NV_WRITE(NV03_FIFO_REGS_DMAGET(channel), chan->pushbuf_base); + if (dev_priv->card_type < NV_50) { + NV_WRITE(NV03_FIFO_REGS_DMAPUT(channel), chan->pushbuf_base); + NV_WRITE(NV03_FIFO_REGS_DMAGET(channel), chan->pushbuf_base); + } else { + NV_WRITE(NV50_FIFO_REGS_DMAPUT(channel), chan->pushbuf_base); + NV_WRITE(NV50_FIFO_REGS_DMAGET(channel), chan->pushbuf_base); + } /* If this is the first channel, setup PFIFO ourselves. For any * other case, the GPU will handle this when it switches contexts. */ - if (dev_priv->fifo_alloc_count == 0) { + if (dev_priv->fifo_alloc_count == 1) { ret = engine->fifo.load_context(dev, channel); if (ret) { nouveau_fifo_free(dev, channel); @@ -352,7 +361,7 @@ int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp, * set. Proper fix would be to find which object+method is * responsible for modifying this state. */ - if (dev_priv->chipset >= 0x10) { + if (dev_priv->chipset >= 0x10 && dev_priv->chipset < 0x50) { uint32_t tmp; tmp = NV_READ(NV10_PGRAPH_SURFACE) & 0x0007ff00; NV_WRITE(NV10_PGRAPH_SURFACE, tmp); @@ -361,15 +370,14 @@ int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp, } } - NV_WRITE(NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001); + NV_WRITE(NV04_PFIFO_CACHE1_DMA_PUSH, + NV_READ(NV04_PFIFO_CACHE1_DMA_PUSH) | 1); NV_WRITE(NV03_PFIFO_CACHE1_PUSH0, 0x00000001); NV_WRITE(NV04_PFIFO_CACHE1_PULL0, 0x00000001); NV_WRITE(NV04_PFIFO_CACHE1_PULL1, 0x00000001); /* reenable the fifo caches */ - NV_WRITE(NV03_PFIFO_CACHES, 0x00000001); - - dev_priv->fifo_alloc_count++; + NV_WRITE(NV03_PFIFO_CACHES, 1); DRM_INFO("%s: initialised FIFO %d\n", __func__, channel); return 0; @@ -380,17 +388,20 @@ void nouveau_fifo_free(drm_device_t* dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; nouveau_engine_func_t *engine = &dev_priv->Engine; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; + + if (!chan) { + DRM_ERROR("Freeing non-existant channel %d\n", channel); + return; + } - chan->used = 0; DRM_INFO("%s: freeing fifo %d\n", __func__, channel); /* disable the fifo caches */ NV_WRITE(NV03_PFIFO_CACHES, 0x00000000); - NV_WRITE(NV04_PFIFO_MODE, NV_READ(NV04_PFIFO_MODE)&~(1<fifo.destroy_context(dev, channel); /* Cleanup PGRAPH state */ @@ -399,13 +410,11 @@ void nouveau_fifo_free(drm_device_t* dev, int channel) /* reenable the fifo caches */ NV_WRITE(NV03_PFIFO_CACHES, 0x00000001); - /* Deallocate command buffer */ - if (chan->pushbuf) - nouveau_gpuobj_ref_del(dev, &chan->pushbuf); - - if (chan->cmdbuf_mem) { - nouveau_mem_free(dev, chan->cmdbuf_mem); - chan->cmdbuf_mem = NULL; + /* Deallocate push buffer */ + nouveau_gpuobj_ref_del(dev, &chan->pushbuf); + if (chan->pushbuf_mem) { + nouveau_mem_free(dev, chan->pushbuf_mem); + chan->pushbuf_mem = NULL; } nouveau_notifier_takedown_channel(dev, channel); @@ -413,7 +422,9 @@ void nouveau_fifo_free(drm_device_t* dev, int channel) /* Destroy objects belonging to the channel */ nouveau_gpuobj_channel_takedown(dev, channel); + dev_priv->fifos[channel] = NULL; dev_priv->fifo_alloc_count--; + drm_free(chan, sizeof(*chan), DRM_MEM_DRIVER); } /* cleanups all the fifos from filp */ @@ -424,7 +435,7 @@ void nouveau_fifo_cleanup(drm_device_t* dev, DRMFILE filp) DRM_DEBUG("clearing FIFO enables from filp\n"); for(i=0;ififos[i].used && dev_priv->fifos[i].filp==filp) + if (dev_priv->fifos[i] && dev_priv->fifos[i]->filp==filp) nouveau_fifo_free(dev,i); } @@ -435,9 +446,9 @@ nouveau_fifo_owner(drm_device_t *dev, DRMFILE filp, int channel) if (channel >= nouveau_fifo_number(dev)) return 0; - if (dev_priv->fifos[channel].used == 0) + if (dev_priv->fifos[channel] == NULL) return 0; - return (dev_priv->fifos[channel].filp == filp); + return (dev_priv->fifos[channel]->filp == filp); } /*********************************** @@ -460,22 +471,28 @@ static int nouveau_ioctl_fifo_alloc(DRM_IOCTL_ARGS) init.tt_ctxdma_handle); if (res) return res; - chan = &dev_priv->fifos[init.channel]; + chan = dev_priv->fifos[init.channel]; init.put_base = chan->pushbuf_base; /* make the fifo available to user space */ /* first, the fifo control regs */ - init.ctrl = dev_priv->mmio->offset + NV03_FIFO_REGS(init.channel); - init.ctrl_size = NV03_FIFO_REGS_SIZE; + init.ctrl = dev_priv->mmio->offset; + if (dev_priv->card_type < NV_50) { + init.ctrl += NV03_FIFO_REGS(init.channel); + init.ctrl_size = NV03_FIFO_REGS_SIZE; + } else { + init.ctrl += NV50_FIFO_REGS(init.channel); + init.ctrl_size = NV50_FIFO_REGS_SIZE; + } res = drm_addmap(dev, init.ctrl, init.ctrl_size, _DRM_REGISTERS, 0, &chan->regs); if (res != 0) return res; /* pass back FIFO map info to the caller */ - init.cmdbuf = chan->cmdbuf_mem->start; - init.cmdbuf_size = chan->cmdbuf_mem->size; + init.cmdbuf = chan->pushbuf_mem->start; + init.cmdbuf_size = chan->pushbuf_mem->size; /* and the notifier block */ init.notifier = chan->notifier_block->start; diff --git a/shared-core/nouveau_irq.c b/shared-core/nouveau_irq.c index 72b12e0c..b4102dd8 100644 --- a/shared-core/nouveau_irq.c +++ b/shared-core/nouveau_irq.c @@ -251,22 +251,25 @@ nouveau_graph_dump_trap_info(drm_device_t *dev) { drm_nouveau_private_t *dev_priv = dev->dev_private; uint32_t address; - uint32_t channel; + uint32_t channel, class; uint32_t method, subc, data; address = NV_READ(0x400704); - data = NV_READ(0x400708); channel = (address >> 20) & 0x1F; subc = (address >> 16) & 0x7; method = address & 0x1FFC; + data = NV_READ(0x400708); + if (dev_priv->card_type < NV_50) { + class = NV_READ(0x400160 + subc*4) & 0xFFFF; + } else { + class = NV_READ(0x400814); + } DRM_ERROR("NV: nSource: 0x%08x, nStatus: 0x%08x\n", NV_READ(0x400108), NV_READ(0x400104)); DRM_ERROR("NV: Channel %d/%d (class 0x%04x) -" "Method 0x%04x, Data 0x%08x\n", - channel, subc, - NV_READ(0x400160+subc*4) & 0xFFFF, - method, data + channel, subc, class, method, data ); } @@ -294,7 +297,7 @@ static void nouveau_pgraph_irq_handler(drm_device_t *dev) instance = NV_READ(0x00400158); notify = NV_READ(0x00400150) >> 16; DRM_DEBUG("instance:0x%08x\tnotify:0x%08x\n", - nsource, nstatus); + instance, notify); } status &= ~NV_PGRAPH_INTR_NOTIFY; diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index 49041862..c75a9356 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -353,7 +353,7 @@ no_agp: /* On at least NV40, RAMIN is actually at the end of vram. * We don't want to allocate this... */ if (dev_priv->card_type >= NV_40) - fb_size -= dev_priv->ramin_size; + fb_size -= dev_priv->ramin_rsvd_vram; dev_priv->fb_available_size = fb_size; DRM_DEBUG("Available VRAM: %dKiB\n", fb_size>>10); @@ -463,147 +463,6 @@ void nouveau_mem_free(struct drm_device* dev, struct mem_block* block) nouveau_mem_free_block(block); } -static void -nouveau_instmem_determine_amount(struct drm_device *dev) -{ - drm_nouveau_private_t *dev_priv = dev->dev_private; - int i; - - /* Figure out how much instance memory we need */ - switch (dev_priv->card_type) { - case NV_40: - /* We'll want more instance memory than this on some NV4x cards. - * There's a 16MB aperture to play with that maps onto the end - * of vram. For now, only reserve a small piece until we know - * more about what each chipset requires. - */ - dev_priv->ramin_size = (1*1024* 1024); - break; - default: - /*XXX: what *are* the limits on ramin_size = (512*1024); - break; - } - DRM_DEBUG("RAMIN size: %dKiB\n", dev_priv->ramin_size>>10); - - /* Clear all of it, except the BIOS image that's in the first 64KiB */ - for (i=(64*1024); iramin_size; i+=4) - NV_WI32(i, 0x00000000); -} - -static void -nouveau_instmem_configure_fixed_tables(struct drm_device *dev) -{ - drm_nouveau_private_t *dev_priv = dev->dev_private; - - /* FIFO hash table (RAMHT) - * use 4k hash table at RAMIN+0x10000 - * TODO: extend the hash table - */ - dev_priv->ramht_offset = 0x10000; - dev_priv->ramht_bits = 9; - dev_priv->ramht_size = (1 << dev_priv->ramht_bits); - DRM_DEBUG("RAMHT offset=0x%x, size=%d\n", dev_priv->ramht_offset, - dev_priv->ramht_size); - - /* FIFO runout table (RAMRO) - 512k at 0x11200 */ - dev_priv->ramro_offset = 0x11200; - dev_priv->ramro_size = 512; - DRM_DEBUG("RAMRO offset=0x%x, size=%d\n", dev_priv->ramro_offset, - dev_priv->ramro_size); - - /* FIFO context table (RAMFC) - * NV40 : Not sure exactly how to position RAMFC on some cards, - * 0x30002 seems to position it at RAMIN+0x20000 on these - * cards. RAMFC is 4kb (32 fifos, 128byte entries). - * Others: Position RAMFC at RAMIN+0x11400 - */ - switch(dev_priv->card_type) - { - case NV_50: - case NV_40: - case NV_44: - dev_priv->ramfc_offset = 0x20000; - dev_priv->ramfc_size = nouveau_fifo_number(dev) * - nouveau_fifo_ctx_size(dev); - break; - case NV_30: - case NV_20: - case NV_17: - case NV_10: - case NV_04: - case NV_03: - default: - dev_priv->ramfc_offset = 0x11400; - dev_priv->ramfc_size = nouveau_fifo_number(dev) * - nouveau_fifo_ctx_size(dev); - break; - } - DRM_DEBUG("RAMFC offset=0x%x, size=%d\n", dev_priv->ramfc_offset, - dev_priv->ramfc_size); -} - -int nouveau_instmem_init(struct drm_device *dev) -{ - drm_nouveau_private_t *dev_priv = dev->dev_private; - uint32_t offset; - int ret = 0; - - nouveau_instmem_determine_amount(dev); - nouveau_instmem_configure_fixed_tables(dev); - - if ((ret = nouveau_gpuobj_new_fake(dev, dev_priv->ramht_offset, - dev_priv->ramht_size, - NVOBJ_FLAG_ZERO_ALLOC | - NVOBJ_FLAG_ALLOW_NO_REFS, - &dev_priv->ramht, NULL))) - return ret; - - /* Create a heap to manage RAMIN allocations, we don't allocate - * the space that was reserved for RAMHT/FC/RO. - */ - offset = dev_priv->ramfc_offset + dev_priv->ramfc_size; - ret = nouveau_mem_init_heap(&dev_priv->ramin_heap, - offset, dev_priv->ramin_size - offset); - if (ret) { - dev_priv->ramin_heap = NULL; - DRM_ERROR("Failed to init RAMIN heap\n"); - } - - return ret; -} - -struct mem_block *nouveau_instmem_alloc(struct drm_device *dev, - uint32_t size, uint32_t align) -{ - drm_nouveau_private_t *dev_priv = dev->dev_private; - struct mem_block *block; - - if (!dev_priv->ramin_heap) { - DRM_ERROR("instmem alloc called without init\n"); - return NULL; - } - - block = nouveau_mem_alloc_block(dev_priv->ramin_heap, size, align, - (DRMFILE)-2); - if (block) { - block->flags = NOUVEAU_MEM_INSTANCE; - DRM_DEBUG("instance(size=%d, align=%d) alloc'd at 0x%08x\n", - size, (1<start); - } - - return block; -} - -void nouveau_instmem_free(struct drm_device *dev, struct mem_block *block) -{ - if (dev && block) { - nouveau_mem_free_block(block); - } -} - /* * Ioctls */ diff --git a/shared-core/nouveau_notifier.c b/shared-core/nouveau_notifier.c index 4d5e26ab..9e792e57 100644 --- a/shared-core/nouveau_notifier.c +++ b/shared-core/nouveau_notifier.c @@ -33,7 +33,7 @@ int nouveau_notifier_init_channel(drm_device_t *dev, int channel, DRMFILE filp) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; int flags, ret; /*TODO: PCI notifier blocks */ @@ -58,7 +58,7 @@ void nouveau_notifier_takedown_channel(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; if (chan->notifier_block) { nouveau_mem_free(dev, chan->notifier_block); @@ -73,7 +73,7 @@ nouveau_notifier_alloc(drm_device_t *dev, int channel, uint32_t handle, int count, uint32_t *b_offset) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; nouveau_gpuobj_t *nobj = NULL; struct mem_block *mem; uint32_t offset; diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index 79875ca1..a394ae6e 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -76,7 +76,8 @@ nouveau_ramht_hash_handle(drm_device_t *dev, int channel, uint32_t handle) hash ^= (handle & ((1 << dev_priv->ramht_bits) - 1)); handle >>= dev_priv->ramht_bits; } - hash ^= channel << (dev_priv->ramht_bits - 4); + if (dev_priv->card_type < NV_50) + hash ^= channel << (dev_priv->ramht_bits - 4); hash <<= 3; DRM_DEBUG("ch%d handle=0x%08x hash=0x%08x\n", channel, handle, hash); @@ -99,7 +100,7 @@ static int nouveau_ramht_insert(drm_device_t* dev, nouveau_gpuobj_ref_t *ref) { drm_nouveau_private_t *dev_priv=dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[ref->channel]; + struct nouveau_fifo *chan = dev_priv->fifos[ref->channel]; nouveau_gpuobj_t *ramht = chan->ramht ? chan->ramht->gpuobj : NULL; nouveau_gpuobj_t *gpuobj = ref->gpuobj; uint32_t ctx, co, ho; @@ -148,7 +149,7 @@ static void nouveau_ramht_remove(drm_device_t* dev, nouveau_gpuobj_ref_t *ref) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[ref->channel]; + struct nouveau_fifo *chan = dev_priv->fifos[ref->channel]; nouveau_gpuobj_t *ramht = chan->ramht ? chan->ramht->gpuobj : NULL; uint32_t co, ho; @@ -183,9 +184,11 @@ nouveau_gpuobj_new(drm_device_t *dev, int channel, int size, int align, uint32_t flags, nouveau_gpuobj_t **gpuobj_ret) { drm_nouveau_private_t *dev_priv = dev->dev_private; + nouveau_engine_func_t *engine = &dev_priv->Engine; struct nouveau_fifo *chan = NULL; nouveau_gpuobj_t *gpuobj; struct mem_block *pramin = NULL; + int ret; DRM_DEBUG("ch%d size=%d align=%d flags=0x%08x\n", channel, size, align, flags); @@ -196,7 +199,7 @@ nouveau_gpuobj_new(drm_device_t *dev, int channel, int size, int align, if (channel >= 0) { if (channel > nouveau_fifo_number(dev)) return DRM_ERR(EINVAL); - chan = &dev_priv->fifos[channel]; + chan = dev_priv->fifos[channel]; } gpuobj = drm_calloc(1, sizeof(*gpuobj), DRM_MEM_DRIVER); @@ -230,6 +233,11 @@ nouveau_gpuobj_new(drm_device_t *dev, int channel, int size, int align, return DRM_ERR(EINVAL); } + if (!chan && (ret = engine->instmem.populate(dev, gpuobj, &size))) { + nouveau_gpuobj_del(dev, &gpuobj); + return ret; + } + /* Allocate a chunk of the PRAMIN aperture */ gpuobj->im_pramin = nouveau_mem_alloc_block(pramin, size, drm_order(align), @@ -240,14 +248,9 @@ nouveau_gpuobj_new(drm_device_t *dev, int channel, int size, int align, } gpuobj->im_pramin->flags = NOUVEAU_MEM_INSTANCE; - /* On NV50 the PRAMIN aperture is paged. When allocating from the - * global instmem heap, alloc and bind VRAM pages into the PRAMIN - * aperture. - */ - if (!chan && dev_priv->card_type >= NV_50) { - DRM_ERROR("back aperture with vram pages\n"); + if (!chan && (ret = engine->instmem.bind(dev, gpuobj))) { nouveau_gpuobj_del(dev, &gpuobj); - return DRM_ERR(EINVAL); + return ret; } if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) { @@ -285,6 +288,7 @@ void nouveau_gpuobj_takedown(drm_device_t *dev) int nouveau_gpuobj_del(drm_device_t *dev, nouveau_gpuobj_t **pgpuobj) { drm_nouveau_private_t *dev_priv = dev->dev_private; + nouveau_engine_func_t *engine = &dev_priv->Engine; nouveau_gpuobj_t *gpuobj; DRM_DEBUG("gpuobj %p\n", pgpuobj ? *pgpuobj : NULL); @@ -298,6 +302,8 @@ int nouveau_gpuobj_del(drm_device_t *dev, nouveau_gpuobj_t **pgpuobj) return DRM_ERR(EINVAL); } + engine->instmem.clear(dev, gpuobj); + if (gpuobj->im_pramin) { if (gpuobj->flags & NVOBJ_FLAG_FAKE) drm_free(gpuobj->im_pramin, sizeof(*gpuobj->im_pramin), @@ -306,9 +312,6 @@ int nouveau_gpuobj_del(drm_device_t *dev, nouveau_gpuobj_t **pgpuobj) nouveau_mem_free_block(gpuobj->im_pramin); } - if (gpuobj->im_backing) - nouveau_mem_free(dev, gpuobj->im_backing); - if (gpuobj->next) gpuobj->next->prev = gpuobj->prev; if (gpuobj->prev) @@ -342,7 +345,7 @@ nouveau_gpuobj_instance_get(drm_device_t *dev, int channel, /* NV50 channel-local instance */ if (channel > 0) { - cpramin = dev_priv->fifos[channel].ramin->gpuobj; + cpramin = dev_priv->fifos[channel]->ramin->gpuobj; *inst = gpuobj->im_pramin->start - cpramin->im_pramin->start; return 0; } @@ -358,7 +361,7 @@ nouveau_gpuobj_instance_get(drm_device_t *dev, int channel, return 0; } else { /* ...from local heap */ - cpramin = dev_priv->fifos[gpuobj->im_channel].ramin->gpuobj; + cpramin = dev_priv->fifos[gpuobj->im_channel]->ramin->gpuobj; *inst = (cpramin->im_backing->start - dev_priv->fb_phys) + (gpuobj->im_pramin->start - cpramin->im_pramin->start); return 0; @@ -385,7 +388,7 @@ nouveau_gpuobj_ref_add(drm_device_t *dev, int channel, uint32_t handle, if (channel >= 0) { if (channel > nouveau_fifo_number(dev)) return DRM_ERR(EINVAL); - chan = &dev_priv->fifos[channel]; + chan = dev_priv->fifos[channel]; } else if (!ref_ret) return DRM_ERR(EINVAL); @@ -591,9 +594,10 @@ nouveau_gpuobj_dma_new(drm_device_t *dev, int channel, int class, INSTANCE_WR(*gpuobj, 2, frame | pte_flags); INSTANCE_WR(*gpuobj, 3, frame | pte_flags); } else { - nouveau_gpuobj_del(dev, gpuobj); - DRM_ERROR("stub\n"); - return DRM_ERR(EINVAL); + INSTANCE_WR(*gpuobj, 0, 0x00190000 | class); + INSTANCE_WR(*gpuobj, 1, offset + size - 1); + INSTANCE_WR(*gpuobj, 2, offset); + INSTANCE_WR(*gpuobj, 5, 0x00010000); } (*gpuobj)->engine = NVOBJ_ENGINE_SW; @@ -672,11 +676,9 @@ nouveau_gpuobj_gr_new(drm_device_t *dev, int channel, int class, } if (dev_priv->card_type >= NV_50) { - nouveau_gpuobj_del(dev, gpuobj); - DRM_ERROR("stub!\n"); - return DRM_ERR(EINVAL); - } - + INSTANCE_WR(*gpuobj, 0, class); + INSTANCE_WR(*gpuobj, 5, 0x00010000); + } else { switch (class) { case NV_CLASS_NULL: INSTANCE_WR(*gpuobj, 0, 0x00001030); @@ -696,6 +698,7 @@ nouveau_gpuobj_gr_new(drm_device_t *dev, int channel, int class, #endif } } + } (*gpuobj)->engine = NVOBJ_ENGINE_GR; (*gpuobj)->class = class; @@ -706,7 +709,7 @@ static int nouveau_gpuobj_channel_init_pramin(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; nouveau_gpuobj_t *pramin = NULL; int size, base, ret; @@ -719,7 +722,16 @@ nouveau_gpuobj_channel_init_pramin(drm_device_t *dev, int channel) /* PGRAPH context */ if (dev_priv->card_type == NV_50) { - /* RAMHT, RAMFC, PD, funny header thingo */ + /* Various fixed table thingos */ + size += 0x1400; /* mostly unknown stuff */ + size += 0x4000; /* vm pd */ + base = 0x6000; + /* RAMHT, not sure about setting size yet, 32KiB to be safe */ + size += 0x8000; + /* RAMFC */ + size += 0x1000; + /* PGRAPH context */ + size += 0x60000; } DRM_DEBUG("ch%d PRAMIN size: 0x%08x bytes, base alloc=0x%08x\n", @@ -748,7 +760,7 @@ nouveau_gpuobj_channel_init(drm_device_t *dev, int channel, uint32_t vram_h, uint32_t tt_h) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; nouveau_gpuobj_t *vram = NULL, *tt = NULL; int ret; @@ -817,7 +829,7 @@ void nouveau_gpuobj_channel_takedown(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; nouveau_gpuobj_ref_t *ref; DRM_DEBUG("ch%d\n", channel); diff --git a/shared-core/nouveau_reg.h b/shared-core/nouveau_reg.h index 4c013c53..c2ebc714 100644 --- a/shared-core/nouveau_reg.h +++ b/shared-core/nouveau_reg.h @@ -47,11 +47,15 @@ #define NV_CLASS_DMA_IN_MEMORY 0x0000003D #define NV03_FIFO_SIZE 0x8000UL -#define NV_MAX_FIFO_NUMBER 32 +#define NV_MAX_FIFO_NUMBER 128 #define NV03_FIFO_REGS_SIZE 0x10000 #define NV03_FIFO_REGS(i) (0x00800000+i*NV03_FIFO_REGS_SIZE) # define NV03_FIFO_REGS_DMAPUT(i) (NV03_FIFO_REGS(i)+0x40) # define NV03_FIFO_REGS_DMAGET(i) (NV03_FIFO_REGS(i)+0x44) +#define NV50_FIFO_REGS_SIZE 0x2000 +#define NV50_FIFO_REGS(i) (0x00c00000+i*NV50_FIFO_REGS_SIZE) +# define NV50_FIFO_REGS_DMAPUT(i) (NV50_FIFO_REGS(i)+0x40) +# define NV50_FIFO_REGS_DMAGET(i) (NV50_FIFO_REGS(i)+0x44) #define NV03_PMC_BOOT_0 0x00000000 #define NV03_PMC_INTR_0 0x00000100 @@ -332,6 +336,12 @@ #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 diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c index 13bc930a..bcb974bf 100644 --- a/shared-core/nouveau_state.c +++ b/shared-core/nouveau_state.c @@ -95,6 +95,12 @@ static int nouveau_init_engine_ptrs(drm_device_t *dev) switch (dev_priv->chipset & 0xf0) { case 0x00: + engine->instmem.init = nv04_instmem_init; + engine->instmem.takedown= nv04_instmem_takedown; + engine->instmem.populate = nv04_instmem_populate; + engine->instmem.clear = nv04_instmem_clear; + engine->instmem.bind = nv04_instmem_bind; + engine->instmem.unbind = nv04_instmem_unbind; engine->mc.init = nv04_mc_init; engine->mc.takedown = nv04_mc_takedown; engine->timer.init = nv04_timer_init; @@ -115,6 +121,12 @@ static int nouveau_init_engine_ptrs(drm_device_t *dev) engine->fifo.save_context = nv04_fifo_save_context; break; case 0x10: + engine->instmem.init = nv04_instmem_init; + engine->instmem.takedown= nv04_instmem_takedown; + engine->instmem.populate = nv04_instmem_populate; + engine->instmem.clear = nv04_instmem_clear; + engine->instmem.bind = nv04_instmem_bind; + engine->instmem.unbind = nv04_instmem_unbind; engine->mc.init = nv04_mc_init; engine->mc.takedown = nv04_mc_takedown; engine->timer.init = nv04_timer_init; @@ -135,6 +147,12 @@ static int nouveau_init_engine_ptrs(drm_device_t *dev) engine->fifo.save_context = nv10_fifo_save_context; break; case 0x20: + engine->instmem.init = nv04_instmem_init; + engine->instmem.takedown= nv04_instmem_takedown; + engine->instmem.populate = nv04_instmem_populate; + engine->instmem.clear = nv04_instmem_clear; + engine->instmem.bind = nv04_instmem_bind; + engine->instmem.unbind = nv04_instmem_unbind; engine->mc.init = nv04_mc_init; engine->mc.takedown = nv04_mc_takedown; engine->timer.init = nv04_timer_init; @@ -155,6 +173,12 @@ static int nouveau_init_engine_ptrs(drm_device_t *dev) engine->fifo.save_context = nv10_fifo_save_context; break; case 0x30: + engine->instmem.init = nv04_instmem_init; + engine->instmem.takedown= nv04_instmem_takedown; + engine->instmem.populate = nv04_instmem_populate; + engine->instmem.clear = nv04_instmem_clear; + engine->instmem.bind = nv04_instmem_bind; + engine->instmem.unbind = nv04_instmem_unbind; engine->mc.init = nv04_mc_init; engine->mc.takedown = nv04_mc_takedown; engine->timer.init = nv04_timer_init; @@ -175,6 +199,12 @@ static int nouveau_init_engine_ptrs(drm_device_t *dev) engine->fifo.save_context = nv10_fifo_save_context; break; case 0x40: + engine->instmem.init = nv04_instmem_init; + engine->instmem.takedown= nv04_instmem_takedown; + engine->instmem.populate = nv04_instmem_populate; + engine->instmem.clear = nv04_instmem_clear; + engine->instmem.bind = nv04_instmem_bind; + engine->instmem.unbind = nv04_instmem_unbind; engine->mc.init = nv40_mc_init; engine->mc.takedown = nv40_mc_takedown; engine->timer.init = nv04_timer_init; @@ -196,6 +226,12 @@ static int nouveau_init_engine_ptrs(drm_device_t *dev) break; case 0x50: case 0x80: /* gotta love NVIDIA's consistency.. */ + engine->instmem.init = nv50_instmem_init; + engine->instmem.takedown= nv50_instmem_takedown; + engine->instmem.populate = nv50_instmem_populate; + engine->instmem.clear = nv50_instmem_clear; + engine->instmem.bind = nv50_instmem_bind; + engine->instmem.unbind = nv50_instmem_unbind; engine->mc.init = nv50_mc_init; engine->mc.takedown = nv50_mc_takedown; engine->timer.init = nouveau_stub_init; @@ -249,7 +285,7 @@ static int nouveau_card_init(drm_device_t *dev) * know exactly how much VRAM we're able to use for "normal" * purposes. */ - ret = nouveau_instmem_init(dev); + ret = engine->instmem.init(dev); if (ret) return ret; /* Setup the memory manager */ @@ -295,6 +331,7 @@ static void nouveau_card_takedown(drm_device_t *dev) engine->mc.takedown(dev); nouveau_gpuobj_takedown(dev); nouveau_mem_close(dev); + engine->instmem.takedown(dev); } /* here a client dies, release the stuff that was allocated for its filp */ @@ -456,6 +493,8 @@ void nouveau_wait_for_idle(struct drm_device *dev) case NV_03: while(NV_READ(NV03_PGRAPH_STATUS)); break; + case NV_50: + break; default: while(NV_READ(NV04_PGRAPH_STATUS)); break; diff --git a/shared-core/nv04_fifo.c b/shared-core/nv04_fifo.c index b84f74c1..e2e934d7 100644 --- a/shared-core/nv04_fifo.c +++ b/shared-core/nv04_fifo.c @@ -39,7 +39,7 @@ int nv04_fifo_create_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; int ret; if ((ret = nouveau_gpuobj_new_fake(dev, NV04_RAMFC(channel), @@ -60,6 +60,9 @@ nv04_fifo_create_context(drm_device_t *dev, int channel) NV_PFIFO_CACHE1_BIG_ENDIAN | #endif 0)); + + /* enable the fifo dma operation */ + NV_WRITE(NV04_PFIFO_MODE,NV_READ(NV04_PFIFO_MODE)|(1<dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; + + NV_WRITE(NV04_PFIFO_MODE, NV_READ(NV04_PFIFO_MODE)&~(1<ramfc) nouveau_gpuobj_ref_del(dev, &chan->ramfc); @@ -77,7 +82,7 @@ int nv04_fifo_load_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; uint32_t tmp; NV_WRITE(NV03_PFIFO_CACHE1_PUSH1, (1<<8) | channel); @@ -105,7 +110,7 @@ int nv04_fifo_save_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; uint32_t tmp; RAMFC_WR(DMA_PUT, NV04_PFIFO_CACHE1_DMA_PUT); diff --git a/shared-core/nv04_graph.c b/shared-core/nv04_graph.c index 1aaae33c..df23d279 100644 --- a/shared-core/nv04_graph.c +++ b/shared-core/nv04_graph.c @@ -309,7 +309,7 @@ void nouveau_nv04_context_switch(drm_device_t *dev) for (i = 0; ififos[channel_old].pgraph_ctx[index] = NV_READ(nv04_graph_ctx_regs[i].reg+j*4); + dev_priv->fifos[channel_old]->pgraph_ctx[index] = NV_READ(nv04_graph_ctx_regs[i].reg+j*4); index++; } @@ -321,7 +321,7 @@ void nouveau_nv04_context_switch(drm_device_t *dev) for (i = 0; ififos[channel].pgraph_ctx[index]); + NV_WRITE(nv04_graph_ctx_regs[i].reg+j*4, dev_priv->fifos[channel]->pgraph_ctx[index]); index++; } @@ -340,10 +340,10 @@ int nv04_graph_create_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; DRM_DEBUG("nv04_graph_context_create %d\n", channel); - memset(dev_priv->fifos[channel].pgraph_ctx, 0, sizeof(dev_priv->fifos[channel].pgraph_ctx)); + memset(dev_priv->fifos[channel]->pgraph_ctx, 0, sizeof(dev_priv->fifos[channel]->pgraph_ctx)); //dev_priv->fifos[channel].pgraph_ctx_user = channel << 24; - dev_priv->fifos[channel].pgraph_ctx[0] = 0x0001ffff; + dev_priv->fifos[channel]->pgraph_ctx[0] = 0x0001ffff; /* is it really needed ??? */ //dev_priv->fifos[channel].pgraph_ctx[1] = NV_READ(NV_PGRAPH_DEBUG_4); //dev_priv->fifos[channel].pgraph_ctx[2] = NV_READ(0x004006b0); @@ -379,7 +379,7 @@ int nv04_graph_init(drm_device_t *dev) { // check the context is big enough for ( i = 0 ; isizeof(dev_priv->fifos[0].pgraph_ctx) ) + if ( sum*4>sizeof(dev_priv->fifos[0]->pgraph_ctx) ) DRM_ERROR("pgraph_ctx too small\n"); NV_WRITE(NV03_PGRAPH_INTR_EN, 0x00000000); diff --git a/shared-core/nv04_instmem.c b/shared-core/nv04_instmem.c new file mode 100644 index 00000000..ac7d4347 --- /dev/null +++ b/shared-core/nv04_instmem.c @@ -0,0 +1,165 @@ +#include "drmP.h" +#include "drm.h" +#include "nouveau_drv.h" + +static void +nv04_instmem_determine_amount(struct drm_device *dev) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + int i; + + /* Figure out how much instance memory we need */ + switch (dev_priv->card_type) { + case NV_40: + /* We'll want more instance memory than this on some NV4x cards. + * There's a 16MB aperture to play with that maps onto the end + * of vram. For now, only reserve a small piece until we know + * more about what each chipset requires. + */ + dev_priv->ramin_rsvd_vram = (1*1024* 1024); + break; + default: + /*XXX: what *are* the limits on ramin_rsvd_vram = (512*1024); + break; + } + DRM_DEBUG("RAMIN size: %dKiB\n", dev_priv->ramin_rsvd_vram>>10); + + /* Clear all of it, except the BIOS image that's in the first 64KiB */ + for (i=(64*1024); iramin_rsvd_vram; i+=4) + NV_WI32(i, 0x00000000); +} + +static void +nv04_instmem_configure_fixed_tables(struct drm_device *dev) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + + /* FIFO hash table (RAMHT) + * use 4k hash table at RAMIN+0x10000 + * TODO: extend the hash table + */ + dev_priv->ramht_offset = 0x10000; + dev_priv->ramht_bits = 9; + dev_priv->ramht_size = (1 << dev_priv->ramht_bits); + DRM_DEBUG("RAMHT offset=0x%x, size=%d\n", dev_priv->ramht_offset, + dev_priv->ramht_size); + + /* FIFO runout table (RAMRO) - 512k at 0x11200 */ + dev_priv->ramro_offset = 0x11200; + dev_priv->ramro_size = 512; + DRM_DEBUG("RAMRO offset=0x%x, size=%d\n", dev_priv->ramro_offset, + dev_priv->ramro_size); + + /* FIFO context table (RAMFC) + * NV40 : Not sure exactly how to position RAMFC on some cards, + * 0x30002 seems to position it at RAMIN+0x20000 on these + * cards. RAMFC is 4kb (32 fifos, 128byte entries). + * Others: Position RAMFC at RAMIN+0x11400 + */ + switch(dev_priv->card_type) + { + case NV_40: + case NV_44: + dev_priv->ramfc_offset = 0x20000; + dev_priv->ramfc_size = nouveau_fifo_number(dev) * + nouveau_fifo_ctx_size(dev); + break; + case NV_30: + case NV_20: + case NV_17: + case NV_10: + case NV_04: + case NV_03: + default: + dev_priv->ramfc_offset = 0x11400; + dev_priv->ramfc_size = nouveau_fifo_number(dev) * + nouveau_fifo_ctx_size(dev); + break; + } + DRM_DEBUG("RAMFC offset=0x%x, size=%d\n", dev_priv->ramfc_offset, + dev_priv->ramfc_size); +} + +int nv04_instmem_init(struct drm_device *dev) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + uint32_t offset; + int ret = 0; + + nv04_instmem_determine_amount(dev); + nv04_instmem_configure_fixed_tables(dev); + + if ((ret = nouveau_gpuobj_new_fake(dev, dev_priv->ramht_offset, + dev_priv->ramht_size, + NVOBJ_FLAG_ZERO_ALLOC | + NVOBJ_FLAG_ALLOW_NO_REFS, + &dev_priv->ramht, NULL))) + return ret; + + /* Create a heap to manage RAMIN allocations, we don't allocate + * the space that was reserved for RAMHT/FC/RO. + */ + offset = dev_priv->ramfc_offset + dev_priv->ramfc_size; + ret = nouveau_mem_init_heap(&dev_priv->ramin_heap, + offset, dev_priv->ramin_rsvd_vram - offset); + if (ret) { + dev_priv->ramin_heap = NULL; + DRM_ERROR("Failed to init RAMIN heap\n"); + } + + return ret; +} + +void +nv04_instmem_takedown(drm_device_t *dev) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + + nouveau_gpuobj_del(dev, &dev_priv->ramht); +} + +int +nv04_instmem_populate(drm_device_t *dev, nouveau_gpuobj_t *gpuobj, uint32_t *sz) +{ + if (gpuobj->im_backing) + return DRM_ERR(EINVAL); + + return 0; +} + +void +nv04_instmem_clear(drm_device_t *dev, nouveau_gpuobj_t *gpuobj) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + + if (gpuobj && gpuobj->im_backing) { + if (gpuobj->im_bound) + dev_priv->Engine.instmem.unbind(dev, gpuobj); + nouveau_mem_free(dev, gpuobj->im_backing); + gpuobj->im_backing = NULL; + } +} + +int +nv04_instmem_bind(drm_device_t *dev, nouveau_gpuobj_t *gpuobj) +{ + if (!gpuobj->im_pramin || gpuobj->im_bound) + return DRM_ERR(EINVAL); + + gpuobj->im_bound = 1; + return 0; +} + +int +nv04_instmem_unbind(drm_device_t *dev, nouveau_gpuobj_t *gpuobj) +{ + if (gpuobj->im_bound == 0) + return DRM_ERR(EINVAL); + + gpuobj->im_bound = 0; + return 0; +} + diff --git a/shared-core/nv10_fifo.c b/shared-core/nv10_fifo.c index 07ec4635..2d8d5a0d 100644 --- a/shared-core/nv10_fifo.c +++ b/shared-core/nv10_fifo.c @@ -40,7 +40,7 @@ int nv10_fifo_create_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; int ret; if ((ret = nouveau_gpuobj_new_fake(dev, NV10_RAMFC(channel), @@ -64,6 +64,8 @@ nv10_fifo_create_context(drm_device_t *dev, int channel) #endif 0); + /* enable the fifo dma operation */ + NV_WRITE(NV04_PFIFO_MODE,NV_READ(NV04_PFIFO_MODE)|(1<dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; + + NV_WRITE(NV04_PFIFO_MODE, NV_READ(NV04_PFIFO_MODE)&~(1<ramfc) nouveau_gpuobj_ref_del(dev, &chan->ramfc); @@ -81,7 +85,7 @@ int nv10_fifo_load_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; uint32_t tmp; NV_WRITE(NV03_PFIFO_CACHE1_PUSH1 , 0x00000100 | channel); @@ -123,7 +127,7 @@ int nv10_fifo_save_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; uint32_t tmp; RAMFC_WR(DMA_PUT , NV_READ(NV04_PFIFO_CACHE1_DMA_PUT)); diff --git a/shared-core/nv10_graph.c b/shared-core/nv10_graph.c index d1fe0a54..c544afac 100644 --- a/shared-core/nv10_graph.c +++ b/shared-core/nv10_graph.c @@ -547,7 +547,7 @@ static int nv10_graph_ctx_regs_find_offset(drm_device_t *dev, int reg) static void restore_ctx_regs(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *fifo = &dev_priv->fifos[channel]; + struct nouveau_fifo *fifo = dev_priv->fifos[channel]; int i, j; for (i = 0; i < sizeof(nv10_graph_ctx_regs)/sizeof(nv10_graph_ctx_regs[0]); i++) NV_WRITE(nv10_graph_ctx_regs[i], fifo->pgraph_ctx[i]); @@ -577,10 +577,10 @@ void nouveau_nv10_context_switch(drm_device_t *dev) // save PGRAPH context for (i = 0; i < sizeof(nv10_graph_ctx_regs)/sizeof(nv10_graph_ctx_regs[0]); i++) - dev_priv->fifos[channel_old].pgraph_ctx[i] = NV_READ(nv10_graph_ctx_regs[i]); + dev_priv->fifos[channel_old]->pgraph_ctx[i] = NV_READ(nv10_graph_ctx_regs[i]); if (dev_priv->chipset>=0x17) { for (j = 0; j < sizeof(nv17_graph_ctx_regs)/sizeof(nv17_graph_ctx_regs[0]); i++,j++) - dev_priv->fifos[channel_old].pgraph_ctx[i] = NV_READ(nv17_graph_ctx_regs[j]); + dev_priv->fifos[channel_old]->pgraph_ctx[i] = NV_READ(nv17_graph_ctx_regs[j]); } nouveau_wait_for_idle(dev); @@ -613,7 +613,7 @@ void nouveau_nv10_context_switch(drm_device_t *dev) } while (0) int nv10_graph_create_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *fifo = &dev_priv->fifos[channel]; + struct nouveau_fifo *fifo = dev_priv->fifos[channel]; uint32_t tmp, vramsz; DRM_DEBUG("nv10_graph_context_create %d\n", channel); diff --git a/shared-core/nv20_graph.c b/shared-core/nv20_graph.c index 13271051..06d7e440 100644 --- a/shared-core/nv20_graph.c +++ b/shared-core/nv20_graph.c @@ -32,7 +32,7 @@ int nv20_graph_create_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = (drm_nouveau_private_t *)dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; unsigned int ctx_size = NV20_GRCTX_SIZE; int ret; @@ -51,7 +51,7 @@ int nv20_graph_create_context(drm_device_t *dev, int channel) { void nv20_graph_destroy_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; if (chan->ramin_grctx) nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx); @@ -76,7 +76,7 @@ static void nv20_graph_rdi(drm_device_t *dev) { int nv20_graph_save_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = (drm_nouveau_private_t *)dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; uint32_t instance; instance = INSTANCE_RD(dev_priv->ctx_table->gpuobj, channel); @@ -97,7 +97,7 @@ int nv20_graph_save_context(drm_device_t *dev, int channel) { int nv20_graph_load_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = (drm_nouveau_private_t *)dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; uint32_t instance; instance = INSTANCE_RD(dev_priv->ctx_table->gpuobj, channel); diff --git a/shared-core/nv30_graph.c b/shared-core/nv30_graph.c index 65f4f868..a83ad714 100644 --- a/shared-core/nv30_graph.c +++ b/shared-core/nv30_graph.c @@ -104,7 +104,7 @@ int nv30_graph_create_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = (drm_nouveau_private_t *)dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; void (*ctx_init)(drm_device_t *, nouveau_gpuobj_t *); unsigned int ctx_size; int ret; @@ -135,7 +135,7 @@ void nv30_graph_destroy_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = (drm_nouveau_private_t *)dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; if (chan->ramin_grctx) nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx); @@ -164,7 +164,7 @@ nouveau_graph_wait_idle(drm_device_t *dev) int nv30_graph_load_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; uint32_t inst; if (!chan->ramin_grctx) @@ -181,7 +181,7 @@ int nv30_graph_load_context(drm_device_t *dev, int channel) int nv30_graph_save_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; uint32_t inst; if (!chan->ramin_grctx) diff --git a/shared-core/nv40_fifo.c b/shared-core/nv40_fifo.c index eed3e45b..818a9024 100644 --- a/shared-core/nv40_fifo.c +++ b/shared-core/nv40_fifo.c @@ -40,7 +40,7 @@ int nv40_fifo_create_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; int ret; if ((ret = nouveau_gpuobj_new_fake(dev, NV40_RAMFC(channel), @@ -67,6 +67,8 @@ nv40_fifo_create_context(drm_device_t *dev, int channel) RAMFC_WR(GRCTX_INSTANCE, chan->ramin_grctx->instance >> 4); RAMFC_WR(DMA_TIMESLICE , 0x0001FFFF); + /* enable the fifo dma operation */ + NV_WRITE(NV04_PFIFO_MODE,NV_READ(NV04_PFIFO_MODE)|(1<dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; + + NV_WRITE(NV04_PFIFO_MODE, NV_READ(NV04_PFIFO_MODE)&~(1<ramfc) nouveau_gpuobj_ref_del(dev, &chan->ramfc); @@ -84,7 +88,7 @@ int nv40_fifo_load_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; uint32_t tmp, tmp2; NV_WRITE(NV04_PFIFO_CACHE1_DMA_GET , RAMFC_RD(DMA_GET)); @@ -143,7 +147,7 @@ int nv40_fifo_save_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; uint32_t tmp; RAMFC_WR(DMA_PUT , NV_READ(NV04_PFIFO_CACHE1_DMA_PUT)); diff --git a/shared-core/nv40_graph.c b/shared-core/nv40_graph.c index 3f33cee6..94d76505 100644 --- a/shared-core/nv40_graph.c +++ b/shared-core/nv40_graph.c @@ -1228,7 +1228,7 @@ nv40_graph_create_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = (drm_nouveau_private_t *)dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; void (*ctx_init)(drm_device_t *, nouveau_gpuobj_t *); unsigned int ctx_size; int ret; @@ -1287,7 +1287,7 @@ void nv40_graph_destroy_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; if (chan->ramin_grctx) nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx); @@ -1330,7 +1330,7 @@ int nv40_graph_save_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; uint32_t inst; if (!chan->ramin_grctx) @@ -1347,7 +1347,7 @@ int nv40_graph_load_context(drm_device_t *dev, int channel) { drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = &dev_priv->fifos[channel]; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; uint32_t inst; int ret; diff --git a/shared-core/nv50_fifo.c b/shared-core/nv50_fifo.c index e5d37949..d4c3ca87 100644 --- a/shared-core/nv50_fifo.c +++ b/shared-core/nv50_fifo.c @@ -28,55 +28,306 @@ #include "drm.h" #include "nouveau_drv.h" +typedef struct { + nouveau_gpuobj_ref_t *thingo; + nouveau_gpuobj_ref_t *dummyctx; +} nv50_fifo_priv; + +#define IS_G80 ((dev_priv->chipset & 0xf0) == 0x50) + +static void +nv50_fifo_init_thingo(drm_device_t *dev) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + nv50_fifo_priv *priv = dev_priv->Engine.fifo.priv; + nouveau_gpuobj_ref_t *thingo = priv->thingo; + int i, fi=2; + + DRM_DEBUG("\n"); + + INSTANCE_WR(thingo->gpuobj, 0, 0x7e); + INSTANCE_WR(thingo->gpuobj, 1, 0x7e); + for (i = 0; i fifos[i]) { + INSTANCE_WR(thingo->gpuobj, fi, i); + fi++; + } + } + + NV_WRITE(0x32f4, thingo->instance >> 12); + NV_WRITE(0x32ec, fi); + NV_WRITE(0x2500, 0x101); +} + +static int +nv50_fifo_channel_enable(drm_device_t *dev, int channel) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; + + DRM_DEBUG("ch%d\n", channel); + + if (IS_G80) { + if (!chan->ramin) + return DRM_ERR(EINVAL); + + NV_WRITE(NV50_PFIFO_CTX_TABLE(channel), + (chan->ramin->instance >> 12) | + NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED); + } else { + if (!chan->ramfc) + return DRM_ERR(EINVAL); + + NV_WRITE(NV50_PFIFO_CTX_TABLE(channel), + (chan->ramfc->instance >> 8) | + NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED); + } + + nv50_fifo_init_thingo(dev); + return 0; +} + +static void +nv50_fifo_channel_disable(drm_device_t *dev, int channel, int nt) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + + DRM_DEBUG("ch%d, nt=%d\n", channel, nt); + + if (IS_G80) { + NV_WRITE(NV50_PFIFO_CTX_TABLE(channel), + NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G80); + } else { + NV_WRITE(NV50_PFIFO_CTX_TABLE(channel), + NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G84); + } + + if (!nt) nv50_fifo_init_thingo(dev); +} + static void nv50_fifo_init_reset(drm_device_t *dev) { drm_nouveau_private_t *dev_priv = dev->dev_private; uint32_t pmc_e; + DRM_DEBUG("\n"); + pmc_e = NV_READ(NV03_PMC_ENABLE); NV_WRITE(NV03_PMC_ENABLE, pmc_e & ~NV_PMC_ENABLE_PFIFO); pmc_e = NV_READ(NV03_PMC_ENABLE); NV_WRITE(NV03_PMC_ENABLE, pmc_e | NV_PMC_ENABLE_PFIFO); } +static void +nv50_fifo_init_context_table(drm_device_t *dev) +{ + int i; + + DRM_DEBUG("\n"); + + for (i = 0; i < NV50_PFIFO_CTX_TABLE__SIZE; i++) + nv50_fifo_channel_disable(dev, i, 1); + nv50_fifo_init_thingo(dev); +} + +static void +nv50_fifo_init_regs__nv(drm_device_t *dev) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + + DRM_DEBUG("\n"); + + NV_WRITE(0x250c, 0x6f3cfc34); +} + +static int +nv50_fifo_init_regs(drm_device_t *dev) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + nv50_fifo_priv *priv = dev_priv->Engine.fifo.priv; + int ret; + + DRM_DEBUG("\n"); + + if ((ret = nouveau_gpuobj_new_ref(dev, -1, -1, 0, 0x1000, + 0x1000, + NVOBJ_FLAG_ZERO_ALLOC | + NVOBJ_FLAG_ZERO_FREE, + &priv->dummyctx))) + return ret; + + NV_WRITE(0x2500, 0); + NV_WRITE(0x3250, 0); + NV_WRITE(0x3220, 0); + NV_WRITE(0x3204, 0); + NV_WRITE(0x3210, 0); + NV_WRITE(0x3270, 0); + + if (IS_G80) { + NV_WRITE(0x2600, (priv->dummyctx->instance>>8) | (1<<31)); + NV_WRITE(0x27fc, (priv->dummyctx->instance>>8) | (1<<31)); + } else { + NV_WRITE(0x2600, (priv->dummyctx->instance>>12) | (1<<31)); + NV_WRITE(0x27fc, (priv->dummyctx->instance>>12) | (1<<31)); + } + + return 0; +} + int nv50_fifo_init(drm_device_t *dev) { + drm_nouveau_private_t *dev_priv = dev->dev_private; + nv50_fifo_priv *priv; + int ret; + + DRM_DEBUG("\n"); + + priv = drm_calloc(1, sizeof(*priv), DRM_MEM_DRIVER); + if (!priv) + return DRM_ERR(ENOMEM); + dev_priv->Engine.fifo.priv = priv; + nv50_fifo_init_reset(dev); - DRM_ERROR("stub!\n"); + if ((ret = nouveau_gpuobj_new_ref(dev, -1, -1, 0, (128+2)*4, 0x1000, + NVOBJ_FLAG_ZERO_ALLOC, + &priv->thingo))) { + DRM_ERROR("error creating thingo: %d\n", ret); + return ret; + } + nv50_fifo_init_context_table(dev); + + nv50_fifo_init_regs__nv(dev); + if ((ret = nv50_fifo_init_regs(dev))) + return ret; + return 0; } void nv50_fifo_takedown(drm_device_t *dev) { - DRM_ERROR("stub!\n"); + drm_nouveau_private_t *dev_priv = dev->dev_private; + nv50_fifo_priv *priv = dev_priv->Engine.fifo.priv; + + DRM_DEBUG("\n"); + + if (!priv) + return; + + nouveau_gpuobj_ref_del(dev, &priv->thingo); + nouveau_gpuobj_ref_del(dev, &priv->dummyctx); + + dev_priv->Engine.fifo.priv = NULL; + drm_free(priv, sizeof(*priv), DRM_MEM_DRIVER); } int nv50_fifo_create_context(drm_device_t *dev, int channel) { - DRM_ERROR("stub!\n"); + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; + nouveau_gpuobj_t *ramfc = NULL; + int ret; + + DRM_DEBUG("ch%d\n", channel); + + if (IS_G80) { + uint32_t ramfc_offset; + ramfc_offset = chan->ramin->gpuobj->im_pramin->start + 0x1000; + if ((ret = nouveau_gpuobj_new_fake(dev, ramfc_offset, 0x100, + NVOBJ_FLAG_ZERO_ALLOC | + NVOBJ_FLAG_ZERO_FREE, + &ramfc, &chan->ramfc))) + return ret; + } else { + if ((ret = nouveau_gpuobj_new_ref(dev, channel, -1, 0, 0x100, + 256, + NVOBJ_FLAG_ZERO_ALLOC | + NVOBJ_FLAG_ZERO_FREE, + &chan->ramfc))) + return ret; + ramfc = chan->ramfc->gpuobj; + } + + INSTANCE_WR(ramfc, 0x48/4, chan->pushbuf->instance >> 4); + INSTANCE_WR(ramfc, 0x80/4, (0xc << 24) | (chan->ramht->instance >> 4)); + INSTANCE_WR(ramfc, 0x3c/4, 0x000f0078); /* fetch? */ + INSTANCE_WR(ramfc, 0x44/4, 0x2101ffff); + INSTANCE_WR(ramfc, 0x60/4, 0x7fffffff); + INSTANCE_WR(ramfc, 0x10/4, 0x00000000); + INSTANCE_WR(ramfc, 0x08/4, 0x00000000); + INSTANCE_WR(ramfc, 0x40/4, 0x00000000); + INSTANCE_WR(ramfc, 0x50/4, 0x2039b2e0); + INSTANCE_WR(ramfc, 0x54/4, 0x000f0000); + INSTANCE_WR(ramfc, 0x7c/4, 0x30000001); + INSTANCE_WR(ramfc, 0x78/4, 0x00000000); + INSTANCE_WR(ramfc, 0x4c/4, 0x00007fff); + + if (!IS_G80) { + INSTANCE_WR(chan->ramin->gpuobj, 0, channel); + INSTANCE_WR(chan->ramin->gpuobj, 1, chan->ramfc->instance); + + INSTANCE_WR(ramfc, 0x88/4, 0x3d520); /* some vram addy >> 10 */ + INSTANCE_WR(ramfc, 0x98/4, chan->ramin->instance >> 12); + } + + if ((ret = nv50_fifo_channel_enable(dev, channel))) { + DRM_ERROR("error enabling ch%d: %d\n", channel, ret); + nouveau_gpuobj_ref_del(dev, &chan->ramfc); + return ret; + } + return 0; } void nv50_fifo_destroy_context(drm_device_t *dev, int channel) { + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; + + DRM_DEBUG("ch%d\n", channel); + + nv50_fifo_channel_disable(dev, channel, 0); + nouveau_gpuobj_ref_del(dev, &chan->ramfc); } int nv50_fifo_load_context(drm_device_t *dev, int channel) { - DRM_ERROR("stub!\n"); + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; + nouveau_gpuobj_t *ramfc = chan->ramfc->gpuobj; + + DRM_DEBUG("ch%d\n", channel); + + /*XXX: incomplete, only touches the regs that NV does */ + + NV_WRITE(0x3244, 0); + NV_WRITE(0x3240, 0); + + NV_WRITE(0x3224, INSTANCE_RD(ramfc, 0x3c/4)); + NV_WRITE(NV04_PFIFO_CACHE1_DMA_INSTANCE, INSTANCE_RD(ramfc, 0x48/4)); + NV_WRITE(0x3234, INSTANCE_RD(ramfc, 0x4c/4)); + NV_WRITE(0x3254, 1); + NV_WRITE(NV03_PFIFO_RAMHT, INSTANCE_RD(ramfc, 0x80/4)); + + if (!IS_G80) { + NV_WRITE(0x340c, INSTANCE_RD(ramfc, 0x88/4)); + NV_WRITE(0x3410, INSTANCE_RD(ramfc, 0x98/4)); + } + + NV_WRITE(NV03_PFIFO_CACHE1_PUSH1, channel | (1<<16)); return 0; } int nv50_fifo_save_context(drm_device_t *dev, int channel) { + DRM_DEBUG("ch%d\n", channel); DRM_ERROR("stub!\n"); return 0; } diff --git a/shared-core/nv50_graph.c b/shared-core/nv50_graph.c index 8c3e2b9b..271ed733 100644 --- a/shared-core/nv50_graph.c +++ b/shared-core/nv50_graph.c @@ -28,57 +28,274 @@ #include "drm.h" #include "nouveau_drv.h" +#define IS_G80 ((dev_priv->chipset & 0xf0) == 0x50) + static void nv50_graph_init_reset(drm_device_t *dev) { drm_nouveau_private_t *dev_priv = dev->dev_private; uint32_t pmc_e; + DRM_DEBUG("\n"); + pmc_e = NV_READ(NV03_PMC_ENABLE); NV_WRITE(NV03_PMC_ENABLE, pmc_e & ~NV_PMC_ENABLE_PGRAPH); pmc_e = NV_READ(NV03_PMC_ENABLE); NV_WRITE(NV03_PMC_ENABLE, pmc_e | NV_PMC_ENABLE_PGRAPH); } +static void +nv50_graph_init_regs__nv(drm_device_t *dev) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + + DRM_DEBUG("\n"); + + NV_WRITE(0x400804, 0xc0000000); + NV_WRITE(0x406800, 0xc0000000); + NV_WRITE(0x400c04, 0xc0000000); + NV_WRITE(0x401804, 0xc0000000); + NV_WRITE(0x405018, 0xc0000000); + NV_WRITE(0x402000, 0xc0000000); + + NV_WRITE(0x400108, 0xffffffff); + NV_WRITE(0x400100, 0xffffffff); + + NV_WRITE(0x400824, 0x00004000); + NV_WRITE(0x400500, 0x00010001); +} + +static void +nv50_graph_init_regs(drm_device_t *dev) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + + DRM_DEBUG("\n"); + + NV_WRITE(NV04_PGRAPH_DEBUG_3, (1<<2) /* HW_CONTEXT_SWITCH_ENABLED */); +} + +static uint32_t nv84_ctx_voodoo[] = { + 0x0070008e, 0x0070009c, 0x00200020, 0x00600008, 0x0050004c, 0x00400e89, + 0x00200000, 0x00600007, 0x00300000, 0x00c000ff, 0x00200000, 0x008000ff, + 0x00700009, 0x0041634d, 0x00402944, 0x00402905, 0x0040290d, 0x00413e06, + 0x00600005, 0x004015c5, 0x00600011, 0x0040270b, 0x004021c5, 0x00700000, + 0x00700081, 0x00600004, 0x0050004a, 0x00216f40, 0x00600007, 0x00c02801, + 0x0020002e, 0x00800001, 0x005000cb, 0x0090ffff, 0x0091ffff, 0x00200020, + 0x00600008, 0x0050004c, 0x00600009, 0x00413e45, 0x0041594d, 0x0070009d, + 0x00402dcf, 0x0070009f, 0x0050009f, 0x00402ac0, 0x00200200, 0x00600008, + 0x00402a4f, 0x00402ac0, 0x004030cc, 0x00700081, 0x00200000, 0x00600006, + 0x00700000, 0x00111bfc, 0x00700083, 0x00300000, 0x00216f40, 0x00600007, + 0x00c00b01, 0x0020001e, 0x00800001, 0x005000cb, 0x00c000ff, 0x00700080, + 0x00700083, 0x00200047, 0x00600006, 0x0011020a, 0x00200480, 0x00600007, + 0x00300000, 0x00c000ff, 0x00c800ff, 0x00414907, 0x00202916, 0x008000ff, + 0x0040508c, 0x005000cb, 0x00a0023f, 0x00200040, 0x00600006, 0x0070000f, + 0x00170202, 0x0011020a, 0x00200032, 0x0010020d, 0x001c0242, 0x00120302, + 0x00140402, 0x00180500, 0x00130509, 0x00150550, 0x00110605, 0x0020000f, + 0x00100607, 0x00110700, 0x00110900, 0x00120902, 0x00110a00, 0x00160b02, + 0x00120b28, 0x00140b2b, 0x00110c01, 0x00111400, 0x00111405, 0x00111407, + 0x00111409, 0x0011140b, 0x002000cb, 0x00101500, 0x0040790f, 0x0040794b, + 0x00214d40, 0x00600007, 0x0020043e, 0x008800ff, 0x0070008f, 0x0040798c, + 0x005000cb, 0x00000000, 0x0020002b, 0x00101a05, 0x00131c00, 0x00121c04, + 0x00141c20, 0x00111c25, 0x00131c40, 0x00121c44, 0x00141c60, 0x00111c65, + 0x00131c80, 0x00121c84, 0x00141ca0, 0x00111ca5, 0x00131cc0, 0x00121cc4, + 0x00141ce0, 0x00111ce5, 0x00131f00, 0x00191f40, 0x0040a1e0, 0x002001ed, + 0x00600006, 0x00200044, 0x00102080, 0x001120c6, 0x001520c9, 0x001920d0, + 0x00122100, 0x00122103, 0x00162200, 0x00122207, 0x00112280, 0x00112300, + 0x00112302, 0x00122380, 0x0011238b, 0x00112394, 0x0011239c, 0x0040bee1, + 0x00200254, 0x00600006, 0x00200044, 0x00102480, 0x0040af0f, 0x0040af4b, + 0x00214d40, 0x00600007, 0x0020043e, 0x008800ff, 0x0070008f, 0x0040af8c, + 0x005000cb, 0x00000000, 0x001124c6, 0x001524c9, 0x001924d0, 0x00122500, + 0x00122503, 0x00162600, 0x00122607, 0x00112680, 0x00112700, 0x00112702, + 0x00122780, 0x0011278b, 0x00112794, 0x0011279c, 0x0040d1e2, 0x002002bb, + 0x00600006, 0x00200044, 0x00102880, 0x001128c6, 0x001528c9, 0x001928d0, + 0x00122900, 0x00122903, 0x00162a00, 0x00122a07, 0x00112a80, 0x00112b00, + 0x00112b02, 0x00122b80, 0x00112b8b, 0x00112b94, 0x00112b9c, 0x0040eee3, + 0x00200322, 0x00600006, 0x00200044, 0x00102c80, 0x0040df0f, 0x0040df4b, + 0x00214d40, 0x00600007, 0x0020043e, 0x008800ff, 0x0070008f, 0x0040df8c, + 0x005000cb, 0x00000000, 0x00112cc6, 0x00152cc9, 0x00192cd0, 0x00122d00, + 0x00122d03, 0x00162e00, 0x00122e07, 0x00112e80, 0x00112f00, 0x00112f02, + 0x00122f80, 0x00112f8b, 0x00112f94, 0x00112f9c, 0x004101e4, 0x00200389, + 0x00600006, 0x00200044, 0x00103080, 0x001130c6, 0x001530c9, 0x001930d0, + 0x00123100, 0x00123103, 0x00163200, 0x00123207, 0x00113280, 0x00113300, + 0x00113302, 0x00123380, 0x0011338b, 0x00113394, 0x0011339c, 0x00411ee5, + 0x002003f0, 0x00600006, 0x00200044, 0x00103480, 0x00410f0f, 0x00410f4b, + 0x00214d40, 0x00600007, 0x0020043e, 0x008800ff, 0x0070008f, 0x00410f8c, + 0x005000cb, 0x00000000, 0x001134c6, 0x001534c9, 0x001934d0, 0x00123500, + 0x00123503, 0x00163600, 0x00123607, 0x00113680, 0x00113700, 0x00113702, + 0x00123780, 0x0011378b, 0x00113794, 0x0011379c, 0x00000000, 0x0041250f, + 0x005000cb, 0x00214d40, 0x00600007, 0x0020043e, 0x008800ff, 0x005000cb, + 0x00412887, 0x0060000a, 0x00000000, 0x00413700, 0x007000a0, 0x00700080, + 0x00200480, 0x00600007, 0x00200004, 0x00c000ff, 0x008000ff, 0x005000cb, + 0x00700000, 0x00200000, 0x00600006, 0x00111bfe, 0x0041594d, 0x00700000, + 0x00200000, 0x00600006, 0x00111bfe, 0x00700080, 0x0070001d, 0x0040114d, + 0x00700081, 0x00600004, 0x0050004a, 0x00414388, 0x0060000b, 0x00200000, + 0x00600006, 0x00700000, 0x0041590b, 0x00111bfd, 0x0040424d, 0x00202916, + 0x008000fd, 0x005000cb, 0x00c00002, 0x00200480, 0x00600007, 0x00200160, + 0x00800002, 0x005000cb, 0x00c01802, 0x002027b6, 0x00800002, 0x005000cb, + 0x00404e4d, 0x0060000b, 0x0041574d, 0x00700001, 0x005000cf, 0x00700003, + 0x00415e06, 0x00415f05, 0x0060000d, 0x00700005, 0x0070000d, 0x00700006, + 0x0070000b, 0x0070000e, 0x0070001c, 0x0060000c, ~0 +}; + +static void +nv50_graph_init_ctxctl(drm_device_t *dev) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + uint32_t *voodoo; + + DRM_DEBUG("\n"); + + switch (dev_priv->chipset) { + case 0x84: + voodoo = nv84_ctx_voodoo; + break; + default: + DRM_ERROR("no voodoo for chipset NV%02x\n", dev_priv->chipset); + break; + } + + if (voodoo) { + NV_WRITE(NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0); + while (*voodoo != ~0) { + NV_WRITE(NV40_PGRAPH_CTXCTL_UCODE_DATA, *voodoo); + voodoo++; + } + } + + NV_WRITE(0x400320, 4); + NV_WRITE(NV40_PGRAPH_CTXCTL_CUR, 0); + NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_POINTER, 0); +} + int nv50_graph_init(drm_device_t *dev) { + DRM_DEBUG("\n"); + nv50_graph_init_reset(dev); + nv50_graph_init_regs__nv(dev); + nv50_graph_init_regs(dev); + nv50_graph_init_ctxctl(dev); - DRM_ERROR("stub!\n"); return 0; } void nv50_graph_takedown(drm_device_t *dev) { - DRM_ERROR("stub!\n"); + DRM_DEBUG("\n"); } int nv50_graph_create_context(drm_device_t *dev, int channel) { - DRM_ERROR("stub!\n"); + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; + nouveau_gpuobj_t *ramin = chan->ramin->gpuobj; + int grctx_size = 0x60000, hdr; + int ret; + + DRM_DEBUG("ch%d\n", channel); + + if ((ret = nouveau_gpuobj_new_ref(dev, channel, -1, 0, + grctx_size, 0x1000, + NVOBJ_FLAG_ZERO_ALLOC | + NVOBJ_FLAG_ZERO_FREE, + &chan->ramin_grctx))) + return ret; + + hdr = IS_G80 ? 0x200 : 0x20; + INSTANCE_WR(ramin, (hdr + 0x00)/4, 0x00190002); + INSTANCE_WR(ramin, (hdr + 0x04)/4, chan->ramin_grctx->instance + + grctx_size - 1); + INSTANCE_WR(ramin, (hdr + 0x08)/4, chan->ramin_grctx->instance); + INSTANCE_WR(ramin, (hdr + 0x0c)/4, 0); + INSTANCE_WR(ramin, (hdr + 0x10)/4, 0); + INSTANCE_WR(ramin, (hdr + 0x14)/4, 0x00010000); + return 0; } void nv50_graph_destroy_context(drm_device_t *dev, int channel) { - DRM_ERROR("stub!\n"); + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; + int i, hdr; + + DRM_DEBUG("ch%d\n", channel); + + hdr = IS_G80 ? 0x200 : 0x20; + for (i=hdr; iramin->gpuobj, i/4, 0); + + nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx); +} + +static int +nv50_graph_transfer_context(drm_device_t *dev, uint32_t inst, int save) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + uint32_t old_cp, tv = 20000; + int i; + + DRM_DEBUG("inst=0x%08x, save=%d\n", inst, save); + + old_cp = NV_READ(NV20_PGRAPH_CHANNEL_CTX_POINTER); + NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_POINTER, inst | (1<<31)); + NV_WRITE(0x400824, NV_READ(0x400824) | + (save ? NV40_PGRAPH_CTXCTL_0310_XFER_SAVE : + NV40_PGRAPH_CTXCTL_0310_XFER_LOAD)); + NV_WRITE(NV40_PGRAPH_CTXCTL_0304, NV40_PGRAPH_CTXCTL_0304_XFER_CTX); + + for (i = 0; i < tv; i++) { + if (NV_READ(NV40_PGRAPH_CTXCTL_030C) == 0) + break; + } + NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_POINTER, old_cp); + + if (i == tv) { + DRM_ERROR("failed: inst=0x%08x save=%d\n", inst, save); + DRM_ERROR("0x40030C = 0x%08x\n", + NV_READ(NV40_PGRAPH_CTXCTL_030C)); + return DRM_ERR(EBUSY); + } + + return 0; } int nv50_graph_load_context(drm_device_t *dev, int channel) { - DRM_ERROR("stub!\n"); + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; + uint32_t inst = ((chan->ramin->instance >> 12) | (1<<31)); + int ret; + + DRM_DEBUG("ch%d\n", channel); + +#if 0 + if ((ret = nv50_graph_transfer_context(dev, inst, 0))) + return ret; +#endif + + NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_POINTER, inst); + NV_WRITE(0x400320, 4); + NV_WRITE(NV40_PGRAPH_CTXCTL_CUR, inst); + return 0; } int nv50_graph_save_context(drm_device_t *dev, int channel) { - DRM_ERROR("stub!\n"); - return 0; + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; + uint32_t inst = ((chan->ramin->instance >> 12) | (1<<31)); + + DRM_DEBUG("ch%d\n", channel); + + return nv50_graph_transfer_context(dev, inst, 1); } diff --git a/shared-core/nv50_instmem.c b/shared-core/nv50_instmem.c new file mode 100644 index 00000000..4aca9e7d --- /dev/null +++ b/shared-core/nv50_instmem.c @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2007 Ben Skeggs. + * + * 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 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. + * + */ + +#include "drmP.h" +#include "drm.h" +#include "nouveau_drv.h" + +typedef struct { + uint32_t save1700[5]; /* 0x1700->0x1710 */ +} nv50_instmem_priv; + +#define NV50_INSTMEM_PAGE_SHIFT 12 +#define NV50_INSTMEM_PAGE_SIZE (1 << NV50_INSTMEM_PAGE_SHIFT) +#define NV50_INSTMEM_RSVD_SIZE (64 * 1024) +#define NV50_INSTMEM_PT_SIZE(a) (((a) >> 12) << 3) + +int +nv50_instmem_init(drm_device_t *dev) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + nv50_instmem_priv *priv; + uint32_t rv, pt, pts, cb, cb0, cb1, unk, as; + uint32_t i, v; + int ret; + + priv = drm_calloc(1, sizeof(*priv), DRM_MEM_DRIVER); + if (!priv) + return DRM_ERR(ENOMEM); + dev_priv->Engine.instmem.priv = priv; + + /* Save current state */ + for (i = 0x1700; i <= 0x1710; i+=4) + priv->save1700[(i-0x1700)/4] = NV_READ(i); + + as = dev_priv->ramin->size; + rv = nouveau_mem_fb_amount(dev) - (1*1024*1024); + pt = rv + 0xd0000; + pts = NV50_INSTMEM_PT_SIZE(as); + cb = rv + 0xc8000; + if ((dev_priv->chipset & 0xf0) != 0x50) { + unk = cb + 0x4200; + cb0 = cb + 0x4240; + cb1 = cb + 0x278; + } else { + unk = cb + 0x5400; + cb0 = cb + 0x5440; + cb1 = cb + 0x1438; + } + + DRM_DEBUG("PRAMIN config:\n"); + DRM_DEBUG(" Rsvd VRAM base: 0x%08x\n", rv); + DRM_DEBUG(" Aperture size: %i MiB\n", as >> 20); + DRM_DEBUG(" PT base: 0x%08x\n", pt); + DRM_DEBUG(" PT size: %d KiB\n", pts >> 10); + DRM_DEBUG(" BIOS image: 0x%08x\n", (NV_READ(0x619f04)&~0xff)<<8); + DRM_DEBUG(" Config base: 0x%08x\n", cb); + DRM_DEBUG(" ctxdma Config0: 0x%08x\n", cb0); + DRM_DEBUG(" Config1: 0x%08x\n", cb1); + + /* Map first MiB of reserved vram into BAR0 PRAMIN aperture */ + NV_WRITE(0x1700, (rv>>16)); + /* Poke some regs.. */ + NV_WRITE(0x1704, (cb>>12)); + NV_WRITE(0x1710, (((unk-cb)>>4))|(1<<31)); + NV_WRITE(0x1704, (cb>>12)|(1<<30)); + + /* CB0, some DMA object, NFI what it points at... Needed however, + * or the PRAMIN aperture doesn't operate as expected. + */ + NV_WRITE(NV_RAMIN + (cb0 - rv) + 0x00, 0x7fc00000); + NV_WRITE(NV_RAMIN + (cb0 - rv) + 0x04, 0xe1ffffff); + NV_WRITE(NV_RAMIN + (cb0 - rv) + 0x08, 0xe0000000); + NV_WRITE(NV_RAMIN + (cb0 - rv) + 0x0c, 0x01000001); + NV_WRITE(NV_RAMIN + (cb0 - rv) + 0x10, 0x00000000); + NV_WRITE(NV_RAMIN + (cb0 - rv) + 0x14, 0x00000000); + + /* CB1, points at PRAMIN PT */ + NV_WRITE(NV_RAMIN + (cb1 - rv) + 0, pt | 0x63); + NV_WRITE(NV_RAMIN + (cb1 - rv) + 4, 0x00000000); + + /* Zero PRAMIN page table */ + v = NV_RAMIN + (pt - rv); + for (i = v; i < v + pts; i += 8) { + NV_WRITE(i + 0x00, 0x00000009); + NV_WRITE(i + 0x04, 0x00000000); + } + + /* Map page table into PRAMIN aperture */ + for (i = pt; i < pt + pts; i += 0x1000) { + uint32_t pte = NV_RAMIN + (pt-rv) + (((i-pt) >> 12) << 3); + DRM_DEBUG("PRAMIN PTE = 0x%08x @ 0x%08x\n", i, pte); + NV_WRITE(pte + 0x00, i | 1); + NV_WRITE(pte + 0x04, 0x00000000); + } + + /* Points at CB0 */ + NV_WRITE(0x170c, (((cb0 - cb)>>4)|(1<<31))); + + /* Confirm it all worked, should be able to read back the page table's + * PTEs from the PRAMIN BAR + */ + NV_WRITE(0x1700, pt >> 16); + if (NV_READ(0x700000) != NV_RI32(0)) { + DRM_ERROR("Failed to init PRAMIN page table\n"); + return DRM_ERR(EINVAL); + } + + /* Create a heap to manage PRAMIN aperture allocations */ + ret = nouveau_mem_init_heap(&dev_priv->ramin_heap, pts, as-pts); + if (ret) { + DRM_ERROR("Failed to init PRAMIN heap\n"); + return DRM_ERR(ENOMEM); + } + DRM_DEBUG("NV50: PRAMIN setup ok\n"); + + /* Don't alloc the last MiB of VRAM, probably too much, but be safe + * at least for now. + */ + dev_priv->ramin_rsvd_vram = 1*1024*1024; + + /*XXX: probably incorrect, but needed to make hash func "work" */ + dev_priv->ramht_offset = 0x10000; + dev_priv->ramht_bits = 9; + dev_priv->ramht_size = (1 << dev_priv->ramht_bits); + return 0; +} + +void +nv50_instmem_takedown(drm_device_t *dev) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + nv50_instmem_priv *priv = dev_priv->Engine.instmem.priv; + int i; + + if (!priv) + return; + + /* Restore state from before init */ + for (i = 0x1700; i <= 0x1710; i+=4) + NV_WRITE(i, priv->save1700[(i-0x1700)/4]); + + dev_priv->Engine.instmem.priv = NULL; + drm_free(priv, sizeof(*priv), DRM_MEM_DRIVER); +} + +int +nv50_instmem_populate(drm_device_t *dev, nouveau_gpuobj_t *gpuobj, uint32_t *sz) +{ + if (gpuobj->im_backing) + return DRM_ERR(EINVAL); + + *sz = (*sz + (NV50_INSTMEM_PAGE_SIZE-1)) & ~(NV50_INSTMEM_PAGE_SIZE-1); + if (*sz == 0) + return DRM_ERR(EINVAL); + + gpuobj->im_backing = nouveau_mem_alloc(dev, NV50_INSTMEM_PAGE_SIZE, + *sz, NOUVEAU_MEM_FB, + (DRMFILE)-2); + if (!gpuobj->im_backing) { + DRM_ERROR("Couldn't allocate vram to back PRAMIN pages\n"); + return DRM_ERR(ENOMEM); + } + + return 0; +} + +void +nv50_instmem_clear(drm_device_t *dev, nouveau_gpuobj_t *gpuobj) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + + if (gpuobj && gpuobj->im_backing) { + if (gpuobj->im_bound) + dev_priv->Engine.instmem.unbind(dev, gpuobj); + nouveau_mem_free(dev, gpuobj->im_backing); + gpuobj->im_backing = NULL; + } +} + +int +nv50_instmem_bind(drm_device_t *dev, nouveau_gpuobj_t *gpuobj) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + uint32_t pte, pte_end, vram; + + if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound) + return DRM_ERR(EINVAL); + + DRM_DEBUG("st=0x%0llx sz=0x%0llx\n", + gpuobj->im_pramin->start, gpuobj->im_pramin->size); + + pte = (gpuobj->im_pramin->start >> 12) << 3; + pte_end = ((gpuobj->im_pramin->size >> 12) << 3) + pte; + vram = gpuobj->im_backing->start - dev_priv->fb_phys; + + if (pte == pte_end) { + DRM_ERROR("WARNING: badness in bind() pte calc\n"); + pte_end++; + } + + DRM_DEBUG("pramin=0x%llx, pte=%d, pte_end=%d\n", + gpuobj->im_pramin->start, pte, pte_end); + DRM_DEBUG("first vram page: 0x%llx\n", + gpuobj->im_backing->start); + + while (pte < pte_end) { + NV_WI32(pte + 0, vram | 1); + NV_WI32(pte + 4, 0x00000000); + + pte += 8; + vram += NV50_INSTMEM_PAGE_SIZE; + } + + gpuobj->im_bound = 1; + return 0; +} + +int +nv50_instmem_unbind(drm_device_t *dev, nouveau_gpuobj_t *gpuobj) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + uint32_t pte, pte_end; + + if (gpuobj->im_bound == 0) + return DRM_ERR(EINVAL); + + pte = (gpuobj->im_pramin->start >> 12) << 3; + pte_end = ((gpuobj->im_pramin->size >> 12) << 3) + pte; + while (pte < pte_end) { + NV_WI32(pte + 0, 0x00000000); + NV_WI32(pte + 4, 0x00000000); + pte += 8; + } + + gpuobj->im_bound = 0; + return 0; +} + -- cgit v1.2.3 From 3c58195ccd346cc61f98b9f89cf074edf6886723 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 9 Jul 2007 15:37:37 +1000 Subject: nouveau: Avoid oops Turns out lastclose() gets called even if firstopen() has never been... --- shared-core/nouveau_drv.h | 6 ++++++ shared-core/nouveau_state.c | 23 +++++++++++++++-------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index 81972db5..12b78a7e 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -184,6 +184,12 @@ typedef struct nouveau_engine_func { } nouveau_engine_func_t; typedef struct drm_nouveau_private { + enum { + NOUVEAU_CARD_INIT_DOWN, + NOUVEAU_CARD_INIT_DONE, + NOUVEAU_CARD_INIT_FAILED + } init_state; + /* the card type, takes NV_* as values */ int card_type; /* exact chipset, derived from NV_PMC_BOOT_0 */ diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c index bcb974bf..c51d7d5d 100644 --- a/shared-core/nouveau_state.c +++ b/shared-core/nouveau_state.c @@ -280,6 +280,7 @@ static int nouveau_card_init(drm_device_t *dev) ret = nouveau_init_engine_ptrs(dev); if (ret) return ret; engine = &dev_priv->Engine; + dev_priv->init_state = NOUVEAU_CARD_INIT_FAILED; /* Initialise instance memory, must happen before mem_init so we * know exactly how much VRAM we're able to use for "normal" @@ -316,6 +317,7 @@ static int nouveau_card_init(drm_device_t *dev) /* what about PVIDEO/PCRTC/PRAMDAC etc? */ + dev_priv->init_state = NOUVEAU_CARD_INIT_DONE; return 0; } @@ -324,14 +326,18 @@ static void nouveau_card_takedown(drm_device_t *dev) drm_nouveau_private_t *dev_priv = dev->dev_private; nouveau_engine_func_t *engine = &dev_priv->Engine; - engine->fifo.takedown(dev); - engine->graph.takedown(dev); - engine->fb.takedown(dev); - engine->timer.takedown(dev); - engine->mc.takedown(dev); - nouveau_gpuobj_takedown(dev); - nouveau_mem_close(dev); - engine->instmem.takedown(dev); + if (dev_priv->init_state != NOUVEAU_CARD_INIT_DOWN) { + engine->fifo.takedown(dev); + engine->graph.takedown(dev); + engine->fb.takedown(dev); + engine->timer.takedown(dev); + engine->mc.takedown(dev); + nouveau_gpuobj_takedown(dev); + nouveau_mem_close(dev); + engine->instmem.takedown(dev); + + dev_priv->init_state = NOUVEAU_CARD_INIT_DOWN; + } } /* here a client dies, release the stuff that was allocated for its filp */ @@ -371,6 +377,7 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) dev_priv->card_type=flags&NOUVEAU_FAMILY; dev_priv->flags=flags&NOUVEAU_FLAGS; + dev_priv->init_state = NOUVEAU_CARD_INIT_DOWN; dev->dev_private = (void *)dev_priv; -- cgit v1.2.3 From 31e33813e8c1b085683e68524e680882368e59a9 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 9 Jul 2007 20:02:14 +1000 Subject: nouveau: Don't be so strict on dev_private; nouveau_gpuobj_t *cpramin; - if ((channel > 0) && gpuobj->im_channel != channel) { - DRM_ERROR("Channel mismatch: obj %d, ref %d\n", - gpuobj->im_channel, channel); - return DRM_ERR(EINVAL); - } - /* card_type < NV_50) { *inst = gpuobj->im_pramin->start; return 0; } + if ((channel > 0) && gpuobj->im_channel != channel) { + DRM_ERROR("Channel mismatch: obj %d, ref %d\n", + gpuobj->im_channel, channel); + return DRM_ERR(EINVAL); + } + /* NV50 channel-local instance */ if (channel > 0) { cpramin = dev_priv->fifos[channel]->ramin->gpuobj; -- cgit v1.2.3 From 023f7d9c0064f912415c92a85c3a9d722191909f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 9 Jul 2007 23:58:00 +1000 Subject: nouveau: Allocate mappable VRAM for notifiers.. --- shared-core/nouveau_fifo.c | 4 ---- shared-core/nouveau_notifier.c | 1 + 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c index c140a634..4095a57f 100644 --- a/shared-core/nouveau_fifo.c +++ b/shared-core/nouveau_fifo.c @@ -497,10 +497,6 @@ static int nouveau_ioctl_fifo_alloc(DRM_IOCTL_ARGS) /* and the notifier block */ init.notifier = chan->notifier_block->start; init.notifier_size = chan->notifier_block->size; - res = drm_addmap(dev, init.notifier, init.notifier_size, _DRM_REGISTERS, - 0, &chan->notifier_map); - if (res != 0) - return res; DRM_COPY_TO_USER_IOCTL((drm_nouveau_fifo_alloc_t __user *)data, init, sizeof(init)); diff --git a/shared-core/nouveau_notifier.c b/shared-core/nouveau_notifier.c index 9e792e57..30216293 100644 --- a/shared-core/nouveau_notifier.c +++ b/shared-core/nouveau_notifier.c @@ -41,6 +41,7 @@ nouveau_notifier_init_channel(drm_device_t *dev, int channel, DRMFILE filp) flags = NOUVEAU_MEM_AGP | NOUVEAU_MEM_FB_ACCEPTABLE; else flags = NOUVEAU_MEM_FB; + flags |= NOUVEAU_MEM_MAPPED; chan->notifier_block = nouveau_mem_alloc(dev, 0, PAGE_SIZE, flags,filp); if (!chan->notifier_block) -- cgit v1.2.3 From 04e4922c0c407a9f0cfe268f62130891e98fc682 Mon Sep 17 00:00:00 2001 From: Arthur Huillet Date: Wed, 11 Jul 2007 02:33:12 +0200 Subject: Made drm_sg_alloc accessible from inside the DRM - drm_sg_alloc_ioctl is the ioctl wrapper --- bsd-core/drmP.h | 3 ++- bsd-core/drm_drv.c | 2 +- bsd-core/drm_scatter.c | 39 +++++++++++++++++++++++--------------- linux-core/drmP.h | 3 ++- linux-core/drm_drv.c | 2 +- linux-core/drm_scatter.c | 49 ++++++++++++++++++++++++++++++------------------ 6 files changed, 61 insertions(+), 37 deletions(-) diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h index 9ba3d502..6e05b58f 100644 --- a/bsd-core/drmP.h +++ b/bsd-core/drmP.h @@ -915,6 +915,7 @@ int drm_agp_unbind(drm_device_t *dev, drm_agp_binding_t *request); /* Scatter Gather Support (drm_scatter.c) */ void drm_sg_cleanup(drm_sg_mem_t *entry); +int drm_sg_alloc(drm_device_t * dev, drm_scatter_gather_t * request); #ifdef __FreeBSD__ /* sysctl support (drm_sysctl.h) */ @@ -989,7 +990,7 @@ int drm_agp_unbind_ioctl(DRM_IOCTL_ARGS); int drm_agp_bind_ioctl(DRM_IOCTL_ARGS); /* Scatter Gather Support (drm_scatter.c) */ -int drm_sg_alloc(DRM_IOCTL_ARGS); +int drm_sg_alloc_ioctl(DRM_IOCTL_ARGS); int drm_sg_free(DRM_IOCTL_ARGS); /* consistent PCI memory functions (drm_pci.c) */ diff --git a/bsd-core/drm_drv.c b/bsd-core/drm_drv.c index baaeb43c..069774c1 100644 --- a/bsd-core/drm_drv.c +++ b/bsd-core/drm_drv.c @@ -117,7 +117,7 @@ static drm_ioctl_desc_t drm_ioctls[256] = { [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = { drm_agp_bind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { drm_agp_unbind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, - [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC)] = { drm_sg_alloc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, + [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC)] = { drm_sg_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, [DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = { drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = { drm_wait_vblank, 0 }, diff --git a/bsd-core/drm_scatter.c b/bsd-core/drm_scatter.c index 9dc280a4..46222f18 100644 --- a/bsd-core/drm_scatter.c +++ b/bsd-core/drm_scatter.c @@ -40,28 +40,20 @@ void drm_sg_cleanup(drm_sg_mem_t *entry) free(entry, M_DRM); } -int drm_sg_alloc(DRM_IOCTL_ARGS) +int drm_sg_alloc(drm_device_t * dev, drm_scatter_gather_t * request) { - DRM_DEVICE; - drm_scatter_gather_t request; drm_sg_mem_t *entry; unsigned long pages; - int i; - - DRM_DEBUG( "%s\n", __FUNCTION__ ); if ( dev->sg ) return EINVAL; - DRM_COPY_FROM_USER_IOCTL(request, (drm_scatter_gather_t *)data, - sizeof(request) ); - entry = malloc(sizeof(*entry), M_DRM, M_WAITOK | M_ZERO); if ( !entry ) return ENOMEM; pages = round_page(request.size) / PAGE_SIZE; - DRM_DEBUG( "sg size=%ld pages=%ld\n", request.size, pages ); + DRM_DEBUG( "sg size=%ld pages=%ld\n", request->size, pages ); entry->pages = pages; @@ -86,11 +78,7 @@ int drm_sg_alloc(DRM_IOCTL_ARGS) DRM_DEBUG( "sg alloc handle = %08lx\n", entry->handle ); entry->virtual = (void *)entry->handle; - request.handle = entry->handle; - - DRM_COPY_TO_USER_IOCTL( (drm_scatter_gather_t *)data, - request, - sizeof(request) ); + request->handle = entry->handle; DRM_LOCK(); if (dev->sg) { @@ -101,6 +89,27 @@ int drm_sg_alloc(DRM_IOCTL_ARGS) dev->sg = entry; DRM_UNLOCK(); +} + +int drm_sg_alloc_ioctl(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_scatter_gather_t request; + int ret; + + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + + DRM_COPY_FROM_USER_IOCTL(request, (drm_scatter_gather_t *)data, + sizeof(request) ); + + ret = drm_sg_alloc(dev, &request); + if ( ret ) return ret; + + DRM_COPY_TO_USER_IOCTL( (drm_scatter_gather_t *)data, + request, + sizeof(request) ); + return 0; } diff --git a/linux-core/drmP.h b/linux-core/drmP.h index c992c8d9..c274f1fa 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1129,8 +1129,9 @@ extern int drm_proc_cleanup(int minor, /* Scatter Gather Support (drm_scatter.h) */ extern void drm_sg_cleanup(drm_sg_mem_t * entry); -extern int drm_sg_alloc(struct inode *inode, struct file *filp, +extern int drm_sg_alloc_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +extern int drm_sg_alloc(drm_device_t *dev, drm_scatter_gather_t * request); extern int drm_sg_free(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 6bbe7fca..0d446a12 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -113,7 +113,7 @@ static drm_ioctl_desc_t drm_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = {drm_agp_unbind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, #endif - [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC)] = {drm_sg_alloc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC)] = {drm_sg_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, [DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = {drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = {drm_wait_vblank, 0}, diff --git a/linux-core/drm_scatter.c b/linux-core/drm_scatter.c index e5c9f877..c0d6db24 100644 --- a/linux-core/drm_scatter.c +++ b/linux-core/drm_scatter.c @@ -55,6 +55,7 @@ void drm_sg_cleanup(drm_sg_mem_t * entry) entry->pages * sizeof(*entry->pagelist), DRM_MEM_PAGES); drm_free(entry, sizeof(*entry), DRM_MEM_SGLISTS); } +EXPORT_SYMBOL(drm_sg_cleanup); #ifdef _LP64 # define ScatterHandle(x) (unsigned int)((x >> 32) + (x & ((1L << 32) - 1))) @@ -62,13 +63,8 @@ void drm_sg_cleanup(drm_sg_mem_t * entry) # define ScatterHandle(x) (unsigned int)(x) #endif -int drm_sg_alloc(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_sg_alloc(drm_device_t * dev, drm_scatter_gather_t * request) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->head->dev; - drm_scatter_gather_t __user *argp = (void __user *)arg; - drm_scatter_gather_t request; drm_sg_mem_t *entry; unsigned long pages, i, j; @@ -80,17 +76,13 @@ int drm_sg_alloc(struct inode *inode, struct file *filp, if (dev->sg) return -EINVAL; - if (copy_from_user(&request, argp, sizeof(request))) - return -EFAULT; - entry = drm_alloc(sizeof(*entry), DRM_MEM_SGLISTS); if (!entry) return -ENOMEM; memset(entry, 0, sizeof(*entry)); - - pages = (request.size + PAGE_SIZE - 1) / PAGE_SIZE; - DRM_DEBUG("sg size=%ld pages=%ld\n", request.size, pages); + pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE; + DRM_DEBUG("sg size=%ld pages=%ld\n", request->size, pages); entry->pages = pages; entry->pagelist = drm_alloc(pages * sizeof(*entry->pagelist), @@ -142,12 +134,7 @@ int drm_sg_alloc(struct inode *inode, struct file *filp, SetPageReserved(entry->pagelist[j]); } - request.handle = entry->handle; - - if (copy_to_user(argp, &request, sizeof(request))) { - drm_sg_cleanup(entry); - return -EFAULT; - } + request->handle = entry->handle; dev->sg = entry; @@ -196,6 +183,32 @@ int drm_sg_alloc(struct inode *inode, struct file *filp, failed: drm_sg_cleanup(entry); return -ENOMEM; + +} +EXPORT_SYMBOL(drm_sg_alloc); + +int drm_sg_alloc_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_scatter_gather_t __user *argp = (void __user *)arg; + drm_scatter_gather_t request; + int ret; + + if (copy_from_user(&request, argp, sizeof(request))) + return -EFAULT; + + ret = drm_sg_alloc(priv->head->dev, &request); + if ( ret ) return ret; + + if (copy_to_user(argp, &request, sizeof(request))) { + drm_sg_cleanup(priv->head->dev->sg); + return -EFAULT; + } + + + return 0; + } int drm_sg_free(struct inode *inode, struct file *filp, -- cgit v1.2.3 From 694e1c5c3f768436651ddf95e11ab5a89ccc8ffa Mon Sep 17 00:00:00 2001 From: Arthur Huillet Date: Wed, 11 Jul 2007 02:35:10 +0200 Subject: Added support for PCIGART for PCI(E) cards. Bumped DRM interface patchlevel. --- shared-core/nouveau_drm.h | 16 +++-- shared-core/nouveau_drv.h | 3 +- shared-core/nouveau_fifo.c | 18 +++-- shared-core/nouveau_mem.c | 89 +++++++++++++++++------- shared-core/nouveau_object.c | 161 ++++++++++++++++++++++++++++++------------- shared-core/nouveau_reg.h | 2 + shared-core/nouveau_state.c | 12 ++++ 7 files changed, 215 insertions(+), 86 deletions(-) diff --git a/shared-core/nouveau_drm.h b/shared-core/nouveau_drm.h index 0758991a..7abe82e0 100644 --- a/shared-core/nouveau_drm.h +++ b/shared-core/nouveau_drm.h @@ -25,7 +25,7 @@ #ifndef __NOUVEAU_DRM_H__ #define __NOUVEAU_DRM_H__ -#define NOUVEAU_DRM_HEADER_PATCHLEVEL 7 +#define NOUVEAU_DRM_HEADER_PATCHLEVEL 8 typedef struct drm_nouveau_fifo_alloc { uint32_t fb_ctxdma_handle; @@ -68,11 +68,14 @@ drm_nouveau_notifier_alloc_t; #define NOUVEAU_MEM_AGP 0x00000002 #define NOUVEAU_MEM_FB_ACCEPTABLE 0x00000004 #define NOUVEAU_MEM_AGP_ACCEPTABLE 0x00000008 -#define NOUVEAU_MEM_PINNED 0x00000010 -#define NOUVEAU_MEM_USER_BACKED 0x00000020 -#define NOUVEAU_MEM_MAPPED 0x00000040 -#define NOUVEAU_MEM_INSTANCE 0x00000080 /* internal */ -#define NOUVEAU_MEM_NOTIFIER 0x00000100 /* internal */ +#define NOUVEAU_MEM_PCI 0x00000010 +#define NOUVEAU_MEM_PCI_ACCEPTABLE 0x00000020 +#define NOUVEAU_MEM_PINNED 0x00000040 +#define NOUVEAU_MEM_USER_BACKED 0x00000080 +#define NOUVEAU_MEM_MAPPED 0x00000100 +#define NOUVEAU_MEM_INSTANCE 0x00000200 /* internal */ +#define NOUVEAU_MEM_NOTIFIER 0x00000400 /* internal */ + typedef struct drm_nouveau_mem_alloc { int flags; int alignment; @@ -95,6 +98,7 @@ drm_nouveau_mem_free_t; #define NOUVEAU_GETPARAM_AGP_PHYSICAL 7 #define NOUVEAU_GETPARAM_FB_SIZE 8 #define NOUVEAU_GETPARAM_AGP_SIZE 9 +#define NOUVEAU_GETPARAM_PCI_PHYSICAL 10 typedef struct drm_nouveau_getparam { uint64_t param; uint64_t value; diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index 12b78a7e..ea03fe37 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -34,7 +34,7 @@ #define DRIVER_MAJOR 0 #define DRIVER_MINOR 0 -#define DRIVER_PATCHLEVEL 7 +#define DRIVER_PATCHLEVEL 8 #define NOUVEAU_FAMILY 0x0000FFFF #define NOUVEAU_FLAGS 0xFFFF0000 @@ -229,6 +229,7 @@ typedef struct drm_nouveau_private { struct mem_block *fb_heap; struct mem_block *fb_nomap_heap; struct mem_block *ramin_heap; + struct mem_block *pci_heap; /* context table pointed to be NV_PGRAPH_CHANNEL_CTX_TABLE (0x400780) */ uint32_t ctx_table_size; diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c index 4095a57f..bc3a9948 100644 --- a/shared-core/nouveau_fifo.c +++ b/shared-core/nouveau_fifo.c @@ -210,11 +210,19 @@ nouveau_fifo_cmdbuf_alloc(struct drm_device *dev, int channel) } if (cb->flags & NOUVEAU_MEM_AGP) { - ret = nouveau_gpuobj_dma_new - (dev, channel, NV_CLASS_DMA_IN_MEMORY, - cb->start - dev_priv->agp_phys, - cb->size, NV_DMA_ACCESS_RO, NV_DMA_TARGET_AGP, - &pushbuf); + DRM_DEBUG("Creating CB in AGP memory\n"); + ret = nouveau_gpuobj_dma_new(dev, channel, + NV_CLASS_DMA_IN_MEMORY, + cb->start - dev_priv->agp_phys, + cb->size, + NV_DMA_ACCESS_RO, NV_DMA_TARGET_AGP, &pushbuf); + } else if ( cb->flags & NOUVEAU_MEM_PCI) { + DRM_DEBUG("Creating CB in PCI memory starting at virt 0x%08llx size %d\n", cb->start, cb->size); + ret = nouveau_gpuobj_dma_new(dev, channel, + NV_CLASS_DMA_IN_MEMORY, + cb->start, + cb->size, + NV_DMA_ACCESS_RO, NV_DMA_TARGET_PCI_NONLINEAR, &pushbuf); } else if (dev_priv->card_type != NV_04) { ret = nouveau_gpuobj_dma_new (dev, channel, NV_CLASS_DMA_IN_MEMORY, diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index c75a9356..79f94fd4 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -211,6 +211,10 @@ void nouveau_mem_close(struct drm_device *dev) drm_nouveau_private_t *dev_priv = dev->dev_private; nouveau_mem_takedown(&dev_priv->agp_heap); nouveau_mem_takedown(&dev_priv->fb_heap); + if ( dev_priv->pci_heap ) + { + nouveau_mem_takedown(&dev_priv->pci_heap); + } } /* returns the amount of FB ram in bytes */ @@ -283,8 +287,10 @@ int nouveau_mem_init(struct drm_device *dev) { drm_nouveau_private_t *dev_priv = dev->dev_private; uint32_t fb_size; + drm_scatter_gather_t sgreq; dev_priv->agp_phys=0; dev_priv->fb_phys=0; + sgreq . size = 4 << 20; //4MB of PCI scatter-gather zone /* init AGP */ dev_priv->agp_heap=NULL; @@ -340,8 +346,26 @@ int nouveau_mem_init(struct drm_device *dev) dev_priv->agp_phys = info.aperture_base; dev_priv->agp_available_size = info.aperture_size; } + +goto have_agp; no_agp: + dev_priv->pci_heap = NULL; + DRM_DEBUG("Allocating sg memory for PCI DMA\n"); + if ( drm_sg_alloc(dev, &sgreq) ) + { + DRM_ERROR("Unable to allocate 4MB of scatter-gather pages for PCI DMA!"); + goto no_pci; + } + DRM_DEBUG("Got %d KiB\n", (dev->sg->pages * PAGE_SIZE) >> 10); + if ( nouveau_mem_init_heap(&dev_priv->pci_heap, dev->sg->virtual, dev->sg->pages * PAGE_SIZE)) + { + DRM_ERROR("Unable to initialize pci_heap!"); + goto no_pci; + } + +no_pci: +have_agp: /* setup a mtrr over the FB */ dev_priv->fb_mtrr = drm_mtrr_add(drm_get_resource_start(dev, 1), nouveau_mem_fb_amount(dev), @@ -405,29 +429,40 @@ struct mem_block* nouveau_mem_alloc(struct drm_device *dev, int alignment, uint6 if (size & (~PAGE_MASK)) size = ((size/PAGE_SIZE) + 1) * PAGE_SIZE; - if (flags&NOUVEAU_MEM_AGP) { - type=NOUVEAU_MEM_AGP; - block = nouveau_mem_alloc_block(dev_priv->agp_heap, size, - alignment, filp); - if (block) goto alloc_ok; - } - if (flags&(NOUVEAU_MEM_FB|NOUVEAU_MEM_FB_ACCEPTABLE)) { - type=NOUVEAU_MEM_FB; - if (!(flags&NOUVEAU_MEM_MAPPED)) { - block = nouveau_mem_alloc_block(dev_priv->fb_nomap_heap, - size, alignment, filp); - if (block) goto alloc_ok; - } - block = nouveau_mem_alloc_block(dev_priv->fb_heap, size, - alignment, filp); - if (block) goto alloc_ok; - } - if (flags&NOUVEAU_MEM_AGP_ACCEPTABLE) { - type=NOUVEAU_MEM_AGP; - block = nouveau_mem_alloc_block(dev_priv->agp_heap, size, - alignment, filp); - if (block) goto alloc_ok; - } + +#define NOUVEAU_MEM_ALLOC_AGP {\ + type=NOUVEAU_MEM_AGP;\ + block = nouveau_mem_alloc_block(dev_priv->agp_heap, size,\ + alignment, filp);\ + if (block) goto alloc_ok;\ + } + +#define NOUVEAU_MEM_ALLOC_PCI {\ + type = NOUVEAU_MEM_PCI;\ + block = nouveau_mem_alloc_block(dev_priv->pci_heap, size, alignment, filp);\ + if ( block ) goto alloc_ok;\ + } + +#define NOUVEAU_MEM_ALLOC_FB {\ + type=NOUVEAU_MEM_FB;\ + if (!(flags&NOUVEAU_MEM_MAPPED)) {\ + block = nouveau_mem_alloc_block(dev_priv->fb_nomap_heap,\ + size, alignment, filp); \ + if (block) goto alloc_ok;\ + }\ + block = nouveau_mem_alloc_block(dev_priv->fb_heap, size,\ + alignment, filp);\ + if (block) goto alloc_ok;\ + } + + + if (flags&NOUVEAU_MEM_FB) NOUVEAU_MEM_ALLOC_FB + if (flags&NOUVEAU_MEM_AGP) NOUVEAU_MEM_ALLOC_AGP + if (flags&NOUVEAU_MEM_PCI) NOUVEAU_MEM_ALLOC_PCI + if (flags&NOUVEAU_MEM_FB_ACCEPTABLE) NOUVEAU_MEM_ALLOC_FB + if (flags&NOUVEAU_MEM_AGP_ACCEPTABLE) NOUVEAU_MEM_ALLOC_AGP + if (flags&NOUVEAU_MEM_PCI_ACCEPTABLE) NOUVEAU_MEM_ALLOC_PCI + return NULL; @@ -436,15 +471,19 @@ alloc_ok: if (flags&NOUVEAU_MEM_MAPPED) { - int ret; + int ret = 0; block->flags|=NOUVEAU_MEM_MAPPED; if (type == NOUVEAU_MEM_AGP) ret = drm_addmap(dev, block->start - dev->agp->base, block->size, _DRM_AGP, 0, &block->map); - else + else if (type == NOUVEAU_MEM_FB) ret = drm_addmap(dev, block->start, block->size, _DRM_FRAME_BUFFER, 0, &block->map); + else if (type == NOUVEAU_MEM_PCI) + ret = drm_addmap(dev, block->start - (unsigned long int)dev->sg->virtual, block->size, + _DRM_SCATTER_GATHER, 0, &block->map); + if (ret) { nouveau_mem_free_block(block); return NULL; diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index bf811b4b..dcb29b40 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -515,6 +515,20 @@ nouveau_gpuobj_new_fake(drm_device_t *dev, uint32_t offset, uint32_t size, return 0; } + +static int +nouveau_gpuobj_class_instmem_size(drm_device_t *dev, int class) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + + /*XXX: dodgy hack for now */ + if (dev_priv->card_type >= NV_50) + return 24; + if (dev_priv->card_type >= NV_40) + return 32; + return 16; +} + /* DMA objects are used to reference a piece of memory in the framebuffer, PCI or AGP address space. Each object is 16 bytes big @@ -528,31 +542,20 @@ nouveau_gpuobj_new_fake(drm_device_t *dev, uint32_t offset, uint32_t size, 17:16 target: 0 NV memory, 1 NV memory tiled, 2 PCI, 3 AGP 31:20 dma adjust (bits 0-11 of the address) entry[1] - dma limit - entry[2] + dma limit (size of transfer) + entry[X] 1 0 readonly, 1 readwrite - 31:12 dma frame address (bits 12-31 of the address) + 31:12 dma frame address of the page (bits 12-31 of the address) + entry[N] + page table terminator, same value as the first pte, as does nvidia + rivatv uses 0xffffffff - Non linear page tables seem to need a list of frame addresses afterwards, - the rivatv project has some info on this. + Non linear page tables need a list of frame addresses afterwards, + the rivatv project has some info on this. The method below creates a DMA object in instance RAM and returns a handle to it that can be used to set up context objects. */ - -static int -nouveau_gpuobj_class_instmem_size(drm_device_t *dev, int class) -{ - drm_nouveau_private_t *dev_priv = dev->dev_private; - - /*XXX: dodgy hack for now */ - if (dev_priv->card_type >= NV_50) - return 24; - if (dev_priv->card_type >= NV_40) - return 32; - return 16; -} - int nouveau_gpuobj_dma_new(drm_device_t *dev, int channel, int class, uint64_t offset, uint64_t size, int access, int target, @@ -560,13 +563,28 @@ nouveau_gpuobj_dma_new(drm_device_t *dev, int channel, int class, { drm_nouveau_private_t *dev_priv = dev->dev_private; int ret; - + uint32_t is_scatter_gather = 0; + DRM_DEBUG("ch%d class=0x%04x offset=0x%llx size=0x%llx\n", channel, class, offset, size); DRM_DEBUG("access=%d target=%d\n", access, target); + switch (target) { + case NV_DMA_TARGET_AGP: + offset += dev_priv->agp_phys; + break; + case NV_DMA_TARGET_PCI_NONLINEAR: + /*assume the "offset" is a virtual memory address*/ + is_scatter_gather = 1; + /*put back the right value*/ + target = NV_DMA_TARGET_PCI; + break; + default: + break; + } + ret = nouveau_gpuobj_new(dev, channel, - nouveau_gpuobj_class_instmem_size(dev, class), + is_scatter_gather ? ((((size + PAGE_SIZE - 1) / PAGE_SIZE) << 2) + 12) : nouveau_gpuobj_class_instmem_size(dev, class), 16, NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE, gpuobj); @@ -577,22 +595,53 @@ nouveau_gpuobj_dma_new(drm_device_t *dev, int channel, int class, if (dev_priv->card_type < NV_50) { uint32_t frame, adjust, pte_flags = 0; - - if (target == NV_DMA_TARGET_AGP) - offset += dev_priv->agp_phys; - if (access != NV_DMA_ACCESS_RO) - pte_flags |= (1<<1); - frame = offset & ~0x00000fff; adjust = offset & 0x00000fff; - - INSTANCE_WR(*gpuobj, 0, ((1<<12) | (1<<13) | - (adjust << 20) | + if (access != NV_DMA_ACCESS_RO) + pte_flags |= (1<<1); + + if ( ! is_scatter_gather ) + { + frame = offset & ~0x00000fff; + + INSTANCE_WR(*gpuobj, 0, ((1<<12) | (1<<13) | + (adjust << 20) | (access << 14) | (target << 16) | class)); - INSTANCE_WR(*gpuobj, 1, size - 1); - INSTANCE_WR(*gpuobj, 2, frame | pte_flags); - INSTANCE_WR(*gpuobj, 3, frame | pte_flags); + INSTANCE_WR(*gpuobj, 1, size - 1); + INSTANCE_WR(*gpuobj, 2, frame | pte_flags); + INSTANCE_WR(*gpuobj, 3, frame | pte_flags); + } + else + { + uint32_t instance_offset; + uint32_t bus_addr; + size = (uint32_t) size; + + DRM_DEBUG("Creating PCI DMA object using virtual zone starting at 0x%08x, size %d\n", (uint32_t) offset, (uint32_t)size); + INSTANCE_WR(*gpuobj, 0, ((1<<12) | (0<<13) | + (adjust << 20) | + (access << 14) | + (target << 16) | + class)); + INSTANCE_WR(*gpuobj, 1, size-1); + + /*write starting at the third dword*/ + instance_offset = 2; + + /*for each PAGE, get its bus address, fill in the page table entry, and advance*/ + while ( size > 0 ) { + bus_addr = (uint32_t) page_address(vmalloc_to_page((void *) (uint32_t) offset)); + bus_addr |= (offset & ~PAGE_MASK); + bus_addr = virt_to_bus((void *)bus_addr); + frame = bus_addr & ~0x00000FFF; + INSTANCE_WR(*gpuobj, instance_offset, frame | pte_flags); + offset += PAGE_SIZE; + instance_offset ++; + size -= PAGE_SIZE; + } + + } } else { INSTANCE_WR(*gpuobj, 0, 0x00190000 | class); INSTANCE_WR(*gpuobj, 1, offset + size - 1); @@ -804,24 +853,38 @@ nouveau_gpuobj_channel_init(drm_device_t *dev, int channel, return ret; } - /* non-AGP unimplemented */ - if (dev_priv->agp_heap == NULL) - return 0; - - /* GART ctxdma */ - if ((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY, - 0, dev_priv->agp_available_size, - NV_DMA_ACCESS_RW, NV_DMA_TARGET_AGP, - &tt))) { - DRM_ERROR("Error creating TT ctxdma: %d\n", ret); - return ret; + if (dev_priv->agp_heap) { + /* AGPGART ctxdma */ + if ((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY, + 0, dev_priv->agp_available_size, + NV_DMA_ACCESS_RW, + NV_DMA_TARGET_AGP, &tt))) { + DRM_ERROR("Error creating AGP TT ctxdma: %d\n", DRM_ERR(ENOMEM)); + return DRM_ERR(ENOMEM); + } + + ret = nouveau_gpuobj_ref_add(dev, channel, tt_h, tt, NULL); + if (ret) { + DRM_ERROR("Error referencing AGP TT ctxdma: %d\n", ret); + return ret; + } } - - if ((ret = nouveau_gpuobj_ref_add(dev, channel, tt_h, tt, NULL))) { - DRM_ERROR("Error referencing TT ctxdma: %d\n", ret); - return ret; + else { + /*PCI*/ + if((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY, + (unsigned int) dev->sg->virtual, dev->sg->pages * PAGE_SIZE, + NV_DMA_ACCESS_RW, + NV_DMA_TARGET_PCI_NONLINEAR, &tt))) { + DRM_ERROR("Error creating PCI TT ctxdma: %d\n", DRM_ERR(ENOMEM)); + return DRM_ERR(ENOMEM); + } + + ret = nouveau_gpuobj_ref_add(dev, channel, tt_h, tt, NULL); + if (ret) { + DRM_ERROR("Error referencing PCI TT ctxdma: %d\n", ret); + return ret; + } } - return 0; } diff --git a/shared-core/nouveau_reg.h b/shared-core/nouveau_reg.h index c2ebc714..a66d2d34 100644 --- a/shared-core/nouveau_reg.h +++ b/shared-core/nouveau_reg.h @@ -39,6 +39,8 @@ #define NV_DMA_TARGET_VIDMEM 0 #define NV_DMA_TARGET_PCI 2 #define NV_DMA_TARGET_AGP 3 +/*The following is not a real value used by nvidia cards, it's changed by nouveau_object_dma_create*/ +#define NV_DMA_TARGET_PCI_NONLINEAR 8 /* Some object classes we care about in the drm */ #define NV_CLASS_DMA_FROM_MEMORY 0x00000002 diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c index c51d7d5d..14b33a4a 100644 --- a/shared-core/nouveau_state.c +++ b/shared-core/nouveau_state.c @@ -348,6 +348,7 @@ void nouveau_preclose(drm_device_t * dev, DRMFILE filp) nouveau_fifo_cleanup(dev, filp); nouveau_mem_release(filp,dev_priv->fb_heap); nouveau_mem_release(filp,dev_priv->agp_heap); + nouveau_mem_release(filp,dev_priv->pci_heap); } /* first module load, setup the mmio/fb mapping */ @@ -442,6 +443,15 @@ int nouveau_ioctl_getparam(DRM_IOCTL_ARGS) case NOUVEAU_GETPARAM_AGP_PHYSICAL: getparam.value=dev_priv->agp_phys; break; + case NOUVEAU_GETPARAM_PCI_PHYSICAL: + if ( dev -> sg ) + getparam.value=dev->sg->virtual; + else + { + DRM_ERROR("Requested PCIGART address, while no PCIGART was created\n"); + DRM_ERR(EINVAL); + } + break; case NOUVEAU_GETPARAM_FB_SIZE: getparam.value=dev_priv->fb_available_size; break; @@ -472,6 +482,8 @@ int nouveau_ioctl_setparam(DRM_IOCTL_ARGS) switch (setparam.value) { case NOUVEAU_MEM_AGP: case NOUVEAU_MEM_FB: + case NOUVEAU_MEM_PCI: + case NOUVEAU_MEM_AGP | NOUVEAU_MEM_PCI_ACCEPTABLE: break; default: DRM_ERROR("invalid CMDBUF_LOCATION value=%lld\n", -- cgit v1.2.3 From 13e1377044d581d692af77656e3bc32c9eb183f7 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 11 Jul 2007 12:38:48 +1000 Subject: nouveau: Some checks on userspace object handles. --- shared-core/nouveau_fifo.c | 3 +++ shared-core/nouveau_object.c | 26 +++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c index bc3a9948..fcdc14c8 100644 --- a/shared-core/nouveau_fifo.c +++ b/shared-core/nouveau_fifo.c @@ -474,6 +474,9 @@ static int nouveau_ioctl_fifo_alloc(DRM_IOCTL_ARGS) DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_fifo_alloc_t __user *) data, sizeof(init)); + if (init.fb_ctxdma_handle == ~0 || init.tt_ctxdma_handle == ~0) + return DRM_ERR(EINVAL); + res = nouveau_fifo_alloc(dev, &init.channel, filp, init.fb_ctxdma_handle, init.tt_ctxdma_handle); diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index dcb29b40..82944c2b 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -470,6 +470,26 @@ nouveau_gpuobj_new_ref(drm_device_t *dev, int oc, int rc, uint32_t handle, return 0; } +static int +nouveau_gpuobj_ref_find(drm_device_t *dev, int channel, uint32_t handle, + nouveau_gpuobj_ref_t **ref_ret) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + struct nouveau_fifo *chan = dev_priv->fifos[channel]; + nouveau_gpuobj_ref_t *ref = chan->ramht_refs; + + while (ref) { + if (ref->handle == handle) { + if (ref_ret) + *ref_ret = ref; + return 0; + } + ref = ref->next; + } + + return DRM_ERR(EINVAL); +} + int nouveau_gpuobj_new_fake(drm_device_t *dev, uint32_t offset, uint32_t size, uint32_t flags, nouveau_gpuobj_t **pgpuobj, @@ -927,7 +947,11 @@ int nouveau_ioctl_grobj_alloc(DRM_IOCTL_ARGS) } //FIXME: check args, only allow trusted objects to be created - //FIXME: check for pre-existing handle + + if (init.handle == ~0) + return DRM_ERR(EINVAL); + if (nouveau_gpuobj_ref_find(dev, init.channel, init.handle, NULL) == 0) + return DRM_ERR(EEXIST); if ((ret = nouveau_gpuobj_gr_new(dev, init.channel, init.class, &gr))) { DRM_ERROR("Error creating gr object: %d (%d/0x%08x)\n", -- cgit v1.2.3 From 5ccadac9e3b1beb8ac0177c7a39862094fe3b6de Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 11 Jul 2007 14:22:59 +1000 Subject: nouveau/nv50: G80 fixes. Again, no hardware, so no idea if it'll even work yet. I understand how the PRAMIN setup works now, un-hardcoding stuff will come "RealSoonNow(tm)". --- shared-core/nv50_fifo.c | 3 +-- shared-core/nv50_instmem.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/shared-core/nv50_fifo.c b/shared-core/nv50_fifo.c index d4c3ca87..ee1fb887 100644 --- a/shared-core/nv50_fifo.c +++ b/shared-core/nv50_fifo.c @@ -235,8 +235,7 @@ nv50_fifo_create_context(drm_device_t *dev, int channel) DRM_DEBUG("ch%d\n", channel); if (IS_G80) { - uint32_t ramfc_offset; - ramfc_offset = chan->ramin->gpuobj->im_pramin->start + 0x1000; + uint32_t ramfc_offset = chan->ramin->gpuobj->im_pramin->start; if ((ret = nouveau_gpuobj_new_fake(dev, ramfc_offset, 0x100, NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE, diff --git a/shared-core/nv50_instmem.c b/shared-core/nv50_instmem.c index 4aca9e7d..1ea64b35 100644 --- a/shared-core/nv50_instmem.c +++ b/shared-core/nv50_instmem.c @@ -68,7 +68,7 @@ nv50_instmem_init(drm_device_t *dev) } else { unk = cb + 0x5400; cb0 = cb + 0x5440; - cb1 = cb + 0x1438; + cb1 = cb + 0x1478; } DRM_DEBUG("PRAMIN config:\n"); -- cgit v1.2.3 From d26ae22c2b17e0f193334cefec7d141befcfa1ee Mon Sep 17 00:00:00 2001 From: Arthur Huillet Date: Wed, 11 Jul 2007 14:56:27 +0200 Subject: fixed bug that prevented PCIE cards from actually using PCIGART - NV50 will probably still have a problem --- shared-core/nouveau_fifo.c | 2 +- shared-core/nouveau_mem.c | 5 ++--- shared-core/nouveau_state.c | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c index fcdc14c8..88f66d70 100644 --- a/shared-core/nouveau_fifo.c +++ b/shared-core/nouveau_fifo.c @@ -217,7 +217,7 @@ nouveau_fifo_cmdbuf_alloc(struct drm_device *dev, int channel) cb->size, NV_DMA_ACCESS_RO, NV_DMA_TARGET_AGP, &pushbuf); } else if ( cb->flags & NOUVEAU_MEM_PCI) { - DRM_DEBUG("Creating CB in PCI memory starting at virt 0x%08llx size %d\n", cb->start, cb->size); + DRM_DEBUG("Creating CB in PCI memory\n", cb->start, cb->size); ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY, cb->start, diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index 79f94fd4..c545acf2 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -345,9 +345,9 @@ int nouveau_mem_init(struct drm_device *dev) dev_priv->agp_phys = info.aperture_base; dev_priv->agp_available_size = info.aperture_size; + goto have_agp; } -goto have_agp; no_agp: dev_priv->pci_heap = NULL; DRM_DEBUG("Allocating sg memory for PCI DMA\n"); @@ -357,8 +357,7 @@ no_agp: goto no_pci; } - DRM_DEBUG("Got %d KiB\n", (dev->sg->pages * PAGE_SIZE) >> 10); - if ( nouveau_mem_init_heap(&dev_priv->pci_heap, dev->sg->virtual, dev->sg->pages * PAGE_SIZE)) + if ( nouveau_mem_init_heap(&dev_priv->pci_heap, (uint64_t) dev->sg->virtual, dev->sg->pages * PAGE_SIZE)) { DRM_ERROR("Unable to initialize pci_heap!"); goto no_pci; diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c index 14b33a4a..fe3db168 100644 --- a/shared-core/nouveau_state.c +++ b/shared-core/nouveau_state.c @@ -445,11 +445,11 @@ int nouveau_ioctl_getparam(DRM_IOCTL_ARGS) break; case NOUVEAU_GETPARAM_PCI_PHYSICAL: if ( dev -> sg ) - getparam.value=dev->sg->virtual; + getparam.value=(uint64_t) dev->sg->virtual; else { DRM_ERROR("Requested PCIGART address, while no PCIGART was created\n"); - DRM_ERR(EINVAL); + return DRM_ERR(EINVAL); } break; case NOUVEAU_GETPARAM_FB_SIZE: -- cgit v1.2.3 From b301a9051b3fd9ad3dce6bcf32b06da7953a8b91 Mon Sep 17 00:00:00 2001 From: Arthur Huillet Date: Wed, 11 Jul 2007 15:01:37 +0200 Subject: NV50 will not attempt to use PCIGART now --- shared-core/nouveau_mem.c | 3 +++ shared-core/nouveau_object.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index c545acf2..a428b813 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -349,6 +349,9 @@ int nouveau_mem_init(struct drm_device *dev) } no_agp: + + if ( dev_priv->card_type >= NV_50 ) goto no_pci; + dev_priv->pci_heap = NULL; DRM_DEBUG("Allocating sg memory for PCI DMA\n"); if ( drm_sg_alloc(dev, &sgreq) ) diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index 82944c2b..0fe32fda 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -890,6 +890,8 @@ nouveau_gpuobj_channel_init(drm_device_t *dev, int channel, } } else { + if ( dev_priv -> card_type >= NV_50 ) return 0; /*no PCIGART for NV50*/ + /*PCI*/ if((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY, (unsigned int) dev->sg->virtual, dev->sg->pages * PAGE_SIZE, -- cgit v1.2.3 From 5fbdf9da8bda996c0a474d13fe69d260f12ffce7 Mon Sep 17 00:00:00 2001 From: Arthur Huillet Date: Thu, 12 Jul 2007 02:35:39 +0200 Subject: fixed object creation code to not Oops on 64bits, worked around memalloc not working on 64bit for PCIGART --- shared-core/nouveau_fifo.c | 2 +- shared-core/nouveau_mem.c | 2 ++ shared-core/nouveau_object.c | 39 +++++++++++++++++++++++++++++++++------ 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c index 88f66d70..7bcb1c8f 100644 --- a/shared-core/nouveau_fifo.c +++ b/shared-core/nouveau_fifo.c @@ -217,7 +217,7 @@ nouveau_fifo_cmdbuf_alloc(struct drm_device *dev, int channel) cb->size, NV_DMA_ACCESS_RO, NV_DMA_TARGET_AGP, &pushbuf); } else if ( cb->flags & NOUVEAU_MEM_PCI) { - DRM_DEBUG("Creating CB in PCI memory\n", cb->start, cb->size); + DRM_DEBUG("Creating CB in PCI memory\n"); ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY, cb->start, diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index a428b813..790f6b5b 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -549,6 +549,8 @@ int nouveau_ioctl_mem_free(DRM_IOCTL_ARGS) block = find_block(dev_priv->fb_heap, memfree.region_offset); else if (memfree.flags&NOUVEAU_MEM_AGP) block = find_block(dev_priv->agp_heap, memfree.region_offset); + else if (memfree.flags&NOUVEAU_MEM_PCI) + block = find_block(dev_priv->pci_heap, memfree.region_offset); if (!block) return DRM_ERR(EFAULT); if (block->filp != filp) diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index 0fe32fda..4f7ad111 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -635,10 +635,10 @@ nouveau_gpuobj_dma_new(drm_device_t *dev, int channel, int class, else { uint32_t instance_offset; - uint32_t bus_addr; + uint64_t bus_addr; size = (uint32_t) size; - DRM_DEBUG("Creating PCI DMA object using virtual zone starting at 0x%08x, size %d\n", (uint32_t) offset, (uint32_t)size); + DRM_DEBUG("Creating PCI DMA object using virtual zone starting at %#llx, size %d\n", offset, (uint32_t)size); INSTANCE_WR(*gpuobj, 0, ((1<<12) | (0<<13) | (adjust << 20) | (access << 14) | @@ -651,10 +651,37 @@ nouveau_gpuobj_dma_new(drm_device_t *dev, int channel, int class, /*for each PAGE, get its bus address, fill in the page table entry, and advance*/ while ( size > 0 ) { - bus_addr = (uint32_t) page_address(vmalloc_to_page((void *) (uint32_t) offset)); + bus_addr = vmalloc_to_page(offset); + if ( ! bus_addr ) + { + DRM_ERROR("Couldn't map virtual address %#llx to a page number\n", offset); + nouveau_gpuobj_del(dev, gpuobj); + return DRM_ERR(ENOMEM); + } + bus_addr = (uint64_t) page_address(bus_addr); + if ( ! bus_addr ) + { + DRM_ERROR("Couldn't find page address for address %#llx\n", offset); + nouveau_gpuobj_del(dev, gpuobj); + return DRM_ERR(ENOMEM); + } bus_addr |= (offset & ~PAGE_MASK); bus_addr = virt_to_bus((void *)bus_addr); - frame = bus_addr & ~0x00000FFF; + if ( ! bus_addr ) + { + DRM_ERROR("Couldn't get bus address for %#llx\n", offset); + nouveau_gpuobj_del(dev, gpuobj); + return DRM_ERR(ENOMEM); + } + + /*if ( bus_addr >= 1 << 32 ) + { + DRM_ERROR("Bus address %#llx is over 32 bits, Nvidia cards cannot address it !\n", bus_addr); + nouveau_gpuobj_del(dev, gpuobj); + return DRM_ERR(EINVAL); + }*/ + + frame = (uint32_t) bus_addr & ~0x00000FFF; INSTANCE_WR(*gpuobj, instance_offset, frame | pte_flags); offset += PAGE_SIZE; instance_offset ++; @@ -894,11 +921,11 @@ nouveau_gpuobj_channel_init(drm_device_t *dev, int channel, /*PCI*/ if((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY, - (unsigned int) dev->sg->virtual, dev->sg->pages * PAGE_SIZE, + dev->sg->virtual, dev->sg->pages * PAGE_SIZE, NV_DMA_ACCESS_RW, NV_DMA_TARGET_PCI_NONLINEAR, &tt))) { DRM_ERROR("Error creating PCI TT ctxdma: %d\n", DRM_ERR(ENOMEM)); - return DRM_ERR(ENOMEM); + return 0; //this is noncritical } ret = nouveau_gpuobj_ref_add(dev, channel, tt_h, tt, NULL); -- cgit v1.2.3 From 750371cb6ea9a64c9d4d4d3b9716c3c68d810d48 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 12 Jul 2007 10:15:16 +1000 Subject: nouveau: separate region_offset into map_handle and offset. --- linux-core/drmP.h | 3 +++ linux-core/drm_bufs.c | 4 ++-- shared-core/nouveau_drm.h | 7 +++--- shared-core/nouveau_drv.h | 3 ++- shared-core/nouveau_fifo.c | 20 ++++++++++++------ shared-core/nouveau_mem.c | 48 ++++++++++++++++++++++++------------------ shared-core/nouveau_notifier.c | 2 -- shared-core/nouveau_object.c | 6 +++--- shared-core/nv50_instmem.c | 2 +- 9 files changed, 55 insertions(+), 40 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index c274f1fa..2bbc6200 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1048,6 +1048,9 @@ extern unsigned long drm_get_resource_start(drm_device_t *dev, unsigned int resource); extern unsigned long drm_get_resource_len(drm_device_t *dev, unsigned int resource); +extern drm_map_list_t *drm_find_matching_map(drm_device_t *dev, + drm_local_map_t *map); + /* DMA support (drm_dma.h) */ extern int drm_dma_setup(drm_device_t * dev); diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c index a2c8a75e..2f3e4b2a 100644 --- a/linux-core/drm_bufs.c +++ b/linux-core/drm_bufs.c @@ -48,8 +48,7 @@ unsigned long drm_get_resource_len(drm_device_t *dev, unsigned int resource) } EXPORT_SYMBOL(drm_get_resource_len); -static drm_map_list_t *drm_find_matching_map(drm_device_t *dev, - drm_local_map_t *map) +drm_map_list_t *drm_find_matching_map(drm_device_t *dev, drm_local_map_t *map) { drm_map_list_t *entry; list_for_each_entry(entry, &dev->maplist, head) { @@ -62,6 +61,7 @@ static drm_map_list_t *drm_find_matching_map(drm_device_t *dev, return NULL; } +EXPORT_SYMBOL(drm_find_matching_map); static int drm_map_handle(drm_device_t *dev, drm_hash_item_t *hash, unsigned long user_token, int hashed_handle) diff --git a/shared-core/nouveau_drm.h b/shared-core/nouveau_drm.h index 7abe82e0..78ab9508 100644 --- a/shared-core/nouveau_drm.h +++ b/shared-core/nouveau_drm.h @@ -25,7 +25,7 @@ #ifndef __NOUVEAU_DRM_H__ #define __NOUVEAU_DRM_H__ -#define NOUVEAU_DRM_HEADER_PATCHLEVEL 8 +#define NOUVEAU_DRM_HEADER_PATCHLEVEL 9 typedef struct drm_nouveau_fifo_alloc { uint32_t fb_ctxdma_handle; @@ -80,12 +80,13 @@ typedef struct drm_nouveau_mem_alloc { int flags; int alignment; uint64_t size; // in bytes - uint64_t region_offset; + uint64_t offset; + drm_handle_t map_handle; } drm_nouveau_mem_alloc_t; typedef struct drm_nouveau_mem_free { - uint64_t region_offset; + uint64_t offset; int flags; } drm_nouveau_mem_free_t; diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index ea03fe37..99ddb586 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -34,7 +34,7 @@ #define DRIVER_MAJOR 0 #define DRIVER_MINOR 0 -#define DRIVER_PATCHLEVEL 8 +#define DRIVER_PATCHLEVEL 9 #define NOUVEAU_FAMILY 0x0000FFFF #define NOUVEAU_FLAGS 0xFFFF0000 @@ -50,6 +50,7 @@ struct mem_block { DRMFILE filp; /* 0: free, -1: heap, other: real files */ int flags; drm_local_map_t *map; + drm_handle_t map_handle; }; enum nouveau_flags { diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c index 7bcb1c8f..7114a931 100644 --- a/shared-core/nouveau_fifo.c +++ b/shared-core/nouveau_fifo.c @@ -213,8 +213,7 @@ nouveau_fifo_cmdbuf_alloc(struct drm_device *dev, int channel) DRM_DEBUG("Creating CB in AGP memory\n"); ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY, - cb->start - dev_priv->agp_phys, - cb->size, + cb->start, cb->size, NV_DMA_ACCESS_RO, NV_DMA_TARGET_AGP, &pushbuf); } else if ( cb->flags & NOUVEAU_MEM_PCI) { DRM_DEBUG("Creating CB in PCI memory\n"); @@ -226,7 +225,7 @@ nouveau_fifo_cmdbuf_alloc(struct drm_device *dev, int channel) } else if (dev_priv->card_type != NV_04) { ret = nouveau_gpuobj_dma_new (dev, channel, NV_CLASS_DMA_IN_MEMORY, - cb->start - drm_get_resource_start(dev, 1), + cb->start, cb->size, NV_DMA_ACCESS_RO, NV_DMA_TARGET_VIDMEM, &pushbuf); } else { @@ -236,7 +235,8 @@ nouveau_fifo_cmdbuf_alloc(struct drm_device *dev, int channel) */ ret = nouveau_gpuobj_dma_new (dev, channel, NV_CLASS_DMA_IN_MEMORY, - cb->start, cb->size, NV_DMA_ACCESS_RO, + cb->start + drm_get_resource_start(dev, 1), + cb->size, NV_DMA_ACCESS_RO, NV_DMA_TARGET_PCI, &pushbuf); } @@ -467,8 +467,9 @@ static int nouveau_ioctl_fifo_alloc(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_nouveau_private_t *dev_priv = dev->dev_private; - struct nouveau_fifo *chan; drm_nouveau_fifo_alloc_t init; + drm_map_list_t *entry; + struct nouveau_fifo *chan; int res; DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_fifo_alloc_t __user *) data, @@ -501,12 +502,17 @@ static int nouveau_ioctl_fifo_alloc(DRM_IOCTL_ARGS) if (res != 0) return res; + entry = drm_find_matching_map(dev, chan->regs); + if (!entry) + return DRM_ERR(EINVAL); + init.ctrl = entry->user_token; + /* pass back FIFO map info to the caller */ - init.cmdbuf = chan->pushbuf_mem->start; + init.cmdbuf = chan->pushbuf_mem->map_handle; init.cmdbuf_size = chan->pushbuf_mem->size; /* and the notifier block */ - init.notifier = chan->notifier_block->start; + init.notifier = chan->notifier_block->map_handle; init.notifier_size = chan->notifier_block->size; DRM_COPY_TO_USER_IOCTL((drm_nouveau_fifo_alloc_t __user *)data, diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index 790f6b5b..d4b2bc04 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -339,8 +339,7 @@ int nouveau_mem_init(struct drm_device *dev) } if (nouveau_mem_init_heap(&dev_priv->agp_heap, - info.aperture_base, - info.aperture_size)) + 0, info.aperture_size)) goto no_agp; dev_priv->agp_phys = info.aperture_base; @@ -360,7 +359,8 @@ no_agp: goto no_pci; } - if ( nouveau_mem_init_heap(&dev_priv->pci_heap, (uint64_t) dev->sg->virtual, dev->sg->pages * PAGE_SIZE)) + if ( nouveau_mem_init_heap(&dev_priv->pci_heap, 0, + dev->sg->pages * PAGE_SIZE)) { DRM_ERROR("Unable to initialize pci_heap!"); goto no_pci; @@ -387,18 +387,13 @@ have_agp: /* On cards with > 256Mb, you can't map everything. * So we create a second FB heap for that type of memory */ if (nouveau_mem_init_heap(&dev_priv->fb_heap, - drm_get_resource_start(dev,1), - 256*1024*1024)) + 0, 256*1024*1024)) return DRM_ERR(ENOMEM); if (nouveau_mem_init_heap(&dev_priv->fb_nomap_heap, - drm_get_resource_start(dev,1) + - 256*1024*1024, - fb_size-256*1024*1024)) + 256*1024*1024, fb_size-256*1024*1024)) return DRM_ERR(ENOMEM); } else { - if (nouveau_mem_init_heap(&dev_priv->fb_heap, - drm_get_resource_start(dev,1), - fb_size)) + if (nouveau_mem_init_heap(&dev_priv->fb_heap, 0, fb_size)) return DRM_ERR(ENOMEM); dev_priv->fb_nomap_heap=NULL; } @@ -473,23 +468,33 @@ alloc_ok: if (flags&NOUVEAU_MEM_MAPPED) { + drm_map_list_t *entry; int ret = 0; block->flags|=NOUVEAU_MEM_MAPPED; if (type == NOUVEAU_MEM_AGP) - ret = drm_addmap(dev, block->start - dev->agp->base, block->size, - _DRM_AGP, 0, &block->map); + ret = drm_addmap(dev, block->start + dev->agp->base, + block->size, _DRM_AGP, 0, &block->map); else if (type == NOUVEAU_MEM_FB) - ret = drm_addmap(dev, block->start, block->size, - _DRM_FRAME_BUFFER, 0, &block->map); + ret = drm_addmap(dev, block->start + dev_priv->fb_phys, + block->size, _DRM_FRAME_BUFFER, + 0, &block->map); else if (type == NOUVEAU_MEM_PCI) - ret = drm_addmap(dev, block->start - (unsigned long int)dev->sg->virtual, block->size, - _DRM_SCATTER_GATHER, 0, &block->map); + ret = drm_addmap(dev, block->start, block->size, + _DRM_SCATTER_GATHER, 0, &block->map); if (ret) { nouveau_mem_free_block(block); return NULL; } + + entry = drm_find_matching_map(dev, block->map); + if (!entry) { + nouveau_mem_free_block(block); + return NULL; + } + DRM_ERROR("user_token=0x%08x\n", entry->user_token); + block->map_handle = entry->user_token; } DRM_INFO("allocated 0x%llx\n", block->start); @@ -526,7 +531,8 @@ int nouveau_ioctl_mem_alloc(DRM_IOCTL_ARGS) block=nouveau_mem_alloc(dev, alloc.alignment, alloc.size, alloc.flags, filp); if (!block) return DRM_ERR(ENOMEM); - alloc.region_offset=block->start; + alloc.map_handle=block->map_handle; + alloc.offset=block->start; alloc.flags=block->flags; DRM_COPY_TO_USER_IOCTL((drm_nouveau_mem_alloc_t __user *) data, alloc, sizeof(alloc)); @@ -546,11 +552,11 @@ int nouveau_ioctl_mem_free(DRM_IOCTL_ARGS) block=NULL; if (memfree.flags&NOUVEAU_MEM_FB) - block = find_block(dev_priv->fb_heap, memfree.region_offset); + block = find_block(dev_priv->fb_heap, memfree.offset); else if (memfree.flags&NOUVEAU_MEM_AGP) - block = find_block(dev_priv->agp_heap, memfree.region_offset); + block = find_block(dev_priv->agp_heap, memfree.offset); else if (memfree.flags&NOUVEAU_MEM_PCI) - block = find_block(dev_priv->pci_heap, memfree.region_offset); + block = find_block(dev_priv->pci_heap, memfree.offset); if (!block) return DRM_ERR(EFAULT); if (block->filp != filp) diff --git a/shared-core/nouveau_notifier.c b/shared-core/nouveau_notifier.c index 30216293..7d892064 100644 --- a/shared-core/nouveau_notifier.c +++ b/shared-core/nouveau_notifier.c @@ -95,10 +95,8 @@ nouveau_notifier_alloc(drm_device_t *dev, int channel, uint32_t handle, offset = chan->notifier_block->start + mem->start; if (chan->notifier_block->flags & NOUVEAU_MEM_FB) { - offset -= drm_get_resource_start(dev, 1); target = NV_DMA_TARGET_VIDMEM; } else if (chan->notifier_block->flags & NOUVEAU_MEM_AGP) { - offset -= dev_priv->agp_phys; target = NV_DMA_TARGET_AGP; } else { DRM_ERROR("Bad DMA target, flags 0x%08x!\n", diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index 4f7ad111..e8ed708f 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -357,12 +357,12 @@ nouveau_gpuobj_instance_get(drm_device_t *dev, int channel, DRM_ERROR("AII, no VRAM backing gpuobj\n"); return DRM_ERR(EINVAL); } - *inst = gpuobj->im_backing->start - dev_priv->fb_phys; + *inst = gpuobj->im_backing->start; return 0; } else { /* ...from local heap */ cpramin = dev_priv->fifos[gpuobj->im_channel]->ramin->gpuobj; - *inst = (cpramin->im_backing->start - dev_priv->fb_phys) + + *inst = cpramin->im_backing->start + (gpuobj->im_pramin->start - cpramin->im_pramin->start); return 0; } @@ -917,7 +917,7 @@ nouveau_gpuobj_channel_init(drm_device_t *dev, int channel, } } else { - if ( dev_priv -> card_type >= NV_50 ) return 0; /*no PCIGART for NV50*/ + if (dev_priv -> card_type >= NV_50 ) return 0; /*no PCIGART for NV50*/ /*PCI*/ if((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY, diff --git a/shared-core/nv50_instmem.c b/shared-core/nv50_instmem.c index 1ea64b35..81c60829 100644 --- a/shared-core/nv50_instmem.c +++ b/shared-core/nv50_instmem.c @@ -215,7 +215,7 @@ nv50_instmem_bind(drm_device_t *dev, nouveau_gpuobj_t *gpuobj) pte = (gpuobj->im_pramin->start >> 12) << 3; pte_end = ((gpuobj->im_pramin->size >> 12) << 3) + pte; - vram = gpuobj->im_backing->start - dev_priv->fb_phys; + vram = gpuobj->im_backing->start; if (pte == pte_end) { DRM_ERROR("WARNING: badness in bind() pte calc\n"); -- cgit v1.2.3 From 522a0c868c79b48c5434f39faab1a02ca4425a90 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 12 Jul 2007 11:39:45 +1000 Subject: nouveau: nuke left over debug message --- shared-core/nouveau_mem.c | 1 - 1 file changed, 1 deletion(-) diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index d4b2bc04..9bfa8365 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -493,7 +493,6 @@ alloc_ok: nouveau_mem_free_block(block); return NULL; } - DRM_ERROR("user_token=0x%08x\n", entry->user_token); block->map_handle = entry->user_token; } -- cgit v1.2.3 From af317f1cc7136dbf03b39ced64c42202703c5066 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 12 Jul 2007 11:55:47 +1000 Subject: nouveau: mem_alloc() returns offsets, not absolute addresses now. --- shared-core/nouveau_object.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index e8ed708f..16b38e95 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -646,6 +646,8 @@ nouveau_gpuobj_dma_new(drm_device_t *dev, int channel, int class, class)); INSTANCE_WR(*gpuobj, 1, size-1); + offset += dev->sg->virtual; + /*write starting at the third dword*/ instance_offset = 2; @@ -921,7 +923,7 @@ nouveau_gpuobj_channel_init(drm_device_t *dev, int channel, /*PCI*/ if((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY, - dev->sg->virtual, dev->sg->pages * PAGE_SIZE, + 0, dev->sg->pages * PAGE_SIZE, NV_DMA_ACCESS_RW, NV_DMA_TARGET_PCI_NONLINEAR, &tt))) { DRM_ERROR("Error creating PCI TT ctxdma: %d\n", DRM_ERR(ENOMEM)); -- cgit v1.2.3 From 851c950d988e5a47fa6add71427e5ef8d4dcf231 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 13 Jul 2007 02:18:59 +1000 Subject: nouveau: unbreak AGP --- shared-core/nouveau_mem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index 9bfa8365..79d1bb87 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -473,8 +473,8 @@ alloc_ok: block->flags|=NOUVEAU_MEM_MAPPED; if (type == NOUVEAU_MEM_AGP) - ret = drm_addmap(dev, block->start + dev->agp->base, - block->size, _DRM_AGP, 0, &block->map); + ret = drm_addmap(dev, block->start, block->size, + _DRM_AGP, 0, &block->map); else if (type == NOUVEAU_MEM_FB) ret = drm_addmap(dev, block->start + dev_priv->fb_phys, block->size, _DRM_FRAME_BUFFER, -- cgit v1.2.3