summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStuart Menefy <stuart.menefy@st.com>2009-08-24 18:27:33 +0900
committerPaul Mundt <lethal@linux-sh.org>2009-08-24 18:27:33 +0900
commit6000fc4d6f3e55ad52cce8d76317187fe01af2aa (patch)
treebc86a1f13465a791b7e77f7663280bcb23fdd378
parentbd4fb4d4c1e4a5a2ffbf57a83817a749df1339dd (diff)
sh: Fixes some write posting issues in the interrupt handling for SH
It is possible for the CPU to re-enable it's interrupt block bit before the write to the interrupt controller has actually masked out the external interupt at the controller. We get around this by reading back from the interrupt controller which will ensure the write has happened. Signed-off-by: Stuart Menefy <stuart.menefy@st.com> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
-rw-r--r--arch/sh/kernel/cpu/irq/ipr.c1
-rw-r--r--drivers/sh/intc.c8
2 files changed, 8 insertions, 1 deletions
diff --git a/arch/sh/kernel/cpu/irq/ipr.c b/arch/sh/kernel/cpu/irq/ipr.c
index 808d99a48ef..c1508a90fc6 100644
--- a/arch/sh/kernel/cpu/irq/ipr.c
+++ b/arch/sh/kernel/cpu/irq/ipr.c
@@ -35,6 +35,7 @@ static void disable_ipr_irq(unsigned int irq)
unsigned long addr = get_ipr_desc(irq)->ipr_offsets[p->ipr_idx];
/* Set the priority in IPR to 0 */
__raw_writew(__raw_readw(addr) & (0xffff ^ (0xf << p->shift)), addr);
+ (void)__raw_readw(addr); /* Read back to flush write posting */
}
static void enable_ipr_irq(unsigned int irq)
diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c
index 3dd231a643b..4b1ca9d2835 100644
--- a/drivers/sh/intc.c
+++ b/drivers/sh/intc.c
@@ -77,7 +77,7 @@ static unsigned long ack_handle[NR_IRQS];
static inline struct intc_desc_int *get_intc_desc(unsigned int irq)
{
struct irq_chip *chip = get_irq_chip(irq);
- return (void *)((char *)chip - offsetof(struct intc_desc_int, chip));
+ return container_of(chip, struct intc_desc_int, chip);
}
static inline unsigned int set_field(unsigned int value,
@@ -95,16 +95,19 @@ static inline unsigned int set_field(unsigned int value,
static void write_8(unsigned long addr, unsigned long h, unsigned long data)
{
__raw_writeb(set_field(0, data, h), addr);
+ (void)__raw_readb(addr); /* Defeat write posting */
}
static void write_16(unsigned long addr, unsigned long h, unsigned long data)
{
__raw_writew(set_field(0, data, h), addr);
+ (void)__raw_readw(addr); /* Defeat write posting */
}
static void write_32(unsigned long addr, unsigned long h, unsigned long data)
{
__raw_writel(set_field(0, data, h), addr);
+ (void)__raw_readl(addr); /* Defeat write posting */
}
static void modify_8(unsigned long addr, unsigned long h, unsigned long data)
@@ -112,6 +115,7 @@ static void modify_8(unsigned long addr, unsigned long h, unsigned long data)
unsigned long flags;
local_irq_save(flags);
__raw_writeb(set_field(__raw_readb(addr), data, h), addr);
+ (void)__raw_readb(addr); /* Defeat write posting */
local_irq_restore(flags);
}
@@ -120,6 +124,7 @@ static void modify_16(unsigned long addr, unsigned long h, unsigned long data)
unsigned long flags;
local_irq_save(flags);
__raw_writew(set_field(__raw_readw(addr), data, h), addr);
+ (void)__raw_readw(addr); /* Defeat write posting */
local_irq_restore(flags);
}
@@ -128,6 +133,7 @@ static void modify_32(unsigned long addr, unsigned long h, unsigned long data)
unsigned long flags;
local_irq_save(flags);
__raw_writel(set_field(__raw_readl(addr), data, h), addr);
+ (void)__raw_readl(addr); /* Defeat write posting */
local_irq_restore(flags);
}