[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#233202: xserver-xfree86: xvideo extensions not working after resume



On Wed, Feb 18, 2004 at 12:57:34AM +0100, Michel Dänzer wrote:
> On Tue, 2004-02-17 at 12:39, Cristiano De Michele wrote: 
> > 
> > Xvideo extensions (2D acceleration) work perfectly but
> > if I perform a suspend/resume cycle, they do not work anymore
> > and if I try for example to watch a movie I get only vertical multicolor
> > bands...
> 
> See http://cpbotha.net/dri_resume.html .

I'm confused.  The patch mentioned on that page has been in the
4.3.0-0pre* series the whole time (attached).

Mr. De Michele, I know this is a stupid question, but are you sure
you're running XFree86 4.3.0-0pre1v5 or later?

I have 4.3.0-2 installed, and the RADEONDRIResume() function that was
added by this patch shows up in my copy of the radeon driver.

$ strings /usr/X11R6/lib/modules/drivers/radeon_drv.o | grep RADEONDRIResume
RADEONDRIResume

Mr. De Michele, what do you get when you run the above command?

-- 
G. Branden Robinson                |     There's nothing an agnostic can't
Debian GNU/Linux                   |     do if he doesn't know whether he
branden@debian.org                 |     believes in it or not.
http://people.debian.org/~branden/ |     -- Graham Chapman
$Id: 025_fix_dri_resume.diff 1044 2004-02-16 17:40:33Z branden $

Fix DRI when resuming from suspend; this patch by Charl P. Botha.

--- xc/programs/Xserver/hw/xfree86/drivers/ati/radeon.h	2003/02/04 12:02:19	1.36
+++ xc/programs/Xserver/hw/xfree86/drivers/ati/radeon.h	2003/02/07 23:56:49
@@ -566,12 +566,15 @@
 extern int         RADEONMinBits(int val);
 
 extern void        RADEONInitVideo(ScreenPtr pScreen);
-
+/* added by cpbotha@ieee.org so that we can call this function from
+ * radeon_driver.c to get xvideo working after a resume from disc/ram */
+extern void        RADEONResetVideo(ScrnInfoPtr pScrn);
 extern void        R300CGWorkaround(ScrnInfoPtr pScrn);
 
 #ifdef XF86DRI
 extern Bool        RADEONDRIScreenInit(ScreenPtr pScreen);
 extern void        RADEONDRICloseScreen(ScreenPtr pScreen);
+extern void        RADEONDRIResume(ScreenPtr pScreen);
 extern Bool        RADEONDRIFinishScreenInit(ScreenPtr pScreen);
 
 extern drmBufPtr   RADEONCPGetBuffer(ScrnInfoPtr pScrn);
--- xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_common.h	2002/10/30 12:52:13	1.1
+++ xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_common.h	2003/02/07 23:56:49
@@ -70,6 +70,7 @@
 #define DRM_RADEON_INIT_HEAP              0x15
 #define DRM_RADEON_IRQ_EMIT               0x16
 #define DRM_RADEON_IRQ_WAIT               0x17
+#define DRM_RADEON_CP_RESUME              0x18
 #define DRM_RADEON_MAX_DRM_COMMAND_INDEX  0x39
 
 
--- xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_dri.c	2003/01/31 15:43:09	1.27
+++ xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_dri.c	2003/02/07 23:56:50
@@ -1557,6 +1557,86 @@
     return TRUE;
 }
 
