import Thomas' shared-core via changes up to 2.4.1
authorKeith Whitwell <keith@tungstengraphics.com>
Tue, 11 Jan 2005 10:42:52 +0000 (10:42 +0000)
committerKeith Whitwell <keith@tungstengraphics.com>
Tue, 11 Jan 2005 10:42:52 +0000 (10:42 +0000)
shared/via.h
shared/via_3d_reg.h
shared/via_dma.c
shared/via_drv.h
shared/via_irq.c
shared/via_mm.c
shared/via_verifier.c

index 1e25377..703c6f3 100644 (file)
 
 #define DRIVER_NAME            "via"
 #define DRIVER_DESC            "VIA Unichrome"
-#define DRIVER_DATE            "20041231"
+#define DRIVER_DATE            "20050106"
 
 #define DRIVER_MAJOR           2
-#define DRIVER_MINOR           3
-#define DRIVER_PATCHLEVEL      4
+#define DRIVER_MINOR           4
+#define DRIVER_PATCHLEVEL      1
 
 #define DRIVER_IOCTLS                                                  \
         [DRM_IOCTL_NR(DRM_IOCTL_VIA_ALLOCMEM)]  = { via_mem_alloc,  1, 0 }, \
index 90010cd..f78fd2d 100644 (file)
 #define HC_HAGPBpID_STOP        0x00000002
 #define HC_HAGPBpH_MASK         0x00ffffff
 
+
+#define VIA_VIDEO_HEADER5       0xFE040000
+#define VIA_VIDEO_HEADER6       0xFE050000
+#define VIA_VIDEO_HEADER7       0xFE060000
+#define VIA_VIDEOMASK           0xFFFF0000
 #endif
index c559f93..ef78987 100644 (file)
@@ -299,12 +299,12 @@ static int via_dispatch_cmdbuffer(drm_device_t * dev, drm_via_cmdbuffer_t * cmd)
        return 0;
 }
 
-static int via_quiescent(drm_device_t * dev)
+int via_driver_dma_quiescent(drm_device_t * dev)
 {
        drm_via_private_t *dev_priv = dev->dev_private;
 
        if (!via_wait_idle(dev_priv)) {
-               return DRM_ERR(EAGAIN);
+               return DRM_ERR(EBUSY);
        }
        return 0;
 }
@@ -315,7 +315,7 @@ int via_flush_ioctl(DRM_IOCTL_ARGS)
 
        LOCK_TEST_WITH_RETURN( dev, filp );
 
-       return via_quiescent(dev);
+       return via_driver_dma_quiescent(dev);
 }
 
 int via_cmdbuffer(DRM_IOCTL_ARGS)
index 8368647..4423a7c 100644 (file)
@@ -75,6 +75,7 @@ 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_verify_command_stream(const uint32_t * buf, unsigned int size,
                                     drm_device_t *dev);
index a58717e..4d62c69 100644 (file)
 /* 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)
 
 
 
-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;
+       int handled = IRQ_NONE;
+       u32 status = VIA_READ(VIA_REG_INTERRUPT);
 
-       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;
+               handled = IRQ_HANDLED;
        }
 
-       /* Acknowlege interrupts ?? */
-       VIA_WRITE(VIA_REG_INTERRUPT, status);
+#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
 
-       if (handled)
-               return IRQ_HANDLED;
-       else
-               return IRQ_NONE;
+       VIA_WRITE(VIA_REG_INTERRUPT, status);
+       return handled;
 }
 
 static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t * dev_priv)
index 79761ca..c627136 100644 (file)
@@ -131,8 +131,12 @@ int via_init_context(struct drm_device *dev, int context)
 }
 
 int via_final_context(struct drm_device *dev, int context)
-{
-       int i;
+{      
+        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 &&
                    (global_ppriv[i].context == context))
@@ -167,6 +171,22 @@ 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 = XVMCLOCKPTR(sAPriv, i);
+               if ( (_DRM_LOCKING_CONTEXT( *lock ) == i) && 
+                    (_DRM_LOCK_IS_HELD( *lock ))) {
+                       if ( *lock & _DRM_LOCK_CONT) {
+                               DRM_WAKEUP( &(dev_priv->decoder_queue[i]));
+                       }
+                       *lock &= ~( _DRM_LOCK_HELD | _DRM_LOCK_CONT );
+               }
+       }
+                       
 #if defined(__linux__)
        /* Linux specific until context tracking code gets ported to BSD */
        /* Last context, perform cleanup */
@@ -362,4 +382,5 @@ void DRM(driver_register_fns) (drm_device_t * dev) {
        dev->fn_tbl.irq_postinstall = via_driver_irq_postinstall;
        dev->fn_tbl.irq_uninstall = via_driver_irq_uninstall;
        dev->fn_tbl.irq_handler = via_driver_irq_handler;
+       dev->fn_tbl.dma_quiescent = via_driver_dma_quiescent;
 }
index 355a64f..1af4ea4 100644 (file)
@@ -36,6 +36,8 @@ typedef enum{
        state_command,
        state_header2,
        state_header1,
+       state_vheader5,
+       state_vheader6,
        state_error
 } verifier_state_t;
 
