summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomi Valkeinen <tomi.valkeinen@nokia.com>2009-05-23 18:00:21 +0300
committerWajahat Khan <w-khan@ti.com>2009-10-19 10:26:37 -0500
commit8344e788f584d362a647bcc8bb366c30d9ac8fdb (patch)
tree859714da249af0dfa81d173a3af32ff1221c324b
parent53e03fb9615961d37065fd104e73bbe7ff4eb003 (diff)
DSS2: DISPC: fix irq handling locking
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@nokia.com>
-rw-r--r--drivers/video/omap2/dss/dispc.c74
1 files changed, 45 insertions, 29 deletions
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index b0e496061129..b3685b28d18a 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);