Index: dev/drm/i915_dma.c =================================================================== --- dev/drm/i915_dma.c (revision 189900) +++ dev/drm/i915_dma.c (working copy) @@ -193,7 +193,7 @@ dev_priv->ring.map.flags = 0; dev_priv->ring.map.mtrr = 0; - drm_core_ioremap(&dev_priv->ring.map, dev); + drm_core_ioremap_wc(&dev_priv->ring.map, dev); if (dev_priv->ring.map.handle == NULL) { i915_dma_cleanup(dev); @@ -209,7 +209,7 @@ dev_priv->back_offset = init->back_offset; dev_priv->front_offset = init->front_offset; dev_priv->current_page = 0; - dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; + dev_priv->sarea_priv->pf_current_page = 0; /* Allow hardware batchbuffers unless told otherwise. */ @@ -721,7 +721,7 @@ DRM_DEBUG("%s\n", __func__); - LOCK_TEST_WITH_RETURN(dev, file_priv); + RING_LOCK_TEST_WITH_RETURN(dev, file_priv); ret = i915_dispatch_flip(dev); @@ -758,7 +758,7 @@ value = 0; break; default: - DRM_ERROR("Unknown parameter %d\n", param->param); + DRM_DEBUG("Unknown parameter %d\n", param->param); return -EINVAL; } @@ -791,7 +791,7 @@ dev_priv->allow_batchbuffer = param->value; break; default: - DRM_ERROR("unknown parameter %d\n", param->param); + DRM_DEBUG("unknown parameter %d\n", param->param); return -EINVAL; } @@ -822,7 +822,7 @@ dev_priv->hws_map.flags = 0; dev_priv->hws_map.mtrr = 0; - drm_core_ioremap(&dev_priv->hws_map, dev); + drm_core_ioremap_wc(&dev_priv->hws_map, dev); if (dev_priv->hws_map.handle == NULL) { i915_dma_cleanup(dev); dev_priv->status_gfx_addr = 0; @@ -880,8 +880,12 @@ /* Init HWS */ if (!I915_NEED_GFX_HWS(dev)) { ret = i915_init_phys_hws(dev); - if (ret != 0) + if (ret != 0) { + drm_rmmap(dev, dev_priv->mmio_map); + drm_free(dev_priv, sizeof(struct drm_i915_private), + DRM_MEM_DRIVER); return ret; + } } #ifdef __linux__ /* On the 945G/GM, the chipset reports the MSI capability on the @@ -901,6 +905,7 @@ intel_opregion_init(dev); #endif DRM_SPININIT(&dev_priv->user_irq_lock, "userirq"); + dev_priv->user_irq_refcount = 0; ret = drm_vblank_init(dev, I915_NUM_PIPE); Index: dev/drm/i915_drv.h =================================================================== --- dev/drm/i915_drv.h (revision 189900) +++ dev/drm/i915_drv.h (working copy) @@ -151,6 +151,8 @@ u32 saveDSPACNTR; u32 saveDSPBCNTR; u32 saveDSPARB; + u32 saveRENDERSTANDBY; + u32 saveHWS; u32 savePIPEACONF; u32 savePIPEBCONF; u32 savePIPEASRC; @@ -232,8 +234,8 @@ u8 saveAR_INDEX; u8 saveAR[21]; u8 saveDACMASK; - u8 saveDACDATA[256*3]; /* 256 3-byte colors */ u8 saveCR[37]; + struct { #ifdef __linux__ struct drm_mm gtt_space; @@ -651,7 +653,8 @@ #define IS_G4X(dev) ((dev)->pci_device == 0x2E02 || \ (dev)->pci_device == 0x2E12 || \ - (dev)->pci_device == 0x2E22) + (dev)->pci_device == 0x2E22 || \ + IS_GM45(dev)) #define IS_G33(dev) ((dev)->pci_device == 0x29C2 || \ (dev)->pci_device == 0x29B2 || \ Index: dev/drm/i915_irq.c =================================================================== --- dev/drm/i915_irq.c (revision 189900) +++ dev/drm/i915_irq.c (working copy) @@ -43,21 +43,28 @@ * we leave them always unmasked in IMR and then control enabling them through * PIPESTAT alone. */ -#define I915_INTERRUPT_ENABLE_FIX (I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \ - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) +#define I915_INTERRUPT_ENABLE_FIX (I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \ + I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) /** Interrupts that we mask and unmask at runtime. */ -#define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT) +#define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT) /** These are all of the interrupts used by the driver */ -#define I915_INTERRUPT_ENABLE_MASK (I915_INTERRUPT_ENABLE_FIX | \ - I915_INTERRUPT_ENABLE_VAR) +#define I915_INTERRUPT_ENABLE_MASK (I915_INTERRUPT_ENABLE_FIX | \ + I915_INTERRUPT_ENABLE_VAR) +#define I915_PIPE_VBLANK_STATUS (PIPE_START_VBLANK_INTERRUPT_STATUS |\ + PIPE_VBLANK_INTERRUPT_STATUS) + +#define I915_PIPE_VBLANK_ENABLE (PIPE_START_VBLANK_INTERRUPT_ENABLE |\ + PIPE_VBLANK_INTERRUPT_ENABLE) + +#define DRM_I915_VBLANK_PIPE_ALL (DRM_I915_VBLANK_PIPE_A | \ + DRM_I915_VBLANK_PIPE_B) + static inline void i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask) { - DRM_DEBUG("irq_enable_reg = 0x%08x, mask = 0x%08x\n", - dev_priv->irq_mask_reg, mask); mask &= I915_INTERRUPT_ENABLE_VAR; if ((dev_priv->irq_mask_reg & mask) != 0) { dev_priv->irq_mask_reg &= ~mask; @@ -189,59 +196,84 @@ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u32 iir, new_iir; u32 pipea_stats, pipeb_stats; + u32 vblank_status; + u32 vblank_enable; + int irq_received; atomic_inc(&dev_priv->irq_received); - for (iir = I915_READ(IIR) ; iir != 0 ; iir = new_iir) { + iir = I915_READ(IIR); - pipea_stats = pipeb_stats = 0; + if (IS_I965G(dev)) { + vblank_status = I915_START_VBLANK_INTERRUPT_STATUS; + vblank_enable = PIPE_START_VBLANK_INTERRUPT_ENABLE; + } else { + vblank_status = I915_VBLANK_INTERRUPT_STATUS; + vblank_enable = I915_VBLANK_INTERRUPT_ENABLE; + } + for (;;) { + irq_received = iir != 0; + + /* Can't rely on pipestat interrupt bit in iir as it might + * have been cleared after the pipestat interrupt was received. + * It doesn't set the bit in iir again, but it still produces + * interrupts (for non-MSI). + */ + DRM_SPINLOCK(&dev_priv->user_irq_lock); + pipea_stats = I915_READ(PIPEASTAT); + pipeb_stats = I915_READ(PIPEBSTAT); + /* * Clear the PIPE(A|B)STAT regs before the IIR */ - if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) { - DRM_SPINLOCK(&dev_priv->user_irq_lock); - pipea_stats = I915_READ(PIPEASTAT); + if (pipea_stats & 0x8000ffff) { I915_WRITE(PIPEASTAT, pipea_stats); - DRM_SPINUNLOCK(&dev_priv->user_irq_lock); + irq_received = 1; } - if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) { - DRM_SPINLOCK(&dev_priv->user_irq_lock); - pipeb_stats = I915_READ(PIPEBSTAT); + if (pipeb_stats & 0x8000ffff) { I915_WRITE(PIPEBSTAT, pipeb_stats); - DRM_SPINUNLOCK(&dev_priv->user_irq_lock); + irq_received = 1; } + DRM_SPINUNLOCK(&dev_priv->user_irq_lock); + if (!irq_received) + break; + I915_WRITE(IIR, iir); - new_iir = I915_READ(IIR); + new_iir = I915_READ(IIR); /* Flush posted writes */ - DRM_DEBUG("iir = 0x%08x, pipestats a = 0x%08x, b = 0x%08x\n", - iir, pipea_stats, pipeb_stats); - if (dev_priv->sarea_priv) dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); if (iir & I915_USER_INTERRUPT) { -#ifdef I915_HAVE_GEM - dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev); -#endif DRM_WAKEUP(&dev_priv->irq_queue); } - if (pipea_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS | - PIPE_VBLANK_INTERRUPT_STATUS)) + if (pipea_stats & vblank_status) drm_handle_vblank(dev, 0); - if (pipeb_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS | - PIPE_VBLANK_INTERRUPT_STATUS)) + if (pipeb_stats & vblank_status) drm_handle_vblank(dev, 1); -#ifdef __linux__ - if ((pipeb_stats & I915_LEGACY_BLC_EVENT_STATUS) || - (iir & I915_ASLE_INTERRUPT)) - opregion_asle_intr(dev); -#endif + + /* With MSI, interrupts are only generated when iir + * transitions from zero to nonzero. If another bit got + * set while we were handling the existing iir bits, then + * we would never get another interrupt. + * + * This is fine on non-MSI as well, as if we hit this path + * we avoid exiting the interrupt handler only to generate + * another one. + * + * Note that for MSI this could cause a stray interrupt report + * if an interrupt landed in the time between writing IIR and + * the posting read. This should be rare enough to never + * trigger the 99% of 100,000 interrupts test for disabling + * stray interrupts. + */ + iir = new_iir; } } @@ -325,10 +357,6 @@ READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); } - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->last_dispatch = - READ_BREADCRUMB(dev_priv); - return ret; } @@ -341,13 +369,13 @@ drm_i915_irq_emit_t *emit = data; int result; - RING_LOCK_TEST_WITH_RETURN(dev, file_priv); - if (!dev_priv) { DRM_ERROR("called with no initialization\n"); return -EINVAL; } + RING_LOCK_TEST_WITH_RETURN(dev, file_priv); + result = i915_emit_irq(dev); if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) { @@ -380,21 +408,21 @@ int i915_enable_vblank(struct drm_device *dev, int pipe) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - unsigned long irqflags; - u32 pipestat; + int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; + u32 pipeconf; - /* - * Older chips didn't have the start vblank interrupt, - * but - */ - if (IS_I965G (dev)) - pipestat = PIPE_START_VBLANK_INTERRUPT_ENABLE; + pipeconf = I915_READ(pipeconf_reg); + if (!(pipeconf & PIPEACONF_ENABLE)) + return -EINVAL; + + DRM_SPINLOCK(&dev_priv->user_irq_lock); + if (IS_I965G(dev)) + i915_enable_pipestat(dev_priv, pipe, + PIPE_START_VBLANK_INTERRUPT_ENABLE); else - pipestat = PIPE_VBLANK_INTERRUPT_ENABLE; - - DRM_SPINLOCK_IRQSAVE(&dev_priv->user_irq_lock, irqflags); - i915_enable_pipestat(dev_priv, pipe, pipestat); - DRM_SPINUNLOCK_IRQRESTORE(&dev_priv->user_irq_lock, irqflags); + i915_enable_pipestat(dev_priv, pipe, + PIPE_VBLANK_INTERRUPT_ENABLE); + DRM_SPINUNLOCK(&dev_priv->user_irq_lock); return 0; } @@ -404,12 +432,12 @@ void i915_disable_vblank(struct drm_device *dev, int pipe) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - unsigned long irqflags; - DRM_SPINLOCK_IRQSAVE(&dev_priv->user_irq_lock, irqflags); + DRM_SPINLOCK(&dev_priv->user_irq_lock); i915_disable_pipestat(dev_priv, pipe, - PIPE_START_VBLANK_INTERRUPT_ENABLE | PIPE_VBLANK_INTERRUPT_ENABLE); - DRM_SPINUNLOCK_IRQRESTORE(&dev_priv->user_irq_lock, irqflags); + PIPE_VBLANK_INTERRUPT_ENABLE | + PIPE_START_VBLANK_INTERRUPT_ENABLE); + DRM_SPINUNLOCK(&dev_priv->user_irq_lock); } /* Set the vblank monitor pipe @@ -463,7 +491,6 @@ * Context switching to userland and back is plenty fast enough for * meeting the requirements of vblank swapping. */ - return -EINVAL; } @@ -473,6 +500,8 @@ { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + atomic_set_int(&dev_priv->irq_received, 0); + I915_WRITE(HWSTAM, 0xeffe); I915_WRITE(PIPEASTAT, 0); I915_WRITE(PIPEBSTAT, 0); @@ -505,14 +534,7 @@ I915_WRITE(IER, I915_INTERRUPT_ENABLE_MASK); I915_WRITE(IMR, dev_priv->irq_mask_reg); (void) I915_READ(IER); -#ifdef __linux__ - opregion_enable_asle(dev); -#endif - DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); - i915_enable_vblank(dev, 0); - i915_enable_vblank(dev, 1); - return 0; } Index: dev/drm/i915_reg.h =================================================================== --- dev/drm/i915_reg.h (revision 189900) +++ dev/drm/i915_reg.h (working copy) @@ -38,7 +38,7 @@ #define INTEL_GMCH_MEM_64M 0x1 #define INTEL_GMCH_MEM_128M 0 -#define INTEL_855_GMCH_GMS_MASK (0x7 << 4) +#define INTEL_GMCH_GMS_MASK (0xf << 4) #define INTEL_855_GMCH_GMS_DISABLED (0x0 << 4) #define INTEL_855_GMCH_GMS_STOLEN_1M (0x1 << 4) #define INTEL_855_GMCH_GMS_STOLEN_4M (0x2 << 4) @@ -48,6 +48,12 @@ #define INTEL_915G_GMCH_GMS_STOLEN_48M (0x6 << 4) #define INTEL_915G_GMCH_GMS_STOLEN_64M (0x7 << 4) +#define INTEL_GMCH_GMS_STOLEN_128M (0x8 << 4) +#define INTEL_GMCH_GMS_STOLEN_256M (0x9 << 4) +#define INTEL_GMCH_GMS_STOLEN_96M (0xa << 4) +#define INTEL_GMCH_GMS_STOLEN_160M (0xb << 4) +#define INTEL_GMCH_GMS_STOLEN_224M (0xc << 4) +#define INTEL_GMCH_GMS_STOLEN_352M (0xd << 4) /* PCI config space */ @@ -178,9 +184,27 @@ #define DISPLAY_PLANE_B (1<<20) /* + * Fence registers + */ +#define FENCE_REG_830_0 0x2000 +#define FENCE_REG_945_8 0x3000 +#define I830_FENCE_START_MASK 0x07f80000 +#define I830_FENCE_TILING_Y_SHIFT 12 +#define I830_FENCE_SIZE_BITS(size) ((ffs((size) >> 19) - 1) << 8) +#define I830_FENCE_PITCH_SHIFT 4 +#define I830_FENCE_REG_VALID (1<<0) + +#define I915_FENCE_START_MASK 0x0ff00000 +#define I915_FENCE_SIZE_BITS(size) ((ffs((size) >> 20) - 1) << 8) + +#define FENCE_REG_965_0 0x03000 +#define I965_FENCE_PITCH_SHIFT 2 +#define I965_FENCE_TILING_Y_SHIFT 1 +#define I965_FENCE_REG_VALID (1<<0) + +/* * Instruction and interrupt control regs */ - #define PRB0_TAIL 0x02030 #define PRB0_HEAD 0x02034 #define PRB0_START 0x02038 @@ -248,6 +272,7 @@ #define CM0_RC_OP_FLUSH_DISABLE (1<<0) #define GFX_FLSH_CNTL 0x02170 /* 915+ only */ + /* * Framebuffer compression (915+ only) */ @@ -525,11 +550,17 @@ #define DCC_ADDRESSING_MODE_DUAL_CHANNEL_INTERLEAVED (2 << 0) #define DCC_ADDRESSING_MODE_MASK (3 << 0) #define DCC_CHANNEL_XOR_DISABLE (1 << 10) +#define DCC_CHANNEL_XOR_BIT_17 (1 << 9) /** 965 MCH register controlling DRAM channel configuration */ #define C0DRB3 0x10206 #define C1DRB3 0x10606 +/** GM965 GM45 render standby register */ +#define MCHBAR_RENDER_STANDBY 0x111B8 + +#define PEG_BAND_GAP_DATA 0x14d68 + /* * Overlay regs */ @@ -593,6 +624,9 @@ /* Hotplug control (945+ only) */ #define PORT_HOTPLUG_EN 0x61110 +#define HDMIB_HOTPLUG_INT_EN (1 << 29) +#define HDMIC_HOTPLUG_INT_EN (1 << 28) +#define HDMID_HOTPLUG_INT_EN (1 << 27) #define SDVOB_HOTPLUG_INT_EN (1 << 26) #define SDVOC_HOTPLUG_INT_EN (1 << 25) #define TV_HOTPLUG_INT_EN (1 << 18) @@ -600,6 +634,9 @@ #define CRT_HOTPLUG_FORCE_DETECT (1 << 3) #define PORT_HOTPLUG_STAT 0x61114 +#define HDMIB_HOTPLUG_INT_STATUS (1 << 29) +#define HDMIC_HOTPLUG_INT_STATUS (1 << 28) +#define HDMID_HOTPLUG_INT_STATUS (1 << 27) #define CRT_HOTPLUG_INT_STATUS (1 << 11) #define TV_HOTPLUG_INT_STATUS (1 << 10) #define CRT_HOTPLUG_MONITOR_MASK (3 << 8) @@ -629,7 +666,16 @@ #define SDVO_PHASE_SELECT_DEFAULT (6 << 19) #define SDVO_CLOCK_OUTPUT_INVERT (1 << 18) #define SDVOC_GANG_MODE (1 << 16) +#define SDVO_ENCODING_SDVO (0x0 << 10) +#define SDVO_ENCODING_HDMI (0x2 << 10) +/** Requird for HDMI operation */ +#define SDVO_NULL_PACKETS_DURING_VSYNC (1 << 9) #define SDVO_BORDER_ENABLE (1 << 7) +#define SDVO_AUDIO_ENABLE (1 << 6) +/** New with 965, default is to be set */ +#define SDVO_VSYNC_ACTIVE_HIGH (1 << 4) +/** New with 965, default is to be set */ +#define SDVO_HSYNC_ACTIVE_HIGH (1 << 3) #define SDVOB_PCIE_CONCURRENCY (1 << 3) #define SDVO_DETECTED (1 << 2) /* Bits to be preserved when writing */ @@ -1403,6 +1449,7 @@ #define PIPEB_FRMCOUNT_GM45 0x71040 #define PIPEB_FLIPCOUNT_GM45 0x71044 + /* Display B control */ #define DSPBCNTR 0x71180 #define DISPPLANE_ALPHA_TRANS_ENABLE (1<<15) Index: dev/drm/i915_suspend.c =================================================================== --- dev/drm/i915_suspend.c (revision 189900) +++ dev/drm/i915_suspend.c (working copy) @@ -125,11 +125,6 @@ /* VGA color palette registers */ dev_priv->saveDACMASK = I915_READ8(VGA_DACMASK); - /* DACCRX automatically increments during read */ - I915_WRITE8(VGA_DACRX, 0); - /* Read 3 bytes of color data from each index */ - for (i = 0; i < 256 * 3; i++) - dev_priv->saveDACDATA[i] = I915_READ8(VGA_DACDATA); /* MSR bits */ dev_priv->saveMSR = I915_READ8(VGA_MSR_READ); @@ -231,12 +226,6 @@ /* VGA color palette registers */ I915_WRITE8(VGA_DACMASK, dev_priv->saveDACMASK); - /* DACCRX automatically increments during read */ - I915_WRITE8(VGA_DACWX, 0); - /* Read 3 bytes of color data from each index */ - for (i = 0; i < 256 * 3; i++) - I915_WRITE8(VGA_DACDATA, dev_priv->saveDACDATA[i]); - } int i915_save_state(struct drm_device *dev) @@ -250,6 +239,13 @@ pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB); #endif + /* Render Standby */ + if (IS_I965G(dev) && IS_MOBILE(dev)) + dev_priv->saveRENDERSTANDBY = I915_READ(MCHBAR_RENDER_STANDBY); + + /* Hardware status page */ + dev_priv->saveHWS = I915_READ(HWS_PGA); + /* Display arbitration control */ dev_priv->saveDSPARB = I915_READ(DSPARB); @@ -379,6 +375,14 @@ pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB); #endif + /* Render Standby */ + if (IS_I965G(dev) && IS_MOBILE(dev)) + I915_WRITE(MCHBAR_RENDER_STANDBY, dev_priv->saveRENDERSTANDBY); + + /* Hardware status page */ + I915_WRITE(HWS_PGA, dev_priv->saveHWS); + + /* Display arbitration */ I915_WRITE(DSPARB, dev_priv->saveDSPARB); /* Pipe & plane A info */