From 88bf512f6c3d7a9be27803d88fe58a3a9a96acbc Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:37:46 -0500 Subject: [PATCH] Import 2.4.0-test6pre10 --- Documentation/Configure.help | 11 +- arch/i386/kernel/apm.c | 2 +- arch/mips/sgi/kernel/setup.c | 4 +- arch/mips64/sgi-ip22/ip22-setup.c | 4 +- arch/sh/boot/compressed/Makefile | 2 +- arch/sh/boot/compressed/head.S | 9 +- arch/sh/config.in | 23 +- arch/sh/defconfig | 5 +- arch/sh/kernel/Makefile | 35 +- arch/sh/kernel/cf-enabler.c | 24 +- arch/sh/kernel/entry.S | 15 +- arch/sh/kernel/io.c | 202 ++++++ arch/sh/kernel/io_generic.c | 119 +++- arch/sh/kernel/io_hd64461.c | 59 +- arch/sh/kernel/io_se.c | 62 +- arch/sh/kernel/io_unknown.c | 47 ++ arch/sh/kernel/irq.c | 29 +- arch/sh/kernel/irq_imask.c | 5 +- arch/sh/kernel/irq_ipr.c | 75 ++- arch/sh/kernel/led_se.c | 67 ++ arch/sh/kernel/mach_hp600.c | 63 ++ arch/sh/kernel/mach_se.c | 80 +++ arch/sh/kernel/mach_unknown.c | 68 ++ arch/sh/kernel/pci-sh.c | 19 +- arch/sh/kernel/semaphore.c | 2 + arch/sh/kernel/setup.c | 134 +++- arch/sh/kernel/setup_cqreek.c | 224 ++++++ arch/sh/kernel/setup_hd64461.c | 19 +- arch/sh/kernel/setup_se.c | 51 +- arch/sh/kernel/sh_bios.c | 2 +- arch/sh/kernel/signal.c | 7 +- arch/sh/kernel/time.c | 16 +- arch/sh/lib/Makefile | 2 +- arch/sh/lib/checksum.S | 54 +- arch/sh/lib/strcasecmp.c | 26 + arch/sh/mm/Makefile | 2 +- arch/sh/mm/cache.c | 116 ++-- arch/sh/mm/fault.c | 14 +- arch/sh/vmlinux.lds.S | 3 + arch/sparc/config.in | 29 +- arch/sparc/defconfig | 11 +- arch/sparc/mm/generic.c | 2 +- arch/sparc/mm/init.c | 2 +- arch/sparc/mm/io-unit.c | 2 +- arch/sparc/mm/iommu.c | 2 +- arch/sparc/mm/srmmu.c | 2 +- arch/sparc/mm/sun4c.c | 2 +- arch/sparc64/kernel/Makefile | 4 +- arch/sparc64/kernel/rtrap.S | 2 +- arch/sparc64/kernel/sys_sparc32.c | 57 +- arch/sparc64/mm/fault.c | 2 +- arch/sparc64/mm/generic.c | 2 +- arch/sparc64/mm/init.c | 2 +- drivers/acorn/char/keyb_arc.c | 3 +- drivers/acorn/char/keyb_ps2.c | 1 - drivers/acorn/scsi/fas216.c | 4 +- drivers/block/ll_rw_blk.c | 33 +- drivers/block/md.c | 2 +- drivers/block/raid1.c | 21 +- drivers/block/raid5.c | 30 +- drivers/block/xd.h | 1 - drivers/char/busmouse.c | 31 +- drivers/char/console.c | 1 + drivers/char/drm/drmP.h | 3 +- drivers/char/hp600_keyb.c | 48 +- drivers/char/scan_keyb.c | 4 +- drivers/char/sh-sci.c | 77 ++- drivers/char/sh-sci.h | 68 +- drivers/net/Config.in | 2 +- drivers/net/bmac.c | 6 + drivers/net/eepro100.c | 11 +- drivers/net/gmac.c | 12 +- drivers/net/hydra.c | 14 +- drivers/net/pcmcia/com20020_cs.c | 43 +- drivers/net/pcmcia/ray_cs.c | 35 +- drivers/net/pppoe.c | 153 +++-- drivers/net/sis900.c | 266 +++++--- drivers/net/sis900.h | 23 +- drivers/net/stnic.c | 5 + drivers/pci/pci.ids | 43 +- drivers/video/Config.in | 4 +- drivers/video/acornfb.c | 8 +- drivers/video/hitfb.c | 2 + fs/Config.in | 3 + fs/jffs/Makefile | 5 +- fs/jffs/inode-v23.c | 347 ++++++---- fs/jffs/intrep.c | 971 +++++++++++++++++++-------- fs/jffs/intrep.h | 26 +- fs/jffs/jffs_fm.c | 34 +- fs/jffs/jffs_fm.h | 37 +- fs/partitions/acorn.c | 170 +++-- fs/partitions/acorn.h | 39 +- include/asm-alpha/page.h | 3 +- include/asm-arm/arch-sa1100/mmzone.h | 2 + include/asm-arm/page.h | 2 + include/asm-i386/page.h | 5 +- include/asm-ia64/page.h | 9 +- include/asm-m68k/page.h | 2 + include/asm-mips/page.h | 3 +- include/asm-mips64/mmzone.h | 5 +- include/asm-mips64/page.h | 3 +- include/asm-ppc/page.h | 3 +- include/asm-s390/page.h | 4 +- include/asm-sh/bugs.h | 13 +- include/asm-sh/delay.h | 2 +- include/asm-sh/dma.h | 7 + include/asm-sh/hd64461.h | 45 +- include/asm-sh/ide.h | 39 +- include/asm-sh/io.h | 388 +++++++++-- include/asm-sh/io_generic.h | 52 ++ include/asm-sh/io_hd64461.h | 67 ++ include/asm-sh/io_od.h | 78 +++ include/asm-sh/io_se.h | 81 +++ include/asm-sh/io_unknown.h | 86 +++ include/asm-sh/irq.h | 65 +- include/asm-sh/keyboard.h | 13 +- include/asm-sh/machvec.h | 96 +++ include/asm-sh/machvec_init.h | 52 ++ include/asm-sh/mmu_context.h | 4 +- include/asm-sh/page.h | 3 +- include/asm-sh/pci.h | 21 +- include/asm-sh/pgtable.h | 5 + include/asm-sh/processor.h | 2 +- include/asm-sparc/page.h | 3 +- include/asm-sparc/pgtable.h | 5 +- include/asm-sparc64/mmu_context.h | 8 +- include/asm-sparc64/page.h | 3 +- include/asm-sparc64/pgtable.h | 5 +- include/asm-sparc64/processor.h | 2 +- include/linux/blk.h | 82 +-- include/linux/blkdev.h | 3 +- include/linux/brlock.h | 12 +- include/linux/highmem.h | 12 +- include/linux/jffs.h | 42 +- include/linux/mm.h | 3 - include/linux/pci_ids.h | 18 +- include/video/fbcon.h | 38 +- kernel/fork.c | 2 +- kernel/timer.c | 4 +- net/atm/mpc.c | 2 +- net/ipv4/ip_options.c | 6 +- net/packet/af_packet.c | 2 +- net/socket.c | 1 - 143 files changed, 4340 insertions(+), 1481 deletions(-) create mode 100644 arch/sh/kernel/io.c create mode 100644 arch/sh/kernel/io_unknown.c create mode 100644 arch/sh/kernel/led_se.c create mode 100644 arch/sh/kernel/mach_hp600.c create mode 100644 arch/sh/kernel/mach_se.c create mode 100644 arch/sh/kernel/mach_unknown.c create mode 100644 arch/sh/kernel/setup_cqreek.c create mode 100644 arch/sh/lib/strcasecmp.c create mode 100644 include/asm-sh/io_generic.h create mode 100644 include/asm-sh/io_hd64461.h create mode 100644 include/asm-sh/io_od.h create mode 100644 include/asm-sh/io_se.h create mode 100644 include/asm-sh/io_unknown.h create mode 100644 include/asm-sh/machvec.h create mode 100644 include/asm-sh/machvec_init.h diff --git a/Documentation/Configure.help b/Documentation/Configure.help index baf746b70b25..310172e91fe7 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -8920,8 +8920,15 @@ CONFIG_EEPRO100 Enable Power Management (EXPERIMENTAL) CONFIG_EEPRO100_PM - If you want to play around with power management code - that has been reported to lock up some machines, say Y here. + Many Intel EtherExpress PRO/100 PCI network cards are capable + of providing power management capabilities. To make use of these + capabilities, say Y. + + WARNING: This option is intended for kernel developers and testers. + It is still very experimental, with some people reporting complete + lockups. + + It is recommended to say N here. ICL EtherTeam 16i/32 support (EXPERIMENTAL) CONFIG_ETH16I diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c index 039ba695c87b..9a4084292277 100644 --- a/arch/i386/kernel/apm.c +++ b/arch/i386/kernel/apm.c @@ -410,7 +410,7 @@ static const lookup_t error_table[] = { #ifndef CONFIG_APM_ALLOW_INTS # define APM_DO_CLI __cli() #else -# define APM_DO_CLI +# define APM_DO_CLI __sti() #endif #ifdef APM_ZERO_SEGS # define APM_DECL_SEGS \ diff --git a/arch/mips/sgi/kernel/setup.c b/arch/mips/sgi/kernel/setup.c index f511e98de95d..bfd831a90f4a 100644 --- a/arch/mips/sgi/kernel/setup.c +++ b/arch/mips/sgi/kernel/setup.c @@ -130,9 +130,9 @@ static void __init sgi_irq_setup(void) int __init page_is_ram(unsigned long pagenr) { - if (pagenr < MAP_NR(PAGE_OFFSET + 0x2000UL)) + if ((pagenr< MAP_NR(PAGE_OFFSET + 0x08002000)) + if ((pagenr< 0x08002000) return 1; return 0; } diff --git a/arch/mips64/sgi-ip22/ip22-setup.c b/arch/mips64/sgi-ip22/ip22-setup.c index 82aa098c5ee1..808e00a3ff11 100644 --- a/arch/mips64/sgi-ip22/ip22-setup.c +++ b/arch/mips64/sgi-ip22/ip22-setup.c @@ -114,9 +114,9 @@ struct kbd_ops sgi_kbd_ops = { int __init page_is_ram(unsigned long pagenr) { - if (pagenr < MAP_NR(PAGE_OFFSET + 0x2000UL)) + if ((pagenr< MAP_NR(PAGE_OFFSET + 0x08002000)) + if ((pagenr< 0x08002000) return 1; return 0; } diff --git a/arch/sh/boot/compressed/Makefile b/arch/sh/boot/compressed/Makefile index d62db272223d..bd419991bd54 100644 --- a/arch/sh/boot/compressed/Makefile +++ b/arch/sh/boot/compressed/Makefile @@ -18,7 +18,7 @@ ZLDFLAGS = -e startup -T $(TOPDIR)/arch/sh/vmlinux.lds # # ZIMAGE_OFFSET is the load offset of the compression loader # -ZIMAGE_OFFSET = $(shell printf "0x%8x" $$[0x80000000+0x$(CONFIG_MEMORY_START)+0x200000+0x10000+0x400]) +ZIMAGE_OFFSET = $(shell printf "0x%8x" $$[0x80000000+0x$(CONFIG_MEMORY_START)+0x200000+0x10000]) ZLINKFLAGS = -Ttext $(ZIMAGE_OFFSET) $(ZLDFLAGS) diff --git a/arch/sh/boot/compressed/head.S b/arch/sh/boot/compressed/head.S index d270d1b47a90..86a3acf825be 100644 --- a/arch/sh/boot/compressed/head.S +++ b/arch/sh/boot/compressed/head.S @@ -10,6 +10,9 @@ .global startup startup: + /* Load initial status register */ + mov.l init_sr, r1 + ldc r1, sr /* First clear BSS */ mov.l end_addr, r1 @@ -20,10 +23,6 @@ l1: cmp/eq r1,r2 bf l1 - /* Load initial status register */ - mov.l init_sr, r1 - ldc r1, sr - /* Set the initial pointer. */ mov.l init_stack_addr, r0 mov.l @r0, r15 @@ -44,7 +43,7 @@ bss_start_addr: end_addr: .long _end init_sr: - .long 0x50000000 /* Privileged mode, Bank=0, Block=1, I3-I0=0 */ + .long 0x40000000 /* Privileged mode, Bank=0, Block=0, I3-I0=0 */ init_stack_addr: .long stack_start decompress_kernel_addr: diff --git a/arch/sh/config.in b/arch/sh/config.in index 2d0790bde548..fa36d92f750e 100644 --- a/arch/sh/config.in +++ b/arch/sh/config.in @@ -28,12 +28,19 @@ choice 'SuperH system type' \ "Generic CONFIG_SH_GENERIC \ SolutionEngine CONFIG_SH_SOLUTION_ENGINE \ Overdrive CONFIG_SH_OVERDRIVE \ - HP600 CONFIG_SH_HP600" Generic + HP600 CONFIG_SH_HP600 \ + CqREEK CONFIG_SH_CQREEK \ + BareCPU CONFIG_SH_UNKNOWN" Generic choice 'Processor type' \ - "SH7708 CONFIG_CPU_SUBTYPE_SH7708 \ + "SH7707 CONFIG_CPU_SUBTYPE_SH7707 \ + SH7708 CONFIG_CPU_SUBTYPE_SH7708 \ SH7709 CONFIG_CPU_SUBTYPE_SH7709 \ SH7750 CONFIG_CPU_SUBTYPE_SH7750" SH7708 +if [ "$CONFIG_CPU_SUBTYPE_SH7707" = "y" ]; then + define_bool CONFIG_CPU_SH3 y + define_bool CONFIG_CPU_SH4 n +fi if [ "$CONFIG_CPU_SUBTYPE_SH7708" = "y" ]; then define_bool CONFIG_CPU_SH3 y define_bool CONFIG_CPU_SH4 n @@ -52,7 +59,6 @@ if [ "$CONFIG_SH_SOLUTION_ENGINE" = "y" -o "$CONFIG_SH_HP600" = "y" -o \ define_hex CONFIG_MEMORY_START 0c000000 else hex 'Physical memory start address' CONFIG_MEMORY_START 08000000 - hex 'I/O port offset address' CONFIG_IOPORT_START ba000000 fi endmenu @@ -178,6 +184,12 @@ bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256 fi + +if [ "$CONFIG_SH_GENERIC" = "y" -o \ + "$CONFIG_SH_OVERDRIVE" = "y" -o "$CONFIG_SH_SOLUTION_ENGINE" = "y" ]; then + bool 'Heartbeat LED' CONFIG_HEARTBEAT +fi + if [ "$CONFIG_PARPORT" != "n" ]; then dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT if [ "$CONFIG_PRINTER" != "n" ]; then @@ -221,7 +233,8 @@ comment 'Kernel hacking' bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ bool 'Use LinuxSH standard BIOS' CONFIG_SH_STANDARD_BIOS if [ "$CONFIG_SH_STANDARD_BIOS" = "y" ]; then - bool 'GDB Stub kernel debug' CONFIG_DEBUG_KERNEL_WITH_GDB_STUB - bool 'Early printk support' CONFIG_SH_EARLY_PRINTK + hex ' GDB Stub VBR' CONFIG_GDB_STUB_VBR a0000000 + bool 'GDB Stub kernel debug' CONFIG_DEBUG_KERNEL_WITH_GDB_STUB + bool 'Early printk support' CONFIG_SH_EARLY_PRINTK fi endmenu diff --git a/arch/sh/defconfig b/arch/sh/defconfig index e1d9d1725916..5ffc0e0abbde 100644 --- a/arch/sh/defconfig +++ b/arch/sh/defconfig @@ -21,6 +21,8 @@ CONFIG_SH_GENERIC=y # CONFIG_SH_SOLUTION_ENGINE is not set # CONFIG_SH_OVERDRIVE is not set # CONFIG_SH_HP600 is not set +# CONFIG_SH_UNKNOWN is not set +# CONFIG_CPU_SUBTYPE_SH7707 is not set CONFIG_CPU_SUBTYPE_SH7708=y # CONFIG_CPU_SUBTYPE_SH7709 is not set # CONFIG_CPU_SUBTYPE_SH7750 is not set @@ -28,7 +30,6 @@ CONFIG_CPU_SH3=y # CONFIG_CPU_SH4 is not set CONFIG_CPU_LITTLE_ENDIAN=y CONFIG_MEMORY_START=0c000000 -CONFIG_IOPORT_START=ba000000 # # General setup @@ -139,6 +140,7 @@ CONFIG_SERIAL_CONSOLE=y # Unix 98 PTY support # # CONFIG_UNIX98_PTYS is not set +# CONFIG_HEARTBEAT is not set # # File systems @@ -200,4 +202,5 @@ CONFIG_MSDOS_PARTITION=y # CONFIG_MAGIC_SYSRQ is not set CONFIG_SH_STANDARD_BIOS=y CONFIG_DEBUG_KERNEL_WITH_GDB_STUB=y +CONFIG_GDB_STUB_VBR=a0000000 CONFIG_SH_EARLY_PRINTK=y diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile index 7b38522958cd..c9de70daf7b9 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile @@ -11,8 +11,8 @@ O_TARGET := kernel.o O_OBJS := process.o signal.o entry.o traps.o irq.o irq_ipr.o \ - ptrace.o setup.o time.o sys_sh.o semaphore.o pci-sh.o \ - irq_imask.o + ptrace.o setup.o time.o sys_sh.o semaphore.o \ + irq_imask.o io.o OX_OBJS := sh_ksyms.o MX_OBJS := @@ -21,26 +21,45 @@ O_OBJS += cf-enabler.o endif ifdef CONFIG_SH_GENERIC + +O_OBJS += mach_se.o setup_se.o setup_cqreek.o io_se.o led_se.o \ + mach_hp600.o io_hd64461.o \ + mach_unknown.o io_unknown.o \ + io_generic.o + +else + +ifdef CONFIG_SH_HP600 +O_OBJS += mach_hp600.o io_hd64461.o io_generic.o +endif + +ifdef CONFIG_SH_OVERDRIVE O_OBJS += io_generic.o endif ifdef CONFIG_SH_SOLUTION_ENGINE -O_OBJS += setup_se.o io_se.o +O_OBJS += mach_se.o setup_se.o io_se.o io_generic.o led_se.o endif -ifdef CONFIG_SH_OVERDRIVE -O_OBJS += setup_od.o io_generic.o +ifdef CONFIG_SH_CQREEK +O_OBJS += setup_cqreek.o +endif + +ifdef CONFIG_SH_UNKNOWN +O_OBJS += mach_unknown.o io_unknown.o io_generic.o endif -ifdef CONFIG_SH_HP600 -O_OBJS += io_hd64461.o endif ifdef CONFIG_CPU_SH4 O_OBJS += fpu.o endif -ifdef CONFIG_HD64461 +ifdef CONFIG_PCI +O_OBJS += pci-sh.o +endif + +ifneq ($(CONFIG_SH_GENERIC)$(CONFIG_HD64461),) O_OBJS += setup_hd64461.o endif diff --git a/arch/sh/kernel/cf-enabler.c b/arch/sh/kernel/cf-enabler.c index 3727c7264810..c446a115179a 100644 --- a/arch/sh/kernel/cf-enabler.c +++ b/arch/sh/kernel/cf-enabler.c @@ -14,15 +14,18 @@ #include #include -#ifdef CONFIG_SH_SOLUTION_ENGINE #include + + /* + * SolutionEngine + * * 0xB8400000 : Common Memory * 0xB8500000 : Attribute * 0xB8600000 : I/O */ -int __init cf_init(void) +static int __init cf_init_se(void) { if ((ctrl_inw(MRSHPC_CSR) & 0x000c) != 0) return 0; /* Not detected */ @@ -68,11 +71,15 @@ int __init cf_init(void) ctrl_outb(0x42, PA_MRSHPC_MW2 + 0x200); return 0; } -#else /* then generic system type */ + #define CF_CIS_BASE 0xb8000000 /* * You can connect Compact Flash directly to the bus of SuperH. * This is the enabler for that. + * + * SIM: How generic is this really? It looks pretty board, or at + * least SH sub-type, specific to me. + * I know it doesn't work on the Overdrive! */ /* @@ -81,7 +88,7 @@ int __init cf_init(void) * 0xBA000000 : I/O */ -int __init cf_init(void) +static int __init cf_init_default(void) { /* Enable the card, and set the level interrupt */ ctrl_outw(0x0042, CF_CIS_BASE+0x0200); @@ -89,6 +96,13 @@ int __init cf_init(void) disable_irq(14); return 0; } -#endif + +int __init cf_init(void) +{ + if (MACH_SE) { + return cf_init_se(); + } + return cf_init_default(); +} __initcall (cf_init); diff --git a/arch/sh/kernel/entry.S b/arch/sh/kernel/entry.S index 450d4982446f..4e57175e76aa 100644 --- a/arch/sh/kernel/entry.S +++ b/arch/sh/kernel/entry.S @@ -62,7 +62,7 @@ ENOSYS = 38 #if defined(__sh3__) TRA = 0xffffffd0 EXPEVT = 0xffffffd4 -#ifdef CONFIG_CPU_SUBTYPE_SH7709 +#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) INTEVT = 0xa4000000 ! INTEVTE2(0xa4000000) #else INTEVT = 0xffffffd8 @@ -182,7 +182,7 @@ tlb_protection_violation_store: 1: .long SYMBOL_NAME(do_page_fault) 2: .long MMU_TEA -#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB +#if defined(CONFIG_DEBUG_KERNEL_WITH_GDB_STUB) || defined(CONFIG_SH_STANDARD_BIOS) .align 2 /* Unwind the stack and jmp to the debug entry */ debug_kernel: @@ -219,12 +219,12 @@ debug_kernel: ldc $k1, $ssr .align 2 1: .long 0x300000f0 -2: .long 0xa0000100 +2: .long CONFIG_GDB_STUB_VBR + 0x100 #endif .align 2 debug_trap: -#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB +#if defined(CONFIG_DEBUG_KERNEL_WITH_GDB_STUB) || defined(CONFIG_SH_STANDARD_BIOS) mov #SR, $r0 mov.l @($r0,$r15), $r0 ! get status register shll $r0 @@ -829,7 +829,7 @@ ENTRY(interrupt_table) .long SYMBOL_NAME(do_IRQ) ! rovi .long SYMBOL_NAME(do_IRQ) .long SYMBOL_NAME(do_IRQ) -#if defined(CONFIG_CPU_SUBTYPE_SH7709) +#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) .long SYMBOL_NAME(do_IRQ) ! 32 IRQ irq0 .long SYMBOL_NAME(do_IRQ) ! 33 irq1 .long SYMBOL_NAME(do_IRQ) ! 34 irq2 @@ -859,6 +859,11 @@ ENTRY(interrupt_table) .long SYMBOL_NAME(do_IRQ) ! 58 bri2 .long SYMBOL_NAME(do_IRQ) ! 59 txi2 .long SYMBOL_NAME(do_IRQ) ! 60 ADC adi +#if defined(CONFIG_CPU_SUBTYPE_SH7707) + .long SYMBOL_NAME(do_IRQ) ! 61 LCDC lcdi + .long SYMBOL_NAME(do_IRQ) ! 62 PCC pcc0i + .long SYMBOL_NAME(do_IRQ) ! 63 pcc1i +#endif #elif defined(__SH4__) .long SYMBOL_NAME(do_IRQ) ! Hitachi UDI .long SYMBOL_NAME(do_IRQ) ! GPIO diff --git a/arch/sh/kernel/io.c b/arch/sh/kernel/io.c new file mode 100644 index 000000000000..27f250f9fdd7 --- /dev/null +++ b/arch/sh/kernel/io.c @@ -0,0 +1,202 @@ +/* + * linux/arch/sh/kernel/io_generic.c + * + * Copyright (C) 2000 Stuart Menefy + * + * Provide real functions which expand to whatever the header file defined. + * Also definitions of machine independant IO functions. + */ + +#include +#include + +unsigned int _inb(unsigned long port) +{ + return __inb(port); +} + +unsigned int _inw(unsigned long port) +{ + return __inw(port); +} + +unsigned int _inl(unsigned long port) +{ + return __inl(port); +} + +void _outb(unsigned char b, unsigned long port) +{ + __outb(b, port); +} + +void _outw(unsigned short b, unsigned long port) +{ + __outw(b, port); +} + +void _outl(unsigned int b, unsigned long port) +{ + __outl(b, port); +} + +unsigned int _inb_p(unsigned long port) +{ + return __inb_p(port); +} + +unsigned int _inw_p(unsigned long port) +{ + return __inw_p(port); +} + +void _outb_p(unsigned char b, unsigned long port) +{ + __outb_p(b, port); +} + +void _outw_p(unsigned short b, unsigned long port) +{ + __outw_p(b, port); +} + +void _insb(unsigned long port, void *buffer, unsigned long count) +{ + return __insb(port, buffer, count); +} + +void _insw(unsigned long port, void *buffer, unsigned long count) +{ + __insw(port, buffer, count); +} + +void _insl(unsigned long port, void *buffer, unsigned long count) +{ + __insl(port, buffer, count); +} + +void _outsb(unsigned long port, const void *buffer, unsigned long count) +{ + __outsb(port, buffer, count); +} + +void _outsw(unsigned long port, const void *buffer, unsigned long count) +{ + __outsw(port, buffer, count); +} + +void _outsl(unsigned long port, const void *buffer, unsigned long count) +{ + __outsl(port, buffer, count); + +} + +unsigned long ___raw_readb(unsigned long addr) +{ + return __readb(addr); +} + +unsigned long ___raw_readw(unsigned long addr) +{ + return __readw(addr); +} + +unsigned long ___raw_readl(unsigned long addr) +{ + return __readl(addr); +} + +unsigned long _readb(unsigned long addr) +{ + unsigned long r = __readb(addr); + mb(); + return r; +} + +unsigned long _readw(unsigned long addr) +{ + unsigned long r = __readw(addr); + mb(); + return r; +} + +unsigned long _readl(unsigned long addr) +{ + unsigned long r = __readl(addr); + mb(); + return r; +} + +void ___raw_writeb(unsigned char b, unsigned long addr) +{ + __writeb(b, addr); +} + +void ___raw_writew(unsigned short b, unsigned long addr) +{ + __writew(b, addr); +} + +void ___raw_writel(unsigned int b, unsigned long addr) +{ + __writel(b, addr); +} + +void _writeb(unsigned char b, unsigned long addr) +{ + __writeb(b, addr); + mb(); +} + +void _writew(unsigned short b, unsigned long addr) +{ + __writew(b, addr); + mb(); +} + +void _writel(unsigned int b, unsigned long addr) +{ + __writel(b, addr); + mb(); +} + +/* + * Copy data from IO memory space to "real" memory space. + * This needs to be optimized. + */ +void memcpy_fromio(void * to, unsigned long from, unsigned long count) +{ + while (count) { + count--; + *(char *) to = readb(from); + ((char *) to)++; + from++; + } +} + +/* + * Copy data from "real" memory space to IO memory space. + * This needs to be optimized. + */ +void memcpy_toio(unsigned long to, const void * from, unsigned long count) +{ + while (count) { + count--; + writeb(*(char *) from, to); + ((char *) from)++; + to++; + } +} + +/* + * "memset" on IO memory space. + * This needs to be optimized. + */ +void memset_io(unsigned long dst, int c, unsigned long count) +{ + while (count) { + count--; + writeb(c, dst); + dst++; + } +} diff --git a/arch/sh/kernel/io_generic.c b/arch/sh/kernel/io_generic.c index 1faa01ce33bd..9e57934505a7 100644 --- a/arch/sh/kernel/io_generic.c +++ b/arch/sh/kernel/io_generic.c @@ -4,7 +4,8 @@ * * Copyright (C) 2000 Niibe Yutaka * - * Generic I/O routine. + * Generic I/O routine. These can be used where a machine specific version + * is not required. * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -14,6 +15,7 @@ #include #include +#include #if defined(__sh3__) /* I'm not sure SH7709 has this kind of bug */ @@ -21,19 +23,31 @@ #define DUMMY_READ_AREA6 0xba000000 #endif -#define PORT2ADDR(x) (CONFIG_IOPORT_START+(x)) +#define PORT2ADDR(x) (sh_mv.mv_isa_port2addr(x)) + +unsigned long generic_io_base; static inline void delay(void) { ctrl_inw(0xa0000000); } -unsigned long inb(unsigned int port) +unsigned long generic_inb(unsigned int port) { return *(volatile unsigned char*)PORT2ADDR(port); } -unsigned long inb_p(unsigned int port) +unsigned long generic_inw(unsigned int port) +{ + return *(volatile unsigned short*)PORT2ADDR(port); +} + +unsigned long generic_inl(unsigned int port) +{ + return *(volatile unsigned long*)PORT2ADDR(port); +} + +unsigned long generic_inb_p(unsigned int port) { unsigned long v = *(volatile unsigned char*)PORT2ADDR(port); @@ -41,23 +55,29 @@ unsigned long inb_p(unsigned int port) return v; } -unsigned long inw(unsigned int port) +unsigned long generic_inw_p(unsigned int port) { - return *(volatile unsigned short*)PORT2ADDR(port); + unsigned long v = *(volatile unsigned short*)PORT2ADDR(port); + + delay(); + return v; } -unsigned long inl(unsigned int port) +unsigned long generic_inl_p(unsigned int port) { - return *(volatile unsigned long*)PORT2ADDR(port); + unsigned long v = *(volatile unsigned long*)PORT2ADDR(port); + + delay(); + return v; } -void insb(unsigned int port, void *buffer, unsigned long count) +void generic_insb(unsigned int port, void *buffer, unsigned long count) { unsigned char *buf=buffer; while(count--) *buf++=inb(port); } -void insw(unsigned int port, void *buffer, unsigned long count) +void generic_insw(unsigned int port, void *buffer, unsigned long count) { unsigned short *buf=buffer; while(count--) *buf++=inw(port); @@ -66,7 +86,7 @@ void insw(unsigned int port, void *buffer, unsigned long count) #endif } -void insl(unsigned int port, void *buffer, unsigned long count) +void generic_insl(unsigned int port, void *buffer, unsigned long count) { unsigned long *buf=buffer; while(count--) *buf++=inl(port); @@ -75,34 +95,46 @@ void insl(unsigned int port, void *buffer, unsigned long count) #endif } -void outb(unsigned long b, unsigned int port) +void generic_outb(unsigned long b, unsigned int port) { *(volatile unsigned char*)PORT2ADDR(port) = b; } -void outb_p(unsigned long b, unsigned int port) +void generic_outw(unsigned long b, unsigned int port) +{ + *(volatile unsigned short*)PORT2ADDR(port) = b; +} + +void generic_outl(unsigned long b, unsigned int port) +{ + *(volatile unsigned long*)PORT2ADDR(port) = b; +} + +void generic_outb_p(unsigned long b, unsigned int port) { *(volatile unsigned char*)PORT2ADDR(port) = b; delay(); } -void outw(unsigned long b, unsigned int port) +void generic_outw_p(unsigned long b, unsigned int port) { *(volatile unsigned short*)PORT2ADDR(port) = b; + delay(); } -void outl(unsigned long b, unsigned int port) +void generic_outl_p(unsigned long b, unsigned int port) { - *(volatile unsigned long*)PORT2ADDR(port) = b; + *(volatile unsigned long*)PORT2ADDR(port) = b; + delay(); } -void outsb(unsigned int port, const void *buffer, unsigned long count) +void generic_outsb(unsigned int port, const void *buffer, unsigned long count) { const unsigned char *buf=buffer; while(count--) outb(*buf++, port); } -void outsw(unsigned int port, const void *buffer, unsigned long count) +void generic_outsw(unsigned int port, const void *buffer, unsigned long count) { const unsigned short *buf=buffer; while(count--) outw(*buf++, port); @@ -111,7 +143,7 @@ void outsw(unsigned int port, const void *buffer, unsigned long count) #endif } -void outsl(unsigned int port, const void *buffer, unsigned long count) +void generic_outsl(unsigned int port, const void *buffer, unsigned long count) { const unsigned long *buf=buffer; while(count--) outl(*buf++, port); @@ -119,3 +151,52 @@ void outsl(unsigned int port, const void *buffer, unsigned long count) ctrl_inb (DUMMY_READ_AREA6); #endif } + +unsigned long generic_readb(unsigned long addr) +{ + return *(volatile unsigned char*)addr; +} + +unsigned long generic_readw(unsigned long addr) +{ + return *(volatile unsigned short*)addr; +} + +unsigned long generic_readl(unsigned long addr) +{ + return *(volatile unsigned long*)addr; +} + +void generic_writeb(unsigned char b, unsigned long addr) +{ + *(volatile unsigned char*)addr = b; +} + +void generic_writew(unsigned short b, unsigned long addr) +{ + *(volatile unsigned short*)addr = b; +} + +void generic_writel(unsigned int b, unsigned long addr) +{ + *(volatile unsigned long*)addr = b; +} + +void * generic_ioremap(unsigned long offset, unsigned long size) +{ + return (void *) P2SEGADDR(offset); +} + +void * generic_ioremap_nocache (unsigned long offset, unsigned long size) +{ + return (void *) P2SEGADDR(offset); +} + +void generic_iounmap(void *addr) +{ +} + +unsigned long generic_isa_port2addr(unsigned long offset) +{ + return offset + generic_io_base; +} diff --git a/arch/sh/kernel/io_hd64461.c b/arch/sh/kernel/io_hd64461.c index 7c655942b660..3fbe6f2d0af3 100644 --- a/arch/sh/kernel/io_hd64461.c +++ b/arch/sh/kernel/io_hd64461.c @@ -10,15 +10,36 @@ static __inline__ unsigned long PORT2ADDR(unsigned long port) { + /* 16550A: HD64461 internal */ + if (0x3f8<=port && port<=0x3ff) + return CONFIG_HD64461_IOBASE + 0x8000 + ((port-0x3f8)<<1); + if (0x2f8<=port && port<=0x2ff) + return CONFIG_HD64461_IOBASE + 0x7000 + ((port-0x2f8)<<1); + +#ifdef CONFIG_HD64461_ENABLER + /* NE2000: HD64461 PCMCIA channel 0 (I/O) */ + if (0x300<=port && port<=0x31f) + return 0xba000000 + port; + + /* ide0: HD64461 PCMCIA channel 1 (memory) */ + /* On HP690, CF in slot 1 is configured as a memory card + device. See CF+ and CompactFlash Specification for the + detail of CF's memory mapped addressing. */ + if (0x1f0<=port && port<=0x1f7) return 0xb5000000 + port; + if (port == 0x3f6) return 0xb50001fe; +#endif + + /* ??? */ + if (port < 0x10000) return 0xa0000000 + port; + /* HD64461 internal devices (0xb0000000) */ - if (port < 0x10000) return CONFIG_HD64461_IOBASE + port; + if (port < 0x20000) return CONFIG_HD64461_IOBASE + port - 0x10000; /* PCMCIA channel 0, I/O (0xba000000) */ - if (port < 0x20000) return 0xba000000 + port - 0x10000; + if (port < 0x30000) return 0xba000000 + port - 0x20000; - /* PCMCIA channel 1, memory (0xb5000000) - SH7709 cannot support I/O card attached to Area 5 */ - if (port < 0x30000) return 0xb5000000 + port - 0x20000; + /* PCMCIA channel 1, memory (0xb5000000) */ + if (port < 0x40000) return 0xb5000000 + port - 0x30000; /* Whole physical address space (0xa0000000) */ return 0xa0000000 + (port & 0x1fffffff); @@ -29,80 +50,80 @@ static inline void delay(void) ctrl_inw(0xa0000000); } -unsigned long inb(unsigned int port) +unsigned long hd64461_inb(unsigned int port) { return *(volatile unsigned char*)PORT2ADDR(port); } -unsigned long inb_p(unsigned int port) +unsigned long hd64461_inb_p(unsigned int port) { unsigned long v = *(volatile unsigned char*)PORT2ADDR(port); delay(); return v; } -unsigned long inw(unsigned int port) +unsigned long hd64461_inw(unsigned int port) { return *(volatile unsigned short*)PORT2ADDR(port); } -unsigned long inl(unsigned int port) +unsigned long hd64461_inl(unsigned int port) { return *(volatile unsigned long*)PORT2ADDR(port); } -void insb(unsigned int port, void *buffer, unsigned long count) +void hd64461_insb(unsigned int port, void *buffer, unsigned long count) { unsigned char *buf=buffer; while(count--) *buf++=inb(port); } -void insw(unsigned int port, void *buffer, unsigned long count) +void hd64461_insw(unsigned int port, void *buffer, unsigned long count) { unsigned short *buf=buffer; while(count--) *buf++=inw(port); } -void insl(unsigned int port, void *buffer, unsigned long count) +void hd64461_insl(unsigned int port, void *buffer, unsigned long count) { unsigned long *buf=buffer; while(count--) *buf++=inl(port); } -void outb(unsigned long b, unsigned int port) +void hd64461_outb(unsigned long b, unsigned int port) { *(volatile unsigned char*)PORT2ADDR(port) = b; } -void outb_p(unsigned long b, unsigned int port) +void hd64461_outb_p(unsigned long b, unsigned int port) { *(volatile unsigned char*)PORT2ADDR(port) = b; delay(); } -void outw(unsigned long b, unsigned int port) +void hd64461_outw(unsigned long b, unsigned int port) { *(volatile unsigned short*)PORT2ADDR(port) = b; } -void outl(unsigned long b, unsigned int port) +void hd64461_outl(unsigned long b, unsigned int port) { *(volatile unsigned long*)PORT2ADDR(port) = b; } -void outsb(unsigned int port, const void *buffer, unsigned long count) +void hd64461_outsb(unsigned int port, const void *buffer, unsigned long count) { const unsigned char *buf=buffer; while(count--) outb(*buf++, port); } -void outsw(unsigned int port, const void *buffer, unsigned long count) +void hd64461_outsw(unsigned int port, const void *buffer, unsigned long count) { const unsigned short *buf=buffer; while(count--) outw(*buf++, port); } -void outsl(unsigned int port, const void *buffer, unsigned long count) +void hd64461_outsl(unsigned int port, const void *buffer, unsigned long count) { const unsigned long *buf=buffer; while(count--) outl(*buf++, port); diff --git a/arch/sh/kernel/io_se.c b/arch/sh/kernel/io_se.c index a16c4738d39e..4d9eeca3b7e7 100644 --- a/arch/sh/kernel/io_se.c +++ b/arch/sh/kernel/io_se.c @@ -56,7 +56,7 @@ shifted_port(unsigned int port) printk("bad PC-like io %s for port 0x%x at 0x%08x\n", \ #name, (port), (__u32) __builtin_return_address(0)) -unsigned long inb(unsigned int port) +unsigned long se_inb(unsigned int port) { if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop) return *(__u8 *) (sh_pcic_io_wbase + 0x40000 + port); @@ -66,7 +66,7 @@ unsigned long inb(unsigned int port) return (*port2adr(port))&0xff; } -unsigned long inb_p(unsigned int port) +unsigned long se_inb_p(unsigned int port) { unsigned long v; @@ -80,7 +80,7 @@ unsigned long inb_p(unsigned int port) return v; } -unsigned long inw(unsigned int port) +unsigned long se_inw(unsigned int port) { if (port >= 0x2000 || (sh_pcic_io_start <= port && port <= sh_pcic_io_stop)) @@ -90,13 +90,13 @@ unsigned long inw(unsigned int port) return 0; } -unsigned long inl(unsigned int port) +unsigned long se_inl(unsigned int port) { maybebadio(inl, port); return 0; } -void outb(unsigned long value, unsigned int port) +void se_outb(unsigned long value, unsigned int port) { if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop) *(__u8 *)(sh_pcic_io_wbase + port) = value; @@ -106,7 +106,7 @@ void outb(unsigned long value, unsigned int port) *(port2adr(port)) = value; } -void outb_p(unsigned long value, unsigned int port) +void se_outb_p(unsigned long value, unsigned int port) { if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop) *(__u8 *)(sh_pcic_io_wbase + port) = value; @@ -117,7 +117,7 @@ void outb_p(unsigned long value, unsigned int port) delay(); } -void outw(unsigned long value, unsigned int port) +void se_outw(unsigned long value, unsigned int port) { if (port >= 0x2000 || (sh_pcic_io_start <= port && port <= sh_pcic_io_stop)) @@ -126,12 +126,12 @@ void outw(unsigned long value, unsigned int port) maybebadio(outw, port); } -void outl(unsigned long value, unsigned int port) +void se_outl(unsigned long value, unsigned int port) { maybebadio(outl, port); } -void insb(unsigned int port, void *addr, unsigned long count) +void se_insb(unsigned int port, void *addr, unsigned long count) { volatile __u16 *p = port2adr(port); @@ -148,19 +148,19 @@ void insb(unsigned int port, void *addr, unsigned long count) } } -void insw(unsigned int port, void *addr, unsigned long count) +void se_insw(unsigned int port, void *addr, unsigned long count) { volatile __u16 *p = port2adr(port); while (count--) *((__u16 *) addr)++ = *p; } -void insl(unsigned int port, void *addr, unsigned long count) +void se_insl(unsigned int port, void *addr, unsigned long count) { maybebadio(insl, port); } -void outsb(unsigned int port, const void *addr, unsigned long count) +void se_outsb(unsigned int port, const void *addr, unsigned long count) { volatile __u16 *p = port2adr(port); @@ -177,24 +177,54 @@ void outsb(unsigned int port, const void *addr, unsigned long count) } } -void outsw(unsigned int port, const void *addr, unsigned long count) +void se_outsw(unsigned int port, const void *addr, unsigned long count) { volatile __u16 *p = port2adr(port); while (count--) *p = *((__u16 *) addr)++; } -void outsl(unsigned int port, const void *addr, unsigned long count) +void se_outsl(unsigned int port, const void *addr, unsigned long count) { maybebadio(outsw, port); } + +unsigned long se_readb(unsigned long addr) +{ + return *(volatile unsigned char*)addr; +} + +unsigned long se_readw(unsigned long addr) +{ + return *(volatile unsigned short*)addr; +} + +unsigned long se_readl(unsigned long addr) +{ + return *(volatile unsigned long*)addr; +} + +void se_writeb(unsigned char b, unsigned long addr) +{ + *(volatile unsigned char*)addr = b; +} + +void se_writew(unsigned short b, unsigned long addr) +{ + *(volatile unsigned short*)addr = b; +} + +void se_writel(unsigned int b, unsigned long addr) +{ + *(volatile unsigned long*)addr = b; +} /* Map ISA bus address to the real address. Only for PCMCIA. */ /* ISA page descriptor. */ static __u32 sh_isa_memmap[256]; -int +static int sh_isa_mmap(__u32 start, __u32 length, __u32 offset) { int idx; @@ -212,7 +242,7 @@ sh_isa_mmap(__u32 start, __u32 length, __u32 offset) } unsigned long -sh_isa_slot(unsigned long offset) +se_isa_port2addr(unsigned long offset) { int idx; diff --git a/arch/sh/kernel/io_unknown.c b/arch/sh/kernel/io_unknown.c new file mode 100644 index 000000000000..a0407cade360 --- /dev/null +++ b/arch/sh/kernel/io_unknown.c @@ -0,0 +1,47 @@ +/* + * linux/arch/sh/kernel/io_unknown.c + * + * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com) + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * I/O routine for unknown hardware. + */ + +static unsigned int unknown_handler(void) +{ + return 0; +} + +#define UNKNOWN_ALIAS(fn) \ + void unknown_##fn(void) __attribute__ ((alias ("unknown_handler"))); + +UNKNOWN_ALIAS(inb) +UNKNOWN_ALIAS(inw) +UNKNOWN_ALIAS(inl) +UNKNOWN_ALIAS(outb) +UNKNOWN_ALIAS(outw) +UNKNOWN_ALIAS(outl) +UNKNOWN_ALIAS(inb_p) +UNKNOWN_ALIAS(inw_p) +UNKNOWN_ALIAS(inl_p) +UNKNOWN_ALIAS(outb_p) +UNKNOWN_ALIAS(outw_p) +UNKNOWN_ALIAS(outl_p) +UNKNOWN_ALIAS(insb) +UNKNOWN_ALIAS(insw) +UNKNOWN_ALIAS(insl) +UNKNOWN_ALIAS(outsb) +UNKNOWN_ALIAS(outsw) +UNKNOWN_ALIAS(outsl) +UNKNOWN_ALIAS(readb) +UNKNOWN_ALIAS(readw) +UNKNOWN_ALIAS(readl) +UNKNOWN_ALIAS(writeb) +UNKNOWN_ALIAS(writew) +UNKNOWN_ALIAS(writel) +UNKNOWN_ALIAS(isa_port2addr) +UNKNOWN_ALIAS(ioremap) +UNKNOWN_ALIAS(ioremap_nocache) +UNKNOWN_ALIAS(iounmap) diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index a353b0995100..6451c4c9effe 100644 --- a/arch/sh/kernel/irq.c +++ b/arch/sh/kernel/irq.c @@ -37,10 +37,6 @@ #include #include -#ifdef CONFIG_HD64461 -#include -#endif - /* * Micro-access to controllers is serialized over the whole * system. We never hold this lock when we call the actual @@ -94,6 +90,7 @@ struct hw_interrupt_type no_irq_type = { * Generic, controller-independent functions: */ +#if defined(CONFIG_PROC_FS) int get_irq_list(char *buf) { int i, j; @@ -105,7 +102,7 @@ int get_irq_list(char *buf) p += sprintf(p, "CPU%d ",j); *p++ = '\n'; - for (i = 0 ; i < NR_IRQS ; i++) { + for (i = 0 ; i < ACTUAL_NR_IRQS ; i++) { action = irq_desc[i].action; if (!action) continue; @@ -120,6 +117,7 @@ int get_irq_list(char *buf) } return p - buf; } +#endif /* * This should really return information about whether @@ -243,18 +241,7 @@ asmlinkage int do_IRQ(unsigned long r4, unsigned long r5, "shlr %0\n\t" "add #-16, %0\n\t" :"=z" (irq)); -#if defined(CONFIG_HD64461) - if (irq == CONFIG_HD64461_IRQ) { - unsigned short bit; - unsigned short nirr = inw(HD64461_NIRR); - unsigned short nimr = inw(HD64461_NIMR); - nirr &= ~nimr; - for (bit = 1, irq = 0; irq < 16; bit <<= 1, irq++) - if (nirr & bit) break; - if (irq == 16) irq = CONFIG_HD64461_IRQ; - else irq += HD64461_IRQBASE; - } -#endif + irq = irq_demux(irq); kstat.irqs[cpu][irq]++; desc = irq_desc + irq; @@ -330,7 +317,7 @@ int request_irq(unsigned int irq, int retval; struct irqaction * action; - if (irq >= NR_IRQS) + if (irq >= ACTUAL_NR_IRQS) return -EINVAL; if (!handler) return -EINVAL; @@ -358,7 +345,7 @@ void free_irq(unsigned int irq, void *dev_id) struct irqaction **p; unsigned long flags; - if (irq >= NR_IRQS) + if (irq >= ACTUAL_NR_IRQS) return; spin_lock_irqsave(&irq_controller_lock,flags); @@ -408,7 +395,7 @@ unsigned long probe_irq_on(void) for (i = NR_IRQS-1; i > 0; i--) { if (!irq_desc[i].action) { irq_desc[i].status |= IRQ_AUTODETECT | IRQ_WAITING; - if(irq_desc[i].handler->startup(i)) + if (irq_desc[i].handler->startup(i)) irq_desc[i].status |= IRQ_PENDING; } } @@ -430,7 +417,7 @@ unsigned long probe_irq_on(void) if (!(status & IRQ_AUTODETECT)) continue; - + /* It triggered already - consider it spurious. */ if (!(status & IRQ_WAITING)) { irq_desc[i].status = status & ~IRQ_AUTODETECT; diff --git a/arch/sh/kernel/irq_imask.c b/arch/sh/kernel/irq_imask.c index 7237ba3b5e26..8ac95823b6ad 100644 --- a/arch/sh/kernel/irq_imask.c +++ b/arch/sh/kernel/irq_imask.c @@ -8,6 +8,9 @@ * */ +/* NOTE: Will not work on level 15 */ + + #include #include #include @@ -71,7 +74,7 @@ void static inline set_interrupt_registers(int ip) : "r" (~0xf0), "r" (ip << 4)); } -void disable_imask_irq(unsigned int irq) +static void disable_imask_irq(unsigned int irq) { clear_bit(irq, &imask_mask); if (interrupt_priority < IMASK_PRIORITY - irq) diff --git a/arch/sh/kernel/irq_ipr.c b/arch/sh/kernel/irq_ipr.c index 8b6b0f5ee17a..f229e8a12f58 100644 --- a/arch/sh/kernel/irq_ipr.c +++ b/arch/sh/kernel/irq_ipr.c @@ -21,6 +21,7 @@ #include #include +#include struct ipr_data { unsigned int addr; /* Address of Interrupt Priority Register */ @@ -29,15 +30,8 @@ struct ipr_data { }; static struct ipr_data ipr_data[NR_IRQS]; -void set_ipr_data(unsigned int irq, unsigned int addr, int pos, int priority) -{ - ipr_data[irq].addr = addr; - ipr_data[irq].shift = pos*4; /* POSition (0-3) x 4 means shift */ - ipr_data[irq].priority = priority; -} - static void enable_ipr_irq(unsigned int irq); -void disable_ipr_irq(unsigned int irq); +static void disable_ipr_irq(unsigned int irq); /* shutdown is same as "disable" */ #define shutdown_ipr_irq disable_ipr_irq @@ -61,7 +55,7 @@ static struct hw_interrupt_type ipr_irq_type = { end_ipr_irq }; -void disable_ipr_irq(unsigned int irq) +static void disable_ipr_irq(unsigned int irq) { unsigned long val, flags; unsigned int addr = ipr_data[irq].addr; @@ -90,18 +84,11 @@ static void enable_ipr_irq(unsigned int irq) restore_flags(flags); } -void make_ipr_irq(unsigned int irq) -{ - disable_irq_nosync(irq); - irq_desc[irq].handler = &ipr_irq_type; - disable_ipr_irq(irq); -} - static void mask_and_ack_ipr(unsigned int irq) { disable_ipr_irq(irq); -#ifdef CONFIG_CPU_SUBTYPE_SH7709 +#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) /* This is needed when we use edge triggered setting */ /* XXX: Is it really needed? */ if (IRQ0_IRQ <= irq && irq <= IRQ5_IRQ) { @@ -118,18 +105,39 @@ static void end_ipr_irq(unsigned int irq) enable_ipr_irq(irq); } +void make_ipr_irq(unsigned int irq, unsigned int addr, int pos, int priority) +{ + disable_irq_nosync(irq); + ipr_data[irq].addr = addr; + ipr_data[irq].shift = pos*4; /* POSition (0-3) x 4 means shift */ + ipr_data[irq].priority = priority; + + irq_desc[irq].handler = &ipr_irq_type; + disable_ipr_irq(irq); +} + void __init init_IRQ(void) { - int i; + make_ipr_irq(TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY); + make_ipr_irq(RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY); - for (i = TIMER_IRQ; i < NR_IRQS; i++) { - irq_desc[i].handler = &ipr_irq_type; - } + make_ipr_irq(SCI_ERI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY); + make_ipr_irq(SCI_RXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY); + make_ipr_irq(SCI_TXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY); + +#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_TXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY); +#endif - set_ipr_data(TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY); - set_ipr_data(RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY); +#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_TXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY); +#endif -#ifdef CONFIG_CPU_SUBTYPE_SH7709 +#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) /* * Initialize the Interrupt Controller (INTC) * registers to their power on values @@ -161,11 +169,16 @@ void __init init_IRQ(void) * You should set corresponding bits of PFC to "00" * to enable these interrupts. */ - set_ipr_data(IRQ0_IRQ, IRQ0_IRP_ADDR, IRQ0_IRP_POS, IRQ0_PRIORITY); - set_ipr_data(IRQ1_IRQ, IRQ1_IRP_ADDR, IRQ1_IRP_POS, IRQ1_PRIORITY); - set_ipr_data(IRQ2_IRQ, IRQ2_IRP_ADDR, IRQ2_IRP_POS, IRQ2_PRIORITY); - set_ipr_data(IRQ3_IRQ, IRQ3_IRP_ADDR, IRQ3_IRP_POS, IRQ3_PRIORITY); - set_ipr_data(IRQ4_IRQ, IRQ4_IRP_ADDR, IRQ4_IRP_POS, IRQ4_PRIORITY); - set_ipr_data(IRQ5_IRQ, IRQ5_IRP_ADDR, IRQ5_IRP_POS, IRQ5_PRIORITY); -#endif /* CONFIG_CPU_SUBTYPE_SH7709 */ + make_ipr_irq(IRQ0_IRQ, IRQ0_IRP_ADDR, IRQ0_IRP_POS, IRQ0_PRIORITY); + make_ipr_irq(IRQ1_IRQ, IRQ1_IRP_ADDR, IRQ1_IRP_POS, IRQ1_PRIORITY); + make_ipr_irq(IRQ2_IRQ, IRQ2_IRP_ADDR, IRQ2_IRP_POS, IRQ2_PRIORITY); + make_ipr_irq(IRQ3_IRQ, IRQ3_IRP_ADDR, IRQ3_IRP_POS, IRQ3_PRIORITY); + make_ipr_irq(IRQ4_IRQ, IRQ4_IRP_ADDR, IRQ4_IRP_POS, IRQ4_PRIORITY); + make_ipr_irq(IRQ5_IRQ, IRQ5_IRP_ADDR, IRQ5_IRP_POS, IRQ5_PRIORITY); +#endif /* CONFIG_CPU_SUBTYPE_SH7707 || CONFIG_CPU_SUBTYPE_SH7709 */ + + /* Perform the machine specific initialisation */ + if (sh_mv.mv_init_irq != NULL) { + sh_mv.mv_init_irq(); + } } diff --git a/arch/sh/kernel/led_se.c b/arch/sh/kernel/led_se.c new file mode 100644 index 000000000000..0476f1bd80dc --- /dev/null +++ b/arch/sh/kernel/led_se.c @@ -0,0 +1,67 @@ +/* + * linux/arch/sh/kernel/led_se.c + * + * Copyright (C) 2000 Stuart Menefy + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * This file contains Solution Engine specific LED code. + */ + +#include + +static void mach_led(int position, int value) +{ + volatile unsigned short* p = (volatile unsigned short*)0xb0c00000; + + if (value) { + *p |= (1<<8); + } else { + *p &= ~(1<<8); + } +} + +#ifdef CONFIG_HEARTBEAT + +#include + +/* Cycle the LED's in the clasic Knightrider/Sun pattern */ +void heartbeat_se(void) +{ + static unsigned int cnt = 0, period = 0; + volatile unsigned short* p = (volatile unsigned short*)0xb0c00000; + static unsigned bit = 0, up = 1; + + cnt += 1; + if (cnt < period) { + return; + } + + cnt = 0; + + /* Go through the points (roughly!): + * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110 + */ + period = 110 - ( (300< + +#include +#include + +#include +#include +#include + +/* + * The Machine Vector + */ + +struct sh_machine_vector mv_hp600 __initmv = { + mv_name: "HP600", + + mv_nr_irqs: 80, /* HD64461_IRQBASE+16, see hd64461.h */ + + mv_inb: hd64461_inb, + mv_inw: hd64461_inw, + mv_inl: hd64461_inl, + mv_outb: hd64461_outb, + mv_outw: hd64461_outw, + mv_outl: hd64461_outl, + + mv_inb_p: hd64461_inb_p, + mv_inw_p: hd64461_inw, + mv_inl_p: hd64461_inl, + mv_outb_p: hd64461_outb_p, + mv_outw_p: hd64461_outw, + mv_outl_p: hd64461_outl, + + mv_insb: hd64461_insb, + mv_insw: hd64461_insw, + mv_insl: hd64461_insl, + mv_outsb: hd64461_outsb, + mv_outsw: hd64461_outsw, + mv_outsl: hd64461_outsl, + + mv_readb: generic_readb, + mv_readw: generic_readw, + mv_readl: generic_readl, + mv_writeb: generic_writeb, + mv_writew: generic_writew, + mv_writel: generic_writel, + + mv_irq_demux: hd64461_irq_demux, + + mv_hw_hp600: 1, + mv_hw_hd64461: 1, +}; +ALIAS_MV(hp600) diff --git a/arch/sh/kernel/mach_se.c b/arch/sh/kernel/mach_se.c new file mode 100644 index 000000000000..ce142a3990ef --- /dev/null +++ b/arch/sh/kernel/mach_se.c @@ -0,0 +1,80 @@ +/* + * linux/arch/sh/kernel/mach_se.c + * + * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com) + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * Machine vector for the Hitachi SolutionEngine + */ + +#include + +#include +#include + +#include + +void heartbeat_se(void); +void setup_se(void); +void init_se_IRQ(void); + +/* + * The Machine Vector + */ + +struct sh_machine_vector mv_se __initmv = { + mv_name: "SolutionEngine", + +#if defined(__SH4__) + mv_nr_irqs: 48, +#elif defined(CONFIG_CPU_SUBTYPE_SH7708) + mv_nr_irqs: 32, +#elif defined(CONFIG_CPU_SUBTYPE_SH7709) + mv_nr_irqs: 61, +#endif + + mv_inb: se_inb, + mv_inw: se_inw, + mv_inl: se_inl, + mv_outb: se_outb, + mv_outw: se_outw, + mv_outl: se_outl, + + mv_inb_p: se_inb_p, + mv_inw_p: se_inw, + mv_inl_p: se_inl, + mv_outb_p: se_outb_p, + mv_outw_p: se_outw, + mv_outl_p: se_outl, + + mv_insb: se_insb, + mv_insw: se_insw, + mv_insl: se_insl, + mv_outsb: se_outsb, + mv_outsw: se_outsw, + mv_outsl: se_outsl, + + mv_readb: se_readb, + mv_readw: se_readw, + mv_readl: se_readl, + mv_writeb: se_writeb, + mv_writew: se_writew, + mv_writel: se_writel, + + mv_ioremap: generic_ioremap, + mv_ioremap_nocache: generic_ioremap_nocache, + mv_iounmap: generic_iounmap, + + mv_isa_port2addr: se_isa_port2addr, + + mv_init_arch: setup_se, + mv_init_irq: init_se_IRQ, +#ifdef CONFIG_HEARTBEAT + mv_heartbeat: heartbeat_se, +#endif + + mv_hw_se: 1, +}; +ALIAS_MV(se) diff --git a/arch/sh/kernel/mach_unknown.c b/arch/sh/kernel/mach_unknown.c new file mode 100644 index 000000000000..895a65c1d1b2 --- /dev/null +++ b/arch/sh/kernel/mach_unknown.c @@ -0,0 +1,68 @@ +/* + * linux/arch/sh/kernel/mach_unknown.c + * + * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com) + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * Machine specific code for an unknown machine (internal peripherials only) + */ + +#include + +#include +#include + +#include + +/* + * The Machine Vector + */ + +struct sh_machine_vector mv_unknown __initmv = { + mv_name: "Unknown", + +#if defined(__SH4__) + mv_nr_irqs: 48, +#elif defined(CONFIG_CPU_SUBTYPE_SH7708) + mv_nr_irqs: 32, +#elif defined(CONFIG_CPU_SUBTYPE_SH7709) + mv_nr_irqs: 61, +#endif + + mv_inb: unknown_inb, + mv_inw: unknown_inw, + mv_inl: unknown_inl, + mv_outb: unknown_outb, + mv_outw: unknown_outw, + mv_outl: unknown_outl, + + mv_inb_p: unknown_inb_p, + mv_inw_p: unknown_inw_p, + mv_inl_p: unknown_inl_p, + mv_outb_p: unknown_outb_p, + mv_outw_p: unknown_outw_p, + mv_outl_p: unknown_outl_p, + + mv_insb: unknown_insb, + mv_insw: unknown_insw, + mv_insl: unknown_insl, + mv_outsb: unknown_outsb, + mv_outsw: unknown_outsw, + mv_outsl: unknown_outsl, + + mv_readb: unknown_readb, + mv_readw: unknown_readw, + mv_readl: unknown_readl, + mv_writeb: unknown_writeb, + mv_writew: unknown_writew, + mv_writel: unknown_writel, + + mv_ioremap: unknown_ioremap, + mv_ioremap_nocache: unknown_ioremap_nocache, + mv_iounmap: unknown_iounmap, + + mv_isa_port2addr: unknown_isa_port2addr, +}; +ALIAS_MV(unknown) diff --git a/arch/sh/kernel/pci-sh.c b/arch/sh/kernel/pci-sh.c index 3613596f7246..a4a6c6918f26 100644 --- a/arch/sh/kernel/pci-sh.c +++ b/arch/sh/kernel/pci-sh.c @@ -4,9 +4,22 @@ #include #include #include +#include -unsigned long resource_fixup(struct pci_dev * dev, struct resource * res, - unsigned long start, unsigned long size) +void __init pcibios_init(void) { - return start; + if (sh_mv.mv_init_pci != NULL) { + sh_mv.mv_init_pci(); + } } + +/* Haven't done anything here as yet */ +char * __init pcibios_setup(char *str) +{ + return str; +} + +/* We don't have anything here to fixup */ +struct pci_fixup pcibios_fixups[] = { + {0, 0, 0, NULL} +}; diff --git a/arch/sh/kernel/semaphore.c b/arch/sh/kernel/semaphore.c index c958745b59b6..f733501c1cc6 100644 --- a/arch/sh/kernel/semaphore.c +++ b/arch/sh/kernel/semaphore.c @@ -12,6 +12,8 @@ #include #include +spinlock_t semaphore_wake_lock; + /* * Semaphores are implemented using a two-way counter: * The "count" variable is decremented for each process diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index be56f8570491..aaea2e6df23d 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -30,13 +30,16 @@ #endif #include #include +#include #include #include #include #include #include #include +#include #include +#include #ifdef CONFIG_SH_EARLY_PRINTK #include #endif @@ -53,10 +56,18 @@ extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */ extern int rd_image_start; /* starting block # of image */ #endif +#if defined(CONFIG_SH_GENERIC) || defined(CONFIG_SH_UNKNOWN) +struct sh_machine_vector sh_mv; +#endif + extern void fpu_init(void); extern int root_mountflags; extern int _text, _etext, _edata, _end; +#define MV_NAME_SIZE 32 + +static struct sh_machine_vector* __init get_mv_byname(const char* name); + /* * This is set up by the setup-routine at boot-time */ @@ -180,8 +191,10 @@ void sh_console_unregister(void) #endif - -static inline void parse_mem_cmdline (char ** cmdline_p) +static inline void parse_cmdline (char ** cmdline_p, char mv_name[MV_NAME_SIZE], + struct sh_machine_vector** mvp, + unsigned long *mv_io_base, + int *mv_mmio_enable) { char c = ' ', *to = command_line, *from = COMMAND_LINE; int len = 0; @@ -208,6 +221,35 @@ static inline void parse_mem_cmdline (char ** cmdline_p) memory_end = memory_start + mem_size; } } + if (c == ' ' && !memcmp(from, "sh_mv=", 6)) { + char* mv_end; + char* mv_comma; + int mv_len; + if (to != command_line) + to--; + from += 6; + mv_end = strchr(from, ' '); + if (mv_end == NULL) + mv_end = from + strlen(from); + + mv_comma = strchr(from, ','); + if ((mv_comma != NULL) && (mv_comma < mv_end)) { + int ints[3]; + get_options(mv_comma+1, ARRAY_SIZE(ints), ints); + *mv_io_base = ints[1]; + *mv_mmio_enable = ints[2]; + mv_len = mv_comma - from; + } else { + mv_len = mv_end - from; + } + if (mv_len > (MV_NAME_SIZE-1)) + mv_len = MV_NAME_SIZE-1; + memcpy(mv_name, from, mv_len); + mv_name[mv_len] = '\0'; + from = mv_end; + + *mvp = get_mv_byname(mv_name); + } c = *(from++); if (!c) break; @@ -221,6 +263,10 @@ static inline void parse_mem_cmdline (char ** cmdline_p) void __init setup_arch(char **cmdline_p) { + struct sh_machine_vector *mv = NULL; + char mv_name[MV_NAME_SIZE] = ""; + unsigned long mv_io_base = 0; + int mv_mmio_enable = 0; unsigned long bootmap_size; unsigned long start_pfn, max_pfn, max_low_pfn; @@ -248,7 +294,58 @@ void __init setup_arch(char **cmdline_p) data_resource.start = virt_to_bus(&_etext); data_resource.end = virt_to_bus(&_edata)-1; - parse_mem_cmdline(cmdline_p); + parse_cmdline(cmdline_p, mv_name, &mv, &mv_io_base, &mv_mmio_enable); + +#ifdef CONFIG_SH_GENERIC + if (mv == NULL) { + extern struct sh_machine_vector mv_unknown; + mv = &mv_unknown; + if (*mv_name != '\0') { + printk("Warning: Unsupported machine %s, using unknown\n", + mv_name); + } + } + sh_mv = *mv; +#endif +#ifdef CONFIG_SH_UNKNOWN + sh_mv = mv_unknown; +#endif + +#if defined(CONFIG_SH_GENERIC) || defined(CONFIG_SH_UNKNOWN) + if (mv_io_base != 0) { + sh_mv.mv_inb = generic_inb; + sh_mv.mv_inw = generic_inw; + sh_mv.mv_inl = generic_inl; + sh_mv.mv_outb = generic_outb; + sh_mv.mv_outw = generic_outw; + sh_mv.mv_outl = generic_outl; + + sh_mv.mv_inb_p = generic_inb_p; + sh_mv.mv_inw_p = generic_inw_p; + sh_mv.mv_inl_p = generic_inl_p; + sh_mv.mv_outb_p = generic_outb_p; + sh_mv.mv_outw_p = generic_outw_p; + sh_mv.mv_outl_p = generic_outl_p; + + sh_mv.mv_insb = generic_insb; + sh_mv.mv_insw = generic_insw; + sh_mv.mv_insl = generic_insl; + sh_mv.mv_outsb = generic_outsb; + sh_mv.mv_outsw = generic_outsw; + sh_mv.mv_outsl = generic_outsl; + + sh_mv.mv_isa_port2addr = generic_isa_port2addr; + generic_io_base = mv_io_base; + } + if (mv_mmio_enable != 0) { + sh_mv.mv_readb = generic_readb; + sh_mv.mv_readw = generic_readw; + sh_mv.mv_readl = generic_readl; + sh_mv.mv_writeb = generic_writeb; + sh_mv.mv_writew = generic_writew; + sh_mv.mv_writel = generic_writel; + } +#endif #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) #define PFN_DOWN(x) ((x) >> PAGE_SHIFT) @@ -358,6 +455,11 @@ void __init setup_arch(char **cmdline_p) #endif #endif + /* Perform the machine specific initialisation */ + if (sh_mv.mv_init_arch != NULL) { + sh_mv.mv_init_arch(); + } + #if defined(__SH4__) /* We already grab/initialized FPU in head.S. Make it consisitent. */ init_task.used_math = 1; @@ -366,10 +468,32 @@ void __init setup_arch(char **cmdline_p) paging_init(); } +struct sh_machine_vector* __init get_mv_byname(const char* name) +{ + extern int strcasecmp(const char *, const char *); + extern long __machvec_start, __machvec_end; + struct sh_machine_vector *all_vecs = + (struct sh_machine_vector *)&__machvec_start; + + int i, n = ((unsigned long)&__machvec_end + - (unsigned long)&__machvec_start)/ + sizeof(struct sh_machine_vector); + + for (i = 0; i < n; ++i) { + struct sh_machine_vector *mv = &all_vecs[i]; + if (mv == NULL) + continue; + if (strcasecmp(name, mv->mv_name) == 0) { + return mv; + } + } + return NULL; +} + /* * Get CPU information for use by the procfs. */ - +#ifdef CONFIG_PROC_FS int get_cpuinfo(char *buffer) { char *p = buffer; @@ -384,6 +508,7 @@ int get_cpuinfo(char *buffer) p += sprintf(p, "bogomips\t: %lu.%02lu\n\n", (loops_per_sec+2500)/500000, ((loops_per_sec+2500)/5000) % 100); + p += sprintf(p, "Machine: %s\n", sh_mv.mv_name); #define PRINT_CLOCK(name, value) \ p += sprintf(p, name " clock: %d.%02dMHz\n", \ @@ -395,3 +520,4 @@ int get_cpuinfo(char *buffer) return p - buffer; } +#endif diff --git a/arch/sh/kernel/setup_cqreek.c b/arch/sh/kernel/setup_cqreek.c new file mode 100644 index 000000000000..3e0422154d2b --- /dev/null +++ b/arch/sh/kernel/setup_cqreek.c @@ -0,0 +1,224 @@ +/* $Id: setup_cqreek.c,v 1.1 2000/08/05 06:25:23 gniibe Exp $ + * + * arch/sh/kernel/setup_cqreek.c + * + * Copyright (C) 2000 Niibe Yutaka + * + * CqREEK IDE/ISA Bridge Support. + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#define BRIDGE_FEATURE 0x0002 + +#define BRIDGE_IDE_CTRL 0x0018 +#define BRIDGE_IDE_INTR_LVL 0x001A +#define BRIDGE_IDE_INTR_MASK 0x001C +#define BRIDGE_IDE_INTR_STAT 0x001E + +#define BRIDGE_ISA_CTRL 0x0028 +#define BRIDGE_ISA_INTR_LVL 0x002A +#define BRIDGE_ISA_INTR_MASK 0x002C +#define BRIDGE_ISA_INTR_STAT 0x002E + +#define IDE_OFFSET 0xA4000000UL +#define ISA_OFFSET 0xA4A00000UL + +static unsigned long cqreek_port2addr(unsigned long port) +{ + if (0x0000<=port && port<=0x0040) + return IDE_OFFSET + port; + if ((0x01f0<=port && port<=0x01f7) || port == 0x03f6) + return IDE_OFFSET + port; + + return ISA_OFFSET + port; +} + +static void disable_cqreek_irq(unsigned int irq) +{ + unsigned long flags; + unsigned short mask; + + save_and_cli(flags); + /* Disable IRQ */ + mask = inw(BRIDGE_ISA_INTR_MASK) & ~(1 << irq); + outw_p(mask, BRIDGE_ISA_INTR_MASK); + restore_flags(flags); +} + +static void enable_cqreek_irq(unsigned int irq) +{ + unsigned long flags; + unsigned short mask; + + save_and_cli(flags); + /* Enable IRQ */ + mask = inw(BRIDGE_ISA_INTR_MASK) | (1 << irq); + outw_p(mask, BRIDGE_ISA_INTR_MASK); + restore_flags(flags); +} + +#define CLEAR_AT_ACCEPT + +static void mask_and_ack_cqreek(unsigned int irq) +{ + inw(BRIDGE_ISA_INTR_STAT); + disable_cqreek_irq(irq); +#ifdef CLEAR_AT_ACCEPT + /* Clear IRQ (it might be edge IRQ) */ + outw_p((1<used_math) { - __copy_to_user(&sc->sc_ownedfp, 0, sizeof(int)); + val = 0; + __copy_to_user(&sc->sc_ownedfp, &val, sizeof(int)); return 0; } - __copy_to_user(&sc->sc_ownedfp, 1, sizeof(int)); + val = 1; + __copy_to_user(&sc->sc_ownedfp, &val, sizeof(int)); /* This will cause a "finit" to be triggered by the next attempted FPU operation by the 'current' process. diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c index 2c73255f4785..f1e8d28bf15d 100644 --- a/arch/sh/kernel/time.c +++ b/arch/sh/kernel/time.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -226,6 +227,11 @@ static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *reg sh_do_profile(regs->pc); #endif +#ifdef CONFIG_HEARTBEAT + if (sh_mv.mv_heartbeat != NULL) + sh_mv.mv_heartbeat(); +#endif + /* * If we have an externally synchronized Linux clock, then update * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be @@ -441,11 +447,11 @@ void __init time_init(void) tmp = (frqcr & 0x2000) >> 11; tmp |= frqcr & 0x0003; pfc = pfc_table[tmp]; -#ifdef CONFIG_SH_HP600 - master_clock = cpu_clock/6; -#else - master_clock = cpu_clock; -#endif + if (MACH_HP600) { + master_clock = cpu_clock/6; + } else { + master_clock = cpu_clock; + } bus_clock = master_clock/pfc; } #elif defined(__SH4__) diff --git a/arch/sh/lib/Makefile b/arch/sh/lib/Makefile index 7af24f1c3c0a..a0d344cb9749 100644 --- a/arch/sh/lib/Makefile +++ b/arch/sh/lib/Makefile @@ -7,6 +7,6 @@ L_TARGET = lib.a L_OBJS = delay.o memcpy.o memset.o memmove.o memchr.o old-checksum.o \ - checksum.o + checksum.o strcasecmp.o include $(TOPDIR)/Rules.make diff --git a/arch/sh/lib/checksum.S b/arch/sh/lib/checksum.S index b34a65383df7..3317b3cccb36 100644 --- a/arch/sh/lib/checksum.S +++ b/arch/sh/lib/checksum.S @@ -185,15 +185,65 @@ ENTRY(csum_partial_copy_generic) mov.l r5,@-r15 mov.l r6,@-r15 + mov #3, r0 ! Check src and dest are equally aligned + mov r4, r1 + and r0, r1 + and r5, r0 + cmp/eq r1, r0 + bf 3f ! Different alignments, use slow version + tst #1,r0 ! Check dest word aligned + bf 3f ! If not, do it the slow way + mov #2,r0 - tst r0,r5 ! Check alignment. + tst r0,r5 ! Check dest alignment. bt 2f ! Jump if alignment is ok. add #-2,r6 ! Alignment uses up two bytes. cmp/pz r6 ! Jump if we had at least two bytes. bt/s 1f clrt bra 4f - add #2,r6 ! $r6 was < 2. Deal with it. + add #2,r6 ! $r6 was < 2. Deal with it. + +3: ! Handle different src and dest alinments. + ! This is not common, so simple byte by byte copy will do. + mov r6, r2 + shlr r6 + tst r6, r6 + bt 4f + clrt +SRC(5: mov.b @r4+,r0 ) +DST( mov.b r0,@r5 ) + add #1, r5 +SRC( mov.b @r4+,r1 ) +DST( mov.b r1,@r5 ) + add #1,r5 + + extu.b r0,r0 + extu.b r1,r1 +#ifdef __LITTLE_ENDIAN__ + shll8 r1 +#else + shll8 r0 +#endif + or r1,r0 + + addc r0,r7 + movt r0 + dt r6 + bf/s 5b + cmp/eq #1,r0 + mov #0,r0 + addc r0, r7 + + mov r2, r0 + tst #1, r0 + bt 7f + bra 5f + clrt + + ! src and dest equally aligned, but to a two byte boundary. + ! Handle first two bytes as a special case + .align 5 SRC(1: mov.w @r4+,r0 ) DST( mov.w r0,@r5 ) add #2,r5 diff --git a/arch/sh/lib/strcasecmp.c b/arch/sh/lib/strcasecmp.c new file mode 100644 index 000000000000..4e57a216feaf --- /dev/null +++ b/arch/sh/lib/strcasecmp.c @@ -0,0 +1,26 @@ +/* + * linux/arch/alpha/lib/strcasecmp.c + */ + +#include + + +/* We handle nothing here except the C locale. Since this is used in + only one place, on strings known to contain only 7 bit ASCII, this + is ok. */ + +int strcasecmp(const char *a, const char *b) +{ + int ca, cb; + + do { + ca = *a++ & 0xff; + cb = *b++ & 0xff; + if (ca >= 'A' && ca <= 'Z') + ca += 'a' - 'A'; + if (cb >= 'A' && cb <= 'Z') + cb += 'a' - 'A'; + } while (ca == cb && ca != '\0'); + + return ca - cb; +} diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile index 981c25380d76..1f1815600b80 100644 --- a/arch/sh/mm/Makefile +++ b/arch/sh/mm/Makefile @@ -8,6 +8,6 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := mm.o -O_OBJS := init.o fault.o ioremap.o extable.o cache.o +O_OBJS := init.o fault.o extable.o cache.o # ioremap.o include $(TOPDIR)/Rules.make diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c index 56f444bf41cb..af494b9a3a2e 100644 --- a/arch/sh/mm/cache.c +++ b/arch/sh/mm/cache.c @@ -207,6 +207,9 @@ static void icache_purge_range(unsigned long start, unsigned long end) * compared the tag of cache and if it's not matched, nothing * will be occurred. (We can avoid flushing other caches.) * + * NOTE: We can use A-bit feature here, because we have valid + * entriy in TLB (at least in UTLB), as dcache_wback_range is + * called before this function is called. */ for (v = start; v < end; v+=L1_CACHE_BYTES) { addr = CACHE_IC_ADDRESS_ARRAY | (v&CACHE_IC_ENTRY_MASK) @@ -225,8 +228,12 @@ static void icache_purge_range(unsigned long start, unsigned long end) */ void flush_icache_range(unsigned long start, unsigned long end) { + unsigned long flags; + + save_and_cli(flags); dcache_wback_range(start, end); icache_purge_range(start, end); + restore_flags(flags); } /* @@ -238,11 +245,6 @@ void flush_icache_page(struct vm_area_struct *vma, struct page *pg) { unsigned long phys, addr, data, i; - /* - * Alas, we don't know where the virtual address is, - * So, we can't use icache_purge_range(). - */ - /* Physical address of this page */ phys = (pg - mem_map)*PAGE_SIZE + __MEMORY_START; @@ -259,6 +261,30 @@ void flush_icache_page(struct vm_area_struct *vma, struct page *pg) back_to_P1(); } +/* + * Write back & invalidate the D-cache of the page. + * (To avoid "alias" issues) + */ +void flush_dcache_page(struct page *pg) +{ + unsigned long phys, addr, data, i; + + /* Physical address of this page */ + phys = (pg - mem_map)*PAGE_SIZE + __MEMORY_START; + + jump_to_P2(); + /* Loop all the D-cache */ + for (i=0; ivm_mm, addr, addr+PAGE_SIZE); + pgd_t *dir; + pmd_t *pmd; + pte_t *pte; + pte_t entry; + unsigned long phys; + struct page *pg; + + dir = pgd_offset(vma->vm_mm, addr); + pmd = pmd_offset(dir, addr); + if (pmd_none(*pmd)) + return; + if (pmd_bad(*pmd)) + return; + pte = pte_offset(pmd, addr); + entry = *pte; + if (pte_none(entry) || !pte_present(entry)) + return; + phys = pte_val(entry)&PAGE_MASK; + pg = virt_to_page(__va(phys)); + flush_dcache_page(pg); } /* * After accessing the memory from kernel space (P1-area), we need to - * write back the cache line, to avoid "alias" issues. + * write back the cache line to maintain DMA coherency. * * We search the D-cache to see if we have the entries corresponding to * the page, and if found, write back them. diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c index 9dd6ae451696..f2e342f0bef3 100644 --- a/arch/sh/mm/fault.c +++ b/arch/sh/mm/fault.c @@ -115,7 +115,8 @@ static void handle_vmalloc_fault(struct mm_struct *mm, unsigned long address) * ITLB is not affected by "ldtlb" instruction. * So, we need to flush the entry by ourselves. */ - __flush_tlb_page(mm, address&PAGE_MASK); + if (mm) + __flush_tlb_page(mm, address&PAGE_MASK); #endif update_mmu_cache(NULL, address, entry); } @@ -281,15 +282,14 @@ void update_mmu_cache(struct vm_area_struct * vma, save_and_cli(flags); #if defined(__SH4__) - if ((vma->vm_flags & VM_SHARED)) { + if (vma && (vma->vm_flags & VM_SHARED)) { + struct page *pg; + pteval = pte_val(pte); pteval &= PAGE_MASK; /* Physicall page address */ - __flush_tlb_phys(vma->vm_mm, pteval); - - /* It would be good we had routine which takes - physical memory as argument */ - flush_cache_page(vma, address&PAGE_MASK); + pg = virt_to_page(__va(pteval)); + flush_dcache_page(pg); } #endif diff --git a/arch/sh/vmlinux.lds.S b/arch/sh/vmlinux.lds.S index 1a7c2e820670..ad1fc1c1b576 100644 --- a/arch/sh/vmlinux.lds.S +++ b/arch/sh/vmlinux.lds.S @@ -61,6 +61,9 @@ SECTIONS __initcall_start = .; .initcall.init : { *(.initcall.init) } __initcall_end = .; + __machvec_start = .; + .machvec.init : { *(.machvec.init) } + __machvec_end = .; . = ALIGN(4096); __init_end = .; diff --git a/arch/sparc/config.in b/arch/sparc/config.in index 570f86325859..e603d2a64108 100644 --- a/arch/sparc/config.in +++ b/arch/sparc/config.in @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.99 2000/08/01 04:53:58 anton Exp $ +# $Id: config.in,v 1.100 2000/08/07 18:06:54 anton Exp $ # For a description of the syntax of this configuration file, # see Documentation/kbuild/config-language.txt. # @@ -86,13 +86,23 @@ comment 'Block devices' bool 'Normal floppy disk support' CONFIG_BLK_DEV_FD -bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD -if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then - tristate ' Linear (append) mode' CONFIG_MD_LINEAR - tristate ' RAID-0 (striping) mode' CONFIG_MD_STRIPED -# tristate ' RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING -# tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 -fi +tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP +dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET + +#tristate 'Logical volume manager (LVM) support' CONFIG_BLK_DEV_LVM N +#if [ "$CONFIG_BLK_DEV_LVM" != "n" ]; then +# bool ' LVM information in proc filesystem' CONFIG_LVM_PROC_FS Y +#fi + +tristate 'Multiple devices driver support' CONFIG_BLK_DEV_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 +dep_tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 $CONFIG_BLK_DEV_MD +#if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_RAID0" = "y" -o "$CONFIG_MD_RAID1" = "y" -o "$CONFIG_MD_RAID5" = "y" ]; then +# bool ' Boot support' CONFIG_MD_BOOT +# bool ' Auto Detect support' CONFIG_AUTODETECT_RAID +#fi tristate 'RAM disk support' CONFIG_BLK_DEV_RAM if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then @@ -100,9 +110,6 @@ if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then fi dep_bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM -tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP -tristate 'Network block device support' CONFIG_BLK_DEV_NBD - endmenu if [ "$CONFIG_NET" = "y" ]; then diff --git a/arch/sparc/defconfig b/arch/sparc/defconfig index c58948e7177e..8bac6f8e3bee 100644 --- a/arch/sparc/defconfig +++ b/arch/sparc/defconfig @@ -2,6 +2,7 @@ # Automatically generated make config: don't edit # CONFIG_UID16=y +CONFIG_HIGHMEM=y # # Code maturity level options @@ -108,14 +109,16 @@ CONFIG_SUN_AURORA=m # Block devices # CONFIG_BLK_DEV_FD=y -CONFIG_BLK_DEV_MD=y +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_MD=m CONFIG_MD_LINEAR=m -CONFIG_MD_STRIPED=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID5=m CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y -CONFIG_BLK_DEV_LOOP=m -CONFIG_BLK_DEV_NBD=m # # Networking options diff --git a/arch/sparc/mm/generic.c b/arch/sparc/mm/generic.c index ad74d0ed2a5f..dedb18f01ed6 100644 --- a/arch/sparc/mm/generic.c +++ b/arch/sparc/mm/generic.c @@ -1,4 +1,4 @@ -/* $Id: generic.c,v 1.9 1999/12/27 06:30:03 anton Exp $ +/* $Id: generic.c,v 1.10 2000/08/09 00:00:15 davem Exp $ * generic.c: Generic Sparc mm routines that are not dependent upon * MMU type but are Sparc specific. * diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c index 3d42e0c630e7..b0d45d82a60e 100644 --- a/arch/sparc/mm/init.c +++ b/arch/sparc/mm/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.89 2000/08/01 04:53:58 anton Exp $ +/* $Id: init.c,v 1.90 2000/08/09 00:00:15 davem Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff --git a/arch/sparc/mm/io-unit.c b/arch/sparc/mm/io-unit.c index f395f06f540c..1679384d6bf1 100644 --- a/arch/sparc/mm/io-unit.c +++ b/arch/sparc/mm/io-unit.c @@ -1,4 +1,4 @@ -/* $Id: io-unit.c,v 1.21 2000/02/06 22:55:45 zaitcev Exp $ +/* $Id: io-unit.c,v 1.22 2000/08/09 00:00:15 davem Exp $ * io-unit.c: IO-UNIT specific routines for memory management. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) diff --git a/arch/sparc/mm/iommu.c b/arch/sparc/mm/iommu.c index e48128479ca7..058fdd0d1781 100644 --- a/arch/sparc/mm/iommu.c +++ b/arch/sparc/mm/iommu.c @@ -1,4 +1,4 @@ -/* $Id: iommu.c,v 1.19 2000/02/06 22:55:45 zaitcev Exp $ +/* $Id: iommu.c,v 1.20 2000/08/09 00:00:15 davem Exp $ * iommu.c: IOMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index 7e76841de034..96fbf1b889a8 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c @@ -1,4 +1,4 @@ -/* $Id: srmmu.c,v 1.219 2000/08/01 04:53:58 anton Exp $ +/* $Id: srmmu.c,v 1.220 2000/08/09 00:00:15 davem Exp $ * srmmu.c: SRMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c index 717269b6807e..0ce0ca1e8236 100644 --- a/arch/sparc/mm/sun4c.c +++ b/arch/sparc/mm/sun4c.c @@ -1,4 +1,4 @@ -/* $Id: sun4c.c,v 1.196 2000/07/07 07:33:11 anton Exp $ +/* $Id: sun4c.c,v 1.197 2000/08/09 00:00:15 davem Exp $ * sun4c.c: Doing in software what should be done in hardware. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index dab4e3bcf149..c93f2efc8aeb 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.60 2000/07/16 18:21:24 ecd Exp $ +# $Id: Makefile,v 1.61 2000/08/09 08:25:19 jj Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -64,7 +64,7 @@ binfmt_elf32.o: $(TOPDIR)/fs/binfmt_elf.c ifneq ($(NEW_GCC),y) CMODEL_CFLAG := -mmedlow else - CMODEL_CFLAG := -mcmodel=medlow + CMODEL_CFLAG := -m64 -mcmodel=medlow endif check_asm: dummy diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S index 3295938e6935..729ecd911758 100644 --- a/arch/sparc64/kernel/rtrap.S +++ b/arch/sparc64/kernel/rtrap.S @@ -1,4 +1,4 @@ -/* $Id: rtrap.S,v 1.51 2000/07/28 09:43:39 davem Exp $ +/* $Id: rtrap.S,v 1.53 2000/08/06 05:20:35 davem Exp $ * rtrap.S: Preparing for return from trap on Sparc V9. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index 7d8a71d6af46..e77d8a3856d7 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.158 2000/07/29 00:55:49 davem Exp $ +/* $Id: sys_sparc32.c,v 1.159 2000/08/08 02:47:50 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -1037,7 +1037,8 @@ asmlinkage int sys32_utime(char * filename, struct utimbuf32 *times) struct iovec32 { u32 iov_base; __kernel_size_t32 iov_len; }; -typedef ssize_t (*IO_fn_t)(struct file *, char *, size_t, loff_t *); +typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *); +typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *); static long do_readv_writev32(int type, struct file *file, const struct iovec32 *vector, u32 count) @@ -1047,14 +1048,15 @@ static long do_readv_writev32(int type, struct file *file, struct iovec *iov=iovstack, *ivp; struct inode *inode; long retval, i; - IO_fn_t fn; + io_fn_t fn; + iov_fn_t fnv; /* First get the "struct iovec" from user memory and * verify all the pointers */ if (!count) return 0; - if(verify_area(VERIFY_READ, vector, sizeof(struct iovec32)*count)) + if (verify_area(VERIFY_READ, vector, sizeof(struct iovec32)*count)) return -EFAULT; if (count > UIO_MAXIOV) return -EINVAL; @@ -1086,33 +1088,19 @@ static long do_readv_writev32(int type, struct file *file, retval = locks_verify_area((type == VERIFY_WRITE ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE), inode, file, file->f_pos, tot_len); - if (retval) { - if (iov != iovstack) - kfree(iov); - return retval; - } + if (retval) + goto out; - /* Then do the actual IO. Note that sockets need to be handled - * specially as they have atomicity guarantees and can handle - * iovec's natively - */ - if (inode->i_sock) { - int err; - err = sock_readv_writev(type, inode, file, iov, count, tot_len); - if (iov != iovstack) - kfree(iov); - return err; + /* VERIFY_WRITE actually means a read, as we write to user space */ + fnv = (type == VERIFY_WRITE ? file->f_op->readv : file->f_op->writev); + if (fnv) { + retval = fnv(file, iov, count, &file->f_pos); + goto out; } - if (!file->f_op) { - if (iov != iovstack) - kfree(iov); - return -EINVAL; - } - /* VERIFY_WRITE actually means a read, as we write to user space */ - fn = file->f_op->read; - if (type == VERIFY_READ) - fn = (IO_fn_t) file->f_op->write; + fn = (type == VERIFY_WRITE ? file->f_op->read : + (io_fn_t) file->f_op->write); + ivp = iov; while (count > 0) { void * base; @@ -1124,17 +1112,18 @@ static long do_readv_writev32(int type, struct file *file, count--; nr = fn(file, base, len, &file->f_pos); if (nr < 0) { - if (retval) - break; - retval = nr; + if (!retval) + retval = nr; break; } retval += nr; if (nr != len) break; } +out: if (iov != iovstack) kfree(iov); + return retval; } @@ -1147,7 +1136,8 @@ asmlinkage long sys32_readv(int fd, struct iovec32 *vector, u32 count) if(!file) goto bad_file; - if (file->f_op && file->f_op->read && (file->f_mode & FMODE_READ)) + if (file->f_op && (file->f_mode & FMODE_READ) && + (file->f_op->readv || file->f_op->read)) ret = do_readv_writev32(VERIFY_WRITE, file, vector, count); fput(file); @@ -1163,7 +1153,8 @@ asmlinkage long sys32_writev(int fd, struct iovec32 *vector, u32 count) file = fget(fd); if(!file) goto bad_file; - if (file->f_op && file->f_op->write && (file->f_mode & FMODE_WRITE)) + if (file->f_op && (file->f_mode & FMODE_WRITE) && + (file->f_op->writev || file->f_op->write)) ret = do_readv_writev32(VERIFY_READ, file, vector, count); fput(file); diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c index cd4b3365c181..8c9b7c9fd240 100644 --- a/arch/sparc64/mm/fault.c +++ b/arch/sparc64/mm/fault.c @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.48 2000/05/03 06:37:03 davem Exp $ +/* $Id: fault.c,v 1.49 2000/08/09 00:00:15 davem Exp $ * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) diff --git a/arch/sparc64/mm/generic.c b/arch/sparc64/mm/generic.c index c469c6062655..68b77cfab4d3 100644 --- a/arch/sparc64/mm/generic.c +++ b/arch/sparc64/mm/generic.c @@ -1,4 +1,4 @@ -/* $Id: generic.c,v 1.13 1999/12/20 05:02:33 davem Exp $ +/* $Id: generic.c,v 1.14 2000/08/09 00:00:15 davem Exp $ * generic.c: Generic Sparc mm routines that are not dependent upon * MMU type but are Sparc specific. * diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 63994c51d388..7eef978365c5 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.153 2000/07/27 01:05:15 davem Exp $ +/* $Id: init.c,v 1.154 2000/08/09 00:00:15 davem Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu) diff --git a/drivers/acorn/char/keyb_arc.c b/drivers/acorn/char/keyb_arc.c index 4e37bb9d0115..93dd19ff3dbe 100644 --- a/drivers/acorn/char/keyb_arc.c +++ b/drivers/acorn/char/keyb_arc.c @@ -33,6 +33,7 @@ #include "../../char/busmouse.h" +extern struct tasklet_struct keyboard_tasklet; extern void kbd_reset_kdown(void); #define VERSION 108 @@ -402,7 +403,7 @@ static void a5kkbd_rx(int irq, void *dev_id, struct pt_regs *regs) { kbd_pt_regs = regs; if (handle_rawcode(inb(IOC_KARTRX))) - mark_bh (KEYBOARD_BH); + tasklet_schedule(&keyboard_tasklet); } static void a5kkbd_tx(int irq, void *dev_id, struct pt_regs *regs) diff --git a/drivers/acorn/char/keyb_ps2.c b/drivers/acorn/char/keyb_ps2.c index 8d26b37b1419..abd25b16dfac 100644 --- a/drivers/acorn/char/keyb_ps2.c +++ b/drivers/acorn/char/keyb_ps2.c @@ -341,6 +341,5 @@ int __init ps2kbd_init_hw(void) (void)IOMD_KARTRX; restore_flags (flags); - printk (KERN_INFO "PS/2 keyboard driver v%d.%02d\n", VERSION/100, VERSION%100); return 0; } diff --git a/drivers/acorn/scsi/fas216.c b/drivers/acorn/scsi/fas216.c index 85503d5340a1..c0f39caeae28 100644 --- a/drivers/acorn/scsi/fas216.c +++ b/drivers/acorn/scsi/fas216.c @@ -2463,7 +2463,7 @@ int fas216_eh_host_reset(Scsi_Cmnd *SCpnt) * IRQs after the sleep. */ spin_unlock_irq(&io_request_lock); - scsi_sleep(5); + scsi_sleep(25*HZ/100); spin_lock_irq(&io_request_lock); /* @@ -2628,7 +2628,7 @@ int fas216_init(struct Scsi_Host *instance) * scsi standard says wait 250ms */ spin_unlock_irq(&io_request_lock); - scsi_sleep(5); + scsi_sleep(25*HZ/100); spin_lock_irq(&io_request_lock); outb(info->scsi.cfg[0], REG_CNTL1(info)); diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index cf6e99878a0a..5c1fda2c3d6a 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -842,10 +842,10 @@ end_io: return 0; } -void generic_make_request (request_queue_t *q, int rw, struct buffer_head * bh) +void generic_make_request (int rw, struct buffer_head * bh) { int major = MAJOR(bh->b_rdev); - + request_queue_t *q; if (blk_size[major]) { unsigned long maxsector = (blk_size[major][MINOR(bh->b_rdev)] << 1) + 1; unsigned int sector, count; @@ -877,12 +877,21 @@ void generic_make_request (request_queue_t *q, int rw, struct buffer_head * bh) * still free to implement/resolve their own stacking * by explicitly returning 0) */ - while (q->make_request_fn(q, rw, bh)) - /* NOTE: we don't repeat the blk_size check even though we now have a - * new device. stacking drivers are expected to know what - * they are doing. - */ + /* NOTE: we don't repeat the blk_size check for each new device. + * Stacking drivers are expected to know what they are doing. + */ + do { q = blk_get_queue(bh->b_rdev); + if (!q) { + printk(KERN_ERR + "generic_make_request: Trying to access nonexistent block-device %s (%ld)\n", + kdevname(bh->b_rdev), bh->b_rsector); + buffer_IO_error(bh); + break; + } + + } + while (q->make_request_fn(q, rw, bh)); } /* This function can be used to request a number of buffers from a block @@ -892,19 +901,11 @@ void generic_make_request (request_queue_t *q, int rw, struct buffer_head * bh) void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]) { struct buffer_head *bh; - request_queue_t *q; unsigned int major; int correct_size; int i; major = MAJOR(bhs[0]->b_dev); - q = blk_get_queue(bhs[0]->b_dev); - if (!q) { - printk(KERN_ERR - "ll_rw_block: Trying to read nonexistent block-device %s (%ld)\n", - kdevname(bhs[0]->b_dev), bhs[0]->b_blocknr); - goto sorry; - } /* Determine correct block size for this device. */ correct_size = BLOCK_SIZE; @@ -948,7 +949,7 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]) bh->b_rdev = bh->b_dev; bh->b_rsector = bh->b_blocknr * (bh->b_size>>9); - generic_make_request(q, rw, bh); + generic_make_request(rw, bh); } return; diff --git a/drivers/block/md.c b/drivers/block/md.c index 9774233cca07..d54669fc8950 100644 --- a/drivers/block/md.c +++ b/drivers/block/md.c @@ -2741,7 +2741,7 @@ static int md_ioctl (struct inode *inode, struct file *file, if (md_copy_from_user(&info, (void*)arg, sizeof(info))) err = -EFAULT; else - err = add_new_disk(mddev, (void *)arg); + err = add_new_disk(mddev, &info); goto done_unlock; } case HOT_REMOVE_DISK: diff --git a/drivers/block/raid1.c b/drivers/block/raid1.c index baf839b1d563..4c364712a330 100644 --- a/drivers/block/raid1.c +++ b/drivers/block/raid1.c @@ -551,7 +551,6 @@ static int raid1_make_request (mddev_t *mddev, int rw, int disks = MD_SB_DISKS; int i, sum_bhs = 0, sectors; struct mirror_info *mirror; - request_queue_t *q; if (!buffer_locked(bh)) BUG(); @@ -628,8 +627,7 @@ static int raid1_make_request (mddev_t *mddev, int rw, /* bh_req->b_rsector = bh->n_rsector; */ bh_req->b_end_io = raid1_end_request; bh_req->b_private = r1_bh; - q = blk_get_queue(bh_req->b_rdev); - generic_make_request (q, rw, bh_req); + generic_make_request (rw, bh_req); return 0; } @@ -704,8 +702,7 @@ static int raid1_make_request (mddev_t *mddev, int rw, while(bh) { struct buffer_head *bh2 = bh; bh = bh->b_next; - q = blk_get_queue(bh2->b_rdev); - generic_make_request(q, rw, bh2); + generic_make_request(rw, bh2); } return (0); } @@ -1124,7 +1121,6 @@ static void raid1d (void *data) struct raid1_bh *r1_bh; struct buffer_head *bh; unsigned long flags; - request_queue_t *q; mddev_t *mddev; kdev_t dev; @@ -1206,8 +1202,7 @@ static void raid1d (void *data) while (mbh) { struct buffer_head *bh1 = mbh; mbh = mbh->b_next; - q = blk_get_queue(bh1->b_rdev); - generic_make_request(q, WRITE, bh1); + generic_make_request(WRITE, bh1); md_sync_acct(bh1->b_rdev, bh1->b_size/512); } } else { @@ -1220,8 +1215,7 @@ static void raid1d (void *data) printk (REDIRECT_SECTOR, partition_name(bh->b_dev), bh->b_blocknr); bh->b_rdev = bh->b_dev; - q = blk_get_queue(bh->b_rdev); - generic_make_request (q, READ, bh); + generic_make_request(READ, bh); } } @@ -1238,8 +1232,7 @@ static void raid1d (void *data) printk (REDIRECT_SECTOR, partition_name(bh->b_dev), bh->b_blocknr); bh->b_rdev = bh->b_dev; - q = blk_get_queue(bh->b_rdev); - generic_make_request (q, r1_bh->cmd, bh); + generic_make_request (r1_bh->cmd, bh); } break; } @@ -1348,7 +1341,6 @@ static int raid1_sync_request (mddev_t *mddev, unsigned long block_nr) { raid1_conf_t *conf = mddev_to_conf(mddev); struct mirror_info *mirror; - request_queue_t *q; struct raid1_bh *r1_bh; struct buffer_head *bh; int bsize; @@ -1435,8 +1427,7 @@ static int raid1_sync_request (mddev_t *mddev, unsigned long block_nr) bh->b_rsector = block_nr<<1; init_waitqueue_head(&bh->b_wait); - q = blk_get_queue(bh->b_rdev); - generic_make_request(q, READ, bh); + generic_make_request(READ, bh); md_sync_acct(bh->b_rdev, bh->b_size/512); return (bsize >> 10); diff --git a/drivers/block/raid5.c b/drivers/block/raid5.c index 346cc2759a5f..5d575a7f55cc 100644 --- a/drivers/block/raid5.c +++ b/drivers/block/raid5.c @@ -1017,7 +1017,6 @@ static void handle_stripe_write (mddev_t *mddev , raid5_conf_t *conf, int nr_failed_other, int nr_cache_overwrite, int nr_failed_overwrite) { int i, allclean; - request_queue_t *q; unsigned int block; struct buffer_head *bh; int method1 = INT_MAX, method2 = INT_MAX; @@ -1088,21 +1087,18 @@ static void handle_stripe_write (mddev_t *mddev , raid5_conf_t *conf, PRINTK("writing spare %d\n", i); atomic_inc(&sh->nr_pending); bh->b_dev = bh->b_rdev = conf->spare->dev; - q = blk_get_queue(bh->b_rdev); - generic_make_request(q, WRITERAW, bh); + generic_make_request(WRITERAW, bh); } else { #if 0 atomic_inc(&sh->nr_pending); bh->b_dev = bh->b_rdev = conf->disks[i].dev; - q = blk_get_queue(bh->b_rdev); - generic_make_request(q, WRITERAW, bh); + generic_make_request(WRITERAW, bh); #else if (!allclean || (i==sh->pd_idx)) { PRINTK("writing dirty %d\n", i); atomic_inc(&sh->nr_pending); bh->b_dev = bh->b_rdev = conf->disks[i].dev; - q = blk_get_queue(bh->b_rdev); - generic_make_request(q, WRITERAW, bh); + generic_make_request(WRITERAW, bh); } else { PRINTK("not writing clean %d\n", i); raid5_end_request(bh, 1); @@ -1147,8 +1143,7 @@ static void handle_stripe_write (mddev_t *mddev , raid5_conf_t *conf, lock_get_bh(sh->bh_old[i]); atomic_inc(&sh->nr_pending); sh->bh_old[i]->b_dev = sh->bh_old[i]->b_rdev = conf->disks[i].dev; - q = blk_get_queue(sh->bh_old[i]->b_rdev); - generic_make_request(q, READ, sh->bh_old[i]); + generic_make_request(READ, sh->bh_old[i]); atomic_dec(&sh->bh_old[i]->b_count); } PRINTK("handle_stripe() %lu, reading %d old buffers\n", sh->sector, md_atomic_read(&sh->nr_pending)); @@ -1163,7 +1158,6 @@ static void handle_stripe_read (mddev_t *mddev , raid5_conf_t *conf, int nr_failed_other, int nr_cache_overwrite, int nr_failed_overwrite) { int i; - request_queue_t *q; int method1 = INT_MAX; method1 = nr_read - nr_cache_overwrite; @@ -1194,8 +1188,7 @@ static void handle_stripe_read (mddev_t *mddev , raid5_conf_t *conf, lock_get_bh(sh->bh_old[i]); atomic_inc(&sh->nr_pending); sh->bh_old[i]->b_dev = sh->bh_old[i]->b_rdev = conf->disks[i].dev; - q = blk_get_queue(sh->bh_old[i]->b_rdev); - generic_make_request(q, READ, sh->bh_old[i]); + generic_make_request(READ, sh->bh_old[i]); atomic_dec(&sh->bh_old[i]->b_count); } PRINTK("handle_stripe() %lu, phase READ_OLD, pending %d buffers\n", sh->sector, md_atomic_read(&sh->nr_pending)); @@ -1224,8 +1217,7 @@ static void handle_stripe_read (mddev_t *mddev , raid5_conf_t *conf, lock_get_bh(sh->bh_req[i]); atomic_inc(&sh->nr_pending); sh->bh_req[i]->b_dev = sh->bh_req[i]->b_rdev = conf->disks[i].dev; - q = blk_get_queue(sh->bh_req[i]->b_rdev); - generic_make_request(q, READ, sh->bh_req[i]); + generic_make_request(READ, sh->bh_req[i]); atomic_dec(&sh->bh_req[i]->b_count); } PRINTK("handle_stripe() %lu, phase READ, pending %d\n", sh->sector, md_atomic_read(&sh->nr_pending)); @@ -1239,7 +1231,6 @@ static void handle_stripe_sync (mddev_t *mddev , raid5_conf_t *conf, int parity, int parity_failed, int nr_cache, int nr_cache_other, int nr_failed_other, int nr_cache_overwrite, int nr_failed_overwrite) { - request_queue_t *q; struct buffer_head *bh; int i, pd_idx; @@ -1262,8 +1253,7 @@ static void handle_stripe_sync (mddev_t *mddev , raid5_conf_t *conf, lock_get_bh(bh); atomic_inc(&sh->nr_pending); bh->b_dev = bh->b_rdev = conf->disks[i].dev; - q = blk_get_queue(bh->b_rdev); - generic_make_request(q, READ, bh); + generic_make_request(READ, bh); md_sync_acct(bh->b_rdev, bh->b_size/512); atomic_dec(&sh->bh_old[i]->b_count); } @@ -1292,8 +1282,7 @@ static void handle_stripe_sync (mddev_t *mddev , raid5_conf_t *conf, atomic_inc(&sh->nr_pending); lock_get_bh(bh); bh->b_dev = bh->b_rdev = conf->spare->dev; - q = blk_get_queue(bh->b_rdev); - generic_make_request(q, WRITERAW, bh); + generic_make_request(WRITERAW, bh); md_sync_acct(bh->b_rdev, bh->b_size/512); atomic_dec(&bh->b_count); PRINTK("handle_stripe_sync() %lu, phase WRITE, pending %d buffers\n", sh->sector, md_atomic_read(&sh->nr_pending)); @@ -1319,8 +1308,7 @@ static void handle_stripe_sync (mddev_t *mddev , raid5_conf_t *conf, lock_get_bh(bh); atomic_inc(&sh->nr_pending); bh->b_dev = bh->b_rdev = conf->disks[pd_idx].dev; - q = blk_get_queue(bh->b_rdev); - generic_make_request(q, WRITERAW, bh); + generic_make_request(WRITERAW, bh); md_sync_acct(bh->b_rdev, bh->b_size/512); atomic_dec(&bh->b_count); PRINTK("handle_stripe_sync() %lu phase WRITE, pending %d buffers\n", diff --git a/drivers/block/xd.h b/drivers/block/xd.h index 1612f321d0fe..7babb59b96d0 100644 --- a/drivers/block/xd.h +++ b/drivers/block/xd.h @@ -103,7 +103,6 @@ typedef struct { const char *name; } XD_SIGNATURE; -static int xd_setup (char *); #ifndef MODULE static int xd_manual_geo_init (char *command); #endif /* MODULE */ diff --git a/drivers/char/busmouse.c b/drivers/char/busmouse.c index 9bfe4b2b3c52..9a983bb3e3bf 100644 --- a/drivers/char/busmouse.c +++ b/drivers/char/busmouse.c @@ -172,12 +172,10 @@ static int busmouse_release(struct inode *inode, struct file *file) busmouse_fasync(-1, file, 0); if (--mse->active == 0) { - if (mse->ops) { - if (mse->ops->release) - ret = mse->ops->release(inode, file); - if (mse->ops->owner) - __MOD_DEC_USE_COUNT(mse->ops->owner); - } + if (mse->ops->release) + ret = mse->ops->release(inode, file); + if (mse->ops->owner) + __MOD_DEC_USE_COUNT(mse->ops->owner); mse->ready = 0; } unlock_kernel(); @@ -189,7 +187,7 @@ static int busmouse_open(struct inode *inode, struct file *file) { struct busmouse_data *mse; unsigned int mousedev; - int ret = -ENODEV; + int ret; mousedev = DEV_TO_MOUSE(inode->i_rdev); if (mousedev >= NR_MICE) @@ -197,13 +195,15 @@ static int busmouse_open(struct inode *inode, struct file *file) down(&mouse_sem); mse = busmouse_data[mousedev]; - if (!mse) - /* shouldn't happen, but... */ + ret = -ENODEV; + if (!mse || !mse->ops) /* shouldn't happen, but... */ goto end; - - if (mse->ops && mse->ops->owner) - __MOD_INC_USE_COUNT(mse->ops->owner); - if (mse->ops && mse->ops->open) { + + if (mse->ops->owner && !try_inc_mod_count(mse->ops->owner)) + goto end; + + ret = 0; + if (mse->ops->open) { ret = mse->ops->open(inode, file); if (ret && mse->ops->owner) __MOD_DEC_USE_COUNT(mse->ops->owner); @@ -222,10 +222,7 @@ static int busmouse_open(struct inode *inode, struct file *file) mse->ready = 0; mse->dxpos = 0; mse->dypos = 0; - if (mse->ops) - mse->buttons = mse->ops->init_button_state; - else - mse->buttons = 7; + mse->buttons = mse->ops->init_button_state; spin_unlock_irq(&mse->lock); end: diff --git a/drivers/char/console.c b/drivers/char/console.c index 3f51c056a05e..67654551c29b 100644 --- a/drivers/char/console.c +++ b/drivers/char/console.c @@ -2674,6 +2674,7 @@ void unblank_screen(void) console_blanked = 0; if (console_blank_hook) console_blank_hook(0); + set_palette(currcons); if (sw->con_blank(vc_cons[currcons].d, 0)) /* Low-level driver cannot restore -> do it ourselves */ update_screen(fg_console); diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index 4f85d07ca931..0fa205717850 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -46,6 +46,7 @@ #include #include #include /* For (un)lock_kernel */ +#include #include #include #include @@ -140,7 +141,7 @@ typedef struct wait_queue *wait_queue_head_t; #endif /* virt_to_page added in 2.4.0-test6 */ -#ifndef virt_to_page +#if LINUX_VERSION_CODE < 0x020400 #define virt_to_page(kaddr) (mem_map + MAP_NR(kaddr)) #endif diff --git a/drivers/char/hp600_keyb.c b/drivers/char/hp600_keyb.c index 7e48ad82149b..4a109265a38f 100644 --- a/drivers/char/hp600_keyb.c +++ b/drivers/char/hp600_keyb.c @@ -5,7 +5,9 @@ */ #include +#include #include +#include #include #include "scan_keyb.h" @@ -23,7 +25,7 @@ static const unsigned char hp690_japanese_table[]={ 0x00, 0x00, 0x00, 0x2c, 0x00, 0x1c, 0x28, 0x35, 0x31, 0x30, 0x32, 0x33, 0x34, 0x2f, 0x2e, 0x2d, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x50, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x50, 0x7b, 0x38, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -46,25 +48,35 @@ static const unsigned char hp690_japanese_table[]={ }; +static const unsigned char hp690_switch[]= { + 0xfd, 0xff, + 0xdf, 0xff, + 0x7f, 0xff, + 0xff, 0xfe, + 0xff, 0xfd, + 0xff, 0xf7, + 0xff, 0xbf, + 0xff, 0x7f, +}; + + static void hp690_japanese_scan_kbd(unsigned char *s) { - ctrl_outb(0xfd, PDDR); ctrl_outb(0xff, PEDR); - *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR); - ctrl_outb(0xdf, PDDR); ctrl_outb(0xff, PEDR); - *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR); - ctrl_outb(0x7f, PDDR); ctrl_outb(0xff, PEDR); - *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR); - ctrl_outb(0xff, PDDR); ctrl_outb(0xfe, PEDR); - *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR); - ctrl_outb(0xff, PDDR); ctrl_outb(0xfd, PEDR); - *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR); - ctrl_outb(0xff, PDDR); ctrl_outb(0xf7, PEDR); - *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR); - ctrl_outb(0xff, PDDR); ctrl_outb(0xbf, PEDR); - *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR); - ctrl_outb(0xff, PDDR); ctrl_outb(0x7f, PEDR); - *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR); - *s++=ctrl_inb(PGDR); *s++=ctrl_inb(PHDR); + int i; + unsigned const char *t=hp690_switch; + + for(i=0; i<9; i++) { + ctrl_outb(*t++, PDDR); + ctrl_outb(*t++, PEDR); + *s++=ctrl_inb(PCDR); + *s++=ctrl_inb(PFDR); + } + + ctrl_outb(0xff, PDDR); + ctrl_outb(0xff, PEDR); + + *s++=ctrl_inb(PGDR); + *s++=ctrl_inb(PHDR); } diff --git a/drivers/char/scan_keyb.c b/drivers/char/scan_keyb.c index 7ec7034e0ff7..1936e0b6eeb4 100644 --- a/drivers/char/scan_keyb.c +++ b/drivers/char/scan_keyb.c @@ -91,9 +91,9 @@ int register_scan_keyboard(void (*scan)(unsigned char *buffer), kbd->s0=kbd->s1=NULL; if((kbd->s0=kmalloc(length, GFP_KERNEL))==NULL) - goto error_out; + goto error_mem_free; if((kbd->s1=kmalloc(length, GFP_KERNEL))==NULL) - goto error_out; + goto error_mem_free; kbd->scan(kbd->s0); kbd->scan(kbd->s1); diff --git a/drivers/char/sh-sci.c b/drivers/char/sh-sci.c index 12ab34d721f5..0605674e0755 100644 --- a/drivers/char/sh-sci.c +++ b/drivers/char/sh-sci.c @@ -60,8 +60,10 @@ static int sercons_baud; static void sci_init_pins_sci(struct sci_port* port, unsigned int cflag); #ifndef SCI_ONLY static void sci_init_pins_scif(struct sci_port* port, unsigned int cflag); -#endif +#if defined(__sh3__) static void sci_init_pins_irda(struct sci_port* port, unsigned int cflag); +#endif +#endif static void sci_disable_tx_interrupts(void *ptr); static void sci_enable_tx_interrupts(void *ptr); static void sci_disable_rx_interrupts(void *ptr); @@ -106,6 +108,8 @@ static void put_char(struct sci_port *port, char c) restore_flags(flags); } +#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB + static void handle_error(struct sci_port *port) { /* Clear error flags */ sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); @@ -133,8 +137,6 @@ static int get_char(struct sci_port *port) return c; } -#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB - /* Taken from sh-stub.c of GDB 4.18 */ static const char hexchars[] = "0123456789abcdef"; @@ -221,7 +223,7 @@ static void sci_init_pins_sci(struct sci_port* port, unsigned int cflag) #if defined(SCIF_ONLY) || defined(SCI_AND_SCIF) #if defined(__sh3__) -/* For SH7709, SH7709A, SH7729 */ +/* For SH7707, SH7709, SH7709A, SH7729 */ static void sci_init_pins_scif(struct sci_port* port, unsigned int cflag) { unsigned int fcr_val = 0; @@ -328,7 +330,7 @@ static void sci_set_baud(struct sci_port *port, int baud) t = BPS_38400; break; default: - printk(KERN_INFO "sci: unsupported baud rate: %d, use 115200 instead.\n", baud); + printk(KERN_INFO "sci: unsupported baud rate: %d, using 115200 instead.\n", baud); case 115200: t = BPS_115200; break; @@ -412,6 +414,17 @@ static int sci_set_real_termios(void *ptr) * the interrupt related routines * * ********************************************************************** */ +/* + * This routine is used by the interrupt handler to schedule + * processing in the software interrupt portion of the driver. + */ +static inline void sci_sched_event(struct sci_port *port, int event) +{ + port->event |= 1 << event; + queue_task(&port->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + static void sci_transmit_chars(struct sci_port *port) { int count, i; @@ -459,6 +472,8 @@ static void sci_transmit_chars(struct sci_port *port) } sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); + port->icount.tx += count; + /* Update the kernel buffer end */ port->gs.xmit_tail = (port->gs.xmit_tail + count) & (SERIAL_XMIT_SIZE-1); @@ -467,12 +482,8 @@ static void sci_transmit_chars(struct sci_port *port) port->gs.xmit_cnt -= count; } - if (port->gs.xmit_cnt <= port->gs.wakeup_chars) { - if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - port->gs.tty->ldisc.write_wakeup) - (port->gs.tty->ldisc.write_wakeup)(port->gs.tty); - wake_up_interruptible(&port->gs.tty->write_wait); - } + if (port->gs.xmit_cnt <= port->gs.wakeup_chars) + sci_sched_event(port, SCI_EVENT_WRITE_WAKEUP); save_and_cli(flags); ctrl = sci_in(port, SCSCR); @@ -530,6 +541,7 @@ static inline void sci_receive_chars(struct sci_port *port) tty->flip.flag_buf_ptr += count; copied += count; + port->icount.rx += count; } if (copied) @@ -572,6 +584,23 @@ static void sci_er_interrupt(int irq, void *ptr, struct pt_regs *regs) sci_tx_interrupt(irq, ptr, regs); } +static void do_softint(void *private_) +{ + struct sci_port *port = (struct sci_port *) private_; + struct tty_struct *tty; + + tty = port->gs.tty; + if (!tty) + return; + + if (test_and_clear_bit(SCI_EVENT_WRITE_WAKEUP, &port->event)) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); + } +} + /* ********************************************************************** * * Here are the routines that actually * * interface with the generic_serial driver * @@ -675,6 +704,10 @@ static int sci_open(struct tty_struct * tty, struct file * filp) port->gs.tty = tty; port->gs.count++; + port->event = 0; + port->tqueue.routine = do_softint; + port->tqueue.data = port; + /* * Start up serial port */ @@ -841,9 +874,22 @@ static int sci_read_proc(char *page, char **start, off_t off, int count, len += sprintf(page, "sciinfo:0.1\n"); for (i = 0; i < SCI_NPORTS && len < 4000; i++) { port = &sci_ports[i]; - len += sprintf(page+len, "%d: uart:%s address: %08x\n", i, + len += sprintf(page+len, "%d: uart:%s address: %08x", i, (port->type == PORT_SCI) ? "SCI" : "SCIF", port->base); + len += sprintf(page+len, " baud:%d", port->gs.baud); + len += sprintf(page+len, " tx:%d rx:%d", + port->icount.tx, port->icount.rx); + + if (port->icount.frame) + len += sprintf(page+len, " fe:%d", port->icount.frame); + if (port->icount.parity) + len += sprintf(page+len, " pe:%d", port->icount.parity); + if (port->icount.brk) + len += sprintf(page+len, " brk:%d", port->icount.brk); + if (port->icount.overrun) + len += sprintf(page+len, " oe:%d", port->icount.overrun); + len += sprintf(page+len, "\n"); } return len; } @@ -923,6 +969,11 @@ static int sci_init_drivers(void) init_waitqueue_head(&port->gs.open_wait); init_waitqueue_head(&port->gs.close_wait); port->old_cflag = 0; + port->icount.cts = port->icount.dsr = + port->icount.rng = port->icount.dcd = 0; + port->icount.rx = port->icount.tx = 0; + port->icount.frame = port->icount.parity = 0; + port->icount.overrun = port->icount.brk = 0; } return 0; @@ -943,8 +994,6 @@ int __init sci_init(void) 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++) { - set_ipr_data(port->irqs[i], port->intc_addr, port->intc_pos, SCI_PRIORITY); - if (request_irq(port->irqs[i], handlers[i], SA_INTERRUPT, "sci", port)) { printk(KERN_ERR "sci: Cannot allocate irq.\n"); diff --git a/drivers/char/sh-sci.h b/drivers/char/sh-sci.h index b9ecad78b8bd..c38e97c52c1e 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, INTC reg, INTC pos */ -#define SCI_IRQS { 23, 24, 25 }, INTC_IPRB, 1 -#define SH3_SCIF_IRQS { 56, 57, 59 }, INTC_IPRE, 1 -#define SH3_IRDA_IRQS { 52, 53, 55 }, INTC_IPRE, 2 -#define SH4_SCIF_IRQS { 40, 41, 43 }, INTC_IPRC, 1 +/* 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 } #if defined(CONFIG_CPU_SUBTYPE_SH7708) # define SCI_NPORTS 1 @@ -34,12 +34,12 @@ # define SCSPTR 0xffffff7c /* 8 bit */ # define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ # define SCI_ONLY -#elif defined(CONFIG_CPU_SUBTYPE_SH7709) +#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) # define SCI_NPORTS 3 # define SCI_INIT { \ - { {}, PORT_SCI, 0xfffffe80, SCI_IRQS, sci_init_pins_sci }, \ - { {}, PORT_SCIF, 0xA4000150, SH3_SCIF_IRQS, sci_init_pins_scif }, \ - { {}, PORT_SCIF, 0xA4000140, SH3_IRDA_IRQS, sci_init_pins_irda } \ + { {}, PORT_SCI, 0xfffffe80, SCI_IRQS, sci_init_pins_sci }, \ + { {}, PORT_SCIF, 0xA4000150, SH3_SCIF_IRQS, sci_init_pins_scif }, \ + { {}, PORT_SCIF, 0xA4000140, SH3_IRDA_IRQS, sci_init_pins_irda } \ } # define SCPCR 0xA4000116 /* 16 bit SCI and SCIF */ # define SCPDR 0xA4000136 /* 8 bit SCI and SCIF */ @@ -68,32 +68,32 @@ #define SCI_CTRL_FLAGS_TE 0x20 /* all */ #define SCI_CTRL_FLAGS_RE 0x10 /* all */ /* SCI_CTRL_FLAGS_REIE 0x08 * 7750 SCIF */ -/* SCI_CTRL_FLAGS_MPIE 0x08 * 7708 SCI, 7709 SCI, 7750 SCI */ -/* SCI_CTRL_FLAGS_TEIE 0x04 * 7708 SCI, 7709 SCI, 7750 SCI */ +/* SCI_CTRL_FLAGS_MPIE 0x08 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ +/* SCI_CTRL_FLAGS_TEIE 0x04 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ /* SCI_CTRL_FLAGS_CKE1 0x02 * all */ -/* SCI_CTRL_FLAGS_CKE0 0x01 * 7708 SCI, 7709 SCI/SCIF, 7750 SCI */ +/* SCI_CTRL_FLAGS_CKE0 0x01 * 7707 SCI/SCIF, 7708 SCI, 7709 SCI/SCIF, 7750 SCI */ /* SCxSR SCI */ -#define SCI_TDRE 0x80 /* 7708 SCI, 7709 SCI, 7750 SCI */ -#define SCI_RDRF 0x40 /* 7708 SCI, 7709 SCI, 7750 SCI */ -#define SCI_ORER 0x20 /* 7708 SCI, 7709 SCI, 7750 SCI */ -#define SCI_FER 0x10 /* 7708 SCI, 7709 SCI, 7750 SCI */ -#define SCI_PER 0x08 /* 7708 SCI, 7709 SCI, 7750 SCI */ -#define SCI_TEND 0x04 /* 7708 SCI, 7709 SCI, 7750 SCI */ -/* SCI_MPB 0x02 * 7708 SCI, 7709 SCI, 7750 SCI */ -/* SCI_MPBT 0x01 * 7708 SCI, 7709 SCI, 7750 SCI */ +#define SCI_TDRE 0x80 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ +#define SCI_RDRF 0x40 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ +#define SCI_ORER 0x20 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ +#define SCI_FER 0x10 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ +#define SCI_PER 0x08 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ +#define SCI_TEND 0x04 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ +/* SCI_MPB 0x02 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ +/* SCI_MPBT 0x01 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ #define SCI_ERRORS ( SCI_PER | SCI_FER | SCI_ORER) /* SCxSR SCIF */ -#define SCIF_ER 0x0080 /* 7709 SCIF, 7750 SCIF */ -#define SCIF_TEND 0x0040 /* 7709 SCIF, 7750 SCIF */ -#define SCIF_TDFE 0x0020 /* 7709 SCIF, 7750 SCIF */ -#define SCIF_BRK 0x0010 /* 7709 SCIF, 7750 SCIF */ -#define SCIF_FER 0x0008 /* 7709 SCIF, 7750 SCIF */ -#define SCIF_PER 0x0004 /* 7709 SCIF, 7750 SCIF */ -#define SCIF_RDF 0x0002 /* 7709 SCIF, 7750 SCIF */ -#define SCIF_DR 0x0001 /* 7709 SCIF, 7750 SCIF */ +#define SCIF_ER 0x0080 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */ +#define SCIF_TEND 0x0040 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */ +#define SCIF_TDFE 0x0020 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */ +#define SCIF_BRK 0x0010 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */ +#define SCIF_FER 0x0008 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */ +#define SCIF_PER 0x0004 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */ +#define SCIF_RDF 0x0002 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */ +#define SCIF_DR 0x0001 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */ #define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK) @@ -128,8 +128,6 @@ #define SCFCR_TFRST 0x0004 #define SCFCR_MCE 0x0008 -#define SCI_PRIORITY 3 - #define SCI_MAJOR 204 #define SCI_MINOR_START 8 @@ -161,14 +159,22 @@ #define SCI_MAGIC 0xbabeface +/* + * Events are used to schedule things to happen at timer-interrupt + * time, instead of at rs interrupt time. + */ +#define SCI_EVENT_WRITE_WAKEUP 0 + struct sci_port { struct gs_port gs; int type; unsigned int base; unsigned char irqs[3]; /* ERI, RXI, TXI */ - unsigned int intc_addr, intc_pos; void (*init_pins)(struct sci_port* port, unsigned int cflag); unsigned int old_cflag; + struct async_icount icount; + struct tq_struct tqueue; + unsigned long event; }; #define SCI_IN(size, offset) \ diff --git a/drivers/net/Config.in b/drivers/net/Config.in index 2238ce5a9de0..2f9442b22522 100644 --- a/drivers/net/Config.in +++ b/drivers/net/Config.in @@ -51,7 +51,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then if [ "$CONFIG_SGI_IP27" = "y" ]; then bool ' SGI IOC3 Ethernet' CONFIG_SGI_IOC3_ETH fi - if [ "$CONFIG_SUPERH" = "y" -a "$CONFIG_SH_SOLUTION_ENGINE" = "y" ]; then + if [ "$CONFIG_SUPERH" = "y" ]; then tristate ' National DP83902AV support' CONFIG_STNIC fi bool ' 3COM cards' CONFIG_NET_VENDOR_3COM diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index 1c297dbec58e..2542fa2d0b42 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -1292,6 +1292,12 @@ static void __init bmac_probe1(struct device_node *bmac, int is_bmac_plus) dev = init_etherdev(NULL, PRIV_BYTES); + if (!dev) { + printk(KERN_ERR "init_etherdev failed, out of memory for BMAC %s\n", + bmac->full_name); + return; + } + dev->base_addr = (unsigned long) ioremap(bmac->addrs[0].address, bmac->addrs[0].size); dev->irq = bmac->intrs[0].line; diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index 233b1e4d35f1..c343bc53c711 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -568,8 +568,11 @@ static const char is_mii[] = { 0, 1, 1, 0, 1, 1, 0, 1 }; static int eepro100_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); static void eepro100_remove_one (struct pci_dev *pdev); + +#ifdef CONFIG_EEPRO100_PM static void eepro100_suspend (struct pci_dev *pdev); static void eepro100_resume (struct pci_dev *pdev); +#endif /* CONFIG_EEPRO100_PM */ static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len); static int mdio_read(long ioaddr, int phy_id, int location); @@ -2182,6 +2185,9 @@ static void set_rx_mode(struct net_device *dev) sp->rx_mode = new_rx_mode; } + +#ifdef CONFIG_EEPRO100_PM + static void eepro100_suspend(struct pci_dev *pdev) { struct net_device *dev = pdev->driver_data; @@ -2214,6 +2220,8 @@ static void eepro100_resume(struct pci_dev *pdev) set_rx_mode(dev); } +#endif /* CONFIG_EEPRO100_PM */ + static void __devexit eepro100_remove_one (struct pci_dev *pdev) { struct net_device *dev = pdev->driver_data; @@ -2252,7 +2260,8 @@ static struct pci_driver eepro100_driver = { id_table: eepro100_pci_tbl, probe: eepro100_init_one, remove: eepro100_remove_one, -#if 0 /* These seem to be broken.. */ + +#ifdef CONFIG_EEPRO100_PM suspend: eepro100_suspend, resume: eepro100_resume, #endif diff --git a/drivers/net/gmac.c b/drivers/net/gmac.c index 17d32829489e..0457d374f27b 100644 --- a/drivers/net/gmac.c +++ b/drivers/net/gmac.c @@ -5,6 +5,10 @@ * Copyright (C) 2000 Paul Mackerras & Ben. Herrenschmidt * * portions based on sunhme.c by David S. Miller + * + * Changes: + * Arnaldo Carvalho de Melo - 08/06/2000 + * - check init_etherdev return in gmac_probe1 * */ @@ -1178,7 +1182,13 @@ gmac_probe1(struct device_node *gmac) } dev = init_etherdev(0, sizeof(struct gmac)); - memset(dev->priv, 0, sizeof(struct gmac)); + + if (!dev) { + printk(KERN_ERR "GMAC: init_etherdev failed, out of memory\n"); + free_page(tx_descpage); + free_page(rx_descpage); + return; + } gm = (struct gmac *) dev->priv; dev->base_addr = gmac->addrs[0].address; diff --git a/drivers/net/hydra.c b/drivers/net/hydra.c index 8e5511da17a6..fd2c79235da9 100644 --- a/drivers/net/hydra.c +++ b/drivers/net/hydra.c @@ -13,6 +13,11 @@ /* The Amiganet is a Zorro-II board made by Hydra Systems. It contains a */ /* NS8390 NIC (network interface controller) clone, 16 or 64K on-board RAM */ /* and 10BASE-2 (thin coax) and AUI connectors. */ +/* */ +/* Changes */ +/* Arnaldo Carvalho de Melo - 08/06/2000 */ +/* - check init_etherdev in hydra_probe */ +/* - dev->priv is already zeroed by init_etherdev */ #include @@ -176,8 +181,13 @@ int __init hydra_probe(struct net_device *dev) strcpy(z->name, "Hydra Ethernet Card"); dev = init_etherdev(NULL, sizeof(struct hydra_private)); - memset(dev->priv, 0, sizeof(struct hydra_private)); - + + if (!dev) { + release_mem_region(base_addr, 0x20); + release_mem_region(board, 0x4000); + continue; + } + for(j = 0; j < ETHER_ADDR_LEN; j++) dev->dev_addr[j] = *((u8 *)ZTWO_VADDR(board + HYDRA_ADDRPROM + 2*j)); diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c index 0c914aec2faf..8d7bc5392268 100644 --- a/drivers/net/pcmcia/com20020_cs.c +++ b/drivers/net/pcmcia/com20020_cs.c @@ -21,6 +21,11 @@ * modified by SRC, incorporated herein by reference. * * ********************** + * Changes: + * Arnaldo Carvalho de Melo - 08/08/2000 + * - reorganize kmallocs in com20020_attach, checking all for failure + * and releasing the previous allocations if one fails + * ********************** * * For more details, see drivers/net/arcnet.c * @@ -198,7 +203,24 @@ static dev_link_t *com20020_attach(void) link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); if (!link) return NULL; + + info = kmalloc(sizeof(struct com20020_dev_t), GFP_KERNEL); + if (!info) + goto fail_alloc_info; + + lp = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); + if (!lp) + goto fail_alloc_lp; + + dev = dev_alloc("arc%d", &ret); + if (!dev) + goto fail_alloc_dev; + + memset(info, 0, sizeof(struct com20020_dev_t)); + memset(lp, 0, sizeof(struct arcnet_local)); memset(link, 0, sizeof(struct dev_link_t)); + dev->priv = lp; + link->release.function = &com20020_release; link->release.data = (u_long)link; link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; @@ -216,19 +238,6 @@ static dev_link_t *com20020_attach(void) link->conf.IntType = INT_MEMORY_AND_IO; link->conf.Present = PRESENT_OPTION; - info = kmalloc(sizeof(struct com20020_dev_t), GFP_KERNEL); - if (!info) - return NULL; - memset(info, 0, sizeof(struct com20020_dev_t)); - - dev = dev_alloc("arc%d", &ret); - if (!dev) - return NULL; - lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); - if (!lp) - return NULL; - memset(lp, 0, sizeof(struct arcnet_local)); - /* fill in our module parameters as defaults */ dev->dev_addr[0] = node; lp->timeout = timeout; @@ -260,6 +269,14 @@ static dev_link_t *com20020_attach(void) } return link; + +fail_alloc_dev: + kfree(lp); +fail_alloc_lp: + kfree(info); +fail_alloc_info: + kfree(link); + return NULL; } /* com20020_attach */ /*====================================================================== diff --git a/drivers/net/pcmcia/ray_cs.c b/drivers/net/pcmcia/ray_cs.c index 281940845193..4415239ab52d 100644 --- a/drivers/net/pcmcia/ray_cs.c +++ b/drivers/net/pcmcia/ray_cs.c @@ -19,6 +19,12 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * Changes: + * Arnaldo Carvalho de Melo - 08/08/2000 + * - reorganize kmallocs in ray_attach, checking all for failure + * and releasing the previous allocations if one fails + * * =============================================================================*/ @@ -333,7 +339,25 @@ static dev_link_t *ray_attach(void) /* Initialize the dev_link_t structure */ link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); + + if (!link) + return NULL; + + /* Allocate space for private device-specific data */ + dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); + + if (!dev) + goto fail_alloc_dev; + + local = kmalloc(sizeof(ray_dev_t), GFP_KERNEL); + + if (!local) + goto fail_alloc_local; + memset(link, 0, sizeof(struct dev_link_t)); + memset(dev, 0, sizeof(struct net_device)); + memset(local, 0, sizeof(ray_dev_t)); + link->release.function = &ray_release; link->release.data = (u_long)link; @@ -355,14 +379,9 @@ static dev_link_t *ray_attach(void) link->conf.ConfigIndex = 1; link->conf.Present = PRESENT_OPTION; - /* Allocate space for private device-specific data */ - dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); - memset(dev, 0, sizeof(struct net_device)); link->priv = dev; link->irq.Instance = dev; - local = kmalloc(sizeof(ray_dev_t), GFP_KERNEL); - memset(local, 0, sizeof(ray_dev_t)); dev->priv = local; local->finder = link; link->dev = &local->node; @@ -416,6 +435,12 @@ static dev_link_t *ray_attach(void) } DEBUG(2,"ray_cs ray_attach ending\n"); return link; + +fail_alloc_local: + kfree(dev); +fail_alloc_dev: + kfree(link); + return NULL; } /* ray_attach */ /*============================================================================= This deletes a driver "instance". The device is de-registered diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 84dc28025bfd..0f624fccdceb 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -5,12 +5,13 @@ * PPPoE --- PPP over Ethernet (RFC 2516) * * - * Version: 0.6.0 + * Version: 0.6.1 * * 030700 : Fixed connect logic to allow for disconnect. * 270700 : Fixed potential SMP problems; we must protect against * simultaneous invocation of ppp_input * and ppp_unregister_channel. + * 040800 : Respect reference count mechanisms on net-devices. * * Module reference count is decremented in the right spot now, * guards against sock_put not actually freeing the sk @@ -169,36 +170,6 @@ static struct pppox_opt *__delete_item(unsigned long sid, char *addr) return ret; } -static struct pppox_opt *__find_on_dev(struct net_device *dev, - struct pppox_opt *start) -{ - struct pppox_opt *po; - int hash; - - if (start != NULL) { - hash = hash_item(start->pppoe_pa.sid, start->pppoe_pa.remote); - po = start; - } else { - hash = 0; - po = NULL; - - while (!po && ++hash < PPPOE_HASH_SIZE) - po = item_hash_table[hash]; - } - - while (po && (po->pppoe_dev != dev)){ - if (po->next) { - po = po->next; - } else { - po = NULL; - while (!po && ++hash < PPPOE_HASH_SIZE) - po = item_hash_table[hash]; - } - } - - return po; -} - /********************************************************************** * * Set/get/delete/rehash items @@ -248,17 +219,7 @@ static inline struct pppox_opt *delete_item(unsigned long sid, char *addr) return ret; } -static struct pppox_opt *find_on_dev(struct net_device *dev, - struct pppox_opt *start) -{ - struct pppox_opt *po; - read_lock_bh(&pppoe_hash_lock); - po = __find_on_dev(dev,start); - if(po) - sock_hold(po->sk); - read_unlock_bh(&pppoe_hash_lock); - return po; -} + /*************************************************************************** * @@ -272,6 +233,7 @@ static int pppoe_device_event(struct notifier_block *this, int error = NOTIFY_DONE; struct net_device *dev = (struct net_device *) ptr; struct pppox_opt *po = NULL; + int hash = 0; /* Only look at sockets that are using this specific device. */ switch (event) { @@ -281,20 +243,40 @@ static int pppoe_device_event(struct notifier_block *this, */ case NETDEV_GOING_DOWN: case NETDEV_DOWN: - do { - po = find_on_dev(dev, po); - if(!po) - break; - - lock_sock(po->sk); - if (po->sk->state & PPPOX_CONNECTED) - pppox_unbind_sock(po->sk); - - release_sock(po->sk); - sock_put(po->sk); - } while (1); + /* Find every socket on this device and kill it. */ + read_lock_bh(&pppoe_hash_lock); + while (!po && hash < PPPOE_HASH_SIZE){ + po = item_hash_table[hash]; + ++hash; + } + + while (po && hash < PPPOE_HASH_SIZE){ + if(po->pppoe_dev == dev){ + lock_sock(po->sk); + if (po->sk->state & (PPPOX_CONNECTED|PPPOX_BOUND)){ + pppox_unbind_sock(po->sk); + + dev_put(po->pppoe_dev); + po->pppoe_dev = NULL; + + po->sk->state = PPPOX_DEAD; + po->sk->state_change(po->sk); + } + release_sock(po->sk); + } + if (po->next) { + po = po->next; + } else { + po = NULL; + while (!po && hash < PPPOE_HASH_SIZE){ + po = item_hash_table[hash]; + ++hash; + } + } + } + read_unlock_bh(&pppoe_hash_lock); break; default: break; @@ -320,34 +302,32 @@ static struct notifier_block pppoe_notifier = { ***********************************************************************/ int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb){ struct pppox_opt *po=sk->protinfo.pppox; + struct pppox_opt *relay_po = NULL; if (sk->state & PPPOX_BOUND) { skb_pull(skb, sizeof(struct pppoe_hdr)); ppp_input(&po->chan, skb); } else if( sk->state & PPPOX_RELAY ){ - struct pppox_opt *relay_po; relay_po = get_item_by_addr( &po->pppoe_relay ); if( relay_po == NULL || !( relay_po->sk->state & PPPOX_CONNECTED ) ){ - sock_put(relay_po->sk); goto abort; } skb_pull(skb, sizeof(struct pppoe_hdr)); if( !__pppoe_xmit( relay_po->sk , skb) ){ - sock_put(relay_po->sk); goto abort; } - } else { sock_queue_rcv_skb(sk, skb); } return 1; abort: - sock_put(sk); + if(relay_po) + sock_put(relay_po->sk); return 0; } @@ -462,20 +442,19 @@ struct packet_type pppoed_ptype = { NULL }; -/********************************************************************** +/*********************************************************************** * - * The destruct hook --- this can be trashed if there is no need for - * the sock to clear its receive queue? + * Really kill the socket. (Called from sock_put if refcnt == 0.) * - *********************************************************************/ -void sock_pppoe_destruct(struct sock *sk) + **********************************************************************/ +void pppoe_sock_destruct(struct sock *sk) { if (sk->protinfo.destruct_hook) kfree(sk->protinfo.destruct_hook); - MOD_DEC_USE_COUNT; } + /*********************************************************************** * * Initialize a new struct sock. @@ -505,6 +484,7 @@ static int pppoe_create(struct socket *sock) sk->pprev = NULL; sk->state = PPPOX_NONE; sk->type = SOCK_STREAM; + sk->destruct = pppoe_sock_destruct; sk->protinfo.pppox = kmalloc(sizeof(struct pppox_opt), GFP_KERNEL); if (!sk->protinfo.pppox) { @@ -546,6 +526,9 @@ int pppoe_release(struct socket *sock) po = sk->protinfo.pppox; if (po->pppoe_pa.sid) delete_item(po->pppoe_pa.sid, po->pppoe_pa.remote); + + if (po->pppoe_dev) + dev_put(po->pppoe_dev); /* Should also do a queue purge here */ @@ -555,7 +538,6 @@ int pppoe_release(struct socket *sock) skb_queue_purge(&sk->receive_queue); sock_put(sk); - MOD_DEC_USE_COUNT; return error; } @@ -576,14 +558,15 @@ int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, if (sp->sa_protocol != PX_PROTO_OE) goto end; + /* Check for already bound sockets */ error = -EBUSY; if ((sk->state & PPPOX_CONNECTED) && sp->sa_addr.pppoe.sid) goto end; - dev = dev_get_by_name(sp->sa_addr.pppoe.dev); - - error = -ENODEV; - if (!dev) + /* Check for already disconnected sockets, + on attempts to disconnect */ + error = -EALREADY; + if((sk->state & PPPOX_DEAD) && !sp->sa_addr.pppoe.sid ) goto end; error = 0; @@ -593,6 +576,8 @@ int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, /* Delete the old binding */ delete_item(po->pppoe_pa.sid,po->pppoe_pa.remote); + dev_put(po->pppoe_dev); + memset(po, 0, sizeof(struct pppox_opt)); po->sk = sk; @@ -601,6 +586,14 @@ int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, /* Don't re-bind if sid==0 */ if (sp->sa_addr.pppoe.sid != 0) { + dev = dev_get_by_name(sp->sa_addr.pppoe.dev); + + error = -ENODEV; + if (!dev) + goto end; + + if( ! (dev->flags & IFF_UP) ) + goto end; memcpy(&po->pppoe_pa, &sp->sa_addr.pppoe, sizeof(struct pppoe_addr)); @@ -773,6 +766,8 @@ int pppoe_sendmsg(struct socket *sock, struct msghdr *m, hdr.code = 0; hdr.sid = sk->num; + lock_sock(sk); + dev = sk->protinfo.pppox->pppoe_dev; skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32, @@ -785,14 +780,19 @@ int pppoe_sendmsg(struct socket *sock, struct msghdr *m, /* Reserve space for headers. */ skb_reserve(skb, dev->hard_header_len); skb->nh.raw = skb->data; - skb->dev = dev; + + skb->rx_dev = skb->dev = dev; + dev_hold(skb->rx_dev); + skb->priority = sk->priority; skb->protocol = __constant_htons(ETH_P_PPP_SES); ph = (struct pppoe_hdr *) skb_put(skb, total_len + sizeof(struct pppoe_hdr)); start = (char *) &ph->tag[0]; - copied = memcpy_fromiovec( start, m->msg_iov, m->msg_iovlen); + error = copied = memcpy_fromiovec( start, m->msg_iov, m->msg_iovlen); + if( error <= 0 ) + goto end; dev->hard_header(skb, dev, ETH_P_PPP_SES, sk->protinfo.pppox->pppoe_pa.remote, @@ -803,9 +803,9 @@ int pppoe_sendmsg(struct socket *sock, struct msghdr *m, ph->length = htons(copied); dev_queue_xmit(skb); - return copied; end: + release_sock(sk); return error; } @@ -860,7 +860,12 @@ int __pppoe_xmit(struct sock *sk, struct sk_buff *skb) skb->protocol = __constant_htons(ETH_P_PPP_SES); skb->nh.raw = skb->data; - skb->dev = dev; + + /* Change device of skb, update reference counts */ + if(skb->rx_dev) + dev_put(skb->rx_dev); + skb->rx_dev = skb->dev = dev; + dev_hold(skb->rx_dev); dev->hard_header(skb, dev, ETH_P_PPP_SES, sk->protinfo.pppox->pppoe_pa.remote, diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index d709ac2ca5a5..3a03fa964beb 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -1,8 +1,8 @@ /* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux. Copyright 1999 Silicon Integrated System Corporation - Revision: 1.07 Mar. 07 2000 - - Modified from the driver which is originally written by Donald Becker. + Revision: 1.07.01 Aug. 08 2000 + + Modified from the driver which is originally written by Donald Becker. This software may be used and distributed according to the terms of the GNU Public License (GPL), incorporated herein by reference. @@ -18,13 +18,14 @@ preliminary Rev. 1.0 Jan. 18, 1998 http://www.sis.com.tw/support/databook.htm + Rev 1.07.01 Aug. 08 2000 Ollie Lho minor update fro SiS 630E and SiS 630E A1 Rev 1.07 Mar. 07 2000 Ollie Lho bug fix in Rx buffer ring Rev 1.06.04 Feb. 11 2000 Jeff Garzik softnet and init for kernel 2.4 Rev 1.06.03 Dec. 23 1999 Ollie Lho Third release - Rev 1.06.02 Nov. 23 1999 Ollie Lho bug in mac probing fixed + Rev 1.06.02 Nov. 23 1999 Ollie Lho bug in mac probing fixed Rev 1.06.01 Nov. 16 1999 Ollie Lho CRC calculation provide by Joseph Zbiciak (im14u2c@primenet.com) Rev 1.06 Nov. 4 1999 Ollie Lho (ollie@sis.com.tw) Second release - Rev 1.05.05 Oct. 29 1999 Ollie Lho (ollie@sis.com.tw) Single buffer Tx/Rx + Rev 1.05.05 Oct. 29 1999 Ollie Lho (ollie@sis.com.tw) Single buffer Tx/Rx Chin-Shan Li (lcs@sis.com.tw) Added AMD Am79c901 HomePNA PHY support Rev 1.05 Aug. 7 1999 Jim Huang (cmhuang@sis.com.tw) Initial release */ @@ -53,7 +54,7 @@ #include "sis900.h" static const char *version = -"sis900.c: v1.07 03/07/2000\n"; +"sis900.c: v1.07.01 08/08/2000\n"; static int max_interrupt_work = 20; static int multicast_filter_limit = 128; @@ -109,23 +110,23 @@ struct mii_phy { }; typedef struct _BufferDesc { - u32 link; - u32 cmdsts; - u32 bufptr; + u32 link; + u32 cmdsts; + u32 bufptr; } BufferDesc; struct sis900_private { struct net_device_stats stats; struct pci_dev * pci_dev; - + spinlock_t lock; struct mii_phy * mii; unsigned int cur_phy; - struct timer_list timer; /* Link status detection timer. */ + struct timer_list timer; /* Link status detection timer. */ - unsigned int cur_rx, dirty_rx; + unsigned int cur_rx, dirty_rx; /* producer/comsumer pointers for Tx/Rx ring */ unsigned int cur_tx, dirty_tx; /* The saved address of a sent/receive-in-place packet buffer */ @@ -196,32 +197,102 @@ static int __init sis900_probe (struct pci_dev *pci_dev, const struct pci_device return 0; } -static struct net_device * __init sis900_mac_probe (struct pci_dev * pci_dev, char * card_name) +/* older SiS900 and friends, use EEPROM to store MAC address */ +static int sis900_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev) { - struct sis900_private *sis_priv; long ioaddr = pci_resource_start(pci_dev, 0); - struct net_device *net_dev = NULL; - int irq = pci_dev->irq; u16 signature; int i; - if ((net_dev = init_etherdev(net_dev, 0)) == NULL) - return NULL; - /* check to see if we have sane EEPROM */ signature = (u16) read_eeprom(ioaddr, EEPROMSignature); if (signature == 0xffff || signature == 0x0000) { printk (KERN_INFO "%s: Error EERPOM read %x\n", net_dev->name, signature); + return 0; + } + + /* get MAC address from EEPROM */ + for (i = 0; i < 3; i++) + ((u16 *)(net_dev->dev_addr))[i] = read_eeprom(ioaddr, i+EEPROMMACAddr); + + return 1; +} + +/* SiS630E model, use APC CMOS RAM to store MAC address */ +static int sis630e_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev) +{ + struct pci_dev *isa_bridge = NULL; + u8 reg; + int i; + + if ((isa_bridge = pci_find_device(0x1039, 0x0008, isa_bridge)) == NULL) { + printk("%s: Can not find ISA bridge\n", net_dev->name); + return 0; + } + pci_read_config_byte(isa_bridge, 0x48, ®); + pci_write_config_byte(isa_bridge, 0x48, reg | 0x40); + + for (i = 0; i < 6; i++) { + outb(0x09 + i, 0x70); + ((u8 *)(net_dev->dev_addr))[i] = inb(0x71); + } + pci_write_config_byte(isa_bridge, 0x48, reg & ~0x40); + + return 1; +} + +/* SiS630E A1, The Mac address is hardcoded in the RFCR register so it is actually not necessary to + probe the MAC address */ +static int sis630ea1_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev) +{ + long ioaddr = pci_resource_start(pci_dev, 0); + u32 reg; + int i; + + /* reload MAC address */ + reg = inl(ioaddr + cr); + outl(reg | RELOAD, ioaddr + cr); + + reg = inl(ioaddr + cr); + outl(reg & ~RELOAD, ioaddr + cr); + + for (i = 0; i < 3; i++) { + outl((u32)(0x00000004+i) << RFADDR_shift, ioaddr + rfcr); + ((u16 *)(net_dev->dev_addr))[i] = inl(ioaddr + rfdr); + } + + return 1; +} + +static struct net_device * __init sis900_mac_probe (struct pci_dev * pci_dev, char * card_name) +{ + struct sis900_private *sis_priv; + long ioaddr = pci_resource_start(pci_dev, 0); + struct net_device *net_dev = NULL; + int irq = pci_dev->irq; + int i, ret = 0; + u8 revision; + + if ((net_dev = init_etherdev(net_dev, 0)) == NULL) + return NULL; + + pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision); + if (revision == SIS630E_REV) + ret = sis630e_get_mac_addr(pci_dev, net_dev); + else if (revision == SIS630EA1_REV) + ret = sis630ea1_get_mac_addr(pci_dev, net_dev); + else + ret = sis900_get_mac_addr(pci_dev, net_dev); + + if (ret == 0) { + unregister_netdevice(net_dev); return NULL; } + /* print some information about our NIC */ printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name, card_name, ioaddr, irq); - - /* get MAC address from EEPROM */ - for (i = 0; i < 3; i++) - ((u16 *)(net_dev->dev_addr))[i] = read_eeprom(ioaddr, i+EEPROMMACAddr); for (i = 0; i < 5; i++) printk("%2.2x:", (u8)net_dev->dev_addr[i]); printk("%2.2x.\n", net_dev->dev_addr[i]); @@ -269,58 +340,69 @@ static int __init sis900_mii_probe (struct net_device * net_dev) { struct sis900_private * sis_priv = (struct sis900_private *)net_dev->priv; int phy_addr; - + u8 revision; + sis_priv->mii = NULL; - + /* search for total of 32 possible mii phy addresses */ for (phy_addr = 0; phy_addr < 32; phy_addr++) { u16 mii_status; u16 phy_id0, phy_id1; int i; - + mii_status = mdio_read(net_dev, phy_addr, MII_STATUS); if (mii_status == 0xffff || mii_status == 0x0000) /* the mii is not accessable, try next one */ continue; - + phy_id0 = mdio_read(net_dev, phy_addr, MII_PHY_ID0); phy_id1 = mdio_read(net_dev, phy_addr, MII_PHY_ID1); - + /* search our mii table for the current mii */ for (i = 0; mii_chip_table[i].phy_id1; i++) if (phy_id0 == mii_chip_table[i].phy_id0) { struct mii_phy * mii_phy; - - printk(KERN_INFO + + printk(KERN_INFO "%s: %s transceiver found at address %d.\n", - net_dev->name, mii_chip_table[i].name, + net_dev->name, mii_chip_table[i].name, phy_addr);; if ((mii_phy = kmalloc(sizeof(struct mii_phy), GFP_KERNEL)) != NULL) { mii_phy->chip_info = mii_chip_table+i; mii_phy->phy_addr = phy_addr; - mii_phy->status = mdio_read(net_dev, phy_addr, + mii_phy->status = mdio_read(net_dev, phy_addr, MII_STATUS); mii_phy->next = sis_priv->mii; sis_priv->mii = mii_phy; } - /* the current mii is on our mii_info_table, + /* the current mii is on our mii_info_table, try next address */ break; } } - + if (sis_priv->mii == NULL) { - printk(KERN_INFO "%s: No MII transceivers found!\n", + printk(KERN_INFO "%s: No MII transceivers found!\n", net_dev->name); return 0; } - /* arbitrary choose that last PHY and current PHY */ + /* arbitrary choose that last PHY as current PHY */ sis_priv->cur_phy = sis_priv->mii->phy_addr; printk(KERN_INFO "%s: Using %s as default\n", net_dev->name, sis_priv->mii->chip_info->name); - if (sis_priv->mii->status & MII_STAT_LINK) + pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); + if (revision == SIS630E_REV) { + /* SiS 630E has some bugs on default value of PHY registers */ + mdio_write(net_dev, sis_priv->cur_phy, MII_ANADV, 0x05e1); + mdio_write(net_dev, sis_priv->cur_phy, MII_CONFIG1, 0x22); + mdio_write(net_dev, sis_priv->cur_phy, MII_CONFIG2, 0xff00); + mdio_write(net_dev, sis_priv->cur_phy, MII_MASK, 0xffc0); + mdio_write(net_dev, sis_priv->cur_phy, MII_CONTROL, 0x1000); + } + + if (sis_priv->mii->status & MII_STAT_LINK) sis_priv->LinkOn = TRUE; else sis_priv->LinkOn = FALSE; @@ -365,7 +447,7 @@ static u16 read_eeprom(long ioaddr, int location) retval = (retval << 1) | ((inl(ee_addr) & EEDO) ? 1 : 0); eeprom_delay(); } - + /* Terminate the EEPROM access. */ outl(0, ee_addr); eeprom_delay(); @@ -426,6 +508,8 @@ static u16 mdio_read(struct net_device *net_dev, int phy_id, int location) outl(MDC, mdio_addr); mdio_delay(); } + outl(0x00, mdio_addr); + return retval; } @@ -454,10 +538,10 @@ static void mdio_write(struct net_device *net_dev, int phy_id, int location, int outl(dataval, mdio_addr); mdio_delay(); outl(dataval | MDC, mdio_addr); - mdio_delay(); + mdio_delay(); } mdio_delay(); - + /* Clear out extra bits. */ for (i = 2; i > 0; i--) { outb(0, mdio_addr); @@ -465,6 +549,8 @@ static void mdio_write(struct net_device *net_dev, int phy_id, int location, int outb(MDC, mdio_addr); mdio_delay(); } + outl(0x00, mdio_addr); + return; } @@ -518,7 +604,7 @@ sis900_init_rxfilter (struct net_device * net_dev) long ioaddr = net_dev->base_addr; u32 rfcrSave; u32 i; - + rfcrSave = inl(rfcr + ioaddr); /* disable packet filtering before setting filter */ @@ -547,12 +633,12 @@ static void sis900_init_tx_ring(struct net_device *net_dev) { struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; - long ioaddr = net_dev->base_addr; + long ioaddr = net_dev->base_addr; int i; - + sis_priv->tx_full = 0; sis_priv->dirty_tx = sis_priv->cur_tx = 0; - + for (i = 0; i < NUM_TX_DESC; i++) { sis_priv->tx_skbuff[i] = NULL; @@ -563,21 +649,21 @@ sis900_init_tx_ring(struct net_device *net_dev) sis_priv->tx_ring[i-1].link = (u32) virt_to_bus(&sis_priv->tx_ring[0]); /* load Transmit Descriptor Register */ - outl(virt_to_bus(&sis_priv->tx_ring[0]), ioaddr + txdp); + outl(virt_to_bus(&sis_priv->tx_ring[0]), ioaddr + txdp); if (sis900_debug > 2) - printk(KERN_INFO "%s: TX descriptor register loaded with: %8.8x\n", + printk(KERN_INFO "%s: TX descriptor register loaded with: %8.8x\n", net_dev->name, inl(ioaddr + txdp)); } -/* Initialize the Rx descriptor ring, pre-allocate recevie buffers */ +/* Initialize the Rx descriptor ring, pre-allocate recevie buffers */ static void -sis900_init_rx_ring(struct net_device *net_dev) -{ - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; - long ioaddr = net_dev->base_addr; +sis900_init_rx_ring(struct net_device *net_dev) +{ + struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + long ioaddr = net_dev->base_addr; int i; - - sis_priv->cur_rx = 0; + + sis_priv->cur_rx = 0; sis_priv->dirty_rx = 0; /* init RX descriptor */ @@ -596,8 +682,8 @@ sis900_init_rx_ring(struct net_device *net_dev) if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) { /* not enough memory for skbuff, this makes a "hole" - on the buffer ring, it is not clear how the - hardware will react to this kind of degenerated + on the buffer ring, it is not clear how the + hardware will react to this kind of degenerated buffer */ break; } @@ -611,7 +697,7 @@ sis900_init_rx_ring(struct net_device *net_dev) /* load Receive Descriptor Register */ outl(virt_to_bus(&sis_priv->rx_ring[0]), ioaddr + rxdp); if (sis900_debug > 2) - printk(KERN_INFO "%s: RX descriptor register loaded with: %8.8x\n", + printk(KERN_INFO "%s: RX descriptor register loaded with: %8.8x\n", net_dev->name, inl(ioaddr + rxdp)); } /* on each timer ticks we check two things, Link Status (ON/OFF) and @@ -625,11 +711,12 @@ static void sis900_timer(unsigned long data) static int next_tick = 5*HZ; u16 status; + status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS); status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS); /* current mii phy is failed to link, try another one */ - while (!(status & MII_STAT_LINK)) { - if (mii_phy->next == NULL) { + while (!(status & MII_STAT_LINK)) { + if (mii_phy->next == NULL) { if (sis_priv->LinkOn) { /* link stat change from ON to OFF */ next_tick = HZ; @@ -653,11 +740,13 @@ static void sis900_timer(unsigned long data) if (mii_phy->phy_addr != sis_priv->cur_phy) { printk(KERN_INFO "%s: Changing transceiver to %s\n", net_dev->name, mii_phy->chip_info->name); + /* disable previous PHY */ status = mdio_read(net_dev, sis_priv->cur_phy, MII_CONTROL); - mdio_write(net_dev, sis_priv->cur_phy, + mdio_write(net_dev, sis_priv->cur_phy, MII_CONTROL, status | MII_CNTL_ISOLATE); + /* enable next PHY */ status = mdio_read(net_dev, mii_phy->phy_addr, MII_CONTROL); - mdio_write(net_dev, mii_phy->phy_addr, + mdio_write(net_dev, mii_phy->phy_addr, MII_CONTROL, status & ~MII_CNTL_ISOLATE); sis_priv->cur_phy = mii_phy->phy_addr; } @@ -700,7 +789,7 @@ static void sis900_read_mode(struct net_device *net_dev, int phy_addr, int *spee { int i = 0; u32 status; - + /* STSOUT register is Latched on Transition, read operation updates it */ while (i++ < 2) status = mdio_read(net_dev, phy_addr, MII_STSOUT); @@ -718,9 +807,9 @@ static void sis900_read_mode(struct net_device *net_dev, int phy_addr, int *spee if (status & MII_STSOUT_LINK_FAIL) printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); else - printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", + printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", net_dev->name, - *speed == HW_SPEED_100_MBPS ? + *speed == HW_SPEED_100_MBPS ? "100mbps" : "10mbps", *duplex == FDX_CAPABLE_FULL_SELECTED ? "full" : "half"); @@ -729,7 +818,7 @@ static void amd79c901_read_mode(struct net_device *net_dev, int phy_addr, int *s { int i; u16 status; - + for (i = 0; i < 2; i++) status = mdio_read(net_dev, phy_addr, MII_STATUS); @@ -747,22 +836,21 @@ static void amd79c901_read_mode(struct net_device *net_dev, int phy_addr, int *s *duplex = FDX_CAPABLE_HALF_SELECTED; if (status & MII_STSSUM_LINK) - printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", + printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", net_dev->name, - *speed == HW_SPEED_100_MBPS ? + *speed == HW_SPEED_100_MBPS ? "100mbps" : "10mbps", *duplex == FDX_CAPABLE_FULL_SELECTED ? "full" : "half"); else printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); - } else { /* HomePNA */ *speed = HW_SPEED_HOME; *duplex = FDX_CAPABLE_HALF_SELECTED; if (status & MII_STAT_LINK) - printk(KERN_INFO "%s: Media Link On 1mbps half-duplex \n", + printk(KERN_INFO "%s: Media Link On 1mbps half-duplex \n", net_dev->name); else printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); @@ -777,7 +865,7 @@ static void sis900_tx_timeout(struct net_device *net_dev) printk(KERN_INFO "%s: Transmit timeout, status %8.8x %8.8x \n", net_dev->name, inl(ioaddr + cr), inl(ioaddr + isr)); - + /* Disable interrupts by clearing the interrupt mask. */ outl(0x0000, ioaddr + imr); @@ -864,7 +952,7 @@ static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs) do { status = inl(ioaddr + isr); - + if ((status & (HIBERR|TxURN|TxERR|TxIDLE|RxORN|RxERR|RxOK)) == 0) /* nothing intresting happened */ break; @@ -891,7 +979,7 @@ static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs) break; } } while (1); - + if (sis900_debug > 3) printk(KERN_INFO "%s: exiting interrupt, " "interrupt status = 0x%#8.8x.\n", @@ -909,17 +997,17 @@ static int sis900_rx(struct net_device *net_dev) long ioaddr = net_dev->base_addr; unsigned int entry = sis_priv->cur_rx % NUM_RX_DESC; u32 rx_status = sis_priv->rx_ring[entry].cmdsts; - + if (sis900_debug > 3) printk(KERN_INFO "sis900_rx, cur_rx:%4.4d, dirty_rx:%4.4d " "status:0x%8.8x\n", sis_priv->cur_rx, sis_priv->dirty_rx, rx_status); - + while (rx_status & OWN) { unsigned int rx_size; - + rx_size = (rx_status & DSIZE) - CRC_SIZE; - + if (rx_status & (ABORT|OVERRUN|TOOLONG|RUNT|RXISERR|CRCERR|FAERR)) { /* corrupted packet received */ if (sis900_debug > 3) @@ -939,15 +1027,15 @@ static int sis900_rx(struct net_device *net_dev) sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE; } else { struct sk_buff * skb; - + /* This situation should never happen, but due to some unknow bugs, it is possible that - we are working on NULL sk_buff :-( */ + we are working on NULL sk_buff :-( */ if (sis_priv->rx_skbuff[entry] == NULL) { printk(KERN_INFO "%s: NULL pointer " "encountered in Rx ring, skipping\n", net_dev->name); - break; + break; } /* gvie the socket buffer to upper layers */ @@ -990,14 +1078,14 @@ static int sis900_rx(struct net_device *net_dev) entry = sis_priv->cur_rx % NUM_RX_DESC; rx_status = sis_priv->rx_ring[entry].cmdsts; } // while - + /* refill the Rx buffer, what if the rate of refilling is slower than consuming ?? */ for (;sis_priv->cur_rx - sis_priv->dirty_rx > 0; sis_priv->dirty_rx++) { struct sk_buff *skb; - + entry = sis_priv->dirty_rx % NUM_RX_DESC; - + if (sis_priv->rx_skbuff[entry] == NULL) { if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) { /* not enough memory for skbuff, this makes a "hole" @@ -1018,7 +1106,7 @@ static int sis900_rx(struct net_device *net_dev) } /* re-enable the potentially idle receive state matchine */ outl(RxENA , ioaddr + cr ); - + return 0; } @@ -1027,21 +1115,21 @@ static int sis900_rx(struct net_device *net_dev) static void sis900_finish_xmit (struct net_device *net_dev) { struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; - + for (; sis_priv->dirty_tx < sis_priv->cur_tx; sis_priv->dirty_tx++) { unsigned int entry; u32 tx_status; - + entry = sis_priv->dirty_tx % NUM_TX_DESC; tx_status = sis_priv->tx_ring[entry].cmdsts; - + if (tx_status & OWN) { /* The packet is not transmited yet (owned by hardware) ! Note: the interrupt is generated only when Tx Machine is idle, so this is an almost impossible case */ break; } - + if (tx_status & (ABORT | UNDERRUN | OWCOLL)) { /* packet unsuccessfully transmited */ if (sis900_debug > 3) @@ -1069,8 +1157,8 @@ static void sis900_finish_xmit (struct net_device *net_dev) sis_priv->tx_ring[entry].bufptr = 0; sis_priv->tx_ring[entry].cmdsts = 0; } - - if (sis_priv->tx_full && netif_queue_stopped(net_dev) && + + if (sis_priv->tx_full && netif_queue_stopped(net_dev) && sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC - 4) { /* The ring is no longer full, clear tx_full and schedule more transmission by netif_wake_queue(net_dev) */ @@ -1085,7 +1173,7 @@ sis900_close(struct net_device *net_dev) long ioaddr = net_dev->base_addr; struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; int i; - + netif_stop_queue(net_dev); /* Disable interrupts by clearing the interrupt mask. */ diff --git a/drivers/net/sis900.h b/drivers/net/sis900.h index c63a3212a08c..93609cd0805e 100644 --- a/drivers/net/sis900.h +++ b/drivers/net/sis900.h @@ -25,19 +25,20 @@ enum sis900_registers { ier=0x18, //Interrupt Enable Register epar=0x18, //Enhanced PHY Access Register txdp=0x20, //Transmit Descriptor Pointer Register - txcfg=0x24, //Transmit Configuration Register - rxdp=0x30, //Receive Descriptor Pointer Register - rxcfg=0x34, //Receive Configuration Register - flctrl=0x38, //Flow Control Register - rxlen=0x3c, //Receive Packet Length Register - rfcr=0x48, //Receive Filter Control Register - rfdr=0x4C, //Receive Filter Data Register - pmctrl=0xB0, //Power Management Control Register - pmer=0xB4 //Power Management Wake-up Event Register + txcfg=0x24, //Transmit Configuration Register + rxdp=0x30, //Receive Descriptor Pointer Register + rxcfg=0x34, //Receive Configuration Register + flctrl=0x38, //Flow Control Register + rxlen=0x3c, //Receive Packet Length Register + rfcr=0x48, //Receive Filter Control Register + rfdr=0x4C, //Receive Filter Data Register + pmctrl=0xB0, //Power Management Control Register + pmer=0xB4 //Power Management Wake-up Event Register }; /* Symbolic names for bits in various registers */ enum sis900_command_register_bits { + RELOAD = 0x00000400, RESET = 0x00000100, SWI = 0x00000080, RxRESET = 0x00000020, TxRESET = 0x00000010, RxDIS = 0x00000008, RxENA = 0x00000004, TxDIS = 0x00000002, TxENA = 0x00000001 @@ -216,6 +217,10 @@ enum mii_stssum_register_bits { MII_STSSUM_AUTO = 0x0002, MII_STSSUM_SPD = 0x0001 }; +enum sis630_revision_id { + SIS630E_REV = 0x81, SIS630EA1_REV = 0x83 +}; + #define FDX_CAPABLE_DUPLEX_UNKNOWN 0 #define FDX_CAPABLE_HALF_SELECTED 1 #define FDX_CAPABLE_FULL_SELECTED 2 diff --git a/drivers/net/stnic.c b/drivers/net/stnic.c index c1787a186db3..e652711197e9 100644 --- a/drivers/net/stnic.c +++ b/drivers/net/stnic.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "8390.h" @@ -100,6 +101,10 @@ int __init stnic_probe(void) tmp.base_addr = 0x1000; dev = &tmp; + /* If we are not running on a SolutionEngine, give up now */ + if (! MACH_SE) + return -ENODEV; + if (load_8390_module ("stnic.c")) return -ENOSYS; diff --git a/drivers/pci/pci.ids b/drivers/pci/pci.ids index 96b4ba97cbfd..0c3a2f533649 100644 --- a/drivers/pci/pci.ids +++ b/drivers/pci/pci.ids @@ -1910,36 +1910,38 @@ 1105 Sigma Designs, Inc. 8300 REALmagic Hollywood Plus DVD Decoder 1106 VIA Technologies, Inc. - 0305 VT8363 [KT133] + 0305 VT8363/8365 [KT133/KM133] 0391 VT8371 [KX133] - 0501 VT8501 + 0501 VT8501 [Apollo MVP4] 0505 VT82C505 0561 VT82C561 - 0571 VT82C586 IDE [Apollo] + 0571 Bus Master IDE 0576 VT82C576 3V [Apollo Master] 0585 VT82C585VP [Apollo VP1/VPX] 0586 VT82C586/A/B PCI-to-ISA [Apollo VP] 1106 0000 MVP3 ISA Bridge 0595 VT82C595 [Apollo VP2] - 0596 VT82C596 ISA [Apollo PRO] + 0596 VT82C596 ISA [Mobile South] 1106 0000 VT82C596/A/B PCI to ISA Bridge 1458 0596 VT82C596/A/B PCI to ISA Bridge 0597 VT82C597 [Apollo VP3] 0598 VT82C598 [Apollo MVP3] - 0601 VT8601 + 0601 VT8601 [Apollo ProMedia] + 0605 VT8605 [ProSavage PM133] 0680 VT82C680 [Apollo P6] - 0686 VT82C686 [Apollo Super] + 0686 VT82C686 [Apollo Super South] 1106 0000 VT82C686/A PCI to ISA Bridge 1106 0686 VT82C686/A PCI to ISA Bridge - 0691 VT82C691 [Apollo PRO] + 0691 VT82C693A/694x [Apollo PRO133x] 1458 0691 VT82C691 Apollo Pro System Controller + 0698 VT82C693A [Ppollo Pro133 AGP] 0693 VT82C693 [Apollo Pro Plus] 0926 VT82C926 [Amazon] 1000 VT82C570MV 1106 VT82C570MV 1571 VT82C416MV 1595 VT82C595/97 [Apollo VP2/97] - 3038 VT82C586B USB + 3038 UHCI USB 1234 0925 MVP3 USB Controller 3040 VT82C586B ACPI 3043 VT86C100A [Rhine 10/100] @@ -1947,20 +1949,31 @@ 1106 0100 VT86C100A Fast Ethernet Adapter 1186 1400 DFE-530TX 3044 OHCI Compliant IEEE 1394 Host Controller + 3050 VT82C596 Power Management + 3051 VT82C596 Power Management 3057 VT82C686 [Apollo Super ACPI] - 3058 VT82C686 [Apollo Super AC97/Audio] + 3058 AC97 Audio Controller 1462 3091 MS-6309 Onboard Audio - 3068 VT82C686 [Apollo Super AC97/Modem] + 3059 AC97 Audio Controller + 3065 Ethernet Controller + 3068 AC97 Modem Controller + 3074 VT8233 PCI to ISA Bridge + 3091 VT8633 [Apollo Pro266] + 3099 VT8367 [KT266] 5030 VT82C596 ACPI [Apollo PRO] 6100 VT85C100A [Rhine II] 8231 VT8231 [PCI-to-ISA Bridge] - 8305 VT8363 [PCI-PCI Bridge] - 8391 VT8371 [PCI-PCI Bridge] - 8501 VT8501 + 8235 VT8235 Power Management + 8305 VT8365 [KM133 AGP] + 8391 VT8363/8371 [KT133/KX133 AGP] + 8501 VT8501 [Apollo MVP4 AGP] 8596 VT82C596 [Apollo PRO AGP] 8597 VT82C597 [Apollo VP3 AGP] - 8598 VT82C598 [Apollo MVP3 AGP] - 8601 VT8601 + 8598 VT82C598/694x [Apollo MVP3/Pro133x AGP] + 8601 VT8601 [Apollo ProMedia AGP] + 8605 VT8605 [PM133 AGP] + B091 VT8633 [Apollo Pro266 AGP] + B099 VT8367 [KT266 AGP] 8691 VT82C691 [Apollo Pro] 1107 Stratus Computers 0576 VIA VT82C570MV [Apollo] (Wrong vendor ID!) diff --git a/drivers/video/Config.in b/drivers/video/Config.in index fe26b4c01327..360e77998e8b 100644 --- a/drivers/video/Config.in +++ b/drivers/video/Config.in @@ -30,9 +30,7 @@ if [ "$CONFIG_FB" = "y" ]; then if [ "$CONFIG_ARCH_ACORN" = "y" ]; then bool ' Acorn VIDC support' CONFIG_FB_ACORN fi - if [ "$CONFIG_ARCH_NETWINDER" = "y" ]; then - tristate ' Cyber2000 support' CONFIG_FB_CYBER2000 - fi + tristate ' Cyber2000 support' CONFIG_FB_CYBER2000 if [ "$CONFIG_ARCH_SA1100" = "y" ]; then bool ' SA-1100 LCD support' CONFIG_FB_SA1100 fi diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c index e5e0e4aadb6c..5eb9970a294d 100644 --- a/drivers/video/acornfb.c +++ b/drivers/video/acornfb.c @@ -1663,8 +1663,12 @@ acornfb_init(void) sizeof(modedb) / sizeof(*modedb), &acornfb_default_mode, DEFAULT_BPP); - if (!rc && fb_find_mode(&init_var, &fb_info, NULL, NULL, 0, - &acornfb_default_mode, DEFAULT_BPP)) { + /* + * If we didn't find an exact match, try the + * generic database. + */ + if (rc != 1 && fb_find_mode(&init_var, &fb_info, NULL, NULL, 0, + &acornfb_default_mode, DEFAULT_BPP)) { printk("Acornfb: no valid mode found\n"); } diff --git a/drivers/video/hitfb.c b/drivers/video/hitfb.c index e48d8a74ca81..91b2b77ebd58 100644 --- a/drivers/video/hitfb.c +++ b/drivers/video/hitfb.c @@ -110,8 +110,10 @@ static int hitfb_encode_fix(struct fb_fix_screeninfo *fix, default: case 8: fix->line_length = par->x; + break; case 16: fix->line_length = par->x*2; + break; } return 0; diff --git a/fs/Config.in b/fs/Config.in index 851c547265c5..e48f75496921 100644 --- a/fs/Config.in +++ b/fs/Config.in @@ -25,6 +25,9 @@ dep_tristate ' UMSDOS: Unix-like file system on top of standard MSDOS fs' CON dep_tristate ' VFAT (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS dep_tristate 'EFS file system support (read only) (EXPERIMENTAL)' CONFIG_EFS_FS $CONFIG_EXPERIMENTAL dep_tristate 'Journalling Flash File System (JFFS) support (EXPERIMENTAL)' CONFIG_JFFS_FS $CONFIG_EXPERIMENTAL $CONFIG_MTD +if [ "$CONFIG_JFFS_FS" != "n" ] ; then + int 'JFFS debugging verbosity (0 = quiet, 3 = noisy)' CONFIG_JFFS_FS_VERBOSE 0 +fi tristate 'Compressed ROM file system support' CONFIG_CRAMFS tristate 'Simple RAM-based file system support' CONFIG_RAMFS diff --git a/fs/jffs/Makefile b/fs/jffs/Makefile index 63d25594a939..541816171acd 100644 --- a/fs/jffs/Makefile +++ b/fs/jffs/Makefile @@ -1,18 +1,21 @@ # # Makefile for the linux Journalling Flash FileSystem (JFFS) routines. # +# $Id: Makefile,v 1.7 2000/08/04 12:46:34 dwmw2 Exp $ +# # Note! Dependencies are done automagically by 'make dep', which also # removes any old dependencies. DON'T put your own dependencies here # unless it's something special (ie not a .c file). # # Note 2! The CFLAGS definitions are now in the main makefile... -ifndef CONFIG_MTD +ifndef CONFIG_JFFS_FS # We're being invoked outside a normal kernel build. Fake it EXTRA_CFLAGS= -I$(shell pwd)/../../include # You need to change this to build for 2.2, dunno how to check for it. + #INODE_O := inode-v22.o INODE_O := inode-v23.o diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c index 06ac42709dc4..9ea2223d3f52 100644 --- a/fs/jffs/inode-v23.c +++ b/fs/jffs/inode-v23.c @@ -1,19 +1,21 @@ /* * JFFS -- Journalling Flash File System, Linux implementation. * - * Copyright (C) 1999, 2000 Finn Hakansson, Axis Communications, Inc. + * Copyright (C) 1999, 2000 Axis Communications AB. + * + * Created by Finn Hakansson . * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * $Id: inode-v23.c,v 1.17 2000/07/06 20:35:19 prumpf Exp $ + * $Id: inode-v23.c,v 1.33 2000/08/09 15:59:06 dwmw2 Exp $ * * * Ported to Linux 2.3.x and MTD: * Copyright (C) 2000 Alexander Larsson (alex@cendio.se), Cendio Systems AB - * + * */ /* inode.c -- Contains the code that is called from the VFS. */ @@ -24,7 +26,15 @@ * maybe other stuff do to. */ -#include +/* Argh. Some architectures have kernel_thread in asm/processor.h + Some have it in unistd.h and you need to define __KERNEL_SYSCALLS__ + Pass me a baseball bat and the person responsible. + dwmw2 +*/ +#define __KERNEL_SYSCALLS__ +#include +#include + #include #include #include @@ -45,16 +55,6 @@ #include "jffs_fm.h" #include "intrep.h" -#if defined(CONFIG_JFFS_FS_VERBOSE) && CONFIG_JFFS_FS_VERBOSE -#define D(x) x -#else -#define D(x) -#endif -#define D1(x) D(x) -#define D2(x) -#define D3(x) -#define ASSERT(x) x - static int jffs_remove(struct inode *dir, struct dentry *dentry, int type); static struct super_operations jffs_ops; @@ -64,22 +64,24 @@ static struct file_operations jffs_dir_operations; static struct inode_operations jffs_dir_inode_operations; static struct address_space_operations jffs_address_operations; + /* Called by the VFS at mount time to initialize the whole file system. */ static struct super_block * jffs_read_super(struct super_block *sb, void *data, int silent) { kdev_t dev = sb->s_dev; struct inode *root_inode; + struct jffs_control *c; - printk(KERN_NOTICE "JFFS: Trying to mount device %s.\n", - kdevname(dev)); + D1(printk(KERN_NOTICE "JFFS: Trying to mount device %s.\n", + kdevname(dev))); - if (MAJOR(dev)!=MTD_BLOCK_MAJOR) { - printk(KERN_WARNING "JFFS: Trying to mount non-mtd device.\n"); - return 0; + if (MAJOR(dev) != MTD_BLOCK_MAJOR) { + printk(KERN_WARNING "JFFS: Trying to mount a " + "non-mtd device.\n"); + return 0; } - set_blocksize(dev, PAGE_CACHE_SIZE); sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->u.generic_sbp = (void *) 0; @@ -98,19 +100,36 @@ jffs_read_super(struct super_block *sb, void *data, int silent) root_inode = iget(sb, JFFS_MIN_INO); if (!root_inode) goto jffs_sb_err2; - + /* Get the root directory of this file system. */ if (!(sb->s_root = d_alloc_root(root_inode))) { goto jffs_sb_err3; } -#ifdef USE_GC - /* Do a garbage collect every time we mount. */ - jffs_garbage_collect((struct jffs_control *)sb->u.generic_sbp); -#endif + c = (struct jffs_control *) sb->u.generic_sbp; - printk(KERN_NOTICE "JFFS: Successfully mounted device %s.\n", - kdevname(dev)); + /* Set the Garbage Collection thresholds */ + + /* GC if free space goes below 5% of the total size */ + c->gc_minfree_threshold = c->fmc->flash_size / 20; + + if (c->gc_minfree_threshold < c->fmc->sector_size) + c->gc_minfree_threshold = c->fmc->sector_size; + + /* GC if dirty space exceeds 33% of the total size. */ + c->gc_maxdirty_threshold = c->fmc->flash_size / 3; + + if (c->gc_maxdirty_threshold < c->fmc->sector_size) + c->gc_maxdirty_threshold = c->fmc->sector_size; + + + c->thread_pid = kernel_thread (jffs_garbage_collect_thread, + (void *) c, + CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + D1(printk(KERN_NOTICE "JFFS: GC thread pid=%d.\n", (int) c->thread_pid)); + + D1(printk(KERN_NOTICE "JFFS: Successfully mounted device %s.\n", + kdevname(dev))); return sb; jffs_sb_err3: @@ -118,7 +137,6 @@ jffs_sb_err3: jffs_sb_err2: jffs_cleanup_control((struct jffs_control *)sb->u.generic_sbp); jffs_sb_err1: - printk(KERN_WARNING "JFFS: Failed to mount device %s.\n", kdevname(dev)); return 0; @@ -129,14 +147,27 @@ jffs_sb_err1: static void jffs_put_super(struct super_block *sb) { - kdev_t dev = sb->s_dev; + struct jffs_control *c = (struct jffs_control *) sb->u.generic_sbp; + D1(kdev_t dev = sb->s_dev); + D2(printk("jffs_put_super()\n")); + + D1(printk (KERN_NOTICE "jffs_put_super(): Telling gc thread to die.\n")); + if (c->gc_task) { + send_sig(SIGQUIT, c->gc_task, 1); + send_sig(SIGCONT, c->gc_task, 1); + } + down (&c->gc_thread_sem); + + D1(printk (KERN_NOTICE "jffs_put_super(): Successfully waited on thread.\n")); + sb->s_dev = 0; jffs_cleanup_control((struct jffs_control *)sb->u.generic_sbp); - printk(KERN_NOTICE "JFFS: Successfully unmounted device %s.\n", - kdevname(dev)); + D1(printk(KERN_NOTICE "JFFS: Successfully unmounted device %s.\n", + kdevname(dev))); } + /* This function is called when user commands like chmod, chgrp and chown are executed. System calls like trunc() results in a call to this function. */ @@ -165,9 +196,9 @@ jffs_setattr(struct dentry *dentry, struct iattr *iattr) c = f->c; fmc = c->fmc; - update_all = iattr->ia_valid & ATTR_FORCE; + update_all = iattr->ia_valid & ATTR_FORCE; - if (!JFFS_ENOUGH_SPACE(fmc)) { + if (!JFFS_ENOUGH_SPACE(c)) { if ( (update_all || iattr->ia_valid & ATTR_SIZE) && (iattr->ia_size < f->size) ) { /* See this case where someone is trying to @@ -212,7 +243,7 @@ jffs_setattr(struct dentry *dentry, struct iattr *iattr) raw_inode.spare = 0; raw_inode.rename = 0; raw_inode.deleted = 0; - + if (update_all || iattr->ia_valid & ATTR_MODE) { raw_inode.mode = iattr->ia_mode; inode->i_mode = iattr->ia_mode; @@ -282,13 +313,16 @@ jffs_setattr(struct dentry *dentry, struct iattr *iattr) } jffs_insert_node(c, f, &raw_inode, 0, new_node); - + mark_inode_dirty(inode); - + return 0; } /* jffs_notify_change() */ -struct inode * jffs_new_inode(const struct inode * dir, struct jffs_raw_inode *raw_inode, int * err) + +struct inode * +jffs_new_inode(const struct inode * dir, struct jffs_raw_inode *raw_inode, + int * err) { struct super_block * sb; struct inode * inode; @@ -299,7 +333,7 @@ struct inode * jffs_new_inode(const struct inode * dir, struct jffs_raw_inode *r *err = -ENOMEM; return NULL; } - + sb = dir->i_sb; c = (struct jffs_control *)sb->u.generic_sbp; @@ -315,12 +349,12 @@ struct inode * jffs_new_inode(const struct inode * dir, struct jffs_raw_inode *r inode->i_atime = raw_inode->atime; inode->i_mtime = raw_inode->mtime; inode->i_ctime = raw_inode->ctime; - inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat), not the fs block size */ - inode->i_blocks = 0; + inode->i_blksize = PAGE_SIZE; + inode->i_blocks = (raw_inode->dsize + PAGE_SIZE - 1) >> PAGE_SHIFT; inode->i_version = 0; inode->i_flags = sb->s_flags; inode->u.generic_ip = (void *)jffs_find_file(c, raw_inode->ino); - + insert_inode_hash(inode); return inode; @@ -343,7 +377,7 @@ jffs_statfs(struct super_block *sb, struct statfs *buf) + jffs_free_size2(fmc) / PAGE_CACHE_SIZE) - (fmc->min_free_size / PAGE_CACHE_SIZE); buf->f_bavail = buf->f_bfree; - + /* Find out how many files there are in the filesystem. */ buf->f_files = jffs_foreach_file(c, jffs_file_count); buf->f_ffree = buf->f_bfree; @@ -352,10 +386,11 @@ jffs_statfs(struct super_block *sb, struct statfs *buf) return 0; } + /* Rename a file. */ int jffs_rename(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry) + struct inode *new_dir, struct dentry *new_dentry) { struct jffs_raw_inode raw_inode; struct jffs_control *c; @@ -382,14 +417,14 @@ jffs_rename(struct inode *old_dir, struct dentry *old_dentry, return -1; }); - if (!JFFS_ENOUGH_SPACE(c->fmc)) { + if (!JFFS_ENOUGH_SPACE(c)) { D1(printk("jffs_rename(): Free size = %u\n", jffs_free_size1(c->fmc) + jffs_free_size2(c->fmc))); D(printk(KERN_NOTICE "JFFS: No space left on device\n")); return -ENOSPC; } - - /* Find the the old directory. */ + + /* Find the old directory. */ result = -ENOTDIR; if (!(old_dir_f = (struct jffs_file *)old_dir->u.generic_ip)) { D(printk("jffs_rename(): Old dir invalid.\n")); @@ -402,8 +437,8 @@ jffs_rename(struct inode *old_dir, struct dentry *old_dentry, old_dentry->d_name.len))) { goto jffs_rename_end; } - - /* Try to find the new directory's node. */ + + /* Find the new directory. */ result = -ENOTDIR; if (!(new_dir_f = (struct jffs_file *)new_dir->u.generic_ip)) { D(printk("jffs_rename(): New dir invalid.\n")); @@ -450,27 +485,31 @@ jffs_rename(struct inode *old_dir, struct dentry *old_dentry, if ((del_f = jffs_find_child(new_dir_f, new_dentry->d_name.name, new_dentry->d_name.len))) { raw_inode.rename = 1; - /*raw_inode.mode = del_f->ino;*/ + raw_inode.dsize = sizeof(__u32); + rename_data = del_f->ino; } /* Write the new node to the flash memory. */ - if ((result = jffs_write_node(c, node, &raw_inode, new_dentry->d_name.name, + if ((result = jffs_write_node(c, node, &raw_inode, + new_dentry->d_name.name, (unsigned char*)&rename_data)) < 0) { D(printk("jffs_rename(): Failed to write node to flash.\n")); kfree(node); DJM(no_jffs_node--); goto jffs_rename_end; } + raw_inode.dsize = 0; if (raw_inode.rename) { /* The file with the same name must be deleted. */ - c->fmc->no_call_gc = 1; /* TODO: What kind of locking is this? */ - if ((result = jffs_remove(new_dir, new_dentry, del_f->mode)) < 0) { + down(&c->fmc->gclock); + if ((result = jffs_remove(new_dir, new_dentry, + del_f->mode)) < 0) { /* This is really bad. */ printk(KERN_ERR "JFFS: An error occurred in " "rename().\n"); } - c->fmc->no_call_gc = 0; + up(&c->fmc->gclock); } if (old_dir_f != new_dir_f) { @@ -501,7 +540,6 @@ jffs_rename(struct inode *old_dir, struct dentry *old_dentry, } jffs_rename_end: - return result; } /* jffs_rename() */ @@ -524,13 +562,14 @@ jffs_readdir(struct file *filp, void *dirent, filldir_t filldir) return 0; } filp->f_pos = 1; - } + } if (filp->f_pos == 1) { if (inode->i_ino == JFFS_MIN_INO) { ddino = JFFS_MIN_INO; } else { - ddino = ((struct jffs_file *)inode->u.generic_ip)->pino; + ddino = ((struct jffs_file *) + inode->u.generic_ip)->pino; } D3(printk("jffs_readdir(): \"..\" %u\n", ddino)); if (filldir(dirent, "..", 2, filp->f_pos, ddino) < 0) @@ -549,7 +588,7 @@ jffs_readdir(struct file *filp, void *dirent, filldir_t filldir) return 0; filp->f_pos++; } - + return filp->f_pos; } /* jffs_readdir() */ @@ -565,10 +604,10 @@ jffs_lookup(struct inode *dir, struct dentry *dentry) int r = 0; const char *name; struct inode *inode = NULL; - + len = dentry->d_name.len; name = dentry->d_name.name; - + D3({ char *s = (char *)kmalloc(len + 1, GFP_KERNEL); memcpy(s, name, len); @@ -576,7 +615,7 @@ jffs_lookup(struct inode *dir, struct dentry *dentry) printk("jffs_lookup(): dir: 0x%p, name: \"%s\"\n", dir, s); kfree(s); }); - + r = -ENAMETOOLONG; if (len > JFFS_MAX_NAME_LEN) { goto jffs_lookup_end; @@ -584,7 +623,8 @@ jffs_lookup(struct inode *dir, struct dentry *dentry) r = -EACCES; if (!(d = (struct jffs_file *)dir->u.generic_ip)) { - D(printk("jffs_lookup(): No such inode! (%lu)\n", dir->i_ino)); + D(printk("jffs_lookup(): No such inode! (%lu)\n", + dir->i_ino)); goto jffs_lookup_end; } @@ -610,10 +650,10 @@ jffs_lookup(struct inode *dir, struct dentry *dentry) f, name, d, d->ino)); inode = NULL; } - + d_add(dentry, inode); return NULL; - + jffs_lookup_end: return ERR_PTR(r); } /* jffs_lookup() */ @@ -665,9 +705,9 @@ jffs_readpage(struct file *file, struct page *page) flush_dcache_page(page); UnlockPage(page); - + put_page(page); - + D3(printk("jffs_readpage(): Leaving...\n")); return result; @@ -686,7 +726,7 @@ jffs_mkdir(struct inode *dir, struct dentry *dentry, int mode) int dir_mode; int result = 0; int err; - + D1({ int len = dentry->d_name.len; char *_name = (char *) kmalloc(len + 1, GFP_KERNEL); @@ -707,7 +747,7 @@ jffs_mkdir(struct inode *dir, struct dentry *dentry, int mode) c = dir_f->c; - if (!JFFS_ENOUGH_SPACE(c->fmc)) { + if (!JFFS_ENOUGH_SPACE(c)) { D1(printk("jffs_mkdir(): Free size = %u\n", jffs_free_size1(c->fmc) + jffs_free_size2(c->fmc))); D(printk(KERN_NOTICE "JFFS: No space left on device\n")); @@ -718,7 +758,7 @@ jffs_mkdir(struct inode *dir, struct dentry *dentry, int mode) dir_mode = S_IFDIR | (mode & (S_IRWXUGO|S_ISVTX) & ~current->fs->umask); if (dir->i_mode & S_ISGID) { - dir_mode |= S_ISGID; + dir_mode |= S_ISGID; } /* Create a node and initialize it as much as needed. */ @@ -754,7 +794,8 @@ jffs_mkdir(struct inode *dir, struct dentry *dentry, int mode) raw_inode.deleted = 0; /* Write the new node to the flash. */ - if ((result = jffs_write_node(c, node, &raw_inode, dentry->d_name.name, 0)) < 0) { + if ((result = jffs_write_node(c, node, &raw_inode, + dentry->d_name.name, 0)) < 0) { D(printk("jffs_mkdir(): jffs_write_node() failed.\n")); kfree(node); DJM(no_jffs_node--); @@ -762,15 +803,17 @@ jffs_mkdir(struct inode *dir, struct dentry *dentry, int mode) } /* Insert the new node into the file system. */ - if ((result = jffs_insert_node(c, 0, &raw_inode, dentry->d_name.name, node))<0) - goto jffs_mkdir_end; - + if ((result = jffs_insert_node(c, 0, &raw_inode, dentry->d_name.name, + node)) < 0) { + goto jffs_mkdir_end; + } + inode = jffs_new_inode(dir, &raw_inode, &err); if (inode == NULL) { result = err; goto jffs_mkdir_end; } - + inode->i_op = &jffs_dir_inode_operations; inode->i_fop = &jffs_dir_operations; @@ -839,7 +882,8 @@ jffs_remove(struct inode *dir, struct dentry *dentry, int type) result = -ENOTEMPTY; goto jffs_remove_end; } - } else if (S_ISDIR(del_f->mode)) { + } + else if (S_ISDIR(del_f->mode)) { D(printk("jffs_remove(): node is a directory " "but it shouldn't be.\n")); result = -EPERM; @@ -847,7 +891,7 @@ jffs_remove(struct inode *dir, struct dentry *dentry, int type) } inode = dentry->d_inode; - + result = -EIO; if (del_f->ino != inode->i_ino) goto jffs_remove_end; @@ -936,7 +980,7 @@ jffs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev) dir_f = (struct jffs_file *)dir->u.generic_ip; c = dir_f->c; - if (!JFFS_ENOUGH_SPACE(c->fmc)) { + if (!JFFS_ENOUGH_SPACE(c)) { D1(printk("jffs_mknod(): Free size = %u\n", jffs_free_size1(c->fmc) + jffs_free_size2(c->fmc))); D(printk(KERN_NOTICE "JFFS: No space left on device\n")); @@ -985,7 +1029,8 @@ jffs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev) } /* Insert the new node into the file system. */ - if ((err = jffs_insert_node(c, 0, &raw_inode, dentry->d_name.name, node)) < 0) { + if ((err = jffs_insert_node(c, 0, &raw_inode, dentry->d_name.name, + node)) < 0) { result = err; goto jffs_mknod_end; } @@ -995,11 +1040,11 @@ jffs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev) result = err; goto jffs_mknod_end; } - + init_special_inode(inode, mode, rdev); d_instantiate(dentry, inode); - + goto jffs_mknod_end; jffs_mknod_err: @@ -1021,7 +1066,7 @@ jffs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) struct jffs_file *dir_f; struct jffs_node *node; struct inode *inode; - + int symname_len = strlen(symname); int err; @@ -1033,7 +1078,8 @@ jffs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) _name[len] = '\0'; memcpy(_symname, symname, symname_len); _symname[symname_len] = '\0'; - printk("***jffs_symlink(): dir = 0x%p, dentry->dname.name = \"%s\", " + printk("***jffs_symlink(): dir = 0x%p, " + "dentry->dname.name = \"%s\", " "symname = \"%s\"\n", dir, _name, _symname); kfree(_name); kfree(_symname); @@ -1048,7 +1094,7 @@ jffs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) c = dir_f->c; - if (!JFFS_ENOUGH_SPACE(c->fmc)) { + if (!JFFS_ENOUGH_SPACE(c)) { D1(printk("jffs_symlink(): Free size = %u\n", jffs_free_size1(c->fmc) + jffs_free_size2(c->fmc))); D(printk(KERN_NOTICE "JFFS: No space left on device\n")); @@ -1058,7 +1104,7 @@ jffs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) /* Create a node and initialize it as much as needed. */ if (!(node = (struct jffs_node *) kmalloc(sizeof(struct jffs_node), GFP_KERNEL))) { - D(printk("jffs_symlink(): Allocation failed: node == NULL\n")); + D(printk("jffs_symlink(): Allocation failed: node = NULL\n")); return -ENOMEM; } DJM(no_jffs_node++); @@ -1095,7 +1141,8 @@ jffs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) } /* Insert the new node into the file system. */ - if ((err = jffs_insert_node(c, 0, &raw_inode, dentry->d_name.name, node)) < 0) { + if ((err = jffs_insert_node(c, 0, &raw_inode, dentry->d_name.name, + node)) < 0) { return err; } @@ -1103,7 +1150,7 @@ jffs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) if (inode == NULL) { return err; } - + inode->i_op = &page_symlink_inode_operations; inode->i_mapping->a_ops = &jffs_address_operations; @@ -1112,14 +1159,15 @@ jffs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) return 0; } /* jffs_symlink() */ -/* Create an inode inside a JFFS directory (dir) and return it. + +/* Create an inode inside a JFFS directory (dir) and return it. * * By the time this is called, we already have created * the directory cache entry for the new file, but it * is so far negative - it has no inode. * * If the create succeeds, we fill in the inode information - * with d_instantiate(). + * with d_instantiate(). */ static int jffs_create(struct inode *dir, struct dentry *dentry, int mode) @@ -1149,7 +1197,7 @@ jffs_create(struct inode *dir, struct dentry *dentry, int mode) c = dir_f->c; - if (!JFFS_ENOUGH_SPACE(c->fmc)) { + if (!JFFS_ENOUGH_SPACE(c)) { D1(printk("jffs_create(): Free size = %u\n", jffs_free_size1(c->fmc) + jffs_free_size2(c->fmc))); D(printk(KERN_NOTICE "JFFS: No space left on device\n")); @@ -1187,7 +1235,8 @@ jffs_create(struct inode *dir, struct dentry *dentry, int mode) raw_inode.deleted = 0; /* Write the new node to the flash. */ - if ((err = jffs_write_node(c, node, &raw_inode, dentry->d_name.name, 0)) < 0) { + if ((err = jffs_write_node(c, node, &raw_inode, + dentry->d_name.name, 0)) < 0) { D(printk("jffs_create(): jffs_write_node() failed.\n")); kfree(node); DJM(no_jffs_node--); @@ -1195,7 +1244,8 @@ jffs_create(struct inode *dir, struct dentry *dentry, int mode) } /* Insert the new node into the file system. */ - if ((err = jffs_insert_node(c, 0, &raw_inode, dentry->d_name.name, node)) < 0) { + if ((err = jffs_insert_node(c, 0, &raw_inode, dentry->d_name.name, + node)) < 0) { return err; } @@ -1211,33 +1261,35 @@ jffs_create(struct inode *dir, struct dentry *dentry, int mode) inode->i_mapping->nrpages = 0; d_instantiate(dentry, inode); - + return 0; } /* jffs_create() */ /* Write, append or rewrite data to an existing file. */ static ssize_t -jffs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos) +jffs_file_write(struct file *filp, const char *buf, size_t count, + loff_t *ppos) { struct jffs_raw_inode raw_inode; struct jffs_control *c; struct jffs_file *f; struct jffs_node *node; - struct dentry *dentry = filp->f_dentry; - struct inode *inode = dentry->d_inode; + struct dentry *dentry = filp->f_dentry; + struct inode *inode = dentry->d_inode; + unsigned char *vbuf; int written = 0; loff_t pos; int err; inode = filp->f_dentry->d_inode; - + D2(printk("***jffs_file_write(): inode: 0x%p (ino: %lu), " "filp: 0x%p, buf: 0x%p, count: %d\n", inode, inode->i_ino, filp, buf, count)); down(&inode->i_sem); - + pos = *ppos; err = -EINVAL; if (pos < 0) @@ -1254,7 +1306,7 @@ jffs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos) err = -ENOSPC; goto out; } - + if (!S_ISREG(inode->i_mode)) { D(printk("jffs_file_write(): inode->i_mode == 0x%08x\n", inode->i_mode)); @@ -1268,10 +1320,10 @@ jffs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos) err = -EINVAL; goto out; } - + c = f->c; - if (!JFFS_ENOUGH_SPACE(c->fmc)) { + if (!JFFS_ENOUGH_SPACE(c)) { D1(printk("jffs_file_write(): Free size = %u\n", jffs_free_size1(c->fmc) + jffs_free_size2(c->fmc))); D(printk(KERN_NOTICE "JFFS: No space left on device\n")); @@ -1282,16 +1334,35 @@ jffs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos) if (filp->f_flags & O_APPEND) pos = inode->i_size; + + if (!(vbuf = kmalloc(count, GFP_KERNEL))) { + D(printk("jffs_file_write(): failed to allocate bounce buffer. Fix me to use page cache\n")); + err = -ENOMEM; + goto out; + } + + /* FIXME: This is entirely gratuitous use of bounce buffers. + Get a clue and use the page cache. + /me wanders off to get a crash course on Linux VFS + dwmw2 + */ + if (copy_from_user(vbuf, buf, count)) { + kfree(vbuf); + return -EFAULT; + } + + /* Things are going to be written so we could allocate and initialize the necessary data structures now. */ if (!(node = (struct jffs_node *) kmalloc(sizeof(struct jffs_node), GFP_KERNEL))) { D(printk("jffs_file_write(): node == 0\n")); err = -ENOMEM; + kfree(vbuf); goto out; } DJM(no_jffs_node++); - node->data_offset = f->size; + node->data_offset = pos; node->removed_size = 0; /* Initialize the raw inode. */ @@ -1300,7 +1371,7 @@ jffs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos) raw_inode.pino = f->pino; raw_inode.version = f->highest_version + 1; raw_inode.mode = f->mode; - + raw_inode.uid = f->uid; raw_inode.gid = f->gid; /* @@ -1310,7 +1381,7 @@ jffs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos) raw_inode.atime = CURRENT_TIME; raw_inode.mtime = raw_inode.atime; raw_inode.ctime = f->ctime; - raw_inode.offset = f->size; + raw_inode.offset = pos; raw_inode.dsize = count; raw_inode.rsize = 0; raw_inode.nsize = 0; @@ -1319,25 +1390,28 @@ jffs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos) raw_inode.rename = 0; raw_inode.deleted = 0; + if (pos < f->size) { + node->removed_size = raw_inode.rsize = jffs_min(count, f->size - pos); + } - /* TODO: BAAAAAAAAD! buf is a userspace-pointer, and should be - treated as such, with copy_from_user etc... - */ /* Write the new node to the flash. */ if ((written = jffs_write_node(c, node, &raw_inode, 0, - (const unsigned char *)buf)) < 0) { + (const unsigned char *)vbuf)) < 0) { D(printk("jffs_file_write(): jffs_write_node() failed.\n")); kfree(node); + kfree(vbuf); DJM(no_jffs_node--); err = written; goto out; } + kfree(vbuf); + /* Insert the new node into the file system. */ if ((err = jffs_insert_node(c, f, &raw_inode, 0, node)) < 0) { goto out; } - + pos += written; *ppos = pos; @@ -1365,7 +1439,8 @@ jffs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, { struct jffs_control *c; - D2(printk("***jffs_ioctl(): cmd = 0x%08x, arg = 0x%08lx\n", cmd, arg)); + D2(printk("***jffs_ioctl(): cmd = 0x%08x, arg = 0x%08lx\n", + cmd, arg)); if (!(c = (struct jffs_control *)inode->i_sb->u.generic_sbp)) { printk(KERN_ERR "JFFS: Bad inode in ioctl() call. " @@ -1402,10 +1477,10 @@ jffs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, fst.size, fst.used, fst.dirty, fst.begin, fst.end); if (copy_to_user((struct jffs_flash_status *)arg, - &fst, sizeof(struct jffs_flash_status))) { + &fst, + sizeof(struct jffs_flash_status))) { return -EFAULT; } - } break; default: @@ -1417,9 +1492,17 @@ jffs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, static struct address_space_operations jffs_address_operations = { - readpage: jffs_readpage, + readpage: jffs_readpage, }; +static int jffs_fsync(struct file *f, struct dentry *d, int datasync) +{ + /* We currently have O_SYNC operations at all times. + Do nothing + */ + return 0; +} + static struct file_operations jffs_file_operations = { @@ -1427,19 +1510,23 @@ static struct file_operations jffs_file_operations = write: jffs_file_write, /* write */ ioctl: jffs_ioctl, /* ioctl */ mmap: generic_file_mmap, /* mmap */ + fsync: jffs_fsync, }; + static struct inode_operations jffs_file_inode_operations = { lookup: jffs_lookup, /* lookup */ setattr: jffs_setattr, }; + static struct file_operations jffs_dir_operations = { readdir: jffs_readdir, }; + static struct inode_operations jffs_dir_inode_operations = { create: jffs_create, @@ -1453,6 +1540,7 @@ static struct inode_operations jffs_dir_inode_operations = setattr: jffs_setattr, }; + /* Initialize an inode for the VFS. */ static void jffs_read_inode(struct inode *inode) @@ -1483,7 +1571,7 @@ jffs_read_inode(struct inode *inode) inode->i_mtime = f->mtime; inode->i_ctime = f->ctime; inode->i_blksize = PAGE_SIZE; - inode->i_blocks = 0; + inode->i_blocks = (inode->i_size + PAGE_SIZE - 1) >> PAGE_SHIFT; if (S_ISREG(inode->i_mode)) { inode->i_op = &jffs_file_inode_operations; inode->i_fop = &jffs_file_operations; @@ -1494,44 +1582,42 @@ jffs_read_inode(struct inode *inode) inode->i_fop = &jffs_dir_operations; } else if (S_ISLNK(inode->i_mode)) { - inode->i_op = &page_symlink_inode_operations; + inode->i_op = &page_symlink_inode_operations; inode->i_mapping->a_ops = &jffs_address_operations; - } else { - /* If the node is a device of some sort, then the number of the - device should be read from the flash memory and then added - to the inode's i_rdev member. */ + } + else { + /* If the node is a device of some sort, then the number of + the device should be read from the flash memory and then + added to the inode's i_rdev member. */ kdev_t rdev; jffs_read_data(f, (char *)&rdev, 0, sizeof(kdev_t)); init_special_inode(inode, inode->i_mode, kdev_t_to_nr(rdev)); } } + void jffs_delete_inode(struct inode *inode) { + D3(printk("jffs_delete_inode(): inode->i_ino == %lu\n", + inode->i_ino)); - D3(printk("jffs_delete_inode(): inode->i_ino == %lu\n", inode->i_ino)); - - lock_kernel(); - + lock_kernel(); inode->i_size = 0; - clear_inode(inode); - unlock_kernel(); } + void jffs_write_super(struct super_block *sb) { -#ifdef USE_GC struct jffs_control *c = (struct jffs_control *)sb->u.generic_sbp; - - if(!c->fmc->no_call_gc) - jffs_garbage_collect(c); -#endif + + jffs_garbage_collect_trigger(c); } + static struct super_operations jffs_ops = { read_inode: jffs_read_inode, @@ -1541,12 +1627,15 @@ static struct super_operations jffs_ops = statfs: jffs_statfs, }; + static DECLARE_FSTYPE_DEV(jffs_fs_type, "jffs", jffs_read_super); static int __init init_jffs_fs(void) { - printk("JFFS version " JFFS_VERSION_STRING ", (C) 1999, 2000 Axis Communications AB\n"); + printk("JFFS version " + JFFS_VERSION_STRING + ", (C) 1999, 2000 Axis Communications AB\n"); return register_filesystem(&jffs_fs_type); } diff --git a/fs/jffs/intrep.c b/fs/jffs/intrep.c index 039aaa04e854..adb2e0c46b5d 100644 --- a/fs/jffs/intrep.c +++ b/fs/jffs/intrep.c @@ -10,7 +10,7 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * $Id: intrep.c,v 1.15 2000/06/27 15:33:43 dwmw2 Exp $ + * $Id: intrep.c,v 1.39 2000/08/09 13:23:36 dwmw2 Exp $ * * Ported to Linux 2.3.x and MTD: * Copyright (C) 2000 Alexander Larsson (alex@cendio.se), Cendio Systems AB @@ -23,7 +23,7 @@ /* * Todo list: * - * memcpy_to_flash() and memcpy_from_flash()-functions. + * memcpy_to_flash() and memcpy_from_flash() functions. * * Implementation of hard links. * @@ -43,9 +43,6 @@ * Implement more meaning of the nlink member in various data structures. * nlink could be used in conjunction with hard links for instance. * - * Fix the rename stuff. (I.e. if we have two files `a' and `b' and we - * do a `mv b a'.) Half of this is already implemented. - * * Better memory management. Allocate data structures in larger chunks * if possible. * @@ -57,8 +54,8 @@ * information to be able to debug (or to supervise) JFFS during run-time. * */ + #define __NO_VERSION__ -#include #include #include #include @@ -69,6 +66,9 @@ #include #include #include +#include +#include + #include "intrep.h" #include "jffs_fm.h" @@ -77,16 +77,6 @@ #define set_current_state(x) do{current->state = x;} while (0) #endif -#if defined(CONFIG_JFFS_FS_VERBOSE) && CONFIG_JFFS_FS_VERBOSE -#define D(x) x -#else -#define D(x) -#endif -#define D1(x) D(x) -#define D2(x) -#define D3(x) -#define ASSERT(x) x - #if defined(JFFS_MEMORY_DEBUG) && JFFS_MEMORY_DEBUG long no_jffs_file = 0; long no_jffs_node = 0; @@ -192,50 +182,53 @@ jffs_hexdump(struct mtd_info *mtd, loff_t pos, int size) } #endif -#define flash_safe_acquire(arg) -#define flash_safe_release(arg) +#define flash_safe_acquire(arg) +#define flash_safe_release(arg) + static int flash_safe_read(struct mtd_info *mtd, loff_t from, u_char *buf, size_t count) { - size_t retlen; - - MTD_READ(mtd, from, count, &retlen, buf); - if (retlen != count) { - printk("Didn't read all bytes in flash_safe_read()\n"); - } - return retlen; + size_t retlen; + + MTD_READ(mtd, from, count, &retlen, buf); + if (retlen != count) { + printk("Didn't read all bytes in flash_safe_read()\n"); + } + return retlen; } + static __u32 flash_read_u32(struct mtd_info *mtd, loff_t from) { - size_t retlen; - __u32 ret; - - MTD_READ(mtd, from, 4, &retlen, (unsigned char *)&ret); - if (retlen != 4) { - printk("Didn't read all bytes in flash_read_u32()\n"); - return 0; - } + size_t retlen; + __u32 ret; + + MTD_READ(mtd, from, 4, &retlen, (unsigned char *)&ret); + if (retlen != 4) { + printk("Didn't read all bytes in flash_read_u32()\n"); + return 0; + } - return ret; + return ret; } + static __u8 flash_read_u8(struct mtd_info *mtd, loff_t from) { - size_t retlen; - __u8 ret; - - MTD_READ(mtd, from, 1, &retlen, &ret); - if (retlen != 1) { - printk("Didn't read all bytes in flash_read_u32()\n"); - return 0; - } + size_t retlen; + __u8 ret; - return ret; + MTD_READ(mtd, from, 1, &retlen, &ret); + if (retlen != 1) { + printk("Didn't read a byte in flash_read_u8()\n"); + return 0; + } + + return ret; } @@ -243,95 +236,100 @@ static int flash_safe_write(struct mtd_info *mtd, loff_t to, const u_char *buf, size_t count) { - size_t retlen; + size_t retlen; - MTD_WRITE(mtd, to, count, &retlen, buf); - if (retlen != count) { - printk("Didn't write all bytes in flash_safe_write()\n"); - } - return retlen; + MTD_WRITE(mtd, to, count, &retlen, buf); + if (retlen != count) { + printk("Didn't write all bytes in flash_safe_write()\n"); + } + return retlen; } + static int flash_memset(struct mtd_info *mtd, loff_t to, const u_char c, size_t size) { - static unsigned char pattern[16]; - int i; + static unsigned char pattern[16]; + int i; - /* fill up pattern */ - - for(i = 0; i < 16; i++) - pattern[i] = c; + /* fill up pattern */ - /* write as many 16-byte chunks as we can */ - - while(size >= 16) { - flash_safe_write(mtd, to, pattern, 16); - size -= 16; - to += 16; - } + for(i = 0; i < 16; i++) + pattern[i] = c; - /* and the rest */ - - if(size) - flash_safe_write(mtd, to, pattern, size); + /* write as many 16-byte chunks as we can */ - return size; + while (size >= 16) { + flash_safe_write(mtd, to, pattern, 16); + size -= 16; + to += 16; + } + + /* and the rest */ + + if(size) + flash_safe_write(mtd, to, pattern, size); + + return size; } -static void intrep_erase_callback(struct erase_info *done) + +static void +intrep_erase_callback(struct erase_info *done) { - wait_queue_head_t *wait_q; + wait_queue_head_t *wait_q; - wait_q = (wait_queue_head_t *)done->priv; + wait_q = (wait_queue_head_t *)done->priv; - wake_up(wait_q); + wake_up(wait_q); } + static int flash_erase_region(struct mtd_info *mtd, loff_t start, size_t size) { - struct erase_info *erase; - DECLARE_WAITQUEUE(wait, current); - wait_queue_head_t wait_q; + struct erase_info *erase; + DECLARE_WAITQUEUE(wait, current); + wait_queue_head_t wait_q; - erase = kmalloc(sizeof(struct erase_info), GFP_KERNEL); - if (!erase) - return -ENOMEM; + erase = kmalloc(sizeof(struct erase_info), GFP_KERNEL); + if (!erase) + return -ENOMEM; - init_waitqueue_head(&wait_q); + init_waitqueue_head(&wait_q); - erase->mtd = mtd; - erase->callback = intrep_erase_callback; - erase->addr = start; - erase->len = size; - erase->priv = (u_long)&wait_q; + erase->mtd = mtd; + erase->callback = intrep_erase_callback; + erase->addr = start; + erase->len = size; + erase->priv = (u_long)&wait_q; - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&wait_q, &wait); - - if (MTD_ERASE(mtd, erase) < 0) { - set_current_state(TASK_RUNNING); - remove_wait_queue(&wait_q, &wait); - kfree(erase); - - printk(KERN_WARNING "flash: erase of region [0x%ld, 0x%ld] totally failed\n", - (long)start, (long)start + size); - - return -1; - } - - schedule(); /* Wait for flash to finish. */ - /* FIXME: We could have been interrupted here. We don't deal with it */ - remove_wait_queue(&wait_q, &wait); - - kfree(erase); - - return 0; + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&wait_q, &wait); + + if (MTD_ERASE(mtd, erase) < 0) { + set_current_state(TASK_RUNNING); + remove_wait_queue(&wait_q, &wait); + kfree(erase); + + printk(KERN_WARNING "flash: erase of region [0x%lx, 0x%lx] " + "totally failed\n", (long)start, (long)start + size); + + return -1; + } + + schedule(); /* Wait for flash to finish. */ + /* FIXME: We could have been interrupted here. We don't deal with it */ + remove_wait_queue(&wait_q, &wait); + + kfree(erase); + + return 0; } + inline int jffs_min(int a, int b) { @@ -359,6 +357,7 @@ jffs_checksum(const void *data, int size) return sum; } + __u32 jffs_checksum_flash(struct mtd_info *mtd, loff_t start, int size) { @@ -371,6 +370,17 @@ jffs_checksum_flash(struct mtd_info *mtd, loff_t start, int size) return sum; } +static __inline__ void jffs_fm_write_lock(struct jffs_fmcontrol *fmc) +{ + down(&fmc->wlock); +} + +static __inline__ void jffs_fm_write_unlock(struct jffs_fmcontrol *fmc) +{ + up(&fmc->wlock); +} + + /* Create and initialize a new struct jffs_file. */ static struct jffs_file * jffs_create_file(struct jffs_control *c, @@ -417,12 +427,13 @@ jffs_create_control(kdev_t dev) goto fail_hash; } DJM(no_hash++); - for (i=0;ihash_len;i++) + for (i = 0; i < c->hash_len; i++) INIT_LIST_HEAD(&c->hash[i]); if (!(c->fmc = jffs_build_begin(c, dev))) { goto fail_fminit; } c->next_ino = JFFS_MIN_INO + 1; + c->delete_list = (struct jffs_delete_list *) 0; return c; fail_fminit: @@ -449,9 +460,17 @@ jffs_cleanup_control(struct jffs_control *c) return; } + while (c->delete_list) { + struct jffs_delete_list *delete_list_element; + delete_list_element = c->delete_list; + c->delete_list = c->delete_list->next; + kfree(delete_list_element); + } + /* Free all files and nodes. */ if (c->hash) { jffs_foreach_file(c, jffs_free_node_list); + jffs_foreach_file(c, jffs_free_file); kfree(c->hash); DJM(no_hash--); } @@ -525,6 +544,18 @@ jffs_build_fs(struct super_block *sb) } } + while (c->delete_list) { + struct jffs_file *f; + struct jffs_delete_list *delete_list_element; + + if ((f = jffs_find_file(c, c->delete_list->ino))) { + f->deleted = 1; + } + delete_list_element = c->delete_list; + c->delete_list = c->delete_list->next; + kfree(delete_list_element); + } + /* Remove deleted nodes. */ if ((err = jffs_foreach_file(c, jffs_possibly_delete_file)) < 0) { printk(KERN_ERR "JFFS: Failed to remove deleted nodes.\n"); @@ -570,46 +601,60 @@ jffs_scan_flash(struct jffs_control *c) __u32 checksum; __u8 tmp_accurate; __u16 tmp_chksum; + __u32 deleted_file; loff_t pos = fmc->flash_start; loff_t start; loff_t end = fmc->flash_start + fmc->flash_size; - D1(printk("jffs_scan_flash(): start pos = 0x%ld, end = 0x%ld\n", + D1(printk("jffs_scan_flash(): start pos = 0x%lx, end = 0x%lx\n", (long)pos, (long)end)); flash_safe_acquire(fmc->mtd); /* Start the scan. */ while (pos < end) { + deleted_file = 0; /* Remember the position from where we started this scan. */ start = pos; switch (flash_read_u32(fmc->mtd, pos)) { case JFFS_EMPTY_BITMASK: - /* We have found 0xff on this block. We have to - scan the rest of the block to be sure it is - filled with 0xff. */ - D1(printk("jffs_scan_flash(): 0xff at pos 0x%ld.\n", + /* We have found 0xff at this position. We have to + scan the rest of the flash till the end or till + something else than 0xff is found. */ + D1(printk("jffs_scan_flash(): 0xff at pos 0x%lx.\n", (long)pos)); for (; pos < end && JFFS_EMPTY_BITMASK == flash_read_u32(fmc->mtd, pos); pos += 4); D1(printk("jffs_scan_flash(): 0xff ended at " - "pos 0x%ld.\n", (long)pos)); + "pos 0x%lx.\n", (long)pos)); + + /* If some free space ends in the middle of a sector, + treat it as dirty rather than clean. + This is to handle the case where one thread + allocated space for a node, but didn't get to + actually _write_ it before power was lost, leaving + a gap in the log. Shifting all node writes into + a single kernel thread will fix the original problem. + */ + if ((__u32) pos % fmc->sector_size) { + jffs_fmalloced(fmc, (__u32) start, + (__u32) (pos - start), 0); + } continue; case JFFS_DIRTY_BITMASK: - /* We have found 0x00 on this block. We have to - scan as far as possible to find out how much - is dirty. */ - D1(printk("jffs_scan_flash(): 0x00 at pos 0x%ld.\n", + /* We have found 0x00 at this position. Scan as far + as possible to find out how much is dirty. */ + D1(printk("jffs_scan_flash(): 0x00 at pos 0x%lx.\n", (long)pos)); for (; pos < end && JFFS_DIRTY_BITMASK == flash_read_u32(fmc->mtd, pos); pos += 4); D1(printk("jffs_scan_flash(): 0x00 ended at " - "pos 0x%ld.\n", (long)pos)); + "pos 0x%lx.\n", (long)pos)); jffs_fmalloced(fmc, (__u32) start, (__u32) (pos - start), 0); continue; @@ -622,8 +667,9 @@ jffs_scan_flash(struct jffs_control *c) bad_inode: /* We're f*cked. This is not solved yet. We have to scan for the magic pattern. */ - D1(printk("*************** Dirty flash memory or bad inode: " - "hexdump(pos = 0x%ld, len = 128):\n", + D1(printk("*************** Dirty flash memory or " + "bad inode: " + "hexdump(pos = 0x%lx, len = 128):\n", (long)pos)); D1(jffs_hexdump(fmc->mtd, pos, 128)); for (pos += 4; pos < end; pos += 4) { @@ -642,7 +688,7 @@ jffs_scan_flash(struct jffs_control *c) } /* We have found the beginning of an inode. Create a - node for it. */ + node for it unless there already is one available. */ if (!node) { if (!(node = (struct jffs_node *) kmalloc(sizeof(struct jffs_node), @@ -655,7 +701,8 @@ jffs_scan_flash(struct jffs_control *c) /* Read the next raw inode. */ - flash_safe_read(fmc->mtd, pos, (u_char *) &raw_inode, sizeof(struct jffs_raw_inode)); + flash_safe_read(fmc->mtd, pos, (u_char *) &raw_inode, + sizeof(struct jffs_raw_inode)); /* When we compute the checksum for the inode, we never count the 'accurate' or the 'checksum' fields. */ @@ -668,7 +715,7 @@ jffs_scan_flash(struct jffs_control *c) raw_inode.accurate = tmp_accurate; raw_inode.chksum = tmp_chksum; - D3(printk("*** We have found this raw inode at pos 0x%ld " + D3(printk("*** We have found this raw inode at pos 0x%lx " "on the flash:\n", (long)pos)); D3(jffs_print_raw_inode(&raw_inode)); @@ -689,6 +736,15 @@ jffs_scan_flash(struct jffs_control *c) if (raw_inode.nsize > JFFS_MAX_NAME_LEN) { goto bad_inode; } + + if (raw_inode.rename && raw_inode.dsize != sizeof(__u32)) { + printk(KERN_WARNING "jffs_scan_flash: Found a " + "rename node with dsize %u.\n", + raw_inode.dsize); + jffs_print_raw_inode(&raw_inode); + goto bad_inode; + } + /* The node's data segment should not exceed a certain length. */ if (raw_inode.dsize > fmc->max_chunk_size) { @@ -728,20 +784,26 @@ jffs_scan_flash(struct jffs_control *c) } } - /* Read the data in order to be sure it matches the - checksum. */ - checksum = jffs_checksum_flash(fmc->mtd, pos, raw_inode.dsize); - pos += raw_inode.dsize + JFFS_GET_PAD_BYTES(raw_inode.dsize); + /* Read the data, if it exists, in order to be sure it + matches the checksum. */ + if (raw_inode.dsize) { + if (raw_inode.rename) { + deleted_file = flash_read_u32(fmc->mtd, pos); + } + checksum = jffs_checksum_flash(fmc->mtd, pos, raw_inode.dsize); + pos += raw_inode.dsize + + JFFS_GET_PAD_BYTES(raw_inode.dsize); - if (checksum != raw_inode.dchksum) { - D1(printk("jffs_scan_flash(): Bad checksum: " - "checksum = %u, " - "raw_inode.dchksum = %u\n", - checksum, raw_inode.dchksum)); - jffs_fmalloced(fmc, (__u32) start, - (__u32) (pos - start), 0); - /* Reuse this unused struct jffs_node. */ - continue; + if (checksum != raw_inode.dchksum) { + D1(printk("jffs_scan_flash(): Bad checksum: " + "checksum = %u, " + "raw_inode.dchksum = %u\n", + checksum, raw_inode.dchksum)); + jffs_fmalloced(fmc, (__u32) start, + (__u32) (pos - start), 0); + /* Reuse this unused struct jffs_node. */ + continue; + } } check_node: @@ -780,6 +842,23 @@ jffs_scan_flash(struct jffs_control *c) "(err = %d)\n", err); break; } + if (raw_inode.rename) { + struct jffs_delete_list *dl + = (struct jffs_delete_list *) + kmalloc(sizeof(struct jffs_delete_list), + GFP_KERNEL); + if (!dl) { + D(printk("jffs_scan_flash: !dl\n")); + kfree(node); + DJM(no_jffs_node--); + flash_safe_release(fmc->flash_part); + return -ENOMEM; + } + dl->ino = deleted_file; + dl->next = c->delete_list; + c->delete_list = dl; + node->data_size = 0; + } D3(jffs_print_node(node)); node = 0; /* Don't free the node! */ } @@ -815,7 +894,8 @@ jffs_insert_node(struct jffs_control *c, struct jffs_file *f, int update_name = 0; int insert_into_tree = 0; - D2(printk("jffs_insert_node(): ino = %u, version = %u, name = \"%s\"\n", + D2(printk("jffs_insert_node(): ino = %u, version = %u, " + "name = \"%s\"\n", raw_inode->ino, raw_inode->version, ((name && *name) ? name : ""))); @@ -942,11 +1022,9 @@ jffs_insert_node(struct jffs_control *c, struct jffs_file *f, } jffs_remove_redundant_nodes(f); } -#ifdef USE_GC - if (!c->fmc->no_call_gc) { - jffs_garbage_collect(c); - } -#endif + + jffs_garbage_collect_trigger(c); + D3(printk("jffs_insert_node(): ---------------------------" "------------------------------------------- 2\n")); } @@ -1247,8 +1325,8 @@ jffs_write_dummy_node(struct jffs_control *c, struct jffs_fm *dirty_fm) (u_char *)&raw_inode, sizeof(struct jffs_raw_inode))) < 0) { - printk(KERN_ERR "JFFS: jffs_write_dummy_node: " - "flash_safe_write failed!\n"); + printk(KERN_ERR "JFFS: jffs_write_dummy_node: " + "flash_safe_write failed!\n"); return err; } } @@ -1262,6 +1340,7 @@ jffs_write_dummy_node(struct jffs_control *c, struct jffs_fm *dirty_fm) return 0; } + /* Write a raw inode, possibly its name and possibly some data. */ int jffs_write_node(struct jffs_control *c, struct jffs_node *node, @@ -1269,7 +1348,7 @@ jffs_write_node(struct jffs_control *c, struct jffs_node *node, const char *name, const unsigned char *data) { struct jffs_fmcontrol *fmc = c->fmc; - struct jffs_fm *fm; + struct jffs_fm *fm = NULL; __u32 pos; int err; __u32 total_name_size = raw_inode->nsize @@ -1296,30 +1375,54 @@ jffs_write_node(struct jffs_control *c, struct jffs_node *node, (name ? name : ""), raw_inode->ino, raw_inode->version, total_size)); - /* First try to allocate some flash memory. */ - if ((err = jffs_fmalloc(fmc, total_size, node, &fm)) < 0) { - D(printk("jffs_write_node(): jffs_fmalloc(0x%p, %u) " - "failed!\n", fmc, total_size)); - return err; - } - else if (!fm->nodes) { - /* The jffs_fm struct that we got is not good enough. - Make that space dirty. */ - if ((err = jffs_write_dummy_node(c, fm)) < 0) { - D(printk("jffs_write_node(): " - "jffs_write_dummy_node(): Failed!\n")); - kfree(fm); - DJM(no_jffs_fm--); + jffs_fm_write_lock(fmc); + + while (!fm) { + + /* First try to allocate some flash memory. */ + err = jffs_fmalloc(fmc, total_size, node, &fm); + + if (err == -ENOSPC) { + /* Just out of space. GC and try again */ + if (fmc->dirty_size < fmc->sector_size) { + D(printk("jffs_write_node(): jffs_fmalloc(0x%p, %u) " + "failed, no dirty space to GC\n", fmc, + total_size)); + return err; + } + + D1(printk(KERN_INFO "jffs_write_node(): Calling jffs_garbage_collect_now()\n")); + jffs_fm_write_unlock(fmc); + if ((err = jffs_garbage_collect_now(c))) { + D(printk("jffs_write_node(): jffs_garbage_collect_now() failed\n")); + return err; + } + jffs_fm_write_lock(fmc); + continue; + } + + if (err < 0) { + jffs_fm_write_unlock(fmc); + + D(printk("jffs_write_node(): jffs_fmalloc(0x%p, %u) " + "failed!\n", fmc, total_size)); return err; } - /* Get a new one. */ - if ((err = jffs_fmalloc(fmc, total_size, node, &fm)) < 0) { - D(printk("jffs_write_node(): Second " - "jffs_fmalloc(0x%p, %u) failed!\n", - fmc, total_size)); - return err; + + if (!fm->nodes) { + /* The jffs_fm struct that we got is not good enough. + Make that space dirty and try again */ + if ((err = jffs_write_dummy_node(c, fm)) < 0) { + kfree(fm); + DJM(no_jffs_fm--); + jffs_fm_write_unlock(fmc); + D(printk("jffs_write_node(): " + "jffs_write_dummy_node(): Failed!\n")); + return err; + } + fm = NULL; } - } + } /* while(!fm) */ node->fm = fm; ASSERT(if (fm->nodes == 0) { @@ -1341,7 +1444,7 @@ jffs_write_node(struct jffs_control *c, struct jffs_node *node, raw_inode->accurate = 0xff; D3(printk("jffs_write_node(): About to write this raw inode to the " - "flash at pos 0x%ld:\n", (long)pos)); + "flash at pos 0x%lx:\n", (long)pos)); D3(jffs_print_raw_inode(raw_inode)); /* Step 1: Write the raw jffs inode to the flash. */ @@ -1350,8 +1453,9 @@ jffs_write_node(struct jffs_control *c, struct jffs_node *node, sizeof(struct jffs_raw_inode))) < 0) { jffs_fmfree_partly(fmc, fm, total_name_size + total_data_size); - printk(KERN_ERR "JFFS: jffs_write_node: Failed to write " - "raw_inode.\n"); + jffs_fm_write_unlock(fmc); + printk(KERN_ERR "JFFS: jffs_write_node: Failed to write " + "raw_inode.\n"); return err; } pos += sizeof(struct jffs_raw_inode); @@ -1359,9 +1463,10 @@ jffs_write_node(struct jffs_control *c, struct jffs_node *node, /* Step 2: Write the name, if there is any. */ if (raw_inode->nsize) { if ((err = flash_safe_write(fmc->mtd, pos, - (u_char *)name, + (u_char *)name, raw_inode->nsize)) < 0) { jffs_fmfree_partly(fmc, fm, total_data_size); + jffs_fm_write_unlock(fmc); printk(KERN_ERR "JFFS: jffs_write_node: Failed to " "write the name.\n"); return err; @@ -1374,12 +1479,13 @@ jffs_write_node(struct jffs_control *c, struct jffs_node *node, if ((err = flash_safe_write(fmc->mtd, pos, data, raw_inode->dsize)) < 0) { jffs_fmfree_partly(fmc, fm, 0); - printk(KERN_ERR "JFFS: jffs_write_node: Failed to " + jffs_fm_write_unlock(fmc); + printk(KERN_ERR "JFFS: jffs_write_node: Failed to " "write the data.\n"); return err; } } - + jffs_fm_write_unlock(fmc); D3(printk("jffs_write_node(): Leaving...\n")); return raw_inode->dsize; } /* jffs_write_node() */ @@ -1498,7 +1604,7 @@ jffs_foreach_file(struct jffs_control *c, int (*func)(struct jffs_file *)) } -/* Free all memory associated with a file. */ +/* Free all nodes associated with a file. */ int jffs_free_node_list(struct jffs_file *f) { @@ -1518,6 +1624,23 @@ jffs_free_node_list(struct jffs_file *f) } +/* Free a file and its name. */ +int +jffs_free_file(struct jffs_file *f) +{ + D3(printk("jffs_free_file: f #%u, \"%s\"\n", + f->ino, (f->name ? f->name : ""))); + + if (f->name) { + kfree(f->name); + DJM(no_name--); + } + kfree(f); + DJM(no_jffs_file--); + return 0; +} + + /* See if a file is deleted. If so, mark that file's nodes as obsolete. */ int jffs_possibly_delete_file(struct jffs_file *f) @@ -1533,7 +1656,8 @@ jffs_possibly_delete_file(struct jffs_file *f) }); if (f->deleted) { - /* First try to remove all older versions. */ + /* First try to remove all older versions. Commence with + the oldest node. */ for (n = f->version_head; n; n = n->version_next) { if (!n->fm) { continue; @@ -1543,15 +1667,12 @@ jffs_possibly_delete_file(struct jffs_file *f) } } /* Unlink the file from the filesystem. */ - jffs_unlink_file_from_tree(f); + if (!f->c->building_fs) { + jffs_unlink_file_from_tree(f); + } jffs_unlink_file_from_hash(f); jffs_free_node_list(f); - if (f->name) { - kfree(f->name); - DJM(no_name--); - } - kfree(f); - DJM(no_jffs_file--); + jffs_free_file(f); } return 0; } @@ -1589,7 +1710,7 @@ jffs_build_file(struct jffs_file *f) Starting offset of area to be removed is node->data_offset, and the length of the area is in node->removed_size. */ -static void +static int jffs_delete_data(struct jffs_file *f, struct jffs_node *node) { struct jffs_node *n; @@ -1604,7 +1725,7 @@ jffs_delete_data(struct jffs_file *f, struct jffs_node *node) && f->range_tail->data_offset + f->range_tail->data_size == offset) { /* A simple append; nothing to remove or no node to split. */ - return; + return 0; } /* Find the node where we should begin the removal. */ @@ -1616,7 +1737,7 @@ jffs_delete_data(struct jffs_file *f, struct jffs_node *node) if (!n) { /* If there's no data in the file there's no data to remove either. */ - return; + return 0; } if (n->data_offset > offset) { @@ -1626,7 +1747,7 @@ jffs_delete_data(struct jffs_file *f, struct jffs_node *node) } else if (n->data_offset < offset) { /* See if the node has to be split into two parts. */ - if (n->data_offset + n->data_size < offset + remove_size) { + if (n->data_offset + n->data_size > offset + remove_size) { /* Do the split. */ struct jffs_node *new_node; D3(printk("jffs_delete_data(): Split node with " @@ -1636,18 +1757,15 @@ jffs_delete_data(struct jffs_file *f, struct jffs_node *node) kmalloc(sizeof(struct jffs_node), GFP_KERNEL))) { D(printk("jffs_delete_data(): -ENOMEM\n")); - return; + return -ENOMEM; } DJM(no_jffs_node++); new_node->ino = n->ino; new_node->version = n->version; new_node->data_offset = offset; - new_node->data_size = n->data_size - - (remove_size - + (offset - n->data_offset)); - new_node->fm_offset = n->fm_offset + n->data_size - + remove_size; + new_node->data_size = n->data_size - (remove_size + (offset - n->data_offset)); + new_node->fm_offset = n->fm_offset + (remove_size + (offset - n->data_offset)); new_node->name_size = n->name_size; new_node->fm = n->fm; new_node->version_prev = n; @@ -1671,7 +1789,12 @@ jffs_delete_data(struct jffs_file *f, struct jffs_node *node) /* A very interesting can of worms. */ n->range_next = new_node; n->data_size = offset - n->data_offset; - jffs_add_node(new_node); + if (new_node->fm) + jffs_add_node(new_node); + else { + D1(printk(KERN_WARNING "jffs_delete_data(): Splitting an empty node (file hold).\n!")); + D1(printk(KERN_WARNING "FIXME: Did dwmw2 do the right thing here?\n")); + } n = new_node->range_next; remove_size = 0; } @@ -1693,8 +1816,9 @@ jffs_delete_data(struct jffs_file *f, struct jffs_node *node) remove_size -= n->data_size; n = n->range_next; D3(printk("jffs_delete_data(): Removing node: " - "ino: %u, version: %u\n", - p->ino, p->version)); + "ino: %u, version: %u%s\n", + p->ino, p->version, + (p->fm ? "" : " (virtual)"))); if (p->fm) { jffs_fmfree(f->c->fmc, p->fm, p); } @@ -1720,12 +1844,13 @@ jffs_delete_data(struct jffs_file *f, struct jffs_node *node) f->size -= node->removed_size; D3(printk("jffs_delete_data(): f->size = %d\n", f->size)); + return 0; } /* jffs_delete_data() */ /* Insert some data into a file. Prior to the call to this function, - jffs_delete_data() should be called. */ -static void + jffs_delete_data should be called. */ +static int jffs_insert_data(struct jffs_file *f, struct jffs_node *node) { D3(printk("jffs_insert_data(): node->data_offset = %u, " @@ -1733,7 +1858,7 @@ jffs_insert_data(struct jffs_file *f, struct jffs_node *node) node->data_offset, node->data_size, f->size)); /* Find the position where we should insert data. */ - + retry: if (node->data_offset == f->size) { /* A simple append. This is the most common operation. */ node->range_next = 0; @@ -1775,7 +1900,7 @@ jffs_insert_data(struct jffs_file *f, struct jffs_node *node) printk(KERN_ERR "jffs_insert_data(): " "Couldn't find a place to insert " "the data!\n"); - return; + return -1; }); } @@ -1788,38 +1913,84 @@ jffs_insert_data(struct jffs_file *f, struct jffs_node *node) f->size += node->data_size; } else if (node->data_offset > f->size) { - /* Not implemented yet. */ -#if 0 - /* Below is some example code for future use if we decide - to implement it. */ - /* This is code that isn't supported by VFS. So there aren't - really any reasons to implement it yet. */ - if (!f->range_head) { - if (node->data_offset > f->size) { - if (!(nn = jffs_alloc_node())) { - D(printk("jffs_insert_data(): " - "Allocation failed.\n")); - return; + /* Okay. This is tricky. This means that we want to insert + data at a place that is beyond the limits of the file as + it is constructed right now. This is actually a common + event that for instance could occur during the mounting + of the file system if a large file have been truncated, + rewritten and then only partially garbage collected. */ + + struct jffs_node *n; + + /* We need a place holder for the data that is missing in + front of this insertion. This "virtual node" will not + be associated with any space on the flash device. */ + struct jffs_node *virtual_node; + if (!(virtual_node = (struct jffs_node *) + kmalloc(sizeof(struct jffs_node), + GFP_KERNEL))) { + return -ENOMEM; + } + + D(printk("jffs_insert_data: Inserting a virtual node.\n")); + D(printk(" node->data_offset = %u\n", node->data_offset)); + D(printk(" f->size = %u\n", f->size)); + + virtual_node->ino = node->ino; + virtual_node->version = node->version; + virtual_node->removed_size = 0; + virtual_node->fm_offset = 0; + virtual_node->name_size = 0; + virtual_node->fm = 0; /* This is a virtual data holder. */ + virtual_node->version_prev = 0; + virtual_node->version_next = 0; + virtual_node->range_next = 0; + + /* Are there any data at all in the file yet? */ + if (f->range_head) { + virtual_node->data_offset + = f->range_tail->data_offset + + f->range_tail->data_size; + virtual_node->data_size + = node->data_offset - virtual_node->data_offset; + virtual_node->range_prev = f->range_tail; + f->range_tail->range_next = virtual_node; + } + else { + virtual_node->data_offset = 0; + virtual_node->data_size = node->data_offset; + virtual_node->range_prev = 0; + f->range_head = virtual_node; + } + + f->range_tail = virtual_node; + f->size += virtual_node->data_size; + + /* Insert this virtual node in the version list as well. */ + for (n = f->version_head; n ; n = n->version_next) { + if (n->version == virtual_node->version) { + virtual_node->version_prev = n->version_prev; + n->version_prev = virtual_node; + if (virtual_node->version_prev) { + virtual_node->version_prev + ->version_next = virtual_node; + } + else { + f->version_head = virtual_node; } - nn->version = JFFS_MAGIC_BITMASK; - nn->data_offset = 0; - nn->data_size = node->data_offset; - nn->removed_size = 0; - nn->fm_offset = 0; - nn->name_size = 0; - nn->fm = 0; /* This is a virtual data holder. */ - nn->version_prev = 0; - nn->version_next = 0; - nn->range_prev = 0; - nn->range_next = 0; - nh->range_head = nn; - nh->range_tail = nn; + virtual_node->version_next = n; + break; } } -#endif + + D(jffs_print_node(virtual_node)); + + /* Make a new try to insert the node. */ + goto retry; } D3(printk("jffs_insert_data(): f->size = %d\n", f->size)); + return 0; } @@ -1828,6 +1999,8 @@ jffs_insert_data(struct jffs_file *f, struct jffs_node *node) static int jffs_update_file(struct jffs_file *f, struct jffs_node *node) { + int err; + D3(printk("jffs_update_file(): ino: %u, version: %u\n", f->ino, node->version)); @@ -1841,15 +2014,21 @@ jffs_update_file(struct jffs_file *f, struct jffs_node *node) /* data_offset == X */ /* data_size == 0 */ /* remove_size != 0 */ - jffs_delete_data(f, node); + if ((err = jffs_delete_data(f, node)) < 0) { + return err; + } } } else { /* data_offset == X */ /* data_size != 0 */ /* remove_size == Y */ - jffs_delete_data(f, node); - jffs_insert_data(f, node); + if ((err = jffs_delete_data(f, node)) < 0) { + return err; + } + if ((err = jffs_insert_data(f, node)) < 0) { + return err; + } } return 0; } @@ -1868,7 +2047,7 @@ jffs_print_node(struct jffs_node *n) D(printk(" 0x%08x, /* fm_offset */\n", n->fm_offset)); D(printk(" 0x%02x, /* name_size */\n", n->name_size)); D(printk(" 0x%p, /* fm, fm->offset: %u */\n", - n->fm, n->fm->offset)); + n->fm, (n->fm ? n->fm->offset : 0))); D(printk(" 0x%p, /* version_prev */\n", n->version_prev)); D(printk(" 0x%p, /* version_next */\n", n->version_next)); D(printk(" 0x%p, /* range_prev */\n", n->range_prev)); @@ -1979,6 +2158,7 @@ jffs_print_tree(struct jffs_file *first_file, int indent) { struct jffs_file *f; char *space; + int dir; if (!first_file) { return; @@ -1993,10 +2173,11 @@ jffs_print_tree(struct jffs_file *first_file, int indent) space[indent] = '\0'; for (f = first_file; f; f = f->sibling_next) { - printk("%s%s (ino: %u, highest_version: %u, size: %u)\n", - space, (f->name ? f->name : "/"), + dir = S_ISDIR(f->mode); + printk("%s%s%s (ino: %u, highest_version: %u, size: %u)\n", + space, (f->name ? f->name : ""), (dir ? "/" : ""), f->ino, f->highest_version, f->size); - if (S_ISDIR(f->mode)) { + if (dir) { jffs_print_tree(f->children, indent + 2); } } @@ -2053,7 +2234,6 @@ jffs_rewrite_data(struct jffs_file *f, struct jffs_node *node, int size) } DJM(no_jffs_node++); new_node->data_offset = node->data_offset; - new_node->data_size = size; new_node->removed_size = size; total_name_size = f->nsize + JFFS_GET_PAD_BYTES(f->nsize); total_data_size = size + JFFS_GET_PAD_BYTES(size); @@ -2062,23 +2242,28 @@ jffs_rewrite_data(struct jffs_file *f, struct jffs_node *node, int size) new_node->fm_offset = sizeof(struct jffs_raw_inode) + total_name_size; + jffs_fm_write_lock(fmc); + if ((err = jffs_fmalloc(fmc, total_size, new_node, &fm)) < 0) { + DJM(no_jffs_node--); + jffs_fm_write_unlock(fmc); D(printk("jffs_rewrite_data(): Failed to allocate fm.\n")); kfree(new_node); - DJM(no_jffs_node--); return err; } else if (!fm->nodes) { /* The jffs_fm struct that we got is not good enough. */ if ((err = jffs_write_dummy_node(c, fm)) < 0) { + DJM(no_jffs_fm--); + jffs_fm_write_unlock(fmc); D(printk("jffs_rewrite_data(): " "jffs_write_dummy_node() Failed!\n")); kfree(fm); - DJM(no_jffs_fm--); return err; } /* Get a new one. */ if ((err = jffs_fmalloc(fmc, total_size, node, &fm)) < 0) { + jffs_fm_write_unlock(fmc); D(printk("jffs_rewrite_data(): Second " "jffs_fmalloc(0x%p, %u) failed!\n", fmc, total_size)); @@ -2127,10 +2312,11 @@ jffs_rewrite_data(struct jffs_file *f, struct jffs_node *node, int size) sizeof(struct jffs_raw_inode) - sizeof(__u32) - sizeof(__u16) - sizeof(__u16))) < 0) { - printk(KERN_ERR "JFFS: jffs_rewrite_data: Write error during " - "rewrite. (raw inode)\n"); jffs_fmfree_partly(fmc, fm, total_name_size + total_data_size); + jffs_fm_write_unlock(fmc); + printk(KERN_ERR "JFFS: jffs_rewrite_data: Write error during " + "rewrite. (raw inode)\n"); return err; } pos += sizeof(struct jffs_raw_inode); @@ -2142,9 +2328,10 @@ jffs_rewrite_data(struct jffs_file *f, struct jffs_node *node, int size) if ((err = flash_safe_write(fmc->mtd, pos, (u_char *)f->name, f->nsize)) < 0) { - printk(KERN_ERR "JFFS: jffs_rewrite_data: Write " - "error during rewrite. (name)\n"); jffs_fmfree_partly(fmc, fm, total_data_size); + jffs_fm_write_unlock(fmc); + printk(KERN_ERR "JFFS: jffs_rewrite_data: Write " + "error during rewrite. (name)\n"); return err; } pos += total_name_size; @@ -2166,19 +2353,22 @@ jffs_rewrite_data(struct jffs_file *f, struct jffs_node *node, int size) __u32 s = jffs_min(size, PAGE_SIZE); if ((r = jffs_read_data(f, (char *)page, offset, s)) < s) { - printk(KERN_ERR "JFFS: jffs_rewrite_data: " + free_page((unsigned long)page); + jffs_fmfree_partly(fmc, fm, 0); + jffs_fm_write_unlock(fmc); + printk(KERN_ERR "JFFS: jffs_rewrite_data: " "jffs_read_data() " "failed! (r = %d)\n", r); - jffs_fmfree_partly(fmc, fm, 0); return -1; } if ((err = flash_safe_write(fmc->mtd, pos, page, r)) < 0) { - printk(KERN_ERR "JFFS: jffs_rewrite_data: " - "Write error during rewrite. " - "(data)\n"); free_page((unsigned long)page); jffs_fmfree_partly(fmc, fm, 0); + jffs_fm_write_unlock(fmc); + printk(KERN_ERR "JFFS: jffs_rewrite_data: " + "Write error during rewrite. " + "(data)\n"); return err; } pos += r; @@ -2202,14 +2392,16 @@ jffs_rewrite_data(struct jffs_file *f, struct jffs_node *node, int size) &raw_inode)[JFFS_RAW_INODE_DCHKSUM_OFFSET], sizeof(__u32) + sizeof(__u16) + sizeof(__u16))) < 0) { - printk(KERN_ERR "JFFS: jffs_rewrite_data: Write error during " - "rewrite. (checksum)\n"); jffs_fmfree_partly(fmc, fm, 0); + jffs_fm_write_unlock(fmc); + printk(KERN_ERR "JFFS: jffs_rewrite_data: Write error during " + "rewrite. (checksum)\n"); return err; } /* Now make the file system aware of the newly written node. */ jffs_insert_node(c, f, &raw_inode, f->name, new_node); + jffs_fm_write_unlock(fmc); D3(printk("jffs_rewrite_data(): Leaving...\n")); return 0; @@ -2219,6 +2411,7 @@ jffs_rewrite_data(struct jffs_file *f, struct jffs_node *node, int size) /* jffs_garbage_collect_next implements one step in the garbage collect process and is often called multiple times at each occasion of a garbage collect. */ + int jffs_garbage_collect_next(struct jffs_control *c) { @@ -2226,8 +2419,8 @@ jffs_garbage_collect_next(struct jffs_control *c) struct jffs_node *node; struct jffs_file *f; int size; - int data_size; - int total_name_size; + int data_size; + int total_name_size; int free_size = fmc->flash_size - (fmc->used_size + fmc->dirty_size); __u32 free_chunk_size1 = jffs_free_size1(fmc); D2(__u32 free_chunk_size2 = jffs_free_size2(fmc)); @@ -2235,17 +2428,17 @@ jffs_garbage_collect_next(struct jffs_control *c) /* Get the oldest node in the flash. */ node = jffs_get_oldest_node(fmc); ASSERT(if (!node) { - printk(KERN_ERR "JFFS: jffs_garbage_collect_next: " - "No oldest node found!\n"); + printk(KERN_ERR "JFFS: jffs_garbage_collect_next: " + "No oldest node found!\n"); return -1; }); /* Find its corresponding file too. */ f = jffs_find_file(c, node->ino); ASSERT(if (!f) { - printk(KERN_ERR "JFFS: jffs_garbage_collect_next: " - "No file to garbage collect! " - "(ino = 0x%08x)\n", node->ino); + printk(KERN_ERR "JFFS: jffs_garbage_collect_next: " + "No file to garbage collect! " + "(ino = 0x%08x)\n", node->ino); return -1; }); @@ -2254,23 +2447,25 @@ jffs_garbage_collect_next(struct jffs_control *c) (f->name ? f->name : ""), node->ino, node->version)); /* Compute how much we want to rewrite at the moment. */ - data_size = f->size - node->data_offset; - total_name_size = f->nsize + JFFS_GET_PAD_BYTES(f->nsize); - size = sizeof(struct jffs_raw_inode) + total_name_size - + data_size + JFFS_GET_PAD_BYTES(data_size); + data_size = f->size - node->data_offset; + total_name_size = f->nsize + JFFS_GET_PAD_BYTES(f->nsize); + size = sizeof(struct jffs_raw_inode) + total_name_size + + data_size + JFFS_GET_PAD_BYTES(data_size); - D2(printk(" total_name_size: %u\n", total_name_size)); - D2(printk(" data_size: %u\n", data_size)); + D2(printk(" total_name_size: %u\n", total_name_size)); + D2(printk(" data_size: %u\n", data_size)); D2(printk(" size: %u\n", size)); D2(printk(" f->nsize: %u\n", f->nsize)); D2(printk(" f->size: %u\n", f->size)); + D2(printk(" node->data_offset: %u\n", node->data_offset)); D2(printk(" free_chunk_size1: %u\n", free_chunk_size1)); D2(printk(" free_chunk_size2: %u\n", free_chunk_size2)); + D2(printk(" node->fm->offset: 0x%08x\n", node->fm->offset)); if (size > fmc->max_chunk_size) { size = fmc->max_chunk_size; - data_size = size - sizeof(struct jffs_raw_inode) - - total_name_size; + data_size = size - sizeof(struct jffs_raw_inode) + - total_name_size; } if (size > free_chunk_size1) { @@ -2282,11 +2477,11 @@ jffs_garbage_collect_next(struct jffs_control *c) = jffs_fmalloced(fmc, fmc->tail->offset + fmc->tail->size, free_chunk_size1, NULL); - if (!dirty_fm) { - printk(KERN_ERR "JFFS: " - "jffs_garbage_collect_next: " - "Failed to allocate `dirty' " - "flash memory!\n"); + if (!dirty_fm) { + printk(KERN_ERR "JFFS: " + "jffs_garbage_collect_next: " + "Failed to allocate `dirty' " + "flash memory!\n"); return -1; } jffs_write_dummy_node(c, dirty_fm); @@ -2294,24 +2489,24 @@ jffs_garbage_collect_next(struct jffs_control *c) } size = free_chunk_size1; - data_size = size - sizeof(struct jffs_raw_inode) - - total_name_size; + data_size = size - sizeof(struct jffs_raw_inode) + - total_name_size; } D2(printk(" size: %u (again)\n", size)); if (free_size - size < fmc->sector_size) { /* Just rewrite that node (or even less). */ - jffs_rewrite_data(f, node, - jffs_min(node->data_size, data_size)); + jffs_rewrite_data(f, node, + jffs_min(node->data_size, data_size)); } else { size -= (sizeof(struct jffs_raw_inode) + f->nsize); - jffs_rewrite_data(f, node, data_size); + jffs_rewrite_data(f, node, data_size); } jffs_garbage_collect_next_end: - D3(printk("jffs_garbage_collect_next: Leaving...\n")); + D3(printk("jffs_garbage_collect_next: Leaving...\n")); return 0; } /* jffs_garbage_collect_next */ @@ -2319,7 +2514,9 @@ jffs_garbage_collect_next_end: /* If an obsolete node is partly going to be erased due to garbage collection, the part that isn't going to be erased must be filled with zeroes so that the scan of the flash will work smoothly next - time. + time. (The data in the file could for instance be a JFFS image + which could cause enormous confusion during a scan of the flash + device if we didn't do this.) There are two phases in this procedure: First, the clearing of the name and data parts of the node. Second, possibly also clearing a part of the raw inode as well. If the box is power cycled during @@ -2400,19 +2597,19 @@ jffs_try_to_erase(struct jffs_control *c) D2(printk("jffs_try_to_erase(): erase_size = %ld\n", erase_size)); - if (erase_size == 0) { - return 0; - } - else if (erase_size < 0) { - printk(KERN_ERR "JFFS: jffs_try_to_erase: " - "jffs_erasable_size returned %ld.\n", erase_size); + if (erase_size == 0) { + return 0; + } + else if (erase_size < 0) { + printk(KERN_ERR "JFFS: jffs_try_to_erase: " + "jffs_erasable_size returned %ld.\n", erase_size); return erase_size; } - if ((err = jffs_clear_end_of_node(c, erase_size)) < 0) { - printk(KERN_ERR "JFFS: jffs_try_to_erase: " - "Clearing of node failed.\n"); - return err; + if ((err = jffs_clear_end_of_node(c, erase_size)) < 0) { + printk(KERN_ERR "JFFS: jffs_try_to_erase: " + "Clearing of node failed.\n"); + return err; } offset = fmc->head->offset - fmc->flash_start; @@ -2444,7 +2641,7 @@ jffs_try_to_erase(struct jffs_control *c) for (; pos < end; pos += 4) { if (*(__u32 *)pos != JFFS_EMPTY_BITMASK) { - printk("JFFS: Erase failed! pos = 0x%ld\n", + printk("JFFS: Erase failed! pos = 0x%lx\n", (long)pos); jffs_hexdump(fmc->mtd, pos, jffs_min(256, end - pos)); @@ -2475,7 +2672,7 @@ jffs_try_to_erase(struct jffs_control *c) /* There are different criteria that should trigger a garbage collect: - + 1. There is too much dirt in the memory. 2. The free space is becoming small. 3. There are many versions of a node. @@ -2485,27 +2682,26 @@ jffs_try_to_erase(struct jffs_control *c) should not be too large (span more than one sector in the flash memory for exemple). Of course there is a limit on how intelligent this garbage collection can be. */ + int -jffs_garbage_collect(struct jffs_control *c) +jffs_garbage_collect_now(struct jffs_control *c) { struct jffs_fmcontrol *fmc = c->fmc; long erased_total = 0; long erased; int result = 0; D1(int i = 1); - - D2(printk("***jffs_garbage_collect(): fmc->dirty_size = %u\n", + D2(printk("***jffs_garbage_collect_now(): fmc->dirty_size = %u\n", fmc->dirty_size)); D2(jffs_print_fmcontrol(fmc)); - c->fmc->no_call_gc = 1; + down(&fmc->gclock); - /* While there is too much dirt left and it is possible - to garbage collect, do so. */ + /* If it is possible to garbage collect, do so. */ - while (fmc->dirty_size >= fmc->sector_size) { + if (fmc->dirty_size >= fmc->sector_size) { - D1(printk("***jffs_garbage_collect(): round #%u, " + D1(printk("***jffs_garbage_collect_now(): round #%u, " "fmc->dirty_size = %u\n", i++, fmc->dirty_size)); D2(jffs_print_fmcontrol(fmc)); @@ -2533,7 +2729,7 @@ jffs_garbage_collect(struct jffs_control *c) } else { /* What should we do here? */ - D(printk(" jffs_garbage_collect(): " + D(printk(" jffs_garbage_collect_now(): " "erased: %ld, free_size: %u\n", erased, free_size)); result = -1; @@ -2541,19 +2737,204 @@ jffs_garbage_collect(struct jffs_control *c) } } - D1(printk(" jffs_garbage_collect(): erased: %ld\n", erased)); + D1(printk(" jffs_garbage_collect_now(): erased: %ld\n", erased)); erased_total += erased; DJM(jffs_print_memory_allocation_statistics()); } - gc_end: - c->fmc->no_call_gc = 0; + up(&fmc->gclock); - D3(printk(" jffs_garbage_collect(): Leaving...\n")); + D3(printk(" jffs_garbage_collect_now(): Leaving...\n")); D1(if (erased_total) { printk("erased_total = %ld\n", erased_total); jffs_print_fmcontrol(fmc); }); + + if (!erased_total && !result) + return -ENOSPC; + return result; +} /* jffs_garbage_collect_now() */ + + +/* Determine if it is reasonable to start garbage collection. + We start a gc pass if either: + - The number of free bytes < MIN_FREE_BYTES && at least one + block is dirty, OR + - The number of dirty bytes > MAX_DIRTY_BYTES +*/ +static inline int thread_should_wake (struct jffs_control *c) +{ + __u32 nfree = c->fmc->flash_size - c->fmc->used_size - c->fmc->dirty_size; + + D1(printk (KERN_NOTICE "thread_should_wake(): free=%d, dirty=%d, blocksize=%d.\n", + nfree, c->fmc->dirty_size, c->fmc->sector_size)); + + /* If there's not enough dirty space to free a block, there's no point. */ + if (c->fmc->dirty_size < c->fmc->sector_size) + return 0; + + /* If there are fewer free bytes than the threshold, GC */ + if (nfree < c->gc_minfree_threshold) + return 1; + + /* If there are more dirty bytes than the threshold, GC */ + if (c->fmc->dirty_size > c->gc_maxdirty_threshold) + return 1; + + /* FIXME: What about the "There are many versions of a node" condition? */ + + return 0; } + + +void jffs_garbage_collect_trigger(struct jffs_control *c) +{ + /* NOTE: We rely on the fact that we have the BKL here. + * Otherwise, the gc_task could go away between the check + * and the wake_up_process() + */ + if (c->gc_task && thread_should_wake(c)) + send_sig(SIGHUP, c->gc_task, 1); +} + + +/* Kernel threads take (void *) as arguments. Thus we pass + the jffs_control data as a (void *) and then cast it. */ +int +jffs_garbage_collect_thread(void *ptr) +{ + struct jffs_control *c = (struct jffs_control *) ptr; + struct jffs_fmcontrol *fmc = c->fmc; + long erased_total = 0; + long erased; + int result = 0; + D1(int i = 1); + + c->gc_task = current; + + lock_kernel(); + exit_mm(c->gc_task); + + current->session = 1; + current->pgrp = 1; + init_MUTEX_LOCKED(&c->gc_thread_sem); /* barrier */ + spin_lock_irq(¤t->sigmask_lock); + siginitsetinv (¤t->blocked, sigmask(SIGHUP) | sigmask(SIGQUIT) | sigmask(SIGSTOP) | sigmask(SIGCONT)); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + strcpy(current->comm, "jffs_gcd"); + + D1(printk (KERN_NOTICE "jffs_garbage_collect_thread(): Starting infinite loop.\n")); + + for (;;) { + /* See if we need to start gc. If we don't, go to sleep. + + Current implementation is a BAD THING(tm). If we try + to unmount the FS, the unmount operation will sleep waiting + for this thread to exit. We need to arrange to send it a + sig before the umount process sleeps. + */ + + if (!thread_should_wake(c)) + set_current_state (TASK_INTERRUPTIBLE); + + schedule(); /* Yes, we do this even if we want to go + on immediately - we're a low priority + background task. */ + + /* Put_super will send a SIGQUIT and then wait on the sem. + */ + while (signal_pending(current)) { + siginfo_t info; + unsigned long signr; + + spin_lock_irq(¤t->sigmask_lock); + signr = dequeue_signal(¤t->blocked, &info); + spin_unlock_irq(¤t->sigmask_lock); + + switch(signr) { + case SIGSTOP: + D1(printk("jffs_garbage_collect_thread(): SIGSTOP received.\n")); + set_current_state(TASK_STOPPED); + schedule(); + break; + + case SIGQUIT: + D1(printk("jffs_garbage_collect_thread(): SIGQUIT received.\n")); + c->gc_task = NULL; + up(&c->gc_thread_sem); + unlock_kernel(); + return(0); + } + } + + + D1(printk (KERN_NOTICE "jffs_garbage_collect_thread(): collecting.\n")); +// printk (KERN_NOTICE "free=%d, dirty=%d, blocksize=%ld.\n", count_free_bytes(c), count_dirty_bytes(c), c->sb->s_blocksize); + + D2(printk("***jffs_garbage_collect_thread(): fmc->dirty_size = %u\n", + fmc->dirty_size)); + D2(jffs_print_fmcontrol(fmc)); + + if (fmc->dirty_size < fmc->sector_size) { + printk(KERN_WARNING "jffs_garbage_collect_thread with insufficient dirty space (0x%x)\n", fmc->dirty_size); + continue; + } + + down(&c->fmc->gclock); + + D1(printk("***jffs_garbage_collect_thread(): round #%u, " + "fmc->dirty_size = %u\n", i++, fmc->dirty_size)); + D2(jffs_print_fmcontrol(fmc)); + + /* At least one sector should be able to free now. */ + if ((erased = jffs_try_to_erase(c)) < 0) { + printk(KERN_WARNING "JFFS: Error in " + "garbage collector.\n"); + result = erased; + goto gc_end; + } + else if (erased == 0) { + __u32 free_size = fmc->flash_size + - (fmc->used_size + + fmc->dirty_size); + + if (free_size > 0) { + /* Let's dare to make a garbage collect. */ + if ((result = jffs_garbage_collect_next(c)) + < 0) { + printk(KERN_ERR "JFFS: Something " + "has gone seriously wrong " + "with a garbage collect.\n"); + goto gc_end; + } + } + else { + /* What should we do here? */ + D(printk(" jffs_garbage_collect(): " + "erased: %ld, free_size: %u\n", + erased, free_size)); + result = -1; + goto gc_end; + } + } + + D1(printk(" jffs_garbage_collect(): erased: %ld\n", erased)); + erased_total += erased; + DJM(jffs_print_memory_allocation_statistics()); + + + gc_end: + up(&c->fmc->gclock); + + D3(printk(" jffs_garbage_collect(): Leaving...\n")); + D1(if (erased_total) { + printk("erased_total = %ld\n", erased_total); + jffs_print_fmcontrol(fmc); + }); + + } /* for (;;) */ +} /* jffs_garbage_collect_thread() */ + diff --git a/fs/jffs/intrep.h b/fs/jffs/intrep.h index 3336c69e649e..d4638af201f5 100644 --- a/fs/jffs/intrep.h +++ b/fs/jffs/intrep.h @@ -10,13 +10,13 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * $Id: intrep.h,v 1.2 2000/05/24 13:13:56 alex Exp $ + * $Id: intrep.h,v 1.6 2000/08/04 14:29:17 dwmw2 Exp $ * */ #ifndef __LINUX_JFFS_INTREP_H__ #define __LINUX_JFFS_INTREP_H__ - +#include "jffs_fm.h" inline int jffs_min(int a, int b); inline int jffs_max(int a, int b); __u32 jffs_checksum(const void *data, int size); @@ -34,6 +34,7 @@ void jffs_free_node(struct jffs_node *node); int jffs_foreach_file(struct jffs_control *c, int (*func)(struct jffs_file *)); int jffs_free_node_list(struct jffs_file *f); +int jffs_free_file(struct jffs_file *f); int jffs_possibly_delete_file(struct jffs_file *f); int jffs_build_file(struct jffs_file *f); int jffs_insert_file_into_hash(struct jffs_file *f); @@ -49,7 +50,26 @@ int jffs_write_node(struct jffs_control *c, struct jffs_node *node, int jffs_read_data(struct jffs_file *f, char *buf, __u32 read_offset, __u32 size); /* Garbage collection stuff. */ -int jffs_garbage_collect(struct jffs_control *c); +int jffs_garbage_collect_thread(void *c); +void jffs_garbage_collect_trigger(struct jffs_control *c); +int jffs_garbage_collect_now(struct jffs_control *c); + +/* Is there enough space on the flash? */ +static inline int JFFS_ENOUGH_SPACE(struct jffs_control *c) +{ + struct jffs_fmcontrol *fmc = c->fmc; + + while (1) { + if ((fmc->flash_size - (fmc->used_size + fmc->dirty_size)) + >= fmc->min_free_size) { + return 1; + } + if (fmc->dirty_size < fmc->sector_size) + return 0; + + jffs_garbage_collect_now(c); + } +} /* For debugging purposes. */ void jffs_print_node(struct jffs_node *n); diff --git a/fs/jffs/jffs_fm.c b/fs/jffs/jffs_fm.c index abdb759a5096..3140b8a53bc0 100644 --- a/fs/jffs/jffs_fm.c +++ b/fs/jffs/jffs_fm.c @@ -10,29 +10,18 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * $Id: jffs_fm.c,v 1.8 2000/07/13 13:15:33 scote1 Exp $ + * $Id: jffs_fm.c,v 1.14 2000/08/09 14:26:35 dwmw2 Exp $ * * Ported to Linux 2.3.x and MTD: * Copyright (C) 2000 Alexander Larsson (alex@cendio.se), Cendio Systems AB * */ #define __NO_VERSION__ -#include #include #include #include #include "jffs_fm.h" -#if defined(CONFIG_JFFS_FS_VERBOSE) && CONFIG_JFFS_FS_VERBOSE -#define D(x) x -#else -#define D(x) -#endif -#define D1(x) D(x) -#define D2(x) -#define D3(x) -#define ASSERT(x) x - #if defined(JFFS_MARK_OBSOLETE) && JFFS_MARK_OBSOLETE static int jffs_mark_obsolete(struct jffs_fmcontrol *fmc, __u32 fm_offset); #endif @@ -72,12 +61,13 @@ jffs_build_begin(struct jffs_control *c, kdev_t dev) fmc->max_chunk_size = fmc->sector_size >> 1; fmc->min_free_size = (fmc->sector_size << 1) - fmc->max_chunk_size; fmc->mtd = mtd; - fmc->no_call_gc = 0; + init_MUTEX(&fmc->gclock); fmc->c = c; fmc->head = 0; fmc->tail = 0; fmc->head_extra = 0; fmc->tail_extra = 0; + init_MUTEX(&fmc->wlock); return fmc; } @@ -425,18 +415,18 @@ int jffs_add_node(struct jffs_node *node) { struct jffs_node_ref *ref; - struct jffs_fm *fm = node->fm; - int s = sizeof(struct jffs_node_ref); D3(printk("jffs_add_node(): ino = %u\n", node->ino)); - if (!(ref = (struct jffs_node_ref *)kmalloc(s, GFP_KERNEL))) { + ref = (struct jffs_node_ref *)kmalloc(sizeof(struct jffs_node_ref), + GFP_KERNEL); + if (!ref) return -ENOMEM; - } + DJM(no_jffs_node_ref++); ref->node = node; - ref->next = fm->nodes; - fm->nodes = ref; + ref->next = node->fm->nodes; + node->fm->nodes = ref; return 0; } @@ -614,16 +604,16 @@ jffs_flash_erasable_size(struct mtd_info *mtd, __u32 offset, __u32 size) ssize = mtd->erasesize; if (offset % ssize) { - printk(KERN_WARNING "jffs_flash_erasable_size() given non-aligned offset %lx (erasesize %lx)\n", offset, ssize); + printk(KERN_WARNING "jffs_flash_erasable_size() given non-aligned offset %x (erasesize %lx)\n", offset, ssize); /* The offset is not sector size aligned. */ return -1; } else if (offset > mtd->size) { - printk(KERN_WARNING "jffs_flash_erasable_size given offset off the end of device (%lx > %lx)\n", offset, mtd->size); + printk(KERN_WARNING "jffs_flash_erasable_size given offset off the end of device (%x > %lx)\n", offset, mtd->size); return -2; } else if (offset + size > mtd->size) { - printk(KERN_WARNING "jffs_flash_erasable_size() given length which runs off the end of device (ofs %lx + len %lx = %lx, > %lx)\n", offset,size, offset+size, mtd->size); + printk(KERN_WARNING "jffs_flash_erasable_size() given length which runs off the end of device (ofs %x + len %x = %x, > %lx)\n", offset,size, offset+size, mtd->size); return -3; } diff --git a/fs/jffs/jffs_fm.h b/fs/jffs/jffs_fm.h index 1461d788a783..82077d9d1ca6 100644 --- a/fs/jffs/jffs_fm.h +++ b/fs/jffs/jffs_fm.h @@ -10,7 +10,7 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * $Id: jffs_fm.h,v 1.3 2000/07/04 16:15:42 dwmw2 Exp $ + * $Id: jffs_fm.h,v 1.7 2000/08/08 09:10:39 dwmw2 Exp $ * * Ported to Linux 2.3.x and MTD: * Copyright (C) 2000 Alexander Larsson (alex@cendio.se), Cendio Systems AB @@ -23,6 +23,7 @@ #include #include #include +#include /* The alignment between two nodes in the flash memory. */ #define JFFS_ALIGN_SIZE 4 @@ -30,7 +31,31 @@ /* Mark the on-flash space as obsolete when appropriate. */ #define JFFS_MARK_OBSOLETE 0 -#define CONFIG_JFFS_FS_VERBOSE 0 +#ifndef CONFIG_JFFS_FS_VERBOSE +#define CONFIG_JFFS_FS_VERBOSE 1 +#endif + +#if CONFIG_JFFS_FS_VERBOSE > 0 +#define D(x) x +#define D1(x) D(x) +#else +#define D(x) +#define D1(x) +#endif + +#if CONFIG_JFFS_FS_VERBOSE > 1 +#define D2(x) D(x) +#else +#define D2(x) +#endif + +#if CONFIG_JFFS_FS_VERBOSE > 2 +#define D3(x) D(x) +#else +#define D3(x) +#endif + +#define ASSERT(x) x /* How many padding bytes should be inserted between two chunks of data on the flash? */ @@ -38,11 +63,6 @@ - ((__u32)(size) % JFFS_ALIGN_SIZE)) \ % JFFS_ALIGN_SIZE) -/* Is there enough space on the flash? */ -#define JFFS_ENOUGH_SPACE(fmc) (((fmc)->flash_size - (fmc)->used_size \ - - (fmc)->dirty_size) >= (fmc)->min_free_size) - - struct jffs_node_ref { struct jffs_node *node; @@ -71,12 +91,13 @@ struct jffs_fmcontrol to perform garbage collections. */ __u32 max_chunk_size; /* The maximum size of a chunk of data. */ struct mtd_info *mtd; - __u32 no_call_gc; + struct semaphore gclock; struct jffs_control *c; struct jffs_fm *head; struct jffs_fm *tail; struct jffs_fm *head_extra; struct jffs_fm *tail_extra; + struct semaphore wlock; }; /* Notice the two members head_extra and tail_extra in the jffs_control diff --git a/fs/partitions/acorn.c b/fs/partitions/acorn.c index 0e1ba2d77df4..fc13e8698b77 100644 --- a/fs/partitions/acorn.c +++ b/fs/partitions/acorn.c @@ -1,11 +1,10 @@ /* * linux/arch/arm/drivers/block/adfspart.c * - * Copyright (c) 1996,1997 Russell King. + * Copyright (c) 1996-2000 Russell King. * * Scan ADFS partitions on hard disk drives. */ - #include #include #include @@ -30,17 +29,9 @@ adfspart_setgeometry(kdev_t dev, unsigned int secspertrack, unsigned int heads, #endif } -#define LINUX_NATIVE_MAGIC 0xdeafa1de -#define LINUX_SWAP_MAGIC 0xdeafab1e - -struct linux_part { - unsigned long magic; - unsigned long start_sect; - unsigned long nr_sects; -}; - -static struct adfs_discrecord *adfs_partition(struct gendisk *hd, char *name, char *data, - unsigned long first_sector, unsigned int minor) +static struct adfs_discrecord * +adfs_partition(struct gendisk *hd, char *name, char *data, + unsigned long first_sector, int minor) { struct adfs_discrecord *dr; unsigned int nr_sects; @@ -63,8 +54,9 @@ static struct adfs_discrecord *adfs_partition(struct gendisk *hd, char *name, ch } #ifdef CONFIG_ACORN_PARTITION_RISCIX -static int riscix_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sect, - unsigned int minor, unsigned long nr_sects) +static int +riscix_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sect, + int minor, unsigned long nr_sects) { struct buffer_head *bh; struct riscix_record *rr; @@ -76,7 +68,8 @@ static int riscix_partition(struct gendisk *hd, kdev_t dev, unsigned long first_ printk(" [RISCiX]"); add_gd_partition(hd, riscix_minor = minor++, first_sect, nr_sects); - hd->sizes[riscix_minor] = hd->part[riscix_minor].nr_sects >> (BLOCK_SIZE_BITS - 9); + hd->sizes[riscix_minor] = hd->part[riscix_minor].nr_sects >> + (BLOCK_SIZE_BITS - 9); dev = MKDEV(hd->major, riscix_minor); if (!(bh = bread(dev, 0, 1024))) @@ -109,8 +102,9 @@ static int riscix_partition(struct gendisk *hd, kdev_t dev, unsigned long first_ } #endif -static int linux_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sect, - unsigned int minor, unsigned long nr_sects) +static int +linux_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sect, + int minor, unsigned long nr_sects) { struct buffer_head *bh; struct linux_part *linuxp; @@ -122,7 +116,8 @@ static int linux_partition(struct gendisk *hd, kdev_t dev, unsigned long first_s printk(" [Linux]"); add_gd_partition(hd, linux_minor = minor++, first_sect, nr_sects); - hd->sizes[linux_minor] = hd->part[linux_minor].nr_sects >> (BLOCK_SIZE_BITS - 9); + hd->sizes[linux_minor] = hd->part[linux_minor].nr_sects >> + (BLOCK_SIZE_BITS - 9); dev = MKDEV(hd->major, linux_minor); if (!(bh = bread(dev, 0, 1024))) @@ -151,8 +146,9 @@ static int linux_partition(struct gendisk *hd, kdev_t dev, unsigned long first_s } #ifdef CONFIG_ACORN_PARTITION_CUMANA -static int adfspart_check_CUMANA(struct gendisk *hd, kdev_t dev, unsigned long first_sector, - unsigned int minor) +static int +adfspart_check_CUMANA(struct gendisk *hd, kdev_t dev, + unsigned long first_sector, int minor) { unsigned int start_blk = 0, mask = (1 << hd->minor_shift) - 1; struct buffer_head *bh = NULL; @@ -163,16 +159,17 @@ static int adfspart_check_CUMANA(struct gendisk *hd, kdev_t dev, unsigned long f return 0; /* - * Try Cumana style partitions - sector 3 contains ADFS boot block with pointer - * to next 'drive'. + * Try Cumana style partitions - sector 3 contains ADFS boot block + * with pointer to next 'drive'. * - * There are unknowns in this code - is the 'cylinder number' of the next - * partition relative to the start of this one - I'm assuming it is. + * There are unknowns in this code - is the 'cylinder number' of the + * next partition relative to the start of this one - I'm assuming + * it is. * * Also, which ID did Cumana use? * - * This is totally unfinished, and will require more work to get it going. - * Hence it is totally untested. + * This is totally unfinished, and will require more work to get it + * going. Hence it is totally untested. */ do { struct adfs_discrecord *dr; @@ -184,7 +181,8 @@ static int adfspart_check_CUMANA(struct gendisk *hd, kdev_t dev, unsigned long f if (!(bh = bread(dev, start_blk + 3, 1024))) return -1; - dr = adfs_partition(hd, name, bh->b_data, first_sector, minor++); + dr = adfs_partition(hd, name, bh->b_data, + first_sector, minor++); if (!dr) break; name = NULL; @@ -206,13 +204,16 @@ static int adfspart_check_CUMANA(struct gendisk *hd, kdev_t dev, unsigned long f break; #ifdef CONFIG_ACORN_PARTITION_RISCIX - case PARTITION_RISCIX_SCSI: /* RiscIX - we don't know how to find the next one. */ - minor = riscix_partition(hd, dev, first_sector, minor, nr_sects); + case PARTITION_RISCIX_SCSI: + /* RISCiX - we don't know how to find the next one. */ + minor = riscix_partition(hd, dev, first_sector, + minor, nr_sects); break; #endif case PARTITION_LINUX: - minor = linux_partition(hd, dev, first_sector, minor, nr_sects); + minor = linux_partition(hd, dev, first_sector, + minor, nr_sects); break; } brelse(bh); @@ -221,7 +222,7 @@ static int adfspart_check_CUMANA(struct gendisk *hd, kdev_t dev, unsigned long f return minor; } while (1); if (bh) - brelse(bh); + bforget(bh); return first ? 0 : 1; } #endif @@ -241,8 +242,9 @@ static int adfspart_check_CUMANA(struct gendisk *hd, kdev_t dev, unsigned long f * hda1 = ADFS partition on first drive. * hda2 = non-ADFS partition. */ -static int adfspart_check_ADFS(struct gendisk *hd, kdev_t dev, unsigned long first_sector, - unsigned int minor) +static int +adfspart_check_ADFS(struct gendisk *hd, kdev_t dev, + unsigned long first_sector, int minor) { unsigned long start_sect, nr_sects, sectscyl, heads; struct buffer_head *bh; @@ -256,12 +258,13 @@ static int adfspart_check_ADFS(struct gendisk *hd, kdev_t dev, unsigned long fir dr = adfs_partition(hd, "ADFS", bh->b_data, first_sector, minor++); if (!dr) { - brelse(bh); + bforget(bh); return 0; } heads = dr->heads + ((dr->lowsector >> 6) & 1); - adfspart_setgeometry(dev, dr->secspertrack, heads, hd->part[MINOR(dev)].nr_sects); + adfspart_setgeometry(dev, dr->secspertrack, heads, + hd->part[MINOR(dev)].nr_sects); sectscyl = dr->secspertrack * heads; /* @@ -272,21 +275,19 @@ static int adfspart_check_ADFS(struct gendisk *hd, kdev_t dev, unsigned long fir if (start_sect) { first_sector += start_sect; - /* - * we now have a problem - how to set the origional disk size if the - * disk doesn't report it, since there is no standard way of getting - * that info. - */ + switch (bh->b_data[0x1fc] & 15) { #ifdef CONFIG_ACORN_PARTITION_RISCIX case PARTITION_RISCIX_SCSI: case PARTITION_RISCIX_MFM: - minor = riscix_partition(hd, dev, first_sector, minor, nr_sects); + minor = riscix_partition(hd, dev, first_sector, + minor, nr_sects); break; #endif case PARTITION_LINUX: - minor = linux_partition(hd, dev, first_sector, minor, nr_sects); + minor = linux_partition(hd, dev, first_sector, + minor, nr_sects); break; } } @@ -326,13 +327,14 @@ static int adfspart_check_ICSLinux(kdev_t dev, unsigned long block) * hda2 = ADFS partition 1 on first drive. * ..etc.. */ -static int adfspart_check_ICS(struct gendisk *hd, kdev_t dev, unsigned long first_sector, - unsigned int minor) +static int +adfspart_check_ICS(struct gendisk *hd, kdev_t dev, + unsigned long first_sector, int minor) { struct buffer_head *bh; unsigned long sum; unsigned int i, mask = (1 << hd->minor_shift) - 1; - struct ics_part { unsigned long start; signed long size; } *p; + struct ics_part *p; if(get_ptable_blocksize(dev)!=1024) return 0; @@ -349,9 +351,9 @@ static int adfspart_check_ICS(struct gendisk *hd, kdev_t dev, unsigned long firs for (i = 0, sum = 0x50617274; i < 508; i++) sum += bh->b_data[i]; - sum -= le32_to_cpu(*(unsigned long *)(&bh->b_data[508])); + sum -= le32_to_cpu(*(__u32 *)(&bh->b_data[508])); if (sum) { - brelse(bh); + bforget(bh); return 0; /* not ICS partition table */ } @@ -392,15 +394,6 @@ static int adfspart_check_ICS(struct gendisk *hd, kdev_t dev, unsigned long firs #endif #ifdef CONFIG_ACORN_PARTITION_POWERTEC -struct ptec_partition { - u32 unused1; - u32 unused2; - u32 start; - u32 size; - u32 unused5; - char type[8]; -}; - /* * Purpose: allocate ICS partitions. * Params : hd - pointer to gendisk structure to store partition info. @@ -413,8 +406,9 @@ struct ptec_partition { * hda2 = ADFS partition 1 on first drive. * ..etc.. */ -static int adfspart_check_POWERTEC(struct gendisk *hd, kdev_t dev, unsigned long first_sector, - unsigned int minor) +static int +adfspart_check_POWERTEC(struct gendisk *hd, kdev_t dev, + unsigned long first_sector, int minor) { struct buffer_head *bh; struct ptec_partition *p; @@ -428,7 +422,7 @@ static int adfspart_check_POWERTEC(struct gendisk *hd, kdev_t dev, unsigned long checksum += bh->b_data[i]; if (checksum != bh->b_data[511]) { - brelse(bh); + bforget(bh); return 0; } @@ -452,44 +446,44 @@ static int adfspart_check_POWERTEC(struct gendisk *hd, kdev_t dev, unsigned long } #endif +static int (*partfn[])(struct gendisk *, kdev_t, unsigned long, int) = { +#ifdef CONFIG_ACORN_PARTITION_ICS + adfspart_check_ICS, +#endif +#ifdef CONFIG_ACORN_PARTITION_CUMANA + adfspart_check_CUMANA, +#endif +#ifdef CONFIG_ACORN_PARTITION_ADFS + adfspart_check_ADFS, +#endif +#ifdef CONFIG_ACORN_PARTITION_POWERTEC + adfspart_check_POWERTEC, +#endif + NULL +}; /* * Purpose: initialise all the partitions on an ADFS drive. - * These may be other ADFS partitions or a Linux/RiscBSD/RiscIX + * These may be other ADFS partitions or a Linux/RiscBSD/RISCiX * partition. * - * Params : hd - pointer to gendisk structure to store devices partitions. - * dev - device number to access - * first_sector - first available sector on the disk. - * minor - first available minor on this device. + * Params : hd - pointer to gendisk structure + * dev - device number to access + * first_sect - first available sector on the disk. + * first_minor - first available minor on this device. * * Returns: -1 on error, 0 if not ADFS format, 1 if ok. */ int acorn_partition(struct gendisk *hd, kdev_t dev, - unsigned long first_sector, int first_part_minor) + unsigned long first_sect, int first_minor) { - int r = 0; + int r = 0, i; -#ifdef CONFIG_ACORN_PARTITION_ICS - if (r == 0) - r = adfspart_check_ICS(hd, dev, first_sector, first_part_minor); -#endif -#ifdef CONFIG_ACORN_PARTITION_CUMANA - if (r == 0) - r = adfspart_check_CUMANA(hd, dev, first_sector, first_part_minor); -#endif -#ifdef CONFIG_ACORN_PARTITION_ADFS - if (r == 0) - r = adfspart_check_ADFS(hd, dev, first_sector, first_part_minor); -#endif -#ifdef CONFIG_ACORN_PARTITION_POWERTEC - if (r == 0) - r = adfspart_check_POWERTEC(hd, dev, first_sector, first_part_minor); -#endif - if (r < 0) { - if (warn_no_part) - printk(" unable to read boot sectors / partition sectors\n"); - } else if (r) { + for (i = 0; partfn[i] && r == 0; i++) + r = partfn[i](hd, dev, first_sect, first_minor); + + if (r < 0 && warn_no_part) + printk(" unable to read boot sectors / partition sectors\n"); + if (r > 0) printk("\n"); - } return r; } diff --git a/fs/partitions/acorn.h b/fs/partitions/acorn.h index 748c7c83f78c..e1d0a3830e8b 100644 --- a/fs/partitions/acorn.h +++ b/fs/partitions/acorn.h @@ -13,20 +13,43 @@ #define PARTITION_LINUX 9 struct riscix_part { - unsigned long start; - unsigned long length; - unsigned long one; + __u32 start; + __u32 length; + __u32 one; char name[16]; }; struct riscix_record { - unsigned long magic; + __u32 magic; #define RISCIX_MAGIC (0x4a657320) - unsigned long date; + __u32 date; struct riscix_part part[8]; }; -int -acorn_partition(struct gendisk *hd, kdev_t dev, - unsigned long first_sector, int first_part_minor); +#define LINUX_NATIVE_MAGIC 0xdeafa1de +#define LINUX_SWAP_MAGIC 0xdeafab1e + +struct linux_part { + __u32 magic; + __u32 start_sect; + __u32 nr_sects; +}; + +struct ics_part { + __u32 start; + __s32 size; +}; + +struct ptec_partition { + __u32 unused1; + __u32 unused2; + __u32 start; + __u32 size; + __u32 unused5; + char type[8]; +}; + + +int acorn_partition(struct gendisk *hd, kdev_t dev, + unsigned long first_sect, int first_minor); diff --git a/include/asm-alpha/page.h b/include/asm-alpha/page.h index 62a72144f3db..41afdcbd82a6 100644 --- a/include/asm-alpha/page.h +++ b/include/asm-alpha/page.h @@ -140,7 +140,8 @@ extern __inline__ int get_order(unsigned long size) #define __pa(x) ((unsigned long) (x) - PAGE_OFFSET) #define __va(x) ((void *)((unsigned long) (x) + PAGE_OFFSET)) -#define MAP_NR(addr) (__pa(addr) >> PAGE_SHIFT) +#define virt_to_page(kaddr) (mem_map + (__pa(kaddr) >> PAGE_SHIFT)) +#define VALID_PAGE(page) ((page - mem_map) < max_mapnr) #endif /* __KERNEL__ */ diff --git a/include/asm-arm/arch-sa1100/mmzone.h b/include/asm-arm/arch-sa1100/mmzone.h index b7abea6f778b..c721a1d55137 100644 --- a/include/asm-arm/arch-sa1100/mmzone.h +++ b/include/asm-arm/arch-sa1100/mmzone.h @@ -79,3 +79,5 @@ extern pg_data_t sa1100_node_data[]; (((unsigned long)ADDR_TO_MAPBASE((kaddr)) - PAGE_OFFSET) / \ sizeof(mem_map_t))) +#define virt_to_page(kaddr) (mem_map + MAP_NR(kaddr)) +#define VALID_PAGE(page) ((page - mem_map) < max_mapnr) diff --git a/include/asm-arm/page.h b/include/asm-arm/page.h index 10f470048b67..4f24702a21b0 100644 --- a/include/asm-arm/page.h +++ b/include/asm-arm/page.h @@ -92,6 +92,8 @@ extern __inline__ int get_order(unsigned long size) #ifndef CONFIG_DISCONTIGMEM #define MAP_NR(addr) ((__pa(addr) - PHYS_OFFSET) >> PAGE_SHIFT) +#define virt_to_page(kaddr) (mem_map + ((__pa(kaddr) - PHYS_OFFSET) >> PAGE_SHIFT)) +#define VALID_PAGE(page) ((page - mem_map) < max_mapnr) #endif #endif diff --git a/include/asm-i386/page.h b/include/asm-i386/page.h index 78d07c2073df..7a070fa530a1 100644 --- a/include/asm-i386/page.h +++ b/include/asm-i386/page.h @@ -116,8 +116,9 @@ extern __inline__ int get_order(unsigned long size) #define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET) #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) -#define MAP_NR(addr) (__pa(addr) >> PAGE_SHIFT) -#define PHYSMAP_NR(addr) ((unsigned long)(addr) >> PAGE_SHIFT) +#define virt_to_page(kaddr) (mem_map + (__pa(kaddr) >> PAGE_SHIFT)) +#define VALID_PAGE(page) ((page - mem_map) < max_mapnr) + #endif /* __KERNEL__ */ diff --git a/include/asm-ia64/page.h b/include/asm-ia64/page.h index 445e42376df1..f046dad8643b 100644 --- a/include/asm-ia64/page.h +++ b/include/asm-ia64/page.h @@ -82,7 +82,7 @@ typedef unsigned long pgprot_t; # endif /* !STRICT_MM_TYPECHECKS */ /* - * Note: the MAP_NR() macro can't use __pa() because MAP_NR(X) MUST + * Note: the MAP_NR_*() macro can't use __pa() because MAP_NR_*(X) MUST * map to something >= max_mapnr if X is outside the identity mapped * kernel space. */ @@ -100,12 +100,13 @@ typedef unsigned long pgprot_t; #define MAP_NR_SN1(addr) (((unsigned long) (addr) - PAGE_OFFSET) >> PAGE_SHIFT) #ifdef CONFIG_IA64_GENERIC -# define MAP_NR(addr) platform_map_nr(addr) +# define virt_to_page(kaddr) (mem_map + platform_map_nr(kaddr)) #elif defined (CONFIG_IA64_SN_SN1_SIM) -# define MAP_NR(addr) MAP_NR_SN1(addr) +# define virt_to_page(kaddr) (mem_map + MAP_NR_SN1(kaddr)) #else -# define MAP_NR(addr) MAP_NR_DENSE(addr) +# define virt_to_page(kaddr) (mem_map + MAP_NR_DENSE(kaddr)) #endif +#define VALID_PAGE(page) ((page - mem_map) < max_mapnr) # endif /* __KERNEL__ */ diff --git a/include/asm-m68k/page.h b/include/asm-m68k/page.h index 7cf002fb7528..80e5269a2448 100644 --- a/include/asm-m68k/page.h +++ b/include/asm-m68k/page.h @@ -160,6 +160,8 @@ static inline void *__va(unsigned long x) #endif /* CONFIG_SUN3 */ #define MAP_NR(addr) (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT) +#define virt_to_page(kaddr) (mem_map + (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT)) +#define VALID_PAGE(page) ((page - mem_map) < max_mapnr) #ifndef CONFIG_SUN3 #define BUG() do { \ diff --git a/include/asm-mips/page.h b/include/asm-mips/page.h index fd391fb85741..124a6d14240a 100644 --- a/include/asm-mips/page.h +++ b/include/asm-mips/page.h @@ -75,7 +75,8 @@ extern __inline__ int get_order(unsigned long size) #define PAGE_OFFSET 0x80000000UL #define __pa(x) ((unsigned long) (x) - PAGE_OFFSET) #define __va(x) ((void *)((unsigned long) (x) + PAGE_OFFSET)) -#define MAP_NR(addr) (__pa(addr) >> PAGE_SHIFT) +#define virt_to_page(kaddr) (mem_map + (__pa(kaddr) >> PAGE_SHIFT)) +#define VALID_PAGE(page) ((page - mem_map) < max_mapnr) #endif /* defined (__KERNEL__) */ diff --git a/include/asm-mips64/mmzone.h b/include/asm-mips64/mmzone.h index 2c6af1d755e4..7b06e7a91a57 100644 --- a/include/asm-mips64/mmzone.h +++ b/include/asm-mips64/mmzone.h @@ -73,7 +73,7 @@ extern plat_pg_data_t *plat_node_data[]; #define LOCAL_MAP_NR(kvaddr) \ (((unsigned long)(kvaddr)-LOCAL_BASE_ADDR((kvaddr))) >> PAGE_SHIFT) -#define MAP_NR(kaddr) (((unsigned long)(kaddr) > (unsigned long)high_memory)\ +#define MIPS64_NR(kaddr) (((unsigned long)(kaddr) > (unsigned long)high_memory)\ ? (max_mapnr + 1) : (LOCAL_MAP_NR((kaddr)) + \ (((unsigned long)ADDR_TO_MAPBASE((kaddr)) - PAGE_OFFSET) / \ sizeof(mem_map_t)))) @@ -82,6 +82,9 @@ extern plat_pg_data_t *plat_node_data[]; -1) ? 0 : (test_bit(LOCAL_MAP_NR((addr)), \ NODE_DATA(KVADDR_TO_NID((unsigned long)addr))->valid_addr_bitmap))) +#define virt_to_page(kaddr) (mem_map + MIPS64_NR(kaddr)) +#define VALID_PAGE(page) ((page - mem_map) < max_mapnr) + #endif /* CONFIG_DISCONTIGMEM */ #endif /* _ASM_MMZONE_H_ */ diff --git a/include/asm-mips64/page.h b/include/asm-mips64/page.h index 16c45aac546e..47f7d7906253 100644 --- a/include/asm-mips64/page.h +++ b/include/asm-mips64/page.h @@ -69,7 +69,8 @@ typedef struct { unsigned long pgprot; } pgprot_t; #define __pa(x) ((unsigned long) (x) - PAGE_OFFSET) #define __va(x) ((void *)((unsigned long) (x) + PAGE_OFFSET)) #ifndef CONFIG_DISCONTIGMEM -#define MAP_NR(addr) (__pa(addr) >> PAGE_SHIFT) +#define virt_to_page(kaddr) (mem_map + (__pa(kaddr) >> PAGE_SHIFT)) +#define VALID_PAGE(page) ((page - mem_map) < max_mapnr) #endif #endif /* defined (__KERNEL__) */ diff --git a/include/asm-ppc/page.h b/include/asm-ppc/page.h index a4f6b0a4bfb9..dee0ced3a066 100644 --- a/include/asm-ppc/page.h +++ b/include/asm-ppc/page.h @@ -114,8 +114,9 @@ static inline void* ___va(unsigned long p) #define __pa(x) ___pa ((unsigned long)(x)) #define __va(x) ___va ((unsigned long)(x)) -#define MAP_NR(addr) (((unsigned long)addr-PAGE_OFFSET) >> PAGE_SHIFT) #define MAP_PAGE_RESERVED (1<<15) +#define virt_to_page(kaddr) (mem_map + (((unsigned long)kaddr-PAGE_OFFSET) >> PAGE_SHIFT)) +#define VALID_PAGE(page) ((page - mem_map) < max_mapnr) extern unsigned long get_zero_page_fast(void); diff --git a/include/asm-s390/page.h b/include/asm-s390/page.h index 49be624a9fb0..e259b2bff093 100644 --- a/include/asm-s390/page.h +++ b/include/asm-s390/page.h @@ -112,8 +112,8 @@ typedef unsigned long pgprot_t; #define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET) #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) -#define MAP_NR(addr) (__pa(addr) >> PAGE_SHIFT) -#define PHYSMAP_NR(addr) ((unsigned long)(addr) >> PAGE_SHIFT) +#define virt_to_page(kaddr) (mem_map + (__pa(kaddr) >> PAGE_SHIFT)) +#define VALID_PAGE(page) ((page - mem_map) < max_mapnr) #endif /* __KERNEL__ */ diff --git a/include/asm-sh/bugs.h b/include/asm-sh/bugs.h index 99728234a1b4..ed5c57692e4d 100644 --- a/include/asm-sh/bugs.h +++ b/include/asm-sh/bugs.h @@ -17,22 +17,33 @@ static void __init check_bugs(void) { extern unsigned long loops_per_sec; + char *p= &system_utsname.machine[2]; /* "sh" */ cpu_data->loops_per_sec = loops_per_sec; switch (cpu_data->type) { case CPU_SH7708: - printk("CPU: SH7708/SH7709\n"); + *p++ = '3'; + printk("CPU: SH7707/SH7708/SH7709\n"); break; case CPU_SH7729: + *p++ = '3'; printk("CPU: SH7709A/SH7729\n"); break; case CPU_SH7750: + *p++ = '4'; printk("CPU: SH7750\n"); break; default: printk("CPU: ??????\n"); break; } + +#ifndef __LITTLE_ENDIAN__ + /* 'eb' means 'Endian Big' */ + *p++ = 'e'; + *p++ = 'b'; +#endif + *p = '\0'; } #endif /* __ASM_SH_BUGS_H */ diff --git a/include/asm-sh/delay.h b/include/asm-sh/delay.h index f8cb1d0bc527..7495d31c894c 100644 --- a/include/asm-sh/delay.h +++ b/include/asm-sh/delay.h @@ -33,7 +33,7 @@ extern __inline__ void __udelay(unsigned long usecs, unsigned long lps) #ifdef CONFIG_SMP #define __udelay_val cpu_data[smp_processor_id()].udelay_val #else -#define __udelay_val loops_per_sec +#define __udelay_val (current_cpu_data.loops_per_sec) #endif #define udelay(usecs) __udelay((usecs),__udelay_val) diff --git a/include/asm-sh/dma.h b/include/asm-sh/dma.h index b5a7f0bea73b..f20096234ce9 100644 --- a/include/asm-sh/dma.h +++ b/include/asm-sh/dma.h @@ -15,4 +15,11 @@ extern int request_dma(unsigned int dmanr, const char * device_id); /* reserve a DMA channel */ extern void free_dma(unsigned int dmanr); /* release it again */ +#ifdef CONFIG_PCI +extern int isa_dma_bridge_buggy; +#else +#define isa_dma_bridge_buggy (0) +#endif + + #endif /* __ASM_SH_DMA_H */ diff --git a/include/asm-sh/hd64461.h b/include/asm-sh/hd64461.h index 1f5851fccb4d..f4f49ff9cb93 100644 --- a/include/asm-sh/hd64461.h +++ b/include/asm-sh/hd64461.h @@ -7,31 +7,38 @@ */ #include -#define HD64461_CPTWAR 0x1030 -#define HD64461_CPTWDR 0x1032 -#define HD64461_CPTRAR 0x1034 -#define HD64461_CPTRDR 0x1036 +#define HD64461_STBCR 0x10000 +#define HD64461_SYSCR 0x10002 +#define HD64461_SCPUCR 0x10004 -#define HD64461_PCC0ISR 0x2000 -#define HD64461_PCC0GCR 0x2002 -#define HD64461_PCC0CSCR 0x2004 -#define HD64461_PCC0CSCIER 0x2006 -#define HD64461_PCC0SCR 0x2008 -#define HD64461_PCC1ISR 0x2010 -#define HD64461_PCC1GCR 0x2012 -#define HD64461_PCC1CSCR 0x2014 -#define HD64461_PCC1CSCIER 0x2016 -#define HD64461_PCC1SCR 0x2018 -#define HD64461_P0OCR 0x202a -#define HD64461_P1OCR 0x202c -#define HD64461_PGCR 0x202e +#define HD64461_CPTWAR 0x11030 +#define HD64461_CPTWDR 0x11032 +#define HD64461_CPTRAR 0x11034 +#define HD64461_CPTRDR 0x11036 -#define HD64461_NIRR 0x5000 -#define HD64461_NIMR 0x5002 +#define HD64461_PCC0ISR 0x12000 +#define HD64461_PCC0GCR 0x12002 +#define HD64461_PCC0CSCR 0x12004 +#define HD64461_PCC0CSCIER 0x12006 +#define HD64461_PCC0SCR 0x12008 +#define HD64461_PCC1ISR 0x12010 +#define HD64461_PCC1GCR 0x12012 +#define HD64461_PCC1CSCR 0x12014 +#define HD64461_PCC1CSCIER 0x12016 +#define HD64461_PCC1SCR 0x12018 +#define HD64461_P0OCR 0x1202a +#define HD64461_P1OCR 0x1202c +#define HD64461_PGCR 0x1202e + +#define HD64461_NIRR 0x15000 +#define HD64461_NIMR 0x15002 #ifndef CONFIG_HD64461_IOBASE #define CONFIG_HD64461_IOBASE 0xb0000000 #endif +#ifndef CONFIG_HD64461_IRQ +#define CONFIG_HD64461_IRQ 36 +#endif #define HD64461_IRQBASE 64 diff --git a/include/asm-sh/ide.h b/include/asm-sh/ide.h index 1112ea36c219..25570cea253e 100644 --- a/include/asm-sh/ide.h +++ b/include/asm-sh/ide.h @@ -15,6 +15,7 @@ #ifdef __KERNEL__ #include +#include #ifndef MAX_HWIFS #define MAX_HWIFS 1 @@ -22,35 +23,51 @@ #define ide__sti() __sti() +static __inline__ int ide_default_irq_hp600(ide_ioreg_t base) +{ + switch (base) { + case 0x01f0: return 77; + case 0x0170: return 77; + default: + return 0; + } +} + static __inline__ int ide_default_irq(ide_ioreg_t base) { + if (MACH_HP600) { + return ide_default_irq_hp600(base); + } switch (base) { -#ifdef CONFIG_SH_HP600 - case 0x201f0: return 77; - case 0x20170: return 77; -#else case 0x01f0: return 14; case 0x0170: return 15; -#endif default: return 0; } } -static __inline__ ide_ioreg_t ide_default_io_base(int index) +static __inline__ ide_ioreg_t ide_default_io_base_hp600(int index) { switch (index) { -#ifdef CONFIG_SH_HP600 case 0: - return 0x201f0; + return 0x01f0; case 1: - return 0x20170; -#else + return 0x0170; + default: + return 0; + } +} + +static __inline__ ide_ioreg_t ide_default_io_base(int index) +{ + if (MACH_HP600) { + return ide_default_io_base_hp600(index); + } + switch (index) { case 0: return 0x1f0; case 1: return 0x170; -#endif default: return 0; } diff --git a/include/asm-sh/io.h b/include/asm-sh/io.h index 0d516620c712..8c7d7f2695bf 100644 --- a/include/asm-sh/io.h +++ b/include/asm-sh/io.h @@ -6,85 +6,342 @@ * read{b,w,l}/write{b,w,l} are for PCI, * while in{b,w,l}/out{b,w,l} are for ISA * These may (will) be platform specific function. + * In addition we have 'pausing' versions: in{b,w,l}_p/out{b,w,l}_p + * and 'string' versions: ins{b,w,l}/outs{b,w,l} + * For read{b,w,l} and write{b,w,l} there are also __raw versions, which + * do not have a memory barrier after them. * * In addition, we have * ctrl_in{b,w,l}/ctrl_out{b,w,l} for SuperH specific I/O. * which are processor specific. */ +/* + * We follow the Alpha convention here: + * __inb expands to an inline function call (which either calls via the + * mach_vec if generic, or a machine specific implementation) + * _inb is a real function call (note ___raw fns are _ version of __raw) + * inb by default expands to _inb, but the machine specif code may + * define it to __inb if it chooses. + */ + #include +#include +#include -#define inw_p inw -#define outw_p outw +/* + * Depending on which platform we are running on, we need different + * I/O functions. + */ -#define virt_to_bus virt_to_phys -#define bus_to_virt phys_to_virt +#ifdef __KERNEL__ +#ifdef CONFIG_SH_GENERIC + +/* In a generic kernel, we always go through the machine vector. */ + +#include + +# define __inb(p) sh_mv.mv_inb((p)) +# define __inw(p) sh_mv.mv_inw((p)) +# define __inl(p) sh_mv.mv_inl((p)) +# define __outb(x,p) sh_mv.mv_outb((x),(p)) +# define __outw(x,p) sh_mv.mv_outw((x),(p)) +# define __outl(x,p) sh_mv.mv_outl((x),(p)) + +# define __inb_p(p) sh_mv.mv_inb_p((p)) +# define __inw_p(p) sh_mv.mv_inw_p((p)) +# define __inl_p(p) sh_mv.mv_inl_p((p)) +# define __outb_p(x,p) sh_mv.mv_outb_p((x),(p)) +# define __outw_p(x,p) sh_mv.mv_outw_p((x),(p)) +# define __outl_p(x,p) sh_mv.mv_outl_p((x),(p)) + +#define __insb(p,b,c) sh_mv.mv_insb((p), (b), (c)) +#define __insw(p,b,c) sh_mv.mv_insw((p), (b), (c)) +#define __insl(p,b,c) sh_mv.mv_insl((p), (b), (c)) +#define __outsb(p,b,c) sh_mv.mv_outsb((p), (b), (c)) +#define __outsw(p,b,c) sh_mv.mv_outsw((p), (b), (c)) +#define __outsl(p,b,c) sh_mv.mv_outsl((p), (b), (c)) + +# define __readb(a) sh_mv.mv_readb((a)) +# define __readw(a) sh_mv.mv_readw((a)) +# define __readl(a) sh_mv.mv_readl((a)) +# define __writeb(v,a) sh_mv.mv_writeb((v),(a)) +# define __writew(v,a) sh_mv.mv_writew((v),(a)) +# define __writel(v,a) sh_mv.mv_writel((v),(a)) + +# define __ioremap(a,s) sh_mv.mv_ioremap((a), (s)) +# define __ioremap_nocache(a,s) sh_mv.mv_ioremap_nocache((a), (s)) +# define __iounmap(a) sh_mv.mv_iounmap((a)) + +# define __isa_port2addr(a) sh_mv.mv_isa_port2addr(a) + +# define inb __inb +# define inw __inw +# define inl __inl +# define outb __outb +# define outw __outw +# define outl __outl + +# define inb_p __inb_p +# define inw_p __inw_p +# define inl_p __inl_p +# define outb_p __outb_p +# define outw_p __outw_p +# define outl_p __outl_p + +# define insb __insb +# define insw __insw +# define insl __insl +# define outsb __outsb +# define outsw __outsw +# define outsl __outsl + +# define __raw_readb __readb +# define __raw_readw __readw +# define __raw_readl __readl +# define __raw_writeb __writeb +# define __raw_writew __writew +# define __raw_writel __writel + +#else + +/* Control operations through platform specific headers */ +# define __WANT_IO_DEF + +# if defined(CONFIG_SH_HP600) +# include +# elif defined(CONFIG_SH_OVERDRIVE) +# include +# elif defined(CONFIG_SH_SOLUTION_ENGINE) +# include +# elif defined(CONFIG_SH_UNKNOWN) +# include +# else +# error "What system is this?" +#endif + +#undef __WANT_IO_DEF + +#endif /* GENERIC */ +#endif /* __KERNEL__ */ -extern __inline__ unsigned long readb(unsigned long addr) -{ - return *(volatile unsigned char*)addr; -} +/* These are always function calls, in both kernel and user space */ +extern unsigned int _inb (unsigned long port); +extern unsigned int _inw (unsigned long port); +extern unsigned int _inl (unsigned long port); +extern void _outb (unsigned char b,unsigned long port); +extern void _outw (unsigned short w,unsigned long port); +extern void _outl (unsigned int l,unsigned long port); +extern unsigned int _inb_p (unsigned long port); +extern unsigned int _inw_p (unsigned long port); +extern unsigned int _inl_p (unsigned long port); +extern void _outb_p (unsigned char b,unsigned long port); +extern void _outw_p (unsigned short w,unsigned long port); +extern void _outl_p (unsigned int l,unsigned long port); +extern void _insb (unsigned long port, void *dst, unsigned long count); +extern void _insw (unsigned long port, void *dst, unsigned long count); +extern void _insl (unsigned long port, void *dst, unsigned long count); +extern void _outsb (unsigned long port, const void *src, unsigned long count); +extern void _outsw (unsigned long port, const void *src, unsigned long count); +extern void _outsl (unsigned long port, const void *src, unsigned long count); +extern unsigned long _readb(unsigned long addr); +extern unsigned long _readw(unsigned long addr); +extern unsigned long _readl(unsigned long addr); +extern void _writeb(unsigned char b, unsigned long addr); +extern void _writew(unsigned short b, unsigned long addr); +extern void _writel(unsigned int b, unsigned long addr); -extern __inline__ unsigned long readw(unsigned long addr) -{ - return *(volatile unsigned short*)addr; -} +#ifdef __KERNEL__ +extern unsigned long ___raw_readb(unsigned long addr); +extern unsigned long ___raw_readw(unsigned long addr); +extern unsigned long ___raw_readl(unsigned long addr); +extern unsigned long ___raw_readq(unsigned long addr); +extern void ___raw_writeb(unsigned char b, unsigned long addr); +extern void ___raw_writew(unsigned short b, unsigned long addr); +extern void ___raw_writel(unsigned int b, unsigned long addr); +extern void ___raw_writeq(unsigned long b, unsigned long addr); +#endif -extern __inline__ unsigned long readl(unsigned long addr) -{ - return *(volatile unsigned long*)addr; -} +#ifdef __KERNEL__ +/* + * The platform header files may define some of these macros to use + * the inlined versions where appropriate. These macros may also be + * redefined by userlevel programs. + */ +#ifndef inb +# define inb(p) _inb(p) +#endif +#ifndef inw +# define inw(p) _inw(p) +#endif +#ifndef inl +# define inl(p) _inl(p) +#endif + +#ifndef outb +# define outb(b,p) _outb((b),(p)) +#endif +#ifndef outw +# define outw(w,p) _outw((w),(p)) +#endif +#ifndef outl +# define outl(l,p) _outl((l),(p)) +#endif + +#ifndef inb_p +# define inb_p _inb_p +#endif +#ifndef inw_p +# define inw_p _inw_p +#endif +#ifndef inl_p +# define inl_p _inl_p +#endif + +#ifndef outb_p +# define outb_p _outb_p +#endif +#ifndef outw_p +# define outw_p _outw_p +#endif +#ifndef outl_p +# define outl_p _outl_p +#endif + +#ifndef insb +# define insb(p,d,c) _insb((p),(d),(c)) +#endif +#ifndef insw +# define insw(p,d,c) _insw((p),(d),(c)) +#endif +#ifndef insl +# define insl(p,d,c) _insl((p),(d),(c)) +#endif +#ifndef outsb +# define outsb(p,s,c) _outsb((p),(s),(c)) +#endif +#ifndef outsw +# define outsw(p,s,c) _outsw((p),(s),(c)) +#endif +#ifndef outsl +# define outsl(p,s,c) _outsl((p),(s),(c)) +#endif + +#ifdef __raw_readb +# define readb(a) ({ unsigned long r_ = __raw_readb(a); mb(); r_; }) +#endif +#ifdef __raw_readw +# define readw(a) ({ unsigned long r_ = __raw_readw(a); mb(); r_; }) +#endif +#ifdef __raw_readl +# define readl(a) ({ unsigned long r_ = __raw_readl(a); mb(); r_; }) +#endif + +#ifdef __raw_writeb +# define writeb(v,a) ({ __raw_writeb((v),(a)); mb(); }) +#endif +#ifdef __raw_writew +# define writew(v,a) ({ __raw_writew((v),(a)); mb(); }) +#endif +#ifdef __raw_writel +# define writel(v,a) ({ __raw_writel((v),(a)); mb(); }) +#endif + +#ifndef __raw_readb +# define __raw_readb(a) ___raw_readb((unsigned long)(a)) +#endif +#ifndef __raw_readw +# define __raw_readw(a) ___raw_readw((unsigned long)(a)) +#endif +#ifndef __raw_readl +# define __raw_readl(a) ___raw_readl((unsigned long)(a)) +#endif + +#ifndef __raw_writeb +# define __raw_writeb(v,a) ___raw_writeb((v),(unsigned long)(a)) +#endif +#ifndef __raw_writew +# define __raw_writew(v,a) ___raw_writew((v),(unsigned long)(a)) +#endif +#ifndef __raw_writel +# define __raw_writel(v,a) ___raw_writel((v),(unsigned long)(a)) +#endif + +#ifndef readb +# define readb(a) _readb((unsigned long)(a)) +#endif +#ifndef readw +# define readw(a) _readw((unsigned long)(a)) +#endif +#ifndef readl +# define readl(a) _readl((unsigned long)(a)) +#endif + +#ifndef writeb +# define writeb(v,a) _writeb((v),(unsigned long)(a)) +#endif +#ifndef writew +# define writew(v,a) _writew((v),(unsigned long)(a)) +#endif +#ifndef writel +# define writel(v,a) _writel((v),(unsigned long)(a)) +#endif + +#else + +/* Userspace declarations. */ + +extern unsigned int inb(unsigned long port); +extern unsigned int inw(unsigned long port); +extern unsigned int inl(unsigned long port); +extern void outb(unsigned char b,unsigned long port); +extern void outw(unsigned short w,unsigned long port); +extern void outl(unsigned int l,unsigned long port); +extern void insb (unsigned long port, void *dst, unsigned long count); +extern void insw (unsigned long port, void *dst, unsigned long count); +extern void insl (unsigned long port, void *dst, unsigned long count); +extern void outsb (unsigned long port, const void *src, unsigned long count); +extern void outsw (unsigned long port, const void *src, unsigned long count); +extern void outsl (unsigned long port, const void *src, unsigned long count); +extern unsigned long readb(unsigned long addr); +extern unsigned long readw(unsigned long addr); +extern unsigned long readl(unsigned long addr); +extern void writeb(unsigned char b, unsigned long addr); +extern void writew(unsigned short b, unsigned long addr); +extern void writel(unsigned int b, unsigned long addr); -extern __inline__ void writeb(unsigned char b, unsigned long addr) -{ - *(volatile unsigned char*)addr = b; -} +#endif /* __KERNEL__ */ -extern __inline__ void writew(unsigned short b, unsigned long addr) -{ - *(volatile unsigned short*)addr = b; -} +#ifdef __KERNEL__ -extern __inline__ void writel(unsigned int b, unsigned long addr) +/* + * If the platform has PC-like I/O, this function converts the offset into + * an address. + */ +extern __inline__ unsigned long isa_port2addr(unsigned long offset) { - *(volatile unsigned long*)addr = b; + return __isa_port2addr(offset); } -extern unsigned long inb(unsigned int port); -extern unsigned long inb_p(unsigned int port); -extern unsigned long inw(unsigned int port); -extern unsigned long inl(unsigned int port); -extern void insb(unsigned int port, void *addr, unsigned long count); -extern void insw(unsigned int port, void *addr, unsigned long count); -extern void insl(unsigned int port, void *addr, unsigned long count); - -extern void outb(unsigned long value, unsigned int port); -extern void outb_p(unsigned long value, unsigned int port); -extern void outw(unsigned long value, unsigned int port); -extern void outl(unsigned long value, unsigned int port); -extern void outsb(unsigned int port, const void *addr, unsigned long count); -extern void outsw(unsigned int port, const void *addr, unsigned long count); -extern void outsl(unsigned int port, const void *addr, unsigned long count); - -/* - * If the platform has PC-like I/O, this function gives us the address - * from the offset. - */ -extern unsigned long sh_isa_slot(unsigned long offset); - -#define isa_readb(a) readb(sh_isa_slot(a)) -#define isa_readw(a) readw(sh_isa_slot(a)) -#define isa_readl(a) readl(sh_isa_slot(a)) -#define isa_writeb(b,a) writeb(b,sh_isa_slot(a)) -#define isa_writew(w,a) writew(w,sh_isa_slot(a)) -#define isa_writel(l,a) writel(l,sh_isa_slot(a)) +#define isa_readb(a) readb(isa_port2addr(a)) +#define isa_readw(a) readw(isa_port2addr(a)) +#define isa_readl(a) readl(isa_port2addr(a)) +#define isa_writeb(b,a) writeb(b,isa_port2addr(a)) +#define isa_writew(w,a) writew(w,isa_port2addr(a)) +#define isa_writel(l,a) writel(l,isa_port2addr(a)) #define isa_memset_io(a,b,c) \ - memset((void *)(sh_isa_slot((unsigned long)a)),(b),(c)) + memset((void *)(isa_port2addr((unsigned long)a)),(b),(c)) #define isa_memcpy_fromio(a,b,c) \ - memcpy((a),(void *)(sh_isa_slot((unsigned long)(b))),(c)) + memcpy((a),(void *)(isa_port2addr((unsigned long)(b))),(c)) #define isa_memcpy_toio(a,b,c) \ - memcpy((void *)(sh_isa_slot((unsigned long)(a))),(b),(c)) + memcpy((void *)(isa_port2addr((unsigned long)(a))),(b),(c)) +/* We really want to try and get these to memcpy etc */ +extern void memcpy_fromio(void *, unsigned long, unsigned long); +extern void memcpy_toio(unsigned long, const void *, unsigned long); +extern void memset_io(unsigned long, int, unsigned long); + +/* SuperH on-chip I/O functions */ extern __inline__ unsigned long ctrl_inb(unsigned long addr) { return *(volatile unsigned char*)addr; @@ -115,8 +372,6 @@ extern __inline__ void ctrl_outl(unsigned int b, unsigned long addr) *(volatile unsigned long*)addr = b; } -#ifdef __KERNEL__ - #define IO_SPACE_LIMIT 0xffffffff #include @@ -135,8 +390,8 @@ extern __inline__ void * phys_to_virt(unsigned long address) return (void *)P1SEGADDR(address); } -extern void * ioremap(unsigned long phys_addr, unsigned long size); -extern void iounmap(void *addr); +#define virt_to_bus virt_to_phys +#define bus_to_virt phys_to_virt /* * readX/writeX() are used to access memory mapped devices. On some @@ -152,9 +407,9 @@ extern void iounmap(void *addr); * We cheat a bit and always return uncachable areas until we've fixed * the drivers to handle caching properly. */ -extern __inline__ void * ioremap(unsigned long offset, unsigned long size) +static __inline__ void * ioremap(unsigned long offset, unsigned long size) { - return (void *) P2SEGADDR(offset); + return __ioremap(offset, size); } /* @@ -162,13 +417,14 @@ extern __inline__ void * ioremap(unsigned long offset, unsigned long size) * it's useful if some control registers are in such an area and write combining * or read caching is not desirable: */ -extern __inline__ void * ioremap_nocache (unsigned long offset, unsigned long size) +static __inline__ void * ioremap_nocache (unsigned long offset, unsigned long size) { - return (void *) P2SEGADDR(offset); + return __ioremap_nocache(offset, size); } -extern __inline__ void iounmap(void *addr) +static __inline__ void iounmap(void *addr) { + return __iounmap(addr); } static __inline__ int check_signature(unsigned long io_addr, diff --git a/include/asm-sh/io_generic.h b/include/asm-sh/io_generic.h new file mode 100644 index 000000000000..92d9019b6107 --- /dev/null +++ b/include/asm-sh/io_generic.h @@ -0,0 +1,52 @@ +/* + * include/asm-sh/io_generic.h + * + * Copyright 2000 Stuart Menefy (stuart.menefy@st.com) + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * Generic IO functions + */ + +#ifndef _ASM_SH_IO_GENERIC_H +#define _ASM_SH_IO_GENERIC_H + +extern unsigned long generic_io_base; + +extern unsigned long generic_inb(unsigned int port); +extern unsigned long generic_inw(unsigned int port); +extern unsigned long generic_inl(unsigned int port); + +extern void generic_outb(unsigned long value, unsigned int port); +extern void generic_outw(unsigned long value, unsigned int port); +extern void generic_outl(unsigned long value, unsigned int port); + +extern unsigned long generic_inb_p(unsigned int port); +extern unsigned long generic_inw_p(unsigned int port); +extern unsigned long generic_inl_p(unsigned int port); +extern void generic_outb_p(unsigned long value, unsigned int port); +extern void generic_outw_p(unsigned long value, unsigned int port); +extern void generic_outl_p(unsigned long value, unsigned int port); + +extern void generic_insb(unsigned int port, void *addr, unsigned long count); +extern void generic_insw(unsigned int port, void *addr, unsigned long count); +extern void generic_insl(unsigned int port, void *addr, unsigned long count); +extern void generic_outsb(unsigned int port, const void *addr, unsigned long count); +extern void generic_outsw(unsigned int port, const void *addr, unsigned long count); +extern void generic_outsl(unsigned int port, const void *addr, unsigned long count); + +extern unsigned long generic_readb(unsigned long addr); +extern unsigned long generic_readw(unsigned long addr); +extern unsigned long generic_readl(unsigned long addr); +extern void generic_writeb(unsigned char b, unsigned long addr); +extern void generic_writew(unsigned short b, unsigned long addr); +extern void generic_writel(unsigned int b, unsigned long addr); + +extern void *generic_ioremap(unsigned long offset, unsigned long size); +extern void *generic_ioremap_nocache (unsigned long offset, unsigned long size); +extern void generic_iounmap(void *addr); + +extern unsigned long generic_isa_port2addr(unsigned long offset); + +#endif /* _ASM_SH_IO_GENERIC_H */ diff --git a/include/asm-sh/io_hd64461.h b/include/asm-sh/io_hd64461.h new file mode 100644 index 000000000000..2574a39aba48 --- /dev/null +++ b/include/asm-sh/io_hd64461.h @@ -0,0 +1,67 @@ +/* + * include/asm-sh/io_hd64461.h + * + * Copyright 2000 Stuart Menefy (stuart.menefy@st.com) + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * IO functions for an HD64461 + */ + +#ifndef _ASM_SH_IO_HD64461_H +#define _ASM_SH_IO_HD64461_H + +#include + +extern unsigned long hd64461_inb(unsigned int port); +extern unsigned long hd64461_inw(unsigned int port); +extern unsigned long hd64461_inl(unsigned int port); + +extern void hd64461_outb(unsigned long value, unsigned int port); +extern void hd64461_outw(unsigned long value, unsigned int port); +extern void hd64461_outl(unsigned long value, unsigned int port); + +extern unsigned long hd64461_inb_p(unsigned int port); +extern void hd64461_outb_p(unsigned long value, unsigned int port); + +extern void hd64461_insb(unsigned int port, void *addr, unsigned long count); +extern void hd64461_insw(unsigned int port, void *addr, unsigned long count); +extern void hd64461_insl(unsigned int port, void *addr, unsigned long count); +extern void hd64461_outsb(unsigned int port, const void *addr, unsigned long count); +extern void hd64461_outsw(unsigned int port, const void *addr, unsigned long count); +extern void hd64461_outsl(unsigned int port, const void *addr, unsigned long count); + +#ifdef __WANT_IO_DEF + +# define __inb hd64461_inb +# define __inw hd64461_inw +# define __inl hd64461_inl +# define __outb hd64461_outb +# define __outw hd64461_outw +# define __outl hd64461_outl + +# define __inb_p hd64461_inb_p +# define __inw_p hd64461_inw +# define __inl_p hd64461_inl +# define __outb_p hd64461_outb_p +# define __outw_p hd64461_outw +# define __outl_p hd64461_outl + +# define __insb hd64461_insb +# define __insw hd64461_insw +# define __insl hd64461_insl +# define __outsb hd64461_outsb +# define __outsw hd64461_outsw +# define __outsl hd64461_outsl + +# define __readb generic_readb +# define __readw generic_readw +# define __readl generic_readl +# define __writeb generic_writeb +# define __writew generic_writew +# define __writel generic_writel + +#endif + +#endif /* _ASM_SH_IO_HD64461_H */ diff --git a/include/asm-sh/io_od.h b/include/asm-sh/io_od.h new file mode 100644 index 000000000000..3a7e477be070 --- /dev/null +++ b/include/asm-sh/io_od.h @@ -0,0 +1,78 @@ +/* + * include/asm-sh/io_od.h + * + * Copyright 2000 Stuart Menefy (stuart.menefy@st.com) + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * IO functions for an STMicroelectronics Overdrive + */ + +#ifndef _ASM_SH_IO_OD_H +#define _ASM_SH_IO_OD_H + +#include + +extern unsigned long od_inb(unsigned int port); +extern unsigned long od_inw(unsigned int port); +extern unsigned long od_inl(unsigned int port); + +extern void od_outb(unsigned long value, unsigned int port); +extern void od_outw(unsigned long value, unsigned int port); +extern void od_outl(unsigned long value, unsigned int port); + +extern unsigned long od_inb_p(unsigned int port); +extern unsigned long od_inw_p(unsigned int port); +extern unsigned long od_inl_p(unsigned int port); +extern void od_outb_p(unsigned long value, unsigned int port); +extern void od_outw_p(unsigned long value, unsigned int port); +extern void od_outl_p(unsigned long value, unsigned int port); + +extern void od_insb(unsigned int port, void *addr, unsigned long count); +extern void od_insw(unsigned int port, void *addr, unsigned long count); +extern void od_insl(unsigned int port, void *addr, unsigned long count); +extern void od_outsb(unsigned int port, const void *addr, unsigned long count); +extern void od_outsw(unsigned int port, const void *addr, unsigned long count); +extern void od_outsl(unsigned int port, const void *addr, unsigned long count); + +extern unsigned long od_isa_port2addr(unsigned long offset); + +#ifdef __WANT_IO_DEF + +# define __inb od_inb +# define __inw od_inw +# define __inl od_inl +# define __outb od_outb +# define __outw od_outw +# define __outl od_outl + +# define __inb_p od_inb_p +# define __inw_p od_inw_p +# define __inl_p od_inl_p +# define __outb_p od_outb_p +# define __outw_p od_outw_p +# define __outl_p od_outl_p + +# define __insb od_insb +# define __insw od_insw +# define __insl od_insl +# define __outsb od_outsb +# define __outsw od_outsw +# define __outsl od_outsl + +# define __readb generic_readb +# define __readw generic_readw +# define __readl generic_readl +# define __writeb generic_writeb +# define __writew generic_writew +# define __writel generic_writel + +# define __isa_port2addr od_isa_port2addr +# define __ioremap generic_ioremap +# define __ioremap_nocache generic_ioremap_nocache +# define __iounmap generic_iounmap + +#endif + +#endif /* _ASM_SH_IO_OD_H */ diff --git a/include/asm-sh/io_se.h b/include/asm-sh/io_se.h new file mode 100644 index 000000000000..d97457d9edcd --- /dev/null +++ b/include/asm-sh/io_se.h @@ -0,0 +1,81 @@ +/* + * include/asm-sh/io_se.h + * + * Copyright 2000 Stuart Menefy (stuart.menefy@st.com) + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * IO functions for an Hitachi SolutionEngine + */ + +#ifndef _ASM_SH_IO_SE_H +#define _ASM_SH_IO_SE_H + +#include + +extern unsigned long se_inb(unsigned int port); +extern unsigned long se_inw(unsigned int port); +extern unsigned long se_inl(unsigned int port); + +extern void se_outb(unsigned long value, unsigned int port); +extern void se_outw(unsigned long value, unsigned int port); +extern void se_outl(unsigned long value, unsigned int port); + +extern unsigned long se_inb_p(unsigned int port); +extern void se_outb_p(unsigned long value, unsigned int port); + +extern void se_insb(unsigned int port, void *addr, unsigned long count); +extern void se_insw(unsigned int port, void *addr, unsigned long count); +extern void se_insl(unsigned int port, void *addr, unsigned long count); +extern void se_outsb(unsigned int port, const void *addr, unsigned long count); +extern void se_outsw(unsigned int port, const void *addr, unsigned long count); +extern void se_outsl(unsigned int port, const void *addr, unsigned long count); + +extern unsigned long se_readb(unsigned long addr); +extern unsigned long se_readw(unsigned long addr); +extern unsigned long se_readl(unsigned long addr); +extern void se_writeb(unsigned char b, unsigned long addr); +extern void se_writew(unsigned short b, unsigned long addr); +extern void se_writel(unsigned int b, unsigned long addr); + +extern unsigned long se_isa_port2addr(unsigned long offset); + +#ifdef __WANT_IO_DEF + +# define __inb se_inb +# define __inw se_inw +# define __inl se_inl +# define __outb se_outb +# define __outw se_outw +# define __outl se_outl + +# define __inb_p se_inb_p +# define __inw_p se_inw +# define __inl_p se_inl +# define __outb_p se_outb_p +# define __outw_p se_outw +# define __outl_p se_outl + +# define __insb se_insb +# define __insw se_insw +# define __insl se_insl +# define __outsb se_outsb +# define __outsw se_outsw +# define __outsl se_outsl + +# define __readb se_readb +# define __readw se_readw +# define __readl se_readl +# define __writeb se_writeb +# define __writew se_writew +# define __writel se_writel + +# define __isa_port2addr se_isa_port2addr +# define __ioremap generic_ioremap +# define __ioremap_nocache generic_ioremap_nocache +# define __iounmap generic_iounmap + +#endif + +#endif /* _ASM_SH_IO_SE_H */ diff --git a/include/asm-sh/io_unknown.h b/include/asm-sh/io_unknown.h new file mode 100644 index 000000000000..b638f2b15988 --- /dev/null +++ b/include/asm-sh/io_unknown.h @@ -0,0 +1,86 @@ +/* + * include/asm-sh/io_unknown.h + * + * Copyright 2000 Stuart Menefy (stuart.menefy@st.com) + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * IO functions for use when we don't know what machine we are on + */ + +#ifndef _ASM_SH_IO_UNKNOWN_H +#define _ASM_SH_IO_UNKNOWN_H + +extern unsigned long unknown_inb(unsigned int port); +extern unsigned long unknown_inw(unsigned int port); +extern unsigned long unknown_inl(unsigned int port); + +extern void unknown_outb(unsigned long value, unsigned int port); +extern void unknown_outw(unsigned long value, unsigned int port); +extern void unknown_outl(unsigned long value, unsigned int port); + +extern unsigned long unknown_inb_p(unsigned int port); +extern unsigned long unknown_inw_p(unsigned int port); +extern unsigned long unknown_inl_p(unsigned int port); +extern void unknown_outb_p(unsigned long value, unsigned int port); +extern void unknown_outw_p(unsigned long value, unsigned int port); +extern void unknown_outl_p(unsigned long value, unsigned int port); + +extern void unknown_insb(unsigned int port, void *addr, unsigned long count); +extern void unknown_insw(unsigned int port, void *addr, unsigned long count); +extern void unknown_insl(unsigned int port, void *addr, unsigned long count); +extern void unknown_outsb(unsigned int port, const void *addr, unsigned long count); +extern void unknown_outsw(unsigned int port, const void *addr, unsigned long count); +extern void unknown_outsl(unsigned int port, const void *addr, unsigned long count); + +extern unsigned long unknown_readb(unsigned long addr); +extern unsigned long unknown_readw(unsigned long addr); +extern unsigned long unknown_readl(unsigned long addr); +extern void unknown_writeb(unsigned char b, unsigned long addr); +extern void unknown_writew(unsigned short b, unsigned long addr); +extern void unknown_writel(unsigned int b, unsigned long addr); + +extern unsigned long unknown_isa_port2addr(unsigned long offset); +extern void * unknown_ioremap(unsigned long offset, unsigned long size); +extern void * unknown_ioremap_nocache (unsigned long offset, unsigned long size); +extern void unknown_iounmap(void *addr); + +#ifdef __WANT_IO_DEF + +# define __inb unknown_inb +# define __inw unknown_inw +# define __inl unknown_inl +# define __outb unknown_outb +# define __outw unknown_outw +# define __outl unknown_outl + +# define __inb_p unknown_inb_p +# define __inw_p unknown_inw_p +# define __inl_p unknown_inl_p +# define __outb_p unknown_outb_p +# define __outw_p unknown_outw_p +# define __outl_p unknown_outl_p + +# define __insb unknown_insb +# define __insw unknown_insw +# define __insl unknown_insl +# define __outsb unknown_outsb +# define __outsw unknown_outsw +# define __outsl unknown_outsl + +# define __readb unknown_readb +# define __readw unknown_readw +# define __readl unknown_readl +# define __writeb unknown_writeb +# define __writew unknown_writew +# define __writel unknown_writel + +# define __isa_port2addr unknown_isa_port2addr +# define __ioremap unknown_ioremap +# define __ioremap_nocache unknown_ioremap_nocache +# define __iounmap unknown_iounmap + +#endif + +#endif /* _ASM_SH_IO_UNKNOWN_H */ diff --git a/include/asm-sh/irq.h b/include/asm-sh/irq.h index 951ad2e9f668..48016e3f958a 100644 --- a/include/asm-sh/irq.h +++ b/include/asm-sh/irq.h @@ -11,6 +11,7 @@ */ #include +#include #if defined(__sh3__) #define INTC_IPRA 0xfffffee2UL @@ -31,6 +32,43 @@ #define RTC_IPR_POS 0 #define RTC_PRIORITY TIMER_PRIORITY +#define SCI_ERI_IRQ 23 +#define SCI_RXI_IRQ 24 +#define SCI_TXI_IRQ 25 +#define SCI_IPR_ADDR INTC_IPRB +#define SCI_IPR_POS 1 +#define SCI_PRIORITY 3 + +#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) +#define SCIF_ERI_IRQ 56 +#define SCIF_RXI_IRQ 57 +#define SCIF_TXI_IRQ 59 +#define SCIF_IPR_ADDR INTC_IPRE +#define SCIF_IPR_POS 1 +#define SCIF_PRIORITY 3 + +#define IRDA_ERI_IRQ 52 +#define IRDA_RXI_IRQ 53 +#define IRDA_TXI_IRQ 55 +#define IRDA_IPR_ADDR INTC_IPRE +#define IRDA_IPR_POS 2 +#define IRDA_PRIORITY 3 +#elif defined(CONFIG_CPU_SUBTYPE_SH7750) +#define SCIF_ERI_IRQ 40 +#define SCIF_RXI_IRQ 41 +#define SCIF_TXI_IRQ 43 +#define SCIF_IPR_ADDR INTC_IPRC +#define SCIF_IPR_POS 1 +#define SCIF_PRIORITY 3 +#endif + +#ifdef CONFIG_SH_GENERIC +/* In a generic kernel, NR_IRQS is an upper bound, and we should use + * ACTUAL_NR_IRQS (which uses the machine vector) to get the correct value. + */ +#define NR_IRQS 80 +#define ACTUAL_NR_IRQS (sh_mv.mv_nr_irqs) +#else #if defined(__SH4__) /* * 48 = 32+16 @@ -40,6 +78,8 @@ * */ #define NR_IRQS 48 +#elif defined(CONFIG_CPU_SUBTYPE_SH7707) +#define NR_IRQS 64 #elif defined(CONFIG_CPU_SUBTYPE_SH7708) #define NR_IRQS 32 #elif defined(CONFIG_CPU_SUBTYPE_SH7709) @@ -49,6 +89,8 @@ #define NR_IRQS 61 #endif #endif +#define ACTUAL_NR_IRQS NR_IRQS +#endif extern void disable_irq(unsigned int); extern void disable_irq_nosync(unsigned int); @@ -57,12 +99,11 @@ extern void enable_irq(unsigned int); /* * Function for "on chip support modules". */ -extern void set_ipr_data(unsigned int irq, unsigned int addr, +extern void make_ipr_irq(unsigned int irq, unsigned int addr, int pos, int priority); -extern void make_ipr_irq(unsigned int irq); extern void make_imask_irq(unsigned int irq); -#if defined(CONFIG_CPU_SUBTYPE_SH7709) +#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) #define INTC_IRR0 0xa4000004UL #define INTC_IRR1 0xa4000006UL #define INTC_IRR2 0xa4000008UL @@ -75,6 +116,9 @@ extern void make_imask_irq(unsigned int irq); #define INTC_IPRC 0xa4000016UL #define INTC_IPRD 0xa4000018UL #define INTC_IPRE 0xa400001aUL +#if defined(CONFIG_CPU_SUBTYPE_SH7707) +#define INTC_IPRF 0xa400001cUL +#endif #define IRQ0_IRQ 32 #define IRQ1_IRQ 33 @@ -105,4 +149,19 @@ extern void make_imask_irq(unsigned int irq); #define IRQ5_PRIORITY 1 #endif +extern int hd64461_irq_demux(int irq); + +#ifdef CONFIG_SH_GENERIC +extern __inline__ int irq_demux(int irq) { + if (sh_mv.mv_irq_demux) { + irq = sh_mv.mv_irq_demux(irq); + } + return irq; +} +#elif defined(CONFIG_HD64461) +#define irq_demux(irq) hd64461_irq_demux(irq) +#else +#define irq_demux(irq) irq +#endif + #endif /* __ASM_SH_IRQ_H */ diff --git a/include/asm-sh/keyboard.h b/include/asm-sh/keyboard.h index 9a64c5113c44..f1b8eb142d0d 100644 --- a/include/asm-sh/keyboard.h +++ b/include/asm-sh/keyboard.h @@ -3,7 +3,8 @@ /* * $Id: keyboard.h,v 1.1 2000/06/10 21:45:48 yaegashi Exp $ */ -#include + +#include static __inline__ int kbd_setkeycode(unsigned int scancode, unsigned int keycode) @@ -32,13 +33,13 @@ static __inline__ void kbd_leds(unsigned char leds) { } -#ifdef CONFIG_SH_HP600 -void __init hp600_kbd_init_hw(void); -#define kbd_init_hw hp600_kbd_init_hw -#else +extern void hp600_kbd_init_hw(void); + static __inline__ void kbd_init_hw(void) { + if (MACH_HP600) { + hp600_kbd_init_hw(); + } } -#endif #endif diff --git a/include/asm-sh/machvec.h b/include/asm-sh/machvec.h new file mode 100644 index 000000000000..918bf969b38a --- /dev/null +++ b/include/asm-sh/machvec.h @@ -0,0 +1,96 @@ +/* + * include/asm-sh/machvec.h + * + * Copyright 2000 Stuart Menefy (stuart.menefy@st.com) + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + */ + +#ifndef _ASM_SH_MACHVEC_H +#define _ASM_SH_MACHVEC_H 1 + +#include +#include + +struct sh_machine_vector +{ + const char *mv_name; + + int mv_nr_irqs; + + unsigned long (*mv_inb)(unsigned int); + unsigned long (*mv_inw)(unsigned int); + unsigned long (*mv_inl)(unsigned int); + void (*mv_outb)(unsigned long, unsigned int); + void (*mv_outw)(unsigned long, unsigned int); + void (*mv_outl)(unsigned long, unsigned int); + + unsigned long (*mv_inb_p)(unsigned int); + unsigned long (*mv_inw_p)(unsigned int); + unsigned long (*mv_inl_p)(unsigned int); + void (*mv_outb_p)(unsigned long, unsigned int); + void (*mv_outw_p)(unsigned long, unsigned int); + void (*mv_outl_p)(unsigned long, unsigned int); + + void (*mv_insb)(unsigned int port, void *addr, unsigned long count); + void (*mv_insw)(unsigned int port, void *addr, unsigned long count); + void (*mv_insl)(unsigned int port, void *addr, unsigned long count); + void (*mv_outsb)(unsigned int port, const void *addr, unsigned long count); + void (*mv_outsw)(unsigned int port, const void *addr, unsigned long count); + void (*mv_outsl)(unsigned int port, const void *addr, unsigned long count); + + unsigned long (*mv_readb)(unsigned long); + unsigned long (*mv_readw)(unsigned long); + unsigned long (*mv_readl)(unsigned long); + void (*mv_writeb)(unsigned char, unsigned long); + void (*mv_writew)(unsigned short, unsigned long); + void (*mv_writel)(unsigned int, unsigned long); + + void* (*mv_ioremap)(unsigned long offset, unsigned long size); + void* (*mv_ioremap_nocache)(unsigned long offset, unsigned long size); + void (*mv_iounmap)(void *addr); + + unsigned long (*mv_port2addr)(unsigned long offset); + unsigned long (*mv_isa_port2addr)(unsigned long offset); + + int (*mv_irq_demux)(int irq); + + void (*mv_init_arch)(void); + void (*mv_init_irq)(void); + void (*mv_init_pci)(void); + void (*mv_kill_arch)(int); + + void (*mv_heartbeat)(void); + + unsigned int mv_hw_se : 1; + unsigned int mv_hw_hp600 : 1; + unsigned int mv_hw_hd64461 : 1; +}; + +extern struct sh_machine_vector sh_mv; + +/* Machine check macros */ +#ifdef CONFIG_SH_GENERIC +#define MACH_SE (sh_mv.mv_hw_se) +#define MACH_HP600 (sh_mv.mv_hw_hp600) +#define MACH_HD64461 (sh_mv.mv_hw_hd64461) +#else +# ifdef CONFIG_SH_SOLUTION_ENGINE +# define MACH_SE 1 +# else +# define MACH_SE 0 +# endif +# ifdef CONFIG_SH_HP600 +# define MACH_HP600 1 +# else +# define MACH_HP600 0 +# endif +# ifdef CONFIG_HD64461 +# define MACH_HD64461 1 +# else +# define MACH_HD64461 0 +# endif +#endif + +#endif /* _ASM_SH_MACHVEC_H */ diff --git a/include/asm-sh/machvec_init.h b/include/asm-sh/machvec_init.h new file mode 100644 index 000000000000..3e82b3f62a63 --- /dev/null +++ b/include/asm-sh/machvec_init.h @@ -0,0 +1,52 @@ +/* + * include/asm-sh/machvec_init.h + * + * Copyright 2000 Stuart Menefy (stuart.menefy@st.com) + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * This file has goodies to help simplify instantiation of machine vectors. + */ + +#ifndef __SH_MACHVEC_INIT_H +#define __SH_MACHVEC_INIT_H + +/* + * In a GENERIC kernel, we have lots of these vectors floating about, + * all but one of which we want to go away. In a non-GENERIC kernel, + * we want only one, ever. + * + * Accomplish this in the GENERIC kernel by puting all of the vectors + * in the .init.data section where they'll go away. We'll copy the + * one we want to the real alpha_mv vector in setup_arch. + * + * Accomplish this in a non-GENERIC kernel by ifdef'ing out all but + * one of the vectors, which will not reside in .init.data. We then + * alias this one vector to alpha_mv, so no copy is needed. + * + * Upshot: set __initdata to nothing for non-GENERIC kernels. + * + * Note we do the same thing for the UNKNOWN kernel, as we need to write + * to the machine vector while setting it up. + */ + +#if defined(CONFIG_SH_GENERIC) || defined(CONFIG_SH_UNKNOWN) +#define __initmv __attribute__((unused,__section__ (".machvec.init"))) +#define ALIAS_MV(x) +#else +#define __initmv + +/* GCC actually has a syntax for defining aliases, but is under some + delusion that you shouldn't be able to declare it extern somewhere + else beforehand. Fine. We'll do it ourselves. */ +#if 0 +#define ALIAS_MV(system) \ + struct sh_machine_vector sh_mv __attribute__((alias("mv_"#system))); +#else +#define ALIAS_MV(system) \ + asm(".global sh_mv\nsh_mv = mv_"#system ); +#endif +#endif /* GENERIC */ + +#endif /* __SH_MACHVEC_INIT_H */ diff --git a/include/asm-sh/mmu_context.h b/include/asm-sh/mmu_context.h index 0f48339b2738..82517a5af3ab 100644 --- a/include/asm-sh/mmu_context.h +++ b/include/asm-sh/mmu_context.h @@ -164,15 +164,15 @@ extern __inline__ void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned int cpu) { - set_bit(cpu, &next->cpu_vm_mask); if (prev != next) { unsigned long __pgdir = (unsigned long)next->pgd; + clear_bit(cpu, &prev->cpu_vm_mask); + set_bit(cpu, &next->cpu_vm_mask); __asm__ __volatile__("mov.l %0, %1" : /* no output */ : "r" (__pgdir), "m" (__m(MMU_TTB))); activate_context(next); - clear_bit(cpu, &prev->cpu_vm_mask); } } diff --git a/include/asm-sh/page.h b/include/asm-sh/page.h index 1348466a9383..dcac85fa6a8d 100644 --- a/include/asm-sh/page.h +++ b/include/asm-sh/page.h @@ -65,7 +65,8 @@ typedef struct { unsigned long pgprot; } pgprot_t; #define PAGE_OFFSET (0x80000000) #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) -#define MAP_NR(addr) ((__pa(addr)-__MEMORY_START) >> PAGE_SHIFT) +#define virt_to_page(kaddr) (mem_map + ((__pa(kaddr)-__MEMORY_START) >> PAGE_SHIFT)) +#define VALID_PAGE(page) ((page - mem_map) < max_mapnr) #ifndef __ASSEMBLY__ diff --git a/include/asm-sh/pci.h b/include/asm-sh/pci.h index 34398480a5cf..2c3ce9038ed5 100644 --- a/include/asm-sh/pci.h +++ b/include/asm-sh/pci.h @@ -9,6 +9,15 @@ #define pcibios_assign_all_busses() 0 +/* These are currently the correct values for the STM overdrive board. + * We need some way of setting this on a board specific way, it will + * not be the same on other boards I think + */ +#if 1 /* def CONFIG_SH_OVERDRIVE */ +#define PCIBIOS_MIN_IO 0x2000 +#define PCIBIOS_MIN_MEM 0x10000000 +#endif + extern inline void pcibios_set_master(struct pci_dev *dev) { /* No special bus mastering setup handling */ @@ -59,7 +68,7 @@ extern void pci_free_consistent(struct pci_dev *hwdev, size_t size, * 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, - size_t size) + size_t size,int directoin) { return virt_to_bus(ptr); } @@ -72,7 +81,7 @@ extern inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, * whatever the device wrote there. */ extern inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, - size_t size) + size_t size,int direction) { /* Nothing to do */ } @@ -93,7 +102,7 @@ extern inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, * the same here. */ extern inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, - int nents) + int nents,int direction) { return nents; } @@ -103,7 +112,7 @@ extern inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, * pci_unmap_single() above. */ extern inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, - int nents) + int nents,int direction) { /* Nothing to do */ } @@ -119,7 +128,7 @@ extern inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, */ extern inline void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, - size_t size) + size_t size,int direction) { /* Nothing to do */ } @@ -132,7 +141,7 @@ extern inline void pci_dma_sync_single(struct pci_dev *hwdev, */ extern inline void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, - int nelems) + int nelems,int direction) { /* Nothing to do */ } diff --git a/include/asm-sh/pgtable.h b/include/asm-sh/pgtable.h index 867cf06acbf5..df3e8edf2b8e 100644 --- a/include/asm-sh/pgtable.h +++ b/include/asm-sh/pgtable.h @@ -23,6 +23,7 @@ extern void paging_init(void); * - flush_cache_page(mm, vmaddr) flushes a single page * - flush_cache_range(mm, start, end) flushes a range of pages * + * - flush_dcache_page(pg) flushes(wback&invalidates) a page for dcache * - flush_page_to_ram(page) write back kernel page to ram * - flush_icache_range(start, end) flushes(invalidates) a range for icache * - flush_icache_page(vma, pg) flushes(invalidates) a page for icache @@ -48,6 +49,7 @@ extern void flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end); extern void flush_cache_page(struct vm_area_struct *vma, unsigned long addr); extern void flush_page_to_ram(struct page *page); +extern void flush_dcache_page(struct page *pg); extern void flush_icache_range(unsigned long start, unsigned long end); extern void flush_icache_page(struct vm_area_struct *vma, struct page *pg); #endif @@ -99,6 +101,9 @@ extern unsigned long empty_zero_page[1024]; #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 */ #if defined(__sh3__) /* Mask which drop software flags */ diff --git a/include/asm-sh/processor.h b/include/asm-sh/processor.h index 77cbe9c1ee88..38d8dbe7c9ec 100644 --- a/include/asm-sh/processor.h +++ b/include/asm-sh/processor.h @@ -21,7 +21,7 @@ * CPU type and hardware bug flags. Kept separately for each CPU. */ enum cpu_type { - CPU_SH7708, /* Represents 7708, 7708S, 7708R, 7709 */ + CPU_SH7708, /* Represents 7707, 7708, 7708S, 7708R, 7709 */ CPU_SH7729, /* Represents 7709A, 7729 */ CPU_SH7750, CPU_SH_NONE diff --git a/include/asm-sparc/page.h b/include/asm-sparc/page.h index c727c06d8a9e..47022fbba04c 100644 --- a/include/asm-sparc/page.h +++ b/include/asm-sparc/page.h @@ -177,7 +177,8 @@ extern __inline__ int get_order(unsigned long size) #define PAGE_OFFSET 0xf0000000 #define __pa(x) ((unsigned long)(x) - PAGE_OFFSET) #define __va(x) ((void *)((unsigned long) (x) + PAGE_OFFSET)) -#define MAP_NR(addr) (__pa(addr) >> PAGE_SHIFT) +#define virt_to_page(kaddr) (mem_map + (__pa(kaddr) >> PAGE_SHIFT)) +#define VALID_PAGE(page) ((page - mem_map) < max_mapnr) #endif /* __KERNEL__ */ diff --git a/include/asm-sparc/pgtable.h b/include/asm-sparc/pgtable.h index 5fc50713292b..2debbf084965 100644 --- a/include/asm-sparc/pgtable.h +++ b/include/asm-sparc/pgtable.h @@ -1,4 +1,4 @@ -/* $Id: pgtable.h,v 1.99 2000/08/05 13:30:34 davem Exp $ */ +/* $Id: pgtable.h,v 1.101 2000/08/09 00:00:17 davem Exp $ */ #ifndef _SPARC_PGTABLE_H #define _SPARC_PGTABLE_H @@ -147,9 +147,6 @@ extern pte_t pg3[1024]; extern unsigned long ptr_in_current_pgd; -/* the no. of pointers that fit on a page: this will go away */ -#define PTRS_PER_PAGE (PAGE_SIZE/sizeof(void*)) - /* Here is a trick, since mmap.c need the initializer elements for * protection_map[] to be constant at compile time, I set the following * to all zeros. I set it to the real values after I link in the diff --git a/include/asm-sparc64/mmu_context.h b/include/asm-sparc64/mmu_context.h index d6ef977d9aa8..ea7b83d5b6b8 100644 --- a/include/asm-sparc64/mmu_context.h +++ b/include/asm-sparc64/mmu_context.h @@ -1,4 +1,4 @@ -/* $Id: mmu_context.h,v 1.42 2000/02/08 07:47:03 davem Exp $ */ +/* $Id: mmu_context.h,v 1.43 2000/08/09 08:04:45 davem Exp $ */ #ifndef __SPARC64_MMU_CONTEXT_H #define __SPARC64_MMU_CONTEXT_H @@ -29,11 +29,9 @@ extern void get_new_mmu_context(struct mm_struct *mm); /* Initialize a new mmu context. This is invoked when a new * address space instance (unique or shared) is instantiated. - * A fresh mm_struct is cleared out to zeros, so this need not - * do anything on Sparc64 since the only thing we care about - * is that mm->context is an invalid context (ie. zero). + * This just needs to set mm->context to an invalid context. */ -#define init_new_context(__tsk, __mm) do { } while(0) +#define init_new_context(__tsk, __mm) ((__mm)->context = 0UL) /* Destroy a dead context. This occurs when mmput drops the * mm_users count to zero, the mmaps have been released, and diff --git a/include/asm-sparc64/page.h b/include/asm-sparc64/page.h index 79f4d7448a60..86bd2640298e 100644 --- a/include/asm-sparc64/page.h +++ b/include/asm-sparc64/page.h @@ -105,7 +105,8 @@ register unsigned long PAGE_OFFSET asm("g4"); #define __pa(x) ((unsigned long)(x) - PAGE_OFFSET) #define __va(x) ((void *)((unsigned long) (x) + PAGE_OFFSET)) -#define MAP_NR(addr) ((__pa(addr)-phys_base) >> PAGE_SHIFT) +#define virt_to_page(kaddr) (mem_map + ((__pa(kaddr)-phys_base) >> PAGE_SHIFT)) +#define VALID_PAGE(page) ((page - mem_map) < max_mapnr) #define virt_to_phys __pa #define phys_to_virt __va diff --git a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h index 3318578f36da..c47527736d84 100644 --- a/include/asm-sparc64/pgtable.h +++ b/include/asm-sparc64/pgtable.h @@ -1,4 +1,4 @@ -/* $Id: pgtable.h,v 1.128 2000/08/05 13:30:34 davem Exp $ +/* $Id: pgtable.h,v 1.130 2000/08/09 00:00:17 davem Exp $ * pgtable.h: SpitFire page table operations. * * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -57,9 +57,6 @@ #define PMD_TABLE_SIZE 0x2000 /* 2048 entries 4 bytes each */ #define PGD_TABLE_SIZE 0x1000 /* 1024 entries 4 bytes each */ -/* the no. of pointers that fit on a page */ -#define PTRS_PER_PAGE (1UL << (PAGE_SHIFT-3)) - /* NOTE: TLB miss handlers depend heavily upon where this is. */ #define VMALLOC_START 0x0000000140000000UL #define VMALLOC_VMADDR(x) ((unsigned long)(x)) diff --git a/include/asm-sparc64/processor.h b/include/asm-sparc64/processor.h index 37433eace43f..eae8b7bdb62b 100644 --- a/include/asm-sparc64/processor.h +++ b/include/asm-sparc64/processor.h @@ -1,4 +1,4 @@ -/* $Id: processor.h,v 1.64 2000/05/09 17:40:15 davem Exp $ +/* $Id: processor.h,v 1.65 2000/08/09 00:00:17 davem Exp $ * include/asm-sparc64/processor.h * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) diff --git a/include/linux/blk.h b/include/linux/blk.h index ce00d0602ae2..778617529036 100644 --- a/include/linux/blk.h +++ b/include/linux/blk.h @@ -85,7 +85,7 @@ void initrd_init(void); * code duplication in drivers. */ -extern inline void blkdev_dequeue_request(struct request * req) +static inline void blkdev_dequeue_request(struct request * req) { if (req->e) { req->e->dequeue_fn(req); @@ -99,6 +99,9 @@ void end_that_request_last(struct request *req); #if defined(MAJOR_NR) || defined(IDE_DRIVER) +#undef DEVICE_ON +#undef DEVICE_OFF + /* * Add entries as needed. */ @@ -106,8 +109,6 @@ void end_that_request_last(struct request *req); #ifdef IDE_DRIVER #define DEVICE_NR(device) (MINOR(device) >> PARTN_BITS) -#define DEVICE_ON(device) /* nothing */ -#define DEVICE_OFF(device) /* nothing */ #define DEVICE_NAME "ide" #elif (MAJOR_NR == RAMDISK_MAJOR) @@ -116,8 +117,6 @@ void end_that_request_last(struct request *req); #define DEVICE_NAME "ramdisk" #define DEVICE_REQUEST rd_request #define DEVICE_NR(device) (MINOR(device)) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) #define DEVICE_NO_RANDOM #elif (MAJOR_NR == Z2RAM_MAJOR) @@ -126,8 +125,6 @@ void end_that_request_last(struct request *req); #define DEVICE_NAME "Z2RAM" #define DEVICE_REQUEST do_z2_request #define DEVICE_NR(device) (MINOR(device)) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) #elif (MAJOR_NR == FLOPPY_MAJOR) @@ -137,7 +134,6 @@ static void floppy_off(unsigned int nr); #define DEVICE_INTR do_floppy #define DEVICE_REQUEST do_fd_request #define DEVICE_NR(device) ( (MINOR(device) & 3) | ((MINOR(device) & 0x80 ) >> 5 )) -#define DEVICE_ON(device) #define DEVICE_OFF(device) floppy_off(DEVICE_NR(device)) #elif (MAJOR_NR == HD_MAJOR) @@ -148,16 +144,12 @@ static void floppy_off(unsigned int nr); #define TIMEOUT_VALUE (6*HZ) #define DEVICE_REQUEST do_hd_request #define DEVICE_NR(device) (MINOR(device)>>6) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) #elif (SCSI_DISK_MAJOR(MAJOR_NR)) #define DEVICE_NAME "scsidisk" #define TIMEOUT_VALUE (2*HZ) #define DEVICE_NR(device) (((MAJOR(device) & SD_MAJOR_MASK) << (8 - 4)) + (MINOR(device) >> 4)) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) /* Kludge to use the same number for both char and block major numbers */ #elif (MAJOR_NR == MD_MAJOR) && defined(MD_DRIVER) @@ -165,47 +157,35 @@ static void floppy_off(unsigned int nr); #define DEVICE_NAME "Multiple devices driver" #define DEVICE_REQUEST do_md_request #define DEVICE_NR(device) (MINOR(device)) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) #elif (MAJOR_NR == SCSI_TAPE_MAJOR) #define DEVICE_NAME "scsitape" #define DEVICE_INTR do_st #define DEVICE_NR(device) (MINOR(device) & 0x7f) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) #elif (MAJOR_NR == SCSI_CDROM_MAJOR) #define DEVICE_NAME "CD-ROM" #define DEVICE_NR(device) (MINOR(device)) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) #elif (MAJOR_NR == XT_DISK_MAJOR) #define DEVICE_NAME "xt disk" #define DEVICE_REQUEST do_xd_request #define DEVICE_NR(device) (MINOR(device) >> 6) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) #elif (MAJOR_NR == PS2ESDI_MAJOR) #define DEVICE_NAME "PS/2 ESDI" #define DEVICE_REQUEST do_ps2esdi_request #define DEVICE_NR(device) (MINOR(device) >> 6) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) #elif (MAJOR_NR == CDU31A_CDROM_MAJOR) #define DEVICE_NAME "CDU31A" #define DEVICE_REQUEST do_cdu31a_request #define DEVICE_NR(device) (MINOR(device)) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) #elif (MAJOR_NR == ACSI_MAJOR) && (defined(CONFIG_ATARI_ACSI) || defined(CONFIG_ATARI_ACSI_MODULE)) @@ -213,8 +193,6 @@ static void floppy_off(unsigned int nr); #define DEVICE_INTR do_acsi #define DEVICE_REQUEST do_acsi_request #define DEVICE_NR(device) (MINOR(device) >> 4) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) #elif (MAJOR_NR == MITSUMI_CDROM_MAJOR) @@ -222,8 +200,6 @@ static void floppy_off(unsigned int nr); /* #define DEVICE_INTR do_mcd */ #define DEVICE_REQUEST do_mcd_request #define DEVICE_NR(device) (MINOR(device)) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) #elif (MAJOR_NR == MITSUMI_X_CDROM_MAJOR) @@ -231,48 +207,36 @@ static void floppy_off(unsigned int nr); /* #define DEVICE_INTR do_mcdx */ #define DEVICE_REQUEST do_mcdx_request #define DEVICE_NR(device) (MINOR(device)) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) #elif (MAJOR_NR == MATSUSHITA_CDROM_MAJOR) #define DEVICE_NAME "Matsushita CD-ROM controller #1" #define DEVICE_REQUEST do_sbpcd_request #define DEVICE_NR(device) (MINOR(device)) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) #elif (MAJOR_NR == MATSUSHITA_CDROM2_MAJOR) #define DEVICE_NAME "Matsushita CD-ROM controller #2" #define DEVICE_REQUEST do_sbpcd2_request #define DEVICE_NR(device) (MINOR(device)) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) #elif (MAJOR_NR == MATSUSHITA_CDROM3_MAJOR) #define DEVICE_NAME "Matsushita CD-ROM controller #3" #define DEVICE_REQUEST do_sbpcd3_request #define DEVICE_NR(device) (MINOR(device)) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) #elif (MAJOR_NR == MATSUSHITA_CDROM4_MAJOR) #define DEVICE_NAME "Matsushita CD-ROM controller #4" #define DEVICE_REQUEST do_sbpcd4_request #define DEVICE_NR(device) (MINOR(device)) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) #elif (MAJOR_NR == AZTECH_CDROM_MAJOR) #define DEVICE_NAME "Aztech CD-ROM" #define DEVICE_REQUEST do_aztcd_request #define DEVICE_NR(device) (MINOR(device)) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) #elif (MAJOR_NR == CDU535_CDROM_MAJOR) @@ -280,55 +244,41 @@ static void floppy_off(unsigned int nr); #define DEVICE_INTR do_cdu535 #define DEVICE_REQUEST do_cdu535_request #define DEVICE_NR(device) (MINOR(device)) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) #elif (MAJOR_NR == GOLDSTAR_CDROM_MAJOR) #define DEVICE_NAME "Goldstar R420" #define DEVICE_REQUEST do_gscd_request #define DEVICE_NR(device) (MINOR(device)) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) #elif (MAJOR_NR == CM206_CDROM_MAJOR) #define DEVICE_NAME "Philips/LMS CD-ROM cm206" #define DEVICE_REQUEST do_cm206_request #define DEVICE_NR(device) (MINOR(device)) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) #elif (MAJOR_NR == OPTICS_CDROM_MAJOR) #define DEVICE_NAME "DOLPHIN 8000AT CD-ROM" #define DEVICE_REQUEST do_optcd_request #define DEVICE_NR(device) (MINOR(device)) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) #elif (MAJOR_NR == SANYO_CDROM_MAJOR) #define DEVICE_NAME "Sanyo H94A CD-ROM" #define DEVICE_REQUEST do_sjcd_request #define DEVICE_NR(device) (MINOR(device)) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) #elif (MAJOR_NR == APBLOCK_MAJOR) #define DEVICE_NAME "apblock" #define DEVICE_REQUEST ap_request #define DEVICE_NR(device) (MINOR(device)) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) #elif (MAJOR_NR == DDV_MAJOR) #define DEVICE_NAME "ddv" #define DEVICE_REQUEST ddv_request #define DEVICE_NR(device) (MINOR(device)>>PARTN_BITS) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) #elif (MAJOR_NR == MFM_ACORN_MAJOR) @@ -336,41 +286,30 @@ static void floppy_off(unsigned int nr); #define DEVICE_INTR do_mfm #define DEVICE_REQUEST do_mfm_request #define DEVICE_NR(device) (MINOR(device) >> 6) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) #elif (MAJOR_NR == NBD_MAJOR) #define DEVICE_NAME "nbd" #define DEVICE_REQUEST do_nbd_request #define DEVICE_NR(device) (MINOR(device)) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) - #elif (MAJOR_NR == MDISK_MAJOR) #define DEVICE_NAME "mdisk" #define DEVICE_REQUEST mdisk_request #define DEVICE_NR(device) (MINOR(device)) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) #elif (MAJOR_NR == DASD_MAJOR) #define DEVICE_NAME "dasd" #define DEVICE_REQUEST do_dasd_request #define DEVICE_NR(device) (MINOR(device) >> PARTN_BITS) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) #elif (MAJOR_NR == I2O_MAJOR) #define DEVICE_NAME "I2O block" #define DEVICE_REQUEST do_i2ob_request #define DEVICE_NR(device) (MINOR(device)>>4) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) #elif (MAJOR_NR == COMPAQ_SMART2_MAJOR) @@ -378,11 +317,18 @@ static void floppy_off(unsigned int nr); #define TIMEOUT_VALUE (25*HZ) #define DEVICE_REQUEST do_ida_request0 #define DEVICE_NR(device) (MINOR(device) >> 4) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) #endif /* MAJOR_NR == whatever */ +/* provide DEVICE_xxx defaults, if not explicitly defined + * above in the MAJOR_NR==xxx if-elif tree */ +#ifndef DEVICE_ON +#define DEVICE_ON(device) do {} while (0) +#endif +#ifndef DEVICE_OFF +#define DEVICE_OFF(device) do {} while (0) +#endif + #if (MAJOR_NR != SCSI_TAPE_MAJOR) #if !defined(IDE_DRIVER) @@ -434,7 +380,7 @@ static void (DEVICE_REQUEST)(request_queue_t *); #if ! SCSI_BLK_MAJOR(MAJOR_NR) && (MAJOR_NR != COMPAQ_SMART2_MAJOR) -static void end_request(int uptodate) { +static inline void end_request(int uptodate) { struct request *req = CURRENT; if (end_that_request_first(req, uptodate, DEVICE_NAME)) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 44853fbe78fe..851bf3c534fe 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -150,8 +150,7 @@ extern struct sec_size * blk_sec[MAX_BLKDEV]; extern struct blk_dev_struct blk_dev[MAX_BLKDEV]; extern void grok_partitions(struct gendisk *dev, int drive, unsigned minors, long size); extern void register_disk(struct gendisk *dev, kdev_t first, unsigned minors, struct block_device_operations *ops, long size); -extern void generic_make_request(request_queue_t *q, int rw, - struct buffer_head * bh); +extern void generic_make_request(int rw, struct buffer_head * bh); extern request_queue_t *blk_get_queue(kdev_t dev); extern void blkdev_release_request(struct request *); diff --git a/include/linux/brlock.h b/include/linux/brlock.h index e68940b0f913..2fd39cac9ef4 100644 --- a/include/linux/brlock.h +++ b/include/linux/brlock.h @@ -77,7 +77,7 @@ extern void __br_lock_usage_bug (void); #ifdef __BRLOCK_USE_ATOMICS -extern inline void br_read_lock (enum brlock_indices idx) +static inline void br_read_lock (enum brlock_indices idx) { /* * This causes a link-time bug message if an @@ -89,7 +89,7 @@ extern inline void br_read_lock (enum brlock_indices idx) read_lock(&__brlock_array[smp_processor_id()][idx]); } -extern inline void br_read_unlock (enum brlock_indices idx) +static inline void br_read_unlock (enum brlock_indices idx) { if (idx >= __BR_END) __br_lock_usage_bug(); @@ -98,7 +98,7 @@ extern inline void br_read_unlock (enum brlock_indices idx) } #else /* ! __BRLOCK_USE_ATOMICS */ -extern inline void br_read_lock (enum brlock_indices idx) +static inline void br_read_lock (enum brlock_indices idx) { unsigned int *ctr; spinlock_t *lock; @@ -124,7 +124,7 @@ again: } } -extern inline void br_read_unlock (enum brlock_indices idx) +static inline void br_read_unlock (enum brlock_indices idx) { unsigned int *ctr; @@ -143,14 +143,14 @@ extern inline void br_read_unlock (enum brlock_indices idx) extern void FASTCALL(__br_write_lock (enum brlock_indices idx)); extern void FASTCALL(__br_write_unlock (enum brlock_indices idx)); -extern inline void br_write_lock (enum brlock_indices idx) +static inline void br_write_lock (enum brlock_indices idx) { if (idx >= __BR_END) __br_lock_usage_bug(); __br_write_lock(idx); } -extern inline void br_write_unlock (enum brlock_indices idx) +static inline void br_write_unlock (enum brlock_indices idx) { if (idx >= __BR_END) __br_lock_usage_bug(); diff --git a/include/linux/highmem.h b/include/linux/highmem.h index bde78147519f..3cd0250eed7a 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -32,7 +32,7 @@ static __inline__ unsigned long kmap(struct page * page) { #endif /* CONFIG_HIGHMEM */ /* when CONFIG_HIGHMEM is not set these will be plain clear/copy_page */ -extern inline void clear_user_highpage(struct page *page, unsigned long vaddr) +static inline void clear_user_highpage(struct page *page, unsigned long vaddr) { unsigned long kaddr; @@ -41,7 +41,7 @@ extern inline void clear_user_highpage(struct page *page, unsigned long vaddr) kunmap(page); } -extern inline void clear_highpage(struct page *page) +static inline void clear_highpage(struct page *page) { unsigned long kaddr; @@ -50,7 +50,7 @@ extern inline void clear_highpage(struct page *page) kunmap(page); } -extern inline void memclear_highpage(struct page *page, unsigned int offset, unsigned int size) +static inline void memclear_highpage(struct page *page, unsigned int offset, unsigned int size) { unsigned long kaddr; @@ -64,7 +64,7 @@ extern inline void memclear_highpage(struct page *page, unsigned int offset, uns /* * Same but also flushes aliased cache contents to RAM. */ -extern inline void memclear_highpage_flush(struct page *page, unsigned int offset, unsigned int size) +static inline void memclear_highpage_flush(struct page *page, unsigned int offset, unsigned int size) { unsigned long kaddr; @@ -76,7 +76,7 @@ extern inline void memclear_highpage_flush(struct page *page, unsigned int offse kunmap(page); } -extern inline void copy_user_highpage(struct page *to, struct page *from, unsigned long vaddr) +static inline void copy_user_highpage(struct page *to, struct page *from, unsigned long vaddr) { unsigned long vfrom, vto; @@ -87,7 +87,7 @@ extern inline void copy_user_highpage(struct page *to, struct page *from, unsign kunmap(to); } -extern inline void copy_highpage(struct page *to, struct page *from) +static inline void copy_highpage(struct page *to, struct page *from) { unsigned long vfrom, vto; diff --git a/include/linux/jffs.h b/include/linux/jffs.h index 07621e2d55b5..61e7b66fe39b 100644 --- a/include/linux/jffs.h +++ b/include/linux/jffs.h @@ -1,14 +1,16 @@ /* * JFFS -- Journalling Flash File System, Linux implementation. * - * Copyright (C) 1999, 2000 Finn Hakansson, Axis Communications, Inc. + * Copyright (C) 1999, 2000 Axis Communications AB. + * + * Created by Finn Hakansson . * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * $Id: jffs.h,v 1.5 2000/06/13 14:22:48 alex Exp $ + * $Id: jffs.h,v 1.11 2000/08/04 12:46:34 dwmw2 Exp $ * * Ported to Linux 2.3.x and MTD: * Copyright (C) 2000 Alexander Larsson (alex@cendio.se), Cendio Systems AB @@ -59,9 +61,6 @@ #define JFFS_MODIFY_DATA 0x04 #define JFFS_MODIFY_EXIST 0x08 -/* Using the garbage collection mechanism. */ -#define USE_GC - struct jffs_control; /* The JFFS raw inode structure: Used for storage on physical media. */ @@ -87,7 +86,7 @@ struct jffs_raw_inode __u8 nsize; /* Name length. */ __u8 nlink; /* Number of links. */ __u8 spare : 6; /* For future use. */ - __u8 rename : 1; /* Is this a special rename? */ + __u8 rename : 1; /* Rename to a name of an already existing file? */ __u8 deleted : 1; /* Has this file been deleted? */ __u8 accurate; /* The inode is obsolete if accurate == 0. */ __u32 dchksum; /* Checksum for the data. */ @@ -161,17 +160,34 @@ struct jffs_file }; +/* This is just a definition of a simple list used for keeping track of + files deleted due to a rename. This list is only used during the + mounting of the file system and only if there have been rename operations + earlier. */ +struct jffs_delete_list +{ + __u32 ino; + struct jffs_delete_list *next; +}; + + /* A struct for the overall file system control. Pointers to jffs_control structs are named `c' in the source code. */ struct jffs_control { - struct super_block *sb; /* Reference to the VFS super block. */ - struct jffs_file *root; /* The root directory file. */ - struct list_head *hash; /* Hash table for finding files by ino. */ - struct jffs_fmcontrol *fmc; /* Flash memory control structure. */ - __u32 hash_len; /* The size of the hash table. */ - __u32 next_ino; /* Next inode number to use for new files. */ - __u16 building_fs; /* Is the file system being built right now? */ + struct super_block *sb; /* Reference to the VFS super block. */ + struct jffs_file *root; /* The root directory file. */ + struct list_head *hash; /* Hash table for finding files by ino. */ + struct jffs_fmcontrol *fmc; /* Flash memory control structure. */ + __u32 hash_len; /* The size of the hash table. */ + __u32 next_ino; /* Next inode number to use for new files. */ + __u16 building_fs; /* Is the file system being built right now? */ + struct jffs_delete_list *delete_list; /* Track deleted files. */ + pid_t thread_pid; /* GC thread's PID */ + struct task_struct *gc_task; /* GC task struct */ + struct semaphore gc_thread_sem; /* GC thread exit mutex */ + __u32 gc_minfree_threshold; /* GC trigger thresholds */ + __u32 gc_maxdirty_threshold; }; diff --git a/include/linux/mm.h b/include/linux/mm.h index 94e30f7c7a6c..a248e939f749 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -338,9 +338,6 @@ extern unsigned long FASTCALL(get_zeroed_page(int gfp_mask)); #define __get_dma_pages(gfp_mask, order) \ __get_free_pages((gfp_mask) | GFP_DMA,(order)) -#define virt_to_page(kaddr) (mem_map + MAP_NR(kaddr)) -#define VALID_PAGE(page) ((page - mem_map) < max_mapnr) - /* * The old interface name will be removed in 2.5: */ diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 9f445ec6a293..f12c936d8874 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -677,9 +677,9 @@ #define PCI_DEVICE_ID_TTI_HPT366 0x0004 #define PCI_VENDOR_ID_VIA 0x1106 +#define PCI_DEVICE_ID_VIA_8363_0 0x0305 #define PCI_DEVICE_ID_VIA_8371_0 0x0391 #define PCI_DEVICE_ID_VIA_8501_0 0x0501 -#define PCI_DEVICE_ID_VIA_8601_0 0x0601 #define PCI_DEVICE_ID_VIA_82C505 0x0505 #define PCI_DEVICE_ID_VIA_82C561 0x0561 #define PCI_DEVICE_ID_VIA_82C586_1 0x0571 @@ -690,25 +690,41 @@ #define PCI_DEVICE_ID_VIA_82C596 0x0596 #define PCI_DEVICE_ID_VIA_82C597_0 0x0597 #define PCI_DEVICE_ID_VIA_82C598_0 0x0598 +#define PCI_DEVICE_ID_VIA_8601_0 0x0601 +#define PCI_DEVICE_ID_VIA_8605_0 0x0605 #define PCI_DEVICE_ID_VIA_82C680 0x0680 #define PCI_DEVICE_ID_VIA_82C686 0x0686 #define PCI_DEVICE_ID_VIA_82C691 0x0691 #define PCI_DEVICE_ID_VIA_82C693 0x0693 +#define PCI_DEVICE_ID_VIA_82C693_1 0x0698 #define PCI_DEVICE_ID_VIA_82C926 0x0926 #define PCI_DEVICE_ID_VIA_82C416 0x1571 #define PCI_DEVICE_ID_VIA_82C595_97 0x1595 #define PCI_DEVICE_ID_VIA_82C586_2 0x3038 #define PCI_DEVICE_ID_VIA_82C586_3 0x3040 +#define PCI_DEVICE_ID_VIA_6305 0x3044 +#define PCI_DEVICE_ID_VIA_82C596_3 0x3050 +#define PCI_DEVICE_ID_VIA_82C596B_3 0x3051 #define PCI_DEVICE_ID_VIA_82C686_4 0x3057 #define PCI_DEVICE_ID_VIA_82C686_5 0x3058 +#define PCI_DEVICE_ID_VIA_8233_5 0x3059 +#define PCI_DEVICE_ID_VIA_8233_7 0x3065 #define PCI_DEVICE_ID_VIA_82C686_6 0x3068 +#define PCI_DEVICE_ID_VIA_8233_0 0x3074 +#define PCI_DEVICE_ID_VIA_8633_0 0x3091 +#define PCI_DEVICE_ID_VIA_8367_0 0x3099 #define PCI_DEVICE_ID_VIA_86C100A 0x6100 #define PCI_DEVICE_ID_VIA_8231 0x8231 +#define PCI_DEVICE_ID_VIA_8231_4 0x8235 +#define PCI_DEVICE_ID_VIA_8365_1 0x8305 #define PCI_DEVICE_ID_VIA_8371_1 0x8391 #define PCI_DEVICE_ID_VIA_8501_1 0x8501 #define PCI_DEVICE_ID_VIA_82C597_1 0x8597 #define PCI_DEVICE_ID_VIA_82C598_1 0x8598 #define PCI_DEVICE_ID_VIA_8601_1 0x8601 +#define PCI_DEVICE_ID_VIA_8505_1 0X8605 +#define PCI_DEVICE_ID_VIA_8633_1 0xB091 +#define PCI_DEVICE_ID_VIA_8367_1 0xB099 #define PCI_VENDOR_ID_SMC2 0x1113 #define PCI_DEVICE_ID_SMC2_1211TX 0x1211 diff --git a/include/video/fbcon.h b/include/video/fbcon.h index e5f26faa4535..332cabf7e4f6 100644 --- a/include/video/fbcon.h +++ b/include/video/fbcon.h @@ -681,32 +681,37 @@ static __inline__ void *fb_memmove(void *d, const void *s, size_t count) while (count--) fb_writeb(fb_readb(src++), dst++); } else { - dst = (unsigned long) d + count - 1; - src = (unsigned long) s + count - 1; + dst = (unsigned long) d + count; + src = (unsigned long) s + count; if ((count < 8) || ((dst ^ src) & 3)) goto restdown; if (dst & 1) { - fb_writeb(fb_readb(src--), dst--); + src--; + dst--; count--; + fb_writeb(fb_readb(src), dst); } if (dst & 2) { - fb_writew(fb_readw(src), dst); src -= 2; dst -= 2; count -= 2; + fb_writew(fb_readw(src), dst); } while (count > 3) { - fb_writel(fb_readl(src), dst); src -= 4; dst -= 4; count -= 4; + fb_writel(fb_readl(src), dst); } restdown: - while (count--) - fb_writeb(fb_readb(src--), dst--); + while (count--) { + src--; + dst--; + fb_writeb(fb_readb(src), dst); + } } return d; @@ -744,32 +749,37 @@ static __inline__ void fast_memmove(char *d, const char *s, size_t count) while (count--) fb_writeb(fb_readb(src++), dst++); } else { - dst = (unsigned long) d + count - 1; - src = (unsigned long) s + count - 1; + dst = (unsigned long) d + count; + src = (unsigned long) s + count; if ((count < 8) || ((dst ^ src) & 3)) goto restdown; if (dst & 1) { - fb_writeb(fb_readb(src--), dst--); + src--; + dst--; count--; + fb_writeb(fb_readb(src), dst); } if (dst & 2) { - fb_writew(fb_readw(src), dst); src -= 2; dst -= 2; count -= 2; + fb_writew(fb_readw(src), dst); } while (count > 3) { - fb_writel(fb_readl(src), dst); src -= 4; dst -= 4; count -= 4; + fb_writel(fb_readl(src), dst); } restdown: - while (count--) - fb_writeb(fb_readb(src--), dst--); + while (count--) { + src--; + dst--; + fb_writeb(fb_readb(src), dst); + } } } diff --git a/kernel/fork.c b/kernel/fork.c index f77eaa4eefc0..641de8b220f2 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -131,6 +131,7 @@ static inline int dup_mmap(struct mm_struct * mm) flush_cache_mm(current->mm); mm->locked_vm = 0; mm->mmap = NULL; + mm->mmap_avl = NULL; mm->mmap_cache = NULL; mm->map_count = 0; mm->context = 0; @@ -301,7 +302,6 @@ static inline int copy_mm(unsigned long clone_flags, struct task_struct * tsk) } retval = -ENOMEM; - mm = mm_alloc(); mm = allocate_mm(); if (!mm) goto fail_nomem; diff --git a/kernel/timer.c b/kernel/timer.c index 92d8af4b5109..6b8538715ebf 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -163,9 +163,9 @@ static inline void internal_add_timer(struct timer_list *timer) /* Initialize both explicitly - let's try to have them in the same cache line */ spinlock_t timerlist_lock = SPIN_LOCK_UNLOCKED; -volatile struct timer_list * volatile running_timer = NULL; #ifdef CONFIG_SMP +volatile struct timer_list * volatile running_timer = NULL; #define timer_enter(t) do { running_timer = t; mb(); } while (0) #define timer_exit() do { running_timer = NULL; } while (0) #define timer_is_running(t) (running_timer == t) @@ -173,8 +173,6 @@ volatile struct timer_list * volatile running_timer = NULL; #else #define timer_enter(t) do { } while (0) #define timer_exit() do { } while (0) -#define timer_is_running(t) (0) -#define timer_synchronize(t) do { (void)(t); barrier(); } while(0) #endif void add_timer(struct timer_list *timer) diff --git a/net/atm/mpc.c b/net/atm/mpc.c index 68cd8a034cf1..cb6179483cb4 100644 --- a/net/atm/mpc.c +++ b/net/atm/mpc.c @@ -166,7 +166,7 @@ struct atm_mpoa_qos *atm_mpoa_add_qos(uint32_t dst_ip, struct atm_qos *qos) return entry; } - entry = kmalloc(sizeof(struct atm_qos), GFP_KERNEL); + entry = kmalloc(sizeof(struct atm_mpoa_qos), GFP_KERNEL); if (entry == NULL) { printk("mpoa: atm_mpoa_add_qos: out of memory\n"); return entry; diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 53e664444588..b511e29fd5b1 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -5,7 +5,7 @@ * * The options processing module for ip.c * - * Version: $Id: ip_options.c,v 1.19 2000/07/26 01:04:17 davem Exp $ + * Version: $Id: ip_options.c,v 1.20 2000/08/09 09:17:00 davem Exp $ * * Authors: A.N.Kuznetsov * @@ -498,8 +498,10 @@ int ip_options_get(struct ip_options **optp, unsigned char *data, int optlen, in memset(opt, 0, sizeof(struct ip_options)); if (optlen) { if (user) { - if (copy_from_user(opt->__data, data, optlen)) + if (copy_from_user(opt->__data, data, optlen)) { + kfree(opt); return -EFAULT; + } } else memcpy(opt->__data, data, optlen); } diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index bf557e2537cb..7a484606bbae 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -5,7 +5,7 @@ * * PACKET - implements raw packet sockets. * - * Version: $Id: af_packet.c,v 1.37 2000/07/26 01:04:21 davem Exp $ + * Version: $Id: af_packet.c,v 1.39 2000/08/09 08:04:45 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, diff --git a/net/socket.c b/net/socket.c index 2993991dd480..f0565ed3e259 100644 --- a/net/socket.c +++ b/net/socket.c @@ -1372,7 +1372,6 @@ asmlinkage long sys_sendmsg(int fd, struct msghdr *msg, unsigned flags) { if (ctl_len > sizeof(ctl)) { - err = -ENOBUFS; ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL); if (ctl_buf == NULL) goto out_freeiov; -- 2.39.5