📄 radeon_cp.c
字号:
if(!dev_priv->sarea) { DRM_ERROR("could not find sarea!\n"); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); return DRM_ERR(EINVAL); } DRM_FIND_MAP( dev_priv->fb, init->fb_offset ); if(!dev_priv->fb) { DRM_ERROR("could not find framebuffer!\n"); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); return DRM_ERR(EINVAL); } DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset ); if(!dev_priv->mmio) { DRM_ERROR("could not find mmio region!\n"); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); return DRM_ERR(EINVAL); } DRM_FIND_MAP( dev_priv->cp_ring, init->ring_offset ); if(!dev_priv->cp_ring) { DRM_ERROR("could not find cp ring region!\n"); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); return DRM_ERR(EINVAL); } DRM_FIND_MAP( dev_priv->ring_rptr, init->ring_rptr_offset ); if(!dev_priv->ring_rptr) { DRM_ERROR("could not find ring read pointer!\n"); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); return DRM_ERR(EINVAL); } DRM_FIND_MAP( dev_priv->buffers, init->buffers_offset ); if(!dev_priv->buffers) { DRM_ERROR("could not find dma buffer region!\n"); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); return DRM_ERR(EINVAL); } if ( !dev_priv->is_pci ) { DRM_FIND_MAP( dev_priv->agp_textures, init->agp_textures_offset ); if(!dev_priv->agp_textures) { DRM_ERROR("could not find agp texture region!\n"); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); return DRM_ERR(EINVAL); } } dev_priv->sarea_priv = (drm_radeon_sarea_t *)((u8 *)dev_priv->sarea->handle + init->sarea_priv_offset); if ( !dev_priv->is_pci ) { DRM_IOREMAP( dev_priv->cp_ring ); DRM_IOREMAP( dev_priv->ring_rptr ); DRM_IOREMAP( dev_priv->buffers ); if(!dev_priv->cp_ring->handle || !dev_priv->ring_rptr->handle || !dev_priv->buffers->handle) { DRM_ERROR("could not find ioremap agp regions!\n"); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); return DRM_ERR(EINVAL); } } else { dev_priv->cp_ring->handle = (void *)dev_priv->cp_ring->offset; dev_priv->ring_rptr->handle = (void *)dev_priv->ring_rptr->offset; dev_priv->buffers->handle = (void *)dev_priv->buffers->offset; DRM_DEBUG( "dev_priv->cp_ring->handle %p\n", dev_priv->cp_ring->handle ); DRM_DEBUG( "dev_priv->ring_rptr->handle %p\n", dev_priv->ring_rptr->handle ); DRM_DEBUG( "dev_priv->buffers->handle %p\n", dev_priv->buffers->handle ); } dev_priv->agp_size = init->agp_size; dev_priv->agp_vm_start = RADEON_READ( RADEON_CONFIG_APER_SIZE );#if __REALLY_HAVE_AGP if ( !dev_priv->is_pci ) dev_priv->agp_buffers_offset = (dev_priv->buffers->offset - dev->agp->base + dev_priv->agp_vm_start); else#endif dev_priv->agp_buffers_offset = (dev_priv->buffers->offset - dev->sg->handle + dev_priv->agp_vm_start); DRM_DEBUG( "dev_priv->agp_size %d\n", dev_priv->agp_size ); DRM_DEBUG( "dev_priv->agp_vm_start 0x%x\n", dev_priv->agp_vm_start ); DRM_DEBUG( "dev_priv->agp_buffers_offset 0x%lx\n", dev_priv->agp_buffers_offset ); dev_priv->ring.head = ((__volatile__ u32 *) dev_priv->ring_rptr->handle); dev_priv->ring.start = (u32 *)dev_priv->cp_ring->handle; dev_priv->ring.end = ((u32 *)dev_priv->cp_ring->handle + init->ring_size / sizeof(u32)); dev_priv->ring.size = init->ring_size; dev_priv->ring.size_l2qw = DRM(order)( init->ring_size / 8 ); dev_priv->ring.tail_mask = (dev_priv->ring.size / sizeof(u32)) - 1; dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK;#if __REALLY_HAVE_SG if ( dev_priv->is_pci ) { if (!DRM(ati_pcigart_init)( dev, &dev_priv->phys_pci_gart, &dev_priv->bus_pci_gart)) { DRM_ERROR( "failed to init PCI GART!\n" ); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); return DRM_ERR(ENOMEM); } /* Turn on PCI GART */ tmp = RADEON_READ( RADEON_AIC_CNTL ) | RADEON_PCIGART_TRANSLATE_EN; RADEON_WRITE( RADEON_AIC_CNTL, tmp ); /* set PCI GART page-table base address */ RADEON_WRITE( RADEON_AIC_PT_BASE, dev_priv->bus_pci_gart ); /* set address range for PCI address translate */ RADEON_WRITE( RADEON_AIC_LO_ADDR, dev_priv->agp_vm_start ); RADEON_WRITE( RADEON_AIC_HI_ADDR, dev_priv->agp_vm_start + dev_priv->agp_size - 1); /* Turn off AGP aperture -- is this required for PCIGART? */ RADEON_WRITE( RADEON_MC_AGP_LOCATION, 0xffffffc0 ); /* ?? */ RADEON_WRITE( RADEON_AGP_COMMAND, 0 ); /* clear AGP_COMMAND */ } else {#endif /* __REALLY_HAVE_SG */ /* Turn off PCI GART */ tmp = RADEON_READ( RADEON_AIC_CNTL ) & ~RADEON_PCIGART_TRANSLATE_EN; RADEON_WRITE( RADEON_AIC_CNTL, tmp );#if __REALLY_HAVE_SG }#endif /* __REALLY_HAVE_SG */ radeon_cp_load_microcode( dev_priv ); radeon_cp_init_ring_buffer( dev, dev_priv ); dev_priv->last_buf = 0; dev->dev_private = (void *)dev_priv; radeon_do_engine_reset( dev ); return 0;}int radeon_do_cleanup_cp( drm_device_t *dev ){ DRM_DEBUG( "\n" ); if ( dev->dev_private ) { drm_radeon_private_t *dev_priv = dev->dev_private; if ( !dev_priv->is_pci ) { DRM_IOREMAPFREE( dev_priv->cp_ring ); DRM_IOREMAPFREE( dev_priv->ring_rptr ); DRM_IOREMAPFREE( dev_priv->buffers ); } else {#if __REALLY_HAVE_SG if (!DRM(ati_pcigart_cleanup)( dev, dev_priv->phys_pci_gart, dev_priv->bus_pci_gart )) DRM_ERROR( "failed to cleanup PCI GART!\n" );#endif /* __REALLY_HAVE_SG */ } DRM(free)( dev->dev_private, sizeof(drm_radeon_private_t), DRM_MEM_DRIVER ); dev->dev_private = NULL; } return 0;}int radeon_cp_init( DRM_IOCTL_ARGS ){ DRM_DEVICE; drm_radeon_init_t init; DRM_COPY_FROM_USER_IOCTL( init, (drm_radeon_init_t *)data, sizeof(init) ); switch ( init.func ) { case RADEON_INIT_CP: case RADEON_INIT_R200_CP: return radeon_do_init_cp( dev, &init ); case RADEON_CLEANUP_CP: return radeon_do_cleanup_cp( dev ); } return DRM_ERR(EINVAL);}int radeon_cp_start( DRM_IOCTL_ARGS ){ DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; DRM_DEBUG( "\n" ); LOCK_TEST_WITH_RETURN( dev ); if ( dev_priv->cp_running ) { DRM_DEBUG( "%s while CP running\n", __FUNCTION__ ); return 0; } if ( dev_priv->cp_mode == RADEON_CSQ_PRIDIS_INDDIS ) { DRM_DEBUG( "%s called with bogus CP mode (%d)\n", __FUNCTION__, dev_priv->cp_mode ); return 0; } radeon_do_cp_start( dev_priv ); return 0;}/* Stop the CP. The engine must have been idled before calling this * routine. */int radeon_cp_stop( DRM_IOCTL_ARGS ){ DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_cp_stop_t stop; int ret; DRM_DEBUG( "\n" ); LOCK_TEST_WITH_RETURN( dev ); DRM_COPY_FROM_USER_IOCTL( stop, (drm_radeon_cp_stop_t *)data, sizeof(stop) ); /* Flush any pending CP commands. This ensures any outstanding * commands are exectuted by the engine before we turn it off. */ if ( stop.flush ) { radeon_do_cp_flush( dev_priv ); } /* If we fail to make the engine go idle, we return an error * code so that the DRM ioctl wrapper can try again. */ if ( stop.idle ) { ret = radeon_do_cp_idle( dev_priv ); if ( ret ) return ret; } /* Finally, we can turn off the CP. If the engine isn't idle, * we will get some dropped triangles as they won't be fully * rendered before the CP is shut down. */ radeon_do_cp_stop( dev_priv ); /* Reset the engine */ radeon_do_engine_reset( dev ); return 0;}/* Just reset the CP ring. Called as part of an X Server engine reset. */int radeon_cp_reset( DRM_IOCTL_ARGS ){ DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; DRM_DEBUG( "\n" ); LOCK_TEST_WITH_RETURN( dev ); if ( !dev_priv ) { DRM_DEBUG( "%s called before init done\n", __FUNCTION__ ); return DRM_ERR(EINVAL); } radeon_do_cp_reset( dev_priv ); /* The CP is no longer running after an engine reset */ dev_priv->cp_running = 0; return 0;}int radeon_cp_idle( DRM_IOCTL_ARGS ){ DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; DRM_DEBUG( "\n" ); LOCK_TEST_WITH_RETURN( dev );/* if (dev->irq) *//* radeon_emit_and_wait_irq( dev ); */ return radeon_do_cp_idle( dev_priv );}int radeon_engine_reset( DRM_IOCTL_ARGS ){ DRM_DEVICE; DRM_DEBUG( "\n" ); LOCK_TEST_WITH_RETURN( dev ); return radeon_do_engine_reset( dev );}/* ================================================================ * Fullscreen mode *//* KW: Deprecated to say the least: */int radeon_fullscreen( DRM_IOCTL_ARGS ){ return 0;}/* ================================================================ * Freelist management *//* Original comment: FIXME: ROTATE_BUFS is a hack to cycle through * bufs until freelist code is used. Note this hides a problem with * the scratch register * (used to keep track of last buffer * completed) being written to before * the last buffer has actually * completed rendering. * * KW: It's also a good way to find free buffers quickly. * * KW: Ideally this loop wouldn't exist, and freelist_get wouldn't * sleep. However, bugs in older versions of radeon_accel.c mean that * we essentially have to do this, else old clients will break. * * However, it does leave open a potential deadlock where all the * buffers are held by other clients, which can't release them because * they can't get the lock. */drm_buf_t *radeon_freelist_get( drm_device_t *dev ){ drm_device_dma_t *dma = dev->dma; drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_buf_priv_t *buf_priv; drm_buf_t *buf; int i, t; int start; if ( ++dev_priv->last_buf >= dma->buf_count ) dev_priv->last_buf = 0; start = dev_priv->last_buf; for ( t = 0 ; t < dev_priv->usec_timeout ; t++ ) { u32 done_age = GET_SCRATCH( 1 ); DRM_DEBUG("done_age = %d\n",done_age); for ( i = start ; i < dma->buf_count ; i++ ) { buf = dma->buflist[i]; buf_priv = buf->dev_private; if ( buf->pid == 0 || (buf->pending && buf_priv->age <= done_age) ) { dev_priv->stats.requested_bufs++; buf->pending = 0; return buf; } start = 0; } if (t) { DRM_UDELAY( 1 ); dev_priv->stats.freelist_loops++; } } DRM_DEBUG( "returning NULL!\n" ); return NULL;}#if 0drm_buf_t *radeon_freelist_get( drm_device_t *dev ){ drm_device_dma_t *dma = dev->dma; drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_buf_priv_t *buf_priv; drm_buf_t *buf; int i, t; int start; u32 done_age = DRM_READ32(&dev_priv->scratch[1]); if ( ++dev_priv->last_buf >= dma->buf_count ) dev_priv->last_buf = 0; start = dev_priv->last_buf; dev_priv->stats.freelist_loops++; for ( t = 0 ; t < 2 ; t++ ) { for ( i = start ; i < dma->buf_count ; i++ ) { buf = dma->buflist[i]; buf_priv = buf->dev_private; if ( buf->pid == 0 || (buf->pending && buf_priv->age <= done_age) ) { dev_priv->stats.requested_bufs++; buf->pending = 0; return buf; } } start = 0; } return NULL;}#endifvoid radeon_freelist_reset( drm_device_t *dev ){ drm_device_dma_t *dma = dev->dma; drm_radeon_private_t *dev_priv = dev->dev_private; int i; dev_priv->last_buf = 0; for ( i = 0 ; i < dma->buf_count ; i++ ) { drm_buf_t *buf = dma->buflist[i]; drm_radeon_buf_priv_t *buf_priv = buf->dev_private; buf_priv->age = 0; }}/* ================================================================ * CP command submission */int radeon_wait_ring( drm_radeon_private_t *dev_priv, int n ){ drm_radeon_ring_buffer_t *ring = &dev_priv->ring; int i; u32 last_head = GET_RING_HEAD(ring); for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { u32 head = GET_RING_HEAD(ring); ring->space = (head - ring->tail) * sizeof(u32); if ( ring->space <= 0 ) ring->space += ring->size; if ( ring->space > n ) return 0; dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; if (head != last_head) i = 0; last_head = head; DRM_UDELAY( 1 ); } /* FIXME: This return value is ignored in the BEGIN_RING macro! */#if RADEON_FIFO_DEBUG radeon_status( dev_priv ); DRM_ERROR( "failed!\n" );#endif return DRM_ERR(EBUSY);}static int radeon_cp_get_buffers( drm_device_t *dev, drm_dma_t *d ){ int i; drm_buf_t *buf; for ( i = d->granted_count ; i < d->request_count ; i++ ) { buf = radeon_freelist_get( dev ); if ( !buf ) return DRM_ERR(EBUSY); /* NOTE: broken client */ buf->pid = DRM_CURRENTPID; if ( DRM_COPY_TO_USER( &d->request_indices[i], &buf->idx, sizeof(buf->idx) ) ) return DRM_ERR(EFAULT); if ( DRM_COPY_TO_USER( &d->request_sizes[i], &buf->total, sizeof(buf->total) ) ) return DRM_ERR(EFAULT); d->granted_count++; } return 0;}int radeon_cp_buffers( DRM_IOCTL_ARGS ){ DRM_DEVICE; drm_device_dma_t *dma = dev->dma; int ret = 0; drm_dma_t d; LOCK_TEST_WITH_RETURN( dev ); DRM_COPY_FROM_USER_IOCTL( d, (drm_dma_t *)data, sizeof(d) ); /* Please don't send us buffers. */ if ( d.send_count != 0 ) { DRM_ERROR( "Process %d trying to send %d buffers via drmDMA\n", DRM_CURRENTPID, d.send_count ); return DRM_ERR(EINVAL); } /* We'll send you buffers. */ if ( d.request_count < 0 || d.request_count > dma->buf_count ) { DRM_ERROR( "Process %d trying to get %d buffers (of %d max)\n", DRM_CURRENTPID, d.request_count, dma->buf_count ); return DRM_ERR(EINVAL); } d.granted_count = 0; if ( d.request_count ) { ret = radeon_cp_get_buffers( dev, &d ); } DRM_COPY_TO_USER_IOCTL( (drm_dma_t *)data, d, sizeof(d) ); return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -