From 093988f36ffcb0201927f8b452e546e1141aa0fa Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Sat, 23 May 2009 15:00:21 +0000 Subject: DSS2: DISPC: fix irq handling locking --- diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index b0e4960..b3685b2 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -154,23 +154,20 @@ static struct { struct clk *dpll4_m4_ck; - spinlock_t irq_lock; - unsigned long cache_req_pck; unsigned long cache_prate; struct dispc_clock_info cache_cinfo; - u32 irq_error_mask; + spinlock_t irq_lock; + u32 irq_error_mask; struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS]; - - spinlock_t error_lock; u32 error_irqs; struct work_struct error_work; u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; } dispc; -static void omap_dispc_set_irqs(void); +static void _omap_dispc_set_irqs(void); static inline void dispc_write_reg(const struct dispc_reg idx, u32 val) { @@ -1691,10 +1688,13 @@ void dispc_enable_digit_out(bool enable) } if (enable) { + unsigned long flags; /* When we enable digit output, we'll get an extra digit * sync lost interrupt, that we need to ignore */ + spin_lock_irqsave(&dispc.irq_lock, flags); dispc.irq_error_mask &= ~DISPC_IRQ_SYNC_LOST_DIGIT; - omap_dispc_set_irqs(); + _omap_dispc_set_irqs(); + spin_unlock_irqrestore(&dispc.irq_lock, flags); } /* When we disable digit output, we need to wait until fields are done. @@ -1728,9 +1728,12 @@ void dispc_enable_digit_out(bool enable) DSSERR("failed to unregister EVSYNC isr\n"); if (enable) { + unsigned long flags; + spin_lock_irqsave(&dispc.irq_lock, flags); dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR; dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT); - omap_dispc_set_irqs(); + _omap_dispc_set_irqs(); + spin_unlock_irqrestore(&dispc.irq_lock, flags); } enable_clocks(0); @@ -2508,14 +2511,14 @@ int dispc_get_clock_div(struct dispc_clock_info *cinfo) return 0; } -static void omap_dispc_set_irqs(void) +/* dispc.irq_lock has to be locked by the caller */ +static void _omap_dispc_set_irqs(void) { - unsigned long flags; - u32 mask = dispc.irq_error_mask; + u32 mask; int i; struct omap_dispc_isr_data *isr_data; - spin_lock_irqsave(&dispc.irq_lock, flags); + mask = dispc.irq_error_mask; for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { isr_data = &dispc.registered_isr[i]; @@ -2528,9 +2531,8 @@ static void omap_dispc_set_irqs(void) enable_clocks(1); dispc_write_reg(DISPC_IRQENABLE, mask); - enable_clocks(0); - spin_unlock_irqrestore(&dispc.irq_lock, flags); + enable_clocks(0); } int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask) @@ -2571,11 +2573,14 @@ int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask) break; } -err: + + _omap_dispc_set_irqs(); + spin_unlock_irqrestore(&dispc.irq_lock, flags); - if (ret == 0) - omap_dispc_set_irqs(); + return 0; +err: + spin_unlock_irqrestore(&dispc.irq_lock, flags); return ret; } @@ -2606,10 +2611,10 @@ int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask) break; } - spin_unlock_irqrestore(&dispc.irq_lock, flags); - if (ret == 0) - omap_dispc_set_irqs(); + _omap_dispc_set_irqs(); + + spin_unlock_irqrestore(&dispc.irq_lock, flags); return ret; } @@ -2645,11 +2650,15 @@ static void print_irq_status(u32 status) void dispc_irq_handler(void) { int i; - u32 irqstatus = dispc_read_reg(DISPC_IRQSTATUS); + u32 irqstatus; u32 handledirqs = 0; u32 unhandled_errors; struct omap_dispc_isr_data *isr_data; + spin_lock(&dispc.irq_lock); + + irqstatus = dispc_read_reg(DISPC_IRQSTATUS); + #ifdef DEBUG if (dss_debug) print_irq_status(irqstatus); @@ -2673,15 +2682,15 @@ void dispc_irq_handler(void) unhandled_errors = irqstatus & ~handledirqs & dispc.irq_error_mask; if (unhandled_errors) { - spin_lock(&dispc.error_lock); dispc.error_irqs |= unhandled_errors; - spin_unlock(&dispc.error_lock); dispc.irq_error_mask &= ~unhandled_errors; - omap_dispc_set_irqs(); + _omap_dispc_set_irqs(); schedule_work(&dispc.error_work); } + + spin_unlock(&dispc.irq_lock); } static void dispc_error_worker(struct work_struct *work) @@ -2690,10 +2699,10 @@ static void dispc_error_worker(struct work_struct *work) u32 errors; unsigned long flags; - spin_lock_irqsave(&dispc.error_lock, flags); + spin_lock_irqsave(&dispc.irq_lock, flags); errors = dispc.error_irqs; dispc.error_irqs = 0; - spin_unlock_irqrestore(&dispc.error_lock, flags); + spin_unlock_irqrestore(&dispc.irq_lock, flags); if (errors & DISPC_IRQ_GFX_FIFO_UNDERFLOW) { DSSERR("GFX_FIFO_UNDERFLOW, disabling GFX\n"); @@ -2836,8 +2845,10 @@ static void dispc_error_worker(struct work_struct *work) } } + spin_lock_irqsave(&dispc.irq_lock, flags); dispc.irq_error_mask |= errors; - omap_dispc_set_irqs(); + _omap_dispc_set_irqs(); + spin_unlock_irqrestore(&dispc.irq_lock, flags); } int omap_dispc_wait_for_irq_timeout(u32 irqmask, unsigned long timeout) @@ -2921,6 +2932,10 @@ void dispc_fake_vsync_irq(void) static void _omap_dispc_initialize_irq(void) { + unsigned long flags; + + spin_lock_irqsave(&dispc.irq_lock, flags); + memset(dispc.registered_isr, 0, sizeof(dispc.registered_isr)); dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR; @@ -2929,7 +2944,9 @@ static void _omap_dispc_initialize_irq(void) * so clear it */ dispc_write_reg(DISPC_IRQSTATUS, dispc_read_reg(DISPC_IRQSTATUS)); - omap_dispc_set_irqs(); + _omap_dispc_set_irqs(); + + spin_unlock_irqrestore(&dispc.irq_lock, flags); } void dispc_enable_sidle(void) @@ -2970,7 +2987,6 @@ int dispc_init(void) u32 rev; spin_lock_init(&dispc.irq_lock); - spin_lock_init(&dispc.error_lock); INIT_WORK(&dispc.error_work, dispc_error_worker); -- cgit v0.8.2.1-10-g45e7