Reworked PCI MMIO command buffer parser, and imported code from the Mesa
authorThomas Hellstrom <unichrome@shipmail.org>
Sat, 27 Nov 2004 22:55:31 +0000 (22:55 +0000)
committerThomas Hellstrom <unichrome@shipmail.org>
Sat, 27 Nov 2004 22:55:31 +0000 (22:55 +0000)
    driver. It can now handle the 3D OpenGL commands from the Mesa
    unichrome driver.
Added vsync frequency detection support. This will be used in the future
    for XvMC and better frame timing.
Bumped minor version number and driver date.

13 files changed:
shared-core/via_3d_reg.h
shared-core/via_dma.c
shared-core/via_drm.h
shared-core/via_drv.h
shared-core/via_irq.c
shared-core/via_map.c
shared-core/via_mm.c
shared/via.h
shared/via_3d_reg.h
shared/via_dma.c
shared/via_drm.h
shared/via_drv.h
shared/via_irq.c

index 3bb59a3..43c0183 100644 (file)
@@ -26,6 +26,8 @@
 #define VIA_3D_REG_H
 #define HC_REG_BASE             0x0400
 
+#define HC_REG_TRANS_SPACE      0x0040
+
 #define HC_ParaN_MASK           0xffffffff
 #define HC_Para_MASK            0x00ffffff
 #define HC_SubA_MASK            0xff000000
 #define HALCYON_CMDB        0XEC000000
 #define HALCYON_CMDBMASK    0XFFFE0000
 #define HALCYON_SUB_ADDR0   0X00000000
-#define HALCYON_HEADER1MASK 0XFFFFFF00
+#define HALCYON_HEADER1MASK 0XFFFFFC00
 #define HALCYON_HEADER1     0XF0000000
 #define HC_SubA_HAGPBstL        0x0060
 #define HC_SubA_HAGPBendL       0x0061
index ee4a02a..179636e 100644 (file)
        *vb++ = (w2);                           \
        dev_priv->dma_low += 8; 
 
-  
+#define PCI_BUF_SIZE 1024000
+
+static char pci_buf[PCI_BUF_SIZE];
+static unsigned long pci_bufsiz = PCI_BUF_SIZE;  
+
 
 static void via_cmdbuf_start(drm_via_private_t * dev_priv);
 static void via_cmdbuf_pause(drm_via_private_t * dev_priv);
@@ -203,6 +207,9 @@ int via_dma_init(DRM_IOCTL_ARGS)
        case VIA_CLEANUP_DMA:
                retcode = via_dma_cleanup(dev);
                break;
+        case VIA_DMA_INITIALIZED:
+         retcode = (dev_priv->ring.virtual_start != NULL) ? 0: DRM_ERR( EFAULT );
+               break;
        default:
                retcode = DRM_ERR(EINVAL);
                break;
@@ -278,52 +285,55 @@ 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;
-       uint32_t offset, value;
        const uint32_t *regbuf = (uint32_t *) buf;
-       unsigned int i;
+       const uint32_t *regend = regbuf + (size >> 2);
        int ret;
+       int check_2d_cmd = 1;
 
        if ((ret = via_check_command_stream(regbuf, size)))
                return ret;
 
