/drivers/char/drm/i830_irq.c

https://bitbucket.org/evzijst/gittest · C · 204 lines · 128 code · 43 blank · 33 comment · 12 complexity · 9e916a159b365df33943b2d34f2de6d5 MD5 · raw file

  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. 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. 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. }