diff options
Diffstat (limited to 'linux-core')
| -rw-r--r-- | linux-core/xgi_cmdlist.c | 2 | ||||
| -rw-r--r-- | linux-core/xgi_drv.c | 21 | ||||
| -rw-r--r-- | linux-core/xgi_drv.h | 13 | ||||
| -rw-r--r-- | linux-core/xgi_fence.c | 92 | 
4 files changed, 113 insertions, 15 deletions
| diff --git a/linux-core/xgi_cmdlist.c b/linux-core/xgi_cmdlist.c index 64401ae5..e433c21d 100644 --- a/linux-core/xgi_cmdlist.c +++ b/linux-core/xgi_cmdlist.c @@ -148,7 +148,9 @@ int xgi_submit_cmdlist(struct drm_device * dev, void * data,  	}  	info->cmdring.last_ptr = xgi_find_pcie_virt(info, pCmdInfo->hw_addr); +#ifdef XGI_HAVE_FENCE  	drm_fence_flush_old(info->dev, 0, info->next_sequence); +#endif /* XGI_HAVE_FENCE */  	return 0;  } diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index f0225f89..532408db 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -37,7 +37,9 @@ static struct pci_device_id pciidlist[] = {  	xgi_PCI_IDS  }; +#ifdef XGI_HAVE_FENCE  extern struct drm_fence_driver xgi_fence_driver; +#endif /* XGI_HAVE_FENCE */  int xgi_bootstrap(struct drm_device *, void *, struct drm_file *); @@ -47,6 +49,8 @@ static struct drm_ioctl_desc xgi_ioctls[] = {  	DRM_IOCTL_DEF(DRM_XGI_FREE, xgi_free_ioctl, DRM_AUTH),  	DRM_IOCTL_DEF(DRM_XGI_SUBMIT_CMDLIST, xgi_submit_cmdlist, DRM_AUTH),  	DRM_IOCTL_DEF(DRM_XGI_STATE_CHANGE, xgi_state_change_ioctl, DRM_AUTH|DRM_MASTER), +	DRM_IOCTL_DEF(DRM_XGI_SET_FENCE, xgi_set_fence_ioctl, DRM_AUTH), +	DRM_IOCTL_DEF(DRM_XGI_WAIT_FENCE, xgi_wait_fence_ioctl, DRM_AUTH),  };  static const int xgi_max_ioctl = DRM_ARRAY_SIZE(xgi_ioctls); @@ -58,6 +62,7 @@ static void xgi_driver_lastclose(struct drm_device * dev);  static void xgi_reclaim_buffers_locked(struct drm_device * dev,  	struct drm_file * filp);  static irqreturn_t xgi_kern_isr(DRM_IRQ_ARGS); +static int xgi_kern_isr_postinstall(struct drm_device * dev);  static struct drm_driver driver = { @@ -70,7 +75,7 @@ static struct drm_driver driver = {  	.lastclose = xgi_driver_lastclose,  	.dma_quiescent = NULL,  	.irq_preinstall = NULL, -	.irq_postinstall = NULL, +	.irq_postinstall = xgi_kern_isr_postinstall,  	.irq_uninstall = NULL,  	.irq_handler = xgi_kern_isr,  	.reclaim_buffers = drm_core_reclaim_buffers, @@ -100,7 +105,9 @@ static struct drm_driver driver = {  		.remove = __devexit_p(drm_cleanup_pci),  	}, +#ifdef XGI_HAVE_FENCE  	.fence_driver = &xgi_fence_driver, +#endif /* XGI_HAVE_FENCE */  	.name = DRIVER_NAME,  	.desc = DRIVER_DESC, @@ -355,7 +362,10 @@ irqreturn_t xgi_kern_isr(DRM_IRQ_ARGS)  		DRM_WRITE32(info->mmio_map,  			    0x2800 + M2REG_AUTO_LINK_SETTING_ADDRESS,  			    cpu_to_le32(M2REG_AUTO_LINK_SETTING_COMMAND | irq_bits)); +#ifdef XGI_HAVE_FENCE  		xgi_fence_handler(dev); +#endif /* XGI_HAVE_FENCE */ +		DRM_WAKEUP(&info->fence_queue);  		return IRQ_HANDLED;  	} else {  		return IRQ_NONE; @@ -363,6 +373,15 @@ irqreturn_t xgi_kern_isr(DRM_IRQ_ARGS)  } +int xgi_kern_isr_postinstall(struct drm_device * dev) +{ +	struct xgi_info *info = dev->dev_private; + +	DRM_INIT_WAITQUEUE(&info->fence_queue); +	return 0; +} + +  int xgi_driver_load(struct drm_device *dev, unsigned long flags)  {  	struct xgi_info *info = drm_alloc(sizeof(*info), DRM_MEM_DRIVER); diff --git a/linux-core/xgi_drv.h b/linux-core/xgi_drv.h index 0d85e559..2fd73b9e 100644 --- a/linux-core/xgi_drv.h +++ b/linux-core/xgi_drv.h @@ -74,6 +74,7 @@ struct xgi_info {  	struct xgi_cmdring_info cmdring;  	DRM_SPINTYPE fence_lock; +	wait_queue_head_t fence_queue;  	unsigned complete_sequence;  	unsigned next_sequence;  }; @@ -98,12 +99,24 @@ extern void xgi_disable_mmio(struct xgi_info * info);  extern void xgi_enable_ge(struct xgi_info * info);  extern void xgi_disable_ge(struct xgi_info * info); +/* TTM-style fences. + */ +#ifdef XGI_HAVE_FENCE  extern void xgi_poke_flush(struct drm_device * dev, uint32_t class);  extern int xgi_fence_emit_sequence(struct drm_device * dev, uint32_t class,  	uint32_t flags, uint32_t * sequence, uint32_t * native_type);  extern void xgi_fence_handler(struct drm_device * dev);  extern int xgi_fence_has_irq(struct drm_device *dev, uint32_t class,  	uint32_t flags); +#endif /* XGI_HAVE_FENCE */ + + +/* Non-TTM-style fences. + */ +extern int xgi_set_fence_ioctl(struct drm_device * dev, void * data, +	struct drm_file * filp); +extern int xgi_wait_fence_ioctl(struct drm_device * dev, void * data, +	struct drm_file * filp);  extern int xgi_alloc_ioctl(struct drm_device * dev, void * data,  	struct drm_file * filp); diff --git a/linux-core/xgi_fence.c b/linux-core/xgi_fence.c index 63ed29ee..38cf9e4f 100644 --- a/linux-core/xgi_fence.c +++ b/linux-core/xgi_fence.c @@ -30,6 +30,76 @@  #include "xgi_misc.h"  #include "xgi_cmdlist.h" +static int xgi_low_level_fence_emit(struct drm_device *dev, u32 *sequence) +{ +	struct xgi_info *const info = dev->dev_private; + +	if (info == NULL) { +		DRM_ERROR("called with no initialization\n"); +		return -EINVAL; +	} + +	DRM_SPINLOCK(&info->fence_lock); +	info->next_sequence++; +	if (info->next_sequence > BEGIN_BEGIN_IDENTIFICATION_MASK) { +		info->next_sequence = 1; +	} + +	*sequence = (u32) info->next_sequence; +	DRM_SPINUNLOCK(&info->fence_lock); + + +	xgi_emit_irq(info); +	return 0; +} + +#define GET_BEGIN_ID(i) (le32_to_cpu(DRM_READ32((i)->mmio_map, 0x2820)) \ +				 & BEGIN_BEGIN_IDENTIFICATION_MASK) + +static int xgi_low_level_fence_wait(struct drm_device *dev, unsigned *sequence) +{ +	struct xgi_info *const info = dev->dev_private; +	unsigned int cur_fence; +	int ret = 0; + +	if (info == NULL) { +		DRM_ERROR("called with no initialization\n"); +		return -EINVAL; +	} + +	/* Assume that the user has missed the current sequence number +	 * by about a day rather than she wants to wait for years +	 * using fences. +	 */ +	DRM_WAIT_ON(ret, info->fence_queue, 3 * DRM_HZ, +		    ((((cur_fence = GET_BEGIN_ID(info)) +		      - *sequence) & BEGIN_BEGIN_IDENTIFICATION_MASK) +		     <= (1 << 18))); + +	info->complete_sequence = cur_fence; +	*sequence = cur_fence; + +	return ret; +} + + +int xgi_set_fence_ioctl(struct drm_device * dev, void * data, +			struct drm_file * filp) +{ +	(void) filp; +	return xgi_low_level_fence_emit(dev, (u32 *) data); +} + + +int xgi_wait_fence_ioctl(struct drm_device * dev, void * data, +			 struct drm_file * filp) +{ +	(void) filp; +	return xgi_low_level_fence_wait(dev, (u32 *) data); +} + + +#ifdef XGI_HAVE_FENCE  static void xgi_fence_poll(struct drm_device * dev, uint32_t class,   			   uint32_t waiting_types)  { @@ -68,25 +138,18 @@ int xgi_fence_emit_sequence(struct drm_device * dev, uint32_t class,  			    uint32_t flags, uint32_t * sequence,  			    uint32_t * native_type)  { -	struct xgi_info * info = dev->dev_private; +	int err; -	if ((info == NULL) || (class != 0)) -		return -EINVAL; - - -	DRM_SPINLOCK(&info->fence_lock); -	info->next_sequence++; -	if (info->next_sequence > BEGIN_BEGIN_IDENTIFICATION_MASK) { -		info->next_sequence = 1; -	} -	DRM_SPINUNLOCK(&info->fence_lock); +	(void) flags; +	if (class != 0) +		return -EINVAL; -	xgi_emit_irq(info); +	err = xgi_low_level_fence_emit(dev, sequence); +	if (err) +		return err; -	*sequence = (uint32_t) info->next_sequence;  	*native_type = DRM_FENCE_TYPE_EXE; -  	return 0;  } @@ -120,3 +183,4 @@ struct drm_fence_driver xgi_fence_driver = {  	.wait = NULL  }; +#endif /* XGI_HAVE_FENCE */ | 
