gamma_dma.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:15k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* gamma_dma.c -- DMA support for GMX 2000 -*- linux-c -*-
  2.  * Created: Fri Mar 19 14:30:16 1999 by faith@precisioninsight.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.  * PRECISION INSIGHT 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 OTHER
  25.  * DEALINGS IN THE SOFTWARE.
  26.  *
  27.  * Authors:
  28.  *    Rickard E. (Rik) Faith <faith@valinux.com>
  29.  *
  30.  */
  31. #include "gamma.h"
  32. #include "drmP.h"
  33. #include "gamma_drv.h"
  34. #include <linux/interrupt.h> /* For task queue support */
  35. #include <linux/delay.h>
  36. static inline void gamma_dma_dispatch(drm_device_t *dev, unsigned long address,
  37.       unsigned long length)
  38. {
  39. drm_gamma_private_t *dev_priv =
  40. (drm_gamma_private_t *)dev->dev_private;
  41. GAMMA_WRITE(GAMMA_DMAADDRESS, virt_to_phys((void *)address));
  42. while (GAMMA_READ(GAMMA_GCOMMANDSTATUS) != 4)
  43. ;
  44. GAMMA_WRITE(GAMMA_DMACOUNT, length / 4);
  45. }
  46. void gamma_dma_quiescent_single(drm_device_t *dev)
  47. {
  48. drm_gamma_private_t *dev_priv =
  49. (drm_gamma_private_t *)dev->dev_private;
  50. while (GAMMA_READ(GAMMA_DMACOUNT))
  51. ;
  52. while (GAMMA_READ(GAMMA_INFIFOSPACE) < 3)
  53. ;
  54. GAMMA_WRITE(GAMMA_FILTERMODE, 1 << 10);
  55. GAMMA_WRITE(GAMMA_SYNC, 0);
  56. do {
  57. while (!GAMMA_READ(GAMMA_OUTFIFOWORDS))
  58. ;
  59. } while (GAMMA_READ(GAMMA_OUTPUTFIFO) != GAMMA_SYNC_TAG);
  60. }
  61. void gamma_dma_quiescent_dual(drm_device_t *dev)
  62. {
  63. drm_gamma_private_t *dev_priv =
  64. (drm_gamma_private_t *)dev->dev_private;
  65. while (GAMMA_READ(GAMMA_DMACOUNT))
  66. ;
  67. while (GAMMA_READ(GAMMA_INFIFOSPACE) < 3)
  68. ;
  69. GAMMA_WRITE(GAMMA_BROADCASTMASK, 3);
  70. GAMMA_WRITE(GAMMA_FILTERMODE, 1 << 10);
  71. GAMMA_WRITE(GAMMA_SYNC, 0);
  72. /* Read from first MX */
  73. do {
  74. while (!GAMMA_READ(GAMMA_OUTFIFOWORDS))
  75. ;
  76. } while (GAMMA_READ(GAMMA_OUTPUTFIFO) != GAMMA_SYNC_TAG);
  77. /* Read from second MX */
  78. do {
  79. while (!GAMMA_READ(GAMMA_OUTFIFOWORDS + 0x10000))
  80. ;
  81. } while (GAMMA_READ(GAMMA_OUTPUTFIFO + 0x10000) != GAMMA_SYNC_TAG);
  82. }
  83. void gamma_dma_ready(drm_device_t *dev)
  84. {
  85. drm_gamma_private_t *dev_priv =
  86. (drm_gamma_private_t *)dev->dev_private;
  87. while (GAMMA_READ(GAMMA_DMACOUNT))
  88. ;
  89. }
  90. static inline int gamma_dma_is_ready(drm_device_t *dev)
  91. {
  92. drm_gamma_private_t *dev_priv =
  93. (drm_gamma_private_t *)dev->dev_private;
  94. return !GAMMA_READ(GAMMA_DMACOUNT);
  95. }
  96. void gamma_dma_service(int irq, void *device, struct pt_regs *regs)
  97. {
  98. drm_device_t     *dev      = (drm_device_t *)device;
  99. drm_device_dma_t    *dma      = dev->dma;
  100. drm_gamma_private_t *dev_priv =
  101. (drm_gamma_private_t *)dev->dev_private;
  102. atomic_inc(&dev->counts[6]); /* _DRM_STAT_IRQ */
  103. GAMMA_WRITE(GAMMA_GDELAYTIMER, 0xc350/2); /* 0x05S */
  104. GAMMA_WRITE(GAMMA_GCOMMANDINTFLAGS, 8);
  105. GAMMA_WRITE(GAMMA_GINTFLAGS, 0x2001);
  106. if (gamma_dma_is_ready(dev)) {
  107. /* Free previous buffer */
  108. if (test_and_set_bit(0, &dev->dma_flag)) return;
  109. if (dma->this_buffer) {
  110. gamma_free_buffer(dev, dma->this_buffer);
  111. dma->this_buffer = NULL;
  112. }
  113. clear_bit(0, &dev->dma_flag);
  114. /* Dispatch new buffer */
  115. queue_task(&dev->tq, &tq_immediate);
  116. mark_bh(IMMEDIATE_BH);
  117. }
  118. }
  119. /* Only called by gamma_dma_schedule. */
  120. static int gamma_do_dma(drm_device_t *dev, int locked)
  121. {
  122. unsigned long  address;
  123. unsigned long  length;
  124. drm_buf_t  *buf;
  125. int  retcode = 0;
  126. drm_device_dma_t *dma = dev->dma;
  127. #if DRM_DMA_HISTOGRAM
  128. cycles_t  dma_start, dma_stop;
  129. #endif
  130. if (test_and_set_bit(0, &dev->dma_flag)) return -EBUSY;
  131. #if DRM_DMA_HISTOGRAM
  132. dma_start = get_cycles();
  133. #endif
  134. if (!dma->next_buffer) {
  135. DRM_ERROR("No next_buffern");
  136. clear_bit(0, &dev->dma_flag);
  137. return -EINVAL;
  138. }
  139. buf = dma->next_buffer;
  140. address = (unsigned long)buf->address;
  141. length = buf->used;
  142. DRM_DEBUG("context %d, buffer %d (%ld bytes)n",
  143.   buf->context, buf->idx, length);
  144. if (buf->list == DRM_LIST_RECLAIM) {
  145. gamma_clear_next_buffer(dev);
  146. gamma_free_buffer(dev, buf);
  147. clear_bit(0, &dev->dma_flag);
  148. return -EINVAL;
  149. }
  150. if (!length) {
  151. DRM_ERROR("0 length buffern");
  152. gamma_clear_next_buffer(dev);
  153. gamma_free_buffer(dev, buf);
  154. clear_bit(0, &dev->dma_flag);
  155. return 0;
  156. }
  157. if (!gamma_dma_is_ready(dev)) {
  158. clear_bit(0, &dev->dma_flag);
  159. return -EBUSY;
  160. }
  161. if (buf->while_locked) {
  162. if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
  163. DRM_ERROR("Dispatching buffer %d from pid %d"
  164.   " "while locked", but no lock heldn",
  165.   buf->idx, buf->pid);
  166. }
  167. } else {
  168. if (!locked && !gamma_lock_take(&dev->lock.hw_lock->lock,
  169.       DRM_KERNEL_CONTEXT)) {
  170. clear_bit(0, &dev->dma_flag);
  171. return -EBUSY;
  172. }
  173. }
  174. if (dev->last_context != buf->context
  175.     && !(dev->queuelist[buf->context]->flags
  176.  & _DRM_CONTEXT_PRESERVED)) {
  177. /* PRE: dev->last_context != buf->context */
  178. if (DRM(context_switch)(dev, dev->last_context,
  179. buf->context)) {
  180. DRM(clear_next_buffer)(dev);
  181. DRM(free_buffer)(dev, buf);
  182. }
  183. retcode = -EBUSY;
  184. goto cleanup;
  185. /* POST: we will wait for the context
  186.    switch and will dispatch on a later call
  187.    when dev->last_context == buf->context.
  188.    NOTE WE HOLD THE LOCK THROUGHOUT THIS
  189.    TIME! */
  190. }
  191. gamma_clear_next_buffer(dev);
  192. buf->pending  = 1;
  193. buf->waiting  = 0;
  194. buf->list  = DRM_LIST_PEND;
  195. #if DRM_DMA_HISTOGRAM
  196. buf->time_dispatched = get_cycles();
  197. #endif
  198. gamma_dma_dispatch(dev, address, length);
  199. gamma_free_buffer(dev, dma->this_buffer);
  200. dma->this_buffer = buf;
  201. atomic_inc(&dev->counts[7]); /* _DRM_STAT_DMA */
  202. atomic_add(length, &dev->counts[8]); /* _DRM_STAT_PRIMARY */
  203. if (!buf->while_locked && !dev->context_flag && !locked) {
  204. if (gamma_lock_free(dev, &dev->lock.hw_lock->lock,
  205.   DRM_KERNEL_CONTEXT)) {
  206. DRM_ERROR("n");
  207. }
  208. }
  209. cleanup:
  210. clear_bit(0, &dev->dma_flag);
  211. #if DRM_DMA_HISTOGRAM
  212. dma_stop = get_cycles();
  213. atomic_inc(&dev->histo.dma[gamma_histogram_slot(dma_stop - dma_start)]);
  214. #endif
  215. return retcode;
  216. }
  217. static void gamma_dma_timer_bh(unsigned long dev)
  218. {
  219. gamma_dma_schedule((drm_device_t *)dev, 0);
  220. }
  221. void gamma_dma_immediate_bh(void *dev)
  222. {
  223. gamma_dma_schedule(dev, 0);
  224. }
  225. int gamma_dma_schedule(drm_device_t *dev, int locked)
  226. {
  227. int  next;
  228. drm_queue_t  *q;
  229. drm_buf_t  *buf;
  230. int  retcode   = 0;
  231. int  processed = 0;
  232. int  missed;
  233. int  expire    = 20;
  234. drm_device_dma_t *dma    = dev->dma;
  235. #if DRM_DMA_HISTOGRAM
  236. cycles_t  schedule_start;
  237. #endif
  238. if (test_and_set_bit(0, &dev->interrupt_flag)) {
  239. /* Not reentrant */
  240. atomic_inc(&dev->counts[10]); /* _DRM_STAT_MISSED */
  241. return -EBUSY;
  242. }
  243. missed = atomic_read(&dev->counts[10]);
  244. #if DRM_DMA_HISTOGRAM
  245. schedule_start = get_cycles();
  246. #endif
  247. again:
  248. if (dev->context_flag) {
  249. clear_bit(0, &dev->interrupt_flag);
  250. return -EBUSY;
  251. }
  252. if (dma->next_buffer) {
  253. /* Unsent buffer that was previously
  254.    selected, but that couldn't be sent
  255.    because the lock could not be obtained
  256.    or the DMA engine wasn't ready.  Try
  257.    again. */
  258. if (!(retcode = gamma_do_dma(dev, locked))) ++processed;
  259. } else {
  260. do {
  261. next = gamma_select_queue(dev, gamma_dma_timer_bh);
  262. if (next >= 0) {
  263. q   = dev->queuelist[next];
  264. buf = gamma_waitlist_get(&q->waitlist);
  265. dma->next_buffer = buf;
  266. dma->next_queue  = q;
  267. if (buf && buf->list == DRM_LIST_RECLAIM) {
  268. gamma_clear_next_buffer(dev);
  269. gamma_free_buffer(dev, buf);
  270. }
  271. }
  272. } while (next >= 0 && !dma->next_buffer);
  273. if (dma->next_buffer) {
  274. if (!(retcode = gamma_do_dma(dev, locked))) {
  275. ++processed;
  276. }
  277. }
  278. }
  279. if (--expire) {
  280. if (missed != atomic_read(&dev->counts[10])) {
  281. if (gamma_dma_is_ready(dev)) goto again;
  282. }
  283. if (processed && gamma_dma_is_ready(dev)) {
  284. processed = 0;
  285. goto again;
  286. }
  287. }
  288. clear_bit(0, &dev->interrupt_flag);
  289. #if DRM_DMA_HISTOGRAM
  290. atomic_inc(&dev->histo.schedule[gamma_histogram_slot(get_cycles()
  291.    - schedule_start)]);
  292. #endif
  293. return retcode;
  294. }
  295. static int gamma_dma_priority(drm_device_t *dev, drm_dma_t *d)
  296. {
  297. unsigned long   address;
  298. unsigned long   length;
  299. int   must_free = 0;
  300. int   retcode   = 0;
  301. int   i;
  302. int   idx;
  303. drm_buf_t   *buf;
  304. drm_buf_t   *last_buf = NULL;
  305. drm_device_dma_t  *dma     = dev->dma;
  306. DECLARE_WAITQUEUE(entry, current);
  307. /* Turn off interrupt handling */
  308. while (test_and_set_bit(0, &dev->interrupt_flag)) {
  309. schedule();
  310. if (signal_pending(current)) return -EINTR;
  311. }
  312. if (!(d->flags & _DRM_DMA_WHILE_LOCKED)) {
  313. while (!gamma_lock_take(&dev->lock.hw_lock->lock,
  314.       DRM_KERNEL_CONTEXT)) {
  315. schedule();
  316. if (signal_pending(current)) {
  317. clear_bit(0, &dev->interrupt_flag);
  318. return -EINTR;
  319. }
  320. }
  321. ++must_free;
  322. }
  323. for (i = 0; i < d->send_count; i++) {
  324. idx = d->send_indices[i];
  325. if (idx < 0 || idx >= dma->buf_count) {
  326. DRM_ERROR("Index %d (of %d max)n",
  327.   d->send_indices[i], dma->buf_count - 1);
  328. continue;
  329. }
  330. buf = dma->buflist[ idx ];
  331. if (buf->pid != current->pid) {
  332. DRM_ERROR("Process %d using buffer owned by %dn",
  333.   current->pid, buf->pid);
  334. retcode = -EINVAL;
  335. goto cleanup;
  336. }
  337. if (buf->list != DRM_LIST_NONE) {
  338. DRM_ERROR("Process %d using %d's buffer on list %dn",
  339.   current->pid, buf->pid, buf->list);
  340. retcode = -EINVAL;
  341. goto cleanup;
  342. }
  343. /* This isn't a race condition on
  344.    buf->list, since our concern is the
  345.    buffer reclaim during the time the
  346.    process closes the /dev/drm? handle, so
  347.    it can't also be doing DMA. */
  348. buf->list   = DRM_LIST_PRIO;
  349. buf->used   = d->send_sizes[i];
  350. buf->context   = d->context;
  351. buf->while_locked = d->flags & _DRM_DMA_WHILE_LOCKED;
  352. address   = (unsigned long)buf->address;
  353. length   = buf->used;
  354. if (!length) {
  355. DRM_ERROR("0 length buffern");
  356. }
  357. if (buf->pending) {
  358. DRM_ERROR("Sending pending buffer:"
  359.   " buffer %d, offset %dn",
  360.   d->send_indices[i], i);
  361. retcode = -EINVAL;
  362. goto cleanup;
  363. }
  364. if (buf->waiting) {
  365. DRM_ERROR("Sending waiting buffer:"
  366.   " buffer %d, offset %dn",
  367.   d->send_indices[i], i);
  368. retcode = -EINVAL;
  369. goto cleanup;
  370. }
  371. buf->pending = 1;
  372. if (dev->last_context != buf->context
  373.     && !(dev->queuelist[buf->context]->flags
  374.  & _DRM_CONTEXT_PRESERVED)) {
  375. add_wait_queue(&dev->context_wait, &entry);
  376. current->state = TASK_INTERRUPTIBLE;
  377. /* PRE: dev->last_context != buf->context */
  378. DRM(context_switch)(dev, dev->last_context,
  379.     buf->context);
  380. /* POST: we will wait for the context
  381.    switch and will dispatch on a later call
  382.    when dev->last_context == buf->context.
  383.    NOTE WE HOLD THE LOCK THROUGHOUT THIS
  384.    TIME! */
  385. schedule();
  386. current->state = TASK_RUNNING;
  387. remove_wait_queue(&dev->context_wait, &entry);
  388. if (signal_pending(current)) {
  389. retcode = -EINTR;
  390. goto cleanup;
  391. }
  392. if (dev->last_context != buf->context) {
  393. DRM_ERROR("Context mismatch: %d %dn",
  394.   dev->last_context,
  395.   buf->context);
  396. }
  397. }
  398. #if DRM_DMA_HISTOGRAM
  399. buf->time_queued     = get_cycles();
  400. buf->time_dispatched = buf->time_queued;
  401. #endif
  402. gamma_dma_dispatch(dev, address, length);
  403. atomic_inc(&dev->counts[9]); /* _DRM_STAT_SPECIAL */
  404. atomic_add(length, &dev->counts[8]); /* _DRM_STAT_PRIMARY */
  405. if (last_buf) {
  406. gamma_free_buffer(dev, last_buf);
  407. }
  408. last_buf = buf;
  409. }
  410. cleanup:
  411. if (last_buf) {
  412. gamma_dma_ready(dev);
  413. gamma_free_buffer(dev, last_buf);
  414. }
  415. if (must_free && !dev->context_flag) {
  416. if (gamma_lock_free(dev, &dev->lock.hw_lock->lock,
  417.   DRM_KERNEL_CONTEXT)) {
  418. DRM_ERROR("n");
  419. }
  420. }
  421. clear_bit(0, &dev->interrupt_flag);
  422. return retcode;
  423. }
  424. static int gamma_dma_send_buffers(drm_device_t *dev, drm_dma_t *d)
  425. {
  426. DECLARE_WAITQUEUE(entry, current);
  427. drm_buf_t   *last_buf = NULL;
  428. int   retcode   = 0;
  429. drm_device_dma_t  *dma     = dev->dma;
  430. if (d->flags & _DRM_DMA_BLOCK) {
  431. last_buf = dma->buflist[d->send_indices[d->send_count-1]];
  432. add_wait_queue(&last_buf->dma_wait, &entry);
  433. }
  434. if ((retcode = gamma_dma_enqueue(dev, d))) {
  435. if (d->flags & _DRM_DMA_BLOCK)
  436. remove_wait_queue(&last_buf->dma_wait, &entry);
  437. return retcode;
  438. }
  439. gamma_dma_schedule(dev, 0);
  440. if (d->flags & _DRM_DMA_BLOCK) {
  441. DRM_DEBUG("%d waitingn", current->pid);
  442. for (;;) {
  443. current->state = TASK_INTERRUPTIBLE;
  444. if (!last_buf->waiting && !last_buf->pending)
  445. break; /* finished */
  446. schedule();
  447. if (signal_pending(current)) {
  448. retcode = -EINTR; /* Can't restart */
  449. break;
  450. }
  451. }
  452. current->state = TASK_RUNNING;
  453. DRM_DEBUG("%d runningn", current->pid);
  454. remove_wait_queue(&last_buf->dma_wait, &entry);
  455. if (!retcode
  456.     || (last_buf->list==DRM_LIST_PEND && !last_buf->pending)) {
  457. if (!waitqueue_active(&last_buf->dma_wait)) {
  458. gamma_free_buffer(dev, last_buf);
  459. }
  460. }
  461. if (retcode) {
  462. DRM_ERROR("ctx%d w%d p%d c%d i%d l%d %d/%dn",
  463.   d->context,
  464.   last_buf->waiting,
  465.   last_buf->pending,
  466.   DRM_WAITCOUNT(dev, d->context),
  467.   last_buf->idx,
  468.   last_buf->list,
  469.   last_buf->pid,
  470.   current->pid);
  471. }
  472. }
  473. return retcode;
  474. }
  475. int gamma_dma(struct inode *inode, struct file *filp, unsigned int cmd,
  476.       unsigned long arg)
  477. {
  478. drm_file_t   *priv     = filp->private_data;
  479. drm_device_t   *dev     = priv->dev;
  480. drm_device_dma_t  *dma     = dev->dma;
  481. int   retcode   = 0;
  482. drm_dma_t   d;
  483. if (copy_from_user(&d, (drm_dma_t *)arg, sizeof(d)))
  484. return -EFAULT;
  485. if (d.send_count < 0 || d.send_count > dma->buf_count) {
  486. DRM_ERROR("Process %d trying to send %d buffers (of %d max)n",
  487.   current->pid, d.send_count, dma->buf_count);
  488. return -EINVAL;
  489. }
  490. if (d.request_count < 0 || d.request_count > dma->buf_count) {
  491. DRM_ERROR("Process %d trying to get %d buffers (of %d max)n",
  492.   current->pid, d.request_count, dma->buf_count);
  493. return -EINVAL;
  494. }
  495. if (d.send_count) {
  496. if (d.flags & _DRM_DMA_PRIORITY)
  497. retcode = gamma_dma_priority(dev, &d);
  498. else
  499. retcode = gamma_dma_send_buffers(dev, &d);
  500. }
  501. d.granted_count = 0;
  502. if (!retcode && d.request_count) {
  503. retcode = gamma_dma_get_buffers(dev, &d);
  504. }
  505. DRM_DEBUG("%d returning, granted = %dn",
  506.   current->pid, d.granted_count);
  507. if (copy_to_user((drm_dma_t *)arg, &d, sizeof(d)))
  508. return -EFAULT;
  509. return retcode;
  510. }