summaryrefslogtreecommitdiff
path: root/linux-core
diff options
context:
space:
mode:
Diffstat (limited to 'linux-core')
-rw-r--r--linux-core/xgi_cmdlist.c2
-rw-r--r--linux-core/xgi_drv.c21
-rw-r--r--linux-core/xgi_drv.h13
-rw-r--r--linux-core/xgi_fence.c92
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 */