From 6bfb9b639ab2ab71969eeeb72105ce7e0c487462 Mon Sep 17 00:00:00 2001 From: George Sapountzis Date: Fri, 25 Jan 2008 16:54:29 +0200 Subject: mach64: fix after vblank-rework don't disable vblank interrupts (similar to r128) --- shared-core/mach64_irq.c | 45 +++++++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/shared-core/mach64_irq.c b/shared-core/mach64_irq.c index 2d522a6c..57879e8d 100644 --- a/shared-core/mach64_irq.c +++ b/shared-core/mach64_irq.c @@ -71,11 +71,10 @@ irqreturn_t mach64_driver_irq_handler(DRM_IRQ_ARGS) u32 mach64_get_vblank_counter(struct drm_device * dev, int crtc) { const drm_mach64_private_t *const dev_priv = dev->dev_private; - - if (crtc != 0) { + + if (crtc != 0) return 0; - } - + return atomic_read(&dev_priv->vbl_received); } @@ -83,14 +82,15 @@ int mach64_enable_vblank(struct drm_device * dev, int crtc) { drm_mach64_private_t *dev_priv = dev->dev_private; u32 status = MACH64_READ(MACH64_CRTC_INT_CNTL); - + if (crtc != 0) { - DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", crtc); - return 0; + DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", + crtc); + return -EINVAL; } - + DRM_DEBUG("before enable vblank CRTC_INT_CTNL: 0x%08x\n", status); - + /* Turn on VBLANK interrupt */ MACH64_WRITE(MACH64_CRTC_INT_CNTL, MACH64_READ(MACH64_CRTC_INT_CNTL) | MACH64_CRTC_VBLANK_INT_EN); @@ -98,12 +98,31 @@ int mach64_enable_vblank(struct drm_device * dev, int crtc) return 0; } - void mach64_disable_vblank(struct drm_device * dev, int crtc) +{ + if (crtc != 0) { + DRM_ERROR("tried to disable vblank on non-existent crtc %d\n", + crtc); + return; + } + + /* + * FIXME: implement proper interrupt disable by using the vblank + * counter register (if available). + */ +} + +static void mach64_disable_vblank_local(struct drm_device * dev, int crtc) { drm_mach64_private_t *dev_priv = dev->dev_private; u32 status = MACH64_READ(MACH64_CRTC_INT_CNTL); + if (crtc != 0) { + DRM_ERROR("tried to disable vblank on non-existent crtc %d\n", + crtc); + return; + } + DRM_DEBUG("before disable vblank CRTC_INT_CTNL: 0x%08x\n", status); /* Disable and clear VBLANK interrupt */ @@ -111,8 +130,6 @@ void mach64_disable_vblank(struct drm_device * dev, int crtc) | MACH64_CRTC_VBLANK_INT); } -/* drm_dma.h hooks -*/ void mach64_driver_irq_preinstall(struct drm_device * dev) { drm_mach64_private_t *dev_priv = dev->dev_private; @@ -121,7 +138,7 @@ void mach64_driver_irq_preinstall(struct drm_device * dev) DRM_DEBUG("before install CRTC_INT_CTNL: 0x%08x\n", status); - mach64_disable_vblank(dev,0); + mach64_disable_vblank_local(dev, 0); } int mach64_driver_irq_postinstall(struct drm_device * dev) @@ -135,7 +152,7 @@ void mach64_driver_irq_uninstall(struct drm_device * dev) if (!dev_priv) return; - mach64_disable_vblank(dev, 0); + mach64_disable_vblank_local(dev, 0); DRM_DEBUG("after uninstall CRTC_INT_CTNL: 0x%08x\n", MACH64_READ(MACH64_CRTC_INT_CNTL)); -- cgit v1.2.3 From b8755ff7c33baac2abe5b5fe00897b33a896a098 Mon Sep 17 00:00:00 2001 From: Maciej Cencora Date: Sun, 27 Jan 2008 12:50:31 +1000 Subject: drm: add initial rs690 support for drm. This adds support for configuring the RS690 GART. --- shared-core/drm_pciids.txt | 1 + shared-core/radeon_cp.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++ shared-core/radeon_drv.h | 42 ++++++++++++++++++++-- 3 files changed, 127 insertions(+), 2 deletions(-) diff --git a/shared-core/drm_pciids.txt b/shared-core/drm_pciids.txt index b14b5241..b2bf8eab 100644 --- a/shared-core/drm_pciids.txt +++ b/shared-core/drm_pciids.txt @@ -232,6 +232,7 @@ 0x1002 0x7297 CHIP_RV560|RADEON_NEW_MEMMAP "ATI RV560" 0x1002 0x7834 CHIP_RS300|RADEON_IS_IGP|RADEON_NEW_MEMMAP "ATI Radeon RS350 9000/9100 IGP" 0x1002 0x7835 CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Radeon RS350 Mobility IGP" +0x1002 0x791e CHIP_RS690|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART "ATI Radeon RS690 X1250 IGP" [r128] 0x1002 0x4c45 0 "ATI Rage 128 Mobility LE (PCI)" diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 3eb81efc..ac46da38 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -825,11 +825,19 @@ static u32 RADEON_READ_MCIND(drm_radeon_private_t *dev_priv, int addr) return ret; } +static u32 RS690_READ_MCIND(drm_radeon_private_t *dev_priv, int addr) +{ + RADEON_WRITE(RS690_MC_INDEX, (addr & RS690_MC_INDEX_MASK)); + return RADEON_READ(RS690_MC_DATA); +} + u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv) { if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) return RADEON_READ_MCIND(dev_priv, RV515_MC_FB_LOCATION); + else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) + return RS690_READ_MCIND(dev_priv, RS690_MC_FB_LOCATION); else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515) return RADEON_READ_MCIND(dev_priv, R520_MC_FB_LOCATION); else @@ -840,6 +848,8 @@ static void radeon_write_fb_location(drm_radeon_private_t *dev_priv, u32 fb_loc) { if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) RADEON_WRITE_MCIND(RV515_MC_FB_LOCATION, fb_loc); + else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) + RS690_WRITE_MCIND(RS690_MC_FB_LOCATION, fb_loc); else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515) RADEON_WRITE_MCIND(R520_MC_FB_LOCATION, fb_loc); else @@ -850,6 +860,8 @@ static void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_lo { if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) RADEON_WRITE_MCIND(RV515_MC_AGP_LOCATION, agp_loc); + else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) + RS690_WRITE_MCIND(RS690_MC_AGP_LOCATION, agp_loc); else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515) RADEON_WRITE_MCIND(R520_MC_AGP_LOCATION, agp_loc); else @@ -1362,6 +1374,74 @@ static void radeon_set_igpgart(drm_radeon_private_t * dev_priv, int on) } } +/* Enable or disable RS690 GART on the chip */ +static void radeon_set_rs690gart(drm_radeon_private_t * dev_priv, int on) +{ + u32 temp; + + if (on) { + DRM_DEBUG("programming rs690 gart %08X %08lX %08X\n", + dev_priv->gart_vm_start, + (long)dev_priv->gart_info.bus_addr, + dev_priv->gart_size); + + temp = RS690_READ_MCIND(dev_priv, RS690_MC_MISC_CNTL); + RS690_WRITE_MCIND(RS690_MC_MISC_CNTL, 0x5000); + + RS690_WRITE_MCIND(RS690_MC_AGP_SIZE, + RS690_MC_GART_EN | RS690_MC_AGP_SIZE_32MB); + + temp = RS690_READ_MCIND(dev_priv, RS690_MC_GART_FEATURE_ID); + RS690_WRITE_MCIND(RS690_MC_GART_FEATURE_ID, 0x42040800); + + RS690_WRITE_MCIND(RS690_MC_GART_BASE, + dev_priv->gart_info.bus_addr); + + temp = RS690_READ_MCIND(dev_priv, RS690_MC_AGP_MODE_CONTROL); + RS690_WRITE_MCIND(RS690_MC_AGP_MODE_CONTROL, 0x01400000); + + RS690_WRITE_MCIND(RS690_MC_AGP_BASE, + (unsigned int)dev_priv->gart_vm_start); + + dev_priv->gart_size = 32*1024*1024; + temp = (((dev_priv->gart_vm_start - 1 + dev_priv->gart_size) & + 0xffff0000) | (dev_priv->gart_vm_start >> 16)); + + RS690_WRITE_MCIND(RS690_MC_AGP_LOCATION, temp); + + temp = RS690_READ_MCIND(dev_priv, RS690_MC_AGP_SIZE); + RS690_WRITE_MCIND(RS690_MC_AGP_SIZE, + RS690_MC_GART_EN | RS690_MC_AGP_SIZE_32MB); + + do + { + temp = RS690_READ_MCIND(dev_priv, RS690_MC_GART_CACHE_CNTL); + if ((temp & RS690_MC_GART_CLEAR_STATUS) == + RS690_MC_GART_CLEAR_DONE) + break; + DRM_UDELAY(1); + } while(1); + + RS690_WRITE_MCIND(RS690_MC_GART_CACHE_CNTL, + RS690_MC_GART_CC_CLEAR); + do + { + temp = RS690_READ_MCIND(dev_priv, RS690_MC_GART_CACHE_CNTL); + if ((temp & RS690_MC_GART_CLEAR_STATUS) == + RS690_MC_GART_CLEAR_DONE) + break; + DRM_UDELAY(1); + } while(1); + + RS690_WRITE_MCIND(RS690_MC_GART_CACHE_CNTL, + RS690_MC_GART_CC_NO_CHANGE); + } + else + { + RS690_WRITE_MCIND(RS690_MC_AGP_SIZE, RS690_MC_GART_DIS); + } +} + static void radeon_set_pciegart(drm_radeon_private_t * dev_priv, int on) { u32 tmp = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_TX_GART_CNTL); @@ -1396,6 +1476,12 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on) { u32 tmp; + if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) + { + radeon_set_rs690gart(dev_priv, on); + return; + } + if (dev_priv->flags & RADEON_IS_IGPGART) { radeon_set_igpgart(dev_priv, on); return; diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index bd51de14..1cf03415 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -124,6 +124,7 @@ enum radeon_family { CHIP_R420, CHIP_RV410, CHIP_RS400, + CHIP_RS690, CHIP_RV515, CHIP_R520, CHIP_RV530, @@ -471,6 +472,36 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev, #define RADEON_IGPGART_ENABLE 0x38 #define RADEON_IGPGART_UNK_39 0x39 +#define RS690_MC_INDEX 0x78 +# define RS690_MC_INDEX_MASK 0x1ff +# define RS690_MC_INDEX_WR_EN (1 << 9) +# define RS690_MC_INDEX_WR_ACK 0x7f +#define RS690_MC_DATA 0x7c + +#define RS690_MC_MISC_CNTL 0x18 +#define RS690_MC_GART_FEATURE_ID 0x2b +#define RS690_MC_GART_BASE 0x2c +#define RS690_MC_GART_CACHE_CNTL 0x2e +# define RS690_MC_GART_CC_NO_CHANGE 0x0 +# define RS690_MC_GART_CC_CLEAR 0x1 +# define RS690_MC_GART_CLEAR_STATUS (1 << 1) +# define RS690_MC_GART_CLEAR_DONE (0 << 1) +# define RS690_MC_GART_CLEAR_PENDING (1 << 1) +#define RS690_MC_AGP_SIZE 0x38 +# define RS690_MC_GART_DIS 0x0 +# define RS690_MC_GART_EN 0x1 +# define RS690_MC_AGP_SIZE_32MB (0 << 1) +# define RS690_MC_AGP_SIZE_64MB (1 << 1) +# define RS690_MC_AGP_SIZE_128MB (2 << 1) +# define RS690_MC_AGP_SIZE_256MB (3 << 1) +# define RS690_MC_AGP_SIZE_512MB (4 << 1) +# define RS690_MC_AGP_SIZE_1GB (5 << 1) +# define RS690_MC_AGP_SIZE_2GB (6 << 1) +#define RS690_MC_AGP_MODE_CONTROL 0x39 +#define RS690_MC_FB_LOCATION 0x100 +#define RS690_MC_AGP_LOCATION 0x101 +#define RS690_MC_AGP_BASE 0x102 + #define R520_MC_IND_INDEX 0x70 #define R520_MC_IND_WR_EN (1<<24) #define R520_MC_IND_DATA 0x74 @@ -1082,8 +1113,8 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev, #define RADEON_PCIGART_TABLE_SIZE (32*1024) -#define RADEON_READ(reg) DRM_READ32( dev_priv->mmio, (reg) ) -#define RADEON_WRITE(reg,val) DRM_WRITE32( dev_priv->mmio, (reg), (val) ) +#define RADEON_READ(reg) DRM_READ32( dev_priv->mmio, (reg) ) +#define RADEON_WRITE(reg,val) DRM_WRITE32( dev_priv->mmio, (reg), (val) ) #define RADEON_READ8(reg) DRM_READ8( dev_priv->mmio, (reg) ) #define RADEON_WRITE8(reg,val) DRM_WRITE8( dev_priv->mmio, (reg), (val) ) @@ -1116,6 +1147,13 @@ do { \ RADEON_WRITE(R520_MC_IND_INDEX, 0); \ } while (0) +#define RS690_WRITE_MCIND( addr, val ) \ +do { \ + RADEON_WRITE(RS690_MC_INDEX, RS690_MC_INDEX_WR_EN | ((addr) & RS690_MC_INDEX_MASK)); \ + RADEON_WRITE(RS690_MC_DATA, val); \ + RADEON_WRITE(RS690_MC_INDEX, RS690_MC_INDEX_WR_ACK); \ +} while (0) + #define CP_PACKET0( reg, n ) \ (RADEON_CP_PACKET0 | ((n) << 16) | ((reg) >> 2)) #define CP_PACKET0_TABLE( reg, n ) \ -- cgit v1.2.3 From 01f6afcfea9d315ad1473045da141bfc95bcb7e6 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 28 Jan 2008 21:05:22 -0800 Subject: Fix hibernate save/restore of VGA attribute regs In hibernate, we may end up calling the VGA save regs function twice, so we need to make sure it's idempotent. That means leaving ARX in index mode after the first save operation. Fixes hibernate on 965. --- linux-core/i915_drv.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index a5f60ee1..5f2e6adc 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -192,6 +192,7 @@ static void i915_save_vga(struct drm_device *dev) dev_priv->saveAR[i] = i915_read_ar(st01, i, 0); inb(st01); outb(dev_priv->saveAR_INDEX, VGA_AR_INDEX); + inb(st01); /* Graphics controller registers */ for (i = 0; i < 9; i++) @@ -257,6 +258,7 @@ static void i915_restore_vga(struct drm_device *dev) i915_write_ar(st01, i, dev_priv->saveAR[i], 0); inb(st01); /* switch back to index mode */ outb(dev_priv->saveAR_INDEX | 0x20, VGA_AR_INDEX); + inb(st01); /* VGA color palette registers */ outb(dev_priv->saveDACMASK, VGA_DACMASK); -- cgit v1.2.3 From 0744cb153aabd290fd4832288a530adeb5561e2c Mon Sep 17 00:00:00 2001 From: Mirko Date: Tue, 29 Jan 2008 10:11:27 -0500 Subject: Add new RV380 pci id bug 14289 --- shared-core/drm_pciids.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/shared-core/drm_pciids.txt b/shared-core/drm_pciids.txt index b2bf8eab..63b5cd50 100644 --- a/shared-core/drm_pciids.txt +++ b/shared-core/drm_pciids.txt @@ -79,6 +79,7 @@ 0x1002 0x5460 CHIP_RV380|RADEON_IS_MOBILITY "ATI Radeon Mobility X300 M22" 0x1002 0x5462 CHIP_RV380|RADEON_IS_MOBILITY "ATI Radeon Mobility X600 SE M24C" 0x1002 0x5464 CHIP_RV380|RADEON_IS_MOBILITY "ATI FireGL M22 GL 5464" +0x1002 0x5657 CHIP_RV380|RADEON_NEW_MEMMAP "ATI Radeon RV370 X550XTX" 0x1002 0x5548 CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R423 X800" 0x1002 0x5549 CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R423 X800 Pro" 0x1002 0x554A CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R423 X800 XT PE" -- cgit v1.2.3 From 9a7e45858d8faa7afbe31b130d2de1be781085da Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 30 Jan 2008 11:40:13 +1100 Subject: nv40: some more nv67 changes With some luck the drm-side will be OK now for this chipset. --- shared-core/nouveau_fifo.c | 1 - shared-core/nouveau_state.c | 1 + shared-core/nv40_graph.c | 4 +++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c index d00f1938..0daf9ac4 100644 --- a/shared-core/nouveau_fifo.c +++ b/shared-core/nouveau_fifo.c @@ -64,7 +64,6 @@ static int nouveau_fifo_instmem_configure(struct drm_device *dev) switch(dev_priv->card_type) { - case NV_50: case NV_40: switch (dev_priv->chipset) { case 0x47: diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c index 7086a0ab..12162167 100644 --- a/shared-core/nouveau_state.c +++ b/shared-core/nouveau_state.c @@ -212,6 +212,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->fifo.save_context = nv10_fifo_save_context; break; case 0x40: + case 0x60: engine->instmem.init = nv04_instmem_init; engine->instmem.takedown= nv04_instmem_takedown; engine->instmem.populate = nv04_instmem_populate; diff --git a/shared-core/nv40_graph.c b/shared-core/nv40_graph.c index fdf51519..6ef02bf9 100644 --- a/shared-core/nv40_graph.c +++ b/shared-core/nv40_graph.c @@ -1511,6 +1511,7 @@ nv40_graph_create_context(struct nouveau_channel *chan) ctx_init = nv4b_graph_context_init; break; case 0x4c: + case 0x67: ctx_size = NV4C_GRCTX_SIZE; ctx_init = nv4c_graph_context_init; break; @@ -2007,7 +2008,8 @@ nv40_graph_init(struct drm_device *dev) 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 0x4c: ctx_voodoo = nv4c_ctx_voodoo; break; + case 0x4c: + case 0x67: ctx_voodoo = nv4c_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 f1edb7ad91d8b92057ffa02eb162e3740d05a147 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 30 Jan 2008 22:06:02 +0100 Subject: Simplify the fencing code and differentiate between flushes and waiting types. Add a "command_stream_barrier" method to the bo driver. --- linux-core/drm_bo.c | 34 ++-- linux-core/drm_fence.c | 389 +++++++++++++++++++++----------------------- linux-core/drm_objects.h | 75 +++++++-- linux-core/i915_drv.c | 13 +- linux-core/i915_fence.c | 246 +++++++++++++++++++++------- linux-core/nouveau_buffer.c | 3 +- linux-core/nouveau_fence.c | 32 +--- linux-core/via_fence.c | 114 +++---------- linux-core/xgi_drv.c | 11 +- linux-core/xgi_fence.c | 55 +++---- shared-core/i915_dma.c | 5 +- shared-core/i915_drv.h | 12 +- shared-core/via_drv.c | 14 +- shared-core/via_drv.h | 11 -- shared-core/via_map.c | 3 - 15 files changed, 537 insertions(+), 480 deletions(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index df10e12b..3b180d15 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -287,7 +287,7 @@ int drm_bo_wait(struct drm_buffer_object *bo, int lazy, int ignore_signals, DRM_ASSERT_LOCKED(&bo->mutex); if (bo->fence) { - if (drm_fence_object_signaled(bo->fence, bo->fence_type, 0)) { + if (drm_fence_object_signaled(bo->fence, bo->fence_type)) { drm_fence_usage_deref_unlocked(&bo->fence); return 0; } @@ -354,7 +354,7 @@ static void drm_bo_cleanup_refs(struct drm_buffer_object *bo, int remove_all) DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); if (bo->fence && drm_fence_object_signaled(bo->fence, - bo->fence_type, 0)) + bo->fence_type)) drm_fence_usage_deref_unlocked(&bo->fence); if (bo->fence && remove_all) @@ -559,7 +559,7 @@ void drm_putback_buffer_objects(struct drm_device *dev) list_del_init(&entry->lru); DRM_FLAG_MASKED(entry->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); - DRM_WAKEUP(&entry->event_queue); + wake_up_all(&entry->event_queue); /* * FIXME: Might want to put back on head of list @@ -660,7 +660,7 @@ int drm_fence_buffer_objects(struct drm_device *dev, entry->fence_type = entry->new_fence_type; DRM_FLAG_MASKED(entry->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); - DRM_WAKEUP(&entry->event_queue); + wake_up_all(&entry->event_queue); drm_bo_add_to_lru(entry); } mutex_unlock(&entry->mutex); @@ -1032,7 +1032,7 @@ static int drm_bo_quick_busy(struct drm_buffer_object *bo) BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); if (fence) { - if (drm_fence_object_signaled(fence, bo->fence_type, 0)) { + if (drm_fence_object_signaled(fence, bo->fence_type)) { drm_fence_usage_deref_unlocked(&bo->fence); return 0; } @@ -1052,12 +1052,12 @@ static int drm_bo_busy(struct drm_buffer_object *bo) BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); if (fence) { - if (drm_fence_object_signaled(fence, bo->fence_type, 0)) { + if (drm_fence_object_signaled(fence, bo->fence_type)) { drm_fence_usage_deref_unlocked(&bo->fence); return 0; } drm_fence_object_flush(fence, DRM_FENCE_TYPE_EXE); - if (drm_fence_object_signaled(fence, bo->fence_type, 0)) { + if (drm_fence_object_signaled(fence, bo->fence_type)) { drm_fence_usage_deref_unlocked(&bo->fence); return 0; } @@ -1249,7 +1249,7 @@ static int drm_buffer_object_map(struct drm_file *file_priv, uint32_t handle, mutex_unlock(&dev->struct_mutex); if (ret) { if (atomic_add_negative(-1, &bo->mapped)) - DRM_WAKEUP(&bo->event_queue); + wake_up_all(&bo->event_queue); } else drm_bo_fill_rep_arg(bo, rep); @@ -1306,7 +1306,7 @@ static void drm_buffer_user_object_unmap(struct drm_file *file_priv, BUG_ON(action != _DRM_REF_TYPE1); if (atomic_add_negative(-1, &bo->mapped)) - DRM_WAKEUP(&bo->event_queue); + wake_up_all(&bo->event_queue); } /* @@ -1364,7 +1364,7 @@ out_unlock: } drm_bo_add_to_lru(bo); if (bo->priv_flags & _DRM_BO_FLAG_UNFENCED) { - DRM_WAKEUP(&bo->event_queue); + wake_up_all(&bo->event_queue); DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); } @@ -1442,13 +1442,21 @@ static int drm_buffer_object_validate(struct drm_buffer_object *bo, * We're switching command submission mechanism, * or cannot simply rely on the hardware serializing for us. * - * Wait for buffer idle. + * Insert a driver-dependant barrier or wait for buffer idle. */ if ((fence_class != bo->fence_class) || ((ftype ^ bo->fence_type) & bo->fence_type)) { - ret = drm_bo_wait(bo, 0, 0, no_wait); + ret = -EINVAL; + if (driver->command_stream_barrier) { + ret = driver->command_stream_barrier(bo, + fence_class, + ftype, + no_wait); + } + if (ret) + ret = drm_bo_wait(bo, 0, 0, no_wait); if (ret) return ret; @@ -1539,7 +1547,7 @@ static int drm_buffer_object_validate(struct drm_buffer_object *bo, } else { drm_bo_add_to_lru(bo); if (bo->priv_flags & _DRM_BO_FLAG_UNFENCED) { - DRM_WAKEUP(&bo->event_queue); + wake_up_all(&bo->event_queue); DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); } diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index 288b4db6..a852c63f 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -30,6 +30,57 @@ #include "drmP.h" + +/* + * Convenience function to be called by fence::wait methods that + * need polling. + */ + +int drm_fence_wait_polling(struct drm_fence_object *fence, int lazy, + int interruptible, uint32_t mask, + unsigned long end_jiffies) +{ + struct drm_device *dev = fence->dev; + struct drm_fence_manager *fm = &dev->fm; + struct drm_fence_class_manager *fc = &fm->fence_class[fence->fence_class]; + uint32_t count = 0; + int ret; + + DECLARE_WAITQUEUE(entry, current); + add_wait_queue(&fc->fence_queue, &entry); + + ret = 0; + + for (;;) { + __set_current_state((interruptible) ? + TASK_INTERRUPTIBLE : + TASK_UNINTERRUPTIBLE); + if (drm_fence_object_signaled(fence, mask)) + break; + if (time_after_eq(jiffies, end_jiffies)) { + ret = -EBUSY; + break; + } + if (lazy) + schedule_timeout(1); + else if ((++count & 0x0F) == 0){ + __set_current_state(TASK_RUNNING); + schedule(); + __set_current_state((interruptible) ? + TASK_INTERRUPTIBLE : + TASK_UNINTERRUPTIBLE); + } + if (interruptible && signal_pending(current)) { + ret = -EAGAIN; + break; + } + } + __set_current_state(TASK_RUNNING); + remove_wait_queue(&fc->fence_queue, &entry); + return ret; +} +EXPORT_SYMBOL(drm_fence_wait_polling); + /* * Typically called by the IRQ handler. */ @@ -39,27 +90,14 @@ void drm_fence_handler(struct drm_device *dev, uint32_t fence_class, { int wake = 0; uint32_t diff; - uint32_t relevant; + uint32_t relevant_type; + uint32_t new_type; struct drm_fence_manager *fm = &dev->fm; struct drm_fence_class_manager *fc = &fm->fence_class[fence_class]; struct drm_fence_driver *driver = dev->driver->fence_driver; struct list_head *head; struct drm_fence_object *fence, *next; int found = 0; - int is_exe = (type & DRM_FENCE_TYPE_EXE); - int ge_last_exe; - - - diff = (sequence - fc->exe_flush_sequence) & driver->sequence_mask; - - if (fc->pending_exe_flush && is_exe && diff < driver->wrap_diff) - fc->pending_exe_flush = 0; - - diff = (sequence - fc->last_exe_flush) & driver->sequence_mask; - ge_last_exe = diff < driver->wrap_diff; - - if (is_exe && ge_last_exe) - fc->last_exe_flush = sequence; if (list_empty(&fc->ring)) return; @@ -72,7 +110,7 @@ void drm_fence_handler(struct drm_device *dev, uint32_t fence_class, } } - fc->pending_flush &= ~type; + fc->waiting_types &= ~type; head = (found) ? &fence->ring : &fc->ring; list_for_each_entry_safe_reverse(fence, next, head, ring) { @@ -81,64 +119,60 @@ void drm_fence_handler(struct drm_device *dev, uint32_t fence_class, if (error) { fence->error = error; - fence->signaled = fence->type; - fence->submitted_flush = fence->type; - fence->flush_mask = fence->type; + fence->signaled_types = fence->type; list_del_init(&fence->ring); wake = 1; break; } - if (is_exe) - type |= fence->native_type; + if (type & DRM_FENCE_TYPE_EXE) + type |= fence->native_types; - relevant = type & fence->type; + relevant_type = type & fence->type; + new_type = (fence->signaled_types | relevant_type) & + ~fence->signaled_types; - if ((fence->signaled | relevant) != fence->signaled) { - fence->signaled |= relevant; - fence->flush_mask |= relevant; - fence->submitted_flush |= relevant; + if (new_type) { + fence->signaled_types |= new_type; DRM_DEBUG("Fence 0x%08lx signaled 0x%08x\n", - fence->base.hash.key, fence->signaled); - wake = 1; - } + fence->base.hash.key, fence->signaled_types); + + if (driver->needed_flush) + fc->pending_flush |= driver->needed_flush(fence); - relevant = fence->flush_mask & - ~(fence->submitted_flush | fence->signaled); + if (new_type & fence->waiting_types) + wake = 1; + } - fc->pending_flush |= relevant; - fence->submitted_flush |= relevant; + fc->waiting_types |= fence->waiting_types & ~fence->signaled_types; - if (!(fence->type & ~fence->signaled)) { + if (!(fence->type & ~fence->signaled_types)) { DRM_DEBUG("Fence completely signaled 0x%08lx\n", fence->base.hash.key); list_del_init(&fence->ring); } - } /* - * Reinstate lost flush flags. + * Reinstate lost waiting types. */ - if ((fc->pending_flush & type) != type) { + if ((fc->waiting_types & type) != type) { head = head->prev; list_for_each_entry(fence, head, ring) { if (&fence->ring == &fc->ring) break; - diff = (fc->last_exe_flush - fence->sequence) & + diff = (fc->highest_waiting_sequence - fence->sequence) & driver->sequence_mask; if (diff > driver->wrap_diff) break; - - relevant = fence->submitted_flush & ~fence->signaled; - fc->pending_flush |= relevant; + + fc->waiting_types |= fence->waiting_types & ~fence->signaled_types; } } - if (wake) { - DRM_WAKEUP(&fc->fence_queue); - } + if (wake) + wake_up_all(&fc->fence_queue); } EXPORT_SYMBOL(drm_fence_handler); @@ -219,41 +253,28 @@ static void drm_fence_object_destroy(struct drm_file *priv, drm_fence_usage_deref_locked(&fence); } -int drm_fence_object_signaled(struct drm_fence_object *fence, - uint32_t mask, int poke_flush) +int drm_fence_object_signaled(struct drm_fence_object *fence, uint32_t mask) { unsigned long flags; int signaled; struct drm_device *dev = fence->dev; struct drm_fence_manager *fm = &dev->fm; struct drm_fence_driver *driver = dev->driver->fence_driver; - - if (poke_flush) - driver->poke_flush(dev, fence->fence_class); + + mask &= fence->type; read_lock_irqsave(&fm->lock, flags); - signaled = - (fence->type & mask & fence->signaled) == (fence->type & mask); + signaled = (mask & fence->signaled_types) == mask; read_unlock_irqrestore(&fm->lock, flags); - + if (!signaled && driver->poll) { + write_lock_irqsave(&fm->lock, flags); + driver->poll(dev, fence->fence_class, mask); + signaled = (mask & fence->signaled_types) == mask; + write_unlock_irqrestore(&fm->lock, flags); + } return signaled; } EXPORT_SYMBOL(drm_fence_object_signaled); -static void drm_fence_flush_exe(struct drm_fence_class_manager *fc, - struct drm_fence_driver *driver, - uint32_t sequence) -{ - uint32_t diff; - - if (!fc->pending_exe_flush) { - fc->exe_flush_sequence = sequence; - fc->pending_exe_flush = 1; - } else { - diff = (sequence - fc->exe_flush_sequence) & driver->sequence_mask; - if (diff < driver->wrap_diff) - fc->exe_flush_sequence = sequence; - } -} int drm_fence_object_flush(struct drm_fence_object *fence, uint32_t type) @@ -262,7 +283,10 @@ int drm_fence_object_flush(struct drm_fence_object *fence, struct drm_fence_manager *fm = &dev->fm; struct drm_fence_class_manager *fc = &fm->fence_class[fence->fence_class]; struct drm_fence_driver *driver = dev->driver->fence_driver; - unsigned long flags; + unsigned long irq_flags; + uint32_t saved_pending_flush; + uint32_t diff; + int call_flush; if (type & ~fence->type) { DRM_ERROR("Flush trying to extend fence type, " @@ -270,24 +294,36 @@ int drm_fence_object_flush(struct drm_fence_object *fence, return -EINVAL; } - write_lock_irqsave(&fm->lock, flags); - fence->flush_mask |= type; - if ((fence->submitted_flush & fence->signaled) - == fence->submitted_flush) { - if ((fence->type & DRM_FENCE_TYPE_EXE) && - !(fence->submitted_flush & DRM_FENCE_TYPE_EXE)) { - drm_fence_flush_exe(fc, driver, fence->sequence); - fence->submitted_flush |= DRM_FENCE_TYPE_EXE; - } else { - fc->pending_flush |= (fence->flush_mask & - ~fence->submitted_flush); - fence->submitted_flush = fence->flush_mask; - } - } - write_unlock_irqrestore(&fm->lock, flags); - driver->poke_flush(dev, fence->fence_class); + write_lock_irqsave(&fm->lock, irq_flags); + fence->waiting_types |= type; + fc->waiting_types |= fence->waiting_types; + diff = (fence->sequence - fc->highest_waiting_sequence) & + driver->sequence_mask; + + if (diff < driver->wrap_diff) + fc->highest_waiting_sequence = fence->sequence; + + /* + * fence->waiting_types has changed. Determine whether + * we need to initiate some kind of flush as a result of this. + */ + + saved_pending_flush = fc->pending_flush; + if (driver->needed_flush) + fc->pending_flush |= driver->needed_flush(fence); + + if (driver->poll) + driver->poll(dev, fence->fence_class, fence->waiting_types); + + call_flush = fc->pending_flush; + write_unlock_irqrestore(&fm->lock, irq_flags); + + if (call_flush && driver->flush) + driver->flush(dev, fence->fence_class); + return 0; } +EXPORT_SYMBOL(drm_fence_object_flush); /* * Make sure old fence objects are signaled before their fence sequences are @@ -299,90 +335,52 @@ void drm_fence_flush_old(struct drm_device *dev, uint32_t fence_class, { struct drm_fence_manager *fm = &dev->fm; struct drm_fence_class_manager *fc = &fm->fence_class[fence_class]; - struct drm_fence_driver *driver = dev->driver->fence_driver; - uint32_t old_sequence; - unsigned long flags; struct drm_fence_object *fence; + unsigned long irq_flags; + struct drm_fence_driver *driver = dev->driver->fence_driver; + int call_flush; + uint32_t diff; - write_lock_irqsave(&fm->lock, flags); - old_sequence = (sequence - driver->flush_diff) & driver->sequence_mask; - diff = (old_sequence - fc->last_exe_flush) & driver->sequence_mask; + write_lock_irqsave(&fm->lock, irq_flags); - if ((diff < driver->wrap_diff) && !fc->pending_exe_flush) { - fc->pending_exe_flush = 1; - fc->exe_flush_sequence = sequence - (driver->flush_diff / 2); - } - write_unlock_irqrestore(&fm->lock, flags); + list_for_each_entry_reverse(fence, &fc->ring, ring) { + diff = (sequence - fence->sequence) & driver->sequence_mask; + if (diff <= driver->flush_diff) + break; + + fence->waiting_types = fence->type; + fc->waiting_types |= fence->type; - mutex_lock(&dev->struct_mutex); - read_lock_irqsave(&fm->lock, flags); + if (driver->needed_flush) + fc->pending_flush |= driver->needed_flush(fence); + } + + if (driver->poll) + driver->poll(dev, fence_class, fc->waiting_types); - if (list_empty(&fc->ring)) { - read_unlock_irqrestore(&fm->lock, flags); - mutex_unlock(&dev->struct_mutex); - return; - } - fence = drm_fence_reference_locked(list_entry(fc->ring.next, struct drm_fence_object, 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(fence, fence->type); - drm_fence_usage_deref_unlocked(&fence); -} -EXPORT_SYMBOL(drm_fence_flush_old); + call_flush = fc->pending_flush; + write_unlock_irqrestore(&fm->lock, irq_flags); -static int drm_fence_lazy_wait(struct drm_fence_object *fence, - int ignore_signals, - uint32_t mask) -{ - struct drm_device *dev = fence->dev; - struct drm_fence_manager *fm = &dev->fm; - struct drm_fence_class_manager *fc = &fm->fence_class[fence->fence_class]; - int signaled; - unsigned long _end = jiffies + 3*DRM_HZ; - int ret = 0; + if (call_flush && driver->flush) + driver->flush(dev, fence->fence_class); + + /* + * FIXME: Shold we implement a wait here for really old fences? + */ - do { - DRM_WAIT_ON(ret, fc->fence_queue, 3 * DRM_HZ, - (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(fence, mask, 0)) - return 0; - if (time_after_eq(jiffies, _end)) - ret = -EBUSY; - if (ret) { - if (ret == -EBUSY) { - DRM_ERROR("Fence timeout. " - "GPU lockup or fence driver was " - "taken down. %d 0x%08x 0x%02x 0x%02x 0x%02x\n", - fence->fence_class, - fence->sequence, - fence->type, - mask, - fence->signaled); - DRM_ERROR("Pending exe flush %d 0x%08x\n", - fc->pending_exe_flush, - fc->exe_flush_sequence); - } - return ((ret == -EINTR) ? -EAGAIN : ret); - } - return 0; } +EXPORT_SYMBOL(drm_fence_flush_old); int drm_fence_object_wait(struct drm_fence_object *fence, int lazy, int ignore_signals, uint32_t mask) { struct drm_device *dev = fence->dev; struct drm_fence_driver *driver = dev->driver->fence_driver; + struct drm_fence_manager *fm = &dev->fm; + struct drm_fence_class_manager *fc = &fm->fence_class[fence->fence_class]; int ret = 0; - unsigned long _end; - int signaled; + unsigned long _end = 3 * DRM_HZ; if (mask & ~fence->type) { DRM_ERROR("Wait trying to extend fence type" @@ -391,58 +389,39 @@ int drm_fence_object_wait(struct drm_fence_object *fence, return -EINVAL; } - if (drm_fence_object_signaled(fence, mask, 0)) - return 0; + if (driver->wait) + return driver->wait(fence, lazy, !ignore_signals, mask); - _end = jiffies + 3 * DRM_HZ; drm_fence_object_flush(fence, mask); + if (driver->has_irq(dev, fence->fence_class, mask)) { + if (!ignore_signals) + ret = wait_event_interruptible_timeout + (fc->fence_queue, + drm_fence_object_signaled(fence, mask), + 3 * DRM_HZ); + else + ret = wait_event_timeout + (fc->fence_queue, + drm_fence_object_signaled(fence, mask), + 3 * DRM_HZ); + + if (unlikely(ret == -ERESTARTSYS)) + return -EAGAIN; + + if (unlikely(ret == 0)) + return -EBUSY; - if (lazy && driver->lazy_capable) { - - ret = drm_fence_lazy_wait(fence, ignore_signals, mask); - if (ret) - return ret; - - } else { - - if (driver->has_irq(dev, fence->fence_class, - DRM_FENCE_TYPE_EXE)) { - ret = drm_fence_lazy_wait(fence, ignore_signals, - DRM_FENCE_TYPE_EXE); - if (ret) - return ret; - } - - if (driver->has_irq(dev, fence->fence_class, - mask & ~DRM_FENCE_TYPE_EXE)) { - ret = drm_fence_lazy_wait(fence, ignore_signals, - mask); - if (ret) - return ret; - } - } - if (drm_fence_object_signaled(fence, mask, 0)) return 0; + } - /* - * Avoid kernel-space busy-waits. - */ - if (!ignore_signals) - return -EAGAIN; - - do { - schedule(); - signaled = drm_fence_object_signaled(fence, mask, 1); - } while (!signaled && !time_after_eq(jiffies, _end)); - - if (!signaled) - return -EBUSY; - - return 0; + return drm_fence_wait_polling(fence, lazy, !ignore_signals, mask, + _end); } EXPORT_SYMBOL(drm_fence_object_wait); + + int drm_fence_object_emit(struct drm_fence_object *fence, uint32_t fence_flags, uint32_t fence_class, uint32_t type) { @@ -452,25 +431,24 @@ int drm_fence_object_emit(struct drm_fence_object *fence, uint32_t fence_flags, struct drm_fence_class_manager *fc = &fm->fence_class[fence->fence_class]; unsigned long flags; uint32_t sequence; - uint32_t native_type; + uint32_t native_types; int ret; drm_fence_unring(dev, &fence->ring); ret = driver->emit(dev, fence_class, fence_flags, &sequence, - &native_type); + &native_types); if (ret) return ret; write_lock_irqsave(&fm->lock, flags); fence->fence_class = fence_class; fence->type = type; - fence->flush_mask = 0x00; - fence->submitted_flush = 0x00; - fence->signaled = 0x00; + fence->waiting_types = 0; + fence->signaled_types = 0; fence->sequence = sequence; - fence->native_type = native_type; + fence->native_types = native_types; if (list_empty(&fc->ring)) - fc->last_exe_flush = sequence - 1; + fc->highest_waiting_sequence = sequence - 1; list_add_tail(&fence->ring, &fc->ring); write_unlock_irqrestore(&fm->lock, flags); return 0; @@ -500,9 +478,8 @@ static int drm_fence_object_init(struct drm_device *dev, uint32_t fence_class, INIT_LIST_HEAD(&fence->base.list); fence->fence_class = fence_class; fence->type = type; - fence->flush_mask = 0; - fence->submitted_flush = 0; - fence->signaled = 0; + fence->signaled_types = 0; + fence->waiting_types = 0; fence->sequence = 0; fence->dev = dev; write_unlock_irqrestore(&fm->lock, flags); @@ -598,7 +575,7 @@ void drm_fence_fill_arg(struct drm_fence_object *fence, arg->handle = fence->base.hash.key; arg->fence_class = fence->fence_class; arg->type = fence->type; - arg->signaled = fence->signaled; + arg->signaled = fence->signaled_types; arg->error = fence->error; arg->sequence = fence->sequence; read_unlock_irqrestore(&fm->lock, irq_flags); diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index a2d10b5d..c35d900f 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -147,12 +147,11 @@ struct drm_fence_object { struct list_head ring; int fence_class; - uint32_t native_type; + uint32_t native_types; uint32_t type; - uint32_t signaled; + uint32_t signaled_types; uint32_t sequence; - uint32_t flush_mask; - uint32_t submitted_flush; + uint32_t waiting_types; uint32_t error; }; @@ -162,10 +161,9 @@ struct drm_fence_object { struct drm_fence_class_manager { struct list_head ring; uint32_t pending_flush; + uint32_t waiting_types; wait_queue_head_t fence_queue; - int pending_exe_flush; - uint32_t last_exe_flush; - uint32_t exe_flush_sequence; + uint32_t highest_waiting_sequence; }; struct drm_fence_manager { @@ -177,19 +175,49 @@ struct drm_fence_manager { }; struct drm_fence_driver { + unsigned long *waiting_jiffies; uint32_t num_classes; uint32_t wrap_diff; uint32_t flush_diff; uint32_t sequence_mask; - int lazy_capable; + + /* + * Driver implemented functions: + * has_irq() : 1 if the hardware can update the indicated type_flags using an + * irq handler. 0 if polling is required. + * + * emit() : Emit a sequence number to the command stream. + * Return the sequence number. + * + * flush() : Make sure the flags indicated in fc->pending_flush will eventually + * signal for fc->highest_received_sequence and all preceding sequences. + * Acknowledge by clearing the flags fc->pending_flush. + * + * poll() : Call drm_fence_handler with any new information. + * + * needed_flush() : Given the current state of the fence->type flags and previusly + * executed or queued flushes, return the type_flags that need flushing. + * + * wait(): Wait for the "mask" flags to signal on a given fence, performing + * whatever's necessary to make this happen. + */ + int (*has_irq) (struct drm_device *dev, uint32_t fence_class, uint32_t flags); int (*emit) (struct drm_device *dev, uint32_t fence_class, uint32_t flags, uint32_t *breadcrumb, uint32_t *native_type); - void (*poke_flush) (struct drm_device *dev, uint32_t fence_class); + void (*flush) (struct drm_device *dev, uint32_t fence_class); + void (*poll) (struct drm_device *dev, uint32_t fence_class, + uint32_t types); + uint32_t (*needed_flush) (struct drm_fence_object *fence); + int (*wait) (struct drm_fence_object *fence, int lazy, + int interruptible, uint32_t mask); }; +extern int drm_fence_wait_polling(struct drm_fence_object *fence, int lazy, + int interruptible, uint32_t mask, + unsigned long end_jiffies); extern void drm_fence_handler(struct drm_device *dev, uint32_t fence_class, uint32_t sequence, uint32_t type, uint32_t error); @@ -200,7 +228,7 @@ extern void drm_fence_flush_old(struct drm_device *dev, uint32_t fence_class, extern int drm_fence_object_flush(struct drm_fence_object *fence, uint32_t type); extern int drm_fence_object_signaled(struct drm_fence_object *fence, - uint32_t type, int flush); + uint32_t type); extern void drm_fence_usage_deref_locked(struct drm_fence_object **fence); extern void drm_fence_usage_deref_unlocked(struct drm_fence_object **fence); extern struct drm_fence_object *drm_fence_reference_locked(struct drm_fence_object *src); @@ -576,6 +604,33 @@ struct drm_bo_driver { * ttm_cache_flush */ void (*ttm_cache_flush)(struct drm_ttm *ttm); + + /* + * command_stream_barrier + * + * @dev: The drm device. + * + * @bo: The buffer object to validate. + * + * @new_fence_class: The new fence class for the buffer object. + * + * @new_fence_type: The new fence type for the buffer object. + * + * @no_wait: whether this should give up and return -EBUSY + * if this operation would require sleeping + * + * Insert a command stream barrier that makes sure that the + * buffer is idle once the commands associated with the + * current validation are starting to execute. If an error + * condition is returned, or the function pointer is NULL, + * the drm core will force buffer idle + * during validation. + */ + + int (*command_stream_barrier) (struct drm_buffer_object *bo, + uint32_t new_fence_class, + uint32_t new_fence_type, + int no_wait); }; /* diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 5f2e6adc..ccc061d3 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -39,17 +39,9 @@ static struct pci_device_id pciidlist[] = { }; #ifdef I915_HAVE_FENCE -static struct drm_fence_driver i915_fence_driver = { - .num_classes = 1, - .wrap_diff = (1U << (BREADCRUMB_BITS - 1)), - .flush_diff = (1U << (BREADCRUMB_BITS - 2)), - .sequence_mask = BREADCRUMB_MASK, - .lazy_capable = 1, - .emit = i915_fence_emit_sequence, - .poke_flush = i915_poke_flush, - .has_irq = i915_fence_has_irq, -}; +extern struct drm_fence_driver i915_fence_driver; #endif + #ifdef I915_HAVE_BUFFER static uint32_t i915_mem_prios[] = {DRM_BO_MEM_PRIV0, DRM_BO_MEM_TT, DRM_BO_MEM_LOCAL}; @@ -67,6 +59,7 @@ static struct drm_bo_driver i915_bo_driver = { .evict_flags = i915_evict_flags, .move = i915_move, .ttm_cache_flush = i915_flush_ttm, + .command_stream_barrier = NULL, }; #endif diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c index e3c76df6..8a2e7f13 100644 --- a/linux-core/i915_fence.c +++ b/linux-core/i915_fence.c @@ -35,97 +35,121 @@ #include "i915_drv.h" /* - * Implements an intel sync flush operation. + * Initiate a sync flush if it's not already pending. */ -static void i915_perform_flush(struct drm_device *dev) +static void i915_initiate_rwflush(struct drm_i915_private *dev_priv, + struct drm_fence_class_manager *fc) +{ + if ((fc->pending_flush & DRM_I915_FENCE_TYPE_RW) && + !dev_priv->flush_pending) { + dev_priv->flush_sequence = (uint32_t) READ_BREADCRUMB(dev_priv); + dev_priv->flush_flags = fc->pending_flush; + dev_priv->saved_flush_status = READ_HWSP(dev_priv, 0); + I915_WRITE(I915REG_INSTPM, (1 << 5) | (1 << 21)); + dev_priv->flush_pending = 1; + fc->pending_flush &= ~DRM_I915_FENCE_TYPE_RW; + } +} + +static void i915_fence_flush(struct drm_device *dev, + uint32_t fence_class) +{ + struct drm_i915_private *dev_priv = + (struct drm_i915_private *) dev->dev_private; + struct drm_fence_manager *fm = &dev->fm; + struct drm_fence_class_manager *fc = &fm->fence_class[0]; + unsigned long irq_flags; + + if (unlikely(!dev_priv)) + return; + + write_lock_irqsave(&fm->lock, irq_flags); + i915_initiate_rwflush(dev_priv, fc); + write_unlock_irqrestore(&fm->lock, irq_flags); +} + +static void i915_fence_poll(struct drm_device *dev, uint32_t fence_class, + uint32_t waiting_types) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; struct drm_fence_manager *fm = &dev->fm; struct drm_fence_class_manager *fc = &fm->fence_class[0]; - struct drm_fence_driver *driver = dev->driver->fence_driver; uint32_t flush_flags = 0; uint32_t flush_sequence = 0; uint32_t i_status; - uint32_t diff; uint32_t sequence; - int rwflush; - if (!dev_priv) + if (unlikely(!dev_priv)) return; - if (fc->pending_exe_flush) { - sequence = READ_BREADCRUMB(dev_priv); + /* + * First, report any executed sync flush: + */ + + if (dev_priv->flush_pending) { + i_status = READ_HWSP(dev_priv, 0); + if ((i_status & (1 << 12)) != + (dev_priv->saved_flush_status & (1 << 12))) { + flush_flags = dev_priv->flush_flags; + flush_sequence = dev_priv->flush_sequence; + dev_priv->flush_pending = 0; + drm_fence_handler(dev, 0, flush_sequence, flush_flags, 0); + } + } - /* - * First update fences with the current breadcrumb. - */ + /* + * Report A new breadcrumb, and adjust IRQs. + */ + + if (waiting_types & DRM_FENCE_TYPE_EXE) { + sequence = READ_BREADCRUMB(dev_priv); - diff = (sequence - fc->last_exe_flush) & BREADCRUMB_MASK; - if (diff < driver->wrap_diff && diff != 0) { - drm_fence_handler(dev, 0, sequence, + if (sequence != dev_priv->reported_sequence || + !dev_priv->reported_sequence_valid) { + drm_fence_handler(dev, 0, sequence, DRM_FENCE_TYPE_EXE, 0); + dev_priv->reported_sequence = sequence; + dev_priv->reported_sequence_valid = 1; } - if (dev_priv->fence_irq_on && !fc->pending_exe_flush) { + if (dev_priv->fence_irq_on && !(waiting_types & DRM_FENCE_TYPE_EXE)) { i915_user_irq_off(dev_priv); dev_priv->fence_irq_on = 0; - } else if (!dev_priv->fence_irq_on && fc->pending_exe_flush) { + } else if (!dev_priv->fence_irq_on && (waiting_types & DRM_FENCE_TYPE_EXE)) { i915_user_irq_on(dev_priv); dev_priv->fence_irq_on = 1; } } - if (dev_priv->flush_pending) { - i_status = READ_HWSP(dev_priv, 0); - if ((i_status & (1 << 12)) != - (dev_priv->saved_flush_status & (1 << 12))) { - flush_flags = dev_priv->flush_flags; - flush_sequence = dev_priv->flush_sequence; - dev_priv->flush_pending = 0; - drm_fence_handler(dev, 0, flush_sequence, flush_flags, 0); - } - } + /* + * There may be new RW flushes pending. Start them. + */ + + i915_initiate_rwflush(dev_priv, fc); - rwflush = fc->pending_flush & DRM_I915_FENCE_TYPE_RW; - if (rwflush && !dev_priv->flush_pending) { - dev_priv->flush_sequence = (uint32_t) READ_BREADCRUMB(dev_priv); - dev_priv->flush_flags = fc->pending_flush; - dev_priv->saved_flush_status = READ_HWSP(dev_priv, 0); - I915_WRITE(I915REG_INSTPM, (1 << 5) | (1 << 21)); - dev_priv->flush_pending = 1; - fc->pending_flush &= ~DRM_I915_FENCE_TYPE_RW; - } + /* + * And possibly, but unlikely, they finish immediately. + */ if (dev_priv->flush_pending) { i_status = READ_HWSP(dev_priv, 0); - if ((i_status & (1 << 12)) != - (dev_priv->saved_flush_status & (1 << 12))) { + if (unlikely((i_status & (1 << 12)) != + (dev_priv->saved_flush_status & (1 << 12)))) { flush_flags = dev_priv->flush_flags; flush_sequence = dev_priv->flush_sequence; dev_priv->flush_pending = 0; drm_fence_handler(dev, 0, flush_sequence, flush_flags, 0); } } - } -void i915_poke_flush(struct drm_device *dev, uint32_t class) -{ - struct drm_fence_manager *fm = &dev->fm; - unsigned long flags; - - write_lock_irqsave(&fm->lock, flags); - i915_perform_flush(dev); - write_unlock_irqrestore(&fm->lock, flags); -} - -int i915_fence_emit_sequence(struct drm_device *dev, uint32_t class, +static int i915_fence_emit_sequence(struct drm_device *dev, uint32_t class, uint32_t flags, uint32_t *sequence, uint32_t *native_type) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - if (!dev_priv) + if (unlikely(!dev_priv)) return -EINVAL; i915_emit_irq(dev); @@ -140,20 +164,130 @@ int i915_fence_emit_sequence(struct drm_device *dev, uint32_t class, void i915_fence_handler(struct drm_device *dev) { struct drm_fence_manager *fm = &dev->fm; + struct drm_fence_class_manager *fc = &fm->fence_class[0]; write_lock(&fm->lock); - i915_perform_flush(dev); + i915_fence_poll(dev, 0, fc->waiting_types); write_unlock(&fm->lock); } -int i915_fence_has_irq(struct drm_device *dev, uint32_t class, uint32_t flags) +/* + * We need a separate wait function since we need to poll for + * sync flushes. + */ + +static int i915_fence_wait(struct drm_fence_object *fence, + int lazy, int interruptible, uint32_t mask) { + struct drm_device *dev = fence->dev; + drm_i915_private_t *dev_priv = (struct drm_i915_private *) dev->dev_private; + struct drm_fence_manager *fm = &dev->fm; + struct drm_fence_class_manager *fc = &fm->fence_class[0]; + int ret; + unsigned long _end = jiffies + 3 * DRM_HZ; + + drm_fence_object_flush(fence, mask); + if (likely(interruptible)) + ret = wait_event_interruptible_timeout + (fc->fence_queue, drm_fence_object_signaled(fence, DRM_FENCE_TYPE_EXE), + 3 * DRM_HZ); + else + ret = wait_event_timeout + (fc->fence_queue, drm_fence_object_signaled(fence, DRM_FENCE_TYPE_EXE), + 3 * DRM_HZ); + + if (unlikely(ret == -ERESTARTSYS)) + return -EAGAIN; + + if (unlikely(ret == 0)) + return -EBUSY; + + if (likely(mask == DRM_FENCE_TYPE_EXE || + drm_fence_object_signaled(fence, mask))) + return 0; + /* - * We have an irq that tells us when we have a new breadcrumb. + * Remove this code snippet when fixed. HWSTAM doesn't let + * flush info through... */ - if (class == 0 && flags == DRM_FENCE_TYPE_EXE) - return 1; + if (unlikely(dev_priv && !dev_priv->irq_enabled)) { + unsigned long irq_flags; - return 0; + DRM_ERROR("X server disabled IRQs before releasing frame buffer.\n"); + msleep(100); + dev_priv->flush_pending = 0; + write_lock_irqsave(&fm->lock, irq_flags); + drm_fence_handler(dev, fence->fence_class, + fence->sequence, fence->type, 0); + write_unlock_irqrestore(&fm->lock, irq_flags); + } + + /* + * Poll for sync flush completion. + */ + + return drm_fence_wait_polling(fence, lazy, interruptible, mask, _end); +} + +static uint32_t i915_fence_needed_flush(struct drm_fence_object *fence) +{ + uint32_t flush_flags = fence->waiting_types & + ~(DRM_FENCE_TYPE_EXE | fence->signaled_types); + + if (likely(flush_flags == 0 || + ((flush_flags & ~fence->native_types) == 0) || + (fence->signaled_types != DRM_FENCE_TYPE_EXE))) + return 0; + else { + struct drm_device *dev = fence->dev; + struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; + struct drm_fence_driver *driver = dev->driver->fence_driver; + + if (unlikely(!dev_priv)) + return 0; + + if (dev_priv->flush_pending) { + uint32_t diff = (dev_priv->flush_sequence - fence->sequence) & + driver->sequence_mask; + + if (diff < driver->wrap_diff) + return 0; + } + } + return flush_flags; +} + +/* + * In the very unlikely event that "poll" is not really called very often + * we need the following function to handle sequence wraparounds. + */ + +void i915_invalidate_reported_sequence(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = (struct drm_i915_private *) + dev->dev_private; + struct drm_fence_manager *fm = &dev->fm; + unsigned long irq_flags; + + if (unlikely(!dev_priv)) + return; + + write_lock_irqsave(&fm->lock, irq_flags); + dev_priv->reported_sequence_valid = 0; + write_unlock_irqrestore(&fm->lock, irq_flags); } + + +struct drm_fence_driver i915_fence_driver = { + .num_classes = 1, + .wrap_diff = (1U << (BREADCRUMB_BITS - 1)), + .flush_diff = (1U << (BREADCRUMB_BITS - 2)), + .sequence_mask = BREADCRUMB_MASK, + .has_irq = NULL, + .emit = i915_fence_emit_sequence, + .flush = i915_fence_flush, + .poll = i915_fence_poll, + .needed_flush = i915_fence_needed_flush, + .wait = i915_fence_wait, +}; diff --git a/linux-core/nouveau_buffer.c b/linux-core/nouveau_buffer.c index a652bb1d..11549317 100644 --- a/linux-core/nouveau_buffer.c +++ b/linux-core/nouveau_buffer.c @@ -294,5 +294,6 @@ struct drm_bo_driver nouveau_bo_driver = { .init_mem_type = nouveau_bo_init_mem_type, .evict_flags = nouveau_bo_evict_flags, .move = nouveau_bo_move, - .ttm_cache_flush= nouveau_bo_flush_ttm + .ttm_cache_flush= nouveau_bo_flush_ttm, + .command_stream_barrier = NULL }; diff --git a/linux-core/nouveau_fence.c b/linux-core/nouveau_fence.c index 4e624a7a..59dcf7d0 100644 --- a/linux-core/nouveau_fence.c +++ b/linux-core/nouveau_fence.c @@ -75,7 +75,7 @@ nouveau_fence_emit(struct drm_device *dev, uint32_t class, uint32_t flags, } static void -nouveau_fence_perform_flush(struct drm_device *dev, uint32_t class) +nouveau_fence_poll(struct drm_device *dev, uint32_t class, uint32_t waiting_types) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_fence_class_manager *fc = &dev->fm.fence_class[class]; @@ -83,42 +83,26 @@ nouveau_fence_perform_flush(struct drm_device *dev, uint32_t class) uint32_t pending_types = 0; DRM_DEBUG("class=%d\n", class); - - pending_types = fc->pending_flush | - ((fc->pending_exe_flush) ? DRM_FENCE_TYPE_EXE : 0); - DRM_DEBUG("pending: 0x%08x 0x%08x\n", pending_types, - fc->pending_flush); + DRM_DEBUG("pending: 0x%08x 0x%08x\n", waiting_types, fc->waiting_types); if (pending_types) { uint32_t sequence = NV_READ(chan->ref_cnt); DRM_DEBUG("got 0x%08x\n", sequence); - drm_fence_handler(dev, class, sequence, pending_types, 0); + drm_fence_handler(dev, class, sequence, waiting_types, 0); } } -static void -nouveau_fence_poke_flush(struct drm_device *dev, uint32_t class) -{ - struct drm_fence_manager *fm = &dev->fm; - unsigned long flags; - - DRM_DEBUG("class=%d\n", class); - - write_lock_irqsave(&fm->lock, flags); - nouveau_fence_perform_flush(dev, class); - write_unlock_irqrestore(&fm->lock, flags); -} - void nouveau_fence_handler(struct drm_device *dev, int channel) { struct drm_fence_manager *fm = &dev->fm; + struct drm_fence_class_manager *fc = &fm->fence_class[channel]; DRM_DEBUG("class=%d\n", channel); write_lock(&fm->lock); - nouveau_fence_perform_flush(dev, channel); + nouveau_fence_poll(dev, channel, fc->waiting_types); write_unlock(&fm->lock); } @@ -127,8 +111,10 @@ struct drm_fence_driver nouveau_fence_driver = { .wrap_diff = (1 << 30), .flush_diff = (1 << 29), .sequence_mask = 0xffffffffU, - .lazy_capable = 1, .has_irq = nouveau_fence_has_irq, .emit = nouveau_fence_emit, - .poke_flush = nouveau_fence_poke_flush + .flush = NULL, + .poll = nouveau_fence_poll, + .needed_flush = NULL, + .wait = NULL }; diff --git a/linux-core/via_fence.c b/linux-core/via_fence.c index 9af1bf3b..3a680a32 100644 --- a/linux-core/via_fence.c +++ b/linux-core/via_fence.c @@ -38,27 +38,21 @@ * DRM_VIA_FENCE_TYPE_ACCEL guarantees that all 2D & 3D rendering is complete. */ - -static uint32_t via_perform_flush(struct drm_device *dev, uint32_t class) +static void via_fence_poll(struct drm_device *dev, uint32_t class, + uint32_t waiting_types) { drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; - struct drm_fence_class_manager *fc = &dev->fm.fence_class[class]; - uint32_t pending_flush_types = 0; uint32_t signaled_flush_types = 0; uint32_t status; if (class != 0) - return 0; + return; - if (!dev_priv) - return 0; + if (unlikely(!dev_priv)) + return; spin_lock(&dev_priv->fence_lock); - - pending_flush_types = fc->pending_flush | - ((fc->pending_exe_flush) ? DRM_FENCE_TYPE_EXE : 0); - - if (pending_flush_types) { + if (waiting_types) { /* * Take the idlelock. This guarantees that the next time a client tries @@ -77,7 +71,7 @@ static uint32_t via_perform_flush(struct drm_device *dev, uint32_t class) * Check if AGP command reader is idle. */ - if (pending_flush_types & DRM_FENCE_TYPE_EXE) + if (waiting_types & DRM_FENCE_TYPE_EXE) if (VIA_READ(0x41C) & 0x80000000) signaled_flush_types |= DRM_FENCE_TYPE_EXE; @@ -85,7 +79,7 @@ static uint32_t via_perform_flush(struct drm_device *dev, uint32_t class) * Check VRAM command queue empty and 2D + 3D engines idle. */ - if (pending_flush_types & DRM_VIA_FENCE_TYPE_ACCEL) { + if (waiting_types & DRM_VIA_FENCE_TYPE_ACCEL) { status = VIA_READ(VIA_REG_STATUS); if ((status & VIA_VR_QUEUE_BUSY) && !(status & (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY))) @@ -93,8 +87,8 @@ static uint32_t via_perform_flush(struct drm_device *dev, uint32_t class) } if (signaled_flush_types) { - pending_flush_types &= ~signaled_flush_types; - if (!pending_flush_types && dev_priv->have_idlelock) { + waiting_types &= ~signaled_flush_types; + if (!waiting_types && dev_priv->have_idlelock) { drm_idlelock_release(&dev->lock); dev_priv->have_idlelock = 0; } @@ -105,8 +99,7 @@ static uint32_t via_perform_flush(struct drm_device *dev, uint32_t class) spin_unlock(&dev_priv->fence_lock); - return fc->pending_flush | - ((fc->pending_exe_flush) ? DRM_FENCE_TYPE_EXE : 0); + return; } @@ -114,8 +107,8 @@ static uint32_t via_perform_flush(struct drm_device *dev, uint32_t class) * Emit a fence sequence. */ -int via_fence_emit_sequence(struct drm_device * dev, uint32_t class, uint32_t flags, - uint32_t * sequence, uint32_t * native_type) +static int via_fence_emit_sequence(struct drm_device * dev, uint32_t class, uint32_t flags, + uint32_t * sequence, uint32_t * native_type) { drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; int ret = 0; @@ -149,36 +142,6 @@ int via_fence_emit_sequence(struct drm_device * dev, uint32_t class, uint32_t fl return ret; } -/** - * Manual poll (from the fence manager). - */ - -void via_poke_flush(struct drm_device * dev, uint32_t class) -{ - drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; - struct drm_fence_manager *fm = &dev->fm; - unsigned long flags; - uint32_t pending_flush; - - if (!dev_priv) - return ; - - write_lock_irqsave(&fm->lock, flags); - pending_flush = via_perform_flush(dev, class); - if (pending_flush) - pending_flush = via_perform_flush(dev, class); - write_unlock_irqrestore(&fm->lock, flags); - - /* - * Kick the timer if there are more flushes pending. - */ - - if (pending_flush && !timer_pending(&dev_priv->fence_timer)) { - dev_priv->fence_timer.expires = jiffies + 1; - add_timer(&dev_priv->fence_timer); - } -} - /** * No irq fence expirations implemented yet. * Although both the HQV engines and PCI dmablit engines signal @@ -187,45 +150,20 @@ void via_poke_flush(struct drm_device * dev, uint32_t class) * unless the caller wanting to wait for a fence object has indicated a lazy wait. */ -int via_fence_has_irq(struct drm_device * dev, uint32_t class, - uint32_t flags) +static int via_fence_has_irq(struct drm_device * dev, uint32_t class, + uint32_t flags) { return 0; } -/** - * Regularly call the flush function. This enables lazy waits, so we can - * set lazy_capable. Lazy waits don't really care when the fence expires, - * so a timer tick delay should be fine. - */ - -void via_fence_timer(unsigned long data) -{ - struct drm_device *dev = (struct drm_device *) data; - drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; - struct drm_fence_manager *fm = &dev->fm; - uint32_t pending_flush; - struct drm_fence_class_manager *fc = &dev->fm.fence_class[0]; - - if (!dev_priv) - return; - if (!fm->initialized) - goto out_unlock; - - via_poke_flush(dev, 0); - pending_flush = fc->pending_flush | - ((fc->pending_exe_flush) ? DRM_FENCE_TYPE_EXE : 0); - - /* - * disable timer if there are no more flushes pending. - */ - - if (!pending_flush && timer_pending(&dev_priv->fence_timer)) { - BUG_ON(dev_priv->have_idlelock); - del_timer(&dev_priv->fence_timer); - } - return; -out_unlock: - return; - -} +struct drm_fence_driver via_fence_driver = { + .num_classes = 1, + .wrap_diff = (1 << 30), + .flush_diff = (1 << 20), + .sequence_mask = 0xffffffffU, + .has_irq = via_fence_has_irq, + .emit = via_fence_emit_sequence, + .poll = via_fence_poll, + .needed_flush = NULL, + .wait = NULL +}; diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index 4f0b4ed0..f0225f89 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -37,16 +37,7 @@ static struct pci_device_id pciidlist[] = { xgi_PCI_IDS }; -static struct drm_fence_driver xgi_fence_driver = { - .num_classes = 1, - .wrap_diff = BEGIN_BEGIN_IDENTIFICATION_MASK, - .flush_diff = BEGIN_BEGIN_IDENTIFICATION_MASK - 1, - .sequence_mask = BEGIN_BEGIN_IDENTIFICATION_MASK, - .lazy_capable = 1, - .emit = xgi_fence_emit_sequence, - .poke_flush = xgi_poke_flush, - .has_irq = xgi_fence_has_irq -}; +extern struct drm_fence_driver xgi_fence_driver; int xgi_bootstrap(struct drm_device *, void *, struct drm_file *); diff --git a/linux-core/xgi_fence.c b/linux-core/xgi_fence.c index 9a75581a..63ed29ee 100644 --- a/linux-core/xgi_fence.c +++ b/linux-core/xgi_fence.c @@ -30,44 +30,37 @@ #include "xgi_misc.h" #include "xgi_cmdlist.h" -static uint32_t xgi_do_flush(struct drm_device * dev, uint32_t class) +static void xgi_fence_poll(struct drm_device * dev, uint32_t class, + uint32_t waiting_types) { struct xgi_info * info = dev->dev_private; - struct drm_fence_class_manager * fc = &dev->fm.fence_class[class]; - uint32_t pending_flush_types = 0; - uint32_t signaled_flush_types = 0; + uint32_t signaled_types = 0; if ((info == NULL) || (class != 0)) - return 0; + return; DRM_SPINLOCK(&info->fence_lock); - pending_flush_types = fc->pending_flush | - ((fc->pending_exe_flush) ? DRM_FENCE_TYPE_EXE : 0); - - if (pending_flush_types) { - if (pending_flush_types & DRM_FENCE_TYPE_EXE) { + if (waiting_types) { + if (waiting_types & DRM_FENCE_TYPE_EXE) { const u32 begin_id = le32_to_cpu(DRM_READ32(info->mmio_map, 0x2820)) & BEGIN_BEGIN_IDENTIFICATION_MASK; if (begin_id != info->complete_sequence) { info->complete_sequence = begin_id; - signaled_flush_types |= DRM_FENCE_TYPE_EXE; + signaled_types |= DRM_FENCE_TYPE_EXE; } } - if (signaled_flush_types) { + if (signaled_types) { drm_fence_handler(dev, 0, info->complete_sequence, - signaled_flush_types, 0); + signaled_types, 0); } } DRM_SPINUNLOCK(&info->fence_lock); - - return fc->pending_flush | - ((fc->pending_exe_flush) ? DRM_FENCE_TYPE_EXE : 0); } @@ -98,25 +91,13 @@ int xgi_fence_emit_sequence(struct drm_device * dev, uint32_t class, } -void xgi_poke_flush(struct drm_device * dev, uint32_t class) -{ - struct drm_fence_manager * fm = &dev->fm; - unsigned long flags; - - - write_lock_irqsave(&fm->lock, flags); - xgi_do_flush(dev, class); - write_unlock_irqrestore(&fm->lock, flags); -} - - void xgi_fence_handler(struct drm_device * dev) { struct drm_fence_manager * fm = &dev->fm; - + struct drm_fence_class_manager *fc = &fm->fence_class[0]; write_lock(&fm->lock); - xgi_do_flush(dev, 0); + xgi_fence_poll(dev, 0, fc->waiting_types); write_unlock(&fm->lock); } @@ -125,3 +106,17 @@ int xgi_fence_has_irq(struct drm_device *dev, uint32_t class, uint32_t flags) { return ((class == 0) && (flags == DRM_FENCE_TYPE_EXE)) ? 1 : 0; } + +struct drm_fence_driver xgi_fence_driver = { + .num_classes = 1, + .wrap_diff = BEGIN_BEGIN_IDENTIFICATION_MASK, + .flush_diff = BEGIN_BEGIN_IDENTIFICATION_MASK - 1, + .sequence_mask = BEGIN_BEGIN_IDENTIFICATION_MASK, + .has_irq = xgi_fence_has_irq, + .emit = xgi_fence_emit_sequence, + .flush = NULL, + .poll = xgi_fence_poll, + .needed_flush = NULL, + .wait = NULL +}; + diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 287e95ac..15fb8117 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -422,6 +422,9 @@ void i915_emit_breadcrumb(struct drm_device *dev) RING_LOCALS; if (++dev_priv->counter > BREADCRUMB_MASK) { +#ifdef I915_HAVE_FENCE + i915_invalidate_reported_sequence(dev); +#endif dev_priv->counter = 1; DRM_DEBUG("Breadcrumb counter wrapped around\n"); } @@ -1113,7 +1116,7 @@ static int i915_execbuffer(struct drm_device *dev, void *data, fence_arg->handle = fence->base.hash.key; fence_arg->fence_class = fence->fence_class; fence_arg->type = fence->type; - fence_arg->signaled = fence->signaled; + fence_arg->signaled = fence->signaled_types; } } drm_fence_usage_deref_unlocked(&fence); diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index c92758fa..3f6c8066 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -136,6 +136,8 @@ typedef struct drm_i915_private { uint32_t flush_flags; uint32_t flush_pending; uint32_t saved_flush_status; + uint32_t reported_sequence; + int reported_sequence_valid; #endif #ifdef I915_HAVE_BUFFER void *agp_iomap; @@ -290,15 +292,9 @@ extern void i915_mem_release(struct drm_device * dev, struct mem_block *heap); #ifdef I915_HAVE_FENCE /* i915_fence.c */ - - extern void i915_fence_handler(struct drm_device *dev); -extern int i915_fence_emit_sequence(struct drm_device *dev, uint32_t class, - uint32_t flags, - uint32_t *sequence, - uint32_t *native_type); -extern void i915_poke_flush(struct drm_device *dev, uint32_t class); -extern int i915_fence_has_irq(struct drm_device *dev, uint32_t class, uint32_t flags); +extern void i915_invalidate_reported_sequence(struct drm_device *dev); + #endif #ifdef I915_HAVE_BUFFER diff --git a/shared-core/via_drv.c b/shared-core/via_drv.c index a802e4ae..dd632c3d 100644 --- a/shared-core/via_drv.c +++ b/shared-core/via_drv.c @@ -40,17 +40,9 @@ static struct pci_device_id pciidlist[] = { #ifdef VIA_HAVE_FENCE -static struct drm_fence_driver via_fence_driver = { - .num_classes = 1, - .wrap_diff = (1 << 30), - .flush_diff = (1 << 20), - .sequence_mask = 0xffffffffU, - .lazy_capable = 1, - .emit = via_fence_emit_sequence, - .poke_flush = via_poke_flush, - .has_irq = via_fence_has_irq, -}; +extern struct drm_fence_driver via_fence_driver; #endif + #ifdef VIA_HAVE_BUFFER /** @@ -76,6 +68,8 @@ static struct drm_bo_driver via_bo_driver = { .init_mem_type = via_init_mem_type, .evict_flags = via_evict_flags, .move = NULL, + .ttm_cache_flush = NULL, + .command_stream_barrier = NULL }; #endif diff --git a/shared-core/via_drv.h b/shared-core/via_drv.h index 8dd4a727..941a2d77 100644 --- a/shared-core/via_drv.h +++ b/shared-core/via_drv.h @@ -196,17 +196,6 @@ extern void via_dmablit_handler(struct drm_device *dev, int engine, int from_irq extern void via_init_dmablit(struct drm_device *dev); #endif -#ifdef VIA_HAVE_FENCE -extern void via_fence_timer(unsigned long data); -extern void via_poke_flush(struct drm_device * dev, uint32_t class); -extern int via_fence_emit_sequence(struct drm_device * dev, uint32_t class, - uint32_t flags, - uint32_t * sequence, - uint32_t * native_type); -extern int via_fence_has_irq(struct drm_device * dev, uint32_t class, - uint32_t flags); -#endif - #ifdef VIA_HAVE_BUFFER extern struct drm_ttm_backend *via_create_ttm_backend_entry(struct drm_device *dev); extern int via_fence_types(struct drm_buffer_object *bo, uint32_t *fclass, diff --git a/shared-core/via_map.c b/shared-core/via_map.c index 11bfa551..54934367 100644 --- a/shared-core/via_map.c +++ b/shared-core/via_map.c @@ -69,9 +69,6 @@ static int via_do_init_map(struct drm_device * dev, drm_via_init_t * init) dev_priv->emit_0_sequence = 0; dev_priv->have_idlelock = 0; spin_lock_init(&dev_priv->fence_lock); - init_timer(&dev_priv->fence_timer); - dev_priv->fence_timer.function = &via_fence_timer; - dev_priv->fence_timer.data = (unsigned long) dev; #endif /* VIA_HAVE_FENCE */ dev->dev_private = (void *)dev_priv; #ifdef VIA_HAVE_BUFFER -- cgit v1.2.3 From 47ee6237fe86a8621744bbd6cecb8b5e58848b05 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 30 Jan 2008 22:14:02 +0100 Subject: i915: Avoid calling drm_fence_flush_old excessively. --- shared-core/i915_dma.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 15fb8117..a012f68e 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -494,7 +494,8 @@ static int i915_dispatch_cmdbuffer(struct drm_device * dev, i915_emit_breadcrumb(dev); #ifdef I915_HAVE_FENCE - drm_fence_flush_old(dev, 0, dev_priv->counter); + if (unlikely((dev_priv->counter & 0xFF) == 0)) + drm_fence_flush_old(dev, 0, dev_priv->counter); #endif return 0; } @@ -548,7 +549,8 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev, i915_emit_breadcrumb(dev); #ifdef I915_HAVE_FENCE - drm_fence_flush_old(dev, 0, dev_priv->counter); + if (unlikely((dev_priv->counter & 0xFF) == 0)) + drm_fence_flush_old(dev, 0, dev_priv->counter); #endif return 0; } @@ -621,7 +623,7 @@ void i915_dispatch_flip(struct drm_device * dev, int planes, int sync) i915_emit_breadcrumb(dev); #ifdef I915_HAVE_FENCE - if (!sync) + if (unlikely(!sync && ((dev_priv->counter & 0xFF) == 0))) drm_fence_flush_old(dev, 0, dev_priv->counter); #endif } -- cgit v1.2.3 From c77b0937f290568604961fa0013691349c5fcf3b Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 31 Jan 2008 14:11:12 +0100 Subject: Add an fence_class_manager::last_queued_sequence member, since a sequence number may actually turn up before the corresponding fence object has been queued on the ring. Fence drivers can use this member to determine whether a sequence number must be re-reported. --- linux-core/drm_fence.c | 7 ++++--- linux-core/drm_objects.h | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index a852c63f..247bc0a4 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -129,8 +129,8 @@ void drm_fence_handler(struct drm_device *dev, uint32_t fence_class, type |= fence->native_types; relevant_type = type & fence->type; - new_type = (fence->signaled_types | relevant_type) & - ~fence->signaled_types; + new_type = (fence->signaled_types | relevant_type) ^ + fence->signaled_types; if (new_type) { fence->signaled_types |= new_type; @@ -450,6 +450,7 @@ int drm_fence_object_emit(struct drm_fence_object *fence, uint32_t fence_flags, if (list_empty(&fc->ring)) fc->highest_waiting_sequence = sequence - 1; list_add_tail(&fence->ring, &fc->ring); + fc->latest_queued_sequence = sequence; write_unlock_irqrestore(&fm->lock, flags); return 0; } @@ -554,8 +555,8 @@ void drm_fence_manager_init(struct drm_device *dev) for (i = 0; i < fm->num_classes; ++i) { fence_class = &fm->fence_class[i]; + memset(fence_class, 0, sizeof(*fence_class)); INIT_LIST_HEAD(&fence_class->ring); - fence_class->pending_flush = 0; DRM_INIT_WAITQUEUE(&fence_class->fence_queue); } diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index c35d900f..e43e8dfd 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -164,6 +164,7 @@ struct drm_fence_class_manager { uint32_t waiting_types; wait_queue_head_t fence_queue; uint32_t highest_waiting_sequence; + uint32_t latest_queued_sequence; }; struct drm_fence_manager { -- cgit v1.2.3 From 733e07663e50087ca1e9af8e9b5def556521e3b5 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sat, 2 Feb 2008 12:46:31 +0100 Subject: nouveau: NV40 can/should now be able to run after the blob. - Moved the fix from the ddx to drm, because it seemed more appropriate. - Don't be shy, report if it works for you or not. --- shared-core/nouveau_reg.h | 1 + shared-core/nv40_fb.c | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/shared-core/nouveau_reg.h b/shared-core/nouveau_reg.h index a2506146..283977b3 100644 --- a/shared-core/nouveau_reg.h +++ b/shared-core/nouveau_reg.h @@ -138,6 +138,7 @@ #define NV40_PFB_TLIMIT(i) (0x00100604 + (i*16)) #define NV40_PFB_TSIZE(i) (0x00100608 + (i*16)) #define NV40_PFB_TSTATUS(i) (0x0010060C + (i*16)) +#define NV40_PFB_UNK_800 0x00100800 #define NV04_PGRAPH_DEBUG_0 0x00400080 #define NV04_PGRAPH_DEBUG_1 0x00400084 diff --git a/shared-core/nv40_fb.c b/shared-core/nv40_fb.c index ceae8079..ae784cb8 100644 --- a/shared-core/nv40_fb.c +++ b/shared-core/nv40_fb.c @@ -11,6 +11,13 @@ nv40_fb_init(struct drm_device *dev) int num_tiles; int i; + /* This is strictly a NV4x register (don't know about NV5x). */ + /* The blob sets these to all kinds of values, and they mess up our setup. */ + /* I got value 0x52802 instead. For some cards the blob even sets it back to 0x1. */ + /* Note: the blob doesn't read this value, so i'm pretty sure this is safe for all cards. */ + /* Any idea what this is? */ + NV_WRITE(NV40_PFB_UNK_800, 0x1); + switch (dev_priv->chipset) { case 0x40: case 0x45: -- cgit v1.2.3 From a0781e762295ce3d5f6e839d437a0de505cefa3b Mon Sep 17 00:00:00 2001 From: Stuart Bennett Date: Mon, 28 Jan 2008 22:59:26 +0000 Subject: nouveau: make nv34 work every time, not just every 2nd time And make nv30_graph_init a bit more like mmio-traces --- shared-core/nv20_graph.c | 45 ++++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/shared-core/nv20_graph.c b/shared-core/nv20_graph.c index 37a147b5..ad73ea91 100644 --- a/shared-core/nv20_graph.c +++ b/shared-core/nv20_graph.c @@ -804,7 +804,7 @@ void nv20_graph_takedown(struct drm_device *dev) int nv30_graph_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t vramsz, tmp; +// uint32_t vramsz, tmp; int ret, i; NV_WRITE(NV03_PMC_ENABLE, NV_READ(NV03_PMC_ENABLE) & @@ -834,6 +834,7 @@ int nv30_graph_init(struct drm_device *dev) NV_WRITE(NV10_PGRAPH_DEBUG_4, 0x00008000); NV_WRITE(NV04_PGRAPH_LIMIT_VIOL_PIX, 0xf04bdff6); NV_WRITE(0x400B80, 0x1003d888); + NV_WRITE(0x400B84, 0x0c000000); NV_WRITE(0x400098, 0x00000000); NV_WRITE(0x40009C, 0x0005ad00); NV_WRITE(0x400B88, 0x62ff00ff); // suspiciously like PGRAPH_DEBUG_2 @@ -843,30 +844,47 @@ int nv30_graph_init(struct drm_device *dev) NV_WRITE(0x400ba0, 0x002f8685); NV_WRITE(0x400ba4, 0x00231f3f); NV_WRITE(0x4008a4, 0x40000020); - NV_WRITE(0x400B84, 0x0c000000); - NV_WRITE(NV04_PGRAPH_DEBUG_2, 0x62ff0f7f); + + if (dev_priv->chipset == 0x34) { + NV_WRITE(NV10_PGRAPH_RDI_INDEX, 0x00EA0004); + NV_WRITE(NV10_PGRAPH_RDI_DATA , 0x00200201); + NV_WRITE(NV10_PGRAPH_RDI_INDEX, 0x00EA0008); + NV_WRITE(NV10_PGRAPH_RDI_DATA , 0x00000008); + NV_WRITE(NV10_PGRAPH_RDI_INDEX, 0x00EA0000); + NV_WRITE(NV10_PGRAPH_RDI_DATA , 0x00000032); + NV_WRITE(NV10_PGRAPH_RDI_INDEX, 0x00E00004); + NV_WRITE(NV10_PGRAPH_RDI_DATA , 0x00000002); + } + NV_WRITE(0x4000c0, 0x00000016); /* copy tile info from PFB */ - for (i=0; ichipset != 0x34) { + NV_WRITE(0x400750, 0x00EA0000); + NV_WRITE(0x400754, NV_READ(NV04_PFB_CFG0)); + NV_WRITE(0x400750, 0x00EA0004); + NV_WRITE(0x400754, NV_READ(NV04_PFB_CFG1)); + } + +#if 0 NV_WRITE(0x400820, 0); NV_WRITE(0x400824, 0); NV_WRITE(0x400864, vramsz-1); @@ -885,6 +903,7 @@ int nv30_graph_init(struct drm_device *dev) NV_WRITE(NV03_PGRAPH_ABS_UCLIP_YMIN, 0); NV_WRITE(NV03_PGRAPH_ABS_UCLIP_XMAX, 0x7fff); NV_WRITE(NV03_PGRAPH_ABS_UCLIP_YMAX, 0x7fff); +#endif return 0; } -- cgit v1.2.3 From 76748efae2f51409813eeb6b91b783c73cb2845e Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 5 Feb 2008 10:35:56 +0100 Subject: i915: Re-report breadcrumbs on poll to the fence manager, since a breadcrumb may actually turn up before a corresponding fence object has been placed on the fence ring. --- linux-core/i915_fence.c | 94 +++++++++++++++++++------------------------------ shared-core/i915_dma.c | 3 -- shared-core/i915_drv.h | 2 -- 3 files changed, 36 insertions(+), 63 deletions(-) diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c index 8a2e7f13..de64a4f2 100644 --- a/linux-core/i915_fence.c +++ b/linux-core/i915_fence.c @@ -38,10 +38,10 @@ * Initiate a sync flush if it's not already pending. */ -static void i915_initiate_rwflush(struct drm_i915_private *dev_priv, - struct drm_fence_class_manager *fc) +static inline void i915_initiate_rwflush(struct drm_i915_private *dev_priv, + struct drm_fence_class_manager *fc) { - if ((fc->pending_flush & DRM_I915_FENCE_TYPE_RW) && + if ((fc->pending_flush & DRM_I915_FENCE_TYPE_RW) && !dev_priv->flush_pending) { dev_priv->flush_sequence = (uint32_t) READ_BREADCRUMB(dev_priv); dev_priv->flush_flags = fc->pending_flush; @@ -52,6 +52,27 @@ static void i915_initiate_rwflush(struct drm_i915_private *dev_priv, } } +static inline void i915_report_rwflush(struct drm_device *dev, + struct drm_i915_private *dev_priv) +{ + if (unlikely(dev_priv->flush_pending)) { + + uint32_t flush_flags; + uint32_t i_status; + uint32_t flush_sequence; + + i_status = READ_HWSP(dev_priv, 0); + if ((i_status & (1 << 12)) != + (dev_priv->saved_flush_status & (1 << 12))) { + flush_flags = dev_priv->flush_flags; + flush_sequence = dev_priv->flush_sequence; + dev_priv->flush_pending = 0; + drm_fence_handler(dev, 0, flush_sequence, + flush_flags, 0); + } + } +} + static void i915_fence_flush(struct drm_device *dev, uint32_t fence_class) { @@ -69,15 +90,13 @@ static void i915_fence_flush(struct drm_device *dev, write_unlock_irqrestore(&fm->lock, irq_flags); } + static void i915_fence_poll(struct drm_device *dev, uint32_t fence_class, uint32_t waiting_types) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; struct drm_fence_manager *fm = &dev->fm; struct drm_fence_class_manager *fc = &fm->fence_class[0]; - uint32_t flush_flags = 0; - uint32_t flush_sequence = 0; - uint32_t i_status; uint32_t sequence; if (unlikely(!dev_priv)) @@ -87,36 +106,24 @@ static void i915_fence_poll(struct drm_device *dev, uint32_t fence_class, * First, report any executed sync flush: */ - if (dev_priv->flush_pending) { - i_status = READ_HWSP(dev_priv, 0); - if ((i_status & (1 << 12)) != - (dev_priv->saved_flush_status & (1 << 12))) { - flush_flags = dev_priv->flush_flags; - flush_sequence = dev_priv->flush_sequence; - dev_priv->flush_pending = 0; - drm_fence_handler(dev, 0, flush_sequence, flush_flags, 0); - } - } + i915_report_rwflush(dev, dev_priv); /* * Report A new breadcrumb, and adjust IRQs. */ if (waiting_types & DRM_FENCE_TYPE_EXE) { - sequence = READ_BREADCRUMB(dev_priv); - if (sequence != dev_priv->reported_sequence || - !dev_priv->reported_sequence_valid) { - drm_fence_handler(dev, 0, sequence, - DRM_FENCE_TYPE_EXE, 0); - dev_priv->reported_sequence = sequence; - dev_priv->reported_sequence_valid = 1; - } + sequence = READ_BREADCRUMB(dev_priv); + drm_fence_handler(dev, 0, sequence, + DRM_FENCE_TYPE_EXE, 0); - if (dev_priv->fence_irq_on && !(waiting_types & DRM_FENCE_TYPE_EXE)) { + if (dev_priv->fence_irq_on && + !(fc->waiting_types & DRM_FENCE_TYPE_EXE)) { i915_user_irq_off(dev_priv); dev_priv->fence_irq_on = 0; - } else if (!dev_priv->fence_irq_on && (waiting_types & DRM_FENCE_TYPE_EXE)) { + } else if (!dev_priv->fence_irq_on && + (fc->waiting_types & DRM_FENCE_TYPE_EXE)) { i915_user_irq_on(dev_priv); dev_priv->fence_irq_on = 1; } @@ -129,19 +136,11 @@ static void i915_fence_poll(struct drm_device *dev, uint32_t fence_class, i915_initiate_rwflush(dev_priv, fc); /* - * And possibly, but unlikely, they finish immediately. + * And possibly, but unlikely, they finish immediately. */ - if (dev_priv->flush_pending) { - i_status = READ_HWSP(dev_priv, 0); - if (unlikely((i_status & (1 << 12)) != - (dev_priv->saved_flush_status & (1 << 12)))) { - flush_flags = dev_priv->flush_flags; - flush_sequence = dev_priv->flush_sequence; - dev_priv->flush_pending = 0; - drm_fence_handler(dev, 0, flush_sequence, flush_flags, 0); - } - } + i915_report_rwflush(dev, dev_priv); + } static int i915_fence_emit_sequence(struct drm_device *dev, uint32_t class, @@ -258,27 +257,6 @@ static uint32_t i915_fence_needed_flush(struct drm_fence_object *fence) return flush_flags; } -/* - * In the very unlikely event that "poll" is not really called very often - * we need the following function to handle sequence wraparounds. - */ - -void i915_invalidate_reported_sequence(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = (struct drm_i915_private *) - dev->dev_private; - struct drm_fence_manager *fm = &dev->fm; - unsigned long irq_flags; - - if (unlikely(!dev_priv)) - return; - - write_lock_irqsave(&fm->lock, irq_flags); - dev_priv->reported_sequence_valid = 0; - write_unlock_irqrestore(&fm->lock, irq_flags); -} - - struct drm_fence_driver i915_fence_driver = { .num_classes = 1, .wrap_diff = (1U << (BREADCRUMB_BITS - 1)), diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index a012f68e..608723f4 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -422,9 +422,6 @@ void i915_emit_breadcrumb(struct drm_device *dev) RING_LOCALS; if (++dev_priv->counter > BREADCRUMB_MASK) { -#ifdef I915_HAVE_FENCE - i915_invalidate_reported_sequence(dev); -#endif dev_priv->counter = 1; DRM_DEBUG("Breadcrumb counter wrapped around\n"); } diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 3f6c8066..87594670 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -136,8 +136,6 @@ typedef struct drm_i915_private { uint32_t flush_flags; uint32_t flush_pending; uint32_t saved_flush_status; - uint32_t reported_sequence; - int reported_sequence_valid; #endif #ifdef I915_HAVE_BUFFER void *agp_iomap; -- cgit v1.2.3 From 79d69285202b55f269aa88a6bcda257257c9dee3 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 7 Feb 2008 10:40:06 -0800 Subject: Fix vblank enable/disable callbacks There were two problems with the existing callback code: the vblank enable callback happened multiple times per disable, making drivers more complex than they had to be, and there was a race between the final decrement of the vblank usage counter and the next enable call, which could have resulted in a put->schedule disable->get->enable->disable sequence, which would be bad. So add a new vblank_enabled array to track vblank enable on per-pipe basis, and add a lock to protect it along with the refcount + enable/disable calls to fix the race. --- linux-core/drmP.h | 2 ++ linux-core/drm_irq.c | 29 ++++++++++++++++++++++++----- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 4e8b087b..33f3649e 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -836,6 +836,8 @@ struct drm_device { u32 *last_vblank; /* protected by dev->vbl_lock, used */ /* for wraparound handling */ u32 *vblank_offset; /* used to track how many vblanks */ + int *vblank_enabled; /* so we don't call enable more than + once per disable */ u32 *vblank_premodeset; /* were lost during modeset */ struct timer_list vblank_disable_timer; diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index 367d2dd8..e4940bb7 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -74,11 +74,18 @@ int drm_irq_by_busid(struct drm_device *dev, void *data, static void vblank_disable_fn(unsigned long arg) { struct drm_device *dev = (struct drm_device *)arg; + unsigned long irqflags; int i; - for (i = 0; i < dev->num_crtcs; i++) - if (atomic_read(&dev->vblank_refcount[i]) == 0) + for (i = 0; i < dev->num_crtcs; i++) { + spin_lock_irqsave(&dev->vbl_lock, irqflags); + if (atomic_read(&dev->vblank_refcount[i]) == 0 && + dev->vblank_enabled[i]) { dev->driver->disable_vblank(dev, i); + dev->vblank_enabled[i] = 0; + } + spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + } } int drm_vblank_init(struct drm_device *dev, int num_crtcs) @@ -111,6 +118,11 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) if (!dev->vblank_refcount) goto err; + dev->vblank_enabled = drm_calloc(num_crtcs, sizeof(int), + DRM_MEM_DRIVER); + if (!dev->vblank_enabled) + goto err; + dev->last_vblank = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); if (!dev->last_vblank) goto err; @@ -143,6 +155,8 @@ err: DRM_MEM_DRIVER); drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) * num_crtcs, DRM_MEM_DRIVER); + drm_free(dev->vblank_enabled, sizeof(*dev->vblank_enabled) * num_crtcs, + DRM_MEM_DRIVER); drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * num_crtcs, DRM_MEM_DRIVER); drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) * @@ -357,14 +371,20 @@ EXPORT_SYMBOL(drm_update_vblank_count); */ int drm_vblank_get(struct drm_device *dev, int crtc) { + unsigned long irqflags; int ret = 0; + spin_lock_irqsave(&dev->vbl_lock, irqflags); /* Going from 0->1 means we have to enable interrupts again */ - if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) { + if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1 && + !dev->vblank_enabled[crtc]) { ret = dev->driver->enable_vblank(dev, crtc); if (ret) atomic_dec(&dev->vblank_refcount[crtc]); + else + dev->vblank_enabled[crtc] = 1; } + spin_unlock_irqrestore(&dev->vbl_lock, irqflags); return ret; } @@ -382,8 +402,7 @@ void drm_vblank_put(struct drm_device *dev, int crtc) { /* Last user schedules interrupt disable */ if (atomic_dec_and_test(&dev->vblank_refcount[crtc])) - mod_timer(&dev->vblank_disable_timer, - round_jiffies_relative(DRM_HZ)); + mod_timer(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ); } EXPORT_SYMBOL(drm_vblank_put); -- cgit v1.2.3 From 8b6c96dedd4ba5dfbfec6a7c831d566e31d28781 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 7 Feb 2008 10:48:08 -0800 Subject: i915: save/restore interrupt state On resume, if the interrupt state isn't restored correctly, we may end up with a flood of unexpected or ill-timed interrupts, which could cause the kernel to disable the interrupt or vblank events to happen at the wrong time. So save/restore them properly. --- linux-core/i915_drv.c | 7 +++++++ shared-core/i915_drv.h | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index ccc061d3..c771ab3e 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -303,6 +303,7 @@ static int i915_suspend(struct drm_device *dev) dev_priv->saveDSPATILEOFF = I915_READ(DSPATILEOFF); } i915_save_palette(dev, PIPE_A); + dev_priv->savePIPEASTAT = I915_READ(I915REG_PIPEASTAT); /* Pipe & plane B info */ dev_priv->savePIPEBCONF = I915_READ(PIPEBCONF); @@ -330,6 +331,7 @@ static int i915_suspend(struct drm_device *dev) dev_priv->saveDSPBTILEOFF = I915_READ(DSPBTILEOFF); } i915_save_palette(dev, PIPE_B); + dev_priv->savePIPEBSTAT = I915_READ(I915REG_PIPEBSTAT); /* CRT state */ dev_priv->saveADPA = I915_READ(ADPA); @@ -356,6 +358,11 @@ static int i915_suspend(struct drm_device *dev) dev_priv->saveFBC_CONTROL2 = I915_READ(FBC_CONTROL2); dev_priv->saveFBC_CONTROL = I915_READ(FBC_CONTROL); + /* Interrupt state */ + dev_priv->saveIIR = I915_READ(I915REG_INT_IDENTITY_R); + dev_priv->saveIER = I915_READ(I915REG_INT_ENABLE_R); + dev_priv->saveIMR = I915_READ(I915REG_INT_MASK_R); + /* VGA state */ dev_priv->saveVCLK_DIVISOR_VGA0 = I915_READ(VCLK_DIVISOR_VGA0); dev_priv->saveVCLK_DIVISOR_VGA1 = I915_READ(VCLK_DIVISOR_VGA1); diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 87594670..d2faee29 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -166,6 +166,7 @@ typedef struct drm_i915_private { u32 saveVBLANK_A; u32 saveVSYNC_A; u32 saveBCLRPAT_A; + u32 savePIPEASTAT; u32 saveDSPASTRIDE; u32 saveDSPASIZE; u32 saveDSPAPOS; @@ -186,6 +187,7 @@ typedef struct drm_i915_private { u32 saveVBLANK_B; u32 saveVSYNC_B; u32 saveBCLRPAT_B; + u32 savePIPEBSTAT; u32 saveDSPBSTRIDE; u32 saveDSPBSIZE; u32 saveDSPBPOS; @@ -214,6 +216,9 @@ typedef struct drm_i915_private { u32 saveFBC_LL_BASE; u32 saveFBC_CONTROL; u32 saveFBC_CONTROL2; + u32 saveIER; + u32 saveIIR; + u32 saveIMR; u32 saveSWF0[16]; u32 saveSWF1[16]; u32 saveSWF2[3]; -- cgit v1.2.3 From 6f19473191ae543fcc199d252c5865c0734d38ad Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 7 Feb 2008 11:21:09 -0800 Subject: Fix saveGR array size Make sure we have enough room for all the GR registers or we'll end up clobbering the AR index register (which should actually be harmless unless the BIOS is making an assumption about it). --- shared-core/i915_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index d2faee29..d08fdf40 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -224,7 +224,7 @@ typedef struct drm_i915_private { u32 saveSWF2[3]; u8 saveMSR; u8 saveSR[8]; - u8 saveGR[24]; + u8 saveGR[25]; u8 saveAR_INDEX; u8 saveAR[20]; u8 saveDACMASK; -- cgit v1.2.3 From d63b57749f097b36df04c6beff9b35a1dd859523 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 7 Feb 2008 17:33:28 -0800 Subject: Restore pipeconf regs unconditionally On many chipsets, the checks for DPLL enable or VGA mode will prevent the pipeconf regs from being restored, which could result in a blank display or X failing to come back after resume. So restore them unconditionally along with actually restoring pipe B's palette correctly. --- linux-core/i915_drv.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index c771ab3e..3e2bfc94 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -434,9 +434,7 @@ static int i915_resume(struct drm_device *dev) I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF); } - if ((dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) && - (dev_priv->saveDPLL_A & DPLL_VGA_MODE_DIS)) - I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF); + I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF); i915_restore_palette(dev, PIPE_A); /* Enable the plane */ @@ -478,10 +476,9 @@ static int i915_resume(struct drm_device *dev) I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF); } - if ((dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) && - (dev_priv->saveDPLL_B & DPLL_VGA_MODE_DIS)) - I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF); - i915_restore_palette(dev, PIPE_A); + I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF); + + i915_restore_palette(dev, PIPE_B); /* Enable the plane */ I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR); I915_WRITE(DSPBBASE, I915_READ(DSPBBASE)); -- cgit v1.2.3 From 4feb0638f1a8eb8527647ff47312ee61e3f683f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 5 Feb 2008 12:25:22 -0500 Subject: i915: Make sarea_priv setup optional. --- shared-core/i915_dma.c | 20 +++++++++++++++----- shared-core/i915_irq.c | 10 +++++++--- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 608723f4..9619525d 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -128,8 +128,14 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) dev_priv->max_validate_buffers = I915_MAX_VALIDATE_BUFFERS; #endif - dev_priv->sarea_priv = (drm_i915_sarea_t *) - ((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset); + if (init->sarea_priv_offset) + dev_priv->sarea_priv = (drm_i915_sarea_t *) + ((u8 *) dev_priv->sarea->handle + + init->sarea_priv_offset); + else { + /* No sarea_priv for you! */ + dev_priv->sarea_priv = NULL; + } dev_priv->ring.Start = init->ring_start; dev_priv->ring.End = init->ring_end; @@ -154,7 +160,9 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) dev_priv->ring.virtual_start = dev_priv->ring.map.handle; dev_priv->cpp = init->cpp; - dev_priv->sarea_priv->pf_current_page = 0; + + if (dev_priv->sarea_priv) + dev_priv->sarea_priv->pf_current_page = 0; /* We are using separate values as placeholders for mechanisms for * private backbuffer/depthbuffer usage. @@ -426,7 +434,8 @@ void i915_emit_breadcrumb(struct drm_device *dev) DRM_DEBUG("Breadcrumb counter wrapped around\n"); } - dev_priv->sarea_priv->last_enqueue = dev_priv->counter; + if (dev_priv->sarea_priv) + dev_priv->sarea_priv->last_enqueue = dev_priv->counter; BEGIN_LP_RING(4); OUT_RING(CMD_STORE_DWORD_IDX); @@ -1101,7 +1110,8 @@ static int i915_execbuffer(struct drm_device *dev, void *data, if (ret) goto out_err0; - sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); + if (sarea_priv) + sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); /* fence */ ret = drm_fence_buffer_objects(dev, NULL, fence_arg->flags, diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index d463f6e6..fd08b6e8 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -450,7 +450,9 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) temp &= (dev_priv->irq_enable_reg | USER_INT_FLAG | VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG); - dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); + if (dev_priv->sarea_priv) + dev_priv->sarea_priv->last_dispatch = + READ_BREADCRUMB(dev_priv); if (temp & USER_INT_FLAG) { DRM_WAKEUP(&dev_priv->irq_queue); @@ -529,7 +531,9 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); } - dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); + if (dev_priv->sarea_priv) + dev_priv->sarea_priv->last_dispatch = + READ_BREADCRUMB(dev_priv); return ret; } @@ -693,7 +697,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data, return -EINVAL; } - if (dev_priv->sarea_priv->rotation) { + if (!dev_priv->sarea_priv || dev_priv->sarea_priv->rotation) { DRM_DEBUG("Rotation not supported\n"); return -EINVAL; } -- cgit v1.2.3 From ee15459483d50b2efe630051b45f36cfbb351683 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 5 Feb 2008 12:27:48 -0500 Subject: i915: Add I915_PARAM_CHIPSET_ID param to get chipset ID. --- shared-core/i915_dma.c | 3 +++ shared-core/i915_drm.h | 1 + 2 files changed, 4 insertions(+) diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 9619525d..0682a334 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -1210,6 +1210,9 @@ static int i915_getparam(struct drm_device *dev, void *data, case I915_PARAM_LAST_DISPATCH: value = READ_BREADCRUMB(dev_priv); break; + case I915_PARAM_CHIPSET_ID: + value = dev->pci_device; + break; default: DRM_ERROR("Unknown parameter %d\n", param->param); return -EINVAL; diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index c8a9cb76..ad0797c2 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -232,6 +232,7 @@ typedef struct drm_i915_irq_wait { #define I915_PARAM_IRQ_ACTIVE 1 #define I915_PARAM_ALLOW_BATCHBUFFER 2 #define I915_PARAM_LAST_DISPATCH 3 +#define I915_PARAM_CHIPSET_ID 4 typedef struct drm_i915_getparam { int param; -- cgit v1.2.3 From db3f03ae3538bea3d29ef66ac24d9a1f54cff418 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 12 Feb 2008 16:08:18 -0500 Subject: i915: Only look up dev_priv->mmio_map if it's not already set up --- shared-core/i915_dma.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 0682a334..fc009204 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -117,7 +117,8 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) return -EINVAL; } - dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset); + if (init->mmio_offset != 0) + dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset); if (!dev_priv->mmio_map) { i915_dma_cleanup(dev); DRM_ERROR("can not find mmio map!\n"); -- cgit v1.2.3 From 373dbcf8b25750967e9ba24433cff872df41cb74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 5 Feb 2008 13:27:16 -0500 Subject: i915: Add a dri2 init path that gets the lock from the dri2 sarea. --- shared-core/i915_dma.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++-- shared-core/i915_drm.h | 8 ++++- shared-core/i915_drv.h | 4 +++ 3 files changed, 103 insertions(+), 3 deletions(-) diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index fc009204..3874ed58 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -106,9 +106,73 @@ static int i915_dma_cleanup(struct drm_device * dev) return 0; } -static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) + +#define DRI2_SAREA_BLOCK_TYPE(b) ((b) >> 16) +#define DRI2_SAREA_BLOCK_SIZE(b) ((b) & 0xffff) +#define DRI2_SAREA_BLOCK_NEXT(p) \ + ((void *) ((unsigned char *) (p) + \ + DRI2_SAREA_BLOCK_SIZE(*(unsigned int *) p))) + +#define DRI2_SAREA_BLOCK_END 0x0000 +#define DRI2_SAREA_BLOCK_LOCK 0x0001 +#define DRI2_SAREA_BLOCK_EVENT_BUFFER 0x0002 + +static int +setup_dri2_sarea(struct drm_device * dev, + struct drm_file *file_priv, + drm_i915_init_t * init) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int ret; + unsigned int *p, *end, *next; + + mutex_lock(&dev->struct_mutex); + dev_priv->sarea_bo = + drm_lookup_buffer_object(file_priv, + init->sarea_handle, 1); + mutex_unlock(&dev->struct_mutex); + + if (!dev_priv->sarea_bo) { + DRM_ERROR("did not find sarea bo\n"); + return -EINVAL; + } + + ret = drm_bo_kmap(dev_priv->sarea_bo, 0, + dev_priv->sarea_bo->num_pages, + &dev_priv->sarea_kmap); + if (ret) { + DRM_ERROR("could not map sarea bo\n"); + return ret; + } + + p = dev_priv->sarea_kmap.virtual; + end = (void *) p + (dev_priv->sarea_bo->num_pages << PAGE_SHIFT); + while (p < end && DRI2_SAREA_BLOCK_TYPE(*p) != DRI2_SAREA_BLOCK_END) { + switch (DRI2_SAREA_BLOCK_TYPE(*p)) { + case DRI2_SAREA_BLOCK_LOCK: + dev->lock.hw_lock = (void *) (p + 1); + dev->sigdata.lock = dev->lock.hw_lock; + break; + } + next = DRI2_SAREA_BLOCK_NEXT(p); + if (next <= p || end < next) { + DRM_ERROR("malformed dri2 sarea: next is %p should be within %p-%p\n", + next, p, end); + return -EINVAL; + } + p = next; + } + + return 0; +} + + +static int i915_initialize(struct drm_device * dev, + struct drm_file *file_priv, + drm_i915_init_t * init) { drm_i915_private_t *dev_priv = dev->dev_private; + int ret; dev_priv->sarea = drm_getsarea(dev); if (!dev_priv->sarea) { @@ -201,6 +265,17 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) #ifdef I915_HAVE_BUFFER mutex_init(&dev_priv->cmdbuf_mutex); #endif + + if (init->func == I915_INIT_DMA2) { + ret = setup_dri2_sarea(dev, file_priv, init); + if (ret) { + i915_dma_cleanup(dev); + DRM_ERROR("could not set up dri2 sarea\n"); + return ret; + } + } + + return 0; } @@ -250,7 +325,8 @@ static int i915_dma_init(struct drm_device *dev, void *data, switch (init->func) { case I915_INIT_DMA: - retcode = i915_initialize(dev, init); + case I915_INIT_DMA2: + retcode = i915_initialize(dev, file_priv, init); break; case I915_CLEANUP_DMA: retcode = i915_dma_cleanup(dev); @@ -1415,6 +1491,20 @@ void i915_driver_lastclose(struct drm_device * dev) if (dev_priv->agp_heap) i915_mem_takedown(&(dev_priv->agp_heap)); + if (dev_priv->sarea_kmap.virtual) { + drm_bo_kunmap(&dev_priv->sarea_kmap); + dev_priv->sarea_kmap.virtual = NULL; + dev->lock.hw_lock = NULL; + dev->sigdata.lock = NULL; + } + + if (dev_priv->sarea_bo) { + mutex_lock(&dev->struct_mutex); + drm_bo_usage_deref_locked(&dev_priv->sarea_bo); + mutex_unlock(&dev->struct_mutex); + dev_priv->sarea_bo = NULL; + } + i915_dma_cleanup(dev); } diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index ad0797c2..b889a303 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -43,7 +43,12 @@ typedef struct _drm_i915_init { enum { I915_INIT_DMA = 0x01, I915_CLEANUP_DMA = 0x02, - I915_RESUME_DMA = 0x03 + I915_RESUME_DMA = 0x03, + + /* Since this struct isn't versioned, just used a new + * 'func' code to indicate the presence of dri2 sarea + * info. */ + I915_INIT_DMA2 = 0x04 } func; unsigned int mmio_offset; int sarea_priv_offset; @@ -61,6 +66,7 @@ typedef struct _drm_i915_init { unsigned int depth_pitch; unsigned int cpp; unsigned int chipset; + unsigned int sarea_handle; } drm_i915_init_t; typedef struct _drm_i915_sarea { diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index d08fdf40..76116df5 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -147,6 +147,10 @@ typedef struct drm_i915_private { drm_i915_vbl_swap_t vbl_swaps; unsigned int swaps_pending; + /* DRI2 sarea */ + struct drm_buffer_object *sarea_bo; + struct drm_bo_kmap_obj sarea_kmap; + /* Register state */ u8 saveLBB; u32 saveDSPACNTR; -- cgit v1.2.3 From 15cbde683f5006b541b22c41ff840aefb017ff8e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 16 Feb 2008 04:33:27 +1100 Subject: nv40: actually init all tile regs. --- shared-core/nouveau_reg.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/shared-core/nouveau_reg.h b/shared-core/nouveau_reg.h index 283977b3..2f7d77cf 100644 --- a/shared-core/nouveau_reg.h +++ b/shared-core/nouveau_reg.h @@ -335,19 +335,19 @@ #define NV04_PGRAPH_BLEND 0x00400824 #define NV04_PGRAPH_STORED_FMT 0x00400830 #define NV04_PGRAPH_PATT_COLORRAM 0x00400900 -#define NV40_PGRAPH_TILE0(i) 0x00400900 -#define NV40_PGRAPH_TLIMIT0(i) 0x00400904 -#define NV40_PGRAPH_TSIZE0(i) 0x00400908 -#define NV40_PGRAPH_TSTATUS0(i) 0x0040090C +#define NV40_PGRAPH_TILE0(i) (0x00400900 + (i*16)) +#define NV40_PGRAPH_TLIMIT0(i) (0x00400904 + (i*16)) +#define NV40_PGRAPH_TSIZE0(i) (0x00400908 + (i*16)) +#define NV40_PGRAPH_TSTATUS0(i) (0x0040090C + (i*16)) #define NV10_PGRAPH_TILE(i) (0x00400B00 + (i*16)) #define NV10_PGRAPH_TLIMIT(i) (0x00400B04 + (i*16)) #define NV10_PGRAPH_TSIZE(i) (0x00400B08 + (i*16)) #define NV10_PGRAPH_TSTATUS(i) (0x00400B0C + (i*16)) #define NV04_PGRAPH_U_RAM 0x00400D00 -#define NV47_PGRAPH_TILE0(i) 0x00400D00 -#define NV47_PGRAPH_TLIMIT0(i) 0x00400D04 -#define NV47_PGRAPH_TSIZE0(i) 0x00400D08 -#define NV47_PGRAPH_TSTATUS0(i) 0x00400D0C +#define NV47_PGRAPH_TILE0(i) (0x00400D00 + (i*16)) +#define NV47_PGRAPH_TLIMIT0(i) (0x00400D04 + (i*16)) +#define NV47_PGRAPH_TSIZE0(i) (0x00400D08 + (i*16)) +#define NV47_PGRAPH_TSTATUS0(i) (0x00400D0C + (i*16)) #define NV04_PGRAPH_V_RAM 0x00400D40 #define NV04_PGRAPH_W_RAM 0x00400D80 #define NV10_PGRAPH_COMBINER0_IN_ALPHA 0x00400E40 @@ -395,10 +395,10 @@ #define NV04_PGRAPH_DMA_B_OFFSET 0x00401098 #define NV04_PGRAPH_DMA_B_SIZE 0x0040109C #define NV04_PGRAPH_DMA_B_Y_SIZE 0x004010A0 -#define NV40_PGRAPH_TILE1(i) 0x00406900 -#define NV40_PGRAPH_TLIMIT1(i) 0x00406904 -#define NV40_PGRAPH_TSIZE1(i) 0x00406908 -#define NV40_PGRAPH_TSTATUS1(i) 0x0040690C +#define NV40_PGRAPH_TILE1(i) (0x00406900 + (i*16)) +#define NV40_PGRAPH_TLIMIT1(i) (0x00406904 + (i*16)) +#define NV40_PGRAPH_TSIZE1(i) (0x00406908 + (i*16)) +#define NV40_PGRAPH_TSTATUS1(i) (0x0040690C + (i*16)) /* It's a guess that this works on NV03. Confirmed on NV04, though */ -- cgit v1.2.3 From cd87e6352bf529ae0bc57e8434ddfccec3660d9a Mon Sep 17 00:00:00 2001 From: Stephane Marchesin Date: Sat, 16 Feb 2008 03:50:10 +0100 Subject: nouveau: no GART on ia64 either. --- 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 f4e641b9..3d376aed 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -393,7 +393,7 @@ nouveau_mem_init_ttm(struct drm_device *dev) } /* GART */ -#ifndef __powerpc__ +#if !defined(__powerpc__) && !defined(__ia64__) if (drm_device_is_agp(dev) && dev->agp) { if ((ret = nouveau_mem_init_agp(dev, 1))) DRM_ERROR("Error initialising AGP: %d\n", ret); @@ -462,7 +462,7 @@ int nouveau_mem_init(struct drm_device *dev) dev_priv->fb_nomap_heap=NULL; } -#ifndef __powerpc__ +#if !defined(__powerpc__) && !defined(__ia64__) /* Init AGP / NV50 PCIEGART */ if (drm_device_is_agp(dev) && dev->agp) { if ((ret = nouveau_mem_init_agp(dev, 0))) -- cgit v1.2.3 From 5d8c754bc2c720d70bbdeca6b294660105717a62 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 16 Feb 2008 19:19:29 -0800 Subject: [915]: more registers for S3 (DSPCLK_GATE_D, CACHE_MODE_0, MI_ARB_STATE) Failing to preserve the MI_ARB_STATE register was causing FIFO underruns on the VGA output on my HP 2510p after resume. --- linux-core/i915_drv.c | 18 ++++++++++++++++++ shared-core/i915_drv.h | 10 ++++++++++ 2 files changed, 28 insertions(+) diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 3e2bfc94..9d8b4685 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -369,6 +369,15 @@ static int i915_suspend(struct drm_device *dev) dev_priv->saveVCLK_POST_DIV = I915_READ(VCLK_POST_DIV); dev_priv->saveVGACNTRL = I915_READ(VGACNTRL); + /* Clock gating state */ + dev_priv->saveDSPCLK_GATE_D = I915_READ(DSPCLK_GATE_D); + + /* Cache mode state */ + dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0); + + /* Memory Arbitration state */ + dev_priv->saveMI_ARB_STATE = I915_READ(MI_ARB_STATE); + /* Scratch space */ for (i = 0; i < 16; i++) { dev_priv->saveSWF0[i] = I915_READ(SWF0 + (i << 2)); @@ -516,6 +525,15 @@ static int i915_resume(struct drm_device *dev) I915_WRITE(VCLK_POST_DIV, dev_priv->saveVCLK_POST_DIV); udelay(150); + /* Clock gating state */ + I915_WRITE (DSPCLK_GATE_D, dev_priv->saveDSPCLK_GATE_D); + + /* Cache mode state */ + I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000); + + /* Memory arbitration state */ + I915_WRITE (MI_ARB_STATE, dev_priv->saveMI_ARB_STATE | 0xffff0000); + for (i = 0; i < 16; i++) { I915_WRITE(SWF0 + (i << 2), dev_priv->saveSWF0[i]); I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i+7]); diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 76116df5..4d3ac0a5 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -223,6 +223,9 @@ typedef struct drm_i915_private { u32 saveIER; u32 saveIIR; u32 saveIMR; + u32 saveCACHE_MODE_0; + u32 saveDSPCLK_GATE_D; + u32 saveMI_ARB_STATE; u32 saveSWF0[16]; u32 saveSWF1[16]; u32 saveSWF2[3]; @@ -576,6 +579,10 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); */ #define DMA_FADD_S 0x20d4 +/* Memory Interface Arbitration State + */ +#define MI_ARB_STATE 0x20e4 + /* Cache mode 0 reg. * - Manipulating render cache behaviour is central * to the concept of zone rendering, tuning this reg can help avoid @@ -586,6 +593,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); * bit of interest either set or cleared. EG: (BIT<<16) | BIT to set. */ #define Cache_Mode_0 0x2120 +#define CACHE_MODE_0 0x2120 #define CM0_MASK_SHIFT 16 #define CM0_IZ_OPT_DISABLE (1<<6) #define CM0_ZR_OPT_DISABLE (1<<5) @@ -775,6 +783,8 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); /** P1 value is 2 greater than this field */ # define VGA0_PD_P1_MASK (0x1f << 0) +#define DSPCLK_GATE_D 0x6200 + /* I830 CRTC registers */ #define HTOTAL_A 0x60000 #define HBLANK_A 0x60004 -- cgit v1.2.3