⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 time.patch

📁 patches for linux-2.6.
💻 PATCH
📖 第 1 页 / 共 3 页
字号:
diff -Naur -x CVS linux26-cvs/arch/mips/au1000/common/irq.c _timer/arch/mips/au1000/common/irq.c--- linux26-cvs/arch/mips/au1000/common/irq.c	2005-05-16 13:39:23.091042560 -0500+++ _timer/arch/mips/au1000/common/irq.c	2005-05-13 22:18:07.000000000 -0500@@ -48,6 +48,7 @@ #include <asm/mipsregs.h> #include <asm/system.h> #include <asm/mach-au1x00/au1000.h>+ #ifdef CONFIG_MIPS_PB1000 #include <asm/mach-pb1x00/pb1000.h> #endif@@ -82,10 +83,6 @@  void	(*board_init_irq)(void); -#ifdef CONFIG_PM-extern void counter0_irq(int irq, void *dev_id, struct pt_regs *regs);-#endif- static DEFINE_SPINLOCK(irq_lock);  @@ -253,7 +250,7 @@   static struct hw_interrupt_type rise_edge_irq_type = {-	.typename = "Au1000 Rise Edge",+	.typename = "Au1 Rise Edge", 	.startup = startup_irq, 	.shutdown = shutdown_irq, 	.enable = local_enable_irq,@@ -263,7 +260,7 @@ };  static struct hw_interrupt_type fall_edge_irq_type = {-	.typename = "Au1000 Fall Edge",+	.typename = "Au1 Fall Edge", 	.startup = startup_irq, 	.shutdown = shutdown_irq, 	.enable = local_enable_irq,@@ -273,7 +270,7 @@ };  static struct hw_interrupt_type either_edge_irq_type = {-	.typename = "Au1000 Rise or Fall Edge",+	.typename = "Au1 Rise or Fall Edge", 	.startup = startup_irq, 	.shutdown = shutdown_irq, 	.enable = local_enable_irq,@@ -283,7 +280,7 @@ };  static struct hw_interrupt_type level_irq_type = {-	.typename = "Au1000 Level",+	.typename = "Au1 Level", 	.startup = startup_irq, 	.shutdown = shutdown_irq, 	.enable = local_enable_irq,@@ -292,12 +289,36 @@ 	.end = end_irq, }; -#ifdef CONFIG_PM-void startup_match20_interrupt(void)+#ifdef CONFIG_SOC_AU1X00_32KHZ_TIMER+void hook_rtcm1_interrupt(void) {-	local_enable_irq(AU1000_TOY_MATCH2_INT);+	extern irqreturn_t rtcm1_irq(int irq, void *dev_id, struct pt_regs *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 :(++       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 = rtcm1_irq;+	action.flags = SA_SHIRQ | SA_INTERRUPT;+	cpus_clear(action.mask);+	action.name = "Au1 RTCM1 timer";+	action.handler = rtcm1_irq;+	action.next = NULL;++	irq_desc[AU1000_RTC_MATCH1_INT].action = &action;+	irq_desc[AU1000_RTC_MATCH1_INT].status+		 &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);++	local_enable_irq(AU1000_RTC_MATCH1_INT); }-#endif+#endif /* CONFIG_SOC_AU1X00_32KHZ_TIMER */+  static void setup_local_irq(unsigned int irq_nr, int type, int int_req) {@@ -422,7 +443,9 @@ 	extern int au1xxx_ic0_nr_irqs;  	cp0_status = read_c0_status();+	/* This causes issues when using IRQ probing -- IDE for example 	memset(irq_desc, 0, sizeof(irq_desc));+	*/ 	set_except_vector(0, au1000_IRQ);  	/* Initialize interrupt controllers to a safe state.@@ -465,7 +488,7 @@ 		imp++; 	} -	set_c0_status(ALLINTS);+	set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5);  	/* Board specific IRQ initialization. 	*/@@ -517,17 +540,7 @@  	irq = au_ffs(intc0_req1) - 1; 	intc0_req1 &= ~(1<<irq);-#ifdef CONFIG_PM-	if (irq == AU1000_TOY_MATCH2_INT) {-		mask_and_ack_rise_edge_irq(irq);-		counter0_irq(irq, NULL, regs);-		local_enable_irq(irq);-	}-	else-#endif-	{-		do_IRQ(irq, regs);-	}+	do_IRQ(irq, regs); }  diff -Naur -x CVS linux26-cvs/arch/mips/au1000/common/power.c _timer/arch/mips/au1000/common/power.c--- linux26-cvs/arch/mips/au1000/common/power.c	2005-05-16 13:39:23.092042408 -0500+++ _timer/arch/mips/au1000/common/power.c	2005-05-13 22:19:33.000000000 -0500@@ -97,7 +97,7 @@ #define SLEEP_TEST_TIMEOUT 1 #ifdef SLEEP_TEST_TIMEOUT static	int	sleep_ticks;-void wakeup_counter0_set(int ticks);+void wakeup_toym2_set(int ticks); #endif  static void@@ -165,7 +165,7 @@ restore_core_regs(void) { 	extern void restore_au1xxx_intctl(void);-	extern void wakeup_counter0_adjust(void);+	extern void wakeup_kernel_timer(void);  	au_writel(sleep_aux_pll_cntrl, SYS_AUXPLL); au_sync(); 	au_writel(sleep_cpu_pll_cntrl, SYS_CPUPLL); au_sync();@@ -200,7 +200,7 @@ 	}  	restore_au1xxx_intctl();-	wakeup_counter0_adjust();+	wakeup_kernel_timer(); }  unsigned long suspend_mode;@@ -239,7 +239,7 @@ 	/* For testing, allow match20 to wake us up. 	*/ #ifdef SLEEP_TEST_TIMEOUT-	wakeup_counter0_set(sleep_ticks);+	wakeup_toym2_set(sleep_ticks); #endif 	wakeup = 1 << 8;	/* turn on match20 wakeup   */ 	wakeup = 0;diff -Naur -x CVS linux26-cvs/arch/mips/au1000/common/setup.c _timer/arch/mips/au1000/common/setup.c--- linux26-cvs/arch/mips/au1000/common/setup.c	2005-05-16 13:39:23.092042408 -0500+++ _timer/arch/mips/au1000/common/setup.c	2005-05-13 22:19:41.000000000 -0500@@ -148,12 +148,13 @@ 	iomem_resource.start = IOMEM_RESOURCE_START; 	iomem_resource.end = IOMEM_RESOURCE_END; +#if 0 /* was removed in the timer patch 2.4.30 */ 	while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_E0S); 	au_writel(SYS_CNTRL_E0 | SYS_CNTRL_EN0, SYS_COUNTER_CNTRL); 	au_sync(); 	while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T0S); 	au_writel(0, SYS_TOYTRIM);-+#endif 	return 0; } diff -Naur -x CVS linux26-cvs/arch/mips/au1000/common/time.c _timer/arch/mips/au1000/common/time.c--- linux26-cvs/arch/mips/au1000/common/time.c	2005-05-16 13:39:23.092042408 -0500+++ _timer/arch/mips/au1000/common/time.c	2005-05-13 22:18:01.000000000 -0500@@ -23,13 +23,16 @@  *  * ########################################################################  *- * Setting up the clock on the MIPS boards.+ * Setting up the clock on the Alchemy boards.  *  * Update.  Always configure the kernel with CONFIG_NEW_TIME_C.  This  * will use the user interface gettimeofday() functions from the  * arch/mips/kernel/time.c, and we provide the clock interrupt processing- * and the timer offset compute functions.  If CONFIG_PM is selected,- * we also ensure the 32KHz timer is available.   -- Dan+ * and the timer offset compute functions. -- Dan+ */++/*+ * See discussion on kernel timer in Docuemtation/mips/Alchemy.README  */  #include <linux/types.h>@@ -38,432 +41,572 @@ #include <linux/kernel_stat.h> #include <linux/sched.h> #include <linux/spinlock.h>+#include <linux/kernel.h>+#include <linux/fcntl.h>+#include <linux/miscdevice.h>+#include <linux/module.h> #include <linux/hardirq.h>+#include <linux/fs.h>  #include <asm/compiler.h> #include <asm/mipsregs.h> #include <asm/ptrace.h> #include <asm/time.h>-#include <asm/div64.h>+#include <asm/debug.h>+#include <asm/time.h>+#include <asm/uaccess.h>+ #include <asm/mach-au1x00/au1000.h> -#include <linux/mc146818rtc.h> #include <linux/timex.h> +/* I haven't found anyone that doesn't use a 12 MHz source clock,+ * but just in case.....+ */+#ifndef CONFIG_AU1000_SRC_CLK+#define CONFIG_AU1000_SRC_CLK 12000000+#endif+ extern void startup_match20_interrupt(void);-extern void do_softirq(void);-extern volatile unsigned long wall_jiffies;-unsigned long missed_heart_beats = 0;--static unsigned long r4k_offset; /* Amount to increment compare reg each time */-static unsigned long r4k_cur;    /* What counter should be at next timer irq */-int	no_au1xxx_32khz; void	(*au1k_wait_ptr)(void); -/* Cycle counter value at the previous timer interrupt.. */-static unsigned int timerhi = 0, timerlo = 0; -#ifdef CONFIG_PM-#define MATCH20_INC 328-extern void startup_match20_interrupt(void);-static unsigned long last_pc0, last_match20;+#ifndef CONFIG_AU1000_32KHZ_CLK+#define CONFIG_AU1000_32KHZ_CLK 32768 #endif -static DEFINE_SPINLOCK(time_lock);+/* I haven't found anyone that doesn't use a 12 MHz source clock,+ * but just in case.....+ */+#ifdef CONFIG_AU1000_SRC_CLK+#define AU1000_SRC_CLK	CONFIG_AU1000_SRC_CLK+#else+#define AU1000_SRC_CLK	12000000+#endif -static inline void ack_r4ktimer(unsigned long newval)-{-	write_c0_compare(newval);-} -/*- * There are a lot of conceptually broken versions of the MIPS timer interrupt- * handler floating around.  This one is rather different, but the algorithm- * is provably more robust.- */-unsigned long wtimer;-void mips_timer_interrupt(struct pt_regs *regs)-{-	int irq = 63;-	unsigned long count;+static DEFINE_SPINLOCK(time_lock);+static u32 r4k_offset; /* Amount to increment compare reg each time */+static u32 r4k_cur;    /* What counter should be at next timer irq */+/* Cycle counter value at the previous timer interrupt.. */+static unsigned int timerhi = 0, timerlo = 0; -	irq_enter();-	kstat_this_cpu.irqs[irq]++; -	if (r4k_offset == 0)-		goto null;+#ifdef CONFIG_SOC_AU1X00_32KHZ_TIMER+/* Use the integrated RTC timer as the system timer tick. RTC (counter1)+match1 is used as the tick source */++static volatile u32 rtcm1_offset; /* Amount to increment match reg each time */+static volatile u32 rtcm1_cur;    /* What counter should be at next timer irq */+static volatile u32 rtcm1_last;   /* What match/counter was at at the last timer irq */+static volatile u32 rtcm1_drift; -	do {-		count = read_c0_count();-		timerhi += (count < timerlo);   /* Wrap around */-		timerlo = count;+irqreturn_t rtcm1_irq(int irq, void *dev_id, struct pt_regs *regs)+{+	/* This handler mirrors mips_timer_interrupt() below, except that+	this handler is called by do_IRQ() */+	static int jiffie_drift = 0;+	int num_do_timer = 0;+	u32 rtc;++	/* disable all other IRQs. without this, this handler can be+	interrupted which allows the RTC to advance *WAY* ahead of the RTCM1+	value which causes the kernel to hang, waiting for rollover. */+	spin_lock_irq(&time_lock); -		kstat_this_cpu.irqs[irq]++;-		do_timer(regs); #ifndef CONFIG_SMP-		update_process_times(user_mode(regs));+	update_process_times(user_mode(regs)); #endif-		r4k_cur += r4k_offset;-		ack_r4ktimer(r4k_cur);+	/* check if RTC counter has rolled-over, but rtcm1_cur has not */+	rtc = au_readl(SYS_RTCREAD);+	while (rtc < rtcm1_cur) {+		++num_do_timer;+		rtcm1_last = rtcm1_cur;+		rtcm1_cur += rtcm1_offset;+	}+	while (rtcm1_cur <= rtc) {+		++num_do_timer;+		rtcm1_last = rtcm1_cur;+		rtcm1_cur += rtcm1_offset;+		/* check if rtcm1_cur has rolled over, and thus ahead of rtc */+		if (rtcm1_last > rtcm1_cur)+			break;+	}+	jiffie_drift += num_do_timer;+	if ((rtcm1_drift != 0) && (jiffie_drift >= rtcm1_drift)) {+		jiffie_drift -= rtcm1_drift;+		++num_do_timer;+	}++	/* Check to make sure that the counter is not at the value we're about+	to program into the match; if so, adjust accordingly. */+	rtc = au_readl(SYS_RTCREAD);++	/* Check to make sure that the value programmed into RTCM1 is no more+	than rtcm1_offset ticks away. This is complicated by the need to handle+	32-bit rollover of the counter, and the fact that the RTC may be ahead+	of RTCM1. This value represents the number of RTC ticks needed for this+	code to read the current RTC value, make any decisions, and write+	to RTCMATCH1. */+#define RTCM1_UPDATE_DELAY 8+	rtc += RTCM1_UPDATE_DELAY;++	if (rtcm1_cur > rtc) {+		if ((rtcm1_cur - rtc) < (2 * rtcm1_offset))+			/* rtcm1_cur is just ahead of rtc */+			au_writel(rtcm1_cur, SYS_RTCMATCH1); /* normal update */+		else+			/* rtc has rolled-over, ahead of rtcm1_cur */+			au_writel(rtc + 2, SYS_RTCMATCH1); /* special update */+	} else {+		/* rtc > rtcm1_cur */+		if ((rtc - rtcm1_cur) < (2 * rtcm1_offset))+			/* rtc is just ahead of rtcm1_cur */+			au_writel(rtc + 2, SYS_RTCMATCH1); /* special update */+		else+			/* rtcm1_cur has rolled-over, ahead of rtc */+			au_writel(rtcm1_cur, SYS_RTCMATCH1); /* normal update */+	} -	} while (((unsigned long)read_c0_count()-	         - r4k_cur) < 0x7fffffff);+	while (num_do_timer-- > 0)+		do_timer(regs); -	irq_exit();-	return;+	/* SYS_CNTRCTRL_RM1 shouldn't need to be examined since this register is+	written no faster than HZ rate, which is plenty long for the updates to+	occur. Nonetheless, in practice this is needed, but by doing it at the+	end, where the update likely should have already occured, we allow the+	update to RTCM1 to occur in parallel with the calls to do_timer().+	This also guarantees that the next rtcm1_irq() write to RTCMATCH1 can+	occur without polling. */+	while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRCTRL_RM1); -null:-	ack_r4ktimer(0);+	spin_unlock_irq(&time_lock);+	return IRQ_HANDLED; } -#ifdef CONFIG_PM-void counter0_irq(int irq, void *dev_id, struct pt_regs *regs)+static void setup_rtcm1_interrupt(void) {-	unsigned long pc0;-	int time_elapsed;-	static int jiffie_drift = 0;+	/* Setup match1 to interrupt HZ times per second.*/+	rtcm1_offset = CONFIG_AU1000_32KHZ_CLK / HZ;+	if ((rtcm1_offset * HZ) != CONFIG_AU1000_32KHZ_CLK)+		rtcm1_offset += 1; /* round up */+	/* Determine the number of ticks until we are one tick off the real rtc+	due to rounding of rtcm1_offset. */+	rtcm1_drift = CONFIG_AU1000_32KHZ_CLK / (rtcm1_offset * HZ - CONFIG_AU1000_32KHZ_CLK);+	rtcm1_cur = au_readl(SYS_RTCREAD) + rtcm1_offset;+	while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRCTRL_RM1);+	au_writel(rtcm1_cur, SYS_RTCMATCH1);+	while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRCTRL_RM1);+} -	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;-	}+static unsigned long do_fast_rtcm1_gettimeoffset(void)+{+	unsigned long rtc, offset;+	static u32 num_huge_offsets = 0; -	pc0 = au_readl(SYS_TOYREAD);-	if (pc0 < last_match20) {-		/* counter overflowed */-		time_elapsed = (0xffffffff - last_match20) + pc0;-	}-	else {-		time_elapsed = pc0 - last_match20;+	rtc = au_readl(SYS_RTCREAD);+	if (rtc < rtcm1_last) /* RTC has rolled-over */+		offset = (0 - rtcm1_last) + rtc;+	else+		offset = rtc - rtcm1_last;++	/* NOTE: The huge offsets are unavoidable since Linux's interrupt+	response time is highly irregular. */+	if (offset > 2*rtcm1_offset) {+		if (++num_huge_offsets > 100) {+			printk("huge offset %x, rtc %x, rtcm1_last %x rtcm1 %x rtcm1_cur %x\n",+			(int)offset, (int)rtc, rtcm1_last, au_readl(SYS_RTCMATCH1), rtcm1_cur);+			num_huge_offsets = 0;+		} 	} -	while (time_elapsed > 0) {-		do_timer(regs);-#ifndef CONFIG_SMP

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -