Commit 3ce86ee1 authored by Pete Popov's avatar Pete Popov Committed by Ralf Baechle

Au1x PM fixes.

Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent 7ab1261f
...@@ -83,7 +83,7 @@ inline void local_disable_irq(unsigned int irq_nr); ...@@ -83,7 +83,7 @@ inline void local_disable_irq(unsigned int irq_nr);
void (*board_init_irq)(void); void (*board_init_irq)(void);
#ifdef CONFIG_PM #ifdef CONFIG_PM
extern void counter0_irq(int irq, void *dev_id, struct pt_regs *regs); extern irqreturn_t counter0_irq(int irq, void *dev_id, struct pt_regs *regs);
#endif #endif
static DEFINE_SPINLOCK(irq_lock); static DEFINE_SPINLOCK(irq_lock);
...@@ -293,29 +293,31 @@ static struct hw_interrupt_type level_irq_type = { ...@@ -293,29 +293,31 @@ static struct hw_interrupt_type level_irq_type = {
}; };
#ifdef CONFIG_PM #ifdef CONFIG_PM
void startup_match20_interrupt(void (*handler)(int, void *, struct pt_regs *)) void startup_match20_interrupt(irqreturn_t (*handler)(int, void *, struct pt_regs *))
{ {
static struct irqaction action; struct irq_desc *desc = &irq_desc[AU1000_TOY_MATCH2_INT];
/* This is a big problem.... since we didn't use request_irq
when kernel/irq.c calls probe_irq_xxx this interrupt will
be probed for usage. This will end up disabling the device :(
Give it a bogus "action" pointer -- this will keep it from static struct irqaction action;
getting auto-probed! memset(&action, 0, sizeof(struct irqaction));
By setting the status to match that of request_irq() we /* This is a big problem.... since we didn't use request_irq
can avoid it. --cgray * when kernel/irq.c calls probe_irq_xxx this interrupt will
* be probed for usage. This will end up disabling the device :(
* Give it a bogus "action" pointer -- this will keep it from
* getting auto-probed!
*
* By setting the status to match that of request_irq() we
* can avoid it. --cgray
*/ */
action.dev_id = handler; action.dev_id = handler;
action.flags = 0; action.flags = SA_INTERRUPT;
action.mask = 0; cpus_clear(action.mask);
action.name = "Au1xxx TOY"; action.name = "Au1xxx TOY";
action.handler = handler; action.handler = handler;
action.next = NULL; action.next = NULL;
irq_desc[AU1000_TOY_MATCH2_INT].action = &action; desc->action = &action;
irq_desc[AU1000_TOY_MATCH2_INT].status desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);
&= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);
local_enable_irq(AU1000_TOY_MATCH2_INT); local_enable_irq(AU1000_TOY_MATCH2_INT);
} }
......
...@@ -34,11 +34,13 @@ ...@@ -34,11 +34,13 @@
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sysctl.h> #include <linux/sysctl.h>
#include <linux/jiffies.h>
#include <asm/string.h> #include <asm/string.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/cacheflush.h>
#include <asm/mach-au1x00/au1000.h> #include <asm/mach-au1x00/au1000.h>
#ifdef CONFIG_PM #ifdef CONFIG_PM
...@@ -50,7 +52,7 @@ ...@@ -50,7 +52,7 @@
# define DPRINTK(fmt, args...) # define DPRINTK(fmt, args...)
#endif #endif
static void calibrate_delay(void); static void au1000_calibrate_delay(void);
extern void set_au1x00_speed(unsigned int new_freq); extern void set_au1x00_speed(unsigned int new_freq);
extern unsigned int get_au1x00_speed(void); extern unsigned int get_au1x00_speed(void);
...@@ -260,7 +262,7 @@ int au_sleep(void) ...@@ -260,7 +262,7 @@ int au_sleep(void)
} }
static int pm_do_sleep(ctl_table * ctl, int write, struct file *file, static int pm_do_sleep(ctl_table * ctl, int write, struct file *file,
void *buffer, size_t * len) void __user *buffer, size_t * len, loff_t *ppos)
{ {
int retval = 0; int retval = 0;
#ifdef SLEEP_TEST_TIMEOUT #ifdef SLEEP_TEST_TIMEOUT
...@@ -294,7 +296,7 @@ static int pm_do_sleep(ctl_table * ctl, int write, struct file *file, ...@@ -294,7 +296,7 @@ static int pm_do_sleep(ctl_table * ctl, int write, struct file *file,
} }
static int pm_do_suspend(ctl_table * ctl, int write, struct file *file, static int pm_do_suspend(ctl_table * ctl, int write, struct file *file,
void *buffer, size_t * len) void __user *buffer, size_t * len, loff_t *ppos)
{ {
int retval = 0; int retval = 0;
...@@ -313,7 +315,7 @@ static int pm_do_suspend(ctl_table * ctl, int write, struct file *file, ...@@ -313,7 +315,7 @@ static int pm_do_suspend(ctl_table * ctl, int write, struct file *file,
static int pm_do_freq(ctl_table * ctl, int write, struct file *file, static int pm_do_freq(ctl_table * ctl, int write, struct file *file,
void *buffer, size_t * len) void __user *buffer, size_t * len, loff_t *ppos)
{ {
int retval = 0, i; int retval = 0, i;
unsigned long val, pll; unsigned long val, pll;
...@@ -408,14 +410,14 @@ static int pm_do_freq(ctl_table * ctl, int write, struct file *file, ...@@ -408,14 +410,14 @@ static int pm_do_freq(ctl_table * ctl, int write, struct file *file,
/* We don't want _any_ interrupts other than /* We don't want _any_ interrupts other than
* match20. Otherwise our calibrate_delay() * match20. Otherwise our au1000_calibrate_delay()
* calculation will be off, potentially a lot. * calculation will be off, potentially a lot.
*/ */
intc0_mask = save_local_and_disable(0); intc0_mask = save_local_and_disable(0);
intc1_mask = save_local_and_disable(1); intc1_mask = save_local_and_disable(1);
local_enable_irq(AU1000_TOY_MATCH2_INT); local_enable_irq(AU1000_TOY_MATCH2_INT);
spin_unlock_irqrestore(&pm_lock, flags); spin_unlock_irqrestore(&pm_lock, flags);
calibrate_delay(); au1000_calibrate_delay();
restore_local_and_enable(0, intc0_mask); restore_local_and_enable(0, intc0_mask);
restore_local_and_enable(1, intc1_mask); restore_local_and_enable(1, intc1_mask);
return retval; return retval;
...@@ -455,7 +457,7 @@ __initcall(pm_init); ...@@ -455,7 +457,7 @@ __initcall(pm_init);
better than 1% */ better than 1% */
#define LPS_PREC 8 #define LPS_PREC 8
static void calibrate_delay(void) static void au1000_calibrate_delay(void)
{ {
unsigned long ticks, loopbit; unsigned long ticks, loopbit;
int lps_precision = LPS_PREC; int lps_precision = LPS_PREC;
......
...@@ -63,8 +63,11 @@ extern int allow_au1k_wait; /* default off for CP0 Counter */ ...@@ -63,8 +63,11 @@ extern int allow_au1k_wait; /* default off for CP0 Counter */
static unsigned int timerhi = 0, timerlo = 0; static unsigned int timerhi = 0, timerlo = 0;
#ifdef CONFIG_PM #ifdef CONFIG_PM
#define MATCH20_INC 328 #if HZ < 100 || HZ > 1000
extern void startup_match20_interrupt(void (*handler)(int, void *, struct pt_regs *)); #error "unsupported HZ value! Must be in [100,1000]"
#endif
#define MATCH20_INC (328*100/HZ) /* magic number 328 is for HZ=100... */
extern void startup_match20_interrupt(irqreturn_t (*handler)(int, void *, struct pt_regs *));
static unsigned long last_pc0, last_match20; static unsigned long last_pc0, last_match20;
#endif #endif
...@@ -116,17 +119,16 @@ null: ...@@ -116,17 +119,16 @@ null:
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
void counter0_irq(int irq, void *dev_id, struct pt_regs *regs) irqreturn_t counter0_irq(int irq, void *dev_id, struct pt_regs *regs)
{ {
unsigned long pc0; unsigned long pc0;
int time_elapsed; int time_elapsed;
static int jiffie_drift = 0; static int jiffie_drift = 0;
kstat.irqs[0][irq]++;
if (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20) { if (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20) {
/* should never happen! */ /* should never happen! */
printk(KERN_WARNING "counter 0 w status eror\n"); printk(KERN_WARNING "counter 0 w status error\n");
return; return IRQ_NONE;
} }
pc0 = au_readl(SYS_TOYREAD); pc0 = au_readl(SYS_TOYREAD);
...@@ -163,6 +165,8 @@ void counter0_irq(int irq, void *dev_id, struct pt_regs *regs) ...@@ -163,6 +165,8 @@ void counter0_irq(int irq, void *dev_id, struct pt_regs *regs)
update_process_times(user_mode(regs)); update_process_times(user_mode(regs));
#endif #endif
} }
return IRQ_HANDLED;
} }
/* When we wakeup from sleep, we have to "catch up" on all of the /* When we wakeup from sleep, we have to "catch up" on all of the
...@@ -439,7 +443,7 @@ void au1xxx_timer_setup(struct irqaction *irq) ...@@ -439,7 +443,7 @@ void au1xxx_timer_setup(struct irqaction *irq)
au_sync(); au_sync();
while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20); while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20);
/* setup match20 to interrupt once every 10ms */ /* setup match20 to interrupt once every HZ */
last_pc0 = last_match20 = au_readl(SYS_TOYREAD); last_pc0 = last_match20 = au_readl(SYS_TOYREAD);
au_writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2); au_writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2);
au_sync(); au_sync();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment