diff options
| author | Ian Romanick <idr@us.ibm.com> | 2007-07-24 13:27:44 -0700 | 
|---|---|---|
| committer | Ian Romanick <idr@us.ibm.com> | 2007-07-24 13:27:44 -0700 | 
| commit | 887cb31ee9ec04e45829500f095aa4a3bc1095ea (patch) | |
| tree | f4a3a1e8fa27888728730137253cd7ac0bb87c21 /linux-core | |
| parent | 46214fc3979ed60b32289ade1b8efbba1c8bf732 (diff) | |
Fix bug preventing X server from restarting.
The core DRM lastclose routine automatically destroys all mappings and
releases SG memory.  XP10 DRM and DDX assumed this data stayed around
until module unload.  xgi_bootstrap was reworked to recreate all these
mappings.  In addition, the drm_addmap for the GART backing store was
moved into the kernel.  This causes a change to the ioctl protocol and
a version bump.
Diffstat (limited to 'linux-core')
| -rw-r--r-- | linux-core/xgi_drv.c | 126 | ||||
| -rw-r--r-- | linux-core/xgi_drv.h | 4 | 
2 files changed, 87 insertions, 43 deletions
| diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index 19a9a10d..11d6e950 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -64,6 +64,7 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id *ent);  static int xgi_driver_load(struct drm_device *dev, unsigned long flags);  static int xgi_driver_unload(struct drm_device *dev);  static void xgi_driver_preclose(struct drm_device * dev, DRMFILE filp); +static void xgi_driver_lastclose(drm_device_t * dev);  static irqreturn_t xgi_kern_isr(DRM_IRQ_ARGS); @@ -75,6 +76,7 @@ static struct drm_driver driver = {  	.load = xgi_driver_load,  	.unload = xgi_driver_unload,  	.preclose = xgi_driver_preclose, +	.lastclose = xgi_driver_lastclose,  	.dma_quiescent = NULL,  	.irq_preinstall = NULL,  	.irq_postinstall = NULL, @@ -144,26 +146,25 @@ int xgi_bootstrap(DRM_IOCTL_ARGS)  	DRM_DEVICE;  	struct xgi_info *info = dev->dev_private;  	struct xgi_bootstrap bs; +	struct drm_map_list *maplist;  	int err;  	DRM_COPY_FROM_USER_IOCTL(bs, (struct xgi_bootstrap __user *) data,  				 sizeof(bs)); -	if (info->bootstrap_done) { -		return 0; -	} +	if (info->mmio_map == NULL) { +		err = drm_addmap(dev, info->mmio.base, info->mmio.size, +				 _DRM_REGISTERS, _DRM_KERNEL, +				 &info->mmio_map); +		if (err) { +			DRM_ERROR("Unable to map MMIO region: %d\n", err); +			return err; +		} -	err = drm_addmap(dev, info->mmio.base, info->mmio.size, -			 _DRM_REGISTERS, _DRM_KERNEL, -			 &info->mmio_map); -	if (err) { -		DRM_ERROR("Unable to map MMIO region: %d\n", err); -		return err; +		xgi_enable_mmio(info);  	} -	xgi_enable_mmio(info); -	//xgi_enable_ge(info);  	info->fb.size = IN3CFB(info->mmio_map, 0x54) * 8 * 1024 * 1024; @@ -172,38 +173,64 @@ int xgi_bootstrap(DRM_IOCTL_ARGS)  	if ((info->fb.base == 0) || (info->fb.size == 0)) { -		DRM_ERROR("frame buffer appears to be wrong: 0x%lx 0x%x\n", +		DRM_ERROR("framebuffer appears to be wrong: 0x%lx 0x%x\n",  			  (unsigned long) info->fb.base, info->fb.size);  		return DRM_ERR(EINVAL);  	}  	/* Init the resource manager */ -	err = xgi_fb_heap_init(info); -	if (err) { -		DRM_ERROR("xgi_fb_heap_init() failed\n"); -		return err; +	if (!info->fb_heap.initialized) { +		err = xgi_fb_heap_init(info); +		if (err) { +			DRM_ERROR("Unable to initialize FB heap.\n"); +			return err; +		}  	} - -	info->pcie.size = bs.gart_size * (1024 * 1024); +	info->pcie.size = bs.gart.size;  	/* Init the resource manager */ -	err = xgi_pcie_heap_init(info); -	if (err) { -		DRM_ERROR("xgi_pcie_heap_init() failed\n"); -		return err; +	if (!info->pcie_heap.initialized) { +		err = xgi_pcie_heap_init(info); +		if (err) { +			DRM_ERROR("Unable to initialize GART heap.\n"); +			return err; +		} + +		/* Alloc 1M bytes for cmdbuffer which is flush2D batch array */ +		err = xgi_cmdlist_initialize(info, 0x100000); +		if (err) { +			DRM_ERROR("xgi_cmdlist_initialize() failed\n"); +			return err; +		}  	} -	/* Alloc 1M bytes for cmdbuffer which is flush2D batch array */ -	err = xgi_cmdlist_initialize(info, 0x100000); -	if (err) { -		DRM_ERROR("xgi_cmdlist_initialize() failed\n"); -		return err; + +	if (info->pcie_map == NULL) { +		err = drm_addmap(info->dev, 0, info->pcie.size, +				 _DRM_SCATTER_GATHER, _DRM_LOCKED, +				 & info->pcie_map); +		if (err) { +			DRM_ERROR("Could not add map for GART backing " +				  "store.\n"); +			return err; +		}  	} -	info->bootstrap_done = 1; + +	maplist = drm_find_matching_map(dev, info->pcie_map); +	if (maplist == NULL) { +		DRM_ERROR("Could not find GART backing store map.\n"); +		return DRM_ERR(EINVAL); +	} + +	bs.gart = *info->pcie_map; +	bs.gart.handle = (void *)(unsigned long) maplist->user_token; +	DRM_COPY_TO_USER_IOCTL((struct xgi_bootstrap __user *) data, +			       bs, sizeof(bs)); +  	return 0;  } @@ -217,6 +244,33 @@ void xgi_driver_preclose(struct drm_device * dev, DRMFILE filp)  } +void xgi_driver_lastclose(drm_device_t * dev) +{ +	struct xgi_info * info = dev->dev_private; + +	if (info != NULL) { +		/* The core DRM lastclose routine will destroy all of our +		 * mappings for us.  NULL out the pointers here so that +		 * xgi_bootstrap can do the right thing. +		 */ +		info->pcie_map = NULL; +		info->mmio_map = NULL; +		info->fb_map = NULL; + +		xgi_cmdlist_cleanup(info); + +		if (info->fb_heap.initialized) { +			xgi_mem_heap_cleanup(&info->fb_heap); +		} + +		if (info->pcie_heap.initialized) { +			xgi_mem_heap_cleanup(&info->pcie_heap); +			xgi_pcie_lut_cleanup(info); +		} +	} +} + +  /*   * driver receives an interrupt if someone waiting, then hand it off.   */ @@ -298,23 +352,13 @@ int xgi_driver_unload(struct drm_device *dev)  {  	struct xgi_info * info = dev->dev_private; -	xgi_cmdlist_cleanup(info); -	if (info->fb_map != NULL) { -		drm_rmmap(info->dev, info->fb_map); -	} - -	if (info->mmio_map != NULL) { -		drm_rmmap(info->dev, info->mmio_map); -	} - -	xgi_mem_heap_cleanup(&info->fb_heap); -	xgi_mem_heap_cleanup(&info->pcie_heap); -	xgi_pcie_lut_cleanup(info); -  	if (xgi_mem_block_cache) {  		kmem_cache_destroy(xgi_mem_block_cache);  		xgi_mem_block_cache = NULL;  	} +	drm_free(info, sizeof(*info), DRM_MEM_DRIVER); +	dev->dev_private = NULL; +  	return 0;  } diff --git a/linux-core/xgi_drv.h b/linux-core/xgi_drv.h index 16102950..ae5fe07e 100644 --- a/linux-core/xgi_drv.h +++ b/linux-core/xgi_drv.h @@ -36,10 +36,10 @@  #define DRIVER_NAME		"xgi"  #define DRIVER_DESC		"XGI XP5 / XP10 / XG47" -#define DRIVER_DATE		"20070721" +#define DRIVER_DATE		"20070723"  #define DRIVER_MAJOR		0 -#define DRIVER_MINOR		9 +#define DRIVER_MINOR		10  #define DRIVER_PATCHLEVEL	0  #include "xgi_cmdlist.h" | 
