DRM part of Radeon DRI suspend/resume support (Charl Botha).
authorDavid Dawes <dawes@xfree86.org>
Tue, 20 May 2003 22:43:39 +0000 (22:43 +0000)
committerDavid Dawes <dawes@xfree86.org>
Tue, 20 May 2003 22:43:39 +0000 (22:43 +0000)
shared-core/radeon_cp.c
shared-core/radeon_drm.h
shared-core/radeon_drv.h
shared/radeon.h
shared/radeon_cp.c
shared/radeon_drm.h
shared/radeon_drv.h

index baca552..cec9df5 100644 (file)
@@ -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 <http://cpbotha.net>
+ */
+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;
index 7efb3c1..c0f1e75 100644 (file)
@@ -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 {
index 3e3b263..8b17b9d 100644 (file)
@@ -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 );
index 7e75e69..d25adba 100644 (file)
@@ -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 }, \
index baca552..cec9df5 100644 (file)
@@ -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 <http://cpbotha.net>
+ */
+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;
index 7efb3c1..c0f1e75 100644 (file)
@@ -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 {
index 3e3b263..8b17b9d 100644 (file)
@@ -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 );