gamma_lists.h 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. /* drm_lists.h -- Buffer list handling routines -*- linux-c -*-
  2. * Created: Mon Apr 19 20:54:22 1999 by faith@valinux.com
  3. *
  4. * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
  5. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  6. * All Rights Reserved.
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a
  9. * copy of this software and associated documentation files (the "Software"),
  10. * to deal in the Software without restriction, including without limitation
  11. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  12. * and/or sell copies of the Software, and to permit persons to whom the
  13. * Software is furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice (including the next
  16. * paragraph) shall be included in all copies or substantial portions of the
  17. * Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  22. * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  23. * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  24. * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  25. * OTHER DEALINGS IN THE SOFTWARE.
  26. *
  27. * Authors:
  28. * Rickard E. (Rik) Faith <faith@valinux.com>
  29. * Gareth Hughes <gareth@valinux.com>
  30. */
  31. #include "drmP.h"
  32. int DRM(waitlist_create)(drm_waitlist_t *bl, int count)
  33. {
  34. if (bl->count) return -EINVAL;
  35. bl->bufs = DRM(alloc)((bl->count + 2) * sizeof(*bl->bufs),
  36. DRM_MEM_BUFLISTS);
  37. if(!bl->bufs) return -ENOMEM;
  38. memset(bl->bufs, 0, sizeof(*bl->bufs));
  39. bl->count = count;
  40. bl->rp = bl->bufs;
  41. bl->wp = bl->bufs;
  42. bl->end = &bl->bufs[bl->count+1];
  43. spin_lock_init(&bl->write_lock);
  44. spin_lock_init(&bl->read_lock);
  45. return 0;
  46. }
  47. int DRM(waitlist_destroy)(drm_waitlist_t *bl)
  48. {
  49. if (bl->rp != bl->wp) return -EINVAL;
  50. if (bl->bufs) DRM(free)(bl->bufs,
  51. (bl->count + 2) * sizeof(*bl->bufs),
  52. DRM_MEM_BUFLISTS);
  53. bl->count = 0;
  54. bl->bufs = NULL;
  55. bl->rp = NULL;
  56. bl->wp = NULL;
  57. bl->end = NULL;
  58. return 0;
  59. }
  60. int DRM(waitlist_put)(drm_waitlist_t *bl, drm_buf_t *buf)
  61. {
  62. int left;
  63. unsigned long flags;
  64. left = DRM_LEFTCOUNT(bl);
  65. if (!left) {
  66. DRM_ERROR("Overflow while adding buffer %d from filp %p\n",
  67. buf->idx, buf->filp);
  68. return -EINVAL;
  69. }
  70. buf->list = DRM_LIST_WAIT;
  71. spin_lock_irqsave(&bl->write_lock, flags);
  72. *bl->wp = buf;
  73. if (++bl->wp >= bl->end) bl->wp = bl->bufs;
  74. spin_unlock_irqrestore(&bl->write_lock, flags);
  75. return 0;
  76. }
  77. drm_buf_t *DRM(waitlist_get)(drm_waitlist_t *bl)
  78. {
  79. drm_buf_t *buf;
  80. unsigned long flags;
  81. spin_lock_irqsave(&bl->read_lock, flags);
  82. buf = *bl->rp;
  83. if (bl->rp == bl->wp) {
  84. spin_unlock_irqrestore(&bl->read_lock, flags);
  85. return NULL;
  86. }
  87. if (++bl->rp >= bl->end) bl->rp = bl->bufs;
  88. spin_unlock_irqrestore(&bl->read_lock, flags);
  89. return buf;
  90. }
  91. int DRM(freelist_create)(drm_freelist_t *bl, int count)
  92. {
  93. atomic_set(&bl->count, 0);
  94. bl->next = NULL;
  95. init_waitqueue_head(&bl->waiting);
  96. bl->low_mark = 0;
  97. bl->high_mark = 0;
  98. atomic_set(&bl->wfh, 0);
  99. spin_lock_init(&bl->lock);
  100. ++bl->initialized;
  101. return 0;
  102. }
  103. int DRM(freelist_destroy)(drm_freelist_t *bl)
  104. {
  105. atomic_set(&bl->count, 0);
  106. bl->next = NULL;
  107. return 0;
  108. }
  109. int DRM(freelist_put)(drm_device_t *dev, drm_freelist_t *bl, drm_buf_t *buf)
  110. {
  111. drm_device_dma_t *dma = dev->dma;
  112. if (!dma) {
  113. DRM_ERROR("No DMA support\n");
  114. return 1;
  115. }
  116. if (buf->waiting || buf->pending || buf->list == DRM_LIST_FREE) {
  117. DRM_ERROR("Freed buffer %d: w%d, p%d, l%d\n",
  118. buf->idx, buf->waiting, buf->pending, buf->list);
  119. }
  120. if (!bl) return 1;
  121. buf->list = DRM_LIST_FREE;
  122. spin_lock(&bl->lock);
  123. buf->next = bl->next;
  124. bl->next = buf;
  125. spin_unlock(&bl->lock);
  126. atomic_inc(&bl->count);
  127. if (atomic_read(&bl->count) > dma->buf_count) {
  128. DRM_ERROR("%d of %d buffers free after addition of %d\n",
  129. atomic_read(&bl->count), dma->buf_count, buf->idx);
  130. return 1;
  131. }
  132. /* Check for high water mark */
  133. if (atomic_read(&bl->wfh) && atomic_read(&bl->count)>=bl->high_mark) {
  134. atomic_set(&bl->wfh, 0);
  135. wake_up_interruptible(&bl->waiting);
  136. }
  137. return 0;
  138. }
  139. static drm_buf_t *DRM(freelist_try)(drm_freelist_t *bl)
  140. {
  141. drm_buf_t *buf;
  142. if (!bl) return NULL;
  143. /* Get buffer */
  144. spin_lock(&bl->lock);
  145. if (!bl->next) {
  146. spin_unlock(&bl->lock);
  147. return NULL;
  148. }
  149. buf = bl->next;
  150. bl->next = bl->next->next;
  151. spin_unlock(&bl->lock);
  152. atomic_dec(&bl->count);
  153. buf->next = NULL;
  154. buf->list = DRM_LIST_NONE;
  155. if (buf->waiting || buf->pending) {
  156. DRM_ERROR("Free buffer %d: w%d, p%d, l%d\n",
  157. buf->idx, buf->waiting, buf->pending, buf->list);
  158. }
  159. return buf;
  160. }
  161. drm_buf_t *DRM(freelist_get)(drm_freelist_t *bl, int block)
  162. {
  163. drm_buf_t *buf = NULL;
  164. DECLARE_WAITQUEUE(entry, current);
  165. if (!bl || !bl->initialized) return NULL;
  166. /* Check for low water mark */
  167. if (atomic_read(&bl->count) <= bl->low_mark) /* Became low */
  168. atomic_set(&bl->wfh, 1);
  169. if (atomic_read(&bl->wfh)) {
  170. if (block) {
  171. add_wait_queue(&bl->waiting, &entry);
  172. for (;;) {
  173. current->state = TASK_INTERRUPTIBLE;
  174. if (!atomic_read(&bl->wfh)
  175. && (buf = DRM(freelist_try)(bl))) break;
  176. schedule();
  177. if (signal_pending(current)) break;
  178. }
  179. current->state = TASK_RUNNING;
  180. remove_wait_queue(&bl->waiting, &entry);
  181. }
  182. return buf;
  183. }
  184. return DRM(freelist_try)(bl);
  185. }