#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);
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;
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;
}
*/
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));
}
}
/**
* 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;
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);
}
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[] = {
.remove = __devexit_p(drm_cleanup_pci),
},
+ .fence_driver = &xgi_fence_driver,
+
.name = DRIVER_NAME,
.desc = DRIVER_DESC,
.date = DRIVER_DATE,
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,
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;
#define DRIVER_DATE "20070814"
#define DRIVER_MAJOR 0
-#define DRIVER_MINOR 12
+#define DRIVER_MINOR 13
#define DRIVER_PATCHLEVEL 0
#include "xgi_cmdlist.h"
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);
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,