diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-10-09 00:00:47 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-10-09 00:00:47 +0000 |
commit | d6434e1042f3b0a6dfe1b1f615af369486f9b1fa (patch) | |
tree | e2be02f33984c48ec019c654051d27964e42c441 /arch/ppc | |
parent | 609d1e803baf519487233b765eb487f9ec227a18 (diff) |
Merge with 2.3.19.
Diffstat (limited to 'arch/ppc')
130 files changed, 9643 insertions, 3024 deletions
diff --git a/arch/ppc/8xx_io/enet.c b/arch/ppc/8xx_io/enet.c index 1c71f473f..737abbebf 100644 --- a/arch/ppc/8xx_io/enet.c +++ b/arch/ppc/8xx_io/enet.c @@ -152,13 +152,13 @@ struct cpm_enet_private { unsigned long lock; }; -static int cpm_enet_open(struct device *dev); -static int cpm_enet_start_xmit(struct sk_buff *skb, struct device *dev); -static int cpm_enet_rx(struct device *dev); +static int cpm_enet_open(struct net_device *dev); +static int cpm_enet_start_xmit(struct sk_buff *skb, struct net_device *dev); +static int cpm_enet_rx(struct net_device *dev); static void cpm_enet_interrupt(void *dev_id); -static int cpm_enet_close(struct device *dev); -static struct net_device_stats *cpm_enet_get_stats(struct device *dev); -static void set_multicast_list(struct device *dev); +static int cpm_enet_close(struct net_device *dev); +static struct net_device_stats *cpm_enet_get_stats(struct net_device *dev); +static void set_multicast_list(struct net_device *dev); /* Get this from various configuration locations (depends on board). */ @@ -181,7 +181,7 @@ static void set_multicast_list(struct device *dev); #endif static int -cpm_enet_open(struct device *dev) +cpm_enet_open(struct net_device *dev) { /* I should reset the ring buffers here, but I don't yet know @@ -196,7 +196,7 @@ cpm_enet_open(struct device *dev) } static int -cpm_enet_start_xmit(struct sk_buff *skb, struct device *dev) +cpm_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct cpm_enet_private *cep = (struct cpm_enet_private *)dev->priv; volatile cbd_t *bdp; @@ -326,7 +326,7 @@ cpm_enet_start_xmit(struct sk_buff *skb, struct device *dev) static void cpm_enet_interrupt(void *dev_id) { - struct device *dev = dev_id; + struct net_device *dev = dev_id; volatile struct cpm_enet_private *cep; volatile cbd_t *bdp; ushort int_events; @@ -503,7 +503,7 @@ cpm_enet_interrupt(void *dev_id) * effectively tossing the packet. */ static int -cpm_enet_rx(struct device *dev) +cpm_enet_rx(struct net_device *dev) { struct cpm_enet_private *cep; volatile cbd_t *bdp; @@ -597,7 +597,7 @@ for (;;) { } static int -cpm_enet_close(struct device *dev) +cpm_enet_close(struct net_device *dev) { /* Don't know what to do yet. */ @@ -605,7 +605,7 @@ cpm_enet_close(struct device *dev) return 0; } -static struct net_device_stats *cpm_enet_get_stats(struct device *dev) +static struct net_device_stats *cpm_enet_get_stats(struct net_device *dev) { struct cpm_enet_private *cep = (struct cpm_enet_private *)dev->priv; @@ -622,7 +622,7 @@ static struct net_device_stats *cpm_enet_get_stats(struct device *dev) * this kind of feature?). */ -static void set_multicast_list(struct device *dev) +static void set_multicast_list(struct net_device *dev) { struct cpm_enet_private *cep; struct dev_mc_list *dmi; @@ -701,7 +701,7 @@ static void set_multicast_list(struct device *dev) int __init cpm_enet_init() { m8xx_enet_init(); } int __init m8xx_enet_init(void) { - struct device *dev; + struct net_device *dev; struct cpm_enet_private *cep; int i, j; unsigned char *eap; diff --git a/arch/ppc/8xx_io/fec.c b/arch/ppc/8xx_io/fec.c index 2b797a498..fb12757f5 100644 --- a/arch/ppc/8xx_io/fec.c +++ b/arch/ppc/8xx_io/fec.c @@ -106,14 +106,14 @@ struct fec_enet_private { unsigned long lock; }; -static int fec_enet_open(struct device *dev); -static int fec_enet_start_xmit(struct sk_buff *skb, struct device *dev); -static int fec_enet_rx(struct device *dev); -static void fec_enet_mii(struct device *dev); +static int fec_enet_open(struct net_device *dev); +static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev); +static int fec_enet_rx(struct net_device *dev); +static void fec_enet_mii(struct net_device *dev); static void fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs); -static int fec_enet_close(struct device *dev); -static struct net_device_stats *fec_enet_get_stats(struct device *dev); -static void set_multicast_list(struct device *dev); +static int fec_enet_close(struct net_device *dev); +static struct net_device_stats *fec_enet_get_stats(struct net_device *dev); +static void set_multicast_list(struct net_device *dev); static ushort my_enet_addr[] = { 0x0800, 0x3e26, 0x1559 }; @@ -142,7 +142,7 @@ static int mii_queue(int request, void (*func)(int)); (VAL & 0xffff)) static int -fec_enet_open(struct device *dev) +fec_enet_open(struct net_device *dev) { /* I should reset the ring buffers here, but I don't yet know @@ -157,7 +157,7 @@ fec_enet_open(struct device *dev) } static int -fec_enet_start_xmit(struct sk_buff *skb, struct device *dev) +fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct fec_enet_private *fep = (struct fec_enet_private *)dev->priv; volatile cbd_t *bdp; @@ -282,7 +282,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct device *dev) static void fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs) { - struct device *dev = dev_id; + struct net_device *dev = dev_id; struct fec_enet_private *fep; volatile cbd_t *bdp; volatile fec_t *ep; @@ -393,7 +393,7 @@ fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs) * effectively tossing the packet. */ static int -fec_enet_rx(struct device *dev) +fec_enet_rx(struct net_device *dev) { struct fec_enet_private *fep; volatile cbd_t *bdp; @@ -506,7 +506,7 @@ for (;;) { } static void -fec_enet_mii(struct device *dev) +fec_enet_mii(struct net_device *dev) { struct fec_enet_private *fep; volatile fec_t *ep; @@ -676,7 +676,7 @@ mii_relink(uint mii_reg) static void mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs) { - struct device *dev = dev_id; + struct net_device *dev = dev_id; struct fec_enet_private *fep; volatile fec_t *ep; @@ -696,7 +696,7 @@ mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs) } static int -fec_enet_close(struct device *dev) +fec_enet_close(struct net_device *dev) { /* Don't know what to do yet. */ @@ -704,7 +704,7 @@ fec_enet_close(struct device *dev) return 0; } -static struct net_device_stats *fec_enet_get_stats(struct device *dev) +static struct net_device_stats *fec_enet_get_stats(struct net_device *dev) { struct fec_enet_private *fep = (struct fec_enet_private *)dev->priv; @@ -721,7 +721,7 @@ static struct net_device_stats *fec_enet_get_stats(struct device *dev) * this kind of feature?). */ -static void set_multicast_list(struct device *dev) +static void set_multicast_list(struct net_device *dev) { struct fec_enet_private *fep; struct dev_mc_list *dmi; @@ -790,9 +790,9 @@ static void set_multicast_list(struct device *dev) /* Initialize the FECC Ethernet on 860T. */ -__initfunc(int m8xx_enet_init(void)) +int __init m8xx_enet_init(void) { - struct device *dev; + struct net_device *dev; struct fec_enet_private *fep; int i, j; unsigned char *eap; diff --git a/arch/ppc/8xx_io/uart.c b/arch/ppc/8xx_io/uart.c index 1816df9ba..4bb555c77 100644 --- a/arch/ppc/8xx_io/uart.c +++ b/arch/ppc/8xx_io/uart.c @@ -1826,7 +1826,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, serial_inp(info, UART_MCR) | (UART_MCR_DTR | UART_MCR_RTS)); sti(); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) { #ifdef SERIAL_DO_RESTART @@ -2243,7 +2243,7 @@ static struct console sercons = { /* * Register console. */ -__initfunc (long console_8xx_init(long kmem_start, long kmem_end)) +long __init console_8xx_init(long kmem_start, long kmem_end) { register_console(&sercons); return kmem_start; @@ -2254,7 +2254,7 @@ __initfunc (long console_8xx_init(long kmem_start, long kmem_end)) /* * The serial driver boot-time initialization code! */ -__initfunc(int rs_8xx_init(void)) +int __init rs_8xx_init(void) { struct serial_state * state; ser_info_t *info; @@ -2596,7 +2596,7 @@ __initfunc(int rs_8xx_init(void)) /* This must always be called before the rs_8xx_init() function, otherwise * it blows away the port control information. */ -__initfunc(static int serial_console_setup(struct console *co, char *options)) +static int __init serial_console_setup(struct console *co, char *options) { struct serial_state *ser; uint mem_addr, dp_addr; diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile index 25a2a0fb7..9977db204 100644 --- a/arch/ppc/Makefile +++ b/arch/ppc/Makefile @@ -21,8 +21,8 @@ endif ASFLAGS = LINKFLAGS = -T arch/ppc/vmlinux.lds -Ttext $(KERNELLOAD) -Bstatic CFLAGSINC = -D__KERNEL__ -I$(TOPDIR)/include -D__powerpc__ -CFLAGS := $(CFLAGS) -D__powerpc__ -fsigned-char -msoft-float -pipe \ - -fno-builtin -ffixed-r2 -Wno-uninitialized -mmultiple \ +CFLAGS := $(CFLAGS) -I$(HPATH) -D__powerpc__ -fsigned-char -msoft-float \ + -pipe -fno-builtin -ffixed-r2 -Wno-uninitialized -mmultiple \ -mstring CPP = $(CC) -E $(CFLAGS) @@ -34,13 +34,23 @@ ifdef CONFIG_PPC64 CFLAGS := $(CFLAGS) -Wa,-mppc64bridge #-mpowerpc64 endif +ifndef CONFIG_8xx HEAD := arch/ppc/kernel/head.o +else +HEAD := arch/ppc/kernel/head_8xx.o +endif ARCH_SUBDIRS = arch/ppc/kernel arch/ppc/mm arch/ppc/lib SUBDIRS := $(SUBDIRS) $(ARCH_SUBDIRS) ARCHIVES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(ARCHIVES) CORE_FILES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(CORE_FILES) +ifdef CONFIG_8xx +SUBDIRS += arch/ppc/math-emu +ARCHIVES += arch/ppc/math-emu/math-emu.o +CORE_FILES += arch/ppc/math-emu/math-emu.o +endif + ifdef CONFIG_XMON SUBDIRS += arch/ppc/xmon CORE_FILES += arch/ppc/xmon/x.o @@ -65,8 +75,7 @@ endif checks: @$(MAKE) -C arch/$(ARCH)/kernel checks -BOOT_TARGETS = netboot znetboot zImage floppy install \ - vmlinux.coff znetboot.initrd zImage.initrd vmlinux.coff.initrd +BOOT_TARGETS = zImage znetboot.initrd zImage.initrd ifdef CONFIG_MBX $(BOOT_TARGETS): $(CHECKS) vmlinux @@ -77,7 +86,29 @@ $(BOOT_TARGETS): $(CHECKS) vmlinux @$(MAKECOFFBOOT) $@ @$(MAKEBOOT) $@ @$(MAKECHRPBOOT) $@ + +znetboot: $(CHECKS) vmlinux +ifdef CONFIG_SMP +ifdef CONFIG_PPC64 + cp -f vmlinux /tftpboot/vmlinux.smp.64 +else + cp -f vmlinux /tftpboot/vmlinux.smp endif +else +ifdef CONFIG_PPC64 + cp -f vmlinux /tftpboot/vmlinux.64 +else + cp -f vmlinux /tftpboot/vmlinux +endif +endif + @$(MAKECOFFBOOT) $@ + @$(MAKEBOOT) $@ + @$(MAKECHRPBOOT) $@ +endif + +gemini_config: + rm -f .config arch/ppc/defconfig + ln -s gemini_defconfig arch/ppc/defconfig pmac_config: rm -f .config arch/ppc/defconfig diff --git a/arch/ppc/amiga/amiints.c b/arch/ppc/amiga/amiints.c index a221dc59b..795ea6378 100644 --- a/arch/ppc/amiga/amiints.c +++ b/arch/ppc/amiga/amiints.c @@ -79,7 +79,7 @@ static void ami_badint(int irq, void *dev_id, struct pt_regs *fp) * the amiga IRQ handling routines. */ -__initfunc(void amiga_init_IRQ(void)) +void __init amiga_init_IRQ(void) { int i; diff --git a/arch/ppc/amiga/bootinfo.c b/arch/ppc/amiga/bootinfo.c index 7639de68e..21fd37aa1 100644 --- a/arch/ppc/amiga/bootinfo.c +++ b/arch/ppc/amiga/bootinfo.c @@ -24,7 +24,7 @@ extern int amiga_parse_bootinfo(const struct bi_record *); extern int atari_parse_bootinfo(const struct bi_record *); extern int mac_parse_bootinfo(const struct bi_record *); -__initfunc(void parse_bootinfo(const struct bi_record *record)) +void __init parse_bootinfo(const struct bi_record *record) { while (record->tag != BI_LAST) { int unknown = 0; diff --git a/arch/ppc/amiga/config.c b/arch/ppc/amiga/config.c index 5a38fa7f0..59050c421 100644 --- a/arch/ppc/amiga/config.c +++ b/arch/ppc/amiga/config.c @@ -183,7 +183,7 @@ int amiga_parse_bootinfo(const struct bi_record *record) * Identify builtin hardware */ -__initfunc(static void amiga_identify(void)) +static void __init amiga_identify(void) { /* Fill in some default values, if necessary */ if (amiga_eclock == 0) @@ -344,7 +344,7 @@ __initfunc(static void amiga_identify(void)) * Setup the Amiga configuration info */ -__initfunc(void config_amiga(void)) +void __init config_amiga(void) { amiga_debug_init(); amiga_identify(); @@ -437,8 +437,8 @@ __initfunc(void config_amiga(void)) static unsigned short jiffy_ticks; -__initfunc(static void amiga_sched_init(void (*timer_routine)(int, void *, - struct pt_regs *))) +static void __init amiga_sched_init(void (*timer_routine)(int, void *, + struct pt_regs *)) { jiffy_ticks = (amiga_eclock+HZ/2)/HZ; @@ -819,7 +819,7 @@ void amiga_serial_gets(struct console *co, char *s, int len) } #endif -__initfunc(static void amiga_debug_init(void)) +static void __init amiga_debug_init(void) { if (!strcmp( m68k_debug_device, "ser" )) { /* no initialization required (?) */ diff --git a/arch/ppc/amiga/ints.c b/arch/ppc/amiga/ints.c index d13ce5db7..c3eabcc83 100644 --- a/arch/ppc/amiga/ints.c +++ b/arch/ppc/amiga/ints.c @@ -42,7 +42,7 @@ static irq_node_t nodes[NUM_IRQ_NODES]; * the IRQ handling routines. */ -__initfunc(void apus_init_IRQ(void)) +void __init apus_init_IRQ(void) { int i; diff --git a/arch/ppc/boot/Makefile b/arch/ppc/boot/Makefile index 58c9c3c82..9e637aa7b 100644 --- a/arch/ppc/boot/Makefile +++ b/arch/ppc/boot/Makefile @@ -47,9 +47,9 @@ OBJCOPY = $(CROSS_COMPILE)objcopy OBJCOPY_ARGS = -O elf32-powerpc OBJECTS += vreset.o kbd.o of1275.o - ifeq ($(CONFIG_SERIAL_CONSOLE),y) - OBJECTS += ns16550.o - endif +ifeq ($(CONFIG_SERIAL_CONSOLE),y) +OBJECTS += ns16550.o +endif all: zImage @@ -71,9 +71,15 @@ zvmlinux.initrd: zvmlinux zvmlinux.initrd.tmp $@ rm zvmlinux.initrd.tmp -zImage: zvmlinux mkprep +zImage: zvmlinux mkprep sImage ./mkprep -pbp zvmlinux zImage +sImage: ../../../vmlinux +ifdef CONFIG_GEMINI + $(OBJCOPY) -I elf32-powerpc -O binary ../../../vmlinux sImage +else +endif + zImage.initrd: zvmlinux.initrd mkprep ./mkprep -pbp zvmlinux.initrd zImage.initrd @@ -105,6 +111,9 @@ mkprep : mkprep.c znetboot : zImage cp zImage $(TFTPIMAGE) +ifdef CONFIG_GEMINI + cp sImage /tftpboot/ +endif znetboot.initrd : zImage.initrd cp zImage.initrd $(TFTPIMAGE) diff --git a/arch/ppc/boot/head.S b/arch/ppc/boot/head.S index 552e82fa1..79377a2ac 100644 --- a/arch/ppc/boot/head.S +++ b/arch/ppc/boot/head.S @@ -6,7 +6,7 @@ .text /* - * $Id: head.S,v 1.31 1999/04/22 06:32:00 davem Exp $ + * $Id: head.S,v 1.33 1999/09/08 01:06:58 cort Exp $ * * Boot loader philosophy: * ROM loads us to some arbitrary location @@ -125,12 +125,11 @@ start_ldr: * get start address of kernel code which is stored as a coff * entry. see boot/head.S -- Cort */ - li r9,0x0 - lwz r9,0(r9) + li r9,0x4 mtlr r9 - li r9,0 lis r10,0xdeadc0de@h ori r10,r10,0xdeadc0de@l + li r9,0 stw r10,0(r9) /* * The Radstone firmware maps PCI memory at 0xc0000000 using BAT2 diff --git a/arch/ppc/boot/misc.c b/arch/ppc/boot/misc.c index 65b0e74a6..aee407542 100644 --- a/arch/ppc/boot/misc.c +++ b/arch/ppc/boot/misc.c @@ -1,7 +1,7 @@ /* * misc.c * - * $Id: misc.c,v 1.65 1999/05/17 19:11:13 cort Exp $ + * $Id: misc.c,v 1.67 1999/08/10 22:53:57 cort Exp $ * * Adapted for PowerPC by Gary Thomas * @@ -309,8 +309,6 @@ void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) inflateEnd(&s); } -unsigned char sanity[0x2000]; - unsigned long decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, RESIDUAL *residual, void *OFW_interface) @@ -333,7 +331,6 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, cols = 80; orig_x = 0; orig_y = 24; - /* * IBM's have the MMU on, so we have to disable it or @@ -525,7 +522,6 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, puts("initrd_start located > 16M\n"); puts("Uncompressing Linux..."); - gunzip(0, 0x400000, zimage_start, &zimage_size); puts("done.\n"); puts("Now booting the kernel\n"); diff --git a/arch/ppc/chrpboot/Makefile b/arch/ppc/chrpboot/Makefile index eb4720927..15f9a8e53 100644 --- a/arch/ppc/chrpboot/Makefile +++ b/arch/ppc/chrpboot/Makefile @@ -57,7 +57,10 @@ floppy: zImage mcopy zImage a:zImage piggyback: piggyback.c - $(HOSTCC) -DKERNELBASE=$(KERNELBASE) -o piggyback piggyback.c + $(HOSTCC) $(HOSTCFLAGS) -DKERNELBASE=$(KERNELBASE) -o piggyback piggyback.c + +mknote: mknote.c + $(HOSTCC) $(HOSTCFLAGS) -o mknote mknote.c image.o: piggyback ../coffboot/vmlinux.gz ./piggyback image < ../coffboot/vmlinux.gz | $(AS) -o image.o @@ -70,9 +73,6 @@ zImage: $(OBJS) no_initrd.o mknote ./mknote > note $(OBJCOPY) $@ $@ --add-section=.note=note -R .comment -mknote: mknote.c - $(HOSTCC) $(HOSTCFLAGS) -o $@ mknote.c - zImage.initrd: $(OBJS) initrd.o $(LD) $(LD_ARGS) -o $@ $(OBJS) initrd.o $(LIBS) diff --git a/arch/ppc/chrpboot/main.c b/arch/ppc/chrpboot/main.c index 210dd43ad..80db69a7b 100644 --- a/arch/ppc/chrpboot/main.c +++ b/arch/ppc/chrpboot/main.c @@ -68,10 +68,10 @@ chrpboot(int a1, int a2, void *prom) flush_cache(dst, len); - sa = *(unsigned long *)PROG_START+PROG_START; + sa = (unsigned long)PROG_START; printf("start address = 0x%x\n\r", sa); - (*(void (*)())sa)(a1, a2, prom, 0, 0); + (*(void (*)())sa)(0, 0, prom, a1, a2); printf("returned?\n\r"); diff --git a/arch/ppc/coffboot/main.c b/arch/ppc/coffboot/main.c index 51e931f5e..b3a310e17 100644 --- a/arch/ppc/coffboot/main.c +++ b/arch/ppc/coffboot/main.c @@ -100,7 +100,7 @@ coffboot(int a1, int a2, void *prom) flush_cache(dst, len); - sa = *(unsigned *)dst + PROG_START; + sa = (unsigned long)dst; printf("start address = 0x%x\n", sa); #if 0 @@ -165,7 +165,7 @@ void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) printf("gunzip: ran out of data in header\n"); exit(); } - +printf("done 1\n"); s.zalloc = zalloc; s.zfree = zfree; r = inflateInit2(&s, -MAX_WBITS); @@ -177,11 +177,14 @@ void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) s.avail_in = *lenp - i; s.next_out = dst; s.avail_out = dstlen; +printf("doing inflate\n"); r = inflate(&s, Z_FINISH); +printf("done inflate\n"); if (r != Z_OK && r != Z_STREAM_END) { printf("inflate returned %d\n", r); exit(); } *lenp = s.next_out - (unsigned char *) dst; +printf("doing end\n"); inflateEnd(&s); } diff --git a/arch/ppc/coffboot/zlib.h b/arch/ppc/coffboot/zlib.h index f4ab77617..f3bee01a7 100644 --- a/arch/ppc/coffboot/zlib.h +++ b/arch/ppc/coffboot/zlib.h @@ -1,4 +1,4 @@ -/* $Id: zlib.h,v 1.1 1997/08/30 04:51:49 ralf Exp $ */ +/* $Id: zlib.h,v 1.1 1997/07/31 07:16:15 paulus Exp $ */ /* * This file is derived from zlib.h and zconf.h from the zlib-0.95 diff --git a/arch/ppc/common_defconfig b/arch/ppc/common_defconfig index 9739f20da..44c17cfcb 100644 --- a/arch/ppc/common_defconfig +++ b/arch/ppc/common_defconfig @@ -35,7 +35,6 @@ CONFIG_SYSVIPC=y CONFIG_BINFMT_ELF=y CONFIG_KERNEL_ELF=y # CONFIG_BINFMT_MISC is not set -# CONFIG_BINFMT_JAVA is not set # CONFIG_PARPORT is not set CONFIG_VGA_CONSOLE=y CONFIG_FB=y @@ -44,8 +43,6 @@ CONFIG_PMAC_PBOOK=y CONFIG_MAC_KEYBOARD=y CONFIG_MAC_FLOPPY=y CONFIG_MAC_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set -CONFIG_ADBMOUSE=y CONFIG_PROC_DEVICETREE=y # CONFIG_TOTALMP is not set CONFIG_BOOTX_TEXT=y @@ -53,11 +50,6 @@ CONFIG_BOOTX_TEXT=y # CONFIG_CMDLINE_BOOL is not set # -# Plug and Play support -# -# CONFIG_PNP is not set - -# # Block devices # CONFIG_BLK_DEV_FD=y @@ -80,9 +72,11 @@ CONFIG_BLK_DEV_IDEFLOPPY=y CONFIG_BLK_DEV_SL82C105=y CONFIG_BLK_DEV_IDE_PMAC=y CONFIG_BLK_DEV_IDEDMA_PMAC=y -CONFIG_BLK_DEV_IDEDMA=y CONFIG_IDEDMA_PMAC_AUTO=y +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_IDEDMA_AUTO=y # CONFIG_IDE_CHIPSETS is not set +# CONFIG_BLK_CPQ_DA is not set # # Additional Block Devices @@ -230,10 +224,18 @@ CONFIG_SCSI_MAC53C94=y # Network device support # CONFIG_NETDEVICES=y + +# +# ARCnet devices +# # CONFIG_ARCNET is not set # CONFIG_DUMMY is not set # CONFIG_EQUALIZER is not set # CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# CONFIG_NET_ETHERNET=y CONFIG_MACE=y CONFIG_BMAC=y @@ -243,10 +245,10 @@ CONFIG_BMAC=y # CONFIG_NET_VENDOR_RACAL is not set # CONFIG_RTL8139 is not set # CONFIG_YELLOWFIN is not set -# CONFIG_ACENIC is not set # CONFIG_NET_ISA is not set CONFIG_NET_EISA=y CONFIG_PCNET32=y +# CONFIG_ACENIC is not set # CONFIG_AC3200 is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set @@ -265,7 +267,10 @@ CONFIG_DE4X5=y # CONFIG_NET_POCKET is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set -# CONFIG_DLCI is not set + +# +# Appletalk devices +# # CONFIG_LTPC is not set # CONFIG_COPS is not set # CONFIG_IPDDP is not set @@ -276,11 +281,21 @@ CONFIG_PPP=y # # CONFIG_SLIP is not set # CONFIG_NET_RADIO is not set + +# +# Token ring devices +# # CONFIG_TR is not set +# CONFIG_RCPCI is not set # CONFIG_SHAPER is not set + +# +# Wan interfaces +# # CONFIG_HOSTESS_SV11 is not set # CONFIG_COSA is not set -# CONFIG_RCPCI is not set +# CONFIG_SEALEVEL_4021 is not set +# CONFIG_DLCI is not set # # Amateur Radio support @@ -342,14 +357,16 @@ CONFIG_SERIAL=m # CONFIG_SERIAL_NONSTANDARD is not set CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 -CONFIG_MOUSE=y # # Mice # +CONFIG_BUSMOUSE=y # CONFIG_ATIXL_BUSMOUSE is not set -# CONFIG_BUSMOUSE is not set +# CONFIG_LOGIBUSMOUSE is not set # CONFIG_MS_BUSMOUSE is not set +CONFIG_ADBMOUSE=y +CONFIG_MOUSE=y CONFIG_PSMOUSE=y # CONFIG_82C710_MOUSE is not set # CONFIG_PC110_PAD is not set @@ -383,17 +400,19 @@ CONFIG_NVRAM=y # CONFIG_FT_ALT_FDC is not set # +# USB drivers - not for the faint of heart +# +# CONFIG_USB is not set + +# # Filesystems # # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=y # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set -CONFIG_HFS_FS=y -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y -# CONFIG_UMSDOS_FS is not set -CONFIG_VFAT_FS=y +# CONFIG_HFS_FS is not set +# CONFIG_FAT_FS is not set # CONFIG_EFS_FS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set @@ -429,38 +448,7 @@ CONFIG_MAC_PARTITION=y # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_SGI_DISKLABEL is not set # CONFIG_UNIXWARE_DISKLABEL is not set -CONFIG_NLS=y - -# -# Native Language Support -# -CONFIG_NLS_CODEPAGE_437=y -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_ISO8859_1 is not set -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_ISO8859_15 is not set -# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS is not set # # Sound diff --git a/arch/ppc/config.in b/arch/ppc/config.in index 66eeedcc8..5d2d2165a 100644 --- a/arch/ppc/config.in +++ b/arch/ppc/config.in @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.80 1998/11/11 03:54:56 paulus Exp $ +# $Id: config.in,v 1.103 1999/09/01 19:04:44 cort Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -17,6 +17,7 @@ choice 'Machine Type' \ PReP/MTX CONFIG_PREP \ CHRP CONFIG_CHRP \ PowerMac/PReP/CHRP CONFIG_ALL_PPC \ + Gemini CONFIG_GEMINI \ APUS CONFIG_APUS \ MBX CONFIG_MBX" PowerMac @@ -25,8 +26,12 @@ if [ "$CONFIG_ALL_PPC" != "y" ];then define_bool CONFIG_MACH_SPECIFIC y fi -if [ "$CONFIG_PPC64" != "y" ];then - define_bool CONFIG_6xx y +if [ "$CONFIG_8xx" = "y" ]; then + bool 'Math emulation' CONFIG_MATH_EMULATION +else + if [ "$CONFIG_PPC64" != "y" ];then + define_bool CONFIG_6xx y + fi fi endmenu @@ -50,12 +55,6 @@ else define_bool CONFIG_PCI y fi -bool 'PCI quirks' CONFIG_PCI_QUIRKS -if [ "$CONFIG_PCI_QUIRKS" = "y" ]; then - bool ' PCI bridge optimization' CONFIG_PCI_OPTIMIZE -fi - -bool 'Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC bool 'Networking support' CONFIG_NET bool 'Sysctl support' CONFIG_SYSCTL bool 'System V IPC' CONFIG_SYSVIPC @@ -66,7 +65,7 @@ define_bool CONFIG_BINFMT_ELF y define_bool CONFIG_KERNEL_ELF y tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC -source drivers/misc/Config.in +source drivers/parport/Config.in bool 'Support for VGA Console' CONFIG_VGA_CONSOLE bool 'Support for frame buffer devices' CONFIG_FB @@ -77,11 +76,10 @@ fi bool 'Power management support for PowerBook 3400/2400' CONFIG_PMAC_PBOOK bool 'Support for PowerMac keyboard' CONFIG_MAC_KEYBOARD bool 'Support for PowerMac floppy' CONFIG_MAC_FLOPPY -bool 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL +tristate 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL if [ "$CONFIG_MAC_SERIAL" = "y" ]; then bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE fi -bool 'Support for PowerMac ADB mouse' CONFIG_ADBMOUSE bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE bool 'Support for TotalImpact TotalMP' CONFIG_TOTALMP bool 'Support for early boot text console (BootX only)' CONFIG_BOOTX_TEXT @@ -139,6 +137,9 @@ if [ "$CONFIG_NET" = "y" ]; then bool 'Network device support' CONFIG_NETDEVICES if [ "$CONFIG_NETDEVICES" = "y" ]; then source drivers/net/Config.in + if [ "$CONFIG_ATM" = "y" ]; then + source drivers/atm/Config.in + fi fi endmenu fi @@ -169,6 +170,7 @@ source drivers/video/Config.in endmenu source drivers/char/Config.in +source drivers/usb/Config.in source fs/Config.in mainmenu_option next_comment diff --git a/arch/ppc/defconfig b/arch/ppc/defconfig index 6b12d2309..44c17cfcb 100644 --- a/arch/ppc/defconfig +++ b/arch/ppc/defconfig @@ -43,8 +43,6 @@ CONFIG_PMAC_PBOOK=y CONFIG_MAC_KEYBOARD=y CONFIG_MAC_FLOPPY=y CONFIG_MAC_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set -CONFIG_ADBMOUSE=y CONFIG_PROC_DEVICETREE=y # CONFIG_TOTALMP is not set CONFIG_BOOTX_TEXT=y @@ -52,11 +50,6 @@ CONFIG_BOOTX_TEXT=y # CONFIG_CMDLINE_BOOL is not set # -# Plug and Play support -# -# CONFIG_PNP is not set - -# # Block devices # CONFIG_BLK_DEV_FD=y @@ -79,9 +72,11 @@ CONFIG_BLK_DEV_IDEFLOPPY=y CONFIG_BLK_DEV_SL82C105=y CONFIG_BLK_DEV_IDE_PMAC=y CONFIG_BLK_DEV_IDEDMA_PMAC=y -CONFIG_BLK_DEV_IDEDMA=y CONFIG_IDEDMA_PMAC_AUTO=y +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_IDEDMA_AUTO=y # CONFIG_IDE_CHIPSETS is not set +# CONFIG_BLK_CPQ_DA is not set # # Additional Block Devices @@ -229,10 +224,18 @@ CONFIG_SCSI_MAC53C94=y # Network device support # CONFIG_NETDEVICES=y + +# +# ARCnet devices +# # CONFIG_ARCNET is not set # CONFIG_DUMMY is not set # CONFIG_EQUALIZER is not set # CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# CONFIG_NET_ETHERNET=y CONFIG_MACE=y CONFIG_BMAC=y @@ -242,10 +245,10 @@ CONFIG_BMAC=y # CONFIG_NET_VENDOR_RACAL is not set # CONFIG_RTL8139 is not set # CONFIG_YELLOWFIN is not set -# CONFIG_ACENIC is not set # CONFIG_NET_ISA is not set CONFIG_NET_EISA=y CONFIG_PCNET32=y +# CONFIG_ACENIC is not set # CONFIG_AC3200 is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set @@ -264,7 +267,10 @@ CONFIG_DE4X5=y # CONFIG_NET_POCKET is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set -# CONFIG_DLCI is not set + +# +# Appletalk devices +# # CONFIG_LTPC is not set # CONFIG_COPS is not set # CONFIG_IPDDP is not set @@ -275,11 +281,21 @@ CONFIG_PPP=y # # CONFIG_SLIP is not set # CONFIG_NET_RADIO is not set + +# +# Token ring devices +# # CONFIG_TR is not set +# CONFIG_RCPCI is not set # CONFIG_SHAPER is not set + +# +# Wan interfaces +# # CONFIG_HOSTESS_SV11 is not set # CONFIG_COSA is not set -# CONFIG_RCPCI is not set +# CONFIG_SEALEVEL_4021 is not set +# CONFIG_DLCI is not set # # Amateur Radio support @@ -341,14 +357,16 @@ CONFIG_SERIAL=m # CONFIG_SERIAL_NONSTANDARD is not set CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 -CONFIG_MOUSE=y # # Mice # +CONFIG_BUSMOUSE=y # CONFIG_ATIXL_BUSMOUSE is not set -# CONFIG_BUSMOUSE is not set +# CONFIG_LOGIBUSMOUSE is not set # CONFIG_MS_BUSMOUSE is not set +CONFIG_ADBMOUSE=y +CONFIG_MOUSE=y CONFIG_PSMOUSE=y # CONFIG_82C710_MOUSE is not set # CONFIG_PC110_PAD is not set @@ -382,17 +400,19 @@ CONFIG_NVRAM=y # CONFIG_FT_ALT_FDC is not set # +# USB drivers - not for the faint of heart +# +# CONFIG_USB is not set + +# # Filesystems # # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=y # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set -CONFIG_HFS_FS=y -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y -# CONFIG_UMSDOS_FS is not set -CONFIG_VFAT_FS=y +# CONFIG_HFS_FS is not set +# CONFIG_FAT_FS is not set # CONFIG_EFS_FS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set @@ -428,38 +448,7 @@ CONFIG_MAC_PARTITION=y # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_SGI_DISKLABEL is not set # CONFIG_UNIXWARE_DISKLABEL is not set -CONFIG_NLS=y - -# -# Native Language Support -# -CONFIG_NLS_CODEPAGE_437=y -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_ISO8859_1 is not set -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_ISO8859_15 is not set -# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS is not set # # Sound diff --git a/arch/ppc/gemini_defconfig b/arch/ppc/gemini_defconfig new file mode 100644 index 000000000..f0f5dc3f6 --- /dev/null +++ b/arch/ppc/gemini_defconfig @@ -0,0 +1,352 @@ +# +# Automatically generated by make menuconfig: don't edit +# + +# +# Platform support +# +CONFIG_PPC=y +CONFIG_6xx=y +# CONFIG_PPC64 is not set +# CONFIG_8xx is not set +# CONFIG_PMAC is not set +# CONFIG_PREP is not set +# CONFIG_CHRP is not set +# CONFIG_ALL_PPC is not set +CONFIG_GEMINI=y +# CONFIG_APUS is not set +# CONFIG_MBX is not set +# CONFIG_SMP is not set +CONFIG_MACH_SPECIFIC=y +CONFIG_6xx=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_MODULES=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y +CONFIG_PCI=y +CONFIG_NET=y +CONFIG_SYSCTL=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_BINFMT_ELF=y +CONFIG_KERNEL_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PARPORT is not set +# CONFIG_VGA_CONSOLE is not set +# CONFIG_FB is not set +# CONFIG_PMAC_PBOOK is not set +CONFIG_MAC_KEYBOARD=y +# CONFIG_MAC_FLOPPY is not set +# CONFIG_MAC_SERIAL is not set +# CONFIG_PROC_DEVICETREE is not set +# CONFIG_TOTALMP is not set +# CONFIG_BOOTX_TEXT is not set +# CONFIG_MOTOROLA_HOTSWAP is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_IDE is not set +# CONFIG_BLK_DEV_HD_ONLY is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_XD is not set +CONFIG_PARIDE_PARPORT=y +# CONFIG_PARIDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK=y +# CONFIG_RTNETLINK is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +CONFIG_IP_ALIAS=y +CONFIG_SYN_COOKIES=y +CONFIG_SKB_LARGE=y +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_BRIDGE is not set +# CONFIG_LLC is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# SCSI support +# +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +CONFIG_BLK_DEV_SR=y +CONFIG_BLK_DEV_SR_VENDOR=y +# CONFIG_CHR_DEV_SG is not set +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_NCR53C8XX is not set +CONFIG_SCSI_SYM53C8XX=y +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 +CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 +CONFIG_SCSI_NCR53C8XX_SYNC=20 +# CONFIG_SCSI_NCR53C8XX_PROFILE is not set +# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set +# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set +# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_SEAGATE is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_MESH is not set +# CONFIG_SCSI_MAC53C94 is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +# CONFIG_ETHERTAP is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +# CONFIG_NET_ETHERNET is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_RADIO is not set + +# +# Token ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_HOSTESS_SV11 is not set +# CONFIG_COSA is not set +# CONFIG_SEALEVEL_4021 is not set +# CONFIG_DLCI is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Console drivers +# + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_PC_KEYB=y +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# Mice +# +CONFIG_BUSMOUSE=y +# CONFIG_ATIXL_BUSMOUSE is not set +# CONFIG_LOGIBUSMOUSE is not set +# CONFIG_MS_BUSMOUSE is not set +CONFIG_ADBMOUSE=y +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_QIC02_TAPE is not set +# CONFIG_WATCHDOG is not set +CONFIG_NVRAM=y +# CONFIG_RTC is not set + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV is not set + +# +# Joystick support +# +# CONFIG_JOYSTICK is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set + +# +# USB drivers - not for the faint of heart +# +# CONFIG_USB is not set + +# +# Filesystems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_NFS_FS is not set +# CONFIG_NFSD is not set +# CONFIG_SUNRPC is not set +# CONFIG_LOCKD is not set +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Kernel hacking +# +CONFIG_MAGIC_SYSRQ=y +# CONFIG_KGDB is not set +# CONFIG_XMON is not set diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index 635dd91b5..a177a3642 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -14,8 +14,11 @@ O_TARGET := kernel.o OX_OBJS := ppc_ksyms.o setup.o -O_OBJS := traps.o irq.o idle.o time.o process.o signal.o syscalls.o misc.o \ - bitops.o ptrace.o align.o ppc_htab.o +O_OBJS := entry.o traps.o irq.o idle.o time.o process.o signal.o syscalls.o \ + misc.o bitops.o ptrace.o align.o ppc_htab.o semaphore.o +ifndef CONFIG_8xx +O_OBJS += hashtable.o +endif ifdef CONFIG_PCI O_OBJS += pci.o endif @@ -27,17 +30,18 @@ O_OBJS += totalmp.o endif ifeq ($(CONFIG_MBX),y) -O_OBJS += mbx_setup.o mbx_pci.o softemu8xx.o i8259.o ppc8xx_pic.o +O_OBJS += mbx_setup.o mbx_pci.o i8259.o ppc8xx_pic.o else ifeq ($(CONFIG_APUS),y) -O_OBJS += apus_setup.o prom.o openpic.o +O_OBJS += apus_setup.o prom.o open_pic.o else ifneq ($(CONFIG_MBX),y) O_OBJS += prep_time.o pmac_time.o chrp_time.o \ pmac_setup.o pmac_support.o \ prep_pci.o pmac_pci.o chrp_pci.o \ - residual.o prom.o openpic.o feature.o \ - prep_nvram.o open_pic.o i8259.o pmac_pic.o indirect_pci.o + residual.o prom.o open_pic.o feature.o \ + prep_nvram.o i8259.o pmac_pic.o indirect_pci.o \ + gemini_pci.o gemini_prom.o gemini_setup.o OX_OBJS += chrp_setup.o prep_setup.o endif endif @@ -49,7 +53,7 @@ endif all: head.o kernel.o -head.o: head.S $(TOPDIR)/include/linux/tasks.h ppc_defs.h +head.o: head.S ppc_defs.h ppc_defs.h: mk_defs.c ppc_defs.head \ $(TOPDIR)/include/asm/mmu.h \ @@ -65,7 +69,7 @@ find_name : find_name.c $(HOSTCC) $(HOSTCFLAGS) -o find_name find_name.c checks: checks.c - $(HOSTCC) $(HOSTCFLAGS) -D__KERNEL__ -o checks checks.c + $(HOSTCC) -I$(HPATH) $(HOSTCFLAGS) -D__KERNEL__ -fno-builtin -o checks checks.c ./checks include $(TOPDIR)/Rules.make diff --git a/arch/ppc/kernel/align.c b/arch/ppc/kernel/align.c index cf5fcffd3..6a20863c5 100644 --- a/arch/ppc/kernel/align.c +++ b/arch/ppc/kernel/align.c @@ -243,10 +243,10 @@ fix_alignment(struct pt_regs *regs) } break; case LD+F: - current->tss.fpr[reg] = data.d; + current->thread.fpr[reg] = data.d; break; case ST+F: - data.d = current->tss.fpr[reg]; + data.d = current->thread.fpr[reg]; break; /* these require some floating point conversions... */ /* we'd like to use the assignment, but we have to compile @@ -254,13 +254,13 @@ fix_alignment(struct pt_regs *regs) * fp regs for copying 8-byte objects. */ case LD+F+S: enable_kernel_fp(); - cvt_fd(&data.f, ¤t->tss.fpr[reg], ¤t->tss.fpscr); - /* current->tss.fpr[reg] = data.f; */ + cvt_fd(&data.f, ¤t->thread.fpr[reg], ¤t->thread.fpscr); + /* current->thread.fpr[reg] = data.f; */ break; case ST+F+S: enable_kernel_fp(); - cvt_df(¤t->tss.fpr[reg], &data.f, ¤t->tss.fpscr); - /* data.f = current->tss.fpr[reg]; */ + cvt_df(¤t->thread.fpr[reg], &data.f, ¤t->thread.fpscr); + /* data.f = current->thread.fpr[reg]; */ break; default: printk("align: can't handle flags=%x\n", flags); diff --git a/arch/ppc/kernel/apus_setup.c b/arch/ppc/kernel/apus_setup.c index 2540e0911..5b9e3f137 100644 --- a/arch/ppc/kernel/apus_setup.c +++ b/arch/ppc/kernel/apus_setup.c @@ -103,8 +103,8 @@ static int __60nsram = 0; /*********************************************************** SETUP */ /* From arch/m68k/kernel/setup.c. */ -__initfunc(void apus_setup_arch(unsigned long * memory_start_p, - unsigned long * memory_end_p)) +void __init apus_setup_arch(unsigned long * memory_start_p, + unsigned long * memory_end_p) { extern char cmd_line[]; int i; @@ -245,7 +245,7 @@ void arch_gettod(int *year, int *mon, int *day, int *hour, /*********************************************************** FLOPPY */ #if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY) -__initfunc(void floppy_setup(char *str, int *ints)) +void __init floppy_setup(char *str, int *ints) { if (mach_floppy_setup) mach_floppy_setup (str, ints); @@ -325,11 +325,11 @@ void kernel_set_cachemode( unsigned long address, unsigned long size, switch (cmode) { - case KERNELMAP_FULL_CACHING: + case IOMAP_FULL_CACHING: mask = ~(_PAGE_NO_CACHE | _PAGE_GUARDED); flags = 0; break; - case KERNELMAP_NOCACHE_SER: + case IOMAP_NOCACHE_SER: mask = ~0; flags = (_PAGE_NO_CACHE | _PAGE_GUARDED); break; @@ -345,7 +345,7 @@ void kernel_set_cachemode( unsigned long address, unsigned long size, { pte_t *pte; - pte = my_find_pte(init_task.mm, address); + pte = my_find_pte(&init_mm, address); if ( !pte ) { printk("pte NULL in kernel_set_cachemode()\n"); @@ -354,7 +354,7 @@ void kernel_set_cachemode( unsigned long address, unsigned long size, pte_val (*pte) &= mask; pte_val (*pte) |= flags; - flush_tlb_page(find_vma(init_task.mm,address),address); + flush_tlb_page(find_vma(&init_mm,address),address); address += PAGE_SIZE; } @@ -560,24 +560,24 @@ apus_ide_fix_driveid(struct hd_driveid *id) m68k_ide_fix_driveid(id); } -__initfunc(void -apus_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)) +void __init +apus_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) { m68k_ide_init_hwif_ports(hw, data_port, ctrl_port, irq); } #endif -__initfunc(void -apus_local_init_IRQ(void)) +void __init +apus_local_init_IRQ(void) { ppc_md.mask_irq = amiga_disable_irq; ppc_md.unmask_irq = amiga_enable_irq; apus_init_IRQ(); } -__initfunc(void +void __init apus_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7)) + unsigned long r6, unsigned long r7) { /* Parse bootinfo. The bootinfo is located right after the kernel bss */ diff --git a/arch/ppc/kernel/chrp_pci.c b/arch/ppc/kernel/chrp_pci.c index c82671947..397f69c18 100644 --- a/arch/ppc/kernel/chrp_pci.c +++ b/arch/ppc/kernel/chrp_pci.c @@ -97,7 +97,7 @@ int gg2_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, #define python_config_data(bus) ((0xfef00000+0xf8010)-(bus*0x100000)) #define PYTHON_CFA(b, d, o) (0x80 | ((b<<6) << 8) | ((d) << 16) \ | (((o) & ~3) << 24)) -unsigned int python_busnr = 1; +unsigned int python_busnr = 0; int python_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned char *val) @@ -279,8 +279,7 @@ chrp_pcibios_fixup(void) if ( !strncmp("IBM", get_property(find_path_device("/"), "name", NULL),3) ) { - pci_scan_peer_bridge(1); - pci_scan_peer_bridge(2); + } /* PCI interrupts are controlled by the OpenPIC */ @@ -290,22 +289,22 @@ chrp_pcibios_fixup(void) dev->irq = openpic_to_irq( dev->irq ); /* adjust the io_port for the NCR cards for busses other than 0 -- Cort */ if ( (dev->bus->number > 0) && (dev->vendor == PCI_VENDOR_ID_NCR) ) - dev->base_address[0] += (dev->bus->number*0x08000000); + dev->resource[0].start += (dev->bus->number*0x08000000); /* these need to be absolute addrs for OF and Matrox FB -- Cort */ if ( dev->vendor == PCI_VENDOR_ID_MATROX ) { - if ( dev->base_address[0] < isa_mem_base ) - dev->base_address[0] += isa_mem_base; - if ( dev->base_address[1] < isa_mem_base ) - dev->base_address[1] += isa_mem_base; + if ( dev->resource[0].start < isa_mem_base ) + dev->resource[0].start += isa_mem_base; + if ( dev->resource[1].start < isa_mem_base ) + dev->resource[1].start += isa_mem_base; } /* the F50 identifies the amd as a trident */ if ( (dev->vendor == PCI_VENDOR_ID_TRIDENT) && - (dev->class == PCI_CLASS_NETWORK_ETHERNET) ) + (dev->class>>8 == PCI_CLASS_NETWORK_ETHERNET) ) { dev->vendor = PCI_VENDOR_ID_AMD; - pcibios_write_config_word(dev->bus->number, dev->devfn, - PCI_VENDOR_ID, PCI_VENDOR_ID_AMD); + pcibios_write_config_word(dev->bus->number, + dev->devfn, PCI_VENDOR_ID, PCI_VENDOR_ID_AMD); } } } @@ -347,7 +346,7 @@ chrp_setup_pci_ptrs(void) } else if ( !strncmp("IBM,7043-260", get_property(find_path_device("/"), "name", NULL),12) ) { - pci_dram_offset = 0x80000000; + pci_dram_offset = 0x0; isa_mem_base = 0xc0000000; isa_io_base = 0xf8000000; } diff --git a/arch/ppc/kernel/chrp_setup.c b/arch/ppc/kernel/chrp_setup.c index 1653ef0d7..7faa1ed4b 100644 --- a/arch/ppc/kernel/chrp_setup.c +++ b/arch/ppc/kernel/chrp_setup.c @@ -71,6 +71,8 @@ void chrp_calibrate_decr(void); void chrp_time_init(void); void chrp_setup_pci_ptrs(void); +extern void chrp_progress(char *, unsigned short); +void chrp_event_scan(void); extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int pckbd_getkeycode(unsigned int scancode); @@ -189,20 +191,20 @@ chrp_get_cpuinfo(char *buffer) * for keyboard and mouse */ -__initfunc(static inline void sio_write(u8 val, u8 index)) +static inline void __init sio_write(u8 val, u8 index) { outb(index, 0x15c); outb(val, 0x15d); } -__initfunc(static inline u8 sio_read(u8 index)) +static inline u8 __init sio_read(u8 index) { outb(index, 0x15c); return inb(0x15d); } -__initfunc(static void sio_fixup_irq(const char *name, u8 device, u8 level, - u8 type)) +static void __init sio_fixup_irq(const char *name, u8 device, u8 level, + u8 type) { u8 level0, type0, active; @@ -224,7 +226,7 @@ __initfunc(static void sio_fixup_irq(const char *name, u8 device, u8 level, } -__initfunc(static void sio_init(void)) +static void __init sio_init(void) { /* logical device 0 (KBC/Keyboard) */ sio_fixup_irq("keyboard", 0, 1, 2); @@ -233,8 +235,8 @@ __initfunc(static void sio_init(void)) } -__initfunc(void - chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)) +void __init + chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p) { extern char cmd_line[]; struct device_node *device; @@ -313,7 +315,10 @@ void chrp_event_scan(void) { unsigned char log[1024]; - call_rtas( "event-scan", 4, 1, NULL, 0x0, 1, __pa(log), 1024 ); + unsigned long ret = 0; + /* XXX: we should loop until the hardware says no more error logs -- Cort */ + call_rtas( "event-scan", 4, 1, &ret, 0xffffffff, 0, + __pa(log), 1024 ); ppc_md.heartbeat_count = ppc_md.heartbeat_reset; } @@ -329,12 +334,8 @@ void chrp_power_off(void) { /* allow power on only with power button press */ -#define PWR_FIELD(x) (0x8000000000000000ULL >> ((x)-96)) printk("RTAS power-off returned %d\n", - call_rtas("power-off", 2, 1, NULL, - ((PWR_FIELD(96)|PWR_FIELD(97))>>32)&0xffffffff, - (PWR_FIELD(96)|PWR_FIELD(97))&0xffffffff)); -#undef PWR_FIELD + call_rtas("power-off", 2, 1, NULL,0xffffffff,0xffffffff)); for (;;); } @@ -432,8 +433,8 @@ out: openpic_eoi(0); } -__initfunc(void - chrp_init_IRQ(void)) +void __init + chrp_init_IRQ(void) { struct device_node *np; int i; @@ -446,12 +447,9 @@ __initfunc(void (*(unsigned long *)get_property(np, "8259-interrupt-acknowledge", NULL)); } + open_pic.irq_offset = 16; for ( i = 16 ; i < NR_IRQS ; i++ ) irq_desc[i].ctl = &open_pic; - /* openpic knows that it's at irq 16 offset - * so we don't need to set it in the pic structure - * -- Cort - */ openpic_init(1); for ( i = 0 ; i < 16 ; i++ ) irq_desc[i].ctl = &i8259_pic; @@ -466,8 +464,8 @@ __initfunc(void #endif /* __SMP__ */ } -__initfunc(void - chrp_init2(void)) +void __init + chrp_init2(void) { adb_init(); @@ -491,12 +489,9 @@ void chrp_ide_probe(void) { chrp_ide_ports_known = 1; if(pdev) { - chrp_ide_regbase[0]=pdev->base_address[0] & - PCI_BASE_ADDRESS_IO_MASK; - chrp_ide_regbase[1]=pdev->base_address[2] & - PCI_BASE_ADDRESS_IO_MASK; - chrp_idedma_regbase=pdev->base_address[4] & - PCI_BASE_ADDRESS_IO_MASK; + chrp_ide_regbase[0]=pdev->resource[0].start; + chrp_ide_regbase[1]=pdev->resource[2].start; + chrp_idedma_regbase=pdev->resource[4].start; chrp_ide_irq=pdev->irq; } } @@ -582,17 +577,17 @@ EXPORT_SYMBOL(chrp_ide_probe); #endif -__initfunc(void +void __init chrp_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7)) + unsigned long r6, unsigned long r7) { chrp_setup_pci_ptrs(); #ifdef CONFIG_BLK_DEV_INITRD /* take care of initrd if we have one */ - if ( r3 ) + if ( r6 ) { - initrd_start = r3 + KERNELBASE; - initrd_end = r3 + r4 + KERNELBASE; + initrd_start = r6 + KERNELBASE; + initrd_end = r6 + r7 + KERNELBASE; } #endif /* CONFIG_BLK_DEV_INITRD */ @@ -658,6 +653,8 @@ __initfunc(void ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate; SYSRQ_KEY = 0x54; #endif + if ( rtas_data ) + ppc_md.progress = chrp_progress; #endif #endif @@ -678,16 +675,48 @@ __initfunc(void * Print the banner, then scroll down so boot progress * can be printed. -- Cort */ - chrp_progress("Linux/PPC "UTS_RELEASE"\n"); + if ( ppc_md.progress ) ppc_md.progress("Linux/PPC "UTS_RELEASE"\n", 0x0); } -void chrp_progress(char *s) +void chrp_progress(char *s, unsigned short hex) { extern unsigned int rtas_data; - + int max_width, width; + struct device_node *root; + char *os = s; + unsigned long *p; + + if ( (root = find_path_device("/rtas")) && + (p = (unsigned long *)get_property(root, + "ibm,display-line-length", + NULL)) ) + max_width = *p; + else + max_width = 0x10; + if ( (_machine != _MACH_chrp) || !rtas_data ) return; - call_rtas( "display-character", 1, 1, NULL, '\r' ); - while ( *s ) - call_rtas( "display-character", 1, 1, NULL, *s++ ); + if ( call_rtas( "display-character", 1, 1, NULL, '\r' ) ) + { + /* assume no display-character RTAS method - use hex display */ + return; + } + + width = max_width; + while ( *os ) + { + if ( (*os == '\n') || (*os == '\r') ) + width = max_width; + else + width--; + call_rtas( "display-character", 1, 1, NULL, *os++ ); + /* if we overwrite the screen length */ + if ( width == 0 ) + while ( (*os != 0) && (*os != '\n') && (*os != '\r') ) + os++; + } + + /*while ( width-- > 0 )*/ + call_rtas( "display-character", 1, 1, NULL, ' ' ); } + diff --git a/arch/ppc/kernel/chrp_time.c b/arch/ppc/kernel/chrp_time.c index c374c9bd1..50c7417fb 100644 --- a/arch/ppc/kernel/chrp_time.c +++ b/arch/ppc/kernel/chrp_time.c @@ -31,7 +31,7 @@ static int nvram_as1 = NVRAM_AS1; static int nvram_as0 = NVRAM_AS0; static int nvram_data = NVRAM_DATA; -__initfunc(void chrp_time_init(void)) +void __init chrp_time_init(void) { struct device_node *rtcs; int base; @@ -151,7 +151,7 @@ unsigned long chrp_get_rtc_time(void) } -__initfunc(void chrp_calibrate_decr(void)) +void __init chrp_calibrate_decr(void) { struct device_node *cpu; int *fp, divisor; diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S new file mode 100644 index 000000000..abff78bc3 --- /dev/null +++ b/arch/ppc/kernel/entry.S @@ -0,0 +1,434 @@ +/* + * arch/ppc/kernel/entry.S + * + * $Id: entry.S,v 1.3 1999/09/05 11:56:26 paulus Exp $ + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP + * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu> + * Adapted for Power Macintosh by Paul Mackerras. + * Low-level exception handlers and MMU support + * rewritten by Paul Mackerras. + * Copyright (C) 1996 Paul Mackerras. + * MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net). + * + * This file contains the system call entry code, context switch + * code, and exception/interrupt return code for PowerPC. + * + * This program 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. + * + */ + +#include "ppc_asm.h" +#include <asm/processor.h> +#include <asm/page.h> +#include <linux/errno.h> +#include <linux/sys.h> +#include <linux/config.h> + +#define SHOW_SYSCALLS +#define SHOW_SYSCALLS_TASK + +#ifdef SHOW_SYSCALLS_TASK + .data +show_syscalls_task: + .long -1 +#endif + +/* + * Handle a system call. + */ + .text +_GLOBAL(DoSyscall) + stw r0,THREAD+LAST_SYSCALL(r2) + lwz r11,_CCR(r1) /* Clear SO bit in CR */ + lis r10,0x1000 + andc r11,r11,r10 + stw r11,_CCR(r1) +#ifdef SHOW_SYSCALLS +#ifdef SHOW_SYSCALLS_TASK + lis r31,show_syscalls_task@ha + lwz r31,show_syscalls_task@l(r31) + cmp 0,r2,r31 + bne 1f +#endif + lis r3,7f@ha + addi r3,r3,7f@l + lwz r4,GPR0(r1) + lwz r5,GPR3(r1) + lwz r6,GPR4(r1) + lwz r7,GPR5(r1) + lwz r8,GPR6(r1) + lwz r9,GPR7(r1) + bl printk + lis r3,77f@ha + addi r3,r3,77f@l + lwz r4,GPR8(r1) + lwz r5,GPR9(r1) + mr r6,r2 + bl printk + lwz r0,GPR0(r1) + lwz r3,GPR3(r1) + lwz r4,GPR4(r1) + lwz r5,GPR5(r1) + lwz r6,GPR6(r1) + lwz r7,GPR7(r1) + lwz r8,GPR8(r1) +1: +#endif /* SHOW_SYSCALLS */ + cmpi 0,r0,0x7777 /* Special case for 'sys_sigreturn' */ + beq- 10f + lwz r10,TASK_FLAGS(r2) + andi. r10,r10,PF_TRACESYS + bne- 50f + cmpli 0,r0,NR_syscalls + bge- 66f + lis r10,sys_call_table@h + ori r10,r10,sys_call_table@l + slwi r0,r0,2 + lwzx r10,r10,r0 /* Fetch system call handler [ptr] */ + cmpi 0,r10,0 + beq- 66f + mtlr r10 + addi r9,r1,STACK_FRAME_OVERHEAD + blrl /* Call handler */ + .globl ret_from_syscall_1 +ret_from_syscall_1: +20: stw r3,RESULT(r1) /* Save result */ +#ifdef SHOW_SYSCALLS +#ifdef SHOW_SYSCALLS_TASK + cmp 0,r2,r31 + bne 91f +#endif + mr r4,r3 + lis r3,79f@ha + addi r3,r3,79f@l + bl printk + lwz r3,RESULT(r1) +91: +#endif + li r10,-_LAST_ERRNO + cmpl 0,r3,r10 + blt 30f + neg r3,r3 + cmpi 0,r3,ERESTARTNOHAND + bne 22f + li r3,EINTR +22: lwz r10,_CCR(r1) /* Set SO bit in CR */ + oris r10,r10,0x1000 + stw r10,_CCR(r1) +30: stw r3,GPR3(r1) /* Update return value */ + b ret_from_except +66: li r3,ENOSYS + b 22b +/* sys_sigreturn */ +10: addi r3,r1,STACK_FRAME_OVERHEAD + bl sys_sigreturn + cmpi 0,r3,0 /* Check for restarted system call */ + bge ret_from_except + b 20b +/* Traced system call support */ +50: bl syscall_trace + lwz r0,GPR0(r1) /* Restore original registers */ + lwz r3,GPR3(r1) + lwz r4,GPR4(r1) + lwz r5,GPR5(r1) + lwz r6,GPR6(r1) + lwz r7,GPR7(r1) + lwz r8,GPR8(r1) + lwz r9,GPR9(r1) + cmpli 0,r0,NR_syscalls + bge- 66f + lis r10,sys_call_table@h + ori r10,r10,sys_call_table@l + slwi r0,r0,2 + lwzx r10,r10,r0 /* Fetch system call handler [ptr] */ + cmpi 0,r10,0 + beq- 66f + mtlr r10 + addi r9,r1,STACK_FRAME_OVERHEAD + blrl /* Call handler */ + .globl ret_from_syscall_2 +ret_from_syscall_2: + stw r3,RESULT(r1) /* Save result */ + stw r3,GPR0(r1) /* temporary gross hack to make strace work */ + li r10,-_LAST_ERRNO + cmpl 0,r3,r10 + blt 60f + neg r3,r3 + cmpi 0,r3,ERESTARTNOHAND + bne 52f + li r3,EINTR +52: lwz r10,_CCR(r1) /* Set SO bit in CR */ + oris r10,r10,0x1000 + stw r10,_CCR(r1) +60: stw r3,GPR3(r1) /* Update return value */ + bl syscall_trace + b ret_from_except +66: li r3,ENOSYS + b 52b +#ifdef SHOW_SYSCALLS +7: .string "syscall %d(%x, %x, %x, %x, %x, " +77: .string "%x, %x), current=%p\n" +79: .string " -> %x\n" + .align 2 +#endif + +/* + * This routine switches between two different tasks. The process + * state of one is saved on its kernel stack. Then the state + * of the other is restored from its kernel stack. The memory + * management hardware is updated to the second process's state. + * Finally, we can return to the second process, via ret_from_except. + * On entry, r3 points to the THREAD for the current task, r4 + * points to the THREAD for the new task. + * + * Note: there are two ways to get to the "going out" portion + * of this code; either by coming in via the entry (_switch) + * or via "fork" which must set up an environment equivalent + * to the "_switch" path. If you change this (or in particular, the + * SAVE_REGS macro), you'll have to change the fork code also. + * + * The code which creates the new task context is in 'copy_thread' + * in arch/ppc/kernel/process.c + */ +_GLOBAL(_switch) + stwu r1,-INT_FRAME_SIZE(r1) + stw r0,GPR0(r1) + lwz r0,0(r1) + stw r0,GPR1(r1) + /* r3-r13 are caller saved -- Cort */ + SAVE_GPR(2, r1) + SAVE_8GPRS(14, r1) + SAVE_10GPRS(22, r1) + mflr r20 /* Return to switch caller */ + mfmsr r22 + li r0,MSR_FP /* Disable floating-point */ + andc r22,r22,r0 + stw r20,_NIP(r1) + stw r22,_MSR(r1) + stw r20,_LINK(r1) + mfcr r20 + mfctr r22 + mfspr r23,XER + stw r20,_CCR(r1) + stw r22,_CTR(r1) + stw r23,_XER(r1) + li r0,0x0ff0 + stw r0,TRAP(r1) + stw r1,KSP(r3) /* Set old stack pointer */ + sync + tophys(r0,r4) + mtspr SPRG3,r0 /* Update current THREAD phys addr */ +#ifdef CONFIG_8xx + /* XXX it would be nice to find a SPRGx for this on 6xx,7xx too */ + lwz r9,PGDIR(r4) /* cache the page table root */ + tophys(r9,r9) /* convert to phys addr */ + mtspr M_TWB,r9 /* Update MMU base address */ +#endif /* CONFIG_8xx */ + lwz r1,KSP(r4) /* Load new stack pointer */ + /* save the old current 'last' for return value */ + mr r3,r2 + addi r2,r4,-THREAD /* Update current */ + lwz r9,_MSR(r1) /* Returning to user mode? */ + andi. r9,r9,MSR_PR + beq+ 10f /* if not, don't adjust kernel stack */ +8: addi r4,r1,INT_FRAME_SIZE /* size of frame */ + stw r4,THREAD+KSP(r2) /* save kernel stack pointer */ + tophys(r9,r1) + mtspr SPRG2,r9 /* phys exception stack pointer */ +10: lwz r2,_CTR(r1) + lwz r0,_LINK(r1) + mtctr r2 + mtlr r0 + lwz r2,_XER(r1) + lwz r0,_CCR(r1) + mtspr XER,r2 + mtcrf 0xFF,r0 + /* r3-r13 are destroyed -- Cort */ + REST_GPR(14, r1) + REST_8GPRS(15, r1) + REST_8GPRS(23, r1) + REST_GPR(31, r1) + lwz r2,_NIP(r1) /* Restore environment */ + lwz r0,_MSR(r1) + mtspr SRR0,r2 + mtspr SRR1,r0 + lwz r0,GPR0(r1) + lwz r2,GPR2(r1) + lwz r1,GPR1(r1) + SYNC + rfi + +/* + * ret_from_int(): + * + * Return from an interrupt (external interrupt and + * decrementer). This checks the first argument so + * we know if rtl_intercept wants us to check for + * a bottom half, signals and so on (normal return) or + * we're returning from a real-time interrupt or have + * interrupts soft disabled so we cannot enter Linux. + * -- Cort + */ + .globl ret_from_int +ret_from_int: + cmpi 0,r3,0 + beq 10f + /* we're allowed to do signal/bh checks */ + b ret_from_syscall +#ifdef __SMP__ + .globl ret_from_smpfork +ret_from_smpfork: + bl schedule_tail +#endif + .globl ret_from_syscall +ret_from_syscall: + .globl ret_from_except +ret_from_except: +0: mfmsr r30 /* Disable interrupts */ + rlwinm r30,r30,0,17,15 /* clear MSR_EE */ + SYNC /* Some chip revs need this... */ + mtmsr r30 + SYNC + lwz r5,_MSR(r1) + andi. r5,r5,MSR_EE + beq 2f +3: lis r4,ppc_n_lost_interrupts@ha + lwz r4,ppc_n_lost_interrupts@l(r4) + cmpi 0,r4,0 + beq+ 1f + addi r3,r1,STACK_FRAME_OVERHEAD + bl do_IRQ + .globl lost_irq_ret +lost_irq_ret: + b 3b +1: lis r4,bh_mask@ha + lwz r4,bh_mask@l(r4) + lis r5,bh_active@ha + lwz r5,bh_active@l(r5) + and. r4,r4,r5 + beq+ 2f + bl do_bottom_half + .globl do_bottom_half_ret +do_bottom_half_ret: +2: SYNC + mtmsr r30 /* disable interrupts again */ + SYNC + lwz r3,_MSR(r1) /* Returning to user mode? */ + andi. r3,r3,MSR_PR + beq+ 10f /* if so, check need_resched and signals */ + lwz r3,NEED_RESCHED(r2) + cmpi 0,r3,0 /* check need_resched flag */ + beq+ 7f + bl schedule + b 0b +7: lwz r5,SIGPENDING(r2) /* Check for pending unblocked signals */ + cmpwi 0,r5,0 + beq+ 8f + li r3,0 + addi r4,r1,STACK_FRAME_OVERHEAD + bl do_signal + .globl do_signal_ret +do_signal_ret: + b 0b +8: addi r4,r1,INT_FRAME_SIZE /* size of frame */ + stw r4,THREAD+KSP(r2) /* save kernel stack pointer */ + tophys(r3,r1) + mtspr SPRG2,r3 /* phys exception stack pointer */ +10: lwz r2,_CTR(r1) + lwz r0,_LINK(r1) + mtctr r2 + mtlr r0 + lwz r2,_XER(r1) + lwz r0,_CCR(r1) + mtspr XER,r2 + mtcrf 0xFF,r0 + REST_10GPRS(3, r1) + REST_10GPRS(13, r1) + REST_8GPRS(23, r1) + REST_GPR(31, r1) + lwz r2,_NIP(r1) /* Restore environment */ + lwz r0,_MSR(r1) + mtspr SRR0,r2 + mtspr SRR1,r0 + lwz r0,GPR0(r1) + lwz r2,GPR2(r1) + lwz r1,GPR1(r1) + SYNC + rfi + +/* + * Fake an interrupt from kernel mode. + * This is used when enable_irq loses an interrupt. + * We only fill in the stack frame minimally. + */ +_GLOBAL(fake_interrupt) + mflr r0 + stw r0,4(r1) + stwu r1,-INT_FRAME_SIZE(r1) + stw r0,_NIP(r1) + stw r0,_LINK(r1) + mfmsr r3 + stw r3,_MSR(r1) + li r0,0x0fac + stw r0,TRAP(r1) + addi r3,r1,STACK_FRAME_OVERHEAD + li r4,1 + bl do_IRQ + addi r1,r1,INT_FRAME_SIZE + lwz r0,4(r1) + mtlr r0 + blr + +#ifndef CONFIG_8xx +/* + * PROM code for specific machines follows. Put it + * here so it's easy to add arch-specific sections later. + * -- Cort + */ + +/* + * On CHRP, the Run-Time Abstraction Services (RTAS) have to be + * called with the MMU off. + */ + .globl enter_rtas +enter_rtas: + mflr r0 + stw r0,20(r1) + lis r4,rtas_data@ha + lwz r4,rtas_data@l(r4) + addis r4,r4,-KERNELBASE@h + lis r6,1f@ha /* physical return address for rtas */ + addi r6,r6,1f@l + addis r6,r6,-KERNELBASE@h + subi r7,r1,INT_FRAME_SIZE + addis r7,r7,-KERNELBASE@h + lis r8,rtas_entry@ha + lwz r8,rtas_entry@l(r8) + addis r5,r8,-KERNELBASE@h + mfmsr r9 + stw r9,8(r1) + ori r0,r0,MSR_EE|MSR_SE|MSR_BE + andc r0,r9,r0 + andi. r9,r9,MSR_ME|MSR_RI + sync /* disable interrupts so SRR0/1 */ + mtmsr r0 /* don't get trashed */ + mtlr r6 + mtspr SPRG2,r7 + mtspr SRR0,r8 + mtspr SRR1,r9 + rfi +1: addis r9,r1,-KERNELBASE@h + lwz r8,20(r9) /* get return address */ + lwz r9,8(r9) /* original msr value */ + li r0,0 + mtspr SPRG2,r0 + mtspr SRR0,r8 + mtspr SRR1,r9 + rfi /* return to caller */ +#endif /* CONFIG_8xx */ diff --git a/arch/ppc/kernel/gemini_pci.c b/arch/ppc/kernel/gemini_pci.c new file mode 100644 index 000000000..89ed43501 --- /dev/null +++ b/arch/ppc/kernel/gemini_pci.c @@ -0,0 +1,265 @@ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/malloc.h> + +#include <asm/machdep.h> +#include <asm/gemini.h> +#include <asm/byteorder.h> +#include <asm/io.h> +#include <asm/uaccess.h> + +#include "pci.h" + +#define pci_config_addr(bus,dev,offset) \ + (0x80000000 | (bus<<16) | (dev<<8) | offset) + + +int +gemini_pcibios_read_config_byte(unsigned char bus, unsigned char dev, + unsigned char offset, unsigned char *val) +{ + unsigned long reg; + reg = grackle_read( pci_config_addr( bus, dev, (offset & ~(0x3)))); + *val = ((reg >> ((offset & 0x3) << 3)) & 0xff); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_read_config_word(unsigned char bus, unsigned char dev, + unsigned char offset, unsigned short *val) +{ + unsigned long reg; + reg = grackle_read( pci_config_addr( bus, dev, (offset & ~(0x3)))); + *val = ((reg >> ((offset & 0x3) << 3)) & 0xffff); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_read_config_dword(unsigned char bus, unsigned char dev, + unsigned char offset, unsigned int *val) +{ + *val = grackle_read( pci_config_addr( bus, dev, (offset & ~(0x3)))); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_write_config_byte(unsigned char bus, unsigned char dev, + unsigned char offset, unsigned char val) +{ + unsigned long reg; + int shifts = offset & 0x3; + + reg = grackle_read( pci_config_addr( bus, dev, (offset & ~(0x3)))); + reg = (reg & ~(0xff << (shifts << 3))) | (val << (shifts << 3)); + grackle_write( pci_config_addr( bus, dev, (offset & ~(0x3))), reg ); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_write_config_word(unsigned char bus, unsigned char dev, + unsigned char offset, unsigned short val) +{ + unsigned long reg; + int shifts = offset & 0x3; + + reg = grackle_read( pci_config_addr( bus, dev, (offset & ~(0x3)))); + reg = (reg & ~(0xffff << (shifts << 3))) | (val << (shifts << 3)); + grackle_write( pci_config_addr( bus, dev, (offset & ~(0x3))), reg ); + return PCIBIOS_SUCCESSFUL; +} + +int +gemini_pcibios_write_config_dword(unsigned char bus, unsigned char dev, + unsigned char offset, unsigned int val) +{ + grackle_write( pci_config_addr( bus, dev, (offset & ~(0x3))), val ); + return PCIBIOS_SUCCESSFUL; +} + +struct gemini_device { + unsigned short vendor, device; + unsigned char irq; + unsigned short cmd; + unsigned char cache_line, latency; + void (*init)(struct pci_dev *dev); +}; + +static struct gemini_device gemini_map[] = { + { PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C885, 11, 0x15, 32, 248, NULL }, + { PCI_VENDOR_ID_NCR, 0x701, 10, 0, 0, 0, NULL }, + { PCI_VENDOR_ID_TUNDRA, PCI_DEVICE_ID_TUNDRA_CA91C042, 3, 0, 0, 0, NULL }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_MPIC, 0xff, 0, 0, 0, NULL }, + { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_670, 0xff, 0, 0, 0, NULL }, + { PCI_VENDOR_ID_MOTOROLA, PCI_DEVICE_ID_MOTOROLA_MPC106, 0xff, 0, 0, 0, NULL }, +}; + +static int gemini_map_count = (sizeof( gemini_map ) / + sizeof( gemini_map[0] )); + + + +/* This just sets up the known devices on the board. */ +static void __init mapin_device( struct pci_dev *dev ) +{ + struct gemini_device *p; + unsigned short cmd; + int i; + + + for( i=0; i < gemini_map_count; i++ ) { + p = &(gemini_map[i]); + + if ( p->vendor == dev->vendor && + p->device == dev->device ) { + + if (p->irq != 0xff) { + pci_write_config_byte( dev, PCI_INTERRUPT_LINE, p->irq ); + dev->irq = p->irq; + } + + if (p->cmd) { + pci_read_config_word( dev, PCI_COMMAND, &cmd ); + pci_write_config_word( dev, PCI_COMMAND, (p->cmd|cmd)); + } + + if (p->cache_line) + pci_write_config_byte( dev, PCI_CACHE_LINE_SIZE, p->cache_line ); + + if (p->latency) + pci_write_config_byte( dev, PCI_LATENCY_TIMER, p->latency ); + } + } +} + +#define KB 1024 +#define MB (KB*KB) + +#define ALIGN(val,align) (((val) + ((align) -1))&(~((align) -1))) +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +#define FIRST_IO_ADDR 0x10000 +#define FIRST_MEM_ADDR 0x02000000 + +#define GEMINI_PCI_MEM_BASE (0xf0000000) +#define GEMINI_PCI_IO_BASE (0xfe800000) + +static unsigned long pci_mem_base = GEMINI_PCI_MEM_BASE; +static unsigned long pci_io_base = GEMINI_PCI_IO_BASE; + +static unsigned int io_base = FIRST_IO_ADDR; +static unsigned int mem_base = FIRST_MEM_ADDR; + + + +__init void layout_dev( struct pci_dev *dev ) +{ + int i; + struct pci_bus *bus; + unsigned short cmd; + unsigned int reg, base, mask, size, alignto, type; + + bus = dev->bus; + + /* make any known settings happen */ + mapin_device( dev ); + + gemini_pcibios_read_config_word( bus->number, dev->devfn, PCI_COMMAND, &cmd ); + + for( reg = PCI_BASE_ADDRESS_0, i=0; reg <= PCI_BASE_ADDRESS_5; reg += 4, i++ ) { + + /* MPIC already done */ + if (dev->vendor == PCI_VENDOR_ID_IBM && + dev->device == PCI_DEVICE_ID_IBM_MPIC) + return; + + gemini_pcibios_write_config_dword( bus->number, dev->devfn, reg, 0xffffffff ); + gemini_pcibios_read_config_dword( bus->number, dev->devfn, reg, &base ); + if (!base) { + dev->resource[i].start = 0; + continue; + } + + if (base & PCI_BASE_ADDRESS_SPACE_IO) { + cmd |= PCI_COMMAND_IO; + base &= PCI_BASE_ADDRESS_IO_MASK; + mask = (~base << 1) | 0x1; + size = (mask & base) & 0xffffffff; + alignto = MAX(0x400, size); + base = ALIGN(io_base, alignto); + io_base = base + size; + gemini_pcibios_write_config_dword( bus->number, dev->devfn, reg, + ((pci_io_base + base) & 0x00ffffff) | 0x1); + dev->resource[i].start = (pci_io_base + base) | 0x1; + } + + else { + cmd |= PCI_COMMAND_MEMORY; + type = base & PCI_BASE_ADDRESS_MEM_TYPE_MASK; + mask = (~base << 1) | 0x1; + size = (mask & base) & 0xffffffff; + switch( type ) { + + case PCI_BASE_ADDRESS_MEM_TYPE_32: + break; + case PCI_BASE_ADDRESS_MEM_TYPE_64: + printk("Warning: Ignoring 64-bit device; slot %d, function %d.\n", + PCI_SLOT( dev->devfn ), PCI_FUNC( dev->devfn )); + reg += 4; + continue; + } + + alignto = MAX(0x1000, size); + base = ALIGN(mem_base, alignto); + mem_base = base + size; + gemini_pcibios_write_config_dword( bus->number, dev->devfn, + reg, (pci_mem_base + base)); + dev->resource[i].start = pci_mem_base + base; + } + } + + if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) + cmd |= PCI_COMMAND_IO; + + gemini_pcibios_write_config_word( bus->number, dev->devfn, PCI_COMMAND, + (cmd|PCI_COMMAND_MASTER)); +} + +__init void layout_bus( struct pci_bus *bus ) +{ + struct pci_dev *dev; + + if (!bus->devices && !bus->children) + return; + + io_base = ALIGN(io_base, 4*KB); + mem_base = ALIGN(mem_base, 4*KB); + + for( dev = bus->devices; dev; dev = dev->sibling ) { + if (((dev->class >> 16) != PCI_BASE_CLASS_BRIDGE) || + ((dev->class >> 8) == PCI_CLASS_BRIDGE_OTHER)) + layout_dev( dev ); + } +} + +void __init gemini_pcibios_fixup(void) +{ + struct pci_bus *bus; + unsigned long orig_mem_base, orig_io_base; + + orig_mem_base = pci_mem_base; + orig_io_base = pci_io_base; + + pci_mem_base = orig_mem_base; + pci_io_base = orig_io_base; +} + +decl_config_access_method(gemini); + +/* The "bootloader" for Synergy boards does none of this for us, so we need to + lay it all out ourselves... --Dan */ +void __init gemini_setup_pci_ptrs(void) +{ + set_config_access_method(gemini); + ppc_md.pcibios_fixup = gemini_pcibios_fixup; +} diff --git a/arch/ppc/kernel/gemini_prom.S b/arch/ppc/kernel/gemini_prom.S new file mode 100644 index 000000000..095f50e8f --- /dev/null +++ b/arch/ppc/kernel/gemini_prom.S @@ -0,0 +1,94 @@ +/* + * arch/ppc/kernel/gemini_prom.S + * + * Not really prom support code (yet), but sort of anti-prom code. The current + * bootloader does a number of things it shouldn't and doesn't do things that it + * should. The stuff in here is mainly a hodge-podge collection of setup code + * to get the board up and running. + * ---Dan + */ + +#include "ppc_asm.tmpl" +#include "ppc_defs.h" +#include <asm/processor.h> +#include <asm/page.h> +#include <asm/gemini.h> + +#define HID0_ABE (1<<3) + +/* + * On 750's the MMU is on when Linux is booted, so we need to clear out the + * bootloader's BAT settings, make sure we're in supervisor state (gotcha!), + * and turn off the MMU. + * + */ + +_GLOBAL(gemini_prom_init) +#ifdef __SMP__ + /* Since the MMU's on, get stuff in rom space that we'll need */ + lis r4,GEMINI_CPUSTAT@h + ori r4,r4,GEMINI_CPUSTAT@l + lbz r5,0(r4) + andi. r5,r5,3 + mr r24,r5 /* cpu # used later on */ +#endif + mfmsr r4 + li r3,MSR_PR /* ensure supervisor! */ + ori r3,r3,MSR_IR|MSR_DR + andc r4,r4,r3 + mtmsr r4 +#if 0 + /* zero out the bats now that the MMU is off */ +prom_no_mmu: + li r3,0 + mtspr IBAT0U,r3 + mtspr IBAT0L,r3 + mtspr IBAT1U,r3 + mtspr IBAT1L,r3 + mtspr IBAT2U,r3 + mtspr IBAT2L,r3 + mtspr IBAT3U,r3 + mtspr IBAT3L,r3 + + mtspr DBAT0U,r3 + mtspr DBAT0L,r3 + mtspr DBAT1U,r3 + mtspr DBAT1L,r3 + mtspr DBAT2U,r3 + mtspr DBAT2L,r3 + mtspr DBAT3U,r3 + mtspr DBAT3L,r3 +#endif + + /* the bootloader (as far as I'm currently aware) doesn't mess with page + tables, but since we're already here, might as well zap these, too */ + li r4,0 + mtspr SDR1,r4 + + li r4,16 + mtctr r4 + li r3,0 + li r4,0 +3: mtsrin r3,r4 + addi r3,r3,1 + bdnz 3b + +#ifdef __SMP__ + /* The 750 book (and Mot/IBM support) says that this will "assist" snooping + when in SMP. Not sure yet whether this should stay or leave... */ + mfspr r4,HID0 + ori r4,r4,HID0_ABE + mtspr HID0,r4 + sync +#endif /* __SMP__ */ + blr + +/* apparently, SMon doesn't pay attention to HID0[SRST]. Disable the MMU and + branch to 0xfff00100 */ +_GLOBAL(_gemini_reboot) + lis r5,GEMINI_BOOT_INIT@h + ori r5,r5,GEMINI_BOOT_INIT@l + li r6,MSR_IP + mtspr SRR0,r5 + mtspr SRR1,r6 + rfi diff --git a/arch/ppc/kernel/gemini_setup.c b/arch/ppc/kernel/gemini_setup.c new file mode 100644 index 000000000..4af02958a --- /dev/null +++ b/arch/ppc/kernel/gemini_setup.c @@ -0,0 +1,527 @@ +/* + * linux/arch/ppc/kernel/setup.c + * + * Copyright (C) 1995 Linus Torvalds + * Adapted from 'alpha' version by Gary Thomas + * Modified by Cort Dougan (cort@cs.nmt.edu) + * Synergy Microsystems board support by Dan Cox (dan@synergymicro.com) + * + */ + +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/types.h> +#include <linux/major.h> +#include <linux/blk.h> +#include <linux/console.h> +#include <linux/openpic.h> + +#include <asm/system.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/dma.h> +#include <asm/io.h> +#include <asm/m48t35.h> +#include <asm/gemini.h> + +#include "time.h" +#include "local_irq.h" +#include "open_pic.h" + +void gemini_setup_pci_ptrs(void); + +static int l2_printed = 0; +static unsigned char gemini_switch_map = 0; +static char *gemini_board_families[] = { + "VGM", "VSS", "KGM", "VGR", "KSS" +}; + +static char *gemini_memtypes[] = { + "EDO DRAM, 60nS", "SDRAM, 15nS, CL=2", "SDRAM, 15nS, CL=2 with ECC" +}; + +static unsigned int cpu_7xx[16] = { + 0, 15, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0 +}; +static unsigned int cpu_6xx[16] = { + 0, 0, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 0, 12, 7, 0 +}; + + +static inline unsigned long _get_HID1(void) +{ + unsigned long val; + + __asm__ __volatile__("mfspr %0,1009" : "=r" (val)); + return val; +} + +int +gemini_get_cpuinfo(char *buffer) +{ + int i, len; + unsigned char reg, rev; + char *family; + unsigned int type; + + reg = readb(GEMINI_FEAT); + family = gemini_board_families[((reg>>4) & 0xf)]; + if (((reg>>4) & 0xf) > 2) + printk(KERN_ERR "cpuinfo(): unable to determine board family\n"); + + reg = readb(GEMINI_BREV); + type = (reg>>4) & 0xf; + rev = reg & 0xf; + + reg = readb(GEMINI_BECO); + + len = sprintf( buffer, "machine\t\t: Gemini %s%d, rev %c, eco %d\n", + family, type, (rev + 'A'), (reg & 0xf)); + + len += sprintf( buffer+len, "vendor\t\t: %s\n", + (_get_PVR() & (1<<15)) ? "IBM" : "Motorola"); + + reg = readb(GEMINI_MEMCFG); + len += sprintf( buffer+len, "memory type\t: %s\n", + gemini_memtypes[(reg & 0xc0)>>6]); + len += sprintf( buffer+len, "switches on\t: "); + for( i=0; i < 8; i++ ) { + if ( gemini_switch_map & (1<<i)) + len += sprintf(buffer+len, "%d ", i); + } + len += sprintf(buffer+len, "\n"); + + return len; +} + +static u_char gemini_openpic_initsenses[] = { + 1, + 1, + 1, + 1, + 0, + 0, + 1, /* remainder are level-triggered */ +}; + +#define GEMINI_MPIC_ADDR (0xfcfc0000) +#define GEMINI_MPIC_PCI_CFG (0x80005800) + +void __init gemini_openpic_init(void) +{ + grackle_write(GEMINI_MPIC_PCI_CFG + PCI_BASE_ADDRESS_0, + GEMINI_MPIC_ADDR); + grackle_write(GEMINI_MPIC_PCI_CFG + PCI_COMMAND, PCI_COMMAND_MEMORY); + + OpenPIC = (volatile struct OpenPIC *) GEMINI_MPIC_ADDR; + OpenPIC_InitSenses = gemini_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof( gemini_openpic_initsenses ); + + ioremap( GEMINI_MPIC_ADDR, sizeof( struct OpenPIC )); +} + + +extern unsigned long loops_per_sec; +extern int root_mountflags; +extern char cmd_line[]; + + +void __init gemini_setup_arch(unsigned long *memstart, unsigned long *memend) +{ + unsigned int cpu; + extern char cmd_line[]; + + + loops_per_sec = 50000000; + +#ifdef CONFIG_BLK_DEV_INITRD + /* bootable off CDROM */ + if (initrd_start) + ROOT_DEV = MKDEV(SCSI_CDROM_MAJOR, 0); + else +#endif + ROOT_DEV = to_kdev_t(0x0801); + + /* nothing but serial consoles... */ + sprintf(cmd_line, "%s console=ttyS0", cmd_line); + + + /* The user switches on the front panel can be used as follows: + + Switch 0 - adds "debug" to the command line for verbose boot info, + Switch 7 - boots in single-user mode + + */ + + gemini_switch_map = readb( GEMINI_USWITCH ); + + if ( gemini_switch_map & (1<<GEMINI_SWITCH_VERBOSE)) + sprintf(cmd_line, "%s debug", cmd_line); + + if ( gemini_switch_map & (1<<GEMINI_SWITCH_SINGLE_USER)) + sprintf(cmd_line, "%s single", cmd_line); + + printk("Boot arguments: %s\n", cmd_line); + + /* mutter some kind words about who made the CPU */ + cpu = _get_PVR(); + printk("CPU manufacturer: %s [rev=%04x]\n", (cpu & (1<<15)) ? "IBM" : + "Motorola", (cpu & 0xffff)); + + /* take special pains to map the MPIC, since it isn't mapped yet */ + gemini_openpic_init(); + + /* start the L2 */ + gemini_init_l2(); + +} + + +int +gemini_get_clock_speed(void) +{ + unsigned long hid1; + int clock; + unsigned char reg; + + hid1 = _get_HID1(); + if ((_get_PVR()>>16) == 8) + hid1 = cpu_7xx[hid1]; + else + hid1 = cpu_6xx[hid1]; + + reg = readb(GEMINI_BSTAT) & 0xc0; + + switch( reg >> 2 ) { + + case 0: + default: + clock = (hid1*100)/3; + break; + + case 1: + clock = (hid1*125)/3; + break; + + case 2: + clock = (hid1*50)/3; + break; + } + + return clock; +} + + +#define L2CR_PIPE_LATEWR (0x01800000) /* late-write SRAM */ +#define L2CR_L2CTL (0x00100000) /* RAM control */ +#define L2CR_INST_DISABLE (0x00400000) /* disable for insn's */ +#define L2CR_L2I (0x00200000) /* global invalidate */ +#define L2CR_L2E (0x80000000) /* enable */ +#define L2CR_L2WT (0x00080000) /* write-through */ + +void __init gemini_init_l2(void) +{ + unsigned char reg; + unsigned long cache; + int speed; + + reg = readb(GEMINI_L2CFG); + + /* 750's L2 initializes differently from a 604's. Also note that a Grackle + bug will hang a dual-604 board, so make sure that doesn't happen by not + turning on the L2 */ + if ( _get_PVR() >> 16 != 8 ) { + + /* check for dual cpus and cry sadly about the loss of an L2... */ + if ((( readb(GEMINI_CPUSTAT) & 0x0c ) >> 2) != 1) + printk("Sorry. Your dual-604 does not allow the L2 to be enabled due " + "to a Grackle bug.\n"); + else if ( reg & GEMINI_L2_SIZE_MASK ) { + printk("Enabling 604 L2 cache: %dKb\n", + (128<<((reg & GEMINI_L2_SIZE_MASK)>>6))); + writeb( 1, GEMINI_L2CFG ); + } + } + + /* do a 750 */ + else { + /* Synergy's first round of 750 boards had the L2 size stuff into the + board register above. If it's there, it's used; if not, the + standard default is 1Mb. The L2 type, I'm told, is "most likely + probably always going to be late-write". --Dan */ + + if (reg & 0xc0) { + if (!l2_printed) { + printk("Enabling 750 L2 cache: %dKb\n", + (128 << ((reg & 0xc0)>>6))); + l2_printed=1; + } + + /* take the size given */ + cache = (((reg>>6) & 0x3)<<28); + } + else + /* default of 1Mb */ + cache = 0x3<<28; + + reg &= 0x3; + + /* a cache ratio of 1:1 and CPU clock speeds in excess of 300Mhz are bad + things. If found, tune it down to 1:1.5. -- Dan */ + if (!reg) { + + speed = gemini_get_clock_speed(); + + if (speed >= 300) { + printk("Warning: L2 ratio is 1:1 on a %dMhz processor. Dropping to 1:1.5.\n", + speed ); + printk("Contact Synergy Microsystems for an ECO to fix this problem\n"); + reg = 0x1; + } + } + + /* standard stuff */ + cache |= ((1<<reg)<<25); +#ifdef __SMP__ + /* A couple errata for the 750's (both IBM and Motorola silicon) + note that you can get missed cache lines on MP implementations. + The workaround - if you call it that - is to make the L2 + write-through. This is fixed in IBM's 3.1 rev (I'm told), but + for now, always make 2.x versions use L2 write-through. --Dan */ + if (((_get_PVR()>>8) & 0xf) <= 2) + cache |= L2CR_L2WT; +#endif + cache |= L2CR_PIPE_LATEWR|L2CR_L2CTL|L2CR_INST_DISABLE; + _set_L2CR(0); + _set_L2CR(cache|L2CR_L2I|L2CR_L2E); + } +} + +void +gemini_restart(char *cmd) +{ + __cli(); + /* make a clean restart, not via the MPIC */ + _gemini_reboot(); + for(;;); +} + +void +gemini_power_off(void) +{ + for(;;); +} + +void +gemini_halt(void) +{ + gemini_restart(NULL); +} + +void __init gemini_init_IRQ(void) +{ + int i; + + /* gemini has no 8259 */ + open_pic.irq_offset = 0; + for( i=0; i < 16; i++ ) + irq_desc[i].ctl = &open_pic; + openpic_init(1); +} + +#define gemini_rtc_read(x) (readb(GEMINI_RTC+(x))) +#define gemini_rtc_write(val,x) (writeb((val),(GEMINI_RTC+(x)))) + +/* ensure that the RTC is up and running */ +void __init gemini_time_init(void) +{ + unsigned char reg; + + reg = gemini_rtc_read(M48T35_RTC_CONTROL); + + if ( reg & M48T35_RTC_STOPPED ) { + printk(KERN_INFO "M48T35 real-time-clock was stopped. Now starting...\n"); + gemini_rtc_write((reg & ~(M48T35_RTC_STOPPED)), M48T35_RTC_CONTROL); + gemini_rtc_write((reg | M48T35_RTC_SET), M48T35_RTC_CONTROL); + } +} + +#undef DEBUG_RTC + +unsigned long +gemini_get_rtc_time(void) +{ + unsigned int year, mon, day, hour, min, sec; + unsigned char reg; + + reg = gemini_rtc_read(M48T35_RTC_CONTROL); + gemini_rtc_write((reg|M48T35_RTC_READ), M48T35_RTC_CONTROL); +#ifdef DEBUG_RTC + printk("get rtc: reg = %x\n", reg); +#endif + + do { + sec = gemini_rtc_read(M48T35_RTC_SECONDS); + min = gemini_rtc_read(M48T35_RTC_MINUTES); + hour = gemini_rtc_read(M48T35_RTC_HOURS); + day = gemini_rtc_read(M48T35_RTC_DOM); + mon = gemini_rtc_read(M48T35_RTC_MONTH); + year = gemini_rtc_read(M48T35_RTC_YEAR); + } while( sec != gemini_rtc_read(M48T35_RTC_SECONDS)); +#ifdef DEBUG_RTC + printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n", + sec, min, hour, day, mon, year); +#endif + + gemini_rtc_write(reg, M48T35_RTC_CONTROL); + + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + + if ((year += 1900) < 1970) + year += 100; +#ifdef DEBUG_RTC + printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n", + sec, min, hour, day, mon, year); +#endif + + return mktime( year, mon, day, hour, min, sec ); +} + + +int +gemini_set_rtc_time( unsigned long now ) +{ + unsigned char reg; + struct rtc_time tm; + + to_tm( now, &tm ); + + reg = gemini_rtc_read(M48T35_RTC_CONTROL); +#if DEBUG_RTC + printk("set rtc: reg = %x\n", reg); +#endif + + gemini_rtc_write((reg|M48T35_RTC_SET), M48T35_RTC_CONTROL); +#if DEBUG_RTC + printk("set rtc: tm vals - sec=%x, min=%x, hour=%x, mon=%x, mday=%x, year=%x\n", + tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_mday, tm.tm_year); +#endif + + tm.tm_year -= 1900; + BIN_TO_BCD(tm.tm_sec); + BIN_TO_BCD(tm.tm_min); + BIN_TO_BCD(tm.tm_hour); + BIN_TO_BCD(tm.tm_mon); + BIN_TO_BCD(tm.tm_mday); + BIN_TO_BCD(tm.tm_year); +#ifdef DEBUG_RTC + printk("set rtc: tm vals - sec=%x, min=%x, hour=%x, mon=%x, mday=%x, year=%x\n", + tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_mday, tm.tm_year); +#endif + + gemini_rtc_write(tm.tm_sec, M48T35_RTC_SECONDS); + gemini_rtc_write(tm.tm_min, M48T35_RTC_MINUTES); + gemini_rtc_write(tm.tm_hour, M48T35_RTC_HOURS); + gemini_rtc_write(tm.tm_mday, M48T35_RTC_DOM); + gemini_rtc_write(tm.tm_mon, M48T35_RTC_MONTH); + gemini_rtc_write(tm.tm_year, M48T35_RTC_YEAR); + + /* done writing */ + gemini_rtc_write(reg, M48T35_RTC_CONTROL); + + if ((time_state == TIME_ERROR) || (time_state == TIME_BAD)) + time_state = TIME_OK; + + return 0; +} + +/* use the RTC to determine the decrementer count */ +void __init gemini_calibrate_decr(void) +{ + int freq, divisor; + unsigned char reg; + + /* determine processor bus speed */ + reg = readb(GEMINI_BSTAT); + + switch(((reg & 0x0c)>>2)&0x3) { + case 0: + default: + freq = 66; + break; + case 1: + freq = 83; + break; + case 2: + freq = 100; + break; + } + + freq *= 1000000; + divisor = 4; + decrementer_count = freq / HZ / divisor; + count_period_num = divisor; + count_period_den = freq / 1000000; +} + + +void __init gemini_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + void chrp_do_IRQ(struct pt_regs *, int, int); + void layout_bus( struct pci_bus * ); + + gemini_setup_pci_ptrs(); + + ISA_DMA_THRESHOLD = 0; + DMA_MODE_READ = 0; + DMA_MODE_WRITE = 0; + +#ifdef CONFIG_BLK_DEV_INITRD + if ( r4 ) + { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif + + ppc_md.setup_arch = gemini_setup_arch; + ppc_md.setup_residual = NULL; + ppc_md.get_cpuinfo = gemini_get_cpuinfo; + ppc_md.irq_cannonicalize = NULL; + ppc_md.init_IRQ = gemini_init_IRQ; + ppc_md.do_IRQ = chrp_do_IRQ; + ppc_md.init = NULL; + + ppc_md.restart = gemini_restart; + ppc_md.power_off = gemini_power_off; + ppc_md.halt = gemini_halt; + + ppc_md.time_init = gemini_time_init; + ppc_md.set_rtc_time = gemini_set_rtc_time; + ppc_md.get_rtc_time = gemini_get_rtc_time; + ppc_md.calibrate_decr = gemini_calibrate_decr; + + /* no keyboard/mouse/video stuff yet.. */ + ppc_md.kbd_setkeycode = NULL; + ppc_md.kbd_getkeycode = NULL; + ppc_md.kbd_translate = NULL; + ppc_md.kbd_unexpected_up = NULL; + ppc_md.kbd_leds = NULL; + ppc_md.kbd_init_hw = NULL; +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.ppc_kbd_sysrq_xlate = NULL; +#endif + ppc_md.pcibios_fixup_bus = layout_bus; +} diff --git a/arch/ppc/kernel/hashtable.S b/arch/ppc/kernel/hashtable.S new file mode 100644 index 000000000..74f00ce10 --- /dev/null +++ b/arch/ppc/kernel/hashtable.S @@ -0,0 +1,478 @@ +/* + * arch/ppc/kernel/hashtable.S + * + * $Id: hashtable.S,v 1.3 1999/09/05 11:56:27 paulus Exp $ + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP + * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu> + * Adapted for Power Macintosh by Paul Mackerras. + * Low-level exception handlers and MMU support + * rewritten by Paul Mackerras. + * Copyright (C) 1996 Paul Mackerras. + * + * This file contains low-level assembler routines for managing + * the PowerPC MMU hash table. (PPC 8xx processors don't use a + * hash table, so this file is not used on them.) + * + * This program 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. + * + */ + +#include "ppc_asm.h" +#include <asm/processor.h> +#include <asm/page.h> +#include <linux/config.h> + +/* + * Load a PTE into the hash table, if possible. + * The address is in r3, and r4 contains access flags: + * _PAGE_USER (4) if a user-mode access, ored with + * _PAGE_RW (2) if a write. r20 contains DSISR or SRR1, + * so bit 1 (0x40000000) is set if the exception was due + * to no matching PTE being found in the hash table. + * r5 contains the physical address of the current task's thread. + * + * Returns to the caller if the access is illegal or there is no + * mapping for the address. Otherwise it places an appropriate PTE + * in the hash table and returns from the exception. + * Uses r0, r2 - r6, ctr, lr. + * + * For speed, 4 of the instructions get patched once the size and + * physical address of the hash table are known. These definitions + * of Hash_base and Hash_bits below are just an example. + */ +Hash_base = 0x180000 +Hash_bits = 12 /* e.g. 256kB hash table */ +Hash_msk = (((1 << Hash_bits) - 1) * 64) + + .globl hash_page +hash_page: +#ifdef __SMP__ + eieio + lis r2,hash_table_lock@h + ori r2,r2,hash_table_lock@l + tophys(r2,r2) + lis r6,100000000@h + mtctr r6 + lwz r0,PROCESSOR-THREAD(r5) + or r0,r0,r6 +10: lwarx r6,0,r2 + cmpi 0,r6,0 + bne- 12f + stwcx. r0,0,r2 + beq+ 11f +12: cmpw r6,r0 + bdnzf 2,10b + tw 31,31,31 +11: eieio +#endif + /* Get PTE (linux-style) and check access */ + mfspr r2,SPRG3 /* current task's THREAD (phys) */ + lwz r5,PGDIR(r2) /* virt page-table root */ + tophys(r5,r5) /* convert to phys addr */ + rlwimi r5,r3,12,20,29 /* insert top 10 bits of address */ + lwz r5,0(r5) /* get pmd entry */ + rlwinm. r5,r5,0,0,19 /* extract address of pte page */ +#ifdef __SMP__ + beq- hash_page_out /* return if no mapping */ +#else + /* XXX it seems like the 601 will give a machine fault on the + rfi if its alignment is wrong (bottom 4 bits of address are + 8 or 0xc) and we have had a not-taken conditional branch + to the address following the rfi. */ + beqlr- +#endif + tophys(r2,r5) + rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ + lwz r6,0(r2) /* get linux-style pte */ + ori r4,r4,1 /* set _PAGE_PRESENT bit in access */ + andc. r0,r4,r6 /* check access & ~permission */ +#ifdef __SMP__ + bne- hash_page_out /* return if access not permitted */ +#else + bnelr- +#endif + + ori r6,r6,0x100 /* set _PAGE_ACCESSED in pte */ + rlwinm r5,r4,5,24,24 /* _PAGE_RW access -> _PAGE_DIRTY */ + rlwimi r5,r4,7,22,22 /* _PAGE_RW -> _PAGE_HWWRITE */ + or r6,r6,r5 + stw r6,0(r2) /* update PTE (accessed/dirty bits) */ + + /* Convert linux-style PTE to low word of PPC-style PTE */ +#ifdef CONFIG_PPC64 + /* clear the high 32 bits just in case */ + clrldi r6,r6,32 + clrldi r4,r4,32 +#endif /* CONFIG_PPC64 */ + rlwinm r4,r6,32-9,31,31 /* _PAGE_HWWRITE -> PP lsb */ + rlwimi r6,r6,32-1,31,31 /* _PAGE_USER -> PP (both bits now) */ + ori r4,r4,0xe04 /* clear out reserved bits */ + andc r6,r6,r4 /* PP=2 or 0, when _PAGE_HWWRITE */ + + /* Construct the high word of the PPC-style PTE */ + mfsrin r5,r3 /* get segment reg for segment */ +#ifdef CONFIG_PPC64 + sldi r5,r5,12 +#else /* CONFIG_PPC64 */ + rlwinm r5,r5,7,1,24 /* put VSID in 0x7fffff80 bits */ +#endif /* CONFIG_PPC64 */ + +#ifndef __SMP__ /* do this later for SMP */ +#ifdef CONFIG_PPC64 + ori r5,r5,1 /* set V (valid) bit */ +#else /* CONFIG_PPC64 */ + oris r5,r5,0x8000 /* set V (valid) bit */ +#endif /* CONFIG_PPC64 */ +#endif + +#ifdef CONFIG_PPC64 +/* XXX: does this insert the api correctly? -- Cort */ + rlwimi r5,r3,17,21,25 /* put in API (abbrev page index) */ +#else /* CONFIG_PPC64 */ + rlwimi r5,r3,10,26,31 /* put in API (abbrev page index) */ +#endif /* CONFIG_PPC64 */ + /* Get the address of the primary PTE group in the hash table */ + .globl hash_page_patch_A +hash_page_patch_A: + lis r4,Hash_base@h /* base address of hash table */ +#ifdef CONFIG_PPC64 + /* just in case */ + clrldi r4,r4,32 +#endif + rlwimi r4,r5,32-1,26-Hash_bits,25 /* (VSID & hash_mask) << 6 */ + rlwinm r0,r3,32-6,26-Hash_bits,25 /* (PI & hash_mask) << 6 */ + xor r4,r4,r0 /* make primary hash */ + + /* See whether it was a PTE not found exception or a + protection violation. */ + andis. r0,r20,0x4000 + li r2,8 /* PTEs/group */ + bne 10f /* no PTE: go look for an empty slot */ + tlbie r3 /* invalidate TLB entry */ + + /* Search the primary PTEG for a PTE whose 1st word matches r5 */ + mtctr r2 + addi r3,r4,-8 +1: lwzu r0,8(r3) /* get next PTE */ + cmp 0,r0,r5 + bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ + beq+ found_slot + + /* Search the secondary PTEG for a matching PTE */ + ori r5,r5,0x40 /* set H (secondary hash) bit */ + .globl hash_page_patch_B +hash_page_patch_B: + xoris r3,r4,Hash_msk>>16 /* compute secondary hash */ + xori r3,r3,0xffc0 + addi r3,r3,-8 + mtctr r2 +2: lwzu r0,8(r3) + cmp 0,r0,r5 + bdnzf 2,2b + beq+ found_slot + xori r5,r5,0x40 /* clear H bit again */ + + /* Search the primary PTEG for an empty slot */ +10: mtctr r2 + addi r3,r4,-8 /* search primary PTEG */ +1: lwzu r0,8(r3) /* get next PTE */ + srwi. r0,r0,31 /* only want to check valid bit */ + bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ + beq+ found_empty + + /* Search the secondary PTEG for an empty slot */ + ori r5,r5,0x40 /* set H (secondary hash) bit */ + .globl hash_page_patch_C +hash_page_patch_C: + xoris r3,r4,Hash_msk>>16 /* compute secondary hash */ + xori r3,r3,0xffc0 + addi r3,r3,-8 + mtctr r2 +2: lwzu r0,8(r3) + srwi. r0,r0,31 /* only want to check valid bit */ + bdnzf 2,2b + beq+ found_empty + + /* + * Choose an arbitrary slot in the primary PTEG to overwrite. + * Since both the primary and secondary PTEGs are full, and we + * have no information that the PTEs in the primary PTEG are + * more important or useful than those in the secondary PTEG, + * and we know there is a definite (although small) speed + * advantage to putting the PTE in the primary PTEG, we always + * put the PTE in the primary PTEG. + */ + xori r5,r5,0x40 /* clear H bit again */ + lwz r2,next_slot@l(0) + addi r2,r2,8 + andi. r2,r2,0x38 + stw r2,next_slot@l(0) + add r3,r4,r2 +11: + /* update counter of evicted pages */ + lis r2,htab_evicts@h + ori r2,r2,htab_evicts@l + tophys(r2,r2) + lwz r4,0(r2) + addi r4,r4,1 + stw r4,0(r2) + +#ifndef __SMP__ + /* Store PTE in PTEG */ +found_empty: + stw r5,0(r3) +found_slot: + stw r6,4(r3) + sync + +#else /* __SMP__ */ +/* + * Between the tlbie above and updating the hash table entry below, + * another CPU could read the hash table entry and put it in its TLB. + * There are 3 cases: + * 1. using an empty slot + * 2. updating an earlier entry to change permissions (i.e. enable write) + * 3. taking over the PTE for an unrelated address + * + * In each case it doesn't really matter if the other CPUs have the old + * PTE in their TLB. So we don't need to bother with another tlbie here, + * which is convenient as we've overwritten the register that had the + * address. :-) The tlbie above is mainly to make sure that this CPU comes + * and gets the new PTE from the hash table. + * + * We do however have to make sure that the PTE is never in an invalid + * state with the V bit set. + */ +found_empty: +found_slot: + stw r5,0(r3) /* clear V (valid) bit in PTE */ + sync + tlbsync + sync + stw r6,4(r3) /* put in correct RPN, WIMG, PP bits */ + sync + oris r5,r5,0x8000 + stw r5,0(r3) /* finally set V bit in PTE */ +#endif /* __SMP__ */ + +/* + * Update the hash table miss count. We only want misses here + * that _are_ valid addresses and have a pte otherwise we don't + * count it as a reload. do_page_fault() takes care of bad addrs + * and entries that need linux-style pte's created. + * + * safe to use r2 here since we're not using it as current yet + * update the htab misses count + * -- Cort + */ + lis r2,htab_reloads@h + ori r2,r2,htab_reloads@l + tophys(r2,r2) + lwz r3,0(r2) + addi r3,r3,1 + stw r3,0(r2) + +#ifdef __SMP__ + lis r2,hash_table_lock@ha + tophys(r2,r2) + li r0,0 + stw r0,hash_table_lock@l(r2) + eieio +#endif + + /* Return from the exception */ + lwz r3,_CCR(r21) + lwz r4,_LINK(r21) + lwz r5,_CTR(r21) + mtcrf 0xff,r3 + mtlr r4 + mtctr r5 + lwz r0,GPR0(r21) + lwz r1,GPR1(r21) + lwz r2,GPR2(r21) + lwz r3,GPR3(r21) + lwz r4,GPR4(r21) + lwz r5,GPR5(r21) + lwz r6,GPR6(r21) + /* we haven't used xer */ + mtspr SRR1,r23 + mtspr SRR0,r22 + lwz r20,GPR20(r21) + lwz r22,GPR22(r21) + lwz r23,GPR23(r21) + lwz r21,GPR21(r21) + rfi + +#ifdef __SMP__ +hash_page_out: + lis r2,hash_table_lock@ha + tophys(r2,r2) + li r0,0 + stw r0,hash_table_lock@l(r2) + eieio + blr + + .data + .globl hash_table_lock +hash_table_lock: + .long 0 + .text +#endif /* __SMP__ */ + +/* next_slot is assumed to be within the first 32kB of physical RAM */ +next_slot: + .long 0 + +/* + * Flush entries from the hash table with VSIDs in the range + * given. + */ +_GLOBAL(flush_hash_segments) + lis r5,Hash@ha + lwz r5,Hash@l(r5) /* base of hash table */ + cmpwi 0,r5,0 + bne+ 99f + tlbia + sync +#ifdef __SMP__ + tlbsync + sync +#endif + blr +99: +#ifdef __SMP__ + /* Note - we had better not do anything which could generate + a hash table miss while we have the hash table locked, + or we'll get a deadlock. -paulus */ + mfmsr r10 + sync + rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ + mtmsr r0 + SYNC + lis r9,hash_table_lock@h + ori r9,r9,hash_table_lock@l + lwz r8,PROCESSOR(r2) + oris r8,r8,8 +10: lwarx r6,0,r9 + cmpi 0,r6,0 + bne- 10b + stwcx. r8,0,r9 + bne- 10b + eieio +#endif + rlwinm r3,r3,7,1,24 /* put VSID lower limit in position */ + oris r3,r3,0x8000 /* set V bit */ + rlwinm r4,r4,7,1,24 /* put VSID upper limit in position */ + oris r4,r4,0x8000 + ori r4,r4,0x7f + lis r6,Hash_size@ha + lwz r6,Hash_size@l(r6) /* size in bytes */ + srwi r6,r6,3 /* # PTEs */ + mtctr r6 + addi r5,r5,-8 + li r0,0 +1: lwzu r6,8(r5) /* get next tag word */ + cmplw 0,r6,r3 + cmplw 1,r6,r4 + cror 0,0,5 /* set cr0.lt if out of range */ + blt 2f /* branch if out of range */ + stw r0,0(r5) /* invalidate entry */ +2: bdnz 1b /* continue with loop */ + sync + tlbia + sync +#ifdef __SMP__ + tlbsync + sync + lis r3,hash_table_lock@ha + stw r0,hash_table_lock@l(r3) + mtmsr r10 + SYNC +#endif + blr + +/* + * Flush the entry for a particular page from the hash table. + * + * flush_hash_page(unsigned context, unsigned long va) + */ +_GLOBAL(flush_hash_page) + lis r6,Hash@ha + lwz r6,Hash@l(r6) /* hash table base */ + cmpwi 0,r6,0 /* hash table in use? */ + bne+ 99f + tlbie r4 /* in hw tlb too */ + sync +#ifdef __SMP__ + tlbsync + sync +#endif + blr +99: +#ifdef __SMP__ + /* Note - we had better not do anything which could generate + a hash table miss while we have the hash table locked, + or we'll get a deadlock. -paulus */ + mfmsr r10 + sync + rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ + mtmsr r0 + SYNC + lis r9,hash_table_lock@h + ori r9,r9,hash_table_lock@l + lwz r8,PROCESSOR(r2) + oris r8,r8,9 +10: lwarx r7,0,r9 + cmpi 0,r7,0 + bne- 10b + stwcx. r8,0,r9 + bne- 10b + eieio +#endif + rlwinm r3,r3,11,1,20 /* put context into vsid */ + rlwimi r3,r4,11,21,24 /* put top 4 bits of va into vsid */ + oris r3,r3,0x8000 /* set V (valid) bit */ + rlwimi r3,r4,10,26,31 /* put in API (abbrev page index) */ + rlwinm r7,r4,32-6,10,25 /* get page index << 6 */ + rlwinm r5,r3,32-1,7,25 /* vsid << 6 */ + xor r7,r7,r5 /* primary hash << 6 */ + lis r5,Hash_mask@ha + lwz r5,Hash_mask@l(r5) /* hash mask */ + slwi r5,r5,6 /* << 6 */ + and r7,r7,r5 + add r6,r6,r7 /* address of primary PTEG */ + li r8,8 + mtctr r8 + addi r7,r6,-8 +1: lwzu r0,8(r7) /* get next PTE */ + cmpw 0,r0,r3 /* see if tag matches */ + bdnzf 2,1b /* while --ctr != 0 && !cr0.eq */ + beq 3f /* if we found it */ + ori r3,r3,0x40 /* set H (alt. hash) bit */ + xor r6,r6,r5 /* address of secondary PTEG */ + mtctr r8 + addi r7,r6,-8 +2: lwzu r0,8(r7) /* get next PTE */ + cmpw 0,r0,r3 /* see if tag matches */ + bdnzf 2,2b /* while --ctr != 0 && !cr0.eq */ + bne 4f /* if we didn't find it */ +3: li r0,0 + stw r0,0(r7) /* invalidate entry */ +4: sync + tlbie r4 /* in hw tlb too */ + sync +#ifdef __SMP__ + tlbsync + sync + li r0,0 + stw r0,0(r9) /* clear hash_table_lock */ + mtmsr r10 + SYNC +#endif + blr diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index e451ac87f..9a0ee6346 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -1,12 +1,13 @@ /* * arch/ppc/kernel/head.S * - * $Id: head.S,v 1.133 1999/05/20 05:13:08 cort Exp $ + * $Id: head.S,v 1.143 1999/09/05 11:56:28 paulus Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP + * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu> * Adapted for Power Macintosh by Paul Mackerras. * Low-level exception handlers and MMU support * rewritten by Paul Mackerras. @@ -16,7 +17,7 @@ * * This file contains the low-level support and setup for the * PowerPC platform, including trap and interrupt dispatch. - * Also included here is low-level thread/task switch support. + * (The PPC 8xx embedded CPUs use head_8xx.S instead.) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -25,118 +26,42 @@ * */ -#include "ppc_asm.tmpl" -#include "ppc_defs.h" +#include "ppc_asm.h" #include <asm/processor.h> #include <asm/page.h> -#include <asm/ptrace.h> -#include <linux/sys.h> -#include <linux/errno.h> #include <linux/config.h> #include <asm/mmu.h> -#include <asm/pgtable.h> -#include <asm/cache.h> #ifdef CONFIG_APUS #include <asm/amigappc.h> #endif -/* optimization for 603 to load the tlb directly from the linux table */ -#define NO_RELOAD_HTAB 1 - -#ifndef CONFIG_8xx -CACHE_LINE_SIZE = 32 -LG_CACHE_LINE_SIZE = 5 -#else -CACHE_LINE_SIZE = 16 -LG_CACHE_LINE_SIZE = 4 -#endif - -#define TOPHYS(x) (x - KERNELBASE) - -/* - * Macros for storing registers into and loading registers from - * exception frames. - */ -#define SAVE_GPR(n, base) stw n,GPR0+4*(n)(base) -#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base) -#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base) -#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base) -#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base) -#define REST_GPR(n, base) lwz n,GPR0+4*(n)(base) -#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base) -#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base) -#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base) -#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base) - -#define SAVE_FPR(n, base) stfd n,TSS_FPR0+8*(n)(base) -#define SAVE_2FPRS(n, base) SAVE_FPR(n, base); SAVE_FPR(n+1, base) -#define SAVE_4FPRS(n, base) SAVE_2FPRS(n, base); SAVE_2FPRS(n+2, base) -#define SAVE_8FPRS(n, base) SAVE_4FPRS(n, base); SAVE_4FPRS(n+4, base) -#define SAVE_16FPRS(n, base) SAVE_8FPRS(n, base); SAVE_8FPRS(n+8, base) -#define SAVE_32FPRS(n, base) SAVE_16FPRS(n, base); SAVE_16FPRS(n+16, base) -#define REST_FPR(n, base) lfd n,TSS_FPR0+8*(n)(base) -#define REST_2FPRS(n, base) REST_FPR(n, base); REST_FPR(n+1, base) -#define REST_4FPRS(n, base) REST_2FPRS(n, base); REST_2FPRS(n+2, base) -#define REST_8FPRS(n, base) REST_4FPRS(n, base); REST_4FPRS(n+4, base) -#define REST_16FPRS(n, base) REST_8FPRS(n, base); REST_8FPRS(n+8, base) -#define REST_32FPRS(n, base) REST_16FPRS(n, base); REST_16FPRS(n+16, base) - -#define SYNC \ - sync; \ - isync - -#ifndef CONFIG_8xx -/* This instruction is not implemented on the PPC 603 or 601 */ -#define tlbia \ - li r4,128; \ - mtctr r4; \ - lis r4,KERNELBASE@h; \ -0: tlbie r4; \ - addi r4,r4,0x1000; \ - bdnz 0b -#endif - #ifdef CONFIG_PPC64 -#define LOAD_BAT(n, offset, reg, RA, RB) \ - ld RA,offset+0(reg); \ - ld RB,offset+8(reg); \ +#define LOAD_BAT(n, reg, RA, RB) \ + ld RA,(n*32)+0(reg); \ + ld RB,(n*32)+8(reg); \ mtspr IBAT##n##U,RA; \ mtspr IBAT##n##L,RB; \ - ld RA,offset+16(reg); \ - ld RB,offset+24(reg); \ + ld RA,(n*32)+16(reg); \ + ld RB,(n*32)+24(reg); \ mtspr DBAT##n##U,RA; \ mtspr DBAT##n##L,RB; \ #else /* CONFIG_PPC64 */ -/* 601 only have IBAT cr0.eq is set on 601 when using this macro */ -#define LOAD_BAT(n, offset, reg, RA, RB) \ - lwz RA,offset+0(reg); \ - lwz RB,offset+4(reg); \ +/* 601 only have IBAT; cr0.eq is set on 601 when using this macro */ +#define LOAD_BAT(n, reg, RA, RB) \ + lwz RA,(n*16)+0(reg); \ + lwz RB,(n*16)+4(reg); \ mtspr IBAT##n##U,RA; \ mtspr IBAT##n##L,RB; \ beq 1f; \ - lwz RA,offset+8(reg); \ - lwz RB,offset+12(reg); \ + lwz RA,(n*16)+8(reg); \ + lwz RB,(n*16)+12(reg); \ mtspr DBAT##n##U,RA; \ mtspr DBAT##n##L,RB; \ 1: #endif /* CONFIG_PPC64 */ - -#ifndef CONFIG_APUS -#define tophys(rd,rs,rt) addis rd,rs,-KERNELBASE@h -#define tovirt(rd,rs,rt) addis rd,rs,KERNELBASE@h -#else -#define tophys(rd,rs,rt) \ - lis rt,CYBERBASEp@h; \ - lwz rt,0(rt); \ - add rd,rs,rt -#define tovirt(rd,rs,rt) \ - lis rt,CYBERBASEp@h; \ - lwz rt,0(rt); \ - sub rd,rs,rt -#endif .text .globl _stext @@ -149,7 +74,15 @@ _stext: .text .globl _start _start: - .long TOPHYS(__start),0,0 + /* + * These are here for legacy reasons, the kernel used to + * need to look like a coff function entry for the pmac + * but we're always started by some kind of bootloader now. + * -- Cort + */ + nop + nop + nop /* PMAC * Enter here with the kernel text, data and bss loaded starting at @@ -168,6 +101,7 @@ _start: * * APUS * r3: 'APUS' + * r4: physical address of memory base * Linux/m68k style BootInfo structure at &_end. * * PREP @@ -183,39 +117,6 @@ _start: * This just gets a minimal mmu environment setup so we can call * start_here() to do the real work. * -- Cort - * - * MPC8xx - * This port was done on an MBX board with an 860. Right now I only - * support an ELF compressed (zImage) boot from EPPC-Bug because the - * code there loads up some registers before calling us: - * r3: ptr to board info data - * r4: initrd_start or if no initrd then 0 - * r5: initrd_end - unused if r4 is 0 - * r6: Start of command line string - * r7: End of command line string - * - * I decided to use conditional compilation instead of checking PVR and - * adding more processor specific branches around code I don't need. - * Since this is an embedded processor, I also appreciate any memory - * savings I can get. - * - * The MPC8xx does not have any BATs, but it supports large page sizes. - * We first initialize the MMU to support 8M byte pages, then load one - * entry into each of the instruction and data TLBs to map the first - * 8M 1:1. I also mapped an additional I/O space 1:1 so we can get to - * the "internal" processor registers before MMU_init is called. - * - * The TLB code currently contains a major hack. Since I use the condition - * code register, I have to save and restore it. I am out of registers, so - * I just store it in memory location 0 (the TLB handlers are not reentrant). - * To avoid making any decisions, I need to use the "segment" valid bit - * in the first level table, but that would require many changes to the - * Linux page directory/table functions that I don't want to do right now. - * - * I used to use SPRG2 for a temporary register in the TLB handler, but it - * has since been put to other uses. I now use a hack to save a register - * and the CCR at memory location 0.....Someday I'll fix this..... - * -- Dan */ .globl __start @@ -241,17 +142,23 @@ __start: mr r28,r6 mr r27,r7 li r24,0 /* cpu # */ -#ifndef CONFIG_8xx bl prom_init - .globl __secondary_start -__secondary_start: + +#ifdef CONFIG_APUS +/* On APUS the __va/__pa constants need to be set to the correct + * values before continuing. + */ + mr r4,r30 + bl fix_mem_constants +#endif + /* * Use the first pair of BAT registers to map the 1st 16MB * of RAM to KERNELBASE. From this point on we can't safely * call OF any more. */ lis r11,KERNELBASE@h -#ifndef CONFIG_PPC64 +#ifndef CONFIG_PPC64xxx mfspr r9,PVR rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ cmpi 0,r9,1 @@ -267,16 +174,9 @@ __secondary_start: b 5f #endif /* CONFIG_PPC64 */ 4: -#ifdef CONFIG_APUS - ori r11,r11,BL_8M<<2|0x2 /* set up an 8MB mapping */ - ori r11,r11,0xfe /* set up an 8MB mapping */ - lis r8,CYBERBASEp@h - lwz r8,0(r8) - addis r8,r8,KERNELBASE@h - addi r8,r8,2 -#else + tophys(r8,r11) + ori r8,r8,2 /* R/W access */ ori r11,r11,BL_256M<<2|0x2 /* set up BAT registers for 604 */ - li r8,2 /* R/W access */ #ifdef CONFIG_PPC64 /* clear out the high 32 bits in the BAT */ clrldi r11,r11,32 @@ -289,21 +189,29 @@ __secondary_start: * allow secondary cpus to get at all of ram in early bootup * since their init_task may be up there -- Cort */ +#if 0 oris r18,r8,0x10000000@h oris r21,r11,(KERNELBASE+0x10000000)@h +#else + lis r18,0x9000 + ori r18,r18,0x12 + lis r21,0x9000 + ori r21,r21,0x7fe +#endif mtspr DBAT1L,r18 /* N.B. 6xx (not 601) have valid */ mtspr DBAT1U,r21 /* bit in upper BAT register */ mtspr IBAT1L,r18 mtspr IBAT1U,r21 - + +#if 0 /* for now, otherwise we overflow the 0x100 bytes we have here */ oris r18,r8,0x20000000@h oris r21,r11,(KERNELBASE+0x20000000)@h mtspr DBAT2L,r18 /* N.B. 6xx (not 601) have valid */ mtspr DBAT2U,r21 /* bit in upper BAT register */ - mtspr IBAT2L,r28 + mtspr IBAT2L,r18 mtspr IBAT2U,r21 +#endif /* 0 */ #endif /* CONFIG_PPC64 */ -#endif mtspr DBAT0L,r8 /* N.B. 6xx (not 601) have valid */ mtspr DBAT0U,r11 /* bit in upper BAT register */ mtspr IBAT0L,r8 @@ -325,7 +233,7 @@ __secondary_start: /* Copy exception code to exception vector base. */ lis r3,KERNELBASE@h - tophys(r4,r3,r5) + tophys(r4,r3) lis r3,0xfff0 /* Copy to 0xfff00000 on APUS */ li r5,0x4000 /* # bytes of memory to copy */ li r6,0 @@ -359,80 +267,6 @@ __secondary_start: * this shouldn't bother the pmac since it just gets turned on again * as we jump to our code at KERNELBASE. -- Cort */ - -#else /* CONFIG_8xx */ - tlbia /* Invalidate all TLB entries */ - li r8, 0 - mtspr MI_CTR, r8 /* Set instruction control to zero */ - lis r8, MD_RESETVAL@h - mtspr MD_CTR, r8 /* Set data TLB control */ - - /* Now map the lower 8 Meg into the TLBs. For this quick hack, - * we can load the instruction and data TLB registers with the - * same values. - */ - lis r8, KERNELBASE@h /* Create vaddr for TLB */ - ori r8, r8, MI_EVALID /* Mark it valid */ - mtspr MI_EPN, r8 - mtspr MD_EPN, r8 - li r8, MI_PS8MEG /* Set 8M byte page */ - ori r8, r8, MI_SVALID /* Make it valid */ - mtspr MI_TWC, r8 - mtspr MD_TWC, r8 - li r8, MI_BOOTINIT /* Create RPN for address 0 */ - mtspr MI_RPN, r8 /* Store TLB entry */ - mtspr MD_RPN, r8 - lis r8, MI_Kp@h /* Set the protection mode */ - mtspr MI_AP, r8 - mtspr MD_AP, r8 - -/* We will get these from a configuration file as soon as I verify - * the extraneous bits don't cause problems in the TLB. - */ -#if defined(CONFIG_MBX) || defined(CONFIG_RPXLITE) -#define BOOT_IMMR 0xfa000000 -#endif -#ifdef CONFIG_BSEIP -#define BOOT_IMMR 0xff000000 -#endif - /* Map another 8 MByte at 0xfa000000 to get the processor - * internal registers (among other things). - */ - lis r8, BOOT_IMMR@h /* Create vaddr for TLB */ - ori r8, r8, MD_EVALID /* Mark it valid */ - mtspr MD_EPN, r8 - li r8, MD_PS8MEG /* Set 8M byte page */ - ori r8, r8, MD_SVALID /* Make it valid */ - mtspr MD_TWC, r8 - lis r8, BOOT_IMMR@h /* Create paddr for TLB */ - ori r8, r8, MI_BOOTINIT|0x2 /* Inhibit cache -- Cort */ - mtspr MD_RPN, r8 - - /* Since the cache is enabled according to the information we - * just loaded into the TLB, invalidate and enable the caches here. - * We should probably check/set other modes....later. - */ - lis r8, IDC_INVALL@h - mtspr IC_CST, r8 - mtspr DC_CST, r8 - lis r8, IDC_ENABLE@h - mtspr IC_CST, r8 -#if 0 - mtspr DC_CST, r8 -#else - /* For a debug option, I left this here to easily enable - * the write through cache mode - */ - lis r8, DC_SFWT@h - mtspr DC_CST, r8 - lis r8, IDC_ENABLE@h - mtspr DC_CST, r8 -#endif - -/* We now have the lower 8 Meg mapped into TLB entries, and the caches - * ready to work. - */ -#endif /* CONFIG_8xx */ turn_on_mmu: mfmsr r0 @@ -445,14 +279,6 @@ turn_on_mmu: rfi /* enables MMU */ /* - * GCC sometimes accesses words at negative offsets from the stack - * pointer, although the SysV ABI says it shouldn't. To cope with - * this, we leave this much untouched space on the stack on exception - * entry. - */ -#define STACK_UNDERHEAD 0 - -/* * Exception entry code. This code runs with address translation * turned off, i.e. using physical addresses. * We assume sprg3 has the physical address of the current @@ -465,8 +291,8 @@ turn_on_mmu: mfspr r21,SPRG2; /* exception stack to use from */ \ cmpwi 0,r21,0; /* user mode or RTAS */ \ bne 1f; \ - tophys(r21,r1,r21); /* use tophys(kernel sp) otherwise */ \ - subi r21,r21,INT_FRAME_SIZE+STACK_UNDERHEAD; /* alloc exc. frame */\ + tophys(r21,r1); /* use tophys(kernel sp) otherwise */ \ + subi r21,r21,INT_FRAME_SIZE; /* alloc exc. frame */\ 1: stw r20,_CCR(r21); /* save registers */ \ stw r22,GPR22(r21); \ stw r23,GPR23(r21); \ @@ -486,7 +312,7 @@ turn_on_mmu: stw r1,GPR1(r21); \ stw r2,GPR2(r21); \ stw r1,0(r21); \ - tovirt(r1,r21,r1); /* set new kernel sp */ \ + tovirt(r1,r21); /* set new kernel sp */ \ SAVE_4GPRS(3, r21); /* * Note: code which follows this uses cr0.eq (set if from kernel), @@ -504,35 +330,30 @@ label: \ li r20,MSR_KERNEL; \ bl transfer_to_handler; \ .long hdlr; \ - .long int_return + .long ret_from_except /* System reset */ #ifdef CONFIG_SMP /* MVME/MTX start the secondary here */ STD_EXCEPTION(0x100, Reset, __secondary_start_psurge) #else STD_EXCEPTION(0x100, Reset, UnknownException) -#endif +#endif /* Machine check */ STD_EXCEPTION(0x200, MachineCheck, MachineCheckException) -/* Data access exception. - * This is "never generated" by the MPC8xx. We jump to it for other - * translation errors. - */ +/* Data access exception. */ . = 0x300 DataAccess: EXCEPTION_PROLOG mfspr r20,DSISR -#ifndef CONFIG_8xx andis. r0,r20,0xa470 /* weird error? */ bne 1f /* if not, try to put a PTE */ mfspr r3,DAR /* into the hash table */ rlwinm r4,r23,32-13,30,30 /* MSR_PR -> _PAGE_USER */ rlwimi r4,r20,32-23,29,29 /* DSISR_STORE -> _PAGE_RW */ - mfspr r5,SPRG3 /* phys addr of TSS */ + mfspr r5,SPRG3 /* phys addr of THREAD */ bl hash_page -#endif 1: stw r20,_DSISR(r21) mr r5,r20 mfspr r4,DAR @@ -542,24 +363,19 @@ DataAccess: rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ bl transfer_to_handler .long do_page_fault - .long int_return + .long ret_from_except -/* Instruction access exception. - * This is "never generated" by the MPC8xx. We jump to it for other - * translation errors. - */ +/* Instruction access exception. */ . = 0x400 InstructionAccess: EXCEPTION_PROLOG -#ifndef CONFIG_8xx andis. r0,r23,0x4000 /* no pte found? */ beq 1f /* if so, try to put a PTE */ mr r3,r22 /* into the hash table */ rlwinm r4,r23,32-13,30,30 /* MSR_PR -> _PAGE_USER */ mr r20,r23 /* SRR1 has reason bits */ - mfspr r5,SPRG3 /* phys addr of TSS */ + mfspr r5,SPRG3 /* phys addr of THREAD */ bl hash_page -#endif 1: addi r3,r1,STACK_FRAME_OVERHEAD mr r4,r22 mr r5,r23 @@ -567,7 +383,7 @@ InstructionAccess: rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ bl transfer_to_handler .long do_page_fault - .long int_return + .long ret_from_except /* External interrupt */ . = 0x500; @@ -606,7 +422,7 @@ HardwareInterrupt: li r4,0 bl transfer_to_handler .long do_IRQ; - .long int_return + .long ret_from_except /* Alignment exception */ @@ -622,7 +438,7 @@ Alignment: rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ bl transfer_to_handler .long AlignmentException - .long int_return + .long ret_from_except /* Program check exception */ . = 0x700 @@ -633,9 +449,8 @@ ProgramCheck: rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ bl transfer_to_handler .long ProgramCheckException - .long int_return + .long ret_from_except -#ifndef CONFIG_8xx /* Floating-point unavailable */ . = 0x800 FPUnavailable: @@ -644,12 +459,7 @@ FPUnavailable: li r20,MSR_KERNEL bl transfer_to_handler /* if from kernel, take a trap */ .long KernelFP - .long int_return -#else -/* No FPU on MPC8xx. This exception is not supposed to happen. -*/ - STD_EXCEPTION(0x800, FPUnavailable, UnknownException) -#endif + .long ret_from_except STD_EXCEPTION(0x900, Decrementer, timer_interrupt) STD_EXCEPTION(0xa00, Trap_0a, UnknownException) @@ -664,7 +474,7 @@ SystemCall: rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ bl transfer_to_handler .long DoSyscall - .long int_return + .long ret_from_except /* Single step - not used on 601 */ STD_EXCEPTION(0xd00, SingleStep, SingleStepException) @@ -672,14 +482,12 @@ SystemCall: STD_EXCEPTION(0xe00, Trap_0e, UnknownException) STD_EXCEPTION(0xf00, Trap_0f, UnknownException) -#ifndef CONFIG_8xx /* * Handle TLB miss for instruction on 603/603e. * Note: we get an alternate set of r0 - r3 to use automatically. */ . = 0x1000 InstructionTLBMiss: -#ifdef NO_RELOAD_HTAB /* * r0: stored ctr * r1: linux style pte ( later becomes ppc hardware pte ) @@ -689,14 +497,14 @@ InstructionTLBMiss: mfctr r0 /* Get PTE (linux-style) and check access */ mfspr r2,SPRG3 - lwz r2,PG_TABLES(r2) - tophys(r2,r2,r3) + lwz r2,PGDIR(r2) + tophys(r2,r2) mfspr r3,IMISS rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */ lwz r2,0(r2) /* get pmd entry */ rlwinm. r2,r2,0,0,19 /* extract address of pte page */ beq- InstructionAddressInvalid /* return if no mapping */ - tophys(r2,r2,r1) + tophys(r2,r2) rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ lwz r1,0(r2) /* get linux-style pte */ /* setup access flags in r3 */ @@ -719,40 +527,11 @@ InstructionTLBMiss: mfspr r3,SRR1 /* Need to restore CR0 */ mtcrf 0x80,r3 rfi -#else - mfctr r0 /* Need to save this - CTR can't be touched! */ - mfspr r2,HASH1 /* Get PTE pointer */ - mfspr r3,ICMP /* Partial item compare value */ -00: li r1,8 /* 8 items / bucket */ - mtctr r1 - subi r2,r2,8 /* Preset pointer */ -10: lwzu r1,8(r2) /* Get next PTE */ - cmp 0,r1,r3 /* Found entry yet? */ - bdnzf 2,10b /* Jump back if not, until CTR==0 */ - bne 30f /* Try secondary hash if CTR==0 */ - lwz r1,4(r2) /* Get second word of entry */ -20: mtctr r0 /* Restore CTR */ - mfspr r3,SRR1 /* Need to restore CR0 */ - mtcrf 0x80,r3 - mfspr r0,IMISS /* Set to update TLB */ - mtspr RPA,r1 - tlbli r0 - rfi /* All done */ -/* Secondary hash */ -30: andi. r1,r3,0x40 /* Already doing secondary hash? */ - bne InstructionAddressInvalid /* Yes - item not in hash table */ - mfspr r2,HASH2 /* Get hash table pointer */ - ori r3,r3,0x40 /* Set secondary hash */ - b 00b /* Try lookup again */ -#endif /* NO_RELOAD_HTAB */ InstructionAddressInvalid: mfspr r3,SRR1 rlwinm r1,r3,9,6,6 /* Get load/store bit */ -#ifdef NO_RELOAD_HTAB + addis r1,r1,0x2000 -#else - addis r1,r1,0x4000 /* Set bit 1 -> PTE not found (in HTAB) */ -#endif /* NO_RELOAD_HTAB */ mtspr DSISR,r1 /* (shouldn't be needed) */ mtctr r0 /* Restore CTR */ andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */ @@ -769,20 +548,12 @@ InstructionAddressInvalid: sync /* Some chip revs have problems here... */ mtmsr r0 b InstructionAccess -#else -/* On the MPC8xx, this is a software emulation interrupt. It occurs - * for all unimplemented and illegal instructions. - */ - STD_EXCEPTION(0x1000, SoftEmu, SoftwareEmulation) -#endif /* * Handle TLB miss for DATA Load operation on 603/603e */ . = 0x1100 -#ifndef CONFIG_8xx DataLoadTLBMiss: -#ifdef NO_RELOAD_HTAB /* * r0: stored ctr * r1: linux style pte ( later becomes ppc hardware pte ) @@ -792,14 +563,14 @@ DataLoadTLBMiss: mfctr r0 /* Get PTE (linux-style) and check access */ mfspr r2,SPRG3 - lwz r2,PG_TABLES(r2) - tophys(r2,r2,r3) + lwz r2,PGDIR(r2) + tophys(r2,r2) mfspr r3,DMISS rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */ lwz r2,0(r2) /* get pmd entry */ rlwinm. r2,r2,0,0,19 /* extract address of pte page */ beq- DataAddressInvalid /* return if no mapping */ - tophys(r2,r2,r1) + tophys(r2,r2) rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ lwz r1,0(r2) /* get linux-style pte */ /* setup access flags in r3 */ @@ -823,40 +594,10 @@ DataLoadTLBMiss: mfspr r3,SRR1 /* Need to restore CR0 */ mtcrf 0x80,r3 rfi -#else - mfctr r0 /* Need to save this - CTR can't be touched! */ - mfspr r2,HASH1 /* Get PTE pointer */ - mfspr r3,DCMP /* Partial item compare value */ -00: li r1,8 /* 8 items / bucket */ - mtctr r1 - subi r2,r2,8 /* Preset pointer */ -10: lwzu r1,8(r2) /* Get next PTE */ - cmp 0,r1,r3 /* Found entry yet? */ - bdnzf 2,10b /* Jump back if not, until CTR==0 */ - bne 30f /* Try secondary hash if CTR==0 */ - lwz r1,4(r2) /* Get second word of entry */ -20: mtctr r0 /* Restore CTR */ - mfspr r3,SRR1 /* Need to restore CR0 */ - mtcrf 0x80,r3 - mfspr r0,DMISS /* Set to update TLB */ - mtspr RPA,r1 - tlbld r0 - rfi /* All done */ -/* Secondary hash */ -30: andi. r1,r3,0x40 /* Already doing secondary hash? */ - bne DataAddressInvalid /* Yes - item not in hash table */ - mfspr r2,HASH2 /* Get hash table pointer */ - ori r3,r3,0x40 /* Set secondary hash */ - b 00b /* Try lookup again */ -#endif /* NO_RELOAD_HTAB */ DataAddressInvalid: mfspr r3,SRR1 rlwinm r1,r3,9,6,6 /* Get load/store bit */ -#ifdef NO_RELOAD_HTAB addis r1,r1,0x2000 -#else - addis r1,r1,0x4000 /* Set bit 1 -> PTE not found */ -#endif /* NO_RELOAD_HTAB */ mtspr DSISR,r1 mtctr r0 /* Restore CTR */ andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */ @@ -872,79 +613,12 @@ DataAddressInvalid: sync /* Some chip revs have problems here... */ mtmsr r0 b DataAccess -#else -/* - * For the MPC8xx, this is a software tablewalk to load the instruction - * TLB. It is modelled after the example in the Motorola manual. The task - * switch loads the M_TWB register with the pointer to the first level table. - * If we discover there is no second level table (the value is zero), the - * plan was to load that into the TLB, which causes another fault into the - * TLB Error interrupt where we can handle such problems. However, that did - * not work, so if we discover there is no second level table, we restore - * registers and branch to the error exception. We have to use the MD_xxx - * registers for the tablewalk because the equivalent MI_xxx registers - * only perform the attribute functions. - */ -InstructionTLBMiss: - mtspr M_TW, r20 /* Save a couple of working registers */ - mfcr r20 - stw r20, 0(r0) - stw r21, 4(r0) - mfspr r20, SRR0 /* Get effective address of fault */ - mtspr MD_EPN, r20 /* Have to use MD_EPN for walk, MI_EPN can't */ - mfspr r20, M_TWB /* Get level 1 table entry address */ - lwz r21, 0(r20) /* Get the level 1 entry */ - rlwinm. r20, r21,0,0,20 /* Extract page descriptor page address */ - beq 2f /* If zero, don't try to find a pte */ - - /* We have a pte table, so load the MI_TWC with the attributes - * for this page, which has only bit 31 set. - */ - tophys(r21,r21,0) - ori r21,r21,1 /* Set valid bit */ - mtspr MI_TWC, r21 /* Set page attributes */ - mtspr MD_TWC, r21 /* Load pte table base address */ - mfspr r21, MD_TWC /* ....and get the pte address */ - lwz r21, 0(r21) /* Get the pte */ - - /* Set four subpage valid bits (24, 25, 26, and 27). - * Since we currently run MI_CTR.PPCS = 0, the manual says, - * "If the page size is larger than 4k byte, then all the - * 4 bits should have the same value." - * I don't really know what to do if the page size is 4k Bytes, - * but I know setting them all to 0 does not work, and setting them - * all to 1 does, so that is the way it is right now. - * BTW, these four bits map to the software only bits in the - * linux page table. I used to turn them all of, but now just - * set them all for the hardware. - li r20, 0x00f0 - andc r20, r21, r20 - ori r20, r20, 0x0080 - */ - ori r20, r21, 0x00f0 - - mtspr MI_RPN, r20 /* Update TLB entry */ - - mfspr r20, M_TW /* Restore registers */ - lwz r21, 0(r0) - mtcr r21 - lwz r21, 4(r0) - rfi - -2: mfspr r20, M_TW /* Restore registers */ - lwz r21, 0(r0) - mtcr r21 - lwz r21, 4(r0) - b InstructionAccess -#endif /* CONFIG_8xx */ /* * Handle TLB miss for DATA Store on 603/603e */ . = 0x1200 DataStoreTLBMiss: -#ifndef CONFIG_8xx -#ifdef NO_RELOAD_HTAB /* * r0: stored ctr * r1: linux style pte ( later becomes ppc hardware pte ) @@ -954,14 +628,14 @@ DataStoreTLBMiss: mfctr r0 /* Get PTE (linux-style) and check access */ mfspr r2,SPRG3 - lwz r2,PG_TABLES(r2) - tophys(r2,r2,r3) + lwz r2,PGDIR(r2) + tophys(r2,r2) mfspr r3,DMISS rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */ lwz r2,0(r2) /* get pmd entry */ rlwinm. r2,r2,0,0,19 /* extract address of pte page */ beq- DataAddressInvalid /* return if no mapping */ - tophys(r2,r2,r1) + tophys(r2,r2) rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ lwz r1,0(r2) /* get linux-style pte */ /* setup access flags in r3 */ @@ -985,171 +659,12 @@ DataStoreTLBMiss: mfspr r3,SRR1 /* Need to restore CR0 */ mtcrf 0x80,r3 rfi -#else - mfctr r0 /* Need to save this - CTR can't be touched! */ - mfspr r2,HASH1 /* Get PTE pointer */ - mfspr r3,DCMP /* Partial item compare value */ -00: li r1,8 /* 8 items / bucket */ - mtctr r1 - subi r2,r2,8 /* Preset pointer */ -10: lwzu r1,8(r2) /* Get next PTE */ - cmp 0,r1,r3 /* Found entry yet? */ - bdnzf 2,10b /* Jump back if not, until CTR==0 */ - bne 30f /* Try secondary hash if CTR==0 */ - lwz r1,4(r2) /* Get second word of entry */ -20: mtctr r0 /* Restore CTR */ - mfspr r3,SRR1 /* Need to restore CR0 */ - mtcrf 0x80,r3 - mfspr r0,DMISS /* Set to update TLB */ - mtspr RPA,r1 - tlbld r0 - rfi /* All done */ -/* Secondary hash */ -30: andi. r1,r3,0x40 /* Already doing secondary hash? */ - bne DataAddressInvalid /* Yes - item not in hash table */ - mfspr r2,HASH2 /* Get hash table pointer */ - ori r3,r3,0x40 /* Set secondary hash */ - b 00b /* Try lookup again */ -#endif /* NO_RELOAD_HTAB */ -#else /* CONFIG_8xx */ - mtspr M_TW, r20 /* Save a couple of working registers */ - mfcr r20 - stw r20, 0(r0) - stw r21, 4(r0) - mfspr r20, M_TWB /* Get level 1 table entry address */ - lwz r21, 0(r20) /* Get the level 1 entry */ - rlwinm. r20, r21,0,0,20 /* Extract page descriptor page address */ - beq 2f /* If zero, don't try to find a pte */ - - /* We have a pte table, so load fetch the pte from the table. - */ - tophys(r21, r21, 0) - ori r21, r21, 1 /* Set valid bit in physical L2 page */ - mtspr MD_TWC, r21 /* Load pte table base address */ - mfspr r21, MD_TWC /* ....and get the pte address */ - lwz r21, 0(r21) /* Get the pte */ - - /* Set four subpage valid bits (24, 25, 26, and 27). - * Since we currently run MD_CTR.PPCS = 0, the manual says, - * "If the page size is larger than 4k byte, then all the - * 4 bits should have the same value." - * I don't really know what to do if the page size is 4k Bytes, - * but I know setting them all to 0 does not work, and setting them - * all to 1 does, so that is the way it is right now. - * BTW, these four bits map to the software only bits in the - * linux page table. I used to turn them all of, but now just - * set them all for the hardware. - li r20, 0x00f0 - andc r20, r21, r20 - ori r20, r20, 0x0080 - */ - ori r20, r21, 0x00f0 - - mtspr MD_RPN, r20 /* Update TLB entry */ - - mfspr r20, M_TW /* Restore registers */ - lwz r21, 0(r0) - mtcr r21 - lwz r21, 4(r0) - rfi - -2: mfspr r20, M_TW /* Restore registers */ - lwz r21, 0(r0) - mtcr r21 - lwz r21, 4(r0) - b DataAccess -#endif /* CONFIG_8xx */ -#ifndef CONFIG_8xx /* Instruction address breakpoint exception (on 603/604) */ STD_EXCEPTION(0x1300, Trap_13, InstructionBreakpoint) -#else - -/* This is an instruction TLB error on the MPC8xx. This could be due - * to many reasons, such as executing guarded memory or illegal instruction - * addresses. There is nothing to do but handle a big time error fault. - */ - . = 0x1300 -InstructionTLBError: - b InstructionAccess -#endif /* System management exception (603?) */ -#ifndef CONFIG_8xx STD_EXCEPTION(0x1400, Trap_14, UnknownException) -#else - -/* This is the data TLB error on the MPC8xx. This could be due to - * many reasons, including a dirty update to a pte. We can catch that - * one here, but anything else is an error. First, we track down the - * Linux pte. If it is valid, write access is allowed, but the - * page dirty bit is not set, we will set it and reload the TLB. For - * any other case, we bail out to a higher level function that can - * handle it. - */ - . = 0x1400 -DataTLBError: - mtspr M_TW, r20 /* Save a couple of working registers */ - mfcr r20 - stw r20, 0(r0) - stw r21, 4(r0) - - /* First, make sure this was a store operation. - */ - mfspr r20, DSISR - andis. r21, r20, 0x0200 /* If set, indicates store op */ - beq 2f - - mfspr r20, M_TWB /* Get level 1 table entry address */ - lwz r21, 0(r20) /* Get the level 1 entry */ - rlwinm. r20, r21,0,0,20 /* Extract page descriptor page address */ - beq 2f /* If zero, bail */ - - /* We have a pte table, so fetch the pte from the table. - */ - tophys(r21, r21, 0) - ori r21, r21, 1 /* Set valid bit in physical L2 page */ - mtspr MD_TWC, r21 /* Load pte table base address */ - mfspr r21, MD_TWC /* ....and get the pte address */ - lwz r21, 0(r21) /* Get the pte */ - - andi. r20, r21, _PAGE_RW /* Is it writeable? */ - beq 2f /* Bail out if not */ - - ori r21, r21, _PAGE_DIRTY /* Update changed bit */ - mfspr r20, MD_TWC /* Get pte address again */ - stw r21, 0(r20) /* and update pte in table */ - - /* Set four subpage valid bits (24, 25, 26, and 27). - * Since we currently run MD_CTR.PPCS = 0, the manual says, - * "If the page size is larger than 4k byte, then all the - * 4 bits should have the same value." - * I don't really know what to do if the page size is 4k Bytes, - * but I know setting them all to 0 does not work, and setting them - * all to 1 does, so that is the way it is right now. - * BTW, these four bits map to the software only bits in the - * linux page table. I used to turn them all of, but now just - * set them all for the hardware. - li r20, 0x00f0 - andc r20, r21, r20 - ori r20, r20, 0x0080 - */ - ori r20, r21, 0x00f0 - - mtspr MD_RPN, r20 /* Update TLB entry */ - - mfspr r20, M_TW /* Restore registers */ - lwz r21, 0(r0) - mtcr r21 - lwz r21, 4(r0) - rfi -2: - mfspr r20, M_TW /* Restore registers */ - lwz r21, 0(r0) - mtcr r21 - lwz r21, 4(r0) - b DataAccess -#endif /* CONFIG_8xx */ STD_EXCEPTION(0x1500, Trap_15, UnknownException) STD_EXCEPTION(0x1600, Trap_16, UnknownException) @@ -1158,16 +673,11 @@ DataTLBError: STD_EXCEPTION(0x1900, Trap_19, UnknownException) STD_EXCEPTION(0x1a00, Trap_1a, UnknownException) STD_EXCEPTION(0x1b00, Trap_1b, UnknownException) -/* On the MPC8xx, these next four traps are used for development - * support of breakpoints and such. Someday I will get around to - * using them. - */ STD_EXCEPTION(0x1c00, Trap_1c, UnknownException) STD_EXCEPTION(0x1d00, Trap_1d, UnknownException) STD_EXCEPTION(0x1e00, Trap_1e, UnknownException) STD_EXCEPTION(0x1f00, Trap_1f, UnknownException) -#ifndef CONFIG_8xx /* Run mode exception */ STD_EXCEPTION(0x2000, RunMode, RunModeException) @@ -1188,9 +698,6 @@ DataTLBError: STD_EXCEPTION(0x2f00, Trap_2f, UnknownException) . = 0x3000 -#else - . = 0x2000 -#endif /* * This code finishes saving the registers to the exception frame @@ -1208,12 +715,12 @@ transfer_to_handler: SAVE_8GPRS(12, r21) SAVE_8GPRS(24, r21) andi. r23,r23,MSR_PR - mfspr r23,SPRG3 /* if from user, fix up tss.regs */ + mfspr r23,SPRG3 /* if from user, fix up THREAD.regs */ beq 2f addi r24,r1,STACK_FRAME_OVERHEAD stw r24,PT_REGS(r23) -2: addi r2,r23,-TSS /* set r2 to current */ - tovirt(r2,r2,r23) +2: addi r2,r23,-THREAD /* set r2 to current */ + tovirt(r2,r2) mflr r23 andi. r24,r23,0x3f00 /* get vector offset */ stw r24,TRAP(r21) @@ -1252,300 +759,6 @@ stack_ovf: SYNC rfi -#ifndef CONFIG_8xx -/* - * Load a PTE into the hash table, if possible. - * The address is in r3, and r4 contains access flags: - * _PAGE_USER (4) if a user-mode access, ored with - * _PAGE_RW (2) if a write. r20 contains DSISR or SRR1, - * so bit 1 (0x40000000) is set if the exception was due - * to no matching PTE being found in the hash table. - * r5 contains the physical address of the current task's tss. - * - * Returns to the caller if the access is illegal or there is no - * mapping for the address. Otherwise it places an appropriate PTE - * in the hash table and returns from the exception. - * Uses r0, r2 - r6, ctr, lr. - * - * For speed, 4 of the instructions get patched once the size and - * physical address of the hash table are known. These definitions - * of Hash_base and Hash_bits below are just an example. - */ -Hash_base = 0x180000 -Hash_bits = 12 /* e.g. 256kB hash table */ -Hash_msk = (((1 << Hash_bits) - 1) * 64) - - .globl hash_page -hash_page: -#ifdef __SMP__ - eieio - lis r2,hash_table_lock@h - ori r2,r2,hash_table_lock@l - tophys(r2,r2,r6) - lis r6,100000000@h - mtctr r6 - lwz r0,PROCESSOR-TSS(r5) - or r0,r0,r6 -10: lwarx r6,0,r2 - cmpi 0,r6,0 - bne- 12f - stwcx. r0,0,r2 - beq+ 11f -12: cmpw r6,r0 - bdnzf 2,10b - tw 31,31,31 -11: eieio -#endif - /* Get PTE (linux-style) and check access */ - lwz r5,PG_TABLES(r5) - tophys(r5,r5,r2) /* convert to phys addr */ - rlwimi r5,r3,12,20,29 /* insert top 10 bits of address */ - lwz r5,0(r5) /* get pmd entry */ - rlwinm. r5,r5,0,0,19 /* extract address of pte page */ -#ifdef __SMP__ - beq- hash_page_out /* return if no mapping */ -#else - /* XXX it seems like the 601 will give a machine fault on the - rfi if its alignment is wrong (bottom 4 bits of address are - 8 or 0xc) and we have had a not-taken conditional branch - to the address following the rfi. */ - beqlr- -#endif - tophys(r2,r5,r2) - rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ - lwz r6,0(r2) /* get linux-style pte */ - ori r4,r4,1 /* set _PAGE_PRESENT bit in access */ - andc. r0,r4,r6 /* check access & ~permission */ -#ifdef __SMP__ - bne- hash_page_out /* return if access not permitted */ -#else - bnelr- -#endif - - ori r6,r6,0x100 /* set _PAGE_ACCESSED in pte */ - rlwinm r5,r4,5,24,24 /* _PAGE_RW access -> _PAGE_DIRTY */ - rlwimi r5,r4,7,22,22 /* _PAGE_RW -> _PAGE_HWWRITE */ - or r6,r6,r5 - stw r6,0(r2) /* update PTE (accessed/dirty bits) */ - - /* Convert linux-style PTE to low word of PPC-style PTE */ -#ifdef CONFIG_PPC64 - /* clear the high 32 bits just in case */ - clrldi r6,r6,32 - clrldi r4,r4,32 -#endif /* CONFIG_PPC64 */ - rlwinm r4,r6,32-9,31,31 /* _PAGE_HWWRITE -> PP lsb */ - rlwimi r6,r6,32-1,31,31 /* _PAGE_USER -> PP (both bits now) */ - ori r4,r4,0xe04 /* clear out reserved bits */ - andc r6,r6,r4 /* PP=2 or 0, when _PAGE_HWWRITE */ - - /* Construct the high word of the PPC-style PTE */ - mfsrin r5,r3 /* get segment reg for segment */ -#ifdef CONFIG_PPC64 - sldi r5,r5,12 -#else /* CONFIG_PPC64 */ - rlwinm r5,r5,7,1,24 /* put VSID in 0x7fffff80 bits */ -#endif /* CONFIG_PPC64 */ - -#ifndef __SMP__ /* do this later for SMP */ -#ifdef CONFIG_PPC64 - ori r5,r5,1 /* set V (valid) bit */ -#else /* CONFIG_PPC64 */ - oris r5,r5,0x8000 /* set V (valid) bit */ -#endif /* CONFIG_PPC64 */ -#endif - -#ifdef CONFIG_PPC64 -/* XXX: does this insert the api correctly? -- Cort */ - rlwimi r5,r3,17,21,25 /* put in API (abbrev page index) */ -#else /* CONFIG_PPC64 */ - rlwimi r5,r3,10,26,31 /* put in API (abbrev page index) */ -#endif /* CONFIG_PPC64 */ - /* Get the address of the primary PTE group in the hash table */ - .globl hash_page_patch_A -hash_page_patch_A: - lis r4,Hash_base@h /* base address of hash table */ -#ifdef CONFIG_PPC64 - /* just in case */ - clrldi r4,r4,32 -#endif - rlwimi r4,r5,32-1,26-Hash_bits,25 /* (VSID & hash_mask) << 6 */ - rlwinm r0,r3,32-6,26-Hash_bits,25 /* (PI & hash_mask) << 6 */ - xor r4,r4,r0 /* make primary hash */ - - /* See whether it was a PTE not found exception or a - protection violation. */ - andis. r0,r20,0x4000 - li r2,8 /* PTEs/group */ - bne 10f /* no PTE: go look for an empty slot */ - tlbie r3 /* invalidate TLB entry */ - - /* Search the primary PTEG for a PTE whose 1st word matches r5 */ - mtctr r2 - addi r3,r4,-8 -1: lwzu r0,8(r3) /* get next PTE */ - cmp 0,r0,r5 - bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ - beq+ found_slot - - /* Search the secondary PTEG for a matching PTE */ - ori r5,r5,0x40 /* set H (secondary hash) bit */ - .globl hash_page_patch_B -hash_page_patch_B: - xoris r3,r4,Hash_msk>>16 /* compute secondary hash */ - xori r3,r3,0xffc0 - addi r3,r3,-8 - mtctr r2 -2: lwzu r0,8(r3) - cmp 0,r0,r5 - bdnzf 2,2b - beq+ found_slot - xori r5,r5,0x40 /* clear H bit again */ - - /* Search the primary PTEG for an empty slot */ -10: mtctr r2 - addi r3,r4,-8 /* search primary PTEG */ -1: lwzu r0,8(r3) /* get next PTE */ - srwi. r0,r0,31 /* only want to check valid bit */ - bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ - beq+ found_empty - - /* Search the secondary PTEG for an empty slot */ - ori r5,r5,0x40 /* set H (secondary hash) bit */ - .globl hash_page_patch_C -hash_page_patch_C: - xoris r3,r4,Hash_msk>>16 /* compute secondary hash */ - xori r3,r3,0xffc0 - addi r3,r3,-8 - mtctr r2 -2: lwzu r0,8(r3) - srwi. r0,r0,31 /* only want to check valid bit */ - bdnzf 2,2b - beq+ found_empty - - /* - * Choose an arbitrary slot in the primary PTEG to overwrite. - * Since both the primary and secondary PTEGs are full, and we - * have no information that the PTEs in the primary PTEG are - * more important or useful than those in the secondary PTEG, - * and we know there is a definite (although small) speed - * advantage to putting the PTE in the primary PTEG, we always - * put the PTE in the primary PTEG. - */ - xori r5,r5,0x40 /* clear H bit again */ - lwz r2,next_slot@l(0) - addi r2,r2,8 - andi. r2,r2,0x38 - stw r2,next_slot@l(0) - add r3,r4,r2 -11: - /* update counter of evicted pages */ - lis r2,htab_evicts@h - ori r2,r2,htab_evicts@l - tophys(r2,r2,r4) - lwz r4,0(r2) - addi r4,r4,1 - stw r4,0(r2) - -#ifndef __SMP__ - /* Store PTE in PTEG */ -found_empty: - stw r5,0(r3) -found_slot: - stw r6,4(r3) - sync - -#else /* __SMP__ */ -/* - * Between the tlbie above and updating the hash table entry below, - * another CPU could read the hash table entry and put it in its TLB. - * There are 3 cases: - * 1. using an empty slot - * 2. updating an earlier entry to change permissions (i.e. enable write) - * 3. taking over the PTE for an unrelated address - * - * In each case it doesn't really matter if the other CPUs have the old - * PTE in their TLB. So we don't need to bother with another tlbie here, - * which is convenient as we've overwritten the register that had the - * address. :-) The tlbie above is mainly to make sure that this CPU comes - * and gets the new PTE from the hash table. - * - * We do however have to make sure that the PTE is never in an invalid - * state with the V bit set. - */ -found_empty: -found_slot: - stw r5,0(r3) /* clear V (valid) bit in PTE */ - sync - tlbsync - sync - stw r6,4(r3) /* put in correct RPN, WIMG, PP bits */ - sync - oris r5,r5,0x8000 - stw r5,0(r3) /* finally set V bit in PTE */ -#endif /* __SMP__ */ - -/* - * Update the hash table miss count. We only want misses here - * that _are_ valid addresses and have a pte otherwise we don't - * count it as a reload. do_page_fault() takes care of bad addrs - * and entries that need linux-style pte's created. - * - * safe to use r2 here since we're not using it as current yet - * update the htab misses count - * -- Cort - */ - lis r2,htab_reloads@h - ori r2,r2,htab_reloads@l - tophys(r2,r2,r3) - lwz r3,0(r2) - addi r3,r3,1 - stw r3,0(r2) - -#ifdef __SMP__ - lis r2,hash_table_lock@ha - tophys(r2,r2,r6) - li r0,0 - stw r0,hash_table_lock@l(r2) - eieio -#endif - - /* Return from the exception */ - lwz r3,_CCR(r21) - lwz r4,_LINK(r21) - lwz r5,_CTR(r21) - mtcrf 0xff,r3 - mtlr r4 - mtctr r5 - REST_GPR(0, r21) - REST_2GPRS(1, r21) - REST_4GPRS(3, r21) - /* we haven't used xer */ - mtspr SRR1,r23 - mtspr SRR0,r22 - REST_GPR(20, r21) - REST_2GPRS(22, r21) - lwz r21,GPR21(r21) - rfi - -#ifdef __SMP__ -hash_page_out: - lis r2,hash_table_lock@ha - tophys(r2,r2,r6) - li r0,0 - stw r0,hash_table_lock@l(r2) - eieio - blr - - .globl hash_table_lock -hash_table_lock: - .long 0 -#endif - -next_slot: - .long 0 - -load_up_fpu: /* * Disable FP for the task which had the FPU previously, * and save its floating-point registers in its thread_struct. @@ -1553,6 +766,7 @@ load_up_fpu: * On SMP we know the fpu is free, since we give it up every * switch. -- Cort */ +load_up_fpu: mfmsr r5 ori r5,r5,MSR_FP SYNC @@ -1564,21 +778,17 @@ load_up_fpu: * to another. Instead we call giveup_fpu in switch_to. */ #ifndef __SMP__ -#ifndef CONFIG_APUS - lis r6,-KERNELBASE@h -#else - lis r6,CYBERBASEp@h - lwz r6,0(r6) -#endif + lis r6,0 /* get __pa constant */ + tophys(r6,r6) addis r3,r6,last_task_used_math@ha lwz r4,last_task_used_math@l(r3) cmpi 0,r4,0 beq 1f add r4,r4,r6 - addi r4,r4,TSS /* want TSS of last_task_used_math */ + addi r4,r4,THREAD /* want THREAD of last_task_used_math */ SAVE_32FPRS(0, r4) mffs fr0 - stfd fr0,TSS_FPSCR-4(r4) + stfd fr0,THREAD_FPSCR-4(r4) lwz r5,PT_REGS(r4) add r5,r5,r6 lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) @@ -1589,12 +799,12 @@ load_up_fpu: #endif /* __SMP__ */ /* enable use of FP after return */ ori r23,r23,MSR_FP|MSR_FE0|MSR_FE1 - mfspr r5,SPRG3 /* current task's TSS (phys) */ - lfd fr0,TSS_FPSCR-4(r5) + mfspr r5,SPRG3 /* current task's THREAD (phys) */ + lfd fr0,THREAD_FPSCR-4(r5) mtfsf 0xff,fr0 REST_32FPRS(0, r5) #ifndef __SMP__ - subi r4,r5,TSS + subi r4,r5,THREAD sub r4,r4,r6 stw r4,last_task_used_math@l(r3) #endif /* __SMP__ */ @@ -1627,7 +837,7 @@ KernelFP: mr r4,r2 /* current */ lwz r5,_NIP(r1) bl printk - b int_return + b ret_from_except 86: .string "floating point used in kernel (task=%p, pc=%x)\n" .align 4 @@ -1646,12 +856,12 @@ giveup_fpu: SYNC cmpi 0,r3,0 beqlr- /* if no previous owner, done */ - addi r3,r3,TSS /* want TSS of task */ + addi r3,r3,THREAD /* want THREAD of task */ lwz r5,PT_REGS(r3) cmpi 0,r5,0 SAVE_32FPRS(0, r3) mffs fr0 - stfd fr0,TSS_FPSCR-4(r3) + stfd fr0,THREAD_FPSCR-4(r3) beq 1f lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) li r3,MSR_FP|MSR_FE0|MSR_FE1 @@ -1665,12 +875,6 @@ giveup_fpu: #endif /* __SMP__ */ blr -#else /* CONFIG_8xx */ - .globl giveup_fpu -giveup_fpu: - blr -#endif /* CONFIG_8xx */ - /* * This code is jumped to from the startup code to copy * the kernel image to physical address 0. @@ -1721,20 +925,70 @@ copy_and_flush: blr #ifdef CONFIG_APUS - /* On APUS the first 0x4000 bytes of the kernel will be mapped - * at a different physical address than the rest. For this - * reason, the exception code cannot use relative branches to - * access the code below. - */ +/* + * On APUS the physical base address of the kernel is not known at compile + * time, which means the __pa/__va constants used are incorect. In the + * __init section is recorded the virtual addresses of instructions using + * these constants, so all that has to be done is fix these before + * continuing the kernel boot. + * + * r4 = The physical address of the kernel base. + */ +fix_mem_constants: + mr r10,r4 + addis r10,r10,-KERNELBASE@h /* virt_to_phys constant */ + neg r11,r10 /* phys_to_virt constant */ + + lis r12,__vtop_table_begin@h + ori r12,r12,__vtop_table_begin@l + add r12,r12,r10 /* table begin phys address */ + lis r13,__vtop_table_end@h + ori r13,r13,__vtop_table_end@l + add r13,r13,r10 /* table end phys address */ + subi r12,r12,4 + subi r13,r13,4 +1: lwzu r14,4(r12) /* virt address of instruction */ + add r14,r14,r10 /* phys address of instruction */ + lwz r15,0(r14) /* instruction, now insert top */ + rlwimi r15,r10,16,16,31 /* half of vp const in low half */ + stw r15,0(r14) /* of instruction and restore. */ + dcbst r0,r14 /* write it to memory */ + sync + icbi r0,r14 /* flush the icache line */ + cmpw r12,r13 + bne 1b + + lis r12,__ptov_table_begin@h + ori r12,r12,__ptov_table_begin@l + add r12,r12,r10 /* table begin phys address */ + lis r13,__ptov_table_end@h + ori r13,r13,__ptov_table_end@l + add r13,r13,r10 /* table end phys address */ + subi r12,r12,4 + subi r13,r13,4 +1: lwzu r14,4(r12) /* virt address of instruction */ + add r14,r14,r10 /* phys address of instruction */ + lwz r15,0(r14) /* instruction, now insert top */ + rlwimi r15,r11,16,16,31 /* half of pv const in low half*/ + stw r15,0(r14) /* of instruction and restore. */ + dcbst r0,r14 /* write it to memory */ + sync + icbi r0,r14 /* flush the icache line */ + cmpw r12,r13 + bne 1b + + isync /* No speculative loading until now */ + blr + + /* On APUS the first 0x4000 bytes of the kernel will be mapped + * at a different physical address than the rest. For this + * reason, the exception code cannot use relative branches to + * access the code below. + */ . = 0x4000 #endif #ifdef CONFIG_SMP - .globl __secondary_start_psurge -__secondary_start_psurge: - li r24,1 /* cpu # */ - b __secondary_start - .globl __secondary_hold __secondary_hold: /* tell the master we're here */ @@ -1752,20 +1006,63 @@ __secondary_hold: /* our cpu # was at addr 0 - go */ lis r5,__secondary_start@h ori r5,r5,__secondary_start@l - tophys(r5,r5,r4) + tophys(r5,r5) mtlr r5 mr r24,r3 /* cpu # */ blr + + .globl __secondary_start_psurge +__secondary_start_psurge: + li r24,1 /* cpu # */ + /* we come in here with IR=0 and DR=1, and DBAT 0 + set to map the 0xf0000000 - 0xffffffff region */ + mfmsr r0 + rlwinm r0,r0,0,28,26 /* clear DR (0x10) */ + sync + mtmsr r0 + isync + + .globl __secondary_start +__secondary_start: + bl enable_caches + + /* get current */ + lis r2,current_set@h + ori r2,r2,current_set@l + tophys(r2,r2) + slwi r24,r24,2 /* get current_set[cpu#] */ + lwzx r2,r2,r24 + + /* stack */ + addi r1,r2,TASK_UNION_SIZE-STACK_FRAME_OVERHEAD + li r0,0 + tophys(r3,r1) + stw r0,0(r3) + + /* load up the MMU */ + bl load_up_mmu + + /* ptr to phys current thread */ + tophys(r4,r2) + addi r4,r4,THREAD /* phys address of our thread_struct */ + mtspr SPRG3,r4 + li r3,0 + mtspr SPRG2,r3 /* 0 => r1 has kernel sp */ + + /* enable MMU and jump to start_secondary */ + li r4,MSR_KERNEL + lis r3,start_secondary@h + ori r3,r3,start_secondary@l + mtspr SRR0,r3 + mtspr SRR1,r4 + rfi + #endif /* CONFIG_SMP */ - + /* - * This is where the main kernel code starts. + * Enable caches and 604-specific features if necessary. */ -start_here: -#ifndef CONFIG_8xx - /* - * Enable caches and 604-specific features if necessary. - */ +enable_caches: mfspr r9,PVR rlwinm r9,r9,16,16,31 cmpi 0,r9,1 @@ -1793,26 +1090,57 @@ start_here: bne 2,5f ori r11,r11,HID0_BTCD 5: mtspr HID0,r11 /* superscalar exec & br history tbl */ -4: -#endif /* CONFIG_8xx */ -#ifdef __SMP__ - /* if we're the second cpu stack and r2 are different - * and we want to not clear the bss -- Cort */ - lis r5,first_cpu_booted@h - ori r5,r5,first_cpu_booted@l - lwz r5,0(r5) - cmpi 0,r5,0 - beq 99f +4: blr + +/* + * Load stuff into the MMU. Intended to be called with + * IR=0 and DR=0. + */ +load_up_mmu: + /* Load the SDR1 register (hash table base & size) */ + lis r6,_SDR1@ha + tophys(r6,r6) +#ifdef CONFIG_PPC64 + ld r6,_SDR1@l(r6) + mtspr SDR1,r6 + /* clear the v bit in the ASR so we can + * behave as if we have segment registers + * -- Cort + */ + clrldi r6,r6,63 + mtasr r6 +#else + lwz r6,_SDR1@l(r6) + mtspr SDR1,r6 +#endif /* CONFIG_PPC64 */ + li r0,16 /* load up segment register values */ + mtctr r0 /* for context 0 */ + lis r3,0x2000 /* Ku = 1, VSID = 0 */ + li r4,0 +3: mtsrin r3,r4 + addi r3,r3,1 /* increment VSID */ + addis r4,r4,0x1000 /* address of next segment */ + bdnz 3b +/* Load the BAT registers with the values set up by MMU_init. + MMU_init takes care of whether we're on a 601 or not. */ + mfpvr r3 + srwi r3,r3,16 + cmpwi r3,1 + lis r3,BATS@ha + addi r3,r3,BATS@l + tophys(r3,r3) + LOAD_BAT(0,r3,r4,r5) + LOAD_BAT(1,r3,r4,r5) + LOAD_BAT(2,r3,r4,r5) + LOAD_BAT(3,r3,r4,r5) + blr + +/* + * This is where the main kernel code starts. + */ +start_here: + bl enable_caches - /* get current */ - lis r2,current_set@h - ori r2,r2,current_set@l - slwi r24,r24,2 /* cpu # to current_set[cpu#] */ - add r2,r2,r24 - lwz r2,0(r2) - b 10f -99: -#endif /* __SMP__ */ /* ptr to current */ lis r2,init_task_union@h ori r2,r2,init_task_union@l @@ -1831,9 +1159,6 @@ start_here: 3: stwu r0,4(r8) bdnz 3b 2: -#ifdef __SMP__ -10: -#endif /* __SMP__ */ /* stack */ addi r1,r2,TASK_UNION_SIZE li r0,0 @@ -1848,33 +1173,15 @@ start_here: mr r7,r27 bl identify_machine bl MMU_init + /* * Go back to running unmapped so we can load up new values * for SDR1 (hash table pointer) and the segment registers * and change to using our exception vectors. - * On the 8xx, all we have to do is invalidate the TLB to clear - * the old 8M byte TLB mappings and load the page table base register. */ -#ifndef CONFIG_8xx - lis r6,_SDR1@ha -#ifdef CONFIG_PPC64 - ld r6,_SDR1@l(r6) -#else - lwz r6,_SDR1@l(r6) -#endif -#else - /* The right way to do this would be to track it down through - * init's TSS like the context switch code does, but this is - * easier......until someone changes init's static structures. - */ - lis r6, swapper_pg_dir@h - tophys(r6,r6,0) - ori r6, r6, swapper_pg_dir@l - mtspr M_TWB, r6 -#endif lis r4,2f@h ori r4,r4,2f@l - tophys(r4,r4,r3) + tophys(r4,r4) li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR) mtspr SRR0,r4 mtspr SRR1,r3 @@ -1888,48 +1195,12 @@ start_here: tlbsync /* ... on all CPUs */ sync #endif -#ifndef CONFIG_8xx - mtspr SDR1,r6 -#ifdef CONFIG_PPC64 - /* clear the v bit in the ASR so we can - * behave as if we have segment registers - * -- Cort - */ - clrldi r6,r6,63 - mtasr r6 -#endif /* CONFIG_PPC64 */ - li r0,16 /* load up segment register values */ - mtctr r0 /* for context 0 */ - lis r3,0x2000 /* Ku = 1, VSID = 0 */ - li r4,0 -3: mtsrin r3,r4 - addi r3,r3,1 /* increment VSID */ - addis r4,r4,0x1000 /* address of next segment */ - bdnz 3b -/* Load the BAT registers with the values set up by MMU_init. - MMU_init takes care of whether we're on a 601 or not. */ - mfpvr r3 - srwi r3,r3,16 - cmpwi r3,1 - lis r3,BATS@ha - addi r3,r3,BATS@l - tophys(r3,r3,r4) -#ifdef CONFIG_PPC64 - LOAD_BAT(0,0,r3,r4,r5) - LOAD_BAT(1,32,r3,r4,r5) - LOAD_BAT(2,64,r3,r4,r5) - LOAD_BAT(3,96,r3,r4,r5) -#else /* CONFIG_PPC64 */ - LOAD_BAT(0,0,r3,r4,r5) - LOAD_BAT(1,16,r3,r4,r5) - LOAD_BAT(2,32,r3,r4,r5) - LOAD_BAT(3,48,r3,r4,r5) -#endif /* CONFIG_PPC64 */ -#endif /* CONFIG_8xx */ + bl load_up_mmu + /* Set up for using our exception vectors */ - /* ptr to phys current tss */ - tophys(r4,r2,r4) - addi r4,r4,TSS /* init task's TSS */ + /* ptr to phys current thread */ + tophys(r4,r2) + addi r4,r4,THREAD /* init task's THREAD */ mtspr SPRG3,r4 li r3,0 mtspr SPRG2,r3 /* 0 => r1 has kernel sp */ @@ -1937,383 +1208,11 @@ start_here: li r4,MSR_KERNEL lis r3,start_kernel@h ori r3,r3,start_kernel@l -#ifdef __SMP__ - /* the second time through here we go to - * start_secondary(). -- Cort - */ - lis r5,first_cpu_booted@h - ori r5,r5,first_cpu_booted@l - tophys(r5,r5,r3) - lwz r5,0(r5) - cmpi 0,r5,0 - beq 10f - lis r3,start_secondary@h - ori r3,r3,start_secondary@l -10: -#endif /* __SMP__ */ mtspr SRR0,r3 mtspr SRR1,r4 rfi /* enable MMU and jump to start_kernel */ /* - * Handle a system call. - */ -DoSyscall: - stw r0,TSS+LAST_SYSCALL(r2) - lwz r11,_CCR(r1) /* Clear SO bit in CR */ - lis r10,0x1000 - andc r11,r11,r10 - stw r11,_CCR(r1) -#ifdef SHOW_SYSCALLS -#ifdef SHOW_SYSCALLS_TASK - lis r31,show_syscalls_task@ha - lwz r31,show_syscalls_task@l(r31) - cmp 0,r2,r31 - bne 1f -#endif - lis r3,7f@ha - addi r3,r3,7f@l - lwz r4,GPR0(r1) - lwz r5,GPR3(r1) - lwz r6,GPR4(r1) - lwz r7,GPR5(r1) - lwz r8,GPR6(r1) - mr r9,r2 - bl printk - lwz r0,GPR0(r1) - lwz r3,GPR3(r1) - lwz r4,GPR4(r1) - lwz r5,GPR5(r1) - lwz r6,GPR6(r1) - lwz r7,GPR7(r1) - lwz r8,GPR8(r1) -1: -#endif /* SHOW_SYSCALLS */ - cmpi 0,r0,0x7777 /* Special case for 'sys_sigreturn' */ - beq- 10f - lwz r10,TASK_FLAGS(r2) - andi. r10,r10,PF_TRACESYS - bne- 50f - cmpli 0,r0,NR_syscalls - bge- 66f - lis r10,sys_call_table@h - ori r10,r10,sys_call_table@l - slwi r0,r0,2 - lwzx r10,r10,r0 /* Fetch system call handler [ptr] */ - cmpi 0,r10,0 - beq- 66f - mtlr r10 - addi r9,r1,STACK_FRAME_OVERHEAD - blrl /* Call handler */ - .globl syscall_ret_1 -syscall_ret_1: -20: stw r3,RESULT(r1) /* Save result */ -#ifdef SHOW_SYSCALLS -#ifdef SHOW_SYSCALLS_TASK - cmp 0,r2,r31 - bne 91f -#endif - mr r4,r3 - lis r3,79f@ha - addi r3,r3,79f@l - bl printk - lwz r3,RESULT(r1) -91: -#endif - li r10,-_LAST_ERRNO - cmpl 0,r3,r10 - blt 30f - neg r3,r3 - cmpi 0,r3,ERESTARTNOHAND - bne 22f - li r3,EINTR -22: lwz r10,_CCR(r1) /* Set SO bit in CR */ - oris r10,r10,0x1000 - stw r10,_CCR(r1) -30: stw r3,GPR3(r1) /* Update return value */ - b int_return -66: li r3,ENOSYS - b 22b -/* sys_sigreturn */ -10: addi r3,r1,STACK_FRAME_OVERHEAD - bl sys_sigreturn - cmpi 0,r3,0 /* Check for restarted system call */ - bge int_return - b 20b -/* Traced system call support */ -50: bl syscall_trace - lwz r0,GPR0(r1) /* Restore original registers */ - lwz r3,GPR3(r1) - lwz r4,GPR4(r1) - lwz r5,GPR5(r1) - lwz r6,GPR6(r1) - lwz r7,GPR7(r1) - lwz r8,GPR8(r1) - lwz r9,GPR9(r1) - cmpli 0,r0,NR_syscalls - bge- 66f - lis r10,sys_call_table@h - ori r10,r10,sys_call_table@l - slwi r0,r0,2 - lwzx r10,r10,r0 /* Fetch system call handler [ptr] */ - cmpi 0,r10,0 - beq- 66f - mtlr r10 - addi r9,r1,STACK_FRAME_OVERHEAD - blrl /* Call handler */ - .globl syscall_ret_2 -syscall_ret_2: - stw r3,RESULT(r1) /* Save result */ - stw r3,GPR0(r1) /* temporary gross hack to make strace work */ - li r10,-_LAST_ERRNO - cmpl 0,r3,r10 - blt 60f - neg r3,r3 - cmpi 0,r3,ERESTARTNOHAND - bne 52f - li r3,EINTR -52: lwz r10,_CCR(r1) /* Set SO bit in CR */ - oris r10,r10,0x1000 - stw r10,_CCR(r1) -60: stw r3,GPR3(r1) /* Update return value */ - bl syscall_trace - b int_return -66: li r3,ENOSYS - b 52b -#ifdef SHOW_SYSCALLS -7: .string "syscall %d(%x, %x, %x, %x), current=%p\n" -79: .string " -> %x\n" - .align 2 -#endif - -/* - * This routine switches between two different tasks. The process - * state of one is saved on its kernel stack. Then the state - * of the other is restored from its kernel stack. The memory - * management hardware is updated to the second process's state. - * Finally, we can return to the second process, via int_return. - * On entry, r3 points to the TSS for the current task, r4 - * points to the TSS for the new task, and r5 contains the - * MMU context number for the new task. - * - * Note: there are two ways to get to the "going out" portion - * of this code; either by coming in via the entry (_switch) - * or via "fork" which must set up an environment equivalent - * to the "_switch" path. If you change this (or in particular, the - * SAVE_REGS macro), you'll have to change the fork code also. - * - * The code which creates the new task context is in 'copy_thread' - * in arch/ppc/kernel/process.c - * - * The MPC8xx has something that currently happens "automagically." - * Unshared user space address translations are subject to ASID (context) - * match. During each task switch, the ASID is incremented. We can - * guarantee (I hope :-) that no entries currently match this ASID - * because every task will cause at least a TLB entry to be loaded for - * the first instruction and data access, plus the kernel running will - * have displaced several more TLBs. The MMU contains 32 entries for - * each TLB, and there are 16 contexts, so we just need to make sure - * two pages get replaced for every context switch, which currently - * happens. There are other TLB management techniques that I will - * eventually implement, but this is the easiest for now. -- Dan - */ -_GLOBAL(_switch) - stwu r1,-INT_FRAME_SIZE-STACK_UNDERHEAD(r1) - stw r0,GPR0(r1) - lwz r0,0(r1) - stw r0,GPR1(r1) - /* r3-r13 are caller saved -- Cort */ - SAVE_GPR(2, r1) - SAVE_8GPRS(14, r1) - SAVE_10GPRS(22, r1) - mflr r20 /* Return to switch caller */ - mfmsr r22 - li r0,MSR_FP /* Disable floating-point */ - andc r22,r22,r0 - stw r20,_NIP(r1) - stw r22,_MSR(r1) - stw r20,_LINK(r1) - mfcr r20 - mfctr r22 - mfspr r23,XER - stw r20,_CCR(r1) - stw r22,_CTR(r1) - stw r23,_XER(r1) - li r0,0x0ff0 - stw r0,TRAP(r1) - stw r1,KSP(r3) /* Set old stack pointer */ - sync - tophys(r0,r4,r3) - mtspr SPRG3,r0 /* Update current TSS phys addr */ - SYNC - lwz r1,KSP(r4) /* Load new stack pointer */ - /* save the old current 'last' for return value */ - mr r3,r2 - addi r2,r4,-TSS /* Update current */ -#ifndef CONFIG_8xx - /* Set up segment registers for new task */ - rlwinm r5,r5,4,8,27 /* VSID = context << 4 */ - addis r5,r5,0x6000 /* Set Ks, Ku bits */ - li r0,12 /* TASK_SIZE / SEGMENT_SIZE */ - mtctr r0 - li r9,0 -3: mtsrin r5,r9 - addi r5,r5,1 /* next VSID */ - addis r9,r9,0x1000 /* address of next segment */ - bdnz 3b -#else -/* On the MPC8xx, we place the physical address of the new task - * page directory loaded into the MMU base register, and set the - * ASID compare register with the new "context". - */ - lwz r9,MM-TSS(r4) /* Get virtual address of mm */ - lwz r9,PGD(r9) /* get new->mm->pgd */ - addis r9,r9,-KERNELBASE@h /* convert to phys addr */ - mtspr M_TWB, r9 /* Update MMU base address */ - mtspr M_CASID, r5 /* Update context */ - tlbia -#endif - SYNC -2: lwz r9,_MSR(r1) /* Returning to user mode? */ - andi. r9,r9,MSR_PR - beq+ 10f /* if not, don't adjust kernel stack */ -8: addi r4,r1,INT_FRAME_SIZE+STACK_UNDERHEAD /* size of frame */ - stw r4,TSS+KSP(r2) /* save kernel stack pointer */ - tophys(r9,r1,r9) - mtspr SPRG2,r9 /* phys exception stack pointer */ -10: lwz r2,_CTR(r1) - lwz r0,_LINK(r1) - mtctr r2 - mtlr r0 - lwz r2,_XER(r1) - lwz r0,_CCR(r1) - mtspr XER,r2 - mtcrf 0xFF,r0 - /* r3-r13 are destroyed -- Cort */ - REST_GPR(14, r1) - REST_8GPRS(15, r1) - REST_8GPRS(23, r1) - REST_GPR(31, r1) - lwz r2,_NIP(r1) /* Restore environment */ - lwz r0,_MSR(r1) - mtspr SRR0,r2 - mtspr SRR1,r0 - lwz r0,GPR0(r1) - lwz r2,GPR2(r1) - lwz r1,GPR1(r1) - SYNC - rfi - -/* - * Trap exit. - */ -#ifdef __SMP__ - .globl ret_from_smpfork -ret_from_smpfork: - bl schedule_tail -#endif - .globl ret_from_syscall -ret_from_syscall: - .globl int_return -int_return: -0: mfmsr r30 /* Disable interrupts */ - li r4,0 - ori r4,r4,MSR_EE - andc r30,r30,r4 - SYNC /* Some chip revs need this... */ - mtmsr r30 - SYNC - lwz r5,_MSR(r1) - and. r5,r5,r4 - beq 2f -3: lis r4,ppc_n_lost_interrupts@ha - lwz r4,ppc_n_lost_interrupts@l(r4) - cmpi 0,r4,0 - beq+ 1f - addi r3,r1,STACK_FRAME_OVERHEAD - bl do_IRQ - .globl lost_irq_ret -lost_irq_ret: - b 3b -1: lis r4,bh_mask@ha - lwz r4,bh_mask@l(r4) - lis r5,bh_active@ha - lwz r5,bh_active@l(r5) - and. r4,r4,r5 - beq+ 2f - bl do_bottom_half - .globl do_bottom_half_ret -do_bottom_half_ret: - SYNC - mtmsr r30 /* disable interrupts again */ - SYNC -2: lwz r3,_MSR(r1) /* Returning to user mode? */ - andi. r3,r3,MSR_PR - beq+ 10f /* if so, check need_resched and signals */ - lwz r3,NEED_RESCHED(r2) - cmpi 0,r3,0 /* check need_resched flag */ - beq+ 7f - bl schedule - b 0b -7: lwz r5,SIGPENDING(r2) /* Check for pending unblocked signals */ - cmpwi 0,r5,0 - beq+ 8f - li r3,0 - addi r4,r1,STACK_FRAME_OVERHEAD - bl do_signal - .globl do_signal_ret -do_signal_ret: - b 0b -8: addi r4,r1,INT_FRAME_SIZE+STACK_UNDERHEAD /* size of frame */ - stw r4,TSS+KSP(r2) /* save kernel stack pointer */ - tophys(r3,r1,r3) - mtspr SPRG2,r3 /* phys exception stack pointer */ -10: lwz r2,_CTR(r1) - lwz r0,_LINK(r1) - mtctr r2 - mtlr r0 - lwz r2,_XER(r1) - lwz r0,_CCR(r1) - mtspr XER,r2 - mtcrf 0xFF,r0 - REST_10GPRS(3, r1) - REST_10GPRS(13, r1) - REST_8GPRS(23, r1) - REST_GPR(31, r1) - lwz r2,_NIP(r1) /* Restore environment */ - lwz r0,_MSR(r1) - mtspr SRR0,r2 - mtspr SRR1,r0 - lwz r0,GPR0(r1) - lwz r2,GPR2(r1) - lwz r1,GPR1(r1) - SYNC - rfi - -/* - * Fake an interrupt from kernel mode. - * This is used when enable_irq loses an interrupt. - * We only fill in the stack frame minimally. - */ -_GLOBAL(fake_interrupt) - mflr r0 - stw r0,4(r1) - stwu r1,-INT_FRAME_SIZE-STACK_UNDERHEAD(r1) - stw r0,_NIP(r1) - stw r0,_LINK(r1) - mfmsr r3 - stw r3,_MSR(r1) - li r0,0x0fac - stw r0,TRAP(r1) - addi r3,r1,STACK_FRAME_OVERHEAD - li r4,1 - bl do_IRQ - addi r1,r1,INT_FRAME_SIZE+STACK_UNDERHEAD - lwz r0,4(r1) - mtlr r0 - blr - -/* * Set up the segment registers for a new context. */ _GLOBAL(set_context) @@ -2330,349 +1229,6 @@ _GLOBAL(set_context) blr /* - * Flush instruction cache. - * This is a no-op on the 601. - */ -_GLOBAL(flush_instruction_cache) - mfspr r3,PVR - rlwinm r3,r3,16,16,31 - cmpi 0,r3,1 - beqlr /* for 601, do nothing */ - /* 603/604 processor - use invalidate-all bit in HID0 */ - mfspr r3,HID0 - ori r3,r3,HID0_ICFI - mtspr HID0,r3 - SYNC - blr - -/* - * Write any modified data cache blocks out to memory - * and invalidate the corresponding instruction cache blocks. - * This is a no-op on the 601. - * - * flush_icache_range(unsigned long start, unsigned long stop) - */ -_GLOBAL(flush_icache_range) - mfspr r5,PVR - rlwinm r5,r5,16,16,31 - cmpi 0,r5,1 - beqlr /* for 601, do nothing */ - li r5,CACHE_LINE_SIZE-1 - andc r3,r3,r5 - subf r4,r3,r4 - add r4,r4,r5 - srwi. r4,r4,LG_CACHE_LINE_SIZE - beqlr - mtctr r4 - mr r6,r3 -1: dcbst 0,r3 - addi r3,r3,CACHE_LINE_SIZE - bdnz 1b - sync /* wait for dcbst's to get to ram */ - mtctr r4 -2: icbi 0,r6 - addi r6,r6,CACHE_LINE_SIZE - bdnz 2b - sync - isync - blr - -/* - * Like above, but only do the D-cache. This is used by the 8xx - * to push the cache so the CPM doesn't get stale data. - * - * flush_dcache_range(unsigned long start, unsigned long stop) - */ -_GLOBAL(flush_dcache_range) - li r5,CACHE_LINE_SIZE-1 - andc r3,r3,r5 - subf r4,r3,r4 - add r4,r4,r5 - srwi. r4,r4,LG_CACHE_LINE_SIZE - beqlr - mtctr r4 - -1: dcbst 0,r3 - addi r3,r3,CACHE_LINE_SIZE - bdnz 1b - sync /* wait for dcbst's to get to ram */ - blr - -/* - * Flush a particular page from the DATA cache - * Note: this is necessary because the instruction cache does *not* - * snoop from the data cache. - * This is a no-op on the 601 which has a unified cache. - * - * void flush_page_to_ram(void *page) - */ -_GLOBAL(flush_page_to_ram) - mfspr r5,PVR - rlwinm r5,r5,16,16,31 - cmpi 0,r5,1 - beqlr /* for 601, do nothing */ - li r4,0x0FFF - andc r3,r3,r4 /* Get page base address */ - li r4,4096/CACHE_LINE_SIZE /* Number of lines in a page */ - mtctr r4 - mr r6,r3 -0: dcbst 0,r3 /* Write line to ram */ - addi r3,r3,CACHE_LINE_SIZE - bdnz 0b - sync - mtctr r4 -1: icbi 0,r6 - addi r6,r6,CACHE_LINE_SIZE - bdnz 1b - sync - isync - blr - -/* - * Clear a page using the dcbz instruction, which doesn't cause any - * memory traffic (except to write out any cache lines which get - * displaced). This only works on cacheable memory. - */ -_GLOBAL(clear_page) - li r0,4096/CACHE_LINE_SIZE - mtctr r0 -1: dcbz 0,r3 - addi r3,r3,CACHE_LINE_SIZE - bdnz 1b - blr - -/* - * Flush entries from the hash table with VSIDs in the range - * given. - */ -#ifndef CONFIG_8xx -_GLOBAL(flush_hash_segments) - lis r5,Hash@ha - lwz r5,Hash@l(r5) /* base of hash table */ -#ifdef NO_RELOAD_HTAB - cmpwi 0,r5,0 - bne+ 99f - tlbia - sync -#ifdef __SMP__ - tlbsync - sync -#endif - blr -99: -#endif /* NO_RELOAD_HTAB */ -#ifdef __SMP__ - /* Note - we had better not do anything which could generate - a hash table miss while we have the hash table locked, - or we'll get a deadlock. -paulus */ - mfmsr r10 - sync - rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ - mtmsr r0 - SYNC - lis r9,hash_table_lock@h - ori r9,r9,hash_table_lock@l - lwz r8,PROCESSOR(r2) - oris r8,r8,8 -10: lwarx r6,0,r9 - cmpi 0,r6,0 - bne- 10b - stwcx. r8,0,r9 - bne- 10b - eieio -#endif - rlwinm r3,r3,7,1,24 /* put VSID lower limit in position */ - oris r3,r3,0x8000 /* set V bit */ - rlwinm r4,r4,7,1,24 /* put VSID upper limit in position */ - oris r4,r4,0x8000 - ori r4,r4,0x7f - lis r6,Hash_size@ha - lwz r6,Hash_size@l(r6) /* size in bytes */ - srwi r6,r6,3 /* # PTEs */ - mtctr r6 - addi r5,r5,-8 - li r0,0 -1: lwzu r6,8(r5) /* get next tag word */ - cmplw 0,r6,r3 - cmplw 1,r6,r4 - cror 0,0,5 /* set cr0.lt if out of range */ - blt 2f /* branch if out of range */ - stw r0,0(r5) /* invalidate entry */ -2: bdnz 1b /* continue with loop */ - sync - tlbia - sync -#ifdef __SMP__ - tlbsync - sync - lis r3,hash_table_lock@ha - stw r0,hash_table_lock@l(r3) - mtmsr r10 - SYNC -#endif - blr - -/* - * Flush the entry for a particular page from the hash table. - * - * flush_hash_page(unsigned context, unsigned long va) - */ -_GLOBAL(flush_hash_page) - lis r6,Hash@ha - lwz r6,Hash@l(r6) /* hash table base */ -#ifdef NO_RELOAD_HTAB - cmpwi 0,r6,0 /* hash table in use? */ - bne+ 99f - tlbie r4 /* in hw tlb too */ - sync -#ifdef __SMP__ - tlbsync - sync -#endif - blr -99: -#endif /* NO_RELOAD_HTAB */ -#ifdef __SMP__ - /* Note - we had better not do anything which could generate - a hash table miss while we have the hash table locked, - or we'll get a deadlock. -paulus */ - mfmsr r10 - sync - rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ - mtmsr r0 - SYNC - lis r9,hash_table_lock@h - ori r9,r9,hash_table_lock@l - lwz r8,PROCESSOR(r2) - oris r8,r8,9 -10: lwarx r7,0,r9 - cmpi 0,r7,0 - bne- 10b - stwcx. r8,0,r9 - bne- 10b - eieio -#endif - rlwinm r3,r3,11,1,20 /* put context into vsid */ - rlwimi r3,r4,11,21,24 /* put top 4 bits of va into vsid */ - oris r3,r3,0x8000 /* set V (valid) bit */ - rlwimi r3,r4,10,26,31 /* put in API (abbrev page index) */ - rlwinm r7,r4,32-6,10,25 /* get page index << 6 */ - rlwinm r5,r3,32-1,7,25 /* vsid << 6 */ - xor r7,r7,r5 /* primary hash << 6 */ - lis r5,Hash_mask@ha - lwz r5,Hash_mask@l(r5) /* hash mask */ - slwi r5,r5,6 /* << 6 */ - and r7,r7,r5 - add r6,r6,r7 /* address of primary PTEG */ - li r8,8 - mtctr r8 - addi r7,r6,-8 -1: lwzu r0,8(r7) /* get next PTE */ - cmpw 0,r0,r3 /* see if tag matches */ - bdnzf 2,1b /* while --ctr != 0 && !cr0.eq */ - beq 3f /* if we found it */ - ori r3,r3,0x40 /* set H (alt. hash) bit */ - xor r6,r6,r5 /* address of secondary PTEG */ - mtctr r8 - addi r7,r6,-8 -2: lwzu r0,8(r7) /* get next PTE */ - cmpw 0,r0,r3 /* see if tag matches */ - bdnzf 2,2b /* while --ctr != 0 && !cr0.eq */ - bne 4f /* if we didn't find it */ -3: li r0,0 - stw r0,0(r7) /* invalidate entry */ -4: sync - tlbie r4 /* in hw tlb too */ - sync -#ifdef __SMP__ - tlbsync - sync - lis r3,hash_table_lock@h - li r0,0 - stw r0,hash_table_lock@l(r3) - mtmsr r10 - SYNC -#endif - blr -#endif /* CONFIG_8xx */ - -/* - * This routine is just here to keep GCC happy - sigh... - */ -_GLOBAL(__main) - blr - -/* - * PROM code for specific machines follows. Put it - * here so it's easy to add arch-specific sections later. - * -- Cort - */ - -#ifndef CONFIG_8xx -/* - * On CHRP, the Run-Time Abstraction Services (RTAS) have to be - * called with the MMU off. - */ - .globl enter_rtas -enter_rtas: - mflr r0 - stw r0,20(r1) - lis r4,rtas_data@ha - lwz r4,rtas_data@l(r4) - addis r4,r4,-KERNELBASE@h - lis r6,1f@ha /* physical return address for rtas */ - addi r6,r6,1f@l - addis r6,r6,-KERNELBASE@h - subi r7,r1,INT_FRAME_SIZE+STACK_UNDERHEAD - addis r7,r7,-KERNELBASE@h - lis r8,rtas_entry@ha - lwz r8,rtas_entry@l(r8) - addis r5,r8,-KERNELBASE@h - mfmsr r9 - stw r9,8(r1) - ori r0,r0,MSR_EE|MSR_SE|MSR_BE - andc r0,r9,r0 - andi. r9,r9,MSR_ME|MSR_RI - sync /* disable interrupts so SRR0/1 */ - mtmsr r0 /* don't get trashed */ - mtlr r6 - mtspr SPRG2,r7 - mtspr SRR0,r8 - mtspr SRR1,r9 - rfi -1: addis r9,r1,-KERNELBASE@h - lwz r8,20(r9) /* get return address */ - lwz r9,8(r9) /* original msr value */ - li r0,0 - mtspr SPRG2,r0 - mtspr SRR0,r8 - mtspr SRR1,r9 - rfi /* return to caller */ -#endif /* CONFIG_8xx */ - -#ifdef CONFIG_8xx -/* Jump into the system reset for the rom. - * We first disable the MMU, and then jump to the ROM reset address. - * - * r3 is the board info structure, r4 is the location for starting. - * I use this for building a small kernel that can load other kernels, - * rather than trying to write or rely on a rom monitor that can tftp load. - */ - .globl m8xx_gorom -m8xx_gorom: - li r5,MSR_KERNEL & ~(MSR_IR|MSR_DR) - lis r6,2f@h - addis r6,r6,-KERNELBASE@h - ori r6,r6,2f@l - mtspr SRR0,r6 - mtspr SRR1,r5 - rfi -2: - mtlr r4 - blr -#endif /* CONFIG_8xx */ - -/* * We put a few things here that have to be page-aligned. * This stuff goes at the beginning of the data segment, * which is page-aligned. diff --git a/arch/ppc/kernel/head_8xx.S b/arch/ppc/kernel/head_8xx.S new file mode 100644 index 000000000..fcda01719 --- /dev/null +++ b/arch/ppc/kernel/head_8xx.S @@ -0,0 +1,903 @@ +/* + * arch/ppc/kernel/except_8xx.S + * + * $Id: head_8xx.S,v 1.2 1999/08/23 02:53:19 paulus Exp $ + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP + * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu> + * Low-level exception handlers and MMU support + * rewritten by Paul Mackerras. + * Copyright (C) 1996 Paul Mackerras. + * MPC8xx modifications by Dan Malek + * Copyright (C) 1997 Dan Malek (dmalek@jlc.net). + * + * This file contains low-level support and setup for PowerPC 8xx + * embedded processors, including trap and interrupt dispatch. + * + * This program 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. + * + */ + +#include "ppc_asm.h" +#include <asm/processor.h> +#include <asm/page.h> +#include <linux/config.h> +#include <asm/mmu.h> + + .text + .globl _stext +_stext: + +/* + * _start is defined this way because the XCOFF loader in the OpenFirmware + * on the powermac expects the entry point to be a procedure descriptor. + */ + .text + .globl _start +_start: + +/* MPC8xx + * This port was done on an MBX board with an 860. Right now I only + * support an ELF compressed (zImage) boot from EPPC-Bug because the + * code there loads up some registers before calling us: + * r3: ptr to board info data + * r4: initrd_start or if no initrd then 0 + * r5: initrd_end - unused if r4 is 0 + * r6: Start of command line string + * r7: End of command line string + * + * I decided to use conditional compilation instead of checking PVR and + * adding more processor specific branches around code I don't need. + * Since this is an embedded processor, I also appreciate any memory + * savings I can get. + * + * The MPC8xx does not have any BATs, but it supports large page sizes. + * We first initialize the MMU to support 8M byte pages, then load one + * entry into each of the instruction and data TLBs to map the first + * 8M 1:1. I also mapped an additional I/O space 1:1 so we can get to + * the "internal" processor registers before MMU_init is called. + * + * The TLB code currently contains a major hack. Since I use the condition + * code register, I have to save and restore it. I am out of registers, so + * I just store it in memory location 0 (the TLB handlers are not reentrant). + * To avoid making any decisions, I need to use the "segment" valid bit + * in the first level table, but that would require many changes to the + * Linux page directory/table functions that I don't want to do right now. + * + * I used to use SPRG2 for a temporary register in the TLB handler, but it + * has since been put to other uses. I now use a hack to save a register + * and the CCR at memory location 0.....Someday I'll fix this..... + * -- Dan + */ + + .globl __start +__start: + mr r31,r3 /* save parameters */ + mr r30,r4 + mr r29,r5 + mr r28,r6 + mr r27,r7 + li r24,0 /* cpu # */ + + tlbia /* Invalidate all TLB entries */ + li r8, 0 + mtspr MI_CTR, r8 /* Set instruction control to zero */ + lis r8, MD_RESETVAL@h + mtspr MD_CTR, r8 /* Set data TLB control */ + + /* Now map the lower 8 Meg into the TLBs. For this quick hack, + * we can load the instruction and data TLB registers with the + * same values. + */ + lis r8, KERNELBASE@h /* Create vaddr for TLB */ + ori r8, r8, MI_EVALID /* Mark it valid */ + mtspr MI_EPN, r8 + mtspr MD_EPN, r8 + li r8, MI_PS8MEG /* Set 8M byte page */ + ori r8, r8, MI_SVALID /* Make it valid */ + mtspr MI_TWC, r8 + mtspr MD_TWC, r8 + li r8, MI_BOOTINIT /* Create RPN for address 0 */ + mtspr MI_RPN, r8 /* Store TLB entry */ + mtspr MD_RPN, r8 + lis r8, MI_Kp@h /* Set the protection mode */ + mtspr MI_AP, r8 + mtspr MD_AP, r8 + +/* We will get these from a configuration file as soon as I verify + * the extraneous bits don't cause problems in the TLB. + */ +#if defined(CONFIG_MBX) || defined(CONFIG_RPXLITE) +#define BOOT_IMMR 0xfa000000 +#endif +#ifdef CONFIG_BSEIP +#define BOOT_IMMR 0xff000000 +#endif + /* Map another 8 MByte at 0xfa000000 to get the processor + * internal registers (among other things). + */ + lis r8, BOOT_IMMR@h /* Create vaddr for TLB */ + ori r8, r8, MD_EVALID /* Mark it valid */ + mtspr MD_EPN, r8 + li r8, MD_PS8MEG /* Set 8M byte page */ + ori r8, r8, MD_SVALID /* Make it valid */ + mtspr MD_TWC, r8 + lis r8, BOOT_IMMR@h /* Create paddr for TLB */ + ori r8, r8, MI_BOOTINIT|0x2 /* Inhibit cache -- Cort */ + mtspr MD_RPN, r8 + + /* Since the cache is enabled according to the information we + * just loaded into the TLB, invalidate and enable the caches here. + * We should probably check/set other modes....later. + */ + lis r8, IDC_INVALL@h + mtspr IC_CST, r8 + mtspr DC_CST, r8 + lis r8, IDC_ENABLE@h + mtspr IC_CST, r8 +#if 0 + mtspr DC_CST, r8 +#else + /* For a debug option, I left this here to easily enable + * the write through cache mode + */ + lis r8, DC_SFWT@h + mtspr DC_CST, r8 + lis r8, IDC_ENABLE@h + mtspr DC_CST, r8 +#endif + +/* We now have the lower 8 Meg mapped into TLB entries, and the caches + * ready to work. + */ + +turn_on_mmu: + mfmsr r0 + ori r0,r0,MSR_DR|MSR_IR + mtspr SRR1,r0 + lis r0,start_here@h + ori r0,r0,start_here@l + mtspr SRR0,r0 + SYNC + rfi /* enables MMU */ + +/* + * Exception entry code. This code runs with address translation + * turned off, i.e. using physical addresses. + * We assume sprg3 has the physical address of the current + * task's thread_struct. + */ +#define EXCEPTION_PROLOG \ + mtspr SPRG0,r20; \ + mtspr SPRG1,r21; \ + mfcr r20; \ + mfspr r21,SPRG2; /* exception stack to use from */ \ + cmpwi 0,r21,0; /* user mode or RTAS */ \ + bne 1f; \ + tophys(r21,r1); /* use tophys(kernel sp) otherwise */ \ + subi r21,r21,INT_FRAME_SIZE; /* alloc exc. frame */\ +1: stw r20,_CCR(r21); /* save registers */ \ + stw r22,GPR22(r21); \ + stw r23,GPR23(r21); \ + mfspr r20,SPRG0; \ + stw r20,GPR20(r21); \ + mfspr r22,SPRG1; \ + stw r22,GPR21(r21); \ + mflr r20; \ + stw r20,_LINK(r21); \ + mfctr r22; \ + stw r22,_CTR(r21); \ + mfspr r20,XER; \ + stw r20,_XER(r21); \ + mfspr r22,SRR0; \ + mfspr r23,SRR1; \ + stw r0,GPR0(r21); \ + stw r1,GPR1(r21); \ + stw r2,GPR2(r21); \ + stw r1,0(r21); \ + tovirt(r1,r21); /* set new kernel sp */ \ + SAVE_4GPRS(3, r21); +/* + * Note: code which follows this uses cr0.eq (set if from kernel), + * r21, r22 (SRR0), and r23 (SRR1). + */ + +/* + * Exception vectors. + */ +#define STD_EXCEPTION(n, label, hdlr) \ + . = n; \ +label: \ + EXCEPTION_PROLOG; \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + li r20,MSR_KERNEL; \ + bl transfer_to_handler; \ + .long hdlr; \ + .long ret_from_except + +/* System reset */ +#ifdef CONFIG_SMP /* MVME/MTX start the secondary here */ + STD_EXCEPTION(0x100, Reset, __secondary_start_psurge) +#else + STD_EXCEPTION(0x100, Reset, UnknownException) +#endif + +/* Machine check */ + STD_EXCEPTION(0x200, MachineCheck, MachineCheckException) + +/* Data access exception. + * This is "never generated" by the MPC8xx. We jump to it for other + * translation errors. + */ + . = 0x300 +DataAccess: + EXCEPTION_PROLOG + mfspr r20,DSISR + stw r20,_DSISR(r21) + mr r5,r20 + mfspr r4,DAR + stw r4,_DAR(r21) + addi r3,r1,STACK_FRAME_OVERHEAD + li r20,MSR_KERNEL + rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ + bl transfer_to_handler + .long do_page_fault + .long ret_from_except + +/* Instruction access exception. + * This is "never generated" by the MPC8xx. We jump to it for other + * translation errors. + */ + . = 0x400 +InstructionAccess: + EXCEPTION_PROLOG + addi r3,r1,STACK_FRAME_OVERHEAD + mr r4,r22 + mr r5,r23 + li r20,MSR_KERNEL + rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ + bl transfer_to_handler + .long do_page_fault + .long ret_from_except + +/* External interrupt */ + . = 0x500; +HardwareInterrupt: + EXCEPTION_PROLOG; +#ifdef CONFIG_APUS + /* This is horrible, but there's no way around it. Enable the + data cache so the IRQ hardware register can be accessed + without cache intervention. Then disable interrupts and get + the current emulated m68k IPL value. */ + + mfmsr 20 + xori r20,r20,MSR_DR + sync + mtmsr r20 + sync + + lis r3,APUS_IPL_EMU@h + + li r20,(IPLEMU_SETRESET|IPLEMU_DISABLEINT) + stb r20,APUS_IPL_EMU@l(r3) + eieio + + lbz r3,APUS_IPL_EMU@l(r3) + + mfmsr r20 + xori r20,r20,MSR_DR + sync + mtmsr r20 + sync + + stw r3,(_CCR+4)(r21); +#endif + addi r3,r1,STACK_FRAME_OVERHEAD + li r20,MSR_KERNEL + li r4,0 + bl transfer_to_handler + .long do_IRQ; + .long ret_from_except + + +/* Alignment exception */ + . = 0x600 +Alignment: + EXCEPTION_PROLOG + mfspr r4,DAR + stw r4,_DAR(r21) + mfspr r5,DSISR + stw r5,_DSISR(r21) + addi r3,r1,STACK_FRAME_OVERHEAD + li r20,MSR_KERNEL + rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ + bl transfer_to_handler + .long AlignmentException + .long ret_from_except + +/* Program check exception */ + . = 0x700 +ProgramCheck: + EXCEPTION_PROLOG + addi r3,r1,STACK_FRAME_OVERHEAD + li r20,MSR_KERNEL + rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ + bl transfer_to_handler + .long ProgramCheckException + .long ret_from_except + +/* No FPU on MPC8xx. This exception is not supposed to happen. +*/ + STD_EXCEPTION(0x800, FPUnavailable, UnknownException) + + STD_EXCEPTION(0x900, Decrementer, timer_interrupt) + STD_EXCEPTION(0xa00, Trap_0a, UnknownException) + STD_EXCEPTION(0xb00, Trap_0b, UnknownException) + +/* System call */ + . = 0xc00 +SystemCall: + EXCEPTION_PROLOG + stw r3,ORIG_GPR3(r21) + li r20,MSR_KERNEL + rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ + bl transfer_to_handler + .long DoSyscall + .long ret_from_except + +/* Single step - not used on 601 */ + STD_EXCEPTION(0xd00, SingleStep, SingleStepException) + + STD_EXCEPTION(0xe00, Trap_0e, UnknownException) + STD_EXCEPTION(0xf00, Trap_0f, UnknownException) + +/* On the MPC8xx, this is a software emulation interrupt. It occurs + * for all unimplemented and illegal instructions. + */ + STD_EXCEPTION(0x1000, SoftEmu, SoftwareEmulation) + + . = 0x1100 +/* + * For the MPC8xx, this is a software tablewalk to load the instruction + * TLB. It is modelled after the example in the Motorola manual. The task + * switch loads the M_TWB register with the pointer to the first level table. + * If we discover there is no second level table (the value is zero), the + * plan was to load that into the TLB, which causes another fault into the + * TLB Error interrupt where we can handle such problems. However, that did + * not work, so if we discover there is no second level table, we restore + * registers and branch to the error exception. We have to use the MD_xxx + * registers for the tablewalk because the equivalent MI_xxx registers + * only perform the attribute functions. + */ +InstructionTLBMiss: + mtspr M_TW, r20 /* Save a couple of working registers */ + mfcr r20 + stw r20, 0(r0) + stw r21, 4(r0) + mfspr r20, SRR0 /* Get effective address of fault */ + mtspr MD_EPN, r20 /* Have to use MD_EPN for walk, MI_EPN can't */ + mfspr r20, M_TWB /* Get level 1 table entry address */ + lwz r21, 0(r20) /* Get the level 1 entry */ + rlwinm. r20, r21,0,0,20 /* Extract page descriptor page address */ + beq 2f /* If zero, don't try to find a pte */ + + /* We have a pte table, so load the MI_TWC with the attributes + * for this page, which has only bit 31 set. + */ + tophys(r21,r21) + ori r21,r21,1 /* Set valid bit */ + mtspr MI_TWC, r21 /* Set page attributes */ + mtspr MD_TWC, r21 /* Load pte table base address */ + mfspr r21, MD_TWC /* ....and get the pte address */ + lwz r21, 0(r21) /* Get the pte */ + + /* Set four subpage valid bits (24, 25, 26, and 27). + * Since we currently run MI_CTR.PPCS = 0, the manual says, + * "If the page size is larger than 4k byte, then all the + * 4 bits should have the same value." + * I don't really know what to do if the page size is 4k Bytes, + * but I know setting them all to 0 does not work, and setting them + * all to 1 does, so that is the way it is right now. + * BTW, these four bits map to the software only bits in the + * linux page table. I used to turn them all of, but now just + * set them all for the hardware. + li r20, 0x00f0 + andc r20, r21, r20 + ori r20, r20, 0x0080 + */ + ori r20, r21, 0x00f0 + + mtspr MI_RPN, r20 /* Update TLB entry */ + + mfspr r20, M_TW /* Restore registers */ + lwz r21, 0(r0) + mtcr r21 + lwz r21, 4(r0) + rfi + +2: mfspr r20, M_TW /* Restore registers */ + lwz r21, 0(r0) + mtcr r21 + lwz r21, 4(r0) + b InstructionAccess + + . = 0x1200 +DataStoreTLBMiss: + mtspr M_TW, r20 /* Save a couple of working registers */ + mfcr r20 + stw r20, 0(r0) + stw r21, 4(r0) + mfspr r20, M_TWB /* Get level 1 table entry address */ + lwz r21, 0(r20) /* Get the level 1 entry */ + rlwinm. r20, r21,0,0,20 /* Extract page descriptor page address */ + beq 2f /* If zero, don't try to find a pte */ + + /* We have a pte table, so load fetch the pte from the table. + */ + tophys(r21, r21) + ori r21, r21, 1 /* Set valid bit in physical L2 page */ + mtspr MD_TWC, r21 /* Load pte table base address */ + mfspr r21, MD_TWC /* ....and get the pte address */ + lwz r21, 0(r21) /* Get the pte */ + + /* Set four subpage valid bits (24, 25, 26, and 27). + * Since we currently run MD_CTR.PPCS = 0, the manual says, + * "If the page size is larger than 4k byte, then all the + * 4 bits should have the same value." + * I don't really know what to do if the page size is 4k Bytes, + * but I know setting them all to 0 does not work, and setting them + * all to 1 does, so that is the way it is right now. + * BTW, these four bits map to the software only bits in the + * linux page table. I used to turn them all of, but now just + * set them all for the hardware. + li r20, 0x00f0 + andc r20, r21, r20 + ori r20, r20, 0x0080 + */ + ori r20, r21, 0x00f0 + + mtspr MD_RPN, r20 /* Update TLB entry */ + + mfspr r20, M_TW /* Restore registers */ + lwz r21, 0(r0) + mtcr r21 + lwz r21, 4(r0) + rfi + +2: mfspr r20, M_TW /* Restore registers */ + lwz r21, 0(r0) + mtcr r21 + lwz r21, 4(r0) + b DataAccess + +/* This is an instruction TLB error on the MPC8xx. This could be due + * to many reasons, such as executing guarded memory or illegal instruction + * addresses. There is nothing to do but handle a big time error fault. + */ + . = 0x1300 +InstructionTLBError: + b InstructionAccess + +/* This is the data TLB error on the MPC8xx. This could be due to + * many reasons, including a dirty update to a pte. We can catch that + * one here, but anything else is an error. First, we track down the + * Linux pte. If it is valid, write access is allowed, but the + * page dirty bit is not set, we will set it and reload the TLB. For + * any other case, we bail out to a higher level function that can + * handle it. + */ + . = 0x1400 +DataTLBError: + mtspr M_TW, r20 /* Save a couple of working registers */ + mfcr r20 + stw r20, 0(r0) + stw r21, 4(r0) + + /* First, make sure this was a store operation. + */ + mfspr r20, DSISR + andis. r21, r20, 0x0200 /* If set, indicates store op */ + beq 2f + + mfspr r20, M_TWB /* Get level 1 table entry address */ + lwz r21, 0(r20) /* Get the level 1 entry */ + rlwinm. r20, r21,0,0,20 /* Extract page descriptor page address */ + beq 2f /* If zero, bail */ + + /* We have a pte table, so fetch the pte from the table. + */ + tophys(r21, r21) + ori r21, r21, 1 /* Set valid bit in physical L2 page */ + mtspr MD_TWC, r21 /* Load pte table base address */ + mfspr r21, MD_TWC /* ....and get the pte address */ + lwz r21, 0(r21) /* Get the pte */ + + andi. r20, r21, _PAGE_RW /* Is it writeable? */ + beq 2f /* Bail out if not */ + + ori r21, r21, _PAGE_DIRTY /* Update changed bit */ + mfspr r20, MD_TWC /* Get pte address again */ + stw r21, 0(r20) /* and update pte in table */ + + /* Set four subpage valid bits (24, 25, 26, and 27). + * Since we currently run MD_CTR.PPCS = 0, the manual says, + * "If the page size is larger than 4k byte, then all the + * 4 bits should have the same value." + * I don't really know what to do if the page size is 4k Bytes, + * but I know setting them all to 0 does not work, and setting them + * all to 1 does, so that is the way it is right now. + * BTW, these four bits map to the software only bits in the + * linux page table. I used to turn them all of, but now just + * set them all for the hardware. + li r20, 0x00f0 + andc r20, r21, r20 + ori r20, r20, 0x0080 + */ + ori r20, r21, 0x00f0 + + mtspr MD_RPN, r20 /* Update TLB entry */ + + mfspr r20, M_TW /* Restore registers */ + lwz r21, 0(r0) + mtcr r21 + lwz r21, 4(r0) + rfi +2: + mfspr r20, M_TW /* Restore registers */ + lwz r21, 0(r0) + mtcr r21 + lwz r21, 4(r0) + b DataAccess +#endif /* CONFIG_8xx */ + + STD_EXCEPTION(0x1500, Trap_15, UnknownException) + STD_EXCEPTION(0x1600, Trap_16, UnknownException) + STD_EXCEPTION(0x1700, Trap_17, TAUException) + STD_EXCEPTION(0x1800, Trap_18, UnknownException) + STD_EXCEPTION(0x1900, Trap_19, UnknownException) + STD_EXCEPTION(0x1a00, Trap_1a, UnknownException) + STD_EXCEPTION(0x1b00, Trap_1b, UnknownException) +/* On the MPC8xx, these next four traps are used for development + * support of breakpoints and such. Someday I will get around to + * using them. + */ + STD_EXCEPTION(0x1c00, Trap_1c, UnknownException) + STD_EXCEPTION(0x1d00, Trap_1d, UnknownException) + STD_EXCEPTION(0x1e00, Trap_1e, UnknownException) + STD_EXCEPTION(0x1f00, Trap_1f, UnknownException) + + . = 0x2000 + +/* + * This code finishes saving the registers to the exception frame + * and jumps to the appropriate handler for the exception, turning + * on address translation. + */ + .globl transfer_to_handler +transfer_to_handler: + stw r22,_NIP(r21) + lis r22,MSR_POW@h + andc r23,r23,r22 + stw r23,_MSR(r21) + SAVE_GPR(7, r21) + SAVE_4GPRS(8, r21) + SAVE_8GPRS(12, r21) + SAVE_8GPRS(24, r21) + andi. r23,r23,MSR_PR + mfspr r23,SPRG3 /* if from user, fix up THREAD.regs */ + beq 2f + addi r24,r1,STACK_FRAME_OVERHEAD + stw r24,PT_REGS(r23) +2: addi r2,r23,-THREAD /* set r2 to current */ + tovirt(r2,r2) + mflr r23 + andi. r24,r23,0x3f00 /* get vector offset */ + stw r24,TRAP(r21) + li r22,RESULT + stwcx. r22,r22,r21 /* to clear the reservation */ + li r22,0 + stw r22,RESULT(r21) + mtspr SPRG2,r22 /* r1 is now kernel sp */ + addi r24,r2,TASK_STRUCT_SIZE /* check for kernel stack overflow */ + cmplw 0,r1,r2 + cmplw 1,r1,r24 + crand 1,1,4 + bgt- stack_ovf /* if r2 < r1 < r2+TASK_STRUCT_SIZE */ + lwz r24,0(r23) /* virtual address of handler */ + lwz r23,4(r23) /* where to go when done */ + mtspr SRR0,r24 + mtspr SRR1,r20 + mtlr r23 + SYNC + rfi /* jump to handler, enable MMU */ + +/* + * On kernel stack overflow, load up an initial stack pointer + * and call StackOverflow(regs), which should not return. + */ +stack_ovf: + addi r3,r1,STACK_FRAME_OVERHEAD + lis r1,init_task_union@ha + addi r1,r1,init_task_union@l + addi r1,r1,TASK_UNION_SIZE-STACK_FRAME_OVERHEAD + lis r24,StackOverflow@ha + addi r24,r24,StackOverflow@l + li r20,MSR_KERNEL + mtspr SRR0,r24 + mtspr SRR1,r20 + SYNC + rfi + + .globl giveup_fpu +giveup_fpu: + blr + +/* + * This code is jumped to from the startup code to copy + * the kernel image to physical address 0. + */ +relocate_kernel: + lis r9,0x426f /* if booted from BootX, don't */ + addi r9,r9,0x6f58 /* translate source addr */ + cmpw r31,r9 /* (we have to on chrp) */ + beq 7f + rlwinm r4,r4,0,8,31 /* translate source address */ + add r4,r4,r3 /* to region mapped with BATs */ +7: addis r9,r26,klimit@ha /* fetch klimit */ + lwz r25,klimit@l(r9) + addis r25,r25,-KERNELBASE@h + li r6,0 /* Destination offset */ + li r5,0x4000 /* # bytes of memory to copy */ + bl copy_and_flush /* copy the first 0x4000 bytes */ + addi r0,r3,4f@l /* jump to the address of 4f */ + mtctr r0 /* in copy and do the rest. */ + bctr /* jump to the copy */ +4: mr r5,r25 + bl copy_and_flush /* copy the rest */ + b turn_on_mmu + +/* + * Copy routine used to copy the kernel to start at physical address 0 + * and flush and invalidate the caches as needed. + * r3 = dest addr, r4 = source addr, r5 = copy limit, r6 = start offset + * on exit, r3, r4, r5 are unchanged, r6 is updated to be >= r5. + */ +copy_and_flush: + addi r5,r5,-4 + addi r6,r6,-4 +4: li r0,8 + mtctr r0 +3: addi r6,r6,4 /* copy a cache line */ + lwzx r0,r6,r4 + stwx r0,r6,r3 + bdnz 3b + dcbst r6,r3 /* write it to memory */ + sync + icbi r6,r3 /* flush the icache line */ + cmplw 0,r6,r5 + blt 4b + isync + addi r5,r5,4 + addi r6,r6,4 + blr + +#ifdef CONFIG_SMP + .globl __secondary_start_psurge +__secondary_start_psurge: + li r24,1 /* cpu # */ + b __secondary_start + + .globl __secondary_hold +__secondary_hold: + /* tell the master we're here */ + lis r5,0x4@h + ori r5,r5,0x4@l + stw r3,0(r5) + dcbf 0,r5 +100: + lis r5,0 + dcbi 0,r5 + lwz r4,0(r5) + /* wait until we're told to start */ + cmp 0,r4,r3 + bne 100b + /* our cpu # was at addr 0 - go */ + lis r5,__secondary_start@h + ori r5,r5,__secondary_start@l + tophys(r5,r5) + mtlr r5 + mr r24,r3 /* cpu # */ + blr +#endif /* CONFIG_SMP */ + +/* + * This is where the main kernel code starts. + */ +start_here: +#ifdef __SMP__ + /* if we're the second cpu stack and r2 are different + * and we want to not clear the bss -- Cort */ + lis r5,first_cpu_booted@h + ori r5,r5,first_cpu_booted@l + lwz r5,0(r5) + cmpi 0,r5,0 + beq 99f + + /* get current */ + lis r2,current_set@h + ori r2,r2,current_set@l + slwi r24,r24,2 /* cpu # to current_set[cpu#] */ + add r2,r2,r24 + lwz r2,0(r2) + b 10f +99: +#endif /* __SMP__ */ + /* ptr to current */ + lis r2,init_task_union@h + ori r2,r2,init_task_union@l + /* Clear out the BSS */ + lis r11,_end@ha + addi r11,r11,_end@l + lis r8,__bss_start@ha + addi r8,r8,__bss_start@l + subf r11,r8,r11 + addi r11,r11,3 + rlwinm. r11,r11,30,2,31 + beq 2f + addi r8,r8,-4 + mtctr r11 + li r0,0 +3: stwu r0,4(r8) + bdnz 3b +2: +#ifdef __SMP__ +10: +#endif /* __SMP__ */ + /* stack */ + addi r1,r2,TASK_UNION_SIZE + li r0,0 + stwu r0,-STACK_FRAME_OVERHEAD(r1) +/* + * Decide what sort of machine this is and initialize the MMU. + */ + mr r3,r31 + mr r4,r30 + mr r5,r29 + mr r6,r28 + mr r7,r27 + bl identify_machine + bl MMU_init + +/* + * Go back to running unmapped so we can load up new values + * for SDR1 (hash table pointer) and the segment registers + * and change to using our exception vectors. + * On the 8xx, all we have to do is invalidate the TLB to clear + * the old 8M byte TLB mappings and load the page table base register. + */ + /* The right way to do this would be to track it down through + * init's THREAD like the context switch code does, but this is + * easier......until someone changes init's static structures. + */ + lis r6, swapper_pg_dir@h + tophys(r6,r6) + ori r6, r6, swapper_pg_dir@l + mtspr M_TWB, r6 + lis r4,2f@h + ori r4,r4,2f@l + tophys(r4,r4) + li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR) + mtspr SRR0,r4 + mtspr SRR1,r3 + rfi +/* Load up the kernel context */ +2: + SYNC /* Force all PTE updates to finish */ + tlbia /* Clear all TLB entries */ + sync /* wait for tlbia/tlbie to finish */ +#ifdef __SMP__ + tlbsync /* ... on all CPUs */ + sync +#endif +/* Set up for using our exception vectors */ + /* ptr to phys current thread */ + tophys(r4,r2) + addi r4,r4,THREAD /* init task's THREAD */ + mtspr SPRG3,r4 + li r3,0 + mtspr SPRG2,r3 /* 0 => r1 has kernel sp */ +/* Now turn on the MMU for real! */ + li r4,MSR_KERNEL + lis r3,start_kernel@h + ori r3,r3,start_kernel@l +#ifdef __SMP__ + /* the second time through here we go to + * start_secondary(). -- Cort + */ + lis r5,first_cpu_booted@h + ori r5,r5,first_cpu_booted@l + tophys(r5,r5) + lwz r5,0(r5) + cmpi 0,r5,0 + beq 10f + lis r3,start_secondary@h + ori r3,r3,start_secondary@l +10: +#endif /* __SMP__ */ + mtspr SRR0,r3 + mtspr SRR1,r4 + rfi /* enable MMU and jump to start_kernel */ + +/* + * Set up to use a given MMU context. + * + * The MPC8xx has something that currently happens "automagically." + * Unshared user space address translations are subject to ASID (context) + * match. During each task switch, the ASID is incremented. We can + * guarantee (I hope :-) that no entries currently match this ASID + * because every task will cause at least a TLB entry to be loaded for + * the first instruction and data access, plus the kernel running will + * have displaced several more TLBs. The MMU contains 32 entries for + * each TLB, and there are 16 contexts, so we just need to make sure + * two pages get replaced for every context switch, which currently + * happens. There are other TLB management techniques that I will + * eventually implement, but this is the easiest for now. -- Dan + * + * On the MPC8xx, we place the physical address of the new task + * page directory loaded into the MMU base register, and set the + * ASID compare register with the new "context". + */ +_GLOBAL(set_context) + mtspr M_CASID,r3 /* Update context */ + tlbia + SYNC + blr + +/* Jump into the system reset for the rom. + * We first disable the MMU, and then jump to the ROM reset address. + * + * r3 is the board info structure, r4 is the location for starting. + * I use this for building a small kernel that can load other kernels, + * rather than trying to write or rely on a rom monitor that can tftp load. + */ + .globl m8xx_gorom +m8xx_gorom: + li r5,MSR_KERNEL & ~(MSR_IR|MSR_DR) + lis r6,2f@h + addis r6,r6,-KERNELBASE@h + ori r6,r6,2f@l + mtspr SRR0,r6 + mtspr SRR1,r5 + rfi +2: + mtlr r4 + blr + +/* + * We put a few things here that have to be page-aligned. + * This stuff goes at the beginning of the data segment, + * which is page-aligned. + */ + .data + .globl sdata +sdata: + .globl empty_zero_page +empty_zero_page: + .space 4096 + + .globl swapper_pg_dir +swapper_pg_dir: + .space 4096 + +/* + * This space gets a copy of optional info passed to us by the bootstrap + * Used to pass parameters into the kernel like root=/dev/sda1, etc. + */ + .globl cmd_line +cmd_line: + .space 512 diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c index 9d8d94e51..f8f59440c 100644 --- a/arch/ppc/kernel/idle.c +++ b/arch/ppc/kernel/idle.c @@ -1,5 +1,5 @@ /* - * $Id: idle.c,v 1.62 1999/05/24 05:43:18 cort Exp $ + * $Id: idle.c,v 1.66 1999/09/05 11:56:30 paulus Exp $ * * Idle daemon for PowerPC. Idle daemon will handle any action * that needs to be taken when the system becomes idle. @@ -45,7 +45,7 @@ unsigned long zeropage_hits; /* # zero'd pages request that we've done */ unsigned long zeropage_calls; /* # zero'd pages request that've been made */ unsigned long zerototal; /* # pages zero'd over time */ -int idled(void *unused) +int idled(void) { /* endless loop with no priority at all */ current->priority = 0; @@ -69,29 +69,15 @@ int idled(void *unused) return 0; } -#ifdef __SMP__ /* * SMP entry into the idle task - calls the same thing as the * non-smp versions. -- Cort */ -int cpu_idle(void *unused) +int cpu_idle() { - idled(unused); + idled(); return 0; } -#endif /* __SMP__ */ - -/* - * Syscall entry into the idle task. -- Cort - */ -asmlinkage int sys_idle(void) -{ - if(current->pid != 0) - return -EPERM; - - idled(NULL); - return 0; /* should never execute this but it makes gcc happy -- Cort */ -} /* * Mark 'zombie' pte's in the hash table as invalid. @@ -227,7 +213,7 @@ void zero_paged(void) /* * Make the page no cache so we don't blow our cache with 0's */ - pte = find_pte(init_task.mm, pageptr); + pte = find_pte(&init_mm, pageptr); if ( !pte ) { printk("pte NULL in zero_paged()\n"); @@ -235,7 +221,7 @@ void zero_paged(void) } pte_uncache(*pte); - flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr); + flush_tlb_page(find_vma(&init_mm,pageptr),pageptr); /* * Important here to not take time away from real processes. */ @@ -260,7 +246,7 @@ void zero_paged(void) /* turn cache on for this page */ pte_cache(*pte); - flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr); + flush_tlb_page(find_vma(&init_mm,pageptr),pageptr); /* atomically add this page to the list */ asm ( "101:lwarx %0,0,%1\n" /* reserve zero_cache */ " stw %0,0(%2)\n" /* update *pageptr */ diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c index 5d906f62a..eece8308a 100644 --- a/arch/ppc/kernel/irq.c +++ b/arch/ppc/kernel/irq.c @@ -1,5 +1,5 @@ /* - * $Id: irq.c,v 1.106 1999/05/25 21:16:04 cort Exp $ + * $Id: irq.c,v 1.109 1999/09/05 11:56:31 paulus Exp $ * * arch/ppc/kernel/irq.c * @@ -31,6 +31,7 @@ #include <linux/ptrace.h> #include <linux/errno.h> +#include <linux/threads.h> #include <linux/kernel_stat.h> #include <linux/signal.h> #include <linux/sched.h> diff --git a/arch/ppc/kernel/local_irq.h b/arch/ppc/kernel/local_irq.h index 5149c291a..adf028590 100644 --- a/arch/ppc/kernel/local_irq.h +++ b/arch/ppc/kernel/local_irq.h @@ -19,10 +19,6 @@ struct hw_interrupt_type { int irq_offset; }; -#define mask_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->disable) irq_desc[irq].ctl->disable(irq);}) -#define unmask_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->enable) irq_desc[irq].ctl->enable(irq);}) -#define mask_and_ack_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->mask_and_ack) irq_desc[irq].ctl->mask_and_ack(irq);}) - struct irqdesc { struct irqaction *action; struct hw_interrupt_type *ctl; diff --git a/arch/ppc/kernel/mbx_pci.c b/arch/ppc/kernel/mbx_pci.c index 5114c3cfb..d7473e128 100644 --- a/arch/ppc/kernel/mbx_pci.c +++ b/arch/ppc/kernel/mbx_pci.c @@ -253,16 +253,14 @@ int mbx_pcibios_find_class(unsigned int class_code, unsigned short index, return PCIBIOS_DEVICE_NOT_FOUND; } -__initfunc( -void -mbx_pcibios_fixup(void)) +void __init +mbx_pcibios_fixup(void) { /* Nothing to do here? */ } -__initfunc( -void -mbx_setup_pci_ptrs(void)) +void __init +mbx_setup_pci_ptrs(void) { set_config_access_method(mbx); diff --git a/arch/ppc/kernel/mbx_setup.c b/arch/ppc/kernel/mbx_setup.c index fdb9c11e0..67cab4503 100644 --- a/arch/ppc/kernel/mbx_setup.c +++ b/arch/ppc/kernel/mbx_setup.c @@ -1,5 +1,5 @@ /* - * $Id: mbx_setup.c,v 1.10 1999/05/14 07:24:19 davem Exp $ + * $Id: mbx_setup.c,v 1.12 1999/08/31 06:53:56 davem Exp $ * * linux/arch/ppc/kernel/setup.c * @@ -75,8 +75,8 @@ void __init adbdev_init(void) { } -__initfunc(void -mbx_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)) +void __init +mbx_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p) { int cpm_page; extern char cmd_line[]; @@ -141,7 +141,7 @@ abort(void) * sixteen, or external oscillator divided by four. Currently, we only * support the MBX, which is system clock divided by sixteen. */ -__initfunc(void mbx_calibrate_decr(void)) +void __init mbx_calibrate_decr(void) { bd_t *binfo = (bd_t *)&res; int freq, fp, divisor; @@ -182,8 +182,7 @@ mbx_set_rtc_time(unsigned long time) return(0); } -initfunc(unsigned long -mbx_get_rtc_time(void) +unsigned long __init mbx_get_rtc_time(void) { /* First, unlock all of the registers we are going to modify. * To protect them from corruption during power down, registers @@ -310,8 +309,8 @@ static void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs) * interrupts can be either edge or level triggered, but there is no * reason for us to change the EPPC-bug values (it would not work if we did). */ -__initfunc(void -mbx_init_IRQ(void)) +void __init +mbx_init_IRQ(void) { int i; @@ -413,9 +412,9 @@ mbx_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_p } #endif -__initfunc(void +void __init mbx_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7)) + unsigned long r6, unsigned long r7) { if ( r3 ) diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index 0caf06a3b..c4bed05e9 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -17,19 +17,17 @@ #include <asm/unistd.h> #include <asm/errno.h> #include <asm/processor.h> -#include "ppc_asm.tmpl" -#include "ppc_defs.h" +#include <asm/page.h> +#include "ppc_asm.h" #ifndef CONFIG_8xx -/* This instruction is not implemented on the PPC 601 or 603 */ -#define tlbia \ - li r4,128; \ - mtspr CTR,r4; \ - li r4,0; \ -0: tlbie r4; \ - addi r4,r4,0x1000; \ - bdnz 0b -#endif +CACHE_LINE_SIZE = 32 +LG_CACHE_LINE_SIZE = 5 +#else +CACHE_LINE_SIZE = 16 +LG_CACHE_LINE_SIZE = 4 +#endif /* CONFIG_8xx */ + .text /* @@ -47,13 +45,7 @@ _GLOBAL(reloc_offset) mtlr r0 blr -/* - * Disable interrupts - * rc = _disable_interrupts() - */ -_GLOBAL(_disable_interrupts) _GLOBAL(__cli) -_GLOBAL(_hard_cli) mfmsr r0 /* Get current interrupt state */ rlwinm r3,r0,16+1,32-1,31 /* Extract old value of 'EE' */ li r4,0 /* Need [unsigned] value of MSR_EE */ @@ -63,16 +55,7 @@ _GLOBAL(_hard_cli) mtmsr r0 /* Update machine state */ blr /* Done */ -/* - * Enable interrupts - * _enable_interrupts(int state) - * turns on interrupts if state = 1. - */ -_GLOBAL(_enable_interrupts) - cmpi 0,r3,0 /* turning them on? */ - beqlr /* nothing to do if state == 0 */ _GLOBAL(__sti) -_GLOBAL(_hard_sti) lis r4,ppc_n_lost_interrupts@ha lwz r4,ppc_n_lost_interrupts@l(r4) mfmsr r3 /* Get current state */ @@ -146,6 +129,117 @@ _GLOBAL(_tlbie) blr /* + * Flush instruction cache. + * This is a no-op on the 601. + */ +_GLOBAL(flush_instruction_cache) + mfspr r3,PVR + rlwinm r3,r3,16,16,31 + cmpi 0,r3,1 + beqlr /* for 601, do nothing */ + /* 603/604 processor - use invalidate-all bit in HID0 */ + mfspr r3,HID0 + ori r3,r3,HID0_ICFI + mtspr HID0,r3 + SYNC + blr + +/* + * Write any modified data cache blocks out to memory + * and invalidate the corresponding instruction cache blocks. + * This is a no-op on the 601. + * + * flush_icache_range(unsigned long start, unsigned long stop) + */ +_GLOBAL(flush_icache_range) + mfspr r5,PVR + rlwinm r5,r5,16,16,31 + cmpi 0,r5,1 + beqlr /* for 601, do nothing */ + li r5,CACHE_LINE_SIZE-1 + andc r3,r3,r5 + subf r4,r3,r4 + add r4,r4,r5 + srwi. r4,r4,LG_CACHE_LINE_SIZE + beqlr + mtctr r4 + mr r6,r3 +1: dcbst 0,r3 + addi r3,r3,CACHE_LINE_SIZE + bdnz 1b + sync /* wait for dcbst's to get to ram */ + mtctr r4 +2: icbi 0,r6 + addi r6,r6,CACHE_LINE_SIZE + bdnz 2b + sync + isync + blr + +/* + * Like above, but only do the D-cache. + * + * flush_dcache_range(unsigned long start, unsigned long stop) + */ +_GLOBAL(flush_dcache_range) + li r5,CACHE_LINE_SIZE-1 + andc r3,r3,r5 + subf r4,r3,r4 + add r4,r4,r5 + srwi. r4,r4,LG_CACHE_LINE_SIZE + beqlr + mtctr r4 + +1: dcbst 0,r3 + addi r3,r3,CACHE_LINE_SIZE + bdnz 1b + sync /* wait for dcbst's to get to ram */ + blr + +/* + * Flush a particular page from the DATA cache + * Note: this is necessary because the instruction cache does *not* + * snoop from the data cache. + * This is a no-op on the 601 which has a unified cache. + * + * void flush_page_to_ram(void *page) + */ +_GLOBAL(flush_page_to_ram) + mfspr r5,PVR + rlwinm r5,r5,16,16,31 + cmpi 0,r5,1 + beqlr /* for 601, do nothing */ + li r4,0x0FFF + andc r3,r3,r4 /* Get page base address */ + li r4,4096/CACHE_LINE_SIZE /* Number of lines in a page */ + mtctr r4 + mr r6,r3 +0: dcbst 0,r3 /* Write line to ram */ + addi r3,r3,CACHE_LINE_SIZE + bdnz 0b + sync + mtctr r4 +1: icbi 0,r6 + addi r6,r6,CACHE_LINE_SIZE + bdnz 1b + sync + isync + blr + +/* + * Clear a page using the dcbz instruction, which doesn't cause any + * memory traffic (except to write out any cache lines which get + * displaced). This only works on cacheable memory. + */ +_GLOBAL(clear_page) + li r0,4096/CACHE_LINE_SIZE + mtctr r0 +1: dcbz 0,r3 + addi r3,r3,CACHE_LINE_SIZE + bdnz 1b + blr + +/* * Atomic [test&set] exchange * * unsigned long xchg_u32(void *ptr, unsigned long val) @@ -659,8 +753,8 @@ _GLOBAL(kernel_thread) sc cmpi 0,r3,0 /* parent or child? */ bnelr /* return if parent */ - li r0,0 /* clear out p->tss.regs */ - stw r0,TSS+PT_REGS(r2) /* since we don't have user ctx */ + li r0,0 /* clear out p->thread.regs */ + stw r0,THREAD+PT_REGS(r2) /* since we don't have user ctx */ mtlr r6 /* fn addr in lr */ mr r3,r4 /* load arg and call fn */ blrl @@ -668,6 +762,12 @@ _GLOBAL(kernel_thread) li r3,0 sc +/* + * This routine is just here to keep GCC happy - sigh... + */ +_GLOBAL(__main) + blr + #define SYSCALL(name) \ _GLOBAL(name) \ li r0,__NR_##name; \ @@ -680,7 +780,6 @@ _GLOBAL(name) \ #define __NR__exit __NR_exit -SYSCALL(idle) SYSCALL(sync) SYSCALL(setsid) SYSCALL(write) @@ -812,7 +911,7 @@ sys_call_table: .long sys_uname .long sys_iopl /* 110 */ .long sys_vhangup - .long sys_idle + .long sys_ni_syscall /* old 'idle' syscall */ .long sys_vm86 .long sys_wait4 .long sys_swapoff /* 115 */ diff --git a/arch/ppc/kernel/mk_defs.c b/arch/ppc/kernel/mk_defs.c index a3977193a..38f38ca92 100644 --- a/arch/ppc/kernel/mk_defs.c +++ b/arch/ppc/kernel/mk_defs.c @@ -35,19 +35,19 @@ main(void) DEFINE(COUNTER, offsetof(struct task_struct, counter)); DEFINE(PROCESSOR, offsetof(struct task_struct, processor)); DEFINE(SIGPENDING, offsetof(struct task_struct, sigpending)); - DEFINE(TSS, offsetof(struct task_struct, tss)); + DEFINE(THREAD, offsetof(struct task_struct, thread)); DEFINE(MM, offsetof(struct task_struct, mm)); + DEFINE(ACTIVE_MM, offsetof(struct task_struct, active_mm)); DEFINE(TASK_STRUCT_SIZE, sizeof(struct task_struct)); DEFINE(KSP, offsetof(struct thread_struct, ksp)); - DEFINE(PG_TABLES, offsetof(struct thread_struct, pg_tables)); - DEFINE(PGD, offsetof(struct mm_struct, pgd)); + DEFINE(PGDIR, offsetof(struct thread_struct, pgdir)); DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall)); DEFINE(PT_REGS, offsetof(struct thread_struct, regs)); DEFINE(PF_TRACESYS, PF_TRACESYS); DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags)); DEFINE(NEED_RESCHED, offsetof(struct task_struct, need_resched)); - DEFINE(TSS_FPR0, offsetof(struct thread_struct, fpr[0])); - DEFINE(TSS_FPSCR, offsetof(struct thread_struct, fpscr)); + DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0])); + DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr)); /* Interrupt register frame */ DEFINE(TASK_UNION_SIZE, sizeof(union task_union)); DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD); diff --git a/arch/ppc/kernel/open_pic.c b/arch/ppc/kernel/open_pic.c index 2ca879dd8..519407eea 100644 --- a/arch/ppc/kernel/open_pic.c +++ b/arch/ppc/kernel/open_pic.c @@ -1,11 +1,87 @@ -#include <linux/stddef.h> -#include <linux/init.h> +/* + * arch/ppc/kernel/openpic.c -- OpenPIC Interrupt Handling + * + * Copyright (C) 1997 Geert Uytterhoeven + * + * 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 + * for more details. + */ + +#include <linux/types.h> +#include <linux/kernel.h> #include <linux/sched.h> -#include <linux/signal.h> +#include <linux/init.h> #include <linux/openpic.h> +#include <asm/ptrace.h> +#include <asm/signal.h> +#include <asm/io.h> #include <asm/irq.h> -#include "open_pic.h" -#include "i8259.h" +#include "local_irq.h" + +volatile struct OpenPIC *OpenPIC = NULL; +u_int OpenPIC_NumInitSenses __initdata = 0; +u_char *OpenPIC_InitSenses __initdata = NULL; + +void chrp_mask_irq(unsigned int); +void chrp_unmask_irq(unsigned int); + +static u_int NumProcessors; +static u_int NumSources; + +struct hw_interrupt_type open_pic = { + " OpenPIC ", + NULL, + NULL, + NULL, + openpic_enable_irq, + openpic_disable_irq, + 0, + 0 +}; + +/* + * Accesses to the current processor's registers + */ +#ifndef __powerpc__ +#define THIS_CPU Private +#define CHECK_THIS_CPU do {} while (0) +#else +#define THIS_CPU Processor[cpu] +#define CHECK_THIS_CPU check_arg_cpu(cpu) +#endif + +#if 1 +#define check_arg_ipi(ipi) \ + if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \ + printk("openpic.c:%d: illegal ipi %d\n", __LINE__, ipi); +#define check_arg_timer(timer) \ + if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \ + printk("openpic.c:%d: illegal timer %d\n", __LINE__, timer); +#define check_arg_vec(vec) \ + if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \ + printk("openpic.c:%d: illegal vector %d\n", __LINE__, vec); +#define check_arg_pri(pri) \ + if (pri < 0 || pri >= OPENPIC_NUM_PRI) \ + printk("openpic.c:%d: illegal priority %d\n", __LINE__, pri); +#define check_arg_irq(irq) \ + if (irq < 0 || irq >= (NumSources+open_pic.irq_offset)) \ + printk("openpic.c:%d: illegal irq %d\n", __LINE__, irq); +#define check_arg_cpu(cpu) \ + if (cpu < 0 || cpu >= NumProcessors) \ + printk("openpic.c:%d: illegal cpu %d\n", __LINE__, cpu); +#else +#define check_arg_ipi(ipi) do {} while (0) +#define check_arg_timer(timer) do {} while (0) +#define check_arg_vec(vec) do {} while (0) +#define check_arg_pri(pri) do {} while (0) +#define check_arg_irq(irq) do {} while (0) +#define check_arg_cpu(cpu) do {} while (0) +#endif + +static void no_action(int ir1, void *dev, struct pt_regs *regs) +{ +} #ifdef __SMP__ void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs) @@ -14,35 +90,349 @@ void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs) } #endif /* __SMP__ */ -void chrp_mask_and_ack_irq(unsigned int irq_nr) +#ifdef __i386__ +static inline u_int ld_le32(volatile u_int *addr) { - if (is_8259_irq(irq_nr)) - i8259_pic.mask_and_ack(irq_nr); + return *addr; } -static void chrp_mask_irq(unsigned int irq_nr) +static inline void out_le32(volatile u_int *addr, u_int val) { - if (is_8259_irq(irq_nr)) - i8259_pic.disable(irq_nr); - else - openpic_disable_irq(irq_to_openpic(irq_nr)); + *addr = val; +} +#endif + +u_int openpic_read(volatile u_int *addr) +{ + u_int val; + + val = ld_le32(addr); + return val; +} + +static inline void openpic_write(volatile u_int *addr, u_int val) +{ + out_le32(addr, val); +} + +static inline u_int openpic_readfield(volatile u_int *addr, u_int mask) +{ + u_int val = openpic_read(addr); + return val & mask; +} + +inline void openpic_writefield(volatile u_int *addr, u_int mask, + u_int field) +{ + u_int val = openpic_read(addr); + openpic_write(addr, (val & ~mask) | (field & mask)); +} + +static inline void openpic_clearfield(volatile u_int *addr, u_int mask) +{ + openpic_writefield(addr, mask, 0); +} + +static inline void openpic_setfield(volatile u_int *addr, u_int mask) +{ + openpic_writefield(addr, mask, mask); +} + +static void openpic_safe_writefield(volatile u_int *addr, u_int mask, + u_int field) +{ + openpic_setfield(addr, OPENPIC_MASK); + /* wait until it's not in use */ + while (openpic_read(addr) & OPENPIC_ACTIVITY); + openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK); } -static void chrp_unmask_irq(unsigned int irq_nr) +void __init openpic_init(int main_pic) { - if (is_8259_irq(irq_nr)) - i8259_pic.enable(irq_nr); + u_int t, i; + u_int timerfreq; + const char *version; + + if (!OpenPIC) + panic("No OpenPIC found"); + + if ( ppc_md.progress ) ppc_md.progress("openpic enter",0x122); + + t = openpic_read(&OpenPIC->Global.Feature_Reporting0); + switch (t & OPENPIC_FEATURE_VERSION_MASK) { + case 1: + version = "1.0"; + break; + case 2: + version = "1.2"; + break; + case 3: + version = "1.3"; + break; + default: + version = "?"; + break; + } + NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >> + OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1; + NumSources = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >> + OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1; + + printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n", version, + NumProcessors, NumSources, OpenPIC); + timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency); + printk("OpenPIC timer frequency is "); + if (timerfreq) + printk("%d Hz\n", timerfreq); else - openpic_enable_irq(irq_to_openpic(irq_nr)); + printk("not set\n"); + + if ( main_pic ) + { + /* Initialize timer interrupts */ + if ( ppc_md.progress ) ppc_md.progress("openpic timer",0x3ba); + for (i = 0; i < OPENPIC_NUM_TIMERS; i++) { + /* Disabled, Priority 0 */ + openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i); + /* No processor */ + openpic_maptimer(i, 0); + } + + /* Initialize IPI interrupts */ + if ( ppc_md.progress ) ppc_md.progress("openpic ipi",0x3bb); + for (i = 0; i < OPENPIC_NUM_IPI; i++) { + /* Disabled, Priority 0 */ + openpic_initipi(i, 0, OPENPIC_VEC_IPI+i); + } + + /* Initialize external interrupts */ + if ( ppc_md.progress ) ppc_md.progress("openpic ext",0x3bc); + /* SIOint (8259 cascade) is special */ + openpic_initirq(0, 8, open_pic.irq_offset, 1, 1); + openpic_mapirq(0, 1<<0); + for (i = 1; i < NumSources; i++) { + /* Enabled, Priority 8 */ + openpic_initirq(i, 8, open_pic.irq_offset+i, 0, + i < OpenPIC_NumInitSenses ? OpenPIC_InitSenses[i] : 1); + /* Processor 0 */ + openpic_mapirq(i, 1<<0); + } + + /* Initialize the spurious interrupt */ + if ( ppc_md.progress ) ppc_md.progress("openpic spurious",0x3bd); + openpic_set_spurious(OPENPIC_VEC_SPURIOUS); + if ( _machine != _MACH_gemini ) + { + if (request_irq(IRQ_8259_CASCADE, no_action, SA_INTERRUPT, + "82c59 cascade", NULL)) + printk("Unable to get OpenPIC IRQ 0 for cascade\n"); + } + openpic_set_priority(0, 0); + openpic_disable_8259_pass_through(); + } + if ( ppc_md.progress ) ppc_md.progress("openpic exit",0x222); } -struct hw_interrupt_type open_pic = { - " OpenPIC ", - NULL, - NULL, - NULL, - chrp_unmask_irq, - chrp_mask_irq, - chrp_mask_and_ack_irq, - 0 -}; +void openpic_reset(void) +{ + openpic_setfield(&OpenPIC->Global.Global_Configuration0, + OPENPIC_CONFIG_RESET); +} + +void openpic_enable_8259_pass_through(void) +{ + openpic_clearfield(&OpenPIC->Global.Global_Configuration0, + OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE); +} + +void openpic_disable_8259_pass_through(void) +{ + openpic_setfield(&OpenPIC->Global.Global_Configuration0, + OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE); +} + +#ifndef __i386__ +/* + * Find out the current interrupt + */ +u_int openpic_irq(u_int cpu) +{ + u_int vec; + + check_arg_cpu(cpu); + vec = openpic_readfield(&OpenPIC->THIS_CPU.Interrupt_Acknowledge, + OPENPIC_VECTOR_MASK); + return vec; +} +#endif + +#ifndef __powerpc__ +void openpic_eoi(void) +#else +void openpic_eoi(u_int cpu) +#endif +{ + check_arg_cpu(cpu); + openpic_write(&OpenPIC->THIS_CPU.EOI, 0); +} + + +#ifndef __powerpc__ +u_int openpic_get_priority(void) +#else +u_int openpic_get_priority(u_int cpu) +#endif +{ + CHECK_THIS_CPU; + return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority, + OPENPIC_CURRENT_TASK_PRIORITY_MASK); +} + +#ifndef __powerpc__ +void openpic_set_priority(u_int pri) +#else +void openpic_set_priority(u_int cpu, u_int pri) +#endif +{ + CHECK_THIS_CPU; + check_arg_pri(pri); + openpic_writefield(&OpenPIC->THIS_CPU.Current_Task_Priority, + OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri); +} + +/* + * Get/set the spurious vector + */ +u_int openpic_get_spurious(void) +{ + return openpic_readfield(&OpenPIC->Global.Spurious_Vector, + OPENPIC_VECTOR_MASK); +} + +void openpic_set_spurious(u_int vec) +{ + check_arg_vec(vec); + openpic_writefield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK, + vec); +} + +void openpic_init_processor(u_int cpumask) +{ + openpic_write(&OpenPIC->Global.Processor_Initialization, cpumask); +} + +/* + * Initialize an interprocessor interrupt (and disable it) + * + * ipi: OpenPIC interprocessor interrupt number + * pri: interrupt source priority + * vec: the vector it will produce + */ +void openpic_initipi(u_int ipi, u_int pri, u_int vec) +{ + check_arg_timer(ipi); + check_arg_pri(pri); + check_arg_vec(vec); + openpic_safe_writefield(&OpenPIC->Global.IPI_Vector_Priority(ipi), + OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK, + (pri << OPENPIC_PRIORITY_SHIFT) | vec); +} + +/* + * Send an IPI to one or more CPUs + */ +#ifndef __powerpc__ +void openpic_cause_IPI(u_int ipi, u_int cpumask) +#else +void openpic_cause_IPI(u_int cpu, u_int ipi, u_int cpumask) +#endif +{ + CHECK_THIS_CPU; + check_arg_ipi(ipi); + openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi), cpumask); +} + +/* + * Initialize a timer interrupt (and disable it) + * + * timer: OpenPIC timer number + * pri: interrupt source priority + * vec: the vector it will produce + */ +void openpic_inittimer(u_int timer, u_int pri, u_int vec) +{ + check_arg_timer(timer); + check_arg_pri(pri); + check_arg_vec(vec); + openpic_safe_writefield(&OpenPIC->Global.Timer[timer].Vector_Priority, + OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK, + (pri << OPENPIC_PRIORITY_SHIFT) | vec); +} + +/* + * Map a timer interrupt to one or more CPUs + */ +void openpic_maptimer(u_int timer, u_int cpumask) +{ + check_arg_timer(timer); + openpic_write(&OpenPIC->Global.Timer[timer].Destination, cpumask); +} + +/* + * Enable/disable an interrupt source + */ +void openpic_enable_irq(u_int irq) +{ + check_arg_irq(irq); + openpic_clearfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK); +} + +void openpic_disable_irq(u_int irq) +{ + check_arg_irq(irq); + openpic_setfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK); +} + +/* + * Initialize an interrupt source (and disable it!) + * + * irq: OpenPIC interrupt number + * pri: interrupt source priority + * vec: the vector it will produce + * pol: polarity (1 for positive, 0 for negative) + * sense: 1 for level, 0 for edge + */ +void openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense) +{ + check_arg_irq(irq); + check_arg_pri(pri); + check_arg_vec(vec); + openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority, + OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK | + OPENPIC_SENSE_POLARITY | OPENPIC_SENSE_LEVEL, + (pri << OPENPIC_PRIORITY_SHIFT) | vec | + (pol ? OPENPIC_SENSE_POLARITY : 0) | + (sense ? OPENPIC_SENSE_LEVEL : 0)); +} + +/* + * Map an interrupt source to one or more CPUs + */ +void openpic_mapirq(u_int irq, u_int cpumask) +{ + check_arg_irq(irq); + openpic_write(&OpenPIC->Source[irq].Destination, cpumask); +} + +/* + * Set the sense for an interrupt source (and disable it!) + * + * sense: 1 for level, 0 for edge + */ +void openpic_set_sense(u_int irq, int sense) +{ + check_arg_irq(irq); + openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority, + OPENPIC_SENSE_LEVEL, + (sense ? OPENPIC_SENSE_LEVEL : 0)); +} diff --git a/arch/ppc/kernel/open_pic.h b/arch/ppc/kernel/open_pic.h index 77b8a46d0..ace8590bb 100644 --- a/arch/ppc/kernel/open_pic.h +++ b/arch/ppc/kernel/open_pic.h @@ -1,9 +1,6 @@ - #ifndef _PPC_KERNEL_OPEN_PIC_H #define _PPC_KERNEL_OPEN_PIC_H -#include "local_irq.h" - extern struct hw_interrupt_type open_pic; void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs); diff --git a/arch/ppc/kernel/openpic.c b/arch/ppc/kernel/openpic.c deleted file mode 100644 index f7893dd79..000000000 --- a/arch/ppc/kernel/openpic.c +++ /dev/null @@ -1,511 +0,0 @@ -/* - * arch/ppc/kernel/openpic.c -- OpenPIC Interrupt Handling - * - * Copyright (C) 1997 Geert Uytterhoeven - * - * 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 - * for more details. - */ - - -/* - * Note: Interprocessor Interrupt (IPI) and Timer support is incomplete - */ - - -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/init.h> -#include <linux/openpic.h> -#include <asm/ptrace.h> -#include <asm/signal.h> -#include <asm/io.h> -#include <asm/irq.h> - - -#define REGISTER_DEBUG -#undef REGISTER_DEBUG - - -volatile struct OpenPIC *OpenPIC = NULL; -u_int OpenPIC_NumInitSenses __initdata = 0; -u_char *OpenPIC_InitSenses __initdata = NULL; - -static u_int NumProcessors; -static u_int NumSources; - - - /* - * Accesses to the current processor's registers - */ - -#ifndef __powerpc__ -#define THIS_CPU Private -#define CHECK_THIS_CPU do {} while (0) -#else -#define THIS_CPU Processor[cpu] -#define CHECK_THIS_CPU check_arg_cpu(cpu) -#endif - - - /* - * Sanity checks - */ - -#if 1 -#define check_arg_ipi(ipi) \ - if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \ - printk("openpic.c:%d: illegal ipi %d\n", __LINE__, ipi); -#define check_arg_timer(timer) \ - if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \ - printk("openpic.c:%d: illegal timer %d\n", __LINE__, timer); -#define check_arg_vec(vec) \ - if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \ - printk("openpic.c:%d: illegal vector %d\n", __LINE__, vec); -#define check_arg_pri(pri) \ - if (pri < 0 || pri >= OPENPIC_NUM_PRI) \ - printk("openpic.c:%d: illegal priority %d\n", __LINE__, pri); -#define check_arg_irq(irq) \ - if (irq < 0 || irq >= NumSources) \ - printk("openpic.c:%d: illegal irq %d\n", __LINE__, irq); -#define check_arg_cpu(cpu) \ - if (cpu < 0 || cpu >= NumProcessors) \ - printk("openpic.c:%d: illegal cpu %d\n", __LINE__, cpu); -#else -#define check_arg_ipi(ipi) do {} while (0) -#define check_arg_timer(timer) do {} while (0) -#define check_arg_vec(vec) do {} while (0) -#define check_arg_pri(pri) do {} while (0) -#define check_arg_irq(irq) do {} while (0) -#define check_arg_cpu(cpu) do {} while (0) -#endif - - - /* - * Dummy interrupt handler - */ - -static void no_action(int ir1, void *dev, struct pt_regs *regs) -{} - - - /* - * I/O functions - */ - -#ifdef __i386__ -static inline u_int ld_le32(volatile u_int *addr) -{ - return *addr; -} - -static inline void out_le32(volatile u_int *addr, u_int val) -{ - *addr = val; -} -#endif - -u_int openpic_read(volatile u_int *addr) -{ - u_int val; - - val = ld_le32(addr); -#ifdef REGISTER_DEBUG - printk("openpic_read(0x%08x) = 0x%08x\n", (u_int)addr, val); -#endif - return val; -} - -static inline void openpic_write(volatile u_int *addr, u_int val) -{ -#ifdef REGISTER_DEBUG - printk("openpic_write(0x%08x, 0x%08x)\n", (u_int)addr, val); -#endif - out_le32(addr, val); -} - - -static inline u_int openpic_readfield(volatile u_int *addr, u_int mask) -{ - u_int val = openpic_read(addr); - return val & mask; -} - -inline void openpic_writefield(volatile u_int *addr, u_int mask, - u_int field) -{ - u_int val = openpic_read(addr); - openpic_write(addr, (val & ~mask) | (field & mask)); -} - -static inline void openpic_clearfield(volatile u_int *addr, u_int mask) -{ - openpic_writefield(addr, mask, 0); -} - -static inline void openpic_setfield(volatile u_int *addr, u_int mask) -{ - openpic_writefield(addr, mask, mask); -} - - - /* - * Update a Vector/Priority register in a safe manner. The interrupt will - * be disabled. - */ - -static void openpic_safe_writefield(volatile u_int *addr, u_int mask, - u_int field) -{ - openpic_setfield(addr, OPENPIC_MASK); - /* wait until it's not in use */ - while (openpic_read(addr) & OPENPIC_ACTIVITY); - openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK); -} - - -/* -------- Global Operations ---------------------------------------------- */ - - - /* - * Initialize the OpenPIC - */ - -__initfunc(void openpic_init(int main_pic)) -{ - u_int t, i; - u_int timerfreq; - const char *version; - - if (!OpenPIC) - panic("No OpenPIC found"); - - t = openpic_read(&OpenPIC->Global.Feature_Reporting0); - switch (t & OPENPIC_FEATURE_VERSION_MASK) { - case 1: - version = "1.0"; - break; - case 2: - version = "1.2"; - break; - case 3: - version = "1.3"; - break; - default: - version = "?"; - break; - } - NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >> - OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1; - NumSources = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >> - OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1; - printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n", version, - NumProcessors, NumSources, OpenPIC); - timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency); - printk("OpenPIC timer frequency is "); - if (timerfreq) - printk("%d Hz\n", timerfreq); - else - printk("not set\n"); - - if ( main_pic ) - { - /* Initialize timer interrupts */ - for (i = 0; i < OPENPIC_NUM_TIMERS; i++) { - /* Disabled, Priority 0 */ - openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i); - /* No processor */ - openpic_maptimer(i, 0); - } - - /* Initialize IPI interrupts */ - for (i = 0; i < OPENPIC_NUM_IPI; i++) { - /* Disabled, Priority 0 */ - openpic_initipi(i, 0, OPENPIC_VEC_IPI+i); - } - - /* Initialize external interrupts */ - /* SIOint (8259 cascade) is special */ - openpic_initirq(0, 8, OPENPIC_VEC_SOURCE, 1, 1); - /* Processor 0 */ - openpic_mapirq(0, 1<<0); - for (i = 1; i < NumSources; i++) { - /* Enabled, Priority 8 */ - openpic_initirq(i, 8, OPENPIC_VEC_SOURCE+i, 0, - i < OpenPIC_NumInitSenses ? OpenPIC_InitSenses[i] : 1); - /* Processor 0 */ - openpic_mapirq(i, 1<<0); - } - - /* Initialize the spurious interrupt */ - openpic_set_spurious(OPENPIC_VEC_SPURIOUS); - - if (request_irq(IRQ_8259_CASCADE, no_action, SA_INTERRUPT, - "82c59 cascade", NULL)) - printk("Unable to get OpenPIC IRQ 0 for cascade\n"); - openpic_set_priority(0, 0); - openpic_disable_8259_pass_through(); - } -} - - - /* - * Reset the OpenPIC - */ - -void openpic_reset(void) -{ - openpic_setfield(&OpenPIC->Global.Global_Configuration0, - OPENPIC_CONFIG_RESET); -} - - - /* - * Enable/disable 8259 Pass Through Mode - */ - -void openpic_enable_8259_pass_through(void) -{ - openpic_clearfield(&OpenPIC->Global.Global_Configuration0, - OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE); -} - -void openpic_disable_8259_pass_through(void) -{ - openpic_setfield(&OpenPIC->Global.Global_Configuration0, - OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE); -} - - -#ifndef __i386__ - /* - * Find out the current interrupt - */ - -u_int openpic_irq(u_int cpu) -{ - u_int vec; - - check_arg_cpu(cpu); - vec = openpic_readfield(&OpenPIC->THIS_CPU.Interrupt_Acknowledge, - OPENPIC_VECTOR_MASK); -#if 0 -if (vec != 22 /* SCSI */) -printk("++openpic_irq: %d\n", vec); -#endif - return vec; -} -#endif - - - /* - * Signal end of interrupt (EOI) processing - */ - -#ifndef __powerpc__ -void openpic_eoi(void) -#else -void openpic_eoi(u_int cpu) -#endif -{ - check_arg_cpu(cpu); - openpic_write(&OpenPIC->THIS_CPU.EOI, 0); -} - - - /* - * Get/set the current task priority - */ - -#ifndef __powerpc__ -u_int openpic_get_priority(void) -#else -u_int openpic_get_priority(u_int cpu) -#endif -{ - CHECK_THIS_CPU; - return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority, - OPENPIC_CURRENT_TASK_PRIORITY_MASK); -} - -#ifndef __powerpc__ -void openpic_set_priority(u_int pri) -#else -void openpic_set_priority(u_int cpu, u_int pri) -#endif -{ - CHECK_THIS_CPU; - check_arg_pri(pri); - openpic_writefield(&OpenPIC->THIS_CPU.Current_Task_Priority, - OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri); -} - - /* - * Get/set the spurious vector - */ - -u_int openpic_get_spurious(void) -{ - return openpic_readfield(&OpenPIC->Global.Spurious_Vector, - OPENPIC_VECTOR_MASK); -} - -void openpic_set_spurious(u_int vec) -{ - check_arg_vec(vec); - openpic_writefield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK, - vec); -} - - - /* - * Initialize one or more CPUs - */ - -void openpic_init_processor(u_int cpumask) -{ - openpic_write(&OpenPIC->Global.Processor_Initialization, cpumask); -} - - -/* -------- Interprocessor Interrupts -------------------------------------- */ - - - /* - * Initialize an interprocessor interrupt (and disable it) - * - * ipi: OpenPIC interprocessor interrupt number - * pri: interrupt source priority - * vec: the vector it will produce - */ - -void openpic_initipi(u_int ipi, u_int pri, u_int vec) -{ - check_arg_timer(ipi); - check_arg_pri(pri); - check_arg_vec(vec); - openpic_safe_writefield(&OpenPIC->Global.IPI_Vector_Priority(ipi), - OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK, - (pri << OPENPIC_PRIORITY_SHIFT) | vec); -} - - - /* - * Send an IPI to one or more CPUs - */ - -#ifndef __powerpc__ -void openpic_cause_IPI(u_int ipi, u_int cpumask) -#else -void openpic_cause_IPI(u_int cpu, u_int ipi, u_int cpumask) -#endif -{ - CHECK_THIS_CPU; - check_arg_ipi(ipi); - openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi), cpumask); -} - - -/* -------- Timer Interrupts ----------------------------------------------- */ - - - /* - * Initialize a timer interrupt (and disable it) - * - * timer: OpenPIC timer number - * pri: interrupt source priority - * vec: the vector it will produce - */ - -void openpic_inittimer(u_int timer, u_int pri, u_int vec) -{ - check_arg_timer(timer); - check_arg_pri(pri); - check_arg_vec(vec); - openpic_safe_writefield(&OpenPIC->Global.Timer[timer].Vector_Priority, - OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK, - (pri << OPENPIC_PRIORITY_SHIFT) | vec); -} - - - /* - * Map a timer interrupt to one or more CPUs - */ - -void openpic_maptimer(u_int timer, u_int cpumask) -{ - check_arg_timer(timer); - openpic_write(&OpenPIC->Global.Timer[timer].Destination, cpumask); -} - - -/* -------- Interrupt Sources ---------------------------------------------- */ - - - /* - * Enable/disable an interrupt source - */ - -void openpic_enable_irq(u_int irq) -{ - check_arg_irq(irq); - openpic_clearfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK); -} - -void openpic_disable_irq(u_int irq) -{ - check_arg_irq(irq); - openpic_setfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK); -} - - - /* - * Initialize an interrupt source (and disable it!) - * - * irq: OpenPIC interrupt number - * pri: interrupt source priority - * vec: the vector it will produce - * pol: polarity (1 for positive, 0 for negative) - * sense: 1 for level, 0 for edge - */ - -void openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense) -{ - check_arg_irq(irq); - check_arg_pri(pri); - check_arg_vec(vec); - openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority, - OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK | - OPENPIC_SENSE_POLARITY | OPENPIC_SENSE_LEVEL, - (pri << OPENPIC_PRIORITY_SHIFT) | vec | - (pol ? OPENPIC_SENSE_POLARITY : 0) | - (sense ? OPENPIC_SENSE_LEVEL : 0)); -} - - - /* - * Map an interrupt source to one or more CPUs - */ - -void openpic_mapirq(u_int irq, u_int cpumask) -{ - check_arg_irq(irq); - openpic_write(&OpenPIC->Source[irq].Destination, cpumask); -} - - - /* - * Set the sense for an interrupt source (and disable it!) - * - * sense: 1 for level, 0 for edge - */ - -void openpic_set_sense(u_int irq, int sense) -{ - check_arg_irq(irq); - openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority, - OPENPIC_SENSE_LEVEL, - (sense ? OPENPIC_SENSE_LEVEL : 0)); -} diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index 985abf6e6..2ed0f4a5b 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -1,5 +1,5 @@ /* - * $Id: pci.c,v 1.54 1999/03/18 04:16:04 cort Exp $ + * $Id: pci.c,v 1.60 1999/09/08 03:04:07 cort Exp $ * Common pmac/prep/chrp pci routines. -- Cort */ @@ -22,58 +22,94 @@ #include "pci.h" +static void __init pcibios_claim_resources(struct pci_bus *); + unsigned long isa_io_base = 0; unsigned long isa_mem_base = 0; unsigned long pci_dram_offset = 0; -int pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned char *val) +struct pci_fixup pcibios_fixups[] = { + { 0 } +}; + +int generic_pcibios_read_byte(struct pci_dev *dev, int where, u8 *val) { - return ppc_md.pcibios_read_config_byte(bus,dev_fn,offset,val); + return ppc_md.pcibios_read_config_byte(dev->bus->number,dev->devfn,where,val); } -int pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned short *val) +int generic_pcibios_read_word(struct pci_dev *dev, int where, u16 *val) { - return ppc_md.pcibios_read_config_word(bus,dev_fn,offset,val); + return ppc_md.pcibios_read_config_word(dev->bus->number,dev->devfn,where,val); } -int pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned int *val) +int generic_pcibios_read_dword(struct pci_dev *dev, int where, u32 *val) { - return ppc_md.pcibios_read_config_dword(bus,dev_fn,offset,val); + return ppc_md.pcibios_read_config_dword(dev->bus->number,dev->devfn,where,val); } -int pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned char val) +int generic_pcibios_write_byte(struct pci_dev *dev, int where, u8 val) { - return ppc_md.pcibios_write_config_byte(bus,dev_fn,offset,val); + return ppc_md.pcibios_write_config_byte(dev->bus->number,dev->devfn,where,val); } -int pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned short val) +int generic_pcibios_write_word(struct pci_dev *dev, int where, u16 val) { - return ppc_md.pcibios_write_config_word(bus,dev_fn,offset,val); + return ppc_md.pcibios_write_config_word(dev->bus->number,dev->devfn,where,val); } -int pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, - unsigned char offset, unsigned int val) +int generic_pcibios_write_dword(struct pci_dev *dev, int where, u32 val) { - return ppc_md.pcibios_write_config_dword(bus,dev_fn,offset,val); + return ppc_md.pcibios_write_config_dword(dev->bus->number,dev->devfn,where,val); } -int pcibios_present(void) +struct pci_ops generic_pci_ops = { - return 1; -} + generic_pcibios_read_byte, + generic_pcibios_read_word, + generic_pcibios_read_dword, + generic_pcibios_write_byte, + generic_pcibios_write_word, + generic_pcibios_write_dword +}; void __init pcibios_init(void) { + printk("PCI: Probing PCI hardware\n"); + ioport_resource.end = ~0L; + pci_scan_bus(0, &generic_pci_ops, NULL); + pcibios_claim_resources(pci_root); + if ( ppc_md.pcibios_fixup ) + ppc_md.pcibios_fixup(); } - -void __init pcibios_fixup(void) +static void __init pcibios_claim_resources(struct pci_bus *bus) { - ppc_md.pcibios_fixup(); + struct pci_dev *dev; + int idx; + + while (bus) + { + for (dev=bus->devices; dev; dev=dev->sibling) + { + for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) + { + struct resource *r = &dev->resource[idx]; + struct resource *pr; + if (!r->start) + continue; + pr = pci_find_parent_resource(dev, r); + if (!pr || request_resource(pr, r) < 0) + { + printk(KERN_ERR "PCI: Address space collision on region %d of device %s\n", idx, dev->name); + /* We probably should disable the region, shouldn't we? */ + } + } + } + if (bus->children) + pcibios_claim_resources(bus->children); + bus = bus->next; + } } void __init pcibios_fixup_bus(struct pci_bus *bus) { + if ( ppc_md.pcibios_fixup_bus ) + ppc_md.pcibios_fixup_bus(bus); } char __init *pcibios_setup(char *str) @@ -105,3 +141,8 @@ void __init fix_intr(struct device_node *node, struct pci_dev *dev) } } #endif + +int pcibios_assign_resource(struct pci_dev *pdev, int resource) +{ + return 0; +} diff --git a/arch/ppc/kernel/pci.h b/arch/ppc/kernel/pci.h index 231f1d952..d79eb0f4a 100644 --- a/arch/ppc/kernel/pci.h +++ b/arch/ppc/kernel/pci.h @@ -11,6 +11,18 @@ extern unsigned char *pci_config_data; void fix_intr(struct device_node *node, struct pci_dev *dev); +#if 0 +#define decl_config_access_method(name) \ +struct pci_ops name##_pci_ops = { \ + name##_pcibios_read_config_byte, \ + name##_pcibios_read_config_word, \ + name##_pcibios_read_config_dword, \ + name##_pcibios_write_config_byte, \ + name##_pcibios_write_config_word, \ + name##_pcibios_write_config_dword \ +} +#endif + #define decl_config_access_method(name) \ extern int name##_pcibios_read_config_byte(unsigned char bus, \ unsigned char dev_fn, unsigned char offset, unsigned char *val); \ diff --git a/arch/ppc/kernel/pmac_pci.c b/arch/ppc/kernel/pmac_pci.c index 089169e37..932e7dbb6 100644 --- a/arch/ppc/kernel/pmac_pci.c +++ b/arch/ppc/kernel/pmac_pci.c @@ -17,6 +17,8 @@ #include <linux/delay.h> #include <linux/string.h> #include <linux/init.h> + +#include <asm/init.h> #include <asm/io.h> #include <asm/pgtable.h> #include <asm/prom.h> @@ -315,7 +317,7 @@ int grackle_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, * N.B. we can't use pcibios_*_config_* here because bridges[] * is not initialized yet. */ -__initfunc(static void init_bandit(struct bridge_data *bp)) +static void __init init_bandit(struct bridge_data *bp) { unsigned int vendev, magic; int rev; @@ -360,7 +362,7 @@ __initfunc(static void init_bandit(struct bridge_data *bp)) bp->io_base); } -__initfunc(unsigned long pmac_find_bridges(unsigned long mem_start, unsigned long mem_end)) +unsigned long __init pmac_find_bridges(unsigned long mem_start, unsigned long mem_end) { int bus; struct bridge_data *bridge; @@ -385,7 +387,7 @@ __initfunc(unsigned long pmac_find_bridges(unsigned long mem_start, unsigned lon * "pci" (a MPC106) and no bandit or chaos bridges, and contrariwise, * if we have one or more bandit or chaos bridges, we don't have a MPC106. */ -__initfunc(static void add_bridges(struct device_node *dev, unsigned long *mem_ptr)) +static void __init add_bridges(struct device_node *dev, unsigned long *mem_ptr) { int *bus_range; int len; @@ -442,9 +444,8 @@ __initfunc(static void add_bridges(struct device_node *dev, unsigned long *mem_p } } -__initfunc( -void -pmac_pcibios_fixup(void)) +void __init +pmac_pcibios_fixup(void) { struct pci_dev *dev; @@ -472,9 +473,8 @@ pmac_pcibios_fixup(void)) } } -__initfunc( -void -pmac_setup_pci_ptrs(void)) +void __init +pmac_setup_pci_ptrs(void) { if (find_devices("pci") != 0) { /* looks like a G3 powermac */ diff --git a/arch/ppc/kernel/pmac_pic.c b/arch/ppc/kernel/pmac_pic.c index 6b9d8ca53..f8404cc9a 100644 --- a/arch/ppc/kernel/pmac_pic.c +++ b/arch/ppc/kernel/pmac_pic.c @@ -3,6 +3,8 @@ #include <linux/init.h> #include <linux/sched.h> #include <linux/signal.h> + +#include <asm/init.h> #include <asm/io.h> #include <asm/smp.h> #include <asm/prom.h> @@ -290,8 +292,8 @@ static void __init pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_b } } -__initfunc(void -pmac_pic_init(void)) +void __init +pmac_pic_init(void) { int i; struct device_node *irqctrler; diff --git a/arch/ppc/kernel/pmac_setup.c b/arch/ppc/kernel/pmac_setup.c index ffdc316ed..ac84aa92b 100644 --- a/arch/ppc/kernel/pmac_setup.c +++ b/arch/ppc/kernel/pmac_setup.c @@ -43,6 +43,8 @@ #include <linux/console.h> #include <linux/ide.h> #include <linux/pci.h> + +#include <asm/init.h> #include <asm/prom.h> #include <asm/system.h> #include <asm/pgtable.h> @@ -58,6 +60,7 @@ #include <asm/ide.h> #include <asm/machdep.h> #include <asm/keyboard.h> +#include <asm/dma.h> #include "time.h" #include "local_irq.h" @@ -204,11 +207,12 @@ kdev_t sd_find_target(void *host, int tgt) { Scsi_Disk *dp; int i; - +#ifdef CONFIG_BLK_DEV_SD for (dp = rscsi_disks, i = 0; i < sd_template.dev_max; ++i, ++dp) if (dp->device != NULL && dp->device->host == host && dp->device->id == tgt) return MKDEV_SD(i); +#endif /* CONFIG_BLK_DEV_SD */ return 0; } #endif @@ -225,8 +229,8 @@ pmac_mksound(unsigned int hz, unsigned int ticks) static volatile u32 *sysctrl_regs; -__initfunc(void -pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p)) +void __init +pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p) { struct device_node *cpu; int *fp; @@ -306,7 +310,7 @@ pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p)) /* * Tweak the PCI-PCI bridge chip on the blue & white G3s. */ -__initfunc(static void init_p2pbridge(void)) +static void __init init_p2pbridge(void) { struct device_node *p2pbridge; unsigned char bus, devfn; @@ -328,7 +332,7 @@ __initfunc(static void init_p2pbridge(void)) pcibios_read_config_word(bus, devfn, PCI_BRIDGE_CONTROL, &val); } -__initfunc(static void ohare_init(void)) +static void __init ohare_init(void) { /* * Turn on the L2 cache. @@ -353,8 +357,8 @@ int boot_target; int boot_part; kdev_t boot_dev; -__initfunc(void -pmac_init2(void)) +void __init +pmac_init2(void) { adb_init(); pmac_nvram_init(); @@ -362,8 +366,8 @@ pmac_init2(void)) } #ifdef CONFIG_SCSI -__initfunc(void -note_scsi_host(struct device_node *node, void *host)) +void __init +note_scsi_host(struct device_node *node, void *host) { int l; char *p; @@ -397,7 +401,7 @@ extern int pmac_ide_count; extern struct device_node *pmac_ide_node[]; static int ide_majors[] = { 3, 22, 33, 34, 56, 57, 88, 89 }; -__initfunc(kdev_t find_ide_boot(void)) +kdev_t __init find_ide_boot(void) { char *p; int i, n; @@ -424,7 +428,7 @@ __initfunc(kdev_t find_ide_boot(void)) } #endif /* CONFIG_BLK_DEV_IDE_PMAC */ -__initfunc(void find_boot_device(void)) +void __init find_boot_device(void) { #ifdef CONFIG_SCSI if (boot_host != NULL) { @@ -438,7 +442,7 @@ __initfunc(void find_boot_device(void)) #endif } -/* can't be initfunc - can be called whenever a disk is first accessed */ +/* can't be __init - can be called whenever a disk is first accessed */ __pmac void note_bootable_part(kdev_t dev, int part) { @@ -517,13 +521,13 @@ pmac_halt(void) void pmac_ide_insw(ide_ioreg_t port, void *buf, int ns) { - _insw_ns(port+_IO_BASE, buf, ns); + _insw_ns((unsigned short *)(port+_IO_BASE), buf, ns); } void pmac_ide_outsw(ide_ioreg_t port, void *buf, int ns) { - _outsw_ns(port+_IO_BASE, buf, ns); + _outsw_ns((unsigned short *)(port+_IO_BASE), buf, ns); } int @@ -587,9 +591,9 @@ void pmac_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t #endif #endif -__initfunc(void +void __init pmac_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7)) + unsigned long r6, unsigned long r7) { pmac_setup_pci_ptrs(); diff --git a/arch/ppc/kernel/pmac_support.c b/arch/ppc/kernel/pmac_support.c index 0196c5eb6..b7cd026b6 100644 --- a/arch/ppc/kernel/pmac_support.c +++ b/arch/ppc/kernel/pmac_support.c @@ -5,6 +5,7 @@ #include <linux/stddef.h> #include <linux/reboot.h> #include <linux/nvram.h> +#include <linux/init.h> #include <asm/init.h> #include <asm/ptrace.h> #include <asm/io.h> diff --git a/arch/ppc/kernel/pmac_time.c b/arch/ppc/kernel/pmac_time.c index a54767737..03795efdc 100644 --- a/arch/ppc/kernel/pmac_time.c +++ b/arch/ppc/kernel/pmac_time.c @@ -15,6 +15,8 @@ #include <linux/string.h> #include <linux/mm.h> #include <linux/init.h> + +#include <asm/init.h> #include <asm/adb.h> #include <asm/cuda.h> #include <asm/pmu.h> @@ -91,7 +93,7 @@ int pmac_set_rtc_time(unsigned long nowtime) * Calibrate the decrementer register using VIA timer 1. * This is used both on powermacs and CHRP machines. */ -__initfunc(int via_calibrate_decr(void)) +int __init via_calibrate_decr(void) { struct device_node *vias; volatile unsigned char *via; @@ -168,7 +170,7 @@ static struct notifier_block time_sleep_notifier = { * This was taken from the pmac time_init() when merging the prep/pmac * time functions. */ -__initfunc(void pmac_calibrate_decr(void)) +void __init pmac_calibrate_decr(void) { struct device_node *cpu; int freq, *fp, divisor; diff --git a/arch/ppc/kernel/ppc-stub.c b/arch/ppc/kernel/ppc-stub.c index d7fef0869..b6397daac 100644 --- a/arch/ppc/kernel/ppc-stub.c +++ b/arch/ppc/kernel/ppc-stub.c @@ -1,4 +1,4 @@ -/* $Id: ppc-stub.c,v 1.4 1998/07/28 08:25:01 paulus Exp $ +/* $Id: ppc-stub.c,v 1.6 1999/08/12 22:18:11 cort Exp $ * ppc-stub.c: KGDB support for the Linux kernel. * * adapted from arch/sparc/kernel/sparc-stub.c for the PowerPC @@ -438,13 +438,13 @@ static struct hard_trap_info { 0x400, SIGBUS }, /* instruction bus error */ { 0x500, SIGINT }, /* interrupt */ { 0x600, SIGBUS }, /* alingment */ - { 0x700, SIGILL }, /* reserved instruction or sumpin' */ + { 0x700, SIGTRAP }, /* breakpoint trap */ { 0x800, SIGFPE }, /* fpu unavail */ { 0x900, SIGALRM }, /* decrementer */ { 0xa00, SIGILL }, /* reserved */ { 0xb00, SIGILL }, /* reserved */ { 0xc00, SIGCHLD }, /* syscall */ - { 0xd00, SIGINT }, /* watch */ + { 0xd00, SIGTRAP }, /* single-step/watch */ { 0xe00, SIGFPE }, /* fp assist */ { 0, 0} /* Must be last */ }; @@ -482,8 +482,10 @@ handle_exception (struct pt_regs *regs) } kgdb_active = 1; +#ifdef KGDB_DEBUG printk("kgdb: entering handle_exception; trap [0x%x]\n", (unsigned int)regs->trap); +#endif kgdb_interruptible(0); lock_kernel(); diff --git a/arch/ppc/kernel/ppc_asm.h b/arch/ppc/kernel/ppc_asm.h new file mode 100644 index 000000000..10be7ceab --- /dev/null +++ b/arch/ppc/kernel/ppc_asm.h @@ -0,0 +1,73 @@ +/* + * arch/ppc/kernel/ppc_asm.h + * + * Definitions used by various bits of low-level assembly code on PowerPC. + * + * Copyright (C) 1995-1999 Gary Thomas, Paul Mackerras, Cort Dougan. + * + * This program 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. + */ +#include "ppc_asm.tmpl" +#include "ppc_defs.h" + +/* + * Macros for storing registers into and loading registers from + * exception frames. + */ +#define SAVE_GPR(n, base) stw n,GPR0+4*(n)(base) +#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base) +#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base) +#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base) +#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base) +#define REST_GPR(n, base) lwz n,GPR0+4*(n)(base) +#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base) +#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base) +#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base) +#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base) + +#define SAVE_FPR(n, base) stfd n,THREAD_FPR0+8*(n)(base) +#define SAVE_2FPRS(n, base) SAVE_FPR(n, base); SAVE_FPR(n+1, base) +#define SAVE_4FPRS(n, base) SAVE_2FPRS(n, base); SAVE_2FPRS(n+2, base) +#define SAVE_8FPRS(n, base) SAVE_4FPRS(n, base); SAVE_4FPRS(n+4, base) +#define SAVE_16FPRS(n, base) SAVE_8FPRS(n, base); SAVE_8FPRS(n+8, base) +#define SAVE_32FPRS(n, base) SAVE_16FPRS(n, base); SAVE_16FPRS(n+16, base) +#define REST_FPR(n, base) lfd n,THREAD_FPR0+8*(n)(base) +#define REST_2FPRS(n, base) REST_FPR(n, base); REST_FPR(n+1, base) +#define REST_4FPRS(n, base) REST_2FPRS(n, base); REST_2FPRS(n+2, base) +#define REST_8FPRS(n, base) REST_4FPRS(n, base); REST_4FPRS(n+4, base) +#define REST_16FPRS(n, base) REST_8FPRS(n, base); REST_8FPRS(n+8, base) +#define REST_32FPRS(n, base) REST_16FPRS(n, base); REST_16FPRS(n+16, base) + +#define SYNC \ + sync; \ + isync + +/* This instruction is not implemented on the PPC 603 or 601 */ +#define tlbia \ + li r4,128; \ + mtctr r4; \ + lis r4,KERNELBASE@h; \ +0: tlbie r4; \ + addi r4,r4,0x1000; \ + bdnz 0b + +/* + * On APUS (Amiga PowerPC cpu upgrade board), we don't know the + * physical base address of RAM at compile time. + */ +#define tophys(rd,rs) \ +0: addis rd,rs,-KERNELBASE@h; \ + .section ".vtop_fixup","aw"; \ + .align 1; \ + .long 0b; \ + .previous + +#define tovirt(rd,rs) \ +0: addis rd,rs,KERNELBASE@h; \ + .section ".ptov_fixup","aw"; \ + .align 1; \ + .long 0b; \ + .previous diff --git a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c index a2aab8354..9da8db6e8 100644 --- a/arch/ppc/kernel/ppc_htab.c +++ b/arch/ppc/kernel/ppc_htab.c @@ -1,5 +1,5 @@ /* - * $Id: ppc_htab.c,v 1.26 1998/12/10 00:24:23 cort Exp $ + * $Id: ppc_htab.c,v 1.28 1999/06/27 10:53:32 davem Exp $ * * PowerPC hash table management proc entry. Will show information * about the current hash table and will allow changes to it. diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index 1d1340331..61806f1af 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -1,5 +1,6 @@ #include <linux/config.h> #include <linux/module.h> +#include <linux/threads.h> #include <linux/smp.h> #include <linux/elfcore.h> #include <linux/sched.h> @@ -7,6 +8,7 @@ #include <linux/interrupt.h> #include <linux/vt_kern.h> #include <linux/nvram.h> +#include <linux/spinlock.h> #include <asm/page.h> #include <asm/semaphore.h> @@ -27,7 +29,6 @@ #include <asm/pci-bridge.h> #include <asm/irq.h> #include <asm/feature.h> -#include <asm/spinlock.h> #include <asm/dma.h> #include <asm/machdep.h> @@ -35,7 +36,6 @@ #define EXPORT_SYMTAB_STROPS extern void transfer_to_handler(void); -extern void int_return(void); extern void syscall_trace(void); extern void do_IRQ(struct pt_regs *regs, int isfake); extern void MachineCheckException(struct pt_regs *regs); @@ -53,7 +53,6 @@ EXPORT_SYMBOL(clear_page); EXPORT_SYMBOL(do_signal); EXPORT_SYMBOL(syscall_trace); EXPORT_SYMBOL(transfer_to_handler); -EXPORT_SYMBOL(int_return); EXPORT_SYMBOL(do_IRQ); EXPORT_SYMBOL(init_task_union); EXPORT_SYMBOL(MachineCheckException); @@ -153,11 +152,9 @@ EXPORT_SYMBOL(ppc_ide_md); EXPORT_SYMBOL(start_thread); EXPORT_SYMBOL(kernel_thread); -EXPORT_SYMBOL(__cli); -EXPORT_SYMBOL(__sti); /*EXPORT_SYMBOL(__restore_flags);*/ -EXPORT_SYMBOL(_disable_interrupts); -EXPORT_SYMBOL(_enable_interrupts); +/*EXPORT_SYMBOL(_disable_interrupts); + EXPORT_SYMBOL(_enable_interrupts);*/ EXPORT_SYMBOL(flush_instruction_cache); EXPORT_SYMBOL(_get_PVR); EXPORT_SYMBOL(giveup_fpu); @@ -189,6 +186,7 @@ EXPORT_SYMBOL(pmu_request); EXPORT_SYMBOL(pmu_poll); #ifdef CONFIG_PMAC_PBOOK EXPORT_SYMBOL(sleep_notifier_list); +EXPORT_SYMBOL(pmu_enable_irled); #endif CONFIG_PMAC_PBOOK EXPORT_SYMBOL(abort); EXPORT_SYMBOL(find_devices); @@ -219,3 +217,7 @@ EXPORT_SYMBOL_NOVERS(memcmp); EXPORT_SYMBOL(abs); EXPORT_SYMBOL(device_is_compatible); + +#ifdef CONFIG_VT +EXPORT_SYMBOL(screen_info); +#endif diff --git a/arch/ppc/kernel/prep_nvram.c b/arch/ppc/kernel/prep_nvram.c index e69563c8a..6a352b341 100644 --- a/arch/ppc/kernel/prep_nvram.c +++ b/arch/ppc/kernel/prep_nvram.c @@ -9,6 +9,7 @@ #include <linux/malloc.h> #include <linux/ioport.h> +#include <asm/init.h> #include <asm/segment.h> #include <asm/io.h> #include <asm/processor.h> @@ -57,7 +58,7 @@ void rs_nvram_write_val(int addr, rs_pcNvRAM[addr]=val; } -__initfunc(void init_prep_nvram(void)) +void __init init_prep_nvram(void) { unsigned char *nvp; int i; diff --git a/arch/ppc/kernel/prep_pci.c b/arch/ppc/kernel/prep_pci.c index 63a1e9ddf..78f207a54 100644 --- a/arch/ppc/kernel/prep_pci.c +++ b/arch/ppc/kernel/prep_pci.c @@ -1,5 +1,5 @@ /* - * $Id: prep_pci.c,v 1.35 1999/05/10 23:31:03 cort Exp $ + * $Id: prep_pci.c,v 1.39 1999/08/31 15:42:39 cort Exp $ * PReP pci functions. * Originally by Gary Thomas * rewritten and updated by Cort Dougan (cort@cs.nmt.edu) @@ -13,6 +13,7 @@ #include <linux/init.h> #include <linux/openpic.h> +#include <asm/init.h> #include <asm/byteorder.h> #include <asm/io.h> #include <asm/ptrace.h> @@ -685,7 +686,7 @@ static u_char mvme2600_openpic_initsenses[] __initdata = { int prep_keybd_present = 1; int MotMPIC = 0; -__initfunc(int raven_init(void)) +int __init raven_init(void) { unsigned int devid; unsigned int pci_membase; @@ -788,7 +789,7 @@ struct mot_info { {0x000, 0x00, 0x00, "", NULL, NULL} }; -__initfunc(unsigned long prep_route_pci_interrupts(void)) +unsigned long __init prep_route_pci_interrupts(void) { unsigned char *ibc_pirq = (unsigned char *)0x80800860; unsigned char *ibc_pcicon = (unsigned char *)0x80800840; @@ -976,9 +977,8 @@ __initfunc(unsigned long prep_route_pci_interrupts(void)) return 0; } -__initfunc( -void -prep_pcibios_fixup(void)) +void __init +prep_pcibios_fixup(void) { struct pci_dev *dev; extern unsigned char *Motherboard_map; @@ -1017,17 +1017,17 @@ prep_pcibios_fixup(void)) for ( i = 0 ; i <= 5 ; i++ ) { - if ( dev->base_address[i] > 0x10000000 ) + if ( dev->resource[i].start > 0x10000000 ) { printk("Relocating PCI address %lx -> %lx\n", - dev->base_address[i], - (dev->base_address[i] & 0x00FFFFFF) + dev->resource[i].start, + (dev->resource[i].start & 0x00FFFFFF) | 0x01000000); - dev->base_address[i] = - (dev->base_address[i] & 0x00FFFFFF) | 0x01000000; + dev->resource[i].start = + (dev->resource[i].start & 0x00FFFFFF) | 0x01000000; pci_write_config_dword(dev, PCI_BASE_ADDRESS_0+(i*0x4), - dev->base_address[i] ); + dev->resource[i].start ); } } #if 0 @@ -1044,9 +1044,8 @@ prep_pcibios_fixup(void)) decl_config_access_method(indirect); -__initfunc( -void -prep_setup_pci_ptrs(void)) +void __init +prep_setup_pci_ptrs(void) { PPC_DEVICE *hostbridge; @@ -1055,7 +1054,7 @@ prep_setup_pci_ptrs(void)) { pci_config_address = (unsigned *)0x80000cf8; pci_config_data = (char *)0x80000cfc; - set_config_access_method(indirect); + set_config_access_method(indirect); } else { diff --git a/arch/ppc/kernel/prep_setup.c b/arch/ppc/kernel/prep_setup.c index c99f6bbd7..14cce93bd 100644 --- a/arch/ppc/kernel/prep_setup.c +++ b/arch/ppc/kernel/prep_setup.c @@ -35,6 +35,7 @@ #include <linux/openpic.h> #include <linux/ide.h> +#include <asm/init.h> #include <asm/mmu.h> #include <asm/processor.h> #include <asm/residual.h> @@ -211,8 +212,8 @@ no_l2: return len; } -__initfunc(void -prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)) +void __init +prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p) { extern char cmd_line[]; unsigned char reg; @@ -365,7 +366,7 @@ prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)) * This allows for a faster boot as we do not need to calibrate the * decrementer against another clock. This is important for embedded systems. */ -__initfunc(void prep_res_calibrate_decr(void)) +void __init prep_res_calibrate_decr(void) { int freq, divisor; @@ -386,10 +387,10 @@ __initfunc(void prep_res_calibrate_decr(void)) int calibrate_done = 0; volatile int *done_ptr = &calibrate_done; -__initfunc(void +void __init prep_calibrate_decr_handler(int irq, void *dev, - struct pt_regs *regs)) + struct pt_regs *regs) { unsigned long freq, divisor; static unsigned long t1 = 0, t2 = 0; @@ -412,7 +413,7 @@ prep_calibrate_decr_handler(int irq, } } -__initfunc(void prep_calibrate_decr(void)) +void __init prep_calibrate_decr(void) { unsigned long flags; @@ -437,7 +438,7 @@ __initfunc(void prep_calibrate_decr(void)) /* We use the NVRAM RTC to time a second to calibrate the decrementer. */ -__initfunc(void mk48t59_calibrate_decr(void)) +void __init mk48t59_calibrate_decr(void) { unsigned long freq, divisor; unsigned long t1, t2; @@ -491,7 +492,7 @@ prep_restart(char *cmd) unsigned long i = 10000; - _disable_interrupts(); + __cli(); /* set exception prefix high - to the prom */ _nmask_and_or_msr(0, MSR_IP); @@ -518,7 +519,7 @@ prep_direct_restart(char *cmd) * This will ALWAYS work regardless of port 92 * functionality */ - _disable_interrupts(); + __cli(); __asm__ __volatile__("\n\ mtspr 26, %1 /* SRR0 */ @@ -535,7 +536,7 @@ void prep_halt(void) { unsigned long flags; - _disable_interrupts(); + __cli(); /* set exception prefix high - to the prom */ save_flags( flags ); restore_flags( flags|MSR_IP ); @@ -603,8 +604,8 @@ prep_do_IRQ(struct pt_regs *regs, int cpu, int isfake) ppc_irq_dispatch_handler( regs, irq ); } -__initfunc(void -prep_init_IRQ(void)) +void __init +prep_init_IRQ(void) { int i; @@ -691,8 +692,8 @@ prep_ide_fix_driveid(struct hd_driveid *id) { } -__initfunc(void -prep_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)) +void __init +prep_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) { ide_ioreg_t reg = data_port; int i; @@ -711,9 +712,9 @@ prep_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl } #endif -__initfunc(void +void __init prep_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7)) + unsigned long r6, unsigned long r7) { /* make a copy of residual data */ if ( r3 ) diff --git a/arch/ppc/kernel/prep_time.c b/arch/ppc/kernel/prep_time.c index 5b8873d79..f720841be 100644 --- a/arch/ppc/kernel/prep_time.c +++ b/arch/ppc/kernel/prep_time.c @@ -19,6 +19,7 @@ #include <linux/kernel_stat.h> #include <linux/init.h> +#include <asm/init.h> #include <asm/segment.h> #include <asm/io.h> #include <asm/processor.h> diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c index e39c2f7e0..b6f6415ff 100644 --- a/arch/ppc/kernel/process.c +++ b/arch/ppc/kernel/process.c @@ -1,5 +1,5 @@ /* - * $Id: process.c,v 1.85 1999/05/16 21:27:08 cort Exp $ + * $Id: process.c,v 1.95 1999/08/31 06:54:07 davem Exp $ * * linux/arch/ppc/kernel/process.c * @@ -47,11 +47,13 @@ extern unsigned long _get_SP(void); struct task_struct *last_task_used_math = NULL; static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM(init_mm); -union task_union init_task_union = { INIT_TASK(init_task_union.task) }; +/* this is 16-byte aligned because it has a stack in it */ +union task_union __attribute((aligned(16))) init_task_union = { + INIT_TASK(init_task_union.task) +}; /* only used to get secondary processor up */ struct task_struct *current_set[NR_CPUS] = {&init_task, }; @@ -75,7 +77,7 @@ dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs) { if (regs->msr & MSR_FP) giveup_fpu(current); - memcpy(fpregs, ¤t->tss.fpr[0], sizeof(*fpregs)); + memcpy(fpregs, ¤t->thread.fpr[0], sizeof(*fpregs)); return 1; } @@ -83,7 +85,7 @@ void enable_kernel_fp(void) { #ifdef __SMP__ - if (current->tss.regs && (current->tss.regs->msr & MSR_FP)) + if (current->thread.regs && (current->thread.regs->msr & MSR_FP)) giveup_fpu(current); else giveup_fpu(NULL); /* just enables FP for kernel */ @@ -100,11 +102,11 @@ int check_stack(struct task_struct *tsk) int ret = 0; #if 0 - /* check tss magic */ - if ( tsk->tss.magic != TSS_MAGIC ) + /* check thread magic */ + if ( tsk->thread.magic != THREAD_MAGIC ) { ret |= 1; - printk("tss.magic bad: %08x\n", tsk->tss.magic); + printk("thread.magic bad: %08x\n", tsk->thread.magic); } #endif @@ -112,12 +114,12 @@ int check_stack(struct task_struct *tsk) printk("check_stack(): tsk bad tsk %p\n",tsk); /* check if stored ksp is bad */ - if ( (tsk->tss.ksp > stack_top) || (tsk->tss.ksp < tsk_top) ) + if ( (tsk->thread.ksp > stack_top) || (tsk->thread.ksp < tsk_top) ) { printk("stack out of bounds: %s/%d\n" " tsk_top %08lx ksp %08lx stack_top %08lx\n", tsk->comm,tsk->pid, - tsk_top, tsk->tss.ksp, stack_top); + tsk_top, tsk->thread.ksp, stack_top); ret |= 2; } @@ -159,8 +161,11 @@ void _switch_to(struct task_struct *prev, struct task_struct *new, struct task_struct **last) { - struct thread_struct *new_tss, *old_tss; - int s = _disable_interrupts(); + struct thread_struct *new_thread, *old_thread; + int s; + + __save_flags(s); + __cli(); #if CHECK_STACK check_stack(prev); check_stack(new); @@ -169,7 +174,7 @@ _switch_to(struct task_struct *prev, struct task_struct *new, #ifdef SHOW_TASK_SWITCHES printk("%s/%d -> %s/%d NIP %08lx cpu %d root %x/%x\n", prev->comm,prev->pid, - new->comm,new->pid,new->tss.regs->nip,new->processor, + new->comm,new->pid,new->thread.regs->nip,new->processor, new->fs->root,prev->fs->root); #endif #ifdef __SMP__ @@ -182,16 +187,16 @@ _switch_to(struct task_struct *prev, struct task_struct *new, * every switch, just a save. * -- Cort */ - if (prev->tss.regs && (prev->tss.regs->msr & MSR_FP)) + if (prev->thread.regs && (prev->thread.regs->msr & MSR_FP)) giveup_fpu(prev); prev->last_processor = prev->processor; current_set[smp_processor_id()] = new; #endif /* __SMP__ */ - new_tss = &new->tss; - old_tss = ¤t->tss; - *last = _switch(old_tss, new_tss, new->mm->context); - _enable_interrupts(s); + new_thread = &new->thread; + old_thread = ¤t->thread; + *last = _switch(old_thread, new_thread); + __restore_flags(s); } void show_regs(struct pt_regs * regs) @@ -205,9 +210,9 @@ void show_regs(struct pt_regs * regs) regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0, regs->msr&MSR_IR ? 1 : 0, regs->msr&MSR_DR ? 1 : 0); - printk("TASK = %p[%d] '%s' mm->pgd %p ", - current, current->pid, current->comm, current->mm->pgd); - printk("Last syscall: %ld ", current->tss.last_syscall); + printk("TASK = %p[%d] '%s' ", + current, current->pid, current->comm); + printk("Last syscall: %ld ", current->thread.last_syscall); printk("\nlast math %p", last_task_used_math); #ifdef __SMP__ @@ -272,10 +277,10 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp, if ((childregs->msr & MSR_PR) == 0) childregs->gpr[2] = (unsigned long) p; /* `current' in new task */ childregs->gpr[3] = 0; /* Result from fork() */ - p->tss.regs = childregs; - p->tss.ksp = (unsigned long) childregs - STACK_FRAME_OVERHEAD; - p->tss.ksp -= sizeof(struct pt_regs ) + STACK_FRAME_OVERHEAD; - kregs = (struct pt_regs *)(p->tss.ksp + STACK_FRAME_OVERHEAD); + p->thread.regs = childregs; + p->thread.ksp = (unsigned long) childregs - STACK_FRAME_OVERHEAD; + p->thread.ksp -= sizeof(struct pt_regs ) + STACK_FRAME_OVERHEAD; + kregs = (struct pt_regs *)(p->thread.ksp + STACK_FRAME_OVERHEAD); #ifdef __SMP__ kregs->nip = (unsigned long)ret_from_smpfork; #else @@ -292,7 +297,7 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp, /* Provided stack is in user space */ childregs->gpr[1] = usp; } - p->tss.last_syscall = -1; + p->thread.last_syscall = -1; /* * copy fpu info - assume lazy fpu switch now always @@ -301,11 +306,10 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp, if (regs->msr & MSR_FP) giveup_fpu(current); - memcpy(&p->tss.fpr, ¤t->tss.fpr, sizeof(p->tss.fpr)); - p->tss.fpscr = current->tss.fpscr; + memcpy(&p->thread.fpr, ¤t->thread.fpr, sizeof(p->thread.fpr)); + p->thread.fpscr = current->thread.fpscr; childregs->msr &= ~MSR_FP; - p->processor = 0; #ifdef __SMP__ p->last_processor = NO_PROC_ID; #endif /* __SMP__ */ @@ -363,7 +367,7 @@ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp) shove_aux_table(sp); if (last_task_used_math == current) last_task_used_math = 0; - current->tss.fpscr = 0; + current->thread.fpscr = 0; } asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, @@ -454,7 +458,7 @@ print_backtrace(unsigned long *sp) /* * Low level print for debugging - Cort */ -__initfunc(int ll_printk(const char *fmt, ...)) +int __init ll_printk(const char *fmt, ...) { va_list args; char buf[256]; @@ -483,7 +487,7 @@ void puthex(unsigned long val) prom_print(buf); } -__initfunc(void ll_puts(const char *s)) +void __init ll_puts(const char *s) { int x,y; char *vidmem = (char *)/*(_ISA_MEM_BASE + 0xB8000) */0xD00B8000; diff --git a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c index 9c0efa754..a7859ca9a 100644 --- a/arch/ppc/kernel/prom.c +++ b/arch/ppc/kernel/prom.c @@ -1,5 +1,5 @@ /* - * $Id: prom.c,v 1.60 1999/05/25 01:42:41 cort Exp $ + * $Id: prom.c,v 1.73 1999/09/05 11:56:32 paulus Exp $ * * Procedures for interfacing to the Open Firmware PROM on * Power Macintosh computers. @@ -16,7 +16,10 @@ #include <linux/string.h> #include <linux/init.h> #include <linux/version.h> -#include <asm/spinlock.h> +#include <linux/threads.h> +#include <linux/spinlock.h> + +#include <asm/init.h> #include <asm/prom.h> #include <asm/page.h> #include <asm/processor.h> @@ -25,6 +28,7 @@ #include <asm/smp.h> #include <asm/bootx.h> #include <asm/system.h> +#include <asm/gemini.h> /* * Properties whose value is longer than this get excluded from our @@ -257,6 +261,9 @@ prom_print(const char *msg) } } +unsigned long smp_ibm_chrp_hack __initdata = 0; +unsigned long smp_chrp_cpu_nr __initdata = 1; + /* * We enter here early on, when the Open Firmware prom is still * handling exceptions and the MMU hash table for us. @@ -266,7 +273,7 @@ void prom_init(int r3, int r4, prom_entry pp) { #ifdef CONFIG_SMP - int cpu = 0, i; + int i; phandle node; char type[16], *path; #endif @@ -275,6 +282,11 @@ prom_init(int r3, int r4, prom_entry pp) unsigned long offset = reloc_offset(); int l; char *p, *d; + +#ifdef CONFIG_GEMINI + gemini_prom_init(); + return; +#endif /* CONFIG_GEMINI */ /* check if we're apus, return if we are */ if ( r3 == 0x61707573 ) @@ -502,8 +514,8 @@ prom_init(int r3, int r4, prom_entry pp) return; /* copy the holding pattern code to someplace safe (8M) */ - memcpy( (void *)(8<<20), RELOC(__secondary_hold), 0x10000 ); - for (i = 8<<20; i < ((8<<20)+0x10000); i += 32) + memcpy( (void *)(8<<20), RELOC(__secondary_hold), 0x100 ); + for (i = 8<<20; i < ((8<<20)+0x100); i += 32) { asm volatile("dcbf 0,%0" : : "r" (i) : "memory"); asm volatile("icbi 0,%0" : : "r" (i) : "memory"); @@ -524,17 +536,18 @@ prom_init(int r3, int r4, prom_entry pp) node, path, 255) < 0) continue; /* XXX: hack - don't start cpu 0, this cpu -- Cort */ - if ( cpu++ == 0 ) + if ( smp_chrp_cpu_nr++ == 0 ) continue; + RELOC(smp_ibm_chrp_hack) = 1; prom_print(RELOC("starting cpu ")); prom_print(path); *(unsigned long *)(0x4) = 0; asm volatile("dcbf 0,%0": : "r" (0x4) : "memory"); - call_prom(RELOC("start-cpu"), 3, 0, node, 8<<20, cpu-1); + call_prom(RELOC("start-cpu"), 3, 0, node, 8<<20, smp_chrp_cpu_nr-1); for ( i = 0 ; (i < 10000) && (*(ulong *)(0x4) == (ulong)0); i++ ) ; - if (*(ulong *)(0x4) == (ulong)cpu-1 ) + if (*(ulong *)(0x4) == (ulong)smp_chrp_cpu_nr-1 ) prom_print(RELOC("...ok\n")); else prom_print(RELOC("...failed\n")); @@ -1296,8 +1309,6 @@ print_properties(struct device_node *np) } #endif -spinlock_t rtas_lock = SPIN_LOCK_UNLOCKED; - /* this can be called after setup -- Cort */ __openfirmware int @@ -1328,12 +1339,12 @@ call_rtas(const char *service, int nargs, int nret, for (i = 0; i < nargs; ++i) u.words[i+3] = va_arg(list, unsigned long); va_end(list); + + save_flags(s); + cli(); - s = _disable_interrupts(); - spin_lock(&rtas_lock); enter_rtas((void *)__pa(&u)); - spin_unlock(&rtas_lock); - _enable_interrupts(s); + restore_flags(s); if (nret > 1 && outputs != NULL) for (i = 0; i < nret-1; ++i) outputs[i] = u.words[i+nargs+4]; diff --git a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c index a9b51a78b..3a4e3b797 100644 --- a/arch/ppc/kernel/ptrace.c +++ b/arch/ppc/kernel/ptrace.c @@ -47,7 +47,7 @@ static inline long get_reg(struct task_struct *task, int regno) { if (regno < sizeof(struct pt_regs) / sizeof(unsigned long)) - return ((unsigned long *)task->tss.regs)[regno]; + return ((unsigned long *)task->thread.regs)[regno]; return (0); } @@ -60,8 +60,8 @@ static inline int put_reg(struct task_struct *task, int regno, if (regno <= PT_MQ) { if (regno == PT_MSR) data = (data & MSR_DEBUGCHANGE) - | (task->tss.regs->msr & ~MSR_DEBUGCHANGE); - ((unsigned long *)task->tss.regs)[regno] = data; + | (task->thread.regs->msr & ~MSR_DEBUGCHANGE); + ((unsigned long *)task->thread.regs)[regno] = data; return 0; } return -1; @@ -70,17 +70,18 @@ static inline int put_reg(struct task_struct *task, int regno, static inline void set_single_step(struct task_struct *task) { - struct pt_regs *regs = task->tss.regs; + struct pt_regs *regs = task->thread.regs; regs->msr |= MSR_SE; } static inline void clear_single_step(struct task_struct *task) { - struct pt_regs *regs = task->tss.regs; + struct pt_regs *regs = task->thread.regs; regs->msr &= ~MSR_SE; } +#if 0 /* * This routine gets a long from any process space by following the page * tables. NOTE! You should check that the long isn't on a page boundary, @@ -283,11 +284,13 @@ static int write_long(struct task_struct * tsk, unsigned long addr, put_long(tsk, vma,addr,data); return 0; } +#endif asmlinkage int sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; int ret = -EPERM; + unsigned long flags; lock_kernel(); if (request == PTRACE_TRACEME) { @@ -302,7 +305,10 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) if (pid == 1) /* you may not mess with init */ goto out; ret = -ESRCH; - if (!(child = find_task_by_pid(pid))) + read_lock(&tasklist_lock); + child = find_task_by_pid(pid); + read_unlock(&tasklist_lock); /* FIXME!!! */ + if ( !child ) goto out; ret = -EPERM; if (request == PTRACE_ATTACH) { @@ -322,11 +328,15 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) if (child->flags & PF_PTRACED) goto out; child->flags |= PF_PTRACED; + + write_lock_irqsave(&tasklist_lock, flags); if (child->p_pptr != current) { REMOVE_LINKS(child); child->p_pptr = current; SET_LINKS(child); } + write_unlock_irqrestore(&tasklist_lock, flags); + send_sig(SIGSTOP, child, 1); ret = 0; goto out; @@ -342,22 +352,19 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) goto out; switch (request) { - /* If I and D space are separate, these will need to be fixed. */ + /* when I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: { unsigned long tmp; + int copied; - down(&child->mm->mmap_sem); - ret = read_long(child, addr, &tmp); - up(&child->mm->mmap_sem); - if (ret < 0) + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + ret = -EIO; + if (copied != sizeof(tmp)) goto out; - ret = verify_area(VERIFY_WRITE, (void *) data, sizeof(long)); - if (!ret) - put_user(tmp, (unsigned long *) data); + ret = put_user(tmp,(unsigned long *) data); goto out; } - /* read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { unsigned long tmp; @@ -377,9 +384,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) tmp = get_reg(child, addr); } else if (addr >= PT_FPR0 && addr <= PT_FPSCR) { - if (child->tss.regs->msr & MSR_FP) + if (child->thread.regs->msr & MSR_FP) giveup_fpu(child); - tmp = ((long *)child->tss.fpr)[addr - PT_FPR0]; + tmp = ((long *)child->thread.fpr)[addr - PT_FPR0]; } else ret = -EIO; @@ -391,11 +398,11 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) /* If I and D space are separate, this will have to be fixed. */ case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: - down(&child->mm->mmap_sem); - ret = write_long(child,addr,data); - up(&child->mm->mmap_sem); + ret = 0; + if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) + goto out; + ret = -EIO; goto out; - case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ ret = -EIO; if ((addr & 3) || addr < 0 || addr >= ((PT_FPR0 + 64) << 2)) @@ -412,9 +419,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) goto out; } if (addr >= PT_FPR0 && addr < PT_FPR0 + 64) { - if (child->tss.regs->msr & MSR_FP) + if (child->thread.regs->msr & MSR_FP) giveup_fpu(child); - ((long *)child->tss.fpr)[addr - PT_FPR0] = data; + ((long *)child->thread.fpr)[addr - PT_FPR0] = data; ret = 0; goto out; } @@ -459,9 +466,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) goto out; child->flags &= ~PF_TRACESYS; set_single_step(child); - wake_up_process(child); child->exit_code = data; /* give it a chance to run. */ + wake_up_process(child); ret = 0; goto out; } @@ -473,9 +480,11 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) child->flags &= ~(PF_PTRACED|PF_TRACESYS); wake_up_process(child); child->exit_code = data; + write_lock_irqsave(&tasklist_lock, flags); REMOVE_LINKS(child); child->p_pptr = child->p_opptr; SET_LINKS(child); + write_unlock_irqrestore(&tasklist_lock, flags); /* make sure the single step bit is not set. */ clear_single_step(child); ret = 0; @@ -493,7 +502,6 @@ out: asmlinkage void syscall_trace(void) { - lock_kernel(); if ((current->flags & (PF_PTRACED|PF_TRACESYS)) != (PF_PTRACED|PF_TRACESYS)) goto out; @@ -511,5 +519,4 @@ asmlinkage void syscall_trace(void) current->exit_code = 0; } out: - unlock_kernel(); } diff --git a/arch/ppc/kernel/semaphore.c b/arch/ppc/kernel/semaphore.c new file mode 100644 index 000000000..d630c80dc --- /dev/null +++ b/arch/ppc/kernel/semaphore.c @@ -0,0 +1,139 @@ +/* + * $Id: semaphore.c,v 1.1 1999/08/31 15:11:44 cort Exp $ + * + * PowerPC-specific semaphore code. + * + * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu> + * + * This program 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. + */ + +#include <linux/sched.h> + +#include <asm/semaphore.h> +#include <asm/semaphore-helper.h> + +/* + * Semaphores are implemented using a two-way counter: + * The "count" variable is decremented for each process + * that tries to sleep, while the "waking" variable is + * incremented when the "up()" code goes to wake up waiting + * processes. + * + * Notably, the inline "up()" and "down()" functions can + * efficiently test if they need to do any extra work (up + * needs to do something only if count was negative before + * the increment operation. + * + * waking_non_zero() (from asm/semaphore.h) must execute + * atomically. + * + * When __up() is called, the count was negative before + * incrementing it, and we need to wake up somebody. + * + * This routine adds one to the count of processes that need to + * wake up and exit. ALL waiting processes actually wake up but + * only the one that gets to the "waking" field first will gate + * through and acquire the semaphore. The others will go back + * to sleep. + * + * Note that these functions are only called when there is + * contention on the lock, and as such all this is the + * "non-critical" part of the whole semaphore business. The + * critical part is the inline stuff in <asm/semaphore.h> + * where we want to avoid any extra jumps and calls. + */ +void __up(struct semaphore *sem) +{ + wake_one_more(sem); + wake_up(&sem->wait); +} + +/* + * Perform the "down" function. Return zero for semaphore acquired, + * return negative for signalled out of the function. + * + * If called from __down, the return is ignored and the wait loop is + * not interruptible. This means that a task waiting on a semaphore + * using "down()" cannot be killed until someone does an "up()" on + * the semaphore. + * + * If called from __down_interruptible, the return value gets checked + * upon return. If the return value is negative then the task continues + * with the negative value in the return register (it can be tested by + * the caller). + * + * Either form may be used in conjunction with "up()". + * + */ + +#define DOWN_VAR \ + struct task_struct *tsk = current; \ + wait_queue_t wait; \ + init_waitqueue_entry(&wait, tsk); + +#define DOWN_HEAD(task_state) \ + \ + \ + tsk->state = (task_state); \ + add_wait_queue(&sem->wait, &wait); \ + \ + /* \ + * Ok, we're set up. sem->count is known to be less than zero \ + * so we must wait. \ + * \ + * We can let go the lock for purposes of waiting. \ + * We re-acquire it after awaking so as to protect \ + * all semaphore operations. \ + * \ + * If "up()" is called before we call waking_non_zero() then \ + * we will catch it right away. If it is called later then \ + * we will have to go through a wakeup cycle to catch it. \ + * \ + * Multiple waiters contend for the semaphore lock to see \ + * who gets to gate through and who has to wait some more. \ + */ \ + for (;;) { + +#define DOWN_TAIL(task_state) \ + tsk->state = (task_state); \ + } \ + tsk->state = TASK_RUNNING; \ + remove_wait_queue(&sem->wait, &wait); + +void __down(struct semaphore * sem) +{ + DOWN_VAR + DOWN_HEAD(TASK_UNINTERRUPTIBLE) + if (waking_non_zero(sem)) + break; + schedule(); + DOWN_TAIL(TASK_UNINTERRUPTIBLE) +} + +int __down_interruptible(struct semaphore * sem) +{ + int ret = 0; + DOWN_VAR + DOWN_HEAD(TASK_INTERRUPTIBLE) + + ret = waking_non_zero_interruptible(sem, tsk); + if (ret) + { + if (ret == 1) + /* ret != 0 only if we get interrupted -arca */ + ret = 0; + break; + } + schedule(); + DOWN_TAIL(TASK_INTERRUPTIBLE) + return ret; +} + +int __down_trylock(struct semaphore * sem) +{ + return waking_non_zero_trylock(sem); +} diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index f3d2b9039..8015b8d30 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -1,5 +1,5 @@ /* - * $Id: setup.c,v 1.133 1999/05/14 07:24:30 davem Exp $ + * $Id: setup.c,v 1.148 1999/09/05 11:56:34 paulus Exp $ * Common prep/pmac/chrp boot and setup code. */ @@ -12,6 +12,7 @@ #include <linux/delay.h> #include <linux/blk.h> +#include <asm/init.h> #include <asm/adb.h> #include <asm/cuda.h> #include <asm/pmu.h> @@ -63,6 +64,12 @@ extern void apus_init(unsigned long r3, unsigned long r6, unsigned long r7); +extern void gemini_init(unsigned long r3, + unsigned long r4, + unsigned long r5, + unsigned long r6, + unsigned long r7); + extern boot_infos_t *boot_infos; extern char cmd_line[512]; char saved_command_line[256]; @@ -121,11 +128,11 @@ struct screen_info screen_info = { /* * I really need to add multiple-console support... -- Cort */ -__initfunc(int pmac_display_supported(char *name)) +int __init pmac_display_supported(char *name) { return 0; } -__initfunc(void pmac_find_display(void)) +void __init pmac_find_display(void) { } @@ -267,6 +274,17 @@ int get_cpuinfo(char *buffer) cpu_node = find_type_devices("cpu"); if ( !cpu_node ) break; + { + int s; + for ( s = 0; (s < i) && cpu_node->next ; + s++, cpu_node = cpu_node->next ) + /* nothing */ ; +#if 0 /* SMP Pmacs don't have all cpu nodes -- Cort */ + if ( s != i ) + printk("get_cpuinfo(): ran out of " + "cpu nodes.\n"); +#endif + } fp = (int *) get_property(cpu_node, "clock-frequency", NULL); if ( !fp ) break; len += sprintf(len+buffer, "clock\t\t: %dMHz\n", @@ -327,10 +345,10 @@ unsigned long __init identify_machine(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) { - #ifdef __SMP__ if ( first_cpu_booted ) return 0; #endif /* __SMP__ */ + if ( ppc_md.progress ) ppc_md.progress("id mach(): start", 0x100); #ifndef CONFIG_MACH_SPECIFIC /* boot loader will tell us if we're APUS */ @@ -391,6 +409,8 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5, _machine = _MACH_fads; #elif defined(CONFIG_APUS) _machine = _MACH_apus; +#elif defined(CONFIG_GEMINI) + _machine = _MACH_gemini; #else #error "Machine not defined correctly" #endif /* CONFIG_APUS */ @@ -474,16 +494,19 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5, mbx_init(r3, r4, r5, r6, r7); break; #endif + case _MACH_gemini: + gemini_init(r3, r4, r5, r6, r7); + break; default: printk("Unknown machine type in identify_machine!\n"); } - /* Check for nobats option (used in mapin_ram). */ if (strstr(cmd_line, "nobats")) { extern int __map_without_bats; __map_without_bats = 1; } - + + if ( ppc_md.progress ) ppc_md.progress("id mach(): done", 0x200); return 0; } @@ -499,16 +522,18 @@ void ppc_setup_l2cr(char *str, int *ints) } } -__initfunc(void - ppc_init(void)) +void __init ppc_init(void) { + /* clear the progress line */ + if ( ppc_md.progress ) ppc_md.progress(" ", 0xffff); + if (ppc_md.init != NULL) { ppc_md.init(); } } -__initfunc(void setup_arch(char **cmdline_p, - unsigned long * memory_start_p, unsigned long * memory_end_p)) +void __init setup_arch(char **cmdline_p, + unsigned long * memory_start_p, unsigned long * memory_end_p) { extern int panic_timeout; extern char _etext[], _edata[]; @@ -525,11 +550,11 @@ __initfunc(void setup_arch(char **cmdline_p, /* reboot on panic */ panic_timeout = 180; - - init_task.mm->start_code = PAGE_OFFSET; - init_task.mm->end_code = (unsigned long) _etext; - init_task.mm->end_data = (unsigned long) _edata; - init_task.mm->brk = (unsigned long) klimit; + + init_mm.start_code = PAGE_OFFSET; + init_mm.end_code = (unsigned long) _etext; + init_mm.end_data = (unsigned long) _edata; + init_mm.brk = (unsigned long) klimit; /* Save unparsed command line copy for /proc/cmdline */ strcpy(saved_command_line, cmd_line); @@ -539,6 +564,8 @@ __initfunc(void setup_arch(char **cmdline_p, *memory_end_p = (unsigned long) end_of_DRAM; ppc_md.setup_arch(memory_start_p, memory_end_p); + /* clear the progress line */ + if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab); } void ppc_generic_ide_fix_driveid(struct hd_driveid *id) diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c index 67dfa437c..0d55bcefc 100644 --- a/arch/ppc/kernel/signal.c +++ b/arch/ppc/kernel/signal.c @@ -1,7 +1,7 @@ /* * linux/arch/ppc/kernel/signal.c * - * $Id: signal.c,v 1.24 1999/04/03 11:25:16 paulus Exp $ + * $Id: signal.c,v 1.27 1999/08/03 19:16:38 cort Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -227,7 +227,7 @@ int sys_sigreturn(struct pt_regs *regs) | (saved_regs[PT_MSR] & MSR_USERCHANGE); memcpy(regs, saved_regs, GP_REGS_SIZE); - if (copy_from_user(current->tss.fpr, &sr->fp_regs, + if (copy_from_user(current->thread.fpr, &sr->fp_regs, sizeof(sr->fp_regs))) goto badframe; @@ -269,7 +269,7 @@ setup_frame(struct pt_regs *regs, struct sigregs *frame, if (regs->msr & MSR_FP) giveup_fpu(current); if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE) - || __copy_to_user(&frame->fp_regs, current->tss.fpr, + || __copy_to_user(&frame->fp_regs, current->thread.fpr, ELF_NFPREG * sizeof(double)) || __put_user(0x38007777UL, &frame->tramp[0]) /* li r0,0x7777 */ || __put_user(0x44000002UL, &frame->tramp[1])) /* sc */ @@ -444,12 +444,8 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: - lock_kernel(); - if (current->binfmt - && current->binfmt->core_dump - && current->binfmt->core_dump(signr, regs)) + if (do_coredump(signr, regs)) exit_code |= 0x80; - unlock_kernel(); /* FALLTHRU */ default: diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c index a22275135..3d2fb057f 100644 --- a/arch/ppc/kernel/smp.c +++ b/arch/ppc/kernel/smp.c @@ -1,5 +1,5 @@ /* - * $Id: smp.c,v 1.52 1999/05/23 22:43:51 cort Exp $ + * $Id: smp.c,v 1.62 1999/09/05 11:56:34 paulus Exp $ * * Smp support for ppc. * @@ -12,7 +12,6 @@ #include <linux/kernel.h> #include <linux/sched.h> -#include <linux/tasks.h> #include <linux/smp.h> #include <linux/smp_lock.h> #include <linux/interrupt.h> @@ -22,18 +21,19 @@ #include <linux/unistd.h> #include <linux/init.h> #include <linux/openpic.h> +#include <linux/spinlock.h> #include <asm/ptrace.h> #include <asm/atomic.h> #include <asm/irq.h> #include <asm/page.h> #include <asm/pgtable.h> -#include <asm/spinlock.h> #include <asm/hardirq.h> #include <asm/softirq.h> #include <asm/init.h> #include <asm/io.h> #include <asm/prom.h> +#include <asm/smp.h> #include "time.h" int first_cpu_booted = 0; @@ -242,6 +242,7 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait) void __init smp_boot_cpus(void) { extern struct task_struct *current_set[NR_CPUS]; + extern unsigned long smp_chrp_cpu_nr; extern void __secondary_start_psurge(void); extern void __secondary_start_chrp(void); int i, cpu_nr; @@ -252,16 +253,18 @@ void __init smp_boot_cpus(void) /* let other processors know to not do certain initialization */ first_cpu_booted = 1; smp_num_cpus = 1; - + smp_store_cpu_info(0); + /* * assume for now that the first cpu booted is * cpu 0, the master -- Cort */ cpu_callin_map[0] = 1; - smp_store_cpu_info(0); active_kernel_processor = 0; current->processor = 0; + init_idle(); + for (i = 0; i < NR_CPUS; i++) { prof_counter[i] = 1; prof_multiplier[i] = 1; @@ -286,9 +289,13 @@ void __init smp_boot_cpus(void) cpu_nr = 2; break; case _MACH_chrp: + /* openpic doesn't report # of cpus, just # possible -- Cort */ +#if 0 cpu_nr = ((openpic_read(&OpenPIC->Global.Feature_Reporting0) & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >> OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT)+1; +#endif + cpu_nr = smp_chrp_cpu_nr; break; } @@ -299,12 +306,21 @@ void __init smp_boot_cpus(void) for ( i = 1 ; i < cpu_nr; i++ ) { int c; + struct pt_regs regs; + struct task_struct *idle; /* create a process for the processor */ - kernel_thread(start_secondary, NULL, CLONE_PID); - p = task[i]; - if ( !p ) - panic("No idle task for secondary processor\n"); + /* we don't care about the values in regs since we'll + never reschedule the forked task. */ + if (do_fork(CLONE_VM|CLONE_PID, 0, ®s) < 0) + panic("failed fork for CPU %d", i); + p = init_task.prev_task; + if (!p) + panic("No idle task for CPU %d", i); + del_from_runqueue(p); + unhash_process(p); + init_tasks[i] = p; + p->processor = i; p->has_cpu = 1; current_set[i] = p; @@ -324,6 +340,7 @@ void __init smp_boot_cpus(void) eieio(); /* interrupt secondary to begin executing code */ out_be32(PSURGE_INTR, ~0); + udelay(1); out_be32(PSURGE_INTR, 0); break; case _MACH_chrp: @@ -380,6 +397,7 @@ void __init smp_commence(void) /* * Lets the callin's below out of their loop. */ + wmb(); smp_commenced = 1; } @@ -389,8 +407,10 @@ void __init initialize_secondary(void) } /* Activate a secondary processor. */ -asmlinkage int __init start_secondary(void *unused) +int __init start_secondary(void *unused) { + atomic_inc(&init_mm.mm_count); + current->active_mm = &init_mm; smp_callin(); return cpu_idle(NULL); } @@ -403,7 +423,7 @@ void __init smp_callin(void) #if 0 current->mm->mmap->vm_page_prot = PAGE_SHARED; current->mm->mmap->vm_start = PAGE_OFFSET; - current->mm->mmap->vm_end = init_task.mm->mmap->vm_end; + current->mm->mmap->vm_end = init_mm.mmap->vm_end; #endif cpu_callin_map[current->processor] = 1; while(!smp_commenced) diff --git a/arch/ppc/kernel/softemu8xx.c b/arch/ppc/kernel/softemu8xx.c index 64f954b2e..a97c272d3 100644 --- a/arch/ppc/kernel/softemu8xx.c +++ b/arch/ppc/kernel/softemu8xx.c @@ -64,7 +64,7 @@ Soft_emulate_8xx(struct pt_regs *regs) disp = instword & 0xffff; ea = (uint *)(regs->gpr[idxreg] + disp); - ip = (uint *)¤t->tss.fpr[flreg]; + ip = (uint *)¤t->thread.fpr[flreg]; switch ( inst ) { @@ -108,7 +108,7 @@ Soft_emulate_8xx(struct pt_regs *regs) break; case FMR: /* assume this is a fp move -- Cort */ - memcpy( ip, ¤t->tss.fpr[(instword>>11)&0x1f], + memcpy( ip, ¤t->thread.fpr[(instword>>11)&0x1f], sizeof(double) ); break; default: diff --git a/arch/ppc/kernel/syscalls.c b/arch/ppc/kernel/syscalls.c index 571b36391..30bed889b 100644 --- a/arch/ppc/kernel/syscalls.c +++ b/arch/ppc/kernel/syscalls.c @@ -37,6 +37,7 @@ #include <asm/uaccess.h> #include <asm/ipc.h> +#include <asm/semaphore.h> void check_bugs(void) diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c index 5990dad90..d38fa7a22 100644 --- a/arch/ppc/kernel/time.c +++ b/arch/ppc/kernel/time.c @@ -1,5 +1,5 @@ /* - * $Id: time.c,v 1.48 1999/05/22 19:35:57 cort Exp $ + * $Id: time.c,v 1.55 1999/08/31 06:54:09 davem Exp $ * Common time routines among all ppc machines. * * Written by Cort Dougan (cort@cs.nmt.edu) to merge @@ -52,7 +52,7 @@ void smp_local_timer_interrupt(struct pt_regs *); /* keep track of when we need to update the rtc */ -unsigned long last_rtc_update = 0; +time_t last_rtc_update = 0; /* The decrementer counts down by 128 every 128ns on a 601. */ #define DECREMENTER_COUNT_601 (1000000000 / HZ) @@ -110,15 +110,15 @@ void timer_interrupt(struct pt_regs * regs) /* * update the rtc when needed */ - if ( xtime.tv_sec > last_rtc_update + 660 ) + if ( (time_status & STA_UNSYNC) && + ((xtime.tv_sec > last_rtc_update + 60) || + (xtime.tv_sec < last_rtc_update)) ) { - if (ppc_md.set_rtc_time(xtime.tv_sec) == 0) { + if (ppc_md.set_rtc_time(xtime.tv_sec) == 0) last_rtc_update = xtime.tv_sec; - } - else { + else /* do it again in 60 s */ - last_rtc_update = xtime.tv_sec - 60; - } + last_rtc_update = xtime.tv_sec; } } } @@ -176,7 +176,7 @@ void do_settimeofday(struct timeval *tv) } -__initfunc(void time_init(void)) +void __init time_init(void) { if (ppc_md.time_init != NULL) { @@ -196,10 +196,8 @@ __initfunc(void time_init(void)) xtime.tv_usec = 0; set_dec(decrementer_count); - /* mark the rtc/on-chip timer as in sync - * so we don't update right away - */ - last_rtc_update = xtime.tv_sec; + /* allow setting the time right away */ + last_rtc_update = 0; } /* Converts Gregorian date to seconds since 1970-01-01 00:00:00. diff --git a/arch/ppc/kernel/time.h b/arch/ppc/kernel/time.h index a1c912308..a0a5c62d2 100644 --- a/arch/ppc/kernel/time.h +++ b/arch/ppc/kernel/time.h @@ -1,5 +1,5 @@ /* - * $Id: time.h,v 1.11 1999/03/18 04:16:34 cort Exp $ + * $Id: time.h,v 1.12 1999/08/27 04:21:23 cort Exp $ * Common time prototypes and such for all ppc machines. * * Written by Cort Dougan (cort@cs.nmt.edu) to merge @@ -15,7 +15,7 @@ extern unsigned count_period_den; extern unsigned long mktime(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); extern void to_tm(int tim, struct rtc_time * tm); -extern unsigned long last_rtc_update; +extern time_t last_rtc_update; int via_calibrate_decr(void); diff --git a/arch/ppc/kernel/totalmp.c b/arch/ppc/kernel/totalmp.c index 5f87755a7..ecbc04b57 100644 --- a/arch/ppc/kernel/totalmp.c +++ b/arch/ppc/kernel/totalmp.c @@ -1,5 +1,5 @@ /* - * $Id: totalmp.c,v 1.5 1998/08/26 13:58:50 cort Exp $ + * $Id: totalmp.c,v 1.6 1999/08/31 06:54:10 davem Exp $ * * Support for Total Impact's TotalMP PowerPC accelerator board. * @@ -25,7 +25,7 @@ extern void totalmp_init(void); extern inline void openpic_writefield(volatile u_int *addr, u_int mask, u_int field); -__initfunc(void totalmp_init(void)) +void __init totalmp_init(void) { struct pci_dev *dev; u32 val; diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index c33bff3e0..70eafd317 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -229,26 +229,26 @@ trace_syscall(struct pt_regs *regs) void SoftwareEmulation(struct pt_regs *regs) { - int errcode; - extern int Soft_emulate_8xx (struct pt_regs *regs); - extern void print_8xx_pte(struct mm_struct *, unsigned long); + extern int do_mathemu(struct pt_regs *); + int errcode; - if (user_mode(regs)) - { - if ((errcode = Soft_emulate_8xx(regs))) { -printk("Software Emulation %s/%d NIP: %lx *NIP: 0x%x code: %x", - current->comm,current->pid, - regs->nip, *((uint *)regs->nip), errcode); -/*print_8xx_pte(current->mm, regs->nip);*/ - if (errcode == EFAULT) - _exception(SIGBUS, regs); - else - _exception(SIGILL, regs); - } - } - else { + if (!user_mode(regs)) { + show_regs(regs); +#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) + debugger(regs); +#endif + print_backtrace((unsigned long *)regs->gpr[1]); panic("Kernel Mode Software FPU Emulation"); } + + if ((errcode = do_mathemu(regs))) { + if (errcode > 0) + _exception(SIGFPE, regs); + else if (errcode == -EFAULT; + _exception(SIGSEGV, regs); + else + _exception(SIGILL, regs); + } } #endif @@ -259,6 +259,6 @@ TAUException(struct pt_regs *regs) regs->nip, regs->msr, regs->trap); } -__initfunc(void trap_init(void)) +void __init trap_init(void) { } diff --git a/arch/ppc/lib/locks.c b/arch/ppc/lib/locks.c index 699c13fad..d6b56dc5f 100644 --- a/arch/ppc/lib/locks.c +++ b/arch/ppc/lib/locks.c @@ -1,5 +1,5 @@ /* - * $Id: locks.c,v 1.23 1999/02/12 07:06:32 cort Exp $ + * $Id: locks.c,v 1.24 1999/08/03 19:16:47 cort Exp $ * * Locks for smp ppc * @@ -10,9 +10,9 @@ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/delay.h> +#include <linux/spinlock.h> #include <asm/processor.h> #include <asm/system.h> -#include <asm/spinlock.h> #include <asm/io.h> #define DEBUG_LOCKS 1 @@ -113,7 +113,7 @@ void _read_unlock(rwlock_t *rw) #ifdef DEBUG_LOCKS if ( rw->lock == 0 ) printk("_read_unlock(): %s/%d (nip %08lX) lock %lx\n", - current->comm,current->pid,current->tss.regs->nip, + current->comm,current->pid,current->thread.regs->nip, rw->lock); #endif /* DEBUG_LOCKS */ wmb(); @@ -173,7 +173,7 @@ void _write_unlock(rwlock_t *rw) #ifdef DEBUG_LOCKS if ( !(rw->lock & (1<<31)) ) printk("_write_lock(): %s/%d (nip %08lX) lock %lx\n", - current->comm,current->pid,current->tss.regs->nip, + current->comm,current->pid,current->thread.regs->nip, rw->lock); #endif /* DEBUG_LOCKS */ wmb(); @@ -189,7 +189,7 @@ void __lock_kernel(struct task_struct *task) if ( (signed long)(task->lock_depth) < 0 ) { printk("__lock_kernel(): %s/%d (nip %08lX) lock depth %x\n", - task->comm,task->pid,task->tss.regs->nip, + task->comm,task->pid,task->thread.regs->nip, task->lock_depth); } #endif /* DEBUG_LOCKS */ @@ -219,7 +219,7 @@ void __unlock_kernel(struct task_struct *task) { printk("__unlock_kernel(): %s/%d (nip %08lX) " "lock depth %x flags %lx\n", - task->comm,task->pid,task->tss.regs->nip, + task->comm,task->pid,task->thread.regs->nip, task->lock_depth, klock_info.kernel_flag); klock_info.akp = NO_PROC_ID; klock_info.kernel_flag = 0; diff --git a/arch/ppc/math-emu/Makefile b/arch/ppc/math-emu/Makefile new file mode 100644 index 000000000..c9a54944c --- /dev/null +++ b/arch/ppc/math-emu/Makefile @@ -0,0 +1,20 @@ +# +# +# + +O_TARGET := math-emu.o + +O_OBJS := math.o fmr.o lfd.o stfd.o + +ifdef CONFIG_MATH_EMULATION +O_OBJS += fabs.o fadd.o fadds.o fcmpo.o fcmpu.o fctiw.o fctiwz.o \ + fdiv.o fdivs.o fmadd.o fmadds.o fmsub.o fmsubs.o \ + fmul.o fmuls.o fnabs.o fneg.o fnmadd.o fnmadds.o \ + fnmsub.o fnmsubs.o fres.o frsp.o frsqrte.o fsel.o \ + fsqrt.o fsqrts.o fsub.o fsubs.o lfs.o \ + mcrfs.o mffs.o mtfsb0.o mtfsb1.o mtfsf.o mtfsfi.o \ + stfiwx.o stfs.o udivmodti4.o types.o +endif + +include $(TOPDIR)/Rules.make + diff --git a/arch/ppc/math-emu/double.h b/arch/ppc/math-emu/double.h new file mode 100644 index 000000000..ffba8b67f --- /dev/null +++ b/arch/ppc/math-emu/double.h @@ -0,0 +1,129 @@ +/* + * Definitions for IEEE Double Precision + */ + +#if _FP_W_TYPE_SIZE < 32 +#error "Here's a nickel kid. Go buy yourself a real computer." +#endif + +#if _FP_W_TYPE_SIZE < 64 +#define _FP_FRACTBITS_D (2 * _FP_W_TYPE_SIZE) +#else +#define _FP_FRACTBITS_D _FP_W_TYPE_SIZE +#endif + +#define _FP_FRACBITS_D 53 +#define _FP_FRACXBITS_D (_FP_FRACTBITS_D - _FP_FRACBITS_D) +#define _FP_WFRACBITS_D (_FP_WORKBITS + _FP_FRACBITS_D) +#define _FP_WFRACXBITS_D (_FP_FRACTBITS_D - _FP_WFRACBITS_D) +#define _FP_EXPBITS_D 11 +#define _FP_EXPBIAS_D 1023 +#define _FP_EXPMAX_D 2047 + +#define _FP_QNANBIT_D \ + ((_FP_W_TYPE)1 << ((_FP_FRACBITS_D-2) % _FP_W_TYPE_SIZE)) +#define _FP_IMPLBIT_D \ + ((_FP_W_TYPE)1 << ((_FP_FRACBITS_D-1) % _FP_W_TYPE_SIZE)) +#define _FP_OVERFLOW_D \ + ((_FP_W_TYPE)1 << (_FP_WFRACBITS_D % _FP_W_TYPE_SIZE)) + +#if _FP_W_TYPE_SIZE < 64 + +union _FP_UNION_D +{ + double flt; + struct { +#if __BYTE_ORDER == __BIG_ENDIAN + unsigned sign : 1; + unsigned exp : _FP_EXPBITS_D; + unsigned frac1 : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0) - _FP_W_TYPE_SIZE; + unsigned frac0 : _FP_W_TYPE_SIZE; +#else + unsigned frac0 : _FP_W_TYPE_SIZE; + unsigned frac1 : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0) - _FP_W_TYPE_SIZE; + unsigned exp : _FP_EXPBITS_D; + unsigned sign : 1; +#endif + } bits __attribute__((packed)); +}; + +#define FP_DECL_D(X) _FP_DECL(2,X) +#define FP_UNPACK_RAW_D(X,val) _FP_UNPACK_RAW_2(D,X,val) +#define FP_PACK_RAW_D(val,X) _FP_PACK_RAW_2(D,val,X) + +#define FP_UNPACK_D(X,val) \ + do { \ + _FP_UNPACK_RAW_2(D,X,val); \ + _FP_UNPACK_CANONICAL(D,2,X); \ + } while (0) + +#define FP_PACK_D(val,X) \ + do { \ + _FP_PACK_CANONICAL(D,2,X); \ + _FP_PACK_RAW_2(D,val,X); \ + } while (0) + +#define FP_NEG_D(R,X) _FP_NEG(D,2,R,X) +#define FP_ADD_D(R,X,Y) _FP_ADD(D,2,R,X,Y) +#define FP_SUB_D(R,X,Y) _FP_SUB(D,2,R,X,Y) +#define FP_MUL_D(R,X,Y) _FP_MUL(D,2,R,X,Y) +#define FP_DIV_D(R,X,Y) _FP_DIV(D,2,R,X,Y) +#define FP_SQRT_D(R,X) _FP_SQRT(D,2,R,X) + +#define FP_CMP_D(r,X,Y,un) _FP_CMP(D,2,r,X,Y,un) +#define FP_CMP_EQ_D(r,X,Y) _FP_CMP_EQ(D,2,r,X,Y) + +#define FP_TO_INT_D(r,X,rsz,rsg) _FP_TO_INT(D,2,r,X,rsz,rsg) +#define FP_FROM_INT_D(X,r,rs,rt) _FP_FROM_INT(D,2,X,r,rs,rt) + +#else + +union _FP_UNION_D +{ + double flt; + struct { +#if __BYTE_ORDER == __BIG_ENDIAN + unsigned sign : 1; + unsigned exp : _FP_EXPBITS_D; + unsigned long frac : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0); +#else + unsigned long frac : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0); + unsigned exp : _FP_EXPBITS_D; + unsigned sign : 1; +#endif + } bits __attribute__((packed)); +}; + +#define FP_DECL_D(X) _FP_DECL(1,X) +#define FP_UNPACK_RAW_D(X,val) _FP_UNPACK_RAW_1(D,X,val) +#define FP_PACK_RAW_D(val,X) _FP_PACK_RAW_1(D,val,X) + +#define FP_UNPACK_D(X,val) \ + do { \ + _FP_UNPACK_RAW_1(D,X,val); \ + _FP_UNPACK_CANONICAL(D,1,X); \ + } while (0) + +#define FP_PACK_D(val,X) \ + do { \ + _FP_PACK_CANONICAL(D,1,X); \ + _FP_PACK_RAW_1(D,val,X); \ + } while (0) + +#define FP_NEG_D(R,X) _FP_NEG(D,1,R,X) +#define FP_ADD_D(R,X,Y) _FP_ADD(D,1,R,X,Y) +#define FP_SUB_D(R,X,Y) _FP_SUB(D,1,R,X,Y) +#define FP_MUL_D(R,X,Y) _FP_MUL(D,1,R,X,Y) +#define FP_DIV_D(R,X,Y) _FP_DIV(D,1,R,X,Y) +#define FP_SQRT_D(R,X) _FP_SQRT(D,1,R,X) + +/* The implementation of _FP_MUL_D and _FP_DIV_D should be chosen by + the target machine. */ + +#define FP_CMP_D(r,X,Y,un) _FP_CMP(D,1,r,X,Y,un) +#define FP_CMP_EQ_D(r,X,Y) _FP_CMP_EQ(D,1,r,X,Y) + +#define FP_TO_INT_D(r,X,rsz,rsg) _FP_TO_INT(D,1,r,X,rsz,rsg) +#define FP_FROM_INT_D(X,r,rs,rt) _FP_FROM_INT(D,1,X,r,rs,rt) + +#endif /* W_TYPE_SIZE < 64 */ diff --git a/arch/ppc/math-emu/fabs.c b/arch/ppc/math-emu/fabs.c new file mode 100644 index 000000000..0e68414e1 --- /dev/null +++ b/arch/ppc/math-emu/fabs.c @@ -0,0 +1,21 @@ +/* $Id: fabs.c,v 1.1 1999/08/23 18:59:21 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +int +fabs(u32 *frD, u32 *frB) +{ + frD[0] = frB[0] & 0x7fffffff; + frD[1] = frB[1]; + +#ifdef DEBUG + printk("%s: D %p, B %p: ", __FUNCTION__, frD, frB); + dump_double(frD); + printk("\n"); +#endif + + return 0; +} diff --git a/arch/ppc/math-emu/fadd.c b/arch/ppc/math-emu/fadd.c new file mode 100644 index 000000000..ca2435824 --- /dev/null +++ b/arch/ppc/math-emu/fadd.c @@ -0,0 +1,41 @@ +/* $Id: fadd.c,v 1.1 1999/08/23 18:59:22 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" +#include "double.h" + +int +fadd(void *frD, void *frA, void *frB) +{ + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(R); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); +#endif + + if (A_s != B_s && A_c == FP_CLS_INF && B_c == FP_CLS_INF) + ret |= EFLAG_VXISI; + + FP_ADD_D(R, A, B); + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_D(frD, R)); +} diff --git a/arch/ppc/math-emu/fadds.c b/arch/ppc/math-emu/fadds.c new file mode 100644 index 000000000..b2460dc73 --- /dev/null +++ b/arch/ppc/math-emu/fadds.c @@ -0,0 +1,42 @@ +/* $Id: fadds.c,v 1.1 1999/08/23 18:59:25 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" +#include "double.h" +#include "single.h" + +int +fadds(void *frD, void *frA, void *frB) +{ + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(R); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); +#endif + + if (A_s != B_s && A_c == FP_CLS_INF && B_c == FP_CLS_INF) + ret |= EFLAG_VXISI; + + FP_ADD_D(R, A, B); + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_DS(frD, R)); +} diff --git a/arch/ppc/math-emu/fcmpo.c b/arch/ppc/math-emu/fcmpo.c new file mode 100644 index 000000000..84424b07b --- /dev/null +++ b/arch/ppc/math-emu/fcmpo.c @@ -0,0 +1,49 @@ +/* $Id: fcmpo.c,v 1.1 1999/08/23 18:59:26 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" +#include "double.h" + +int +fcmpo(u32 *ccr, int crfD, void *frA, void *frB) +{ + FP_DECL_D(A); + FP_DECL_D(B); + int code[4] = { (1 << 3), (1 << 1), (1 << 2), (1 << 0) }; + long cmp; + int ret = 0; + +#ifdef DEBUG + printk("%s: %p (%08x) %d %p %p\n", __FUNCTION__, ccr, *ccr, crfD, frA, frB); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); +#endif + + if (A_c == FP_CLS_NAN || B_c == FP_CLS_NAN) + ret |= EFLAG_VXVC; + + FP_CMP_D(cmp, A, B, 2); + cmp = code[(cmp + 1) & 3]; + + __FPU_FPSCR &= ~(0x1f000); + __FPU_FPSCR |= (cmp << 12); + + *ccr &= ~(15 << ((7 - crfD) << 2)); + *ccr |= (cmp << ((7 - crfD) << 2)); + +#ifdef DEBUG + printk("CR: %08x\n", *ccr); +#endif + + return ret; +} diff --git a/arch/ppc/math-emu/fcmpu.c b/arch/ppc/math-emu/fcmpu.c new file mode 100644 index 000000000..f3689b5b5 --- /dev/null +++ b/arch/ppc/math-emu/fcmpu.c @@ -0,0 +1,45 @@ +/* $Id: fcmpu.c,v 1.1 1999/08/23 18:59:28 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" +#include "double.h" + +int +fcmpu(u32 *ccr, int crfD, void *frA, void *frB) +{ + FP_DECL_D(A); + FP_DECL_D(B); + int code[4] = { (1 << 3), (1 << 1), (1 << 2), (1 << 0) }; + long cmp; + +#ifdef DEBUG + printk("%s: %p (%08x) %d %p %p\n", __FUNCTION__, ccr, *ccr, crfD, frA, frB); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); +#endif + + FP_CMP_D(cmp, A, B, 2); + cmp = code[(cmp + 1) & 3]; + + __FPU_FPSCR &= ~(0x1f000); + __FPU_FPSCR |= (cmp << 12); + + *ccr &= ~(15 << ((7 - crfD) << 2)); + *ccr |= (cmp << ((7 - crfD) << 2)); + +#ifdef DEBUG + printk("CR: %08x\n", *ccr); +#endif + + return 0; +} diff --git a/arch/ppc/math-emu/fctiw.c b/arch/ppc/math-emu/fctiw.c new file mode 100644 index 000000000..417a91832 --- /dev/null +++ b/arch/ppc/math-emu/fctiw.c @@ -0,0 +1,28 @@ +/* $Id: fctiw.c,v 1.1 1999/08/23 18:59:30 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" +#include "double.h" + +int +fctiw(u32 *frD, void *frB) +{ + FP_DECL_D(B); + unsigned int r; + + __FP_UNPACK_D(B, frB); + FP_TO_INT_D(r, B, 32, 1); + frD[1] = r; + +#ifdef DEBUG + printk("%s: D %p, B %p: ", __FUNCTION__, frD, frB); + dump_double(frD); + printk("\n"); +#endif + + return 0; +} diff --git a/arch/ppc/math-emu/fctiwz.c b/arch/ppc/math-emu/fctiwz.c new file mode 100644 index 000000000..6e4fbe007 --- /dev/null +++ b/arch/ppc/math-emu/fctiwz.c @@ -0,0 +1,35 @@ +/* $Id: fctiwz.c,v 1.1 1999/08/23 18:59:31 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" +#include "double.h" + +int +fctiwz(u32 *frD, void *frB) +{ + FP_DECL_D(B); + u32 fpscr; + unsigned int r; + + fpscr = __FPU_FPSCR; + __FPU_FPSCR &= ~(3); + __FPU_FPSCR |= FP_RND_ZERO; + + __FP_UNPACK_D(B, frB); + FP_TO_INT_D(r, B, 32, 1); + frD[1] = r; + + __FPU_FPSCR = fpscr; + +#ifdef DEBUG + printk("%s: D %p, B %p: ", __FUNCTION__, frD, frB); + dump_double(frD); + printk("\n"); +#endif + + return 0; +} diff --git a/arch/ppc/math-emu/fdiv.c b/arch/ppc/math-emu/fdiv.c new file mode 100644 index 000000000..8604e4d6f --- /dev/null +++ b/arch/ppc/math-emu/fdiv.c @@ -0,0 +1,56 @@ +/* $Id: fdiv.c,v 1.1 1999/08/23 18:59:33 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" +#include "double.h" + +int +fdiv(void *frD, void *frA, void *frB) +{ + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(R); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); +#endif + + if (A_c == FP_CLS_ZERO && B_c == FP_CLS_ZERO) { + ret |= EFLAG_VXZDZ; +#ifdef DEBUG + printk("%s: FPSCR_VXZDZ raised\n", __FUNCTION__); +#endif + } + if (A_c == FP_CLS_INF && B_c == FP_CLS_INF) { + ret |= EFLAG_VXIDI; +#ifdef DEBUG + printk("%s: FPSCR_VXIDI raised\n", __FUNCTION__); +#endif + } + + if (B_c == FP_CLS_ZERO && A_c != FP_CLS_ZERO) { + ret |= EFLAG_DIVZERO; + if (__FPU_TRAP_P(EFLAG_DIVZERO)) + return ret; + } + FP_DIV_D(R, A, B); + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_D(frD, R)); +} diff --git a/arch/ppc/math-emu/fdivs.c b/arch/ppc/math-emu/fdivs.c new file mode 100644 index 000000000..ee9c5e629 --- /dev/null +++ b/arch/ppc/math-emu/fdivs.c @@ -0,0 +1,58 @@ +/* $Id: fdivs.c,v 1.1 1999/08/23 18:59:35 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" +#include "double.h" +#include "single.h" + +int +fdivs(void *frD, void *frA, void *frB) +{ + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(R); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); +#endif + + if (A_c == FP_CLS_ZERO && B_c == FP_CLS_ZERO) { + ret |= EFLAG_VXZDZ; +#ifdef DEBUG + printk("%s: FPSCR_VXZDZ raised\n", __FUNCTION__); +#endif + } + if (A_c == FP_CLS_INF && B_c == FP_CLS_INF) { + ret |= EFLAG_VXIDI; +#ifdef DEBUG + printk("%s: FPSCR_VXIDI raised\n", __FUNCTION__); +#endif + } + + if (B_c == FP_CLS_ZERO && A_c != FP_CLS_ZERO) { + ret |= EFLAG_DIVZERO; + if (__FPU_TRAP_P(EFLAG_DIVZERO)) + return ret; + } + + FP_DIV_D(R, A, B); + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_DS(frD, R)); +} diff --git a/arch/ppc/math-emu/fmadd.c b/arch/ppc/math-emu/fmadd.c new file mode 100644 index 000000000..c65bd1daa --- /dev/null +++ b/arch/ppc/math-emu/fmadd.c @@ -0,0 +1,51 @@ +/* $Id: fmadd.c,v 1.1 1999/08/23 18:59:36 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" +#include "double.h" + +int +fmadd(void *frD, void *frA, void *frB, void *frC) +{ + FP_DECL_D(R); + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(C); + FP_DECL_D(T); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + __FP_UNPACK_D(C, frC); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); + printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c); +#endif + + if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || + (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) + ret |= EFLAG_VXIMZ; + + FP_MUL_D(T, A, C); + + if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) + ret |= EFLAG_VXISI; + + FP_ADD_D(R, T, B); + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_D(frD, R)); +} diff --git a/arch/ppc/math-emu/fmadds.c b/arch/ppc/math-emu/fmadds.c new file mode 100644 index 000000000..06591212a --- /dev/null +++ b/arch/ppc/math-emu/fmadds.c @@ -0,0 +1,52 @@ +/* $Id: fmadds.c,v 1.1 1999/08/23 18:59:38 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" +#include "double.h" +#include "single.h" + +int +fmadds(void *frD, void *frA, void *frB, void *frC) +{ + FP_DECL_D(R); + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(C); + FP_DECL_D(T); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + __FP_UNPACK_D(C, frC); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); + printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c); +#endif + + if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || + (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) + ret |= EFLAG_VXIMZ; + + FP_MUL_D(T, A, C); + + if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) + ret |= EFLAG_VXISI; + + FP_ADD_D(R, T, B); + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_DS(frD, R)); +} diff --git a/arch/ppc/math-emu/fmr.c b/arch/ppc/math-emu/fmr.c new file mode 100644 index 000000000..1a4de69f7 --- /dev/null +++ b/arch/ppc/math-emu/fmr.c @@ -0,0 +1,21 @@ +/* $Id: fmr.c,v 1.1 1999/08/23 18:59:40 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +int +fmr(u32 *frD, u32 *frB) +{ + frD[0] = frB[0]; + frD[1] = frB[1]; + +#ifdef DEBUG + printk("%s: D %p, B %p: ", __FUNCTION__, frD, frB); + dump_double(frD); + printk("\n"); +#endif + + return 0; +} diff --git a/arch/ppc/math-emu/fmsub.c b/arch/ppc/math-emu/fmsub.c new file mode 100644 index 000000000..3a91ded20 --- /dev/null +++ b/arch/ppc/math-emu/fmsub.c @@ -0,0 +1,54 @@ +/* $Id: fmsub.c,v 1.1 1999/08/23 18:59:41 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" +#include "double.h" + +int +fmsub(void *frD, void *frA, void *frB, void *frC) +{ + FP_DECL_D(R); + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(C); + FP_DECL_D(T); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + __FP_UNPACK_D(C, frC); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); + printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c); +#endif + + if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || + (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) + ret |= EFLAG_VXIMZ; + + FP_MUL_D(T, A, C); + + if (B_c != FP_CLS_NAN) + B_s ^= 1; + + if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) + ret |= EFLAG_VXISI; + + FP_ADD_D(R, T, B); + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_D(frD, R)); +} diff --git a/arch/ppc/math-emu/fmsubs.c b/arch/ppc/math-emu/fmsubs.c new file mode 100644 index 000000000..313857156 --- /dev/null +++ b/arch/ppc/math-emu/fmsubs.c @@ -0,0 +1,55 @@ +/* $Id: fmsubs.c,v 1.1 1999/08/23 18:59:42 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" +#include "double.h" +#include "single.h" + +int +fmsubs(void *frD, void *frA, void *frB, void *frC) +{ + FP_DECL_D(R); + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(C); + FP_DECL_D(T); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + __FP_UNPACK_D(C, frC); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); + printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c); +#endif + + if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || + (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) + ret |= EFLAG_VXIMZ; + + FP_MUL_D(T, A, C); + + if (B_c != FP_CLS_NAN) + B_s ^= 1; + + if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) + ret |= EFLAG_VXISI; + + FP_ADD_D(R, T, B); + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_DS(frD, R)); +} diff --git a/arch/ppc/math-emu/fmul.c b/arch/ppc/math-emu/fmul.c new file mode 100644 index 000000000..e1c542fed --- /dev/null +++ b/arch/ppc/math-emu/fmul.c @@ -0,0 +1,45 @@ +/* $Id: fmul.c,v 1.1 1999/08/23 18:59:44 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" +#include "double.h" + +int +fmul(void *frD, void *frA, void *frB) +{ + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(R); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld) [%08lx.%08lx %lx]\n", + A_s, A_f1, A_f0, A_e, A_c, A_f1, A_f0, A_e + 1023); + printk("B: %ld %lu %lu %ld (%ld) [%08lx.%08lx %lx]\n", + B_s, B_f1, B_f0, B_e, B_c, B_f1, B_f0, B_e + 1023); +#endif + + if ((A_c == FP_CLS_INF && B_c == FP_CLS_ZERO) || + (A_c == FP_CLS_ZERO && B_c == FP_CLS_INF)) + ret |= EFLAG_VXIMZ; + + FP_MUL_D(R, A, B); + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld) [%08lx.%08lx %lx]\n", + R_s, R_f1, R_f0, R_e, R_c, R_f1, R_f0, R_e + 1023); +#endif + + return (ret | __FP_PACK_D(frD, R)); +} diff --git a/arch/ppc/math-emu/fmuls.c b/arch/ppc/math-emu/fmuls.c new file mode 100644 index 000000000..f22839800 --- /dev/null +++ b/arch/ppc/math-emu/fmuls.c @@ -0,0 +1,46 @@ +/* $Id: fmuls.c,v 1.1 1999/08/23 18:59:45 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" +#include "double.h" +#include "single.h" + +int +fmuls(void *frD, void *frA, void *frB) +{ + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(R); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld) [%08lx.%08lx %lx]\n", + A_s, A_f1, A_f0, A_e, A_c, A_f1, A_f0, A_e + 1023); + printk("B: %ld %lu %lu %ld (%ld) [%08lx.%08lx %lx]\n", + B_s, B_f1, B_f0, B_e, B_c, B_f1, B_f0, B_e + 1023); +#endif + + if ((A_c == FP_CLS_INF && B_c == FP_CLS_ZERO) || + (A_c == FP_CLS_ZERO && B_c == FP_CLS_INF)) + ret |= EFLAG_VXIMZ; + + FP_MUL_D(R, A, B); + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld) [%08lx.%08lx %lx]\n", + R_s, R_f1, R_f0, R_e, R_c, R_f1, R_f0, R_e + 1023); +#endif + + return (ret | __FP_PACK_DS(frD, R)); +} diff --git a/arch/ppc/math-emu/fnabs.c b/arch/ppc/math-emu/fnabs.c new file mode 100644 index 000000000..90395c3d2 --- /dev/null +++ b/arch/ppc/math-emu/fnabs.c @@ -0,0 +1,21 @@ +/* $Id: fnabs.c,v 1.1 1999/08/23 18:59:47 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +int +fnabs(u32 *frD, u32 *frB) +{ + frD[0] = frB[0] | 0x80000000; + frD[1] = frB[1]; + +#ifdef DEBUG + printk("%s: D %p, B %p: ", __FUNCTION__, frD, frB); + dump_double(frD); + printk("\n"); +#endif + + return 0; +} diff --git a/arch/ppc/math-emu/fneg.c b/arch/ppc/math-emu/fneg.c new file mode 100644 index 000000000..f5547e3da --- /dev/null +++ b/arch/ppc/math-emu/fneg.c @@ -0,0 +1,21 @@ +/* $Id: fneg.c,v 1.1 1999/08/23 18:59:48 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +int +fneg(u32 *frD, u32 *frB) +{ + frD[0] = frB[0] ^ 0x80000000; + frD[1] = frB[1]; + +#ifdef DEBUG + printk("%s: D %p, B %p: ", __FUNCTION__, frD, frB); + dump_double(frD); + printk("\n"); +#endif + + return 0; +} diff --git a/arch/ppc/math-emu/fnmadd.c b/arch/ppc/math-emu/fnmadd.c new file mode 100644 index 000000000..b519607c3 --- /dev/null +++ b/arch/ppc/math-emu/fnmadd.c @@ -0,0 +1,54 @@ +/* $Id: fnmadd.c,v 1.1 1999/08/23 18:59:50 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" +#include "double.h" + +int +fnmadd(void *frD, void *frA, void *frB, void *frC) +{ + FP_DECL_D(R); + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(C); + FP_DECL_D(T); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + __FP_UNPACK_D(C, frC); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); + printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c); +#endif + + if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || + (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) + ret |= EFLAG_VXIMZ; + + FP_MUL_D(T, A, C); + + if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) + ret |= EFLAG_VXISI; + + FP_ADD_D(R, T, B); + + if (R_c != FP_CLS_NAN) + R_s ^= 1; + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_D(frD, R)); +} diff --git a/arch/ppc/math-emu/fnmadds.c b/arch/ppc/math-emu/fnmadds.c new file mode 100644 index 000000000..28f6a0520 --- /dev/null +++ b/arch/ppc/math-emu/fnmadds.c @@ -0,0 +1,55 @@ +/* $Id: fnmadds.c,v 1.1 1999/08/23 18:59:51 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" +#include "double.h" +#include "single.h" + +int +fnmadds(void *frD, void *frA, void *frB, void *frC) +{ + FP_DECL_D(R); + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(C); + FP_DECL_D(T); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + __FP_UNPACK_D(C, frC); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); + printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c); +#endif + + if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || + (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) + ret |= EFLAG_VXIMZ; + + FP_MUL_D(T, A, C); + + if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) + ret |= EFLAG_VXISI; + + FP_ADD_D(R, T, B); + + if (R_c != FP_CLS_NAN) + R_s ^= 1; + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_DS(frD, R)); +} diff --git a/arch/ppc/math-emu/fnmsub.c b/arch/ppc/math-emu/fnmsub.c new file mode 100644 index 000000000..df8f52af1 --- /dev/null +++ b/arch/ppc/math-emu/fnmsub.c @@ -0,0 +1,57 @@ +/* $Id: fnmsub.c,v 1.1 1999/08/23 18:59:53 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" +#include "double.h" + +int +fnmsub(void *frD, void *frA, void *frB, void *frC) +{ + FP_DECL_D(R); + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(C); + FP_DECL_D(T); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + __FP_UNPACK_D(C, frC); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); + printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c); +#endif + + if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || + (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) + ret |= EFLAG_VXIMZ; + + FP_MUL_D(T, A, C); + + if (B_c != FP_CLS_NAN) + B_s ^= 1; + + if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) + ret |= EFLAG_VXISI; + + FP_ADD_D(R, T, B); + + if (R_c != FP_CLS_NAN) + R_s ^= 1; + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_D(frD, R)); +} diff --git a/arch/ppc/math-emu/fnmsubs.c b/arch/ppc/math-emu/fnmsubs.c new file mode 100644 index 000000000..bb2939aa4 --- /dev/null +++ b/arch/ppc/math-emu/fnmsubs.c @@ -0,0 +1,58 @@ +/* $Id: fnmsubs.c,v 1.1 1999/08/23 18:59:54 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" +#include "double.h" +#include "single.h" + +int +fnmsubs(void *frD, void *frA, void *frB, void *frC) +{ + FP_DECL_D(R); + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(C); + FP_DECL_D(T); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + __FP_UNPACK_D(C, frC); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); + printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c); +#endif + + if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || + (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) + ret |= EFLAG_VXIMZ; + + FP_MUL_D(T, A, C); + + if (B_c != FP_CLS_NAN) + B_s ^= 1; + + if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) + ret |= EFLAG_VXISI; + + FP_ADD_D(R, T, B); + + if (R_c != FP_CLS_NAN) + R_s ^= 1; + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_DS(frD, R)); +} diff --git a/arch/ppc/math-emu/fres.c b/arch/ppc/math-emu/fres.c new file mode 100644 index 000000000..eb0d2fe3b --- /dev/null +++ b/arch/ppc/math-emu/fres.c @@ -0,0 +1,15 @@ +/* $Id: fres.c,v 1.1 1999/08/23 18:59:56 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +int +fres(void *frD, void *frB) +{ +#ifdef DEBUG + printk("%s: %p %p\n", __FUNCTION__, frD, frB); +#endif + return -ENOSYS; +} diff --git a/arch/ppc/math-emu/frsp.c b/arch/ppc/math-emu/frsp.c new file mode 100644 index 000000000..e71e64875 --- /dev/null +++ b/arch/ppc/math-emu/frsp.c @@ -0,0 +1,28 @@ +/* $Id: frsp.c,v 1.1 1999/08/23 18:59:57 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" +#include "double.h" +#include "single.h" + +int +frsp(void *frD, void *frB) +{ + FP_DECL_D(B); + +#ifdef DEBUG + printk("%s: D %p, B %p\n", __FUNCTION__, frD, frB); +#endif + + __FP_UNPACK_D(B, frB); + +#ifdef DEBUG + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); +#endif + + return __FP_PACK_DS(frD, B); +} diff --git a/arch/ppc/math-emu/frsqrte.c b/arch/ppc/math-emu/frsqrte.c new file mode 100644 index 000000000..d14995567 --- /dev/null +++ b/arch/ppc/math-emu/frsqrte.c @@ -0,0 +1,15 @@ +/* $Id: frsqrte.c,v 1.1 1999/08/23 18:59:58 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +int +frsqrte(void *frD, void *frB) +{ +#ifdef DEBUG + printk("%s: %p %p\n", __FUNCTION__, frD, frB); +#endif + return 0; +} diff --git a/arch/ppc/math-emu/fsel.c b/arch/ppc/math-emu/fsel.c new file mode 100644 index 000000000..1ed9b6697 --- /dev/null +++ b/arch/ppc/math-emu/fsel.c @@ -0,0 +1,41 @@ +/* $Id: fsel.c,v 1.1 1999/08/23 18:59:59 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" +#include "double.h" + +int +fsel(u32 *frD, void *frA, u32 *frB, u32 *frC) +{ + FP_DECL_D(A); + +#ifdef DEBUG + printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC); +#endif + + __FP_UNPACK_D(A, frA); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %08x %08x\n", frB[0], frB[1]); + printk("C: %08x %08x\n", frC[0], frC[1]); +#endif + + if (A_c == FP_CLS_NAN || (A_c != FP_CLS_ZERO && A_s)) { + frD[0] = frB[0]; + frD[1] = frB[1]; + } else { + frD[0] = frC[0]; + frD[1] = frC[1]; + } + +#ifdef DEBUG + printk("D: %08x.%08x\n", frD[0], frD[1]); +#endif + + return 0; +} diff --git a/arch/ppc/math-emu/fsqrt.c b/arch/ppc/math-emu/fsqrt.c new file mode 100644 index 000000000..60ab5d03f --- /dev/null +++ b/arch/ppc/math-emu/fsqrt.c @@ -0,0 +1,40 @@ +/* $Id: fsqrt.c,v 1.1 1999/08/23 19:00:01 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" +#include "double.h" + +int +fsqrt(void *frD, void *frB) +{ + FP_DECL_D(B); + FP_DECL_D(R); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frB); +#endif + + __FP_UNPACK_D(B, frB); + +#ifdef DEBUG + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); +#endif + + if (B_s && B_c != FP_CLS_ZERO) + ret |= EFLAG_VXSQRT; + if (B_c == FP_CLS_NAN) + ret |= EFLAG_VXSNAN; + + FP_SQRT_D(R, B); + +#ifdef DEBUG + printk("R: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_D(frD, R)); +} diff --git a/arch/ppc/math-emu/fsqrts.c b/arch/ppc/math-emu/fsqrts.c new file mode 100644 index 000000000..ce21b8066 --- /dev/null +++ b/arch/ppc/math-emu/fsqrts.c @@ -0,0 +1,41 @@ +/* $Id: fsqrts.c,v 1.1 1999/08/23 19:00:03 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" +#include "double.h" +#include "single.h" + +int +fsqrts(void *frD, void *frB) +{ + FP_DECL_D(B); + FP_DECL_D(R); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frB); +#endif + + __FP_UNPACK_D(B, frB); + +#ifdef DEBUG + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); +#endif + + if (B_s && B_c != FP_CLS_ZERO) + ret |= EFLAG_VXSQRT; + if (B_c == FP_CLS_NAN) + ret |= EFLAG_VXSNAN; + + FP_SQRT_D(R, B); + +#ifdef DEBUG + printk("R: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_DS(frD, R)); +} diff --git a/arch/ppc/math-emu/fsub.c b/arch/ppc/math-emu/fsub.c new file mode 100644 index 000000000..963efc7f3 --- /dev/null +++ b/arch/ppc/math-emu/fsub.c @@ -0,0 +1,44 @@ +/* $Id: fsub.c,v 1.1 1999/08/23 19:00:05 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" +#include "double.h" + +int +fsub(void *frD, void *frA, void *frB) +{ + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(R); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); +#endif + + if (B_c != FP_CLS_NAN) + B_s ^= 1; + + if (A_s != B_s && A_c == FP_CLS_INF && B_c == FP_CLS_INF) + ret |= EFLAG_VXISI; + + FP_ADD_D(R, A, B); + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_D(frD, R)); +} diff --git a/arch/ppc/math-emu/fsubs.c b/arch/ppc/math-emu/fsubs.c new file mode 100644 index 000000000..80c808f98 --- /dev/null +++ b/arch/ppc/math-emu/fsubs.c @@ -0,0 +1,45 @@ +/* $Id: fsubs.c,v 1.1 1999/08/23 19:00:07 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" +#include "double.h" +#include "single.h" + +int +fsubs(void *frD, void *frA, void *frB) +{ + FP_DECL_D(A); + FP_DECL_D(B); + FP_DECL_D(R); + int ret = 0; + +#ifdef DEBUG + printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB); +#endif + + __FP_UNPACK_D(A, frA); + __FP_UNPACK_D(B, frB); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); + printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); +#endif + + if (B_c != FP_CLS_NAN) + B_s ^= 1; + + if (A_s != B_s && A_c == FP_CLS_INF && B_c == FP_CLS_INF) + ret |= EFLAG_VXISI; + + FP_ADD_D(R, A, B); + +#ifdef DEBUG + printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return (ret | __FP_PACK_DS(frD, R)); +} diff --git a/arch/ppc/math-emu/lfd.c b/arch/ppc/math-emu/lfd.c new file mode 100644 index 000000000..11eeb5715 --- /dev/null +++ b/arch/ppc/math-emu/lfd.c @@ -0,0 +1,22 @@ +/* $Id: lfd.c,v 1.1 1999/08/23 19:00:08 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "sfp-machine.h" +#include "double.h" + +int +lfd(void *frD, void *ea) +{ + if (copy_from_user(frD, ea, sizeof(double))) + return -EFAULT; +#ifdef DEBUG + printk("%s: D %p, ea %p: ", __FUNCTION__, frD, ea); + dump_double(frD); + printk("\n"); +#endif + return 0; +} diff --git a/arch/ppc/math-emu/lfs.c b/arch/ppc/math-emu/lfs.c new file mode 100644 index 000000000..ac94bd38f --- /dev/null +++ b/arch/ppc/math-emu/lfs.c @@ -0,0 +1,40 @@ +/* $Id: lfs.c,v 1.1 1999/08/23 19:00:10 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" +#include "double.h" +#include "single.h" + +int +lfs(void *frD, void *ea) +{ + FP_DECL_D(R); + FP_DECL_S(A); + float f; + +#ifdef DEBUG + printk("%s: D %p, ea %p\n", __FUNCTION__, frD, ea); +#endif + + if (copy_from_user(&f, ea, sizeof(float))) + return -EFAULT; + + __FP_UNPACK_S(A, &f); + +#ifdef DEBUG + printk("A: %ld %lu %ld (%ld) [%08lx]\n", A_s, A_f, A_e, A_c, + *(unsigned long *)&f); +#endif + + FP_CONV(D, S, 2, 1, R, A); + +#ifdef DEBUG + printk("R: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); +#endif + + return __FP_PACK_D(frD, R); +} diff --git a/arch/ppc/math-emu/math.c b/arch/ppc/math-emu/math.c new file mode 100644 index 000000000..aed5c7062 --- /dev/null +++ b/arch/ppc/math-emu/math.c @@ -0,0 +1,485 @@ +/* $Id: math.c,v 1.1 1999/08/23 19:00:11 cort Exp $ + * arch/ppc/math-emu/math.c + * + * Copyright (C) 1999 Eddie C. Dost (ecd@atecom.com) + */ + +#include <linux/config.h> +#include <linux/types.h> +#include <linux/sched.h> + +#include <asm/uaccess.h> +#include <asm/processor.h> + +#include "sfp-machine.h" +#include "double.h" + +#define FLOATFUNC(x) extern int x(void *, void *, void *, void *) + +FLOATFUNC(fadd); +FLOATFUNC(fadds); +FLOATFUNC(fdiv); +FLOATFUNC(fdivs); +FLOATFUNC(fmul); +FLOATFUNC(fmuls); +FLOATFUNC(fsub); +FLOATFUNC(fsubs); + +FLOATFUNC(fmadd); +FLOATFUNC(fmadds); +FLOATFUNC(fmsub); +FLOATFUNC(fmsubs); +FLOATFUNC(fnmadd); +FLOATFUNC(fnmadds); +FLOATFUNC(fnmsub); +FLOATFUNC(fnmsubs); + +FLOATFUNC(fctiw); +FLOATFUNC(fctiwz); +FLOATFUNC(frsp); + +FLOATFUNC(fcmpo); +FLOATFUNC(fcmpu); + +FLOATFUNC(mcrfs); +FLOATFUNC(mffs); +FLOATFUNC(mtfsb0); +FLOATFUNC(mtfsb1); +FLOATFUNC(mtfsf); +FLOATFUNC(mtfsfi); + +FLOATFUNC(lfd); +FLOATFUNC(lfs); + +FLOATFUNC(stfd); +FLOATFUNC(stfs); +FLOATFUNC(stfiwx); + +FLOATFUNC(fabs); +FLOATFUNC(fmr); +FLOATFUNC(fnabs); +FLOATFUNC(fneg); + +/* Optional */ +FLOATFUNC(fres); +FLOATFUNC(frsqrte); +FLOATFUNC(fsel); +FLOATFUNC(fsqrt); +FLOATFUNC(fsqrts); + + +#define OP31 0x1f /* 31 */ +#define LFS 0x30 /* 48 */ +#define LFSU 0x31 /* 49 */ +#define LFD 0x32 /* 50 */ +#define LFDU 0x33 /* 51 */ +#define STFS 0x34 /* 52 */ +#define STFSU 0x35 /* 53 */ +#define STFD 0x36 /* 54 */ +#define STFDU 0x37 /* 55 */ +#define OP59 0x3b /* 59 */ +#define OP63 0x3f /* 63 */ + +/* Opcode 31: */ +/* X-Form: */ +#define LFSX 0x217 /* 535 */ +#define LFSUX 0x237 /* 567 */ +#define LFDX 0x257 /* 599 */ +#define LFDUX 0x277 /* 631 */ +#define STFSX 0x297 /* 663 */ +#define STFSUX 0x2b7 /* 695 */ +#define STFDX 0x2d7 /* 727 */ +#define STFDUX 0x2f7 /* 759 */ +#define STFIWX 0x3d7 /* 983 */ + +/* Opcode 59: */ +/* A-Form: */ +#define FDIVS 0x012 /* 18 */ +#define FSUBS 0x014 /* 20 */ +#define FADDS 0x015 /* 21 */ +#define FSQRTS 0x016 /* 22 */ +#define FRES 0x018 /* 24 */ +#define FMULS 0x019 /* 25 */ +#define FMSUBS 0x01c /* 28 */ +#define FMADDS 0x01d /* 29 */ +#define FNMSUBS 0x01e /* 30 */ +#define FNMADDS 0x01f /* 31 */ + +/* Opcode 63: */ +/* A-Form: */ +#define FDIV 0x012 /* 18 */ +#define FSUB 0x014 /* 20 */ +#define FADD 0x015 /* 21 */ +#define FSQRT 0x016 /* 22 */ +#define FSEL 0x017 /* 23 */ +#define FMUL 0x019 /* 25 */ +#define FRSQRTE 0x01a /* 26 */ +#define FMSUB 0x01c /* 28 */ +#define FMADD 0x01d /* 29 */ +#define FNMSUB 0x01e /* 30 */ +#define FNMADD 0x01f /* 31 */ + +/* X-Form: */ +#define FCMPU 0x000 /* 0 */ +#define FRSP 0x00c /* 12 */ +#define FCTIW 0x00e /* 14 */ +#define FCTIWZ 0x00f /* 15 */ +#define FCMPO 0x020 /* 32 */ +#define MTFSB1 0x026 /* 38 */ +#define FNEG 0x028 /* 40 */ +#define MCRFS 0x040 /* 64 */ +#define MTFSB0 0x046 /* 70 */ +#define FMR 0x048 /* 72 */ +#define MTFSFI 0x086 /* 134 */ +#define FNABS 0x088 /* 136 */ +#define FABS 0x108 /* 264 */ +#define MFFS 0x247 /* 583 */ +#define MTFSF 0x2c7 /* 711 */ + + +#define AB 2 +#define AC 3 +#define ABC 4 +#define D 5 +#define DU 6 +#define X 7 +#define XA 8 +#define XB 9 +#define XCR 11 +#define XCRB 12 +#define XCRI 13 +#define XCRL 16 +#define XE 14 +#define XEU 15 +#define XFLB 10 + +#ifdef CONFIG_MATH_EMULATION +static int +record_exception(struct pt_regs *regs, int eflag) +{ + u32 fpscr; + + fpscr = __FPU_FPSCR; + + if (eflag) { + fpscr |= FPSCR_FX; + if (eflag & EFLAG_OVERFLOW) + fpscr |= FPSCR_OX; + if (eflag & EFLAG_UNDERFLOW) + fpscr |= FPSCR_UX; + if (eflag & EFLAG_DIVZERO) + fpscr |= FPSCR_ZX; + if (eflag & EFLAG_INEXACT) + fpscr |= FPSCR_XX; + if (eflag & EFLAG_VXSNAN) + fpscr |= FPSCR_VXSNAN; + if (eflag & EFLAG_VXISI) + fpscr |= FPSCR_VXISI; + if (eflag & EFLAG_VXIDI) + fpscr |= FPSCR_VXIDI; + if (eflag & EFLAG_VXZDZ) + fpscr |= FPSCR_VXZDZ; + if (eflag & EFLAG_VXIMZ) + fpscr |= FPSCR_VXIMZ; + if (eflag & EFLAG_VXVC) + fpscr |= FPSCR_VXVC; + if (eflag & EFLAG_VXSOFT) + fpscr |= FPSCR_VXSOFT; + if (eflag & EFLAG_VXSQRT) + fpscr |= FPSCR_VXSQRT; + if (eflag & EFLAG_VXCVI) + fpscr |= FPSCR_VXCVI; + } + + fpscr &= ~(FPSCR_VX); + if (fpscr & (FPSCR_VXSNAN | FPSCR_VXISI | FPSCR_VXIDI | + FPSCR_VXZDZ | FPSCR_VXIMZ | FPSCR_VXVC | + FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI)) + fpscr |= FPSCR_VX; + + fpscr &= ~(FPSCR_FEX); + if (((fpscr & FPSCR_VX) && (fpscr & FPSCR_VE)) || + ((fpscr & FPSCR_OX) && (fpscr & FPSCR_OE)) || + ((fpscr & FPSCR_UX) && (fpscr & FPSCR_UE)) || + ((fpscr & FPSCR_ZX) && (fpscr & FPSCR_ZE)) || + ((fpscr & FPSCR_XX) && (fpscr & FPSCR_XE))) + fpscr |= FPSCR_FEX; + + __FPU_FPSCR = fpscr; + + return (fpscr & FPSCR_FEX) ? 1 : 0; +} +#endif /* CONFIG_MATH_EMULATION */ + +int +do_mathemu(struct pt_regs *regs) +{ + void *op0 = 0, *op1 = 0, *op2 = 0, *op3 = 0; + unsigned long pc = regs->nip; + signed short sdisp; + u32 insn = 0; + int idx = 0; +#ifdef CONFIG_MATH_EMULATION + int (*func)(void *, void *, void *, void *); + int type = 0; + int eflag, trap; +#endif + + if (get_user(insn, (u32 *)pc)) + return -EFAULT; + +#ifndef CONFIG_MATH_EMULATION + switch (insn >> 26) { + case LFD: + idx = (insn >> 16) & 0x1f; + sdisp = (insn & 0xffff); + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp); + lfd(op0, op1, op2, op3); + break; + case LFDU: + idx = (insn >> 16) & 0x1f; + sdisp = (insn & 0xffff); + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp); + lfd(op0, op1, op2, op3); + regs->gpr[idx] = (unsigned long)op1; + break; + case STFD: + idx = (insn >> 16) & 0x1f; + sdisp = (insn & 0xffff); + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp); + stfd(op0, op1, op2, op3); + break; + case STFDU: + idx = (insn >> 16) & 0x1f; + sdisp = (insn & 0xffff); + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp); + stfd(op0, op1, op2, op3); + regs->gpr[idx] = (unsigned long)op1; + break; + case OP63: + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + op1 = (void *)¤t->tss.fpr[(insn >> 11) & 0x1f]; + fmr(op0, op1, op2, op3); + break; + default: + goto illegal; + } +#else /* CONFIG_MATH_EMULATION */ + switch (insn >> 26) { + case LFS: func = lfs; type = D; break; + case LFSU: func = lfs; type = DU; break; + case LFD: func = lfd; type = D; break; + case LFDU: func = lfd; type = DU; break; + case STFS: func = stfs; type = D; break; + case STFSU: func = stfs; type = DU; break; + case STFD: func = stfd; type = D; break; + case STFDU: func = stfd; type = DU; break; + + case OP31: + switch ((insn >> 1) & 0x3ff) { + case LFSX: func = lfs; type = XE; break; + case LFSUX: func = lfs; type = XEU; break; + case LFDX: func = lfd; type = XE; break; + case LFDUX: func = lfd; type = XEU; break; + case STFSX: func = stfs; type = XE; break; + case STFSUX: func = stfs; type = XEU; break; + case STFDX: func = stfd; type = XE; break; + case STFDUX: func = stfd; type = XEU; break; + case STFIWX: func = stfiwx; type = XE; break; + default: + goto illegal; + } + break; + + case OP59: + switch ((insn >> 1) & 0x1f) { + case FDIVS: func = fdivs; type = AB; break; + case FSUBS: func = fsubs; type = AB; break; + case FADDS: func = fadds; type = AB; break; + case FSQRTS: func = fsqrts; type = AB; break; + case FRES: func = fres; type = AB; break; + case FMULS: func = fmuls; type = AC; break; + case FMSUBS: func = fmsubs; type = ABC; break; + case FMADDS: func = fmadds; type = ABC; break; + case FNMSUBS: func = fnmsubs; type = ABC; break; + case FNMADDS: func = fnmadds; type = ABC; break; + default: + goto illegal; + } + break; + + case OP63: + if (insn & 0x20) { + switch ((insn >> 1) & 0x1f) { + case FDIV: func = fdiv; type = AB; break; + case FSUB: func = fsub; type = AB; break; + case FADD: func = fadd; type = AB; break; + case FSQRT: func = fsqrt; type = AB; break; + case FSEL: func = fsel; type = ABC; break; + case FMUL: func = fmul; type = AC; break; + case FRSQRTE: func = frsqrte; type = AB; break; + case FMSUB: func = fmsub; type = ABC; break; + case FMADD: func = fmadd; type = ABC; break; + case FNMSUB: func = fnmsub; type = ABC; break; + case FNMADD: func = fnmadd; type = ABC; break; + default: + goto illegal; + } + break; + } + + switch ((insn >> 1) & 0x3ff) { + case FCMPU: func = fcmpu; type = XCR; break; + case FRSP: func = frsp; type = XB; break; + case FCTIW: func = fctiw; type = XB; break; + case FCTIWZ: func = fctiwz; type = XB; break; + case FCMPO: func = fcmpo; type = XCR; break; + case MTFSB1: func = mtfsb1; type = XCRB; break; + case FNEG: func = fneg; type = XB; break; + case MCRFS: func = mcrfs; type = XCRL; break; + case MTFSB0: func = mtfsb0; type = XCRB; break; + case FMR: func = fmr; type = XB; break; + case MTFSFI: func = mtfsfi; type = XCRI; break; + case FNABS: func = fnabs; type = XB; break; + case FABS: func = fabs; type = XB; break; + case MFFS: func = mffs; type = X; break; + case MTFSF: func = mtfsf; type = XFLB; break; + default: + goto illegal; + } + break; + + default: + goto illegal; + } + + switch (type) { + case AB: + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + op1 = (void *)¤t->tss.fpr[(insn >> 16) & 0x1f]; + op2 = (void *)¤t->tss.fpr[(insn >> 11) & 0x1f]; + break; + + case AC: + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + op1 = (void *)¤t->tss.fpr[(insn >> 16) & 0x1f]; + op2 = (void *)¤t->tss.fpr[(insn >> 6) & 0x1f]; + break; + + case ABC: + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + op1 = (void *)¤t->tss.fpr[(insn >> 16) & 0x1f]; + op2 = (void *)¤t->tss.fpr[(insn >> 11) & 0x1f]; + op3 = (void *)¤t->tss.fpr[(insn >> 6) & 0x1f]; + break; + + case D: + idx = (insn >> 16) & 0x1f; + sdisp = (insn & 0xffff); + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp); + break; + + case DU: + idx = (insn >> 16) & 0x1f; + if (!idx) + goto illegal; + + sdisp = (insn & 0xffff); + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + op1 = (void *)(regs->gpr[idx] + sdisp); + break; + + case X: + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + break; + + case XA: + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + op1 = (void *)¤t->tss.fpr[(insn >> 16) & 0x1f]; + break; + + case XB: + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + op1 = (void *)¤t->tss.fpr[(insn >> 11) & 0x1f]; + break; + + case XE: + idx = (insn >> 16) & 0x1f; + if (!idx) + goto illegal; + + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + op1 = (void *)(regs->gpr[idx] + regs->gpr[(insn >> 11) & 0x1f]); + break; + + case XEU: + idx = (insn >> 16) & 0x1f; + op0 = (void *)¤t->tss.fpr[(insn >> 21) & 0x1f]; + op1 = (void *)((idx ? regs->gpr[idx] : 0) + + regs->gpr[(insn >> 11) & 0x1f]); + break; + + case XCR: + op0 = (void *)®s->ccr; + op1 = (void *)((insn >> 23) & 0x7); + op2 = (void *)¤t->tss.fpr[(insn >> 16) & 0x1f]; + op3 = (void *)¤t->tss.fpr[(insn >> 11) & 0x1f]; + break; + + case XCRL: + op0 = (void *)®s->ccr; + op1 = (void *)((insn >> 23) & 0x7); + op2 = (void *)((insn >> 18) & 0x7); + break; + + case XCRB: + op0 = (void *)((insn >> 21) & 0x1f); + break; + + case XCRI: + op0 = (void *)((insn >> 23) & 0x7); + op1 = (void *)((insn >> 12) & 0xf); + break; + + case XFLB: + op0 = (void *)((insn >> 17) & 0xff); + op1 = (void *)¤t->tss.fpr[(insn >> 11) & 0x1f]; + break; + + default: + goto illegal; + } + + eflag = func(op0, op1, op2, op3); + + if (insn & 1) { + regs->ccr &= ~(0x0f000000); + regs->ccr |= (__FPU_FPSCR >> 4) & 0x0f000000; + } + + trap = record_exception(regs, eflag); + if (trap) + return 1; + + switch (type) { + case DU: + case XEU: + regs->gpr[idx] = (unsigned long)op1; + break; + + default: + break; + } +#endif /* CONFIG_MATH_EMULATION */ + + regs->nip += 4; + return 0; + +illegal: + return -ENOSYS; +} diff --git a/arch/ppc/math-emu/mcrfs.c b/arch/ppc/math-emu/mcrfs.c new file mode 100644 index 000000000..8f8ade21f --- /dev/null +++ b/arch/ppc/math-emu/mcrfs.c @@ -0,0 +1,34 @@ +/* $Id: mcrfs.c,v 1.1 1999/08/23 19:00:13 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" + +int +mcrfs(u32 *ccr, u32 crfD, u32 crfS) +{ + u32 value, clear; + +#ifdef DEBUG + printk("%s: %p (%08x) %d %d\n", __FUNCTION__, ccr, *ccr, crfD, crfS); +#endif + + clear = 15 << ((7 - crfS) << 2); + if (!crfS) + clear = 0x90000000; + + value = (__FPU_FPSCR >> ((7 - crfS) << 2)) & 15; + __FPU_FPSCR &= ~(clear); + + *ccr &= ~(15 << ((7 - crfD) << 2)); + *ccr |= (value << ((7 - crfD) << 2)); + +#ifdef DEBUG + printk("CR: %08x\n", __FUNCTION__, *ccr); +#endif + + return 0; +} diff --git a/arch/ppc/math-emu/mffs.c b/arch/ppc/math-emu/mffs.c new file mode 100644 index 000000000..a23fa4339 --- /dev/null +++ b/arch/ppc/math-emu/mffs.c @@ -0,0 +1,20 @@ +/* $Id: mffs.c,v 1.1 1999/08/23 19:00:14 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" + +int +mffs(u32 *frD) +{ + frD[1] = __FPU_FPSCR; + +#ifdef DEBUG + printk("%s: frD %p: %08x.%08x\n", __FUNCTION__, frD, frD[0], frD[1]); +#endif + + return 0; +} diff --git a/arch/ppc/math-emu/mtfsb0.c b/arch/ppc/math-emu/mtfsb0.c new file mode 100644 index 000000000..b2e1c8c32 --- /dev/null +++ b/arch/ppc/math-emu/mtfsb0.c @@ -0,0 +1,21 @@ +/* $Id: mtfsb0.c,v 1.1 1999/08/23 19:00:16 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" + +int +mtfsb0(int crbD) +{ + if ((crbD != 1) && (crbD != 2)) + __FPU_FPSCR &= ~(1 << (31 - crbD)); + +#ifdef DEBUG + printk("%s: %d %08lx\n", __FUNCTION__, crbD, __FPU_FPSCR); +#endif + + return 0; +} diff --git a/arch/ppc/math-emu/mtfsb1.c b/arch/ppc/math-emu/mtfsb1.c new file mode 100644 index 000000000..fa8b628f3 --- /dev/null +++ b/arch/ppc/math-emu/mtfsb1.c @@ -0,0 +1,21 @@ +/* $Id: mtfsb1.c,v 1.1 1999/08/23 19:00:17 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" + +int +mtfsb1(int crbD) +{ + if ((crbD != 1) && (crbD != 2)) + __FPU_FPSCR |= (1 << (31 - crbD)); + +#ifdef DEBUG + printk("%s: %d %08lx\n", __FUNCTION__, crbD, __FPU_FPSCR); +#endif + + return 0; +} diff --git a/arch/ppc/math-emu/mtfsf.c b/arch/ppc/math-emu/mtfsf.c new file mode 100644 index 000000000..cb406dd53 --- /dev/null +++ b/arch/ppc/math-emu/mtfsf.c @@ -0,0 +1,48 @@ +/* $Id: mtfsf.c,v 1.1 1999/08/23 19:00:19 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" + +int +mtfsf(unsigned int FM, u32 *frB) +{ + u32 mask; + + if (FM == 0) + return 0; + + if (FM == 0xff) + mask = 0x9fffffff; + else { + mask = 0; + if (FM & (1 << 0)) + mask |= 0x90000000; + if (FM & (1 << 1)) + mask |= 0x0f000000; + if (FM & (1 << 2)) + mask |= 0x00f00000; + if (FM & (1 << 3)) + mask |= 0x000f0000; + if (FM & (1 << 4)) + mask |= 0x0000f000; + if (FM & (1 << 5)) + mask |= 0x00000f00; + if (FM & (1 << 6)) + mask |= 0x000000f0; + if (FM & (1 << 7)) + mask |= 0x0000000f; + } + + __FPU_FPSCR &= ~(mask); + __FPU_FPSCR |= (frB[1] & mask); + +#ifdef DEBUG + printk("%s: %02x %p: %08lx\n", __FUNCTION__, FM, frB, __FPU_FPSCR); +#endif + + return 0; +} diff --git a/arch/ppc/math-emu/mtfsfi.c b/arch/ppc/math-emu/mtfsfi.c new file mode 100644 index 000000000..6ee756fd4 --- /dev/null +++ b/arch/ppc/math-emu/mtfsfi.c @@ -0,0 +1,26 @@ +/* $Id: mtfsfi.c,v 1.1 1999/08/23 19:00:20 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" + +int +mtfsfi(unsigned int crfD, unsigned int IMM) +{ + u32 mask = 0xf; + + if (!crfD) + mask = 9; + + __FPU_FPSCR &= ~(mask << ((7 - crfD) << 2)); + __FPU_FPSCR |= (IMM & 0xf) << ((7 - crfD) << 2); + +#ifdef DEBUG + printk("%s: %d %x: %08lx\n", __FUNCTION__, crfD, IMM, __FPU_FPSCR); +#endif + + return 0; +} diff --git a/arch/ppc/math-emu/op-1.h b/arch/ppc/math-emu/op-1.h new file mode 100644 index 000000000..87960c287 --- /dev/null +++ b/arch/ppc/math-emu/op-1.h @@ -0,0 +1,245 @@ +/* + * Basic one-word fraction declaration and manipulation. + */ + +#define _FP_FRAC_DECL_1(X) _FP_W_TYPE X##_f +#define _FP_FRAC_COPY_1(D,S) (D##_f = S##_f) +#define _FP_FRAC_SET_1(X,I) (X##_f = I) +#define _FP_FRAC_HIGH_1(X) (X##_f) +#define _FP_FRAC_LOW_1(X) (X##_f) +#define _FP_FRAC_WORD_1(X,w) (X##_f) + +#define _FP_FRAC_ADDI_1(X,I) (X##_f += I) +#define _FP_FRAC_SLL_1(X,N) \ + do { \ + if (__builtin_constant_p(N) && (N) == 1) \ + X##_f += X##_f; \ + else \ + X##_f <<= (N); \ + } while (0) +#define _FP_FRAC_SRL_1(X,N) (X##_f >>= N) + +/* Right shift with sticky-lsb. */ +#define _FP_FRAC_SRS_1(X,N,sz) __FP_FRAC_SRS_1(X##_f, N, sz) + +#define __FP_FRAC_SRS_1(X,N,sz) \ + (X = (X >> (N) | (__builtin_constant_p(N) && (N) == 1 \ + ? X & 1 : (X << (_FP_W_TYPE_SIZE - (N))) != 0))) + +#define _FP_FRAC_ADD_1(R,X,Y) (R##_f = X##_f + Y##_f) +#define _FP_FRAC_SUB_1(R,X,Y) (R##_f = X##_f - Y##_f) +#define _FP_FRAC_CLZ_1(z, X) __FP_CLZ(z, X##_f) + +/* Predicates */ +#define _FP_FRAC_NEGP_1(X) ((_FP_WS_TYPE)X##_f < 0) +#define _FP_FRAC_ZEROP_1(X) (X##_f == 0) +#define _FP_FRAC_OVERP_1(fs,X) (X##_f & _FP_OVERFLOW_##fs) +#define _FP_FRAC_EQ_1(X, Y) (X##_f == Y##_f) +#define _FP_FRAC_GE_1(X, Y) (X##_f >= Y##_f) +#define _FP_FRAC_GT_1(X, Y) (X##_f > Y##_f) + +#define _FP_ZEROFRAC_1 0 +#define _FP_MINFRAC_1 1 + +/* + * Unpack the raw bits of a native fp value. Do not classify or + * normalize the data. + */ + +#define _FP_UNPACK_RAW_1(fs, X, val) \ + do { \ + union _FP_UNION_##fs _flo; _flo.flt = (val); \ + \ + X##_f = _flo.bits.frac; \ + X##_e = _flo.bits.exp; \ + X##_s = _flo.bits.sign; \ + } while (0) + + +/* + * Repack the raw bits of a native fp value. + */ + +#define _FP_PACK_RAW_1(fs, val, X) \ + do { \ + union _FP_UNION_##fs _flo; \ + \ + _flo.bits.frac = X##_f; \ + _flo.bits.exp = X##_e; \ + _flo.bits.sign = X##_s; \ + \ + (val) = _flo.flt; \ + } while (0) + + +/* + * Multiplication algorithms: + */ + +/* Basic. Assuming the host word size is >= 2*FRACBITS, we can do the + multiplication immediately. */ + +#define _FP_MUL_MEAT_1_imm(fs, R, X, Y) \ + do { \ + R##_f = X##_f * Y##_f; \ + /* Normalize since we know where the msb of the multiplicands \ + were (bit B), we know that the msb of the of the product is \ + at either 2B or 2B-1. */ \ + _FP_FRAC_SRS_1(R, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs); \ + } while (0) + +/* Given a 1W * 1W => 2W primitive, do the extended multiplication. */ + +#define _FP_MUL_MEAT_1_wide(fs, R, X, Y, doit) \ + do { \ + _FP_W_TYPE _Z_f0, _Z_f1; \ + doit(_Z_f1, _Z_f0, X##_f, Y##_f); \ + /* Normalize since we know where the msb of the multiplicands \ + were (bit B), we know that the msb of the of the product is \ + at either 2B or 2B-1. */ \ + _FP_FRAC_SRS_2(_Z, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs); \ + R##_f = _Z_f0; \ + } while (0) + +/* Finally, a simple widening multiply algorithm. What fun! */ + +#define _FP_MUL_MEAT_1_hard(fs, R, X, Y) \ + do { \ + _FP_W_TYPE _xh, _xl, _yh, _yl, _z_f0, _z_f1, _a_f0, _a_f1; \ + \ + /* split the words in half */ \ + _xh = X##_f >> (_FP_W_TYPE_SIZE/2); \ + _xl = X##_f & (((_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE/2)) - 1); \ + _yh = Y##_f >> (_FP_W_TYPE_SIZE/2); \ + _yl = Y##_f & (((_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE/2)) - 1); \ + \ + /* multiply the pieces */ \ + _z_f0 = _xl * _yl; \ + _a_f0 = _xh * _yl; \ + _a_f1 = _xl * _yh; \ + _z_f1 = _xh * _yh; \ + \ + /* reassemble into two full words */ \ + if ((_a_f0 += _a_f1) < _a_f1) \ + _z_f1 += (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE/2); \ + _a_f1 = _a_f0 >> (_FP_W_TYPE_SIZE/2); \ + _a_f0 = _a_f0 << (_FP_W_TYPE_SIZE/2); \ + _FP_FRAC_ADD_2(_z, _z, _a); \ + \ + /* normalize */ \ + _FP_FRAC_SRS_2(_z, _FP_WFRACBITS_##fs - 1, 2*_FP_WFRACBITS_##fs); \ + R##_f = _z_f0; \ + } while (0) + + +/* + * Division algorithms: + */ + +/* Basic. Assuming the host word size is >= 2*FRACBITS, we can do the + division immediately. Give this macro either _FP_DIV_HELP_imm for + C primitives or _FP_DIV_HELP_ldiv for the ISO function. Which you + choose will depend on what the compiler does with divrem4. */ + +#define _FP_DIV_MEAT_1_imm(fs, R, X, Y, doit) \ + do { \ + _FP_W_TYPE _q, _r; \ + X##_f <<= (X##_f < Y##_f \ + ? R##_e--, _FP_WFRACBITS_##fs \ + : _FP_WFRACBITS_##fs - 1); \ + doit(_q, _r, X##_f, Y##_f); \ + R##_f = _q | (_r != 0); \ + } while (0) + +/* GCC's longlong.h defines a 2W / 1W => (1W,1W) primitive udiv_qrnnd + that may be useful in this situation. This first is for a primitive + that requires normalization, the second for one that does not. Look + for UDIV_NEEDS_NORMALIZATION to tell which your machine needs. */ + +#define _FP_DIV_MEAT_1_udiv_norm(fs, R, X, Y) \ + do { \ + _FP_W_TYPE _nh, _nl, _q, _r; \ + \ + /* Normalize Y -- i.e. make the most significant bit set. */ \ + Y##_f <<= _FP_WFRACXBITS_##fs - 1; \ + \ + /* Shift X op correspondingly high, that is, up one full word. */ \ + if (X##_f <= Y##_f) \ + { \ + _nl = 0; \ + _nh = X##_f; \ + } \ + else \ + { \ + R##_e++; \ + _nl = X##_f << (_FP_W_TYPE_SIZE-1); \ + _nh = X##_f >> 1; \ + } \ + \ + udiv_qrnnd(_q, _r, _nh, _nl, Y##_f); \ + R##_f = _q | (_r != 0); \ + } while (0) + +#define _FP_DIV_MEAT_1_udiv(fs, R, X, Y) \ + do { \ + _FP_W_TYPE _nh, _nl, _q, _r; \ + if (X##_f < Y##_f) \ + { \ + R##_e--; \ + _nl = X##_f << _FP_WFRACBITS_##fs; \ + _nh = X##_f >> _FP_WFRACXBITS_##fs; \ + } \ + else \ + { \ + _nl = X##_f << (_FP_WFRACBITS_##fs - 1); \ + _nh = X##_f >> (_FP_WFRACXBITS_##fs + 1); \ + } \ + udiv_qrnnd(_q, _r, _nh, _nl, Y##_f); \ + R##_f = _q | (_r != 0); \ + } while (0) + + +/* + * Square root algorithms: + * We have just one right now, maybe Newton approximation + * should be added for those machines where division is fast. + */ + +#define _FP_SQRT_MEAT_1(R, S, T, X, q) \ + do { \ + while (q) \ + { \ + T##_f = S##_f + q; \ + if (T##_f <= X##_f) \ + { \ + S##_f = T##_f + q; \ + X##_f -= T##_f; \ + R##_f += q; \ + } \ + _FP_FRAC_SLL_1(X, 1); \ + q >>= 1; \ + } \ + } while (0) + +/* + * Assembly/disassembly for converting to/from integral types. + * No shifting or overflow handled here. + */ + +#define _FP_FRAC_ASSEMBLE_1(r, X, rsize) (r = X##_f) +#define _FP_FRAC_DISASSEMBLE_1(X, r, rsize) (X##_f = r) + + +/* + * Convert FP values between word sizes + */ + +#define _FP_FRAC_CONV_1_1(dfs, sfs, D, S) \ + do { \ + D##_f = S##_f; \ + if (_FP_WFRACBITS_##sfs > _FP_WFRACBITS_##dfs) \ + _FP_FRAC_SRS_1(D, (_FP_WFRACBITS_##sfs-_FP_WFRACBITS_##dfs), \ + _FP_WFRACBITS_##sfs); \ + else \ + D##_f <<= _FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs; \ + } while (0) diff --git a/arch/ppc/math-emu/op-2.h b/arch/ppc/math-emu/op-2.h new file mode 100644 index 000000000..68ec50e39 --- /dev/null +++ b/arch/ppc/math-emu/op-2.h @@ -0,0 +1,433 @@ +/* + * Basic two-word fraction declaration and manipulation. + */ + +#define _FP_FRAC_DECL_2(X) _FP_W_TYPE X##_f0, X##_f1 +#define _FP_FRAC_COPY_2(D,S) (D##_f0 = S##_f0, D##_f1 = S##_f1) +#define _FP_FRAC_SET_2(X,I) __FP_FRAC_SET_2(X, I) +#define _FP_FRAC_HIGH_2(X) (X##_f1) +#define _FP_FRAC_LOW_2(X) (X##_f0) +#define _FP_FRAC_WORD_2(X,w) (X##_f##w) + +#define _FP_FRAC_SLL_2(X,N) \ + do { \ + if ((N) < _FP_W_TYPE_SIZE) \ + { \ + if (__builtin_constant_p(N) && (N) == 1) \ + { \ + X##_f1 = X##_f1 + X##_f1 + (((_FP_WS_TYPE)(X##_f0)) < 0); \ + X##_f0 += X##_f0; \ + } \ + else \ + { \ + X##_f1 = X##_f1 << (N) | X##_f0 >> (_FP_W_TYPE_SIZE - (N)); \ + X##_f0 <<= (N); \ + } \ + } \ + else \ + { \ + X##_f1 = X##_f0 << ((N) - _FP_W_TYPE_SIZE); \ + X##_f0 = 0; \ + } \ + } while (0) + +#define _FP_FRAC_SRL_2(X,N) \ + do { \ + if ((N) < _FP_W_TYPE_SIZE) \ + { \ + X##_f0 = X##_f0 >> (N) | X##_f1 << (_FP_W_TYPE_SIZE - (N)); \ + X##_f1 >>= (N); \ + } \ + else \ + { \ + X##_f0 = X##_f1 >> ((N) - _FP_W_TYPE_SIZE); \ + X##_f1 = 0; \ + } \ + } while (0) + +/* Right shift with sticky-lsb. */ +#define _FP_FRAC_SRS_2(X,N,sz) \ + do { \ + if ((N) < _FP_W_TYPE_SIZE) \ + { \ + X##_f0 = (X##_f1 << (_FP_W_TYPE_SIZE - (N)) | X##_f0 >> (N) | \ + (__builtin_constant_p(N) && (N) == 1 \ + ? X##_f0 & 1 \ + : (X##_f0 << (_FP_W_TYPE_SIZE - (N))) != 0)); \ + X##_f1 >>= (N); \ + } \ + else \ + { \ + X##_f0 = (X##_f1 >> ((N) - _FP_W_TYPE_SIZE) | \ + (((X##_f1 << (sz - (N))) | X##_f0) != 0)); \ + X##_f1 = 0; \ + } \ + } while (0) + +#define _FP_FRAC_ADDI_2(X,I) \ + __FP_FRAC_ADDI_2(X##_f1, X##_f0, I) + +#define _FP_FRAC_ADD_2(R,X,Y) \ + __FP_FRAC_ADD_2(R##_f1, R##_f0, X##_f1, X##_f0, Y##_f1, Y##_f0) + +#define _FP_FRAC_SUB_2(R,X,Y) \ + __FP_FRAC_SUB_2(R##_f1, R##_f0, X##_f1, X##_f0, Y##_f1, Y##_f0) + +#define _FP_FRAC_CLZ_2(R,X) \ + do { \ + if (X##_f1) \ + __FP_CLZ(R,X##_f1); \ + else \ + { \ + __FP_CLZ(R,X##_f0); \ + R += _FP_W_TYPE_SIZE; \ + } \ + } while(0) + +/* Predicates */ +#define _FP_FRAC_NEGP_2(X) ((_FP_WS_TYPE)X##_f1 < 0) +#define _FP_FRAC_ZEROP_2(X) ((X##_f1 | X##_f0) == 0) +#define _FP_FRAC_OVERP_2(fs,X) (X##_f1 & _FP_OVERFLOW_##fs) +#define _FP_FRAC_EQ_2(X, Y) (X##_f1 == Y##_f1 && X##_f0 == Y##_f0) +#define _FP_FRAC_GT_2(X, Y) \ + ((X##_f1 > Y##_f1) || (X##_f1 == Y##_f1 && X##_f0 > Y##_f0)) +#define _FP_FRAC_GE_2(X, Y) \ + ((X##_f1 > Y##_f1) || (X##_f1 == Y##_f1 && X##_f0 >= Y##_f0)) + +#define _FP_ZEROFRAC_2 0, 0 +#define _FP_MINFRAC_2 0, 1 + +/* + * Internals + */ + +#define __FP_FRAC_SET_2(X,I1,I0) (X##_f0 = I0, X##_f1 = I1) + +#define __FP_CLZ_2(R, xh, xl) \ + do { \ + if (xh) \ + __FP_CLZ(R,xl); \ + else \ + { \ + __FP_CLZ(R,xl); \ + R += _FP_W_TYPE_SIZE; \ + } \ + } while(0) + +#if 0 + +#ifndef __FP_FRAC_ADDI_2 +#define __FP_FRAC_ADDI_2(xh, xl, i) \ + (xh += ((xl += i) < i)) +#endif +#ifndef __FP_FRAC_ADD_2 +#define __FP_FRAC_ADD_2(rh, rl, xh, xl, yh, yl) \ + (rh = xh + yh + ((rl = xl + yl) < xl)) +#endif +#ifndef __FP_FRAC_SUB_2 +#define __FP_FRAC_SUB_2(rh, rl, xh, xl, yh, yl) \ + (rh = xh - yh - ((rl = xl - yl) > xl)) +#endif + +#else + +#undef __FP_FRAC_ADDI_2 +#define __FP_FRAC_ADDI_2(xh, xl, i) add_ssaaaa(xh, xl, xh, xl, 0, i) +#undef __FP_FRAC_ADD_2 +#define __FP_FRAC_ADD_2 add_ssaaaa +#undef __FP_FRAC_SUB_2 +#define __FP_FRAC_SUB_2 sub_ddmmss + +#endif + +/* + * Unpack the raw bits of a native fp value. Do not classify or + * normalize the data. + */ + +#define _FP_UNPACK_RAW_2(fs, X, val) \ + do { \ + union _FP_UNION_##fs _flo; _flo.flt = (val); \ + \ + X##_f0 = _flo.bits.frac0; \ + X##_f1 = _flo.bits.frac1; \ + X##_e = _flo.bits.exp; \ + X##_s = _flo.bits.sign; \ + } while (0) + + +/* + * Repack the raw bits of a native fp value. + */ + +#define _FP_PACK_RAW_2(fs, val, X) \ + do { \ + union _FP_UNION_##fs _flo; \ + \ + _flo.bits.frac0 = X##_f0; \ + _flo.bits.frac1 = X##_f1; \ + _flo.bits.exp = X##_e; \ + _flo.bits.sign = X##_s; \ + \ + (val) = _flo.flt; \ + } while (0) + + +/* + * Multiplication algorithms: + */ + +/* Given a 1W * 1W => 2W primitive, do the extended multiplication. */ + +#define _FP_MUL_MEAT_2_wide(fs, R, X, Y, doit) \ + do { \ + _FP_FRAC_DECL_4(_z); _FP_FRAC_DECL_2(_b); _FP_FRAC_DECL_2(_c); \ + \ + doit(_FP_FRAC_WORD_4(_z,1), _FP_FRAC_WORD_4(_z,0), X##_f0, Y##_f0); \ + doit(_b_f1, _b_f0, X##_f0, Y##_f1); \ + doit(_c_f1, _c_f0, X##_f1, Y##_f0); \ + doit(_FP_FRAC_WORD_4(_z,3), _FP_FRAC_WORD_4(_z,2), X##_f1, Y##_f1); \ + \ + __FP_FRAC_ADD_4(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ + _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0), \ + 0, _b_f1, _b_f0, 0, \ + _FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ + _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0)); \ + __FP_FRAC_ADD_4(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ + _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0), \ + 0, _c_f1, _c_f0, 0, \ + _FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ + _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0)); \ + \ + /* Normalize since we know where the msb of the multiplicands \ + were (bit B), we know that the msb of the of the product is \ + at either 2B or 2B-1. */ \ + _FP_FRAC_SRS_4(_z, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs); \ + R##_f0 = _FP_FRAC_WORD_4(_z,0); \ + R##_f1 = _FP_FRAC_WORD_4(_z,1); \ + } while (0) + +/* This next macro appears to be totally broken. Fortunately nowhere + * seems to use it :-> The problem is that we define _z[4] but + * then use it in _FP_FRAC_SRS_4, which will attempt to access + * _z_f[n] which will cause an error. The fix probably involves + * declaring it with _FP_FRAC_DECL_4, see previous macro. -- PMM 02/1998 + */ +#define _FP_MUL_MEAT_2_gmp(fs, R, X, Y) \ + do { \ + _FP_W_TYPE _x[2], _y[2], _z[4]; \ + _x[0] = X##_f0; _x[1] = X##_f1; \ + _y[0] = Y##_f0; _y[1] = Y##_f1; \ + \ + mpn_mul_n(_z, _x, _y, 2); \ + \ + /* Normalize since we know where the msb of the multiplicands \ + were (bit B), we know that the msb of the of the product is \ + at either 2B or 2B-1. */ \ + _FP_FRAC_SRS_4(_z, _FP_WFRACBITS##_fs-1, 2*_FP_WFRACBITS_##fs); \ + R##_f0 = _z[0]; \ + R##_f1 = _z[1]; \ + } while (0) + + +/* + * Division algorithms: + * This seems to be giving me difficulties -- PMM + * Look, NetBSD seems to be able to comment algorithms. Can't you? + * I've thrown printks at the problem. + * This now appears to work, but I still don't really know why. + * Also, I don't think the result is properly normalised... + */ + +#define _FP_DIV_MEAT_2_udiv_64(fs, R, X, Y) \ + do { \ + extern void _fp_udivmodti4(_FP_W_TYPE q[2], _FP_W_TYPE r[2], \ + _FP_W_TYPE n1, _FP_W_TYPE n0, \ + _FP_W_TYPE d1, _FP_W_TYPE d0); \ + _FP_W_TYPE _n_f3, _n_f2, _n_f1, _n_f0, _r_f1, _r_f0; \ + _FP_W_TYPE _q_f1, _q_f0, _m_f1, _m_f0; \ + _FP_W_TYPE _rmem[2], _qmem[2]; \ + /* I think this check is to ensure that the result is normalised. \ + * Assuming X,Y normalised (ie in [1.0,2.0)) X/Y will be in \ + * [0.5,2.0). Furthermore, it will be less than 1.0 iff X < Y. \ + * In this case we tweak things. (this is based on comments in \ + * the NetBSD FPU emulation code. ) \ + * We know X,Y are normalised because we ensure this as part of \ + * the unpacking process. -- PMM \ + */ \ + if (_FP_FRAC_GT_2(X, Y)) \ + { \ +/* R##_e++; */ \ + _n_f3 = X##_f1 >> 1; \ + _n_f2 = X##_f1 << (_FP_W_TYPE_SIZE - 1) | X##_f0 >> 1; \ + _n_f1 = X##_f0 << (_FP_W_TYPE_SIZE - 1); \ + _n_f0 = 0; \ + } \ + else \ + { \ + R##_e--; \ + _n_f3 = X##_f1; \ + _n_f2 = X##_f0; \ + _n_f1 = _n_f0 = 0; \ + } \ + \ + /* Normalize, i.e. make the most significant bit of the \ + denominator set. CHANGED: - 1 to nothing -- PMM */ \ + _FP_FRAC_SLL_2(Y, _FP_WFRACXBITS_##fs /* -1 */); \ + \ + /* Do the 256/128 bit division given the 128-bit _fp_udivmodtf4 \ + primitive snagged from libgcc2.c. */ \ + \ + _fp_udivmodti4(_qmem, _rmem, _n_f3, _n_f2, 0, Y##_f1); \ + _q_f1 = _qmem[0]; \ + umul_ppmm(_m_f1, _m_f0, _q_f1, Y##_f0); \ + _r_f1 = _rmem[0]; \ + _r_f0 = _n_f1; \ + if (_FP_FRAC_GT_2(_m, _r)) \ + { \ + _q_f1--; \ + _FP_FRAC_ADD_2(_r, _r, Y); \ + if (_FP_FRAC_GE_2(_r, Y) && _FP_FRAC_GT_2(_m, _r)) \ + { \ + _q_f1--; \ + _FP_FRAC_ADD_2(_r, _r, Y); \ + } \ + } \ + _FP_FRAC_SUB_2(_r, _r, _m); \ + \ + _fp_udivmodti4(_qmem, _rmem, _r_f1, _r_f0, 0, Y##_f1); \ + _q_f0 = _qmem[0]; \ + umul_ppmm(_m_f1, _m_f0, _q_f0, Y##_f0); \ + _r_f1 = _rmem[0]; \ + _r_f0 = _n_f0; \ + if (_FP_FRAC_GT_2(_m, _r)) \ + { \ + _q_f0--; \ + _FP_FRAC_ADD_2(_r, _r, Y); \ + if (_FP_FRAC_GE_2(_r, Y) && _FP_FRAC_GT_2(_m, _r)) \ + { \ + _q_f0--; \ + _FP_FRAC_ADD_2(_r, _r, Y); \ + } \ + } \ + _FP_FRAC_SUB_2(_r, _r, _m); \ + \ + R##_f1 = _q_f1; \ + R##_f0 = _q_f0 | ((_r_f1 | _r_f0) != 0); \ + /* adjust so answer is normalized again. I'm not sure what the \ + * final sz param should be. In practice it's never used since \ + * N is 1 which is always going to be < _FP_W_TYPE_SIZE... \ + */ \ + /* _FP_FRAC_SRS_2(R,1,_FP_WFRACBITS_##fs); */ \ + } while (0) + + +#define _FP_DIV_MEAT_2_gmp(fs, R, X, Y) \ + do { \ + _FP_W_TYPE _x[4], _y[2], _z[4]; \ + _y[0] = Y##_f0; _y[1] = Y##_f1; \ + _x[0] = _x[3] = 0; \ + if (_FP_FRAC_GT_2(X, Y)) \ + { \ + R##_e++; \ + _x[1] = (X##_f0 << (_FP_WFRACBITS-1 - _FP_W_TYPE_SIZE) | \ + X##_f1 >> (_FP_W_TYPE_SIZE - \ + (_FP_WFRACBITS-1 - _FP_W_TYPE_SIZE))); \ + _x[2] = X##_f1 << (_FP_WFRACBITS-1 - _FP_W_TYPE_SIZE); \ + } \ + else \ + { \ + _x[1] = (X##_f0 << (_FP_WFRACBITS - _FP_W_TYPE_SIZE) | \ + X##_f1 >> (_FP_W_TYPE_SIZE - \ + (_FP_WFRACBITS - _FP_W_TYPE_SIZE))); \ + _x[2] = X##_f1 << (_FP_WFRACBITS - _FP_W_TYPE_SIZE); \ + } \ + \ + (void) mpn_divrem (_z, 0, _x, 4, _y, 2); \ + R##_f1 = _z[1]; \ + R##_f0 = _z[0] | ((_x[0] | _x[1]) != 0); \ + } while (0) + + +/* + * Square root algorithms: + * We have just one right now, maybe Newton approximation + * should be added for those machines where division is fast. + */ + +#define _FP_SQRT_MEAT_2(R, S, T, X, q) \ + do { \ + while (q) \ + { \ + T##_f1 = S##_f1 + q; \ + if (T##_f1 <= X##_f1) \ + { \ + S##_f1 = T##_f1 + q; \ + X##_f1 -= T##_f1; \ + R##_f1 += q; \ + } \ + _FP_FRAC_SLL_2(X, 1); \ + q >>= 1; \ + } \ + q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1); \ + while (q) \ + { \ + T##_f0 = S##_f0 + q; \ + T##_f1 = S##_f1; \ + if (T##_f1 < X##_f1 || \ + (T##_f1 == X##_f1 && T##_f0 < X##_f0)) \ + { \ + S##_f0 = T##_f0 + q; \ + if (((_FP_WS_TYPE)T##_f0) < 0 && \ + ((_FP_WS_TYPE)S##_f0) >= 0) \ + S##_f1++; \ + _FP_FRAC_SUB_2(X, X, T); \ + R##_f0 += q; \ + } \ + _FP_FRAC_SLL_2(X, 1); \ + q >>= 1; \ + } \ + } while (0) + + +/* + * Assembly/disassembly for converting to/from integral types. + * No shifting or overflow handled here. + */ + +#define _FP_FRAC_ASSEMBLE_2(r, X, rsize) \ + do { \ + if (rsize <= _FP_W_TYPE_SIZE) \ + r = X##_f0; \ + else \ + { \ + r = X##_f1; \ + r <<= _FP_W_TYPE_SIZE; \ + r += X##_f0; \ + } \ + } while (0) + +#define _FP_FRAC_DISASSEMBLE_2(X, r, rsize) \ + do { \ + X##_f0 = r; \ + X##_f1 = (rsize <= _FP_W_TYPE_SIZE ? 0 : r >> _FP_W_TYPE_SIZE); \ + } while (0) + +/* + * Convert FP values between word sizes + */ + +#define _FP_FRAC_CONV_1_2(dfs, sfs, D, S) \ + do { \ + _FP_FRAC_SRS_2(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs), \ + _FP_WFRACBITS_##sfs); \ + D##_f = S##_f0; \ + } while (0) + +#define _FP_FRAC_CONV_2_1(dfs, sfs, D, S) \ + do { \ + D##_f0 = S##_f; \ + D##_f1 = 0; \ + _FP_FRAC_SLL_2(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs)); \ + } while (0) + diff --git a/arch/ppc/math-emu/op-4.h b/arch/ppc/math-emu/op-4.h new file mode 100644 index 000000000..5f7099271 --- /dev/null +++ b/arch/ppc/math-emu/op-4.h @@ -0,0 +1,297 @@ +/* + * Basic four-word fraction declaration and manipulation. + * + * When adding quadword support for 32 bit machines, we need + * to be a little careful as double multiply uses some of these + * macros: (in op-2.h) + * _FP_MUL_MEAT_2_wide() uses _FP_FRAC_DECL_4, _FP_FRAC_WORD_4, + * _FP_FRAC_ADD_4, _FP_FRAC_SRS_4 + * _FP_MUL_MEAT_2_gmp() uses _FP_FRAC_SRS_4 (and should use + * _FP_FRAC_DECL_4: it appears to be broken and is not used + * anywhere anyway. ) + * + * I've now fixed all the macros that were here from the sparc64 code. + * [*none* of the shift macros were correct!] -- PMM 02/1998 + * + * The only quadword stuff that remains to be coded is: + * 1) the conversion to/from ints, which requires + * that we check (in op-common.h) that the following do the right thing + * for quadwords: _FP_TO_INT(Q,4,r,X,rsz,rsg), _FP_FROM_INT(Q,4,X,r,rs,rt) + * 2) multiply, divide and sqrt, which require: + * _FP_MUL_MEAT_4_*(R,X,Y), _FP_DIV_MEAT_4_*(R,X,Y), _FP_SQRT_MEAT_4(R,S,T,X,q), + * This also needs _FP_MUL_MEAT_Q and _FP_DIV_MEAT_Q to be defined to + * some suitable _FP_MUL_MEAT_4_* macros in sfp-machine.h. + * [we're free to choose whatever FP_MUL_MEAT_4_* macros we need for + * these; they are used nowhere else. ] + */ + +#define _FP_FRAC_DECL_4(X) _FP_W_TYPE X##_f[4] +#define _FP_FRAC_COPY_4(D,S) \ + (D##_f[0] = S##_f[0], D##_f[1] = S##_f[1], \ + D##_f[2] = S##_f[2], D##_f[3] = S##_f[3]) +/* The _FP_FRAC_SET_n(X,I) macro is intended for use with another + * macro such as _FP_ZEROFRAC_n which returns n comma separated values. + * The result is that we get an expansion of __FP_FRAC_SET_n(X,I0,I1,I2,I3) + * which just assigns the In values to the array X##_f[]. + * This is why the number of parameters doesn't appear to match + * at first glance... -- PMM + */ +#define _FP_FRAC_SET_4(X,I) __FP_FRAC_SET_4(X, I) +#define _FP_FRAC_HIGH_4(X) (X##_f[3]) +#define _FP_FRAC_LOW_4(X) (X##_f[0]) +#define _FP_FRAC_WORD_4(X,w) (X##_f[w]) + +#define _FP_FRAC_SLL_4(X,N) \ + do { \ + _FP_I_TYPE _up, _down, _skip, _i; \ + _skip = (N) / _FP_W_TYPE_SIZE; \ + _up = (N) % _FP_W_TYPE_SIZE; \ + _down = _FP_W_TYPE_SIZE - _up; \ + for (_i = 3; _i > _skip; --_i) \ + X##_f[_i] = X##_f[_i-_skip] << _up | X##_f[_i-_skip-1] >> _down; \ +/* bugfixed: was X##_f[_i] <<= _up; -- PMM 02/1998 */ \ + X##_f[_i] = X##_f[0] << _up; \ + for (--_i; _i >= 0; --_i) \ + X##_f[_i] = 0; \ + } while (0) + +/* This one was broken too */ +#define _FP_FRAC_SRL_4(X,N) \ + do { \ + _FP_I_TYPE _up, _down, _skip, _i; \ + _skip = (N) / _FP_W_TYPE_SIZE; \ + _down = (N) % _FP_W_TYPE_SIZE; \ + _up = _FP_W_TYPE_SIZE - _down; \ + for (_i = 0; _i < 3-_skip; ++_i) \ + X##_f[_i] = X##_f[_i+_skip] >> _down | X##_f[_i+_skip+1] << _up; \ + X##_f[_i] = X##_f[3] >> _down; \ + for (++_i; _i < 4; ++_i) \ + X##_f[_i] = 0; \ + } while (0) + + +/* Right shift with sticky-lsb. + * What this actually means is that we do a standard right-shift, + * but that if any of the bits that fall off the right hand side + * were one then we always set the LSbit. + */ +#define _FP_FRAC_SRS_4(X,N,size) \ + do { \ + _FP_I_TYPE _up, _down, _skip, _i; \ + _FP_W_TYPE _s; \ + _skip = (N) / _FP_W_TYPE_SIZE; \ + _down = (N) % _FP_W_TYPE_SIZE; \ + _up = _FP_W_TYPE_SIZE - _down; \ + for (_s = _i = 0; _i < _skip; ++_i) \ + _s |= X##_f[_i]; \ + _s |= X##_f[_i] << _up; \ +/* s is now != 0 if we want to set the LSbit */ \ + for (_i = 0; _i < 3-_skip; ++_i) \ + X##_f[_i] = X##_f[_i+_skip] >> _down | X##_f[_i+_skip+1] << _up; \ + X##_f[_i] = X##_f[3] >> _down; \ + for (++_i; _i < 4; ++_i) \ + X##_f[_i] = 0; \ + /* don't fix the LSB until the very end when we're sure f[0] is stable */ \ + X##_f[0] |= (_s != 0); \ + } while (0) + +#define _FP_FRAC_ADD_4(R,X,Y) \ + __FP_FRAC_ADD_4(R##_f[3], R##_f[2], R##_f[1], R##_f[0], \ + X##_f[3], X##_f[2], X##_f[1], X##_f[0], \ + Y##_f[3], Y##_f[2], Y##_f[1], Y##_f[0]) + +#define _FP_FRAC_SUB_4(R,X,Y) \ + __FP_FRAC_SUB_4(R##_f[3], R##_f[2], R##_f[1], R##_f[0], \ + X##_f[3], X##_f[2], X##_f[1], X##_f[0], \ + Y##_f[3], Y##_f[2], Y##_f[1], Y##_f[0]) + +#define _FP_FRAC_ADDI_4(X,I) \ + __FP_FRAC_ADDI_4(X##_f[3], X##_f[2], X##_f[1], X##_f[0], I) + +#define _FP_ZEROFRAC_4 0,0,0,0 +#define _FP_MINFRAC_4 0,0,0,1 + +#define _FP_FRAC_ZEROP_4(X) ((X##_f[0] | X##_f[1] | X##_f[2] | X##_f[3]) == 0) +#define _FP_FRAC_NEGP_4(X) ((_FP_WS_TYPE)X##_f[3] < 0) +#define _FP_FRAC_OVERP_4(fs,X) (X##_f[0] & _FP_OVERFLOW_##fs) + +#define _FP_FRAC_EQ_4(X,Y) \ + (X##_f[0] == Y##_f[0] && X##_f[1] == Y##_f[1] \ + && X##_f[2] == Y##_f[2] && X##_f[3] == Y##_f[3]) + +#define _FP_FRAC_GT_4(X,Y) \ + (X##_f[3] > Y##_f[3] || \ + (X##_f[3] == Y##_f[3] && (X##_f[2] > Y##_f[2] || \ + (X##_f[2] == Y##_f[2] && (X##_f[1] > Y##_f[1] || \ + (X##_f[1] == Y##_f[1] && X##_f[0] > Y##_f[0]) \ + )) \ + )) \ + ) + +#define _FP_FRAC_GE_4(X,Y) \ + (X##_f[3] > Y##_f[3] || \ + (X##_f[3] == Y##_f[3] && (X##_f[2] > Y##_f[2] || \ + (X##_f[2] == Y##_f[2] && (X##_f[1] > Y##_f[1] || \ + (X##_f[1] == Y##_f[1] && X##_f[0] >= Y##_f[0]) \ + )) \ + )) \ + ) + + +#define _FP_FRAC_CLZ_4(R,X) \ + do { \ + if (X##_f[3]) \ + { \ + __FP_CLZ(R,X##_f[3]); \ + } \ + else if (X##_f[2]) \ + { \ + __FP_CLZ(R,X##_f[2]); \ + R += _FP_W_TYPE_SIZE; \ + } \ + else if (X##_f[1]) \ + { \ + __FP_CLZ(R,X##_f[2]); \ + R += _FP_W_TYPE_SIZE*2; \ + } \ + else \ + { \ + __FP_CLZ(R,X##_f[0]); \ + R += _FP_W_TYPE_SIZE*3; \ + } \ + } while(0) + + +#define _FP_UNPACK_RAW_4(fs, X, val) \ + do { \ + union _FP_UNION_##fs _flo; _flo.flt = (val); \ + X##_f[0] = _flo.bits.frac0; \ + X##_f[1] = _flo.bits.frac1; \ + X##_f[2] = _flo.bits.frac2; \ + X##_f[3] = _flo.bits.frac3; \ + X##_e = _flo.bits.exp; \ + X##_s = _flo.bits.sign; \ + } while (0) + +#define _FP_PACK_RAW_4(fs, val, X) \ + do { \ + union _FP_UNION_##fs _flo; \ + _flo.bits.frac0 = X##_f[0]; \ + _flo.bits.frac1 = X##_f[1]; \ + _flo.bits.frac2 = X##_f[2]; \ + _flo.bits.frac3 = X##_f[3]; \ + _flo.bits.exp = X##_e; \ + _flo.bits.sign = X##_s; \ + (val) = _flo.flt; \ + } while (0) + + +/* + * Internals + */ + +#define __FP_FRAC_SET_4(X,I3,I2,I1,I0) \ + (X##_f[3] = I3, X##_f[2] = I2, X##_f[1] = I1, X##_f[0] = I0) + +#ifndef __FP_FRAC_ADD_4 +#define __FP_FRAC_ADD_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0) \ + (r0 = x0 + y0, \ + r1 = x1 + y1 + (r0 < x0), \ + r2 = x2 + y2 + (r1 < x1), \ + r3 = x3 + y3 + (r2 < x2)) +#endif + +#ifndef __FP_FRAC_SUB_4 +#define __FP_FRAC_SUB_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0) \ + (r0 = x0 - y0, \ + r1 = x1 - y1 - (r0 > x0), \ + r2 = x2 - y2 - (r1 > x1), \ + r3 = x3 - y3 - (r2 > x2)) +#endif + +#ifndef __FP_FRAC_ADDI_4 +/* I always wanted to be a lisp programmer :-> */ +#define __FP_FRAC_ADDI_4(x3,x2,x1,x0,i) \ + (x3 += ((x2 += ((x1 += ((x0 += i) < x0)) < x1) < x2))) +#endif + +/* Convert FP values between word sizes. This appears to be more + * complicated than I'd have expected it to be, so these might be + * wrong... These macros are in any case somewhat bogus because they + * use information about what various FRAC_n variables look like + * internally [eg, that 2 word vars are X_f0 and x_f1]. But so do + * the ones in op-2.h and op-1.h. + */ +#define _FP_FRAC_CONV_1_4(dfs, sfs, D, S) \ + do { \ + _FP_FRAC_SRS_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs), \ + _FP_WFRACBITS_##sfs); \ + D##_f = S##_f[0]; \ + } while (0) + +#define _FP_FRAC_CONV_2_4(dfs, sfs, D, S) \ + do { \ + _FP_FRAC_SRS_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs), \ + _FP_WFRACBITS_##sfs); \ + D##_f0 = S##_f[0]; \ + D##_f1 = S##_f[1]; \ + } while (0) + +/* Assembly/disassembly for converting to/from integral types. + * No shifting or overflow handled here. + */ +/* Put the FP value X into r, which is an integer of size rsize. */ +#define _FP_FRAC_ASSEMBLE_4(r, X, rsize) \ + do { \ + if (rsize <= _FP_W_TYPE_SIZE) \ + r = X##_f[0]; \ + else if (rsize <= 2*_FP_W_TYPE_SIZE) \ + { \ + r = X##_f[1]; \ + r <<= _FP_W_TYPE_SIZE; \ + r += X##_f[0]; \ + } \ + else \ + { \ + /* I'm feeling lazy so we deal with int == 3words (implausible)*/ \ + /* and int == 4words as a single case. */ \ + r = X##_f[3]; \ + r <<= _FP_W_TYPE_SIZE; \ + r += X##_f[2]; \ + r <<= _FP_W_TYPE_SIZE; \ + r += X##_f[1]; \ + r <<= _FP_W_TYPE_SIZE; \ + r += X##_f[0]; \ + } \ + } while (0) + +/* "No disassemble Number Five!" */ +/* move an integer of size rsize into X's fractional part. We rely on + * the _f[] array consisting of words of size _FP_W_TYPE_SIZE to avoid + * having to mask the values we store into it. + */ +#define _FP_FRAC_DISASSEMBLE_4(X, r, rsize) \ + do { \ + X##_f[0] = r; \ + X##_f[1] = (rsize <= _FP_W_TYPE_SIZE ? 0 : r >> _FP_W_TYPE_SIZE); \ + X##_f[2] = (rsize <= 2*_FP_W_TYPE_SIZE ? 0 : r >> 2*_FP_W_TYPE_SIZE); \ + X##_f[3] = (rsize <= 3*_FP_W_TYPE_SIZE ? 0 : r >> 3*_FP_W_TYPE_SIZE); \ + } while (0); + +#define _FP_FRAC_CONV_4_1(dfs, sfs, D, S) \ + do { \ + D##_f[0] = S##_f; \ + D##_f[1] = D##_f[2] = D##_f[3] = 0; \ + _FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs)); \ + } while (0) + +#define _FP_FRAC_CONV_4_2(dfs, sfs, D, S) \ + do { \ + D##_f[0] = S##_f0; \ + D##_f[1] = S##_f1; \ + D##_f[2] = D##_f[3] = 0; \ + _FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs)); \ + } while (0) + +/* FIXME! This has to be written */ +#define _FP_SQRT_MEAT_4(R, S, T, X, q) diff --git a/arch/ppc/math-emu/op-common.h b/arch/ppc/math-emu/op-common.h new file mode 100644 index 000000000..374045830 --- /dev/null +++ b/arch/ppc/math-emu/op-common.h @@ -0,0 +1,690 @@ + +#define _FP_DECL(wc, X) \ + _FP_I_TYPE X##_c, X##_s, X##_e; \ + _FP_FRAC_DECL_##wc(X) + +/* + * Finish truely unpacking a native fp value by classifying the kind + * of fp value and normalizing both the exponent and the fraction. + */ + +#define _FP_UNPACK_CANONICAL(fs, wc, X) \ +do { \ + switch (X##_e) \ + { \ + default: \ + _FP_FRAC_HIGH_##wc(X) |= _FP_IMPLBIT_##fs; \ + _FP_FRAC_SLL_##wc(X, _FP_WORKBITS); \ + X##_e -= _FP_EXPBIAS_##fs; \ + X##_c = FP_CLS_NORMAL; \ + break; \ + \ + case 0: \ + if (_FP_FRAC_ZEROP_##wc(X)) \ + X##_c = FP_CLS_ZERO; \ + else \ + { \ + /* a denormalized number */ \ + _FP_I_TYPE _shift; \ + _FP_FRAC_CLZ_##wc(_shift, X); \ + _shift -= _FP_FRACXBITS_##fs; \ + _FP_FRAC_SLL_##wc(X, (_shift+_FP_WORKBITS)); \ + X##_e -= _FP_EXPBIAS_##fs - 1 + _shift; \ + X##_c = FP_CLS_NORMAL; \ + } \ + break; \ + \ + case _FP_EXPMAX_##fs: \ + if (_FP_FRAC_ZEROP_##wc(X)) \ + X##_c = FP_CLS_INF; \ + else \ + /* we don't differentiate between signaling and quiet nans */ \ + X##_c = FP_CLS_NAN; \ + break; \ + } \ +} while (0) + + +/* + * Before packing the bits back into the native fp result, take care + * of such mundane things as rounding and overflow. Also, for some + * kinds of fp values, the original parts may not have been fully + * extracted -- but that is ok, we can regenerate them now. + */ + +#define _FP_PACK_CANONICAL(fs, wc, X) \ +({int __ret = 0; \ + switch (X##_c) \ + { \ + case FP_CLS_NORMAL: \ + X##_e += _FP_EXPBIAS_##fs; \ + if (X##_e > 0) \ + { \ + __ret |= _FP_ROUND(wc, X); \ + if (_FP_FRAC_OVERP_##wc(fs, X)) \ + { \ + _FP_FRAC_SRL_##wc(X, (_FP_WORKBITS+1)); \ + X##_e++; \ + } \ + else \ + _FP_FRAC_SRL_##wc(X, _FP_WORKBITS); \ + if (X##_e >= _FP_EXPMAX_##fs) \ + { \ + /* overflow to infinity */ \ + X##_e = _FP_EXPMAX_##fs; \ + _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ + __ret |= EFLAG_OVERFLOW; \ + } \ + } \ + else \ + { \ + /* we've got a denormalized number */ \ + X##_e = -X##_e + 1; \ + if (X##_e <= _FP_WFRACBITS_##fs) \ + { \ + _FP_FRAC_SRS_##wc(X, X##_e, _FP_WFRACBITS_##fs); \ + __ret |= _FP_ROUND(wc, X); \ + _FP_FRAC_SLL_##wc(X, 1); \ + if (_FP_FRAC_OVERP_##wc(fs, X)) \ + { \ + X##_e = 1; \ + _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ + } \ + else \ + { \ + X##_e = 0; \ + _FP_FRAC_SRL_##wc(X, _FP_WORKBITS+1); \ + __ret |= EFLAG_UNDERFLOW; \ + } \ + } \ + else \ + { \ + /* underflow to zero */ \ + X##_e = 0; \ + _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ + __ret |= EFLAG_UNDERFLOW; \ + } \ + } \ + break; \ + \ + case FP_CLS_ZERO: \ + X##_e = 0; \ + _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ + break; \ + \ + case FP_CLS_INF: \ + X##_e = _FP_EXPMAX_##fs; \ + _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ + break; \ + \ + case FP_CLS_NAN: \ + X##_e = _FP_EXPMAX_##fs; \ + if (!_FP_KEEPNANFRACP) \ + { \ + _FP_FRAC_SET_##wc(X, _FP_NANFRAC_##fs); \ + X##_s = 0; \ + } \ + else \ + _FP_FRAC_HIGH_##wc(X) |= _FP_QNANBIT_##fs; \ + break; \ + } \ + __ret; \ +}) + + +/* + * Main addition routine. The input values should be cooked. + */ + +#define _FP_ADD(fs, wc, R, X, Y) \ +do { \ + switch (_FP_CLS_COMBINE(X##_c, Y##_c)) \ + { \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL): \ + { \ + /* shift the smaller number so that its exponent matches the larger */ \ + _FP_I_TYPE diff = X##_e - Y##_e; \ + \ + if (diff < 0) \ + { \ + diff = -diff; \ + if (diff <= _FP_WFRACBITS_##fs) \ + _FP_FRAC_SRS_##wc(X, diff, _FP_WFRACBITS_##fs); \ + else if (!_FP_FRAC_ZEROP_##wc(X)) \ + _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc); \ + else \ + _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ + R##_e = Y##_e; \ + } \ + else \ + { \ + if (diff > 0) \ + { \ + if (diff <= _FP_WFRACBITS_##fs) \ + _FP_FRAC_SRS_##wc(Y, diff, _FP_WFRACBITS_##fs); \ + else if (!_FP_FRAC_ZEROP_##wc(Y)) \ + _FP_FRAC_SET_##wc(Y, _FP_MINFRAC_##wc); \ + else \ + _FP_FRAC_SET_##wc(Y, _FP_ZEROFRAC_##wc); \ + } \ + R##_e = X##_e; \ + } \ + \ + R##_c = FP_CLS_NORMAL; \ + \ + if (X##_s == Y##_s) \ + { \ + R##_s = X##_s; \ + _FP_FRAC_ADD_##wc(R, X, Y); \ + if (_FP_FRAC_OVERP_##wc(fs, R)) \ + { \ + _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs); \ + R##_e++; \ + } \ + } \ + else \ + { \ + R##_s = X##_s; \ + _FP_FRAC_SUB_##wc(R, X, Y); \ + if (_FP_FRAC_ZEROP_##wc(R)) \ + { \ + /* return an exact zero */ \ + if (FP_ROUNDMODE == FP_RND_MINF) \ + R##_s |= Y##_s; \ + else \ + R##_s &= Y##_s; \ + R##_c = FP_CLS_ZERO; \ + } \ + else \ + { \ + if (_FP_FRAC_NEGP_##wc(R)) \ + { \ + _FP_FRAC_SUB_##wc(R, Y, X); \ + R##_s = Y##_s; \ + } \ + \ + /* renormalize after subtraction */ \ + _FP_FRAC_CLZ_##wc(diff, R); \ + diff -= _FP_WFRACXBITS_##fs; \ + if (diff) \ + { \ + R##_e -= diff; \ + _FP_FRAC_SLL_##wc(R, diff); \ + } \ + } \ + } \ + break; \ + } \ + \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN): \ + _FP_CHOOSENAN(fs, wc, R, X, Y); \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO): \ + R##_e = X##_e; \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL): \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF): \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO): \ + _FP_FRAC_COPY_##wc(R, X); \ + R##_s = X##_s; \ + R##_c = X##_c; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL): \ + R##_e = Y##_e; \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN): \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN): \ + _FP_FRAC_COPY_##wc(R, Y); \ + R##_s = Y##_s; \ + R##_c = Y##_c; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF): \ + if (X##_s != Y##_s) \ + { \ + /* +INF + -INF => NAN */ \ + _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \ + R##_s = X##_s ^ Y##_s; \ + R##_c = FP_CLS_NAN; \ + break; \ + } \ + /* FALLTHRU */ \ + \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL): \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO): \ + R##_s = X##_s; \ + R##_c = FP_CLS_INF; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF): \ + R##_s = Y##_s; \ + R##_c = FP_CLS_INF; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO): \ + /* make sure the sign is correct */ \ + if (FP_ROUNDMODE == FP_RND_MINF) \ + R##_s = X##_s | Y##_s; \ + else \ + R##_s = X##_s & Y##_s; \ + R##_c = FP_CLS_ZERO; \ + break; \ + \ + default: \ + abort(); \ + } \ +} while (0) + + +/* + * Main negation routine. FIXME -- when we care about setting exception + * bits reliably, this will not do. We should examine all of the fp classes. + */ + +#define _FP_NEG(fs, wc, R, X) \ + do { \ + _FP_FRAC_COPY_##wc(R, X); \ + R##_c = X##_c; \ + R##_e = X##_e; \ + R##_s = 1 ^ X##_s; \ + } while (0) + + +/* + * Main multiplication routine. The input values should be cooked. + */ + +#define _FP_MUL(fs, wc, R, X, Y) \ +do { \ + R##_s = X##_s ^ Y##_s; \ + switch (_FP_CLS_COMBINE(X##_c, Y##_c)) \ + { \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL): \ + R##_c = FP_CLS_NORMAL; \ + R##_e = X##_e + Y##_e + 1; \ + \ + _FP_MUL_MEAT_##fs(R,X,Y); \ + \ + if (_FP_FRAC_OVERP_##wc(fs, R)) \ + _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs); \ + else \ + R##_e--; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN): \ + _FP_CHOOSENAN(fs, wc, R, X, Y); \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL): \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF): \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO): \ + R##_s = X##_s; \ + \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF): \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO): \ + _FP_FRAC_COPY_##wc(R, X); \ + R##_c = X##_c; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN): \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN): \ + R##_s = Y##_s; \ + \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF): \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO): \ + _FP_FRAC_COPY_##wc(R, Y); \ + R##_c = Y##_c; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF): \ + R##_c = FP_CLS_NAN; \ + _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \ + break; \ + \ + default: \ + abort(); \ + } \ +} while (0) + + +/* + * Main division routine. The input values should be cooked. + */ + +#define _FP_DIV(fs, wc, R, X, Y) \ +do { \ + R##_s = X##_s ^ Y##_s; \ + switch (_FP_CLS_COMBINE(X##_c, Y##_c)) \ + { \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL): \ + R##_c = FP_CLS_NORMAL; \ + R##_e = X##_e - Y##_e; \ + \ + _FP_DIV_MEAT_##fs(R,X,Y); \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN): \ + _FP_CHOOSENAN(fs, wc, R, X, Y); \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL): \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF): \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO): \ + R##_s = X##_s; \ + _FP_FRAC_COPY_##wc(R, X); \ + R##_c = X##_c; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN): \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN): \ + R##_s = Y##_s; \ + _FP_FRAC_COPY_##wc(R, Y); \ + R##_c = Y##_c; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL): \ + R##_c = FP_CLS_ZERO; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO): \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO): \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL): \ + R##_c = FP_CLS_INF; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO): \ + R##_c = FP_CLS_NAN; \ + _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \ + break; \ + \ + default: \ + abort(); \ + } \ +} while (0) + + +/* + * Main differential comparison routine. The inputs should be raw not + * cooked. The return is -1,0,1 for normal values, 2 otherwise. + */ + +#define _FP_CMP(fs, wc, ret, X, Y, un) \ + do { \ + /* NANs are unordered */ \ + if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(X)) \ + || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(Y))) \ + { \ + ret = un; \ + } \ + else \ + { \ + int __x_zero = (!X##_e && _FP_FRAC_ZEROP_##wc(X)) ? 1 : 0; \ + int __y_zero = (!Y##_e && _FP_FRAC_ZEROP_##wc(Y)) ? 1 : 0; \ + \ + if (__x_zero && __y_zero) \ + ret = 0; \ + else if (__x_zero) \ + ret = Y##_s ? 1 : -1; \ + else if (__y_zero) \ + ret = X##_s ? -1 : 1; \ + else if (X##_s != Y##_s) \ + ret = X##_s ? -1 : 1; \ + else if (X##_e > Y##_e) \ + ret = X##_s ? -1 : 1; \ + else if (X##_e < Y##_e) \ + ret = X##_s ? 1 : -1; \ + else if (_FP_FRAC_GT_##wc(X, Y)) \ + ret = X##_s ? -1 : 1; \ + else if (_FP_FRAC_GT_##wc(Y, X)) \ + ret = X##_s ? 1 : -1; \ + else \ + ret = 0; \ + } \ + } while (0) + + +/* Simplification for strict equality. */ + +#define _FP_CMP_EQ(fs, wc, ret, X, Y) \ + do { \ + /* NANs are unordered */ \ + if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(X)) \ + || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(Y))) \ + { \ + ret = 1; \ + } \ + else \ + { \ + ret = !(X##_e == Y##_e \ + && _FP_FRAC_EQ_##wc(X, Y) \ + && (X##_s == Y##_s || !X##_e && _FP_FRAC_ZEROP_##wc(X))); \ + } \ + } while (0) + +/* + * Main square root routine. The input value should be cooked. + */ + +#define _FP_SQRT(fs, wc, R, X) \ +do { \ + _FP_FRAC_DECL_##wc(T); _FP_FRAC_DECL_##wc(S); \ + _FP_W_TYPE q; \ + switch (X##_c) \ + { \ + case FP_CLS_NAN: \ + R##_s = 0; \ + R##_c = FP_CLS_NAN; \ + _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ + break; \ + case FP_CLS_INF: \ + if (X##_s) \ + { \ + R##_s = 0; \ + R##_c = FP_CLS_NAN; /* sNAN */ \ + } \ + else \ + { \ + R##_s = 0; \ + R##_c = FP_CLS_INF; /* sqrt(+inf) = +inf */ \ + } \ + break; \ + case FP_CLS_ZERO: \ + R##_s = X##_s; \ + R##_c = FP_CLS_ZERO; /* sqrt(+-0) = +-0 */ \ + break; \ + case FP_CLS_NORMAL: \ + R##_s = 0; \ + if (X##_s) \ + { \ + R##_c = FP_CLS_NAN; /* sNAN */ \ + break; \ + } \ + R##_c = FP_CLS_NORMAL; \ + if (X##_e & 1) \ + _FP_FRAC_SLL_##wc(X, 1); \ + R##_e = X##_e >> 1; \ + _FP_FRAC_SET_##wc(S, _FP_ZEROFRAC_##wc); \ + _FP_FRAC_SET_##wc(R, _FP_ZEROFRAC_##wc); \ + q = _FP_OVERFLOW_##fs; \ + _FP_FRAC_SLL_##wc(X, 1); \ + _FP_SQRT_MEAT_##wc(R, S, T, X, q); \ + _FP_FRAC_SRL_##wc(R, 1); \ + } \ + } while (0) + +/* + * Convert from FP to integer + */ + +/* "When a NaN, infinity, large positive argument >= 2147483648.0, or + * large negative argument <= -2147483649.0 is converted to an integer, + * the invalid_current bit...should be set and fp_exception_IEEE_754 should + * be raised. If the floating point invalid trap is disabled, no trap occurs + * and a numerical result is generated: if the sign bit of the operand + * is 0, the result is 2147483647; if the sign bit of the operand is 1, + * the result is -2147483648." + * Similarly for conversion to extended ints, except that the boundaries + * are >= 2^63, <= -(2^63 + 1), and the results are 2^63 + 1 for s=0 and + * -2^63 for s=1. + * -- SPARC Architecture Manual V9, Appendix B, which specifies how + * SPARCs resolve implementation dependencies in the IEEE-754 spec. + * I don't believe that the code below follows this. I'm not even sure + * it's right! + * It doesn't cope with needing to convert to an n bit integer when there + * is no n bit integer type. Fortunately gcc provides long long so this + * isn't a problem for sparc32. + * I have, however, fixed its NaN handling to conform as above. + * -- PMM 02/1998 + * NB: rsigned is not 'is r declared signed?' but 'should the value stored + * in r be signed or unsigned?'. r is always(?) declared unsigned. + * Comments below are mine, BTW -- PMM + */ +#define _FP_TO_INT(fs, wc, r, X, rsize, rsigned) \ + do { \ + switch (X##_c) \ + { \ + case FP_CLS_NORMAL: \ + if (X##_e < 0) \ + { \ + /* case FP_CLS_NAN: see above! */ \ + case FP_CLS_ZERO: \ + r = 0; \ + } \ + else if (X##_e >= rsize - (rsigned != 0)) \ + { /* overflow */ \ + case FP_CLS_NAN: \ + case FP_CLS_INF: \ + if (rsigned) \ + { \ + r = 1; \ + r <<= rsize - 1; \ + r -= 1 - X##_s; \ + } \ + else \ + { \ + r = 0; \ + if (!X##_s) \ + r = ~r; \ + } \ + } \ + else \ + { \ + if (_FP_W_TYPE_SIZE*wc < rsize) \ + { \ + _FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \ + r <<= X##_e - _FP_WFRACBITS_##fs; \ + } \ + else \ + { \ + if (X##_e >= _FP_WFRACBITS_##fs) \ + _FP_FRAC_SLL_##wc(X, (X##_e - _FP_WFRACBITS_##fs + 1));\ + else \ + _FP_FRAC_SRL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1));\ + _FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \ + } \ + if (rsigned && X##_s) \ + r = -r; \ + } \ + break; \ + } \ + } while (0) + +#define _FP_FROM_INT(fs, wc, X, r, rsize, rtype) \ + do { \ + if (r) \ + { \ + X##_c = FP_CLS_NORMAL; \ + \ + if ((X##_s = (r < 0))) \ + r = -r; \ + /* Note that `r' is now considered unsigned, so we don't have \ + to worry about the single signed overflow case. */ \ + \ + if (rsize <= _FP_W_TYPE_SIZE) \ + __FP_CLZ(X##_e, r); \ + else \ + __FP_CLZ_2(X##_e, (_FP_W_TYPE)(r >> _FP_W_TYPE_SIZE), \ + (_FP_W_TYPE)r); \ + if (rsize < _FP_W_TYPE_SIZE) \ + X##_e -= (_FP_W_TYPE_SIZE - rsize); \ + X##_e = rsize - X##_e - 1; \ + \ + if (_FP_FRACBITS_##fs < rsize && _FP_WFRACBITS_##fs < X##_e) \ + __FP_FRAC_SRS_1(r, (X##_e - _FP_WFRACBITS_##fs), rsize); \ + r &= ~((_FP_W_TYPE)1 << X##_e); \ + _FP_FRAC_DISASSEMBLE_##wc(X, ((unsigned rtype)r), rsize); \ + _FP_FRAC_SLL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1)); \ + } \ + else \ + { \ + X##_c = FP_CLS_ZERO, X##_s = 0; \ + } \ + } while (0) + + +#define FP_CONV(dfs,sfs,dwc,swc,D,S) \ + do { \ + _FP_FRAC_CONV_##dwc##_##swc(dfs, sfs, D, S); \ + D##_e = S##_e; \ + D##_c = S##_c; \ + D##_s = S##_s; \ + } while (0) + +/* + * Helper primitives. + */ + +/* Count leading zeros in a word. */ + +#ifndef __FP_CLZ +#if _FP_W_TYPE_SIZE < 64 +/* this is just to shut the compiler up about shifts > word length -- PMM 02/1998 */ +#define __FP_CLZ(r, x) \ + do { \ + _FP_W_TYPE _t = (x); \ + r = _FP_W_TYPE_SIZE - 1; \ + if (_t > 0xffff) r -= 16; \ + if (_t > 0xffff) _t >>= 16; \ + if (_t > 0xff) r -= 8; \ + if (_t > 0xff) _t >>= 8; \ + if (_t & 0xf0) r -= 4; \ + if (_t & 0xf0) _t >>= 4; \ + if (_t & 0xc) r -= 2; \ + if (_t & 0xc) _t >>= 2; \ + if (_t & 0x2) r -= 1; \ + } while (0) +#else /* not _FP_W_TYPE_SIZE < 64 */ +#define __FP_CLZ(r, x) \ + do { \ + _FP_W_TYPE _t = (x); \ + r = _FP_W_TYPE_SIZE - 1; \ + if (_t > 0xffffffff) r -= 32; \ + if (_t > 0xffffffff) _t >>= 32; \ + if (_t > 0xffff) r -= 16; \ + if (_t > 0xffff) _t >>= 16; \ + if (_t > 0xff) r -= 8; \ + if (_t > 0xff) _t >>= 8; \ + if (_t & 0xf0) r -= 4; \ + if (_t & 0xf0) _t >>= 4; \ + if (_t & 0xc) r -= 2; \ + if (_t & 0xc) _t >>= 2; \ + if (_t & 0x2) r -= 1; \ + } while (0) +#endif /* not _FP_W_TYPE_SIZE < 64 */ +#endif /* ndef __FP_CLZ */ + +#define _FP_DIV_HELP_imm(q, r, n, d) \ + do { \ + q = n / d, r = n % d; \ + } while (0) + diff --git a/arch/ppc/math-emu/sfp-machine.h b/arch/ppc/math-emu/sfp-machine.h new file mode 100644 index 000000000..73b7e69c6 --- /dev/null +++ b/arch/ppc/math-emu/sfp-machine.h @@ -0,0 +1,377 @@ +/* Machine-dependent software floating-point definitions. PPC version. + Copyright (C) 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Actually, this is a PPC (32bit) version, written based on the + i386, sparc, and sparc64 versions, by me, + Peter Maydell (pmaydell@chiark.greenend.org.uk). + Comments are by and large also mine, although they may be inaccurate. + + In picking out asm fragments I've gone with the lowest common + denominator, which also happens to be the hardware I have :-> + That is, a SPARC without hardware multiply and divide. + */ + +/* basic word size definitions */ +#define _FP_W_TYPE_SIZE 32 +#define _FP_W_TYPE unsigned long +#define _FP_WS_TYPE signed long +#define _FP_I_TYPE long + +#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2)) +#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1)) +#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2)) + +/* You can optionally code some things like addition in asm. For + * example, i386 defines __FP_FRAC_ADD_2 as asm. If you don't + * then you get a fragment of C code [if you change an #ifdef 0 + * in op-2.h] or a call to add_ssaaaa (see below). + * Good places to look for asm fragments to use are gcc and glibc. + * gcc's longlong.h is useful. + */ + +/* We need to know how to multiply and divide. If the host word size + * is >= 2*fracbits you can use FP_MUL_MEAT_n_imm(t,R,X,Y) which + * codes the multiply with whatever gcc does to 'a * b'. + * _FP_MUL_MEAT_n_wide(t,R,X,Y,f) is used when you have an asm + * function that can multiply two 1W values and get a 2W result. + * Otherwise you're stuck with _FP_MUL_MEAT_n_hard(t,R,X,Y) which + * does bitshifting to avoid overflow. + * For division there is FP_DIV_MEAT_n_imm(t,R,X,Y,f) for word size + * >= 2*fracbits, where f is either _FP_DIV_HELP_imm or + * _FP_DIV_HELP_ldiv (see op-1.h). + * _FP_DIV_MEAT_udiv() is if you have asm to do 2W/1W => (1W, 1W). + * [GCC and glibc have longlong.h which has the asm macro udiv_qrnnd + * to do this.] + * In general, 'n' is the number of words required to hold the type, + * and 't' is either S, D or Q for single/double/quad. + * -- PMM + */ +/* Example: SPARC64: + * #define _FP_MUL_MEAT_S(R,X,Y) _FP_MUL_MEAT_1_imm(S,R,X,Y) + * #define _FP_MUL_MEAT_D(R,X,Y) _FP_MUL_MEAT_1_wide(D,R,X,Y,umul_ppmm) + * #define _FP_MUL_MEAT_Q(R,X,Y) _FP_MUL_MEAT_2_wide(Q,R,X,Y,umul_ppmm) + * + * #define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_imm(S,R,X,Y,_FP_DIV_HELP_imm) + * #define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_1_udiv(D,R,X,Y) + * #define _FP_DIV_MEAT_Q(R,X,Y) _FP_DIV_MEAT_2_udiv_64(Q,R,X,Y) + * + * Example: i386: + * #define _FP_MUL_MEAT_S(R,X,Y) _FP_MUL_MEAT_1_wide(S,R,X,Y,_i386_mul_32_64) + * #define _FP_MUL_MEAT_D(R,X,Y) _FP_MUL_MEAT_2_wide(D,R,X,Y,_i386_mul_32_64) + * + * #define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_udiv(S,R,X,Y,_i386_div_64_32) + * #define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_2_udiv_64(D,R,X,Y) + */ + +#define _FP_MUL_MEAT_S(R,X,Y) _FP_MUL_MEAT_1_wide(S,R,X,Y,umul_ppmm) +#define _FP_MUL_MEAT_D(R,X,Y) _FP_MUL_MEAT_2_wide(D,R,X,Y,umul_ppmm) + +#define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_udiv(S,R,X,Y) +#define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_2_udiv_64(D,R,X,Y) + +/* These macros define what NaN looks like. They're supposed to expand to + * a comma-separated set of 32bit unsigned ints that encode NaN. + */ +#define _FP_NANFRAC_S _FP_QNANBIT_S +#define _FP_NANFRAC_D _FP_QNANBIT_D, 0 +#define _FP_NANFRAC_Q _FP_QNANBIT_Q, 0, 0, 0 + +#define _FP_KEEPNANFRACP 1 + +/* This macro appears to be called when both X and Y are NaNs, and + * has to choose one and copy it to R. i386 goes for the larger of the + * two, sparc64 just picks Y. I don't understand this at all so I'll + * go with sparc64 because it's shorter :-> -- PMM + */ +#define _FP_CHOOSENAN(fs, wc, R, X, Y) \ + do { \ + R##_s = Y##_s; \ + _FP_FRAC_COPY_##wc(R,Y); \ + R##_c = FP_CLS_NAN; \ + } while (0) + + +extern void fp_unpack_d(long *, unsigned long *, unsigned long *, + long *, long *, void *); +extern int fp_pack_d(void *, long, unsigned long, unsigned long, long, long); +extern int fp_pack_ds(void *, long, unsigned long, unsigned long, long, long); + +#define __FP_UNPACK_RAW_1(fs, X, val) \ + do { \ + union _FP_UNION_##fs *_flo = \ + (union _FP_UNION_##fs *)val; \ + \ + X##_f = _flo->bits.frac; \ + X##_e = _flo->bits.exp; \ + X##_s = _flo->bits.sign; \ + } while (0) + +#define __FP_UNPACK_RAW_2(fs, X, val) \ + do { \ + union _FP_UNION_##fs *_flo = \ + (union _FP_UNION_##fs *)val; \ + \ + X##_f0 = _flo->bits.frac0; \ + X##_f1 = _flo->bits.frac1; \ + X##_e = _flo->bits.exp; \ + X##_s = _flo->bits.sign; \ + } while (0) + +#define __FP_UNPACK_S(X,val) \ + do { \ + __FP_UNPACK_RAW_1(S,X,val); \ + _FP_UNPACK_CANONICAL(S,1,X); \ + } while (0) + +#define __FP_UNPACK_D(X,val) \ + fp_unpack_d(&X##_s, &X##_f1, &X##_f0, &X##_e, &X##_c, val) + +#define __FP_PACK_RAW_1(fs, val, X) \ + do { \ + union _FP_UNION_##fs *_flo = \ + (union _FP_UNION_##fs *)val; \ + \ + _flo->bits.frac = X##_f; \ + _flo->bits.exp = X##_e; \ + _flo->bits.sign = X##_s; \ + } while (0) + +#define __FP_PACK_RAW_2(fs, val, X) \ + do { \ + union _FP_UNION_##fs *_flo = \ + (union _FP_UNION_##fs *)val; \ + \ + _flo->bits.frac0 = X##_f0; \ + _flo->bits.frac1 = X##_f1; \ + _flo->bits.exp = X##_e; \ + _flo->bits.sign = X##_s; \ + } while (0) + +#include <linux/kernel.h> +#include <linux/sched.h> + +#define __FPU_FPSCR (current->tss.fpscr) + +/* We only actually write to the destination register + * if exceptions signalled (if any) will not trap. + */ +#define __FPU_ENABLED_EXC \ +({ \ + (__FPU_FPSCR >> 3) & 0x1f; \ +}) + +#define __FPU_TRAP_P(bits) \ + ((__FPU_ENABLED_EXC & (bits)) != 0) + +#define __FP_PACK_S(val,X) \ +({ int __exc = _FP_PACK_CANONICAL(S,1,X); \ + if(!__exc || !__FPU_TRAP_P(__exc)) \ + __FP_PACK_RAW_1(S,val,X); \ + __exc; \ +}) + +#define __FP_PACK_D(val,X) \ + fp_pack_d(val, X##_s, X##_f1, X##_f0, X##_e, X##_c) + +#define __FP_PACK_DS(val,X) \ + fp_pack_ds(val, X##_s, X##_f1, X##_f0, X##_e, X##_c) + +/* Obtain the current rounding mode. */ +#define FP_ROUNDMODE \ +({ \ + __FPU_FPSCR & 0x3; \ +}) + +/* the asm fragments go here: all these are taken from glibc-2.0.5's + * stdlib/longlong.h + */ + +#include <linux/types.h> +#include <asm/byteorder.h> + +/* add_ssaaaa is used in op-2.h and should be equivalent to + * #define add_ssaaaa(sh,sl,ah,al,bh,bl) (sh = ah+bh+ (( sl = al+bl) < al)) + * add_ssaaaa(high_sum, low_sum, high_addend_1, low_addend_1, + * high_addend_2, low_addend_2) adds two UWtype integers, composed by + * HIGH_ADDEND_1 and LOW_ADDEND_1, and HIGH_ADDEND_2 and LOW_ADDEND_2 + * respectively. The result is placed in HIGH_SUM and LOW_SUM. Overflow + * (i.e. carry out) is not stored anywhere, and is lost. + */ +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + do { \ + if (__builtin_constant_p (bh) && (bh) == 0) \ + __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "%r" ((USItype)(ah)), \ + "%r" ((USItype)(al)), \ + "rI" ((USItype)(bl))); \ + else if (__builtin_constant_p (bh) && (bh) ==~(USItype) 0) \ + __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "%r" ((USItype)(ah)), \ + "%r" ((USItype)(al)), \ + "rI" ((USItype)(bl))); \ + else \ + __asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "%r" ((USItype)(ah)), \ + "r" ((USItype)(bh)), \ + "%r" ((USItype)(al)), \ + "rI" ((USItype)(bl))); \ + } while (0) + +/* sub_ddmmss is used in op-2.h and udivmodti4.c and should be equivalent to + * #define sub_ddmmss(sh, sl, ah, al, bh, bl) (sh = ah-bh - ((sl = al-bl) > al)) + * sub_ddmmss(high_difference, low_difference, high_minuend, low_minuend, + * high_subtrahend, low_subtrahend) subtracts two two-word UWtype integers, + * composed by HIGH_MINUEND_1 and LOW_MINUEND_1, and HIGH_SUBTRAHEND_2 and + * LOW_SUBTRAHEND_2 respectively. The result is placed in HIGH_DIFFERENCE + * and LOW_DIFFERENCE. Overflow (i.e. carry out) is not stored anywhere, + * and is lost. + */ +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + do { \ + if (__builtin_constant_p (ah) && (ah) == 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "r" ((USItype)(bh)), \ + "rI" ((USItype)(al)), \ + "r" ((USItype)(bl))); \ + else if (__builtin_constant_p (ah) && (ah) ==~(USItype) 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "r" ((USItype)(bh)), \ + "rI" ((USItype)(al)), \ + "r" ((USItype)(bl))); \ + else if (__builtin_constant_p (bh) && (bh) == 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "r" ((USItype)(ah)), \ + "rI" ((USItype)(al)), \ + "r" ((USItype)(bl))); \ + else if (__builtin_constant_p (bh) && (bh) ==~(USItype) 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "r" ((USItype)(ah)), \ + "rI" ((USItype)(al)), \ + "r" ((USItype)(bl))); \ + else \ + __asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "r" ((USItype)(ah)), \ + "r" ((USItype)(bh)), \ + "rI" ((USItype)(al)), \ + "r" ((USItype)(bl))); \ + } while (0) + +/* asm fragments for mul and div */ + +/* umul_ppmm(high_prod, low_prod, multipler, multiplicand) multiplies two + * UWtype integers MULTIPLER and MULTIPLICAND, and generates a two UWtype + * word product in HIGH_PROD and LOW_PROD. + */ +#define umul_ppmm(ph, pl, m0, m1) \ + do { \ + USItype __m0 = (m0), __m1 = (m1); \ + __asm__ ("mulhwu %0,%1,%2" \ + : "=r" ((USItype)(ph)) \ + : "%r" (__m0), \ + "r" (__m1)); \ + (pl) = __m0 * __m1; \ + } while (0) + +/* udiv_qrnnd(quotient, remainder, high_numerator, low_numerator, + * denominator) divides a UDWtype, composed by the UWtype integers + * HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and places the quotient + * in QUOTIENT and the remainder in REMAINDER. HIGH_NUMERATOR must be less + * than DENOMINATOR for correct operation. If, in addition, the most + * significant bit of DENOMINATOR must be 1, then the pre-processor symbol + * UDIV_NEEDS_NORMALIZATION is defined to 1. + */ +#define udiv_qrnnd(q, r, n1, n0, d) \ + do { \ + UWtype __d1, __d0, __q1, __q0, __r1, __r0, __m; \ + __d1 = __ll_highpart (d); \ + __d0 = __ll_lowpart (d); \ + \ + __r1 = (n1) % __d1; \ + __q1 = (n1) / __d1; \ + __m = (UWtype) __q1 * __d0; \ + __r1 = __r1 * __ll_B | __ll_highpart (n0); \ + if (__r1 < __m) \ + { \ + __q1--, __r1 += (d); \ + if (__r1 >= (d)) /* we didn't get carry when adding to __r1 */ \ + if (__r1 < __m) \ + __q1--, __r1 += (d); \ + } \ + __r1 -= __m; \ + \ + __r0 = __r1 % __d1; \ + __q0 = __r1 / __d1; \ + __m = (UWtype) __q0 * __d0; \ + __r0 = __r0 * __ll_B | __ll_lowpart (n0); \ + if (__r0 < __m) \ + { \ + __q0--, __r0 += (d); \ + if (__r0 >= (d)) \ + if (__r0 < __m) \ + __q0--, __r0 += (d); \ + } \ + __r0 -= __m; \ + \ + (q) = (UWtype) __q1 * __ll_B | __q0; \ + (r) = __r0; \ + } while (0) + +#define UDIV_NEEDS_NORMALIZATION 1 + +#define abort() \ + return 0 + +#ifdef __BIG_ENDIAN +#define __BYTE_ORDER __BIG_ENDIAN +#else +#define __BYTE_ORDER __LITTLE_ENDIAN +#endif + +/* Exception flags. */ +#define EFLAG_INVALID (1 << (31 - 2)) +#define EFLAG_OVERFLOW (1 << (31 - 3)) +#define EFLAG_UNDERFLOW (1 << (31 - 4)) +#define EFLAG_DIVZERO (1 << (31 - 5)) +#define EFLAG_INEXACT (1 << (31 - 6)) + +#define EFLAG_VXSNAN (1 << (31 - 7)) +#define EFLAG_VXISI (1 << (31 - 8)) +#define EFLAG_VXIDI (1 << (31 - 9)) +#define EFLAG_VXZDZ (1 << (31 - 10)) +#define EFLAG_VXIMZ (1 << (31 - 11)) +#define EFLAG_VXVC (1 << (31 - 12)) +#define EFLAG_VXSOFT (1 << (31 - 21)) +#define EFLAG_VXSQRT (1 << (31 - 22)) +#define EFLAG_VXCVI (1 << (31 - 23)) diff --git a/arch/ppc/math-emu/single.h b/arch/ppc/math-emu/single.h new file mode 100644 index 000000000..f19d99451 --- /dev/null +++ b/arch/ppc/math-emu/single.h @@ -0,0 +1,66 @@ +/* + * Definitions for IEEE Single Precision + */ + +#if _FP_W_TYPE_SIZE < 32 +#error "Here's a nickel kid. Go buy yourself a real computer." +#endif + +#define _FP_FRACBITS_S 24 +#define _FP_FRACXBITS_S (_FP_W_TYPE_SIZE - _FP_FRACBITS_S) +#define _FP_WFRACBITS_S (_FP_WORKBITS + _FP_FRACBITS_S) +#define _FP_WFRACXBITS_S (_FP_W_TYPE_SIZE - _FP_WFRACBITS_S) +#define _FP_EXPBITS_S 8 +#define _FP_EXPBIAS_S 127 +#define _FP_EXPMAX_S 255 +#define _FP_QNANBIT_S ((_FP_W_TYPE)1 << (_FP_FRACBITS_S-2)) +#define _FP_IMPLBIT_S ((_FP_W_TYPE)1 << (_FP_FRACBITS_S-1)) +#define _FP_OVERFLOW_S ((_FP_W_TYPE)1 << (_FP_WFRACBITS_S)) + +/* The implementation of _FP_MUL_MEAT_S and _FP_DIV_MEAT_S should be + chosen by the target machine. */ + +union _FP_UNION_S +{ + float flt; + struct { +#if __BYTE_ORDER == __BIG_ENDIAN + unsigned sign : 1; + unsigned exp : _FP_EXPBITS_S; + unsigned frac : _FP_FRACBITS_S - (_FP_IMPLBIT_S != 0); +#else + unsigned frac : _FP_FRACBITS_S - (_FP_IMPLBIT_S != 0); + unsigned exp : _FP_EXPBITS_S; + unsigned sign : 1; +#endif + } bits __attribute__((packed)); +}; + +#define FP_DECL_S(X) _FP_DECL(1,X) +#define FP_UNPACK_RAW_S(X,val) _FP_UNPACK_RAW_1(S,X,val) +#define FP_PACK_RAW_S(val,X) _FP_PACK_RAW_1(S,val,X) + +#define FP_UNPACK_S(X,val) \ + do { \ + _FP_UNPACK_RAW_1(S,X,val); \ + _FP_UNPACK_CANONICAL(S,1,X); \ + } while (0) + +#define FP_PACK_S(val,X) \ + do { \ + _FP_PACK_CANONICAL(S,1,X); \ + _FP_PACK_RAW_1(S,val,X); \ + } while (0) + +#define FP_NEG_S(R,X) _FP_NEG(S,1,R,X) +#define FP_ADD_S(R,X,Y) _FP_ADD(S,1,R,X,Y) +#define FP_SUB_S(R,X,Y) _FP_SUB(S,1,R,X,Y) +#define FP_MUL_S(R,X,Y) _FP_MUL(S,1,R,X,Y) +#define FP_DIV_S(R,X,Y) _FP_DIV(S,1,R,X,Y) +#define FP_SQRT_S(R,X) _FP_SQRT(S,1,R,X) + +#define FP_CMP_S(r,X,Y,un) _FP_CMP(S,1,r,X,Y,un) +#define FP_CMP_EQ_S(r,X,Y) _FP_CMP_EQ(S,1,r,X,Y) + +#define FP_TO_INT_S(r,X,rsz,rsg) _FP_TO_INT(S,1,r,X,rsz,rsg) +#define FP_FROM_INT_S(X,r,rs,rt) _FP_FROM_INT(S,1,X,r,rs,rt) diff --git a/arch/ppc/math-emu/soft-fp.h b/arch/ppc/math-emu/soft-fp.h new file mode 100644 index 000000000..cca39598f --- /dev/null +++ b/arch/ppc/math-emu/soft-fp.h @@ -0,0 +1,104 @@ +#ifndef SOFT_FP_H +#define SOFT_FP_H + +#include "sfp-machine.h" + +#define _FP_WORKBITS 3 +#define _FP_WORK_LSB ((_FP_W_TYPE)1 << 3) +#define _FP_WORK_ROUND ((_FP_W_TYPE)1 << 2) +#define _FP_WORK_GUARD ((_FP_W_TYPE)1 << 1) +#define _FP_WORK_STICKY ((_FP_W_TYPE)1 << 0) + +#ifndef FP_RND_NEAREST +# define FP_RND_NEAREST 0 +# define FP_RND_ZERO 1 +# define FP_RND_PINF 2 +# define FP_RND_MINF 3 +#ifndef FP_ROUNDMODE +# define FP_ROUNDMODE FP_RND_NEAREST +#endif +#endif + +#define _FP_ROUND_NEAREST(wc, X) \ +({ int __ret = 0; \ + int __frac = _FP_FRAC_LOW_##wc(X) & 15; \ + if (__frac & 7) { \ + __ret = EFLAG_INEXACT; \ + if ((__frac & 7) != _FP_WORK_ROUND) \ + _FP_FRAC_ADDI_##wc(X, _FP_WORK_ROUND); \ + else if (__frac & _FP_WORK_LSB) \ + _FP_FRAC_ADDI_##wc(X, _FP_WORK_ROUND); \ + } \ + __ret; \ +}) + +#define _FP_ROUND_ZERO(wc, X) \ +({ int __ret = 0; \ + if (_FP_FRAC_LOW_##wc(X) & 7) \ + __ret = EFLAG_INEXACT; \ + __ret; \ +}) + +#define _FP_ROUND_PINF(wc, X) \ +({ int __ret = EFLAG_INEXACT; \ + if (!X##_s && (_FP_FRAC_LOW_##wc(X) & 7)) \ + _FP_FRAC_ADDI_##wc(X, _FP_WORK_LSB); \ + else __ret = 0; \ + __ret; \ +}) + +#define _FP_ROUND_MINF(wc, X) \ +({ int __ret = EFLAG_INEXACT; \ + if (X##_s && (_FP_FRAC_LOW_##wc(X) & 7)) \ + _FP_FRAC_ADDI_##wc(X, _FP_WORK_LSB); \ + else __ret = 0; \ + __ret; \ +}) + +#define _FP_ROUND(wc, X) \ +({ int __ret = 0; \ + switch (FP_ROUNDMODE) \ + { \ + case FP_RND_NEAREST: \ + __ret |= _FP_ROUND_NEAREST(wc,X); \ + break; \ + case FP_RND_ZERO: \ + __ret |= _FP_ROUND_ZERO(wc,X); \ + break; \ + case FP_RND_PINF: \ + __ret |= _FP_ROUND_PINF(wc,X); \ + break; \ + case FP_RND_MINF: \ + __ret |= _FP_ROUND_MINF(wc,X); \ + break; \ + }; \ + __ret; \ +}) + +#define FP_CLS_NORMAL 0 +#define FP_CLS_ZERO 1 +#define FP_CLS_INF 2 +#define FP_CLS_NAN 3 + +#define _FP_CLS_COMBINE(x,y) (((x) << 2) | (y)) + +#include "op-1.h" +#include "op-2.h" +#include "op-4.h" +#include "op-common.h" + +/* Sigh. Silly things longlong.h needs. */ +#define UWtype _FP_W_TYPE +#define W_TYPE_SIZE _FP_W_TYPE_SIZE + +typedef int SItype __attribute__((mode(SI))); +typedef int DItype __attribute__((mode(DI))); +typedef unsigned int USItype __attribute__((mode(SI))); +typedef unsigned int UDItype __attribute__((mode(DI))); +#if _FP_W_TYPE_SIZE == 32 +typedef unsigned int UHWtype __attribute__((mode(HI))); +#elif _FP_W_TYPE_SIZE == 64 +typedef USItype UHWtype; +#endif + +#endif diff --git a/arch/ppc/math-emu/stfd.c b/arch/ppc/math-emu/stfd.c new file mode 100644 index 000000000..2febc6344 --- /dev/null +++ b/arch/ppc/math-emu/stfd.c @@ -0,0 +1,23 @@ +/* $Id: stfd.c,v 1.1 1999/08/23 19:00:33 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +int +stfd(void *frS, void *ea) +{ +#if 0 +#ifdef DEBUG + printk("%s: S %p, ea %p: ", __FUNCTION__, frS, ea); + dump_double(frS); + printk("\n"); +#endif +#endif + + if (copy_to_user(ea, frS, sizeof(double))) + return -EFAULT; + + return 0; +} diff --git a/arch/ppc/math-emu/stfiwx.c b/arch/ppc/math-emu/stfiwx.c new file mode 100644 index 000000000..63b1dfc15 --- /dev/null +++ b/arch/ppc/math-emu/stfiwx.c @@ -0,0 +1,19 @@ +/* $Id: stfiwx.c,v 1.1 1999/08/23 19:00:34 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +int +stfiwx(u32 *frS, void *ea) +{ +#ifdef DEBUG + printk("%s: %p %p\n", __FUNCTION__, frS, ea); +#endif + + if (copy_to_user(ea, &frS[1], sizeof(frS[1]))) + return -EFAULT; + + return 0; +} diff --git a/arch/ppc/math-emu/stfs.c b/arch/ppc/math-emu/stfs.c new file mode 100644 index 000000000..5cb576cd5 --- /dev/null +++ b/arch/ppc/math-emu/stfs.c @@ -0,0 +1,44 @@ +/* $Id: stfs.c,v 1.1 1999/08/23 19:00:35 cort Exp $ + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <asm/uaccess.h> + +#include "soft-fp.h" +#include "double.h" +#include "single.h" + +int +stfs(void *frS, void *ea) +{ + FP_DECL_D(A); + FP_DECL_S(R); + float f; + int err; + +#ifdef DEBUG + printk("%s: S %p, ea %p\n", __FUNCTION__, frS, ea); +#endif + + __FP_UNPACK_D(A, frS); + +#ifdef DEBUG + printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); +#endif + + FP_CONV(S, D, 1, 2, R, A); + +#ifdef DEBUG + printk("R: %ld %lu %ld (%ld)\n", R_s, R_f, R_e, R_c); +#endif + + err = _FP_PACK_CANONICAL(S, 1, R); + if (!err || !__FPU_TRAP_P(err)) { + __FP_PACK_RAW_1(S, &f, R); + if (copy_to_user(ea, &f, sizeof(float))) + return -EFAULT; + } + + return err; +} diff --git a/arch/ppc/math-emu/types.c b/arch/ppc/math-emu/types.c new file mode 100644 index 000000000..efe8baf76 --- /dev/null +++ b/arch/ppc/math-emu/types.c @@ -0,0 +1,52 @@ + +#include "soft-fp.h" +#include "double.h" +#include "single.h" + +void +fp_unpack_d(long *_s, unsigned long *_f1, unsigned long *_f0, + long *_e, long *_c, void *val) +{ + FP_DECL_D(X); + + __FP_UNPACK_RAW_2(D, X, val); + + _FP_UNPACK_CANONICAL(D, 2, X); + + *_s = X_s; + *_f1 = X_f1; + *_f0 = X_f0; + *_e = X_e; + *_c = X_c; +} + +int +fp_pack_d(void *val, long X_s, unsigned long X_f1, + unsigned long X_f0, long X_e, long X_c) +{ + int exc; + + exc = _FP_PACK_CANONICAL(D, 2, X); + if (!exc || !__FPU_TRAP_P(exc)) + __FP_PACK_RAW_2(D, val, X); + return exc; +} + +int +fp_pack_ds(void *val, long X_s, unsigned long X_f1, + unsigned long X_f0, long X_e, long X_c) +{ + FP_DECL_S(__X); + int exc; + + FP_CONV(S, D, 1, 2, __X, X); + exc = _FP_PACK_CANONICAL(S, 1, __X); + if (!exc || !__FPU_TRAP_P(exc)) { + _FP_UNPACK_CANONICAL(S, 1, __X); + FP_CONV(D, S, 2, 1, X, __X); + exc |= _FP_PACK_CANONICAL(D, 2, X); + if (!exc || !__FPU_TRAP_P(exc)) + __FP_PACK_RAW_2(D, val, X); + } + return exc; +} diff --git a/arch/ppc/math-emu/udivmodti4.c b/arch/ppc/math-emu/udivmodti4.c new file mode 100644 index 000000000..7e112dc1e --- /dev/null +++ b/arch/ppc/math-emu/udivmodti4.c @@ -0,0 +1,191 @@ +/* This has so very few changes over libgcc2's __udivmoddi4 it isn't funny. */ + +#include "soft-fp.h" + +#undef count_leading_zeros +#define count_leading_zeros __FP_CLZ + +void +_fp_udivmodti4(_FP_W_TYPE q[2], _FP_W_TYPE r[2], + _FP_W_TYPE n1, _FP_W_TYPE n0, + _FP_W_TYPE d1, _FP_W_TYPE d0) +{ + _FP_W_TYPE q0, q1, r0, r1; + _FP_I_TYPE b, bm; + + if (d1 == 0) + { +#if !UDIV_NEEDS_NORMALIZATION + if (d0 > n1) + { + /* 0q = nn / 0D */ + + udiv_qrnnd (q0, n0, n1, n0, d0); + q1 = 0; + + /* Remainder in n0. */ + } + else + { + /* qq = NN / 0d */ + + if (d0 == 0) + d0 = 1 / d0; /* Divide intentionally by zero. */ + + udiv_qrnnd (q1, n1, 0, n1, d0); + udiv_qrnnd (q0, n0, n1, n0, d0); + + /* Remainder in n0. */ + } + + r0 = n0; + r1 = 0; + +#else /* UDIV_NEEDS_NORMALIZATION */ + + if (d0 > n1) + { + /* 0q = nn / 0D */ + + count_leading_zeros (bm, d0); + + if (bm != 0) + { + /* Normalize, i.e. make the most significant bit of the + denominator set. */ + + d0 = d0 << bm; + n1 = (n1 << bm) | (n0 >> (_FP_W_TYPE_SIZE - bm)); + n0 = n0 << bm; + } + + udiv_qrnnd (q0, n0, n1, n0, d0); + q1 = 0; + + /* Remainder in n0 >> bm. */ + } + else + { + /* qq = NN / 0d */ + + if (d0 == 0) + d0 = 1 / d0; /* Divide intentionally by zero. */ + + count_leading_zeros (bm, d0); + + if (bm == 0) + { + /* From (n1 >= d0) /\ (the most significant bit of d0 is set), + conclude (the most significant bit of n1 is set) /\ (the + leading quotient digit q1 = 1). + + This special case is necessary, not an optimization. + (Shifts counts of SI_TYPE_SIZE are undefined.) */ + + n1 -= d0; + q1 = 1; + } + else + { + _FP_W_TYPE n2; + + /* Normalize. */ + + b = _FP_W_TYPE_SIZE - bm; + + d0 = d0 << bm; + n2 = n1 >> b; + n1 = (n1 << bm) | (n0 >> b); + n0 = n0 << bm; + + udiv_qrnnd (q1, n1, n2, n1, d0); + } + + /* n1 != d0... */ + + udiv_qrnnd (q0, n0, n1, n0, d0); + + /* Remainder in n0 >> bm. */ + } + + r0 = n0 >> bm; + r1 = 0; +#endif /* UDIV_NEEDS_NORMALIZATION */ + } + else + { + if (d1 > n1) + { + /* 00 = nn / DD */ + + q0 = 0; + q1 = 0; + + /* Remainder in n1n0. */ + r0 = n0; + r1 = n1; + } + else + { + /* 0q = NN / dd */ + + count_leading_zeros (bm, d1); + if (bm == 0) + { + /* From (n1 >= d1) /\ (the most significant bit of d1 is set), + conclude (the most significant bit of n1 is set) /\ (the + quotient digit q0 = 0 or 1). + + This special case is necessary, not an optimization. */ + + /* The condition on the next line takes advantage of that + n1 >= d1 (true due to program flow). */ + if (n1 > d1 || n0 >= d0) + { + q0 = 1; + sub_ddmmss (n1, n0, n1, n0, d1, d0); + } + else + q0 = 0; + + q1 = 0; + + r0 = n0; + r1 = n1; + } + else + { + _FP_W_TYPE m1, m0, n2; + + /* Normalize. */ + + b = _FP_W_TYPE_SIZE - bm; + + d1 = (d1 << bm) | (d0 >> b); + d0 = d0 << bm; + n2 = n1 >> b; + n1 = (n1 << bm) | (n0 >> b); + n0 = n0 << bm; + + udiv_qrnnd (q0, n1, n2, n1, d1); + umul_ppmm (m1, m0, q0, d0); + + if (m1 > n1 || (m1 == n1 && m0 > n0)) + { + q0--; + sub_ddmmss (m1, m0, m1, m0, d1, d0); + } + + q1 = 0; + + /* Remainder in (n1n0 - m1m0) >> bm. */ + sub_ddmmss (n1, n0, n1, n0, m1, m0); + r0 = (n1 << b) | (n0 >> bm); + r1 = n1 >> bm; + } + } + } + + q[0] = q0; q[1] = q1; + r[0] = r0, r[1] = r1; +} diff --git a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c index fde053df9..524087541 100644 --- a/arch/ppc/mm/fault.c +++ b/arch/ppc/mm/fault.c @@ -89,13 +89,9 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, printk("page fault in interrupt handler, addr=%lx\n", address); show_regs(regs); -#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) - if (debugger_kernel_faults) - debugger(regs); -#endif } } - if (current == NULL) { + if (current == NULL || mm == NULL) { bad_page_fault(regs, address); return; } @@ -161,6 +157,7 @@ void bad_page_fault(struct pt_regs *regs, unsigned long address) { unsigned long fixup; + if (user_mode(regs)) { force_sig(SIGSEGV, current); return; @@ -174,11 +171,11 @@ bad_page_fault(struct pt_regs *regs, unsigned long address) /* kernel has accessed a bad area */ show_regs(regs); - print_backtrace( (unsigned long *)regs->gpr[1] ); #if defined(CONFIG_XMON) || defined(CONFIG_KGDB) if (debugger_kernel_faults) debugger(regs); #endif + print_backtrace( (unsigned long *)regs->gpr[1] ); panic("kernel access of bad area pc %lx lr %lx address %lX tsk %s/%d", regs->nip,regs->link,address,current->comm,current->pid); } diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index ecbd79d63..20296b4e2 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -1,5 +1,5 @@ /* - * $Id: init.c,v 1.166 1999/05/22 18:18:30 cort Exp $ + * $Id: init.c,v 1.183 1999/09/05 19:29:44 cort Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -50,10 +50,10 @@ #include <asm/mbx.h> #include <asm/smp.h> #include <asm/bootx.h> -/* APUS includes */ +#include <asm/machdep.h> #include <asm/setup.h> #include <asm/amigahw.h> -/* END APUS includes */ +#include <asm/gemini.h> int prom_trashed; atomic_t next_mmu_context; @@ -65,6 +65,7 @@ extern char etext[], _stext[]; extern char __init_begin, __init_end; extern char __prep_begin, __prep_end; extern char __pmac_begin, __pmac_end; +extern char __apus_begin, __apus_end; extern char __openfirmware_begin, __openfirmware_end; char *klimit = _end; struct device_node *memory_node; @@ -83,13 +84,13 @@ static void *MMU_get_page(void); unsigned long *prep_find_end_of_memory(void); unsigned long *pmac_find_end_of_memory(void); unsigned long *apus_find_end_of_memory(void); +unsigned long *gemini_find_end_of_memory(void); extern unsigned long *find_end_of_memory(void); #ifdef CONFIG_MBX unsigned long *mbx_find_end_of_memory(void); #endif /* CONFIG_MBX */ static void mapin_ram(void); -void map_page(struct task_struct *, unsigned long va, - unsigned long pa, int flags); +void map_page(unsigned long va, unsigned long pa, int flags); extern void die_if_kernel(char *,struct pt_regs *,long); extern void show_net_buffers(void); @@ -125,6 +126,7 @@ unsigned long long _SDR1; unsigned long _SDR1; #endif static void hash_init(void); + union ubat { /* BAT register values to be loaded */ BAT bat; #ifdef CONFIG_PPC64 @@ -139,8 +141,38 @@ struct batrange { /* stores address ranges mapped by BATs */ unsigned long limit; unsigned long phys; } bat_addrs[4]; -unsigned long inline v_mapped_by_bats(unsigned long); -unsigned long inline p_mapped_by_bats(unsigned long); + +/* + * Return PA for this VA if it is mapped by a BAT, or 0 + */ +static inline unsigned long v_mapped_by_bats(unsigned long va) +{ + int b; + for (b = 0; b < 4; ++b) + if (va >= bat_addrs[b].start && va < bat_addrs[b].limit) + return bat_addrs[b].phys + (va - bat_addrs[b].start); + return 0; +} + +/* + * Return VA for a given PA or 0 if not mapped + */ +static inline unsigned long p_mapped_by_bats(unsigned long pa) +{ + int b; + for (b = 0; b < 4; ++b) + if (pa >= bat_addrs[b].phys + && pa < (bat_addrs[b].limit-bat_addrs[b].start) + +bat_addrs[b].phys) + return bat_addrs[b].start+(pa-bat_addrs[b].phys); + return 0; +} + +#else /* CONFIG_8xx */ + +/* 8xx doesn't have BATs */ +#define v_mapped_by_bats(x) (0UL) +#define p_mapped_by_bats(x) (0UL) #endif /* CONFIG_8xx */ /* @@ -150,8 +182,6 @@ unsigned long inline p_mapped_by_bats(unsigned long); */ int __map_without_bats = 0; -/* optimization for 603 to load the tlb directly from the linux table -- Cort */ -#define NO_RELOAD_HTAB 1 /* change in kernel/head.S too! */ void __bad_pte(pmd_t *pmd) { @@ -161,10 +191,12 @@ void __bad_pte(pmd_t *pmd) pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) { - pte_t *pte/* = (pte_t *) __get_free_page(GFP_KERNEL)*/; + pte_t *pte; if (pmd_none(*pmd)) { - if ( (pte = (pte_t *) get_zero_page_fast()) == NULL ) + if (!mem_init_done) + pte = (pte_t *) MMU_get_page(); + else if ((pte = (pte_t *) get_zero_page_fast()) == NULL) if ((pte = (pte_t *) __get_free_page(GFP_KERNEL))) clear_page((unsigned long)pte); if (pte) { @@ -174,7 +206,6 @@ pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) pmd_val(*pmd) = (unsigned long)BAD_PAGETABLE; return NULL; } - /*free_page((unsigned long)pte);*/ if (pmd_bad(*pmd)) { __bad_pte(pmd); return NULL; @@ -257,7 +288,7 @@ void show_mem(void) #ifdef CONFIG_NET show_net_buffers(); #endif - printk("%-8s %3s %3s %8s %8s %8s %9s %8s", "Process", "Pid", "Cnt", + printk("%-8s %3s %8s %8s %8s %9s %8s", "Process", "Pid", "Ctx", "Ctx<<4", "Last Sys", "pc", "task"); #ifdef __SMP__ printk(" %3s", "CPU"); @@ -265,14 +296,13 @@ void show_mem(void) printk("\n"); for_each_task(p) { - printk("%-8.8s %3d %3d %8ld %8ld %8ld %c%08lx %08lx ", + printk("%-8.8s %3d %8ld %8ld %8ld %c%08lx %08lx ", p->comm,p->pid, - (p->mm)?atomic_read(&p->mm->count):0, (p->mm)?p->mm->context:0, (p->mm)?(p->mm->context<<4):0, - p->tss.last_syscall, - (p->tss.regs)?user_mode(p->tss.regs) ? 'u' : 'k' : '?', - (p->tss.regs)?p->tss.regs->nip:0, + p->thread.last_syscall, + (p->thread.regs)?user_mode(p->thread.regs) ? 'u' : 'k' : '?', + (p->thread.regs)?p->thread.regs->nip:0, (ulong)p); { int iscur = 0; @@ -368,7 +398,6 @@ __ioremap(unsigned long addr, unsigned long size, unsigned long flags) if (size == 0) return NULL; -#ifndef CONFIG_8xx /* * Is it already mapped? Perhaps overlapped by a previous * BAT mapping. If the whole area is mapped then we're done, @@ -380,9 +409,8 @@ __ioremap(unsigned long addr, unsigned long size, unsigned long flags) * same virt address (and this is contiguous). * -- Cort */ - if ( (v = p_mapped_by_bats(p)) /*&& p_mapped_by_bats(p+size-1)*/ ) + if ((v = p_mapped_by_bats(p)) /*&& p_mapped_by_bats(p+size-1)*/ ) goto out; -#endif /* CONFIG_8xx */ if (mem_init_done) { struct vm_struct *area; @@ -402,14 +430,12 @@ __ioremap(unsigned long addr, unsigned long size, unsigned long flags) if (flags & (_PAGE_NO_CACHE | _PAGE_WRITETHRU)) flags |= _PAGE_GUARDED; -#ifndef CONFIG_8xx /* * Is it a candidate for a BAT mapping? */ -#endif /* CONFIG_8xx */ for (i = 0; i < size; i += PAGE_SIZE) - map_page(&init_task, v+i, p+i, flags); + map_page(v+i, p+i, flags); out: return (void *) (v + (addr & ~PAGE_MASK)); } @@ -421,68 +447,47 @@ void iounmap(void *addr) unsigned long iopa(unsigned long addr) { - unsigned long idx; + unsigned long pa; pmd_t *pd; pte_t *pg; -#ifndef CONFIG_8xx - int b; -#endif - idx = addr & ~PAGE_MASK; - addr = addr & PAGE_MASK; -#ifndef CONFIG_8xx /* Check the BATs */ - for (b = 0; b < 4; ++b) - if (addr >= bat_addrs[b].start && addr <= bat_addrs[b].limit) -#ifndef CONFIG_APUS - return bat_addrs[b].phys | idx; -#else - /* Do a more precise remapping of virtual address */ - /* --Carsten */ - return (bat_addrs[b].phys - bat_addrs[b].start + addr) | idx; -#endif /* CONFIG_APUS */ -#endif /* CONFIG_8xx */ + pa = v_mapped_by_bats(addr); + if (pa) + return pa; + /* Do we have a page table? */ - if (init_task.mm->pgd == NULL) + if (init_mm.pgd == NULL) return 0; /* Use upper 10 bits of addr to index the first level map */ - pd = (pmd_t *) (init_task.mm->pgd + (addr >> PGDIR_SHIFT)); + pd = (pmd_t *) (init_mm.pgd + (addr >> PGDIR_SHIFT)); if (pmd_none(*pd)) return 0; /* Use middle 10 bits of addr to index the second-level map */ pg = pte_offset(pd, addr); - return (pte_val(*pg) & PAGE_MASK) | idx; + return (pte_val(*pg) & PAGE_MASK) | (addr & ~PAGE_MASK); } void -map_page(struct task_struct *tsk, unsigned long va, - unsigned long pa, int flags) +map_page(unsigned long va, unsigned long pa, int flags) { - pmd_t *pd; + pmd_t *pd, oldpd; pte_t *pg; - if (tsk->mm->pgd == NULL) { - /* Allocate upper level page map */ - tsk->mm->pgd = (pgd_t *) MMU_get_page(); - } /* Use upper 10 bits of VA to index the first level map */ - pd = (pmd_t *) (tsk->mm->pgd + (va >> PGDIR_SHIFT)); - if (pmd_none(*pd)) { - if ( v_mapped_by_bats(va) ) - return; - pg = (pte_t *) MMU_get_page(); - pmd_val(*pd) = (unsigned long) pg; - } + pd = pmd_offset(pgd_offset_k(va), va); + oldpd = *pd; /* Use middle 10 bits of VA to index the second-level map */ - pg = pte_offset(pd, va); + pg = pte_alloc(pd, va); + if (pmd_none(oldpd) && mem_init_done) + set_pgdir(va, *(pgd_t *)pd); set_pte(pg, mk_pte_phys(pa & PAGE_MASK, __pgprot(flags))); -#ifndef CONFIG_8xx flush_hash_page(0, va); -#endif } +#ifndef CONFIG_8xx /* * TLB flushing: * @@ -503,12 +508,8 @@ map_page(struct task_struct *tsk, unsigned long va, void local_flush_tlb_all(void) { -#ifndef CONFIG_8xx __clear_user(Hash, Hash_size); _tlbia(); -#else - asm volatile ("tlbia" : : ); -#endif } /* @@ -519,26 +520,18 @@ local_flush_tlb_all(void) void local_flush_tlb_mm(struct mm_struct *mm) { -#ifndef CONFIG_8xx mm->context = NO_CONTEXT; if (mm == current->mm) - activate_context(current); -#else - asm volatile ("tlbia" : : ); -#endif + activate_mm(mm, mm); } void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) { -#ifndef CONFIG_8xx if (vmaddr < TASK_SIZE) flush_hash_page(vma->vm_mm->context, vmaddr); else flush_hash_page(0, vmaddr); -#else - asm volatile ("tlbia" : : ); -#endif } @@ -552,7 +545,6 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) void local_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { -#ifndef CONFIG_8xx start &= PAGE_MASK; if (end - start > 20 * PAGE_SIZE) @@ -565,9 +557,6 @@ local_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long e { flush_hash_page(mm->context, start); } -#else - asm volatile ("tlbia" : : ); -#endif } /* @@ -579,7 +568,6 @@ local_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long e void mmu_context_overflow(void) { -#ifndef CONFIG_8xx struct task_struct *tsk; printk(KERN_DEBUG "mmu_context_overflow\n"); @@ -594,19 +582,13 @@ mmu_context_overflow(void) /* make sure current always has a context */ current->mm->context = MUNGE_CONTEXT(atomic_inc_return(&next_mmu_context)); set_context(current->mm->context); -#else - /* We set the value to -1 because it is pre-incremented before - * before use. - */ - atomic_set(&next_mmu_context, -1); -#endif } +#endif /* CONFIG_8xx */ /* * Scan a region for a piece of a given size with the required alignment. */ -__initfunc(void * -find_mem_piece(unsigned size, unsigned align)) +void __init *find_mem_piece(unsigned size, unsigned align) { int i; unsigned a, e; @@ -629,9 +611,9 @@ find_mem_piece(unsigned size, unsigned align)) /* * Remove some memory from an array of pieces */ -__initfunc(static void +static void __init remove_mem_piece(struct mem_pieces *mp, unsigned start, unsigned size, - int must_exist)) + int must_exist) { int i, j; unsigned end, rs, re; @@ -685,7 +667,7 @@ remove_mem_piece(struct mem_pieces *mp, unsigned start, unsigned size, } } -__initfunc(static void print_mem_pieces(struct mem_pieces *mp)) +static void __init print_mem_pieces(struct mem_pieces *mp) { int i; @@ -698,8 +680,8 @@ __initfunc(static void print_mem_pieces(struct mem_pieces *mp)) /* * Add some memory to an array of pieces */ -__initfunc(static void - append_mem_piece(struct mem_pieces *mp, unsigned start, unsigned size)) +static void __init +append_mem_piece(struct mem_pieces *mp, unsigned start, unsigned size) { struct reg_property *rp; @@ -716,34 +698,7 @@ static void get_mem_prop(char *, struct mem_pieces *); static void sort_mem_pieces(struct mem_pieces *); static void coalesce_mem_pieces(struct mem_pieces *); -/* - * Return 1 if this VA is mapped by BATs - */ -unsigned long inline v_mapped_by_bats(unsigned long va) -{ - int b; - for (b = 0; b < 4; ++b) - if (va >= bat_addrs[b].start - && va < bat_addrs[b].limit) - return 1; - return 0; -} - -/* - * Return VA for a given PA or 0 if not mapped - */ -unsigned long inline p_mapped_by_bats(unsigned long pa) -{ - int b; - for (b = 0; b < 4; ++b) - if (pa >= bat_addrs[b].phys - && pa < (bat_addrs[b].limit-bat_addrs[b].start) - +bat_addrs[b].phys) - return bat_addrs[b].start+(pa-bat_addrs[b].phys); - return 0; -} - -__initfunc(static void sort_mem_pieces(struct mem_pieces *mp)) +static void __init sort_mem_pieces(struct mem_pieces *mp) { unsigned long a, s; int i, j; @@ -761,7 +716,7 @@ __initfunc(static void sort_mem_pieces(struct mem_pieces *mp)) } } -__initfunc(static void coalesce_mem_pieces(struct mem_pieces *mp)) +static void __init coalesce_mem_pieces(struct mem_pieces *mp) { unsigned long a, s, ns; int i, j, d; @@ -787,7 +742,7 @@ __initfunc(static void coalesce_mem_pieces(struct mem_pieces *mp)) * Read in a property describing some pieces of memory. */ -__initfunc(static void get_mem_prop(char *name, struct mem_pieces *mp)) +static void __init get_mem_prop(char *name, struct mem_pieces *mp) { struct reg_property *rp; int s; @@ -806,16 +761,13 @@ __initfunc(static void get_mem_prop(char *name, struct mem_pieces *mp)) coalesce_mem_pieces(mp); } -#endif /* CONFIG_8xx */ - -#ifndef CONFIG_8xx /* * Set up one of the I/D BAT (block address translation) register pairs. * The parameters are not checked; in particular size must be a power * of 2 between 128k and 256M. */ -__initfunc(void setbat(int index, unsigned long virt, unsigned long phys, - unsigned int size, int flags)) +void __init setbat(int index, unsigned long virt, unsigned long phys, + unsigned int size, int flags) { unsigned int bl; int wimgxpp; @@ -869,7 +821,7 @@ __initfunc(void setbat(int index, unsigned long virt, unsigned long phys, */ #define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED) -__initfunc(static void mapin_ram(void)) +static void __init mapin_ram(void) { int i; unsigned long v, p, s, f; @@ -909,7 +861,6 @@ __initfunc(static void mapin_ram(void)) RAM_PAGE); } } - v = KERNELBASE; for (i = 0; i < phys_mem.n_regions; ++i) { p = phys_mem.regions[i].address; @@ -921,15 +872,22 @@ __initfunc(static void mapin_ram(void)) /* On the powerpc, no user access forces R/W kernel access */ f |= _PAGE_USER; + map_page(v, p, f); + v += PAGE_SIZE; + p += PAGE_SIZE; + } + } + #else /* CONFIG_8xx */ - for (i = 0; i < phys_mem.n_regions; ++i) { - v = (ulong)__va(phys_mem.regions[i].address); - p = phys_mem.regions[i].address; - for (s = 0; s < phys_mem.regions[i].size; s += PAGE_SIZE) { + + for (i = 0; i < phys_mem.n_regions; ++i) { + v = (ulong)__va(phys_mem.regions[i].address); + p = phys_mem.regions[i].address; + for (s = 0; s < phys_mem.regions[i].size; s += PAGE_SIZE) { /* On the MPC8xx, we want the page shared so we * don't get ASID compares on kernel space. */ - f = _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_SHARED; + f = _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_SHARED; /* I don't really need the rest of this code, but * I grabbed it because I think the line: @@ -939,18 +897,18 @@ __initfunc(static void mapin_ram(void)) * the MPC8xx, the PAGE_DIRTY takes care of that * for us (along with the RW software state). */ - if ((char *) v < _stext || (char *) v >= etext) - f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE; -#endif /* CONFIG_8xx */ - map_page(&init_task, v, p, f); + if ((char *) v < _stext || (char *) v >= etext) + f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE; + map_page(v, p, f); v += PAGE_SIZE; p += PAGE_SIZE; } } +#endif /* CONFIG_8xx */ } -/* This can get called from ioremap, so don't make it an initfunc, OK? */ -static void *MMU_get_page(void) +/* This can get called from ioremap, so don't make it an __init, OK? */ +static void __init *MMU_get_page(void) { void *p; @@ -961,16 +919,16 @@ static void *MMU_get_page(void) } else { p = find_mem_piece(PAGE_SIZE, PAGE_SIZE); } - /*memset(p, 0, PAGE_SIZE);*/ __clear_user(p, PAGE_SIZE); return p; } -__initfunc(void free_initmem(void)) +void __init free_initmem(void) { unsigned long a; unsigned long num_freed_pages = 0, num_prep_pages = 0, - num_pmac_pages = 0, num_openfirmware_pages = 0; + num_pmac_pages = 0, num_openfirmware_pages = 0, + num_apus_pages = 0; #define FREESEC(START,END,CNT) do { \ a = (unsigned long)(&START); \ for (; a < (unsigned long)(&END); a += PAGE_SIZE) { \ @@ -985,16 +943,29 @@ __initfunc(void free_initmem(void)) switch (_machine) { case _MACH_Pmac: + FREESEC(__apus_begin,__apus_end,num_apus_pages); FREESEC(__prep_begin,__prep_end,num_prep_pages); break; case _MACH_chrp: + FREESEC(__apus_begin,__apus_end,num_apus_pages); FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); FREESEC(__prep_begin,__prep_end,num_prep_pages); break; case _MACH_prep: + FREESEC(__apus_begin,__apus_end,num_apus_pages); FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); break; case _MACH_mbx: + FREESEC(__apus_begin,__apus_end,num_apus_pages); + FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); + FREESEC(__prep_begin,__prep_end,num_prep_pages); + break; + case _MACH_apus: + FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); + FREESEC(__prep_begin,__prep_end,num_prep_pages); + break; + case _MACH_gemini: + FREESEC(__apus_begin,__apus_end,num_apus_pages); FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); FREESEC(__prep_begin,__prep_end,num_prep_pages); break; @@ -1012,6 +983,8 @@ __initfunc(void free_initmem(void)) printk(" %ldk pmac",(num_pmac_pages*PAGE_SIZE)>>10); if ( num_openfirmware_pages ) printk(" %ldk open firmware",(num_openfirmware_pages*PAGE_SIZE)>>10); + if ( num_apus_pages ) + printk(" %ldk apus",(num_apus_pages*PAGE_SIZE)>>10); printk("\n"); } @@ -1022,12 +995,12 @@ __initfunc(void free_initmem(void)) * still be merged. * -- Cort */ -__initfunc(void MMU_init(void)) +void __init MMU_init(void) { #ifdef __SMP__ if ( first_cpu_booted ) return; #endif /* __SMP__ */ - + if ( ppc_md.progress ) ppc_md.progress("MMU:enter", 0x111); #ifndef CONFIG_8xx if (have_of) end_of_DRAM = pmac_find_end_of_memory(); @@ -1035,13 +1008,17 @@ __initfunc(void MMU_init(void)) else if (_machine == _MACH_apus ) end_of_DRAM = apus_find_end_of_memory(); #endif + else if ( _machine == _MACH_gemini ) + end_of_DRAM = gemini_find_end_of_memory(); else /* prep */ end_of_DRAM = prep_find_end_of_memory(); + if ( ppc_md.progress ) ppc_md.progress("MMU:hash init", 0x300); hash_init(); _SDR1 = __pa(Hash) | (Hash_mask >> 10); ioremap_base = 0xf8000000; + if ( ppc_md.progress ) ppc_md.progress("MMU:mapin", 0x301); /* Map in all of RAM starting at KERNELBASE */ mapin_ram(); @@ -1050,6 +1027,7 @@ __initfunc(void MMU_init(void)) * the io areas. RAM was mapped by mapin_ram(). * -- Cort */ + if ( ppc_md.progress ) ppc_md.progress("MMU:setbat", 0x302); switch (_machine) { case _MACH_prep: setbat(0, 0x80000000, 0x80000000, 0x10000000, IO_PAGE); @@ -1080,6 +1058,10 @@ __initfunc(void MMU_init(void)) (kernel_map) remaps individual IO regions to 0x90000000. */ break; + case _MACH_gemini: + setbat(0, 0xf0000000, 0xf0000000, 0x10000000, IO_PAGE); + setbat(1, 0x80000000, 0x80000000, 0x10000000, IO_PAGE); + break; } ioremap_bot = ioremap_base; #else /* CONFIG_8xx */ @@ -1102,6 +1084,7 @@ __initfunc(void MMU_init(void)) ioremap(0x80000000, 0x4000); ioremap(0x81000000, 0x4000); #endif /* CONFIG_8xx */ + if ( ppc_md.progress ) ppc_md.progress("MMU:exit", 0x211); } /* @@ -1110,7 +1093,7 @@ __initfunc(void MMU_init(void)) * that setup_arch returns, making sure that there are at * least 32 pages unused before this for MMU_get_page to use. */ -__initfunc(unsigned long find_available_memory(void)) +unsigned long __init find_available_memory(void) { int i, rn; unsigned long a, free; @@ -1146,7 +1129,7 @@ __initfunc(unsigned long find_available_memory(void)) /* * paging_init() sets up the page tables - in fact we've already done this. */ -__initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)) +unsigned long __init paging_init(unsigned long start_mem, unsigned long end_mem) { extern unsigned long free_area_init(unsigned long, unsigned long); /* @@ -1162,7 +1145,7 @@ __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_ return start_mem; } -__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) +void __init mem_init(unsigned long start_mem, unsigned long end_mem) { unsigned long addr; int i; @@ -1258,7 +1241,7 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) * functions in the image just to get prom_init, all we really need right * now is the initialization of the physical memory region. */ -__initfunc(unsigned long *mbx_find_end_of_memory(void)) +unsigned long __init *mbx_find_end_of_memory(void) { unsigned long kstart, ksize; bd_t *binfo; @@ -1295,6 +1278,7 @@ __initfunc(unsigned long *mbx_find_end_of_memory(void)) return ret; } #endif /* CONFIG_MBX */ + #ifndef CONFIG_8xx /* * On systems with Open Firmware, collect information about @@ -1303,14 +1287,14 @@ __initfunc(unsigned long *mbx_find_end_of_memory(void)) * Our text, data, bss use something over 1MB, starting at 0. * Open Firmware may be using 1MB at the 4MB point. */ -__initfunc(unsigned long *pmac_find_end_of_memory(void)) +unsigned long __init *pmac_find_end_of_memory(void) { unsigned long a, total; unsigned long kstart, ksize; int i; /* max amount of RAM we allow -- Cort */ -#define RAM_LIMIT (768<<20) +#define RAM_LIMIT (256<<20) memory_node = find_devices("memory"); if (memory_node == NULL) { @@ -1395,7 +1379,7 @@ __initfunc(unsigned long *pmac_find_end_of_memory(void)) * this will likely stay separate from the pmac. * -- Cort */ -__initfunc(unsigned long *prep_find_end_of_memory(void)) +unsigned long __init *prep_find_end_of_memory(void) { unsigned long kstart, ksize; unsigned long total; @@ -1421,9 +1405,30 @@ __initfunc(unsigned long *prep_find_end_of_memory(void)) return (__va(total)); } +unsigned long __init *gemini_find_end_of_memory(void) +{ + unsigned long total, kstart, ksize, *ret; + unsigned char reg; + + reg = readb(GEMINI_MEMCFG); + total = ((1<<((reg & 0x7) - 1)) * + (8<<((reg >> 3) & 0x7))); + total *= (1024*1024); + phys_mem.regions[0].address = 0; + phys_mem.regions[0].size = total; + phys_mem.n_regions = 1; + + ret = __va(phys_mem.regions[0].size); + phys_avail = phys_mem; + kstart = __pa(_stext); + ksize = PAGE_ALIGN( _end - _stext ); + remove_mem_piece( &phys_avail, kstart, ksize, 0 ); + return ret; +} + #ifdef CONFIG_APUS #define HARDWARE_MAPPED_SIZE (512*1024) -__initfunc(unsigned long *apus_find_end_of_memory(void)) +unsigned long __init *apus_find_end_of_memory(void) { int shadow = 0; @@ -1501,7 +1506,7 @@ __initfunc(unsigned long *apus_find_end_of_memory(void)) /* * Initialize the hash table and patch the instructions in head.S. */ -__initfunc(static void hash_init(void)) +static void __init hash_init(void) { int Hash_bits; unsigned long h, ramsize; @@ -1509,6 +1514,7 @@ __initfunc(static void hash_init(void)) extern unsigned int hash_page_patch_A[], hash_page_patch_B[], hash_page_patch_C[], hash_page[]; + if ( ppc_md.progress ) ppc_md.progress("hash:enter", 0x105); /* * Allow 64k of hash table for every 16MB of memory, * up to a maximum of 2MB. @@ -1527,7 +1533,6 @@ __initfunc(static void hash_init(void)) Hash_mask = (h >> 6) - 1; #endif -#ifdef NO_RELOAD_HTAB /* shrink the htab since we don't use it on 603's -- Cort */ switch (_get_PVR()>>16) { case 3: /* 603 */ @@ -1540,8 +1545,8 @@ __initfunc(static void hash_init(void)) /* on 601/4 let things be */ break; } -#endif /* NO_RELOAD_HTAB */ + if ( ppc_md.progress ) ppc_md.progress("hash:find piece", 0x322); /* Find some memory for the hash table. */ if ( Hash_size ) Hash = find_mem_piece(Hash_size, Hash_size); @@ -1552,34 +1557,28 @@ __initfunc(static void hash_init(void)) ramsize >> 20, Hash_size >> 10, Hash); if ( Hash_size ) { -#ifdef CONFIG_APUS -#define b(x) ((unsigned int*)(((unsigned long)(x)) - KERNELBASE + 0xfff00000)) -#else -#define b(x) (x) -#endif - /*memset(Hash, 0, Hash_size);*/ + Hash_end = (PTE *) ((unsigned long)Hash + Hash_size); __clear_user(Hash, Hash_size); - Hash_end = (PTE *) ((unsigned long)Hash + Hash_size); - + if ( ppc_md.progress ) ppc_md.progress("hash:patch", 0x345); /* * Patch up the instructions in head.S:hash_page */ Hash_bits = ffz(~Hash_size) - 6; - *b(hash_page_patch_A) = (*b(hash_page_patch_A) & ~0xffff) + hash_page_patch_A[0] = (hash_page_patch_A[0] & ~0xffff) | (__pa(Hash) >> 16); - *b(hash_page_patch_A + 1) = (*b(hash_page_patch_A + 1)& ~0x7c0) + hash_page_patch_A[1] = (hash_page_patch_A[1] & ~0x7c0) | ((26 - Hash_bits) << 6); if (Hash_bits > 16) Hash_bits = 16; - *b(hash_page_patch_A + 2) = (*b(hash_page_patch_A + 2)& ~0x7c0) + hash_page_patch_A[2] = (hash_page_patch_A[2] & ~0x7c0) | ((26 - Hash_bits) << 6); - *b(hash_page_patch_B) = (*b(hash_page_patch_B) & ~0xffff) + hash_page_patch_B[0] = (hash_page_patch_B[0] & ~0xffff) | (Hash_mask >> 10); - *b(hash_page_patch_C) = (*b(hash_page_patch_C) & ~0xffff) + hash_page_patch_C[0] = (hash_page_patch_C[0] & ~0xffff) | (Hash_mask >> 10); #if 0 /* see hash_page in head.S, note also patch_C ref below */ - *b(hash_page_patch_D) = (*b(hash_page_patch_D) & ~0xffff) + hash_page_patch_D[0] = (hash_page_patch_D[0] & ~0xffff) | (Hash_mask >> 10); #endif /* @@ -1587,8 +1586,8 @@ __initfunc(static void hash_init(void)) * out from the data cache and invalidated in the instruction * cache, on those machines with split caches. */ - flush_icache_range((unsigned long) b(hash_page_patch_A), - (unsigned long) b(hash_page_patch_C + 1)); + flush_icache_range((unsigned long) &hash_page_patch_A[0], + (unsigned long) &hash_page_patch_C[1]); } else { Hash_end = 0; @@ -1597,9 +1596,10 @@ __initfunc(static void hash_init(void)) * start of hash_page, since we can still get DSI * exceptions on a 603. */ - *b(hash_page) = 0x4e800020; - flush_icache_range((unsigned long) b(hash_page), - (unsigned long) b(hash_page + 1)); + hash_page[0] = 0x4e800020; + flush_icache_range((unsigned long) &hash_page[0], + (unsigned long) &hash_page[1]); } + if ( ppc_md.progress ) ppc_md.progress("hash:done", 0x205); } #endif /* ndef CONFIG_8xx */ diff --git a/arch/ppc/vmlinux.lds b/arch/ppc/vmlinux.lds index e322d138b..c1b89ef98 100644 --- a/arch/ppc/vmlinux.lds +++ b/arch/ppc/vmlinux.lds @@ -70,10 +70,24 @@ SECTIONS . = ALIGN(4096); __init_begin = .; .text.init : { *(.text.init) } - .data.init : { *(.data.init) } + .data.init : { + *(.data.init); + __vtop_table_begin = .; + *(.vtop_fixup); + __vtop_table_end = .; + __ptov_table_begin = .; + *(.ptov_fixup); + __ptov_table_end = .; + } + . = ALIGN(16); + __setup_start = .; + .setup.init : { *(.setup.init) } + __setup_end = .; + __initcall_start = .; + .initcall.init : { *(.initcall.init) } + __initcall_end = .; . = ALIGN(4096); __init_end = .; - . = ALIGN(4096); __pmac_begin = .; .text.pmac : { *(.text.pmac) } @@ -89,6 +103,13 @@ SECTIONS __prep_end = .; . = ALIGN(4096); + __apus_begin = .; + .text.apus : { *(.text.apus) } + .data.apus : { *(.data.apus) } + . = ALIGN(4096); + __apus_end = .; + + . = ALIGN(4096); __openfirmware_begin = .; .text.openfirmware : { *(.text.openfirmware) } .data.openfirmware : { *(.data.openfirmware) } diff --git a/arch/ppc/xmon/start.c b/arch/ppc/xmon/start.c index 561571639..300659d98 100644 --- a/arch/ppc/xmon/start.c +++ b/arch/ppc/xmon/start.c @@ -13,7 +13,7 @@ static volatile unsigned char *sccc, *sccd; unsigned long TXRDY, RXRDY; extern void xmon_printf(const char *fmt, ...); -static int console = 0; +static int console = 1; void buf_access(void) { diff --git a/arch/ppc/xmon/subr_prf.c b/arch/ppc/xmon/subr_prf.c index 263538f94..358da2063 100644 --- a/arch/ppc/xmon/subr_prf.c +++ b/arch/ppc/xmon/subr_prf.c @@ -1,6 +1,7 @@ /* - * Written by Cort Dougan to replace the version written by - * Paul Mackerras that had copyright conflicts with Linux. + * Written by Cort Dougan to replace the version originally used + * by Paul Mackerras, which came from NetBSD and thus had copyright + * conflicts with Linux. * * This file makes liberal use of the standard linux utility * routines to reduce the size of the binary. We assume we can @@ -20,9 +21,11 @@ extern int xmon_write(void *, void *, int); void xmon_vfprintf(void *f, const char *fmt, va_list ap) { - char buf[2048]; - vsprintf( buf, fmt, ap ); - xmon_write( f, buf, strlen(buf) ); + static char xmon_buf[2048]; + int n; + + n = vsprintf(xmon_buf, fmt, ap); + xmon_write(f, xmon_buf, n); } void diff --git a/arch/ppc/xmon/xmon.c b/arch/ppc/xmon/xmon.c index 0e9a432cb..b07d7fc99 100644 --- a/arch/ppc/xmon/xmon.c +++ b/arch/ppc/xmon/xmon.c @@ -116,13 +116,11 @@ xmon(struct pt_regs *excp) struct pt_regs regs; int msr, cmd; - printk("Entering xmon kernel debugger.\n"); - if (excp == NULL) { asm volatile ("stw 0,0(%0)\n\ lwz 0,0(1)\n\ stw 0,4(%0)\n\ - stmw 2,8(%0)" : : "r" (®s)); + stmw 2,8(%0)" : : "b" (®s)); regs.nip = regs.link = ((unsigned long *)regs.gpr[1])[1]; regs.msr = get_msr(); regs.ctr = get_ctr(); @@ -472,8 +470,9 @@ backtrace(struct pt_regs *excp) unsigned sp; unsigned stack[2]; struct pt_regs regs; - extern char int_return, syscall_ret_1, syscall_ret_2; + extern char ret_from_int, ret_from_syscall_1, ret_from_syscall_2; extern char lost_irq_ret, do_bottom_half_ret, do_signal_ret; + extern char ret_from_except; if (excp != NULL) sp = excp->gpr[1]; @@ -485,9 +484,10 @@ backtrace(struct pt_regs *excp) if (mread(sp, stack, sizeof(stack)) != sizeof(stack)) break; printf("%x ", stack[1]); - if (stack[1] == (unsigned) &int_return - || stack[1] == (unsigned) &syscall_ret_1 - || stack[1] == (unsigned) &syscall_ret_2 + if (stack[1] == (unsigned) &ret_from_int + || stack[1] == (unsigned) &ret_from_except + || stack[1] == (unsigned) &ret_from_syscall_1 + || stack[1] == (unsigned) &ret_from_syscall_2 || stack[1] == (unsigned) &lost_irq_ret || stack[1] == (unsigned) &do_bottom_half_ret || stack[1] == (unsigned) &do_signal_ret) { |