Implement fence support.
authorIan Romanick <idr@us.ibm.com>
Thu, 16 Aug 2007 04:05:26 +0000 (21:05 -0700)
committerIan Romanick <idr@us.ibm.com>
Thu, 16 Aug 2007 04:05:26 +0000 (21:05 -0700)
linux-core/Makefile.kernel
linux-core/xgi_cmdlist.c
linux-core/xgi_cmdlist.h
linux-core/xgi_drv.c
linux-core/xgi_drv.h
linux-core/xgi_regs.h

index c898206..c651b0b 100644 (file)
@@ -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
index a728c0e..5409892 100644 (file)
 #include "xgi_regs.h"
 #include "xgi_misc.h"
 #include "xgi_cmdlist.h"
+#include <linux/delay.h>
 
-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);
 }
index dc3fbe5..f6f1c1e 100644 (file)
@@ -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_ */
index 0e77d4c..241cd39 100644 (file)
@@ -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;
index 194313c..c815f63 100644 (file)
@@ -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,
index 2f9fbe6..5c0100a 100644 (file)
 #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
 /**
  * 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