@@ -72,6 +74,8 @@ typedef enum{
        check_texture_addr7,
        check_texture_addr8,
        check_texture_addr_mode,
+       check_for_vertex_count,
+       check_number_texunits,
        forbidden_command
 }hazard_t;
 
@@ -165,7 +169,7 @@ static hz_init_t init_table1[] = {
        {0x7A, no_check},
        {0x7B, no_check},
        {0x7C, no_check},
-       {0x7D, no_check}
+       {0x7D, check_for_vertex_count}
 };
 
    
@@ -232,7 +236,7 @@ static hz_init_t init_table3[] = {
        {0xf2, check_for_header2_err},
        {0xf0, check_for_header1_err},
        {0xcc, check_for_dummy},
-       {0x00, no_check}
+       {0x00, check_number_texunits}
 };
    
                       
@@ -254,8 +258,10 @@ typedef struct{
        uint32_t tex_palette_size[2];
        sequence_t unfinished;
        int agp_texture;
+       int multitex;
        drm_device_t *dev;
        drm_map_t *map_cache;
+       uint32_t vertex_count;
 } sequence_context_t;
 
 static sequence_context_t hc_sequence;
@@ -497,6 +503,12 @@ investigate_hazard( uint32_t cmd, hazard_t hz, sequence_context_t *cur_seq)
                cur_seq->tex_palette_size[cur_seq->texture] = 
                        (cmd >> 16) & 0x000000007;
                return 0;
+       case check_for_vertex_count:
+               cur_seq->vertex_count = cmd & 0x0000FFFF;
+               return 0;
+       case check_number_texunits:
+               cur_seq->multitex = (cmd >> 3) & 1;
+               return 0;
        default:
                DRM_ERROR("Illegal DMA data: 0x%x\n", cmd);
                return 2;
@@ -505,6 +517,84 @@ investigate_hazard( uint32_t cmd, hazard_t hz, sequence_context_t *cur_seq)
 }
 
 
+static __inline__ int
+via_check_prim_list(uint32_t const **buffer, const uint32_t *buf_end,
+                   sequence_context_t *cur_seq)
+{
+       uint32_t a_fire, bcmd , dw_count;
+       int ret = 0;
+       int have_fire;
+       const uint32_t *buf = *buffer;
+
+       while(buf < buf_end) {
+               have_fire = 0;
+               if ((buf_end - buf) < 2) {
+                       DRM_ERROR("Unexpected termination of primitive list.\n");
+                       ret = 1;
+                       break;
+               }
+               if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdB) break;
+               bcmd = *buf++;
+               if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdA) {
+                       DRM_ERROR("Expected Vertex List A command, got 0x%x\n",
+                                 *buf);
+                       ret = 1;
+                       break;
+               }
+               a_fire = *buf++ | HC_HPLEND_MASK | HC_HPMValidN_MASK | HC_HE3Fire_MASK; 
+       
+               /*
+                * How many dwords per vertex ?
+                */ 
+               
+               if ((bcmd & (0xF << 11)) == 0) {
+                       DRM_ERROR("Illegal B command vertex data for AGP.\n");
+                       ret = 1;
+                       break;
+               } 
+
+               dw_count = 0;
+               if (bcmd & (1 << 7)) dw_count += (cur_seq->multitex) ? 2:1;
+               if (bcmd & (1 << 8)) dw_count += (cur_seq->multitex) ? 2:1;
+               if (bcmd & (1 << 9)) dw_count++;
+               if (bcmd & (1 << 10)) dw_count++;
+               if (bcmd & (1 << 11)) dw_count++;
+               if (bcmd & (1 << 12)) dw_count++;
+               if (bcmd & (1 << 13)) dw_count++;
+               if (bcmd & (1 << 14)) dw_count++;
+
+               while(buf < buf_end) {
+                       if (*buf == HALCYON_HEADER2) {
+                               DRM_ERROR("Missing Vertex Fire command or verifier "
+                                         "lost sync.\n");
+                               ret = 1;
+                               break;
+                       }
+                       if (*buf == a_fire) {
+                               have_fire = 1;
+                               buf++;
+                               if (buf < buf_end && *buf == a_fire) 
+                                       buf++;
+                               break;
+                       }
+                       if ((ret = eat_words(&buf, buf_end, dw_count)))
+                               break;
+               }
+               if (buf >= buf_end && !have_fire) {
+                       DRM_ERROR("Missing Vertex Fire command or verifier "
+                                 "lost sync.\n");
+                       ret = 1;
+                       break;
+               }
+       } 
+       *buffer = buf;
+       return ret;
+}
+
+
+                      
+
+
 static __inline__ verifier_state_t
 via_check_header2( uint32_t const **buffer, const uint32_t *buf_end )
 {
@@ -514,6 +604,7 @@ via_check_header2( uint32_t const **buffer, const uint32_t *buf_end )
        const uint32_t *buf = *buffer;
        const hazard_t *hz_table;
 
+
        if ((buf_end - buf) < 2) {
                DRM_ERROR("Illegal termination of DMA HALCYON_HEADER2 sequence.\n");
                return state_error;
@@ -523,32 +614,10 @@ via_check_header2( uint32_t const **buffer, const uint32_t *buf_end )
 
        switch(cmd) {
        case HC_ParaType_CmdVdata:
-
-               /* 
-                * Command vertex data.
-                * It is assumed that the command regulator remains in this state
-                * until it encounters a possibly double fire command or a header2 data.
-                * FIXME: Vertex data can accidently be header2 or fire.
-                * CHECK: What does the regulator do if it encounters a header1 
-                * cmd?
-                */
-
-               while (buf < buf_end) {
-                       if (*buf == HALCYON_HEADER2) break;
-                       if ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD) {
-                               buf++;
-                               if ((buf < buf_end) && 
-                                   ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD))
-                                       buf++;
-                               if ((buf < buf_end) && 
-                                   ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD))
-                                       break;
-                       }
-                       buf++;
-               }
+               if (via_check_prim_list(&buf, buf_end, &hc_sequence )) 
+                       return state_error;
                *buffer = buf;
                return state_command;
