summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Hellstrom <unichrome@shipmail.org>2005-03-28 21:21:42 +0000
committerThomas Hellstrom <unichrome@shipmail.org>2005-03-28 21:21:42 +0000
commit532ccb98b5f2946f574a747b90c39edbe783f888 (patch)
treecfbdf4e8e2b8e0827b35b92a7e57e7f6104e18f1
parentc6161eff86b250f3113791edcc162dc97322c401 (diff)
Via updates:
New PCI command parser. Moved from via_dma.c to via_verifier.c so functions with similar functionality are close to eachother. Moved video related functions to via_video.c, which might be extended in the future, as new video functionality is added. New device-specific generic IRQ IOCTL, similar to the general VBLANK IOCTL, but with support for multiple device IRQ sources and functionality. Support for Unichrome Pro PM800/CN400 video DMA commands in verifier and PCI parser. Support for Unichrome Pro PM800/CN400 HQV IRQs in the new generic IRQ IOCTL. Bumped minor. New version 2.6.0.
-rw-r--r--linux-core/Makefile2
-rw-r--r--linux-core/Makefile.kernel3
-rw-r--r--linux-core/drm_irq.c4
-rw-r--r--linux/Makefile2
-rw-r--r--linux/Makefile.kernel3
-rw-r--r--shared-core/via_dma.c70
-rw-r--r--shared-core/via_drm.h24
-rw-r--r--shared-core/via_drv.c3
-rw-r--r--shared-core/via_drv.h27
-rw-r--r--shared-core/via_irq.c192
-rw-r--r--shared-core/via_map.c36
-rw-r--r--shared-core/via_mm.c19
-rw-r--r--shared-core/via_verifier.c181
-rw-r--r--shared/via.h11
-rw-r--r--shared/via_dma.c74
-rw-r--r--shared/via_drm.h24
-rw-r--r--shared/via_drv.h22
-rw-r--r--shared/via_irq.c247
-rw-r--r--shared/via_map.c35
-rw-r--r--shared/via_mm.c17
-rw-r--r--shared/via_verifier.c181
21 files changed, 865 insertions, 312 deletions
diff --git a/linux-core/Makefile b/linux-core/Makefile
index bc9c00a0..64704a35 100644
--- a/linux-core/Makefile
+++ b/linux-core/Makefile
@@ -93,7 +93,7 @@ VIAHEADERS = via_drm.h via_drv.h via_mm.h via_ds.h \
via_3d_reg.h via_verifier.h $(DRMHEADERS)
VIASHARED = via_drm.h via_drv.h via_mm.h via_ds.h \
via_3d_reg.h via_drv.c via_ds.c via_irq.c via_map.c \
- via_mm.c via_dma.c via_verifier.c via_verifier.h
+ via_mm.c via_dma.c via_verifier.c via_verifier.h via_video.c
MACH64HEADERS = mach64_drv.h mach64_drm.h $(DRMHEADERS)
MACH64SHARED = mach64_drv.h mach64_drm.h mach64_dma.c \
mach64_irq.c mach64_state.c
diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel
index 6868aa0f..93082355 100644
--- a/linux-core/Makefile.kernel
+++ b/linux-core/Makefile.kernel
@@ -22,7 +22,8 @@ radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o
sis-objs := sis_drv.o sis_ds.o sis_mm.o
ffb-objs := ffb_drv.o ffb_context.o
savage-objs := savage_drv.o savage_bci.o savage_state.o
-via-objs := via_irq.o via_drv.o via_ds.o via_map.o via_mm.o via_dma.o via_verifier.o
+via-objs := via_irq.o via_drv.o via_ds.o via_map.o via_mm.o via_dma.o via_verifier.o \
+ via_video.o
mach64-objs := mach64_drv.o mach64_dma.o mach64_irq.o mach64_state.o
obj-m += drm.o
diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c
index a6ebb173..27c9bc18 100644
--- a/linux-core/drm_irq.c
+++ b/linux-core/drm_irq.c
@@ -222,12 +222,12 @@ int drm_control(struct inode *inode, struct file *filp,
* Wait for VBLANK.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param filp file pointer.rm.
* \param cmd command.
* \param data user argument, pointing to a drm_wait_vblank structure.
* \return zero on success or a negative number on failure.
*
- * Verifies the IRQ is installed.
+ * Verifies the IRQ is installed
*
* If a signal is requested checks if this task has already scheduled the same signal
* for the same vblank sequence number - nothing to be done in
diff --git a/linux/Makefile b/linux/Makefile
index 08654cf2..ac1d25c0 100644
--- a/linux/Makefile
+++ b/linux/Makefile
@@ -99,7 +99,7 @@ VIAHEADERS = via_drm.h via_drv.h via.h via_mm.h via_ds.h \
via_3d_reg.h $(DRMHEADERS) $(DRMTEMPLATES)
VIASHARED = via_drm.h via_drv.h via.h via_mm.h via_ds.h \
via_3d_reg.h via_drv.c via_ds.c via_irq.c via_map.c \
- via_mm.c via_dma.c via_verifier.c via_verifier.h
+ via_mm.c via_dma.c via_verifier.c via_verifier.h via_video.c
MACH64HEADERS = mach64.h mach64_drv.h mach64_drm.h $(DRMHEADERS) \
$(DRMTEMPLATES)
MACH64SHARED = mach64.h mach64_drv.h mach64_drm.h mach64_dma.c \
diff --git a/linux/Makefile.kernel b/linux/Makefile.kernel
index edd885f7..40b54e04 100644
--- a/linux/Makefile.kernel
+++ b/linux/Makefile.kernel
@@ -17,7 +17,8 @@ radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o
sis-objs := sis_drv.o sis_ds.o sis_mm.o
ffb-objs := ffb_drv.o ffb_context.o
savage-objs := savage_drv.o savage_dma.o
-via-objs := via_irq.o via_drv.o via_ds.o via_map.o via_mm.o via_dma.o via_verifier.o
+via-objs := via_irq.o via_drv.o via_ds.o via_map.o via_mm.o via_dma.o via_verifier.o \
+ via_video.o
mach64-objs := mach64_drv.o mach64_dma.o mach64_irq.o mach64_state.o
# Kernel version checks
diff --git a/shared-core/via_dma.c b/shared-core/via_dma.c
index 1f5d3b94..081fefc1 100644
--- a/shared-core/via_dma.c
+++ b/shared-core/via_dma.c
@@ -28,7 +28,10 @@
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
- * Authors: Various
+ * Authors:
+ * Tungsten Graphics,
+ * Erdi Chen,
+ * Thomas Hellstrom.
*/
#include "drmP.h"
@@ -58,7 +61,7 @@
dev_priv->dma_low +=8; \
}
-#define via_flush_write_combine() DRM_MEMORYBARRIER()
+#define via_flush_write_combine() DRM_MEMORYBARRIER()
#define VIA_OUT_RING_QW(w1,w2) \
*vb++ = (w1); \
@@ -275,7 +278,7 @@ static int via_dispatch_cmdbuffer(drm_device_t * dev, drm_via_cmdbuffer_t * cmd)
* copy it to AGP memory when ready.
*/
-
+
if ((ret = via_verify_command_stream((uint32_t *)dev_priv->pci_buf, cmd->size, dev, 1))) {
return ret;
}
@@ -333,58 +336,8 @@ int via_cmdbuffer(DRM_IOCTL_ARGS)
return 0;
}
-static int via_parse_pci_cmdbuffer(drm_device_t * dev, const char *buf,
- unsigned int size)
-{
- drm_via_private_t *dev_priv = dev->dev_private;
- const uint32_t *regbuf = (const uint32_t *) buf;
- const uint32_t *regend = regbuf + (size >> 2);
- const uint32_t *next_fire;
- int fire_count = 0;
- int ret;
- int check_2d_cmd = 1;
-
-
-
- if ((ret = via_verify_command_stream(regbuf, size, dev, 0)))
- return ret;
-
- next_fire = dev_priv->fire_offsets[fire_count];
- while (regbuf != regend) {
- if ( *regbuf == HALCYON_HEADER2 ) {
-
- regbuf++;
- check_2d_cmd = ( *regbuf != HALCYON_SUB_ADDR0 );
- VIA_WRITE(HC_REG_TRANS_SET + HC_REG_BASE, *regbuf++);
-
- } else if ( check_2d_cmd && ((*regbuf & HALCYON_HEADER1MASK) == HALCYON_HEADER1 )) {
-
- register uint32_t addr = ( (*regbuf++ ) & ~HALCYON_HEADER1MASK) << 2;
- VIA_WRITE( addr, *regbuf++ );
-
- } else if ( (fire_count < dev_priv->num_fire_offsets) &&
- (regbuf == next_fire) &&
- (( *regbuf & HALCYON_FIREMASK ) == HALCYON_FIRECMD) ) {
-
- next_fire = dev_priv->fire_offsets[++fire_count];
-
- VIA_WRITE(HC_REG_TRANS_SPACE + HC_REG_BASE, *regbuf++);
-
- if ( ( regbuf != regend ) &&
- ((*regbuf & HALCYON_FIREMASK) == HALCYON_FIRECMD))
- regbuf++;
- if (( *regbuf & HALCYON_CMDBMASK ) != HC_ACMD_HCmdB )
- check_2d_cmd = 1;
- } else {
-
- VIA_WRITE(HC_REG_TRANS_SPACE + HC_REG_BASE , *regbuf++);
-
- }
- }
- return 0;
-
-}
-
+extern int
+via_parse_command_stream(drm_device_t *dev, const uint32_t * buf, unsigned int size);
static int via_dispatch_pci_cmdbuffer(drm_device_t * dev,
drm_via_cmdbuffer_t * cmd)
{
@@ -396,7 +349,12 @@ static int via_dispatch_pci_cmdbuffer(drm_device_t * dev,
}
if (DRM_COPY_FROM_USER(dev_priv->pci_buf, cmd->buf, cmd->size))
return DRM_ERR(EFAULT);
- ret = via_parse_pci_cmdbuffer(dev, dev_priv->pci_buf, cmd->size);
+
+ if ((ret = via_verify_command_stream((uint32_t *)dev_priv->pci_buf, cmd->size, dev, 0))) {
+ return ret;
+ }
+
+ ret = via_parse_command_stream(dev, (const uint32_t *)dev_priv->pci_buf, cmd->size);
return ret;
}
diff --git a/shared-core/via_drm.h b/shared-core/via_drm.h
index f3b4a28a..4588c9bd 100644
--- a/shared-core/via_drm.h
+++ b/shared-core/via_drm.h
@@ -73,6 +73,8 @@
#define DRM_VIA_FLUSH 0x09
#define DRM_VIA_PCICMD 0x0a
#define DRM_VIA_CMDBUF_SIZE 0x0b
+#define NOT_USED
+#define DRM_VIA_WAIT_IRQ 0x0d
#define DRM_IOCTL_VIA_ALLOCMEM DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_ALLOCMEM, drm_via_mem_t)
#define DRM_IOCTL_VIA_FREEMEM DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_FREEMEM, drm_via_mem_t)
@@ -86,6 +88,7 @@
#define DRM_IOCTL_VIA_PCICMD DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_PCICMD, drm_via_cmdbuffer_t)
#define DRM_IOCTL_VIA_CMDBUF_SIZE DRM_IOWR( DRM_COMMAND_BASE + DRM_VIA_CMDBUF_SIZE, \
drm_via_cmdbuf_size_t)
+#define DRM_IOCTL_VIA_WAIT_IRQ DRM_IOWR( DRM_COMMAND_BASE + DRM_VIA_WAIT_IRQ, drm_via_irqwait_t)
/* Indices into buf.Setup where various bits of state are mirrored per
* context and per buffer. These can be fired at the card as a unit,
@@ -200,6 +203,26 @@ typedef struct _drm_via_cmdbuf_size {
uint32_t size;
} drm_via_cmdbuf_size_t;
+typedef enum {
+ VIA_IRQ_ABSOLUTE = 0x0,
+ VIA_IRQ_RELATIVE = 0x1,
+ VIA_IRQ_SIGNAL = 0x10000000,
+ VIA_IRQ_FORCE_SEQUENCE = 0x20000000
+} via_irq_seq_type_t;
+
+#define VIA_IRQ_FLAGS_MASK 0xF0000000
+
+struct drm_via_wait_irq_request{
+ unsigned irq;
+ via_irq_seq_type_t type;
+ uint32_t sequence;
+ uint32_t signal;
+};
+
+typedef union drm_via_irqwait {
+ struct drm_via_wait_irq_request request;
+ struct drm_wait_vblank_reply reply;
+} drm_via_irqwait_t;
#ifdef __KERNEL__
@@ -214,6 +237,7 @@ int via_cmdbuffer(DRM_IOCTL_ARGS);
int via_flush_ioctl(DRM_IOCTL_ARGS);
int via_pci_cmdbuffer(DRM_IOCTL_ARGS);
int via_cmdbuf_size(DRM_IOCTL_ARGS);
+int via_wait_irq(DRM_IOCTL_ARGS);
#endif
#endif /* _VIA_DRM_H_ */
diff --git a/shared-core/via_drv.c b/shared-core/via_drv.c
index 13a22eca..21f28a63 100644
--- a/shared-core/via_drv.c
+++ b/shared-core/via_drv.c
@@ -69,7 +69,8 @@ static drm_ioctl_desc_t ioctls[] = {
[DRM_IOCTL_NR(DRM_VIA_CMDBUFFER)] = {via_cmdbuffer, 1, 0},
[DRM_IOCTL_NR(DRM_VIA_FLUSH)] = {via_flush_ioctl, 1, 0},
[DRM_IOCTL_NR(DRM_VIA_PCICMD)] = {via_pci_cmdbuffer, 1, 0},
- [DRM_IOCTL_NR(DRM_VIA_CMDBUF_SIZE)] = {via_cmdbuf_size, 1, 0}
+ [DRM_IOCTL_NR(DRM_VIA_CMDBUF_SIZE)] = {via_cmdbuf_size, 1, 0},
+ [DRM_IOCTL_NR(DRM_VIA_WAIT_IRQ)] = {via_wait_irq, 1, 0}
};
static int probe(struct pci_dev *pdev, const struct pci_device_id *ent);
diff --git a/shared-core/via_drv.h b/shared-core/via_drv.h
index 00382e5d..353a9b9b 100644
--- a/shared-core/via_drv.h
+++ b/shared-core/via_drv.h
@@ -27,23 +27,35 @@
#define DRIVER_AUTHOR "VIA"
#define DRIVER_NAME "via"
-#define DRIVER_DESC "VIA Unichrome"
-#define DRIVER_DATE "20050314"
+#define DRIVER_DESC "VIA Unichrome / Pro"
+#define DRIVER_DATE "20050328"
#define DRIVER_MAJOR 2
-#define DRIVER_MINOR 5
+#define DRIVER_MINOR 6
#define DRIVER_PATCHLEVEL 0
#include "via_verifier.h"
#define VIA_PCI_BUF_SIZE 120000
#define VIA_FIRE_BUF_SIZE 2048
+#define VIA_NUM_IRQS 2
+
+
typedef struct drm_via_ring_buffer {
drm_map_t map;
char *virtual_start;
} drm_via_ring_buffer_t;
+typedef uint32_t maskarray_t[5];
+
+typedef struct drm_via_irq {
+ atomic_t irq_received;
+ uint32_t pending_mask;
+ uint32_t enable_mask;
+ wait_queue_head_t irq_queue;
+} drm_via_irq_t;
+
typedef struct drm_via_private {
drm_via_sarea_t *sarea_priv;
drm_map_t *sarea;
@@ -66,6 +78,12 @@ typedef struct drm_via_private {
char pci_buf[VIA_PCI_BUF_SIZE];
const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE];
uint32_t num_fire_offsets;
+ int pro_group_a;
+ drm_via_irq_t via_irqs[VIA_NUM_IRQS];
+ unsigned num_irqs;
+ maskarray_t *irq_masks;
+ uint32_t irq_enable_mask;
+ uint32_t irq_pending_mask;
} drm_via_private_t;
/* VIA MMIO register access */
@@ -92,6 +110,9 @@ extern void via_driver_irq_uninstall(drm_device_t * dev);
extern int via_dma_cleanup(drm_device_t * dev);
extern void via_init_command_verifier(void);
extern int via_driver_dma_quiescent(drm_device_t * dev);
+extern void via_init_futex(drm_via_private_t *dev_priv);
+extern void via_cleanup_futex(drm_via_private_t *dev_priv);
+extern void via_release_futex(drm_via_private_t *dev_priv, int context);
#endif
diff --git a/shared-core/via_irq.c b/shared-core/via_irq.c
index 2d78dd44..c0a30c63 100644
--- a/shared-core/via_irq.c
+++ b/shared-core/via_irq.c
@@ -2,6 +2,7 @@
*
* Copyright 2004 BEAM Ltd.
* Copyright 2002 Tungsten Graphics, Inc.
+ * Copyright 2005 Thomas Hellstrom.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
@@ -27,10 +28,11 @@
* Authors:
* Terry Barnaby <terry1@beam.ltd.uk>
* Keith Whitwell <keith@tungstengraphics.com>
+ * Thomas Hellstrom <unichrome@shipmail.org>
*
- *
- * This code provides standard DRM access to the Via CLE266's Vertical blank
- * interrupt.
+ * This code provides standard DRM access to the Via Unichrome / Pro Vertical blank
+ * interrupt, as well as an infrastructure to handle other interrupts of the chip.
+ * The refresh rate is also calculated for video playback sync purposes.
*/
#include "drmP.h"
@@ -42,9 +44,26 @@
/* VIA_REG_INTERRUPT */
#define VIA_IRQ_GLOBAL (1 << 31)
-#define VIA_IRQ_VBI_ENABLE (1 << 19)
-#define VIA_IRQ_VBI_PENDING (1 << 3)
+#define VIA_IRQ_VBLANK_ENABLE (1 << 19)
+#define VIA_IRQ_VBLANK_PENDING (1 << 3)
+#define VIA_IRQ_HQV0_ENABLE (1 << 11)
+#define VIA_IRQ_HQV1_ENABLE (1 << 25)
+#define VIA_IRQ_HQV0_PENDING (1 << 9)
+#define VIA_IRQ_HQV1_PENDING (1 << 10)
+
+/*
+ * Device-specific IRQs go here. This type might need to be extended with
+ * the register if there are multiple IRQ control registers.
+ * Currently we activate the HQV interrupts of Unichrome Pro group A.
+ */
+static maskarray_t via_pro_group_a_irqs[] = {
+ {VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010, 0x00000000 },
+ {VIA_IRQ_HQV1_ENABLE, VIA_IRQ_HQV1_PENDING, 0x000013D0, 0x00008010, 0x00000000 }};
+static int via_num_pro_group_a = sizeof(via_pro_group_a_irqs)/sizeof(maskarray_t);
+
+static maskarray_t via_unichrome_irqs[] = {};
+static int via_num_unichrome = sizeof(via_unichrome_irqs)/sizeof(maskarray_t);
static unsigned time_diff(struct timeval *now,struct timeval *then)
@@ -61,9 +80,11 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
u32 status;
int handled = 0;
struct timeval cur_vblank;
+ drm_via_irq_t *cur_irq = dev_priv->via_irqs;
+ int i;
status = VIA_READ(VIA_REG_INTERRUPT);
- if (status & VIA_IRQ_VBI_PENDING) {
+ if (status & VIA_IRQ_VBLANK_PENDING) {
atomic_inc(&dev->vbl_received);
if (!(atomic_read(&dev->vbl_received) & 0x0F)) {
do_gettimeofday(&cur_vblank);
@@ -82,10 +103,28 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
drm_vbl_send_signals(dev);
handled = 1;
}
+
+
+ for (i=0; i<dev_priv->num_irqs; ++i) {
+ if (status & cur_irq->pending_mask) {
+ atomic_inc( &cur_irq->irq_received );
+ DRM_WAKEUP( &cur_irq->irq_queue );
+ handled = 1;
+ VIA_WRITE(VIA_REG_INTERRUPT, status);
+
+ if (handled)
+ return IRQ_HANDLED;
+ else
+ return IRQ_NONE;
- /* Acknowlege interrupts ?? */
+ }
+ cur_irq++;
+ }
+
+ /* Acknowlege interrupts */
VIA_WRITE(VIA_REG_INTERRUPT, status);
+
if (handled)
return IRQ_HANDLED;
else
@@ -97,9 +136,10 @@ static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t * dev_priv)
u32 status;
if (dev_priv) {
- /* Acknowlege interrupts ?? */
+ /* Acknowlege interrupts */
status = VIA_READ(VIA_REG_INTERRUPT);
- VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_VBI_PENDING);
+ VIA_WRITE(VIA_REG_INTERRUPT, status |
+ dev_priv->irq_pending_mask);
}
}
@@ -121,32 +161,94 @@ int via_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)
* by about a day rather than she wants to wait for years
* using vertical blanks...
*/
+
DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
(((cur_vblank = atomic_read(&dev->vbl_received)) -
*sequence) <= (1 << 23)));
-
+
*sequence = cur_vblank;
return ret;
}
+static int
+via_driver_irq_wait(drm_device_t * dev, unsigned int irq, int force_sequence,
+ unsigned int *sequence)
+{
+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+ unsigned int cur_irq_sequence;
+ drm_via_irq_t *cur_irq = dev_priv->via_irqs;
+ int ret = 0;
+ maskarray_t *masks = dev_priv->irq_masks;
+
+ DRM_DEBUG("%s\n", __FUNCTION__);
+
+ if (!dev_priv) {
+ DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+ return DRM_ERR(EINVAL);
+ }
+
+ if (irq >= dev_priv->num_irqs ) {
+ DRM_ERROR("%s Trying to wait on unknown irq %d\n", __FUNCTION__, irq);
+ return DRM_ERR(EINVAL);
+ }
+
+ cur_irq += irq;
+
+ if (masks[irq][2] && !force_sequence) {
+ DRM_WAIT_ON(ret, cur_irq->irq_queue, 3 * DRM_HZ,
+ ((VIA_READ(masks[irq][2]) & masks[irq][3]) == masks[irq][4]));
+ cur_irq_sequence = atomic_read(&cur_irq->irq_received);
+ } else {
+ DRM_WAIT_ON(ret, cur_irq->irq_queue, 3 * DRM_HZ,
+ (((cur_irq_sequence = atomic_read(&cur_irq->irq_received)) -
+ *sequence) <= (1 << 23)));
+ }
+ *sequence = cur_irq_sequence;
+ return ret;
+}
+
+
/*
* drm_dma.h hooks
*/
+
void via_driver_irq_preinstall(drm_device_t * dev)
{
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
u32 status;
+ drm_via_irq_t *cur_irq = dev_priv->via_irqs;
+ int i;
DRM_DEBUG("driver_irq_preinstall: dev_priv: %p\n", dev_priv);
if (dev_priv) {
+
+ dev_priv->irq_enable_mask = VIA_IRQ_VBLANK_ENABLE;
+ dev_priv->irq_pending_mask = VIA_IRQ_VBLANK_PENDING;
+
+ dev_priv->irq_masks = (dev_priv->pro_group_a) ?
+ via_pro_group_a_irqs : via_unichrome_irqs;
+ dev_priv->num_irqs = (dev_priv->pro_group_a) ?
+ via_num_pro_group_a : via_num_unichrome;
+
+ for(i=0; i < dev_priv->num_irqs; ++i) {
+ atomic_set(&cur_irq->irq_received, 0);
+ cur_irq->enable_mask = dev_priv->irq_masks[i][0];
+ cur_irq->pending_mask = dev_priv->irq_masks[i][1];
+ DRM_INIT_WAITQUEUE( &cur_irq->irq_queue );
+ dev_priv->irq_enable_mask |= cur_irq->enable_mask;
+ dev_priv->irq_pending_mask |= cur_irq->pending_mask;
+ cur_irq++;
+
+ DRM_DEBUG("Initializing IRQ %d\n", i);
+ }
+
dev_priv->last_vblank_valid = 0;
- DRM_DEBUG("mmio: %p\n", dev_priv->mmio);
- status = VIA_READ(VIA_REG_INTERRUPT);
- DRM_DEBUG("intreg: %x\n", status & VIA_IRQ_VBI_ENABLE);
// Clear VSync interrupt regs
- VIA_WRITE(VIA_REG_INTERRUPT, status & ~VIA_IRQ_VBI_ENABLE);
-
+ status = VIA_READ(VIA_REG_INTERRUPT);
+ VIA_WRITE(VIA_REG_INTERRUPT, status &
+ ~(dev_priv->irq_enable_mask));
+
/* Clear bits if they're already high */
viadrv_acknowledge_irqs(dev_priv);
}
@@ -161,12 +263,13 @@ void via_driver_irq_postinstall(drm_device_t * dev)
if (dev_priv) {
status = VIA_READ(VIA_REG_INTERRUPT);
VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL
- | VIA_IRQ_VBI_ENABLE);
+ | dev_priv->irq_enable_mask);
+
/* Some magic, oh for some data sheets ! */
VIA_WRITE8(0x83d4, 0x11);
VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
-
+
}
}
@@ -184,7 +287,60 @@ void via_driver_irq_uninstall(drm_device_t * dev)
VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) & ~0x30);
status = VIA_READ(VIA_REG_INTERRUPT);
- VIA_WRITE(VIA_REG_INTERRUPT, status & ~VIA_IRQ_VBI_ENABLE);
+ VIA_WRITE(VIA_REG_INTERRUPT, status &
+ ~(VIA_IRQ_VBLANK_ENABLE | dev_priv->irq_enable_mask));
}
}
+int via_wait_irq(DRM_IOCTL_ARGS)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->head->dev;
+ drm_via_irqwait_t __user *argp = (void __user *)data;
+ drm_via_irqwait_t irqwait;
+ struct timeval now;
+ int ret = 0;
+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+ drm_via_irq_t *cur_irq = dev_priv->via_irqs;
+ int force_sequence;
+
+ if (!dev->irq)
+ return DRM_ERR(EINVAL);
+
+ DRM_COPY_FROM_USER_IOCTL(irqwait, argp, sizeof(irqwait));
+ if (irqwait.request.irq >= dev_priv->num_irqs) {
+ DRM_ERROR("%s Trying to wait on unknown irq %d\n", __FUNCTION__,
+ irqwait.request.irq);
+ return DRM_ERR(EINVAL);
+ }
+
+ cur_irq += irqwait.request.irq;
+
+ switch (irqwait.request.type & ~VIA_IRQ_FLAGS_MASK) {
+ case VIA_IRQ_RELATIVE:
+ irqwait.request.sequence += atomic_read(&cur_irq->irq_received);
+ irqwait.request.type &= ~_DRM_VBLANK_RELATIVE;
+ case VIA_IRQ_ABSOLUTE:
+ break;
+ default:
+ return DRM_ERR(EINVAL);
+ }
+
+ if (irqwait.request.type & VIA_IRQ_SIGNAL) {
+ DRM_ERROR("%s Signals on Via IRQs not implemented yet.\n",
+ __FUNCTION__);
+ return DRM_ERR(EINVAL);
+ }
+
+ force_sequence = (irqwait.request.type & VIA_IRQ_FORCE_SEQUENCE);
+
+ ret = via_driver_irq_wait(dev, irqwait.request.irq, force_sequence,
+ &irqwait.request.sequence);
+ do_gettimeofday(&now);
+ irqwait.reply.tval_sec = now.tv_sec;
+ irqwait.reply.tval_usec = now.tv_usec;
+
+ DRM_COPY_TO_USER_IOCTL(argp, irqwait, sizeof(irqwait));
+
+ return ret;
+}
diff --git a/shared-core/via_map.c b/shared-core/via_map.c
index 50ca96cb..0be829b6 100644
--- a/shared-core/via_map.c
+++ b/shared-core/via_map.c
@@ -28,7 +28,6 @@
static int via_do_init_map(drm_device_t * dev, drm_via_init_t * init)
{
drm_via_private_t *dev_priv;
- unsigned int i;
DRM_DEBUG("%s\n", __FUNCTION__);
@@ -67,13 +66,10 @@ static int via_do_init_map(drm_device_t * dev, drm_via_init_t * init)
dev_priv->agpAddr = init->agpAddr;
- for (i = 0; i < VIA_NR_XVMC_LOCKS; ++i) {
- DRM_INIT_WAITQUEUE(&(dev_priv->decoder_queue[i]));
- XVMCLOCKPTR(dev_priv->sarea_priv, i)->lock = 0;
- }
+ via_init_futex( dev_priv );
+ dev_priv->pro_group_a = (dev->pdev->device == 0x3118);
dev->dev_private = (void *)dev_priv;
-
return 0;
}
@@ -112,31 +108,3 @@ int via_map_init(DRM_IOCTL_ARGS)
}
-int via_decoder_futex(DRM_IOCTL_ARGS)
-{
- DRM_DEVICE;
- drm_via_futex_t fx;
- volatile int *lock;
- drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
- drm_via_sarea_t *sAPriv = dev_priv->sarea_priv;
- int ret = 0;
-
- DRM_COPY_FROM_USER_IOCTL(fx, (drm_via_futex_t *) data, sizeof(fx));
-
- if (fx.lock > VIA_NR_XVMC_LOCKS)
- return -EFAULT;
-
- lock = (int *)XVMCLOCKPTR(sAPriv, fx.lock);
-
- switch (fx.func) {
- case VIA_FUTEX_WAIT:
- DRM_WAIT_ON(ret, dev_priv->decoder_queue[fx.lock],
- (fx.ms / 10) * (DRM_HZ / 100), *lock != fx.val);
- return ret;
- case VIA_FUTEX_WAKE:
- DRM_WAKEUP(&(dev_priv->decoder_queue[fx.lock]));
- return 0;
- }
- return 0;
-}
-
diff --git a/shared-core/via_mm.c b/shared-core/via_mm.c
index 5cead8c4..cf286b49 100644
--- a/shared-core/via_mm.c
+++ b/shared-core/via_mm.c
@@ -135,9 +135,7 @@ int via_init_context(struct drm_device *dev, int context)
int via_final_context(struct drm_device *dev, int context)
{
int i;
- volatile int *lock;
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
- drm_via_sarea_t *sAPriv = dev_priv->sarea_priv;
for (i = 0; i < MAX_CONTEXT; i++)
if (global_ppriv[i].used &&
@@ -170,23 +168,10 @@ int via_final_context(struct drm_device *dev, int context)
retval = via_setNext(set, &item);
}
via_setDestroy(set);
-
global_ppriv[i].used = 0;
}
+ via_release_futex(dev_priv, context);
- /*
- * Release futex locks.
- */
-
- for (i=0; i < VIA_NR_XVMC_LOCKS; ++i) {
- lock = (int *) XVMCLOCKPTR(sAPriv, i);
- if ( (_DRM_LOCKING_CONTEXT( *lock ) == context)) {
- if (_DRM_LOCK_IS_HELD( *lock ) && (*lock & _DRM_LOCK_CONT)) {
- DRM_WAKEUP( &(dev_priv->decoder_queue[i]));
- }
- *lock = 0;
- }
- }
#if defined(__linux__)
/* Linux specific until context tracking code gets ported to BSD */
@@ -196,6 +181,7 @@ int via_final_context(struct drm_device *dev, int context)
if (dev->irq)
drm_irq_uninstall(dev);
+ via_cleanup_futex(dev_priv);
via_do_cleanup_map(dev);
}
#endif
@@ -208,6 +194,7 @@ int via_mem_alloc(DRM_IOCTL_ARGS)
drm_via_mem_t mem;
DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t *) data, sizeof(mem));
+
switch (mem.type) {
case VIDEO:
if (via_fb_alloc(&mem) < 0)
diff --git a/shared-core/via_verifier.c b/shared-core/via_verifier.c
index 6b08f5d8..5b1f30a7 100644
--- a/shared-core/via_verifier.c
+++ b/shared-core/via_verifier.c
@@ -1,5 +1,6 @@
/*
* Copyright 2004 The Unichrome Project. All Rights Reserved.
+ * Copyright 2005 Thomas Hellstrom. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -15,12 +16,12 @@
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE UNICHROME PROJECT, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * THE AUTHOR(S), AND/OR THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
- * Author: Thomas Hellström 2004.
+ * Author: Thomas Hellstrom 2004, 2005.
* This code was written using docs obtained under NDA from VIA Inc.
*
* Don't run this code directly on an AGP buffer. Due to cache problems it will
@@ -677,16 +678,62 @@ via_check_header2( uint32_t const **buffer, const uint32_t *buf_end,
return state_command;
}
+static __inline__ verifier_state_t
+via_parse_header2( drm_via_private_t *dev_priv, uint32_t const **buffer, const uint32_t *buf_end,
+ int *fire_count)
+{
+ uint32_t cmd;
+ const uint32_t *buf = *buffer;
+ const uint32_t *next_fire;
+ int burst = 0;
+
+ next_fire = dev_priv->fire_offsets[*fire_count];
+ buf++;
+ cmd = (*buf & 0xFFFF0000) >> 16;
+ VIA_WRITE(HC_REG_TRANS_SET + HC_REG_BASE, *buf++);
+ switch(cmd) {
+ case HC_ParaType_CmdVdata:
+ while ((buf < buf_end) &&
+ (*fire_count < dev_priv->num_fire_offsets) &&
+ (*buf & HC_ACMD_MASK) == HC_ACMD_HCmdB ) {
+ while(buf <= next_fire) {
+ VIA_WRITE(HC_REG_TRANS_SPACE + HC_REG_BASE + (burst & 63), *buf++);
+ burst += 4;
+ }
+ if ( ( buf < buf_end ) && ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD))
+ buf++;
+
+ if (++(*fire_count) < dev_priv->num_fire_offsets)
+ next_fire = dev_priv->fire_offsets[*fire_count];
+ }
+ break;
+ default:
+ while(buf < buf_end) {
+
+ if ( *buf == HC_HEADER2 ||
+ (*buf & HALCYON_HEADER1MASK) == HALCYON_HEADER1 ||
+ (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5 ||
+ (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6 ) break;
+
+ VIA_WRITE(HC_REG_TRANS_SPACE + HC_REG_BASE + (burst & 63), *buf++);
+ burst +=4;
+ }
+ }
+ *buffer = buf;
+ return state_command;
+}
+
+
static __inline__ int
verify_mmio_address( uint32_t address)
{
if ((address > 0x3FF) && (address < 0xC00 )) {
- DRM_ERROR("Invalid HALCYON_HEADER1 command. "
+ DRM_ERROR("Invalid VIDEO DMA command. "
"Attempt to access 3D- or command burst area.\n");
return 1;
- } else if (address > 0xCFF ) {
- DRM_ERROR("Invalid HALCYON_HEADER1 command. "
+ } else if (address > 0x13FF ) {
+ DRM_ERROR("Invalid VIDEO DMA command. "
"Attempt to access VGA registers.\n");
return 1;
}
@@ -746,6 +793,22 @@ via_check_header1( uint32_t const **buffer, const uint32_t *buf_end )
}
static __inline__ verifier_state_t
+via_parse_header1( drm_via_private_t *dev_priv, uint32_t const **buffer, const uint32_t *buf_end )
+{
+ register uint32_t cmd;
+ const uint32_t *buf = *buffer;
+
+ while (buf < buf_end) {
+ cmd = *buf;
+ if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1) break;
+ VIA_WRITE( (cmd & ~HALCYON_HEADER1MASK) << 2, *++buf);
+ buf++;
+ }
+ *buffer = buf;
+ return state_command;
+}
+
+static __inline__ verifier_state_t
via_check_vheader5( uint32_t const **buffer, const uint32_t *buf_end )
{
uint32_t data;
@@ -771,7 +834,7 @@ via_check_vheader5( uint32_t const **buffer, const uint32_t *buf_end )
}
if (eat_words(&buf, buf_end, data))
return state_error;
- if (verify_video_tail(&buf, buf_end, 4 - (data & 3)))
+ if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3)))
return state_error;
*buffer = buf;
return state_command;
@@ -779,19 +842,36 @@ via_check_vheader5( uint32_t const **buffer, const uint32_t *buf_end )
}
static __inline__ verifier_state_t
+via_parse_vheader5( drm_via_private_t *dev_priv, uint32_t const **buffer, const uint32_t *buf_end )
+{
+ uint32_t addr, count, i;
+ const uint32_t *buf = *buffer;
+
+ addr = *buf++ & ~VIA_VIDEOMASK;
+ i = count = *buf;
+ buf += 3;
+ while(i--) {
+ VIA_WRITE(addr, *buf++);
+ }
+ if (count & 3) buf += 4 - (count & 3);
+ *buffer = buf;
+ return state_command;
+}
+
+
+static __inline__ verifier_state_t
via_check_vheader6( uint32_t const **buffer, const uint32_t *buf_end )
{
uint32_t data;
const uint32_t *buf = *buffer;
uint32_t i;
- DRM_ERROR("H6\n");
if (buf_end - buf < 4) {
DRM_ERROR("Illegal termination of video header6 command\n");
return state_error;
}
-
+ buf++;
data = *buf++;
if (*buf++ != 0x00F60000) {
DRM_ERROR("Illegal header6 header data\n");
@@ -803,18 +883,40 @@ via_check_vheader6( uint32_t const **buffer, const uint32_t *buf_end )
}
if ((buf_end - buf) < (data << 1)) {
DRM_ERROR("Illegal termination of video header6 command\n");
+ return state_error;
}
for (i=0; i<data; ++i) {
if (verify_mmio_address(*buf++))
return state_error;
buf++;
}
- if (verify_video_tail(&buf, buf_end, 4 - ((data << 1) & 3)))
+ data <<= 1;
+ if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3)))
return state_error;
*buffer = buf;
return state_command;
}
+static __inline__ verifier_state_t
+via_parse_vheader6( drm_via_private_t *dev_priv, uint32_t const **buffer, const uint32_t *buf_end )
+{
+
+ uint32_t addr, count, i;
+ const uint32_t *buf = *buffer;
+
+ i = count = *++buf;
+ buf += 3;
+ while(i--) {
+ addr = *buf++;
+ VIA_WRITE(addr, *buf++);
+ }
+ count <<= 1;
+ if (count & 3) buf += 4 - (count & 3);
+ *buffer = buf;
+ return state_command;
+}
+
+
int
via_verify_command_stream(const uint32_t * buf, unsigned int size, drm_device_t *dev,
@@ -827,7 +929,7 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size, drm_device_t
uint32_t cmd;
const uint32_t *buf_end = buf + ( size >> 2 );
verifier_state_t state = state_command;
-
+ int pro_group_a = dev_priv->pro_group_a;
hc_state->dev = dev;
hc_state->unfinished = no_sequence;
@@ -840,7 +942,7 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size, drm_device_t
switch (state) {
case state_header2:
- state = via_check_header2( &buf, buf_end, hc_state );
+ state = via_check_header2( &buf, buf_end, hc_state );
break;
case state_header1:
state = via_check_header1( &buf, buf_end );
@@ -856,9 +958,9 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size, drm_device_t
state = state_header2;
else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
state = state_header1;
- else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5)
+ else if (pro_group_a && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5)
state = state_vheader5;
- else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
+ else if (pro_group_a && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
state = state_vheader6;
else {
DRM_ERROR("Invalid / Unimplemented DMA HEADER command. 0x%x\n",
@@ -879,6 +981,59 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size, drm_device_t
return 0;
}
+int
+via_parse_command_stream(drm_device_t *dev, const uint32_t * buf, unsigned int size)
+{
+
+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+ uint32_t cmd;
+ const uint32_t *buf_end = buf + ( size >> 2 );
+ verifier_state_t state = state_command;
+ int fire_count = 0;
+
+ while (buf < buf_end) {
+
+ switch (state) {
+ case state_header2:
+ state = via_parse_header2( dev_priv, &buf, buf_end, &fire_count );
+ break;
+ case state_header1:
+ state = via_parse_header1( dev_priv, &buf, buf_end );
+ break;
+ case state_vheader5:
+ state = via_parse_vheader5( dev_priv, &buf, buf_end );
+ break;
+ case state_vheader6:
+ state = via_parse_vheader6( dev_priv, &buf, buf_end );
+ break;
+ case state_command:
+ if (HALCYON_HEADER2 == (cmd = *buf))
+ state = state_header2;
+ else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
+ state = state_header1;
+ else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5)
+ state = state_vheader5;
+ else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
+ state = state_vheader6;
+ else {
+ DRM_ERROR("Invalid / Unimplemented DMA HEADER command. 0x%x\n",
+ cmd);
+ state = state_error;
+ }
+ break;
+ case state_error:
+ default:
+ return DRM_ERR(EINVAL);
+ }
+ }
+ if (state == state_error) {
+ return DRM_ERR(EINVAL);
+ }
+ return 0;
+}
+
+
+
static void
setup_hazard_table(hz_init_t init_table[], hazard_t table[], int size)
{
diff --git a/shared/via.h b/shared/via.h
index b35164e4..816880e7 100644
--- a/shared/via.h
+++ b/shared/via.h
@@ -29,11 +29,11 @@
#define DRIVER_AUTHOR "VIA"
#define DRIVER_NAME "via"
-#define DRIVER_DESC "VIA Unichrome"
-#define DRIVER_DATE "20050314"
+#define DRIVER_DESC "VIA Unichrome / Pro"
+#define DRIVER_DATE "20050328"
#define DRIVER_MAJOR 2
-#define DRIVER_MINOR 5
+#define DRIVER_MINOR 6
#define DRIVER_PATCHLEVEL 0
#define DRIVER_IOCTLS \
@@ -46,8 +46,9 @@
[DRM_IOCTL_NR(DRM_IOCTL_VIA_DMA_INIT)] = { via_dma_init, 1, 0}, \
[DRM_IOCTL_NR(DRM_IOCTL_VIA_CMDBUFFER)] = { via_cmdbuffer, 1, 0}, \
[DRM_IOCTL_NR(DRM_IOCTL_VIA_FLUSH)] = { via_flush_ioctl, 1, 0}, \
- [DRM_IOCTL_NR(DRM_IOCTL_VIA_PCICMD)] = { via_pci_cmdbuffer, 1, 0}, \
- [DRM_IOCTL_NR(DRM_IOCTL_VIA_CMDBUF_SIZE)] = {via_cmdbuf_size, 1, 0}
+ [DRM_IOCTL_NR(DRM_IOCTL_VIA_PCICMD)] = {via_pci_cmdbuffer, 1, 0}, \
+ [DRM_IOCTL_NR(DRM_IOCTL_VIA_CMDBUF_SIZE)] = {via_cmdbuf_size, 1, 0}, \
+ [DRM_IOCTL_NR(DRM_IOCTL_VIA_WAIT_IRQ)] = {via_wait_irq, 1, 0}
#endif
diff --git a/shared/via_dma.c b/shared/via_dma.c
index 6f877c5c..34ac6cc1 100644
--- a/shared/via_dma.c
+++ b/shared/via_dma.c
@@ -28,7 +28,10 @@
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
- * Authors: Various
+ * Authors:
+ * Tungsten Graphics,
+ * Erdi Chen,
+ * Thomas Hellstrom.
*/
#include "via.h"
@@ -59,7 +62,7 @@
dev_priv->dma_low +=8; \
}
-#define via_flush_write_combine() DRM_MEMORYBARRIER()
+#define via_flush_write_combine() DRM_MEMORYBARRIER()
#define VIA_OUT_RING_QW(w1,w2) \
*vb++ = (w1); \
@@ -70,7 +73,7 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv);
static void via_cmdbuf_pause(drm_via_private_t * dev_priv);
static void via_cmdbuf_reset(drm_via_private_t * dev_priv);
static void via_cmdbuf_rewind(drm_via_private_t * dev_priv);
-
+static int via_wait_idle(drm_via_private_t * dev_priv);
/*
* Free space in command buffer.
*/
@@ -276,7 +279,7 @@ static int via_dispatch_cmdbuffer(drm_device_t * dev, drm_via_cmdbuffer_t * cmd)
* copy it to AGP memory when ready.
*/
-
+
if ((ret = via_verify_command_stream((uint32_t *)dev_priv->pci_buf, cmd->size, dev, 1))) {
return ret;
}
@@ -334,58 +337,8 @@ int via_cmdbuffer(DRM_IOCTL_ARGS)
return 0;
}
-static int via_parse_pci_cmdbuffer(drm_device_t * dev, const char *buf,
- unsigned int size)
-{
- drm_via_private_t *dev_priv = dev->dev_private;
- const uint32_t *regbuf = (const uint32_t *) buf;
- const uint32_t *regend = regbuf + (size >> 2);
- const uint32_t *next_fire;
- int fire_count = 0;
- int ret;
- int check_2d_cmd = 1;
-
-
-
- if ((ret = via_verify_command_stream(regbuf, size, dev, 0)))
- return ret;
-
- next_fire = dev_priv->fire_offsets[fire_count];
- while (regbuf != regend) {
- if ( *regbuf == HALCYON_HEADER2 ) {
-
- regbuf++;
- check_2d_cmd = ( *regbuf != HALCYON_SUB_ADDR0 );
- VIA_WRITE(HC_REG_TRANS_SET + HC_REG_BASE, *regbuf++);
-
- } else if ( check_2d_cmd && ((*regbuf & HALCYON_HEADER1MASK) == HALCYON_HEADER1 )) {
-
- register uint32_t addr = ( (*regbuf++ ) & ~HALCYON_HEADER1MASK) << 2;
- VIA_WRITE( addr, *regbuf++ );
-
- } else if ( (fire_count < dev_priv->num_fire_offsets) &&
- (regbuf == next_fire) &&
- (( *regbuf & HALCYON_FIREMASK ) == HALCYON_FIRECMD) ) {
-
- next_fire = dev_priv->fire_offsets[++fire_count];
-
- VIA_WRITE(HC_REG_TRANS_SPACE + HC_REG_BASE, *regbuf++);
-
- if ( ( regbuf != regend ) &&
- ((*regbuf & HALCYON_FIREMASK) == HALCYON_FIRECMD))
- regbuf++;
- if (( *regbuf & HALCYON_CMDBMASK ) != HC_ACMD_HCmdB )
- check_2d_cmd = 1;
- } else {
-
- VIA_WRITE(HC_REG_TRANS_SPACE + HC_REG_BASE , *regbuf++);
-
- }
- }
- return 0;
-
-}
-
+extern int
+via_parse_command_stream(drm_device_t *dev, const uint32_t * buf, unsigned int size);
static int via_dispatch_pci_cmdbuffer(drm_device_t * dev,
drm_via_cmdbuffer_t * cmd)
{
@@ -397,7 +350,12 @@ static int via_dispatch_pci_cmdbuffer(drm_device_t * dev,
}
if (DRM_COPY_FROM_USER(dev_priv->pci_buf, cmd->buf, cmd->size))
return DRM_ERR(EFAULT);
- ret = via_parse_pci_cmdbuffer(dev, dev_priv->pci_buf, cmd->size);
+
+ if ((ret = via_verify_command_stream((uint32_t *)dev_priv->pci_buf, cmd->size, dev, 0))) {
+ return ret;
+ }
+
+ ret = via_parse_command_stream(dev, (const uint32_t *)dev_priv->pci_buf, cmd->size);
return ret;
}
@@ -515,7 +473,7 @@ static int via_hook_segment(drm_via_private_t *dev_priv,
-int via_wait_idle(drm_via_private_t * dev_priv)
+static int via_wait_idle(drm_via_private_t * dev_priv)
{
int count = 10000000;
while (count-- && (VIA_READ(VIA_REG_STATUS) &
diff --git a/shared/via_drm.h b/shared/via_drm.h
index f3b4a28a..4588c9bd 100644
--- a/shared/via_drm.h
+++ b/shared/via_drm.h
@@ -73,6 +73,8 @@
#define DRM_VIA_FLUSH 0x09
#define DRM_VIA_PCICMD 0x0a
#define DRM_VIA_CMDBUF_SIZE 0x0b
+#define NOT_USED
+#define DRM_VIA_WAIT_IRQ 0x0d
#define DRM_IOCTL_VIA_ALLOCMEM DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_ALLOCMEM, drm_via_mem_t)
#define DRM_IOCTL_VIA_FREEMEM DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_FREEMEM, drm_via_mem_t)
@@ -86,6 +88,7 @@
#define DRM_IOCTL_VIA_PCICMD DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_PCICMD, drm_via_cmdbuffer_t)
#define DRM_IOCTL_VIA_CMDBUF_SIZE DRM_IOWR( DRM_COMMAND_BASE + DRM_VIA_CMDBUF_SIZE, \
drm_via_cmdbuf_size_t)
+#define DRM_IOCTL_VIA_WAIT_IRQ DRM_IOWR( DRM_COMMAND_BASE + DRM_VIA_WAIT_IRQ, drm_via_irqwait_t)
/* Indices into buf.Setup where various bits of state are mirrored per
* context and per buffer. These can be fired at the card as a unit,
@@ -200,6 +203,26 @@ typedef struct _drm_via_cmdbuf_size {
uint32_t size;
} drm_via_cmdbuf_size_t;
+typedef enum {
+ VIA_IRQ_ABSOLUTE = 0x0,
+ VIA_IRQ_RELATIVE = 0x1,
+ VIA_IRQ_SIGNAL = 0x10000000,
+ VIA_IRQ_FORCE_SEQUENCE = 0x20000000
+} via_irq_seq_type_t;
+
+#define VIA_IRQ_FLAGS_MASK 0xF0000000
+
+struct drm_via_wait_irq_request{
+ unsigned irq;
+ via_irq_seq_type_t type;
+ uint32_t sequence;
+ uint32_t signal;
+};
+
+typedef union drm_via_irqwait {
+ struct drm_via_wait_irq_request request;
+ struct drm_wait_vblank_reply reply;
+} drm_via_irqwait_t;
#ifdef __KERNEL__
@@ -214,6 +237,7 @@ int via_cmdbuffer(DRM_IOCTL_ARGS);
int via_flush_ioctl(DRM_IOCTL_ARGS);
int via_pci_cmdbuffer(DRM_IOCTL_ARGS);
int via_cmdbuf_size(DRM_IOCTL_ARGS);
+int via_wait_irq(DRM_IOCTL_ARGS);
#endif
#endif /* _VIA_DRM_H_ */
diff --git a/shared/via_drv.h b/shared/via_drv.h
index 5d90c9ca..8227b735 100644
--- a/shared/via_drv.h
+++ b/shared/via_drv.h
@@ -29,12 +29,23 @@
#define VIA_PCI_BUF_SIZE 120000
#define VIA_FIRE_BUF_SIZE 2048
+#define VIA_NUM_IRQS 2
+
typedef struct drm_via_ring_buffer {
drm_map_t map;
char *virtual_start;
} drm_via_ring_buffer_t;
+typedef uint32_t maskarray_t[5];
+
+typedef struct drm_via_irq {
+ atomic_t irq_received;
+ uint32_t pending_mask;
+ uint32_t enable_mask;
+ wait_queue_head_t irq_queue;
+} drm_via_irq_t;
+
typedef struct drm_via_private {
drm_via_sarea_t *sarea_priv;
drm_map_t *sarea;
@@ -57,6 +68,12 @@ typedef struct drm_via_private {
char pci_buf[VIA_PCI_BUF_SIZE];
const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE];
uint32_t num_fire_offsets;
+ int pro_group_a;
+ drm_via_irq_t via_irqs[VIA_NUM_IRQS];
+ unsigned num_irqs;
+ maskarray_t *irq_masks;
+ uint32_t irq_enable_mask;
+ uint32_t irq_pending_mask;
} drm_via_private_t;
/* VIA MMIO register access */
@@ -82,10 +99,13 @@ extern void via_driver_irq_postinstall(drm_device_t * dev);
extern void via_driver_irq_uninstall(drm_device_t * dev);
extern int via_dma_cleanup(drm_device_t * dev);
-extern int via_wait_idle(drm_via_private_t * dev_priv);
extern int via_driver_dma_quiescent(drm_device_t * dev);
extern void via_init_command_verifier( void );
extern int via_fb_free(drm_via_mem_t * mem);
extern int via_fb_alloc(drm_via_mem_t * mem);
+extern void via_init_futex(drm_via_private_t *dev_priv);
+extern void via_cleanup_futex(drm_via_private_t *dev_priv);
+extern void via_release_futex(drm_via_private_t *dev_priv, int context);
+
#endif
diff --git a/shared/via_irq.c b/shared/via_irq.c
index 1e22a773..f61081c2 100644
--- a/shared/via_irq.c
+++ b/shared/via_irq.c
@@ -2,6 +2,7 @@
*
* Copyright 2004 BEAM Ltd.
* Copyright 2002 Tungsten Graphics, Inc.
+ * Copyright 2005 Thomas Hellstrom.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
@@ -10,27 +11,28 @@
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
- *
+ *
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * BEAM LTD, TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * BEAM LTD, TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
- * Authors:
+ * Authors:
* Terry Barnaby <terry1@beam.ltd.uk>
* Keith Whitwell <keith@tungstengraphics.com>
+ * Thomas Hellstrom <unichrome@shipmail.org>
*
- *
- * This code provides standard DRM access to the Via CLE266's Vertical blank
- * interrupt.
+ * This code provides standard DRM access to the Via Unichrome / Pro Vertical blank
+ * interrupt, as well as an infrastructure to handle other interrupts of the chip.
+ * The refresh rate is also calculated for video playback sync purposes.
*/
#include "via.h"
@@ -43,39 +45,91 @@
/* VIA_REG_INTERRUPT */
#define VIA_IRQ_GLOBAL (1 << 31)
-#define VIA_IRQ_VBI_ENABLE (1 << 19)
-#define VIA_IRQ_SEC_VBI_ENABLE (1 << 17)
-#define VIA_IRQ_SEC_VBI_PENDING (1 << 15)
-#define VIA_IRQ_VBI_PENDING (1 << 3)
+#define VIA_IRQ_VBLANK_ENABLE (1 << 19)
+#define VIA_IRQ_VBLANK_PENDING (1 << 3)
+#define VIA_IRQ_HQV0_ENABLE (1 << 11)
+#define VIA_IRQ_HQV1_ENABLE (1 << 25)
+#define VIA_IRQ_HQV0_PENDING (1 << 9)
+#define VIA_IRQ_HQV1_PENDING (1 << 10)
+
+/*
+ * Device-specific IRQs go here. This type might need to be extended with
+ * the register if there are multiple IRQ control registers.
+ * Currently we activate the HQV interrupts of Unichrome Pro group A.
+ */
+
+static maskarray_t via_pro_group_a_irqs[] = {
+ {VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010, 0x00000000 },
+ {VIA_IRQ_HQV1_ENABLE, VIA_IRQ_HQV1_PENDING, 0x000013D0, 0x00008010, 0x00000000 }};
+static int via_num_pro_group_a = sizeof(via_pro_group_a_irqs)/sizeof(maskarray_t);
+
+static maskarray_t via_unichrome_irqs[] = {};
+static int via_num_unichrome = sizeof(via_unichrome_irqs)/sizeof(maskarray_t);
+static unsigned time_diff(struct timeval *now,struct timeval *then)
+{
+ return (now->tv_usec >= then->tv_usec) ?
+ now->tv_usec - then->tv_usec :
+ 1000000 - (then->tv_usec - now->tv_usec);
+}
irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
{
drm_device_t *dev = (drm_device_t *) arg;
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
- u32 status = VIA_READ(VIA_REG_INTERRUPT);
+ u32 status;
+ int handled = 0;
+ struct timeval cur_vblank;
+ drm_via_irq_t *cur_irq = dev_priv->via_irqs;
+ int i;
- if (status & VIA_IRQ_VBI_PENDING) {
+ status = VIA_READ(VIA_REG_INTERRUPT);
+ if (status & VIA_IRQ_VBLANK_PENDING) {
atomic_inc(&dev->vbl_received);
+ if (!(atomic_read(&dev->vbl_received) & 0x0F)) {
+ do_gettimeofday(&cur_vblank);
+ if (dev_priv->last_vblank_valid) {
+ dev_priv->usec_per_vblank =
+ time_diff( &cur_vblank,&dev_priv->last_vblank) >> 4;
+ }
+ dev_priv->last_vblank = cur_vblank;
+ dev_priv->last_vblank_valid = 1;
+ }
+ if (!(atomic_read(&dev->vbl_received) & 0xFF)) {
+ DRM_DEBUG("US per vblank is: %u\n",
+ dev_priv->usec_per_vblank);
+ }
DRM_WAKEUP(&dev->vbl_queue);
- DRM(vbl_send_signals) (dev);
-
- VIA_WRITE(VIA_REG_INTERRUPT, status);
- return IRQ_HANDLED;
+ DRM(vbl_send_signals)( dev );
+ handled = 1;
}
+
-#if 0
- if (status & VIA_IRQ_SEC_VBI_PENDING) {
- atomic_inc(&dev->sec_vbl_received);
- DRM_WAKEUP(&dev->sec_vbl_queue);
- DRM(vbl_send_signals)(dev); /* KW: Need a parameter here? */
- handled = IRQ_HANDLED;
- }
-#endif
+ for (i=0; i<dev_priv->num_irqs; ++i) {
+ if (status & cur_irq->pending_mask) {
+ atomic_inc( &cur_irq->irq_received );
+ DRM_WAKEUP( &cur_irq->irq_queue );
+ handled = 1;
+ VIA_WRITE(VIA_REG_INTERRUPT, status);
+ if (handled)
+ return IRQ_HANDLED;
+ else
+ return IRQ_NONE;
+
+ }
+ cur_irq++;
+ }
+
+ /* Acknowlege interrupts */
VIA_WRITE(VIA_REG_INTERRUPT, status);
- return IRQ_NONE;
+
+
+ if (handled)
+ return IRQ_HANDLED;
+ else
+ return IRQ_NONE;
}
static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t * dev_priv)
@@ -83,9 +137,10 @@ static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t * dev_priv)
u32 status;
if (dev_priv) {
- /* Acknowlege interrupts ?? */
+ /* Acknowlege interrupts */
status = VIA_READ(VIA_REG_INTERRUPT);
- VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_VBI_PENDING);
+ VIA_WRITE(VIA_REG_INTERRUPT, status |
+ dev_priv->irq_pending_mask);
}
}
@@ -105,34 +160,96 @@ int via_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)
/* Assume that the user has missed the current sequence number
* by about a day rather than she wants to wait for years
- * using vertical blanks...
+ * using vertical blanks...
*/
+
DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
(((cur_vblank = atomic_read(&dev->vbl_received)) -
*sequence) <= (1 << 23)));
-
+
*sequence = cur_vblank;
return ret;
}
+static int
+via_driver_irq_wait(drm_device_t * dev, unsigned int irq, int force_sequence,
+ unsigned int *sequence)
+{
+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+ unsigned int cur_irq_sequence;
+ drm_via_irq_t *cur_irq = dev_priv->via_irqs;
+ int ret = 0;
+ maskarray_t *masks = dev_priv->irq_masks;
+
+ DRM_DEBUG("%s\n", __FUNCTION__);
+
+ if (!dev_priv) {
+ DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+ return DRM_ERR(EINVAL);
+ }
+
+ if (irq >= dev_priv->num_irqs ) {
+ DRM_ERROR("%s Trying to wait on unknown irq %d\n", __FUNCTION__, irq);
+ return DRM_ERR(EINVAL);
+ }
+
+ cur_irq += irq;
+
+ if (masks[irq][2] && !force_sequence) {
+ DRM_WAIT_ON(ret, cur_irq->irq_queue, 3 * DRM_HZ,
+ ((VIA_READ(masks[irq][2]) & masks[irq][3]) == masks[irq][4]));
+ cur_irq_sequence = atomic_read(&cur_irq->irq_received);
+ } else {
+ DRM_WAIT_ON(ret, cur_irq->irq_queue, 3 * DRM_HZ,
+ (((cur_irq_sequence = atomic_read(&cur_irq->irq_received)) -
+ *sequence) <= (1 << 23)));
+ }
+ *sequence = cur_irq_sequence;
+ return ret;
+}
+
+
/*
* drm_dma.h hooks
*/
+
void via_driver_irq_preinstall(drm_device_t * dev)
{
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
u32 status;
+ drm_via_irq_t *cur_irq = dev_priv->via_irqs;
+ int i;
DRM_DEBUG("driver_irq_preinstall: dev_priv: %p\n", dev_priv);
if (dev_priv) {
+
+ dev_priv->irq_enable_mask = VIA_IRQ_VBLANK_ENABLE;
+ dev_priv->irq_pending_mask = VIA_IRQ_VBLANK_PENDING;
+
+ dev_priv->irq_masks = (dev_priv->pro_group_a) ?
+ via_pro_group_a_irqs : via_unichrome_irqs;
+ dev_priv->num_irqs = (dev_priv->pro_group_a) ?
+ via_num_pro_group_a : via_num_unichrome;
+
+ for(i=0; i < dev_priv->num_irqs; ++i) {
+ atomic_set(&cur_irq->irq_received, 0);
+ cur_irq->enable_mask = dev_priv->irq_masks[i][0];
+ cur_irq->pending_mask = dev_priv->irq_masks[i][1];
+ DRM_INIT_WAITQUEUE( &cur_irq->irq_queue );
+ dev_priv->irq_enable_mask |= cur_irq->enable_mask;
+ dev_priv->irq_pending_mask |= cur_irq->pending_mask;
+ cur_irq++;
+
+ DRM_DEBUG("Initializing IRQ %d\n", i);
+ }
+
dev_priv->last_vblank_valid = 0;
- DRM_DEBUG("mmio: %p\n", dev_priv->mmio);
- status = VIA_READ(VIA_REG_INTERRUPT);
- DRM_DEBUG("intreg: %x\n", status & VIA_IRQ_VBI_ENABLE);
// Clear VSync interrupt regs
- VIA_WRITE(VIA_REG_INTERRUPT, status & ~VIA_IRQ_VBI_ENABLE);
-
+ status = VIA_READ(VIA_REG_INTERRUPT);
+ VIA_WRITE(VIA_REG_INTERRUPT, status &
+ ~(dev_priv->irq_enable_mask));
+
/* Clear bits if they're already high */
viadrv_acknowledge_irqs(dev_priv);
}
@@ -147,12 +264,13 @@ void via_driver_irq_postinstall(drm_device_t * dev)
if (dev_priv) {
status = VIA_READ(VIA_REG_INTERRUPT);
VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL
- | VIA_IRQ_VBI_ENABLE);
+ | dev_priv->irq_enable_mask);
+
/* Some magic, oh for some data sheets ! */
VIA_WRITE8(0x83d4, 0x11);
VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
-
+
}
}
@@ -170,7 +288,60 @@ void via_driver_irq_uninstall(drm_device_t * dev)
VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) & ~0x30);
status = VIA_READ(VIA_REG_INTERRUPT);
- VIA_WRITE(VIA_REG_INTERRUPT, status & ~VIA_IRQ_VBI_ENABLE);
+ VIA_WRITE(VIA_REG_INTERRUPT, status &
+ ~(VIA_IRQ_VBLANK_ENABLE | dev_priv->irq_enable_mask));
}
}
+int via_wait_irq(DRM_IOCTL_ARGS)
+{
+ DRM_DEVICE;
+
+ drm_via_irqwait_t __user *argp = (void __user *)data;
+ drm_via_irqwait_t irqwait;
+ struct timeval now;
+ int ret = 0;
+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+ drm_via_irq_t *cur_irq = dev_priv->via_irqs;
+ int force_sequence;
+
+ if (!dev->irq)
+ return DRM_ERR(EINVAL);
+
+ DRM_COPY_FROM_USER_IOCTL(irqwait, argp, sizeof(irqwait));
+ if (irqwait.request.irq >= dev_priv->num_irqs) {
+ DRM_ERROR("%s Trying to wait on unknown irq %d\n", __FUNCTION__,
+ irqwait.request.irq);
+ return DRM_ERR(EINVAL);
+ }
+
+ cur_irq += irqwait.request.irq;
+
+ switch (irqwait.request.type & ~VIA_IRQ_FLAGS_MASK) {
+ case VIA_IRQ_RELATIVE:
+ irqwait.request.sequence += atomic_read(&cur_irq->irq_received);
+ irqwait.request.type &= ~_DRM_VBLANK_RELATIVE;
+ case VIA_IRQ_ABSOLUTE:
+ break;
+ default:
+ return DRM_ERR(EINVAL);
+ }
+
+ if (irqwait.request.type & VIA_IRQ_SIGNAL) {
+ DRM_ERROR("%s Signals on Via IRQs not implemented yet.\n",
+ __FUNCTION__);
+ return DRM_ERR(EINVAL);
+ }
+
+ force_sequence = (irqwait.request.type & VIA_IRQ_FORCE_SEQUENCE);
+
+ ret = via_driver_irq_wait(dev, irqwait.request.irq, force_sequence,
+ &irqwait.request.sequence);
+ do_gettimeofday(&now);
+ irqwait.reply.tval_sec = now.tv_sec;
+ irqwait.reply.tval_usec = now.tv_usec;
+
+ DRM_COPY_TO_USER_IOCTL(argp, irqwait, sizeof(irqwait));
+
+ return ret;
+}
diff --git a/shared/via_map.c b/shared/via_map.c
index 178284c1..af850d73 100644
--- a/shared/via_map.c
+++ b/shared/via_map.c
@@ -29,7 +29,6 @@
int via_do_init_map(drm_device_t * dev, drm_via_init_t * init)
{
drm_via_private_t *dev_priv;
- unsigned int i;
DRM_DEBUG("%s\n", __FUNCTION__);
@@ -69,10 +68,8 @@ int via_do_init_map(drm_device_t * dev, drm_via_init_t * init)
dev_priv->agpAddr = init->agpAddr;
- for (i = 0; i < VIA_NR_XVMC_LOCKS; ++i) {
- DRM_INIT_WAITQUEUE(&(dev_priv->decoder_queue[i]));
- XVMCLOCKPTR(dev_priv->sarea_priv, i)->lock = 0;
- }
+ via_init_futex( dev_priv );
+ dev_priv->pro_group_a = (dev->pdev->device == 0x3118);
dev->dev_private = (void *)dev_priv;
@@ -113,31 +110,3 @@ int via_map_init(DRM_IOCTL_ARGS)
return -EINVAL;
}
-
-int via_decoder_futex(DRM_IOCTL_ARGS)
-{
- DRM_DEVICE;
- drm_via_futex_t fx;
- volatile int *lock;
- drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
- drm_via_sarea_t *sAPriv = dev_priv->sarea_priv;
- int ret = 0;
-
- DRM_COPY_FROM_USER_IOCTL(fx, (drm_via_futex_t *) data, sizeof(fx));
-
- if (fx.lock > VIA_NR_XVMC_LOCKS)
- return -EFAULT;
-
- lock = (int *)XVMCLOCKPTR(sAPriv, fx.lock);
-
- switch (fx.func) {
- case VIA_FUTEX_WAIT:
- DRM_WAIT_ON(ret, dev_priv->decoder_queue[fx.lock],
- (fx.ms / 10) * (DRM_HZ / 100), *lock != fx.val);
- return ret;
- case VIA_FUTEX_WAKE:
- DRM_WAKEUP(&(dev_priv->decoder_queue[fx.lock]));
- return 0;
- }
- return 0;
-}
diff --git a/shared/via_mm.c b/shared/via_mm.c
index fadfbfba..d450cdd5 100644
--- a/shared/via_mm.c
+++ b/shared/via_mm.c
@@ -133,9 +133,7 @@ int via_init_context(struct drm_device *dev, int context)
int via_final_context(struct drm_device *dev, int context)
{
int i;
- volatile int *lock;
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
- drm_via_sarea_t *sAPriv = dev_priv->sarea_priv;
for (i = 0; i < MAX_CONTEXT; i++)
if (global_ppriv[i].used &&
@@ -172,20 +170,6 @@ int via_final_context(struct drm_device *dev, int context)
global_ppriv[i].used = 0;
}
- /*
- * Release futex locks.
- */
-
- for (i=0; i < VIA_NR_XVMC_LOCKS; ++i) {
- lock = (int *) XVMCLOCKPTR(sAPriv, i);
- if ( (_DRM_LOCKING_CONTEXT( *lock ) == context)) {
- if (_DRM_LOCK_IS_HELD( *lock ) && (*lock & _DRM_LOCK_CONT)) {
- DRM_WAKEUP( &(dev_priv->decoder_queue[i]));
- }
- *lock = 0;
- }
- }
-
#if defined(__linux__)
/* Linux specific until context tracking code gets ported to BSD */
/* Last context, perform cleanup */
@@ -193,6 +177,7 @@ int via_final_context(struct drm_device *dev, int context)
if (dev->irq)
DRM(irq_uninstall) (dev);
+ via_cleanup_futex(dev_priv);
via_do_cleanup_map(dev);
}
#endif
diff --git a/shared/via_verifier.c b/shared/via_verifier.c
index edc9decd..742d7cea 100644
--- a/shared/via_verifier.c
+++ b/shared/via_verifier.c
@@ -1,5 +1,6 @@
/*
* Copyright 2004 The Unichrome Project. All Rights Reserved.
+ * Copyright 2005 Thomas Hellstrom. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -15,19 +16,18 @@
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE UNICHROME PROJECT, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * THE AUTHOR(S), AND/OR THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
- * Author: Thomas Hellström 2004.
+ * Author: Thomas Hellstrom 2004, 2005.
* This code was written using docs obtained under NDA from VIA Inc.
*
* Don't run this code directly on an AGP buffer. Due to cache problems it will
* be very slow.
*/
-
#include "via.h"
#include "via_3d_reg.h"
#include "drmP.h"
@@ -678,16 +678,61 @@ via_check_header2( uint32_t const **buffer, const uint32_t *buf_end,
return state_command;
}
+static __inline__ verifier_state_t
+via_parse_header2( drm_via_private_t *dev_priv, uint32_t const **buffer, const uint32_t *buf_end,
+ int *fire_count)
+{
+ uint32_t cmd;
+ const uint32_t *buf = *buffer;
+ const uint32_t *next_fire;
+ int burst = 0;
+
+ next_fire = dev_priv->fire_offsets[*fire_count];
+ buf++;
+ cmd = (*buf & 0xFFFF0000) >> 16;
+ VIA_WRITE(HC_REG_TRANS_SET + HC_REG_BASE, *buf++);
+ switch(cmd) {
+ case HC_ParaType_CmdVdata:
+ while ((*fire_count < dev_priv->num_fire_offsets) &&
+ (*buf & HC_ACMD_MASK) == HC_ACMD_HCmdB ) {
+ while(buf <= next_fire) {
+ VIA_WRITE(HC_REG_TRANS_SPACE + HC_REG_BASE + (burst & 63), *buf++);
+ burst += 4;
+ }
+ if ( ( buf < buf_end ) && ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD))
+ buf++;
+
+ if (++(*fire_count) < dev_priv->num_fire_offsets)
+ next_fire = dev_priv->fire_offsets[*fire_count];
+ }
+ break;
+ default:
+ while(buf < buf_end) {
+
+ if ( *buf == HC_HEADER2 ||
+ (*buf & HALCYON_HEADER1MASK) == HALCYON_HEADER1 ||
+ (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5 ||
+ (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6 ) break;
+
+ VIA_WRITE(HC_REG_TRANS_SPACE + HC_REG_BASE + (burst & 63), *buf++);
+ burst +=4;
+ }
+ }
+ *buffer = buf;
+ return state_command;
+}
+
+
static __inline__ int
verify_mmio_address( uint32_t address)
{
if ((address > 0x3FF) && (address < 0xC00 )) {
- DRM_ERROR("Invalid HALCYON_HEADER1 command. "
+ DRM_ERROR("Invalid VIDEO DMA command. "
"Attempt to access 3D- or command burst area.\n");
return 1;
- } else if (address > 0xCFF ) {
- DRM_ERROR("Invalid HALCYON_HEADER1 command. "
+ } else if (address > 0x13FF ) {
+ DRM_ERROR("Invalid VIDEO DMA command. "
"Attempt to access VGA registers.\n");
return 1;
}
@@ -747,6 +792,22 @@ via_check_header1( uint32_t const **buffer, const uint32_t *buf_end )
}
static __inline__ verifier_state_t
+via_parse_header1( drm_via_private_t *dev_priv, uint32_t const **buffer, const uint32_t *buf_end )
+{
+ register uint32_t cmd;
+ const uint32_t *buf = *buffer;
+
+ while (buf < buf_end) {
+ cmd = *buf;
+ if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1) break;
+ VIA_WRITE( (cmd & ~HALCYON_HEADER1MASK) << 2, *++buf);
+ buf++;
+ }
+ *buffer = buf;
+ return state_command;
+}
+
+static __inline__ verifier_state_t
via_check_vheader5( uint32_t const **buffer, const uint32_t *buf_end )
{
uint32_t data;
@@ -772,7 +833,7 @@ via_check_vheader5( uint32_t const **buffer, const uint32_t *buf_end )
}
if (eat_words(&buf, buf_end, data))
return state_error;
- if (verify_video_tail(&buf, buf_end, 4 - (data & 3)))
+ if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3)))
return state_error;
*buffer = buf;
return state_command;
@@ -780,19 +841,36 @@ via_check_vheader5( uint32_t const **buffer, const uint32_t *buf_end )
}
static __inline__ verifier_state_t
+via_parse_vheader5( drm_via_private_t *dev_priv, uint32_t const **buffer, const uint32_t *buf_end )
+{
+ uint32_t addr, count, i;
+ const uint32_t *buf = *buffer;
+
+ addr = *buf++ & ~VIA_VIDEOMASK;
+ i = count = *buf;
+ buf += 3;
+ while(i--) {
+ VIA_WRITE(addr, *buf++);
+ }
+ if (count & 3) buf += 4 - (count & 3);
+ *buffer = buf;
+ return state_command;
+}
+
+
+static __inline__ verifier_state_t
via_check_vheader6( uint32_t const **buffer, const uint32_t *buf_end )
{
uint32_t data;
const uint32_t *buf = *buffer;
uint32_t i;
- DRM_ERROR("H6\n");
if (buf_end - buf < 4) {
DRM_ERROR("Illegal termination of video header6 command\n");
return state_error;
}
-
+ buf++;
data = *buf++;
if (*buf++ != 0x00F60000) {
DRM_ERROR("Illegal header6 header data\n");
@@ -804,18 +882,40 @@ via_check_vheader6( uint32_t const **buffer, const uint32_t *buf_end )
}
if ((buf_end - buf) < (data << 1)) {
DRM_ERROR("Illegal termination of video header6 command\n");
+ return state_error;
}
for (i=0; i<data; ++i) {
if (verify_mmio_address(*buf++))
return state_error;
buf++;
}
- if (verify_video_tail(&buf, buf_end, 4 - ((data << 1) & 3)))
+ data <<= 1;
+ if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3)))
return state_error;
*buffer = buf;
return state_command;
}
+static __inline__ verifier_state_t
+via_parse_vheader6( drm_via_private_t *dev_priv, uint32_t const **buffer, const uint32_t *buf_end )
+{
+
+ uint32_t addr, count, i;
+ const uint32_t *buf = *buffer;
+
+ i = count = *++buf;
+ buf += 3;
+ while(i--) {
+ addr = *buf++;
+ VIA_WRITE(addr, *buf++);
+ }
+ count <<= 1;
+ if (count & 3) buf += 4 - (count & 3);
+ *buffer = buf;
+ return state_command;
+}
+
+
int
via_verify_command_stream(const uint32_t * buf, unsigned int size, drm_device_t *dev,
@@ -828,7 +928,7 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size, drm_device_t
uint32_t cmd;
const uint32_t *buf_end = buf + ( size >> 2 );
verifier_state_t state = state_command;
-
+ int pro_group_a = dev_priv->pro_group_a;
hc_state->dev = dev;
hc_state->unfinished = no_sequence;
@@ -841,7 +941,7 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size, drm_device_t
switch (state) {
case state_header2:
- state = via_check_header2( &buf, buf_end, hc_state );
+ state = via_check_header2( &buf, buf_end, hc_state );
break;
case state_header1:
state = via_check_header1( &buf, buf_end );
@@ -857,9 +957,9 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size, drm_device_t
state = state_header2;
else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
state = state_header1;
- else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5)
+ else if (pro_group_a && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5)
state = state_vheader5;
- else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
+ else if (pro_group_a && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
state = state_vheader6;
else {
DRM_ERROR("Invalid / Unimplemented DMA HEADER command. 0x%x\n",
@@ -880,6 +980,59 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size, drm_device_t
return 0;
}
+int
+via_parse_command_stream(drm_device_t *dev, const uint32_t * buf, unsigned int size)
+{
+
+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+ uint32_t cmd;
+ const uint32_t *buf_end = buf + ( size >> 2 );
+ verifier_state_t state = state_command;
+ int fire_count = 0;
+
+ while (buf < buf_end) {
+
+ switch (state) {
+ case state_header2:
+ state = via_parse_header2( dev_priv, &buf, buf_end, &fire_count );
+ break;
+ case state_header1:
+ state = via_parse_header1( dev_priv, &buf, buf_end );
+ break;
+ case state_vheader5:
+ state = via_parse_vheader5( dev_priv, &buf, buf_end );
+ break;
+ case state_vheader6:
+ state = via_parse_vheader6( dev_priv, &buf, buf_end );
+ break;
+ case state_command:
+ if (HALCYON_HEADER2 == (cmd = *buf))
+ state = state_header2;
+ else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
+ state = state_header1;
+ else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5)
+ state = state_vheader5;
+ else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
+ state = state_vheader6;
+ else {
+ DRM_ERROR("Invalid / Unimplemented DMA HEADER command. 0x%x\n",
+ cmd);
+ state = state_error;
+ }
+ break;
+ case state_error:
+ default:
+ return DRM_ERR(EINVAL);
+ }
+ }
+ if (state == state_error) {
+ return DRM_ERR(EINVAL);
+ }
+ return 0;
+}
+
+
+
static void
setup_hazard_table(hz_init_t init_table[], hazard_t table[], int size)
{