summaryrefslogtreecommitdiffstats
path: root/arch/ppc/kernel
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/kernel
parent609d1e803baf519487233b765eb487f9ec227a18 (diff)
Merge with 2.3.19.
Diffstat (limited to 'arch/ppc/kernel')
-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
51 files changed, 4227 insertions, 2639 deletions
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)
{
}