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)) + (void) flags; + + if (class != 0) return -EINVAL; + err = xgi_low_level_fence_emit(dev, sequence); + if (err) + return err; - 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); - - - xgi_emit_irq(info); - - *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 */ diff --git a/shared-core/xgi_drm.h b/shared-core/xgi_drm.h index ce584420..7d01065e 100644 --- a/shared-core/xgi_drm.h +++ b/shared-core/xgi_drm.h @@ -123,11 +123,15 @@ struct xgi_state_info { #define DRM_XGI_FREE 2 #define DRM_XGI_SUBMIT_CMDLIST 3 #define DRM_XGI_STATE_CHANGE 4 +#define DRM_XGI_SET_FENCE 5 +#define DRM_XGI_WAIT_FENCE 6 #define XGI_IOCTL_BOOTSTRAP DRM_IOWR(DRM_COMMAND_BASE + DRM_XGI_BOOTSTRAP, struct xgi_bootstrap) #define XGI_IOCTL_ALLOC DRM_IOWR(DRM_COMMAND_BASE + DRM_XGI_ALLOC, struct xgi_mem_alloc) #define XGI_IOCTL_FREE DRM_IOW(DRM_COMMAND_BASE + DRM_XGI_FREE, __u32) #define XGI_IOCTL_SUBMIT_CMDLIST DRM_IOW(DRM_COMMAND_BASE + DRM_XGI_SUBMIT_CMDLIST, struct xgi_cmd_info) #define XGI_IOCTL_STATE_CHANGE DRM_IOW(DRM_COMMAND_BASE + DRM_XGI_STATE_CHANGE, struct xgi_state_info) +#define XGI_IOCTL_SET_FENCE DRM_IOWR(DRM_COMMAND_BASE + DRM_XGI_SET_FENCE, u32) +#define XGI_IOCTL_WAIT_FENCE DRM_IOWR(DRM_COMMAND_BASE + DRM_XGI_WAIT_FENCE, u32) #endif /* _XGI_DRM_H_ */