diff options
author | Thomas Hellstrom <unichrome@shipmail.org> | 2004-11-27 22:55:31 +0000 |
---|---|---|
committer | Thomas Hellstrom <unichrome@shipmail.org> | 2004-11-27 22:55:31 +0000 |
commit | 4f8fa6028631fa1d799e9a68ed710fbc98976656 (patch) | |
tree | df753d0e728afd97ac03388283df51f4e73a9e0d | |
parent | f0a86288fa4d7b951f33f7b1a6ef36106c7df788 (diff) |
Reworked PCI MMIO command buffer parser, and imported code from the Mesa
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.
-rw-r--r-- | shared-core/via_3d_reg.h | 4 | ||||
-rw-r--r-- | shared-core/via_dma.c | 74 | ||||
-rw-r--r-- | shared-core/via_drm.h | 7 | ||||
-rw-r--r-- | shared-core/via_drv.h | 12 | ||||
-rw-r--r-- | shared-core/via_irq.c | 25 | ||||
-rw-r--r-- | shared-core/via_map.c | 1 | ||||
-rw-r--r-- | shared-core/via_mm.c | 1 | ||||
-rw-r--r-- | shared/via.h | 8 | ||||
-rw-r--r-- | shared/via_3d_reg.h | 4 | ||||
-rw-r--r-- | shared/via_dma.c | 74 | ||||
-rw-r--r-- | shared/via_drm.h | 7 | ||||
-rw-r--r-- | shared/via_drv.h | 6 | ||||
-rw-r--r-- | shared/via_irq.c | 25 |
13 files changed, 165 insertions, 83 deletions
diff --git a/shared-core/via_3d_reg.h b/shared-core/via_3d_reg.h index 3bb59a34..43c01836 100644 --- a/shared-core/via_3d_reg.h +++ b/shared-core/via_3d_reg.h @@ -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 @@ -1621,7 +1623,7 @@ #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 diff --git a/shared-core/via_dma.c b/shared-core/via_dma.c index ee4a02ab..179636ea 100644 --- a/shared-core/via_dma.c +++ b/shared-core/via_dma.c @@ -26,7 +26,11 @@ *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; } diff --git a/shared-core/via_drm.h b/shared-core/via_drm.h index 75c72806..142b8dac 100644 --- a/shared-core/via_drm.h +++ b/shared-core/via_drm.h @@ -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); diff --git a/shared-core/via_drv.h b/shared-core/via_drv.h index 14afaa13..3bca72f3 100644 --- a/shared-core/via_drv.h +++ b/shared-core/via_drv.h @@ -28,11 +28,11 @@ #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 diff --git a/shared-core/via_irq.c b/shared-core/via_irq.c index 3d54edc2..2d78dd44 100644 --- a/shared-core/via_irq.c +++ b/shared-core/via_irq.c @@ -45,16 +45,39 @@ #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); } } + diff --git a/shared-core/via_map.c b/shared-core/via_map.c index dcf714db..e00dc64a 100644 --- a/shared-core/via_map.c +++ b/shared-core/via_map.c @@ -136,3 +136,4 @@ int via_decoder_futex(DRM_IOCTL_ARGS) } return 0; } + diff --git a/shared-core/via_mm.c b/shared-core/via_mm.c index 985ad0d9..5199f6c9 100644 --- a/shared-core/via_mm.c +++ b/shared-core/via_mm.c @@ -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); diff --git a/shared/via.h b/shared/via.h index 0746a46d..6b312210 100644 --- a/shared/via.h +++ b/shared/via.h @@ -30,11 +30,11 @@ #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 diff --git a/shared/via_3d_reg.h b/shared/via_3d_reg.h index 38ab25bc..90010cdc 100644 --- a/shared/via_3d_reg.h +++ b/shared/via_3d_reg.h @@ -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 @@ -1621,7 +1623,7 @@ #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 diff --git a/shared/via_dma.c b/shared/via_dma.c index 39613bc5..4b591fa4 100644 --- a/shared/via_dma.c +++ b/shared/via_dma.c @@ -27,7 +27,11 @@ *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; } diff --git a/shared/via_drm.h b/shared/via_drm.h index ed2ee2ac..ee703c79 100644 --- a/shared/via_drm.h +++ b/shared/via_drm.h @@ -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); diff --git a/shared/via_drv.h b/shared/via_drv.h index 91edbab8..9ed8cd3a 100644 --- a/shared/via_drv.h +++ b/shared/via_drv.h @@ -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 diff --git a/shared/via_irq.c b/shared/via_irq.c index da3c1414..a58717ee 100644 --- a/shared/via_irq.c +++ b/shared/via_irq.c @@ -46,16 +46,39 @@ #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); } } + |