i830_irq.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  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. drm_device_t *dev = (drm_device_t *)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(drm_device_t *dev)
  49. {
  50. drm_i830_private_t *dev_priv = dev->dev_private;
  51. RING_LOCALS;
  52. DRM_DEBUG("%s\n", __FUNCTION__);
  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(drm_device_t *dev, int irq_nr)
  61. {
  62. drm_i830_private_t *dev_priv =
  63. (drm_i830_private_t *)dev->dev_private;
  64. DECLARE_WAITQUEUE(entry, current);
  65. unsigned long end = jiffies + HZ*3;
  66. int ret = 0;
  67. DRM_DEBUG("%s\n", __FUNCTION__);
  68. if (atomic_read(&dev_priv->irq_received) >= irq_nr)
  69. return 0;
  70. dev_priv->sarea_priv->perf_boxes |= I830_BOX_WAIT;
  71. add_wait_queue(&dev_priv->irq_queue, &entry);
  72. for (;;) {
  73. __set_current_state(TASK_INTERRUPTIBLE);
  74. if (atomic_read(&dev_priv->irq_received) >= irq_nr)
  75. break;
  76. if((signed)(end - jiffies) <= 0) {
  77. DRM_ERROR("timeout iir %x imr %x ier %x hwstam %x\n",
  78. I830_READ16( I830REG_INT_IDENTITY_R ),
  79. I830_READ16( I830REG_INT_MASK_R ),
  80. I830_READ16( I830REG_INT_ENABLE_R ),
  81. I830_READ16( I830REG_HWSTAM ));
  82. ret = -EBUSY; /* Lockup? Missed irq? */
  83. break;
  84. }
  85. schedule_timeout(HZ*3);
  86. if (signal_pending(current)) {
  87. ret = -EINTR;
  88. break;
  89. }
  90. }
  91. __set_current_state(TASK_RUNNING);
  92. remove_wait_queue(&dev_priv->irq_queue, &entry);
  93. return ret;
  94. }
  95. /* Needs the lock as it touches the ring.
  96. */
  97. int i830_irq_emit( struct inode *inode, struct file *filp, unsigned int cmd,
  98. unsigned long arg )
  99. {
  100. drm_file_t *priv = filp->private_data;
  101. drm_device_t *dev = priv->head->dev;
  102. drm_i830_private_t *dev_priv = dev->dev_private;
  103. drm_i830_irq_emit_t emit;
  104. int result;
  105. LOCK_TEST_WITH_RETURN(dev, filp);
  106. if ( !dev_priv ) {
  107. DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
  108. return -EINVAL;
  109. }
  110. if (copy_from_user( &emit, (drm_i830_irq_emit_t __user *)arg, sizeof(emit) ))
  111. return -EFAULT;
  112. result = i830_emit_irq( dev );
  113. if ( copy_to_user( emit.irq_seq, &result, sizeof(int) ) ) {
  114. DRM_ERROR( "copy_to_user\n" );
  115. return -EFAULT;
  116. }
  117. return 0;
  118. }
  119. /* Doesn't need the hardware lock.
  120. */
  121. int i830_irq_wait( struct inode *inode, struct file *filp, unsigned int cmd,
  122. unsigned long arg )
  123. {
  124. drm_file_t *priv = filp->private_data;
  125. drm_device_t *dev = priv->head->dev;
  126. drm_i830_private_t *dev_priv = dev->dev_private;
  127. drm_i830_irq_wait_t irqwait;
  128. if ( !dev_priv ) {
  129. DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
  130. return -EINVAL;
  131. }
  132. if (copy_from_user( &irqwait, (drm_i830_irq_wait_t __user *)arg,
  133. sizeof(irqwait) ))
  134. return -EFAULT;
  135. return i830_wait_irq( dev, irqwait.irq_seq );
  136. }
  137. /* drm_dma.h hooks
  138. */
  139. void i830_driver_irq_preinstall( drm_device_t *dev ) {
  140. drm_i830_private_t *dev_priv =
  141. (drm_i830_private_t *)dev->dev_private;
  142. I830_WRITE16( I830REG_HWSTAM, 0xffff );
  143. I830_WRITE16( I830REG_INT_MASK_R, 0x0 );
  144. I830_WRITE16( I830REG_INT_ENABLE_R, 0x0 );
  145. atomic_set(&dev_priv->irq_received, 0);
  146. atomic_set(&dev_priv->irq_emitted, 0);
  147. init_waitqueue_head(&dev_priv->irq_queue);
  148. }
  149. void i830_driver_irq_postinstall( drm_device_t *dev ) {
  150. drm_i830_private_t *dev_priv =
  151. (drm_i830_private_t *)dev->dev_private;
  152. I830_WRITE16( I830REG_INT_ENABLE_R, 0x2 );
  153. }
  154. void i830_driver_irq_uninstall( drm_device_t *dev ) {
  155. drm_i830_private_t *dev_priv =
  156. (drm_i830_private_t *)dev->dev_private;
  157. if (!dev_priv)
  158. return;
  159. I830_WRITE16( I830REG_INT_MASK_R, 0xffff );
  160. I830_WRITE16( I830REG_INT_ENABLE_R, 0x0 );
  161. }