diff options
author | Dave Airlie <airlied@redhat.com> | 2013-07-04 10:46:17 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2013-07-04 10:46:17 +1000 |
commit | d0aaa2836aa3f12b4ebf3e21811616a083c8c91b (patch) | |
tree | 7702a9d1b553890f40075d7e35dc2f6bd2670799 /drivers | |
parent | 1586ba727f08293f1b48f40683b59746f9f71d0b (diff) | |
parent | 446f8d81ca2d9cefb614e87f2fabcc996a9e4e7e (diff) |
Merge tag 'drm-intel-fixes-2013-07-03' of git://people.freedesktop.org/~danvet/drm-intel into drm-next
Pile of fixes for 3.11. A bit large in patch count, but that's simply due
to two fixes being split up into really small parts. Also I've included a
few more vlv patches than I'd have included for other platforms. But since
vlv is officially supported for the first time only in 3.11 that shouldn't
result in unbearable risks.
Highlights:
- ghost eDP fixes for hsw from Paulo
- fix PCH detection in virtualized enviroments (Rui Guo)
- duct-tape dma sg construction when swiotlb is in use (Konrad), dupe with
a patch in your drm-fixes branch
- fix sdvo hotplug on i965g
- tune down a bunch of dmesg ERRORs which can be hit under normal
conditions
- detect invalid pitches for tiled scanout buffers (Chris)
- a pile of vlv fixes from Ville: rps improvements, fixes for the dpll
LPF, fixup the sprite mmio offsets
- fix context size on hsw (Ben)
- locking fixes for the hotplug code, specifically the storm handling
- fix get_config on CPT (Xiong Zhang)
- Fix the domain tracking when an unlocked seqno wait was interrupt
(Chris), this seems to explain tons of little corruption bugs in the
ddx. Chris also added a nice igt to exercise this.
- work around stack-corrupting vnsprintf in our error state dumper
* tag 'drm-intel-fixes-2013-07-03' of git://people.freedesktop.org/~danvet/drm-intel: (39 commits)
drm/i915: Don't try to tear down the stolen drm_mm if it's not there
drm/i915: Break up the large vsnprintf() in print_error_buffers()
drm/i915: Refactor the wait_rendering completion into a common routine
drm/i915: Only clear write-domains after a successful wait-seqno
drm/i915: correct intel_dp_get_config() function for DevCPT
drm/i915: fix hpd interrupt register locking
drm/i915: fold the no-irq check into intel_hpd_irq_handler
drm/i915: fold the queue_work into intel_hpd_irq_handler
drm/i915: fold the hpd_irq_setup call into intel_hpd_irq_handler
drm/i915: s/hotplug_irq_storm_detect/intel_hpd_irq_handler/
drm/i915: close tiny race in the ilk pcu even interrupt setup
drm/i915: fix locking around ironlake_enable|disable_display_irq
drm/i915: Fix context sizes on HSW
drm/i915: Fix VLV sprite register offsets
Revert "drm/i915: Don't use the HDMI port color range bit on Valleyview"
drm/i915: s/LFP/LPF in DPIO PLL register names
drm/i915: Fix VLV PLL LPF coefficients for DAC
drm/i915: Jump to at least RPe on VLV when increasing the GPU frequency
drm/i915: Don't increase the GPU frequency from the delayed VLV rps timer
drm/i915: GEN6_RP_INTERRUPT_LIMITS doesn't seem to exist on VLV
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/i915/i915_debugfs.c | 119 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.c | 18 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 64 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_context.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_stolen.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 137 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 84 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_ddi.c | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 38 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_dp.c | 215 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_hdmi.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_opregion.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_pm.c | 110 |
15 files changed, 498 insertions, 322 deletions
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index d4e78b64ca8..47d6c748057 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -647,41 +647,44 @@ static const char *purgeable_flag(int purgeable) return purgeable ? " purgeable" : ""; } -static void i915_error_vprintf(struct drm_i915_error_state_buf *e, - const char *f, va_list args) +static bool __i915_error_ok(struct drm_i915_error_state_buf *e) { - unsigned len; if (!e->err && WARN(e->bytes > (e->size - 1), "overflow")) { e->err = -ENOSPC; - return; + return false; } if (e->bytes == e->size - 1 || e->err) - return; + return false; - /* Seek the first printf which is hits start position */ - if (e->pos < e->start) { - len = vsnprintf(NULL, 0, f, args); - if (e->pos + len <= e->start) { - e->pos += len; - return; - } + return true; +} - /* First vsnprintf needs to fit in full for memmove*/ - if (len >= e->size) { - e->err = -EIO; - return; - } +static bool __i915_error_seek(struct drm_i915_error_state_buf *e, + unsigned len) +{ + if (e->pos + len <= e->start) { + e->pos += len; + return false; } - len = vsnprintf(e->buf + e->bytes, e->size - e->bytes, f, args); - if (len >= e->size - e->bytes) - len = e->size - e->bytes - 1; + /* First vsnprintf needs to fit in its entirety for memmove */ + if (len >= e->size) { + e->err = -EIO; + return false; + } + return true; +} + +static void __i915_error_advance(struct drm_i915_error_state_buf *e, + unsigned len) +{ /* If this is first printf in this window, adjust it so that * start position matches start of the buffer */ + if (e->pos < e->start) { const size_t off = e->start - e->pos; @@ -701,6 +704,51 @@ static void i915_error_vprintf(struct drm_i915_error_state_buf *e, e->pos += len; } +static void i915_error_vprintf(struct drm_i915_error_state_buf *e, + const char *f, va_list args) +{ + unsigned len; + + if (!__i915_error_ok(e)) + return; + + /* Seek the first printf which is hits start position */ + if (e->pos < e->start) { + len = vsnprintf(NULL, 0, f, args); + if (!__i915_error_seek(e, len)) + return; + } + + len = vsnprintf(e->buf + e->bytes, e->size - e->bytes, f, args); + if (len >= e->size - e->bytes) + len = e->size - e->bytes - 1; + + __i915_error_advance(e, len); +} + +static void i915_error_puts(struct drm_i915_error_state_buf *e, + const char *str) +{ + unsigned len; + + if (!__i915_error_ok(e)) + return; + + len = strlen(str); + + /* Seek the first printf which is hits start position */ + if (e->pos < e->start) { + if (!__i915_error_seek(e, len)) + return; + } + + if (len >= e->size - e->bytes) + len = e->size - e->bytes - 1; + memcpy(e->buf + e->bytes, str, len); + + __i915_error_advance(e, len); +} + void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...) { va_list args; @@ -711,6 +759,7 @@ void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...) } #define err_printf(e, ...) i915_error_printf(e, __VA_ARGS__) +#define err_puts(e, s) i915_error_puts(e, s) static void print_error_buffers(struct drm_i915_error_state_buf *m, const char *name, @@ -720,26 +769,26 @@ static void print_error_buffers(struct drm_i915_error_state_buf *m, err_printf(m, "%s [%d]:\n", name, count); while (count--) { - err_printf(m, " %08x %8u %02x %02x %x %x%s%s%s%s%s%s%s", + err_printf(m, " %08x %8u %02x %02x %x %x", err->gtt_offset, err->size, err->read_domains, err->write_domain, - err->rseqno, err->wseqno, - pin_flag(err->pinned), - tiling_flag(err->tiling), - dirty_flag(err->dirty), - purgeable_flag(err->purgeable), - err->ring != -1 ? " " : "", - ring_str(err->ring), - cache_level_str(err->cache_level)); + err->rseqno, err->wseqno); + err_puts(m, pin_flag(err->pinned)); + err_puts(m, tiling_flag(err->tiling)); + err_puts(m, dirty_flag(err->dirty)); + err_puts(m, purgeable_flag(err->purgeable)); + err_puts(m, err->ring != -1 ? " " : ""); + err_puts(m, ring_str(err->ring)); + err_puts(m, cache_level_str(err->cache_level)); if (err->name) err_printf(m, " (name: %d)", err->name); if (err->fence_reg != I915_FENCE_REG_NONE) err_printf(m, " (fence: %d)", err->fence_reg); - err_printf(m, "\n"); + err_puts(m, "\n"); err++; } } @@ -1483,7 +1532,7 @@ static int i915_ips_status(struct seq_file *m, void *unused) struct drm_device *dev = node->minor->dev; struct drm_i915_private *dev_priv = dev->dev_private; - if (!IS_ULT(dev)) { + if (!HAS_IPS(dev)) { seq_puts(m, "not supported\n"); return 0; } @@ -1862,10 +1911,10 @@ static int i915_dpio_info(struct seq_file *m, void *data) seq_printf(m, "DPIO_CORE_CLK_B: 0x%08x\n", vlv_dpio_read(dev_priv, _DPIO_CORE_CLK_B)); - seq_printf(m, "DPIO_LFP_COEFF_A: 0x%08x\n", - vlv_dpio_read(dev_priv, _DPIO_LFP_COEFF_A)); - seq_printf(m, "DPIO_LFP_COEFF_B: 0x%08x\n", - vlv_dpio_read(dev_priv, _DPIO_LFP_COEFF_B)); + seq_printf(m, "DPIO_LPF_COEFF_A: 0x%08x\n", + vlv_dpio_read(dev_priv, _DPIO_LPF_COEFF_A)); + seq_printf(m, "DPIO_LPF_COEFF_B: 0x%08x\n", + vlv_dpio_read(dev_priv, _DPIO_LPF_COEFF_B)); seq_printf(m, "DPIO_FASTCLK_DISABLE: 0x%08x\n", vlv_dpio_read(dev_priv, DPIO_FASTCLK_DISABLE)); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index deaa32e8113..062cbda1bf4 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -465,9 +465,15 @@ void intel_detect_pch(struct drm_device *dev) * make graphics device passthrough work easy for VMM, that only * need to expose ISA bridge to let driver know the real hardware * underneath. This is a requirement from virtualization team. + * + * In some virtualized environments (e.g. XEN), there is irrelevant + * ISA bridge in the system. To work reliably, we should scan trhough + * all the ISA bridge devices and check for the first match, instead + * of only checking the first one. */ pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL); - if (pch) { + while (pch) { + struct pci_dev *curr = pch; if (pch->vendor == PCI_VENDOR_ID_INTEL) { unsigned short id; id = pch->device & INTEL_PCH_DEVICE_ID_MASK; @@ -496,10 +502,18 @@ void intel_detect_pch(struct drm_device *dev) DRM_DEBUG_KMS("Found LynxPoint LP PCH\n"); WARN_ON(!IS_HASWELL(dev)); WARN_ON(!IS_ULT(dev)); + } else { + goto check_next; } + pci_dev_put(pch); + break; } - pci_dev_put(pch); +check_next: + pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, curr); + pci_dev_put(curr); } + if (!pch) + DRM_DEBUG_KMS("No PCH found?\n"); } bool i915_semaphore_is_enabled(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9e1bf6dcbb2..cc1d6056ab7 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1474,6 +1474,8 @@ struct drm_i915_file_private { #define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr) #define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc) +#define HAS_IPS(dev) (IS_ULT(dev)) + #define HAS_PIPE_CONTROL(dev) (INTEL_INFO(dev)->gen >= 5) #define HAS_DDI(dev) (INTEL_INFO(dev)->has_ddi) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a6178baccb5..769f75262fe 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1087,6 +1087,25 @@ i915_wait_seqno(struct intel_ring_buffer *ring, uint32_t seqno) interruptible, NULL); } +static int +i915_gem_object_wait_rendering__tail(struct drm_i915_gem_object *obj, + struct intel_ring_buffer *ring) +{ + i915_gem_retire_requests_ring(ring); + + /* Manually manage the write flush as we may have not yet + * retired the buffer. + * + * Note that the last_write_seqno is always the earlier of + * the two (read/write) seqno, so if we haved successfully waited, + * we know we have passed the last write. + */ + obj->last_write_seqno = 0; + obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS; + + return 0; +} + /** * Ensures that all rendering to the object has completed and the object is * safe to unbind from the GTT or access from the CPU. @@ -1107,18 +1126,7 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj, if (ret) return ret; - i915_gem_retire_requests_ring(ring); - - /* Manually manage the write flush as we may have not yet - * retired the buffer. - */ - if (obj->last_write_seqno && - i915_seqno_passed(seqno, obj->last_write_seqno)) { - obj->last_write_seqno = 0; - obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS; - } - - return 0; + return i915_gem_object_wait_rendering__tail(obj, ring); } /* A nonblocking variant of the above wait. This is a highly dangerous routine @@ -1154,19 +1162,10 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj, mutex_unlock(&dev->struct_mutex); ret = __wait_seqno(ring, seqno, reset_counter, true, NULL); mutex_lock(&dev->struct_mutex); + if (ret) + return ret; - i915_gem_retire_requests_ring(ring); - - /* Manually manage the write flush as we may have not yet - * retired the buffer. - */ - if (obj->last_write_seqno && - i915_seqno_passed(seqno, obj->last_write_seqno)) { - obj->last_write_seqno = 0; - obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS; - } - - return ret; + return i915_gem_object_wait_rendering__tail(obj, ring); } /** @@ -1802,7 +1801,14 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) gfp |= __GFP_NORETRY | __GFP_NOWARN | __GFP_NO_KSWAPD; gfp &= ~(__GFP_IO | __GFP_WAIT); } - +#ifdef CONFIG_SWIOTLB + if (swiotlb_nr_tbl()) { + st->nents++; + sg_set_page(sg, page, PAGE_SIZE, 0); + sg = sg_next(sg); + continue; + } +#endif if (!i || page_to_pfn(page) != last_pfn + 1) { if (i) sg = sg_next(sg); @@ -1813,8 +1819,10 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) } last_pfn = page_to_pfn(page); } - - sg_mark_end(sg); +#ifdef CONFIG_SWIOTLB + if (!swiotlb_nr_tbl()) +#endif + sg_mark_end(sg); obj->pages = st; if (i915_gem_object_needs_bit17_swizzle(obj)) @@ -3103,7 +3111,7 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, * before evicting everything in a vain attempt to find space. */ if (obj->base.size > gtt_max) { - DRM_ERROR("Attempting to bind an object larger than the aperture: object=%zd > %s aperture=%ld\n", + DRM_ERROR("Attempting to bind an object larger than the aperture: object=%zd > %s aperture=%zu\n", obj->base.size, map_and_fenceable ? "mappable" : "total", gtt_max); diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index ff471454968..51b7a2171ca 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -113,7 +113,7 @@ static int get_context_size(struct drm_device *dev) case 7: reg = I915_READ(GEN7_CXT_SIZE); if (IS_HASWELL(dev)) - ret = HSW_CXT_TOTAL_SIZE(reg) * 64; + ret = HSW_CXT_TOTAL_SIZE; else ret = GEN7_CXT_TOTAL_SIZE(reg) * 64; break; diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index f713294618f..982d4732cec 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -147,7 +147,7 @@ int i915_gem_stolen_setup_compression(struct drm_device *dev, int size) { struct drm_i915_private *dev_priv = dev->dev_private; - if (dev_priv->mm.stolen_base == 0) + if (!drm_mm_initialized(&dev_priv->mm.stolen)) return -ENODEV; if (size < dev_priv->cfb_size) @@ -179,6 +179,9 @@ void i915_gem_cleanup_stolen(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + if (!drm_mm_initialized(&dev_priv->mm.stolen)) + return; + i915_gem_stolen_cleanup_compression(dev); drm_mm_takedown(&dev_priv->mm.stolen); } @@ -300,7 +303,7 @@ i915_gem_object_create_stolen(struct drm_device *dev, u32 size) struct drm_i915_gem_object *obj; struct drm_mm_node *stolen; - if (dev_priv->mm.stolen_base == 0) + if (!drm_mm_initialized(&dev_priv->mm.stolen)) return NULL; DRM_DEBUG_KMS("creating stolen object: size=%x\n", size); @@ -331,7 +334,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, struct drm_i915_gem_object *obj; struct drm_mm_node *stolen; - if (dev_priv->mm.stolen_base == 0) + if (!drm_mm_initialized(&dev_priv->mm.stolen)) return NULL; DRM_DEBUG_KMS("creating preallocated stolen object: stolen_offset=%x, gtt_offset=%x, size=%x\n", diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 7857430943e..3d92a7cef15 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -70,15 +70,6 @@ static const u32 hpd_status_gen4[] = { [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS }; -static const u32 hpd_status_i965[] = { - [HPD_CRT] = CRT_HOTPLUG_INT_STATUS, - [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I965, - [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_I965, - [HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS, - [HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS, - [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS -}; - static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */ [HPD_CRT] = CRT_HOTPLUG_INT_STATUS, [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I915, @@ -88,13 +79,12 @@ static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */ [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS }; -static void ibx_hpd_irq_setup(struct drm_device *dev); -static void i915_hpd_irq_setup(struct drm_device *dev); - /* For display hotplug interrupt */ static void ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask) { + assert_spin_locked(&dev_priv->irq_lock); + if ((dev_priv->irq_mask & mask) != 0) { dev_priv->irq_mask &= ~mask; I915_WRITE(DEIMR, dev_priv->irq_mask); @@ -105,6 +95,8 @@ ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask) static void ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask) { + assert_spin_locked(&dev_priv->irq_lock); + if ((dev_priv->irq_mask & mask) != mask) { dev_priv->irq_mask |= mask; I915_WRITE(DEIMR, dev_priv->irq_mask); @@ -118,6 +110,8 @@ static bool ivb_can_enable_err_int(struct drm_device *dev) struct intel_crtc *crtc; enum pipe pipe; + assert_spin_locked(&dev_priv->irq_lock); + for_each_pipe(pipe) { crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); @@ -708,16 +702,24 @@ static void gen6_pm_rps_work(struct work_struct *work) mutex_lock(&dev_priv->rps.hw_lock); - if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) + if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) { new_delay = dev_priv->rps.cur_delay + 1; - else + + /* + * For better performance, jump directly + * to RPe if we're below it. + */ + if (IS_VALLEYVIEW(dev_priv->dev) && + dev_priv->rps.cur_delay < dev_priv->rps.rpe_delay) + new_delay = dev_priv->rps.rpe_delay; + } else new_delay = dev_priv->rps.cur_delay - 1; /* sysfs frequency interfaces may have snuck in while servicing the * interrupt */ - if (!(new_delay > dev_priv->rps.max_delay || - new_delay < dev_priv->rps.min_delay)) { + if (new_delay >= dev_priv->rps.min_delay && + new_delay <= dev_priv->rps.max_delay) { if (IS_VALLEYVIEW(dev_priv->dev)) valleyview_set_rps(dev_priv->dev, new_delay); else @@ -870,17 +872,18 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv, #define HPD_STORM_DETECT_PERIOD 1000 #define HPD_STORM_THRESHOLD 5 -static inline bool hotplug_irq_storm_detect(struct drm_device *dev, - u32 hotplug_trigger, - const u32 *hpd) +static inline void intel_hpd_irq_handler(struct drm_device *dev, + u32 hotplug_trigger, + const u32 *hpd) { drm_i915_private_t *dev_priv = dev->dev_private; - unsigned long irqflags; int i; - bool ret = false; + bool storm_detected = false; - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + if (!hotplug_trigger) + return; + spin_lock(&dev_priv->irq_lock); for (i = 1; i < HPD_NUM_PINS; i++) { if (!(hpd[i] & hotplug_trigger) || @@ -897,15 +900,18 @@ static inline bool hotplug_irq_storm_detect(struct drm_device *dev, dev_priv->hpd_stats[i].hpd_mark = HPD_MARK_DISABLED; dev_priv->hpd_event_bits &= ~(1 << i); DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", i); - ret = true; + storm_detected = true; } else { dev_priv->hpd_stats[i].hpd_cnt++; } } - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + if (storm_detected) + dev_priv->display.hpd_irq_setup(dev); + spin_unlock(&dev_priv->irq_lock); - return ret; + queue_work(dev_priv->wq, + &dev_priv->hotplug_work); } static void gmbus_irq_handler(struct drm_device *dev) @@ -1012,12 +1018,9 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); - if (hotplug_trigger) { - if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915)) - i915_hpd_irq_setup(dev); - queue_work(dev_priv->wq, - &dev_priv->hotplug_work); - } + + intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915); + I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); I915_READ(PORT_HOTPLUG_STAT); } @@ -1043,11 +1046,8 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir) int pipe; u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK; - if (hotplug_trigger) { - if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_ibx)) - ibx_hpd_irq_setup(dev); - queue_work(dev_priv->wq, &dev_priv->hotplug_work); - } + intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx); + if (pch_iir & SDE_AUDIO_POWER_MASK) { int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >> SDE_AUDIO_POWER_SHIFT); @@ -1148,11 +1148,8 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) int pipe; u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT; - if (hotplug_trigger) { - if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_cpt)) - ibx_hpd_irq_setup(dev); - queue_work(dev_priv->wq, &dev_priv->hotplug_work); - } + intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt); + if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) { int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >> SDE_AUDIO_POWER_SHIFT_CPT); @@ -1218,8 +1215,11 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg) /* On Haswell, also mask ERR_INT because we don't want to risk * generating "unclaimed register" interrupts from inside the interrupt * handler. */ - if (IS_HASWELL(dev)) + if (IS_HASWELL(dev)) { + spin_lock(&dev_priv->irq_lock); ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB); + spin_unlock(&dev_priv->irq_lock); + } gt_iir = I915_READ(GTIIR); if (gt_iir) { @@ -1272,8 +1272,12 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg) ret = IRQ_HANDLED; } - if (IS_HASWELL(dev) && ivb_can_enable_err_int(dev)) - ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB); + if (IS_HASWELL(dev)) { + spin_lock(&dev_priv->irq_lock); + if (ivb_can_enable_err_int(dev)) + ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB); + spin_unlock(&dev_priv->irq_lock); + } I915_WRITE(DEIER, de_ier); POSTING_READ(DEIER); @@ -2698,6 +2702,8 @@ static void ibx_irq_postinstall(struct drm_device *dev) static int ironlake_irq_postinstall(struct drm_device *dev) { + unsigned long irqflags; + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; /* enable kind of interrupts always enabled */ u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT | @@ -2711,7 +2717,8 @@ static int ironlake_irq_postinstall(struct drm_device *dev) /* should always can generate irq */ I915_WRITE(DEIIR, I915_READ(DEIIR)); I915_WRITE(DEIMR, dev_priv->irq_mask); - I915_WRITE(DEIER, display_mask | DE_PIPEA_VBLANK | DE_PIPEB_VBLANK); + I915_WRITE(DEIER, display_mask | + DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT); POSTING_READ(DEIER); dev_priv->gt_irq_mask = ~0; @@ -2733,10 +2740,14 @@ static int ironlake_irq_postinstall(struct drm_device *dev) ibx_irq_postinstall(dev); if (IS_IRONLAKE_M(dev)) { - /* Clear & enable PCU event interrupts */ - I915_WRITE(DEIIR, DE_PCU_EVENT); - I915_WRITE(DEIER, I915_READ(DEIER) | DE_PCU_EVENT); + /* Enable PCU event interrupts + * + * spinlocking not required here for correctness since interrupt + * setup is guaranteed to run in single-threaded context. But we + * need it to make the assert_spin_locked happy. */ + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); ironlake_enable_display_irq(dev_priv, DE_PCU_EVENT); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } return 0; @@ -3212,12 +3223,9 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); - if (hotplug_trigger) { - if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915)) - i915_hpd_irq_setup(dev); - queue_work(dev_priv->wq, - &dev_priv->hotplug_work); - } + + intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915); + I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); POSTING_READ(PORT_HOTPLUG_STAT); } @@ -3369,6 +3377,8 @@ static void i915_hpd_irq_setup(struct drm_device *dev) struct intel_encoder *intel_encoder; u32 hotplug_en; + assert_spin_locked(&dev_priv->irq_lock); + if (I915_HAS_HOTPLUG(dev)) { hotplug_en = I915_READ(PORT_HOTPLUG_EN); hotplug_en &= ~HOTPLUG_INT_EN_MASK; @@ -3449,17 +3459,14 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); u32 hotplug_trigger = hotplug_status & (IS_G4X(dev) ? HOTPLUG_INT_STATUS_G4X : - HOTPLUG_INT_STATUS_I965); + HOTPLUG_INT_STATUS_I915); DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); - if (hotplug_trigger) { - if (hotplug_irq_storm_detect(dev, hotplug_trigger, - IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i965)) - i915_hpd_irq_setup(dev); - queue_work(dev_priv->wq, - &dev_priv->hotplug_work); - } + + intel_hpd_irq_handler(dev, hotplug_trigger, + IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i915); + I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); I915_READ(PORT_HOTPLUG_STAT); } @@ -3655,6 +3662,7 @@ void intel_hpd_init(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct drm_mode_config *mode_config = &dev->mode_config; struct drm_connector *connector; + unsigned long irqflags; int i; for (i = 1; i < HPD_NUM_PINS; i++) { @@ -3667,6 +3675,11 @@ void intel_hpd_init(struct drm_device *dev) if (!connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE) connector->polled = DRM_CONNECTOR_POLL_HPD; } + + /* Interrupt setup is already guaranteed to be single-threaded, this is + * just to make the assert_spin_locked checks happy. */ + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); if (dev_priv->display.hpd_irq_setup) dev_priv->display.hpd_irq_setup(dev); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 2102ff32ee2..f2326fc60ac 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -448,9 +448,9 @@ #define _DPIO_PLL_CML_B 0x806c #define DPIO_PLL_CML(pipe) _PIPE(pipe, _DPIO_PLL_CML_A, _DPIO_PLL_CML_B) -#define _DPIO_LFP_COEFF_A 0x8048 -#define _DPIO_LFP_COEFF_B 0x8068 -#define DPIO_LFP_COEFF(pipe) _PIPE(pipe, _DPIO_LFP_COEFF_A, _DPIO_LFP_COEFF_B) +#define _DPIO_LPF_COEFF_A 0x8048 +#define _DPIO_LPF_COEFF_B 0x8068 +#define DPIO_LPF_COEFF(pipe) _PIPE(pipe, _DPIO_LPF_COEFF_A, _DPIO_LPF_COEFF_B) #define DPIO_CALIBRATION 0x80ac @@ -1718,14 +1718,13 @@ GEN7_CXT_EXTENDED_SIZE(ctx_reg) + \ GEN7_CXT_GT1_SIZE(ctx_reg) + \ GEN7_CXT_VFSTATE_SIZE(ctx_reg)) -#define HSW_CXT_POWER_SIZE(ctx_reg) ((ctx_reg >> 26) & 0x3f) -#define HSW_CXT_RING_SIZE(ctx_reg) ((ctx_reg >> 23) & 0x7) -#define HSW_CXT_RENDER_SIZE(ctx_reg) ((ctx_reg >> 15) & 0xff) -#define HSW_CXT_TOTAL_SIZE(ctx_reg) (HSW_CXT_POWER_SIZE(ctx_reg) + \ - HSW_CXT_RING_SIZE(ctx_reg) + \ - HSW_CXT_RENDER_SIZE(ctx_reg) + \ - GEN7_CXT_VFSTATE_SIZE(ctx_reg)) - +/* Haswell does have the CXT_SIZE register however it does not appear to be + * valid. Now, docs explain in dwords what is in the context object. The full + * size is 70720 bytes, however, the power context and execlist context will + * never be saved (power context is stored elsewhere, and execlists don't work + * on HSW) - so the final size is 66944 bytes, which rounds to 17 pages. + */ +#define HSW_CXT_TOTAL_SIZE (17 * PAGE_SIZE) /* * Overlay regs @@ -1874,6 +1873,12 @@ /* SDVO is different across gen3/4 */ #define SDVOC_HOTPLUG_INT_STATUS_G4X (1 << 3) #define SDVOB_HOTPLUG_INT_STATUS_G4X (1 << 2) +/* + * Bspec seems to be seriously misleaded about the SDVO hpd bits on i965g/gm, + * since reality corrobates that they're the same as on gen3. But keep these + * bits here (and the comment!) to help any other lost wanderers back onto the + * right tracks. + */ #define SDVOC_HOTPLUG_INT_STATUS_I965 (3 << 4) #define SDVOB_HOTPLUG_INT_STATUS_I965 (3 << 2) #define SDVOC_HOTPLUG_INT_STATUS_I915 (1 << 7) @@ -1885,13 +1890,6 @@ PORTC_HOTPLUG_INT_STATUS | \ PORTD_HOTPLUG_INT_STATUS) -#define HOTPLUG_INT_STATUS_I965 (CRT_HOTPLUG_INT_STATUS | \ - SDVOB_HOTPLUG_INT_STATUS_I965 | \ - SDVOC_HOTPLUG_INT_STATUS_I965 | \ - PORTB_HOTPLUG_INT_STATUS | \ - PORTC_HOTPLUG_INT_STATUS | \ - PORTD_HOTPLUG_INT_STATUS) - #define HOTPLUG_INT_STATUS_I915 (CRT_HOTPLUG_INT_STATUS | \ SDVOB_HOTPLUG_INT_STATUS_I915 | \ SDVOC_HOTPLUG_INT_STATUS_I915 | \ @@ -3488,7 +3486,7 @@ #define SPRGAMC(pipe) _PIPE(pipe, _SPRA_GAMC, _SPRB_GAMC) #define SPRSURFLIVE(pipe) _PIPE(pipe, _SPRA_SURFLIVE, _SPRB_SURFLIVE) -#define _SPACNTR 0x72180 +#define _SPACNTR (VLV_DISPLAY_BASE + 0x72180) #define SP_ENABLE (1<<31) #define SP_GEAMMA_ENABLE (1<<30) #define SP_PIXFORMAT_MASK (0xf<<26) @@ -3507,30 +3505,30 @@ #define SP_YUV_ORDER_YVYU (2<<16) #define SP_YUV_ORDER_VYUY (3<<16) #define SP_TILED (1<<10) -#define _SPALINOFF 0x72184 -#define _SPASTRIDE 0x72188 -#define _SPAPOS 0x7218c -#define _SPASIZE 0x72190 -#define _SPAKEYMINVAL 0x72194 -#define _SPAKEYMSK 0x72198 -#define _SPASURF 0x7219c -#define _SPAKEYMAXVAL 0x721a0 -#define _SPATILEOFF 0x721a4 -#define _SPACONSTALPHA 0x721a8 -#define _SPAGAMC 0x721f4 - -#define _SPBCNTR 0x72280 -#define _SPBLINOFF 0x72284 -#define _SPBSTRIDE 0x72288 -#define _SPBPOS 0x7228c -#define _SPBSIZE 0x72290 -#define _SPBKEYMINVAL 0x72294 -#define _SPBKEYMSK 0x72298 -#define _SPBSURF 0x7229c -#define _SPBKEYMAXVAL 0x722a0 -#define _SPBTILEOFF 0x722a4 -#define _SPBCONSTALPHA 0x722a8 -#define _SPBGAMC 0x722f4 +#define _SPALINOFF (VLV_DISPLAY_BASE + 0x72184) +#define _SPASTRIDE (VLV_DISPLAY_BASE + 0x72188) +#define _SPAPOS (VLV_DISPLAY_BASE + 0x7218c) +#define _SPASIZE (VLV_DISPLAY_BASE + 0x72190) +#define _SPAKEYMINVAL (VLV_DISPLAY_BASE + 0x72194) +#define _SPAKEYMSK (VLV_DISPLAY_BASE + 0x72198) +#define _SPASURF (VLV_DISPLAY_BASE + 0x7219c) +#define _SPAKEYMAXVAL (VLV_DISPLAY_BASE + 0x721a0) +#define _SPATILEOFF (VLV_DISPLAY_BASE + 0x721a4) +#define _SPACONSTALPHA (VLV_DISPLAY_BASE + 0x721a8) +#define _SPAGAMC (VLV_DISPLAY_BASE + 0x721f4) + +#define _SPBCNTR (VLV_DISPLAY_BASE + 0x72280) +#define _SPBLINOFF (VLV_DISPLAY_BASE + 0x72284) +#define _SPBSTRIDE (VLV_DISPLAY_BASE + 0x72288) +#define _SPBPOS (VLV_DISPLAY_BASE + 0x7228c) +#define _SPBSIZE (VLV_DISPLAY_BASE + 0x72290) +#define _SPBKEYMINVAL (VLV_DISPLAY_BASE + 0x72294) +#define _SPBKEYMSK (VLV_DISPLAY_BASE + 0x72298) +#define _SPBSURF (VLV_DISPLAY_BASE + 0x7229c) +#define _SPBKEYMAXVAL (VLV_DISPLAY_BASE + 0x722a0) +#define _SPBTILEOFF (VLV_DISPLAY_BASE + 0x722a4) +#define _SPBCONSTALPHA (VLV_DISPLAY_BASE + 0x722a8) +#define _SPBGAMC (VLV_DISPLAY_BASE + 0x722f4) #define SPCNTR(pipe, plane) _PIPE(pipe * 2 + plane, _SPACNTR, _SPBCNTR) #define SPLINOFF(pipe, plane) _PIPE(pipe * 2 + plane, _SPALINOFF, _SPBLINOFF) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 224ce25129c..324211ac9c5 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1356,7 +1356,12 @@ void intel_ddi_init(struct drm_device *dev, enum port port) intel_encoder->cloneable = false; intel_encoder->hot_plug = intel_ddi_hot_plug; - intel_dp_init_connector(intel_dig_port, dp_connector); + if (!intel_dp_init_connector(intel_dig_port, dp_connector)) { + drm_encoder_cleanup(encoder); + kfree(intel_dig_port); + kfree(dp_connector); + return; + } if (intel_encoder->type != INTEL_OUTPUT_EDP) { hdmi_connector = kzalloc(sizeof(struct intel_connector), diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b08d1f9ce0d..85f3eb74d2b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3250,7 +3250,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) /* IPS only exists on ULT machines and is tied to pipe A. */ static bool hsw_crtc_supports_ips(struct intel_crtc *crtc) { - return IS_ULT(crtc->base.dev) && crtc->pipe == PIPE_A; + return HAS_IPS(crtc->base.dev) && crtc->pipe == PIPE_A; } static void hsw_enable_ips(struct intel_crtc *crtc) @@ -4069,7 +4069,7 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc, pipe_config->pipe_bpp = 8*3; } - if (IS_HASWELL(dev)) + if (HAS_IPS(dev)) hsw_compute_ips_config(crtc, pipe_config); /* XXX: PCH clock sharing is done in ->mode_set, so make sure the old @@ -4404,11 +4404,12 @@ static void vlv_update_pll(struct intel_crtc *crtc) /* Set HBR and RBR LPF coefficients */ if (crtc->config.port_clock == 162000 || + intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_ANALOG) || intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI)) - vlv_dpio_write(dev_priv, DPIO_LFP_COEFF(pipe), + vlv_dpio_write(dev_priv, DPIO_LPF_COEFF(pipe), 0x005f0021); else - vlv_dpio_write(dev_priv, DPIO_LFP_COEFF(pipe), + vlv_dpio_write(dev_priv, DPIO_LPF_COEFF(pipe), 0x00d0000f); if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP) || @@ -8753,8 +8754,8 @@ static int intel_crtc_set_config(struct drm_mode_set *set) } if (ret) { - DRM_ERROR("failed to set mode on [CRTC:%d], err = %d\n", - set->crtc->base.id, ret); + DRM_DEBUG_KMS("failed to set mode on [CRTC:%d], err = %d\n", + set->crtc->base.id, ret); fail: intel_set_config_restore_state(dev, config); @@ -9121,6 +9122,7 @@ int intel_framebuffer_init(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, struct drm_i915_gem_object *obj) { + int pitch_limit; int ret; if (obj->tiling_mode == I915_TILING_Y) { @@ -9134,10 +9136,26 @@ int intel_framebuffer_init(struct drm_device *dev, return -EINVAL; } - /* FIXME <= Gen4 stride limits are bit unclear */ - if (mode_cmd->pitches[0] > 32768) { - DRM_DEBUG("pitch (%d) must be at less than 32768\n", - mode_cmd->pitches[0]); + if (INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev)) { + pitch_limit = 32*1024; + } else if (INTEL_INFO(dev)->gen >= 4) { + if (obj->tiling_mode) + pitch_limit = 16*1024; + else + pitch_limit = 32*1024; + } else if (INTEL_INFO(dev)->gen >= 3) { + if (obj->tiling_mode) + pitch_limit = 8*1024; + else + pitch_limit = 16*1024; + } else + /* XXX DSPC is limited to 4k tiled */ + pitch_limit = 8*1024; + + if (mode_cmd->pitches[0] > pitch_limit) { + DRM_DEBUG("%s pitch (%d) must be at less than %d\n", + obj->tiling_mode ? "tiled" : "linear", + mode_cmd->pitches[0], pitch_limit); return -EINVAL; } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 98686005dcf..b7397123401 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1324,20 +1324,35 @@ static void intel_dp_get_config(struct intel_encoder *encoder, struct intel_crtc_config *pipe_config) { struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); - struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; u32 tmp, flags = 0; + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum port port = dp_to_dig_port(intel_dp)->port; + struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); - tmp = I915_READ(intel_dp->output_reg); + if ((port == PORT_A) || !HAS_PCH_CPT(dev)) { + tmp = I915_READ(intel_dp->output_reg); + if (tmp & DP_SYNC_HS_HIGH) + flags |= DRM_MODE_FLAG_PHSYNC; + else + flags |= DRM_MODE_FLAG_NHSYNC; - if (tmp & DP_SYNC_HS_HIGH) - flags |= DRM_MODE_FLAG_PHSYNC; - else - flags |= DRM_MODE_FLAG_NHSYNC; + if (tmp & DP_SYNC_VS_HIGH) + flags |= DRM_MODE_FLAG_PVSYNC; + else + flags |= DRM_MODE_FLAG_NVSYNC; + } else { + tmp = I915_READ(TRANS_DP_CTL(crtc->pipe)); + if (tmp & TRANS_DP_HSYNC_ACTIVE_HIGH) + flags |= DRM_MODE_FLAG_PHSYNC; + else + flags |= DRM_MODE_FLAG_NHSYNC; - if (tmp & DP_SYNC_VS_HIGH) - flags |= DRM_MODE_FLAG_PVSYNC; - else - flags |= DRM_MODE_FLAG_NVSYNC; + if (tmp & TRANS_DP_VSYNC_ACTIVE_HIGH) + flags |= DRM_MODE_FLAG_PVSYNC; + else + flags |= DRM_MODE_FLAG_NVSYNC; + } pipe_config->adjusted_mode.flags |= flags; } @@ -2681,15 +2696,16 @@ done: } static void -intel_dp_destroy(struct drm_connector *connector) +intel_dp_connector_destroy(struct drm_connector *connector) { - struct intel_dp *intel_dp = intel_attached_dp(connector); struct intel_connector *intel_connector = to_intel_connector(connector); if (!IS_ERR_OR_NULL(intel_connector->edid)) kfree(intel_connector->edid); - if (is_edp(intel_dp)) + /* Can't call is_edp() since the encoder may have been destroyed + * already. */ + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) intel_panel_fini(&intel_connector->panel); drm_sysfs_connector_remove(connector); @@ -2723,7 +2739,7 @@ static const struct drm_connector_funcs intel_dp_connector_funcs = { .detect = intel_dp_detect, .fill_modes = drm_helper_probe_single_connector_modes, .set_property = intel_dp_set_property, - .destroy = intel_dp_destroy, + .destroy = intel_dp_connector_destroy, }; static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = { @@ -2954,7 +2970,85 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, I915_READ(pp_div_reg)); } -void +static bool intel_edp_init_connector(struct intel_dp *intel_dp, + struct intel_connector *intel_connector) +{ + struct drm_connector *connector = &intel_connector->base; + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct drm_device *dev = intel_dig_port->base.base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_display_mode *fixed_mode = NULL; + struct edp_power_seq power_seq = { 0 }; + bool has_dpcd; + struct drm_display_mode *scan; + struct edid *edid; + + if (!is_edp(intel_dp)) + return true; + + intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq); + + /* Cache DPCD and EDID for edp. */ + ironlake_edp_panel_vdd_on(intel_dp); + has_dpcd = intel_dp_get_dpcd(intel_dp); + ironlake_edp_panel_vdd_off(intel_dp, false); + + if (has_dpcd) { + if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11) + dev_priv->no_aux_handshake = + intel_dp->dpcd[DP_MAX_DOWNSPREAD] & + DP_NO_AUX_HANDSHAKE_LINK_TRAINING; + } else { + /* if this fails, presume the device is a ghost */ + DRM_INFO("failed to retrieve link info, disabling eDP\n"); + return false; + } + + /* We now know it's not a ghost, init power sequence regs. */ + intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, + &power_seq); + + ironlake_edp_panel_vdd_on(intel_dp); + edid = drm_get_edid(connector, &intel_dp->adapter); + if (edid) { + if (drm_add_edid_modes(connector, edid)) { + drm_mode_connector_update_edid_property(connector, + edid); + drm_edid_to_eld(connector, edid); + } else { + kfree(edid); + edid = ERR_PTR(-EINVAL); + } + } else { + edid = ERR_PTR(-ENOENT); + } + intel_connector->edid = edid; + + /* prefer fixed mode from EDID if available */ + list_for_each_entry(scan, &connector->probed_modes, head) { + if ((scan->type & DRM_MODE_TYPE_PREFERRED)) { + fixed_mode = drm_mode_duplicate(dev, scan); + break; + } + } + + /* fallback to VBT if available for eDP */ + if (!fixed_mode && dev_priv->vbt.lfp_lvds_vbt_mode) { + fixed_mode = drm_mode_duplicate(dev, + dev_priv->vbt.lfp_lvds_vbt_mode); + if (fixed_mode) + fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; + } + + ironlake_edp_panel_vdd_off(intel_dp, false); + + intel_panel_init(&intel_connector->panel, fixed_mode); + intel_panel_setup_backlight(connector); + + return true; +} + +bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port, struct intel_connector *intel_connector) { @@ -2963,11 +3057,9 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, struct intel_encoder *intel_encoder = &intel_dig_port->base; struct drm_device *dev = intel_encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_display_mode *fixed_mode = NULL; - struct edp_power_seq power_seq = { 0 }; enum port port = intel_dig_port->port; const char *name = NULL; - int type; + int type, error; /* Preserve the current hw state. */ intel_dp->DP = I915_READ(intel_dp->output_reg); @@ -3065,74 +3157,21 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, BUG(); } - if (is_edp(intel_dp)) - intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq); - - intel_dp_i2c_init(intel_dp, intel_connector, name); - - /* Cache DPCD and EDID for edp. */ - if (is_edp(intel_dp)) { - bool ret; - struct drm_display_mode *scan; - struct edid *edid; - - ironlake_edp_panel_vdd_on(intel_dp); - ret = intel_dp_get_dpcd(intel_dp); - ironlake_edp_panel_vdd_off(intel_dp, false); - - if (ret) { - if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11) - dev_priv->no_aux_handshake = - intel_dp->dpcd[DP_MAX_DOWNSPREAD] & - DP_NO_AUX_HANDSHAKE_LINK_TRAINING; - } else { - /* if this fails, presume the device is a ghost */ - DRM_INFO("failed to retrieve link info, disabling eDP\n"); - intel_dp_encoder_destroy(&intel_encoder->base); - intel_dp_destroy(connector); - return; - } - - /* We now know it's not a ghost, init power sequence regs. */ - intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, - &power_seq); + error = intel_dp_i2c_init(intel_dp, intel_connector, name); + WARN(error, "intel_dp_i2c_init failed with error %d for port %c\n", + error, port_name(port)); - ironlake_edp_panel_vdd_on(intel_dp); - edid = drm_get_edid(connector, &intel_dp->adapter); - if (edid) { - if (drm_add_edid_modes(connector, edid)) { - drm_mode_connector_update_edid_property(connector, edid); - drm_edid_to_eld(connector, edid); - } else { - kfree(edid); - edid = ERR_PTR(-EINVAL); - } - } else { - edid = ERR_PTR(-ENOENT); + if (!intel_edp_init_connector(intel_dp, intel_connector)) { + i2c_del_adapter(&intel_dp->adapter); + if (is_edp(intel_dp)) { + cancel_delayed_work_sync(&intel_dp->panel_vdd_work); + mutex_lock(&dev->mode_config.mutex); + ironlake_panel_vdd_off_sync(intel_dp); + mutex_unlock(&dev->mode_config.mutex); } - intel_connector->edid = edid; - - /* prefer fixed mode from EDID if available */ - list_for_each_entry(scan, &connector->probed_modes, head) { - if ((scan->type & DRM_MODE_TYPE_PREFERRED)) { - fixed_mode = drm_mode_duplicate(dev, scan); - break; - } - } - - /* fallback to VBT if available for eDP */ - if (!fixed_mode && dev_priv->vbt.lfp_lvds_vbt_mode) { - fixed_mode = drm_mode_duplicate(dev, dev_priv->vbt.lfp_lvds_vbt_mode); - if (fixed_mode) - fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; - } - - ironlake_edp_panel_vdd_off(intel_dp, false); - } - - if (is_edp(intel_dp)) { - intel_panel_init(&intel_connector->panel, fixed_mode); - intel_panel_setup_backlight(connector); + drm_sysfs_connector_remove(connector); + drm_connector_cleanup(connector); + return false; } intel_dp_add_properties(intel_dp, connector); @@ -3145,6 +3184,8 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, u32 temp = I915_READ(PEG_BAND_GAP_DATA); I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd); } + + return true; } void @@ -3190,5 +3231,9 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) intel_encoder->cloneable = false; intel_encoder->hot_plug = intel_dp_hot_plug; - intel_dp_init_connector(intel_dig_port, intel_connector); + if (!intel_dp_init_connector(intel_dig_port, intel_connector)) { + drm_encoder_cleanup(encoder); + kfree(intel_dig_port); + kfree(intel_connector); + } } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index ffe9d35b37b..c8c9b6f4823 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -141,7 +141,8 @@ struct intel_encoder { bool (*get_hw_state)(struct intel_encoder *, enum pipe *pipe); /* Reconstructs the equivalent mode flags for the current hardware * state. This must be called _after_ display->get_pipe_config has - * pre-filled the pipe config. */ + * pre-filled the pipe config. Note that intel_encoder->base.crtc must + * be set correctly before calling this function. */ void (*get_config)(struct intel_encoder *, struct intel_crtc_config *pipe_config); int crtc_mask; @@ -586,7 +587,7 @@ extern void intel_lvds_init(struct drm_device *dev); extern bool intel_is_dual_link_lvds(struct drm_device *dev); extern void intel_dp_init(struct drm_device *dev, int output_reg, enum port port); -extern void intel_dp_init_connector(struct intel_digital_port *intel_dig_port, +extern bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port, struct intel_connector *intel_connector); extern void intel_dp_init_link_config(struct intel_dp *intel_dp); extern void intel_dp_start_link_train(struct intel_dp *intel_dp); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index bc12518a21b..98df2a0c85b 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -602,7 +602,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, u32 hdmi_val; hdmi_val = SDVO_ENCODING_HDMI; - if (!HAS_PCH_SPLIT(dev) && !IS_VALLEYVIEW(dev)) + if (!HAS_PCH_SPLIT(dev)) hdmi_val |= intel_hdmi->color_range; if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) hdmi_val |= SDVO_VSYNC_ACTIVE_HIGH; diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 79be7cfd315..cfb8fb68f09 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -311,8 +311,8 @@ static void intel_didl_outputs(struct drm_device *dev) list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) { if (i >= 8) { - dev_printk(KERN_ERR, &dev->pdev->dev, - "More than 8 outputs detected via ACPI\n"); + dev_dbg(&dev->pdev->dev, + "More than 8 outputs detected via ACPI\n"); return; } status = @@ -338,8 +338,8 @@ blind_set: list_for_each_entry(connector, &dev->mode_config.connector_list, head) { int output_type = ACPI_OTHER_OUTPUT; if (i >= 8) { - dev_printk(KERN_ERR, &dev->pdev->dev, - "More than 8 outputs in connector list\n"); + dev_dbg(&dev->pdev->dev, + "More than 8 outputs in connector list\n"); return; } switch (connector->connector_type) { diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index b27bda07f4a..ccbdd83f522 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3069,26 +3069,17 @@ void gen6_set_rps(struct drm_device *dev, u8 val) trace_intel_gpu_freq_change(val * 50); } -void valleyview_set_rps(struct drm_device *dev, u8 val) +/* + * Wait until the previous freq change has completed, + * or the timeout elapsed, and then update our notion + * of the current GPU frequency. + */ +static void vlv_update_rps_cur_delay(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; unsigned long timeout = jiffies + msecs_to_jiffies(10); - u32 limits = gen6_rps_limits(dev_priv, &val); u32 pval; WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); - WARN_ON(val > dev_priv->rps.max_delay); - WARN_ON(val < dev_priv->rps.min_delay); - - DRM_DEBUG_DRIVER("gpu freq request from %d to %d\n", - vlv_gpu_freq(dev_priv->mem_freq, - dev_priv->rps.cur_delay), - vlv_gpu_freq(dev_priv->mem_freq, val)); - - if (val == dev_priv->rps.cur_delay) - return; - - vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val); do { pval = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS); @@ -3099,17 +3090,41 @@ void valleyview_set_rps(struct drm_device *dev, u8 val) udelay(10); } while (pval & 1); - pval = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS); - if ((pval >> 8) != val) - DRM_DEBUG_DRIVER("punit overrode freq: %d requested, but got %d\n", - val, pval >> 8); + pval >>= 8; - /* Make sure we continue to get interrupts - * until we hit the minimum or maximum frequencies. - */ - I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, limits); + if (pval != dev_priv->rps.cur_delay) + DRM_DEBUG_DRIVER("Punit overrode GPU freq: %d MHz (%u) requested, but got %d Mhz (%u)\n", + vlv_gpu_freq(dev_priv->mem_freq, dev_priv->rps.cur_delay), + dev_priv->rps.cur_delay, + vlv_gpu_freq(dev_priv->mem_freq, pval), pval); + + dev_priv->rps.cur_delay = pval; +} + +void valleyview_set_rps(struct drm_device *dev, u8 val) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + gen6_rps_limits(dev_priv, &val); - dev_priv->rps.cur_delay = pval >> 8; + WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); + WARN_ON(val > dev_priv->rps.max_delay); + WARN_ON(val < dev_priv->rps.min_delay); + + vlv_update_rps_cur_delay(dev_priv); + + DRM_DEBUG_DRIVER("GPU freq request from %d MHz (%u) to %d MHz (%u)\n", + vlv_gpu_freq(dev_priv->mem_freq, + dev_priv->rps.cur_delay), + dev_priv->rps.cur_delay, + vlv_gpu_freq(dev_priv->mem_freq, val), val); + + if (val == dev_priv->rps.cur_delay) + return; + + vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val); + + dev_priv->rps.cur_delay = val; trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv->mem_freq, val)); } @@ -3446,7 +3461,8 @@ static void vlv_rps_timer_work(struct work_struct *work) * min freq available. */ mutex_lock(&dev_priv->rps.hw_lock); - valleyview_set_rps(dev_priv->dev, dev_priv->rps.rpe_delay); + if (dev_priv->rps.cur_delay > dev_priv->rps.rpe_delay) + valleyview_set_rps(dev_priv->dev, dev_priv->rps.rpe_delay); mutex_unlock(&dev_priv->rps.hw_lock); } @@ -3496,7 +3512,7 @@ static void valleyview_enable_rps(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_ring_buffer *ring; - u32 gtfifodbg, val, rpe; + u32 gtfifodbg, val; int i; WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); @@ -3557,31 +3573,39 @@ static void valleyview_enable_rps(struct drm_device *dev) DRM_DEBUG_DRIVER("GPLL enabled? %s\n", val & 0x10 ? "yes" : "no"); DRM_DEBUG_DRIVER("GPU status: 0x%08x\n", val); - DRM_DEBUG_DRIVER("current GPU freq: %d\n", - vlv_gpu_freq(dev_priv->mem_freq, (val >> 8) & 0xff)); dev_priv->rps.cur_delay = (val >> 8) & 0xff; + DRM_DEBUG_DRIVER("current GPU freq: %d MHz (%u)\n", + vlv_gpu_freq(dev_priv->mem_freq, + dev_priv->rps.cur_delay), + dev_priv->rps.cur_delay); dev_priv->rps.max_delay = valleyview_rps_max_freq(dev_priv); dev_priv->rps.hw_max = dev_priv->rps.max_delay; - DRM_DEBUG_DRIVER("max GPU freq: %d\n", vlv_gpu_freq(dev_priv->mem_freq, - dev_priv->rps.max_delay)); + DRM_DEBUG_DRIVER("max GPU freq: %d MHz (%u)\n", + vlv_gpu_freq(dev_priv->mem_freq, + dev_priv->rps.max_delay), + dev_priv->rps.max_delay); - rpe = valleyview_rps_rpe_freq(dev_priv); - DRM_DEBUG_DRIVER("RPe GPU freq: %d\n", - vlv_gpu_freq(dev_priv->mem_freq, rpe)); - dev_priv->rps.rpe_delay = rpe; + dev_priv->rps.rpe_delay = valleyview_rps_rpe_freq(dev_priv); + DRM_DEBUG_DRIVER("RPe GPU freq: %d MHz (%u)\n", + vlv_gpu_freq(dev_priv->mem_freq, + dev_priv->rps.rpe_delay), + dev_priv->rps.rpe_delay); - val = valleyview_rps_min_freq(dev_priv); - DRM_DEBUG_DRIVER("min GPU freq: %d\n", vlv_gpu_freq(dev_priv->mem_freq, - val)); - dev_priv->rps.min_delay = val; + dev_priv->rps.min_delay = valleyview_rps_min_freq(dev_priv); + DRM_DEBUG_DRIVER("min GPU freq: %d MHz (%u)\n", + vlv_gpu_freq(dev_priv->mem_freq, + dev_priv->rps.min_delay), + dev_priv->rps.min_delay); - DRM_DEBUG_DRIVER("setting GPU freq to %d\n", - vlv_gpu_freq(dev_priv->mem_freq, rpe)); + DRM_DEBUG_DRIVER("setting GPU freq to %d MHz (%u)\n", + vlv_gpu_freq(dev_priv->mem_freq, + dev_priv->rps.rpe_delay), + dev_priv->rps.rpe_delay); INIT_DELAYED_WORK(&dev_priv->rps.vlv_work, vlv_rps_timer_work); - valleyview_set_rps(dev_priv->dev, rpe); + valleyview_set_rps(dev_priv->dev, dev_priv->rps.rpe_delay); /* requires MSI enabled */ I915_WRITE(GEN6_PMIER, GEN6_PM_RPS_EVENTS); @@ -4834,10 +4858,6 @@ static void valleyview_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN7_ROW_CHICKEN2, _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE)); - /* WaForceL3Serialization:vlv */ - I915_WRITE(GEN7_L3SQCREG4, I915_READ(GEN7_L3SQCREG4) & - ~L3SQ_URB_READ_CAM_MATCH_DISABLE); - /* This is required by WaCatErrorRejectionIssue:vlv */ I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG, I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) | |