-
        case HC_ParaType_NotTex:
                hz_table = table1;
                break;
@@ -590,7 +659,8 @@ via_check_header2( uint32_t const **buffer, const uint32_t *buf_end )
                 */
 
                DRM_ERROR("Invalid or unimplemented HALCYON_HEADER2 "
-                         "DMA subcommand: 0x%x\n", cmd);
+                         "DMA subcommand: 0x%x. Previous dword: 0x%x\n", 
+                         cmd, *(buf -2));
                *buffer = buf;
                return state_error;
        }
@@ -618,6 +688,41 @@ via_check_header2( uint32_t const **buffer, const uint32_t *buf_end )
 }
 
 
+static __inline__ int
+verify_mmio_address( uint32_t address)
+{
+       if ((address > 0x3FF) && (address < 0xC00 )) {
+               DRM_ERROR("Invalid HALCYON_HEADER1 command. "
+                         "Attempt to access 3D- or command burst area.\n");
+               return 1;
+       } else if (address > 0xCFF ) {
+               DRM_ERROR("Invalid HALCYON_HEADER1 command. "
+                         "Attempt to access VGA registers.\n");
+               return 1;
+       }
+       return 0;
+}
+
+static __inline__ int
+verify_video_tail( uint32_t const **buffer, const uint32_t *buf_end, uint32_t dwords) 
+{
+       const uint32_t *buf = *buffer;
+
+       if (buf_end - buf < dwords) {
+               DRM_ERROR("Illegal termination of video command.\n");
+               return 1;
+       }
+       while (dwords--) {
+               if (*buf++) {
+                       DRM_ERROR("Illegal video command tail.\n");
+                       return 1;
+               }
+       }
+       *buffer = buf;
+       return 0;
+}
+               
+
 static __inline__ verifier_state_t
 via_check_header1( uint32_t const **buffer, const uint32_t *buf_end )
 {
@@ -650,6 +755,75 @@ via_check_header1( uint32_t const **buffer, const uint32_t *buf_end )
        return ret;
 }
 
+static __inline__ verifier_state_t
+via_check_vheader5( uint32_t const **buffer, const uint32_t *buf_end )
+{
+       uint32_t data;
+       const uint32_t *buf = *buffer;
+
+       if (buf_end - buf < 4) {
+               DRM_ERROR("Illegal termination of video header5 command\n");
+               return state_error;
+       }
+
+       data = *buf++ & ~VIA_VIDEOMASK;
+       if (verify_mmio_address(data))
+               return state_error;
+
+       data = *buf++;
+       if (*buf++ != 0x00F50000) {
+               DRM_ERROR("Illegal header5 header data\n");
+               return state_error;
+       }
+       if (*buf++ != 0x00000000) {
+               DRM_ERROR("Illegal header5 header data\n");
+               return state_error;
+       }
+       if (eat_words(&buf, buf_end, data)) 
+               return state_error;
+       if (verify_video_tail(&buf, buf_end, 4 - (data & 3))) 
+               return state_error;
+       *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;
+       }
+
+       data = *buf++;
+       if (*buf++ != 0x00F60000) {
+               DRM_ERROR("Illegal header6 header data\n");
+               return state_error;
+       }
+       if (*buf++ != 0x00000000) {
+               DRM_ERROR("Illegal header6 header data\n");
+               return state_error;
+       }
+       if ((buf_end - buf) < (data << 1)) {
+               DRM_ERROR("Illegal termination of video header6 command\n");
+       }
+       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)))
+               return state_error;
+       *buffer = buf;
+       return state_command;
+} 
 
 
 int 
@@ -665,6 +839,7 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size, drm_device_t
        hc_sequence.map_cache = NULL;
 
        while (buf < buf_end) {
+
                switch (state) {
                case state_header2:
                        state = via_check_header2( &buf, buf_end );
@@ -672,11 +847,21 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size, drm_device_t
                case state_header1:
                        state = via_check_header1( &buf, buf_end );
                        break;
+               case state_vheader5:
+                       state = via_check_vheader5( &buf, buf_end );
+                       break;
+               case state_vheader6:
+                       state = via_check_vheader6( &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);