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

Au1x PM fixes.

parent 7ab1261f
Loading
Loading
Loading
Loading
+17 −15
Original line number Diff line number Diff line
@@ -83,7 +83,7 @@ inline void local_disable_irq(unsigned int irq_nr);
void	(*board_init_irq)(void);

#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

static DEFINE_SPINLOCK(irq_lock);
@@ -293,29 +293,31 @@ static struct hw_interrupt_type level_irq_type = {
};

#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;
	/* 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 :(
	struct irq_desc *desc = &irq_desc[AU1000_TOY_MATCH2_INT];

       Give it a bogus "action" pointer -- this will keep it from
	   getting auto-probed!
	static struct irqaction action;
	memset(&action, 0, sizeof(struct irqaction));

       By setting the status to match that of request_irq() we
       can avoid it.  --cgray
	/* 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
	 * getting auto-probed!
	 *
	 * By setting the status to match that of request_irq() we
	 * can avoid it.  --cgray
	*/
	action.dev_id = handler;
	action.flags = 0;
	action.mask = 0;
	action.flags = SA_INTERRUPT;
	cpus_clear(action.mask);
	action.name = "Au1xxx TOY";
	action.handler = handler;
	action.next = NULL;

	irq_desc[AU1000_TOY_MATCH2_INT].action = &action; 
	irq_desc[AU1000_TOY_MATCH2_INT].status 
		 &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);
	desc->action = &action;
	desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);

	local_enable_irq(AU1000_TOY_MATCH2_INT);
}
+9 −7
Original line number Diff line number Diff line
@@ -34,11 +34,13 @@
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/sysctl.h>
#include <linux/jiffies.h>

#include <asm/string.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/cacheflush.h>
#include <asm/mach-au1x00/au1000.h>

#ifdef CONFIG_PM
@@ -50,7 +52,7 @@
#  define DPRINTK(fmt, args...)
#endif

static void calibrate_delay(void);
static void au1000_calibrate_delay(void);

extern void set_au1x00_speed(unsigned int new_freq);
extern unsigned int get_au1x00_speed(void);
@@ -260,7 +262,7 @@ int au_sleep(void)
}

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;
#ifdef SLEEP_TEST_TIMEOUT
@@ -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,
			 void *buffer, size_t * len)
			 void __user *buffer, size_t * len, loff_t *ppos)
{
	int retval = 0;

@@ -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,
		      void *buffer, size_t * len)
		      void __user *buffer, size_t * len, loff_t *ppos)
{
	int retval = 0, i;
	unsigned long val, pll;
@@ -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
	 * match20. Otherwise our calibrate_delay()
	 * match20. Otherwise our au1000_calibrate_delay()
	 * calculation will be off, potentially a lot.
	 */
	intc0_mask = save_local_and_disable(0);
	intc1_mask = save_local_and_disable(1);
	local_enable_irq(AU1000_TOY_MATCH2_INT);
	spin_unlock_irqrestore(&pm_lock, flags);
	calibrate_delay();
	au1000_calibrate_delay();
	restore_local_and_enable(0, intc0_mask);
	restore_local_and_enable(1, intc1_mask);
	return retval;
@@ -455,7 +457,7 @@ __initcall(pm_init);
   better than 1% */
#define LPS_PREC 8

static void calibrate_delay(void)
static void au1000_calibrate_delay(void)
{
	unsigned long ticks, loopbit;
	int lps_precision = LPS_PREC;
+11 −7
Original line number Diff line number Diff line
@@ -63,8 +63,11 @@ extern int allow_au1k_wait; /* default off for CP0 Counter */
static unsigned int timerhi = 0, timerlo = 0;

#ifdef CONFIG_PM
#define MATCH20_INC 328
extern void startup_match20_interrupt(void (*handler)(int, void *, struct pt_regs *));
#if HZ < 100 || HZ > 1000
#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;
#endif

@@ -116,17 +119,16 @@ void mips_timer_interrupt(struct pt_regs *regs)
}

#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;
	int time_elapsed;
	static int jiffie_drift = 0;

	kstat.irqs[0][irq]++;
	if (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20) {
		/* should never happen! */
		printk(KERN_WARNING "counter 0 w status eror\n");
		return;
		printk(KERN_WARNING "counter 0 w status error\n");
		return IRQ_NONE;
	}

	pc0 = au_readl(SYS_TOYREAD);
@@ -163,6 +165,8 @@ void counter0_irq(int irq, void *dev_id, struct pt_regs *regs)
		update_process_times(user_mode(regs));
#endif
	}

	return IRQ_HANDLED;
}

/* 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)
		au_sync();
		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);
		au_writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2);
		au_sync();