Via updates:
authorThomas Hellstrom <unichrome@shipmail.org>
Mon, 28 Mar 2005 21:21:42 +0000 (21:21 +0000)
committerThomas Hellstrom <unichrome@shipmail.org>
Mon, 28 Mar 2005 21:21:42 +0000 (21:21 +0000)
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.

21 files changed:
linux-core/Makefile
linux-core/Makefile.kernel
linux-core/drm_irq.c
linux/Makefile
linux/Makefile.kernel
shared-core/via_dma.c
shared-core/via_drm.h
shared-core/via_drv.c
shared-core/via_drv.h
shared-core/via_irq.c
shared-core/via_map.c
shared-core/via_mm.c
shared-core/via_verifier.c
shared/via.h
shared/via_dma.c
shared/via_drm.h
shared/via_drv.h
shared/via_irq.c
shared/via_map.c
shared/via_mm.c
shared/via_verifier.c

index bc9c00a..64704a3 100644 (file)
@@ -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
index 6868aa0..9308235 100644 (file)
@@ -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
index a6ebb17..27c9bc1 100644 (file)
@@ -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
index 08654cf..ac1d25c 100644 (file)
@@ -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 \
index edd885f..40b54e0 100644 (file)
@@ -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
index 1f5d3b9..081fefc 100644 (file)
  * 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;
 }
 
index f3b4a28..4588c9b 100644 (file)
@@ -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_ */
index 13a22ec..21f28a6 100644 (file)
@@ -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);
index 00382e5..353a9b9 100644 (file)
 #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
index 2d78dd4..c0a30c6 100644 (file)
@@ -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
  * 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"
 
 /* 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;
+}
index 50ca96c..0be829b 100644 (file)
@@ -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;
-}
-
index 5cead8c..cf286b4 100644 (file)
@@ -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)
index 6b08f5d..5b1f30a 100644 (file)
@@ -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"),
  * 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)
 {
index b35164e..816880e 100644 (file)
 #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
index 6f877c5..34ac6cc 100644 (file)
  * 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) &
index f3b4a28..4588c9b 100644 (file)
@@ -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_ */
index 5d90c9c..8227b73 100644 (file)
 
 #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
index 1e22a77..f61081c 100644 (file)
@@ -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
  * 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"
 
 /* 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;
+}
index 178284c..af850d7 100644 (file)
@@ -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;
-}
index fadfbfb..d450cdd 100644 (file)
@@ -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
index edc9dec..742d7ce 100644 (file)
@@ -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"),
  * 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)
 {