@@ -2446,6 +2446,152 @@ static void i915_driver_irq_uninstall(struct drm_device * dev)
24462446 I915_WRITE (IIR , I915_READ (IIR ));
24472447}
24482448
2449+ static void i8xx_irq_preinstall (struct drm_device * dev )
2450+ {
2451+ drm_i915_private_t * dev_priv = (drm_i915_private_t * ) dev -> dev_private ;
2452+ int pipe ;
2453+
2454+ atomic_set (& dev_priv -> irq_received , 0 );
2455+
2456+ for_each_pipe (pipe )
2457+ I915_WRITE (PIPESTAT (pipe ), 0 );
2458+ I915_WRITE16 (IMR , 0xffff );
2459+ I915_WRITE16 (IER , 0x0 );
2460+ POSTING_READ16 (IER );
2461+ }
2462+
2463+ static int i8xx_irq_postinstall (struct drm_device * dev )
2464+ {
2465+ drm_i915_private_t * dev_priv = (drm_i915_private_t * ) dev -> dev_private ;
2466+
2467+ dev_priv -> vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B ;
2468+
2469+ dev_priv -> pipestat [0 ] = 0 ;
2470+ dev_priv -> pipestat [1 ] = 0 ;
2471+
2472+ I915_WRITE16 (EMR ,
2473+ ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH ));
2474+
2475+ /* Unmask the interrupts that we always want on. */
2476+ dev_priv -> irq_mask =
2477+ ~(I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
2478+ I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
2479+ I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
2480+ I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT |
2481+ I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT );
2482+ I915_WRITE16 (IMR , dev_priv -> irq_mask );
2483+
2484+ I915_WRITE16 (IER ,
2485+ I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
2486+ I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
2487+ I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT |
2488+ I915_USER_INTERRUPT );
2489+ POSTING_READ16 (IER );
2490+
2491+ return 0 ;
2492+ }
2493+
2494+ static irqreturn_t i8xx_irq_handler (DRM_IRQ_ARGS )
2495+ {
2496+ struct drm_device * dev = (struct drm_device * ) arg ;
2497+ drm_i915_private_t * dev_priv = (drm_i915_private_t * ) dev -> dev_private ;
2498+ struct drm_i915_master_private * master_priv ;
2499+ u16 iir , new_iir ;
2500+ u32 pipe_stats [2 ];
2501+ unsigned long irqflags ;
2502+ int irq_received ;
2503+ int pipe ;
2504+ u16 flip_mask =
2505+ I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
2506+ I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT ;
2507+
2508+ atomic_inc (& dev_priv -> irq_received );
2509+
2510+ iir = I915_READ16 (IIR );
2511+ if (iir == 0 )
2512+ return IRQ_NONE ;
2513+
2514+ while (iir & ~flip_mask ) {
2515+ /* Can't rely on pipestat interrupt bit in iir as it might
2516+ * have been cleared after the pipestat interrupt was received.
2517+ * It doesn't set the bit in iir again, but it still produces
2518+ * interrupts (for non-MSI).
2519+ */
2520+ spin_lock_irqsave (& dev_priv -> irq_lock , irqflags );
2521+ if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT )
2522+ i915_handle_error (dev , false);
2523+
2524+ for_each_pipe (pipe ) {
2525+ int reg = PIPESTAT (pipe );
2526+ pipe_stats [pipe ] = I915_READ (reg );
2527+
2528+ /*
2529+ * Clear the PIPE*STAT regs before the IIR
2530+ */
2531+ if (pipe_stats [pipe ] & 0x8000ffff ) {
2532+ if (pipe_stats [pipe ] & PIPE_FIFO_UNDERRUN_STATUS )
2533+ DRM_DEBUG_DRIVER ("pipe %c underrun\n" ,
2534+ pipe_name (pipe ));
2535+ I915_WRITE (reg , pipe_stats [pipe ]);
2536+ irq_received = 1 ;
2537+ }
2538+ }
2539+ spin_unlock_irqrestore (& dev_priv -> irq_lock , irqflags );
2540+
2541+ I915_WRITE16 (IIR , iir & ~flip_mask );
2542+ new_iir = I915_READ16 (IIR ); /* Flush posted writes */
2543+
2544+ if (dev -> primary -> master ) {
2545+ master_priv = dev -> primary -> master -> driver_priv ;
2546+ if (master_priv -> sarea_priv )
2547+ master_priv -> sarea_priv -> last_dispatch =
2548+ READ_BREADCRUMB (dev_priv );
2549+ }
2550+
2551+ if (iir & I915_USER_INTERRUPT )
2552+ notify_ring (dev , & dev_priv -> ring [RCS ]);
2553+
2554+ if (pipe_stats [0 ] & PIPE_VBLANK_INTERRUPT_STATUS &&
2555+ drm_handle_vblank (dev , 0 )) {
2556+ if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT ) {
2557+ intel_prepare_page_flip (dev , 0 );
2558+ intel_finish_page_flip (dev , 0 );
2559+ flip_mask &= ~I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT ;
2560+ }
2561+ }
2562+
2563+ if (pipe_stats [1 ] & PIPE_VBLANK_INTERRUPT_STATUS &&
2564+ drm_handle_vblank (dev , 1 )) {
2565+ if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT ) {
2566+ intel_prepare_page_flip (dev , 1 );
2567+ intel_finish_page_flip (dev , 1 );
2568+ flip_mask &= ~I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT ;
2569+ }
2570+ }
2571+
2572+ iir = new_iir ;
2573+ }
2574+
2575+ return IRQ_HANDLED ;
2576+ }
2577+
2578+ static void i8xx_irq_uninstall (struct drm_device * dev )
2579+ {
2580+ drm_i915_private_t * dev_priv = (drm_i915_private_t * ) dev -> dev_private ;
2581+ int pipe ;
2582+
2583+ dev_priv -> vblank_pipe = 0 ;
2584+
2585+ for_each_pipe (pipe ) {
2586+ /* Clear enable bits; then clear status bits */
2587+ I915_WRITE (PIPESTAT (pipe ), 0 );
2588+ I915_WRITE (PIPESTAT (pipe ), I915_READ (PIPESTAT (pipe )));
2589+ }
2590+ I915_WRITE16 (IMR , 0xffff );
2591+ I915_WRITE16 (IER , 0x0 );
2592+ I915_WRITE16 (IIR , I915_READ16 (IIR ));
2593+ }
2594+
24492595void intel_irq_init (struct drm_device * dev )
24502596{
24512597 dev -> driver -> get_vblank_counter = i915_get_vblank_counter ;
@@ -2485,10 +2631,17 @@ void intel_irq_init(struct drm_device *dev)
24852631 dev -> driver -> enable_vblank = ironlake_enable_vblank ;
24862632 dev -> driver -> disable_vblank = ironlake_disable_vblank ;
24872633 } else {
2488- dev -> driver -> irq_preinstall = i915_driver_irq_preinstall ;
2489- dev -> driver -> irq_postinstall = i915_driver_irq_postinstall ;
2490- dev -> driver -> irq_uninstall = i915_driver_irq_uninstall ;
2491- dev -> driver -> irq_handler = i915_driver_irq_handler ;
2634+ if (INTEL_INFO (dev )-> gen == 2 ) {
2635+ dev -> driver -> irq_preinstall = i8xx_irq_preinstall ;
2636+ dev -> driver -> irq_postinstall = i8xx_irq_postinstall ;
2637+ dev -> driver -> irq_handler = i8xx_irq_handler ;
2638+ dev -> driver -> irq_uninstall = i8xx_irq_uninstall ;
2639+ } else {
2640+ dev -> driver -> irq_preinstall = i915_driver_irq_preinstall ;
2641+ dev -> driver -> irq_postinstall = i915_driver_irq_postinstall ;
2642+ dev -> driver -> irq_uninstall = i915_driver_irq_uninstall ;
2643+ dev -> driver -> irq_handler = i915_driver_irq_handler ;
2644+ }
24922645 dev -> driver -> enable_vblank = i915_enable_vblank ;
24932646 dev -> driver -> disable_vblank = i915_disable_vblank ;
24942647 }
0 commit comments