From accf94969f226ddfe7dd3a6a76ce093ace839b26 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 16 Mar 2012 12:40:17 +1000 Subject: [PATCH 01/14] drm/nouveau/ttm: always do buffer moves on kernel channel There was once good reasons for wanting the drm to be able to use M2MF etc on user channels, but they're not relevant anymore. For the general buffer move case, we've already lost by transferring between vram/sysmem already so the context switching overhead is minimal in comparison. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bo.c | 11 +++-------- drivers/gpu/drm/nouveau/nouveau_drv.h | 2 -- drivers/gpu/drm/nouveau/nouveau_gem.c | 10 +--------- 3 files changed, 4 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index ec54364ac828..7d15a774f9c9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -693,16 +693,12 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr, struct ttm_mem_reg *new_mem) { struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); + struct nouveau_channel *chan = chan = dev_priv->channel; struct nouveau_bo *nvbo = nouveau_bo(bo); struct ttm_mem_reg *old_mem = &bo->mem; - struct nouveau_channel *chan; int ret; - chan = nvbo->channel; - if (!chan) { - chan = dev_priv->channel; - mutex_lock_nested(&chan->mutex, NOUVEAU_KCHANNEL_MUTEX); - } + mutex_lock_nested(&chan->mutex, NOUVEAU_KCHANNEL_MUTEX); /* create temporary vmas for the transfer and attach them to the * old nouveau_mem node, these will get cleaned up after ttm has @@ -734,8 +730,7 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr, } out: - if (chan == dev_priv->channel) - mutex_unlock(&chan->mutex); + mutex_unlock(&chan->mutex); return ret; } diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index a184ba331273..0df21752d274 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -113,8 +113,6 @@ struct nouveau_bo { int pbbo_index; bool validate_mapped; - struct nouveau_channel *channel; - struct list_head vma_list; unsigned page_shift; diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 7ce3fde40743..ed52a6f41613 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -426,9 +426,7 @@ validate_list(struct nouveau_channel *chan, struct list_head *list, return ret; } - nvbo->channel = (b->read_domains & (1 << 31)) ? NULL : chan; ret = nouveau_bo_validate(nvbo, true, false, false); - nvbo->channel = NULL; if (unlikely(ret)) { if (ret != -ERESTARTSYS) NV_ERROR(dev, "fail ttm_validate\n"); @@ -678,19 +676,13 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, return PTR_ERR(bo); } - /* Mark push buffers as being used on PFIFO, the validation code - * will then make sure that if the pushbuf bo moves, that they - * happen on the kernel channel, which will in turn cause a sync - * to happen before we try and submit the push buffer. - */ + /* Ensure all push buffers are on validate list */ for (i = 0; i < req->nr_push; i++) { if (push[i].bo_index >= req->nr_buffers) { NV_ERROR(dev, "push %d buffer not in list\n", i); ret = -EINVAL; goto out_prevalid; } - - bo[push[i].bo_index].read_domains |= (1 << 31); } /* Validate buffer list */ From b5b2e5988bd18a2f6e3f192adf7439599de00d3f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 16 Mar 2012 00:09:54 +1000 Subject: [PATCH 02/14] drm/nouveau: remove subchannel names from places where it doesn't matter These are FIFO methods, it doesn't matter what subchannel is being used. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 23 ++++++++++++++++++----- drivers/gpu/drm/nouveau/nouveau_fence.c | 24 ++++++++++++------------ drivers/gpu/drm/nouveau/nv50_display.c | 12 ++++++------ drivers/gpu/drm/nouveau/nvd0_display.c | 4 ++-- 4 files changed, 38 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 0df21752d274..eaf9872f9ee2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -1763,13 +1763,26 @@ nv44_graph_class(struct drm_device *dev) #define NV_MEM_TYPE_VM 0x7f #define NV_MEM_COMP_VM 0x03 +/* FIFO methods */ +#define NV01_SUBCHAN_OBJECT 0x00000000 +#define NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH 0x00000010 +#define NV84_SUBCHAN_SEMAPHORE_ADDRESS_LOW 0x00000014 +#define NV84_SUBCHAN_SEMAPHORE_SEQUENCE 0x00000018 +#define NV84_SUBCHAN_SEMAPHORE_TRIGGER 0x0000001c +#define NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL 0x00000001 +#define NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG 0x00000002 +#define NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_GEQUAL 0x00000004 +#define NV84_SUBCHAN_NOTIFY_INTR 0x00000020 +#define NV84_SUBCHAN_WRCACHE_FLUSH 0x00000024 +#define NV10_SUBCHAN_REF_CNT 0x00000050 +#define NV11_SUBCHAN_DMA_SEMAPHORE 0x00000060 +#define NV11_SUBCHAN_SEMAPHORE_OFFSET 0x00000064 +#define NV11_SUBCHAN_SEMAPHORE_ACQUIRE 0x00000068 +#define NV11_SUBCHAN_SEMAPHORE_RELEASE 0x0000006c +#define NV40_SUBCHAN_YIELD 0x00000080 + /* NV_SW object class */ #define NV_SW 0x0000506e -#define NV_SW_DMA_SEMAPHORE 0x00000060 -#define NV_SW_SEMAPHORE_OFFSET 0x00000064 -#define NV_SW_SEMAPHORE_ACQUIRE 0x00000068 -#define NV_SW_SEMAPHORE_RELEASE 0x0000006c -#define NV_SW_YIELD 0x00000080 #define NV_SW_DMA_VBLSEM 0x0000018c #define NV_SW_VBLSEM_OFFSET 0x00000400 #define NV_SW_VBLSEM_RELEASE_VALUE 0x00000404 diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 2f6daae68b9d..f676ecd3fd3c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -165,9 +165,9 @@ nouveau_fence_emit(struct nouveau_fence *fence) if (USE_REFCNT(dev)) { if (dev_priv->card_type < NV_C0) - BEGIN_RING(chan, NvSubSw, 0x0050, 1); + BEGIN_RING(chan, 0, NV10_SUBCHAN_REF_CNT, 1); else - BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0050, 1); + BEGIN_NVC0(chan, 2, 0, NV10_SUBCHAN_REF_CNT, 1); } else { BEGIN_RING(chan, NvSubSw, 0x0150, 1); } @@ -344,7 +344,7 @@ semaphore_acquire(struct nouveau_channel *chan, struct nouveau_semaphore *sema) if (ret) return ret; - BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 3); + BEGIN_RING(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 3); OUT_RING (chan, NvSema); OUT_RING (chan, offset); OUT_RING (chan, 1); @@ -354,9 +354,9 @@ semaphore_acquire(struct nouveau_channel *chan, struct nouveau_semaphore *sema) if (ret) return ret; - BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 1); + BEGIN_RING(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1); OUT_RING (chan, chan->vram_handle); - BEGIN_RING(chan, NvSubSw, 0x0010, 4); + BEGIN_RING(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); OUT_RING (chan, upper_32_bits(offset)); OUT_RING (chan, lower_32_bits(offset)); OUT_RING (chan, 1); @@ -366,7 +366,7 @@ semaphore_acquire(struct nouveau_channel *chan, struct nouveau_semaphore *sema) if (ret) return ret; - BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0010, 4); + BEGIN_NVC0(chan, 2, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); OUT_RING (chan, upper_32_bits(offset)); OUT_RING (chan, lower_32_bits(offset)); OUT_RING (chan, 1); @@ -397,10 +397,10 @@ semaphore_release(struct nouveau_channel *chan, struct nouveau_semaphore *sema) if (ret) return ret; - BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 2); + BEGIN_RING(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2); OUT_RING (chan, NvSema); OUT_RING (chan, offset); - BEGIN_RING(chan, NvSubSw, NV_SW_SEMAPHORE_RELEASE, 1); + BEGIN_RING(chan, 0, NV11_SUBCHAN_SEMAPHORE_RELEASE, 1); OUT_RING (chan, 1); } else if (dev_priv->chipset < 0xc0) { @@ -408,9 +408,9 @@ semaphore_release(struct nouveau_channel *chan, struct nouveau_semaphore *sema) if (ret) return ret; - BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 1); + BEGIN_RING(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1); OUT_RING (chan, chan->vram_handle); - BEGIN_RING(chan, NvSubSw, 0x0010, 4); + BEGIN_RING(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); OUT_RING (chan, upper_32_bits(offset)); OUT_RING (chan, lower_32_bits(offset)); OUT_RING (chan, 1); @@ -420,7 +420,7 @@ semaphore_release(struct nouveau_channel *chan, struct nouveau_semaphore *sema) if (ret) return ret; - BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0010, 4); + BEGIN_NVC0(chan, 2, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); OUT_RING (chan, upper_32_bits(offset)); OUT_RING (chan, lower_32_bits(offset)); OUT_RING (chan, 1); @@ -510,7 +510,7 @@ nouveau_fence_channel_init(struct nouveau_channel *chan) if (ret) return ret; - BEGIN_RING(chan, NvSubSw, 0, 1); + BEGIN_RING(chan, NvSubSw, NV01_SUBCHAN_OBJECT, 1); OUT_RING (chan, NvSw); FIRE_RING (chan); } diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 0e47a898f415..8b78b9cfa383 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -474,15 +474,15 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, } if (dev_priv->chipset < 0xc0) { - BEGIN_RING(chan, NvSubSw, 0x0060, 2); + BEGIN_RING(chan, 0, 0x0060, 2); OUT_RING (chan, NvEvoSema0 + nv_crtc->index); OUT_RING (chan, dispc->sem.offset); - BEGIN_RING(chan, NvSubSw, 0x006c, 1); + BEGIN_RING(chan, 0, 0x006c, 1); OUT_RING (chan, 0xf00d0000 | dispc->sem.value); - BEGIN_RING(chan, NvSubSw, 0x0064, 2); + BEGIN_RING(chan, 0, 0x0064, 2); OUT_RING (chan, dispc->sem.offset ^ 0x10); OUT_RING (chan, 0x74b1e000); - BEGIN_RING(chan, NvSubSw, 0x0060, 1); + BEGIN_RING(chan, 0, 0x0060, 1); if (dev_priv->chipset < 0x84) OUT_RING (chan, NvSema); else @@ -490,12 +490,12 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, } else { u64 offset = chan->dispc_vma[nv_crtc->index].offset; offset += dispc->sem.offset; - BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0010, 4); + BEGIN_NVC0(chan, 2, 0, 0x0010, 4); OUT_RING (chan, upper_32_bits(offset)); OUT_RING (chan, lower_32_bits(offset)); OUT_RING (chan, 0xf00d0000 | dispc->sem.value); OUT_RING (chan, 0x1002); - BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0010, 4); + BEGIN_NVC0(chan, 2, 0, 0x0010, 4); OUT_RING (chan, upper_32_bits(offset)); OUT_RING (chan, lower_32_bits(offset ^ 0x10)); OUT_RING (chan, 0x74b1e000); diff --git a/drivers/gpu/drm/nouveau/nvd0_display.c b/drivers/gpu/drm/nouveau/nvd0_display.c index dfb8a951cbbe..5e2b79bdcae0 100644 --- a/drivers/gpu/drm/nouveau/nvd0_display.c +++ b/drivers/gpu/drm/nouveau/nvd0_display.c @@ -303,12 +303,12 @@ nvd0_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, offset = chan->dispc_vma[nv_crtc->index].offset; offset += evo->sem.offset; - BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0010, 4); + BEGIN_NVC0(chan, 2, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); OUT_RING (chan, upper_32_bits(offset)); OUT_RING (chan, lower_32_bits(offset)); OUT_RING (chan, 0xf00d0000 | evo->sem.value); OUT_RING (chan, 0x1002); - BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0010, 4); + BEGIN_NVC0(chan, 2, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); OUT_RING (chan, upper_32_bits(offset)); OUT_RING (chan, lower_32_bits(offset ^ 0x10)); OUT_RING (chan, 0x74b1e000); From b08abd4e9a11d637d3c2ff52b2ebbc1b3f686d06 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 21 Mar 2012 13:51:03 +1000 Subject: [PATCH 03/14] drm/nouveau: move fence sequence check to start of loop I want to be able to use REF_CNT from other places in the kernel without pushing a fence object onto the list of emitted fences. The current code makes an assumption that every time the acked sequence is bumped that there's at least one fence on the list that'll be signalled. This will no longer be true in the near future. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_fence.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index f676ecd3fd3c..c1dc20f6cb85 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -93,18 +93,17 @@ nouveau_fence_update(struct nouveau_channel *chan) } list_for_each_entry_safe(fence, tmp, &chan->fence.pending, entry) { - sequence = fence->sequence; + if (fence->sequence > chan->fence.sequence_ack) + break; + fence->signalled = true; list_del(&fence->entry); - - if (unlikely(fence->work)) + if (fence->work) fence->work(fence->priv, true); kref_put(&fence->refcount, nouveau_fence_del); - - if (sequence == chan->fence.sequence_ack) - break; } + out: spin_unlock(&chan->fence.lock); } From d5316e251230c4e54a157349a362229c3d4daa32 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 21 Mar 2012 13:53:49 +1000 Subject: [PATCH 04/14] drm/nvc0-/disp: reimplement flip completion method as fifo method Removes need for M2MF subchannel usage on NVC0+. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_display.c | 14 +++++---- drivers/gpu/drm/nouveau/nouveau_drv.h | 1 + drivers/gpu/drm/nouveau/nvc0_fifo.c | 36 ++++++++++++++++++++--- drivers/gpu/drm/nouveau/nvc0_graph.c | 9 ------ 4 files changed, 42 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 35acc92f647b..ab447275da28 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -438,15 +438,19 @@ nouveau_page_flip_emit(struct nouveau_channel *chan, goto fail; /* Emit the pageflip */ - ret = RING_SPACE(chan, 2); + ret = RING_SPACE(chan, 3); if (ret) goto fail; - if (dev_priv->card_type < NV_C0) + if (dev_priv->card_type < NV_C0) { BEGIN_RING(chan, NvSubSw, NV_SW_PAGE_FLIP, 1); - else - BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0500, 1); - OUT_RING (chan, 0); + OUT_RING (chan, 0x00000000); + OUT_RING (chan, 0x00000000); + } else { + BEGIN_NVC0(chan, 2, 0, NV10_SUBCHAN_REF_CNT, 1); + OUT_RING (chan, ++chan->fence.sequence); + BEGIN_NVC0(chan, 8, 0, NVSW_SUBCHAN_PAGE_FLIP, 0x0000); + } FIRE_RING (chan); ret = nouveau_fence_new(chan, pfence, true); diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index eaf9872f9ee2..3dd620fc7837 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -1775,6 +1775,7 @@ nv44_graph_class(struct drm_device *dev) #define NV84_SUBCHAN_NOTIFY_INTR 0x00000020 #define NV84_SUBCHAN_WRCACHE_FLUSH 0x00000024 #define NV10_SUBCHAN_REF_CNT 0x00000050 +#define NVSW_SUBCHAN_PAGE_FLIP 0x00000054 #define NV11_SUBCHAN_DMA_SEMAPHORE 0x00000060 #define NV11_SUBCHAN_SEMAPHORE_OFFSET 0x00000064 #define NV11_SUBCHAN_SEMAPHORE_ACQUIRE 0x00000068 diff --git a/drivers/gpu/drm/nouveau/nvc0_fifo.c b/drivers/gpu/drm/nouveau/nvc0_fifo.c index dcbe0d5d0241..50d68a7a1379 100644 --- a/drivers/gpu/drm/nouveau/nvc0_fifo.c +++ b/drivers/gpu/drm/nouveau/nvc0_fifo.c @@ -436,6 +436,24 @@ nvc0_fifo_isr_vm_fault(struct drm_device *dev, int unit) printk(" on channel 0x%010llx\n", (u64)inst << 12); } +static int +nvc0_fifo_page_flip(struct drm_device *dev, u32 chid) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_channel *chan = NULL; + unsigned long flags; + int ret = -EINVAL; + + spin_lock_irqsave(&dev_priv->channels.lock, flags); + if (likely(chid >= 0 && chid < dev_priv->engine.fifo.channels)) { + chan = dev_priv->channels.ptr[chid]; + if (likely(chan)) + ret = nouveau_finish_page_flip(chan, NULL); + } + spin_unlock_irqrestore(&dev_priv->channels.lock, flags); + return ret; +} + static void nvc0_fifo_isr_subfifo_intr(struct drm_device *dev, int unit) { @@ -445,11 +463,21 @@ nvc0_fifo_isr_subfifo_intr(struct drm_device *dev, int unit) u32 chid = nv_rd32(dev, 0x040120 + (unit * 0x2000)) & 0x7f; u32 subc = (addr & 0x00070000); u32 mthd = (addr & 0x00003ffc); + u32 show = stat; - NV_INFO(dev, "PSUBFIFO %d:", unit); - nouveau_bitfield_print(nvc0_fifo_subfifo_intr, stat); - NV_INFO(dev, "PSUBFIFO %d: ch %d subc %d mthd 0x%04x data 0x%08x\n", - unit, chid, subc, mthd, data); + if (stat & 0x00200000) { + if (mthd == 0x0054) { + if (!nvc0_fifo_page_flip(dev, chid)) + show &= ~0x00200000; + } + } + + if (show) { + NV_INFO(dev, "PFIFO%d:", unit); + nouveau_bitfield_print(nvc0_fifo_subfifo_intr, show); + NV_INFO(dev, "PFIFO%d: ch %d subc %d mthd 0x%04x data 0x%08x\n", + unit, chid, subc, mthd, data); + } nv_wr32(dev, 0x0400c0 + (unit * 0x2000), 0x80600008); nv_wr32(dev, 0x040108 + (unit * 0x2000), stat); diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c index 8ee3963f9030..9066102d1159 100644 --- a/drivers/gpu/drm/nouveau/nvc0_graph.c +++ b/drivers/gpu/drm/nouveau/nvc0_graph.c @@ -333,14 +333,6 @@ nvc0_graph_fini(struct drm_device *dev, int engine, bool suspend) return 0; } -static int -nvc0_graph_mthd_page_flip(struct nouveau_channel *chan, - u32 class, u32 mthd, u32 data) -{ - nouveau_finish_page_flip(chan, NULL); - return 0; -} - static void nvc0_graph_init_obj418880(struct drm_device *dev) { @@ -889,7 +881,6 @@ nvc0_graph_create(struct drm_device *dev) NVOBJ_CLASS(dev, 0x902d, GR); /* 2D */ NVOBJ_CLASS(dev, 0x9039, GR); /* M2MF */ - NVOBJ_MTHD (dev, 0x9039, 0x0500, nvc0_graph_mthd_page_flip); NVOBJ_CLASS(dev, 0x9097, GR); /* 3D */ if (fermi >= 0x9197) NVOBJ_CLASS(dev, 0x9197, GR); /* 3D (NVC1-) */ From 48aca13f0167ae78c28c6b48d82a157a6692eecb Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sun, 18 Mar 2012 00:40:41 +1000 Subject: [PATCH 05/14] drm/nouveau: remove m2mf creation on userspace channels Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_channel.c | 19 +++-- drivers/gpu/drm/nouveau/nouveau_dma.c | 61 +-------------- drivers/gpu/drm/nouveau/nouveau_drv.h | 3 +- drivers/gpu/drm/nouveau/nouveau_state.c | 91 +++++++++++++++++++---- 4 files changed, 93 insertions(+), 81 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index a018defb7621..337e228629ed 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -122,7 +122,7 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, struct nouveau_fpriv *fpriv = nouveau_fpriv(file_priv); struct nouveau_channel *chan; unsigned long flags; - int ret; + int ret, i; /* allocate and lock channel structure */ chan = kzalloc(sizeof(*chan), GFP_KERNEL); @@ -184,7 +184,7 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, return ret; } - nouveau_dma_pre_init(chan); + nouveau_dma_init(chan); chan->user_put = 0x40; chan->user_get = 0x44; if (dev_priv->card_type >= NV_50) @@ -202,9 +202,18 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, pfifo->reassign(dev, true); - ret = nouveau_dma_init(chan); - if (!ret) - ret = nouveau_fence_channel_init(chan); + /* Insert NOPs for NOUVEAU_DMA_SKIPS */ + ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS); + if (ret) { + nouveau_channel_put(&chan); + return ret; + } + + for (i = 0; i < NOUVEAU_DMA_SKIPS; i++) + OUT_RING (chan, 0x00000000); + FIRE_RING(chan); + + ret = nouveau_fence_channel_init(chan); if (ret) { nouveau_channel_put(&chan); return ret; diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c index 4c2e4e5925fe..295932e66ac5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.c +++ b/drivers/gpu/drm/nouveau/nouveau_dma.c @@ -31,7 +31,7 @@ #include "nouveau_ramht.h" void -nouveau_dma_pre_init(struct nouveau_channel *chan) +nouveau_dma_init(struct nouveau_channel *chan) { struct drm_nouveau_private *dev_priv = chan->dev->dev_private; struct nouveau_bo *pushbuf = chan->pushbuf_bo; @@ -54,65 +54,6 @@ nouveau_dma_pre_init(struct nouveau_channel *chan) chan->dma.free = chan->dma.max - chan->dma.cur; } -int -nouveau_dma_init(struct nouveau_channel *chan) -{ - struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - int ret, i; - - if (dev_priv->card_type >= NV_C0) { - ret = nouveau_gpuobj_gr_new(chan, 0x9039, 0x9039); - if (ret) - return ret; - - ret = RING_SPACE(chan, 2); - if (ret) - return ret; - - BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0000, 1); - OUT_RING (chan, 0x00009039); - FIRE_RING (chan); - return 0; - } - - /* Create NV_MEMORY_TO_MEMORY_FORMAT for buffer moves */ - ret = nouveau_gpuobj_gr_new(chan, NvM2MF, dev_priv->card_type < NV_50 ? - 0x0039 : 0x5039); - if (ret) - return ret; - - /* NV_MEMORY_TO_MEMORY_FORMAT requires a notifier object */ - ret = nouveau_notifier_alloc(chan, NvNotify0, 32, 0xfe0, 0x1000, - &chan->m2mf_ntfy); - if (ret) - return ret; - - /* Insert NOPS for NOUVEAU_DMA_SKIPS */ - ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS); - if (ret) - return ret; - - for (i = 0; i < NOUVEAU_DMA_SKIPS; i++) - OUT_RING(chan, 0); - - /* Initialise NV_MEMORY_TO_MEMORY_FORMAT */ - ret = RING_SPACE(chan, 6); - if (ret) - return ret; - BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_NAME, 1); - OUT_RING (chan, NvM2MF); - BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 3); - OUT_RING (chan, NvNotify0); - OUT_RING (chan, chan->vram_handle); - OUT_RING (chan, chan->gart_handle); - - /* Sit back and pray the channel works.. */ - FIRE_RING(chan); - - return 0; -} - void OUT_RINGp(struct nouveau_channel *chan, const void *data, unsigned nr_dwords) { diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 3dd620fc7837..2d6032e2063f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -1089,8 +1089,7 @@ nouveau_debugfs_channel_fini(struct nouveau_channel *chan) #endif /* nouveau_dma.c */ -extern void nouveau_dma_pre_init(struct nouveau_channel *); -extern int nouveau_dma_init(struct nouveau_channel *); +extern void nouveau_dma_init(struct nouveau_channel *); extern int nouveau_dma_wait(struct nouveau_channel *, int slots, int size); /* nouveau_acpi.c */ diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 9c144fb8bbba..6476cf604cc4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -552,6 +552,75 @@ static bool nouveau_switcheroo_can_switch(struct pci_dev *pdev) return can_switch; } +static void +nouveau_card_channel_fini(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + if (dev_priv->channel) + nouveau_channel_put_unlocked(&dev_priv->channel); +} + +static int +nouveau_card_channel_init(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_channel *chan; + int ret, oclass; + + ret = nouveau_channel_alloc(dev, &chan, NULL, NvDmaFB, NvDmaTT); + dev_priv->channel = chan; + if (ret) + return ret; + + mutex_unlock(&dev_priv->channel->mutex); + + if (dev_priv->card_type <= NV_50) { + if (dev_priv->card_type < NV_50) + oclass = 0x0039; + else + oclass = 0x5039; + + ret = nouveau_gpuobj_gr_new(chan, NvM2MF, oclass); + if (ret) + goto error; + + ret = nouveau_notifier_alloc(chan, NvNotify0, 32, 0xfe0, 0x1000, + &chan->m2mf_ntfy); + if (ret) + goto error; + + ret = RING_SPACE(chan, 6); + if (ret) + goto error; + + BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_NAME, 1); + OUT_RING (chan, NvM2MF); + BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 3); + OUT_RING (chan, NvNotify0); + OUT_RING (chan, chan->vram_handle); + OUT_RING (chan, chan->gart_handle); + } else + if (dev_priv->card_type <= NV_C0) { + ret = nouveau_gpuobj_gr_new(chan, 0x9039, 0x9039); + if (ret) + goto error; + + ret = RING_SPACE(chan, 2); + if (ret) + goto error; + + BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0000, 1); + OUT_RING (chan, 0x00009039); + } + + FIRE_RING (chan); +error: + if (ret) + nouveau_card_channel_fini(dev); + return ret; +} + int nouveau_card_init(struct drm_device *dev) { @@ -738,17 +807,14 @@ nouveau_card_init(struct drm_device *dev) nouveau_backlight_init(dev); nouveau_pm_init(dev); - if (dev_priv->eng[NVOBJ_ENGINE_GR]) { - ret = nouveau_fence_init(dev); - if (ret) - goto out_pm; + ret = nouveau_fence_init(dev); + if (ret) + goto out_pm; - ret = nouveau_channel_alloc(dev, &dev_priv->channel, NULL, - NvDmaFB, NvDmaTT); + if (!dev_priv->noaccel) { + ret = nouveau_card_channel_init(dev); if (ret) goto out_fence; - - mutex_unlock(&dev_priv->channel->mutex); } if (dev->mode_config.num_crtc) { @@ -762,7 +828,7 @@ nouveau_card_init(struct drm_device *dev) return 0; out_chan: - nouveau_channel_put_unlocked(&dev_priv->channel); + nouveau_card_channel_fini(dev); out_fence: nouveau_fence_fini(dev); out_pm: @@ -820,11 +886,8 @@ static void nouveau_card_takedown(struct drm_device *dev) nouveau_display_fini(dev); } - if (dev_priv->channel) { - nouveau_channel_put_unlocked(&dev_priv->channel); - nouveau_fence_fini(dev); - } - + nouveau_card_channel_fini(dev); + nouveau_fence_fini(dev); nouveau_pm_fini(dev); nouveau_backlight_exit(dev); nouveau_display_destroy(dev); From 664695ae6f8b2b72aa5820aa20f4d65016cb3fd0 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 21 Mar 2012 13:57:40 +1000 Subject: [PATCH 06/14] drm/nouveau: inform userspace of new kernel subchannel requirements All available subchannels are now available for userspace to do with as it pleases on NVC0+. On all earlier chipsets, the kernel still uses a software object on subc 0 to implement the page flip completion method. I hope to find some decent way of addressing this too, but it's a tad tricker prior to fermi. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_channel.c | 15 ++++----------- drivers/gpu/drm/nouveau/nouveau_dma.h | 4 ++-- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index 337e228629ed..44e6416d4a33 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -436,18 +436,11 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data, } if (dev_priv->card_type < NV_C0) { - init->subchan[0].handle = NvM2MF; - if (dev_priv->card_type < NV_50) - init->subchan[0].grclass = 0x0039; - else - init->subchan[0].grclass = 0x5039; - init->subchan[1].handle = NvSw; - init->subchan[1].grclass = NV_SW; - init->nr_subchan = 2; - } else { - init->subchan[0].handle = 0x9039; - init->subchan[0].grclass = 0x9039; + init->subchan[0].handle = NvSw; + init->subchan[0].grclass = NV_SW; init->nr_subchan = 1; + } else { + init->nr_subchan = 0; } /* Named memory object area */ diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.h b/drivers/gpu/drm/nouveau/nouveau_dma.h index 23d4edf992b7..bcf0fd9e313e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.h +++ b/drivers/gpu/drm/nouveau/nouveau_dma.h @@ -48,8 +48,8 @@ void nv50_dma_push(struct nouveau_channel *, struct nouveau_bo *, /* Hardcoded object assignments to subchannels (subchannel id). */ enum { - NvSubM2MF = 0, - NvSubSw = 1, + NvSubSw = 0, + NvSubM2MF = 1, NvSub2D = 2, NvSubCtxSurf2D = 2, NvSubGdiRect = 3, From 27100ac95a8eee0b083e46bfa67b229ac641d28c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 16 Mar 2012 13:45:09 +1000 Subject: [PATCH 07/14] drm/nouveau: oops, increase channel dispc_vma to 4 Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 2d6032e2063f..c1e9a6afc991 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -294,7 +294,7 @@ struct nouveau_channel { uint32_t sw_subchannel[8]; - struct nouveau_vma dispc_vma[2]; + struct nouveau_vma dispc_vma[4]; struct { struct nouveau_gpuobj *vblsem; uint32_t vblsem_head; From dd62608bcc8a629c4c583fb50b90003fd5213516 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 16 Mar 2012 15:32:16 +1000 Subject: [PATCH 08/14] drm/nvd0/disp: ignore clock set if no pclk This happens somehow during init on a machine I have, and leads to a divide-by-zero. Lets avoid that... Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvd0_display.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvd0_display.c b/drivers/gpu/drm/nouveau/nvd0_display.c index 5e2b79bdcae0..421d301b3797 100644 --- a/drivers/gpu/drm/nouveau/nvd0_display.c +++ b/drivers/gpu/drm/nouveau/nvd0_display.c @@ -1661,7 +1661,9 @@ nvd0_display_unk2_handler(struct drm_device *dev, u32 crtc, u32 mask) } pclk = nv_rd32(dev, 0x660450 + (crtc * 0x300)) / 1000; - if (mask & 0x00010000) { + NV_DEBUG_KMS(dev, "PDISP: crtc %d pclk %d mask 0x%08x\n", + crtc, pclk, mask); + if (pclk && (mask & 0x00010000)) { nv50_crtc_set_clock(dev, crtc, pclk); } From f887c425f9eeed8ffbca64c8be45da62b07096c0 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 16 Mar 2012 12:44:34 +1000 Subject: [PATCH 09/14] drm/nouveau: bump version to 1.0.0 The time has come to get a proper version number that we can change to indicate new features etc, rather than the lock-step 0.0.XX that we previously had. libdrm has recognised this version as compatible with 0.0.16 since 2.4.22, so hopefully any breakage people see should be very minimal. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index c1e9a6afc991..211d8000aac7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -26,15 +26,15 @@ #define __NOUVEAU_DRV_H__ #define DRIVER_AUTHOR "Stephane Marchesin" -#define DRIVER_EMAIL "dri-devel@lists.sourceforge.net" +#define DRIVER_EMAIL "nouveau@lists.freedesktop.org" #define DRIVER_NAME "nouveau" #define DRIVER_DESC "nVidia Riva/TNT/GeForce" -#define DRIVER_DATE "20090420" +#define DRIVER_DATE "20120316" -#define DRIVER_MAJOR 0 +#define DRIVER_MAJOR 1 #define DRIVER_MINOR 0 -#define DRIVER_PATCHLEVEL 16 +#define DRIVER_PATCHLEVEL 0 #define NOUVEAU_FAMILY 0x0000FFFF #define NOUVEAU_FLAGS 0xFFFF0000 From f3c93cbde7eab38671ae085cb1027b08f5f36757 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 16 Mar 2012 18:19:14 +1000 Subject: [PATCH 10/14] drm/nouveau: move out of staging drivers There's really no good reason for us to be in here anymore, we have to maintain this ABI anyway to avoid angering people. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/Kconfig | 2 ++ drivers/staging/Kconfig | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 2418429a9836..8ea3bca22ee2 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -71,6 +71,8 @@ config DRM_RADEON source "drivers/gpu/drm/radeon/Kconfig" +source "drivers/gpu/drm/nouveau/Kconfig" + config DRM_I810 tristate "Intel I810" # !PREEMPT because of missing ioctl locking diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 21e2f4b87f14..71cb8157f47d 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -66,8 +66,6 @@ source "drivers/staging/phison/Kconfig" source "drivers/staging/line6/Kconfig" -source "drivers/gpu/drm/nouveau/Kconfig" - source "drivers/staging/octeon/Kconfig" source "drivers/staging/serqt_usb2/Kconfig" From fa2c113ac1da39f922ab287b75c8d3f21a4b16dd Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 22 Mar 2012 11:27:15 +1000 Subject: [PATCH 11/14] drm/nouveau: add bios connector type for dms59 Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.h | 2 ++ drivers/gpu/drm/nouveau/nouveau_connector.c | 13 ++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h index 1f3233df00e6..298a3af48d14 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.h +++ b/drivers/gpu/drm/nouveau/nouveau_bios.h @@ -69,6 +69,8 @@ enum dcb_connector_type { DCB_CONNECTOR_TV_3 = 0x13, DCB_CONNECTOR_DVI_I = 0x30, DCB_CONNECTOR_DVI_D = 0x31, + DCB_CONNECTOR_DMS59_0 = 0x38, + DCB_CONNECTOR_DMS59_1 = 0x39, DCB_CONNECTOR_LVDS = 0x40, DCB_CONNECTOR_LVDS_SPWG = 0x41, DCB_CONNECTOR_DP = 0x46, diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 9f9d50dbca7f..8f510fd956b0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -867,6 +867,8 @@ drm_conntype_from_dcb(enum dcb_connector_type dcb) case DCB_CONNECTOR_TV_0 : case DCB_CONNECTOR_TV_1 : case DCB_CONNECTOR_TV_3 : return DRM_MODE_CONNECTOR_TV; + case DCB_CONNECTOR_DMS59_0 : + case DCB_CONNECTOR_DMS59_1 : case DCB_CONNECTOR_DVI_I : return DRM_MODE_CONNECTOR_DVII; case DCB_CONNECTOR_DVI_D : return DRM_MODE_CONNECTOR_DVID; case DCB_CONNECTOR_LVDS : @@ -1013,13 +1015,10 @@ nouveau_connector_create(struct drm_device *dev, int index) /* Add overscan compensation options to digital outputs */ if (disp->underscan_property && - (nv_connector->type == DCB_CONNECTOR_DVI_D || - nv_connector->type == DCB_CONNECTOR_DVI_I || - nv_connector->type == DCB_CONNECTOR_HDMI_0 || - nv_connector->type == DCB_CONNECTOR_HDMI_1 || - nv_connector->type == DCB_CONNECTOR_DP || - nv_connector->type == DCB_CONNECTOR_DMS59_DP0 || - nv_connector->type == DCB_CONNECTOR_DMS59_DP1)) { + (type == DRM_MODE_CONNECTOR_DVID || + type == DRM_MODE_CONNECTOR_DVII || + type == DRM_MODE_CONNECTOR_HDMIA || + type == DRM_MODE_CONNECTOR_DisplayPort)) { drm_connector_attach_property(connector, disp->underscan_property, UNDERSCAN_OFF); From 68455a43debe26dd1d2a42c0b67dd5697c201420 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sun, 4 Mar 2012 14:47:55 +1000 Subject: [PATCH 12/14] drm/nve0: initial modesetting support for kepler chipsets Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 1 + drivers/gpu/drm/nouveau/nouveau_state.c | 61 ++++++++++++++++++++++--- 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 211d8000aac7..3aef353a926c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -701,6 +701,7 @@ enum nouveau_card_type { NV_50 = 0x50, NV_C0 = 0xc0, NV_D0 = 0xd0, + NV_E0 = 0xe0, }; struct drm_nouveau_private { diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 6476cf604cc4..a3ae91fa8141 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -479,6 +479,47 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->pm.voltage_get = nouveau_voltage_gpio_get; engine->pm.voltage_set = nouveau_voltage_gpio_set; break; + case 0xe0: + engine->instmem.init = nvc0_instmem_init; + engine->instmem.takedown = nvc0_instmem_takedown; + engine->instmem.suspend = nvc0_instmem_suspend; + engine->instmem.resume = nvc0_instmem_resume; + engine->instmem.get = nv50_instmem_get; + engine->instmem.put = nv50_instmem_put; + engine->instmem.map = nv50_instmem_map; + engine->instmem.unmap = nv50_instmem_unmap; + engine->instmem.flush = nv84_instmem_flush; + engine->mc.init = nv50_mc_init; + engine->mc.takedown = nv50_mc_takedown; + engine->timer.init = nv04_timer_init; + engine->timer.read = nv04_timer_read; + engine->timer.takedown = nv04_timer_takedown; + engine->fb.init = nvc0_fb_init; + engine->fb.takedown = nvc0_fb_takedown; + engine->fifo.channels = 0; + engine->fifo.init = nouveau_stub_init; + engine->fifo.takedown = nouveau_stub_takedown; + engine->fifo.disable = nvc0_fifo_disable; + engine->fifo.enable = nvc0_fifo_enable; + engine->fifo.reassign = nvc0_fifo_reassign; + engine->fifo.unload_context = nouveau_stub_init; + engine->display.early_init = nouveau_stub_init; + engine->display.late_takedown = nouveau_stub_takedown; + engine->display.create = nvd0_display_create; + engine->display.destroy = nvd0_display_destroy; + engine->display.init = nvd0_display_init; + engine->display.fini = nvd0_display_fini; + engine->gpio.init = nv50_gpio_init; + engine->gpio.fini = nv50_gpio_fini; + engine->gpio.drive = nvd0_gpio_drive; + engine->gpio.sense = nvd0_gpio_sense; + engine->gpio.irq_enable = nv50_gpio_irq_enable; + engine->vram.init = nvc0_vram_init; + engine->vram.takedown = nv50_vram_fini; + engine->vram.get = nvc0_vram_new; + engine->vram.put = nv50_vram_del; + engine->vram.flags_valid = nvc0_vram_flags_valid; + break; default: NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset); return 1; @@ -1056,8 +1097,8 @@ static int nouveau_remove_conflicting_drivers(struct drm_device *dev) int nouveau_load(struct drm_device *dev, unsigned long flags) { struct drm_nouveau_private *dev_priv; + unsigned long long offset, length; uint32_t reg0 = ~0, strap; - resource_size_t mmio_start_offs; int ret; dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL); @@ -1111,6 +1152,9 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) case 0xd0: dev_priv->card_type = NV_D0; break; + case 0xe0: + dev_priv->card_type = NV_E0; + break; default: break; } @@ -1135,17 +1179,20 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n", dev_priv->card_type, reg0); - /* map the mmio regs */ - mmio_start_offs = pci_resource_start(dev->pdev, 0); - dev_priv->mmio = ioremap(mmio_start_offs, 0x00800000); + /* map the mmio regs, limiting the amount to preserve vmap space */ + offset = pci_resource_start(dev->pdev, 0); + length = pci_resource_len(dev->pdev, 0); + if (dev_priv->card_type < NV_E0) + length = min(length, (unsigned long long)0x00800000); + + dev_priv->mmio = ioremap(offset, length); if (!dev_priv->mmio) { NV_ERROR(dev, "Unable to initialize the mmio mapping. " "Please report your setup to " DRIVER_EMAIL "\n"); ret = -EINVAL; goto err_priv; } - NV_DEBUG(dev, "regs mapped ok at 0x%llx\n", - (unsigned long long)mmio_start_offs); + NV_DEBUG(dev, "regs mapped ok at 0x%llx\n", offset); /* determine frequency of timing crystal */ strap = nv_rd32(dev, 0x101000); @@ -1203,7 +1250,7 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) } } else { dev_priv->ramin_size = 1 * 1024 * 1024; - dev_priv->ramin = ioremap(mmio_start_offs + NV_RAMIN, + dev_priv->ramin = ioremap(offset + NV_RAMIN, dev_priv->ramin_size); if (!dev_priv->ramin) { NV_ERROR(dev, "Failed to map BAR0 PRAMIN.\n"); From e592c73b91e9dfc7403fe41f649dd18593805ccd Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 5 Mar 2012 10:05:45 +1000 Subject: [PATCH 13/14] drm/nve0/disp: nvidia randomly decided to move the dithering method Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvd0_display.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvd0_display.c b/drivers/gpu/drm/nouveau/nvd0_display.c index 421d301b3797..d69642da8b56 100644 --- a/drivers/gpu/drm/nouveau/nvd0_display.c +++ b/drivers/gpu/drm/nouveau/nvd0_display.c @@ -363,10 +363,12 @@ nvd0_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, static int nvd0_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update) { + struct drm_nouveau_private *dev_priv = nv_crtc->base.dev->dev_private; struct drm_device *dev = nv_crtc->base.dev; struct nouveau_connector *nv_connector; struct drm_connector *connector; u32 *push, mode = 0x00; + u32 mthd; nv_connector = nouveau_crtc_connector_get(nv_crtc); connector = &nv_connector->base; @@ -384,9 +386,14 @@ nvd0_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update) mode |= nv_connector->dithering_depth; } + if (dev_priv->card_type < NV_E0) + mthd = 0x0490 + (nv_crtc->index * 0x0300); + else + mthd = 0x04a0 + (nv_crtc->index * 0x0300); + push = evo_wait(dev, EVO_MASTER, 4); if (push) { - evo_mthd(push, 0x0490 + (nv_crtc->index * 0x300), 1); + evo_mthd(push, mthd, 1); evo_data(push, mode); if (update) { evo_mthd(push, 0x0080, 1); From 6544599249086ce50f216a6cedbea56514ffefc6 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sun, 11 Mar 2012 16:08:05 +1000 Subject: [PATCH 14/14] drm/nouveau/dp: support version 4.0 of DP table Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 3 ++- drivers/gpu/drm/nouveau/nouveau_dp.c | 11 +++++++++++ drivers/gpu/drm/nouveau/nvd0_display.c | 6 ++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 8dbeeea91872..637afe71de56 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -1144,7 +1144,8 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) break; case 1: case 2: - if (!(entry[5] & cond)) + if ((table[0] < 0x40 && !(entry[5] & cond)) || + (table[0] == 0x40 && !(entry[4] & cond))) iexec->execute = false; break; case 5: diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index 302b2f7d0678..d996134b1b28 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -188,6 +188,7 @@ nouveau_dp_bios_data(struct drm_device *dev, struct dcb_entry *dcb, u8 **entry) case 0x20: case 0x21: case 0x30: + case 0x40: break; default: NV_ERROR(dev, "displayport table 0x%02x unknown\n", table[0]); @@ -366,6 +367,10 @@ dp_set_downspread(struct drm_device *dev, struct dp_state *dp, bool enable) if (table[0] >= 0x20 && table[0] <= 0x30) { if (enable) script = ROM16(entry[12]); else script = ROM16(entry[14]); + } else + if (table[0] == 0x40) { + if (enable) script = ROM16(entry[11]); + else script = ROM16(entry[13]); } } @@ -380,6 +385,9 @@ dp_link_train_init(struct drm_device *dev, struct dp_state *dp) if (table) { if (table[0] >= 0x20 && table[0] <= 0x30) script = ROM16(entry[6]); + else + if (table[0] == 0x40) + script = ROM16(entry[5]); } nouveau_bios_run_init_table(dev, script, dp->dcb, dp->crtc); @@ -393,6 +401,9 @@ dp_link_train_fini(struct drm_device *dev, struct dp_state *dp) if (table) { if (table[0] >= 0x20 && table[0] <= 0x30) script = ROM16(entry[8]); + else + if (table[0] == 0x40) + script = ROM16(entry[7]); } nouveau_bios_run_init_table(dev, script, dp->dcb, dp->crtc); diff --git a/drivers/gpu/drm/nouveau/nvd0_display.c b/drivers/gpu/drm/nouveau/nvd0_display.c index d69642da8b56..0247250939e8 100644 --- a/drivers/gpu/drm/nouveau/nvd0_display.c +++ b/drivers/gpu/drm/nouveau/nvd0_display.c @@ -1226,6 +1226,11 @@ nvd0_sor_dp_train_adj(struct drm_device *dev, struct dcb_entry *dcb, if (table[0] == 0x30) { config = entry + table[4]; config += table[5] * preem; + } else + if (table[0] == 0x40) { + config = table + table[1]; + config += table[2] * table[3]; + config += table[6] * preem; } } @@ -1258,6 +1263,7 @@ nvd0_sor_dp_link_set(struct drm_device *dev, struct dcb_entry *dcb, int crtc, table = nouveau_dp_bios_data(dev, dcb, &entry); if (table) { if (table[0] == 0x30) entry = ROMPTR(dev, entry[10]); + else if (table[0] == 0x40) entry = ROMPTR(dev, entry[9]); else entry = NULL; while (entry) {