From d8a800b63de09f41d482d2b3367e4da67ed0f92b Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Wed, 15 Aug 2007 21:05:26 -0700 Subject: Implement fence support. --- linux-core/Makefile.kernel | 3 +- linux-core/xgi_cmdlist.c | 76 ++++++++++++++++++++++++++++++++++++---------- linux-core/xgi_cmdlist.h | 2 ++ linux-core/xgi_drv.c | 18 +++++++++++ linux-core/xgi_drv.h | 13 +++++++- linux-core/xgi_regs.h | 9 ++++++ 6 files changed, 103 insertions(+), 18 deletions(-) (limited to 'linux-core') diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index c898206d..c651b0b2 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -38,7 +38,8 @@ via-objs := via_irq.o via_drv.o via_map.o via_mm.o via_dma.o via_verifier.o \ via_video.o via_dmablit.o via_fence.o via_buffer.o mach64-objs := mach64_drv.o mach64_dma.o mach64_irq.o mach64_state.o nv-objs := nv_drv.o -xgi-objs := xgi_cmdlist.o xgi_drv.o xgi_fb.o xgi_misc.o xgi_pcie.o +xgi-objs := xgi_cmdlist.o xgi_drv.o xgi_fb.o xgi_misc.o xgi_pcie.o \ + xgi_fence.o ifeq ($(CONFIG_COMPAT),y) drm-objs += drm_ioc32.o diff --git a/linux-core/xgi_cmdlist.c b/linux-core/xgi_cmdlist.c index a728c0ef..5409892a 100644 --- a/linux-core/xgi_cmdlist.c +++ b/linux-core/xgi_cmdlist.c @@ -28,8 +28,10 @@ #include "xgi_regs.h" #include "xgi_misc.h" #include "xgi_cmdlist.h" +#include -static void xgi_emit_flush(struct xgi_info * info, bool link); +static void xgi_emit_flush(struct xgi_info * info, bool stop); +static void xgi_emit_nop(struct xgi_info * info); static unsigned int get_batch_command(enum xgi_batch_type type); static void triggerHWCommandList(struct xgi_info * info); static void xgi_cmdlist_reset(struct xgi_info * info); @@ -101,7 +103,7 @@ int xgi_submit_cmdlist(struct drm_device * dev, void * data, begin[0] = (cmd << 24) | BEGIN_VALID_MASK - | (BEGIN_BEGIN_IDENTIFICATION_MASK & pCmdInfo->id); + | (BEGIN_BEGIN_IDENTIFICATION_MASK & info->next_sequence); begin[1] = BEGIN_LINK_ENABLE_MASK | pCmdInfo->size; begin[2] = pCmdInfo->hw_addr >> 4; begin[3] = 0; @@ -134,19 +136,20 @@ int xgi_submit_cmdlist(struct drm_device * dev, void * data, DRM_DEBUG("info->cmdring.last_ptr != NULL\n"); if (pCmdInfo->type == BTYPE_3D) { - xgi_emit_flush(info, TRUE); + xgi_emit_flush(info, FALSE); } info->cmdring.last_ptr[1] = begin[1]; info->cmdring.last_ptr[2] = begin[2]; info->cmdring.last_ptr[3] = begin[3]; - wmb(); + DRM_WRITEMEMORYBARRIER(); info->cmdring.last_ptr[0] = begin[0]; triggerHWCommandList(info); } info->cmdring.last_ptr = xgi_find_pcie_virt(info, pCmdInfo->hw_addr); + drm_fence_flush_old(info->dev, 0, info->next_sequence); return 0; } @@ -213,9 +216,11 @@ void xgi_cmdlist_cleanup(struct xgi_info * info) */ if (info->cmdring.last_ptr != NULL) { xgi_emit_flush(info, FALSE); - xgi_waitfor_pci_idle(info); + xgi_emit_nop(info); } + xgi_waitfor_pci_idle(info); + (void) memset(&info->cmdring, 0, sizeof(info->cmdring)); } } @@ -233,23 +238,25 @@ static void triggerHWCommandList(struct xgi_info * info) /** * Emit a flush to the CRTL command stream. * @info XGI info structure - * @link Emit (or don't emit) link information at start of flush command. * * This function assumes info->cmdring.ptr is non-NULL. */ -static void xgi_emit_flush(struct xgi_info * info, bool link) +void xgi_emit_flush(struct xgi_info * info, bool stop) { - static const u32 flush_command[8] = { - (0x10 << 24), + const u32 flush_command[8] = { + ((0x10 << 24) + | (BEGIN_BEGIN_IDENTIFICATION_MASK & info->next_sequence)), BEGIN_LINK_ENABLE_MASK | (0x00004), 0x00000000, 0x00000000, - /* Flush everything with the default 32 clock delay. + /* Flush the 2D engine with the default 32 clock delay. */ - 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff + M2REG_FLUSH_ENGINE_COMMAND | M2REG_FLUSH_2D_ENGINE_MASK, + M2REG_FLUSH_ENGINE_COMMAND | M2REG_FLUSH_2D_ENGINE_MASK, + M2REG_FLUSH_ENGINE_COMMAND | M2REG_FLUSH_2D_ENGINE_MASK, + M2REG_FLUSH_ENGINE_COMMAND | M2REG_FLUSH_2D_ENGINE_MASK, }; - const unsigned int base = (link) ? 0 : 4; - const unsigned int flush_size = (8 - base) * sizeof(u32); + const unsigned int flush_size = sizeof(flush_command); u32 *batch_addr; u32 hw_addr; @@ -263,17 +270,54 @@ static void xgi_emit_flush(struct xgi_info * info, bool link) batch_addr = info->cmdring.ptr + (info->cmdring.ring_offset / 4); - (void) memcpy(batch_addr, & flush_command[base], flush_size); + (void) memcpy(batch_addr, flush_command, flush_size); + + if (stop) { + *batch_addr |= BEGIN_STOP_STORE_CURRENT_POINTER_MASK; + } info->cmdring.last_ptr[1] = BEGIN_LINK_ENABLE_MASK | (flush_size / 4); info->cmdring.last_ptr[2] = hw_addr >> 4; info->cmdring.last_ptr[3] = 0; - wmb(); + DRM_WRITEMEMORYBARRIER(); info->cmdring.last_ptr[0] = (get_batch_command(BTYPE_CTRL) << 24) | (BEGIN_VALID_MASK); triggerHWCommandList(info); info->cmdring.ring_offset += flush_size; - info->cmdring.last_ptr = (link) ? batch_addr : NULL; + info->cmdring.last_ptr = batch_addr; +} + + +/** + * Emit an empty command to the CRTL command stream. + * @info XGI info structure + * + * This function assumes info->cmdring.ptr is non-NULL. In addition, since + * this function emits a command that does not have linkage information, + * it sets info->cmdring.ptr to NULL. + */ +void xgi_emit_nop(struct xgi_info * info) +{ + info->cmdring.last_ptr[1] = BEGIN_LINK_ENABLE_MASK + | (BEGIN_BEGIN_IDENTIFICATION_MASK & info->next_sequence); + info->cmdring.last_ptr[2] = 0; + info->cmdring.last_ptr[3] = 0; + DRM_WRITEMEMORYBARRIER(); + info->cmdring.last_ptr[0] = (get_batch_command(BTYPE_CTRL) << 24) + | (BEGIN_VALID_MASK); + + triggerHWCommandList(info); + + info->cmdring.last_ptr = NULL; +} + + +void xgi_emit_irq(struct xgi_info * info) +{ + if (info->cmdring.last_ptr == NULL) + return; + + xgi_emit_flush(info, TRUE); } diff --git a/linux-core/xgi_cmdlist.h b/linux-core/xgi_cmdlist.h index dc3fbe5a..f6f1c1ef 100644 --- a/linux-core/xgi_cmdlist.h +++ b/linux-core/xgi_cmdlist.h @@ -61,4 +61,6 @@ extern int xgi_state_change(struct xgi_info * info, unsigned int to, extern void xgi_cmdlist_cleanup(struct xgi_info * info); +extern void xgi_emit_irq(struct xgi_info * info); + #endif /* _XGI_CMDLIST_H_ */ diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index 0e77d4cd..241cd39f 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -37,6 +37,17 @@ static struct pci_device_id pciidlist[] = { xgi_PCI_IDS }; +static struct drm_fence_driver xgi_fence_driver = { + .num_classes = 1, + .wrap_diff = BEGIN_BEGIN_IDENTIFICATION_MASK, + .flush_diff = BEGIN_BEGIN_IDENTIFICATION_MASK - 1, + .sequence_mask = BEGIN_BEGIN_IDENTIFICATION_MASK, + .lazy_capable = 1, + .emit = xgi_fence_emit_sequence, + .poke_flush = xgi_poke_flush, + .has_irq = xgi_fence_has_irq +}; + static int xgi_bootstrap(struct drm_device *, void *, struct drm_file *); static struct drm_ioctl_desc xgi_ioctls[] = { @@ -95,6 +106,8 @@ static struct drm_driver driver = { .remove = __devexit_p(drm_cleanup_pci), }, + .fence_driver = &xgi_fence_driver, + .name = DRIVER_NAME, .desc = DRIVER_DESC, .date = DRIVER_DATE, @@ -189,6 +202,10 @@ int xgi_bootstrap(struct drm_device * dev, void * data, int err; + spin_lock_init(&info->fence_lock); + info->next_sequence = 0; + info->complete_sequence = 0; + if (info->mmio_map == NULL) { err = drm_addmap(dev, info->mmio.base, info->mmio.size, _DRM_REGISTERS, _DRM_KERNEL, @@ -344,6 +361,7 @@ irqreturn_t xgi_kern_isr(DRM_IRQ_ARGS) DRM_WRITE32(info->mmio_map, 0x2800 + M2REG_AUTO_LINK_SETTING_ADDRESS, M2REG_AUTO_LINK_SETTING_COMMAND | irq_bits); + xgi_fence_handler(dev); return IRQ_HANDLED; } else { return IRQ_NONE; diff --git a/linux-core/xgi_drv.h b/linux-core/xgi_drv.h index 194313cd..c815f63e 100644 --- a/linux-core/xgi_drv.h +++ b/linux-core/xgi_drv.h @@ -38,7 +38,7 @@ #define DRIVER_DATE "20070814" #define DRIVER_MAJOR 0 -#define DRIVER_MINOR 12 +#define DRIVER_MINOR 13 #define DRIVER_PATCHLEVEL 0 #include "xgi_cmdlist.h" @@ -72,6 +72,10 @@ struct xgi_info { bool pcie_heap_initialized; struct xgi_cmdring_info cmdring; + + spinlock_t fence_lock; + unsigned complete_sequence; + unsigned next_sequence; }; extern int xgi_fb_heap_init(struct xgi_info * info); @@ -92,6 +96,13 @@ 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); +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); + extern int xgi_alloc_ioctl(struct drm_device * dev, void * data, struct drm_file * filp); extern int xgi_free_ioctl(struct drm_device * dev, void * data, diff --git a/linux-core/xgi_regs.h b/linux-core/xgi_regs.h index 2f9fbe64..5c0100a0 100644 --- a/linux-core/xgi_regs.h +++ b/linux-core/xgi_regs.h @@ -83,6 +83,14 @@ #define M2REG_FLUSH_2D_ENGINE_MASK (ONE_BIT_MASK<<20) #define M2REG_FLUSH_3D_ENGINE_MASK TWENTY_BIT_MASK +#define M2REG_RESET_ADDRESS 0x004 +#define M2REG_RESET_COMMAND 0x01 +#define M2REG_RESET_STATUS2_MASK (ONE_BIT_MASK<<10) +#define M2REG_RESET_STATUS1_MASK (ONE_BIT_MASK<<9) +#define M2REG_RESET_STATUS0_MASK (ONE_BIT_MASK<<8) +#define M2REG_RESET_3DENG_MASK (ONE_BIT_MASK<<4) +#define M2REG_RESET_2DENG_MASK (ONE_BIT_MASK<<2) + /* Write register */ #define M2REG_AUTO_LINK_SETTING_ADDRESS 0x010 #define M2REG_AUTO_LINK_SETTING_COMMAND 0x04 @@ -110,6 +118,7 @@ /** * Begin instruction, double-word 0 */ +#define BEGIN_STOP_STORE_CURRENT_POINTER_MASK (ONE_BIT_MASK<<22) #define BEGIN_VALID_MASK (ONE_BIT_MASK<<20) #define BEGIN_BEGIN_IDENTIFICATION_MASK TWENTY_BIT_MASK -- cgit v1.2.3