From: NIIBE Y. <gn...@m1...> - 2002-01-08 05:13:25
|
Here's the changes against linux-2.5.2-pre10, I'm about to send to Linus. -------------------------- All are SuperH specific. Follow up: asm/scatterlist, Use of yield(), Matin Mares' e-mail address. Improvement: Implement pgprot_noncached (Takashi Yoshii) include/asm-sh/pgtable.h SH Watchdog timer update (Paul Mundt) drivers/char/shwdt.c FPU handling change (Kazumoto Kojima, NIIBE Yutaka) arch/sh/kernel/entry.S arch/sh/kernel/fpu.c arch/sh/kernel/head.S arch/sh/kernel/processor.h Bug fix: Unaligned access & null current->mm (Jeremy Siegel) arch/sh/kernel/traps.c arch/sh/mm/fault.c HW-bug workaround of RTC (SUGIOKA Toshinobu) arch/sh/kernel/rtc.c diff -ruNp linux/arch/sh/kernel/entry.S linux-2.5.2-pre10.superh/arch/sh/kernel/entry.S --- linux/arch/sh/kernel/entry.S Tue Oct 9 02:39:18 2001 +++ linux-2.5.2-pre10.superh/arch/sh/kernel/entry.S Sat Dec 29 15:50:38 2001 @@ -66,7 +66,6 @@ need_resched = 20 tsk_ptrace = 24 PT_TRACESYS = 0x00000002 -PF_USEDFPU = 0x00100000 ENOSYS = 38 EINVAL = 22 @@ -567,12 +566,6 @@ __irq_stat: .align 2 restore_all: -#if defined(__SH4__) - mov.l __fpu_prepare_fd, r0 - jsr @r0 - stc sr, r4 -#endif - ! mov.l @r15+, r0 mov.l @r15+, r1 mov.l @r15+, r2 @@ -585,7 +578,7 @@ restore_all: stc sr, r8 mov.l __blrb_flags, r9 ! BL =1, RB=1 or r9, r8 - ldc r8, sr ! here, change the register bank + ldc r8, sr ! here, change the register bank ! mov.l @r15+, r8 mov.l @r15+, r9 @@ -594,25 +587,25 @@ restore_all: mov.l @r15+, r12 mov.l @r15+, r13 mov.l @r15+, r14 - mov.l @r15+, k4 ! original stack pointer + mov.l @r15+, k4 ! original stack pointer ldc.l @r15+, spc lds.l @r15+, pr - mov.l @r15+, k3 ! original SR + mov.l @r15+, k3 ! original SR ldc.l @r15+, gbr lds.l @r15+, mach lds.l @r15+, macl - add #4, r15 ! Skip syscall number + add #4, r15 ! Skip syscall number ! ! Calculate new SR value - mov k3, k2 ! original SR value + mov k3, k2 ! original SR value mov.l 1f, k1 stc sr, k0 - and k1, k0 ! Get current FD-bit + and k1, k0 ! Get current FD-bit mov.l 2f, k1 - and k1, k2 ! Mask orignal SR value - or k0, k2 ! Inherit current FD-bit + and k1, k2 ! Mask orignal SR value + or k0, k2 ! Inherit current FD-bit ! - mov k3, k0 ! Calculate IMASK-bits + mov k3, k0 ! Calculate IMASK-bits shlr2 k0 and #0x3c, k0 cmp/eq #0x3c, k0 @@ -620,69 +613,15 @@ restore_all: shll2 k0 mov g_imask, k0 ! -7: or k0, k2 ! Set the IMASK-bits +7: or k0, k2 ! Set the IMASK-bits ldc k2, ssr ! -#if defined(__SH4__) - shll k2 - shll k2 - bf 9f ! user mode - /* Kernel to kernel transition */ - mov.l 1f, k1 - tst k1, k3 - bf 9f ! it hadn't FPU - ! Kernel to kernel and FPU was used - ! There's the case we don't get FPU now - stc sr, k2 - tst k1, k2 - bt 8f - ! We need to grab FPU here - xor k1, k2 - ldc k2, sr ! Grab FPU - mov.l __init_task_flags, k1 - mov.l @k1, k2 - mov.l __PF_USEDFPU, k0 - or k0, k2 - mov.l k2, @k1 ! Set init_task.flags |= PF_USEDFPU - ! - ! Restoring FPU... - ! -8: mov.l 3f, k1 - lds k1, fpscr - fmov.s @r15+, fr0 - fmov.s @r15+, fr1 - fmov.s @r15+, fr2 - fmov.s @r15+, fr3 - fmov.s @r15+, fr4 - fmov.s @r15+, fr5 - fmov.s @r15+, fr6 - fmov.s @r15+, fr7 - fmov.s @r15+, fr8 - fmov.s @r15+, fr9 - fmov.s @r15+, fr10 - fmov.s @r15+, fr11 - fmov.s @r15+, fr12 - fmov.s @r15+, fr13 - fmov.s @r15+, fr14 - fmov.s @r15+, fr15 - lds.l @r15+, fpscr - lds.l @r15+, fpul -9: -#endif mov k4, r15 rte nop .align 2 __blrb_flags: .long 0x30000000 -#if defined(__SH4__) -__fpu_prepare_fd: - .long SYMBOL_NAME(fpu_prepare_fd) -__init_task_flags: - .long SYMBOL_NAME(init_task_union)+4 -__PF_USEDFPU: - .long PF_USEDFPU -#endif 1: .long 0x00008000 ! FD 2: .long 0xffff7f0f ! ~(IMASK+FD) 3: .long 0x00080000 ! SZ=0, PR=1 @@ -732,61 +671,21 @@ handle_exception: ! Using k0, k1 for scratch registers (r0_bank1, r1_bank), ! save all registers onto stack. ! - stc ssr, k0 ! from kernel space? - shll k0 ! Check MD bit (bit30) by shifting it into the T bit - shll k0 -#if defined(__SH4__) - bf/s 8f ! it's from user to kernel transition - mov r15, k0 ! save original stack to k0 - /* It's a kernel to kernel transition. */ - /* Is the FPU disabled? */ - mov.l 2f, k1 - stc ssr, k0 - tst k1, k0 - mov.l 4f, k1 - bf/s 9f ! FPU is not enabled, no need to save it - mov r15, k0 ! save original stack to k0 - ! FPU is enabled, save it - ! /* XXX: Need to save another bank of FPU if all FPU feature is used */ - ! /* Currently it's not the case for GCC (only udivsi3_i4, divsi3_i4) */ - sts.l fpul, @-r15 - sts.l fpscr, @-r15 - mov.l 6f, k1 - lds k1, fpscr - mov.l 3f, k1 - fmov.s fr15, @-r15 - fmov.s fr14, @-r15 - fmov.s fr13, @-r15 - fmov.s fr12, @-r15 - fmov.s fr11, @-r15 - fmov.s fr10, @-r15 - fmov.s fr9, @-r15 - fmov.s fr8, @-r15 - fmov.s fr7, @-r15 - fmov.s fr6, @-r15 - fmov.s fr5, @-r15 - fmov.s fr4, @-r15 - fmov.s fr3, @-r15 - fmov.s fr2, @-r15 - fmov.s fr1, @-r15 - bra 9f - fmov.s fr0, @-r15 -#else - mov.l 3f, k1 - bt/s 9f ! it's a kernel to kernel transition, and skip the FPU save. - mov r15, k0 ! save original stack to k0 anyway -#endif -8: /* User space to kernel */ + stc ssr, k0 ! Is it from kernel space? + shll k0 ! Check MD bit (bit30) by shifting it into... + shll k0 ! ...the T bit + bt/s 9f ! It's a kernel to kernel transition. + mov r15, k0 ! save original stack to k0 + /* User space to kernel */ mov #0x20, k1 - shll8 k1 ! k1 <= 8192 == THREAD_SIZE + shll8 k1 ! k1 <= 8192 == THREAD_SIZE add current, k1 mov k1, r15 ! change to kernel stack ! - mov.l 4f, k1 ! let kernel release FPU -9: ! Save the user registers on the stack. - ! At this point, k1 should have been set to the new SR value - mov #-1, k4 - mov.l k4, @-r15 ! syscall_nr (default: -1) +9: mov #-1, k4 + mov.l 3f, k1 + ! Save the user registers on the stack. + mov.l k4, @-r15 ! syscall_nr (default: -1) ! sts.l macl, @-r15 sts.l mach, @-r15 @@ -806,11 +705,11 @@ handle_exception: mov.l r9, @-r15 mov.l r8, @-r15 ! - stc sr, r8 ! Back to normal register bank, and - or k1, r8 ! Block all interrupts, may release FPU + stc sr, r8 ! Back to normal register bank, and + or k1, r8 ! Block all interrupts mov.l 5f, k1 - and k1, r8 ! ... - ldc r8, sr ! ...changed here. + and k1, r8 ! ... + ldc r8, sr ! ...changed here. ! mov.l r7, @-r15 mov.l r6, @-r15 @@ -831,9 +730,7 @@ handle_exception: nop .align 2 1: .long SYMBOL_NAME(exception_handling_table) -2: .long 0x00008000 ! FD=1 3: .long 0x000000f0 ! FD=0, IMASK=15 -4: .long 0x000080f0 ! FD=1, IMASK=15 5: .long 0xcfffffff ! RB=0, BL=0 6: .long 0x00080000 ! SZ=0, PR=1 diff -ruNp linux/arch/sh/kernel/fpu.c linux-2.5.2-pre10.superh/arch/sh/kernel/fpu.c --- linux/arch/sh/kernel/fpu.c Mon Jan 29 11:56:00 2001 +++ linux-2.5.2-pre10.superh/arch/sh/kernel/fpu.c Sat Dec 29 15:50:38 2001 @@ -18,6 +18,10 @@ #include <asm/processor.h> #include <asm/io.h> +/* + * Save FPU registers onto task structure. + * Assume called with FPU enabled (SR.FD=0). + */ void save_fpu(struct task_struct *tsk) { @@ -118,7 +122,8 @@ restore_fpu(struct task_struct *tsk) * double precission represents signaling NANS. */ -void fpu_init(void) +static void +fpu_init(void) { asm volatile("lds %0, fpul\n\t" "lds %1, fpscr\n\t" @@ -160,15 +165,125 @@ void fpu_init(void) : "r" (0), "r" (FPSCR_INIT)); } +/** + * denormal_to_double - Given denormalized float number, + * store double float + * + * @fpu: Pointer to sh_fpu_hard structure + * @n: Index to FP register + */ +static void +denormal_to_double (struct sh_fpu_hard_struct *fpu, int n) +{ + unsigned long du, dl; + unsigned long x = fpu->fpul; + int exp = 1023 - 126; + + if (x != 0 && (x & 0x7f800000) == 0) { + du = (x & 0x80000000); + while ((x & 0x00800000) == 0) { + x <<= 1; + exp--; + } + x &= 0x007fffff; + du |= (exp << 20) | (x >> 3); + dl = x << 29; + + fpu->fp_regs[n] = du; + fpu->fp_regs[n+1] = dl; + } +} + +/** + * ieee_fpe_handler - Handle denormalized number exception + * + * @regs: Pointer to register structure + * + * Returns 1 when it's handled (should not cause exception). + */ +static int +ieee_fpe_handler (struct pt_regs *regs) +{ + unsigned short insn = *(unsigned short *) regs->pc; + unsigned short finsn; + unsigned long nextpc; + int nib[4] = { + (insn >> 12) & 0xf, + (insn >> 8) & 0xf, + (insn >> 4) & 0xf, + insn & 0xf}; + + if (nib[0] == 0xb || + (nib[0] == 0x4 && nib[2] == 0x0 && nib[3] == 0xb)) /* bsr & jsr */ + regs->pr = regs->pc + 4; + + if (nib[0] == 0xa || nib[0] == 0xb) { /* bra & bsr */ + nextpc = regs->pc + 4 + ((short) ((insn & 0xfff) << 4) >> 3); + finsn = *(unsigned short *) (regs->pc + 2); + } else if (nib[0] == 0x8 && nib[1] == 0xd) { /* bt/s */ + if (regs->sr & 1) + nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1); + else + nextpc = regs->pc + 4; + finsn = *(unsigned short *) (regs->pc + 2); + } else if (nib[0] == 0x8 && nib[1] == 0xf) { /* bf/s */ + if (regs->sr & 1) + nextpc = regs->pc + 4; + else + nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1); + finsn = *(unsigned short *) (regs->pc + 2); + } else if (nib[0] == 0x4 && nib[3] == 0xb && + (nib[2] == 0x0 || nib[2] == 0x2)) { /* jmp & jsr */ + nextpc = regs->regs[nib[1]]; + finsn = *(unsigned short *) (regs->pc + 2); + } else if (nib[0] == 0x0 && nib[3] == 0x3 && + (nib[2] == 0x0 || nib[2] == 0x2)) { /* braf & bsrf */ + nextpc = regs->pc + 4 + regs->regs[nib[1]]; + finsn = *(unsigned short *) (regs->pc + 2); + } else if (insn == 0x000b) { /* rts */ + nextpc = regs->pr; + finsn = *(unsigned short *) (regs->pc + 2); + } else { + nextpc = regs->pc + 2; + finsn = insn; + } + + if ((finsn & 0xf1ff) == 0xf0ad) { /* fcnvsd */ + struct task_struct *tsk = current; + + save_fpu(tsk); + if ((tsk->thread.fpu.hard.fpscr & (1 << 17))) { + /* FPU error */ + denormal_to_double (&tsk->thread.fpu.hard, + (finsn >> 8) & 0xf); + tsk->thread.fpu.hard.fpscr &= + ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK); + grab_fpu(); + restore_fpu(tsk); + tsk->flags |= PF_USEDFPU; + } else { + tsk->thread.trap_no = 11; + tsk->thread.error_code = 0; + force_sig(SIGFPE, tsk); + } + + regs->pc = nextpc; + return 1; + } + + return 0; +} + asmlinkage void do_fpu_error(unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, struct pt_regs regs) { struct task_struct *tsk = current; - regs.pc += 2; + if (ieee_fpe_handler (®s)) + return; - grab_fpu(); + regs.pc += 2; save_fpu(tsk); tsk->thread.trap_no = 11; tsk->thread.error_code = 0; @@ -181,102 +296,12 @@ do_fpu_state_restore(unsigned long r4, u { struct task_struct *tsk = current; - if (!user_mode(®s)) { - if (tsk != &init_task) { - unlazy_fpu(tsk); - } - tsk = &init_task; - if (tsk->flags & PF_USEDFPU) { - /* - * This weird situation can be occurred. - * - * There's race condition in __cli: - * - * (1) SR --> register - * (2) Set IMASK of register - * (3) SR <-- register - * - * Between (1) and (2), or (2) and (3) getting - * interrupt, and interrupt handler (or - * softirq) may use FPU. - * - * Then, SR.FD is overwritten by (3). - * - * This results init_task.PF_USEDFPU is on, - * with SR.FD == 1. - * - */ - release_fpu(); - return; - } - } - grab_fpu(); - if (tsk->used_math) { - /* Using the FPU again. */ - restore_fpu(tsk); - } else { - /* First time FPU user. */ - fpu_init(); - tsk->used_math = 1; - } - tsk->flags |= PF_USEDFPU; - release_fpu(); -} - -/* - * Change current FD flag to set FD flag back to exception - */ -asmlinkage void -fpu_prepare_fd(unsigned long sr, unsigned long r5, unsigned long r6, - unsigned long r7, struct pt_regs regs) -{ - __cli(); if (!user_mode(®s)) { - if (init_task.flags & PF_USEDFPU) - grab_fpu(); - else { - if (!(sr & SR_FD)) { - BUG(); - release_fpu(); - } - } + printk(KERN_ERR "BUG: FPU is used in kernel mode.\n"); return; } - if (sr & SR_FD) { /* Kernel doesn't grab FPU */ - if (current->flags & PF_USEDFPU) - grab_fpu(); - else { - if (init_task.flags & PF_USEDFPU) { - /* - * This weird situation can be occurred. - * See the comment in do_fpu_state_restore. - */ - grab_fpu(); - save_fpu(&init_task); - } - } - } else { - if (init_task.flags & PF_USEDFPU) - save_fpu(&init_task); - else { - BUG(); - release_fpu(); - } - } -} - -/* Short cut for the FPU exception */ -asmlinkage void -enable_fpu_in_danger(void) -{ - struct task_struct *tsk = current; - - if (tsk != &init_task) - unlazy_fpu(tsk); - - tsk = &init_task; if (tsk->used_math) { /* Using the FPU again. */ restore_fpu(tsk); diff -ruNp linux/arch/sh/kernel/head.S linux-2.5.2-pre10.superh/arch/sh/kernel/head.S --- linux/arch/sh/kernel/head.S Mon Jan 29 11:56:00 2001 +++ linux-2.5.2-pre10.superh/arch/sh/kernel/head.S Sat Dec 29 15:50:38 2001 @@ -50,12 +50,6 @@ ENTRY(_stext) sub r1, r0 ! ldc r0, r7_bank ! ... and init_task ! -#if defined(__SH4__) - ! Initialize fpu - mov.l 7f, r0 - jsr @r0 - nop -#endif ! Enable cache mov.l 6f, r0 jsr @r0 @@ -74,12 +68,9 @@ ENTRY(_stext) nop .balign 4 -1: .long 0x400000F0 ! MD=1, RB=0, BL=0, FD=0, IMASK=0xF +1: .long 0x400080F0 ! MD=1, RB=0, BL=0, FD=1, IMASK=0xF 2: .long SYMBOL_NAME(stack) 3: .long SYMBOL_NAME(__bss_start) 4: .long SYMBOL_NAME(_end) 5: .long SYMBOL_NAME(start_kernel) 6: .long SYMBOL_NAME(cache_init) -#if defined(__SH4__) -7: .long SYMBOL_NAME(fpu_init) -#endif diff -ruNp linux/arch/sh/kernel/pci-sh7751.c linux-2.5.2-pre10.superh/arch/sh/kernel/pci-sh7751.c --- linux/arch/sh/kernel/pci-sh7751.c Mon Nov 5 02:31:58 2001 +++ linux-2.5.2-pre10.superh/arch/sh/kernel/pci-sh7751.c Tue Oct 16 05:44:49 2001 @@ -3,7 +3,7 @@ * * Dustin McIntire (du...@se...) * Derived from arch/i386/kernel/pci-*.c which bore the message: - * (c) 1999--2000 Martin Mares <mj...@uc...> + * (c) 1999--2000 Martin Mares <mj...@su...> * * May be copied or modified under the terms of the GNU General Public * License. See linux/COPYING for more information. diff -ruNp linux/arch/sh/kernel/rtc.c linux-2.5.2-pre10.superh/arch/sh/kernel/rtc.c --- linux/arch/sh/kernel/rtc.c Thu Jun 28 05:55:29 2001 +++ linux-2.5.2-pre10.superh/arch/sh/kernel/rtc.c Wed Dec 12 19:14:20 2001 @@ -46,7 +46,7 @@ void sh_rtc_gettimeofday(struct timeval } while ((ctrl_inb(RCR1) & RCR1_CF) != 0); #if RTC_BIT_INVERTED != 0 - /* Work around to avoid reading correct value. */ + /* Work around to avoid reading incorrect value. */ if (sec128 == RTC_BIT_INVERTED) { schedule_timeout(1); goto again; @@ -81,12 +81,18 @@ void sh_rtc_gettimeofday(struct timeval goto again; } +#if RTC_BIT_INVERTED != 0 + if ((sec128 & RTC_BIT_INVERTED)) + sec--; +#endif + tv->tv_sec = mktime(yr100 * 100 + yr, mon, day, hr, min, sec); - tv->tv_usec = ((sec128 ^ RTC_BIT_INVERTED) * 1000000) / 128; + tv->tv_usec = (sec128 * 1000000) / 128; } -static int set_rtc_time(unsigned long nowtime) +int sh_rtc_settimeofday(const struct timeval *tv) { + unsigned long nowtime = tv->tv_sec; int retval = 0; int real_seconds, real_minutes, cmos_minutes; @@ -122,13 +128,4 @@ static int set_rtc_time(unsigned long no ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2); /* Start RTC */ return retval; -} - -int sh_rtc_settimeofday(const struct timeval *tv) -{ -#if RTC_BIT_INVERTED != 0 - /* This is not accurate, but better than nothing. */ - schedule_timeout(HZ/2); -#endif - return set_rtc_time(tv->tv_sec); } diff -ruNp linux/arch/sh/kernel/traps.c linux-2.5.2-pre10.superh/arch/sh/kernel/traps.c --- linux/arch/sh/kernel/traps.c Tue Jan 8 11:22:54 2002 +++ linux-2.5.2-pre10.superh/arch/sh/kernel/traps.c Fri Dec 28 11:46:10 2001 @@ -300,10 +300,19 @@ static inline int handle_unaligned_delay /* * handle an instruction that does an unaligned memory access * - have to be careful of branch delay-slot instructions that fault + * SH3: * - if the branch would be taken PC points to the branch * - if the branch would not be taken, PC points to delay-slot + * SH4: + * - PC always points to delayed branch * - return 0 if handled, -EFAULT if failed (may not return if in kernel) */ + +/* Macros to determine offset from current PC for branch instructions */ +/* Explicit type coercion is used to force sign extension where needed */ +#define SH_PC_8BIT_OFFSET(instr) ((((signed char)(instr))*2) + 4) +#define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4) + static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) { u_int rm; @@ -392,15 +401,27 @@ static int handle_unaligned_access(u16 i break; case 0x0F00: /* bf/s lab */ ret = handle_unaligned_delayslot(regs); - if (ret==0) - regs->pc += (instruction&0x00FF)*2 + 4; + if (ret==0) { +#if defined(__SH4__) + if ((regs->sr & 0x00000001) != 0) + regs->pc += 4; /* next after slot */ + else +#endif + regs->pc += SH_PC_8BIT_OFFSET(instruction); + } break; case 0x0900: /* bt lab - no delayslot */ break; case 0x0D00: /* bt/s lab */ ret = handle_unaligned_delayslot(regs); - if (ret==0) - regs->pc += (instruction&0x00FF)*2 + 4; + if (ret==0) { +#if defined(__SH4__) + if ((regs->sr & 0x00000001) == 0) + regs->pc += 4; /* next after slot */ + else +#endif + regs->pc += SH_PC_8BIT_OFFSET(instruction); + } break; } break; @@ -408,14 +429,14 @@ static int handle_unaligned_access(u16 i case 0xA000: /* bra label */ ret = handle_unaligned_delayslot(regs); if (ret==0) - regs->pc += (instruction&0x0FFF)*2 + 4; + regs->pc += SH_PC_12BIT_OFFSET(instruction); break; case 0xB000: /* bsr label */ ret = handle_unaligned_delayslot(regs); if (ret==0) { regs->pr = regs->pc + 4; - regs->pc += (instruction&0x0FFF)*2 + 4; + regs->pc += SH_PC_12BIT_OFFSET(instruction); } break; } diff -ruNp linux/arch/sh/mm/fault.c linux-2.5.2-pre10.superh/arch/sh/mm/fault.c --- linux/arch/sh/mm/fault.c Tue Oct 16 05:36:48 2001 +++ linux-2.5.2-pre10.superh/arch/sh/mm/fault.c Fri Dec 28 11:46:10 2001 @@ -207,8 +207,7 @@ no_context: out_of_memory: up_read(&mm->mmap_sem); if (current->pid == 1) { - current->policy |= SCHED_YIELD; - schedule(); + yield(); down_read(&mm->mmap_sem); goto survive; } @@ -248,6 +247,8 @@ asmlinkage int __do_page_fault(struct pt if (address >= P3SEG && address < P4SEG) dir = pgd_offset_k(address); else if (address >= TASK_SIZE) + return 1; + else if (!current->mm) return 1; else dir = pgd_offset(current->mm, address); diff -ruNp linux/drivers/char/shwdt.c linux-2.5.2-pre10.superh/drivers/char/shwdt.c --- linux/drivers/char/shwdt.c Tue Jan 8 12:24:45 2002 +++ linux-2.5.2-pre10.superh/drivers/char/shwdt.c Tue Jan 8 13:13:00 2002 @@ -19,7 +19,6 @@ #include <linux/watchdog.h> #include <linux/reboot.h> #include <linux/notifier.h> -#include <linux/smp_lock.h> #include <linux/ioport.h> #include <asm/io.h> @@ -47,18 +46,47 @@ #define WTCSR_CKS1 0x02 #define WTCSR_CKS0 0x01 -#define WTCSR_CKS 0x07 -#define WTCSR_CKS_1 0x00 -#define WTCSR_CKS_4 0x01 -#define WTCSR_CKS_16 0x02 -#define WTCSR_CKS_32 0x03 -#define WTCSR_CKS_64 0x04 -#define WTCSR_CKS_256 0x05 -#define WTCSR_CKS_1024 0x06 +/* + * CKS0-2 supports a number of clock division ratios. At the time the watchdog + * is enabled, it defaults to a 41 usec overflow period .. we overload this to + * something a little more reasonable, and really can't deal with anything + * lower than WTCSR_CKS_1024, else we drop back into the usec range. + * + * Clock Division Ratio Overflow Period + * -------------------------------------------- + * 1/32 (initial value) 41 usecs + * 1/64 82 usecs + * 1/128 164 usecs + * 1/256 328 usecs + * 1/512 656 usecs + * 1/1024 1.31 msecs + * 1/2048 2.62 msecs + * 1/4096 5.25 msecs + */ +#define WTCSR_CKS_32 0x00 +#define WTCSR_CKS_64 0x01 +#define WTCSR_CKS_128 0x02 +#define WTCSR_CKS_256 0x03 +#define WTCSR_CKS_512 0x04 +#define WTCSR_CKS_1024 0x05 +#define WTCSR_CKS_2048 0x06 #define WTCSR_CKS_4096 0x07 -static int sh_is_open = 0; +/* + * Default clock division ratio is 5.25 msecs. Overload this at module load + * time. Any value not in the msec range will default to a timeout of one + * jiffy, which exceeds the usec overflow periods. + */ +static int clock_division_ratio = WTCSR_CKS_4096; + +#define msecs_to_jiffies(msecs) (jiffies + ((HZ * msecs + 999) / 1000)) +#define next_ping_period(cks) msecs_to_jiffies(cks - 4) +#define user_ping_period(cks) (next_ping_period(cks) * 10) + +static unsigned long sh_is_open = 0; static struct watchdog_info sh_wdt_info; +static struct timer_list timer; +static unsigned long next_heartbeat; /** * sh_wdt_write_cnt - Write to Counter @@ -93,6 +121,10 @@ static void sh_wdt_write_csr(__u8 val) */ static void sh_wdt_start(void) { + timer.expires = next_ping_period(clock_division_ratio); + next_heartbeat = user_ping_period(clock_division_ratio); + add_timer(&timer); + sh_wdt_write_csr(WTCSR_WT | WTCSR_CKS_4096); sh_wdt_write_cnt(0); sh_wdt_write_csr((ctrl_inb(WTCSR) | WTCSR_TME)); @@ -105,6 +137,8 @@ static void sh_wdt_start(void) */ static void sh_wdt_stop(void) { + del_timer(&timer); + sh_wdt_write_csr((ctrl_inb(WTCSR) & ~WTCSR_TME)); } @@ -117,8 +151,13 @@ static void sh_wdt_stop(void) */ static void sh_wdt_ping(unsigned long data) { - sh_wdt_write_csr((ctrl_inb(WTCSR) & ~WTCSR_IOVF)); - sh_wdt_write_cnt(0); + if (time_before(jiffies, next_heartbeat)) { + sh_wdt_write_csr((ctrl_inb(WTCSR) & ~WTCSR_IOVF)); + sh_wdt_write_cnt(0); + + timer.expires = next_ping_period(clock_division_ratio); + add_timer(&timer); + } } /** @@ -133,14 +172,12 @@ static int sh_wdt_open(struct inode *ino { switch (minor(inode->i_rdev)) { case WATCHDOG_MINOR: - if (sh_is_open) { + if (test_and_set_bit(0, &sh_is_open)) return -EBUSY; - } - sh_is_open = 1; sh_wdt_start(); - return 0; + break; default: return -ENODEV; } @@ -158,17 +195,13 @@ static int sh_wdt_open(struct inode *ino */ static int sh_wdt_close(struct inode *inode, struct file *file) { - lock_kernel(); - if (minor(inode->i_rdev) == WATCHDOG_MINOR) { #ifndef CONFIG_WATCHDOG_NOWAYOUT sh_wdt_stop(); #endif - sh_is_open = 0; + clear_bit(0, &sh_is_open); } - unlock_kernel(); - return 0; } @@ -206,7 +239,7 @@ static ssize_t sh_wdt_write(struct file return -ESPIPE; if (count) { - sh_wdt_ping(0); + next_heartbeat = user_ping_period(clock_division_ratio); return 1; } @@ -245,7 +278,7 @@ static int sh_wdt_ioctl(struct inode *in break; case WDIOC_KEEPALIVE: - sh_wdt_ping(0); + next_heartbeat = user_ping_period(clock_division_ratio); break; default: @@ -336,6 +369,10 @@ static int __init sh_wdt_init(void) return -EINVAL; } + init_timer(&timer); + timer.function = sh_wdt_ping; + timer.data = 0; + return 0; } @@ -358,6 +395,8 @@ EXPORT_NO_SYMBOLS; MODULE_AUTHOR("Paul Mundt <le...@ch...>"); MODULE_DESCRIPTION("SH 3/4 watchdog driver"); MODULE_LICENSE("GPL"); +MODULE_PARM(clock_division_ratio, "i"); +MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). Defaults to 0x7."); module_init(sh_wdt_init); module_exit(sh_wdt_exit); diff -ruNp linux/include/asm-sh/pgtable.h linux-2.5.2-pre10.superh/include/asm-sh/pgtable.h --- linux/include/asm-sh/pgtable.h Mon Nov 12 03:20:21 2001 +++ linux-2.5.2-pre10.superh/include/asm-sh/pgtable.h Thu Dec 20 10:38:10 2001 @@ -237,6 +237,19 @@ static inline pte_t pte_mkyoung(pte_t pt static inline pte_t pte_mkwrite(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_RW)); return pte; } /* + * Macro and implementation to make a page protection as uncachable. + */ +#define pgprot_noncached pgprot_noncached + +static inline pgprot_t pgprot_noncached(pgprot_t _prot) +{ + unsigned long prot = pgprot_val(_prot); + + prot &= ~_PAGE_CACHABLE; + return __pgprot(prot); +} + +/* * Conversion functions: convert a page and protection to a page entry, * and a page entry and page directory to the page they refer to. * diff -ruNp linux/include/asm-sh/processor.h linux-2.5.2-pre10.superh/include/asm-sh/processor.h --- linux/include/asm-sh/processor.h Sat Oct 6 04:11:05 2001 +++ linux-2.5.2-pre10.superh/include/asm-sh/processor.h Fri Dec 28 11:37:29 2001 @@ -184,18 +184,22 @@ extern void save_fpu(struct task_struct #define unlazy_fpu(tsk) do { \ if ((tsk)->flags & PF_USEDFPU) { \ - grab_fpu(); \ save_fpu(tsk); \ } \ } while (0) #define clear_fpu(tsk) do { \ - if ((tsk)->flags & PF_USEDFPU) \ + if ((tsk)->flags & PF_USEDFPU) { \ (tsk)->flags &= ~PF_USEDFPU; \ + release_fpu(); \ + } \ } while (0) /* Double presision, NANS as NANS, rounding to nearest, no exceptions */ #define FPSCR_INIT 0x00080000 + +#define FPSCR_CAUSE_MASK 0x0001f000 /* Cause bits */ +#define FPSCR_FLAG_MASK 0x0000007c /* Flag bits */ /* * Return saved PC of a blocked thread. diff -ruNp linux/include/asm-sh/scatterlist.h linux-2.5.2-pre10.superh/include/asm-sh/scatterlist.h --- linux/include/asm-sh/scatterlist.h Sat Oct 13 07:35:54 2001 +++ linux-2.5.2-pre10.superh/include/asm-sh/scatterlist.h Sat Jan 5 16:29:31 2002 @@ -2,7 +2,11 @@ #define __ASM_SH_SCATTERLIST_H struct scatterlist { - char * address; /* Location data is to be transferred to */ + char * address; /* Location data is to be transferred to, NULL for + * highmem page */ + struct page * page; /* Location for highmem page, if any */ + unsigned int offset;/* for highmem, page offset */ + dma_addr_t dma_address; unsigned int length; }; -- |