+/**
+ * This function will attempt to get the Radeon hardware back into shape
+ * after a resume from disc.  Basically, it's an extract of all hardware-
+ * affecting code from RADEONDRIAgpInit() (which is normally called by
+ * RADEONDRIScreenInit()) and RADEONDRIFinishScreenInit()
+ * including a new ioctl in the radeon DRM that in its turn is an extraction
+ * of the hardware-affecting bits from radeon_do_init_cp() (see radeon_cp.c)
+ *
+ * Charl P. Botha <http://cpbotha.net>
+ */
+void RADEONDRIResume(ScreenPtr pScreen)
+{
+    unsigned long mode;
+    int _ret;
+    ScrnInfoPtr   pScrn   = xf86Screens[pScreen->myNum];
+    RADEONInfoPtr info    = RADEONPTR(pScrn);
+    unsigned char *RADEONMMIO = info->MMIO;
+
+    xf86DrvMsg(pScreen->myNum, X_INFO,
+	       "[RESUME] Attempting to re-init Radeon hardware.\n");
+    
+    
+    /* Following bits from RADEONDRIAgpInit() */
+    /* -------------------------------------- */
+
+    mode   = drmAgpGetMode(info->drmFD);	/* Default mode */
+
+    mode &= ~RADEON_AGP_MODE_MASK;
+    switch (info->agpMode) {
+    case 4:          mode |= RADEON_AGP_4X_MODE;
+    case 2:          mode |= RADEON_AGP_2X_MODE;
+    case 1: default: mode |= RADEON_AGP_1X_MODE;
+    }
+
+    xf86DrvMsg(pScreen->myNum, X_INFO,
+		"[agp] Mode 0x%08lx [Card 0x%04x/0x%04x]\n",
+		mode,
+		info->PciInfo->vendor,
+		info->PciInfo->chipType);
+
+    if (drmAgpEnable(info->drmFD, mode) < 0) {
+	xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] AGP not enabled\n");
+	drmAgpRelease(info->drmFD);
+	return;
+    }
+
+    /* Ring buffer is at AGP offset 0 - from RADEONAgpInit() */
+    OUTREG(RADEON_AGP_BASE, info->ringHandle);
+
+    /* enable bus-mastering - we do this here bacause RADEONAgpInit() does it.
+     * The bus-mastering fix does this in RADEONEnterVT() as well, leave that!
+     */
+    /* xf86EnablePciBusMaster(info->PciInfo, TRUE); */
+    /* NB: it seems the root of this problem has been solved: X now
+     * explicitly enables bus-mastering after a VT switch */
+
+    /* Following bits from RADEONDRIFinishScreenInit() */
+    /* ----------------------------------------------- */
+    
+    /* this will make the IOCTL call we've added to try and re-tickle the 
+     * radeon chip in all the right places - similar to what the 
+     * DRM_RADEON_CP_INIT ioctl does in RADEONDRIKernelInit()
+     */
+    _ret = drmCommandNone(info->drmFD, DRM_RADEON_CP_RESUME); 
+    if (_ret) {      
+	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,  
+		   "%s: CP resume %d\n", __FUNCTION__, _ret); 
+    }       
+
+
+    /* DRM_RADEON_CP_RESUME does an engine reset, which resets some engine
+       registers back to their default values, so we need to restore
+       those engine register here. - from RADEONDRIKernelInit() that's called by
+       RADEONDRIFinishScreenInit() */
+    RADEONEngineRestore(pScrn);
+
+    /* Initialize and start the CP if required - from RADEONDRIFinishScreenInit() */
+    RADEONDRICPInit(pScrn);
+}
+
 /* The screen is being closed, so clean up any state and free any
  * resources used by the DRI.
  */
--- xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_driver.c	2003/01/30 05:31:31	1.84
+++ xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_driver.c	2003/02/07 23:56:51
@@ -5772,6 +5772,23 @@
     } else
 	if (!RADEONModeInit(pScrn, pScrn->currentMode)) return FALSE;
 
+    /* BEGIN RESUME CODE */
+    /*********************/
+
+#ifdef XF86DRI
+    if (info->directRenderingEnabled) {
+	/* get the Radeon back into shape after resume */
+	RADEONDRIResume(pScrn->pScreen);
+    }
+#endif
+    /* this will get XVideo going again, but only if XVideo was initialised 
+       during server startup (hence the info->adaptor if). */
+    if(info->adaptor)
+	RADEONResetVideo(pScrn);
+
+    /* END RESUME CODE */
+    /*******************/
+
     if (info->accelOn)
 	RADEONEngineRestore(pScrn);
 
--- xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_video.c	2003/01/29 18:06:07	1.23
+++ xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_video.c	2003/02/07 23:56:52
@@ -24,6 +24,7 @@
 
 #ifndef XvExtension
 void RADEONInitVideo(ScreenPtr pScreen) {}
+void RADEONResetVideo(ScrnInfoPtr Pscrn) {}
 #else
 
 static void RADEONInitOffscreenImages(ScreenPtr);
@@ -40,9 +41,6 @@
 static int  RADEONQueryImageAttributes(ScrnInfoPtr, int, unsigned short *,
 			unsigned short *,  int *, int *);
 
-
-static void RADEONResetVideo(ScrnInfoPtr);
-
 static void RADEONVideoTimerCallback(ScrnInfoPtr pScrn, Time now);
 
 #define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
@@ -380,7 +378,7 @@
     OUTREG(RADEON_OV0_GRAPHICS_KEY_CLR_LOW, min);
 }
 
-static void
+void
 RADEONResetVideo(ScrnInfoPtr pScrn)
 {
     RADEONInfoPtr   info      = RADEONPTR(pScrn);
--- xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon.h	2002/10/30 12:52:41	1.1
+++ xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon.h	2003/02/07 23:56:52
@@ -85,6 +85,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 }, \
--- xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon_cp.c	2003/02/04 01:48:38	1.5
+++ xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon_cp.c	2003/02/07 23:56:53
@@ -1283,6 +1283,177 @@
 	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_SG
+	if ( dev_priv->is_pci ) {
+	        /* 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 */
+	} 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 );
+
+	radeon_do_engine_reset( dev );
+
+	return 0;
+}
+
+
 int radeon_cp_init( DRM_IOCTL_ARGS )
 {
 	DRM_DEVICE;
@@ -1402,6 +1573,16 @@
 
 	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 )
 {
--- xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon_drm.h	2003/02/04 03:02:00	1.2
+++ xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon_drm.h	2003/02/07 23:56:53
@@ -391,6 +391,8 @@
 #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 {
--- xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon_drv.h	2003/02/05 00:23:15	1.3
+++ xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon_drv.h	2003/02/07 23:56:53
@@ -153,6 +153,7 @@
 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 );

Attachment: signature.asc
Description: Digital signature


Reply to: