aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915')
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c1
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h4
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c6
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c79
4 files changed, 77 insertions, 13 deletions
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 14d679ab52b7..93630669c6dc 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1737,6 +1737,7 @@ int i915_driver_unload(struct drm_device *dev)
1737 intel_teardown_mchbar(dev); 1737 intel_teardown_mchbar(dev);
1738 1738
1739 destroy_workqueue(dev_priv->wq); 1739 destroy_workqueue(dev_priv->wq);
1740 pm_qos_remove_request(&dev_priv->pm_qos);
1740 1741
1741 if (dev_priv->slab) 1742 if (dev_priv->slab)
1742 kmem_cache_destroy(dev_priv->slab); 1743 kmem_cache_destroy(dev_priv->slab);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 3843383e13cc..a00ee3da632f 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -40,6 +40,7 @@
40#include <linux/backlight.h> 40#include <linux/backlight.h>
41#include <linux/intel-iommu.h> 41#include <linux/intel-iommu.h>
42#include <linux/kref.h> 42#include <linux/kref.h>
43#include <linux/pm_qos.h>
43 44
44/* General customization: 45/* General customization:
45 */ 46 */
@@ -665,6 +666,9 @@ typedef struct drm_i915_private {
665 /* protects the irq masks */ 666 /* protects the irq masks */
666 spinlock_t irq_lock; 667 spinlock_t irq_lock;
667 668
669 /* To control wakeup latency, e.g. for irq-driven dp aux transfers. */
670 struct pm_qos_request pm_qos;
671
668 /* DPIO indirect register protection */ 672 /* DPIO indirect register protection */
669 spinlock_t dpio_lock; 673 spinlock_t dpio_lock;
670 674
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 1e245e501e5a..58bb11b58796 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -536,7 +536,11 @@ static void gmbus_irq_handler(struct drm_device *dev)
536 536
537static void dp_aux_irq_handler(struct drm_device *dev) 537static void dp_aux_irq_handler(struct drm_device *dev)
538{ 538{
539 struct drm_i915_private *dev_priv = (drm_i915_private_t *) dev->dev_private;
540
539 DRM_DEBUG_DRIVER("AUX channel interrupt\n"); 541 DRM_DEBUG_DRIVER("AUX channel interrupt\n");
542
543 wake_up_all(&dev_priv->gmbus_wait_queue);
540} 544}
541 545
542static irqreturn_t valleyview_irq_handler(int irq, void *arg) 546static irqreturn_t valleyview_irq_handler(int irq, void *arg)
@@ -2732,6 +2736,8 @@ void intel_irq_init(struct drm_device *dev)
2732 setup_timer(&dev_priv->hangcheck_timer, i915_hangcheck_elapsed, 2736 setup_timer(&dev_priv->hangcheck_timer, i915_hangcheck_elapsed,
2733 (unsigned long) dev); 2737 (unsigned long) dev);
2734 2738
2739 pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, 0);
2740
2735 dev->driver->get_vblank_counter = i915_get_vblank_counter; 2741 dev->driver->get_vblank_counter = i915_get_vblank_counter;
2736 dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ 2742 dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
2737 if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { 2743 if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index b51043e651b5..ada1b316195c 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -322,6 +322,48 @@ intel_dp_check_edp(struct intel_dp *intel_dp)
322 } 322 }
323} 323}
324 324
325static uint32_t
326intel_dp_aux_wait_done(struct intel_dp *intel_dp, bool has_aux_irq)
327{
328 struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
329 struct drm_device *dev = intel_dig_port->base.base.dev;
330 struct drm_i915_private *dev_priv = dev->dev_private;
331 uint32_t ch_ctl = intel_dp->output_reg + 0x10;
332 uint32_t status;
333 bool done;
334
335 if (IS_HASWELL(dev)) {
336 switch (intel_dig_port->port) {
337 case PORT_A:
338 ch_ctl = DPA_AUX_CH_CTL;
339 break;
340 case PORT_B:
341 ch_ctl = PCH_DPB_AUX_CH_CTL;
342 break;
343 case PORT_C:
344 ch_ctl = PCH_DPC_AUX_CH_CTL;
345 break;
346 case PORT_D:
347 ch_ctl = PCH_DPD_AUX_CH_CTL;
348 break;
349 default:
350 BUG();
351 }
352 }
353
354#define C (((status = I915_READ(ch_ctl)) & DP_AUX_CH_CTL_SEND_BUSY) == 0)
355 if (has_aux_irq)
356 done = wait_event_timeout(dev_priv->gmbus_wait_queue, C, 10);
357 else
358 done = wait_for_atomic(C, 10) == 0;
359 if (!done)
360 DRM_ERROR("dp aux hw did not signal timeout (has irq: %i)!\n",
361 has_aux_irq);
362#undef C
363
364 return status;
365}
366
325static int 367static int
326intel_dp_aux_ch(struct intel_dp *intel_dp, 368intel_dp_aux_ch(struct intel_dp *intel_dp,
327 uint8_t *send, int send_bytes, 369 uint8_t *send, int send_bytes,
@@ -333,11 +375,17 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
333 struct drm_i915_private *dev_priv = dev->dev_private; 375 struct drm_i915_private *dev_priv = dev->dev_private;
334 uint32_t ch_ctl = output_reg + 0x10; 376 uint32_t ch_ctl = output_reg + 0x10;
335 uint32_t ch_data = ch_ctl + 4; 377 uint32_t ch_data = ch_ctl + 4;
336 int i; 378 int i, ret, recv_bytes;
337 int recv_bytes;
338 uint32_t status; 379 uint32_t status;
339 uint32_t aux_clock_divider; 380 uint32_t aux_clock_divider;
340 int try, precharge; 381 int try, precharge;
382 bool has_aux_irq = INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev);
383
384 /* dp aux is extremely sensitive to irq latency, hence request the
385 * lowest possible wakeup latency and so prevent the cpu from going into
386 * deep sleep states.
387 */
388 pm_qos_update_request(&dev_priv->pm_qos, 0);
341 389
342 if (IS_HASWELL(dev)) { 390 if (IS_HASWELL(dev)) {
343 switch (intel_dig_port->port) { 391 switch (intel_dig_port->port) {
@@ -400,7 +448,8 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
400 if (try == 3) { 448 if (try == 3) {
401 WARN(1, "dp_aux_ch not started status 0x%08x\n", 449 WARN(1, "dp_aux_ch not started status 0x%08x\n",
402 I915_READ(ch_ctl)); 450 I915_READ(ch_ctl));
403 return -EBUSY; 451 ret = -EBUSY;
452 goto out;
404 } 453 }
405 454
406 /* Must try at least 3 times according to DP spec */ 455 /* Must try at least 3 times according to DP spec */
@@ -413,6 +462,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
413 /* Send the command and wait for it to complete */ 462 /* Send the command and wait for it to complete */
414 I915_WRITE(ch_ctl, 463 I915_WRITE(ch_ctl,
415 DP_AUX_CH_CTL_SEND_BUSY | 464 DP_AUX_CH_CTL_SEND_BUSY |
465 (has_aux_irq ? DP_AUX_CH_CTL_INTERRUPT : 0) |
416 DP_AUX_CH_CTL_TIME_OUT_400us | 466 DP_AUX_CH_CTL_TIME_OUT_400us |
417 (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) | 467 (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
418 (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) | 468 (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
@@ -420,12 +470,8 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
420 DP_AUX_CH_CTL_DONE | 470 DP_AUX_CH_CTL_DONE |
421 DP_AUX_CH_CTL_TIME_OUT_ERROR | 471 DP_AUX_CH_CTL_TIME_OUT_ERROR |
422 DP_AUX_CH_CTL_RECEIVE_ERROR); 472 DP_AUX_CH_CTL_RECEIVE_ERROR);
423 for (;;) { 473
424 status = I915_READ(ch_ctl); 474 status = intel_dp_aux_wait_done(intel_dp, has_aux_irq);
425 if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0)
426 break;
427 udelay(100);
428 }
429 475
430 /* Clear done status and any errors */ 476 /* Clear done status and any errors */
431 I915_WRITE(ch_ctl, 477 I915_WRITE(ch_ctl,
@@ -443,7 +489,8 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
443 489
444 if ((status & DP_AUX_CH_CTL_DONE) == 0) { 490 if ((status & DP_AUX_CH_CTL_DONE) == 0) {
445 DRM_ERROR("dp_aux_ch not done status 0x%08x\n", status); 491 DRM_ERROR("dp_aux_ch not done status 0x%08x\n", status);
446 return -EBUSY; 492 ret = -EBUSY;
493 goto out;
447 } 494 }
448 495
449 /* Check for timeout or receive error. 496 /* Check for timeout or receive error.
@@ -451,14 +498,16 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
451 */ 498 */
452 if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) { 499 if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
453 DRM_ERROR("dp_aux_ch receive error status 0x%08x\n", status); 500 DRM_ERROR("dp_aux_ch receive error status 0x%08x\n", status);
454 return -EIO; 501 ret = -EIO;
502 goto out;
455 } 503 }
456 504
457 /* Timeouts occur when the device isn't connected, so they're 505 /* Timeouts occur when the device isn't connected, so they're
458 * "normal" -- don't fill the kernel log with these */ 506 * "normal" -- don't fill the kernel log with these */
459 if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR) { 507 if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR) {
460 DRM_DEBUG_KMS("dp_aux_ch timeout status 0x%08x\n", status); 508 DRM_DEBUG_KMS("dp_aux_ch timeout status 0x%08x\n", status);
461 return -ETIMEDOUT; 509 ret = -ETIMEDOUT;
510 goto out;
462 } 511 }
463 512
464 /* Unload any bytes sent back from the other side */ 513 /* Unload any bytes sent back from the other side */
@@ -471,7 +520,11 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
471 unpack_aux(I915_READ(ch_data + i), 520 unpack_aux(I915_READ(ch_data + i),
472 recv + i, recv_bytes - i); 521 recv + i, recv_bytes - i);
473 522
474 return recv_bytes; 523 ret = recv_bytes;
524out:
525 pm_qos_update_request(&dev_priv->pm_qos, PM_QOS_DEFAULT_VALUE);
526
527 return ret;
475} 528}
476 529
477/* Write data to the aux channel in native mode */ 530/* Write data to the aux channel in native mode */