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
#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 \
int __init page_is_ram(unsigned long pagenr)
{
- if (pagenr < MAP_NR(PAGE_OFFSET + 0x2000UL))
+ if ((pagenr<<PAGE_SHIFT) < 0x2000UL)
return 1;
- if (pagenr > MAP_NR(PAGE_OFFSET + 0x08002000))
+ if ((pagenr<<PAGE_SHIFT) > 0x08002000)
return 1;
return 0;
}
int __init page_is_ram(unsigned long pagenr)
{
- if (pagenr < MAP_NR(PAGE_OFFSET + 0x2000UL))
+ if ((pagenr<<PAGE_SHIFT) < 0x2000UL)
return 1;
- if (pagenr > MAP_NR(PAGE_OFFSET + 0x08002000))
+ if ((pagenr<<PAGE_SHIFT) > 0x08002000)
return 1;
return 0;
}
#
# 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)
.global startup
startup:
+ /* Load initial status register */
+ mov.l init_sr, r1
+ ldc r1, sr
/* First clear BSS */
mov.l end_addr, r1
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
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:
"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
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
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
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
# 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
# CONFIG_CPU_SH4 is not set
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_MEMORY_START=0c000000
-CONFIG_IOPORT_START=ba000000
#
# General setup
# Unix 98 PTY support
#
# CONFIG_UNIX98_PTYS is not set
+# CONFIG_HEARTBEAT is not set
#
# File systems
# 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
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 :=
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
#include <asm/io.h>
#include <asm/irq.h>
-#ifdef CONFIG_SH_SOLUTION_ENGINE
#include <asm/hitachi_se.h>
+
+
/*
+ * 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 */
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!
*/
/*
* 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);
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);
#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
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:
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
.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
.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
--- /dev/null
+/*
+ * 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 <linux/config.h>
+#include <asm/io.h>
+
+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++;
+ }
+}
*
* 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
#include <linux/config.h>
#include <asm/io.h>
+#include <asm/machvec.h>
#if defined(__sh3__)
/* I'm not sure SH7709 has this kind of bug */
#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);
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);
#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);
#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);
#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);
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;
+}
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);
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);
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);
return (*port2adr(port))&0xff;
}
-unsigned long inb_p(unsigned int port)
+unsigned long se_inb_p(unsigned int port)
{
unsigned long v;
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))
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;
*(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;
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))
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);
}
}
-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);
}
}
-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;
+}
\f
/* 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;
}
unsigned long
-sh_isa_slot(unsigned long offset)
+se_isa_port2addr(unsigned long offset)
{
int idx;
--- /dev/null
+/*
+ * 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)
#include <asm/irq.h>
#include <linux/irq.h>
-#ifdef CONFIG_HD64461
-#include <asm/hd64461.h>
-#endif
-
/*
* Micro-access to controllers is serialized over the whole
* system. We never hold this lock when we call the actual
* Generic, controller-independent functions:
*/
+#if defined(CONFIG_PROC_FS)
int get_irq_list(char *buf)
{
int i, j;
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;
}
return p - buf;
}
+#endif
/*
* This should really return information about whether
"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;
int retval;
struct irqaction * action;
- if (irq >= NR_IRQS)
+ if (irq >= ACTUAL_NR_IRQS)
return -EINVAL;
if (!handler)
return -EINVAL;
struct irqaction **p;
unsigned long flags;
- if (irq >= NR_IRQS)
+ if (irq >= ACTUAL_NR_IRQS)
return;
spin_lock_irqsave(&irq_controller_lock,flags);
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;
}
}
if (!(status & IRQ_AUTODETECT))
continue;
-
+
/* It triggered already - consider it spurious. */
if (!(status & IRQ_WAITING)) {
irq_desc[i].status = status & ~IRQ_AUTODETECT;
*
*/
+/* NOTE: Will not work on level 15 */
+
+
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/kernel_stat.h>
: "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)
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/machvec.h>
struct ipr_data {
unsigned int addr; /* Address of Interrupt Priority Register */
};
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
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;
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) {
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
* 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();
+ }
}
--- /dev/null
+/*
+ * linux/arch/sh/kernel/led_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.
+ *
+ * This file contains Solution Engine specific LED code.
+ */
+
+#include <linux/config.h>
+
+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 <linux/sched.h>
+
+/* 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<<FSHIFT)/
+ ((avenrun[0]/5) + (3<<FSHIFT)) );
+
+ if (up) {
+ if (bit == 7) {
+ bit--;
+ up=0;
+ } else {
+ bit ++;
+ }
+ } else {
+ if (bit == 0) {
+ bit++;
+ up=1;
+ } else {
+ bit--;
+ }
+ }
+ *p = 1<<(bit+8);
+
+}
+#endif /* CONFIG_HEARTBEAT */
--- /dev/null
+/*
+ * linux/arch/sh/kernel/mach_hp600.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 HP600
+ */
+
+#include <linux/init.h>
+
+#include <asm/machvec.h>
+#include <asm/machvec_init.h>
+
+#include <asm/io_hd64461.h>
+#include <asm/io_generic.h>
+#include <asm/irq.h>
+
+/*
+ * 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)
--- /dev/null
+/*
+ * 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 <linux/init.h>
+
+#include <asm/machvec.h>
+#include <asm/machvec_init.h>
+
+#include <asm/io_se.h>
+
+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)
--- /dev/null
+/*
+ * 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 <linux/init.h>
+
+#include <asm/machvec.h>
+#include <asm/machvec_init.h>
+
+#include <asm/io_unknown.h>
+
+/*
+ * 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)
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/errno.h>
+#include <asm/machvec.h>
-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}
+};
#include <asm/semaphore.h>
#include <asm/semaphore-helper.h>
+spinlock_t semaphore_wake_lock;
+
/*
* Semaphores are implemented using a two-way counter:
* The "count" variable is decremented for each process
#endif
#include <linux/bootmem.h>
#include <linux/console.h>
+#include <linux/ctype.h>
#include <asm/processor.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/io_generic.h>
#include <asm/smp.h>
+#include <asm/machvec.h>
#ifdef CONFIG_SH_EARLY_PRINTK
#include <asm/sh_bios.h>
#endif
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
*/
#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;
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;
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;
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)
#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;
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;
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", \
return p - buffer;
}
+#endif
--- /dev/null
+/* $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 <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/io.h>
+#include <asm/io_generic.h>
+#include <asm/irq.h>
+#include <asm/machvec.h>
+#include <asm/machvec_init.h>
+
+#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
+\f
+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<<irq), BRIDGE_ISA_INTR_STAT);
+#endif
+}
+
+static void end_cqreek_irq(unsigned int irq)
+{
+#ifndef CLEAR_AT_ACCEPT
+ /* Clear IRQ (it might be edge IRQ) */
+ outw_p((1<<irq), BRIDGE_ISA_INTR_STAT);
+#endif
+ enable_cqreek_irq(irq);
+}
+
+static unsigned int startup_cqreek_irq(unsigned int irq)
+{
+ enable_cqreek_irq(irq);
+ return 0;
+}
+
+static void shutdown_cqreek_irq(unsigned int irq)
+{
+ disable_cqreek_irq(irq);
+}
+
+static struct hw_interrupt_type cqreek_irq_type = {
+ "CQREEK-IRQ",
+ startup_cqreek_irq,
+ shutdown_cqreek_irq,
+ enable_cqreek_irq,
+ disable_cqreek_irq,
+ mask_and_ack_cqreek,
+ end_cqreek_irq
+};
+
+static int has_ide, has_isa;
+
+/* XXX: This is just for test for my NE2000 ISA board
+ What we really need is virtualized IRQ and demultiplexer like HP600 port */
+void __init init_cqreek_IRQ(void)
+{
+ if (has_ide)
+ make_ipr_irq(14, IDE_OFFSET+BRIDGE_IDE_INTR_LVL, 0, 0x0f-14);
+
+ if (has_isa) {
+ /* XXX: Err... we may need demultiplexer for ISA irq... */
+ irq_desc[10].handler = &cqreek_irq_type;
+ irq_desc[10].status = IRQ_DISABLED;
+ irq_desc[10].action = 0;
+ irq_desc[10].depth = 1;
+
+ disable_cqreek_irq(10);
+ }
+}
+
+/*
+ * Initialize the board
+ */
+void __init setup_cqreek(void)
+{
+ int i;
+/* udelay is not available at setup time yet... */
+#define DELAY() do {for (i=0; i<10000; i++) ctrl_inw(0xa0000000);} while(0)
+
+ if ((inw (BRIDGE_FEATURE) & 1)) { /* We have IDE interface */
+ outw_p(0, BRIDGE_IDE_INTR_LVL);
+ outw_p(0, BRIDGE_IDE_INTR_MASK);
+
+ outw_p(0, BRIDGE_IDE_CTRL);
+ DELAY();
+
+ outw_p(0x8000, BRIDGE_IDE_CTRL);
+ DELAY();
+
+ outw_p(0xffff, BRIDGE_IDE_INTR_STAT); /* Clear interrupt status */
+ outw_p(0x0f-14, BRIDGE_IDE_INTR_LVL); /* Use 14 IPR */
+ outw_p(1, BRIDGE_IDE_INTR_MASK); /* Enable interrupt */
+ has_ide=1;
+ }
+
+ if ((inw (BRIDGE_FEATURE) & 2)) { /* We have ISA interface */
+ outw_p(0, BRIDGE_ISA_INTR_LVL);
+ outw_p(0, BRIDGE_ISA_INTR_MASK);
+
+ outw_p(0, BRIDGE_ISA_CTRL);
+ DELAY();
+ outw_p(0x8000, BRIDGE_ISA_CTRL);
+ DELAY();
+
+ outw_p(0xffff, BRIDGE_ISA_INTR_STAT); /* Clear interrupt status */
+ outw_p(0x0f-10, BRIDGE_ISA_INTR_LVL); /* Use 10 IPR */
+ outw_p(0xfff8, BRIDGE_ISA_INTR_MASK); /* Enable interrupt */
+ has_isa=1;
+ }
+
+ printk(KERN_INFO "CqREEK Setup (IDE=%d, ISA=%d)...done\n", has_ide, has_isa);
+}
+\f
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_cqreek __initmv = {
+ mv_name: "CqREEK",
+
+#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: generic_inb,
+ mv_inw: generic_inw,
+ mv_inl: generic_inl,
+ mv_outb: generic_outb,
+ mv_outw: generic_outw,
+ mv_outl: generic_outl,
+
+ mv_inb_p: generic_inb_p,
+ mv_inw_p: generic_inw_p,
+ mv_inl_p: generic_inl_p,
+ mv_outb_p: generic_outb_p,
+ mv_outw_p: generic_outw_p,
+ mv_outl_p: generic_outl_p,
+
+ mv_insb: generic_insb,
+ mv_insw: generic_insw,
+ mv_insl: generic_insl,
+ mv_outsb: generic_outsb,
+ mv_outsw: generic_outsw,
+ mv_outsl: generic_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_init_arch: setup_cqreek,
+ mv_init_irq: init_cqreek_IRQ,
+
+ mv_port2addr: cqreek_port2addr,
+ mv_isa_port2addr: cqreek_port2addr,
+};
+ALIAS_MV(cqreek)
inw(HD64461_NIRR), inw(HD64461_NIMR));
}
+int hd64461_irq_demux(int irq)
+{
+ 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;
+ }
+ return irq;
+}
static struct irqaction irq0 = { hd64461_interrupt, SA_INTERRUPT, 0, "HD64461", NULL, NULL};
{
int i;
+ if (!MACH_HD64461)
+ return 0;
+
printk(KERN_INFO "HD64461 configured at 0x%x on irq %d(mapped into %d to %d)\n",
CONFIG_HD64461_IOBASE, CONFIG_HD64461_IRQ,
HD64461_IRQBASE, HD64461_IRQBASE+15);
-#if 1
+#ifdef CONFIG_CPU_SUBTYPE_SH7709
/* IRQ line for HD64461 should be set level trigger mode("10"). */
/* And this should be done earlier than the kernel starts. */
ctrl_outw(0x0200, INTC_ICR1); /* when connected to IRQ4. */
/*
* Initialize IRQ setting
*/
-static void __init init_se_IRQ(void)
+void __init init_se_IRQ(void)
{
- int i;
-
/*
* Super I/O (Just mimic PC):
* 1: keyboard
* 12: mouse
* 14: ide0
*/
- set_ipr_data(14, BCR_ILCRA, 2, 0x0f-14);
- set_ipr_data(12, BCR_ILCRA, 1, 0x0f-12);
- set_ipr_data( 8, BCR_ILCRB, 1, 0x0f- 8);
- set_ipr_data( 6, BCR_ILCRC, 3, 0x0f- 6);
- set_ipr_data( 5, BCR_ILCRC, 2, 0x0f- 5);
- set_ipr_data( 4, BCR_ILCRC, 1, 0x0f- 4);
- set_ipr_data( 3, BCR_ILCRC, 0, 0x0f- 3);
- set_ipr_data( 1, BCR_ILCRD, 3, 0x0f- 1);
-
- set_ipr_data(10, BCR_ILCRD, 1, 0x0f-10); /* LAN */
-
- set_ipr_data( 0, BCR_ILCRE, 3, 0x0f- 0); /* PCIRQ3 */
- set_ipr_data(11, BCR_ILCRE, 2, 0x0f-11); /* PCIRQ2 */
- set_ipr_data( 9, BCR_ILCRE, 1, 0x0f- 9); /* PCIRQ1 */
- set_ipr_data( 7, BCR_ILCRE, 0, 0x0f- 7); /* PCIRQ0 */
+ make_ipr_irq(14, BCR_ILCRA, 2, 0x0f-14);
+ make_ipr_irq(12, BCR_ILCRA, 1, 0x0f-12);
+ make_ipr_irq( 8, BCR_ILCRB, 1, 0x0f- 8);
+ make_ipr_irq( 6, BCR_ILCRC, 3, 0x0f- 6);
+ make_ipr_irq( 5, BCR_ILCRC, 2, 0x0f- 5);
+ make_ipr_irq( 4, BCR_ILCRC, 1, 0x0f- 4);
+ make_ipr_irq( 3, BCR_ILCRC, 0, 0x0f- 3);
+ make_ipr_irq( 1, BCR_ILCRD, 3, 0x0f- 1);
+
+ make_ipr_irq(10, BCR_ILCRD, 1, 0x0f-10); /* LAN */
+
+ make_ipr_irq( 0, BCR_ILCRE, 3, 0x0f- 0); /* PCIRQ3 */
+ make_ipr_irq(11, BCR_ILCRE, 2, 0x0f-11); /* PCIRQ2 */
+ make_ipr_irq( 9, BCR_ILCRE, 1, 0x0f- 9); /* PCIRQ1 */
+ make_ipr_irq( 7, BCR_ILCRE, 0, 0x0f- 7); /* PCIRQ0 */
/* #2, #13 are allocated for SLOT IRQ #1 and #2 (for now) */
/* NOTE: #2 and #13 are not used on PC */
- set_ipr_data(13, BCR_ILCRG, 1, 0x0f-13); /* SLOTIRQ2 */
- set_ipr_data( 2, BCR_ILCRG, 0, 0x0f- 2); /* SLOTIRQ1 */
-
- for (i = 0; i < 15; i++) {
- make_ipr_irq(i);
- }
+ make_ipr_irq(13, BCR_ILCRG, 1, 0x0f-13); /* SLOTIRQ2 */
+ make_ipr_irq( 2, BCR_ILCRG, 0, 0x0f- 2); /* SLOTIRQ1 */
}
+
/*
* Initialize the board
*/
-int __init setup_se(void)
+void __init setup_se(void)
{
- init_se_IRQ();
init_smsc();
/* XXX: RTC setting comes here */
-
- printk(KERN_INFO "Hitach SolutionEngine Setup...done\n");
- return 0;
}
-
-module_init(setup_se);
-/* $Id$
+/* $Id: sh_bios.c,v 1.2 2000/07/26 04:37:32 gniibe Exp $
*
* linux/arch/sh/kernel/sh_bios.c
* C interface for trapping into the standard LinuxSH BIOS.
{
struct task_struct *tsk = current;
unsigned long flags;
+ int val;
if (!tsk->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.
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/delay.h>
+#include <asm/machvec.h>
#include <linux/timex.h>
#include <linux/irq.h>
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
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__)
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
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
--- /dev/null
+/*
+ * linux/arch/alpha/lib/strcasecmp.c
+ */
+
+#include <linux/string.h>
+
+
+/* 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;
+}
# 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
* 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)
*/
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);
}
/*
{
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;
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; i<CACHE_OC_NUM_ENTRIES; i++) {
+ addr = CACHE_OC_ADDRESS_ARRAY| (i<<CACHE_OC_ENTRY_SHIFT);
+ data = ctrl_inl(addr);
+ if ((data & CACHE_VALID) && (data&PAGE_MASK) == phys) {
+ data &= ~(CACHE_VALID|CACHE_UPDATED);
+ ctrl_outl(data, addr);
+ }
+ }
+ back_to_P1();
+}
+
void flush_cache_all(void)
{
unsigned long addr, data, i;
flush_cache_all();
}
+/*
+ * Write back and invalidate D-caches.
+ *
+ * START, END: Virtual Address (U0 address)
+ *
+ * NOTE: We need to flush the _physical_ page entry.
+ * Flushing the cache lines for U0 only isn't enough.
+ * We need to flush for P1 too, which may contain aliases.
+ */
void flush_cache_range(struct mm_struct *mm, unsigned long start,
unsigned long end)
{
/*
- * Calling
- * dcache_flush_range(start, end);
- * is not good for the purpose of this function. That is,
- * flushing cache lines indexed by the virtual address is not
- * sufficient.
- *
- * Instead, we need to flush the relevant cache lines which
- * hold the data of the corresponding physical memory, as we
- * have "alias" issues.
- *
- * This is needed because, kernel accesses the memory through
- * P1-area (and/or U0-area) and user-space accesses through U0-area.
- * And P1-area and U0-area may use different cache lines for
- * same physical memory.
+ * We could call flush_cache_page for the pages of these range,
+ * but it's not efficient (scan the caches all the time...).
*
- * If we would call dcache_flush_range(), the line of P1-area
- * could remain in the cache, unflushed.
+ * We can't use A-bit magic, as there's the case we don't have
+ * valid entry on TLB.
*/
- unsigned long addr, data, v;
-
- start &= ~(L1_CACHE_BYTES-1);
- jump_to_P2();
-
- for (v = start; v < end; v+=L1_CACHE_BYTES) {
- addr = CACHE_OC_ADDRESS_ARRAY |
- (v&CACHE_OC_ENTRY_PHYS_MASK) | 0x8 /* A-bit */;
- data = (v&0xfffffc00); /* Update=0, Valid=0 */
-
- /* Try all the cases for aliases */
- ctrl_outl(data, addr);
- ctrl_outl(data, addr | 0x1000);
- ctrl_outl(data, addr | 0x2000);
- ctrl_outl(data, addr | 0x3000);
- }
- back_to_P1();
+ flush_cache_all();
}
+/*
+ * Write back and invalidate D-caches for the page.
+ *
+ * ADDR: Virtual Address (U0 address)
+ *
+ * NOTE: We need to flush the _physical_ page entry.
+ * Flushing the cache lines for U0 only isn't enough.
+ * We need to flush for P1 too, which may contain aliases.
+ */
void flush_cache_page(struct vm_area_struct *vma, unsigned long addr)
{
- /* XXX: Umm... this flush out all the cache lines. Any improvement? */
- flush_cache_range(vma->vm_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.
* 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);
}
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
__initcall_start = .;
.initcall.init : { *(.initcall.init) }
__initcall_end = .;
+ __machvec_start = .;
+ .machvec.init : { *(.machvec.init) }
+ __machvec_end = .;
. = ALIGN(4096);
__init_end = .;
-# $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.
#
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
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
# Automatically generated make config: don't edit
#
CONFIG_UID16=y
+CONFIG_HIGHMEM=y
#
# Code maturity level options
# 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
-/* $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.
*
-/* $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)
-/* $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)
-/* $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)
-/* $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)
-/* $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)
-# $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
ifneq ($(NEW_GCC),y)
CMODEL_CFLAG := -mmedlow
else
- CMODEL_CFLAG := -mcmodel=medlow
+ CMODEL_CFLAG := -m64 -mcmodel=medlow
endif
check_asm: dummy
-/* $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)
-/* $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)
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)
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;
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;
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;
}
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);
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);
-/* $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)
-/* $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.
*
-/* $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)
#include "../../char/busmouse.h"
+extern struct tasklet_struct keyboard_tasklet;
extern void kbd_reset_kdown(void);
#define VERSION 108
{
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)
(void)IOMD_KARTRX;
restore_flags (flags);
- printk (KERN_INFO "PS/2 keyboard driver v%d.%02d\n", VERSION/100, VERSION%100);
return 0;
}
* IRQs after the sleep.
*/
spin_unlock_irq(&io_request_lock);
- scsi_sleep(5);
+ scsi_sleep(25*HZ/100);
spin_lock_irq(&io_request_lock);
/*
* 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));
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;
* 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
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;
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;
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:
int disks = MD_SB_DISKS;
int i, sum_bhs = 0, sectors;
struct mirror_info *mirror;
- request_queue_t *q;
if (!buffer_locked(bh))
BUG();
/* 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;
}
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);
}
struct raid1_bh *r1_bh;
struct buffer_head *bh;
unsigned long flags;
- request_queue_t *q;
mddev_t *mddev;
kdev_t dev;
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 {
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);
}
}
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;
}
{
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;
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);
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;
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);
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));
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;
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));
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));
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;
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);
}
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));
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",
const char *name;
} XD_SIGNATURE;
-static int xd_setup (char *);
#ifndef MODULE
static int xd_manual_geo_init (char *command);
#endif /* MODULE */
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();
{
struct busmouse_data *mse;
unsigned int mousedev;
- int ret = -ENODEV;
+ int ret;
mousedev = DEV_TO_MOUSE(inode->i_rdev);
if (mousedev >= NR_MICE)
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);
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:
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);
#include <linux/version.h>
#include <linux/sched.h>
#include <linux/smp_lock.h> /* For (un)lock_kernel */
+#include <linux/mm.h>
#include <asm/io.h>
#include <asm/mman.h>
#include <asm/uaccess.h>
#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
*/
#include <linux/kernel.h>
+#include <linux/sched.h>
#include <linux/init.h>
+#include <asm/delay.h>
#include <asm/io.h>
#include "scan_keyb.h"
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,
};
+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);
}
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);
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);
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));
return c;
}
-#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB
-
/* Taken from sh-stub.c of GDB 4.18 */
static const char hexchars[] = "0123456789abcdef";
#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;
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;
* 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;
}
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);
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);
tty->flip.flag_buf_ptr += count;
copied += count;
+ port->icount.rx += count;
}
if (copied)
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 *
port->gs.tty = tty;
port->gs.count++;
+ port->event = 0;
+ port->tqueue.routine = do_softint;
+ port->tqueue.data = port;
+
/*
* Start up serial port
*/
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;
}
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;
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");
#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
# 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 */
#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)
#define SCFCR_TFRST 0x0004
#define SCFCR_MCE 0x0008
-#define SCI_PRIORITY 3
-
#define SCI_MAJOR 204
#define SCI_MINOR_START 8
#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) \
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
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;
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);
sp->rx_mode = new_rx_mode;
}
\f
+
+#ifdef CONFIG_EEPRO100_PM
+
static void eepro100_suspend(struct pci_dev *pdev)
{
struct net_device *dev = pdev->driver_data;
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;
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
* Copyright (C) 2000 Paul Mackerras & Ben. Herrenschmidt
*
* portions based on sunhme.c by David S. Miller
+ *
+ * Changes:
+ * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/06/2000
+ * - check init_etherdev return in gmac_probe1
*
*/
}
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;
/* 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 <acme@conectiva.com.br> - 08/06/2000 */
+/* - check init_etherdev in hydra_probe */
+/* - dev->priv is already zeroed by init_etherdev */
#include <linux/module.h>
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));
* modified by SRC, incorporated herein by reference.
*
* **********************
+ * Changes:
+ * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 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
*
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;
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;
}
return link;
+
+fail_alloc_dev:
+ kfree(lp);
+fail_alloc_lp:
+ kfree(info);
+fail_alloc_info:
+ kfree(link);
+ return NULL;
} /* com20020_attach */
/*======================================================================
* 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 <acme@conectiva.com.br> - 08/08/2000
+ * - reorganize kmallocs in ray_attach, checking all for failure
+ * and releasing the previous allocations if one fails
+ *
*
=============================================================================*/
/* 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;
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;
}
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
* 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
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
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;
-}
+
/***************************************************************************
*
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) {
*/
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;
***********************************************************************/
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;
}
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.
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) {
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 */
skb_queue_purge(&sk->receive_queue);
sock_put(sk);
- MOD_DEC_USE_COUNT;
return error;
}
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;
/* 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;
/* 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));
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,
/* 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,
ph->length = htons(copied);
dev_queue_xmit(skb);
- return copied;
end:
+ release_sock(sk);
return error;
}
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,
/* 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.
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 <jgarzik@mandrakesoft.com> 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
*/
#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;
};
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 */
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]);
{
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;
retval = (retval << 1) | ((inl(ee_addr) & EEDO) ? 1 : 0);
eeprom_delay();
}
-
+
/* Terminate the EEPROM access. */
outl(0, ee_addr);
eeprom_delay();
outl(MDC, mdio_addr);
mdio_delay();
}
+ outl(0x00, mdio_addr);
+
return retval;
}
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);
outb(MDC, mdio_addr);
mdio_delay();
}
+ outl(0x00, mdio_addr);
+
return;
}
long ioaddr = net_dev->base_addr;
u32 rfcrSave;
u32 i;
-
+
rfcrSave = inl(rfcr + ioaddr);
/* disable packet filtering before setting filter */
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;
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 */
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;
}
/* 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
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;
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;
}
{
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);
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");
{
int i;
u16 status;
-
+
for (i = 0; i < 2; i++)
status = mdio_read(net_dev, phy_addr, MII_STATUS);
*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);
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);
do {
status = inl(ioaddr + isr);
-
+
if ((status & (HIBERR|TxURN|TxERR|TxIDLE|RxORN|RxERR|RxOK)) == 0)
/* nothing intresting happened */
break;
break;
}
} while (1);
-
+
if (sis900_debug > 3)
printk(KERN_INFO "%s: exiting interrupt, "
"interrupt status = 0x%#8.8x.\n",
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)
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 */
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"
}
/* re-enable the potentially idle receive state matchine */
outl(RxENA , ioaddr + cr );
-
+
return 0;
}
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)
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) */
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. */
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
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
#include <asm/system.h>
#include <asm/io.h>
#include <asm/hitachi_se.h>
+#include <asm/machvec.h>
#include "8390.h"
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;
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]
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!)
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
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");
}
default:
case 8:
fix->line_length = par->x;
+ break;
case 16:
fix->line_length = par->x*2;
+ break;
}
return 0;
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
#
# 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
/*
* 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 <finn@axis.com>.
*
* 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. */
* maybe other stuff do to.
*/
-#include <linux/config.h>
+/* 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 <linux/sched.h>
+#include <linux/unistd.h>
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#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;
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;
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:
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;
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. */
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
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;
}
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;
*err = -ENOMEM;
return NULL;
}
-
+
sb = dir->i_sb;
c = (struct jffs_control *)sb->u.generic_sbp;
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;
+ 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;
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;
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"));
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"));
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) {
}
jffs_rename_end:
-
return result;
} /* jffs_rename() */
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)
return 0;
filp->f_pos++;
}
-
+
return filp->f_pos;
} /* jffs_readdir() */
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);
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;
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;
}
f, name, d, d->ino));
inode = NULL;
}
-
+
d_add(dentry, inode);
return NULL;
-
+
jffs_lookup_end:
return ERR_PTR(r);
} /* jffs_lookup() */
flush_dcache_page(page);
UnlockPage(page);
-
+
put_page(page);
-
+
D3(printk("jffs_readpage(): Leaving...\n"));
return result;
int dir_mode;
int result = 0;
int err;
-
+
D1({
int len = dentry->d_name.len;
char *_name = (char *) kmalloc(len + 1, GFP_KERNEL);
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"));
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. */
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--);
}
/* 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;
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;
}
inode = dentry->d_inode;
-
+
result = -EIO;
if (del_f->ino != inode->i_ino)
goto jffs_remove_end;
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"));
}
/* 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;
}
result = err;
goto jffs_mknod_end;
}
-
+
init_special_inode(inode, mode, rdev);
d_instantiate(dentry, inode);
-
+
goto jffs_mknod_end;
jffs_mknod_err:
struct jffs_file *dir_f;
struct jffs_node *node;
struct inode *inode;
-
+
int symname_len = strlen(symname);
int err;
_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);
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"));
/* 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++);
}
/* 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;
}
if (inode == NULL) {
return err;
}
-
+
inode->i_op = &page_symlink_inode_operations;
inode->i_mapping->a_ops = &jffs_address_operations;
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)
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"));
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--);
}
/* 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;
}
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)
err = -ENOSPC;
goto out;
}
-
+
if (!S_ISREG(inode->i_mode)) {
D(printk("jffs_file_write(): inode->i_mode == 0x%08x\n",
inode->i_mode));
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"));
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. */
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;
/*
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;
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;
{
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. "
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:
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 =
{
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,
setattr: jffs_setattr,
};
+
/* Initialize an inode for the VFS. */
static void
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;
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,
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);
}
* 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
/*
* Todo list:
*
- * memcpy_to_flash() and memcpy_from_flash()-functions.
+ * memcpy_to_flash() and memcpy_from_flash() functions.
*
* Implementation of hard links.
*
* 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.
*
* information to be able to debug (or to supervise) JFFS during run-time.
*
*/
+
#define __NO_VERSION__
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/malloc.h>
#include <linux/jffs.h>
#include <asm/semaphore.h>
#include <asm/byteorder.h>
#include <linux/version.h>
+#include <linux/smp_lock.h>
+#include <linux/sched.h>
+
#include "intrep.h"
#include "jffs_fm.h"
#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;
}
#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;
}
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)
{
return sum;
}
+
__u32
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,
goto fail_hash;
}
DJM(no_hash++);
- for (i=0;i<c->hash_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:
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--);
}
}
}
+ 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");
__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;
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) {
}
/* 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),
/* 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. */
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));
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) {
}
}
- /* 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:
"(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! */
}
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 : "")));
}
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"));
}
(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;
}
}
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,
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
(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) {
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. */
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);
/* 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;
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() */
}
-/* Free all memory associated with a file. */
+/* Free all nodes associated with a file. */
int
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)
});
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;
}
}
/* 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;
}
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;
&& 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. */
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) {
}
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 "
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;
/* 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;
}
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);
}
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, "
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;
printk(KERN_ERR "jffs_insert_data(): "
"Couldn't find a place to insert "
"the data!\n");
- return;
+ return -1;
});
}
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;
}
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));
/* 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;
}
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));
{
struct jffs_file *f;
char *space;
+ int dir;
if (!first_file) {
return;
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);
}
}
}
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);
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));
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);
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;
__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;
&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;
/* 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)
{
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));
/* 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;
});
(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) {
= 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);
}
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 */
/* 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
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;
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));
/* 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.
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));
}
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;
}
}
- 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() */
+
* 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);
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);
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);
* 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 <linux/config.h>
#include <linux/malloc.h>
#include <linux/blkdev.h>
#include <linux/jffs.h>
#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
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;
}
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;
}
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;
}
* 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
#include <linux/types.h>
#include <linux/jffs.h>
#include <linux/mtd/mtd.h>
+#include <linux/config.h>
/* The alignment between two nodes in the flash memory. */
#define JFFS_ALIGN_SIZE 4
/* 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? */
- ((__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;
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
/*
* 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 <linux/config.h>
#include <linux/kernel.h>
#include <linux/kdev_t.h>
#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;
}
#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;
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)))
}
#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;
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)))
}
#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;
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;
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;
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);
return minor;
} while (1);
if (bh)
- brelse(bh);
+ bforget(bh);
return first ? 0 : 1;
}
#endif
* 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;
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;
/*
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;
}
}
* 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;
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 */
}
#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.
* 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;
checksum += bh->b_data[i];
if (checksum != bh->b_data[511]) {
- brelse(bh);
+ bforget(bh);
return 0;
}
}
#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;
}
#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);
#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__ */
(((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)
#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
#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__ */
# 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.
*/
#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__ */
#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 { \
#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__) */
#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))))
-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_ */
#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__) */
#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);
#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__ */
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 */
#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)
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 */
*/
#include <linux/config.h>
-#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
#ifdef __KERNEL__
#include <linux/config.h>
+#include <asm/machvec.h>
#ifndef MAX_HWIFS
#define MAX_HWIFS 1
#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;
}
* 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 <asm/cache.h>
+#include <asm/system.h>
+#include <linux/config.h>
-#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 <asm/machvec.h>
+
+# 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 <asm/io_hd64461.h>
+# elif defined(CONFIG_SH_OVERDRIVE)
+# include <asm/io_od.h>
+# elif defined(CONFIG_SH_SOLUTION_ENGINE)
+# include <asm/io_se.h>
+# elif defined(CONFIG_SH_UNKNOWN)
+# include <asm/io_unknown.h>
+# 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;
*(volatile unsigned long*)addr = b;
}
-#ifdef __KERNEL__
-
#define IO_SPACE_LIMIT 0xffffffff
#include <asm/addrspace.h>
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
* 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);
}
/*
* 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,
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 <asm/io_generic.h>
+
+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 */
--- /dev/null
+/*
+ * 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 <asm/io_generic.h>
+
+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 */
--- /dev/null
+/*
+ * 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 <asm/io_generic.h>
+
+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 */
--- /dev/null
+/*
+ * 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 */
*/
#include <linux/config.h>
+#include <asm/machvec.h>
#if defined(__sh3__)
#define INTC_IPRA 0xfffffee2UL
#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
*
*/
#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)
#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);
/*
* 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
#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
#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 */
/*
* $Id: keyboard.h,v 1.1 2000/06/10 21:45:48 yaegashi Exp $
*/
-#include <linux/config.h>
+
+#include <asm/machvec.h>
static __inline__ int kbd_setkeycode(unsigned int scancode,
unsigned int keycode)
{
}
-#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
--- /dev/null
+/*
+ * 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 <linux/config.h>
+#include <linux/types.h>
+
+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 */
--- /dev/null
+/*
+ * 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 */
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);
}
}
#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__
#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 */
* 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);
}
* 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 */
}
* the same here.
*/
extern inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
- int nents)
+ int nents,int direction)
{
return nents;
}
* 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 */
}
*/
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 */
}
*/
extern inline void pci_dma_sync_sg(struct pci_dev *hwdev,
struct scatterlist *sg,
- int nelems)
+ int nelems,int direction)
{
/* Nothing to do */
}
* - 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
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
#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 */
* 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
#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__ */
-/* $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
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
-/* $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
/* 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
#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
-/* $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)
#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))
-/* $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)
* 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);
#if defined(MAJOR_NR) || defined(IDE_DRIVER)
+#undef DEVICE_ON
+#undef DEVICE_OFF
+
/*
* Add entries as needed.
*/
#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)
#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)
#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)
#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)
#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)
#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))
#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)
/* #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)
/* #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)
#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)
#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)
#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)
#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))
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 *);
#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
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();
}
#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;
}
}
-extern inline void br_read_unlock (enum brlock_indices idx)
+static inline void br_read_unlock (enum brlock_indices idx)
{
unsigned int *ctr;
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();
#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;
kunmap(page);
}
-extern inline void clear_highpage(struct page *page)
+static inline void clear_highpage(struct page *page)
{
unsigned long kaddr;
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;
/*
* 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;
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;
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;
/*
* 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 <finn@axis.com>.
*
* 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
#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. */
__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. */
};
+/* 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;
};
#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:
*/
#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
#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
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;
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);
+ }
}
}
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;
}
retval = -ENOMEM;
- mm = mm_alloc();
mm = allocate_mm();
if (!mm)
goto fail_nomem;
/* 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)
#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)
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;
*
* 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
*
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);
}
*
* 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, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
{
if (ctl_len > sizeof(ctl))
{
- err = -ENOBUFS;
ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL);
if (ctl_buf == NULL)
goto out_freeiov;