From c0efa1a777baf90561a31957014d760f89146e4f Mon Sep 17 00:00:00 2001 From: David Dawes Date: Tue, 20 May 2003 22:43:39 +0000 Subject: DRM part of Radeon DRI suspend/resume support (Charl Botha). --- shared-core/radeon_cp.c | 180 +++++++++++++++++++++++++++++++++++++++++++++++ shared-core/radeon_drm.h | 2 + shared-core/radeon_drv.h | 1 + shared/radeon.h | 2 + shared/radeon_cp.c | 180 +++++++++++++++++++++++++++++++++++++++++++++++ shared/radeon_drm.h | 2 + shared/radeon_drv.h | 1 + 7 files changed, 368 insertions(+) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index baca5521..cec9df59 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -1301,6 +1301,176 @@ int radeon_do_cleanup_cp( drm_device_t *dev ) return 0; } +/* This code will reinit the Radeon CP hardware after a resume from disc. + * AFAIK, it would be very difficult to pickle the state at suspend time, so + * here we make sure that all Radeon hardware initialisation is re-done without + * affecting running applications. This function is called radeon_do_resume_cp() + * as it was derived from radeon_init_cp, where most of the initialisation takes + * place during DRI init. + * + * This patch is NOT to be confused with my and Michel Daenzer's earlier DRI + * reinit work, which de- and re-initialised the complete DRI at every VT + * switch. + * + * Charl P. Botha + */ +static int radeon_do_resume_cp( drm_device_t *dev) +{ + drm_radeon_private_t *dev_priv; + u32 tmp; + DRM_DEBUG( "\n" ); + + DRM_DEBUG("Starting radeon_do_resume_cp()\n"); + + /* get the existing dev_private */ + dev_priv = dev->dev_private; + +#if !defined(PCIGART_ENABLED) + /* PCI support is not 100% working, so we disable it here. + */ + if ( dev_priv->is_pci ) { + DRM_ERROR( "PCI GART not yet supported for Radeon!\n" ); + radeon_do_cleanup_cp(dev); + return DRM_ERR(EINVAL); + } +#endif + + if ( dev_priv->is_pci && !dev->sg ) { + DRM_ERROR( "PCI GART memory not allocated!\n" ); + radeon_do_cleanup_cp(dev); + return DRM_ERR(EINVAL); + } + + if ( dev_priv->usec_timeout < 1 || + dev_priv->usec_timeout > RADEON_MAX_USEC_TIMEOUT ) { + DRM_DEBUG( "TIMEOUT problem!\n" ); + radeon_do_cleanup_cp(dev); + return DRM_ERR(EINVAL); + } + + if ( ( dev_priv->cp_mode != RADEON_CSQ_PRIBM_INDDIS ) && + ( dev_priv->cp_mode != RADEON_CSQ_PRIBM_INDBM ) ) { + DRM_DEBUG( "BAD cp_mode (%x)!\n", dev_priv->cp_mode ); + radeon_do_cleanup_cp(dev); + return DRM_ERR(EINVAL); + } + + if(!dev_priv->sarea) { + DRM_ERROR("could not find sarea!\n"); + radeon_do_cleanup_cp(dev); + return DRM_ERR(EINVAL); + } + + if(!dev_priv->fb) { + DRM_ERROR("could not find framebuffer!\n"); + radeon_do_cleanup_cp(dev); + return DRM_ERR(EINVAL); + } + + if(!dev_priv->mmio) { + DRM_ERROR("could not find mmio region!\n"); + radeon_do_cleanup_cp(dev); + return DRM_ERR(EINVAL); + } + + if(!dev_priv->cp_ring) { + DRM_ERROR("could not find cp ring region!\n"); + radeon_do_cleanup_cp(dev); + return DRM_ERR(EINVAL); + } + + if(!dev_priv->ring_rptr) { + DRM_ERROR("could not find ring read pointer!\n"); + radeon_do_cleanup_cp(dev); + return DRM_ERR(EINVAL); + } + + if(!dev_priv->buffers) { + DRM_ERROR("could not find dma buffer region!\n"); + radeon_do_cleanup_cp(dev); + return DRM_ERR(EINVAL); + } + + if ( !dev_priv->is_pci ) { + if(!dev_priv->agp_textures) { + DRM_ERROR("could not find agp texture region!\n"); + radeon_do_cleanup_cp(dev); + return DRM_ERR(EINVAL); + } + } + + if ( !dev_priv->is_pci ) { + if(!dev_priv->cp_ring->handle || + !dev_priv->ring_rptr->handle || + !dev_priv->buffers->handle) { + DRM_ERROR("could not find ioremap agp regions!\n"); + radeon_do_cleanup_cp(dev); + return DRM_ERR(EINVAL); + } + } else { + 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 ); + } + + + 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 ); + +#if __REALLY_HAVE_AGP + if ( !dev_priv->is_pci ) { + /* Turn off PCI GART + */ + tmp = RADEON_READ( RADEON_AIC_CNTL ) + & ~RADEON_PCIGART_TRANSLATE_EN; + RADEON_WRITE( RADEON_AIC_CNTL, tmp ); + } else +#endif + { + /* I'm not so sure about this ati_picgart_init after at resume-time... */ + if (!DRM(ati_pcigart_init)( dev, &dev_priv->phys_pci_gart, + &dev_priv->bus_pci_gart)) { + DRM_ERROR( "failed to init PCI GART!\n" ); + radeon_do_cleanup_cp(dev); + return DRM_ERR(ENOMEM); + } + + 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 */ + } + + radeon_cp_load_microcode( dev_priv ); + radeon_cp_init_ring_buffer( dev, dev_priv ); + + radeon_do_engine_reset( dev ); + + return 0; +} + + int radeon_cp_init( DRM_IOCTL_ARGS ) { DRM_DEVICE; @@ -1456,6 +1626,16 @@ int radeon_cp_idle( DRM_IOCTL_ARGS ) return radeon_do_cp_idle( dev_priv ); } +/* Added by Charl P. Botha to call radeon_do_resume_cp(). + */ +int radeon_cp_resume( DRM_IOCTL_ARGS ) +{ + DRM_DEVICE; + + return radeon_do_resume_cp(dev); +} + + int radeon_engine_reset( DRM_IOCTL_ARGS ) { DRM_DEVICE; diff --git a/shared-core/radeon_drm.h b/shared-core/radeon_drm.h index 7efb3c16..c0f1e75d 100644 --- a/shared-core/radeon_drm.h +++ b/shared-core/radeon_drm.h @@ -385,6 +385,8 @@ typedef struct { #define DRM_IOCTL_RADEON_INIT_HEAP DRM_IOW( 0x55, drm_radeon_mem_init_heap_t) #define DRM_IOCTL_RADEON_IRQ_EMIT DRM_IOWR( 0x56, drm_radeon_irq_emit_t) #define DRM_IOCTL_RADEON_IRQ_WAIT DRM_IOW( 0x57, drm_radeon_irq_wait_t) +/* added by Charl P. Botha - see radeon_cp.c for details */ +#define DRM_IOCTL_RADEON_CP_RESUME DRM_IO(0x58) typedef struct drm_radeon_init { enum { diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 3e3b263e..8b17b9d4 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -159,6 +159,7 @@ extern int radeon_cp_start( DRM_IOCTL_ARGS ); extern int radeon_cp_stop( DRM_IOCTL_ARGS ); extern int radeon_cp_reset( DRM_IOCTL_ARGS ); extern int radeon_cp_idle( DRM_IOCTL_ARGS ); +extern int radeon_cp_resume( DRM_IOCTL_ARGS ); extern int radeon_engine_reset( DRM_IOCTL_ARGS ); extern int radeon_fullscreen( DRM_IOCTL_ARGS ); extern int radeon_cp_buffers( DRM_IOCTL_ARGS ); diff --git a/shared/radeon.h b/shared/radeon.h index 7e75e69d..d25adba2 100644 --- a/shared/radeon.h +++ b/shared/radeon.h @@ -79,6 +79,7 @@ * R200_EMIT_PP_CUBIC_OFFSETS_[0..5]. (brian) * 1.8 - Remove need to call cleanup ioctls on last client exit (keith) * Add 'GET' queries for starting additional clients on different VT's. + * Add DRM_IOCTL_RADEON_CP_RESUME ioctl. */ #define DRIVER_IOCTLS \ [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { radeon_cp_buffers, 1, 0 }, \ @@ -87,6 +88,7 @@ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_STOP)] = { radeon_cp_stop, 1, 1 }, \ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_RESET)] = { radeon_cp_reset, 1, 1 }, \ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_IDLE)] = { radeon_cp_idle, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_RESUME)] = { radeon_cp_resume, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_RESET)] = { radeon_engine_reset, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_FULLSCREEN)] = { radeon_fullscreen, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_SWAP)] = { radeon_cp_swap, 1, 0 }, \ diff --git a/shared/radeon_cp.c b/shared/radeon_cp.c index baca5521..cec9df59 100644 --- a/shared/radeon_cp.c +++ b/shared/radeon_cp.c @@ -1301,6 +1301,176 @@ int radeon_do_cleanup_cp( drm_device_t *dev ) return 0; } +/* This code will reinit the Radeon CP hardware after a resume from disc. + * AFAIK, it would be very difficult to pickle the state at suspend time, so + * here we make sure that all Radeon hardware initialisation is re-done without + * affecting running applications. This function is called radeon_do_resume_cp() + * as it was derived from radeon_init_cp, where most of the initialisation takes + * place during DRI init. + * + * This patch is NOT to be confused with my and Michel Daenzer's earlier DRI + * reinit work, which de- and re-initialised the complete DRI at every VT + * switch. + * + * Charl P. Botha + */ +static int radeon_do_resume_cp( drm_device_t *dev) +{ + drm_radeon_private_t *dev_priv; + u32 tmp; + DRM_DEBUG( "\n" ); + + DRM_DEBUG("Starting radeon_do_resume_cp()\n"); + + /* get the existing dev_private */ + dev_priv = dev->dev_private; + +#if !defined(PCIGART_ENABLED) + /* PCI support is not 100% working, so we disable it here. + */ + if ( dev_priv->is_pci ) { + DRM_ERROR( "PCI GART not yet supported for Radeon!\n" ); + radeon_do_cleanup_cp(dev); + return DRM_ERR(EINVAL); + } +#endif + + if ( dev_priv->is_pci && !dev->sg ) { + DRM_ERROR( "PCI GART memory not allocated!\n" ); + radeon_do_cleanup_cp(dev); + return DRM_ERR(EINVAL); + } + + if ( dev_priv->usec_timeout < 1 || + dev_priv->usec_timeout > RADEON_MAX_USEC_TIMEOUT ) { + DRM_DEBUG( "TIMEOUT problem!\n" ); + radeon_do_cleanup_cp(dev); + return DRM_ERR(EINVAL); + } + + if ( ( dev_priv->cp_mode != RADEON_CSQ_PRIBM_INDDIS ) && + ( dev_priv->cp_mode != RADEON_CSQ_PRIBM_INDBM ) ) { + DRM_DEBUG( "BAD cp_mode (%x)!\n", dev_priv->cp_mode ); + radeon_do_cleanup_cp(dev); + return DRM_ERR(EINVAL); + } + + if(!dev_priv->sarea) { + DRM_ERROR("could not find sarea!\n"); + radeon_do_cleanup_cp(dev); + return DRM_ERR(EINVAL); + } + + if(!dev_priv->fb) { + DRM_ERROR("could not find framebuffer!\n"); + radeon_do_cleanup_cp(dev); + return DRM_ERR(EINVAL); + } + + if(!dev_priv->mmio) { + DRM_ERROR("could not find mmio region!\n"); + radeon_do_cleanup_cp(dev); + return DRM_ERR(EINVAL); + } + + if(!dev_priv->cp_ring) { + DRM_ERROR("could not find cp ring region!\n"); + radeon_do_cleanup_cp(dev); + return DRM_ERR(EINVAL); + } + + if(!dev_priv->ring_rptr) { + DRM_ERROR("could not find ring read pointer!\n"); + radeon_do_cleanup_cp(dev); + return DRM_ERR(EINVAL); + } + + if(!dev_priv->buffers) { + DRM_ERROR("could not find dma buffer region!\n"); + radeon_do_cleanup_cp(dev); + return DRM_ERR(EINVAL); + } + + if ( !dev_priv->is_pci ) { + if(!dev_priv->agp_textures) { + DRM_ERROR("could not find agp texture region!\n"); + radeon_do_cleanup_cp(dev); + return DRM_ERR(EINVAL); + } + } + + if ( !dev_priv->is_pci ) { + if(!dev_priv->cp_ring->handle || + !dev_priv->ring_rptr->handle || + !dev_priv->buffers->handle) { + DRM_ERROR("could not find ioremap agp regions!\n"); + radeon_do_cleanup_cp(dev); + return DRM_ERR(EINVAL); + } + } else { + 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 ); + } + + + 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 ); + +#if __REALLY_HAVE_AGP + if ( !dev_priv->is_pci ) { + /* Turn off PCI GART + */ + tmp = RADEON_READ( RADEON_AIC_CNTL ) + & ~RADEON_PCIGART_TRANSLATE_EN; + RADEON_WRITE( RADEON_AIC_CNTL, tmp ); + } else +#endif + { + /* I'm not so sure about this ati_picgart_init after at resume-time... */ + if (!DRM(ati_pcigart_init)( dev, &dev_priv->phys_pci_gart, + &dev_priv->bus_pci_gart)) { + DRM_ERROR( "failed to init PCI GART!\n" ); + radeon_do_cleanup_cp(dev); + return DRM_ERR(ENOMEM); + } + + 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 */ + } + + radeon_cp_load_microcode( dev_priv ); + radeon_cp_init_ring_buffer( dev, dev_priv ); + + radeon_do_engine_reset( dev ); + + return 0; +} + + int radeon_cp_init( DRM_IOCTL_ARGS ) { DRM_DEVICE; @@ -1456,6 +1626,16 @@ int radeon_cp_idle( DRM_IOCTL_ARGS ) return radeon_do_cp_idle( dev_priv ); } +/* Added by Charl P. Botha to call radeon_do_resume_cp(). + */ +int radeon_cp_resume( DRM_IOCTL_ARGS ) +{ + DRM_DEVICE; + + return radeon_do_resume_cp(dev); +} + + int radeon_engine_reset( DRM_IOCTL_ARGS ) { DRM_DEVICE; diff --git a/shared/radeon_drm.h b/shared/radeon_drm.h index 7efb3c16..c0f1e75d 100644 --- a/shared/radeon_drm.h +++ b/shared/radeon_drm.h @@ -385,6 +385,8 @@ typedef struct { #define DRM_IOCTL_RADEON_INIT_HEAP DRM_IOW( 0x55, drm_radeon_mem_init_heap_t) #define DRM_IOCTL_RADEON_IRQ_EMIT DRM_IOWR( 0x56, drm_radeon_irq_emit_t) #define DRM_IOCTL_RADEON_IRQ_WAIT DRM_IOW( 0x57, drm_radeon_irq_wait_t) +/* added by Charl P. Botha - see radeon_cp.c for details */ +#define DRM_IOCTL_RADEON_CP_RESUME DRM_IO(0x58) typedef struct drm_radeon_init { enum { diff --git a/shared/radeon_drv.h b/shared/radeon_drv.h index 3e3b263e..8b17b9d4 100644 --- a/shared/radeon_drv.h +++ b/shared/radeon_drv.h @@ -159,6 +159,7 @@ extern int radeon_cp_start( DRM_IOCTL_ARGS ); extern int radeon_cp_stop( DRM_IOCTL_ARGS ); extern int radeon_cp_reset( DRM_IOCTL_ARGS ); extern int radeon_cp_idle( DRM_IOCTL_ARGS ); +extern int radeon_cp_resume( DRM_IOCTL_ARGS ); extern int radeon_engine_reset( DRM_IOCTL_ARGS ); extern int radeon_fullscreen( DRM_IOCTL_ARGS ); extern int radeon_cp_buffers( DRM_IOCTL_ARGS ); -- cgit v1.2.3