📄 i830_dma.c
字号:
{ drm_i830_private_t *dev_priv = dev->dev_private; drm_i830_buf_priv_t *buf_priv = buf->dev_private; drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_clip_rect_t *box = sarea_priv->boxes; int nbox = sarea_priv->nbox; unsigned long address = (unsigned long)buf->bus_address; unsigned long start = address - dev->agp->base; int i = 0, u; RING_LOCALS; i830_kernel_lost_context(dev); if (nbox > I830_NR_SAREA_CLIPRECTS) nbox = I830_NR_SAREA_CLIPRECTS; if (discard) { u = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT, I830_BUF_HARDWARE); if(u != I830_BUF_CLIENT) { DRM_DEBUG("xxxx 2\n"); } } if (used > 4*1024) used = 0; if (sarea_priv->dirty) i830EmitState( dev ); DRM_DEBUG("dispatch vertex addr 0x%lx, used 0x%x nbox %d\n", address, used, nbox); dev_priv->counter++; DRM_DEBUG( "dispatch counter : %ld\n", dev_priv->counter); DRM_DEBUG( "i830_dma_dispatch\n"); DRM_DEBUG( "start : %lx\n", start); DRM_DEBUG( "used : %d\n", used); DRM_DEBUG( "start + used - 4 : %ld\n", start + used - 4); if (buf_priv->currently_mapped == I830_BUF_MAPPED) { *(u32 *)buf_priv->virtual = (GFX_OP_PRIMITIVE | sarea_priv->vertex_prim | ((used/4)-2)); if (used & 4) { *(u32 *)((u32)buf_priv->virtual + used) = 0; used += 4; } i830_unmap_buffer(buf); } if (used) { do { if (i < nbox) { BEGIN_LP_RING(6); OUT_RING( GFX_OP_DRAWRECT_INFO ); OUT_RING( sarea_priv->BufferState[I830_DESTREG_DR1] ); OUT_RING( box[i].x1 | (box[i].y1<<16) ); OUT_RING( box[i].x2 | (box[i].y2<<16) ); OUT_RING( sarea_priv->BufferState[I830_DESTREG_DR4] ); OUT_RING( 0 ); ADVANCE_LP_RING(); } BEGIN_LP_RING(4); OUT_RING( MI_BATCH_BUFFER ); OUT_RING( start | MI_BATCH_NON_SECURE ); OUT_RING( start + used - 4 ); OUT_RING( 0 ); ADVANCE_LP_RING(); } while (++i < nbox); } BEGIN_LP_RING(10); OUT_RING( CMD_STORE_DWORD_IDX ); OUT_RING( 20 ); OUT_RING( dev_priv->counter ); OUT_RING( 0 ); if (discard) { OUT_RING( CMD_STORE_DWORD_IDX ); OUT_RING( buf_priv->my_use_idx ); OUT_RING( I830_BUF_FREE ); OUT_RING( 0 ); } OUT_RING( CMD_REPORT_HEAD ); OUT_RING( 0 ); ADVANCE_LP_RING();}/* Interrupts are only for flushing */void i830_dma_service(int irq, void *device, struct pt_regs *regs){ drm_device_t *dev = (drm_device_t *)device; drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; u16 temp; temp = I830_READ16(I830REG_INT_IDENTITY_R); temp = temp & ~(0x6000); if(temp != 0) I830_WRITE16(I830REG_INT_IDENTITY_R, temp); /* Clear all interrupts */ else return; queue_task(&dev->tq, &tq_immediate); mark_bh(IMMEDIATE_BH);}void DRM(dma_immediate_bh)(void *device){ drm_device_t *dev = (drm_device_t *) device; drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; atomic_set(&dev_priv->flush_done, 1); wake_up_interruptible(&dev_priv->flush_queue);}static inline void i830_dma_emit_flush(drm_device_t *dev){ drm_i830_private_t *dev_priv = dev->dev_private; RING_LOCALS; i830_kernel_lost_context(dev); BEGIN_LP_RING(2); OUT_RING( CMD_REPORT_HEAD ); OUT_RING( GFX_OP_USER_INTERRUPT ); ADVANCE_LP_RING(); i830_wait_ring( dev, dev_priv->ring.Size - 8 ); atomic_set(&dev_priv->flush_done, 1); wake_up_interruptible(&dev_priv->flush_queue);}static inline void i830_dma_quiescent_emit(drm_device_t *dev){ drm_i830_private_t *dev_priv = dev->dev_private; RING_LOCALS; i830_kernel_lost_context(dev); BEGIN_LP_RING(4); OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE ); OUT_RING( CMD_REPORT_HEAD ); OUT_RING( 0 ); OUT_RING( GFX_OP_USER_INTERRUPT ); ADVANCE_LP_RING(); i830_wait_ring( dev, dev_priv->ring.Size - 8 ); atomic_set(&dev_priv->flush_done, 1); wake_up_interruptible(&dev_priv->flush_queue);}void i830_dma_quiescent(drm_device_t *dev){ DECLARE_WAITQUEUE(entry, current); drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; unsigned long end; if(dev_priv == NULL) { return; } atomic_set(&dev_priv->flush_done, 0); add_wait_queue(&dev_priv->flush_queue, &entry); end = jiffies + (HZ*3); for (;;) { current->state = TASK_INTERRUPTIBLE; i830_dma_quiescent_emit(dev); if (atomic_read(&dev_priv->flush_done) == 1) break; if(time_before(end, jiffies)) { DRM_ERROR("lockup\n"); break; } schedule_timeout(HZ*3); if (signal_pending(current)) { break; } } current->state = TASK_RUNNING; remove_wait_queue(&dev_priv->flush_queue, &entry); return;}static int i830_flush_queue(drm_device_t *dev){ DECLARE_WAITQUEUE(entry, current); drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; drm_device_dma_t *dma = dev->dma; unsigned long end; int i, ret = 0; if(dev_priv == NULL) { return 0; } atomic_set(&dev_priv->flush_done, 0); add_wait_queue(&dev_priv->flush_queue, &entry); end = jiffies + (HZ*3); for (;;) { current->state = TASK_INTERRUPTIBLE; i830_dma_emit_flush(dev); if (atomic_read(&dev_priv->flush_done) == 1) break; if(time_before(end, jiffies)) { DRM_ERROR("lockup\n"); break; } schedule_timeout(HZ*3); if (signal_pending(current)) { ret = -EINTR; /* Can't restart */ break; } } current->state = TASK_RUNNING; remove_wait_queue(&dev_priv->flush_queue, &entry); for (i = 0; i < dma->buf_count; i++) { drm_buf_t *buf = dma->buflist[ i ]; drm_i830_buf_priv_t *buf_priv = buf->dev_private; int used = cmpxchg(buf_priv->in_use, I830_BUF_HARDWARE, I830_BUF_FREE); if (used == I830_BUF_HARDWARE) DRM_DEBUG("reclaimed from HARDWARE\n"); if (used == I830_BUF_CLIENT) DRM_DEBUG("still on client HARDWARE\n"); } return ret;}/* Must be called with the lock held */void i830_reclaim_buffers(drm_device_t *dev, pid_t pid){ drm_device_dma_t *dma = dev->dma; int i; if (!dma) return; if (!dev->dev_private) return; if (!dma->buflist) return; i830_flush_queue(dev); for (i = 0; i < dma->buf_count; i++) { drm_buf_t *buf = dma->buflist[ i ]; drm_i830_buf_priv_t *buf_priv = buf->dev_private; if (buf->pid == pid && buf_priv) { int used = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT, I830_BUF_FREE); if (used == I830_BUF_CLIENT) DRM_DEBUG("reclaimed from client\n"); if(buf_priv->currently_mapped == I830_BUF_MAPPED) buf_priv->currently_mapped = I830_BUF_UNMAPPED; } }}int i830_flush_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; DRM_DEBUG("i830_flush_ioctl\n"); if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("i830_flush_ioctl called without lock held\n"); return -EINVAL; } i830_flush_queue(dev); return 0;}int i830_dma_vertex(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; drm_device_dma_t *dma = dev->dma; drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; u32 *hw_status = (u32 *)dev_priv->hw_status_page; drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *) dev_priv->sarea_priv; drm_i830_vertex_t vertex; if (copy_from_user(&vertex, (drm_i830_vertex_t *)arg, sizeof(vertex))) return -EFAULT; if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("i830_dma_vertex called without lock held\n"); return -EINVAL; } DRM_DEBUG("i830 dma vertex, idx %d used %d discard %d\n", vertex.idx, vertex.used, vertex.discard); if(vertex.idx < 0 || vertex.idx > dma->buf_count) return -EINVAL; i830_dma_dispatch_vertex( dev, dma->buflist[ vertex.idx ], vertex.discard, vertex.used ); sarea_priv->last_enqueue = dev_priv->counter-1; sarea_priv->last_dispatch = (int) hw_status[5]; return 0;}int i830_clear_bufs(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; drm_i830_clear_t clear; if (copy_from_user(&clear, (drm_i830_clear_t *)arg, sizeof(clear))) return -EFAULT; if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("i830_clear_bufs called without lock held\n"); return -EINVAL; } /* GH: Someone's doing nasty things... */ if (!dev->dev_private) { return -EINVAL; } i830_dma_dispatch_clear( dev, clear.flags, clear.clear_color, clear.clear_depth, clear.clear_depthmask); return 0;}int i830_swap_bufs(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; DRM_DEBUG("i830_swap_bufs\n"); if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("i830_swap_buf called without lock held\n"); return -EINVAL; } i830_dma_dispatch_swap( dev ); return 0;}int i830_getage(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; u32 *hw_status = (u32 *)dev_priv->hw_status_page; drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *) dev_priv->sarea_priv; sarea_priv->last_dispatch = (int) hw_status[5]; return 0;}int i830_getbuf(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; int retcode = 0; drm_i830_dma_t d; drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; u32 *hw_status = (u32 *)dev_priv->hw_status_page; drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *) dev_priv->sarea_priv; DRM_DEBUG("getbuf\n"); if (copy_from_user(&d, (drm_i830_dma_t *)arg, sizeof(d))) return -EFAULT; if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("i830_dma called without lock held\n"); return -EINVAL; } d.granted = 0; retcode = i830_dma_get_buffer(dev, &d, filp); DRM_DEBUG("i830_dma: %d returning %d, granted = %d\n", current->pid, retcode, d.granted); if (copy_to_user((drm_dma_t *)arg, &d, sizeof(d))) return -EFAULT; sarea_priv->last_dispatch = (int) hw_status[5]; return retcode;}int i830_copybuf(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; drm_i830_copy_t d; drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; u32 *hw_status = (u32 *)dev_priv->hw_status_page; drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *) dev_priv->sarea_priv; drm_buf_t *buf; drm_i830_buf_priv_t *buf_priv; drm_device_dma_t *dma = dev->dma; if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("i830_dma called without lock held\n"); return -EINVAL; } if (copy_from_user(&d, (drm_i830_copy_t *)arg, sizeof(d))) return -EFAULT; if(d.idx < 0 || d.idx > dma->buf_count) return -EINVAL; buf = dma->buflist[ d.idx ]; buf_priv = buf->dev_private; if (buf_priv->currently_mapped != I830_BUF_MAPPED) return -EPERM; if(d.used < 0 || d.used > buf->total) return -EINVAL; if (copy_from_user(buf_priv->virtual, d.address, d.used)) return -EFAULT; sarea_priv->last_dispatch = (int) hw_status[5]; return 0;}int i830_docopy(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ if(VM_DONTCOPY == 0) return 1; return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -