i830_irq.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /* i830_dma.c -- DMA support for the I830 -*- linux-c -*-
  2. *
  3. * Copyright 2002 Tungsten Graphics, Inc.
  4. * All Rights Reserved.
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a
  7. * copy of this software and associated documentation files (the "Software"),
  8. * to deal in the Software without restriction, including without limitation
  9. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  10. * and/or sell copies of the Software, and to permit persons to whom the
  11. * Software is furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice (including the next
  14. * paragraph) shall be included in all copies or substantial portions of the
  15. * Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  20. * TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  21. * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  22. * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  23. * DEALINGS IN THE SOFTWARE.
  24. *
  25. * Authors: Keith Whitwell <keith@tungstengraphics.com>
  26. *
  27. */
  28. #include "drmP.h"
  29. #include "drm.h"
  30. #include "i830_drm.h"
  31. #include "i830_drv.h"
  32. #include <linux/interrupt.h> /* For task queue support */
  33. #include <linux/delay.h>
  34. irqreturn_t i830_driver_irq_handler(DRM_IRQ_ARGS)
  35. {
  36. struct drm_device *dev = (struct drm_device *) arg;
  37. drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
  38. u16 temp;
  39. temp = I830_READ16(I830REG_INT_IDENTITY_R);
  40. DRM_DEBUG("%x\n", temp);
  41. if (!(temp & 2))
  42. return IRQ_NONE;
  43. I830_WRITE16(I830REG_INT_IDENTITY_R, temp);
  44. atomic_inc(&dev_priv->irq_received);
  45. wake_up_interruptible(&dev_priv->irq_queue);
  46. return IRQ_HANDLED;
  47. }
  48. static int i830_emit_irq(struct drm_device * dev)
  49. {
  50. drm_i830_private_t *dev_priv = dev->dev_private;
  51. RING_LOCALS;
  52. DRM_DEBUG("%s\n", __func__);
  53. atomic_inc(&dev_priv->irq_emitted);
  54. BEGIN_LP_RING(2);
  55. OUT_RING(0);
  56. OUT_RING(GFX_OP_USER_INTERRUPT);
  57. ADVANCE_LP_RING();
  58. return atomic_read(&dev_priv->irq_emitted);
  59. }
  60. static int i830_wait_irq(struct drm_device * dev, int irq_nr)
  61. {
  62. drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
  63. DECLARE_WAITQUEUE(entry, current);
  64. unsigned long end = jiffies + HZ * 3;
  65. int ret = 0;
  66. DRM_DEBUG("%s\n", __func__);
  67. if (atomic_read(&dev_priv->irq_received) >= irq_nr)
  68. return 0;
  69. dev_priv->sarea_priv->perf_boxes |= I830_BOX_WAIT;
  70. add_wait_queue(&dev_priv->irq_queue, &entry);
  71. for (;;) {
  72. __set_current_state(TASK_INTERRUPTIBLE);
  73. if (atomic_read(&dev_priv->irq_received) >= irq_nr)
  74. break;
  75. if ((signed)(end - jiffies) <= 0) {
  76. DRM_ERROR("timeout iir %x imr %x ier %x hwstam %x\n",
  77. I830_READ16(I830REG_INT_IDENTITY_R),
  78. I830_READ16(I830REG_INT_MASK_R),
  79. I830_READ16(I830REG_INT_ENABLE_R),
  80. I830_READ16(I830REG_HWSTAM));
  81. ret = -EBUSY; /* Lockup? Missed irq? */
  82. break;
  83. }
  84. schedule_timeout(HZ * 3);
  85. if (signal_pending(current)) {
  86. ret = -EINTR;
  87. break;
  88. }
  89. }
  90. __set_current_state(TASK_RUNNING);
  91. remove_wait_queue(&dev_priv->irq_queue, &entry);
  92. return ret;
  93. }
  94. /* Needs the lock as it touches the ring.
  95. */
  96. int i830_irq_emit(struct drm_device *dev, void *data,
  97. struct drm_file *file_priv)
  98. {
  99. drm_i830_private_t *dev_priv = dev->dev_private;
  100. drm_i830_irq_emit_t *emit = data;
  101. int result;
  102. LOCK_TEST_WITH_RETURN(dev, file_priv);
  103. if (!dev_priv) {
  104. DRM_ERROR("%s called with no initialization\n", __func__);
  105. return -EINVAL;
  106. }
  107. result = i830_emit_irq(dev);
  108. if (copy_to_user(emit->irq_seq, &result, sizeof(int))) {
  109. DRM_ERROR("copy_to_user\n");
  110. return -EFAULT;
  111. }
  112. return 0;
  113. }
  114. /* Doesn't need the hardware lock.
  115. */
  116. int i830_irq_wait(struct drm_device *dev, void *data,
  117. struct drm_file *file_priv)
  118. {
  119. drm_i830_private_t *dev_priv = dev->dev_private;
  120. drm_i830_irq_wait_t *irqwait = data;
  121. if (!dev_priv) {
  122. DRM_ERROR("%s called with no initialization\n", __func__);
  123. return -EINVAL;
  124. }
  125. return i830_wait_irq(dev, irqwait->irq_seq);
  126. }
  127. /* drm_dma.h hooks
  128. */
  129. void i830_driver_irq_preinstall(struct drm_device * dev)
  130. {
  131. drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
  132. I830_WRITE16(I830REG_HWSTAM, 0xffff);
  133. I830_WRITE16(I830REG_INT_MASK_R, 0x0);
  134. I830_WRITE16(I830REG_INT_ENABLE_R, 0x0);
  135. atomic_set(&dev_priv->irq_received, 0);
  136. atomic_set(&dev_priv->irq_emitted, 0);
  137. init_waitqueue_head(&dev_priv->irq_queue);
  138. }
  139. void i830_driver_irq_postinstall(struct drm_device * dev)
  140. {
  141. drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
  142. I830_WRITE16(I830REG_INT_ENABLE_R, 0x2);
  143. }
  144. void i830_driver_irq_uninstall(struct drm_device * dev)
  145. {
  146. drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
  147. if (!dev_priv)
  148. return;
  149. I830_WRITE16(I830REG_INT_MASK_R, 0xffff);
  150. I830_WRITE16(I830REG_INT_ENABLE_R, 0x0);
  151. }