summaryrefslogtreecommitdiffstats
path: root/arch/ppc
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-10-09 00:00:47 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-10-09 00:00:47 +0000
commitd6434e1042f3b0a6dfe1b1f615af369486f9b1fa (patch)
treee2be02f33984c48ec019c654051d27964e42c441 /arch/ppc
parent609d1e803baf519487233b765eb487f9ec227a18 (diff)
Merge with 2.3.19.
Diffstat (limited to 'arch/ppc')
-rw-r--r--arch/ppc/8xx_io/enet.c28
-rw-r--r--arch/ppc/8xx_io/fec.c36
-rw-r--r--arch/ppc/8xx_io/uart.c8
-rw-r--r--arch/ppc/Makefile39
-rw-r--r--arch/ppc/amiga/amiints.c2
-rw-r--r--arch/ppc/amiga/bootinfo.c2
-rw-r--r--arch/ppc/amiga/config.c10
-rw-r--r--arch/ppc/amiga/ints.c2
-rw-r--r--arch/ppc/boot/Makefile17
-rw-r--r--arch/ppc/boot/head.S7
-rw-r--r--arch/ppc/boot/misc.c6
-rw-r--r--arch/ppc/chrpboot/Makefile8
-rw-r--r--arch/ppc/chrpboot/main.c4
-rw-r--r--arch/ppc/coffboot/main.c7
-rw-r--r--arch/ppc/coffboot/zlib.h2
-rw-r--r--arch/ppc/common_defconfig90
-rw-r--r--arch/ppc/config.in26
-rw-r--r--arch/ppc/defconfig89
-rw-r--r--arch/ppc/gemini_defconfig352
-rw-r--r--arch/ppc/kernel/Makefile20
-rw-r--r--arch/ppc/kernel/align.c12
-rw-r--r--arch/ppc/kernel/apus_setup.c26
-rw-r--r--arch/ppc/kernel/chrp_pci.c23
-rw-r--r--arch/ppc/kernel/chrp_setup.c105
-rw-r--r--arch/ppc/kernel/chrp_time.c4
-rw-r--r--arch/ppc/kernel/entry.S434
-rw-r--r--arch/ppc/kernel/gemini_pci.c265
-rw-r--r--arch/ppc/kernel/gemini_prom.S94
-rw-r--r--arch/ppc/kernel/gemini_setup.c527
-rw-r--r--arch/ppc/kernel/hashtable.S478
-rw-r--r--arch/ppc/kernel/head.S1958
-rw-r--r--arch/ppc/kernel/head_8xx.S903
-rw-r--r--arch/ppc/kernel/idle.c28
-rw-r--r--arch/ppc/kernel/irq.c3
-rw-r--r--arch/ppc/kernel/local_irq.h4
-rw-r--r--arch/ppc/kernel/mbx_pci.c10
-rw-r--r--arch/ppc/kernel/mbx_setup.c19
-rw-r--r--arch/ppc/kernel/misc.S159
-rw-r--r--arch/ppc/kernel/mk_defs.c10
-rw-r--r--arch/ppc/kernel/open_pic.c444
-rw-r--r--arch/ppc/kernel/open_pic.h3
-rw-r--r--arch/ppc/kernel/openpic.c511
-rw-r--r--arch/ppc/kernel/pci.c91
-rw-r--r--arch/ppc/kernel/pci.h12
-rw-r--r--arch/ppc/kernel/pmac_pci.c18
-rw-r--r--arch/ppc/kernel/pmac_pic.c6
-rw-r--r--arch/ppc/kernel/pmac_setup.c36
-rw-r--r--arch/ppc/kernel/pmac_support.c1
-rw-r--r--arch/ppc/kernel/pmac_time.c6
-rw-r--r--arch/ppc/kernel/ppc-stub.c8
-rw-r--r--arch/ppc/kernel/ppc_asm.h73
-rw-r--r--arch/ppc/kernel/ppc_htab.c2
-rw-r--r--arch/ppc/kernel/ppc_ksyms.c16
-rw-r--r--arch/ppc/kernel/prep_nvram.c3
-rw-r--r--arch/ppc/kernel/prep_pci.c31
-rw-r--r--arch/ppc/kernel/prep_setup.c33
-rw-r--r--arch/ppc/kernel/prep_time.c1
-rw-r--r--arch/ppc/kernel/process.c68
-rw-r--r--arch/ppc/kernel/prom.c39
-rw-r--r--arch/ppc/kernel/ptrace.c59
-rw-r--r--arch/ppc/kernel/semaphore.c139
-rw-r--r--arch/ppc/kernel/setup.c57
-rw-r--r--arch/ppc/kernel/signal.c12
-rw-r--r--arch/ppc/kernel/smp.c42
-rw-r--r--arch/ppc/kernel/softemu8xx.c4
-rw-r--r--arch/ppc/kernel/syscalls.c1
-rw-r--r--arch/ppc/kernel/time.c24
-rw-r--r--arch/ppc/kernel/time.h4
-rw-r--r--arch/ppc/kernel/totalmp.c4
-rw-r--r--arch/ppc/kernel/traps.c36
-rw-r--r--arch/ppc/lib/locks.c12
-rw-r--r--arch/ppc/math-emu/Makefile20
-rw-r--r--arch/ppc/math-emu/double.h129
-rw-r--r--arch/ppc/math-emu/fabs.c21
-rw-r--r--arch/ppc/math-emu/fadd.c41
-rw-r--r--arch/ppc/math-emu/fadds.c42
-rw-r--r--arch/ppc/math-emu/fcmpo.c49
-rw-r--r--arch/ppc/math-emu/fcmpu.c45
-rw-r--r--arch/ppc/math-emu/fctiw.c28
-rw-r--r--arch/ppc/math-emu/fctiwz.c35
-rw-r--r--arch/ppc/math-emu/fdiv.c56
-rw-r--r--arch/ppc/math-emu/fdivs.c58
-rw-r--r--arch/ppc/math-emu/fmadd.c51
-rw-r--r--arch/ppc/math-emu/fmadds.c52
-rw-r--r--arch/ppc/math-emu/fmr.c21
-rw-r--r--arch/ppc/math-emu/fmsub.c54
-rw-r--r--arch/ppc/math-emu/fmsubs.c55
-rw-r--r--arch/ppc/math-emu/fmul.c45
-rw-r--r--arch/ppc/math-emu/fmuls.c46
-rw-r--r--arch/ppc/math-emu/fnabs.c21
-rw-r--r--arch/ppc/math-emu/fneg.c21
-rw-r--r--arch/ppc/math-emu/fnmadd.c54
-rw-r--r--arch/ppc/math-emu/fnmadds.c55
-rw-r--r--arch/ppc/math-emu/fnmsub.c57
-rw-r--r--arch/ppc/math-emu/fnmsubs.c58
-rw-r--r--arch/ppc/math-emu/fres.c15
-rw-r--r--arch/ppc/math-emu/frsp.c28
-rw-r--r--arch/ppc/math-emu/frsqrte.c15
-rw-r--r--arch/ppc/math-emu/fsel.c41
-rw-r--r--arch/ppc/math-emu/fsqrt.c40
-rw-r--r--arch/ppc/math-emu/fsqrts.c41
-rw-r--r--arch/ppc/math-emu/fsub.c44
-rw-r--r--arch/ppc/math-emu/fsubs.c45
-rw-r--r--arch/ppc/math-emu/lfd.c22
-rw-r--r--arch/ppc/math-emu/lfs.c40
-rw-r--r--arch/ppc/math-emu/math.c485
-rw-r--r--arch/ppc/math-emu/mcrfs.c34
-rw-r--r--arch/ppc/math-emu/mffs.c20
-rw-r--r--arch/ppc/math-emu/mtfsb0.c21
-rw-r--r--arch/ppc/math-emu/mtfsb1.c21
-rw-r--r--arch/ppc/math-emu/mtfsf.c48
-rw-r--r--arch/ppc/math-emu/mtfsfi.c26
-rw-r--r--arch/ppc/math-emu/op-1.h245
-rw-r--r--arch/ppc/math-emu/op-2.h433
-rw-r--r--arch/ppc/math-emu/op-4.h297
-rw-r--r--arch/ppc/math-emu/op-common.h690
-rw-r--r--arch/ppc/math-emu/sfp-machine.h377
-rw-r--r--arch/ppc/math-emu/single.h66
-rw-r--r--arch/ppc/math-emu/soft-fp.h104
-rw-r--r--arch/ppc/math-emu/stfd.c23
-rw-r--r--arch/ppc/math-emu/stfiwx.c19
-rw-r--r--arch/ppc/math-emu/stfs.c44
-rw-r--r--arch/ppc/math-emu/types.c52
-rw-r--r--arch/ppc/math-emu/udivmodti4.c191
-rw-r--r--arch/ppc/mm/fault.c9
-rw-r--r--arch/ppc/mm/init.c350
-rw-r--r--arch/ppc/vmlinux.lds25
-rw-r--r--arch/ppc/xmon/start.c2
-rw-r--r--arch/ppc/xmon/subr_prf.c13
-rw-r--r--arch/ppc/xmon/xmon.c14
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, &current->tss.fpr[reg], &current->tss.fpscr);
- /* current->tss.fpr[reg] = data.f; */
+ cvt_fd(&data.f, &current->thread.fpr[reg], &current->thread.fpscr);
+ /* current->thread.fpr[reg] = data.f; */
break;
case ST+F+S:
enable_kernel_fp();
- cvt_df(&current->tss.fpr[reg], &data.f, &current->tss.fpscr);
- /* data.f = current->tss.fpr[reg]; */
+ cvt_df(&current->thread.fpr[reg], &data.f, &current->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, &current->tss.fpr[0], sizeof(*fpregs));
+ memcpy(fpregs, &current->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 = &current->tss;
- *last = _switch(old_tss, new_tss, new->mm->context);
- _enable_interrupts(s);
+ new_thread = &new->thread;
+ old_thread = &current->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, &current->tss.fpr, sizeof(p->tss.fpr));
- p->tss.fpscr = current->tss.fpscr;
+ memcpy(&p->thread.fpr, &current->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, &regs) < 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 *)&current->tss.fpr[flreg];
+ ip = (uint *)&current->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, &current->tss.fpr[(instword>>11)&0x1f],
+ memcpy( ip, &current->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 *)&current->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 *)&current->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 *)&current->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 *)&current->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 *)&current->tss.fpr[(insn >> 21) & 0x1f];
+ op1 = (void *)&current->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 *)&current->tss.fpr[(insn >> 21) & 0x1f];
+ op1 = (void *)&current->tss.fpr[(insn >> 16) & 0x1f];
+ op2 = (void *)&current->tss.fpr[(insn >> 11) & 0x1f];
+ break;
+
+ case AC:
+ op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
+ op1 = (void *)&current->tss.fpr[(insn >> 16) & 0x1f];
+ op2 = (void *)&current->tss.fpr[(insn >> 6) & 0x1f];
+ break;
+
+ case ABC:
+ op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
+ op1 = (void *)&current->tss.fpr[(insn >> 16) & 0x1f];
+ op2 = (void *)&current->tss.fpr[(insn >> 11) & 0x1f];
+ op3 = (void *)&current->tss.fpr[(insn >> 6) & 0x1f];
+ break;
+
+ case D:
+ idx = (insn >> 16) & 0x1f;
+ sdisp = (insn & 0xffff);
+ op0 = (void *)&current->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 *)&current->tss.fpr[(insn >> 21) & 0x1f];
+ op1 = (void *)(regs->gpr[idx] + sdisp);
+ break;
+
+ case X:
+ op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
+ break;
+
+ case XA:
+ op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
+ op1 = (void *)&current->tss.fpr[(insn >> 16) & 0x1f];
+ break;
+
+ case XB:
+ op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
+ op1 = (void *)&current->tss.fpr[(insn >> 11) & 0x1f];
+ break;
+
+ case XE:
+ idx = (insn >> 16) & 0x1f;
+ if (!idx)
+ goto illegal;
+
+ op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
+ op1 = (void *)(regs->gpr[idx] + regs->gpr[(insn >> 11) & 0x1f]);
+ break;
+
+ case XEU:
+ idx = (insn >> 16) & 0x1f;
+ op0 = (void *)&current->tss.fpr[(insn >> 21) & 0x1f];
+ op1 = (void *)((idx ? regs->gpr[idx] : 0)
+ + regs->gpr[(insn >> 11) & 0x1f]);
+ break;
+
+ case XCR:
+ op0 = (void *)&regs->ccr;
+ op1 = (void *)((insn >> 23) & 0x7);
+ op2 = (void *)&current->tss.fpr[(insn >> 16) & 0x1f];
+ op3 = (void *)&current->tss.fpr[(insn >> 11) & 0x1f];
+ break;
+
+ case XCRL:
+ op0 = (void *)&regs->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 *)&current->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" (&regs));
+ stmw 2,8(%0)" : : "b" (&regs));
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) {