-       size >>= 3;
-       for (i = 0; i < size; ++i) {
-               offset = (*regbuf++ & ~HALCYON_HEADER1) << 2;
-               value = *regbuf++;
-               VIA_WRITE(offset, value);
-       }
+       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 ( ( *regbuf & HALCYON_FIREMASK ) == HALCYON_FIRECMD ) {
+
+                       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;
+
 }
 
 static int via_dispatch_pci_cmdbuffer(drm_device_t * dev,
                                      drm_via_cmdbuffer_t * cmd)
 {
-       drm_via_private_t *dev_priv = dev->dev_private;
-       char *hugebuf;
        int ret;
 
-       /*
-        * We must be able to parse the buffer all at a time, so as
-        * to return an error on an invalid operation without doing
-        * anything.
-        * Small buffers must, on the other hand be handled fast.
-        */
-
-       if (cmd->size > VIA_MAX_PCI_SIZE) {
+       if (cmd->size > pci_bufsiz && pci_bufsiz > 0) {
                return DRM_ERR(ENOMEM);
-       } else if (cmd->size > VIA_PREALLOCATED_PCI_SIZE) {
-               if (NULL == (hugebuf = (char *)kmalloc(cmd->size, GFP_KERNEL)))
-                       return DRM_ERR(ENOMEM);
-               if (DRM_COPY_FROM_USER(hugebuf, cmd->buf, cmd->size))
-                       return DRM_ERR(EFAULT);
-               ret = via_parse_pci_cmdbuffer(dev, hugebuf, cmd->size);
-               kfree(hugebuf);
-       } else {
-               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 (DRM_COPY_FROM_USER(pci_buf, cmd->buf, cmd->size))
+               return DRM_ERR(EFAULT);
+       ret = via_parse_pci_cmdbuffer(dev, pci_buf, cmd->size);
        return ret;
 }
 
index 75c7280..142b8da 100644 (file)
@@ -38,8 +38,6 @@
 #define VIA_NR_XVMC_PORTS               10
 #define VIA_NR_XVMC_LOCKS               5
 #define VIA_MAX_CACHELINE_SIZE          64
-#define VIA_PREALLOCATED_PCI_SIZE       16384
-#define VIA_MAX_PCI_SIZE                65536
 #define XVMCLOCKPTR(saPriv,lockNo)                                     \
         ((volatile int *)(((((unsigned long) (saPriv)->XvMCLockArea) + \
                             (VIA_MAX_CACHELINE_SIZE - 1)) &             \
@@ -143,7 +141,8 @@ typedef struct _drm_via_futex {
 typedef struct _drm_via_dma_init {
        enum {
                VIA_INIT_DMA = 0x01,
-               VIA_CLEANUP_DMA = 0x02
+               VIA_CLEANUP_DMA = 0x02,
+                VIA_DMA_INITIALIZED = 0x03
        } func;
 
        unsigned long offset;
@@ -202,6 +201,8 @@ typedef struct _drm_via_flush_sys {
        int discard;            /* client is finished with the buffer? */
 } drm_via_flush_sys_t;
 
+
+
 #ifdef __KERNEL__
 
 int via_fb_init(DRM_IOCTL_ARGS);
index 14afaa1..3bca72f 100644 (file)
 
 #define DRIVER_NAME            "via"
 #define DRIVER_DESC            "VIA Unichrome"
-#define DRIVER_DATE            "20041103"
+#define DRIVER_DATE            "20041127"
 
 #define DRIVER_MAJOR           2
-#define DRIVER_MINOR           0
-#define DRIVER_PATCHLEVEL      4
+#define DRIVER_MINOR           1
+#define DRIVER_PATCHLEVEL      0
 
 typedef struct drm_via_ring_buffer {
        drm_map_t map;
@@ -53,7 +53,9 @@ typedef struct drm_via_private {
        volatile uint32_t *last_pause_ptr;
        volatile uint32_t *hw_addr_ptr;
        drm_via_ring_buffer_t ring;
-       char pci_buf[VIA_PREALLOCATED_PCI_SIZE];
+        struct timeval last_vblank;
+        int last_vblank_valid;
+        unsigned usec_per_vblank;
 } drm_via_private_t;
 
 /* VIA MMIO register access */
@@ -80,6 +82,6 @@ extern void via_driver_irq_uninstall(drm_device_t * dev);
 
 extern int via_dma_cleanup(drm_device_t * dev);
 
-extern int via_dma_cleanup(drm_device_t * dev);
+
 
 #endif
index 3d54edc..2d78dd4 100644 (file)
 #define VIA_IRQ_VBI_ENABLE      (1 << 19)
 #define VIA_IRQ_VBI_PENDING     (1 << 3)
 
+
+
+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;
        int handled = 0;
+       struct timeval cur_vblank;
 
        status = VIA_READ(VIA_REG_INTERRUPT);
        if (status & VIA_IRQ_VBI_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);
                handled = 1;
@@ -116,6 +139,7 @@ void via_driver_irq_preinstall(drm_device_t * dev)
 
        DRM_DEBUG("driver_irq_preinstall: dev_priv: %p\n", dev_priv);
        if (dev_priv) {
+               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);
@@ -163,3 +187,4 @@ void via_driver_irq_uninstall(drm_device_t * dev)
                VIA_WRITE(VIA_REG_INTERRUPT, status & ~VIA_IRQ_VBI_ENABLE);
        }
 }
+
index dcf714d..e00dc64 100644 (file)
@@ -136,3 +136,4 @@ int via_decoder_futex(DRM_IOCTL_ARGS)
        }
        return 0;
 }
+
index 985ad0d..5199f6c 100644 (file)
@@ -170,6 +170,7 @@ int via_final_context(struct drm_device *dev, int context)
        /* Linux specific until context tracking code gets ported to BSD */
        /* Last context, perform cleanup */
        if (dev->ctx_count == 1 && dev->dev_private) {
+               DRM_DEBUG("Last Context\n");
                if (dev->irq)
                        drm_irq_uninstall(dev);
 
index 0746a46..6b31221 100644 (file)
 
 #define DRIVER_NAME            "via"
 #define DRIVER_DESC            "VIA Unichrome"
-#define DRIVER_DATE            "20041103"
+#define DRIVER_DATE            "20041127"
 
 #define DRIVER_MAJOR           2
-#define DRIVER_MINOR           0
-#define DRIVER_PATCHLEVEL      4
+#define DRIVER_MINOR           1
+#define DRIVER_PATCHLEVEL      0
 
 #define DRIVER_IOCTLS                                                  \
         [DRM_IOCTL_NR(DRM_IOCTL_VIA_ALLOCMEM)]  = { via_mem_alloc,  1, 0 }, \
@@ -46,6 +46,6 @@
         [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_PCICMD)] = { via_pci_cmdbuffer, 1, 0}
 
 #endif
index 38ab25b..90010cd 100644 (file)
@@ -26,6 +26,8 @@
 #define VIA_3D_REG_H
 #define HC_REG_BASE             0x0400
 
+#define HC_REG_TRANS_SPACE      0x0040
+
 #define HC_ParaN_MASK           0xffffffff
 #define HC_Para_MASK            0x00ffffff
 #define HC_SubA_MASK            0xff000000
 #define HALCYON_CMDB        0XEC000000
 #define HALCYON_CMDBMASK    0XFFFE0000
 #define HALCYON_SUB_ADDR0   0X00000000
-#define HALCYON_HEADER1MASK 0XFFFFFF00
+#define HALCYON_HEADER1MASK 0XFFFFFC00
 #define HALCYON_HEADER1     0XF0000000
 #define HC_SubA_HAGPBstL        0x0060
 #define HC_SubA_HAGPBendL       0x0061
index 39613bc..4b591fa 100644 (file)
        *vb++ = (w2);                           \
        dev_priv->dma_low += 8; 
 
-  
+#define PCI_BUF_SIZE 1024000
+
+static char pci_buf[PCI_BUF_SIZE];
+static unsigned long pci_bufsiz = PCI_BUF_SIZE;  
+
 
 static void via_cmdbuf_start(drm_via_private_t * dev_priv);
 static void via_cmdbuf_pause(drm_via_private_t * dev_priv);
@@ -204,6 +208,9 @@ int via_dma_init(DRM_IOCTL_ARGS)
        case VIA_CLEANUP_DMA:
                retcode = via_dma_cleanup(dev);
                break;
+        case VIA_DMA_INITIALIZED:
+         retcode = (dev_priv->ring.virtual_start != NULL) ? 0: DRM_ERR( EFAULT );
+               break;
        default:
                retcode = DRM_ERR(EINVAL);
                break;
@@ -279,52 +286,55 @@ 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;
-       uint32_t offset, value;
        const uint32_t *regbuf = (uint32_t *) buf;
-       unsigned int i;
+       const uint32_t *regend = regbuf + (size >> 2);
        int ret;
+       int check_2d_cmd = 1;
 
        if ((ret = via_check_command_stream(regbuf, size)))
                return ret;
 
-       size >>= 3;
-       for (i = 0; i < size; ++i) {
-               offset = (*regbuf++ & ~HALCYON_HEADER1) << 2;
-               value = *regbuf++;
-               VIA_WRITE(offset, value);
-       }
+       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 ( ( *regbuf & HALCYON_FIREMASK ) == HALCYON_FIRECMD ) {
+
+                       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;
+
 }
 
 static int via_dispatch_pci_cmdbuffer(drm_device_t * dev,
                                      drm_via_cmdbuffer_t * cmd)
 {
-       drm_via_private_t *dev_priv = dev->dev_private;
-       char *hugebuf;
        int ret;
 
-       /*
-        * We must be able to parse the buffer all at a time, so as
-        * to return an error on an invalid operation without doing
-        * anything.
-        * Small buffers must, on the other hand be handled fast.
-        */
-
-       if (cmd->size > VIA_MAX_PCI_SIZE) {
+       if (cmd->size > pci_bufsiz && pci_bufsiz > 0) {
                return DRM_ERR(ENOMEM);
-       } else if (cmd->size > VIA_PREALLOCATED_PCI_SIZE) {
-               if (NULL == (hugebuf = (char *)kmalloc(cmd->size, GFP_KERNEL)))
-                       return DRM_ERR(ENOMEM);
-               if (DRM_COPY_FROM_USER(hugebuf, cmd->buf, cmd->size))
-                       return DRM_ERR(EFAULT);
-               ret = via_parse_pci_cmdbuffer(dev, hugebuf, cmd->size);
-               kfree(hugebuf);
-       } else {
-               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 (DRM_COPY_FROM_USER(pci_buf, cmd->buf, cmd->size))
+               return DRM_ERR(EFAULT);
+       ret = via_parse_pci_cmdbuffer(dev, pci_buf, cmd->size);
        return ret;
 }
 
index ed2ee2a..ee703c7 100644 (file)
@@ -38,8 +38,6 @@
 #define VIA_NR_XVMC_PORTS               10
 #define VIA_NR_XVMC_LOCKS               5
 #define VIA_MAX_CACHELINE_SIZE          64
-#define VIA_PREALLOCATED_PCI_SIZE       16384
-#define VIA_MAX_PCI_SIZE                65536
 #define XVMCLOCKPTR(saPriv,lockNo)                                     \
         ((volatile int *)(((((unsigned long) (saPriv)->XvMCLockArea) + \
                             (VIA_MAX_CACHELINE_SIZE - 1)) &             \
@@ -131,7 +129,8 @@ typedef struct _drm_via_futex {
 typedef struct _drm_via_dma_init {
        enum {
                VIA_INIT_DMA = 0x01,
-               VIA_CLEANUP_DMA = 0x02
+               VIA_CLEANUP_DMA = 0x02,
+                VIA_DMA_INITIALIZED = 0x03
        } func;
 
        unsigned long offset;
@@ -190,6 +189,8 @@ typedef struct _drm_via_flush_sys {
        int discard;            /* client is finished with the buffer? */
 } drm_via_flush_sys_t;
 
+
+
 #ifdef __KERNEL__
 
 int via_fb_init(DRM_IOCTL_ARGS);
index 91edbab..9ed8cd3 100644 (file)
@@ -45,7 +45,9 @@ typedef struct drm_via_private {
        volatile uint32_t *last_pause_ptr;
        volatile uint32_t *hw_addr_ptr;
        drm_via_ring_buffer_t ring;
-       char pci_buf[VIA_PREALLOCATED_PCI_SIZE];
+        struct timeval last_vblank;
+        int last_vblank_valid;
+        unsigned usec_per_vblank;
 } drm_via_private_t;
 
 /* VIA MMIO register access */
@@ -72,6 +74,6 @@ extern void via_driver_irq_uninstall(drm_device_t * dev);
 
 extern int via_dma_cleanup(drm_device_t * dev);
 
-extern int via_dma_cleanup(drm_device_t * dev);
+
 
 #endif
index da3c141..a58717e 100644 (file)
 #define VIA_IRQ_VBI_ENABLE      (1 << 19)
 #define VIA_IRQ_VBI_PENDING     (1 << 3)
 
+
+
+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;
        int handled = 0;
+       struct timeval cur_vblank;
 
        status = VIA_READ(VIA_REG_INTERRUPT);
        if (status & VIA_IRQ_VBI_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);
                handled = 1;
@@ -117,6 +140,7 @@ void via_driver_irq_preinstall(drm_device_t * dev)
 
        DRM_DEBUG("driver_irq_preinstall: dev_priv: %p\n", dev_priv);
        if (dev_priv) {
+               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);
@@ -164,3 +188,4 @@ void via_driver_irq_uninstall(drm_device_t * dev)
                VIA_WRITE(VIA_REG_INTERRUPT, status & ~VIA_IRQ_VBI_ENABLE);
        }
 }
+