diff --git a/debian/changelog b/debian/changelog index 074aca083..53e68220e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -34,6 +34,9 @@ linux (3.2.23-1) UNRELEASED; urgency=low * udf: Improve table length check to avoid possible overflow * CIFS: Respect negotiated MaxMpxCount (deferred from 3.2.14) * epoll: clear the tfile_check_list on -ELOOP (CVE-2012-3375) + * nouveau: Update to support Fermi (NVC0+) acceleration (Closes: #679566) + - Refactor sub-channel use + - Bump version to 1.0.0 -- Ben Hutchings Fri, 29 Jun 2012 15:01:22 +0100 diff --git a/debian/patches/features/all/fermi-accel/drm-nouveau-bump-version-to-1.0.0.patch b/debian/patches/features/all/fermi-accel/drm-nouveau-bump-version-to-1.0.0.patch new file mode 100644 index 000000000..8313d3741 --- /dev/null +++ b/debian/patches/features/all/fermi-accel/drm-nouveau-bump-version-to-1.0.0.patch @@ -0,0 +1,42 @@ +From: Ben Skeggs +Date: Fri, 16 Mar 2012 12:44:34 +1000 +Subject: [9/9] drm/nouveau: bump version to 1.0.0 + +commit f887c425f9eeed8ffbca64c8be45da62b07096c0 upstream. + +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 c1e9a6a..211d800 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 diff --git a/debian/patches/features/all/fermi-accel/drm-nouveau-inform-userspace-of-relaxed-kernel-subch.patch b/debian/patches/features/all/fermi-accel/drm-nouveau-inform-userspace-of-relaxed-kernel-subch.patch new file mode 100644 index 000000000..543581ecf --- /dev/null +++ b/debian/patches/features/all/fermi-accel/drm-nouveau-inform-userspace-of-relaxed-kernel-subch.patch @@ -0,0 +1,37 @@ +From: Ben Skeggs +Date: Thu, 29 Mar 2012 20:24:34 +1000 +Subject: [6/9] drm/nouveau: inform userspace of relaxed kernel subchannel + requirements + +commit 02bfc2881e0d5b23147211bb6420798d946a7b5c upstream. + +Signed-off-by: Ben Skeggs +--- + drivers/gpu/drm/nouveau/nouveau_channel.c | 11 ++--------- + 1 file changed, 2 insertions(+), 9 deletions(-) + +diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c +index 337e228..846afb0 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[0].handle = 0x00000000; ++ init->subchan[0].grclass = 0x0000; + 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->nr_subchan = 1; + } + + /* Named memory object area */ diff --git a/debian/patches/features/all/fermi-accel/drm-nouveau-move-fence-sequence-check-to-start-of-lo.patch b/debian/patches/features/all/fermi-accel/drm-nouveau-move-fence-sequence-check-to-start-of-lo.patch new file mode 100644 index 000000000..9736d7b4a --- /dev/null +++ b/debian/patches/features/all/fermi-accel/drm-nouveau-move-fence-sequence-check-to-start-of-lo.patch @@ -0,0 +1,47 @@ +From: Ben Skeggs +Date: Wed, 21 Mar 2012 13:51:03 +1000 +Subject: [3/9] drm/nouveau: move fence sequence check to start of loop + +commit b08abd4e9a11d637d3c2ff52b2ebbc1b3f686d06 upstream. + +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 f676ecd..c1dc20f 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); + } diff --git a/debian/patches/features/all/fermi-accel/drm-nouveau-oops-increase-channel-dispc_vma-to-4.patch b/debian/patches/features/all/fermi-accel/drm-nouveau-oops-increase-channel-dispc_vma-to-4.patch new file mode 100644 index 000000000..8d809d3eb --- /dev/null +++ b/debian/patches/features/all/fermi-accel/drm-nouveau-oops-increase-channel-dispc_vma-to-4.patch @@ -0,0 +1,24 @@ +From: Ben Skeggs +Date: Fri, 16 Mar 2012 13:45:09 +1000 +Subject: [7/9] drm/nouveau: oops, increase channel dispc_vma to 4 + +commit 27100ac95a8eee0b083e46bfa67b229ac641d28c upstream. + +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 2d6032e..c1e9a6a 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; diff --git a/debian/patches/features/all/fermi-accel/drm-nouveau-remove-m2mf-creation-on-userspace-channe.patch b/debian/patches/features/all/fermi-accel/drm-nouveau-remove-m2mf-creation-on-userspace-channe.patch new file mode 100644 index 000000000..c7fd2a7dc --- /dev/null +++ b/debian/patches/features/all/fermi-accel/drm-nouveau-remove-m2mf-creation-on-userspace-channe.patch @@ -0,0 +1,274 @@ +From: Ben Skeggs +Date: Sun, 18 Mar 2012 00:40:41 +1000 +Subject: [5/9] drm/nouveau: remove m2mf creation on userspace channels + +commit 48aca13f0167ae78c28c6b48d82a157a6692eecb upstream. + +Signed-off-by: Ben Skeggs +[mlankhorst: Backported to 3.2: +Conflicts: + + drivers/gpu/drm/nouveau/nouveau_state.c +] +--- + 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(-) + +--- 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; + +@@ -200,9 +200,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; +--- 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) + { +--- a/drivers/gpu/drm/nouveau/nouveau_drv.h ++++ b/drivers/gpu/drm/nouveau/nouveau_drv.h +@@ -1030,8 +1030,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 */ +--- a/drivers/gpu/drm/nouveau/nouveau_state.c ++++ b/drivers/gpu/drm/nouveau/nouveau_state.c +@@ -547,6 +547,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); + +- if (dev_priv->eng[NVOBJ_ENGINE_GR]) { +- ret = nouveau_fence_init(dev); +- if (ret) +- goto out_disp; ++ ret = nouveau_fence_init(dev); ++ if (ret) ++ goto out_disp; + +- 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) { +@@ -763,7 +829,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_disp: +@@ -823,11 +889,8 @@ static void nouveau_card_takedown(struct drm_device *dev) + drm_vblank_cleanup(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_backlight_exit(dev); + engine->display.destroy(dev); + drm_mode_config_cleanup(dev); diff --git a/debian/patches/features/all/fermi-accel/drm-nouveau-remove-subchannel-names-from-places-wher.patch b/debian/patches/features/all/fermi-accel/drm-nouveau-remove-subchannel-names-from-places-wher.patch new file mode 100644 index 000000000..5df79115a --- /dev/null +++ b/debian/patches/features/all/fermi-accel/drm-nouveau-remove-subchannel-names-from-places-wher.patch @@ -0,0 +1,179 @@ +From: Ben Skeggs +Date: Fri, 16 Mar 2012 00:09:54 +1000 +Subject: [2/9] drm/nouveau: remove subchannel names from places where it + doesn't matter + +commit b5b2e5988bd18a2f6e3f192adf7439599de00d3f upstream. + +These are FIFO methods, it doesn't matter what subchannel is being used. + +Signed-off-by: Ben Skeggs +[mlankhorst: Backported to 3.2: +Resolved conflict by reverting, since it's not used yet in nvd0_display.c +Conflicts: + drivers/gpu/drm/nouveau/nvd0_display.c +] +--- + drivers/gpu/drm/nouveau/nouveau_drv.h | 23 ++++++++++++++++++----- + drivers/gpu/drm/nouveau/nouveau_fence.c | 24 ++++++++++++------------ + drivers/gpu/drm/nouveau/nv50_display.c | 12 ++++++------ + 3 files changed, 36 insertions(+), 23 deletions(-) + +--- a/drivers/gpu/drm/nouveau/nouveau_drv.h ++++ b/drivers/gpu/drm/nouveau/nouveau_drv.h +@@ -1660,13 +1660,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 +--- 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); + } +--- a/drivers/gpu/drm/nouveau/nv50_display.c ++++ b/drivers/gpu/drm/nouveau/nv50_display.c +@@ -413,15 +413,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 +@@ -429,12 +429,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/debian/patches/features/all/fermi-accel/drm-nouveau-ttm-always-do-buffer-moves-on-kernel-cha.patch b/debian/patches/features/all/fermi-accel/drm-nouveau-ttm-always-do-buffer-moves-on-kernel-cha.patch new file mode 100644 index 000000000..0e24d8668 --- /dev/null +++ b/debian/patches/features/all/fermi-accel/drm-nouveau-ttm-always-do-buffer-moves-on-kernel-cha.patch @@ -0,0 +1,99 @@ +From: Ben Skeggs +Date: Fri, 16 Mar 2012 12:40:17 +1000 +Subject: [1/9] drm/nouveau/ttm: always do buffer moves on kernel channel + +commit accf94969f226ddfe7dd3a6a76ce093ace839b26 upstream. + +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 ec54364..7d15a77 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 a184ba3..0df2175 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 7ce3fde..ed52a6f 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 */ diff --git a/debian/patches/features/all/fermi-accel/drm-nvc0-disp-reimplement-flip-completion-method-as-.patch b/debian/patches/features/all/fermi-accel/drm-nvc0-disp-reimplement-flip-completion-method-as-.patch new file mode 100644 index 000000000..f48e59284 --- /dev/null +++ b/debian/patches/features/all/fermi-accel/drm-nvc0-disp-reimplement-flip-completion-method-as-.patch @@ -0,0 +1,140 @@ +From: Ben Skeggs +Date: Wed, 21 Mar 2012 13:53:49 +1000 +Subject: [4/9] drm/nvc0-/disp: reimplement flip completion method as fifo + method + +commit d5316e251230c4e54a157349a362229c3d4daa32 upstream. + +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 35acc92..ab44727 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 eaf9872..3dd620fc 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 dcbe0d5..50d68a7 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 8ee3963..9066102 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-) */ diff --git a/debian/patches/features/all/fermi-accel/drm-nvd0-disp-ignore-clock-set-if-no-pclk.patch b/debian/patches/features/all/fermi-accel/drm-nvd0-disp-ignore-clock-set-if-no-pclk.patch new file mode 100644 index 000000000..3b2764762 --- /dev/null +++ b/debian/patches/features/all/fermi-accel/drm-nvd0-disp-ignore-clock-set-if-no-pclk.patch @@ -0,0 +1,31 @@ +From: Ben Skeggs +Date: Fri, 16 Mar 2012 15:32:16 +1000 +Subject: [8/9] drm/nvd0/disp: ignore clock set if no pclk + +commit dd62608bcc8a629c4c583fb50b90003fd5213516 upstream. + +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 5e2b79b..421d301 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); + } + diff --git a/debian/patches/series b/debian/patches/series index cbdbce6bb..77cb4ae66 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -368,3 +368,14 @@ debian/driver-core-avoid-ABI-change-for-removal-of-__must_check.patch bugfix/all/scsi-Silence-unnecessary-warnings-about-ioctl-to-par.patch bugfix/all/udf-Improve-table-length-check-to-avoid-possible-underflow.patch bugfix/all/epoll-clear-the-tfile_check_list-on-eloop.patch + +# nouveau update to support Fermi (NVC0+) acceleration +features/all/fermi-accel/drm-nouveau-ttm-always-do-buffer-moves-on-kernel-cha.patch +features/all/fermi-accel/drm-nouveau-remove-subchannel-names-from-places-wher.patch +features/all/fermi-accel/drm-nouveau-move-fence-sequence-check-to-start-of-lo.patch +features/all/fermi-accel/drm-nvc0-disp-reimplement-flip-completion-method-as-.patch +features/all/fermi-accel/drm-nouveau-remove-m2mf-creation-on-userspace-channe.patch +features/all/fermi-accel/drm-nouveau-inform-userspace-of-relaxed-kernel-subch.patch +features/all/fermi-accel/drm-nouveau-oops-increase-channel-dispc_vma-to-4.patch +features/all/fermi-accel/drm-nvd0-disp-ignore-clock-set-if-no-pclk.patch +features/all/fermi-accel/drm-nouveau-bump-version-to-1.0.0.patch