diff options
Diffstat (limited to 'shared')
-rw-r--r-- | shared/via_dma.c | 88 | ||||
-rw-r--r-- | shared/via_drm.h | 7 | ||||
-rw-r--r-- | shared/via_drv.c | 8 | ||||
-rw-r--r-- | shared/via_drv.h | 1 |
4 files changed, 100 insertions, 4 deletions
diff --git a/shared/via_dma.c b/shared/via_dma.c index 83c14cf0..c11652c0 100644 --- a/shared/via_dma.c +++ b/shared/via_dma.c @@ -16,6 +16,8 @@ #include "via_drm.h" #include "via_drv.h" +#define VIA_2D_CMD 0xF0000000 + 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); @@ -223,6 +225,92 @@ 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; + uint32_t offset, value; + const uint32_t *regbuf = (uint32_t *)buf; + unsigned int i; + + size >>=3 ; + for (i=0; i<size; ++i) { + offset = *regbuf; + regbuf += 2; + if ((offset > ((0x7FF >> 2) | VIA_2D_CMD)) && + (offset < ((0xC00 >> 2) | VIA_2D_CMD)) ) { + DRM_DEBUG("Attempt to access Burst Command Area.\n"); + return DRM_ERR( EINVAL ); + } else if (offset > ((0xDFF >> 2) | VIA_2D_CMD)) { + DRM_DEBUG("Attempt to access DMA or VGA registers.\n"); + return DRM_ERR( EINVAL ); + } + } + + regbuf = (uint32_t *)buf; + for ( i=0; i<size; ++i ) { + offset = (*regbuf++ & ~VIA_2D_CMD) << 2; + value = *regbuf++; + VIA_WRITE( offset, value ); + } + 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 ) { + 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 ); + DRM_COPY_FROM_USER( hugebuf, cmd->buf, cmd->size ); + ret = via_parse_pci_cmdbuffer( dev, hugebuf, cmd->size ); + kfree( hugebuf ); + } else { + DRM_COPY_FROM_USER( dev_priv->pci_buf, cmd->buf, cmd->size ); + ret = via_parse_pci_cmdbuffer( dev, dev_priv->pci_buf, cmd->size ); + } + return ret; +} + + + +int via_pci_cmdbuffer( DRM_IOCTL_ARGS ) +{ + DRM_DEVICE; + drm_via_cmdbuffer_t cmdbuf; + int ret; + + DRM_COPY_FROM_USER_IOCTL( cmdbuf, (drm_via_cmdbuffer_t *)data, + sizeof(cmdbuf) ); + + DRM_DEBUG("via_pci_cmdbuffer, buf %p size %lu\n", cmdbuf.buf, cmdbuf.size); + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("via_pci_cmdbuffer called without lock held\n"); + return DRM_ERR(EINVAL); + } + + ret = via_dispatch_pci_cmdbuffer( dev, &cmdbuf ); + if (ret) { + return ret; + } + + return 0; +} + diff --git a/shared/via_drm.h b/shared/via_drm.h index 5325f62f..ddc89f83 100644 --- a/shared/via_drm.h +++ b/shared/via_drm.h @@ -38,6 +38,8 @@ #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)) & \ @@ -67,8 +69,10 @@ #define DRM_IOCTL_VIA_MAP_INIT DRM_IOWR(0x44, drm_via_init_t) #define DRM_IOCTL_VIA_DEC_FUTEX DRM_IOW(0x45, drm_via_futex_t) #define DRM_IOCTL_VIA_DMA_INIT DRM_IOWR(0x47, drm_via_dma_init_t) -#define DRM_IOCTL_VIA_CMDBUFFER DRM_IOWR(0x48, drm_via_dma_init_t) +#define DRM_IOCTL_VIA_CMDBUFFER DRM_IOW(0x48, drm_via_cmdbuffer_t) #define DRM_IOCTL_VIA_FLUSH DRM_IO(0x49) +#define DRM_IOCTL_VIA_PCICMD DRM_IOW(0x4A, drm_via_cmdbuffer_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 +204,7 @@ int via_decoder_futex( DRM_IOCTL_ARGS ); int via_dma_init( DRM_IOCTL_ARGS ); int via_cmdbuffer( DRM_IOCTL_ARGS ); int via_flush_ioctl( DRM_IOCTL_ARGS ); +int via_pci_cmdbuffer( DRM_IOCTL_ARGS ); #endif #endif /* _VIA_DRM_H_ */ diff --git a/shared/via_drv.c b/shared/via_drv.c index b3119f66..8c4e7480 100644 --- a/shared/via_drv.c +++ b/shared/via_drv.c @@ -21,6 +21,7 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ + #include <linux/config.h> #include "via.h" #include "drmP.h" @@ -31,10 +32,10 @@ #define DRIVER_NAME "via" #define DRIVER_DESC "VIA Unichrome" -#define DRIVER_DATE "20040819" +#define DRIVER_DATE "20040907" #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 4 +#define DRIVER_MINOR 5 #define DRIVER_PATCHLEVEL 0 @@ -47,7 +48,8 @@ [DRM_IOCTL_NR(DRM_IOCTL_VIA_DEC_FUTEX)] = { via_decoder_futex, 1, 0}, \ [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_FLUSH)] = { via_flush_ioctl, 1, 0}, \ + [DRM_IOCTL_NR(DRM_IOCTL_VIA_PCICMD)] = { via_pci_cmdbuffer, 1, 0} #define __HAVE_COUNTERS 0 diff --git a/shared/via_drv.h b/shared/via_drv.h index dd4a370f..39ccf0bd 100644 --- a/shared/via_drv.h +++ b/shared/via_drv.h @@ -46,6 +46,7 @@ typedef struct drm_via_private { uint32_t * last_pause_ptr; volatile uint32_t * hw_addr_ptr; drm_via_ring_buffer_t ring; + char pci_buf[VIA_PREALLOCATED_PCI_SIZE]; } drm_via_private_t; |