From 33aa1817c101dafc56564bed526ca5ab42ebc33b Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:39:14 -0500 Subject: [PATCH] Linux 2.4.0-test9pre9 - USB: documentation. - Yeah. MD/LVM should really be fixed this time. - SH architecture update - i810 RNG driver update - IDE-PCI: make sure we initialize the chipsets correctly - VIA IDE driver fixes - VM balancing, part 53761 of 798321 - SCHED_YIELD cleanups --- Documentation/usb/CREDITS | 1 + Documentation/usb/URB.txt | 34 ++++- Documentation/usb/error-codes.txt | 5 + Makefile | 2 +- arch/i386/defconfig | 8 +- arch/i386/kernel/entry.S | 1 + arch/i386/kernel/traps.c | 4 +- arch/sh/boot/compressed/Makefile | 2 +- arch/sh/kernel/entry.S | 236 ++++++++++++++++++------------ arch/sh/kernel/head.S | 2 +- arch/sh/kernel/io.c | 2 +- arch/sh/kernel/irq_imask.c | 7 +- arch/sh/kernel/irq_ipr.c | 2 + arch/sh/kernel/process.c | 19 +-- arch/sh/kernel/setup_cqreek.c | 64 +++++--- arch/sh/kernel/sh_bios.c | 12 +- arch/sh/kernel/sh_ksyms.c | 29 ++++ arch/sh/kernel/time.c | 3 +- arch/sh/kernel/traps.c | 13 +- arch/sh/lib/checksum.S | 10 +- arch/sh/mm/cache.c | 124 ++++++++++++++-- arch/sh/mm/fault.c | 179 ++++++++++++---------- arch/sh/mm/init.c | 1 + arch/sh/vmlinux.lds.S | 5 +- drivers/acorn/net/etherh.c | 2 +- drivers/block/xd.c | 10 +- drivers/char/i810_rng.c | 208 ++++++++++++++------------ drivers/char/sh-sci.c | 140 ++++++++++++++++-- drivers/char/sh-sci.h | 61 +++++++- drivers/ide/ide-pci.c | 16 +- drivers/ide/via82cxxx.c | 8 +- drivers/md/Config.in | 6 +- drivers/net/3c505.c | 10 +- drivers/net/acenic.c | 20 +-- drivers/net/hamachi.c | 5 - drivers/net/rrunner.c | 2 +- drivers/net/wan/comx-hw-comx.c | 6 +- drivers/net/wan/cosa.c | 8 +- drivers/pci/names.c | 3 +- drivers/usb/hid.c | 5 +- drivers/usb/pegasus.c | 11 +- drivers/usb/storage/freecom.c | 1 - drivers/usb/storage/scsiglue.c | 1 - drivers/usb/usb.c | 20 ++- fs/Makefile | 2 +- fs/buffer.c | 29 ++-- include/asm-ppc/atomic.h | 2 - include/asm-sh/atomic.h | 23 +-- include/asm-sh/bitops.h | 34 +++-- include/asm-sh/checksum.h | 12 +- include/asm-sh/delay.h | 3 +- include/asm-sh/fcntl.h | 12 ++ include/asm-sh/ide.h | 3 +- include/asm-sh/io_hd64461.h | 4 + include/asm-sh/irq.h | 3 + include/asm-sh/page.h | 10 +- include/asm-sh/pci.h | 16 +- include/asm-sh/pgtable.h | 62 ++++---- include/asm-sh/string.h | 13 +- include/asm-sh/system.h | 33 +++-- include/asm-sh/uaccess.h | 24 +-- include/asm-sh/unistd.h | 44 +++--- include/linux/inet.h | 1 - include/linux/slab.h | 1 - include/linux/swap.h | 1 + include/linux/vmalloc.h | 3 - init/version.c | 2 +- kernel/sched.c | 79 +++++----- mm/filemap.c | 1 - mm/page_alloc.c | 96 +++++++++--- mm/swap.c | 38 ++++- mm/vmscan.c | 93 ++++++------ net/ipv4/arp.c | 19 ++- net/ipv4/utils.c | 6 - net/ipv6/protocol.c | 7 +- 75 files changed, 1288 insertions(+), 696 deletions(-) diff --git a/Documentation/usb/CREDITS b/Documentation/usb/CREDITS index 7e6939e888c0..5eb41a557ff4 100644 --- a/Documentation/usb/CREDITS +++ b/Documentation/usb/CREDITS @@ -5,6 +5,7 @@ order by last name). I'm sure this list should be longer, its difficult to maintain, add yourself with a patch if desired. Georg Acher + David Brownell Alan Cox Randy Dunlap Johannes Erdfelt diff --git a/Documentation/usb/URB.txt b/Documentation/usb/URB.txt index 6cfd89ef34f0..3fc29d1f29aa 100644 --- a/Documentation/usb/URB.txt +++ b/Documentation/usb/URB.txt @@ -26,6 +26,7 @@ You only have read/write the data from/to the buffers in the completion handler, the continuous streaming itself is transparently done by the URB-machinery. + 1.2. The URB structure typedef struct urb @@ -68,6 +69,7 @@ typedef struct urb iso_packet_descriptor_t iso_frame_desc[0]; } urb_t, *purb_t; + 1.3. How to get an URB? URBs are allocated with the following call @@ -85,6 +87,7 @@ To free an URB, use This call also may free internal (host controller specific) memory in the future. + 1.4. What has to be filled in? Depending on the type of transaction, there are some macros @@ -107,6 +110,7 @@ AFTER the URB re-submission. You can get the other way by setting USB_URB_EARLY_COMPLETE in transfer_flags. This is implicit for INT transfers. + 1.5. How to submit an URB? Just call @@ -133,9 +137,12 @@ execution cannot be scheduled later than 900 frames from the 'now'-time. The same applies to INT transfers, but here the seamless continuation is independent of the transfer flags (implicitly ASAP). + 1.6. How to cancel an already running URB? -Call +For an URB which you've submitted, but which hasn't been returned to +your driver by the host controller, call + int unlink_urb(purb_t purb) It removes the urb from the internal list and frees all allocated @@ -143,6 +150,13 @@ HW descriptors. The status is changed to USB_ST_URB_KILLED. After unlink_urb() returns, you can safely free the URB with free_urb(urb) and all other possibly associated data (urb->context etc.) +There is also an asynchronous unlink mode. To use this, set the +the USB_ASYNC_UNLINK flag in urb->transfer flags before calling +usb_unlink_urb(). When using async unlinking, the URB will not +normally be unlinked when unlink_urb() returns. Instead, wait for +the completion handler to be called. + + 1.7. What about the completion handler? The completion handler is optional, but useful for fast data processing @@ -158,6 +172,16 @@ In the completion handler, you should have a look at urb->status to detect any USB errors. Since the context parameter is included in the URB, you can pass information to the completion handler. +Avoid using the urb->dev field in your completion handler; it's cleared +as part of URB unlinking. Instead, use urb->context to hold all the +data your driver needs. + +Also, NEVER SLEEP IN A COMPLETION HANDLER. These are normally called +during hardware interrupt processing. If you can, defer substantial +work to a tasklet (bottom half) to keep system latencies low. You'll +probably need to use spinlocks to protect data structures you manipulate +in completion handlers. + 1.8. How to do isochronous (ISO) transfers? @@ -184,11 +208,13 @@ queuing more than one ISO frame with ASAP to the same device&endpoint result in seamless ISO streaming. For continuous streaming you have to use URB linking. + 1.9. How to start interrupt (INT) transfers? -INT transfers are currently implemented with 8 different queues for intervals -for 1, 2, 4,... 128ms. Only one TD is allocated for each interrupt. After -calling the completion handler, the TD is recycled. +INT transfers are currently implemented with different queues for intervals +for 1, 2, 4,... 128ms. Only one URB is allocated for each interrupt. After +calling the completion handler, that URB is recycled by the host controller +driver (HCD). With the submission of one URB, the interrupt is scheduled until it is canceled by unlink_urb. diff --git a/Documentation/usb/error-codes.txt b/Documentation/usb/error-codes.txt index 7d67ac67e087..d1dccece539c 100644 --- a/Documentation/usb/error-codes.txt +++ b/Documentation/usb/error-codes.txt @@ -46,6 +46,9 @@ USB_ST_BANDWIDTH_ERROR -ENOSPC The host controller's bandwidth is already consumed and this request would push it past its allowed limit. +-ESHUTDOWN The host controller has been disabled due to some + problem that could not be worked around. + ************************************************************************** * Error codes returned by in urb->status * @@ -93,6 +96,8 @@ USB_ST_PARTIAL_ERROR USB_ST_URB_INVALID_ERROR -EINVAL ISO madness, if this happens: Log off and go home +-ECONNRESET the URB is being unlinked asynchronously + ************************************************************************** * Error codes returned by usbcore-functions * * (expect also other submit and transfer status codes) * diff --git a/Makefile b/Makefile index 4ce5cde9b9ca..0ea776b0faef 100644 --- a/Makefile +++ b/Makefile @@ -176,7 +176,7 @@ DRIVERS-$(CONFIG_IRDA) += drivers/net/irda/irda.o DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.o DRIVERS-$(CONFIG_PHONE) += drivers/telephony/telephony.o DRIVERS-$(CONFIG_ACPI_INTERPRETER) += drivers/acpi/acpi.o -DRIVERS-$(CONFIG_BLK_DEV_MD) += drivers/md/mddev.o +DRIVERS-$(CONFIG_MD) += drivers/md/mddev.o DRIVERS += $(DRIVERS-y) diff --git a/arch/i386/defconfig b/arch/i386/defconfig index 993ec1fa0968..7dddf30572ab 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -26,8 +26,8 @@ CONFIG_KMOD=y # CONFIG_M586 is not set # CONFIG_M586TSC is not set # CONFIG_M586MMX is not set -CONFIG_M686=y -# CONFIG_M686FXSR is not set +# CONFIG_M686 is not set +CONFIG_M686FXSR=y # CONFIG_MK6 is not set # CONFIG_MK7 is not set # CONFIG_MCRUSOE is not set @@ -44,6 +44,8 @@ CONFIG_X86_TSC=y CONFIG_X86_GOOD_APIC=y CONFIG_X86_PGE=y CONFIG_X86_USE_PPRO_CHECKSUM=y +CONFIG_X86_FXSR=y +CONFIG_X86_XMM=y # CONFIG_TOSHIBA is not set # CONFIG_MICROCODE is not set # CONFIG_X86_MSR is not set @@ -51,7 +53,6 @@ CONFIG_X86_USE_PPRO_CHECKSUM=y CONFIG_NOHIGHMEM=y # CONFIG_HIGHMEM4G is not set # CONFIG_HIGHMEM64G is not set -# CONFIG_MATH_EMULATION is not set # CONFIG_MTRR is not set CONFIG_SMP=y CONFIG_HAVE_DEC_LOCK=y @@ -123,6 +124,7 @@ CONFIG_BLK_DEV_FD=y # # Multi-device support (RAID and LVM) # +# CONFIG_MD is not set # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set # CONFIG_MD_RAID0 is not set diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index bf19449f4a62..57aada83198a 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -648,6 +648,7 @@ ENTRY(sys_call_table) .long SYMBOL_NAME(sys_madvise) .long SYMBOL_NAME(sys_getdents64) /* 220 */ .long SYMBOL_NAME(sys_fcntl64) + .long SYMBOL_NAME(sys_ni_syscall) /* reserved for TUX */ /* * NOTE!! This doesn't have to be exact - we just have diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index b305a85392ea..953c23d5504c 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -416,8 +416,8 @@ inline void nmi_watchdog_tick(struct pt_regs * regs) * here too!] */ - static unsigned int last_irq_sums [NR_CPUS] = { 0, }, - alert_counter [NR_CPUS] = { 0, }; + static unsigned int last_irq_sums [NR_CPUS], + alert_counter [NR_CPUS]; /* * Since current-> is always on the stack, and we always switch diff --git a/arch/sh/boot/compressed/Makefile b/arch/sh/boot/compressed/Makefile index bd419991bd54..7e34e14dab2b 100644 --- a/arch/sh/boot/compressed/Makefile +++ b/arch/sh/boot/compressed/Makefile @@ -36,7 +36,7 @@ piggy.o: $(SYSTEM) $(OBJCOPY) -R .empty_zero_page $(SYSTEM) $$tmppiggy; \ gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \ echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \ - $(LD) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-shl -T $$tmppiggy.lnk; \ + $(LD) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-sh-linux -T $$tmppiggy.lnk; \ rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk clean: diff --git a/arch/sh/kernel/entry.S b/arch/sh/kernel/entry.S index 7335803da8f6..3b74e2d8e2fa 100644 --- a/arch/sh/kernel/entry.S +++ b/arch/sh/kernel/entry.S @@ -14,7 +14,12 @@ #include #include -#define COMPAT_OLD_SYSCALL_ABI 1 + +/* + * Define this to turn on compatibility with the previous + * system call ABI. This feature is not properly maintained. + */ +#undef COMPAT_OLD_SYSCALL_ABI ! NOTE: ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address @@ -28,6 +33,12 @@ * NOTE: This code handles signal-recognition, which happens every time * after a timer-interrupt and after each system call. * + * NOTE: This code uses a convention that instructions in the delay slot + * of a transfer-control instruction are indented by an extra space, thus: + * + * jmp @$k0 ! control-transfer instruction + * ldc $k1, $ssr ! delay slot + * * Stack layout in 'ret_from_syscall': * ptrace needs to have all regs on the stack. * if the order here is changed, it needs to be @@ -58,6 +69,7 @@ PT_TRACESYS = 0x00000002 PF_USEDFPU = 0x00100000 ENOSYS = 38 +EINVAL = 22 #if defined(__sh3__) TRA = 0xffffffd0 @@ -76,7 +88,14 @@ MMU_TEA = 0xff00000c ! TLB Exception Address Register #endif /* Offsets to the stack */ -R0 = 0 /* Return value */ +R0 = 0 /* Return value. New ABI also arg4 */ +R1 = 4 /* New ABI: arg5 */ +R2 = 8 /* New ABI: arg6 */ +R3 = 12 /* New ABI: syscall_nr */ +R4 = 16 /* New ABI: arg0 */ +R5 = 20 /* New ABI: arg1 */ +R6 = 24 /* New ABI: arg2 */ +R7 = 28 /* New ABI: arg3 */ SP = (15*4) SR = (16*4+8) SYSCALL_NR = (16*4+6*4) @@ -132,7 +151,6 @@ SYSCALL_NR = (16*4+6*4) tlb_miss_load: mov.l 2f, $r0 mov.l @$r0, $r6 - STI() mov $r15, $r4 mov.l 1f, $r0 jmp @$r0 @@ -142,7 +160,6 @@ tlb_miss_load: tlb_miss_store: mov.l 2f, $r0 mov.l @$r0, $r6 - STI() mov $r15, $r4 mov.l 1f, $r0 jmp @$r0 @@ -152,7 +169,6 @@ tlb_miss_store: initial_page_write: mov.l 2f, $r0 mov.l @$r0, $r6 - STI() mov $r15, $r4 mov.l 1f, $r0 jmp @$r0 @@ -162,7 +178,6 @@ initial_page_write: tlb_protection_violation_load: mov.l 2f, $r0 mov.l @$r0, $r6 - STI() mov $r15, $r4 mov.l 1f, $r0 jmp @$r0 @@ -172,14 +187,13 @@ tlb_protection_violation_load: tlb_protection_violation_store: mov.l 2f, $r0 mov.l @$r0, $r6 - STI() mov $r15, $r4 mov.l 1f, $r0 jmp @$r0 mov #1, $r5 .align 2 -1: .long SYMBOL_NAME(do_page_fault) +1: .long SYMBOL_NAME(__do_page_fault) 2: .long MMU_TEA #if defined(CONFIG_DEBUG_KERNEL_WITH_GDB_STUB) || defined(CONFIG_SH_STANDARD_BIOS) @@ -249,9 +263,6 @@ error: .align 2 1: .long SYMBOL_NAME(do_exception_error) -badsys: mov #-ENOSYS, $r0 - rts ! go to ret_from_syscall.. - mov.l $r0, @(R0,$r15) ! ! @@ -291,7 +302,7 @@ ENTRY(ret_from_fork) */ system_call: - mov.l 1f, $r9 + mov.l __TRA, $r9 mov.l @$r9, $r8 ! ! Is the trap argument >= 0x20? (TRA will be >= 0x80) @@ -304,121 +315,159 @@ system_call: mov #SYSCALL_NR, $r14 add $r15, $r14 ! - mov #0x40, $r9 #ifdef COMPAT_OLD_SYSCALL_ABI + mov #0x40, $r9 cmp/hs $r9, $r8 - mov $r0, $r10 - bf/s 0f - mov $r0, $r9 + bf/s old_abi_system_call + nop #endif ! New Syscall ABI add #-0x40, $r8 shlr2 $r8 shll8 $r8 - shll8 $r8 + shll8 $r8 ! $r8 = num_args<<16 mov $r3, $r10 or $r8, $r10 ! Encode syscall # and # of arguments - ! - mov $r3, $r9 - mov #0, $r8 -0: mov.l $r10, @$r14 ! set syscall_nr STI() - mov.l __n_sys, $r10 - cmp/hs $r10, $r9 - bt badsys ! -#ifdef COMPAT_OLD_SYSCALL_ABI - ! Build the stack frame if TRA > 0 - mov $r8, $r10 - cmp/pl $r10 - bf 0f - mov.l @(SP,$r15), $r0 ! get original stack -7: add #-4, $r10 -4: mov.l @($r0,$r10), $r1 ! May cause address error exception.. - mov.l $r1, @-$r15 - cmp/pl $r10 - bt 7b -#endif -0: stc $k_current, $r11 - mov.l @(tsk_ptrace,$r11), $r10 ! Is it trace? + stc $k_current, $r11 + mov.l @(tsk_ptrace,$r11), $r10 ! Is current PTRACE_SYSCALL'd? mov #PT_TRACESYS, $r11 tst $r11, $r10 bt 5f - ! Trace system call - mov #-ENOSYS, $r11 - mov.l $r11, @(R0,$r15) - ! Push up $R0--$R2, and $R4--$R7 - mov.l $r0, @-$r15 - mov.l $r1, @-$r15 - mov.l $r2, @-$r15 - mov.l $r4, @-$r15 - mov.l $r5, @-$r15 - mov.l $r6, @-$r15 - mov.l $r7, @-$r15 - ! - mov.l 2f, $r11 - jsr @$r11 + ! Yes it is traced. + mov.l __syscall_trace, $r11 ! Call syscall_trace() which notifies + jsr @$r11 ! superior (will chomp $R[0-7]) nop - ! Pop down $R0--$R2, and $R4--$R7 - mov.l @$r15+, $r7 - mov.l @$r15+, $r6 - mov.l @$r15+, $r5 - mov.l @$r15+, $r4 - mov.l @$r15+, $r2 - mov.l @$r15+, $r1 - mov.l @$r15+, $r0 - ! + ! Reload $R0-$R4 from kernel stack, where the + ! parent may have modified them using + ! ptrace(POKEUSR). (Note that $R0-$R2 are + ! used by the system call handler directly + ! from the kernel stack anyway, so don't need + ! to be reloaded here.) This allows the parent + ! to rewrite system calls and args on the fly. + mov.l @(R4,$r15), $r4 ! arg0 + mov.l @(R5,$r15), $r5 + mov.l @(R6,$r15), $r6 + mov.l @(R7,$r15), $r7 ! arg3 + mov.l @(R3,$r15), $r3 ! syscall_nr + ! Arrange for syscall_trace() to be called + ! again as the system call returns. mov.l __syscall_ret_trace, $r10 bra 6f lds $r10, $pr - ! + ! No it isn't traced. + ! Arrange for normal system call return. 5: mov.l __syscall_ret, $r10 lds $r10, $pr - ! -6: mov $r9, $r10 - shll2 $r10 ! x4 + ! Call the system call handler through the table. + ! (both normal and ptrace'd) + ! First check for bad syscall number +6: mov $r3, $r9 + mov.l __n_sys, $r10 + cmp/hs $r10, $r9 + bf 2f + ! Bad syscall number + rts ! go to syscall_ret or syscall_ret_trace + mov #-ENOSYS, $r0 + ! Good syscall number +2: shll2 $r9 ! x4 mov.l __sct, $r11 - add $r11, $r10 - mov.l @$r10, $r11 - jmp @$r11 + add $r11, $r9 + mov.l @$r9, $r11 + jmp @$r11 ! jump to specific syscall handler nop ! In case of trace - .align 2 -3: -#ifdef COMPAT_OLD_SYSCALL_ABI - add $r8, $r15 ! pop off the arguments -#endif +syscall_ret_trace: mov.l $r0, @(R0,$r15) ! save the return value - mov.l 2f, $r1 + mov.l __syscall_trace, $r1 mova SYMBOL_NAME(ret_from_syscall), $r0 - jmp @$r1 - lds $r0, $pr - .align 2 -1: .long TRA -2: .long SYMBOL_NAME(syscall_trace) -__n_sys: .long NR_syscalls -__sct: .long SYMBOL_NAME(sys_call_table) -__syscall_ret_trace: - .long 3b -__syscall_ret: - .long SYMBOL_NAME(syscall_ret) + jmp @$r1 ! Call syscall_trace() which notifies superior + lds $r0, $pr ! Then return to ret_from_syscall() + + #ifdef COMPAT_OLD_SYSCALL_ABI +! Handle old ABI system call. +! Note that ptrace(SYSCALL) is not supported for the old ABI. +! At this point: +! $r0, $r4-7 as per ABI +! $r8 = value of TRA register (= num_args<<2) +! $r14 = points to SYSCALL_NR in stack frame +old_abi_system_call: + mov $r0, $r9 ! Save system call number in $r9 + ! ! arrange for return which pops stack + mov.l __old_abi_syscall_ret, $r10 + lds $r10, $pr + ! Build the stack frame if TRA > 0 + mov $r8, $r10 + cmp/pl $r10 + bf 0f + mov.l @(SP,$r15), $r0 ! get original user stack +7: add #-4, $r10 +4: mov.l @($r0,$r10), $r1 ! May cause address error exception.. + mov.l $r1, @-$r15 + cmp/pl $r10 + bt 7b +0: + mov.l $r9, @$r14 ! set syscall_nr + STI() + ! Call the system call handler through the table. + ! First check for bad syscall number + mov.l __n_sys, $r10 + cmp/hs $r10, $r9 + bf 2f + ! Bad syscall number + rts ! return to old_abi_syscall_ret + mov #-ENOSYS, $r0 + ! Good syscall number +2: shll2 $r9 ! x4 + mov.l __sct, $r11 + add $r11, $r9 + mov.l @$r9, $r11 + jmp @$r11 ! call specific syscall handler, + nop + + .align 2 +__old_abi_syscall_ret: + .long old_abi_syscall_ret + + ! This code gets called on address error exception when copying + ! syscall arguments from user stack to kernel stack. It is + ! supposed to return -EINVAL through old_abi_syscall_ret, but it + ! appears to have been broken for a long time in that the $r0 + ! return value will be saved into the kernel stack relative to $r15 + ! but the value of $r15 is not correct partway through the loop. + ! So the user prog is returned its old $r0 value, not -EINVAL. + ! Greg Banks 28 Aug 2000. .section .fixup,"ax" fixup_syscall_argerr: + ! First get $r15 back to rts - mov.l 1f, $r0 -1: .long -22 ! -EINVAL -.previous + mov #-EINVAL, $r0 + .previous .section __ex_table, "a" .align 2 .long 4b,fixup_syscall_argerr -.previous + .previous #endif + .align 2 +__TRA: .long TRA +__syscall_trace: + .long SYMBOL_NAME(syscall_trace) +__n_sys:.long NR_syscalls +__sct: .long SYMBOL_NAME(sys_call_table) +__syscall_ret_trace: + .long syscall_ret_trace +__syscall_ret: + .long SYMBOL_NAME(syscall_ret) + + + .align 2 reschedule: mova SYMBOL_NAME(ret_from_syscall), $r0 @@ -454,10 +503,12 @@ __INV_IMASK: .long 0xffffff0f ! ~(IMASK) .align 2 -syscall_ret: #ifdef COMPAT_OLD_SYSCALL_ABI +old_abi_syscall_ret: add $r8, $r15 ! pop off the arguments + /* fall through */ #endif +syscall_ret: mov.l $r0, @(R0,$r15) ! save the return value /* fall through */ @@ -707,7 +758,7 @@ handle_exception: #endif 8: /* User space to kernel */ mov #0x20, $k1 - shll8 $k1 ! $k1 <= 8192 + shll8 $k1 ! $k1 <= 8192 == THREAD_SIZE add $current, $k1 mov $k1, $r15 ! change to kernel stack ! @@ -1107,6 +1158,7 @@ ENTRY(sys_call_table) .long SYMBOL_NAME(sys_mincore) .long SYMBOL_NAME(sys_madvise) .long SYMBOL_NAME(sys_getdents64) /* 220 */ + .long SYMBOL_NAME(sys_fcntl64) /* * NOTE!! This doesn't have to be exact - we just have @@ -1114,7 +1166,7 @@ ENTRY(sys_call_table) * entries. Don't panic if you notice that this hasn't * been shrunk every time we add a new system call. */ - .rept NR_syscalls-220 + .rept NR_syscalls-221 .long SYMBOL_NAME(sys_ni_syscall) .endr diff --git a/arch/sh/kernel/head.S b/arch/sh/kernel/head.S index db3e8b0a3523..f1ac6fd17b07 100644 --- a/arch/sh/kernel/head.S +++ b/arch/sh/kernel/head.S @@ -21,9 +21,9 @@ ENTRY(empty_zero_page) .long 0x00360000 /* INITRD_START */ .long 0x000a0000 /* INITRD_SIZE */ .long 0 + .balign 4096,0,4096 .text - .balign 4096,0,4096 /* * Condition at the entry of _stext: * diff --git a/arch/sh/kernel/io.c b/arch/sh/kernel/io.c index fca718ece748..80f50d9adb40 100644 --- a/arch/sh/kernel/io.c +++ b/arch/sh/kernel/io.c @@ -1,5 +1,5 @@ /* - * linux/arch/sh/kernel/io_generic.c + * linux/arch/sh/kernel/io.c * * Copyright (C) 2000 Stuart Menefy * diff --git a/arch/sh/kernel/irq_imask.c b/arch/sh/kernel/irq_imask.c index 8ac95823b6ad..27d91b372c8f 100644 --- a/arch/sh/kernel/irq_imask.c +++ b/arch/sh/kernel/irq_imask.c @@ -41,7 +41,7 @@ static void end_imask_irq(unsigned int irq); static unsigned int startup_imask_irq(unsigned int irq) { - enable_imask_irq(irq); + /* Nothing to do */ return 0; /* never anything pending */ } @@ -71,7 +71,8 @@ void static inline set_interrupt_registers(int ip) "ldc %0, $sr\n" "1:" : "=&z" (__dummy) - : "r" (~0xf0), "r" (ip << 4)); + : "r" (~0xf0), "r" (ip << 4) + : "t"); } static void disable_imask_irq(unsigned int irq) @@ -103,7 +104,7 @@ static void end_imask_irq(unsigned int irq) static void shutdown_imask_irq(unsigned int irq) { - disable_imask_irq(irq); + /* Nothing to do */ } void make_imask_irq(unsigned int irq) diff --git a/arch/sh/kernel/irq_ipr.c b/arch/sh/kernel/irq_ipr.c index f229e8a12f58..918e010e9ea6 100644 --- a/arch/sh/kernel/irq_ipr.c +++ b/arch/sh/kernel/irq_ipr.c @@ -128,12 +128,14 @@ void __init init_IRQ(void) #ifdef SCIF_ERI_IRQ make_ipr_irq(SCIF_ERI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY); make_ipr_irq(SCIF_RXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY); + make_ipr_irq(SCIF_BRI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY); make_ipr_irq(SCIF_TXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY); #endif #ifdef IRDA_ERI_IRQ make_ipr_irq(IRDA_ERI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY); make_ipr_irq(IRDA_RXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY); + make_ipr_irq(IRDA_BRI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY); make_ipr_irq(IRDA_TXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY); #endif diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c index 4a6a639833e7..c7511093bef6 100644 --- a/arch/sh/kernel/process.c +++ b/arch/sh/kernel/process.c @@ -136,11 +136,12 @@ void free_task_struct(struct task_struct *p) */ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { /* Don't use this in BL=1(cli). Or else, CPU resets! */ - register unsigned long __sc0 __asm__ ("$r3") = __NR_clone; - register unsigned long __sc4 __asm__ ("$r4") = (long) flags | CLONE_VM; - register unsigned long __sc5 __asm__ ("$r5") = 0; - register unsigned long __sc8 __asm__ ("$r8") = (long) arg; - register unsigned long __sc9 __asm__ ("$r9") = (long) fn; + register unsigned long __sc0 __asm__ ("r0"); + register unsigned long __sc3 __asm__ ("r3") = __NR_clone; + register unsigned long __sc4 __asm__ ("r4") = (long) flags | CLONE_VM; + register unsigned long __sc5 __asm__ ("r5") = 0; + register unsigned long __sc8 __asm__ ("r8") = (long) arg; + register unsigned long __sc9 __asm__ ("r9") = (long) fn; __asm__("trapa #0x12\n\t" /* Linux/SH system call */ "tst #0xff, $r0\n\t" /* child or parent? */ @@ -148,13 +149,13 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) "jsr @$r9\n\t" /* call fn */ " mov $r8, $r4\n\t" /* push argument */ "mov $r0, $r4\n\t" /* return value to arg of exit */ - "mov %2, $r3\n\t" /* exit */ + "mov %1, $r3\n\t" /* exit */ "trapa #0x11\n" "1:" : "=z" (__sc0) - : "0" (__sc0), "i" (__NR_exit), - "r" (__sc4), "r" (__sc5), "r" (__sc8), "r" (__sc9) - : "memory"); + : "i" (__NR_exit), "r" (__sc3), "r" (__sc4), "r" (__sc5), + "r" (__sc8), "r" (__sc9) + : "memory", "t"); return __sc0; } diff --git a/arch/sh/kernel/setup_cqreek.c b/arch/sh/kernel/setup_cqreek.c index ea5dd7ece2a6..af7dfe568c67 100644 --- a/arch/sh/kernel/setup_cqreek.c +++ b/arch/sh/kernel/setup_cqreek.c @@ -1,4 +1,4 @@ -/* $Id: setup_cqreek.c,v 1.1 2000/08/05 06:25:23 gniibe Exp $ +/* $Id: setup_cqreek.c,v 1.5 2000/09/18 05:51:24 gniibe Exp $ * * arch/sh/kernel/setup_cqreek.c * @@ -44,15 +44,24 @@ static unsigned long cqreek_port2addr(unsigned long port) return ISA_OFFSET + port; } +struct cqreek_irq_data { + unsigned short mask_port; /* Port of Interrupt Mask Register */ + unsigned short stat_port; /* Port of Interrupt Status Register */ + unsigned short bit; /* Value of the bit */ +}; +static struct cqreek_irq_data cqreek_irq_data[NR_IRQS]; + static void disable_cqreek_irq(unsigned int irq) { unsigned long flags; unsigned short mask; + unsigned short mask_port = cqreek_irq_data[irq].mask_port; + unsigned short bit = cqreek_irq_data[irq].bit; save_and_cli(flags); /* Disable IRQ */ - mask = inw(BRIDGE_ISA_INTR_MASK) & ~(1 << irq); - outw_p(mask, BRIDGE_ISA_INTR_MASK); + mask = inw(mask_port) & ~bit; + outw_p(mask, mask_port); restore_flags(flags); } @@ -60,32 +69,29 @@ static void enable_cqreek_irq(unsigned int irq) { unsigned long flags; unsigned short mask; + unsigned short mask_port = cqreek_irq_data[irq].mask_port; + unsigned short bit = cqreek_irq_data[irq].bit; save_and_cli(flags); /* Enable IRQ */ - mask = inw(BRIDGE_ISA_INTR_MASK) | (1 << irq); - outw_p(mask, BRIDGE_ISA_INTR_MASK); + mask = inw(mask_port) | bit; + outw_p(mask, mask_port); restore_flags(flags); } -#define CLEAR_AT_ACCEPT - static void mask_and_ack_cqreek(unsigned int irq) { - inw(BRIDGE_ISA_INTR_STAT); + unsigned short stat_port = cqreek_irq_data[irq].stat_port; + unsigned short bit = cqreek_irq_data[irq].bit; + + inw(stat_port); disable_cqreek_irq(irq); -#ifdef CLEAR_AT_ACCEPT /* Clear IRQ (it might be edge IRQ) */ - outw_p((1< #include #include +#include extern void dump_thread(struct pt_regs *, struct user *); extern int dump_fpu(elf_fpregset_t *); @@ -35,7 +36,35 @@ EXPORT_SYMBOL(csum_partial_copy); EXPORT_SYMBOL(strtok); EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strstr); +EXPORT_SYMBOL(strlen); + +/* mem exports */ +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(memmove); + +/* this is not provided by arch/sh/lib/*.S but is + potentially needed by modules (af_packet.o/unix.o + use memcmp, for instance) */ +EXPORT_SYMBOL(memcmp); #ifdef CONFIG_VT EXPORT_SYMBOL(screen_info); #endif + + +#define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL_NOVERS(name) + +/* These symbols are generated by the compiler itself */ +#ifdef __SH4__ + +DECLARE_EXPORT(__udivsi3_i4); +DECLARE_EXPORT(__sdivsi3_i4); +DECLARE_EXPORT(__movstr_i4_even); +DECLARE_EXPORT(__movstr_i4_odd); +DECLARE_EXPORT(__ashrdi3); +DECLARE_EXPORT(__ashldi3); + +/* needed by some modules */ +EXPORT_SYMBOL(flush_dcache_page); +#endif diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c index ac40844f07d2..5af1e6de8cc2 100644 --- a/arch/sh/kernel/time.c +++ b/arch/sh/kernel/time.c @@ -342,7 +342,8 @@ static __init unsigned int get_cpu_mhz(void) "bt/s 1b\n\t" " add #1,%0" : "=r"(count), "=z" (__dummy) - : "0" (0), "1" (0)); + : "0" (0), "1" (0) + : "t"); cli(); /* * SH-3: diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c index a9775f3062cc..db11c1247072 100644 --- a/arch/sh/kernel/traps.c +++ b/arch/sh/kernel/traps.c @@ -131,9 +131,16 @@ void dump_stack(void) asm("mov $r15, %0" : "=r" (start)); asm("stc $r7_bank, %0" : "=r" (end)); - end += 8192; + end += 8192/4; printk("%08lx:%08lx\n", (unsigned long)start, (unsigned long)end); - for (p=start; p < end; p++) - printk("%08lx\n", *p); + for (p=start; p < end; p++) { + extern long _text, _etext; + unsigned long v=*p; + + if ((v >= (unsigned long )&_text) + && (v <= (unsigned long )&_etext)) { + printk("%08lx\n", v); + } + } } diff --git a/arch/sh/lib/checksum.S b/arch/sh/lib/checksum.S index 3317b3cccb36..c7e96a394fae 100644 --- a/arch/sh/lib/checksum.S +++ b/arch/sh/lib/checksum.S @@ -159,14 +159,14 @@ unsigned int csum_partial_copy_generic (const char *src, char *dst, int len, * them all but there's no guarantee. */ -#define SRC(y...) \ - 9999: y; \ +#define SRC(x,y) \ + 9999: x,y; \ .section __ex_table, "a"; \ .long 9999b, 6001f ; \ .previous -#define DST(y...) \ - 9999: y; \ +#define DST(x,y) \ + 9999: x,y; \ .section __ex_table, "a"; \ .long 9999b, 6002f ; \ .previous @@ -276,7 +276,7 @@ DST( mov.l r0,@r5 ) DST( mov.l r1,@r5 ) add #4,r5 -SRC( mov.l @r4+,r0 ) +SRC( mov.l @r4+,r0 ) SRC( mov.l @r4+,r1 ) addc r0,r7 DST( mov.l r0,@r5 ) diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c index af494b9a3a2e..ab63535e4dcc 100644 --- a/arch/sh/mm/cache.c +++ b/arch/sh/mm/cache.c @@ -64,9 +64,9 @@ static struct _cache_system_info cache_system_info = {0,}; #define CACHE_IC_WAY_SHIFT 13 #define CACHE_OC_ENTRY_SHIFT 5 #define CACHE_IC_ENTRY_SHIFT 5 -#define CACHE_OC_ENTRY_MASK 0x3fe0 -#define CACHE_OC_ENTRY_PHYS_MASK 0x0fe0 -#define CACHE_IC_ENTRY_MASK 0x1fe0 +#define CACHE_OC_ENTRY_MASK 0x3fe0 +#define CACHE_OC_ENTRY_PHYS_MASK 0x0fe0 +#define CACHE_IC_ENTRY_MASK 0x1fe0 #define CACHE_IC_NUM_ENTRIES 256 #define CACHE_OC_NUM_ENTRIES 512 #define CACHE_OC_NUM_WAYS 1 @@ -92,7 +92,8 @@ static inline void cache_wback_all(void) addr = CACHE_OC_ADDRESS_ARRAY|(j<>CACHE_OC_ENTRY_SHIFT; jump_to_P2(); /* Loop all the D-cache */ for (i=0; i extern void die(const char *,struct pt_regs *,long); -static void __flush_tlb_page(struct mm_struct *mm, unsigned long page); +static void __flush_tlb_page(unsigned long asid, unsigned long page); #if defined(__SH4__) -static void __flush_tlb_phys(struct mm_struct *mm, unsigned long phys); +static void __flush_tlb_phys(unsigned long phys); #endif /* @@ -85,42 +85,6 @@ bad_area: return 0; } -static void handle_vmalloc_fault(struct mm_struct *mm, unsigned long address) -{ - pgd_t *dir; - pmd_t *pmd; - pte_t *pte; - pte_t entry; - - dir = pgd_offset_k(address); - pmd = pmd_offset(dir, address); - if (pmd_none(*pmd)) { - printk(KERN_ERR "vmalloced area %08lx bad\n", address); - return; - } - if (pmd_bad(*pmd)) { - pmd_ERROR(*pmd); - pmd_clear(pmd); - return; - } - pte = pte_offset(pmd, address); - entry = *pte; - if (pte_none(entry) || !pte_present(entry) || !pte_write(entry)) { - printk(KERN_ERR "vmalloced area %08lx bad\n", address); - return; - } - -#if defined(__SH4__) - /* - * ITLB is not affected by "ldtlb" instruction. - * So, we need to flush the entry by ourselves. - */ - if (mm) - __flush_tlb_page(mm, address&PAGE_MASK); -#endif - update_mmu_cache(NULL, address, entry); -} - /* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate @@ -138,11 +102,6 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess, tsk = current; mm = tsk->mm; - if (address >= VMALLOC_START && address < VMALLOC_END) { - handle_vmalloc_fault(mm, address); - return; - } - /* * If we're in an interrupt or have no user * context, we must not take the fault.. @@ -272,6 +231,67 @@ do_sigbus: goto no_context; } +static int __do_page_fault1(struct pt_regs *regs, unsigned long writeaccess, + unsigned long address) +{ + pgd_t *dir; + pmd_t *pmd; + pte_t *pte; + pte_t entry; + + if (address >= VMALLOC_START && address < VMALLOC_END) + /* We can change the implementation of P3 area pte entries. + set_pgdir and such. */ + dir = pgd_offset_k(address); + else + dir = pgd_offset(current->mm, address); + + pmd = pmd_offset(dir, address); + if (pmd_none(*pmd)) + return 1; + if (pmd_bad(*pmd)) { + pmd_ERROR(*pmd); + pmd_clear(pmd); + return 1; + } + pte = pte_offset(pmd, address); + entry = *pte; + if (pte_none(entry) || !pte_present(entry) + || (writeaccess && !pte_write(entry))) + return 1; + + if (writeaccess) + entry = pte_mkdirty(entry); + entry = pte_mkyoung(entry); +#if defined(__SH4__) + /* + * ITLB is not affected by "ldtlb" instruction. + * So, we need to flush the entry by ourselves. + */ + __flush_tlb_page(get_asid(), address&PAGE_MASK); +#endif + set_pte(pte, entry); + update_mmu_cache(NULL, address, entry); + return 0; +} + +/* + * Called with interrupt disabled. + */ +asmlinkage void __do_page_fault(struct pt_regs *regs, unsigned long writeaccess, + unsigned long address) +{ + /* + * XXX: Could you please implement this (calling __do_page_fault1) + * in assembler language in entry.S? + */ + if (__do_page_fault1(regs, writeaccess, address) == 0) + /* Done. */ + return; + sti(); + do_page_fault(regs, writeaccess, address); +} + void update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte) { @@ -282,28 +302,30 @@ void update_mmu_cache(struct vm_area_struct * vma, save_and_cli(flags); #if defined(__SH4__) - if (vma && (vma->vm_flags & VM_SHARED)) { + if (pte_shared(pte)) { struct page *pg; pteval = pte_val(pte); pteval &= PAGE_MASK; /* Physicall page address */ - __flush_tlb_phys(vma->vm_mm, pteval); + __flush_tlb_phys(pteval); pg = virt_to_page(__va(pteval)); flush_dcache_page(pg); } #endif - /* Set PTEH register */ - if (vma) { - pteaddr = (address & MMU_VPN_MASK) | - (vma->vm_mm->context & MMU_CONTEXT_ASID_MASK); - ctrl_outl(pteaddr, MMU_PTEH); + /* Ptrace may call this routine. */ + if (vma && current->active_mm != vma->vm_mm) { + restore_flags(flags); + return; } + /* Set PTEH register */ + pteaddr = (address & MMU_VPN_MASK) | get_asid(); + ctrl_outl(pteaddr, MMU_PTEH); + /* Set PTEL register */ pteval = pte_val(pte); pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */ - pteval |= _PAGE_FLAGS_HARDWARE_DEFAULT; /* add default flags */ ctrl_outl(pteval, MMU_PTEL); /* Load the TLB */ @@ -311,24 +333,16 @@ void update_mmu_cache(struct vm_area_struct * vma, restore_flags(flags); } -static void __flush_tlb_page(struct mm_struct *mm, unsigned long page) +static void __flush_tlb_page(unsigned long asid, unsigned long page) { - unsigned long addr, data, asid; - unsigned long saved_asid = MMU_NO_ASID; - - if (mm->context == NO_CONTEXT) - return; - - asid = mm->context & MMU_CONTEXT_ASID_MASK; - if (mm != current->mm) { - saved_asid = get_asid(); - /* - * We need to set ASID of the target entry to flush, - * because TLB is indexed by (ASID and PAGE). - */ - set_asid(asid); - } + unsigned long addr, data; + /* + * NOTE: PTEH.ASID should be set to this MM + * _AND_ we need to write ASID to the array. + * + * It would be simple if we didn't need to set PTEH.ASID... + */ #if defined(__sh3__) addr = MMU_TLB_ADDRESS_ARRAY |(page & 0x1F000)| MMU_PAGE_ASSOC_BIT; data = (page & 0xfffe0000) | asid; /* VALID bit is off */ @@ -340,12 +354,10 @@ static void __flush_tlb_page(struct mm_struct *mm, unsigned long page) ctrl_outl(data, addr); back_to_P1(); #endif - if (saved_asid != MMU_NO_ASID) - set_asid(saved_asid); } #if defined(__SH4__) -static void __flush_tlb_phys(struct mm_struct *mm, unsigned long phys) +static void __flush_tlb_phys(unsigned long phys) { int i; unsigned long addr, data; @@ -373,12 +385,22 @@ static void __flush_tlb_phys(struct mm_struct *mm, unsigned long phys) void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) { - unsigned long flags; + if (vma->vm_mm && vma->vm_mm->context != NO_CONTEXT) { + unsigned long flags; + unsigned long asid; + unsigned long saved_asid = MMU_NO_ASID; - if (vma->vm_mm) { + asid = vma->vm_mm->context & MMU_CONTEXT_ASID_MASK; page &= PAGE_MASK; + save_and_cli(flags); - __flush_tlb_page(vma->vm_mm, page); + if (vma->vm_mm != current->mm) { + saved_asid = get_asid(); + set_asid(asid); + } + __flush_tlb_page(asid, page); + if (saved_asid != MMU_NO_ASID) + set_asid(saved_asid); restore_flags(flags); } } @@ -397,13 +419,22 @@ void flush_tlb_range(struct mm_struct *mm, unsigned long start, if (mm == current->mm) activate_context(mm); } else { + unsigned long asid = mm->context&MMU_CONTEXT_ASID_MASK; + unsigned long saved_asid = MMU_NO_ASID; + start &= PAGE_MASK; end += (PAGE_SIZE - 1); end &= PAGE_MASK; + if (mm != current->mm) { + saved_asid = get_asid(); + set_asid(asid); + } while (start < end) { - __flush_tlb_page(mm, start); + __flush_tlb_page(asid, start); start += PAGE_SIZE; } + if (saved_asid != MMU_NO_ASID) + set_asid(saved_asid); } restore_flags(flags); } diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index ccabeb85f050..8568afb31c11 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -241,6 +241,7 @@ void __init mem_init(void) /* clear the zero-page */ memset(empty_zero_page, 0, PAGE_SIZE); + flush_page_to_ram(virt_to_page(empty_zero_page)); /* this will put all low memory onto the freelists */ totalram_pages += free_all_bootmem(); diff --git a/arch/sh/vmlinux.lds.S b/arch/sh/vmlinux.lds.S index ad1fc1c1b576..93ea453cb0c2 100644 --- a/arch/sh/vmlinux.lds.S +++ b/arch/sh/vmlinux.lds.S @@ -4,9 +4,9 @@ */ #include #ifdef CONFIG_CPU_LITTLE_ENDIAN -OUTPUT_FORMAT("elf32-shl", "elf32-shl", "elf32-shl") +OUTPUT_FORMAT("elf32-sh-linux", "elf32-sh-linux", "elf32-sh-linux") #else -OUTPUT_FORMAT("elf32-sh", "elf32-sh", "elf32-sh") +OUTPUT_FORMAT("elf32-shbig-linux", "elf32-shbig-linux", "elf32-shbig-linux") #endif OUTPUT_ARCH(sh) ENTRY(_start) @@ -89,6 +89,7 @@ SECTIONS /DISCARD/ : { *(.text.exit) *(.data.exit) + *(.exitcall.exit) } /* Stabs debugging sections. */ diff --git a/drivers/acorn/net/etherh.c b/drivers/acorn/net/etherh.c index 03c4919724fe..bf84fca568d0 100644 --- a/drivers/acorn/net/etherh.c +++ b/drivers/acorn/net/etherh.c @@ -67,7 +67,7 @@ static const card_ids __init etherh_cids[] = { MODULE_AUTHOR("Russell King"); MODULE_DESCRIPTION("i3 EtherH driver"); -static char *version __initdata = +static char version[] __initdata = "etherh [500/600/600A] ethernet driver (c) 2000 R.M.King v1.07\n"; #define ETHERH500_DATAPORT 0x200 /* MEMC */ diff --git a/drivers/block/xd.c b/drivers/block/xd.c index 8bd2ec3bc260..b5df63bd97f4 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -116,7 +116,7 @@ static unsigned int xd_bases[] __initdata = }; static struct hd_struct xd_struct[XD_MAXDRIVES << 6]; -static int xd_sizes[XD_MAXDRIVES << 6], xd_access[XD_MAXDRIVES] = { 0, 0 }; +static int xd_sizes[XD_MAXDRIVES << 6], xd_access[XD_MAXDRIVES]; static int xd_blocksizes[XD_MAXDRIVES << 6]; extern struct block_device_operations xd_fops; @@ -141,12 +141,12 @@ static struct block_device_operations xd_fops = { static DECLARE_WAIT_QUEUE_HEAD(xd_wait_int); static DECLARE_WAIT_QUEUE_HEAD(xd_wait_open); static u_char xd_valid[XD_MAXDRIVES] = { 0,0 }; -static u_char xd_drives = 0, xd_irq = 5, xd_dma = 3, xd_maxsectors; -static u_char xd_override __initdata = 0, xd_type = 0; +static u_char xd_drives, xd_irq = 5, xd_dma = 3, xd_maxsectors; +static u_char xd_override __initdata, xd_type __initdata; static u_short xd_iobase = 0x320; -static int xd_geo[XD_MAXDRIVES*3] __initdata = { 0,0,0,0,0,0 }; +static int xd_geo[XD_MAXDRIVES*3] __initdata; -static volatile int xdc_busy = 0; +static volatile int xdc_busy; static DECLARE_WAIT_QUEUE_HEAD(xdc_wait); static struct timer_list xd_timer, xd_watchdog_int; diff --git a/drivers/char/i810_rng.c b/drivers/char/i810_rng.c index 7a6718c02b76..18e198f51b6e 100644 --- a/drivers/char/i810_rng.c +++ b/drivers/char/i810_rng.c @@ -119,13 +119,6 @@ * The timer and the character device may be used simultaneously, if desired. - * FIXME: Currently only one open() of the character device is allowed. - If another user tries to open() the device, they will get an - -EBUSY error. Instead, this really should either support - multiple simultaneous users of the character device (not hard), - or simply block open() until the current user of the chrdev - calls close(). - * FIXME: support poll() * FIXME: should we be crazy and support mmap()? @@ -138,11 +131,16 @@ This will slow things down but guarantee that bad data is never passed upstream. + * Since the RNG is accessed from a timer as well as normal + kernel code, but not from interrupts, we use spin_lock_bh + in regular code, and spin_lock in the timer function, to + serialize access to the RNG hardware area. + ---------------------------------------------------------- Change history: - 0.6.2: + Version 0.6.2: * Clean up spinlocks. Since we don't have any interrupts to worry about, but we do have a timer to worry about, we use spin_lock_bh everywhere except the timer function @@ -152,6 +150,20 @@ * New timer interval sysctl * Clean up sysctl names + Version 0.9.0: + * Don't register a pci_driver, because we are really + using PCI bridge vendor/device ids, and someone + may want to register a driver for the bridge. (bug fix) + * Don't let the usage count go negative (bug fix) + * Clean up spinlocks (bug fix) + * Enable PCI device, if necessary (bug fix) + * iounmap on module unload (bug fix) + * If RNG chrdev is already in use when open(2) is called, + sleep until it is available. + * Remove redundant globals rng_allocated, rng_use_count + * Convert numeric globals to unsigned + * Module unload cleanup + */ @@ -166,6 +178,7 @@ #include #include #include +#include #include #include @@ -174,7 +187,7 @@ /* * core module and version information */ -#define RNG_VERSION "0.6.2" +#define RNG_VERSION "0.9.0" #define RNG_MODULE_NAME "i810_rng" #define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver " RNG_VERSION #define PFX RNG_MODULE_NAME ": " @@ -253,22 +266,24 @@ static void rng_run_fips_test (void); * various RNG status variables. they are globals * as we only support a single RNG device */ -static int rng_allocated; /* is someone using the RNG region? */ static int rng_hw_enabled; /* is the RNG h/w enabled? */ static int rng_timer_enabled; /* is the RNG timer enabled? */ -static int rng_use_count; /* number of times RNG has been enabled */ static int rng_trusted; /* does FIPS trust out data? */ static int rng_enabled_sysctl; /* sysctl for enabling/disabling RNG */ -static int rng_entropy = 8; /* number of entropy bits we submit to /dev/random */ -static int rng_entropy_sysctl; /* sysctl for changing entropy bits */ -static int rng_interval_sysctl; /* sysctl for changing timer interval */ +static unsigned int rng_entropy = 8; /* number of entropy bits we submit to /dev/random */ +static unsigned int rng_entropy_sysctl; /* sysctl for changing entropy bits */ +static unsigned int rng_interval_sysctl; /* sysctl for changing timer interval */ static int rng_have_mem_region; /* did we grab RNG region via request_mem_region? */ -static int rng_fips_counter; /* size of internal FIPS test data pool */ -static int rng_timer_len = RNG_DEF_TIMER_LEN; /* timer interval, in jiffies */ +static unsigned int rng_fips_counter; /* size of internal FIPS test data pool */ +static unsigned int rng_timer_len = RNG_DEF_TIMER_LEN; /* timer interval, in jiffies */ static void *rng_mem; /* token to our ioremap'd RNG register area */ static spinlock_t rng_lock = SPIN_LOCK_UNLOCKED; /* hardware lock */ static struct timer_list rng_timer; /* kernel timer for RNG hardware reads and tests */ -static int rng_open; /* boolean, 0 (false) if chrdev is closed, 1 (true) if open */ +static struct pci_dev *rng_pdev; /* Firmware Hub PCI device found during PCI probe */ +static struct semaphore rng_open_sem; /* Semaphore for serializing rng_open/release */ +static wait_queue_head_t rng_open_wait; /* Wait queue for serializing open/release */ +static int rng_open_mode; /* Open mode (we only allow reads) */ + /* * inlined helper functions for accessing RNG registers @@ -320,6 +335,8 @@ static void rng_timer_tick (unsigned long data) /* gimme some thermal noise, baby */ rng_data = rng_data_read (); + spin_unlock (&rng_lock); + /* * if RNG has been verified in the past, add * data just read to the /dev/random pool, @@ -333,6 +350,8 @@ static void rng_timer_tick (unsigned long data) rng_fips_test_store (rng_data); if (rng_fips_counter > RNG_FIPS_TEST_THRESHOLD) rng_run_fips_test (); + } else { + spin_unlock (&rng_lock); } /* run the timer again, if enabled */ @@ -340,9 +359,6 @@ static void rng_timer_tick (unsigned long data) rng_timer.expires = jiffies + rng_timer_len; add_timer (&rng_timer); } - - spin_unlock (&rng_lock); - } @@ -351,8 +367,8 @@ static void rng_timer_tick (unsigned long data) */ static int rng_enable (int enable) { - int rc = 0; - u8 hw_status; + int rc = 0, action = 0; + u8 hw_status, new_status; DPRINTK ("ENTER\n"); @@ -362,28 +378,36 @@ static int rng_enable (int enable) if (enable) { rng_hw_enabled = 1; - rng_use_count++; MOD_INC_USE_COUNT; } else { - rng_use_count--; - if (rng_use_count == 0) +#ifndef __alpha__ + if (GET_USE_COUNT (THIS_MODULE) > 0) + MOD_DEC_USE_COUNT; + if (GET_USE_COUNT (THIS_MODULE) == 0) rng_hw_enabled = 0; - MOD_DEC_USE_COUNT; +#endif } if (rng_hw_enabled && ((hw_status & RNG_ENABLED) == 0)) { rng_hwstatus_set (hw_status | RNG_ENABLED); - printk (KERN_INFO PFX "RNG h/w enabled\n"); + action = 1; } else if (!rng_hw_enabled && (hw_status & RNG_ENABLED)) { rng_hwstatus_set (hw_status & ~RNG_ENABLED); - printk (KERN_INFO PFX "RNG h/w disabled\n"); + action = 2; } + new_status = rng_hwstatus (); + spin_unlock_bh (&rng_lock); - if ((!!enable) != (!!(rng_hwstatus () & RNG_ENABLED))) { + if (action == 1) + printk (KERN_INFO PFX "RNG h/w enabled\n"); + else if (action == 2) + printk (KERN_INFO PFX "RNG h/w disabled\n"); + + if ((!!enable) != (!!(new_status & RNG_ENABLED))) { printk (KERN_ERR PFX "Unable to %sable the RNG\n", enable ? "en" : "dis"); rc = -EIO; @@ -406,15 +430,14 @@ static int rng_handle_sysctl_enable (ctl_table * table, int write, struct file * DPRINTK ("ENTER\n"); spin_lock_bh (&rng_lock); - rng_enabled_sysctl = enabled_save = rng_timer_enabled; + spin_unlock_bh (&rng_lock); rc = proc_dointvec (table, write, filp, buffer, lenp); - if (rc) { - spin_unlock_bh (&rng_lock); + if (rc) return rc; - } + spin_lock_bh (&rng_lock); if (enabled_save != rng_enabled_sysctl) { rng_timer_enabled = rng_enabled_sysctl; spin_unlock_bh (&rng_lock); @@ -591,53 +614,49 @@ static int rng_dev_open (struct inode *inode, struct file *filp) int rc = -EINVAL; if ((filp->f_mode & FMODE_READ) == 0) - goto err_out; + goto err_out_ret; if (filp->f_mode & FMODE_WRITE) - goto err_out; + goto err_out_ret; - spin_lock_bh (&rng_lock); - - /* only allow one open of this device, exit with -EBUSY if already open */ - /* FIXME: we should sleep on a semaphore here, unless O_NONBLOCK */ - if (rng_open) { - spin_unlock_bh (&rng_lock); - rc = -EBUSY; - goto err_out; + /* wait for device to become free */ + down (&rng_open_sem); + while (rng_open_mode & filp->f_mode) { + if (filp->f_flags & O_NONBLOCK) { + up (&rng_open_sem); + return -EWOULDBLOCK; + } + up (&rng_open_sem); + interruptible_sleep_on (&rng_open_wait); + if (signal_pending (current)) + return -ERESTARTSYS; + down (&rng_open_sem); } - rng_open = 1; - - spin_unlock_bh (&rng_lock); - - if (rng_enable(1) != 0) { - spin_lock_bh (&rng_lock); - rng_open = 0; - spin_unlock_bh (&rng_lock); + if (rng_enable (1)) { rc = -EIO; goto err_out; } + rng_open_mode |= filp->f_mode & (FMODE_READ | FMODE_WRITE); + up (&rng_open_sem); return 0; err_out: + up (&rng_open_sem); +err_out_ret: return rc; } static int rng_dev_release (struct inode *inode, struct file *filp) { + down(&rng_open_sem); - lock_kernel(); - if (rng_enable(0) != 0) { - unlock_kernel(); - return -EIO; - } - - spin_lock_bh (&rng_lock); - rng_open = 0; - spin_unlock_bh (&rng_lock); - unlock_kernel(); + rng_enable(0); + rng_open_mode &= (~filp->f_mode) & (FMODE_READ|FMODE_WRITE); + up (&rng_open_sem); + wake_up (&rng_open_wait); return 0; } @@ -705,19 +724,15 @@ read_loop: /* * rng_init_one - look for and attempt to init a single RNG */ -static int __init rng_init_one (struct pci_dev *dev, - const struct pci_device_id *id) +static int __init rng_init_one (struct pci_dev *dev) { int rc; u8 hw_status; DPRINTK ("ENTER\n"); - if (rng_allocated) { - printk (KERN_ERR PFX "this driver only supports one RNG\n"); - DPRINTK ("EXIT, returning -EBUSY\n"); - return -EBUSY; - } + if (pci_enable_device (dev)) + return -EIO; /* XXX currently fails, investigate who has our mem region */ if (request_mem_region (RNG_ADDR, RNG_ADDR_LEN, RNG_MODULE_NAME)) @@ -728,7 +743,7 @@ static int __init rng_init_one (struct pci_dev *dev, printk (KERN_ERR PFX "cannot ioremap RNG Memory\n"); DPRINTK ("EXIT, returning -EBUSY\n"); rc = -EBUSY; - goto err_out; + goto err_out_free_res; } /* Check for Intel 82802 */ @@ -737,11 +752,9 @@ static int __init rng_init_one (struct pci_dev *dev, printk (KERN_ERR PFX "RNG not detected\n"); DPRINTK ("EXIT, returning -ENODEV\n"); rc = -ENODEV; - goto err_out; + goto err_out_free_map; } - rng_allocated = 1; - if (rng_entropy < 0 || rng_entropy > RNG_MAX_ENTROPY) rng_entropy = RNG_MAX_ENTROPY; @@ -749,10 +762,11 @@ static int __init rng_init_one (struct pci_dev *dev, init_timer (&rng_timer); rng_timer.function = rng_timer_tick; + /* turn RNG h/w off, if it's on */ rc = rng_enable (0); if (rc) { printk (KERN_ERR PFX "cannot disable RNG, aborting\n"); - goto err_out; + goto err_out_free_map; } /* add sysctls */ @@ -761,9 +775,9 @@ static int __init rng_init_one (struct pci_dev *dev, DPRINTK ("EXIT, returning 0\n"); return 0; -err_out: - if (rng_mem) - iounmap (rng_mem); +err_out_free_map: + iounmap (rng_mem); +err_out_free_res: if (rng_have_mem_region) release_mem_region (RNG_ADDR, RNG_ADDR_LEN); return rc; @@ -772,6 +786,11 @@ err_out: /* * Data for PCI driver interface + * + * This data only exists for exporting the supported + * PCI ids via MODULE_DEVICE_TABLE. We do not actually + * register a pci_driver, because someone else might one day + * want to register another driver on the same PCI id. */ const static struct pci_device_id rng_pci_tbl[] __initdata = { { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, }, @@ -780,11 +799,6 @@ const static struct pci_device_id rng_pci_tbl[] __initdata = { }; MODULE_DEVICE_TABLE (pci, rng_pci_tbl); -static struct pci_driver rng_driver = { - name: RNG_MODULE_NAME, - id_table: rng_pci_tbl, - probe: rng_init_one, -}; MODULE_AUTHOR("Jeff Garzik, Matt Sottek"); MODULE_DESCRIPTION("Intel i8xx chipset Random Number Generator (RNG) driver"); @@ -813,23 +827,36 @@ static struct miscdevice rng_miscdev = { static int __init rng_init (void) { int rc; + struct pci_dev *pdev; DPRINTK ("ENTER\n"); - if (pci_register_driver (&rng_driver) < 1) { - DPRINTK ("EXIT, returning -ENODEV\n"); + init_MUTEX (&rng_open_sem); + init_waitqueue_head (&rng_open_wait); + + pdev = pci_find_device (0x8086, 0x2418, NULL); + if (!pdev) + pdev = pci_find_device (0x8086, 0x2428, NULL); + if (!pdev) return -ENODEV; - } + + rc = rng_init_one (pdev); + if (rc) + return rc; rc = misc_register (&rng_miscdev); if (rc) { - pci_unregister_driver (&rng_driver); + iounmap (rng_mem); + if (rng_have_mem_region) + release_mem_region (RNG_ADDR, RNG_ADDR_LEN); DPRINTK ("EXIT, returning %d\n", rc); return rc; } printk (KERN_INFO RNG_DRIVER_NAME " loaded\n"); + rng_pdev = pdev; + DPRINTK ("EXIT, returning 0\n"); return 0; } @@ -842,18 +869,17 @@ static void __exit rng_cleanup (void) { DPRINTK ("ENTER\n"); - del_timer_sync (&rng_timer); + assert (rng_timer_enabled == 0); + assert (rng_hw_enabled == 0); + + misc_deregister (&rng_miscdev); rng_sysctl (0); - pci_unregister_driver (&rng_driver); + iounmap (rng_mem); if (rng_have_mem_region) release_mem_region (RNG_ADDR, RNG_ADDR_LEN); - rng_hwstatus_set (rng_hwstatus() & ~RNG_ENABLED); - - misc_deregister (&rng_miscdev); - DPRINTK ("EXIT\n"); } diff --git a/drivers/char/sh-sci.c b/drivers/char/sh-sci.c index 0605674e0755..8f0178d9b71e 100644 --- a/drivers/char/sh-sci.c +++ b/drivers/char/sh-sci.c @@ -90,6 +90,8 @@ int sci_debug = 0; MODULE_PARM(sci_debug, "i"); #endif +#define dprintk(x...) do { if (sci_debug) printk(x); } while(0) + static void put_char(struct sci_port *port, char c) { unsigned long flags; @@ -329,6 +331,9 @@ static void sci_set_baud(struct sci_port *port, int baud) case 38400: t = BPS_38400; break; + case 57600: + t = BPS_57600; + break; default: printk(KERN_INFO "sci: unsupported baud rate: %d, using 115200 instead.\n", baud); case 115200: @@ -341,6 +346,8 @@ static void sci_set_baud(struct sci_port *port, int baud) if(t >= 256) { sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1); t >>= 2; + } else { + sci_out(port, SCSMR, sci_in(port, SCSMR) & ~3); } sci_out(port, SCBRR, t); udelay((1000000+(baud-1)) / baud); /* Wait one bit interval */ @@ -374,10 +381,9 @@ static void sci_set_termios_cflag(struct sci_port *port, int cflag, int baud) if (cflag & CSTOPB) smr_val |= 0x08; sci_out(port, SCSMR, smr_val); + sci_set_baud(port, baud); port->init_pins(port, cflag); - - sci_set_baud(port, baud); sci_out(port, SCSCR, SCSCR_INIT(port)); } @@ -528,13 +534,28 @@ static inline void sci_receive_chars(struct sci_port *port) if (count == 0) break; - for (i=0; iflip.char_buf_ptr[i] = sci_in(port, SCxRDR); + if (port->type == PORT_SCI) { + tty->flip.char_buf_ptr[0] = sci_in(port, SCxRDR); + tty->flip.flag_buf_ptr[0] = TTY_NORMAL; + } else { + for (i=0; iflip.char_buf_ptr[i] = sci_in(port, SCxRDR); + status = sci_in(port, SCxSR); + if (status&SCxSR_FER(port)) { + tty->flip.flag_buf_ptr[i] = TTY_FRAME; + dprintk("sci: frame error\n"); + } else if (status&SCxSR_PER(port)) { + tty->flip.flag_buf_ptr[i] = TTY_PARITY; + dprintk("sci: parity error\n"); + } else { + tty->flip.flag_buf_ptr[i] = TTY_NORMAL; + } + } + } + sci_in(port, SCxSR); /* dummy read */ sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); - memset(tty->flip.flag_buf_ptr, TTY_NORMAL, count); - /* Update the kernel buffer end */ tty->flip.count += count; tty->flip.char_buf_ptr += count; @@ -549,6 +570,82 @@ static inline void sci_receive_chars(struct sci_port *port) tty_flip_buffer_push(tty); } +static inline int sci_handle_errors(struct sci_port *port) +{ + int copied = 0; + unsigned short status = sci_in(port, SCxSR); + struct tty_struct *tty = port->gs.tty; + + if (status&SCxSR_ORER(port) && tty->flip.countflip.flag_buf_ptr++ = TTY_OVERRUN; + dprintk("sci: overrun error\n"); + } + + if (status&SCxSR_FER(port) && tty->flip.countflip.flag_buf_ptr++ = TTY_BREAK; + dprintk("sci: BREAK detected\n"); + } + else { + /* frame error */ + copied++; + *tty->flip.flag_buf_ptr++ = TTY_FRAME; + dprintk("sci: frame error\n"); + } + } + + if (status&SCxSR_PER(port) && tty->flip.countflip.flag_buf_ptr++ = TTY_PARITY; + dprintk("sci: parity error\n"); + } + + if (copied) { + tty->flip.count += copied; + tty_flip_buffer_push(tty); + } + + return copied; +} + +static inline int sci_handle_breaks(struct sci_port *port) +{ + int copied = 0; + unsigned short status = sci_in(port, SCxSR); + struct tty_struct *tty = port->gs.tty; + + if (status&SCxSR_BRK(port) && tty->flip.countflip.flag_buf_ptr++ = TTY_BREAK; + dprintk("sci: BREAK detected\n"); + } + +#if defined(CONFIG_CPU_SUBTYPE_SH7750) + /* XXX: Handle SCIF overrun error */ + if (port->type == PORT_SCIF && (ctrl_inw(SCLSR2) & SCIF_ORER) != 0) { + ctrl_outw(0, SCLSR2); + if(tty->flip.countflip.flag_buf_ptr++ = TTY_OVERRUN; + dprintk("sci: overrun error\n"); + } + } +#endif + + if (copied) { + tty->flip.count += copied; + tty_flip_buffer_push(tty); + } + + return copied; +} + static void sci_rx_interrupt(int irq, void *ptr, struct pt_regs *regs) { struct sci_port *port = ptr; @@ -577,13 +674,31 @@ static void sci_er_interrupt(int irq, void *ptr, struct pt_regs *regs) struct sci_port *port = ptr; /* Handle errors */ - if (sci_in(port, SCxSR) & SCxSR_ERRORS(port)) - sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); + if (port->type == PORT_SCI) { + if(sci_handle_errors(port)) { + /* discard character in rx buffer */ + sci_in(port, SCxSR); + sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); + } + } + else + sci_rx_interrupt(irq, ptr, regs); + + sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); /* Kick the transmission */ sci_tx_interrupt(irq, ptr, regs); } +static void sci_br_interrupt(int irq, void *ptr, struct pt_regs *regs) +{ + struct sci_port *port = ptr; + + /* Handle BREAKs */ + sci_handle_breaks(port); + sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port)); +} + static void do_softint(void *private_) { struct sci_port *port = (struct sci_port *) private_; @@ -983,8 +1098,9 @@ int __init sci_init(void) { struct sci_port *port; int i, j; - void (*handlers[3])(int irq, void *ptr, struct pt_regs *regs) = { - sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt + void (*handlers[4])(int irq, void *ptr, struct pt_regs *regs) = { + sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt, + sci_br_interrupt, }; printk("SuperH SCI(F) driver initialized\n"); @@ -993,7 +1109,8 @@ int __init sci_init(void) port = &sci_ports[j]; printk("ttySC%d at 0x%08x is a %s\n", j, port->base, (port->type == PORT_SCI) ? "SCI" : "SCIF"); - for (i=0; i<3; i++) { + for (i=0; i<4; i++) { + if (!port->irqs[i]) continue; if (request_irq(port->irqs[i], handlers[i], SA_INTERRUPT, "sci", port)) { printk(KERN_ERR "sci: Cannot allocate irq.\n"); @@ -1001,7 +1118,6 @@ int __init sci_init(void) } } } - /* XXX: How about BRI interrupt?? */ sci_init_drivers(); diff --git a/drivers/char/sh-sci.h b/drivers/char/sh-sci.h index c38e97c52c1e..6f99a2b5f1ad 100644 --- a/drivers/char/sh-sci.h +++ b/drivers/char/sh-sci.h @@ -20,11 +20,11 @@ #define SCIx_RXI_IRQ 1 #define SCIx_TXI_IRQ 2 -/* ERI, RXI, TXI, */ -#define SCI_IRQS { 23, 24, 25 } -#define SH3_SCIF_IRQS { 56, 57, 59 } -#define SH3_IRDA_IRQS { 52, 53, 55 } -#define SH4_SCIF_IRQS { 40, 41, 43 } +/* ERI, RXI, TXI, BRI */ +#define SCI_IRQS { 23, 24, 25, 0 } +#define SH3_SCIF_IRQS { 56, 57, 59, 58 } +#define SH3_IRDA_IRQS { 52, 53, 55, 54 } +#define SH4_SCIF_IRQS { 40, 41, 43, 42 } #if defined(CONFIG_CPU_SUBTYPE_SH7708) # define SCI_NPORTS 1 @@ -54,6 +54,7 @@ # define SCSPTR1 0xffe0001c /* 8 bit SCI */ # define SCSPTR2 0xFFE80020 /* 16 bit SCIF */ # define SCLSR2 0xFFE80024 /* 16 bit SCIF */ +# define SCIF_ORER 0x0001 /* overrun error bit */ # define SCSCR_INIT(port) (((port)->type == PORT_SCI) ? \ 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \ 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ ) @@ -102,25 +103,40 @@ # define SCxSR_ERRORS(port) SCI_ERRORS # define SCxSR_RDxF(port) SCI_RDRF # define SCxSR_TDxE(port) SCI_TDRE +# define SCxSR_ORER(port) SCI_ORER +# define SCxSR_FER(port) SCI_FER +# define SCxSR_PER(port) SCI_PER +# define SCxSR_BRK(port) 0x00 # define SCxSR_RDxF_CLEAR(port) 0xbc # define SCxSR_ERROR_CLEAR(port) 0xc4 # define SCxSR_TDxE_CLEAR(port) 0x78 +# define SCxSR_BREAK_CLEAR(port) 0xc4 #elif defined(SCIF_ONLY) # define SCxSR_TEND(port) SCIF_TEND # define SCxSR_ERRORS(port) SCIF_ERRORS # define SCxSR_RDxF(port) SCIF_RDF # define SCxSR_TDxE(port) SCIF_TDFE +# define SCxSR_ORER(port) 0x0000 +# define SCxSR_FER(port) SCIF_FER +# define SCxSR_PER(port) SCIF_PER +# define SCxSR_BRK(port) SCIF_BRK # define SCxSR_RDxF_CLEAR(port) 0x00fc -# define SCxSR_ERROR_CLEAR(port) 0x0063 +# define SCxSR_ERROR_CLEAR(port) 0x0073 # define SCxSR_TDxE_CLEAR(port) 0x00df +# define SCxSR_BREAK_CLEAR(port) 0x00e3 #else # define SCxSR_TEND(port) (((port)->type == PORT_SCI) ? SCI_TEND : SCIF_TEND) # define SCxSR_ERRORS(port) (((port)->type == PORT_SCI) ? SCI_ERRORS : SCIF_ERRORS) # define SCxSR_RDxF(port) (((port)->type == PORT_SCI) ? SCI_RDRF : SCIF_RDF) # define SCxSR_TDxE(port) (((port)->type == PORT_SCI) ? SCI_TDRE : SCIF_TDFE) +# define SCxSR_ORER(port) (((port)->type == PORT_SCI) ? SCI_ORER : 0x0000) +# define SCxSR_FER(port) (((port)->type == PORT_SCI) ? SCI_FER : SCIF_FER) +# define SCxSR_PER(port) (((port)->type == PORT_SCI) ? SCI_PER : SCIF_PER) +# define SCxSR_BRK(port) (((port)->type == PORT_SCI) ? 0x00 : SCIF_BRK) # define SCxSR_RDxF_CLEAR(port) (((port)->type == PORT_SCI) ? 0xbc : 0x00fc) -# define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0063) +# define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0073) # define SCxSR_TDxE_CLEAR(port) (((port)->type == PORT_SCI) ? 0x78 : 0x00df) +# define SCxSR_BREAK_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x00e3) #endif /* SCFCR */ @@ -169,7 +185,7 @@ struct sci_port { struct gs_port gs; int type; unsigned int base; - unsigned char irqs[3]; /* ERI, RXI, TXI */ + unsigned char irqs[4]; /* ERI, RXI, TXI, BRI */ void (*init_pins)(struct sci_port* port, unsigned int cflag); unsigned int old_cflag; struct async_icount icount; @@ -248,6 +264,34 @@ SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16) #define sci_in(port, reg) sci_##reg##_in(port) #define sci_out(port, reg, value) sci_##reg##_out(port, value) +#if defined(CONFIG_CPU_SUBTYPE_SH7708) +static inline int sci_rxd_in(struct sci_port *port) +{ + if (port->base == 0xfffffe80) + return ctrl_inb(SCSPTR)&0x01 ? 1 : 0; /* SCI */ + return 1; +} +#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) +static inline int sci_rxd_in(struct sci_port *port) +{ + if (port->base == 0xfffffe80) + return ctrl_inb(SCPDR)&0x01 ? 1 : 0; /* SCI */ + if (port->base == 0xa4000150) + return ctrl_inb(SCPDR)&0x10 ? 1 : 0; /* SCIF */ + if (port->base == 0xa4000140) + return ctrl_inb(SCPDR)&0x04 ? 1 : 0; /* IRDA */ + return 1; +} +#elif defined(CONFIG_CPU_SUBTYPE_SH7750) +static inline int sci_rxd_in(struct sci_port *port) +{ + if (port->base == 0xffe00000) + return ctrl_inb(SCSPTR1)&0x01 ? 1 : 0; /* SCI */ + if (port->base == 0xffe80000) + return ctrl_inw(SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */ + return 1; +} +#endif /* * Values for the BitRate Register (SCBRR) @@ -289,5 +333,6 @@ SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16) #define BPS_9600 SCBRR_VALUE(9600) #define BPS_19200 SCBRR_VALUE(19200) #define BPS_38400 SCBRR_VALUE(38400) +#define BPS_57600 SCBRR_VALUE(57600) #define BPS_115200 SCBRR_VALUE(115200) diff --git a/drivers/ide/ide-pci.c b/drivers/ide/ide-pci.c index 549e3c4dbe35..561b1c3cf898 100644 --- a/drivers/ide/ide-pci.c +++ b/drivers/ide/ide-pci.c @@ -493,6 +493,7 @@ static void __init ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t * byte tmp = 0; ide_hwif_t *hwif, *mate = NULL; unsigned int class_rev; + int pci_class_ide; #ifdef CONFIG_IDEDMA_AUTO autodma = 1; @@ -538,7 +539,8 @@ check_if_enabled: * Can we trust the reported IRQ? */ pciirq = dev->irq; - if ((dev->class & ~(0xff)) != (PCI_CLASS_STORAGE_IDE << 8)) { + pci_class_ide = ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE); + if (!pci_class_ide) { printk("%s: not 100%% native mode: will probe irqs later\n", d->name); /* * This allows offboard ide-pci cards the enable a BIOS, @@ -548,11 +550,17 @@ check_if_enabled: */ pciirq = (d->init_chipset) ? d->init_chipset(dev, d->name) : ide_special_settings(dev, d->name); } else if (tried_config) { - printk("%s: will probe irqs later\n", d->name); + printk(KERN_INFO "%s: will probe irqs later\n", d->name); pciirq = 0; } else if (!pciirq) { - printk("%s: bad irq (%d): will probe later\n", d->name, pciirq); - pciirq = 0; + if (pci_class_ide) { + /* this is the normal path for most IDE devices */ + if (d->init_chipset) + pciirq = d->init_chipset(dev, d->name); + else + printk(KERN_INFO "%s standard IDE storage device detected\n", d->name); + } else + printk(KERN_WARNING "%s: bad irq (0): will probe later\n", d->name); } else { if (d->init_chipset) (void) d->init_chipset(dev, d->name); diff --git a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c index b33e7270c5dd..1c1b68ff2503 100644 --- a/drivers/ide/via82cxxx.c +++ b/drivers/ide/via82cxxx.c @@ -1,5 +1,5 @@ /* - * $Id: via82cxxx.c,v 2.1b 2000/09/20 23:19:60 vojtech Exp $ + * $Id: via82cxxx.c,v 2.1d 2000/10/01 10:01:00 vojtech Exp $ * * Copyright (c) 2000 Vojtech Pavlik * @@ -192,7 +192,7 @@ static int via_get_info(char *buffer, char **addr, off_t offset, int count) via_print("----------VIA BusMastering IDE Configuration----------------"); - via_print("Driver Version: 2.1b"); + via_print("Driver Version: 2.1d"); pci_read_config_byte(isa_dev, PCI_REVISION_ID, &t); via_print("South Bridge: VIA %s rev %#x", via_isa_bridges[via_config].name, t); @@ -334,7 +334,7 @@ static int via_set_speed(ide_drive_t *drive, byte speed) */ switch(via_isa_bridges[via_config].speed) { - case XFER_UDMA_2: t = via_timing[i].udma ? (0x60 | (FIT(via_timing[i].udma, 2, 5) - 2)) : 0x03; break; + case XFER_UDMA_2: t = via_timing[i].udma ? (0xe0 | (FIT(via_timing[i].udma, 2, 5) - 2)) : 0x03; break; case XFER_UDMA_4: t = via_timing[i].udma ? (0xe8 | (FIT(via_timing[i].udma, 2, 9) - 2)) : 0x0f; break; } @@ -588,7 +588,7 @@ unsigned int __init pci_init_via82cxxx(struct pci_dev *dev, const char *name) unsigned int __init ata66_via82cxxx(ide_hwif_t *hwif) { - return ((via_enabled && via_ata66) >> hwif->channel) & 1; + return ((via_enabled & via_ata66) >> hwif->channel) & 1; } void __init ide_init_via82cxxx(ide_hwif_t *hwif) diff --git a/drivers/md/Config.in b/drivers/md/Config.in index f7c23cd87aa2..565055a68faa 100644 --- a/drivers/md/Config.in +++ b/drivers/md/Config.in @@ -4,7 +4,9 @@ mainmenu_option next_comment comment 'Multi-device support (RAID and LVM)' -tristate 'Multiple devices driver support (RAID and LVM)' CONFIG_BLK_DEV_MD +bool 'Multiple devices driver support (RAID and LVM)' CONFIG_MD + +dep_tristate ' RAID support' CONFIG_BLK_DEV_MD $CONFIG_MD dep_tristate ' Linear (append) mode' CONFIG_MD_LINEAR $CONFIG_BLK_DEV_MD dep_tristate ' RAID-0 (striping) mode' CONFIG_MD_RAID0 $CONFIG_BLK_DEV_MD dep_tristate ' RAID-1 (mirroring) mode' CONFIG_MD_RAID1 $CONFIG_BLK_DEV_MD @@ -14,7 +16,7 @@ if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_RAID0" = "y" -o "$CONFIG_MD_RAID1" bool ' Auto Detect support' CONFIG_AUTODETECT_RAID fi -dep_tristate 'Logical volume manager (LVM) support' CONFIG_BLK_DEV_LVM $CONFIG_BLK_DEV_MD +dep_tristate ' Logical volume manager (LVM) support' CONFIG_BLK_DEV_LVM $CONFIG_MD dep_mbool ' LVM information in proc filesystem' CONFIG_LVM_PROC_FS $CONFIG_BLK_DEV_LVM endmenu diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index da8ba5e77276..ba6d5839abec 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -130,15 +130,15 @@ static const char *invalid_pcb_msg = #define INVALID_PCB_MSG(len) \ printk(invalid_pcb_msg, (len),filename,__FUNCTION__,__LINE__) -static char *search_msg __initdata = "%s: Looking for 3c505 adapter at address %#x..."; +static char search_msg[] __initdata = "%s: Looking for 3c505 adapter at address %#x..."; -static char *stilllooking_msg __initdata = "still looking..."; +static char stilllooking_msg[] __initdata = "still looking..."; -static char *found_msg __initdata = "found.\n"; +static char found_msg[] __initdata = "found.\n"; -static char *notfound_msg __initdata = "not found (reason = %d)\n"; +static char notfound_msg[] __initdata = "not found (reason = %d)\n"; -static char *couldnot_msg __initdata = "%s: 3c505 not found\n"; +static char couldnot_msg[] __initdata = "%s: 3c505 not found\n"; /********************************************************* * diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index b3a67b380378..8ccc6ebf050c 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -393,22 +393,22 @@ static inline void netif_start_queue(struct net_device *dev) #define DEF_TRACE 0 #define DEF_STAT (2 * TICKS_PER_SEC) -static int link[ACE_MAX_MOD_PARMS] = {0, }; -static int trace[ACE_MAX_MOD_PARMS] = {0, }; -static int tx_coal_tick[ACE_MAX_MOD_PARMS] = {0, }; -static int rx_coal_tick[ACE_MAX_MOD_PARMS] = {0, }; -static int max_tx_desc[ACE_MAX_MOD_PARMS] = {0, }; -static int max_rx_desc[ACE_MAX_MOD_PARMS] = {0, }; -static int tx_ratio[ACE_MAX_MOD_PARMS] = {0, }; +static int link[ACE_MAX_MOD_PARMS]; +static int trace[ACE_MAX_MOD_PARMS]; +static int tx_coal_tick[ACE_MAX_MOD_PARMS]; +static int rx_coal_tick[ACE_MAX_MOD_PARMS]; +static int max_tx_desc[ACE_MAX_MOD_PARMS]; +static int max_rx_desc[ACE_MAX_MOD_PARMS]; +static int tx_ratio[ACE_MAX_MOD_PARMS]; static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1}; -static const char __initdata *version = +static char version[] __initdata = "acenic.c: v0.47 09/18/2000 Jes Sorensen, linux-acenic@SunSITE.auc.dk\n" " http://home.cern.ch/~jes/gige/acenic.html\n"; -static struct net_device *root_dev = NULL; +static struct net_device *root_dev; -static int probed __initdata = 0; +static int probed __initdata; #ifdef NEW_NETINIT diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index fd00d7c4b9f3..dda42edd84bb 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -1742,9 +1742,6 @@ static int hamachi_close(struct net_device *dev) hmp->rx_ring[i].status_n_length = 0; hmp->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */ if (hmp->rx_skbuff[i]) { -#if LINUX_VERSION_CODE < 0x20100 - hmp->rx_skbuff[i]->free = 1; -#endif dev_kfree_skb(hmp->rx_skbuff[i]); } hmp->rx_skbuff[i] = 0; @@ -1777,10 +1774,8 @@ static struct net_device_stats *hamachi_get_stats(struct net_device *dev) */ /* hmp->stats.tx_packets = readl(ioaddr + 0x000); */ -#if LINUX_VERSION_CODE >= 0x20119 hmp->stats.rx_bytes = readl(ioaddr + 0x330); /* Total Uni+Brd+Multi */ hmp->stats.tx_bytes = readl(ioaddr + 0x3B0); /* Total Uni+Brd+Multi */ -#endif hmp->stats.multicast = readl(ioaddr + 0x320); /* Multicast Rx */ hmp->stats.rx_length_errors = readl(ioaddr + 0x368); /* Over+Undersized */ diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index c3dc74c937c7..d12a9e150504 100644 --- a/drivers/net/rrunner.c +++ b/drivers/net/rrunner.c @@ -102,7 +102,7 @@ static inline void netif_start_queue(struct net_device *dev) * stack will need to know about I/O vectors or something similar. */ -static const char __initdata *version = "rrunner.c: v0.22 03/01/2000 Jes Sorensen (Jes.Sorensen@cern.ch)\n"; +static char version[] __initdata = "rrunner.c: v0.22 03/01/2000 Jes Sorensen (Jes.Sorensen@cern.ch)\n"; static struct net_device *root_dev = NULL; diff --git a/drivers/net/wan/comx-hw-comx.c b/drivers/net/wan/comx-hw-comx.c index 0031cad3a60f..8ace26d886a6 100644 --- a/drivers/net/wan/comx-hw-comx.c +++ b/drivers/net/wan/comx-hw-comx.c @@ -46,9 +46,6 @@ #define VERSION "0.86" -#include -#include -#include #include #include #include @@ -57,6 +54,9 @@ #include #include #include +#include +#include +#include #include "comx.h" #include "comxhw.h" diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index 130f6b27d830..5ab238eb0002 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -303,8 +303,7 @@ static void chardev_channel_init(struct channel_data *chan); static char *chrdev_setup_rx(struct channel_data *channel, int size); static int chrdev_rx_done(struct channel_data *channel); static int chrdev_tx_done(struct channel_data *channel, int size); -static long long cosa_lseek(struct file *file, - long long offset, int origin); +static loff_t cosa_lseek(struct file *file, loff_t offset, int origin); static ssize_t cosa_read(struct file *file, char *buf, size_t count, loff_t *ppos); static ssize_t cosa_write(struct file *file, @@ -783,8 +782,7 @@ static void chardev_channel_init(struct channel_data *chan) init_MUTEX(&chan->wsem); } -static long long cosa_lseek(struct file * file, - long long offset, int origin) +static loff_t cosa_lseek(struct file * file, loff_t offset, int origin) { return -ESPIPE; } @@ -1212,7 +1210,7 @@ static int cosa_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, { int rv; struct channel_data *chan = (struct channel_data *)dev->priv; - rv = cosa_ioctl_common(chan->cosa, chan, cmd, (int)ifr->ifr_data); + rv = cosa_ioctl_common(chan->cosa, chan, cmd, (unsigned long)ifr->ifr_data); if (rv == -ENOIOCTLCMD) { return sppp_do_ioctl(dev, ifr, cmd); } diff --git a/drivers/pci/names.c b/drivers/pci/names.c index a6114e789190..4e047d691b26 100644 --- a/drivers/pci/names.c +++ b/drivers/pci/names.c @@ -131,4 +131,5 @@ pci_class_name(u32 class) return NULL; } -#endif +#endif /* CONFIG_PCI_NAMES */ + diff --git a/drivers/usb/hid.c b/drivers/usb/hid.c index 6339ba6f18d1..db4df7931fda 100644 --- a/drivers/usb/hid.c +++ b/drivers/usb/hid.c @@ -1231,6 +1231,7 @@ static int hid_submit_out(struct hid_device *hid) hid->urbout.transfer_buffer_length = hid->out[hid->outtail].dr.length; hid->urbout.transfer_buffer = hid->out[hid->outtail].buffer; hid->urbout.setup_packet = (void *) &(hid->out[hid->outtail].dr); + hid->urbout.dev = hid->dev; if (usb_submit_urb(&hid->urbout)) { err("usb_submit_urb(out) failed"); @@ -1288,7 +1289,9 @@ static int hid_open(struct input_dev *dev) if (hid->open++) return 0; - if (usb_submit_urb(&hid->urb)) + hid->urb.dev = hid->dev; + + if (usb_submit_urb(&hid->urb)) return -EIO; return 0; diff --git a/drivers/usb/pegasus.c b/drivers/usb/pegasus.c index 5096393f0bf4..a58c29c8ef51 100644 --- a/drivers/usb/pegasus.c +++ b/drivers/usb/pegasus.c @@ -617,6 +617,7 @@ static void read_bulk_callback( struct urb *urb ) pegasus->stats.rx_bytes += pkt_len; goon: + pegasus->rx_urb.dev = pegasus->usb; if ( (res = usb_submit_urb(&pegasus->rx_urb)) ) warn( __FUNCTION__ " failed submint rx_urb %d", res); } @@ -698,6 +699,7 @@ static int pegasus_start_xmit( struct sk_buff *skb, struct net_device *net ) pegasus->tx_urb.transfer_buffer_length = count; pegasus->tx_urb.transfer_flags |= USB_ASYNC_UNLINK; + pegasus->tx_urb.dev = pegasus->usb; if ((res = usb_submit_urb(&pegasus->tx_urb))) { warn("failed tx_urb %d", res); pegasus->stats.tx_errors++; @@ -737,9 +739,11 @@ static int pegasus_open(struct net_device *net) err("can't start_net() - %d", res); return -EIO; } + pegasus->rx_urb.dev = pegasus->usb; if ( (res = usb_submit_urb(&pegasus->rx_urb)) ) warn( __FUNCTION__ " failed rx_urb %d", res ); #ifdef PEGASUS_USE_INTR + pegasus->intr_urb.dev = pegasus->usb; if ( (res = usb_submit_urb(&pegasus->intr_urb)) ) warn( __FUNCTION__ " failed intr_urb %d", res); #endif @@ -894,6 +898,7 @@ static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum ) init_MUTEX( &pegasus-> ctrl_sem ); init_waitqueue_head( &pegasus->ctrl_wait ); + usb_inc_dev_use (dev); pegasus->usb = dev; pegasus->net = net; @@ -951,11 +956,7 @@ static void pegasus_disconnect( struct usb_device *dev, void *ptr ) netif_stop_queue( pegasus->net ); unregister_netdev( pegasus->net ); - usb_unlink_urb( &pegasus->rx_urb ); - usb_unlink_urb( &pegasus->tx_urb ); - usb_unlink_urb( &pegasus->ctrl_urb ); - usb_unlink_urb( &pegasus->intr_urb ); - + usb_dec_dev_use (pegasus->usb); kfree( pegasus ); pegasus = NULL; diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c index ba3fb026f55e..860c381584f2 100644 --- a/drivers/usb/storage/freecom.c +++ b/drivers/usb/storage/freecom.c @@ -28,7 +28,6 @@ * (http://www.freecom.de/) */ -#include #include "transport.h" #include "protocol.h" #include "usb.h" diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 4172d5777f20..e5420ff6b218 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -221,7 +221,6 @@ static int device_reset( Scsi_Cmnd *srb ) static int bus_reset( Scsi_Cmnd *srb ) { struct us_data *us = (struct us_data *)srb->host->hostdata[0]; - int result; int i; /* we use the usb_reset_device() function to handle this for us */ diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c index 36d1c743bbee..ececaa03b1f4 100644 --- a/drivers/usb/usb.c +++ b/drivers/usb/usb.c @@ -705,7 +705,7 @@ static void usb_find_drivers(struct usb_device *dev) dbg("unhandled interfaces on device"); if (!claimed) { - warn("USB device %d (prod/vend 0x%x/0x%x) is not claimed by any active driver.", + warn("USB device %d (vend/prod 0x%x/0x%x) is not claimed by any active driver.", dev->devnum, dev->descriptor.idVendor, dev->descriptor.idProduct); @@ -1205,7 +1205,7 @@ int usb_parse_configuration(struct usb_device *dev, struct usb_config_descriptor config->interface = (struct usb_interface *) kmalloc(config->bNumInterfaces * sizeof(struct usb_interface), GFP_KERNEL); - dbg("kmalloc IF %p, numif %i",config->interface,config->bNumInterfaces); + dbg("kmalloc IF %p, numif %i", config->interface, config->bNumInterfaces); if (!config->interface) { err("out of memory"); return -1; @@ -1467,7 +1467,7 @@ void usb_connect(struct usb_device *dev) int devnum; // FIXME needs locking for SMP!! /* why? this is called only from the hub thread, - * which hopefully doesn't run on multiple CPU's simulatenously 8-) + * which hopefully doesn't run on multiple CPU's simultaneously 8-) */ dev->descriptor.bMaxPacketSize0 = 8; /* Start off at 8 bytes */ devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1); @@ -1876,7 +1876,8 @@ int usb_new_device(struct usb_device *dev) err = usb_set_address(dev); if (err < 0) { - err("USB device not accepting new address (error=%d)", err); + err("USB device not accepting new address=%d (error=%d)", + dev->devnum, err); clear_bit(dev->devnum, &dev->bus->devmap.devicemap); dev->devnum = -1; return 1; @@ -1889,7 +1890,7 @@ int usb_new_device(struct usb_device *dev) if (err < 0) err("USB device not responding, giving up (error=%d)", err); else - err("USB device descriptor short read (expected %i, got %i)",8,err); + err("USB device descriptor short read (expected %i, got %i)", 8, err); clear_bit(dev->devnum, &dev->bus->devmap.devicemap); dev->devnum = -1; return 1; @@ -1902,7 +1903,8 @@ int usb_new_device(struct usb_device *dev) if (err < 0) err("unable to get device descriptor (error=%d)", err); else - err("USB device descriptor short read (expected %i, got %i)", sizeof(dev->descriptor), err); + err("USB device descriptor short read (expected %i, got %i)", + sizeof(dev->descriptor), err); clear_bit(dev->devnum, &dev->bus->devmap.devicemap); dev->devnum = -1; @@ -1911,7 +1913,8 @@ int usb_new_device(struct usb_device *dev) err = usb_get_configuration(dev); if (err < 0) { - err("unable to get configuration (error=%d)", err); + err("unable to get device %d configuration (error=%d)", + dev->devnum, err); usb_destroy_configuration(dev); clear_bit(dev->devnum, &dev->bus->devmap.devicemap); dev->devnum = -1; @@ -1921,7 +1924,8 @@ int usb_new_device(struct usb_device *dev) /* we set the default configuration here */ err = usb_set_configuration(dev, dev->config[0].bConfigurationValue); if (err) { - err("failed to set default configuration (error=%d)", err); + err("failed to set device %d default configuration (error=%d)", + dev->devnum, err); clear_bit(dev->devnum, &dev->bus->devmap.devicemap); dev->devnum = -1; return 1; diff --git a/fs/Makefile b/fs/Makefile index 2fbec78cb7d0..5bed63c84b57 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -17,7 +17,7 @@ obj-y := open.o read_write.o devices.o file_table.o buffer.o \ filesystems.o ifeq ($(CONFIG_QUOTA),y) -obj=ADy += dquot.o +obj-y += dquot.o else obj-y += noquot.o endif diff --git a/fs/buffer.c b/fs/buffer.c index f00018a3a772..145e11793bd5 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -706,7 +706,9 @@ void set_blocksize(kdev_t dev, int size) static void refill_freelist(int size) { if (!grow_buffers(size)) { - try_to_free_pages(GFP_BUFFER); + wakeup_bdflush(1); + current->policy |= SCHED_YIELD; + schedule(); } } @@ -859,6 +861,7 @@ repeat: int balance_dirty_state(kdev_t dev) { unsigned long dirty, tot, hard_dirty_limit, soft_dirty_limit; + int shortage; dirty = size_buffers_type[BUF_DIRTY] >> PAGE_SHIFT; tot = nr_free_buffer_pages(); @@ -869,21 +872,21 @@ int balance_dirty_state(kdev_t dev) /* First, check for the "real" dirty limit. */ if (dirty > soft_dirty_limit) { - if (dirty > hard_dirty_limit || inactive_shortage()) + if (dirty > hard_dirty_limit) return 1; return 0; } /* - * Then, make sure the number of inactive pages won't overwhelm - * page replacement ... this should avoid stalls. + * If we are about to get low on free pages and + * cleaning the inactive_dirty pages would help + * fix this, wake up bdflush. */ - if (nr_inactive_dirty_pages > - nr_free_pages() + nr_inactive_clean_pages()) { - if (free_shortage() > freepages.min) - return 1; + shortage = free_shortage(); + if (shortage && nr_inactive_dirty_pages > shortage && + nr_inactive_dirty_pages > freepages.high) return 0; - } + return -1; } @@ -1807,9 +1810,9 @@ int block_truncate_page(struct address_space *mapping, loff_t from, get_block_t if (Page_Uptodate(page)) set_bit(BH_Uptodate, &bh->b_state); + bh->b_end_io = end_buffer_io_sync; if (!buffer_uptodate(bh)) { err = -EIO; - bh->b_end_io = end_buffer_io_sync; ll_rw_block(READ, 1, &bh); wait_on_buffer(bh); /* Uhhuh. Read error. Complain and punt. */ @@ -2234,6 +2237,7 @@ static int grow_buffers(int size) return 1; no_buffer_head: + UnlockPage(page); page_cache_release(page); out: return 0; @@ -2663,9 +2667,8 @@ int bdflush(void *sem) CHECK_EMERGENCY_SYNC flushed = flush_dirty_buffers(0); - if (nr_inactive_dirty_pages > nr_free_pages() + - nr_inactive_clean_pages()) - flushed += page_launder(GFP_KSWAPD, 0); + if (free_shortage()) + flushed += page_launder(GFP_BUFFER, 0); /* If wakeup_bdflush will wakeup us after our bdflush_done wakeup, then diff --git a/include/asm-ppc/atomic.h b/include/asm-ppc/atomic.h index 2391a2e85ee1..cf0e122dc142 100644 --- a/include/asm-ppc/atomic.h +++ b/include/asm-ppc/atomic.h @@ -5,8 +5,6 @@ #ifndef _ASM_PPC_ATOMIC_H_ #define _ASM_PPC_ATOMIC_H_ -#include - typedef struct { volatile int counter; } atomic_t; #define ATOMIC_INIT(i) { (i) } diff --git a/include/asm-sh/atomic.h b/include/asm-sh/atomic.h index e46fdc7bc9c5..f9aa875aea98 100644 --- a/include/asm-sh/atomic.h +++ b/include/asm-sh/atomic.h @@ -9,11 +9,7 @@ #include -#ifdef CONFIG_SMP typedef struct { volatile int counter; } atomic_t; -#else -typedef struct { int counter; } atomic_t; -#endif #define ATOMIC_INIT(i) ( (atomic_t) { (i) } ) @@ -22,20 +18,13 @@ typedef struct { int counter; } atomic_t; #include -/* - * Make sure gcc doesn't try to be clever and move things around - * on us. We need to use _exactly_ the address the user gave us, - * not some alias that contains the same information. - */ -#define __atomic_fool_gcc(x) (*(volatile struct { int a[100]; } *)x) - /* * To get proper branch prediction for the main line, we must branch * forward to code at the end of this object's .text section, then * branch back to restart the operation. */ -extern __inline__ void atomic_add(int i, atomic_t * v) +static __inline__ void atomic_add(int i, atomic_t * v) { unsigned long flags; @@ -44,7 +33,7 @@ extern __inline__ void atomic_add(int i, atomic_t * v) restore_flags(flags); } -extern __inline__ void atomic_sub(int i, atomic_t *v) +static __inline__ void atomic_sub(int i, atomic_t *v) { unsigned long flags; @@ -53,7 +42,7 @@ extern __inline__ void atomic_sub(int i, atomic_t *v) restore_flags(flags); } -extern __inline__ int atomic_add_return(int i, atomic_t * v) +static __inline__ int atomic_add_return(int i, atomic_t * v) { unsigned long temp, flags; @@ -66,7 +55,7 @@ extern __inline__ int atomic_add_return(int i, atomic_t * v) return temp; } -extern __inline__ int atomic_sub_return(int i, atomic_t * v) +static __inline__ int atomic_sub_return(int i, atomic_t * v) { unsigned long temp, flags; @@ -88,7 +77,7 @@ extern __inline__ int atomic_sub_return(int i, atomic_t * v) #define atomic_inc(v) atomic_add(1,(v)) #define atomic_dec(v) atomic_sub(1,(v)) -extern __inline__ void atomic_clear_mask(unsigned int mask, atomic_t *v) +static __inline__ void atomic_clear_mask(unsigned int mask, atomic_t *v) { unsigned long flags; @@ -97,7 +86,7 @@ extern __inline__ void atomic_clear_mask(unsigned int mask, atomic_t *v) restore_flags(flags); } -extern __inline__ void atomic_set_mask(unsigned int mask, atomic_t *v) +static __inline__ void atomic_set_mask(unsigned int mask, atomic_t *v) { unsigned long flags; diff --git a/include/asm-sh/bitops.h b/include/asm-sh/bitops.h index fde5f21215cd..d74bd4fbf046 100644 --- a/include/asm-sh/bitops.h +++ b/include/asm-sh/bitops.h @@ -6,7 +6,7 @@ /* For __swab32 */ #include -extern __inline__ void set_bit(int nr, volatile void * addr) +static __inline__ void set_bit(int nr, volatile void * addr) { int mask; volatile unsigned int *a = addr; @@ -19,7 +19,12 @@ extern __inline__ void set_bit(int nr, volatile void * addr) restore_flags(flags); } -extern __inline__ void clear_bit(int nr, volatile void * addr) +/* + * clear_bit() doesn't provide any barrier for the compiler. + */ +#define smp_mb__before_clear_bit() barrier() +#define smp_mb__after_clear_bit() barrier() +static __inline__ void clear_bit(int nr, volatile void * addr) { int mask; volatile unsigned int *a = addr; @@ -32,7 +37,7 @@ extern __inline__ void clear_bit(int nr, volatile void * addr) restore_flags(flags); } -extern __inline__ void change_bit(int nr, volatile void * addr) +static __inline__ void change_bit(int nr, volatile void * addr) { int mask; volatile unsigned int *a = addr; @@ -45,7 +50,7 @@ extern __inline__ void change_bit(int nr, volatile void * addr) restore_flags(flags); } -extern __inline__ int test_and_set_bit(int nr, volatile void * addr) +static __inline__ int test_and_set_bit(int nr, volatile void * addr) { int mask, retval; volatile unsigned int *a = addr; @@ -61,7 +66,7 @@ extern __inline__ int test_and_set_bit(int nr, volatile void * addr) return retval; } -extern __inline__ int test_and_clear_bit(int nr, volatile void * addr) +static __inline__ int test_and_clear_bit(int nr, volatile void * addr) { int mask, retval; volatile unsigned int *a = addr; @@ -77,7 +82,7 @@ extern __inline__ int test_and_clear_bit(int nr, volatile void * addr) return retval; } -extern __inline__ int test_and_change_bit(int nr, volatile void * addr) +static __inline__ int test_and_change_bit(int nr, volatile void * addr) { int mask, retval; volatile unsigned int *a = addr; @@ -94,12 +99,12 @@ extern __inline__ int test_and_change_bit(int nr, volatile void * addr) } -extern __inline__ int test_bit(int nr, const volatile void *addr) +static __inline__ int test_bit(int nr, const volatile void *addr) { return 1UL & (((const volatile unsigned int *) addr)[nr >> 5] >> (nr & 31)); } -extern __inline__ unsigned long ffz(unsigned long word) +static __inline__ unsigned long ffz(unsigned long word) { unsigned long result; @@ -108,11 +113,12 @@ extern __inline__ unsigned long ffz(unsigned long word) "bt/s 1b\n\t" " add #1, %0" : "=r" (result), "=r" (word) - : "0" (~0L), "1" (word)); + : "0" (~0L), "1" (word) + : "t"); return result; } -extern __inline__ int find_next_zero_bit(void *addr, int size, int offset) +static __inline__ int find_next_zero_bit(void *addr, int size, int offset) { unsigned long *p = ((unsigned long *) addr) + (offset >> 5); unsigned long result = offset & ~31UL; @@ -159,7 +165,7 @@ found_middle: #define ext2_find_next_zero_bit(addr, size, offset) \ find_next_zero_bit((addr), (size), (offset)) #else -extern __inline__ int ext2_set_bit(int nr, volatile void * addr) +static __inline__ int ext2_set_bit(int nr, volatile void * addr) { int mask, retval; unsigned long flags; @@ -174,7 +180,7 @@ extern __inline__ int ext2_set_bit(int nr, volatile void * addr) return retval; } -extern __inline__ int ext2_clear_bit(int nr, volatile void * addr) +static __inline__ int ext2_clear_bit(int nr, volatile void * addr) { int mask, retval; unsigned long flags; @@ -189,7 +195,7 @@ extern __inline__ int ext2_clear_bit(int nr, volatile void * addr) return retval; } -extern __inline__ int ext2_test_bit(int nr, const volatile void * addr) +static __inline__ int ext2_test_bit(int nr, const volatile void * addr) { int mask; const volatile unsigned char *ADDR = (const unsigned char *) addr; @@ -202,7 +208,7 @@ extern __inline__ int ext2_test_bit(int nr, const volatile void * addr) #define ext2_find_first_zero_bit(addr, size) \ ext2_find_next_zero_bit((addr), (size), 0) -extern __inline__ unsigned long ext2_find_next_zero_bit(void *addr, unsigned long size, unsigned long offset) +static __inline__ unsigned long ext2_find_next_zero_bit(void *addr, unsigned long size, unsigned long offset) { unsigned long *p = ((unsigned long *) addr) + (offset >> 5); unsigned long result = offset & ~31UL; diff --git a/include/asm-sh/checksum.h b/include/asm-sh/checksum.h index 05a556fc7e02..7e9418b3bad4 100644 --- a/include/asm-sh/checksum.h +++ b/include/asm-sh/checksum.h @@ -82,7 +82,8 @@ static __inline__ unsigned int csum_fold(unsigned int sum) "add %1, %0\n\t" "not %0, %0\n\t" : "=r" (sum), "=&r" (__dummy) - : "0" (sum)); + : "0" (sum) + : "t"); return sum; } @@ -115,7 +116,8 @@ static __inline__ unsigned short ip_fast_csum(unsigned char * iph, unsigned int are modified, we must also specify them as outputs, or gcc will assume they contain their original values. */ : "=r" (sum), "=r" (iph), "=r" (ihl), "=&r" (__dummy0), "=&z" (__dummy1) - : "1" (iph), "2" (ihl)); + : "1" (iph), "2" (ihl) + : "t"); return csum_fold(sum); } @@ -138,7 +140,8 @@ static __inline__ unsigned long csum_tcpudp_nofold(unsigned long saddr, "movt %0\n\t" "add %1, %0" : "=r" (sum), "=r" (len_proto) - : "r" (daddr), "r" (saddr), "1" (len_proto), "0" (sum)); + : "r" (daddr), "r" (saddr), "1" (len_proto), "0" (sum) + : "t"); return sum; } @@ -197,7 +200,8 @@ static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr, "add %1, %0\n" : "=r" (sum), "=&r" (__dummy) : "r" (saddr), "r" (daddr), - "r" (htonl(len)), "r" (htonl(proto)), "0" (sum)); + "r" (htonl(len)), "r" (htonl(proto)), "0" (sum) + : "t"); return csum_fold(sum); } diff --git a/include/asm-sh/delay.h b/include/asm-sh/delay.h index 7495d31c894c..38e5a48c0438 100644 --- a/include/asm-sh/delay.h +++ b/include/asm-sh/delay.h @@ -15,7 +15,8 @@ extern __inline__ void __delay(unsigned long loops) "bf/s 1b\n\t" " dt %0" : "=r" (loops) - : "0" (loops)); + : "0" (loops) + : "t"); } extern __inline__ void __udelay(unsigned long usecs, unsigned long lps) diff --git a/include/asm-sh/fcntl.h b/include/asm-sh/fcntl.h index c2d0ea1c2a77..21e39b7cc05a 100644 --- a/include/asm-sh/fcntl.h +++ b/include/asm-sh/fcntl.h @@ -35,6 +35,10 @@ #define F_SETSIG 10 /* for sockets. */ #define F_GETSIG 11 /* for sockets. */ +#define F_GETLK64 12 /* using 'struct flock64' */ +#define F_SETLK64 13 +#define F_SETLKW64 14 + /* for F_[GET|SET]FL */ #define FD_CLOEXEC 1 /* actually anything with low bit set goes */ @@ -70,6 +74,14 @@ struct flock { pid_t l_pid; }; +struct flock64 { + short l_type; + short l_whence; + loff_t l_start; + loff_t l_len; + pid_t l_pid; +}; + #define F_LINUX_SPECIFIC_BASE 1024 #endif /* __ASM_SH_FCNTL_H */ diff --git a/include/asm-sh/ide.h b/include/asm-sh/ide.h index 25570cea253e..db9df9256f11 100644 --- a/include/asm-sh/ide.h +++ b/include/asm-sh/ide.h @@ -18,7 +18,8 @@ #include #ifndef MAX_HWIFS -#define MAX_HWIFS 1 +/* Should never have less than 2, ide-pci.c(ide_match_hwif) requires it */ +#define MAX_HWIFS 2 #endif #define ide__sti() __sti() diff --git a/include/asm-sh/io_hd64461.h b/include/asm-sh/io_hd64461.h index 2574a39aba48..ab7a8a506ed6 100644 --- a/include/asm-sh/io_hd64461.h +++ b/include/asm-sh/io_hd64461.h @@ -62,6 +62,10 @@ extern void hd64461_outsl(unsigned int port, const void *addr, unsigned long cou # define __writew generic_writew # define __writel generic_writel +# define __isa_port2addr generic_isa_port2addr +# define __ioremap generic_ioremap +# define __iounmap generic_iounmap + #endif #endif /* _ASM_SH_IO_HD64461_H */ diff --git a/include/asm-sh/irq.h b/include/asm-sh/irq.h index 48016e3f958a..28d25be33521 100644 --- a/include/asm-sh/irq.h +++ b/include/asm-sh/irq.h @@ -42,6 +42,7 @@ #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) #define SCIF_ERI_IRQ 56 #define SCIF_RXI_IRQ 57 +#define SCIF_BRI_IRQ 58 #define SCIF_TXI_IRQ 59 #define SCIF_IPR_ADDR INTC_IPRE #define SCIF_IPR_POS 1 @@ -49,6 +50,7 @@ #define IRDA_ERI_IRQ 52 #define IRDA_RXI_IRQ 53 +#define IRDA_BRI_IRQ 54 #define IRDA_TXI_IRQ 55 #define IRDA_IPR_ADDR INTC_IPRE #define IRDA_IPR_POS 2 @@ -56,6 +58,7 @@ #elif defined(CONFIG_CPU_SUBTYPE_SH7750) #define SCIF_ERI_IRQ 40 #define SCIF_RXI_IRQ 41 +#define SCIF_BRI_IRQ 42 #define SCIF_TXI_IRQ 43 #define SCIF_IPR_ADDR INTC_IPRC #define SCIF_IPR_POS 1 diff --git a/include/asm-sh/page.h b/include/asm-sh/page.h index dcac85fa6a8d..aa406533f2b6 100644 --- a/include/asm-sh/page.h +++ b/include/asm-sh/page.h @@ -9,7 +9,7 @@ [ P0/U0 (virtual) ] 0x00000000 <------ User space [ P1 (fixed) cached ] 0x80000000 <------ Kernel space [ P2 (fixed) non-cachable] 0xA0000000 <------ Physical access - [ P3 (virtual) cached] 0xC0000000 <------ not used + [ P3 (virtual) cached] 0xC0000000 <------ vmalloced area [ P4 control ] 0xE0000000 */ @@ -26,8 +26,14 @@ #define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) #define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE) + +#if defined(__sh3__) #define clear_user_page(page, vaddr) clear_page(page) #define copy_user_page(to, from, vaddr) copy_page(to, from) +#elif defined(__SH4__) +extern void clear_user_page(void *to, unsigned long address); +extern void copy_user_page(void *to, void *from, unsigned long address); +#endif /* * These are used to make use of C type-checking.. @@ -62,7 +68,7 @@ typedef struct { unsigned long pgprot; } pgprot_t; #define __MEMORY_START CONFIG_MEMORY_START -#define PAGE_OFFSET (0x80000000) +#define PAGE_OFFSET (0x80000000UL) #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) #define virt_to_page(kaddr) (mem_map + ((__pa(kaddr)-__MEMORY_START) >> PAGE_SHIFT)) diff --git a/include/asm-sh/pci.h b/include/asm-sh/pci.h index 2c3ce9038ed5..9c53169f677c 100644 --- a/include/asm-sh/pci.h +++ b/include/asm-sh/pci.h @@ -18,12 +18,12 @@ #define PCIBIOS_MIN_MEM 0x10000000 #endif -extern inline void pcibios_set_master(struct pci_dev *dev) +static inline void pcibios_set_master(struct pci_dev *dev) { /* No special bus mastering setup handling */ } -extern inline void pcibios_penalize_isa_irq(int irq) +static inline void pcibios_penalize_isa_irq(int irq) { /* We don't do dynamic PCI IRQ allocation */ } @@ -67,7 +67,7 @@ extern void pci_free_consistent(struct pci_dev *hwdev, size_t size, * Once the device is given the dma address, the device owns this memory * until either pci_unmap_single or pci_dma_sync_single is performed. */ -extern inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, +static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size,int directoin) { return virt_to_bus(ptr); @@ -80,7 +80,7 @@ extern inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, * After this call, reads by the cpu to the buffer are guarenteed to see * whatever the device wrote there. */ -extern inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, +static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size,int direction) { /* Nothing to do */ @@ -101,7 +101,7 @@ extern inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, * Device ownership issues as mentioned above for pci_map_single are * the same here. */ -extern inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, +static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents,int direction) { return nents; @@ -111,7 +111,7 @@ extern inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, * Again, cpu read rules concerning calls here are the same as for * pci_unmap_single() above. */ -extern inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, +static inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents,int direction) { /* Nothing to do */ @@ -126,7 +126,7 @@ extern inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, * next point you give the PCI dma address back to the card, the * device again owns the buffer. */ -extern inline void pci_dma_sync_single(struct pci_dev *hwdev, +static inline void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size,int direction) { @@ -139,7 +139,7 @@ extern inline void pci_dma_sync_single(struct pci_dev *hwdev, * The same as pci_dma_sync_single but for a scatter-gather list, * same rules and usage. */ -extern inline void pci_dma_sync_sg(struct pci_dev *hwdev, +static inline void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nelems,int direction) { diff --git a/include/asm-sh/pgtable.h b/include/asm-sh/pgtable.h index df3e8edf2b8e..f84b7904afd5 100644 --- a/include/asm-sh/pgtable.h +++ b/include/asm-sh/pgtable.h @@ -92,45 +92,44 @@ extern unsigned long empty_zero_page[1024]; #define VMALLOC_VMADDR(x) ((unsigned long)(x)) #define VMALLOC_END P4SEG -#define _PAGE_PRESENT 0x001 /* software: page is present */ -#define _PAGE_ACCESSED 0x002 /* software: page referenced */ +/* 0x001 WT-bit on SH-4, 0 on SH-3 */ +#define _PAGE_HW_SHARED 0x002 /* SH-bit : page is shared among processes */ #define _PAGE_DIRTY 0x004 /* D-bit : page changed */ #define _PAGE_CACHABLE 0x008 /* C-bit : cachable */ -/* 0x010 SZ-bit : size of page */ +/* 0x010 SZ0-bit : Size of page */ #define _PAGE_RW 0x020 /* PR0-bit : write access allowed */ #define _PAGE_USER 0x040 /* PR1-bit : user space access allowed */ -#define _PAGE_PROTNONE 0x080 /* software: if not present */ -/* 0x100 V-bit : page is valid */ -/* 0x200 can be used as software flag */ -/* 0x400 can be used as software flag */ -/* 0x800 can be used as software flag */ +/* 0x080 SZ1-bit : Size of page (on SH-4) */ +#define _PAGE_PRESENT 0x100 /* V-bit : page is valid */ +#define _PAGE_PROTNONE 0x200 /* software: if not present */ +#define _PAGE_ACCESSED 0x400 /* software: page referenced */ +#define _PAGE_U0_SHARED 0x800 /* software: page is shared in user space */ -#if defined(__sh3__) /* Mask which drop software flags */ -#define _PAGE_FLAGS_HARDWARE_MASK 0x1ffff06c -/* Flags defalult: SZ=1 (4k-byte), C=0 (non-cachable), SH=0 (not shared) */ -#define _PAGE_FLAGS_HARDWARE_DEFAULT 0x00000110 +#define _PAGE_FLAGS_HARDWARE_MASK 0x1ffff1ff +/* Hardware flags: SZ=1 (4k-byte) */ +#define _PAGE_FLAGS_HARD 0x00000010 + +#if defined(__sh3__) +#define _PAGE_SHARED _PAGE_HW_SHARED #elif defined(__SH4__) -/* Mask which drops software flags */ -#define _PAGE_FLAGS_HARDWARE_MASK 0x1ffff06c -/* Flags defalult: SZ=01 (4k-byte), C=0 (non-cachable), SH=0 (not shared), WT=0 */ -#define _PAGE_FLAGS_HARDWARE_DEFAULT 0x00000110 +#define _PAGE_SHARED _PAGE_U0_SHARED #endif #define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY) #define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) -#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_CACHABLE | _PAGE_DIRTY) +#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_CACHABLE | _PAGE_DIRTY | _PAGE_SHARED) -#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_CACHABLE |_PAGE_ACCESSED) -#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_CACHABLE |_PAGE_ACCESSED) -#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_CACHABLE | _PAGE_ACCESSED) -#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_CACHABLE | _PAGE_ACCESSED) -#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_CACHABLE | _PAGE_DIRTY | _PAGE_ACCESSED) -#define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_CACHABLE | _PAGE_DIRTY | _PAGE_ACCESSED) +#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_CACHABLE |_PAGE_ACCESSED | _PAGE_FLAGS_HARD) +#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_CACHABLE |_PAGE_ACCESSED | _PAGE_SHARED | _PAGE_FLAGS_HARD) +#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_CACHABLE | _PAGE_ACCESSED | _PAGE_FLAGS_HARD) +#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_CACHABLE | _PAGE_ACCESSED | _PAGE_FLAGS_HARD) +#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_CACHABLE | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_HW_SHARED | _PAGE_FLAGS_HARD) +#define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_CACHABLE | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_HW_SHARED | _PAGE_FLAGS_HARD) /* * As i386 and MIPS, SuperH can't do page protection for execute, and - * considers that the same are read. Also, write permissions imply + * considers that the same as a read. Also, write permissions imply * read permissions. This is the closest we can get.. */ @@ -184,6 +183,7 @@ extern inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_USER; } extern inline int pte_dirty(pte_t pte){ return pte_val(pte) & _PAGE_DIRTY; } extern inline int pte_young(pte_t pte){ return pte_val(pte) & _PAGE_ACCESSED; } extern inline int pte_write(pte_t pte){ return pte_val(pte) & _PAGE_RW; } +extern inline int pte_shared(pte_t pte){ return pte_val(pte) & _PAGE_SHARED; } extern inline pte_t pte_rdprotect(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_USER)); return pte; } extern inline pte_t pte_exprotect(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_USER)); return pte; } @@ -244,11 +244,15 @@ extern void update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte); /* Encode and de-code a swap entry */ -#define SWP_TYPE(x) (((x).val >> 1) & 0x3f) -#define SWP_OFFSET(x) ((x).val >> 8) -#define SWP_ENTRY(type, offset) ((swp_entry_t) { ((type) << 1) | ((offset) << 8) }) -#define pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) -#define swp_entry_to_pte(x) ((pte_t) { (x).val }) +/* + * NOTE: We should set ZEROs at the position of _PAGE_PRESENT + * and _PAGE_PROTONOE bits + */ +#define SWP_TYPE(x) ((x).val & 0xff) +#define SWP_OFFSET(x) ((x).val >> 10) +#define SWP_ENTRY(type, offset) ((swp_entry_t) { (type) | ((offset) << 10) }) +#define pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) +#define swp_entry_to_pte(x) ((pte_t) { (x).val }) #define module_map vmalloc #define module_unmap vfree diff --git a/include/asm-sh/string.h b/include/asm-sh/string.h index 3eab1c1234dd..d85e4e4066d4 100644 --- a/include/asm-sh/string.h +++ b/include/asm-sh/string.h @@ -20,7 +20,7 @@ extern __inline__ char *strcpy(char *__dest, const char *__src) " add #1, %0\n\t" : "=r" (__dest), "=r" (__src), "=&z" (__dummy) : "0" (__dest), "1" (__src) - : "memory"); + : "memory", "t"); return __xdest; } @@ -46,7 +46,7 @@ extern __inline__ char *strncpy(char *__dest, const char *__src, size_t __n) "2:" : "=r" (__dest), "=r" (__src), "=&z" (__dummy) : "0" (__dest), "1" (__src), "r" (__src+__n) - : "memory"); + : "memory", "t"); return __xdest; } @@ -71,7 +71,8 @@ extern __inline__ int strcmp(const char *__cs, const char *__ct) "sub %3, %2\n" "2:" : "=r" (__cs), "=r" (__ct), "=&r" (__res), "=&z" (__dummy) - : "0" (__cs), "1" (__ct)); + : "0" (__cs), "1" (__ct) + : "t"); return __res; } @@ -82,6 +83,9 @@ extern __inline__ int strncmp(const char *__cs, const char *__ct, size_t __n) register int __res; unsigned long __dummy; + if (__n == 0) + return 0; + __asm__ __volatile__( "mov.b @%1+, %3\n" "1:\n\t" @@ -99,7 +103,8 @@ extern __inline__ int strncmp(const char *__cs, const char *__ct, size_t __n) "sub %3, %2\n" "3:" :"=r" (__cs), "=r" (__ct), "=&r" (__res), "=&z" (__dummy) - : "0" (__cs), "1" (__ct), "r" (__cs+__n)); + : "0" (__cs), "1" (__ct), "r" (__cs+__n) + : "t"); return __res; } diff --git a/include/asm-sh/system.h b/include/asm-sh/system.h index c3ca3b467c68..86786c730665 100644 --- a/include/asm-sh/system.h +++ b/include/asm-sh/system.h @@ -21,12 +21,12 @@ typedef struct { #define prepare_to_switch() do { } while(0) #define switch_to(prev,next,last) do { \ register struct task_struct *__last; \ - register unsigned long *__ts1 __asm__ ("$r1") = &prev->thread.sp; \ - register unsigned long *__ts2 __asm__ ("$r2") = &prev->thread.pc; \ - register unsigned long *__ts4 __asm__ ("$r4") = (unsigned long *)prev; \ - register unsigned long *__ts5 __asm__ ("$r5") = (unsigned long *)next; \ - register unsigned long *__ts6 __asm__ ("$r6") = &next->thread.sp; \ - register unsigned long __ts7 __asm__ ("$r7") = next->thread.pc; \ + register unsigned long *__ts1 __asm__ ("r1") = &prev->thread.sp; \ + register unsigned long *__ts2 __asm__ ("r2") = &prev->thread.pc; \ + register unsigned long *__ts4 __asm__ ("r4") = (unsigned long *)prev; \ + register unsigned long *__ts5 __asm__ ("r5") = (unsigned long *)next; \ + register unsigned long *__ts6 __asm__ ("r6") = &next->thread.sp; \ + register unsigned long __ts7 __asm__ ("r7") = next->thread.pc; \ __asm__ __volatile__ (".balign 4\n\t" \ "stc.l $gbr, @-$r15\n\t" \ "sts.l $pr, @-$r15\n\t" \ @@ -63,7 +63,7 @@ typedef struct { :"0" (prev), \ "r" (__ts1), "r" (__ts2), \ "r" (__ts4), "r" (__ts5), "r" (__ts6), "r" (__ts7) \ - :"r3"); \ + :"r3", "t"); \ last = __last; \ } while (0) #endif @@ -88,11 +88,22 @@ extern void __xchg_called_with_bad_pointer(void); #define mb() __asm__ __volatile__ ("": : :"memory") #define rmb() mb() #define wmb() __asm__ __volatile__ ("": : :"memory") + +#ifdef CONFIG_SMP +#define smp_mb() mb() +#define smp_rmb() rmb() +#define smp_wmb() wmb() +#else +#define smp_mb() barrier() +#define smp_rmb() barrier() +#define smp_wmb() barrier() +#endif + #define set_mb(var, value) do { xchg(&var, value); } while (0) #define set_wmb(var, value) do { var = value; wmb(); } while (0) /* Interrupt Control */ -extern __inline__ void __sti(void) +static __inline__ void __sti(void) { unsigned long __dummy0, __dummy1; @@ -106,7 +117,7 @@ extern __inline__ void __sti(void) : "memory"); } -extern __inline__ void __cli(void) +static __inline__ void __cli(void) { unsigned long __dummy; __asm__ __volatile__("stc $sr, %0\n\t" @@ -205,7 +216,7 @@ extern void __global_restore_flags(unsigned long); #endif -extern __inline__ unsigned long xchg_u32(volatile int * m, unsigned long val) +static __inline__ unsigned long xchg_u32(volatile int * m, unsigned long val) { unsigned long flags, retval; @@ -216,7 +227,7 @@ extern __inline__ unsigned long xchg_u32(volatile int * m, unsigned long val) return retval; } -extern __inline__ unsigned long xchg_u8(volatile unsigned char * m, unsigned long val) +static __inline__ unsigned long xchg_u8(volatile unsigned char * m, unsigned long val) { unsigned long flags, retval; diff --git a/include/asm-sh/uaccess.h b/include/asm-sh/uaccess.h index 5434ccb5fd7e..4fe09b005037 100644 --- a/include/asm-sh/uaccess.h +++ b/include/asm-sh/uaccess.h @@ -45,11 +45,12 @@ * sum := addr + size; carry? --> flag = true; * if (sum >= addr_limit) flag = true; */ -#define __range_ok(addr,size) ({ \ - unsigned long flag,sum; \ - __asm__("clrt; addc %3, %1; movt %0; cmp/hi %4, %1; rotcl %0" \ - :"=&r" (flag), "=r" (sum) \ - :"1" (addr), "r" ((int)(size)), "r" (current->addr_limit.seg)); \ +#define __range_ok(addr,size) ({ \ + unsigned long flag,sum; \ + __asm__("clrt; addc %3, %1; movt %0; cmp/hi %4, %1; rotcl %0" \ + :"=&r" (flag), "=r" (sum) \ + :"1" (addr), "r" ((int)(size)), "r" (current->addr_limit.seg) \ + :"t"); \ flag; }) #define access_ok(type,addr,size) (__range_ok(addr,size) == 0) @@ -186,7 +187,8 @@ __asm__ __volatile__( \ ".long 1b, 3b\n\t" \ ".previous" \ :"=&r" (__pu_err) \ - :"r" (__pu_val), "m" (__m(__pu_addr)), "i" (-EFAULT)); }) + :"r" (__pu_val), "m" (__m(__pu_addr)), "i" (-EFAULT) \ + :"memory"); }) extern void __put_user_unknown(void); @@ -224,7 +226,7 @@ __copy_user(void *__to, const void *__from, __kernel_size_t __n) ".previous" : "=r" (res), "=&z" (__dummy), "=r" (_f), "=r" (_t) : "2" (__from), "3" (__to), "0" (res) - : "memory"); + : "memory", "t"); return res; } @@ -284,7 +286,8 @@ __clear_user(void *addr, __kernel_size_t size) " .long 1b,3b\n" ".previous" : "=r" (size), "=r" (__a) - : "0" (size), "1" (addr), "r" (0)); + : "0" (size), "1" (addr), "r" (0) + : "memory", "t"); return size; } @@ -330,7 +333,7 @@ __strncpy_from_user(unsigned long __dest, unsigned long __src, int __count) : "=r" (res), "=&z" (__dummy), "=r" (_s), "=r" (_d) : "0" (__count), "2" (__src), "3" (__dest), "r" (__count), "i" (-EFAULT) - : "memory"); + : "memory", "t"); return res; } @@ -376,7 +379,8 @@ extern __inline__ long __strnlen_user(const char *__s, long __n) " .long 1b,3b\n" ".previous" : "=z" (res), "=&r" (__dummy) - : "0" (0), "r" (__s), "r" (__n), "i" (-EFAULT)); + : "0" (0), "r" (__s), "r" (__n), "i" (-EFAULT) + : "t"); return res; } diff --git a/include/asm-sh/unistd.h b/include/asm-sh/unistd.h index 132a4edc19fb..e5896abec545 100644 --- a/include/asm-sh/unistd.h +++ b/include/asm-sh/unistd.h @@ -230,6 +230,7 @@ #define __NR_mincore 218 #define __NR_madvise 219 #define __NR_getdents64 220 +#define __NR_fcntl64 221 /* user-visible error numbers are in the range -1 - -125: see */ @@ -249,7 +250,7 @@ do { \ #define _syscall0(type,name) \ type name(void) \ { \ -register long __sc0 __asm__ ("$r3") = __NR_##name; \ +register long __sc0 __asm__ ("r3") = __NR_##name; \ __asm__ __volatile__ ("trapa #0x10" \ : "=z" (__sc0) \ : "0" (__sc0) \ @@ -260,8 +261,8 @@ __syscall_return(type,__sc0); \ #define _syscall1(type,name,type1,arg1) \ type name(type1 arg1) \ { \ -register long __sc0 __asm__ ("$r3") = __NR_##name; \ -register long __sc4 __asm__ ("$r4") = (long) arg1; \ +register long __sc0 __asm__ ("r3") = __NR_##name; \ +register long __sc4 __asm__ ("r4") = (long) arg1; \ __asm__ __volatile__ ("trapa #0x11" \ : "=z" (__sc0) \ : "0" (__sc0), "r" (__sc4) \ @@ -272,9 +273,9 @@ __syscall_return(type,__sc0); \ #define _syscall2(type,name,type1,arg1,type2,arg2) \ type name(type1 arg1,type2 arg2) \ { \ -register long __sc0 __asm__ ("$r3") = __NR_##name; \ -register long __sc4 __asm__ ("$r4") = (long) arg1; \ -register long __sc5 __asm__ ("$r5") = (long) arg2; \ +register long __sc0 __asm__ ("r3") = __NR_##name; \ +register long __sc4 __asm__ ("r4") = (long) arg1; \ +register long __sc5 __asm__ ("r5") = (long) arg2; \ __asm__ __volatile__ ("trapa #0x12" \ : "=z" (__sc0) \ : "0" (__sc0), "r" (__sc4), "r" (__sc5) \ @@ -285,10 +286,10 @@ __syscall_return(type,__sc0); \ #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ type name(type1 arg1,type2 arg2,type3 arg3) \ { \ -register long __sc0 __asm__ ("$r3") = __NR_##name; \ -register long __sc4 __asm__ ("$r4") = (long) arg1; \ -register long __sc5 __asm__ ("$r5") = (long) arg2; \ -register long __sc6 __asm__ ("$r6") = (long) arg3; \ +register long __sc0 __asm__ ("r3") = __NR_##name; \ +register long __sc4 __asm__ ("r4") = (long) arg1; \ +register long __sc5 __asm__ ("r5") = (long) arg2; \ +register long __sc6 __asm__ ("r6") = (long) arg3; \ __asm__ __volatile__ ("trapa #0x13" \ : "=z" (__sc0) \ : "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6) \ @@ -299,11 +300,11 @@ __syscall_return(type,__sc0); \ #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \ { \ -register long __sc0 __asm__ ("$r3") = __NR_##name; \ -register long __sc4 __asm__ ("$r4") = (long) arg1; \ -register long __sc5 __asm__ ("$r5") = (long) arg2; \ -register long __sc6 __asm__ ("$r6") = (long) arg3; \ -register long __sc7 __asm__ ("$r7") = (long) arg4; \ +register long __sc0 __asm__ ("r3") = __NR_##name; \ +register long __sc4 __asm__ ("r4") = (long) arg1; \ +register long __sc5 __asm__ ("r5") = (long) arg2; \ +register long __sc6 __asm__ ("r6") = (long) arg3; \ +register long __sc7 __asm__ ("r7") = (long) arg4; \ __asm__ __volatile__ ("trapa #0x14" \ : "=z" (__sc0) \ : "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6), \ @@ -315,12 +316,12 @@ __syscall_return(type,__sc0); \ #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \ type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ { \ -register long __sc3 __asm__ ("$r3") = __NR_##name; \ -register long __sc4 __asm__ ("$r4") = (long) arg1; \ -register long __sc5 __asm__ ("$r5") = (long) arg2; \ -register long __sc6 __asm__ ("$r6") = (long) arg3; \ -register long __sc7 __asm__ ("$r7") = (long) arg4; \ -register long __sc0 __asm__ ("$r0") = (long) arg5; \ +register long __sc3 __asm__ ("r3") = __NR_##name; \ +register long __sc4 __asm__ ("r4") = (long) arg1; \ +register long __sc5 __asm__ ("r5") = (long) arg2; \ +register long __sc6 __asm__ ("r6") = (long) arg3; \ +register long __sc7 __asm__ ("r7") = (long) arg4; \ +register long __sc0 __asm__ ("r0") = (long) arg5; \ __asm__ __volatile__ ("trapa #0x15" \ : "=z" (__sc0) \ : "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6), "r" (__sc7), \ @@ -345,7 +346,6 @@ __syscall_return(type,__sc0); \ */ #define __NR__exit __NR_exit static __inline__ _syscall0(int,pause) -static __inline__ _syscall1(int,setup,int,magic) static __inline__ _syscall0(int,sync) static __inline__ _syscall0(pid_t,setsid) static __inline__ _syscall3(int,write,int,fd,const char *,buf,off_t,count) diff --git a/include/linux/inet.h b/include/linux/inet.h index 6a8e27bcd414..acb93765fae4 100644 --- a/include/linux/inet.h +++ b/include/linux/inet.h @@ -46,7 +46,6 @@ extern void inet_proto_init(struct net_proto *pro); extern char *in_ntoa(__u32 in); -extern char *in_ntoa2(__u32 in, char *buf); extern __u32 in_aton(const char *str); #endif diff --git a/include/linux/slab.h b/include/linux/slab.h index c4173a7e5b61..9a6e6102573e 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -11,7 +11,6 @@ typedef struct kmem_cache_s kmem_cache_t; -#include #include #include diff --git a/include/linux/swap.h b/include/linux/swap.h index 6bfff47a8db9..05317e725f92 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -91,6 +91,7 @@ extern void age_page_up(struct page *); extern void age_page_up_nolock(struct page *); extern void age_page_down(struct page *); extern void age_page_down_nolock(struct page *); +extern void age_page_down_ageonly(struct page *); extern void deactivate_page(struct page *); extern void deactivate_page_nolock(struct page *); extern void activate_page(struct page *); diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index bba1e159e27a..f87bd857133b 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -26,9 +26,6 @@ extern void vmfree_area_pages(unsigned long address, unsigned long size); extern int vmalloc_area_pages(unsigned long address, unsigned long size, int gfp_mask, pgprot_t prot); -extern struct vm_struct * vmlist; - - /* * Allocate any pages */ diff --git a/init/version.c b/init/version.c index 08d91a3b95c7..2ec3dee252ed 100644 --- a/init/version.c +++ b/init/version.c @@ -14,7 +14,7 @@ #define version(a) Version_ ## a #define version_string(a) version(a) -int version_string(LINUX_VERSION_CODE) = 0; +int version_string(LINUX_VERSION_CODE); struct new_utsname system_utsname = { UTS_SYSNAME, UTS_NODENAME, UTS_RELEASE, UTS_VERSION, diff --git a/kernel/sched.c b/kernel/sched.c index de489bfd5ca9..361b72491179 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -141,64 +141,53 @@ static inline int goodness(struct task_struct * p, int this_cpu, struct mm_struc int weight; /* - * Realtime process, select the first one on the - * runqueue (taking priorities within processes - * into account). + * select the current process after every other + * runnable process, but before the idle thread. + * Also, dont trigger a counter recalculation. */ - if (p->policy != SCHED_OTHER) { - weight = 1000 + p->rt_priority; + weight = -1; + if (p->policy & SCHED_YIELD) goto out; - } /* - * Give the process a first-approximation goodness value - * according to the number of clock-ticks it has left. - * - * Don't do any other calculations if the time slice is - * over.. + * Non-RT process - normal case first. */ - weight = p->counter; - if (!weight) - goto out; + if (p->policy == SCHED_OTHER) { + /* + * Give the process a first-approximation goodness value + * according to the number of clock-ticks it has left. + * + * Don't do any other calculations if the time slice is + * over.. + */ + weight = p->counter; + if (!weight) + goto out; #ifdef CONFIG_SMP - /* Give a largish advantage to the same processor... */ - /* (this is equivalent to penalizing other processors) */ - if (p->processor == this_cpu) - weight += PROC_CHANGE_PENALTY; + /* Give a largish advantage to the same processor... */ + /* (this is equivalent to penalizing other processors) */ + if (p->processor == this_cpu) + weight += PROC_CHANGE_PENALTY; #endif - /* .. and a slight advantage to the current MM */ - if (p->mm == this_mm || !p->mm) - weight += 1; - weight += 20 - p->nice; + /* .. and a slight advantage to the current MM */ + if (p->mm == this_mm || !p->mm) + weight += 1; + weight += 20 - p->nice; + goto out; + } + /* + * Realtime process, select the first one on the + * runqueue (taking priorities within processes + * into account). + */ + weight = 1000 + p->rt_priority; out: return weight; } -/* - * subtle. We want to discard a yielded process only if it's being - * considered for a reschedule. Wakeup-time 'queries' of the scheduling - * state do not count. Another optimization we do: sched_yield()-ed - * processes are runnable (and thus will be considered for scheduling) - * right when they are calling schedule(). So the only place we need - * to care about SCHED_YIELD is when we calculate the previous process' - * goodness ... - */ -static inline int prev_goodness(struct task_struct * p, int this_cpu, struct mm_struct *this_mm) -{ - if (p->policy & SCHED_YIELD) { - /* - * select the current process after every other - * runnable process, but before the idle thread. - * Also, dont trigger a counter recalculation. - */ - return -1; - } - return goodness(p, this_cpu, this_mm); -} - /* * the 'goodness value' of replacing a process on a given CPU. * positive value means 'replace', zero or negative means 'dont'. @@ -678,7 +667,7 @@ recalculate: goto repeat_schedule; still_running: - c = prev_goodness(prev, this_cpu, prev->active_mm); + c = goodness(prev, this_cpu, prev->active_mm); next = prev; goto still_running_back; diff --git a/mm/filemap.c b/mm/filemap.c index f27892d1b1ca..6aca16409ec2 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -44,7 +44,6 @@ atomic_t page_cache_size = ATOMIC_INIT(0); unsigned int page_hash_bits; struct page **page_hash_table; -struct list_head lru_cache; spinlock_t pagecache_lock = SPIN_LOCK_UNLOCKED; /* diff --git a/mm/page_alloc.c b/mm/page_alloc.c index d364d6dc5732..0b5990a11509 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -258,13 +258,13 @@ static struct page * __alloc_pages_limit(zonelist_t *zonelist, */ switch (limit) { default: - case 0: + case PAGES_MIN: water_mark = z->pages_min; break; - case 1: + case PAGES_LOW: water_mark = z->pages_low; break; - case 2: + case PAGES_HIGH: water_mark = z->pages_high; } @@ -318,10 +318,19 @@ struct page * __alloc_pages(zonelist_t *zonelist, unsigned long order) direct_reclaim = 1; /* - * Are we low on inactive pages? + * If we are about to get low on free pages and we also have + * an inactive page shortage, wake up kswapd. */ if (inactive_shortage() > inactive_target / 2 && free_shortage()) wakeup_kswapd(0); + /* + * If we are about to get low on free pages and cleaning + * the inactive_dirty pages would fix the situation, + * wake up bdflush. + */ + else if (free_shortage() && nr_inactive_dirty_pages > free_shortage() + && nr_inactive_dirty_pages > freepages.high) + wakeup_bdflush(0); try_again: /* @@ -378,8 +387,23 @@ try_again: * * We wake up kswapd, in the hope that kswapd will * resolve this situation before memory gets tight. + * + * We also yield the CPU, because that: + * - gives kswapd a chance to do something + * - slows down allocations, in particular the + * allocations from the fast allocator that's + * causing the problems ... + * - ... which minimises the impact the "bad guys" + * have on the rest of the system + * - if we don't have __GFP_IO set, kswapd may be + * able to free some memory we can't free ourselves */ wakeup_kswapd(0); + if (gfp_mask & __GFP_WAIT) { + __set_current_state(TASK_RUNNING); + current->policy |= SCHED_YIELD; + schedule(); + } /* * After waking up kswapd, we try to allocate a page @@ -440,28 +464,43 @@ try_again: * up again. After that we loop back to the start. * * We have to do this because something else might eat - * the memory kswapd frees for us (interrupts, other - * processes, etc). + * the memory kswapd frees for us and we need to be + * reliable. Note that we don't loop back for higher + * order allocations since it is possible that kswapd + * simply cannot free a large enough contiguous area + * of memory *ever*. */ - if (gfp_mask & __GFP_WAIT) { - /* - * Give other processes a chance to run: - */ - if (current->need_resched) { - __set_current_state(TASK_RUNNING); - schedule(); - } + if ((gfp_mask & (__GFP_WAIT|__GFP_IO)) == (__GFP_WAIT|__GFP_IO)) { + wakeup_kswapd(1); + memory_pressure++; + if (!order) + goto try_again; + /* + * If __GFP_IO isn't set, we can't wait on kswapd because + * kswapd just might need some IO locks /we/ are holding ... + * + * SUBTLE: The scheduling point above makes sure that + * kswapd does get the chance to free memory we can't + * free ourselves... + */ + } else if (gfp_mask & __GFP_WAIT) { try_to_free_pages(gfp_mask); memory_pressure++; - goto try_again; + if (!order) + goto try_again; } + } /* * Final phase: allocate anything we can! * - * This is basically reserved for PF_MEMALLOC and - * GFP_ATOMIC allocations... + * Higher order allocations, GFP_ATOMIC allocations and + * recursive allocations (PF_MEMALLOC) end up here. + * + * Only recursive allocations can use the very last pages + * in the system, otherwise it would be just too easy to + * deadlock the system... */ zone = zonelist->zones; for (;;) { @@ -472,8 +511,21 @@ try_again: if (!z->size) BUG(); + /* + * SUBTLE: direct_reclaim is only possible if the task + * becomes PF_MEMALLOC while looping above. This will + * happen when the OOM killer selects this task for + * instant execution... + */ if (direct_reclaim) page = reclaim_page(z); + if (page) + return page; + + /* XXX: is pages_min/4 a good amount to reserve for this? */ + if (z->free_pages < z->pages_min / 4 && + !(current->flags & PF_MEMALLOC)) + continue; if (!page) page = rmqueue(z, order); if (page) @@ -481,8 +533,7 @@ try_again: } /* No luck.. */ - if (!order) - show_free_areas(); + printk(KERN_ERR "__alloc_pages: %lu-order allocation failed.\n", order); return NULL; } @@ -572,6 +623,13 @@ unsigned int nr_free_buffer_pages (void) sum = nr_free_pages(); sum += nr_inactive_clean_pages(); sum += nr_inactive_dirty_pages; + + /* + * Keep our write behind queue filled, even if + * kswapd lags a bit right now. + */ + if (sum < freepages.high + inactive_target) + sum = freepages.high + inactive_target; /* * We don't want dirty page writebehind to put too * much pressure on the working set, but we want it diff --git a/mm/swap.c b/mm/swap.c index dbbd218f8281..8cb160b81549 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -100,6 +100,15 @@ void age_page_up_nolock(struct page * page) page->age = PAGE_AGE_MAX; } +/* + * We use this (minimal) function in the case where we + * know we can't deactivate the page (yet). + */ +void age_page_down_ageonly(struct page * page) +{ + page->age /= 2; +} + void age_page_down_nolock(struct page * page) { /* The actual page aging bit */ @@ -155,30 +164,39 @@ void age_page_down(struct page * page) */ void deactivate_page_nolock(struct page * page) { + /* + * One for the cache, one for the extra reference the + * caller has and (maybe) one for the buffers. + * + * This isn't perfect, but works for just about everything. + * Besides, as long as we don't move unfreeable pages to the + * inactive_clean list it doesn't need to be perfect... + */ + int maxcount = (page->buffers ? 3 : 2); page->age = 0; /* * Don't touch it if it's not on the active list. * (some pages aren't on any list at all) */ - if (PageActive(page) && (page_count(page) <= 2 || page->buffers) && + if (PageActive(page) && page_count(page) <= maxcount && !page_ramdisk(page)) { /* * We can move the page to the inactive_dirty list - * if we know there is backing store available. + * if we have the strong suspicion that they might + * become freeable in the near future. * - * We also move pages here that we cannot free yet, - * but may be able to free later - because most likely - * we're holding an extra reference on the page which - * will be dropped right after deactivate_page(). + * That is, the page has buffer heads attached (that + * need to be cleared away) and/or the function calling + * us has an extra reference count on the page. */ if (page->buffers || page_count(page) == 2) { del_page_from_active_list(page); add_page_to_inactive_dirty_list(page); /* - * If the page is clean and immediately reusable, - * we can move it to the inactive_clean list. + * Only if we are SURE the page is clean and immediately + * reusable, we move it to the inactive_clean list. */ } else if (page->mapping && !PageDirty(page) && !PageLocked(page)) { @@ -215,6 +233,10 @@ void activate_page_nolock(struct page * page) * not to do anything. */ } + + /* Make sure the page gets a fair chance at staying active. */ + if (page->age < PAGE_AGE_START) + page->age = PAGE_AGE_START; } void activate_page(struct page * page) diff --git a/mm/vmscan.c b/mm/vmscan.c index 16f91fd79554..aacd9a5b033d 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -74,7 +74,8 @@ static int try_to_swap_out(struct mm_struct * mm, struct vm_area_struct* vma, un goto out_failed; } if (!onlist) - age_page_down(page); + /* The page is still mapped, so it can't be freeable... */ + age_page_down_ageonly(page); /* * If the page is in active use by us, or if the page @@ -419,7 +420,7 @@ static int swap_out(unsigned int priority, int gfp_mask, unsigned long idle_time continue; /* Skip tasks which haven't slept long enough yet when idle-swapping. */ if (idle_time && !assign && (!(p->state & TASK_INTERRUPTIBLE) || - time_before(p->sleep_time + idle_time * HZ, jiffies))) + time_after(p->sleep_time + idle_time * HZ, jiffies))) continue; found_task++; /* Refresh swap_cnt? */ @@ -536,6 +537,7 @@ struct page * reclaim_page(zone_t * zone) found_page: del_page_from_inactive_clean_list(page); UnlockPage(page); + page->age = PAGE_AGE_START; if (page_count(page) != 1) printk("VM: reclaim_page, found page with count %d!\n", page_count(page)); @@ -565,22 +567,24 @@ out: * This code is heavily inspired by the FreeBSD source code. Thanks * go out to Matthew Dillon. */ -#define MAX_SYNC_LAUNDER (1 << page_cluster) -#define MAX_LAUNDER (MAX_SYNC_LAUNDER * 4) +#define MAX_LAUNDER (4 * (1 << page_cluster)) int page_launder(int gfp_mask, int sync) { - int synclaunder, launder_loop, maxscan, cleaned_pages, maxlaunder; + int launder_loop, maxscan, cleaned_pages, maxlaunder; + int can_get_io_locks; struct list_head * page_lru; struct page * page; + /* + * We can only grab the IO locks (eg. for flushing dirty + * buffers to disk) if __GFP_IO is set. + */ + can_get_io_locks = gfp_mask & __GFP_IO; + launder_loop = 0; - synclaunder = 0; maxlaunder = 0; cleaned_pages = 0; - if (!(gfp_mask & __GFP_IO)) - return 0; - dirty_page_rescan: spin_lock(&pagemap_lru_lock); maxscan = nr_inactive_dirty_pages; @@ -638,7 +642,7 @@ dirty_page_rescan: spin_unlock(&pagemap_lru_lock); /* Will we do (asynchronous) IO? */ - if (launder_loop && synclaunder-- > 0) + if (launder_loop && maxlaunder == 0 && sync) wait = 2; /* Synchrounous IO */ else if (launder_loop && maxlaunder-- > 0) wait = 1; /* Async IO */ @@ -725,10 +729,11 @@ dirty_page_rescan: * loads, flush out the dirty pages before we have to wait on * IO. */ - if (!launder_loop && free_shortage()) { + if (can_get_io_locks && !launder_loop && free_shortage()) { launder_loop = 1; - if (sync && !cleaned_pages) - synclaunder = MAX_SYNC_LAUNDER; + /* If we cleaned pages, never do synchronous IO. */ + if (cleaned_pages) + sync = 0; /* We only do a few "out of order" flushes. */ maxlaunder = MAX_LAUNDER; /* Kflushd takes care of the rest. */ @@ -774,8 +779,23 @@ int refill_inactive_scan(unsigned int priority, int oneshot) age_page_up_nolock(page); page_active = 1; } else { - age_page_down_nolock(page); - page_active = 0; + age_page_down_ageonly(page); + /* + * Since we don't hold a reference on the page + * ourselves, we have to do our test a bit more + * strict then deactivate_page(). This is needed + * since otherwise the system could hang shuffling + * unfreeable pages from the active list to the + * inactive_dirty list and back again... + * + * SUBTLE: we can have buffer pages with count 1. + */ + if (page_count(page) <= (page->buffers ? 2 : 1)) { + deactivate_page_nolock(page); + page_active = 0; + } else { + page_active = 1; + } } /* * If the page is still on the active list, move it @@ -805,14 +825,11 @@ int free_shortage(void) pg_data_t *pgdat = pgdat_list; int sum = 0; int freeable = nr_free_pages() + nr_inactive_clean_pages(); + int freetarget = freepages.high + inactive_target / 3; - /* Are we low on truly free pages? */ - if (nr_free_pages() < freepages.min) - return freepages.high - nr_free_pages(); - - /* Are we low on free pages over-all? */ - if (freeable < freepages.high) - return freepages.high - freeable; + /* Are we low on free pages globally? */ + if (freeable < freetarget) + return freetarget - freeable; /* If not, are we very low on any particular zone? */ do { @@ -1043,14 +1060,7 @@ int kswapd(void *unused) /* Do we need to do some synchronous flushing? */ if (waitqueue_active(&kswapd_done)) wait = 1; - if (!do_try_to_free_pages(GFP_KSWAPD, wait)) { - /* - * if (out_of_memory()) { - * try again a few times; - * oom_kill(); - * } - */ - } + do_try_to_free_pages(GFP_KSWAPD, wait); } /* @@ -1087,6 +1097,10 @@ int kswapd(void *unused) */ if (!free_shortage() || !inactive_shortage()) interruptible_sleep_on_timeout(&kswapd_wait, HZ); + /* + * TODO: insert out of memory check & oom killer + * invocation in an else branch here. + */ } } @@ -1121,25 +1135,18 @@ void wakeup_kswapd(int block) /* * Called by non-kswapd processes when they want more - * memory. - * - * In a perfect world, this should just wake up kswapd - * and return. We don't actually want to swap stuff out - * from user processes, because the locking issues are - * nasty to the extreme (file write locks, and MM locking) - * - * One option might be to let kswapd do all the page-out - * and VM page table scanning that needs locking, and this - * process thread could do just the mmap shrink stage that - * can be done by just dropping cached pages without having - * any deadlock issues. + * memory but are unable to sleep on kswapd because + * they might be holding some IO locks ... */ int try_to_free_pages(unsigned int gfp_mask) { int ret = 1; - if (gfp_mask & __GFP_WAIT) + if (gfp_mask & __GFP_WAIT) { + current->flags |= PF_MEMALLOC; ret = do_try_to_free_pages(gfp_mask, 1); + current->flags &= ~PF_MEMALLOC; + } return ret; } diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 2dfd1763c816..bbbefdbf45ba 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -1099,15 +1099,18 @@ static int arp_get_info(char *buffer, char **start, off_t offset, int length) struct net_device *dev = n->dev; int hatype = dev ? dev->type : 0; - size = sprintf(buffer+len, - "%u.%u.%u.%u0x%-10x0x%-10x%s", - NIPQUAD(*(u32*)n->key), - hatype, - ATF_PUBL|ATF_PERM, - "00:00:00:00:00:00"); + { + char tbuf[16]; + sprintf(tbuf, "%u.%u.%u.%u", NIPQUAD(*(u32*)n->key)); + size = sprintf(buffer+len, "%-16s 0x%-10x0x%-10x%s", + tbuf, + hatype, + ATF_PUBL|ATF_PERM, + "00:00:00:00:00:00"); + } size += sprintf(buffer+len+size, - " %-17s %s\n", - "*", dev ? dev->name : "*"); + " * %-16s\n", + dev ? dev->name : "*"); len += size; pos += size; diff --git a/net/ipv4/utils.c b/net/ipv4/utils.c index 5992cbc5543e..c6494d87fbc8 100644 --- a/net/ipv4/utils.c +++ b/net/ipv4/utils.c @@ -57,12 +57,6 @@ char *in_ntoa(__u32 in) return(buff); } -char *in_ntoa2(__u32 in, char *buff) -{ - sprintf(buff, "%d.%d.%d.%d", NIPQUAD(in)); - return buff; -} - /* * Convert an ASCII string to binary IP. */ diff --git a/net/ipv6/protocol.c b/net/ipv6/protocol.c index accc87cbe802..43ac35004a85 100644 --- a/net/ipv6/protocol.c +++ b/net/ipv6/protocol.c @@ -32,11 +32,8 @@ #include #include -struct inet6_protocol *inet6_protocol_base = NULL; -struct inet6_protocol *inet6_protos[MAX_INET_PROTOS] = -{ - NULL -}; +struct inet6_protocol *inet6_protocol_base; +struct inet6_protocol *inet6_protos[MAX_INET_PROTOS]; void inet6_add_protocol(struct inet6_protocol *prot) { -- 2.39.5