summaryrefslogtreecommitdiffstats
path: root/arch/ppc/kernel
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-03-17 22:05:47 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-03-17 22:05:47 +0000
commit27cfca1ec98e91261b1a5355d10a8996464b63af (patch)
tree8e895a53e372fa682b4c0a585b9377d67ed70d0e /arch/ppc/kernel
parent6a76fb7214c477ccf6582bd79c5b4ccc4f9c41b1 (diff)
Look Ma' what I found on my harddisk ...
o New faster syscalls for 2.1.x, too o Upgrade to 2.1.89. Don't try to run this. It's flaky as hell. But feel free to debug ...
Diffstat (limited to 'arch/ppc/kernel')
-rw-r--r--arch/ppc/kernel/Makefile11
-rw-r--r--arch/ppc/kernel/checks.c1
-rw-r--r--arch/ppc/kernel/chrp_pci.c258
-rw-r--r--arch/ppc/kernel/chrp_setup.c188
-rw-r--r--arch/ppc/kernel/chrp_time.c64
-rw-r--r--arch/ppc/kernel/find_name.c47
-rw-r--r--arch/ppc/kernel/head.S1182
-rw-r--r--arch/ppc/kernel/idle.c201
-rw-r--r--arch/ppc/kernel/irq.c367
-rw-r--r--arch/ppc/kernel/misc.S121
-rw-r--r--arch/ppc/kernel/mk_defs.c8
-rw-r--r--arch/ppc/kernel/openpic.c75
-rw-r--r--arch/ppc/kernel/pci.c154
-rw-r--r--arch/ppc/kernel/pmac_pci.c99
-rw-r--r--arch/ppc/kernel/pmac_setup.c156
-rw-r--r--arch/ppc/kernel/pmac_support.c17
-rw-r--r--arch/ppc/kernel/pmac_time.c76
-rw-r--r--arch/ppc/kernel/ppc_asm.tmpl123
-rw-r--r--arch/ppc/kernel/ppc_htab.c354
-rw-r--r--arch/ppc/kernel/ppc_ksyms.c33
-rw-r--r--arch/ppc/kernel/prep_pci.c142
-rw-r--r--arch/ppc/kernel/prep_setup.c186
-rw-r--r--arch/ppc/kernel/prep_time.c8
-rw-r--r--arch/ppc/kernel/process.c90
-rw-r--r--arch/ppc/kernel/prom.c539
-rw-r--r--arch/ppc/kernel/ptrace.c32
-rw-r--r--arch/ppc/kernel/residual.c590
-rw-r--r--arch/ppc/kernel/setup.c494
-rw-r--r--arch/ppc/kernel/signal.c512
-rw-r--r--arch/ppc/kernel/smp.c181
-rw-r--r--arch/ppc/kernel/syscalls.c45
-rw-r--r--arch/ppc/kernel/time.c138
-rw-r--r--arch/ppc/kernel/time.h58
-rw-r--r--arch/ppc/kernel/traps.c15
34 files changed, 4474 insertions, 2091 deletions
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
index 6fd50a6fb..37776109d 100644
--- a/arch/ppc/kernel/Makefile
+++ b/arch/ppc/kernel/Makefile
@@ -8,7 +8,7 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
.S.o:
- $(CC) -D__ASSEMBLY__ -c $< -o $*.o
+ $(CC) $(CFLAGS) -D__ASSEMBLY__ -c $< -o $*.o
O_TARGET := kernel.o
O_OBJS := misc.o traps.o process.o signal.o syscalls.o \
@@ -19,6 +19,10 @@ O_OBJS := misc.o traps.o process.o signal.o syscalls.o \
residual.o prom.o
OX_OBJS := ppc_ksyms.o
+ifdef SMP
+O_OBJS += smp.o
+endif
+
all: head.o kernel.o
head.o: head.S $(TOPDIR)/include/linux/tasks.h ppc_defs.h
@@ -33,8 +37,11 @@ ppc_defs.h: mk_defs.c ppc_defs.head \
grep '^#define' mk_defs.s >>ppc_defs.h
rm mk_defs.s
+find_name : find_name.c
+ $(HOSTCC) -DKERNELBASE=$(KERNELBASE) -o find_name find_name.c
+
checks: checks.c
- $(HOSTCC) -fno-builtin -I$(TOPDIR)/include -D__KERNEL__ -o checks checks.c
+ $(HOSTCC) -DKERNELBASE=$(KERNELBASE) -fno-builtin -I$(TOPDIR)/include -D__KERNEL__ -o checks checks.c
./checks
include $(TOPDIR)/Rules.make
diff --git a/arch/ppc/kernel/checks.c b/arch/ppc/kernel/checks.c
index 312229552..6b33511f2 100644
--- a/arch/ppc/kernel/checks.c
+++ b/arch/ppc/kernel/checks.c
@@ -10,7 +10,6 @@
#include <linux/malloc.h>
#include <linux/user.h>
#include <linux/a.out.h>
-#include <linux/config.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
diff --git a/arch/ppc/kernel/chrp_pci.c b/arch/ppc/kernel/chrp_pci.c
index 8af9ba9d6..16b379254 100644
--- a/arch/ppc/kernel/chrp_pci.c
+++ b/arch/ppc/kernel/chrp_pci.c
@@ -13,11 +13,17 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/hydra.h>
+#include <asm/prom.h>
+#include <asm/gg2.h>
/* LongTrail */
#define pci_config_addr(bus, dev, offset) \
- (0xfec00000 | ((bus)<<16) | ((dev)<<8) | (offset))
+ (GG2_PCI_CONFIG_BASE | ((bus)<<16) | ((dev)<<8) | (offset))
+volatile struct Hydra *Hydra = NULL;
+
+
+#if 1
int chrp_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned char *val)
{
@@ -45,6 +51,7 @@ int chrp_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
return PCIBIOS_SUCCESSFUL;
}
+
int chrp_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned int *val)
{
@@ -77,80 +84,207 @@ int chrp_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
int chrp_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned int val)
{
- if (bus > 7)
+ if (bus > 7)
return PCIBIOS_DEVICE_NOT_FOUND;
out_le32((unsigned int *)pci_config_addr(bus, dev_fn, offset), val);
return PCIBIOS_SUCCESSFUL;
}
+#else
+volatile unsigned int *pci_config_address=(volatile unsigned int *)0xfec00cf8;
+volatile unsigned char *pci_config_data=(volatile unsigned char *)0xfee00cfc;
+
+#define DEV_FN_MAX (31<<3)
-int chrp_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
- unsigned short index, unsigned char *bus_ptr,
- unsigned char *dev_fn_ptr)
+int chrp_pcibios_read_config_byte(unsigned char bus,
+ unsigned char dev_fn,
+ unsigned char offset,
+ unsigned char *val)
{
- int num, devfn;
- unsigned int x, vendev;
-
- if (vendor == 0xffff)
- return PCIBIOS_BAD_VENDOR_ID;
- vendev = (dev_id << 16) + vendor;
- num = 0;
- for (devfn = 0; devfn < 32; devfn++) {
- chrp_pcibios_read_config_dword(0, devfn<<3, PCI_VENDOR_ID, &x);
- if (x == vendev) {
- if (index == num) {
- *bus_ptr = 0;
- *dev_fn_ptr = devfn<<3;
- return PCIBIOS_SUCCESSFUL;
- }
- ++num;
- }
- }
- return PCIBIOS_DEVICE_NOT_FOUND;
+ if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
+ out_be32(pci_config_address,
+ 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
+ *val = in_8(pci_config_data+(offset&3));
+ return PCIBIOS_SUCCESSFUL;
}
-int chrp_pcibios_find_class(unsigned int class_code, unsigned short index,
- unsigned char *bus_ptr, unsigned char *dev_fn_ptr)
+int chrp_pcibios_read_config_word(unsigned char bus,
+ unsigned char dev_fn,
+ unsigned char offset,
+ unsigned short *val)
{
- int devnr, x, num;
-
- num = 0;
- for (devnr = 0; devnr < 32; devnr++) {
- chrp_pcibios_read_config_dword(0, devnr<<3, PCI_CLASS_REVISION, &x);
- if ((x>>8) == class_code) {
- if (index == num) {
- *bus_ptr = 0;
- *dev_fn_ptr = devnr<<3;
- return PCIBIOS_SUCCESSFUL;
- }
- ++num;
- }
- }
- return PCIBIOS_DEVICE_NOT_FOUND;
+ if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
+ if (offset&1)return PCIBIOS_BAD_REGISTER_NUMBER;
+ out_be32(pci_config_address,
+ 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
+ *val = in_le16((volatile unsigned short *)
+ (pci_config_data+(offset&3)));
+ return PCIBIOS_SUCCESSFUL;
}
-__initfunc(volatile struct Hydra *find_hydra(void))
+int chrp_pcibios_read_config_dword(unsigned char bus,
+ unsigned char dev_fn,
+ unsigned char offset,
+ unsigned int *val)
{
- u_char bus, dev;
- volatile struct Hydra *hydra = 0;
- if (chrp_pcibios_find_device(PCI_VENDOR_ID_APPLE,
- PCI_DEVICE_ID_APPLE_HYDRA, 0, &bus, &dev)
- == PCIBIOS_SUCCESSFUL)
- chrp_pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0,
- (unsigned int *)&hydra);
- return hydra;
+ if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
+ if (offset&3)return PCIBIOS_BAD_REGISTER_NUMBER;
+ out_be32(pci_config_address,
+ 0x80|(bus<<8)|(dev_fn<<16)|(offset<<24));
+ *val = in_le32((volatile unsigned int *)(pci_config_data));
+ return PCIBIOS_SUCCESSFUL;
}
-__initfunc(void hydra_post_openpic_init(void))
+int chrp_pcibios_write_config_byte(unsigned char bus,
+ unsigned char dev_fn,
+ unsigned char offset,
+ unsigned char val)
{
- openpic_set_sense(HYDRA_INT_SCSI_DMA, 0);
- openpic_set_sense(HYDRA_INT_SCCA_TX_DMA, 0);
- openpic_set_sense(HYDRA_INT_SCCA_RX_DMA, 0);
- openpic_set_sense(HYDRA_INT_SCCB_TX_DMA, 0);
- openpic_set_sense(HYDRA_INT_SCCB_RX_DMA, 0);
- openpic_set_sense(HYDRA_INT_SCSI, 1);
- openpic_set_sense(HYDRA_INT_SCCA, 1);
- openpic_set_sense(HYDRA_INT_SCCB, 1);
- openpic_set_sense(HYDRA_INT_VIA, 1);
- openpic_set_sense(HYDRA_INT_ADB, 1);
- openpic_set_sense(HYDRA_INT_ADB_NMI, 0);
+ if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
+ out_be32(pci_config_address,
+ 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
+ out_8(pci_config_data+(offset&3),val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int chrp_pcibios_write_config_word(unsigned char bus,
+ unsigned char dev_fn,
+ unsigned char offset,
+ unsigned short val)
+{
+ if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
+ if (offset&1)return PCIBIOS_BAD_REGISTER_NUMBER;
+ out_be32(pci_config_address,
+ 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
+ out_le16((volatile unsigned short *)(pci_config_data+(offset&3)),val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int chrp_pcibios_write_config_dword(unsigned char bus,
+ unsigned char dev_fn,
+ unsigned char offset,
+ unsigned int val)
+{
+ if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
+ if (offset&3)return PCIBIOS_BAD_REGISTER_NUMBER;
+ out_be32(pci_config_address,
+ 0x80|(bus<<8)|(dev_fn<<16)|(offset<<24));
+ out_le32((volatile unsigned int *)pci_config_data,val);
+ return PCIBIOS_SUCCESSFUL;
+}
+#endif
+
+ /*
+ * Temporary fixes for PCI devices. These should be replaced by OF query
+ * code -- Geert
+ */
+
+static u_char hydra_openpic_initsenses[] __initdata = {
+ 1, /* HYDRA_INT_SIO */
+ 0, /* HYDRA_INT_SCSI_DMA */
+ 0, /* HYDRA_INT_SCCA_TX_DMA */
+ 0, /* HYDRA_INT_SCCA_RX_DMA */
+ 0, /* HYDRA_INT_SCCB_TX_DMA */
+ 0, /* HYDRA_INT_SCCB_RX_DMA */
+ 1, /* HYDRA_INT_SCSI */
+ 1, /* HYDRA_INT_SCCA */
+ 1, /* HYDRA_INT_SCCB */
+ 1, /* HYDRA_INT_VIA */
+ 1, /* HYDRA_INT_ADB */
+ 0, /* HYDRA_INT_ADB_NMI */
+ /* all others are 1 (= default) */
+};
+
+__initfunc(int hydra_init(void))
+{
+ struct device_node *np;
+
+ np = find_devices("mac-io");
+ if (np == NULL || np->n_addrs == 0) {
+ printk(KERN_WARNING "Warning: no mac-io found\n");
+ return 0;
+ }
+ Hydra = ioremap(np->addrs[0].address, np->addrs[0].size);
+ printk("Hydra Mac I/O at %x\n", np->addrs[0].address);
+ out_le32(&Hydra->Feature_Control, (HYDRA_FC_SCC_CELL_EN |
+ HYDRA_FC_SCSI_CELL_EN |
+ HYDRA_FC_SCCA_ENABLE |
+ HYDRA_FC_SCCB_ENABLE |
+ HYDRA_FC_ARB_BYPASS |
+ HYDRA_FC_MPIC_ENABLE |
+ HYDRA_FC_SLOW_SCC_PCLK |
+ HYDRA_FC_MPIC_IS_MASTER));
+ OpenPIC = (volatile struct OpenPIC *)&Hydra->OpenPIC;
+ OpenPIC_InitSenses = hydra_openpic_initsenses;
+ OpenPIC_NumInitSenses = sizeof(hydra_openpic_initsenses);
+ return 1;
+}
+
+
+extern int chrp_ide_irq;
+
+__initfunc(int w83c553f_init(void))
+{
+ u_char bus, dev;
+ unsigned char t8;
+ unsigned short t16;
+ unsigned int t32;
+ if (pcibios_find_device(PCI_VENDOR_ID_WINBOND,
+ PCI_DEVICE_ID_WINBOND_83C553, 0, &bus, &dev)
+ == PCIBIOS_SUCCESSFUL) {
+ dev++;
+ chrp_pcibios_read_config_dword(bus, dev, PCI_VENDOR_ID, &t32);
+ if (t32 == (PCI_DEVICE_ID_WINBOND_82C105<<16) + PCI_VENDOR_ID_WINBOND) {
+#if 0
+ printk("Enabling SL82C105 IDE on W83C553F\n");
+ /*
+ * FIXME: this doesn't help :-(
+ */
+
+ /* I/O mapping */
+ chrp_pcibios_read_config_word(bus, dev, PCI_COMMAND, &t16);
+ t16 |= PCI_COMMAND_IO;
+ chrp_pcibios_write_config_word(bus, dev, PCI_COMMAND, t16);
+
+ /* Standard IDE registers */
+ chrp_pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_0,
+ 0xffffffff);
+ chrp_pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32);
+ chrp_pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_0,
+ 0x000001f0 | 1);
+ chrp_pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_1,
+ 0xffffffff);
+ chrp_pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_1, &t32);
+ chrp_pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_1,
+ 0x000003f4 | 1);
+ chrp_pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_2,
+ 0xffffffff);
+ chrp_pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_2, &t32);
+ chrp_pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_2,
+ 0x00000170 | 1);
+ chrp_pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_3,
+ 0xffffffff);
+ chrp_pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_3, &t32);
+ chrp_pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_3,
+ 0x00000374 | 1);
+
+ /* IDE Bus Master Control */
+ chrp_pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_4,
+ 0xffffffff);
+ chrp_pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_4, &t32);
+ chrp_pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_4,
+ 0x1000 | 1);
+ chrp_pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_5,
+ 0xffffffff);
+ chrp_pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_5, &t32);
+ chrp_pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_5,
+ 0x1010 | 1);
+
+ /* IDE Interrupt */
+ chrp_pcibios_read_config_byte(bus, dev, PCI_INTERRUPT_LINE, &t8);
+ chrp_ide_irq = t8;
+#endif
+ return 1;
+ }
+ }
+ return 0;
}
diff --git a/arch/ppc/kernel/chrp_setup.c b/arch/ppc/kernel/chrp_setup.c
index 0a5544b96..6c5d2afa5 100644
--- a/arch/ppc/kernel/chrp_setup.c
+++ b/arch/ppc/kernel/chrp_setup.c
@@ -28,11 +28,20 @@
#include <linux/init.h>
#include <linux/blk.h>
#include <linux/ioport.h>
+#ifdef CONFIG_ABSTRACT_CONSOLE
+#include <linux/console.h>
+#endif
#include <asm/mmu.h>
#include <asm/processor.h>
#include <asm/io.h>
#include <asm/pgtable.h>
+#include <asm/ide.h>
+#include <asm/prom.h>
+#include <asm/gg2.h>
+
+extern void hydra_init(void);
+extern void w83c553f_init(void);
/* for the mac fs */
kdev_t boot_dev;
@@ -52,110 +61,103 @@ extern int rd_image_start; /* starting block # of image */
#endif
-extern char saved_command_line[256];
+int chrp_ide_irq = 0;
+
+void chrp_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+{
+ ide_ioreg_t port = base;
+ int i = 8;
+
+ while (i--)
+ *p++ = port++;
+ *p++ = base + 0x206;
+ if (irq != NULL)
+ *irq = chrp_ide_irq;
+}
-long TotalMemory;
+static const char *gg2_memtypes[4] = {
+ "FPM", "SDRAM", "EDO", "BEDO"
+};
+static const char *gg2_cachesizes[4] = {
+ "256 KB", "512 KB", "1 MB", "Reserved"
+};
+static const char *gg2_cachetypes[4] = {
+ "Asynchronous", "Reserved", "Flow-Through Synchronous",
+ "Pipelined Synchronous"
+};
+static const char *gg2_cachemodes[4] = {
+ "Disabled", "Write-Through", "Copy-Back", "Transparent Mode"
+};
int
chrp_get_cpuinfo(char *buffer)
{
- int pvr = _get_PVR();
- int len;
- char *model;
-
- switch (pvr>>16)
- {
- case 1:
- model = "601";
- break;
- case 3:
- model = "603";
- break;
- case 4:
- model = "604";
- break;
- case 6:
- model = "603e";
- break;
- case 7:
- model = "603ev";
- break;
- case 9:
- model = "604e";
- break;
- default:
- model = "unknown";
- break;
+ int i, len, sdramen;
+ unsigned int t;
+ struct device_node *root;
+ const char *model = "";
+
+ root = find_path_device("/");
+ if (root)
+ model = get_property(root, "model", NULL);
+ len = sprintf(buffer,"machine\t\t: CHRP %s\n", model);
+
+ /* VLSI VAS96011/12 `Golden Gate 2' */
+ /* Memory banks */
+ sdramen = (in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+GG2_PCI_DRAM_CTRL))
+ >>31) & 1;
+ for (i = 0; i < (sdramen ? 4 : 6); i++) {
+ t = in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+GG2_PCI_DRAM_BANK0+
+ i*4));
+ if (!(t & 1))
+ continue;
+ switch ((t>>8) & 0x1f) {
+ case 0x1f:
+ model = "4 MB";
+ break;
+ case 0x1e:
+ model = "8 MB";
+ break;
+ case 0x1c:
+ model = "16 MB";
+ break;
+ case 0x18:
+ model = "32 MB";
+ break;
+ case 0x10:
+ model = "64 MB";
+ break;
+ case 0x00:
+ model = "128 MB";
+ break;
+ default:
+ model = "Reserved";
+ break;
+ }
+ len += sprintf(buffer+len, "memory bank %d\t: %s %s\n", i, model,
+ gg2_memtypes[sdramen ? 1 : ((t>>1) & 3)]);
}
-
- len = sprintf(buffer, "PowerPC %s rev %d.%d\n", model,
- (pvr & 0xff00) >> 8, pvr & 0xff);
-
- len += sprintf(buffer+len, "bogomips\t: %lu.%02lu\n",
- (loops_per_sec+2500)/500000,
- ((loops_per_sec+2500)/5000) % 100);
-
-#if 0
- /*
- * Ooh's and aah's info about zero'd pages in idle task
- */
- {
- extern unsigned int zerocount, zerototal, zeropage_hits,zeropage_calls;
- len += sprintf(buffer+len,"zero pages\t: total %u (%uKb) "
- "current: %u (%uKb) hits: %u/%u (%lu%%)\n",
- zerototal, (zerototal*PAGE_SIZE)>>10,
- zerocount, (zerocount*PAGE_SIZE)>>10,
- zeropage_hits,zeropage_calls,
- /* : 1 below is so we don't div by zero */
- (zeropage_hits*100) /
- ((zeropage_calls)?zeropage_calls:1));
- }
-#endif
+ /* L2 cache */
+ t = in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+GG2_PCI_CC_CTRL));
+ len += sprintf(buffer+len, "l2\t\t: %s %s (%s)\n",
+ gg2_cachesizes[(t>>7) & 3], gg2_cachetypes[(t>>2) & 3],
+ gg2_cachemodes[t & 3]);
return len;
}
__initfunc(void
-chrp_setup_arch(char **cmdline_p, unsigned long * memory_start_p,
- unsigned long * memory_end_p))
+chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
{
extern char cmd_line[];
- extern char _etext[], _edata[], _end[];
- extern int panic_timeout;
-
- /* Save unparsed command line copy for /proc/cmdline */
- strcpy( saved_command_line, cmd_line );
- *cmdline_p = cmd_line;
-
- *memory_start_p = (unsigned long) Hash+Hash_size;
- (unsigned long *)*memory_end_p = (unsigned long *)(TotalMemory+KERNELBASE);
/* init to some ~sane value until calibrate_delay() runs */
loops_per_sec = 50000000;
- /* 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) _end;
-
aux_device_present = 0xaa;
-
- switch ( _machine )
- {
- case _MACH_chrp:
- ROOT_DEV = to_kdev_t(0x0801); /* sda1 */
- break;
- }
+
+ ROOT_DEV = to_kdev_t(0x0802); /* sda2 (sda1 is for the kernel) */
#ifdef CONFIG_BLK_DEV_RAM
-#if 0
- ROOT_DEV = to_kdev_t(0x0200); /* floppy */
- rd_prompt = 1;
- rd_doload = 1;
- rd_image_start = 0;
-#endif
/* initrd_start and size are setup by boot/head.S and kernel/head.S */
if ( initrd_start )
{
@@ -177,4 +179,20 @@ chrp_setup_arch(char **cmdline_p, unsigned long * memory_start_p,
request_region(0x40,0x20,"timer");
request_region(0x80,0x10,"dma page reg");
request_region(0xc0,0x20,"dma2");
+
+ /* PCI bridge config space access area -
+ * appears to be not in devtree on longtrail. */
+ ioremap(GG2_PCI_CONFIG_BASE, 0x80000);
+
+ /*
+ * Temporary fixes for PCI devices.
+ * -- Geert
+ */
+ hydra_init(); /* Mac I/O */
+ w83c553f_init(); /* PCI-ISA bridge and IDE */
+
+#ifdef CONFIG_ABSTRACT_CONSOLE
+ /* Frame buffer device based console */
+ conswitchp = &fb_con;
+#endif
}
diff --git a/arch/ppc/kernel/chrp_time.c b/arch/ppc/kernel/chrp_time.c
index bf58953cd..73dcf9844 100644
--- a/arch/ppc/kernel/chrp_time.c
+++ b/arch/ppc/kernel/chrp_time.c
@@ -8,7 +8,6 @@
* copied and modified from intel version
*
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -24,21 +23,41 @@
#include <asm/io.h>
#include <asm/processor.h>
#include <asm/nvram.h>
-
+#include <asm/prom.h>
#include "time.h"
+static int nvram_as1 = NVRAM_AS1;
+static int nvram_as0 = NVRAM_AS0;
+static int nvram_data = NVRAM_DATA;
+
+void chrp_time_init(void)
+{
+ struct device_node *rtcs;
+ int base;
+
+ rtcs = find_compatible_devices("rtc", "pnpPNP,b00");
+ if (rtcs == NULL || rtcs->addrs == NULL)
+ return;
+ base = ((int *)rtcs->addrs)[2];
+ nvram_as1 = 0;
+ nvram_as0 = base;
+ nvram_data = base + 1;
+}
+
int chrp_cmos_clock_read(int addr)
{
- outb(addr>>8, NVRAM_AS1);
- outb(addr, NVRAM_AS0);
- return (inb(NVRAM_DATA));
+ if (nvram_as1 != 0)
+ outb(addr>>8, nvram_as1);
+ outb(addr, nvram_as0);
+ return (inb(nvram_data));
}
void chrp_cmos_clock_write(unsigned long val, int addr)
{
- outb(addr>>8, NVRAM_AS1);
- outb(addr, NVRAM_AS0);
- outb(val,NVRAM_DATA);
+ if (nvram_as1 != 0)
+ outb(addr>>8, nvram_as1);
+ outb(addr, nvram_as0);
+ outb(val, nvram_data);
return;
}
@@ -50,7 +69,7 @@ int chrp_set_rtc_time(unsigned long nowtime)
unsigned char save_control, save_freq_select;
struct rtc_time tm;
- to_tm(nowtime, &tm);
+ to_tm(nowtime + 10*60*60, &tm); /* XXX for now */
save_control = chrp_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */
@@ -127,6 +146,31 @@ unsigned long chrp_get_rtc_time(void)
}
if ((year += 1900) < 1970)
year += 100;
- return mktime(year, mon, day, hour, min, sec);
+ return mktime(year, mon, day, hour, min, sec) - 10*60*60 /* XXX for now */;
}
+
+void chrp_calibrate_decr(void)
+{
+ struct device_node *cpu;
+ int freq, *fp, divisor;
+
+ /*
+ * The cpu node should have a timebase-frequency property
+ * to tell us the rate at which the decrementer counts.
+ */
+ freq = 16666000; /* hardcoded default */
+ cpu = find_type_devices("cpu");
+ if (cpu != 0) {
+ fp = (int *) get_property(cpu, "timebase-frequency", NULL);
+ if (fp != 0)
+ freq = *fp;
+ }
+
+ freq *= 60; /* try to make freq/1e6 an integer */
+ divisor = 60;
+ printk("time_init: decrementer frequency = %d/%d\n", freq, divisor);
+ decrementer_count = freq / HZ / divisor;
+ count_period_num = divisor;
+ count_period_den = freq / 1000000;
+}
diff --git a/arch/ppc/kernel/find_name.c b/arch/ppc/kernel/find_name.c
new file mode 100644
index 000000000..23646fb69
--- /dev/null
+++ b/arch/ppc/kernel/find_name.c
@@ -0,0 +1,47 @@
+#include <stdio.h>
+#include <asm/page.h>
+#include <sys/mman.h>
+/*
+ * Finds a given address in the System.map and prints it out
+ * with its neighbors. -- Cort
+ */
+
+void main(int argc, char **argv)
+{
+ unsigned long addr, cmp, i;
+ FILE *f;
+ char *ptr;
+ char s[256], last[256];
+
+ if ( argc < 2 )
+ {
+ fprintf(stderr, "Usage: %s <address>\n", argv[0]);
+ exit(-1);
+ }
+
+ for ( i = 1 ; argv[i] ; i++ )
+ {
+ sscanf( argv[i], "%0x", &addr );
+ /* adjust if addr is relative to kernelbase */
+ if ( addr < PAGE_OFFSET )
+ addr += PAGE_OFFSET;
+
+ if ( (f = fopen( "System.map", "r" )) == NULL )
+ {
+ perror("fopen()\n");
+ exit(-1);
+ }
+
+ while ( !feof(f) )
+ {
+ fgets(s, 255 , f);
+ sscanf( s, "%0x", &cmp );
+ if ( addr < cmp )
+ break;
+ strcpy( last, s);
+ }
+
+ printf( "%s", last);
+ }
+ fclose(f);
+}
diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
index 3038e8cc1..2924febc5 100644
--- a/arch/ppc/kernel/head.S
+++ b/arch/ppc/kernel/head.S
@@ -30,7 +30,50 @@
#include <linux/errno.h>
#include <linux/config.h>
-#define SYNC() \
+#ifdef CONFIG_APUS
+/* At CYBERBASEp we'll find the following sum:
+ * -KERNELBASE+CyberStormMemoryBase
+ */
+#define CYBERBASEp (0xfff00000)
+#endif
+
+/* optimization for 603 to load the tlb directly from the linux table */
+#define NO_RELOAD_HTAB 1
+
+CACHE_LINE_SIZE = 32
+LG_CACHE_LINE_SIZE = 5
+
+#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
@@ -43,94 +86,16 @@
addi r4,r4,0x1000; \
bdnz 0b
-#define TOPHYS(x) (x - KERNELBASE)
+#define LOAD_BAT(n, offset, reg, RA, RB) \
+ lwz RA,offset+0(reg); \
+ lwz RB,offset+4(reg); \
+ mtspr IBAT##n##U,RA; \
+ mtspr IBAT##n##L,RB; \
+ lwz RA,offset+8(reg); \
+ lwz RB,offset+12(reg); \
+ mtspr DBAT##n##U,RA; \
+ mtspr DBAT##n##L,RB
-/* this is a very kludgey way of loading up the BATs on the
- prep system. I'll kill this horrible macro and write
- something clean when I have a chance -- Cort
- */
-#define LOAD_BATS(RA,RB) \
- mfspr RA,PVR ; \
- srwi RA,RA,16 ; \
- cmpi 0,RA,1 ; \
- beq 199f ; \
- /* load bats for 60x */ ; \
- lis RA,BAT0@h ; \
- ori RA,RA,BAT0@l ; \
- addis RA,RA,-KERNELBASE@h;\
- lwz RB,0(RA) ; \
- mtspr IBAT0U,RB ; \
- mtspr DBAT0U,RB ; \
- lwz RB,4(RA) ; \
- mtspr IBAT0L,RB ; \
- mtspr DBAT0L,RB ; \
- lis RA,BAT1@h ; \
- ori RA,RA,BAT1@l ; \
- addis RA,RA,-KERNELBASE@h;\
- lwz RB,0(RA) ; \
- mtspr IBAT1U,RB ; \
- mtspr DBAT1U,RB ; \
- lwz RB,4(RA) ; \
- mtspr IBAT1L,RB ; \
- mtspr DBAT1L,RB ; \
- lis RA,BAT2@h ; \
- ori RA,RA,BAT2@l ; \
- addis RA,RA,-KERNELBASE@h;\
- lwz RB,0(RA) ; \
- mtspr IBAT2U,RB ; \
- mtspr DBAT2U,RB ; \
- lwz RB,4(RA) ; \
- mtspr IBAT2L,RB ; \
- mtspr DBAT2L,RB ; \
- lis RA,BAT3@h ; \
- ori RA,RA,BAT3@l ; \
- addis RA,RA,-KERNELBASE@h;\
- lwz RB,0(RA) ; \
- mtspr IBAT3U,RB ; \
- mtspr DBAT3U,RB ; \
- lwz RB,4(RA) ; \
- mtspr IBAT3L,RB ; \
- mtspr DBAT3L,RB ; \
- b 200f ; \
-199: /*load bats for 601 */ ; \
- lis RA,BAT0_601@h ; \
- ori RA,RA,BAT0_601@l; \
- addis RA,RA,-KERNELBASE@h;\
- lwz RB,0(RA) ; \
- mtspr IBAT0U,RB ; \
- mtspr DBAT0U,RB ; \
- lwz RB,4(RA) ; \
- mtspr IBAT0L,RB ; \
- mtspr DBAT0L,RB ; \
- lis RA,BAT1_601@h ; \
- ori RA,RA,BAT1_601@l; \
- addis RA,RA,-KERNELBASE@h;\
- lwz RB,0(RA) ; \
- mtspr IBAT1U,RB ; \
- mtspr DBAT1U,RB ; \
- lwz RB,4(RA) ; \
- mtspr IBAT1L,RB ; \
- mtspr DBAT1L,RB ; \
- lis RA,BAT2_601@h ; \
- ori RA,RA,BAT2_601@l; \
- addis RA,RA,-KERNELBASE@h;\
- lwz RB,0(RA) ; \
- mtspr IBAT2U,RB ; \
- mtspr DBAT2U,RB ; \
- lwz RB,4(RA) ; \
- mtspr IBAT2L,RB ; \
- mtspr DBAT2L,RB ; \
- lis RA,BAT3_601@h ; \
- ori RA,RA,BAT3_601@l; \
- addis RA,RA,-KERNELBASE@h;\
- lwz RB,0(RA) ; \
- mtspr IBAT3U,RB ; \
- mtspr DBAT3U,RB ; \
- lwz RB,4(RA) ; \
- mtspr IBAT3L,RB ; \
- mtspr DBAT3L,RB ; \
-200:
-
.text
.globl _stext
_stext:
@@ -152,8 +117,8 @@ _start:
* managing the hash table. Interrupts are disabled. The stack
* pointer (r1) points to just below the end of the half-meg region
* from 0x380000 - 0x400000, which is mapped in already.
- */
-/* PREP
+ *
+ * PREP
* This is jumped to on prep systems right after the kernel is relocated
* to its proper place in memory by the boot loader. The expected layout
* of the regs is:
@@ -172,30 +137,47 @@ _start:
__start:
/*
+ * We have to do any OF calls before we map ourselves to KERNELBASE,
+ * because OF may have I/O devices mapped in in that area
+ * (particularly on CHRP).
+ */
+ mr r31,r3 /* save parameters */
+ mr r30,r4
+ mr r29,r5
+ mr r28,r6
+ mr r29,r7
+ bl prom_init
+
+/*
* Use the first pair of BAT registers to map the 1st 16MB
* of RAM to KERNELBASE.
*/
- mfspr r9,PVR
- rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */
- cmpi 0,r9,1
- lis r11,KERNELBASE@h
- bne 4f
- ori r11,r11,4 /* set up BAT registers for 601 */
- li r8,0x7f
- ori r11,r11,4 /* set up BAT registers for 601 */
- li r8,0x7f
- oris r9,r11,0x800000@h /* set up BAT reg for 2nd 8M */
- oris r10,r8,0x800000@h /* set up BAT reg for 2nd 8M */
- mtspr IBAT1U,r9
- mtspr IBAT1L,r10
- b 5f
-4: ori r11,r11,0x1ff /* set up BAT registers for 604 */
- li r8,2
- mtspr DBAT0U,r11
- mtspr DBAT0L,r8
-5: mtspr IBAT0U,r11
- mtspr IBAT0L,r8
- isync
+ mfspr r9,PVR
+ rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */
+ cmpi 0,r9,1
+ lis r11,KERNELBASE@h
+ bne 4f
+ ori r11,r11,4 /* set up BAT registers for 601 */
+ li r8,0x7f
+ oris r9,r11,0x800000@h /* set up BAT reg for 2nd 8M */
+ oris r10,r8,0x800000@h /* set up BAT reg for 2nd 8M */
+ mtspr IBAT1U,r9
+ mtspr IBAT1L,r10
+ b 5f
+4: ori r11,r11,0x1ff /* set up BAT registers for 604 */
+#ifndef CONFIG_APUS
+ li r8,2
+#else
+ lis r8,CYBERBASEp@h
+ lwz r8,0(r8)
+ addis r8,r8,KERNELBASE@h
+ addi r8,r8,2
+#endif
+ mtspr DBAT0U,r11
+ mtspr DBAT0L,r8
+5: mtspr IBAT0U,r11
+ mtspr IBAT0L,r8
+ isync
/*
* we now have the 1st 16M of ram mapped with the bats.
* prep needs the mmu to be turned on here, but pmac already has it on.
@@ -247,6 +229,20 @@ __start:
#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)
+#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
+
/*
* Exception entry code. This code runs with address translation
* turned off, i.e. using physical addresses.
@@ -254,21 +250,15 @@ __start:
* task's thread_struct.
*/
#define EXCEPTION_PROLOG \
-0: mtspr SPRG0,r20; \
+ mtspr SPRG0,r20; \
mtspr SPRG1,r21; \
mfcr r20; \
- mfspr r21,SRR1; /* test whether from user or kernel */\
- andi. r21,r21,MSR_PR; \
- mr r21,r1; /* from kernel - use current sp */\
- beq 1f; \
- mfspr r21,SPRG3; /* from user - load kernel sp */\
- lwz r21,KSP(r21); \
-1: addis r21,r21,-KERNELBASE@h; /* convert sp to physical */ \
+ 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 */\
- stw r1,GPR1(r21); \
- stw r1,0(r21); \
- addis r1,r21,KERNELBASE@h; /* set new kernel sp */ \
- stw r20,_CCR(r21); /* save registers */ \
+1: stw r20,_CCR(r21); /* save registers */ \
stw r22,GPR22(r21); \
stw r23,GPR23(r21); \
mfspr r20,SPRG0; \
@@ -282,9 +272,12 @@ __start:
mfspr r20,XER; \
stw r20,_XER(r21); \
mfspr r22,SRR0; \
- mfspr r23,SRR1; /* we can now take exceptions */\
+ mfspr r23,SRR1; \
stw r0,GPR0(r21); \
+ stw r1,GPR1(r21); \
stw r2,GPR2(r21); \
+ stw r1,0(r21); \
+ tovirt(r1,r21,r1); /* set new kernel sp */ \
SAVE_4GPRS(3, r21);
/*
* Note: code which follows this uses cr0.eq (set if from kernel),
@@ -315,7 +308,7 @@ label: \
DataAccess:
EXCEPTION_PROLOG
mfspr r20,DSISR
- andis. r0,r20,0x8470 /* weird error? */
+ 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 */
@@ -419,6 +412,47 @@ SystemCall:
*/
. = 0x1000
InstructionTLBMiss:
+#ifdef NO_RELOAD_HTAB
+/*
+ * r0: stored ctr
+ * r1: linux style pte ( later becomes ppc hardware pte )
+ * r2: ptr to linux-style pte
+ * r3: scratch
+ */
+ mfctr r0
+ /* Get PTE (linux-style) and check access */
+ mfspr r2,SPRG3
+ lwz r2,PG_TABLES(r2)
+ tophys(r2,r2,r3)
+ 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)
+ 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 */
+ mfmsr r3
+ rlwinm r3,r3,32-13,30,30 /* MSR_PR -> _PAGE_USER */
+ ori r3,r3,1 /* set _PAGE_PRESENT bit in access */
+ andc. r3,r3,r1 /* check access & ~permission */
+ bne- InstructionAddressInvalid /* return if access not permitted */
+ ori r1,r1,0x100 /* set _PAGE_ACCESSED in pte */
+ stw r1,0(r2) /* update PTE (accessed bit) */
+ /* Convert linux-style PTE to low word of PPC-style PTE */
+ /* this computation could be done better -- Cort */
+ rlwinm r3,r1,32-9,31,31 /* _PAGE_HWWRITE -> PP lsb */
+ rlwimi r1,r1,32-1,31,31 /* _PAGE_USER -> PP (both bits now) */
+ ori r3,r3,0xe04 /* clear out reserved bits */
+ andc r1,r1,r3 /* PP=2 or 0, when _PAGE_HWWRITE */
+ mtspr RPA,r1
+ mfspr r3,IMISS
+ tlbli r3
+ 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 */
@@ -443,20 +477,25 @@ InstructionTLBMiss:
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 */
- addis r1,r1,0x4000 /* Set bit 1 -> PTE not found */
- mtspr DSISR,r1
+#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 */
or r2,r2,r1
mtspr SRR1,r2
mfspr r1,IMISS /* Get failing address */
rlwinm. r2,r2,0,31,31 /* Check for little endian access */
- beq 20f /* Jump if big endian */
- xori r1,r1,3
-20: mtspr DAR,r1 /* Set fault address */
+ rlwimi r2,r2,1,30,30 /* change 1 -> 3 */
+ xor r1,r1,r2
+ mtspr DAR,r1 /* Set fault address */
mfmsr r0 /* Restore "normal" registers */
xoris r0,r0,MSR_TGPR>>16
mtcrf 0x80,r3 /* Restore CR0 */
@@ -469,6 +508,48 @@ InstructionAddressInvalid:
*/
. = 0x1100
DataLoadTLBMiss:
+#ifdef NO_RELOAD_HTAB
+/*
+ * r0: stored ctr
+ * r1: linux style pte ( later becomes ppc hardware pte )
+ * r2: ptr to linux-style pte
+ * r3: scratch
+ */
+ mfctr r0
+ /* Get PTE (linux-style) and check access */
+ mfspr r2,SPRG3
+ lwz r2,PG_TABLES(r2)
+ tophys(r2,r2,r3)
+ 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)
+ 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 */
+ mfmsr r3
+ rlwinm r3,r3,32-13,30,30 /* MSR_PR -> _PAGE_USER */
+ ori r3,r3,1 /* set _PAGE_PRESENT bit in access */
+ /* save r2 and use it as scratch for the andc. */
+ andc. r3,r3,r1 /* check access & ~permission */
+ bne- DataAddressInvalid /* return if access not permitted */
+ ori r1,r1,0x100 /* set _PAGE_ACCESSED in pte */
+ stw r1,0(r2) /* update PTE (accessed bit) */
+ /* Convert linux-style PTE to low word of PPC-style PTE */
+ /* this computation could be done better -- Cort */
+ rlwinm r3,r1,32-9,31,31 /* _PAGE_HWWRITE -> PP lsb */
+ rlwimi r1,r1,32-1,31,31 /* _PAGE_USER -> PP (both bits now) */
+ ori r3,r3,0xe04 /* clear out reserved bits */
+ andc r1,r1,r3 /* PP=2 or 0, when _PAGE_HWWRITE */
+ mtspr RPA,r1
+ mfspr r3,DMISS
+ tlbld r3
+ 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 */
@@ -493,10 +574,15 @@ DataLoadTLBMiss:
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 */
@@ -518,6 +604,48 @@ DataAddressInvalid:
*/
. = 0x1200
DataStoreTLBMiss:
+#ifdef NO_RELOAD_HTAB
+/*
+ * r0: stored ctr
+ * r1: linux style pte ( later becomes ppc hardware pte )
+ * r2: ptr to linux-style pte
+ * r3: scratch
+ */
+ mfctr r0
+ /* Get PTE (linux-style) and check access */
+ mfspr r2,SPRG3
+ lwz r2,PG_TABLES(r2)
+ tophys(r2,r2,r3)
+ 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)
+ 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 */
+ mfmsr r3
+ rlwinm r3,r3,32-13,30,30 /* MSR_PR -> _PAGE_USER */
+ ori r3,r3,0x5 /* _PAGE_PRESENT|_PAGE_RW */
+ /* save r2 and use it as scratch for the andc. */
+ andc. r3,r3,r1 /* check access & ~permission */
+ bne- DataAddressInvalid /* return if access not permitted */
+ ori r1,r1,0x384 /* set _PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_RW|_PAGE_HWWRITE in pte */
+ stw r1,0(r2) /* update PTE (accessed bit) */
+ /* Convert linux-style PTE to low word of PPC-style PTE */
+ /* this computation could be done better -- Cort */
+ rlwinm r3,r1,32-9,31,31 /* _PAGE_HWWRITE -> PP lsb */
+ rlwimi r1,r1,32-1,31,31 /* _PAGE_USER -> PP (both bits now) */
+ ori r3,r3,0xe04 /* clear out reserved bits */
+ andc r1,r1,r3 /* PP=2 or 0, when _PAGE_HWWRITE */
+ mtspr RPA,r1
+ mfspr r3,DMISS
+ tlbld r3
+ 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 */
@@ -542,6 +670,8 @@ DataStoreTLBMiss:
mfspr r2,HASH2 /* Get hash table pointer */
ori r3,r3,0x40 /* Set secondary hash */
b 00b /* Try lookup again */
+#endif /* NO_RELOAD_HTAB */
+
/* Instruction address breakpoint exception (on 603/604) */
STD_EXCEPTION(0x1300, Trap_13, InstructionBreakpoint)
@@ -596,17 +726,23 @@ 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 */
+ mfspr r23,SPRG3 /* if from user, fix up tss.regs */
beq 2f
addi r24,r1,STACK_FRAME_OVERHEAD
stw r24,PT_REGS(r23)
2: addi r2,r23,-TSS /* set r2 to current */
- addis r2,r2,KERNELBASE@h
+ tovirt(r2,r2,r23)
mflr r23
andi. r24,r23,0x3f00 /* get vector offset */
stw r24,TRAP(r21)
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
@@ -616,28 +752,67 @@ transfer_to_handler:
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
+
+/*
* Continuation of the floating-point unavailable handler.
*/
load_up_fpu:
- bl giveup_fpu_unmapped
- ori r23,r23,MSR_FP /* enable use of FP after return */
+
+/*
+ * Disable FP for the task which had the FPU previously,
+ * and save its floating-point registers in its thread_struct.
+ * Enables the FPU for use in the kernel on return.
+ */
+#ifndef CONFIG_APUS
+ lis r6,-KERNELBASE@h
+#else
+ lis r6,CYBERBASEp@h
+ lwz r6,0(r6)
+#endif
+ addis r3,r6,last_task_used_math@ha
+ lwz r4,last_task_used_math@l(r3)
+ mfmsr r5
+ ori r5,r5,MSR_FP
+ SYNC
+ mtmsr r5 /* enable use of fpu now */
+ SYNC
+ cmpi 0,r4,0
+ beq 1f
+ add r4,r4,r6
+ addi r4,r4,TSS /* want TSS of last_task_used_math */
+ SAVE_32FPRS(0, r4)
+ mffs fr0
+ stfd fr0,TSS_FPSCR-4(r4)
+ lwz r5,PT_REGS(r4)
+ add r5,r5,r6
+ lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+ li r20,MSR_FP
+ andc r4,r4,r20 /* disable FP for previous task */
+ stw r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+
+1: ori r23,r23,MSR_FP /* enable use of FP after return */
mfspr r5,SPRG3 /* current task's TSS (phys) */
lfd fr0,TSS_FPSCR-4(r5)
mtfsf 0xff,fr0
REST_32FPRS(0, r5)
-
-/* use last_task_used_math instead of fpu_tss */
- lis r3,last_task_used_math@ha
- addis r3,r3,-KERNELBASE@h
subi r4,r5,TSS
- addis r4,r4,KERNELBASE@h
+ sub r4,r4,r6
stw r4,last_task_used_math@l(r3)
-#if 0
- lis r3,fpu_tss@ha
- addis r4,r5,KERNELBASE@h
- addis r3,r3,-KERNELBASE@h
- stw r4,fpu_tss@l(r3)
-#endif
/* restore registers and return */
lwz r3,_CCR(r21)
lwz r4,_LINK(r21)
@@ -672,27 +847,42 @@ load_up_fpu:
* physical address of the hash table are known. These definitions
* of Hash_base and Hash_bits below are just an example.
*/
+/*
+ * Note that the 603s won't come here, since the 603
+ * loads tlb directly into the tlb from the linux tables, while
+ * others (601, 604, etc.) call hash_page() to load entries from
+ * the linux tables into the hash table. -- Cort
+ */
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__
+ lis r6,hash_table_lock@h
+ ori r6,r6,hash_table_lock@l
+ tophys(r6,r6,r2)
+1011: lwarx r0,0,r6
+ stwcx. r6,0,r6
+ bne- 1011b
+ cmpi 0,r0,0
+ bne 1011b
+#endif /* __SMP__ */
/* Get PTE (linux-style) and check access */
- lwz r5,MM-TSS(r5)
- addis r5,r5,-KERNELBASE@h /* get physical current->mm */
- lwz r5,PGD(r5) /* get current->mm->pgd */
- addis r5,r5,-KERNELBASE@h /* convert to phys addr */
+ 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 */
- beqlr- /* return if no mapping */
- addis r2,r5,-KERNELBASE@h
+ beq- hash_page_out /* return if no mapping */
+ 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 */
- bnelr- /* return if access not permitted */
+ bne- hash_page_out /* return if access not permitted */
+
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 */
@@ -752,7 +942,7 @@ hash_page_patch_B:
10: mtctr r2
addi r3,r4,-8 /* search primary PTEG */
1: lwzu r0,8(r3) /* get next PTE */
- cmpi 0,r0,0 /* empty? */
+ srwi. r0,r0,31 /* only want to check valid bit */
bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */
beq+ found_empty
@@ -765,24 +955,71 @@ hash_page_patch_C:
addi r3,r3,-8
mtctr r2
2: lwzu r0,8(r3)
- cmpi 0,r0,0
+ 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 */
+#if 0
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
+#else
+ /* now, allow 2nd hash as well as 1st */
+ lwz r2,next_slot@l(0)
+ addi r2,r2,8
+ andi. r2,r2,0x78
+ stw r2,next_slot@l(0)
+ cmpi 0,0,r2,0x38 /* if it's the 2nd hash */
+ bgt second_evict
+first_evict:
+ xori r5,r5,0x40 /* clear H bit again */
+ add r3,r4,r2
+ b 11f
+second_evict:
+ .globl hash_page_patch_D
+hash_page_patch_D:
+ xoris r3,r4,Hash_msk>>16 /* compute secondary hash */
+ xori r3,r3,0xffc0
+ subi r2,r2,0x40
+ addi r3,r3,r2
+#endif
+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)
/* Store PTE in PTEG */
found_empty:
stw r5,0(r3)
found_slot:
stw r6,4(r3)
+
+/*
+ * 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)
SYNC
+
/* Return from the exception */
lwz r3,_CCR(r21)
lwz r4,_LINK(r21)
@@ -790,6 +1027,13 @@ found_slot:
mtcrf 0xff,r3
mtlr r4
mtctr r5
+#ifdef __SMP__
+ lis r5,hash_table_lock@h
+ ori r5,r5,hash_table_lock@l
+ tophys(r5,r5,r6)
+ li r6,0
+ stw r6,0(r5)
+#endif /* __SMP__ */
REST_GPR(0, r21)
REST_2GPRS(1, r21)
REST_4GPRS(3, r21)
@@ -801,10 +1045,28 @@ found_slot:
lwz r21,GPR21(r21)
SYNC
rfi
-
+
+hash_page_out:
+#ifdef __SMP__
+ lis r5,hash_table_lock@h
+ ori r5,r5,hash_table_lock@l
+ tophys(r5,r5,r6)
+ li r6,0
+ stw r6,0(r5)
+#endif /* __SMP__ */
+ blr
next_slot:
.long 0
+#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.
+ */
+ . = 0x4000
+#endif
+
/*
* This is where the main kernel code starts.
*/
@@ -831,23 +1093,24 @@ start_here:
10:
sync
mtspr HID0,r8 /* enable and invalidate caches */
+ sync
mtspr HID0,r11 /* enable caches */
sync
isync
cmpi 0,r9,4 /* check for 604 */
cmpi 1,r9,9 /* or 604e */
+ cmpi 2,r9,10 /* or mach5 */
cror 2,2,6
+ cror 2,2,10
bne 4f
ori r11,r11,HID0_SIED|HID0_BHTE /* for 604[e], enable */
- mtspr HID0,r11 /* superscalar exec & br history tbl */
+ bne 2,5f
+ ori r11,r11,HID0_BTCD
+5: mtspr HID0,r11 /* superscalar exec & br history tbl */
4:
/* ptr to current */
lis r2,init_task_union@h
ori r2,r2,init_task_union@l
- /* ptr to phys current tss */
- addis r11,r2,-KERNELBASE@h
- addi r11,r11,TSS /* init task's TSS */
- mtspr SPRG3,r11
/* stack */
addi r1,r2,TASK_UNION_SIZE
li r0,0
@@ -869,10 +1132,14 @@ start_here:
bdnz 3b
2:
/*
- * Initialize the prom stuff and the MMU.
+ * 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 prom_init
bl MMU_init
/*
@@ -882,10 +1149,10 @@ start_here:
*/
lis r6,_SDR1@ha
lwz r6,_SDR1@l(r6)
- li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR)
lis r4,2f@h
- addis r4,r4,-KERNELBASE@h
ori r4,r4,2f@l
+ tophys(r4,r4,r3)
+ li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR)
mtspr SRR0,r4
mtspr SRR1,r3
rfi
@@ -902,38 +1169,55 @@ start_here:
addi r3,r3,1 /* increment VSID */
addis r4,r4,0x1000 /* address of next segment */
bdnz 3b
-
- lis r3,_machine@ha
- addis r3,r3,-KERNELBASE@h
- lwz r0,_machine@l(r3)
- cmpi 0,r0,_MACH_Pmac
- beq 99f
-
-/* on prep reload the bats now that MMU_init() has setup them up -- Cort */
- LOAD_BATS(r3,r14)
- b 100f
-/* on pmac clear the bats out */
-99: li r0,0 /* zot the BATs */
-#if 1
- mtspr IBAT0U,r0
- mtspr IBAT0L,r0
- mtspr DBAT0U,r0
- mtspr DBAT0L,r0
-#endif
- mtspr IBAT1U,r0
- mtspr IBAT1L,r0
- mtspr DBAT1U,r0
- mtspr DBAT1L,r0
- mtspr IBAT2U,r0
- mtspr IBAT2L,r0
- mtspr DBAT2U,r0
- mtspr DBAT2L,r0
- mtspr IBAT3U,r0
- mtspr IBAT3L,r0
- mtspr DBAT3U,r0
- mtspr DBAT3L,r0
-100:
+/* 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. */
+ lis r3,BATS@ha
+ addi r3,r3,BATS@l
+ tophys(r3,r3,r4)
+ 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)
+
+/* Set up for using our exception vectors */
+ /* ptr to phys current tss */
+ tophys(r4,r2,r4)
+ addi r4,r4,TSS /* init task's TSS */
+ mtspr SPRG3,r4
+ li r3,0
+ mtspr SPRG2,r3 /* 0 => r1 has kernel sp */
+
+/* On CHRP copy exception vectors down to 0 */
+ lis r5,_stext@ha
+ addi r5,r5,_stext@l
+ addis r5,r5,-KERNELBASE@h
+ cmpwi 0,r5,0
+ beq 77f /* vectors are already at 0 */
+ li r3,0x1000
+ mtctr r3
+ li r4,-4
+ addi r5,r5,-4
+74: lwzu r0,4(r5)
+ stwu r0,4(r4)
+ bdnz 74b
+ /* need to flush/invalidate caches too */
+ li r3,0x4000/CACHE_LINE_SIZE
+ li r4,0
+ mtctr r3
+73: dcbst 0,r4
+ addi r4,r4,CACHE_LINE_SIZE
+ bdnz 73b
+ sync
+ li r4,0
+ mtctr r3
+72: icbi 0,r4
+ addi r4,r4,CACHE_LINE_SIZE
+ bdnz 72b
+ sync
+ isync
+77:
+
/* Now turn on the MMU for real! */
li r4,MSR_KERNEL
lis r3,start_kernel@h
@@ -947,25 +1231,25 @@ start_here:
reset_SDR1:
lis r6,_SDR1@ha
lwz r6,_SDR1@l(r6)
- mfmsr r3
- li r4,MSR_IR|MSR_DR
- andc r3,r3,r4
+ mfmsr r5
+ li r4,0
+ ori r4,r4,MSR_EE|MSR_IR|MSR_DR
+ andc r3,r5,r4
lis r4,2f@h
- addis r4,r4,-KERNELBASE@h
ori r4,r4,2f@l
+ tophys(r4,r4,r5)
mtspr SRR0,r4
mtspr SRR1,r3
rfi
2: /* load new SDR1 */
- tlbia
+ tlbia
mtspr SDR1,r6
/* turn the mmu back on */
- li r4,MSR_KERNEL
mflr r3
mtspr SRR0,r3
- mtspr SRR1,r4
+ mtspr SRR1,r5
rfi
-
+
/*
* FP unavailable trap from kernel - print a message, but let
* the task use FP in the kernel until it returns to user mode.
@@ -987,19 +1271,10 @@ KernelFP:
* Disable FP for the task which had the FPU previously,
* and save its floating-point registers in its thread_struct.
* Enables the FPU for use in the kernel on return.
- * (If giveup_fpu_unmapped uses any integer registers other than
- * r3 - r6, the return code at load_up_fpu above will have
- * to be adjusted.)
*/
-giveup_fpu_unmapped:
- lis r6,-KERNELBASE@h
- b 1f
-
.globl giveup_fpu
giveup_fpu:
- li r6,0
-1:
- addis r3,r6,last_task_used_math@ha
+ lis r3,last_task_used_math@ha
lwz r4,last_task_used_math@l(r3)
mfmsr r5
ori r5,r5,MSR_FP
@@ -1008,7 +1283,6 @@ giveup_fpu:
SYNC
cmpi 0,r4,0
beqlr- /* if no previous owner, done */
- add r4,r4,r6
addi r4,r4,TSS /* want TSS of last_task_used_math */
li r5,0
stw r5,last_task_used_math@l(r3)
@@ -1016,7 +1290,6 @@ giveup_fpu:
mffs fr0
stfd fr0,TSS_FPSCR-4(r4)
lwz r5,PT_REGS(r4)
- add r5,r5,r6
lwz r3,_MSR-STACK_FRAME_OVERHEAD(r5)
li r4,MSR_FP
andc r3,r3,r4 /* disable FP for previous task */
@@ -1104,12 +1377,12 @@ syscall_ret_1:
b 22b
/* sys_sigreturn */
10: addi r3,r1,STACK_FRAME_OVERHEAD
- bl _EXTERN(sys_sigreturn)
+ bl sys_sigreturn
cmpi 0,r3,0 /* Check for restarted system call */
bge int_return
b 20b
/* Traced system call support */
-50: bl _EXTERN(syscall_trace)
+50: bl syscall_trace
lwz r0,GPR0(r1) /* Restore original registers */
lwz r3,GPR3(r1)
lwz r4,GPR4(r1)
@@ -1144,7 +1417,7 @@ syscall_ret_2:
oris r10,r10,0x1000
stw r10,_CCR(r1)
60: stw r3,GPR3(r1) /* Update return value */
- bl _EXTERN(syscall_trace)
+ bl syscall_trace
b int_return
66: li r3,ENOSYS
b 52b
@@ -1198,7 +1471,7 @@ _GLOBAL(_switch)
stw r0,TRAP(r1)
stw r1,KSP(r3) /* Set old stack pointer */
sync
- addis r0,r4,-KERNELBASE@h
+ tophys(r0,r4,r3)
mtspr SPRG3,r0 /* Update current TSS phys addr */
SYNC
lwz r1,KSP(r4) /* Load new stack pointer */
@@ -1220,6 +1493,8 @@ _GLOBAL(_switch)
/*
* Trap exit.
*/
+ .globl ret_from_syscall
+ret_from_syscall:
.globl int_return
int_return:
0: mfmsr r30 /* Disable interrupts */
@@ -1245,34 +1520,31 @@ int_return:
lwz r5,bh_active@l(r5)
and. r4,r4,r5
beq+ 2f
- ori r31,r30,MSR_EE /* re-enable interrupts */
- SYNC
- mtmsr r31
- SYNC
- bl _EXTERN(do_bottom_half)
+ bl do_bottom_half
SYNC
mtmsr r30 /* disable interrupts again */
SYNC
2: lwz r3,_MSR(r1) /* Returning to user mode? */
andi. r3,r3,MSR_PR
- beq+ 10f /* no - no need to mess with stack */
+ beq+ 10f /* if so, check need_resched and signals */
lis r3,need_resched@ha
lwz r3,need_resched@l(r3)
cmpi 0,r3,0 /* check need_resched flag */
beq+ 7f
- bl _EXTERN(schedule)
+ bl schedule
b 0b
-7: lwz r3,BLOCKED(r2) /* Check for pending unblocked signals */
- lwz r5,SIGNAL(r2)
- andc. r0,r5,r3 /* Lets thru any unblocked */
+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 _EXTERN(do_signal)
+ bl do_signal
b 0b
8: addi r4,r1,INT_FRAME_SIZE+STACK_UNDERHEAD /* size of frame */
stw r4,TSS+KSP(r2) /* save kernel stack pointer */
-10:
- lwz r2,_CTR(r1)
+ tophys(r3,r1,r3)
+ mtspr SPRG2,r3 /* phys exception stack pointer */
+10: lwz r2,_CTR(r1)
lwz r0,_LINK(r1)
mtctr r2
mtlr r0
@@ -1355,8 +1627,6 @@ _GLOBAL(flush_instruction_cache)
*
* flush_icache_range(unsigned long start, unsigned long stop)
*/
-CACHE_LINE_SIZE = 32
-LG_CACHE_LINE_SIZE = 5
_GLOBAL(flush_icache_range)
mfspr r5,PVR
rlwinm r5,r5,16,16,31
@@ -1417,6 +1687,28 @@ _GLOBAL(flush_page_to_ram)
* given.
*/
_GLOBAL(flush_hash_segments)
+#ifdef NO_RELOAD_HTAB
+/*
+ * Bitmask of PVR numbers of 603-like chips,
+ * for which we don't use the hash table at all.
+ */
+#define PVR_603_LIKE 0x13000000 /* bits 3, 6, 7 set */
+
+ mfspr r0,PVR
+ rlwinm r0,r0,16,27,31
+ lis r9,PVR_603_LIKE@h
+ rlwnm. r0,r9,r0,0,0
+ bne 99f
+#endif /* NO_RELOAD_HTAB */
+#ifdef __SMP__
+ lis r6,hash_table_lock@h
+ ori r6,r6,hash_table_lock@l
+1011: lwarx r0,0,r6
+ stwcx. r6,0,r6
+ bne- 1011b
+ cmpi 0,r0,0
+ bne 1011b
+#endif /* __SMP__ */
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 */
@@ -1438,7 +1730,13 @@ _GLOBAL(flush_hash_segments)
stw r0,0(r5) /* invalidate entry */
2: bdnz 1b /* continue with loop */
sync
- tlbia
+#ifdef __SMP__
+ lis r5,hash_table_lock@h
+ ori r5,r5,hash_table_lock@l
+ li r6,0
+ stw r6,0(r5)
+#endif /* __SMP__ */
+99: tlbia
isync
blr
@@ -1448,6 +1746,22 @@ _GLOBAL(flush_hash_segments)
* flush_hash_page(unsigned context, unsigned long va)
*/
_GLOBAL(flush_hash_page)
+#ifdef NO_RELOAD_HTAB
+ mfspr r0,PVR
+ rlwinm r0,r0,16,27,31
+ lis r9,PVR_603_LIKE@h
+ rlwnm. r0,r9,r0,0,0
+ bne 99f
+#endif /* NO_RELOAD_HTAB */
+#ifdef __SMP__
+ lis r6,hash_table_lock@h
+ ori r6,r6,hash_table_lock@l
+1011: lwarx r0,0,r6
+ stwcx. r6,0,r6
+ bne- 1011b
+ cmpi 0,r0,0
+ bne 1011b
+#endif /* __SMP__ */
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 */
@@ -1480,7 +1794,13 @@ _GLOBAL(flush_hash_page)
3: li r0,0
stw r0,0(r7) /* invalidate entry */
4: sync
- tlbie r4 /* in hw tlb too */
+#ifdef __SMP__
+ lis r5,hash_table_lock@h
+ ori r5,r5,hash_table_lock@l
+ li r6,0
+ stw r6,0(r5)
+#endif /* __SMP__ */
+99: tlbie r4 /* in hw tlb too */
isync
blr
@@ -1491,200 +1811,221 @@ _GLOBAL(__main)
blr
/*
- * These exception handlers are used when we have called a prom
- * routine after we have taken over the exception vectors and MMU.
- */
- .globl prom_exc_table
-prom_exc_table:
- .long TOPHYS(prom_exception) /* 0 */
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception) /* 400 */
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception) /* 800 */
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception) /* c00 */
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception) /* 1000 */
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception) /* 1400 */
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception) /* 1800 */
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception) /* 1c00 */
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception) /* 1000 */
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception) /* 1400 */
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception) /* 1800 */
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception) /* 1c00 */
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception)
- .long TOPHYS(prom_exception)
-
-/*
- * When we come in to these prom exceptions, r1 and lr have been
- * saved in sprg1 and sprg2, and lr points to a word containing
- * the vector offset.
+ * On CHRP, the Run-Time Abstraction Services (RTAS) have to be
+ * called with the MMU off.
*/
-prom_exception:
- mr r1,r21 /* save r21 */
- lis r21,prom_sp@ha /* get a stack to use */
- addis r21,r21,-KERNELBASE@h
- lwz r21,prom_sp@l(r21)
- addis r21,r21,-KERNELBASE@h /* convert to physical addr */
- subi r21,r21,INT_FRAME_SIZE+STACK_UNDERHEAD
- stw r0,GPR0(r21)
- stw r2,GPR2(r21)
- stw r3,GPR3(r21)
- stw r4,GPR4(r21)
- stw r5,GPR5(r21)
- stw r6,GPR6(r21)
- stw r20,GPR20(r21)
- stw r1,GPR21(r21)
- stw r22,GPR22(r21)
- stw r23,GPR23(r21)
- mfspr r1,SPRG1
- stw r1,GPR1(r21)
- mfcr r3
- mfspr r4,SPRG2
- stw r3,_CCR(r21)
- stw r4,_LINK(r21)
- mfctr r3
- mfspr r4,XER
- stw r3,_CTR(r21)
- stw r4,_XER(r21)
- mfspr r22,SRR0
- mfspr r23,SRR1
-
- /* at this point we have set things up pretty much exactly
- how EXCEPTION_PROLOG does */
- mflr r3
- lwz r3,0(r3) /* get exception vector */
- stw r3,TRAP(r21)
- cmpi 0,r3,0x300 /* was it a dsi? */
- bne 1f
-
- mfspr r20,DSISR /* here on data access exc. */
- andis. r0,r20,0x8470 /* weird error? */
- bne 3f /* 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 */
- b 2f
-
-1: cmpi 0,r3,0x400 /* was it an isi? */
- bne 3f
- andis. r0,r23,0x4000 /* if so, check if no pte found */
- beq 3f /* 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 */
-2: lis r5,prom_tss@ha /* phys addr of TSS */
- addis r5,r5,-KERNELBASE@h
- lwz r5,prom_tss@l(r5)
- bl hash_page
-
-3: addis r1,r21,KERNELBASE@h /* restore kernel stack ptr */
- addi r3,r1,INT_FRAME_SIZE+STACK_UNDERHEAD
- stw r3,0(r21) /* set stack chain pointer */
- lis r5,prom_tss@ha
- addis r5,r5,-KERNELBASE@h
- lwz r5,prom_tss@l(r5)
- mtspr SPRG3,r5 /* reset phys TSS pointer */
- lwz r4,TRAP(r21) /* the real exception vector */
- addi r3,r1,STACK_FRAME_OVERHEAD
- li r20,MSR_KERNEL
- bl transfer_to_handler
- .long PromException
- .long prom_int_return
-
- .comm prom_sp,4
- .comm prom_tss,4
-
- .globl prom_int_return
-prom_int_return:
- lis r3,prom_exc_table@ha /* restore sprg3 for prom vectors */
- addi r3,r3,prom_exc_table@l
+ .globl enter_rtas
+enter_rtas:
+ stwu r1,-16(r1)
+ mflr r0
+ stw r0,20(r1)
addis r3,r3,-KERNELBASE@h
- mtspr SPRG3,r3
- b int_return
+ lis r4,rtas_data@ha
+ lwz r4,rtas_data@l(r4)
+ 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)
+ mfmsr r9
+ stw r9,8(r1)
+ li r0,0
+ 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 */
+
+ .globl amhere
+amhere: .long 0
+
+#ifdef __SMP__
/*
- * When entering the prom, we have to change to using a different
- * set of exception vectors.
+ * Secondary processor begins executing here.
*/
- .globl enter_prom
-enter_prom:
- stwu r1,-32(r1)
- mflr r0
- stw r0,36(r1)
- stw r29,20(r1)
- stw r30,24(r1)
- stw r31,28(r1)
- lis r8,prom_entry@ha
- lwz r8,prom_entry@l(r8)
- mfmsr r31
- andi. r0,r31,MSR_IP /* using our own vectors yet? */
- beq 1f /* if so, have to switch */
- mtlr r8
- blrl /* if not, can just charge ahead */
- b 2f
-1: lis r9,prom_sp@ha /* save sp for exception handler */
- stw r1,prom_sp@l(r9)
- mfspr r29,SPRG3 /* save physical tss pointer */
- lis r9,prom_tss@ha
- stw r29,prom_tss@l(r9)
- li r9,0
- ori r9,r9,MSR_EE
- andc r30,r31,r9
- lis r9,prom_exc_table@ha /* set pointer to exception table */
- addi r9,r9,prom_exc_table@l
- addis r9,r9,-KERNELBASE@h
- ori r0,r31,MSR_IP
+ .globl secondary_entry
+secondary_entry:
+ lis r0,amhere@h
+ ori r0,r0,amhere@l
+ addis r0,r0,-KERNELBASE@h
+ stw r0,0(r0)
sync
- mtmsr r30 /* disable interrupts */
- mtspr SPRG3,r9 /* while we update MSR_IP and sprg3 */
+ isync
+ /* just like __start() with a few changes -- Cort */
+ mfspr r9,PVR
+ rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */
+ cmpi 0,r9,1
+ lis r11,KERNELBASE@h
+ bne 4f
+ ori r11,r11,4 /* set up BAT registers for 601 */
+ li r8,0x7f
+ oris r9,r11,0x800000@h /* set up BAT reg for 2nd 8M */
+ oris r10,r8,0x800000@h /* set up BAT reg for 2nd 8M */
+ mtspr IBAT1U,r9
+ mtspr IBAT1L,r10
+ b 5f
+4: ori r11,r11,0x1ff /* set up BAT registers for 604 */
+ li r8,2
+ mtspr DBAT0U,r11
+ mtspr DBAT0L,r8
+5: mtspr IBAT0U,r11
+ mtspr IBAT0L,r8
+ isync
+/*
+ * we now have the 1st 16M of ram mapped with the bats.
+ * prep needs the mmu to be turned on here, but pmac already has it on.
+ * this shouldn't bother the pmac since it just gets turned on again
+ * as we jump to our code at KERNELBASE. -- Cort
+ */
+ mfmsr r0
+ ori r0,r0,MSR_DR|MSR_IR
+ mtspr SRR1,r0
+ lis r0,100f@h
+ ori r0,r0,100f@l
+ mtspr SRR0,r0
+ SYNC
+ rfi /* enables MMU */
+100:
+ /*
+ * Enable caches and 604-specific features if necessary.
+ */
+ mfspr r9,PVR
+ rlwinm r9,r9,16,16,31
+ cmpi 0,r9,1
+ beq 4f /* not needed for 601 */
+ mfspr r11,HID0
+ andi. r0,r11,HID0_DCE
+ ori r11,r11,HID0_ICE|HID0_DCE
+ ori r8,r11,HID0_ICFI
+ bne 3f /* don't invalidate the D-cache */
+ ori r8,r8,HID0_DCI /* unless it wasn't enabled */
+3:
+ /* turn on dpm for 603 */
+ cmpi 0,r9,3
+ bne 10f
+ oris r11,r11,HID0_DPM@h
+10:
sync
- mtmsr r0 /* start using exc. vectors in prom */
- mtlr r8
- blrl /* call prom */
+ mtspr HID0,r8 /* enable and invalidate caches */
sync
- mtmsr r30 /* disable interrupts again */
- mtspr SPRG3,r29 /* while we restore MSR_IP and sprg3 */
+ mtspr HID0,r11 /* enable caches */
sync
- mtmsr r31 /* reenable interrupts */
-2: lwz r0,36(r1)
- mtlr r0
- lwz r29,20(r1)
- lwz r30,24(r1)
- lwz r31,28(r1)
- lwz r1,0(r1)
- blr
+ isync
+ cmpi 0,r9,4 /* check for 604 */
+ cmpi 1,r9,9 /* or 604e */
+ cmpi 2,r9,10 /* or mach5 */
+ cror 2,2,6
+ cror 2,2,10
+ bne 4f
+ ori r11,r11,HID0_SIED|HID0_BHTE /* for 604[e], enable */
+ bne 2,5f
+ ori r11,r11,HID0_BTCD
+5: mtspr HID0,r11 /* superscalar exec & br history tbl */
+4:
+ /* get ptr to current */
+ lis r2,current_set@h
+ ori r2,r2,current_set@l
+ /* assume we're second processor for now */
+ lwz r2,4(r2)
+ /* stack */
+ addi r1,r2,TASK_UNION_SIZE
+ li r0,0
+ stwu r0,-STACK_FRAME_OVERHEAD(r1)
+
+/*
+ * init_MMU on the first processor has setup the variables
+ * for us - all we need to do is load them -- Cort
+ */
+
+/*
+ * 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.
+ */
+ lis r6,_SDR1@ha
+ lwz r6,_SDR1@l(r6)
+ lis r4,2f@h
+ ori r4,r4,2f@l
+ tophys(r4,r4,r3)
+ 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 */
+ mtspr SDR1,r6
+ 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. */
+ lis r3,BATS@ha
+ addi r3,r3,BATS@l
+ tophys(r3,r3,r4)
+ 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)
+
+/* Set up for using our exception vectors */
+ /* ptr to phys current tss */
+ tophys(r4,r2,r4)
+ addi r4,r4,TSS /* init task's TSS */
+ mtspr SPRG3,r4
+ li r3,0
+ mtspr SPRG2,r3 /* 0 => r1 has kernel sp */
+ /* need to flush/invalidate caches too */
+ li r3,0x4000/CACHE_LINE_SIZE
+ li r4,0
+ mtctr r3
+73: dcbst 0,r4
+ addi r4,r4,CACHE_LINE_SIZE
+ bdnz 73b
+ sync
+ li r4,0
+ mtctr r3
+72: icbi 0,r4
+ addi r4,r4,CACHE_LINE_SIZE
+ bdnz 72b
+ sync
+ isync
+77:
+/* Now turn on the MMU for real! */
+ li r4,MSR_KERNEL
+ lis r3,start_secondary@h
+ ori r3,r3,start_secondary@l
+ mtspr SRR0,r3
+ mtspr SRR1,r4
+ rfi /* enable MMU and jump to start_kernel */
+/* should never return */
+ .long 0
+#endif /* __SMP__ */
+
/*
* We put a few things here that have to be page-aligned.
* This stuff goes at the beginning of the data segment,
@@ -1708,4 +2049,3 @@ swapper_pg_dir:
.globl cmd_line
cmd_line:
.space 512
-
diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c
index bfe1a4146..f47d6f3d6 100644
--- a/arch/ppc/kernel/idle.c
+++ b/arch/ppc/kernel/idle.c
@@ -1,5 +1,5 @@
/*
- * $Id: idle.c,v 1.4 1997/08/23 22:46:01 cort Exp $
+ * $Id: idle.c,v 1.13 1998/01/06 06:44:55 cort Exp $
*
* Idle daemon for PowerPC. Idle daemon will handle any action
* that needs to be taken when the system becomes idle.
@@ -23,7 +23,6 @@
#include <linux/unistd.h>
#include <linux/ptrace.h>
#include <linux/malloc.h>
-#include <linux/config.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
@@ -31,40 +30,126 @@
#include <asm/io.h>
#include <asm/smp_lock.h>
#include <asm/processor.h>
+#include <asm/mmu.h>
int zero_paged(void *unused);
-int power_saved(void *unused);
+void inline power_save(void);
+void inline htab_reclaim(void);
-asmlinkage int sys_idle(void)
+int idled(void *unused)
{
int ret = -EPERM;
- if (current->pid != 0)
- goto out;
-
/*
* want one per cpu since it would be nice to have all
* processors who aren't doing anything
* zero-ing pages since this daemon is lock-free
* -- Cort
*/
- kernel_thread(zero_paged, NULL, 0);
- /* no powersaving modes on 601 */
- /*if( (_get_PVR()>>16) != 1 )
- kernel_thread(power_saved, NULL, 0);*/
+ /* kernel_thread(zero_paged, NULL, 0); */
- /* endless loop with no priority at all */
- current->priority = -100;
- current->counter = -100;
+#ifdef __SMP__
+printk("SMP %d: in idle. current = %s/%d\n",
+ current->processor,current->comm,current->pid);
+#endif /* __SMP__ */
for (;;)
{
+ /* endless loop with no priority at all */
+ current->priority = -100;
+ current->counter = -100;
+
+ /* endless idle loop with no priority at all */
+ /* htab_reclaim(); */
schedule();
+#ifndef __SMP__
+ /* can't do this on smp since second processor
+ will never wake up -- Cort */
+ /* power_save(); */
+#endif /* __SMP__ */
}
ret = 0;
-out:
return ret;
}
+
+/*
+ * Mark 'zombie' pte's in the hash table as invalid.
+ * This improves performance for the hash table reload code
+ * a bit since we don't consider unused pages as valid.
+ * I haven't done any rigorous performance analysis yet
+ * so it's still experimental and turned off here.
+ * -- Cort
+ */
+void inline htab_reclaim(void)
+{
+ PTE *ptr, *start;
+ struct task_struct *p;
+ unsigned long valid = 0;
+ extern PTE *Hash, *Hash_end;
+ extern unsigned long Hash_size;
+
+ /* if we don't have a htab */
+ if ( Hash_size == 0 )
+ return;
+ /*lock_dcache();*/
+
+ /* find a random place in the htab to start each time */
+ start = &Hash[jiffies%(Hash_size/sizeof(ptr))];
+ for ( ptr = start; ptr < Hash_end ; ptr++)
+ {
+ if ( ptr == start )
+ return;
+ if ( ptr == Hash_end )
+ ptr = Hash;
+ valid = 0;
+ if (!ptr->v)
+ continue;
+ for_each_task(p)
+ {
+ if ( need_resched )
+ {
+ /*unlock_dcache();*/
+ return;
+ }
+ /* if this vsid/context is in use */
+ if ( (ptr->vsid >> 4) == p->mm->context )
+ {
+ valid = 1;
+ break;
+ }
+ }
+ if ( valid )
+ continue;
+ /* this pte isn't used */
+ ptr->v = 0;
+ }
+ /*unlock_dcache();*/
+}
+
+/*
+ * 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 */
+}
+
+#ifdef __SMP__
+/*
+ * SMP entry into the idle task - calls the same thing as the
+ * non-smp versions. -- Cort
+ */
+int cpu_idle(void *unused)
+{
+ idled(unused);
+ return 0;
+}
+#endif /* __SMP__ */
+
/*
* vars for idle task zero'ing out pages
*/
@@ -105,7 +190,7 @@ unsigned long get_prezerod_page(void)
atomic_inc((atomic_t *)&zeropage_hits);
atomic_dec((atomic_t *)&zerocount);
wake_up(&page_zerod_wait);
- resched_force();
+ need_resched = 1;
/* zero out the pointer to next in the page */
*(unsigned long *)page = 0;
@@ -120,7 +205,6 @@ unsigned long get_prezerod_page(void)
* Zero's out pages until we need to resched or
* we've reached the limit of zero'd pages.
*/
-
int zero_paged(void *unused)
{
extern pte_t *get_pte( struct mm_struct *mm, unsigned long address );
@@ -129,14 +213,18 @@ int zero_paged(void *unused)
pte_t *pte;
sprintf(current->comm, "zero_paged (idle)");
- current->blocked = ~0UL;
+ /* current->blocked = ~0UL; */
+#ifdef __SMP__
+ printk("Started zero_paged (cpu %d)\n", hard_smp_processor_id());
+#else
printk("Started zero_paged\n");
+#endif /* __SMP__ */
__sti();
while ( 1 )
{
- /* don't want to be pre-empted by swapper or power_saved */
+ /* don't want to be pre-empted by swapper or power_save */
current->priority = -98;
current->counter = -98;
/* we don't want to run until we have something to do */
@@ -147,14 +235,11 @@ int zero_paged(void *unused)
* If we're interrupted we keep this page and our place in it
* since we validly hold it and it's reserved for us.
*/
- pageptr = __get_free_pages(GFP_ATOMIC, 0, 0 );
+ pageptr = __get_free_pages(GFP_ATOMIC, 0);
if ( !pageptr )
- {
- printk("!pageptr in zero_paged\n");
goto retry;
- }
- if ( resched_needed() )
+ if ( need_resched )
schedule();
/*
@@ -180,7 +265,7 @@ int zero_paged(void *unused)
*/
for ( bytecount = 0; bytecount < PAGE_SIZE ; bytecount += 4 )
{
- if ( resched_needed() )
+ if ( need_resched )
schedule();
*(unsigned long *)(bytecount + pageptr) = 0;
}
@@ -228,52 +313,30 @@ retry:
}
}
-int power_saved(void *unused)
+void inline power_save(void)
{
unsigned long msr, hid0;
- sprintf(current->comm, "power_saved (idle)");
- current->blocked = ~0UL;
-
- printk("Power saving daemon started\n");
+
+ /* no powersaving modes on the 601 */
+ if( (_get_PVR()>>16) == 1 )
+ return;
__sti();
- while (1)
- {
- /* don't want to be pre-empted by swapper */
- current->priority = -99;
- current->counter = -99;
- /* go ahead and wakeup page_zerod() */
- wake_up(&page_zerod_wait);
- schedule();
- asm volatile(
- /* clear powersaving modes and set nap mode */
- "mfspr %3,1008 \n\t"
- "andc %3,%3,%4 \n\t"
- "or %3,%3,%5 \n\t"
- "mtspr 1008,%3 \n\t"
- /* enter the mode */
- "mfmsr %0 \n\t"
- "oris %0,%0,%2 \n\t"
- "sync \n\t"
- "mtmsr %0 \n\t"
- "isync \n\t"
- : "=&r" (msr)
- : "0" (msr), "i" (MSR_POW>>16),
- "r" (hid0),
- "r" (HID0_DOZE|HID0_NAP|HID0_SLEEP),
- "r" (HID0_NAP));
- /*
- * The ibm carolina spec says that the eagle memory
- * controller will detect the need for a snoop
- * and wake up the processor so we don't need to
- * check for cache operations that need to be
- * snooped. The ppc book says the run signal
- * must be asserted while napping for this though.
- *
- * Paul, what do you know about the pmac here?
- * -- Cort
- */
- schedule();
- }
+ asm volatile(
+ /* clear powersaving modes and set nap mode */
+ "mfspr %3,1008 \n\t"
+ "andc %3,%3,%4 \n\t"
+ "or %3,%3,%5 \n\t"
+ "mtspr 1008,%3 \n\t"
+ /* enter the mode */
+ "mfmsr %0 \n\t"
+ "oris %0,%0,%2 \n\t"
+ "sync \n\t"
+ "mtmsr %0 \n\t"
+ "isync \n\t"
+ : "=&r" (msr)
+ : "0" (msr), "i" (MSR_POW>>16),
+ "r" (hid0),
+ "r" (HID0_DOZE|HID0_NAP|HID0_SLEEP),
+ "r" (HID0_NAP));
}
-
diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c
index da3c53697..4616d59a2 100644
--- a/arch/ppc/kernel/irq.c
+++ b/arch/ppc/kernel/irq.c
@@ -38,17 +38,22 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/bitops.h>
+#include <asm/gg2.h>
#undef SHOW_IRQ
-#define OPENPIC_DEBUG
unsigned lost_interrupts = 0;
unsigned int local_irq_count[NR_CPUS];
static struct irqaction irq_action[NR_IRQS];
static int spurious_interrupts = 0;
-int __ppc_bh_counter;
static unsigned int cached_irq_mask = 0xffffffff;
static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
+spinlock_t irq_controller_lock;
+#ifdef __SMP__
+atomic_t __ppc_bh_counter = ATOMIC_INIT(0);
+#else
+int __ppc_bh_counter = 0;
+#endif
#define cached_21 (((char *)(&cached_irq_mask))[3])
#define cached_A1 (((char *)(&cached_irq_mask))[2])
@@ -57,7 +62,8 @@ static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
* These are set to the appropriate functions by init_IRQ()
*/
void (*mask_and_ack_irq)(int irq_nr);
-void (*set_irq_mask)(int irq_nr);
+void (*mask_irq)(unsigned int irq_nr);
+void (*unmask_irq)(unsigned int irq_nr);
/* prep */
@@ -72,8 +78,6 @@ extern unsigned long route_pci_interrupts(void);
#define KEYBOARD_IRQ 20 /* irq number for command-power interrupt */
#define PMAC_IRQ_MASK (~ld_le32(IRQ_ENABLE))
-/* chrp */
-volatile struct Hydra *Hydra = NULL;
void i8259_mask_and_ack_irq(int irq_nr)
{
@@ -97,10 +101,14 @@ void i8259_mask_and_ack_irq(int irq_nr)
void pmac_mask_and_ack_irq(int irq_nr)
{
+ unsigned long bit = 1UL << irq_nr;
+
spin_lock(&irq_controller_lock);
- cached_irq_mask |= 1 << irq_nr;
- out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) & ~(1 << irq_nr));
- out_le32(IRQ_ACK, 1U << irq_nr);
+ cached_irq_mask |= bit;
+ lost_interrupts &= ~bit;
+ out_le32(IRQ_ACK, bit);
+ out_le32(IRQ_ENABLE, ~cached_irq_mask);
+ out_le32(IRQ_ACK, bit);
spin_unlock(&irq_controller_lock);
}
@@ -109,11 +117,10 @@ void chrp_mask_and_ack_irq(int irq_nr)
/* spinlocks are done by i8259_mask_and_ack() - Cort */
if (is_8259_irq(irq_nr))
i8259_mask_and_ack_irq(irq_nr);
- openpic_eoi(0);
}
-void i8259_set_irq_mask(int irq_nr)
+static void i8259_set_irq_mask(int irq_nr)
{
if (irq_nr > 7) {
outb(cached_A1,0xA1);
@@ -122,8 +129,10 @@ void i8259_set_irq_mask(int irq_nr)
}
}
-void pmac_set_irq_mask(int irq_nr)
+static void pmac_set_irq_mask(int irq_nr)
{
+ unsigned long bit = 1UL << irq_nr;
+
/* this could be being enabled or disabled - so use cached_irq_mask */
out_le32(IRQ_ENABLE, ~cached_irq_mask /* enable all unmasked */ );
/*
@@ -131,39 +140,53 @@ void pmac_set_irq_mask(int irq_nr)
* when the device interrupt is already on *doesn't* set
* the bit in the flag register or request another interrupt.
*/
- if ((ld_le32(IRQ_LEVEL) & (1UL<<irq_nr)) && !(ld_le32(IRQ_FLAG) & (1UL<<irq_nr)))
- lost_interrupts |= (1UL<<irq_nr);
-}
-
-void chrp_set_irq_mask(int irq_nr)
-{
- if (is_8259_irq(irq_nr)) {
- i8259_set_irq_mask(irq_nr);
- } else
- {
- /* disable? */
- if ( cached_irq_mask & (1UL<<irq_nr) )
- openpic_disable_irq(irq_to_openpic(irq_nr));
- /* enable */
- else
- openpic_disable_irq(irq_to_openpic(irq_nr));
- }
+ if ((bit & ~cached_irq_mask)
+ && (ld_le32(IRQ_LEVEL) & bit) && !(ld_le32(IRQ_FLAG) & bit))
+ lost_interrupts |= bit;
}
/*
* These have to be protected by the spinlock
* before being called.
*/
-static inline void mask_irq(unsigned int irq_nr)
+static void i8259_mask_irq(unsigned int irq_nr)
{
cached_irq_mask |= 1 << irq_nr;
- set_irq_mask(irq_nr);
+ i8259_set_irq_mask(irq_nr);
}
-static inline void unmask_irq(unsigned int irq_nr)
+static void i8259_unmask_irq(unsigned int irq_nr)
{
cached_irq_mask &= ~(1 << irq_nr);
- set_irq_mask(irq_nr);
+ i8259_set_irq_mask(irq_nr);
+}
+
+static void pmac_mask_irq(unsigned int irq_nr)
+{
+ cached_irq_mask |= 1 << irq_nr;
+ pmac_set_irq_mask(irq_nr);
+}
+
+static void pmac_unmask_irq(unsigned int irq_nr)
+{
+ cached_irq_mask &= ~(1 << irq_nr);
+ pmac_set_irq_mask(irq_nr);
+}
+
+static void chrp_mask_irq(unsigned int irq_nr)
+{
+ if (is_8259_irq(irq_nr))
+ i8259_mask_irq(irq_nr);
+ else
+ openpic_disable_irq(irq_to_openpic(irq_nr));
+}
+
+static void chrp_unmask_irq(unsigned int irq_nr)
+{
+ if (is_8259_irq(irq_nr))
+ i8259_unmask_irq(irq_nr);
+ else
+ openpic_enable_irq(irq_to_openpic(irq_nr));
}
void disable_irq(unsigned int irq_nr)
@@ -201,15 +224,167 @@ int get_irq_list(char *buf)
}
len += sprintf(buf+len, "\n");
}
-#ifdef __SMP_PROF__
- len+=sprintf(buf+len, "IPI: %8lu received\n",
- ipi_count);
-#endif
- len += sprintf(buf+len, "99: %10u spurious or short\n",
+ len += sprintf(buf+len, "99: %10u spurious or short\n",
spurious_interrupts);
return len;
}
+
+#ifdef __SMP__
+/* Who has global_irq_lock. */
+unsigned char global_irq_holder = NO_PROC_ID;
+
+/* This protects IRQ's. */
+spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED;
+unsigned long previous_irqholder;
+
+/* This protects BH software state (masks, things like that). */
+spinlock_t global_bh_lock = SPIN_LOCK_UNLOCKED;
+
+/* Global IRQ locking depth. */
+atomic_t global_irq_count = ATOMIC_INIT(0);
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, atomic_read(&global_irq_count)); stuck = INIT_STUCK; }
+
+void wait_on_irq(int cpu, unsigned long where)
+{
+ int stuck = INIT_STUCK;
+ int local_count = local_irq_count[cpu];
+
+ /* Are we the only one in an interrupt context? */
+ while (local_count != atomic_read(&global_irq_count)) {
+ /*
+ * No such luck. Now we need to release the lock,
+ * _and_ release our interrupt context, because
+ * otherwise we'd have dead-locks and live-locks
+ * and other fun things.
+ */
+ atomic_sub(local_count, &global_irq_count);
+ spin_unlock(&global_irq_lock);
+
+ /*
+ * Wait for everybody else to go away and release
+ * their things before trying to get the lock again.
+ */
+ for (;;) {
+ STUCK;
+ if (atomic_read(&global_irq_count))
+ continue;
+ if (*((unsigned char *)&global_irq_lock))
+ continue;
+ if (spin_trylock(&global_irq_lock))
+ break;
+ }
+ atomic_add(local_count, &global_irq_count);
+ }
+}
+
+#define irq_active(cpu) \
+ (global_irq_count != local_irq_count[cpu])
+
+/*
+ * This is called when we want to synchronize with
+ * interrupts. We may for example tell a device to
+ * stop sending interrupts: but to make sure there
+ * are no interrupts that are executing on another
+ * CPU we need to call this function.
+ *
+ * On UP this is a no-op.
+ */
+void synchronize_irq(void)
+{
+ int cpu = smp_processor_id();
+ int local_count = local_irq_count[cpu];
+
+ /* Do we need to wait? */
+ if (local_count != atomic_read(&global_irq_count)) {
+ /* The stupid way to do this */
+ cli();
+ sti();
+ }
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 10000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) {\
+ll_printk("get_irqlock stuck at %08lx, waiting for %08lx\n", where, previous_irqholder); stuck = INIT_STUCK;}
+
+void get_irqlock(int cpu, unsigned long where)
+{
+ int stuck = INIT_STUCK;
+ if (!spin_trylock(&global_irq_lock)) {
+ /* do we already hold the lock? */
+ if ((unsigned char) cpu == global_irq_holder)
+ return;
+ /* Uhhuh.. Somebody else got it. Wait.. */
+ do {
+ do {
+ STUCK;
+ barrier();
+ } while (*((unsigned char *)&global_irq_lock));
+ } while (!spin_trylock(&global_irq_lock));
+ }
+
+ /*
+ * Ok, we got the lock bit.
+ * But that's actually just the easy part.. Now
+ * we need to make sure that nobody else is running
+ * in an interrupt context.
+ */
+ wait_on_irq(cpu, where);
+ /*
+ * Finally.
+ */
+ global_irq_holder = cpu;
+ previous_irqholder = where;
+}
+
+void __global_cli(void)
+{
+ int cpu = smp_processor_id();
+ unsigned long where;
+ __asm__("mr %0,31" : "=r" (where)); /* get lr */
+ __cli();
+ get_irqlock(cpu, where);
+}
+
+void __global_sti(void)
+{
+ release_irqlock(smp_processor_id());
+ __sti();
+}
+
+unsigned long __global_save_flags(void)
+{
+ return global_irq_holder == (unsigned char) smp_processor_id();
+}
+
+void __global_restore_flags(unsigned long flags)
+{
+ switch (flags) {
+ case 0:
+ release_irqlock(smp_processor_id());
+ __sti();
+ break;
+ case 1:
+ __global_cli();
+ break;
+ default:
+ printk("global_restore_flags: %08lx (%08lx)\n",
+ flags, (&flags)[-1]);
+ }
+}
+#endif /* __SMP__ */
+
+
asmlinkage void do_IRQ(struct pt_regs *regs)
{
int irq;
@@ -217,9 +392,14 @@ asmlinkage void do_IRQ(struct pt_regs *regs)
struct irqaction *action;
int cpu = smp_processor_id();
int status;
+ int openpic_eoi_done = 0;
- hardirq_enter(cpu);
+#ifdef __SMP__
+ if ( cpu != 0 )
+ panic("cpu %d received interrupt", cpu);
+#endif /* __SMP__ */
+ hardirq_enter(cpu);
/*
* I'll put this ugly mess of code into a function
@@ -232,7 +412,6 @@ asmlinkage void do_IRQ(struct pt_regs *regs)
{
case _MACH_Pmac:
bits = ld_le32(IRQ_FLAG) | lost_interrupts;
- lost_interrupts = 0;
for (irq = NR_IRQS - 1; irq >= 0; --irq)
if (bits & (1U << irq))
break;
@@ -246,30 +425,37 @@ asmlinkage void do_IRQ(struct pt_regs *regs)
*
* This should go in the above mask/ack code soon. -- Cort
*/
- irq = (*(volatile unsigned char *)0xfec80000) & 0x0f;
+ irq = *(volatile unsigned char *)GG2_INT_ACK_SPECIAL;
+ /*
+ * Acknowledge as soon as possible to allow i8259
+ * interrupt nesting
+ */
+ openpic_eoi(0);
+ openpic_eoi_done = 1;
}
- else if (irq >= 64)
+ else if (irq >= OPENPIC_VEC_TIMER)
{
/*
* OpenPIC interrupts >64 will be used for other purposes
* like interprocessor interrupts and hardware errors
*/
-#ifdef OPENPIC_DEBUG
- printk("OpenPIC interrupt %d\n", irq);
-#endif
- if (irq==99)
+ if (irq == OPENPIC_VEC_SPURIOUS) {
+ /*
+ * Spurious interrupts should never be
+ * acknowledged
+ */
spurious_interrupts++;
- }
- else {
- /*
- * Here we should process IPI timer
- * for now the interrupt is dismissed.
- */
+ openpic_eoi_done = 1;
+ } else {
+ /*
+ * Here we should process IPI timer
+ * for now the interrupt is dismissed.
+ */
+ }
goto out;
}
break;
- case _MACH_IBM:
- case _MACH_Motorola:
+ case _MACH_prep:
#if 1
outb(0x0C, 0x20);
irq = inb(0x20) & 7;
@@ -314,12 +500,11 @@ retry_cascade:
status = 0;
action = irq_action + irq;
kstat.interrupts[irq]++;
- if ( action && action->handler)
- {
+ if (action->handler) {
if (!(action->flags & SA_INTERRUPT))
__sti();
status |= action->flags;
- action->handler(irq, action->dev_id, regs);
+ action->handler(irq, action->dev_id, regs);
/*if (status & SA_SAMPLE_RANDOM)
add_interrupt_randomness(irq);*/
__cli(); /* in case the handler turned them on */
@@ -337,6 +522,8 @@ retry_cascade:
goto retry_cascade;
/* do_bottom_half is called if necessary from int_return in head.S */
out:
+ if (_machine == _MACH_chrp && !openpic_eoi_done)
+ openpic_eoi(0);
hardirq_exit(cpu);
}
@@ -369,6 +556,7 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
restore_flags(flags);
return 0;
}
+
void free_irq(unsigned int irq, void *dev_id)
{
struct irqaction * action = irq + irq_action;
@@ -411,17 +599,15 @@ __initfunc(static void i8259_init(void))
{
/* init master interrupt controller */
outb(0x11, 0x20); /* Start init sequence */
- outb(0x40, 0x21); /* Vector base */
- /*outb(0x04, 0x21);*/ /* edge tiggered, Cascade (slave) on IRQ2 */
- outb(0x0C, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
+ outb(0x00, 0x21); /* Vector base */
+ outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */
outb(0x01, 0x21); /* Select 8086 mode */
outb(0xFF, 0x21); /* Mask all */
/* init slave interrupt controller */
outb(0x11, 0xA0); /* Start init sequence */
- outb(0x48, 0xA1); /* Vector base */
- /*outb(0x02, 0xA1);*/ /* edge triggered, Cascade (slave) on IRQ2 */
- outb(0x0A, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
+ outb(0x08, 0xA1); /* Vector base */
+ outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */
outb(0x01, 0xA1); /* Select 8086 mode */
outb(0xFF, 0xA1); /* Mask all */
outb(cached_A1, 0xA1);
@@ -439,17 +625,30 @@ __initfunc(void init_IRQ(void))
{
case _MACH_Pmac:
mask_and_ack_irq = pmac_mask_and_ack_irq;
- set_irq_mask = pmac_set_irq_mask;
+ mask_irq = pmac_mask_irq;
+ unmask_irq = pmac_unmask_irq;
*IRQ_ENABLE = 0;
#ifdef CONFIG_XMON
request_irq(KEYBOARD_IRQ, xmon_irq, 0, "NMI", 0);
#endif /* CONFIG_XMON */
break;
- case _MACH_Motorola:
- case _MACH_IBM:
+ case _MACH_chrp:
+ mask_and_ack_irq = chrp_mask_and_ack_irq;
+ mask_irq = chrp_mask_irq;
+ unmask_irq = chrp_unmask_irq;
+ ioremap(GG2_INT_ACK_SPECIAL, 1);
+ openpic_init();
+ i8259_init();
+#ifdef CONFIG_XMON
+ request_irq(openpic_to_irq(HYDRA_INT_ADB_NMI),
+ xmon_irq, 0, "NMI", 0);
+#endif /* CONFIG_XMON */
+ break;
+ case _MACH_prep:
mask_and_ack_irq = i8259_mask_and_ack_irq;
- set_irq_mask = i8259_set_irq_mask;
+ mask_irq = i8259_mask_irq;
+ unmask_irq = i8259_unmask_irq;
i8259_init();
route_pci_interrupts();
@@ -472,46 +671,20 @@ __initfunc(void init_IRQ(void))
/*
* On Carolina, irq 15 and 13 must be level (scsi/ide/net).
*/
- if ( _machine == _MACH_IBM )
+ if ( _prep_type == _PREP_IBM )
irq_mode2 |= 0xa0;
/*
* Sound on the Powerstack reportedly needs to be edge triggered
*/
- if ( _machine == _MACH_Motorola )
+ if ( _prep_type == _PREP_Motorola )
{
- /*irq_mode2 &= ~0x04L;
+ irq_mode2 &= ~0x04L;
+ irq_mode2 = 0xca;
outb( irq_mode1 , 0x4d0 );
- outb( irq_mode2 , 0x4d1 );*/
+ outb( irq_mode2 , 0x4d1 );
}
}
break;
- case _MACH_chrp:
- mask_and_ack_irq = chrp_mask_and_ack_irq;
- set_irq_mask = chrp_set_irq_mask;
- if ((Hydra = find_hydra())) {
- printk("Hydra Mac I/O at %p\n", Hydra);
- out_le32(&Hydra->Feature_Control, HYDRA_FC_SCC_CELL_EN |
- HYDRA_FC_SCSI_CELL_EN |
- HYDRA_FC_SCCA_ENABLE |
- HYDRA_FC_SCCB_ENABLE |
- HYDRA_FC_ARB_BYPASS |
- HYDRA_FC_MPIC_ENABLE |
- HYDRA_FC_SLOW_SCC_PCLK |
- HYDRA_FC_MPIC_IS_MASTER);
- OpenPIC = (volatile struct OpenPIC *)&Hydra->OpenPIC;
- } else if (!OpenPIC /* && find_xxx */) {
- printk("Unknown openpic implementation\n");
- /* other OpenPIC implementations */
- /* ... */
- }
- if (OpenPIC)
- openpic_init();
- else
- panic("No OpenPIC found");
- if (Hydra)
- hydra_post_openpic_init();
- i8259_init();
- break;
}
}
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index f4174df38..9e3c6165d 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -2,14 +2,16 @@
* This file contains miscellaneous low-level functions.
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
*
- * 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.
+ * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras.
+ *
+ * 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/config.h>
#include <linux/sys.h>
#include <asm/unistd.h>
#include <asm/errno.h>
@@ -26,7 +28,21 @@
addi r4,r4,0x1000; \
bdnz 0b
-_TEXT()
+ .text
+
+/*
+ * Returns (address we're running at) - (address we were linked at)
+ * for use before the text and data are mapped to KERNELBASE.
+ */
+_GLOBAL(reloc_offset)
+ mflr r0
+ bl 1f
+1: mflr r3
+ lis r4,1b@ha
+ addi r4,r4,1b@l
+ subf r3,r4,r3
+ mtlr r0
+ blr
/*
* Disable interrupts
@@ -64,24 +80,6 @@ _GLOBAL(_hard_sti)
mtmsr r3 /* Update machine state */
blr
-#if 0
-/*
- * Restore 'flags'
- * __restore_flags(long val)
- */
-_GLOBAL(__restore_flags)
- andi. r0,r3,MSR_EE /* enabling interrupts? */
- beq 2f
- lis r4,lost_interrupts@ha
- lwz r4,lost_interrupts@l(r4)
- cmpi 0,r4,0
- bne do_lost_interrupts
-2: sync /* Some chip revs have problems here... */
- mtmsr r3
- isync
- blr
-#endif
-
/*
* We were about to enable interrupts but we have to simulate
* some interrupts that were lost by enable_irq first.
@@ -151,6 +149,13 @@ _GLOBAL(atomic_add)
stwcx. r5,0,r4 /* Update with new value */
bne- 10b /* Retry if "reservation" (i.e. lock) lost */
blr
+_GLOBAL(atomic_add_return)
+10: lwarx r5,0,r4 /* Fetch old value & reserve */
+ add r5,r5,r3 /* Perform 'add' operation */
+ stwcx. r5,0,r4 /* Update with new value */
+ bne- 10b /* Retry if "reservation" (i.e. lock) lost */
+ mr r3,r5
+ blr
_GLOBAL(atomic_sub)
10: lwarx r5,0,r4 /* Fetch old value & reserve */
sub r5,r5,r3 /* Perform 'add' operation */
@@ -209,11 +214,29 @@ _GLOBAL(atomic_set_mask)
/*
* I/O string operations
*
+ * insb(port, buf, len)
+ * outsb(port, buf, len)
* insw(port, buf, len)
* outsw(port, buf, len)
* insl(port, buf, len)
* outsl(port, buf, len)
*/
+_GLOBAL(_insb)
+ mtctr r5
+ subi r4,r4,1
+00: lbz r5,0(r3)
+ stbu r5,1(r4)
+ bdnz 00b
+ blr
+
+_GLOBAL(_outsb)
+ mtctr r5
+ subi r4,r4,1
+00: lbzu r5,1(r4)
+ stb r5,0(r3)
+ bdnz 00b
+ blr
+
_GLOBAL(_insw)
mtctr r5
subi r4,r4,2
@@ -325,6 +348,33 @@ cvt_df:
stfs 0,0(r4)
blr
+
+_GLOBAL(lock_dcache)
+ mfspr r3,PVR /* nop on 601 */
+ rlwinm r3,r3,16,16,31
+ cmpwi 0,r3,1
+ beqlr-
+ mfspr r3,HID0
+ ori r3,r3,HID0_DLOCK
+ mtspr HID0,r3
+ sync
+ isync
+ blr
+
+_GLOBAL(unlock_dcache)
+ mfspr r3,PVR /* nop on 601 */
+ rlwinm r3,r3,16,16,31
+ cmpwi 0,r3,1
+ beqlr-
+ mfspr r3,HID0
+ li r4,HID0_DLOCK
+ andc r3,r3,r4
+ mtspr HID0,r3
+ sync
+ isync
+ blr
+
+
/*
* Create a kernel thread
* __kernel_thread(flags, fn, arg)
@@ -387,7 +437,7 @@ sys_call_table:
.long sys_mknod
.long sys_chmod /* 15 */
.long sys_chown
- .long sys_break
+ .long /*sys_break*/ sys_ni_syscall
.long sys_stat
.long sys_lseek
.long sys_getpid /* 20 */
@@ -401,11 +451,11 @@ sys_call_table:
.long sys_fstat
.long sys_pause
.long sys_utime /* 30 */
- .long sys_stty
- .long sys_gtty
+ .long /*sys_stty*/ sys_ni_syscall
+ .long /*sys_gtty*/ sys_ni_syscall
.long sys_access
.long sys_nice
- .long sys_ftime /* 35 */
+ .long /*sys_ftime*/ sys_ni_syscall /* 35 */
.long sys_sync
.long sys_kill
.long sys_rename
@@ -414,7 +464,7 @@ sys_call_table:
.long sys_dup
.long sys_pipe
.long sys_times
- .long sys_prof
+ .long /*sys_prof*/ sys_ni_syscall
.long sys_brk /* 45 */
.long sys_setgid
.long sys_getgid
@@ -422,13 +472,13 @@ sys_call_table:
.long sys_geteuid
.long sys_getegid /* 50 */
.long sys_acct
- .long sys_phys
- .long sys_lock
+ .long /*sys_phys*/ sys_ni_syscall
+ .long /*sys_lock*/ sys_ni_syscall
.long sys_ioctl
.long sys_fcntl /* 55 */
- .long sys_mpx
+ .long /*sys_mpx*/ sys_ni_syscall
.long sys_setpgid
- .long sys_ulimit
+ .long /*sys_ulimit*/ sys_ni_syscall
.long sys_olduname
.long sys_umask /* 60 */
.long sys_chroot
@@ -468,7 +518,7 @@ sys_call_table:
.long sys_fchown /* 95 */
.long sys_getpriority
.long sys_setpriority
- .long sys_profil
+ .long /*sys_profil*/ sys_ni_syscall
.long sys_statfs
.long sys_fstatfs /* 100 */
.long sys_ioperm
@@ -539,7 +589,8 @@ sys_call_table:
.long sys_query_module
.long sys_poll
.long sys_nfsservctl
+ .long sys_setresgid
+ .long sys_getresgid /* 170 */
.long sys_prctl
- .long sys_debug
.space (NR_syscalls-171)*4
diff --git a/arch/ppc/kernel/mk_defs.c b/arch/ppc/kernel/mk_defs.c
index 80f10c59e..8db1763db 100644
--- a/arch/ppc/kernel/mk_defs.c
+++ b/arch/ppc/kernel/mk_defs.c
@@ -32,12 +32,12 @@ main(void)
DEFINE(STATE, offsetof(struct task_struct, state));
DEFINE(NEXT_TASK, offsetof(struct task_struct, next_task));
DEFINE(COUNTER, offsetof(struct task_struct, counter));
- DEFINE(BLOCKED, offsetof(struct task_struct, blocked));
- DEFINE(SIGNAL, offsetof(struct task_struct, signal));
+ DEFINE(SIGPENDING, offsetof(struct task_struct, sigpending));
DEFINE(TSS, offsetof(struct task_struct, tss));
- DEFINE(KSP, offsetof(struct thread_struct, ksp));
- /*DEFINE(PG_TABLES, offsetof(struct thread_struct, pg_tables));*/
DEFINE(MM, offsetof(struct task_struct, 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(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall));
DEFINE(PT_REGS, offsetof(struct thread_struct, regs));
diff --git a/arch/ppc/kernel/openpic.c b/arch/ppc/kernel/openpic.c
index 7eb5e5aa9..11660cbea 100644
--- a/arch/ppc/kernel/openpic.c
+++ b/arch/ppc/kernel/openpic.c
@@ -17,6 +17,7 @@
#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>
@@ -28,21 +29,12 @@
#undef REGISTER_DEBUG
-#define VEC_TIMER 0x40 /* and up */
-#define VEC_IPI 0x50 /* and up */
-#define VEC_SOURCE 0x10 /* and up */
-#define VEC_SPURIOUS 99
+volatile struct OpenPIC *OpenPIC = NULL;
+u_int OpenPIC_NumInitSenses __initdata = 0;
+u_char *OpenPIC_InitSenses __initdata = NULL;
-
-volatile struct OpenPIC *OpenPIC;
-
-static u_int Version;
static u_int NumProcessors;
static u_int NumSources;
-static u_int VendorID;
-static u_int DeviceID;
-static u_int Stepping;
-static u_int TimerFrequency;
/*
@@ -181,24 +173,17 @@ static void openpic_safe_writefield(volatile u_int *addr, u_int mask,
* Initialize the OpenPIC
*/
-void openpic_init(void)
+__initfunc(void openpic_init(void))
{
u_int t, i;
+ u_int vendorid, devid, stepping, timerfreq;
const char *version, *vendor, *device;
- if (!OpenPIC) {
- printk("No OpenPIC present\n");
- return;
- }
+ if (!OpenPIC)
+ panic("No OpenPIC found");
t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
- Version = t & OPENPIC_FEATURE_VERSION_MASK;
- 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;
-
- switch (Version) {
+ switch (t & OPENPIC_FEATURE_VERSION_MASK) {
case 1:
version = "1.0";
break;
@@ -206,19 +191,23 @@ void openpic_init(void)
version = "1.2";
break;
default:
- version = "?.?";
+ 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);
t = openpic_read(&OpenPIC->Global.Vendor_Identification);
- VendorID = t & OPENPIC_VENDOR_ID_VENDOR_ID_MASK;
- DeviceID = (t & OPENPIC_VENDOR_ID_DEVICE_ID_MASK) >>
- OPENPIC_VENDOR_ID_DEVICE_ID_SHIFT;
- Stepping = (t & OPENPIC_VENDOR_ID_STEPPING_MASK) >>
+ vendorid = t & OPENPIC_VENDOR_ID_VENDOR_ID_MASK;
+ devid = (t & OPENPIC_VENDOR_ID_DEVICE_ID_MASK) >>
+ OPENPIC_VENDOR_ID_DEVICE_ID_SHIFT;
+ stepping = (t & OPENPIC_VENDOR_ID_STEPPING_MASK) >>
OPENPIC_VENDOR_ID_STEPPING_SHIFT;
- switch (VendorID) {
+ switch (vendorid) {
case OPENPIC_VENDOR_ID_APPLE:
vendor = "Apple";
break;
@@ -226,7 +215,7 @@ void openpic_init(void)
vendor = "Unknown";
break;
}
- switch (DeviceID) {
+ switch (devid) {
case OPENPIC_DEVICE_ID_APPLE_HYDRA:
device = "Hydra";
break;
@@ -234,20 +223,20 @@ void openpic_init(void)
device = "Unknown";
break;
}
- printk("OpenPIC Vendor %d (%s), Device %d (%s), Stepping %d\n", VendorID,
- vendor, DeviceID, device, Stepping);
+ printk("OpenPIC Vendor %d (%s), Device %d (%s), Stepping %d\n", vendorid,
+ vendor, devid, device, stepping);
- TimerFrequency = openpic_read(&OpenPIC->Global.Timer_Frequency);
+ timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
printk("OpenPIC timer frequency is ");
- if (TimerFrequency)
- printk("%d Hz\n", TimerFrequency);
+ if (timerfreq)
+ printk("%d Hz\n", timerfreq);
else
printk("not set\n");
/* Initialize timer interrupts */
for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
/* Disabled, Priority 0 */
- openpic_inittimer(i, 0, VEC_TIMER+i);
+ openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i);
/* No processor */
openpic_maptimer(i, 0);
}
@@ -255,23 +244,24 @@ void openpic_init(void)
/* Initialize IPI interrupts */
for (i = 0; i < OPENPIC_NUM_IPI; i++) {
/* Disabled, Priority 0 */
- openpic_initipi(i, 0, VEC_IPI+i);
+ openpic_initipi(i, 0, OPENPIC_VEC_IPI+i);
}
/* Initialize external interrupts */
/* SIOint (8259 cascade) is special */
- openpic_initirq(0, 8, VEC_SOURCE, 1, 1); /* 0,1 gives interrupt storm */
+ 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, VEC_SOURCE+i, 0, 1);
+ 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(VEC_SPURIOUS);
+ openpic_set_spurious(OPENPIC_VEC_SPURIOUS);
if (request_irq(IRQ_8259_CASCADE, no_action, SA_INTERRUPT,
"OpenPIC cascade", NULL))
@@ -340,9 +330,6 @@ void openpic_eoi(void)
void openpic_eoi(u_int cpu)
#endif
{
-#if 0
-printk("++openpic_eoi:\n");
-#endif
check_arg_cpu(cpu);
openpic_write(&OpenPIC->THIS_CPU.EOI, 0);
}
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index 49f2f37be..7e39487d8 100644
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -1,22 +1,27 @@
/*
- * $Id: pci.c,v 1.12 1997/08/27 05:05:28 cort Exp $
+ * $Id: pci.c,v 1.18 1997/10/29 03:35:07 cort Exp $
* Common pmac/prep/chrp pci routines. -- Cort
*/
#include <linux/kernel.h>
#include <linux/pci.h>
-/*#include <linux/bios32.h>*/
+#include <linux/bios32.h>
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/init.h>
+#include <linux/config.h>
+#include <linux/pci.h>
#include <asm/processor.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/pci-bridge.h>
-unsigned long io_base;
+#if !defined(CONFIG_MACH_SPECIFIC)
+unsigned long isa_io_base;
+unsigned long isa_mem_base;
unsigned long pci_dram_offset;
+#endif /* CONFIG_MACH_SPECIFIC */
/*
* It would be nice if we could create a include/asm/pci.h and have just
@@ -29,77 +34,56 @@ unsigned long pci_dram_offset;
* -- Cort
*/
int (*ptr_pcibios_read_config_byte)(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned char *val);
+ unsigned char offset, unsigned char *val);
int (*ptr_pcibios_read_config_word)(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned short *val);
+ unsigned char offset, unsigned short *val);
int (*ptr_pcibios_read_config_dword)(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned int *val);
+ unsigned char offset, unsigned int *val);
int (*ptr_pcibios_write_config_byte)(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned char val);
+ unsigned char offset, unsigned char val);
int (*ptr_pcibios_write_config_word)(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned short val);
+ unsigned char offset, unsigned short val);
int (*ptr_pcibios_write_config_dword)(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned int val);
-int (*ptr_pcibios_find_device)(unsigned short vendor, unsigned short dev_id,
- unsigned short index, unsigned char *bus_ptr,
- unsigned char *dev_fn_ptr);
-int (*ptr_pcibios_find_class)(unsigned int class_code, unsigned short index,
- unsigned char *bus_ptr, unsigned char *dev_fn_ptr);
+ unsigned char offset, unsigned int val);
extern int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned char *val);
+ unsigned char offset, unsigned char *val);
extern int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned short *val);
+ unsigned char offset, unsigned short *val);
extern int pmac_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned int *val);
+ unsigned char offset, unsigned int *val);
extern int pmac_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned char val);
+ unsigned char offset, unsigned char val);
extern int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned short val);
+ unsigned char offset, unsigned short val);
extern int pmac_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned int val);
-extern int pmac_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
- unsigned short index, unsigned char *bus_ptr,
- unsigned char *dev_fn_ptr);
-extern int pmac_pcibios_find_class(unsigned int class_code, unsigned short index,
- unsigned char *bus_ptr, unsigned char *dev_fn_ptr);
+ unsigned char offset, unsigned int val);
extern int chrp_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned char *val);
+ unsigned char offset, unsigned char *val);
extern int chrp_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned short *val);
+ unsigned char offset, unsigned short *val);
extern int chrp_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned int *val);
+ unsigned char offset, unsigned int *val);
extern int chrp_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned char val);
+ unsigned char offset, unsigned char val);
extern int chrp_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned short val);
+ unsigned char offset, unsigned short val);
extern int chrp_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned int val);
-extern int chrp_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
- unsigned short index, unsigned char *bus_ptr,
- unsigned char *dev_fn_ptr);
-extern int chrp_pcibios_find_class(unsigned int class_code, unsigned short index,
- unsigned char *bus_ptr, unsigned char *dev_fn_ptr);
+ unsigned char offset, unsigned int val);
extern int prep_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned char *val);
+ unsigned char offset, unsigned char *val);
extern int prep_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned short *val);
+ unsigned char offset, unsigned short *val);
extern int prep_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned int *val);
+ unsigned char offset, unsigned int *val);
extern int prep_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned char val);
+ unsigned char offset, unsigned char val);
extern int prep_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned short val);
+ unsigned char offset, unsigned short val);
extern int prep_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned int val);
-extern int prep_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
- unsigned short index, unsigned char *bus_ptr,
- unsigned char *dev_fn_ptr);
-extern int prep_pcibios_find_class(unsigned int class_code, unsigned short index,
- unsigned char *bus_ptr, unsigned char *dev_fn_ptr);
-
+ unsigned char offset, unsigned int val);
int pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned char *val)
@@ -131,64 +115,94 @@ int pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
{
return ptr_pcibios_write_config_dword(bus,dev_fn,offset,val);
}
-int pcibios_find_device(unsigned short vendor, unsigned short dev_id,
- unsigned short index, unsigned char *bus_ptr,
- unsigned char *dev_fn_ptr)
+
+int pcibios_present(void)
{
- return ptr_pcibios_find_device(vendor,dev_id,index,bus_ptr,dev_fn_ptr);
+ return 1;
}
-int pcibios_find_class(unsigned int class_code, unsigned short index,
- unsigned char *bus_ptr, unsigned char *dev_fn_ptr)
+
+int pcibios_find_device (unsigned short vendor, unsigned short device_id,
+ unsigned short index, unsigned char *bus,
+ unsigned char *devfn)
{
- return ptr_pcibios_find_class(class_code,index,bus_ptr,dev_fn_ptr);
+ unsigned int curr = 0;
+ struct pci_dev *dev;
+ for (dev = pci_devices; dev; dev = dev->next) {
+ if (dev->vendor == vendor && dev->device == device_id) {
+ if (curr == index) {
+ *devfn = dev->devfn;
+ *bus = dev->bus->number;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++curr;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
}
-int pcibios_present(void)
+/*
+ * Given the class, find the n'th instance of that device
+ * in the system.
+ */
+int pcibios_find_class (unsigned int class_code, unsigned short index,
+ unsigned char *bus, unsigned char *devfn)
{
- return 1;
+ unsigned int curr = 0;
+ struct pci_dev *dev;
+
+ for (dev = pci_devices; dev; dev = dev->next) {
+ if (dev->class == class_code) {
+ if (curr == index) {
+ *devfn = dev->devfn;
+ *bus = dev->bus->number;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++curr;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
}
+
__initfunc(unsigned long
-pcibios_init(unsigned long mem_start,unsigned long mem_end))
+ pcibios_init(unsigned long mem_start,unsigned long mem_end))
+{
+ return mem_start;
+}
+
+__initfunc(void
+ setup_pci_ptrs(void))
{
switch (_machine) {
- case _MACH_Motorola:
- case _MACH_IBM:
+ case _MACH_prep:
ptr_pcibios_read_config_byte = prep_pcibios_read_config_byte;
ptr_pcibios_read_config_word = prep_pcibios_read_config_word;
ptr_pcibios_read_config_dword = prep_pcibios_read_config_dword;
ptr_pcibios_write_config_byte = prep_pcibios_write_config_byte;
ptr_pcibios_write_config_word = prep_pcibios_write_config_word;
ptr_pcibios_write_config_dword = prep_pcibios_write_config_dword;
- ptr_pcibios_find_device = prep_pcibios_find_device;
- ptr_pcibios_find_class = prep_pcibios_find_class;
break;
- case _MACH_Pmac:
+ case _MACH_Pmac:
ptr_pcibios_read_config_byte = pmac_pcibios_read_config_byte;
ptr_pcibios_read_config_word = pmac_pcibios_read_config_word;
ptr_pcibios_read_config_dword = pmac_pcibios_read_config_dword;
ptr_pcibios_write_config_byte = pmac_pcibios_write_config_byte;
ptr_pcibios_write_config_word = pmac_pcibios_write_config_word;
ptr_pcibios_write_config_dword = pmac_pcibios_write_config_dword;
- ptr_pcibios_find_device = pmac_pcibios_find_device;
- ptr_pcibios_find_class = pmac_pcibios_find_class;
break;
- case _MACH_chrp:
+ case _MACH_chrp:
ptr_pcibios_read_config_byte = chrp_pcibios_read_config_byte;
ptr_pcibios_read_config_word = chrp_pcibios_read_config_word;
ptr_pcibios_read_config_dword = chrp_pcibios_read_config_dword;
ptr_pcibios_write_config_byte = chrp_pcibios_write_config_byte;
ptr_pcibios_write_config_word = chrp_pcibios_write_config_word;
ptr_pcibios_write_config_dword = chrp_pcibios_write_config_dword;
- ptr_pcibios_find_device = chrp_pcibios_find_device;
- ptr_pcibios_find_class = chrp_pcibios_find_class;
break;
}
- return mem_start;
}
__initfunc(unsigned long
-pcibios_fixup(unsigned long mem_start, unsigned long mem_end))
+ pcibios_fixup(unsigned long mem_start, unsigned long mem_end))
{
return mem_start;
}
diff --git a/arch/ppc/kernel/pmac_pci.c b/arch/ppc/kernel/pmac_pci.c
index a48385b3f..d0144a567 100644
--- a/arch/ppc/kernel/pmac_pci.c
+++ b/arch/ppc/kernel/pmac_pci.c
@@ -135,11 +135,10 @@ static void add_bridges(struct device_node *dev, unsigned long *mem_ptr)
bp = (struct bridge_data *) *mem_ptr;
*mem_ptr += sizeof(struct bridge_data);
bp->cfg_addr = (volatile unsigned int *)
- (dev->addrs[0].address + 0x800000);
+ ioremap(dev->addrs[0].address + 0x800000, 0x1000);
bp->cfg_data = (volatile unsigned char *)
- (dev->addrs[0].address + 0xc00000);
- bp->io_base = (void *) dev->addrs[0].address;
- ioremap(dev->addrs[0].address, 0x800000);
+ ioremap(dev->addrs[0].address + 0xc00000, 0x1000);
+ bp->io_base = (void *) ioremap(dev->addrs[0].address, 0x10000);
bp->bus_number = bus_range[0];
bp->max_bus = bus_range[1];
bp->next = bridge_list;
@@ -329,95 +328,3 @@ int pmac_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
out_le32((volatile unsigned int *)bp->cfg_data, val);
return PCIBIOS_SUCCESSFUL;
}
-
-int pmac_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
- unsigned short index, unsigned char *bus_ptr,
- unsigned char *dev_fn_ptr)
-{
- int bus, unit, fn, num, devfn;
- unsigned int x, vendev;
- unsigned char h;
-
- if (vendor == 0xffff)
- return PCIBIOS_BAD_VENDOR_ID;
- vendev = (dev_id << 16) + vendor;
- num = 0;
- for (bus = 0; bus <= max_bus; ++bus) {
- if (bridges[bus] == 0)
- continue;
- unit = fn = 0;
- if (bus == bridges[bus]->bus_number)
- unit = 11;
- while (unit < 32) {
- devfn = PCI_DEVFN(unit, fn);
- if (pcibios_read_config_dword(bus, devfn,
- PCI_VENDOR_ID, &x)
- == PCIBIOS_SUCCESSFUL && x == vendev) {
- if (index == num) {
- *bus_ptr = bus;
- *dev_fn_ptr = devfn;
- return PCIBIOS_SUCCESSFUL;
- }
- ++num;
- }
- if (fn != 0) {
- if (++fn >= 8) {
- ++unit;
- fn = 0;
- }
- continue;
- }
- if (pcibios_read_config_byte(bus, devfn,
- PCI_HEADER_TYPE, &h)
- == PCIBIOS_SUCCESSFUL && (h & 0x80) != 0)
- ++fn;
- else
- ++unit;
- }
- }
- return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-int pmac_pcibios_find_class(unsigned int class_code, unsigned short index,
- unsigned char *bus_ptr, unsigned char *dev_fn_ptr)
-{
- int bus, unit, fn, num, devfn;
- unsigned int x;
- unsigned char h;
-
- num = 0;
- for (bus = 0; bus <= max_bus; ++bus) {
- if (bridges[bus] == 0)
- continue;
- unit = fn = 0;
- if (bus == bridges[bus]->bus_number)
- unit = 11;
- while (unit < 32) {
- devfn = PCI_DEVFN(unit, fn);
- if (pcibios_read_config_dword(bus, devfn,
- PCI_CLASS_REVISION, &x)
- == PCIBIOS_SUCCESSFUL && (x >> 8) == class_code) {
- if (index == num) {
- *bus_ptr = bus;
- *dev_fn_ptr = devfn;
- return PCIBIOS_SUCCESSFUL;
- }
- ++num;
- }
- if (fn != 0) {
- if (++fn >= 8) {
- ++unit;
- fn = 0;
- }
- continue;
- }
- if (pcibios_read_config_byte(bus, devfn,
- PCI_HEADER_TYPE, &h)
- == PCIBIOS_SUCCESSFUL && (h & 0x80) != 0)
- ++fn;
- else
- ++unit;
- }
- }
- return PCIBIOS_DEVICE_NOT_FOUND;
-}
diff --git a/arch/ppc/kernel/pmac_setup.c b/arch/ppc/kernel/pmac_setup.c
index 74a8ff92d..4e37becd5 100644
--- a/arch/ppc/kernel/pmac_setup.c
+++ b/arch/ppc/kernel/pmac_setup.c
@@ -37,12 +37,16 @@
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/major.h>
+#ifdef CONFIG_ABSTRACT_CONSOLE
+#include <linux/console.h>
+#endif
#include <asm/prom.h>
#include <asm/system.h>
#include <asm/pgtable.h>
#include <asm/io.h>
#include <asm/ide.h>
#include <asm/pci-bridge.h>
+#include <asm/adb.h>
#include "time.h"
/*
@@ -55,32 +59,18 @@
extern int root_mountflags;
-extern char command_line[];
-extern char saved_command_line[256];
-
unsigned char drive_info;
#define DEFAULT_ROOT_DEVICE 0x0801 /* sda1 - slightly silly choice */
-extern unsigned long find_available_memory(void);
+static void gc_init(const char *, int);
-void pmac_setup_arch(char **cmdline_p,
- unsigned long * memory_start_p, unsigned long * memory_end_p)
+void
+pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p)
{
- extern unsigned long *end_of_DRAM;
struct device_node *cpu;
int *fp;
- strcpy(saved_command_line, command_line);
- *cmdline_p = command_line;
-
- *memory_start_p = find_available_memory();
- *memory_end_p = (unsigned long) end_of_DRAM;
-
- set_prom_callback();
-
- *memory_start_p = copy_device_tree(*memory_start_p, *memory_end_p);
-
/* Set loops_per_sec to a half-way reasonable value,
for use until calibrate_delay gets called. */
cpu = find_type_devices("cpu");
@@ -90,6 +80,7 @@ void pmac_setup_arch(char **cmdline_p,
switch (_get_PVR() >> 16) {
case 4: /* 604 */
case 9: /* 604e */
+ case 10: /* mach V (604ev5) */
case 20: /* 620 */
loops_per_sec = *fp;
break;
@@ -99,10 +90,33 @@ void pmac_setup_arch(char **cmdline_p,
} else
loops_per_sec = 50000000;
}
+
+ *memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p);
+ gc_init("gc", 0);
+ gc_init("ohare", 1);
+
+#ifdef CONFIG_ABSTRACT_CONSOLE
+ /* Frame buffer device based console */
+ conswitchp = &fb_con;
+#endif
+}
+
+static void gc_init(const char *name, int isohare)
+{
+ struct device_node *np;
+
+ for (np = find_devices(name); np != NULL; np = np->next) {
+ if (np->n_addrs > 0)
+ ioremap(np->addrs[0].address, np->addrs[0].size);
+ if (isohare) {
+ printk(KERN_INFO "Twiddling the magic ohare bits\n");
+ out_le32(OMAGICPLACE, OMAGICCONT);
+ }
+ }
}
-char *bootpath;
-char bootdevice[256];
+extern char *bootpath;
+extern char *bootdevice;
void *boot_host;
int boot_target;
int boot_part;
@@ -111,31 +125,15 @@ kdev_t boot_dev;
unsigned long
powermac_init(unsigned long mem_start, unsigned long mem_end)
{
- struct device_node *chosen_np, *ohare_np;
-
- mem_start = pmac_find_bridges(mem_start, mem_end);
- ohare_np = find_devices("ohare");
- if (ohare_np != NULL) {
- printk(KERN_INFO "Twiddling the magic ohare bits\n");
- out_le32(OMAGICPLACE, OMAGICCONT);
- }
pmac_nvram_init();
- via_cuda_init();
- pmac_read_rtc_time();
- pmac_find_display();
- bootpath = NULL;
- chosen_np = find_devices("chosen");
- if (chosen_np != NULL)
- bootpath = (char *) get_property(chosen_np, "bootpath", NULL);
- if (bootpath != NULL) {
- /*
- * There's a bug in the prom. (Why am I not surprised.)
- * If you pass a path like scsi/sd@1:0 to canon, it returns
- * something like /bandit@F2000000/gc@10/53c94@10000/sd@0,0
- * That is, the scsi target number doesn't get preserved.
- */
- call_prom("canon", 3, 1, bootpath, bootdevice, sizeof(bootdevice));
+ adb_init();
+ if (_machine == _MACH_Pmac) {
+ pmac_read_rtc_time();
}
+#ifdef CONFIG_PMAC_CONSOLE
+ pmac_find_display();
+#endif
+
return mem_start;
}
@@ -146,9 +144,17 @@ note_scsi_host(struct device_node *node, void *host)
char *p;
l = strlen(node->full_name);
- if (strncmp(node->full_name, bootdevice, l) == 0
+ if (bootpath != NULL && bootdevice != NULL
+ && strncmp(node->full_name, bootdevice, l) == 0
&& (bootdevice[l] == '/' || bootdevice[l] == 0)) {
boot_host = host;
+ /*
+ * There's a bug in OF 1.0.5. (Why am I not surprised.)
+ * If you pass a path like scsi/sd@1:0 to canon, it returns
+ * something like /bandit@F2000000/gc@10/53c94@10000/sd@0,0
+ * That is, the scsi target number doesn't get preserved.
+ * So we pick the target number out of bootpath and use that.
+ */
p = strstr(bootpath, "/sd@");
if (p != NULL) {
p += 4;
@@ -160,6 +166,28 @@ note_scsi_host(struct device_node *node, void *host)
}
}
+#ifdef CONFIG_SCSI
+/* Find the device number for the disk (if any) at target tgt
+ on host adaptor host.
+ XXX this really really should be in drivers/scsi/sd.c. */
+#include <linux/blkdev.h>
+#include "../../../drivers/scsi/scsi.h"
+#include "../../../drivers/scsi/sd.h"
+#include "../../../drivers/scsi/hosts.h"
+
+int sd_find_target(void *host, int tgt)
+{
+ Scsi_Disk *dp;
+ int i;
+
+ 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(SCSI_DISK_MAJOR, i << 4);
+ return 0;
+}
+#endif
+
void find_boot_device(void)
{
int dev;
@@ -230,42 +258,8 @@ void pmac_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
int
pmac_get_cpuinfo(char *buffer)
{
- int pvr = _get_PVR();
- char *model;
- struct device_node *cpu;
- int l, *fp;
-
- l = 0;
- cpu = find_type_devices("cpu");
- if (cpu != 0) {
- fp = (int *) get_property(cpu, "clock-frequency", NULL);
- if (fp != 0)
- l += sprintf(buffer, "%dMHz ", *fp / 1000000);
- }
-
- switch (pvr>>16) {
- case 1:
- model = "601";
- break;
- case 3:
- model = "603";
- break;
- case 4:
- model = "604";
- break;
- case 6:
- model = "603e";
- break;
- case 7:
- model = "603ev";
- break;
- case 9:
- model = "604e";
- break;
- default:
- model = "unknown";
- break;
- }
- return l + sprintf(buffer+l, "PowerPC %s rev %d.%d\n", model,
- (pvr & 0xff00) >> 8, pvr & 0xff);
+ int len;
+ /* should find motherboard type here as well */
+ len = sprintf(buffer,"machine\t\t: PowerMac\n");
+ return len;
}
diff --git a/arch/ppc/kernel/pmac_support.c b/arch/ppc/kernel/pmac_support.c
index 3c1895088..17226f8ff 100644
--- a/arch/ppc/kernel/pmac_support.c
+++ b/arch/ppc/kernel/pmac_support.c
@@ -7,16 +7,18 @@
#include <linux/nvram.h>
#include <asm/ptrace.h>
#include <asm/io.h>
-#include <asm/cuda.h>
#include <asm/system.h>
#include <asm/prom.h>
/*
- * Read and write the non-volatile RAM on PowerMacs.
+ * Read and write the non-volatile RAM on PowerMacs and CHRP machines.
*/
static int nvram_naddrs;
static volatile unsigned char *nvram_addr;
static volatile unsigned char *nvram_data;
+static int nvram_mult;
+
+#define NVRAM_SIZE 0x2000 /* 8kB of non-volatile RAM */
void pmac_nvram_init(void)
{
@@ -29,8 +31,13 @@ void pmac_nvram_init(void)
return;
}
nvram_naddrs = dp->n_addrs;
- if (nvram_naddrs == 1) {
+ if (_machine == _MACH_chrp && nvram_naddrs == 1) {
+ /* XXX for now */
+ nvram_data = ioremap(0xf70e0000, NVRAM_SIZE);
+ nvram_mult = 1;
+ } else if (nvram_naddrs == 1) {
nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
+ nvram_mult = (dp->addrs[0].size + NVRAM_SIZE - 1) / NVRAM_SIZE;
} else if (nvram_naddrs == 2) {
nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
@@ -44,7 +51,7 @@ unsigned char nvram_read_byte(int addr)
{
switch (nvram_naddrs) {
case 1:
- return nvram_data[(addr & 0x1fff) << 4];
+ return nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult];
case 2:
*nvram_addr = addr >> 5;
eieio();
@@ -57,7 +64,7 @@ void nvram_write_byte(unsigned char val, int addr)
{
switch (nvram_naddrs) {
case 1:
- nvram_data[(addr & 0x1fff) << 4] = val;
+ nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult] = val;
break;
case 2:
*nvram_addr = addr >> 5;
diff --git a/arch/ppc/kernel/pmac_time.c b/arch/ppc/kernel/pmac_time.c
index 69a17321d..1a31ffa9a 100644
--- a/arch/ppc/kernel/pmac_time.c
+++ b/arch/ppc/kernel/pmac_time.c
@@ -2,9 +2,7 @@
* Support for periodic interrupts (100 per second) and for getting
* the current time from the RTC on Power Macintoshes.
*
- * At present, we use the decrementer register in the 601 CPU
- * for our periodic interrupts. This will probably have to be
- * changed for other processors.
+ * We use the decrementer register for our periodic interrupts.
*
* Paul Mackerras August 1996.
* Copyright (C) 1996 Paul Mackerras.
@@ -15,17 +13,79 @@
#include <linux/param.h>
#include <linux/string.h>
#include <linux/mm.h>
+#include <asm/adb.h>
#include <asm/cuda.h>
#include <asm/prom.h>
#include <asm/system.h>
#include "time.h"
-
/* Apparently the RTC stores seconds since 1 Jan 1904 */
#define RTC_OFFSET 2082844800
/*
+ * Calibrate the decrementer frequency with the VIA timer 1.
+ */
+#define VIA_TIMER_FREQ_6 4700000 /* time 1 frequency * 6 */
+
+/* VIA registers */
+#define RS 0x200 /* skip between registers */
+#define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */
+#define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */
+#define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */
+#define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */
+#define ACR (11*RS) /* Auxiliary control register */
+#define IFR (13*RS) /* Interrupt flag register */
+
+/* Bits in ACR */
+#define T1MODE 0xc0 /* Timer 1 mode */
+#define T1MODE_CONT 0x40 /* continuous interrupts */
+
+/* Bits in IFR and IER */
+#define T1_INT 0x40 /* Timer 1 interrupt */
+
+static int via_calibrate_decr(void)
+{
+ struct device_node *vias;
+ volatile unsigned char *via;
+ int count = VIA_TIMER_FREQ_6 / HZ;
+ unsigned int dstart, dend;
+
+ vias = find_devices("via-cuda");
+ if (vias == 0)
+ vias = find_devices("via-pmu");
+ if (vias == 0 || vias->n_addrs == 0)
+ return 0;
+ via = (volatile unsigned char *) vias->addrs[0].address;
+
+ /* set timer 1 for continuous interrupts */
+ out_8(&via[ACR], (via[ACR] & ~T1MODE) | T1MODE_CONT);
+ /* set the counter to a small value */
+ out_8(&via[T1CH], 2);
+ /* set the latch to `count' */
+ out_8(&via[T1LL], count);
+ out_8(&via[T1LH], count >> 8);
+ /* wait until it hits 0 */
+ while ((in_8(&via[IFR]) & T1_INT) == 0)
+ ;
+ dstart = get_dec();
+ /* clear the interrupt & wait until it hits 0 again */
+ in_8(&via[T1CL]);
+ while ((in_8(&via[IFR]) & T1_INT) == 0)
+ ;
+ dend = get_dec();
+
+ decrementer_count = (dstart - dend) / 6;
+ count_period_num = 60;
+ count_period_den = decrementer_count * 6 * HZ / 100000;
+
+ printk(KERN_INFO "via_calibrate_decr: decrementer_count = %u (%u ticks)\n",
+ decrementer_count, dstart - dend);
+
+ return 1;
+}
+
+/*
* Query the OF and get the decr frequency.
* This was taken from the pmac time_init() when merging the prep/pmac
* time functions.
@@ -35,6 +95,9 @@ void pmac_calibrate_decr(void)
struct device_node *cpu;
int freq, *fp, divisor;
+ if (via_calibrate_decr())
+ return;
+
/*
* The cpu node should have a timebase-frequency property
* to tell us the rate at which the decrementer counts.
@@ -57,11 +120,11 @@ void pmac_calibrate_decr(void)
unsigned long
pmac_get_rtc_time(void)
{
- struct cuda_request req;
+ struct adb_request req;
/* Get the time from the RTC */
cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME);
- while (!req.got_reply)
+ while (!req.complete)
cuda_poll();
if (req.reply_len != 7)
printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
@@ -84,4 +147,5 @@ pmac_read_rtc_time(void)
{
xtime.tv_sec = pmac_get_rtc_time();
xtime.tv_usec = 0;
+ last_rtc_update = xtime.tv_sec;
}
diff --git a/arch/ppc/kernel/ppc_asm.tmpl b/arch/ppc/kernel/ppc_asm.tmpl
index 7036f4a62..e3004c8f6 100644
--- a/arch/ppc/kernel/ppc_asm.tmpl
+++ b/arch/ppc/kernel/ppc_asm.tmpl
@@ -1,27 +1,3 @@
-/*
- * This file contains all the macros and symbols which define
- * a PowerPC assembly language environment.
- */
-#include <linux/config.h>
-#define _TEXT()\
- .text
-
-#define _EXTERN(n) n
-
-#define SYMBOL_NAME(x) x
-
-#define _GLOBAL(n)\
- .globl n;\
-n:
-
-#ifndef FALSE
-#define FALSE 0
-#define TRUE 1
-#endif
-
-#define _ORG(n)\
- .org n
-
/* Register names */
#define r0 0
#define r1 1
@@ -88,102 +64,3 @@ n:
#define fr29 29
#define fr30 30
#define fr31 31
-
-/* Some special registers */
-
-#define TBRU 269 /* Time base Upper/Lower (Reading) */
-#define TBRL 268
-#define TBWU 284 /* Time base Upper/Lower (Writing) */
-#define TBWL 285
-#define XER 1
-#define LR 8
-#define CTR 9
-#define HID0 1008 /* Hardware Implementation */
-#define PVR 287 /* Processor Version */
-#define IBAT0U 528 /* Instruction BAT #0 Upper/Lower */
-#define IBAT0L 529
-#define IBAT1U 530 /* Instruction BAT #1 Upper/Lower */
-#define IBAT1L 531
-#define IBAT2U 532 /* Instruction BAT #2 Upper/Lower */
-#define IBAT2L 533
-#define IBAT3U 534 /* Instruction BAT #3 Upper/Lower */
-#define IBAT3L 535
-#define DBAT0U 536 /* Data BAT #0 Upper/Lower */
-#define DBAT0L 537
-#define DBAT1U 538 /* Data BAT #1 Upper/Lower */
-#define DBAT1L 539
-#define DBAT2U 540 /* Data BAT #2 Upper/Lower */
-#define DBAT2L 541
-#define DBAT3U 542 /* Data BAT #3 Upper/Lower */
-#define DBAT3L 543
-#define DMISS 976 /* TLB Lookup/Refresh registers */
-#define DCMP 977
-#define HASH1 978
-#define HASH2 979
-#define IMISS 980
-#define ICMP 981
-#define RPA 982
-#define SDR1 25 /* MMU hash base register */
-#define DAR 19 /* Data Address Register */
-#define SPR0 272 /* Supervisor Private Registers */
-#define SPRG0 272
-#define SPR1 273
-#define SPRG1 273
-#define SPR2 274
-#define SPRG2 274
-#define SPR3 275
-#define SPRG3 275
-#define DSISR 18
-#define SRR0 26 /* Saved Registers (exception) */
-#define SRR1 27
-#define IABR 1010 /* Instruction Address Breakpoint */
-#define DEC 22 /* Decrementer */
-#define EAR 282 /* External Address Register */
-
-/* Segment Registers */
-#define SR0 0
-#define SR1 1
-#define SR2 2
-#define SR3 3
-#define SR4 4
-#define SR5 5
-#define SR6 6
-#define SR7 7
-#define SR8 8
-#define SR9 9
-#define SR10 10
-#define SR11 11
-#define SR12 12
-#define SR13 13
-#define SR14 14
-#define SR15 15
-
-#define curptr r2
-
-/*
- * 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)
diff --git a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c
index ea2a073eb..386bfe3ac 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.7 1997/08/24 19:33:32 cort Exp $
+ * $Id: ppc_htab.c,v 1.16 1997/11/17 18:25:04 cort Exp $
*
* PowerPC hash table management proc entry. Will show information
* about the current hash table and will allow changes to it.
@@ -25,16 +25,19 @@
#include <asm/io.h>
#include <asm/pgtable.h>
-static long ppc_htab_read(struct inode * inode, struct file * file,
- char * buf, unsigned long nbytes);
-static long ppc_htab_write(struct inode * inode, struct file * file,
- const char * buffer, unsigned long count);
-static long long ppc_htab_lseek(struct inode * inode, struct file * file,
- long long offset, int orig);
+static ssize_t ppc_htab_read(struct file * file, char * buf,
+ size_t count, loff_t *ppos);
+static ssize_t ppc_htab_write(struct file * file, const char * buffer,
+ size_t count, loff_t *ppos);
+static long long ppc_htab_lseek(struct file * file, loff_t offset, int orig);
extern PTE *Hash, *Hash_end;
extern unsigned long Hash_size, Hash_mask;
extern unsigned long _SDR1;
+extern unsigned long htab_reloads;
+extern unsigned long htab_evicts;
+extern unsigned long pte_misses;
+extern unsigned long pte_errors;
static struct file_operations ppc_htab_operations = {
ppc_htab_lseek, /* lseek */
@@ -72,24 +75,107 @@ struct inode_operations proc_ppc_htab_inode_operations = {
NULL /* permission */
};
+/* these will go into processor.h when I'm done debugging -- Cort */
+#define MMCR0 952
+#define MMCR0_PMC1_CYCLES (0x1<<7)
+#define MMCR0_PMC1_ICACHEMISS (0x5<<7)
+#define MMCR0_PMC1_DTLB (0x6<<7)
+#define MMCR0_PMC2_DCACHEMISS (0x6)
+#define MMCR0_PMC2_CYCLES (0x1)
+#define MMCR0_PMC2_ITLB (0x7)
+#define MMCR0_PMC2_LOADMISSTIME (0x5)
+
+#define PMC1 953
+#define PMC2 954
+
+char *pmc1_lookup(unsigned long mmcr0)
+{
+ switch ( mmcr0 & (0x7f<<7) )
+ {
+ case 0x0:
+ return "none";
+ case MMCR0_PMC1_CYCLES:
+ return "cycles";
+ case MMCR0_PMC1_ICACHEMISS:
+ return "ic miss";
+ case MMCR0_PMC1_DTLB:
+ return "dtlb miss";
+ default:
+ return "unknown";
+ }
+}
+
+char *pmc2_lookup(unsigned long mmcr0)
+{
+ switch ( mmcr0 & 0x3f )
+ {
+ case 0x0:
+ return "none";
+ case MMCR0_PMC2_CYCLES:
+ return "cycles";
+ case MMCR0_PMC2_DCACHEMISS:
+ return "dc miss";
+ case MMCR0_PMC2_ITLB:
+ return "itlb miss";
+ case MMCR0_PMC2_LOADMISSTIME:
+ return "load miss time";
+ default:
+ return "unknown";
+ }
+}
+
/*
* print some useful info about the hash table. This function
* is _REALLY_ slow (see the nested for loops below) but nothing
* in here should be really timing critical. -- Cort
*/
-static long ppc_htab_read(struct inode * inode, struct file * file,
- char * buf, unsigned long nbytes)
+static ssize_t ppc_htab_read(struct file * file, char * buf,
+ size_t count, loff_t *ppos)
{
+ unsigned long mmcr0 = 0, pmc1 = 0, pmc2 = 0;
int n = 0, valid;
- unsigned int kptes = 0, overflow = 0, uptes = 0;
+ unsigned int kptes = 0, overflow = 0, uptes = 0, zombie_ptes = 0;
PTE *ptr;
struct task_struct *p;
- char buffer[128];
-
- if (nbytes < 0)
+ char buffer[512];
+
+ if (count < 0)
return -EINVAL;
+ switch ( _get_PVR()>>16 )
+ {
+ case 4: /* 604 */
+ case 9: /* 604e */
+ case 10: /* 604ev5 */
+ asm volatile ("mfspr %0,952 \n\t"
+ "mfspr %1,953 \n\t"
+ "mfspr %2,954 \n\t"
+ : "=r" (mmcr0), "=r" (pmc1), "=r" (pmc2) );
+ n += sprintf( buffer + n,
+ "604 Performance Monitoring\n"
+ "MMCR0\t\t: %08lx %s%s ",
+ mmcr0,
+ ( mmcr0>>28 & 0x2 ) ? "(user mode counted)" : "",
+ ( mmcr0>>28 & 0x4 ) ? "(kernel mode counted)" : "");
+ n += sprintf( buffer + n,
+ "\nPMC1\t\t: %08lx (%s)\n"
+ "PMC2\t\t: %08lx (%s)\n",
+ pmc1, pmc1_lookup(mmcr0),
+ pmc2, pmc2_lookup(mmcr0));
+ break;
+ default:
+ break;
+ }
+
+
+ /* if we don't have a htab */
+ if ( Hash_size == 0 )
+ {
+ n += sprintf( buffer + n, "No Hash Table used\n");
+ goto return_string;
+ }
+
/*
* compute user/kernel pte's table this info can be
* misleading since there can be valid (v bit set) entries
@@ -97,11 +183,12 @@ static long ppc_htab_read(struct inode * inode, struct file * file,
* due to the way tlb invalidation is handled on the ppc
* -- Cort
*/
- for ( ptr = Hash ; ptr < Hash_end ; ptr += sizeof(PTE))
+ for ( ptr = Hash ; ptr < Hash_end ; ptr++)
{
if (ptr->v)
{
/* make sure someone is using this context/vsid */
+ valid = 0;
for_each_task(p)
{
if ( (ptr->vsid >> 4) == p->mm->context )
@@ -111,7 +198,10 @@ static long ppc_htab_read(struct inode * inode, struct file * file,
}
}
if ( !valid )
+ {
+ zombie_ptes++;
continue;
+ }
/* user not allowed read or write */
if (ptr->pp == PP_RWXX)
kptes++;
@@ -122,7 +212,8 @@ static long ppc_htab_read(struct inode * inode, struct file * file,
}
}
- n += sprintf( buffer,
+ n += sprintf( buffer + n,
+ "PTE Hash Table Information\n"
"Size\t\t: %luKb\n"
"Buckets\t\t: %lu\n"
"Address\t\t: %08lx\n"
@@ -130,6 +221,7 @@ static long ppc_htab_read(struct inode * inode, struct file * file,
"User ptes\t: %u\n"
"Kernel ptes\t: %u\n"
"Overflows\t: %u\n"
+ "Zombies\t\t: %u\n"
"Percent full\t: %%%lu\n",
(unsigned long)(Hash_size>>10),
(Hash_size/(sizeof(PTE)*8)),
@@ -138,30 +230,233 @@ static long ppc_htab_read(struct inode * inode, struct file * file,
uptes,
kptes,
overflow,
+ zombie_ptes,
((kptes+uptes)*100) / (Hash_size/sizeof(PTE))
);
- if (file->f_pos >= strlen(buffer))
+ n += sprintf( buffer + n,
+ "Reloads\t\t: %08lx\n"
+ "Evicts\t\t: %08lx\n"
+ "Non-error misses: %08lx\n"
+ "Error misses\t: %08lx\n",
+ htab_reloads, htab_evicts, pte_misses, pte_errors);
+
+return_string:
+ if (*ppos >= strlen(buffer))
return 0;
- if (n > strlen(buffer) - file->f_pos)
- n = strlen(buffer) - file->f_pos;
- copy_to_user(buf, buffer + file->f_pos, n);
- file->f_pos += n;
+ if (n > strlen(buffer) - *ppos)
+ n = strlen(buffer) - *ppos;
+ copy_to_user(buf, buffer + *ppos, n);
+ *ppos += n;
return n;
}
/*
- * Can't _yet_ adjust the hash table size while running. -- Cort
+ * Allow user to define performance counters and resize the hash table
*/
-static long
-ppc_htab_write(struct inode * inode, struct file * file,
- const char * buffer, unsigned long count)
+static ssize_t ppc_htab_write(struct file * file, const char * buffer,
+ size_t count, loff_t *ppos)
{
- unsigned long size;
- extern void reset_SDR1(void);
-
+ unsigned long tmp;
if ( current->uid != 0 )
return -EACCES;
+ /* don't set the htab size for now */
+ if ( !strncmp( buffer, "size ", 5) )
+ return -EBUSY;
+
+ /* turn off performance monitoring */
+ if ( !strncmp( buffer, "off", 3) )
+ {
+ switch ( _get_PVR()>>16 )
+ {
+ case 4: /* 604 */
+ case 9: /* 604e */
+ case 10: /* 604ev5 */
+ asm volatile ("mtspr %0, %3 \n\t"
+ "mtspr %1, %3 \n\t"
+ "mtspr %2, %3 \n\t"
+ :: "i" (MMCR0), "i" (PMC1), "i" (PMC2), "r" (0));
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ if ( !strncmp( buffer, "reset", 5) )
+ {
+ switch ( _get_PVR()>>16 )
+ {
+ case 4: /* 604 */
+ case 9: /* 604e */
+ case 10: /* 604ev5 */
+ /* reset PMC1 and PMC2 */
+ asm volatile (
+ "mtspr 953, %0 \n\t"
+ "mtspr 954, %0 \n\t"
+ :: "r" (0));
+ break;
+ default:
+ break;
+ }
+ htab_reloads = 0;
+ htab_evicts = 0;
+ pte_misses = 0;
+ pte_errors = 0;
+ }
+
+ if ( !strncmp( buffer, "user", 4) )
+ {
+ switch ( _get_PVR()>>16 )
+ {
+ case 4: /* 604 */
+ case 9: /* 604e */
+ case 10: /* 604ev5 */
+ /* setup mmcr0 and clear the correct pmc */
+ asm("mfspr %0,%1\n\t" : "=r" (tmp) : "i" (MMCR0));
+ tmp &= ~(0x60000000);
+ tmp |= 0x20000000;
+ asm volatile (
+ "mtspr %1,%0 \n\t" /* set new mccr0 */
+ "mtspr %3,%4 \n\t" /* reset the pmc */
+ "mtspr %5,%4 \n\t" /* reset the pmc2 */
+ :: "r" (tmp), "i" (MMCR0), "i" (0),
+ "i" (PMC1), "r" (0), "i"(PMC2) );
+ break;
+ default:
+ break;
+ }
+ }
+
+ if ( !strncmp( buffer, "kernel", 6) )
+ {
+ switch ( _get_PVR()>>16 )
+ {
+ case 4: /* 604 */
+ case 9: /* 604e */
+ case 10: /* 604ev5 */
+ /* setup mmcr0 and clear the correct pmc */
+ asm("mfspr %0,%1\n\t" : "=r" (tmp) : "i" (MMCR0));
+ tmp &= ~(0x60000000);
+ tmp |= 0x40000000;
+ asm volatile (
+ "mtspr %1,%0 \n\t" /* set new mccr0 */
+ "mtspr %3,%4 \n\t" /* reset the pmc */
+ "mtspr %5,%4 \n\t" /* reset the pmc2 */
+ :: "r" (tmp), "i" (MMCR0), "i" (0),
+ "i" (PMC1), "r" (0), "i"(PMC2) );
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* PMC1 values */
+ if ( !strncmp( buffer, "dtlb", 4) )
+ {
+ switch ( _get_PVR()>>16 )
+ {
+ case 4: /* 604 */
+ case 9: /* 604e */
+ case 10: /* 604ev5 */
+ /* setup mmcr0 and clear the correct pmc */
+ asm("mfspr %0,%1\n\t" : "=r" (tmp) : "i" (MMCR0));
+ tmp &= ~(0x7f<<7);
+ tmp |= MMCR0_PMC1_DTLB;
+ asm volatile (
+ "mtspr %1,%0 \n\t" /* set new mccr0 */
+ "mtspr %3,%4 \n\t" /* reset the pmc */
+ :: "r" (tmp), "i" (MMCR0), "i" (MMCR0_PMC1_DTLB),
+ "i" (PMC1), "r" (0) );
+ }
+ }
+
+ if ( !strncmp( buffer, "ic miss", 7) )
+ {
+ switch ( _get_PVR()>>16 )
+ {
+ case 4: /* 604 */
+ case 9: /* 604e */
+ case 10: /* 604ev5 */
+ /* setup mmcr0 and clear the correct pmc */
+ asm("mfspr %0,%1\n\t" : "=r" (tmp) : "i" (MMCR0));
+ tmp &= ~(0x7f<<7);
+ tmp |= MMCR0_PMC1_ICACHEMISS;
+ asm volatile (
+ "mtspr %1,%0 \n\t" /* set new mccr0 */
+ "mtspr %3,%4 \n\t" /* reset the pmc */
+ :: "r" (tmp), "i" (MMCR0),
+ "i" (MMCR0_PMC1_ICACHEMISS), "i" (PMC1), "r" (0));
+ }
+ }
+
+ /* PMC2 values */
+ if ( !strncmp( buffer, "load miss time", 14) )
+ {
+ switch ( _get_PVR()>>16 )
+ {
+ case 4: /* 604 */
+ case 9: /* 604e */
+ case 10: /* 604ev5 */
+ /* setup mmcr0 and clear the correct pmc */
+ asm volatile(
+ "mfspr %0,%1\n\t" /* get current mccr0 */
+ "rlwinm %0,%0,0,0,31-6\n\t" /* clear bits [26-31] */
+ "ori %0,%0,%2 \n\t" /* or in mmcr0 settings */
+ "mtspr %1,%0 \n\t" /* set new mccr0 */
+ "mtspr %3,%4 \n\t" /* reset the pmc */
+ : "=r" (tmp)
+ : "i" (MMCR0), "i" (MMCR0_PMC2_LOADMISSTIME),
+ "i" (PMC2), "r" (0) );
+ }
+ }
+
+ if ( !strncmp( buffer, "itlb", 4) )
+ {
+ switch ( _get_PVR()>>16 )
+ {
+ case 4: /* 604 */
+ case 9: /* 604e */
+ case 10: /* 604ev5 */
+ /* setup mmcr0 and clear the correct pmc */
+ asm volatile(
+ "mfspr %0,%1\n\t" /* get current mccr0 */
+ "rlwinm %0,%0,0,0,31-6\n\t" /* clear bits [26-31] */
+ "ori %0,%0,%2 \n\t" /* or in mmcr0 settings */
+ "mtspr %1,%0 \n\t" /* set new mccr0 */
+ "mtspr %3,%4 \n\t" /* reset the pmc */
+ : "=r" (tmp)
+ : "i" (MMCR0), "i" (MMCR0_PMC2_ITLB),
+ "i" (PMC2), "r" (0) );
+ }
+ }
+
+ if ( !strncmp( buffer, "dc miss", 7) )
+ {
+ switch ( _get_PVR()>>16 )
+ {
+ case 4: /* 604 */
+ case 9: /* 604e */
+ case 10: /* 604ev5 */
+ /* setup mmcr0 and clear the correct pmc */
+ asm volatile(
+ "mfspr %0,%1\n\t" /* get current mccr0 */
+ "rlwinm %0,%0,0,0,31-6\n\t" /* clear bits [26-31] */
+ "ori %0,%0,%2 \n\t" /* or in mmcr0 settings */
+ "mtspr %1,%0 \n\t" /* set new mccr0 */
+ "mtspr %3,%4 \n\t" /* reset the pmc */
+ : "=r" (tmp)
+ : "i" (MMCR0), "i" (MMCR0_PMC2_DCACHEMISS),
+ "i" (PMC2), "r" (0) );
+ }
+ }
+
+
+ return count;
+
+#if 0 /* resizing htab is a bit difficult right now -- Cort */
+ unsigned long size;
+ extern void reset_SDR1(void);
/* only know how to set size right now */
if ( strncmp( buffer, "size ", 5) )
@@ -196,14 +491,13 @@ ppc_htab_write(struct inode * inode, struct file * file,
flush_tlb_all();
reset_SDR1();
- printk("done\n");
+#endif
return count;
}
static long long
-ppc_htab_lseek(struct inode * inode, struct file * file,
- long long offset, int orig)
+ppc_htab_lseek(struct file * file, loff_t offset, int orig)
{
switch (orig) {
case 0:
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index fd2ad89ff..8f3225d59 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -5,6 +5,7 @@
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/bios32.h>
+#include <linux/interrupt.h>
#include <asm/semaphore.h>
#include <asm/processor.h>
@@ -14,23 +15,24 @@
#include <asm/bitops.h>
#include <asm/checksum.h>
#include <asm/pgtable.h>
+#include <asm/adb.h>
#include <asm/cuda.h>
#include <asm/prom.h>
#include <asm/system.h>
#include <asm/pci-bridge.h>
-void transfer_to_handler();
-void int_return();
-void syscall_trace();
-void do_IRQ();
-void MachineCheckException();
-void AlignmentException();
-void ProgramCheckException();
-void SingleStepException();
-void FloatingPointCheckException();
-void sys_sigreturn();
+extern void transfer_to_handler(void);
+extern void int_return(void);
+extern void syscall_trace(void);
+extern void do_IRQ(struct pt_regs *regs);
+extern void MachineCheckException(struct pt_regs *regs);
+extern void AlignmentException(struct pt_regs *regs);
+extern void ProgramCheckException(struct pt_regs *regs);
+extern void SingleStepException(struct pt_regs *regs);
+extern int sys_sigreturn(struct pt_regs *regs);
extern unsigned lost_interrupts;
extern void do_lost_interrupts(unsigned long);
+extern int do_signal(sigset_t *, struct pt_regs *);
EXPORT_SYMBOL(do_signal);
EXPORT_SYMBOL(syscall_trace);
@@ -45,6 +47,12 @@ EXPORT_SYMBOL(SingleStepException);
EXPORT_SYMBOL(sys_sigreturn);
EXPORT_SYMBOL(lost_interrupts);
EXPORT_SYMBOL(do_lost_interrupts);
+EXPORT_SYMBOL(__ppc_bh_counter);
+
+#if !defined(CONFIG_MACH_SPECIFIC)
+EXPORT_SYMBOL(isa_io_base);
+EXPORT_SYMBOL(pci_dram_offset);
+#endif
EXPORT_SYMBOL(atomic_add);
EXPORT_SYMBOL(atomic_sub);
@@ -126,11 +134,12 @@ EXPORT_SYMBOL(giveup_fpu);
EXPORT_SYMBOL(flush_icache_range);
EXPORT_SYMBOL(xchg_u32);
+EXPORT_SYMBOL(adb_request);
+EXPORT_SYMBOL(adb_autopoll);
+EXPORT_SYMBOL(adb_register);
EXPORT_SYMBOL(cuda_request);
EXPORT_SYMBOL(cuda_send_request);
-EXPORT_SYMBOL(adb_register);
EXPORT_SYMBOL(abort);
-EXPORT_SYMBOL(call_prom);
EXPORT_SYMBOL(find_devices);
EXPORT_SYMBOL(find_type_devices);
EXPORT_SYMBOL(find_path_device);
diff --git a/arch/ppc/kernel/prep_pci.c b/arch/ppc/kernel/prep_pci.c
index ffacd94c9..193ded4df 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.7 1997/08/23 22:46:02 cort Exp $
+ * $Id: prep_pci.c,v 1.12 1997/10/29 03:35:08 cort Exp $
* PReP pci functions.
* Originally by Gary Thomas
* rewritten and updated by Cort Dougan (cort@cs.nmt.edu)
@@ -7,7 +7,6 @@
* The motherboard routes/maps will disappear shortly. -- Cort
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/bios32.h>
#include <linux/pci.h>
@@ -31,6 +30,83 @@ unsigned char *Motherboard_routes;
/* Tables for known hardware */
+/* Motorola PowerStackII - Utah */
+static char Utah_pci_IRQ_map[23] =
+{
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 4, /* Slot 2 - SCSI - NCR825A */
+ 0, /* Slot 3 - unused */
+ 1, /* Slot 4 - Ethernet - DEC2114x */
+ 0, /* Slot 5 - unused */
+ 2, /* Slot 6 - PCI Card slot #1 */
+ 3, /* Slot 7 - PCI Card slot #2 */
+ 4, /* Slot 8 - PCI Card slot #3 */
+ 4, /* Slot 9 - PCI Bridge */
+ /* added here in case we ever support PCI bridges */
+ /* Secondary PCI bus cards are at slot-9,6 & slot-9,7 */
+ 0, /* Slot 10 - unused */
+ 0, /* Slot 11 - unused */
+ 4, /* Slot 12 - SCSI - NCR825A */
+ 0, /* Slot 13 - unused */
+ 2, /* Slot 14 - enet */
+ 0, /* Slot 15 - unused */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+};
+
+static char Utah_pci_IRQ_routes[] =
+{
+ 0, /* Line 0 - Unused */
+ 9, /* Line 1 */
+ 11, /* Line 2 */
+ 14, /* Line 3 */
+ 15, /* Line 4 */
+};
+
+/* Motorola PowerStackII - Omaha */
+/* no integrated SCSI or ethernet */
+static char Omaha_pci_IRQ_map[23] =
+{
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 3, /* Slot 2 - Winbond EIDE */
+ 0, /* Slot 3 - unused */
+ 0, /* Slot 4 - unused */
+ 0, /* Slot 5 - unused */
+ 1, /* Slot 6 - PCI slot 1 */
+ 2, /* Slot 7 - PCI slot 2 */
+ 3, /* Slot 8 - PCI slot 3 */
+ 4, /* Slot 9 - PCI slot 4 */ /* needs indirect access */
+ 0, /* Slot 10 - unused */
+ 0, /* Slot 11 - unused */
+ 0, /* Slot 12 - unused */
+ 0, /* Slot 13 - unused */
+ 0, /* Slot 14 - unused */
+ 0, /* Slot 15 - unused */
+ 1, /* Slot 16 - PCI slot 1 */
+ 2, /* Slot 17 - PCI slot 2 */
+ 3, /* Slot 18 - PCI slot 3 */
+ 4, /* Slot 19 - PCI slot 4 */ /* needs indirect access */
+ 0,
+ 0,
+ 0,
+};
+
+static char Omaha_pci_IRQ_routes[] =
+{
+ 0, /* Line 0 - Unused */
+ 9, /* Line 1 */
+ 11, /* Line 2 */
+ 14, /* Line 3 */
+ 15 /* Line 4 */
+};
+
/* Motorola PowerStack */
static char Blackhawk_pci_IRQ_map[16] =
{
@@ -323,59 +399,13 @@ prep_pcibios_write_config_byte (unsigned char bus,
return PCIBIOS_SUCCESSFUL;
}
-int prep_pcibios_find_device (unsigned short vendor, unsigned short device_id,
- unsigned short index, unsigned char *bus,
- unsigned char *devfn)
-{
- unsigned int curr = 0;
- struct pci_dev *dev;
-/*printk("pcibios_find_device(): vendor %04x devid %04x index %d\n",
- vendor,device_id,index);*/
- for (dev = pci_devices; dev; dev = dev->next) {
-/*printk(" dev->vendor %04x dev->device %04x\n",
- dev->vendor,dev->device);*/
- if (dev->vendor == vendor && dev->device == device_id) {
- if (curr == index) {
- *devfn = dev->devfn;
- *bus = dev->bus->number;
- return PCIBIOS_SUCCESSFUL;
- }
- ++curr;
- }
- }
- return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-/*
- * Given the class, find the n'th instance of that device
- * in the system.
- */
-int prep_pcibios_find_class (unsigned int class_code, unsigned short index,
- unsigned char *bus, unsigned char *devfn)
-{
- unsigned int curr = 0;
- struct pci_dev *dev;
-
- for (dev = pci_devices; dev; dev = dev->next) {
- if (dev->class == class_code) {
- if (curr == index) {
- *devfn = dev->devfn;
- *bus = dev->bus->number;
- return PCIBIOS_SUCCESSFUL;
- }
- ++curr;
- }
- }
- return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
__initfunc(unsigned long route_pci_interrupts(void))
{
unsigned char *ibc_pirq = (unsigned char *)0x80800860;
unsigned char *ibc_pcicon = (unsigned char *)0x80800840;
int i;
- if ( _machine == _MACH_Motorola)
+ if ( _prep_type == _PREP_Motorola)
{
switch (inb(0x800) & 0xF0)
{
@@ -385,18 +415,28 @@ __initfunc(unsigned long route_pci_interrupts(void))
Motherboard_routes = Genesis_pci_IRQ_routes;
break;
case 0x20: /* Series E */
- Motherboard_map_name = "Series E";
+ Motherboard_map_name = "Powerstack (Series E)";
Motherboard_map = Comet_pci_IRQ_map;
Motherboard_routes = Comet_pci_IRQ_routes;
break;
+ case 0x50: /* PowerStackII Pro3000 */
+ Motherboard_map_name = "Omaha (PowerStack II Pro3000)";
+ Motherboard_map = Omaha_pci_IRQ_map;
+ Motherboard_routes = Omaha_pci_IRQ_routes;
+ case 0x60: /* PowerStackII Pro4000 */
+ Motherboard_map_name = "Utah (Powerstack II Pro4000)";
+ Motherboard_map = Utah_pci_IRQ_map;
+ Motherboard_routes = Utah_pci_IRQ_routes;
+ break;
case 0x40: /* PowerStack */
default: /* Can't hurt, can it? */
+
Motherboard_map_name = "Blackhawk (Powerstack)";
Motherboard_map = Blackhawk_pci_IRQ_map;
Motherboard_routes = Blackhawk_pci_IRQ_routes;
break;
}
- } else if ( _machine == _MACH_IBM )
+ } else if ( _prep_type == _PREP_IBM )
{
unsigned char pl_id;
diff --git a/arch/ppc/kernel/prep_setup.c b/arch/ppc/kernel/prep_setup.c
index 18e013964..0aee7cff4 100644
--- a/arch/ppc/kernel/prep_setup.c
+++ b/arch/ppc/kernel/prep_setup.c
@@ -28,6 +28,9 @@
#include <linux/init.h>
#include <linux/blk.h>
#include <linux/ioport.h>
+#ifdef CONFIG_ABSTRACT_CONSOLE
+#include <linux/console.h>
+#endif
#include <asm/mmu.h>
#include <asm/processor.h>
@@ -36,15 +39,21 @@
#include <asm/pgtable.h>
#include <asm/ide.h>
+#ifdef CONFIG_SOUND
+#include <../drivers/sound/sound_config.h>
+#include <../drivers/sound/dev_table.h>
+#endif
+
/* for the mac fs */
kdev_t boot_dev;
+/* used in nasty hack for sound - see prep_setup_arch() -- Cort */
+long ppc_cs4232_dma, ppc_cs4232_dma2;
+unsigned long empty_zero_page[1024];
extern PTE *Hash, *Hash_end;
extern unsigned long Hash_size, Hash_mask;
extern int probingmem;
extern unsigned long loops_per_sec;
-
-unsigned long empty_zero_page[1024];
extern unsigned char aux_device_present;
#ifdef CONFIG_BLK_DEV_RAM
@@ -53,9 +62,6 @@ extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */
extern int rd_image_start; /* starting block # of image */
#endif
-
-extern char saved_command_line[256];
-
void prep_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
{
ide_ioreg_t port = base;
@@ -75,68 +81,25 @@ prep_get_cpuinfo(char *buffer)
extern char *Motherboard_map_name;
extern RESIDUAL res;
int i;
- int pvr = _get_PVR();
int len;
- char *model;
-
- switch (pvr>>16)
- {
- case 1:
- model = "601";
- break;
- case 3:
- model = "603";
- break;
- case 4:
- model = "604";
- break;
- case 6:
- model = "603e";
- break;
- case 7:
- model = "603ev";
- break;
- default:
- model = "unknown";
- break;
- }
#ifdef __SMP__
#define CD(X) (cpu_data[n].X)
#else
#define CD(X) (X)
-#define CPUN 0
#endif
- len = sprintf(buffer,"processor\t: %d\n"
- "cpu\t\t: %s\n"
- "revision\t: %d.%d\n"
- "upgrade\t\t: %s\n"
- "clock\t\t: %dMHz\n"
- "bus clock\t: %dMHz\n"
- "machine\t\t: %s (sn %s)\n"
- "pci map\t\t: %s\n",
- CPUN,
- model,
- MAJOR(pvr), MINOR(pvr),
- (inb(IBM_EQUIP_PRESENT) & 2) ? "not upgrade" : "upgrade",
- (res.VitalProductData.ProcessorHz > 1024) ?
- res.VitalProductData.ProcessorHz>>20 :
- res.VitalProductData.ProcessorHz,
- (res.VitalProductData.ProcessorBusHz > 1024) ?
- res.VitalProductData.ProcessorBusHz>>20 :
- res.VitalProductData.ProcessorBusHz,
- res.VitalProductData.PrintableModel,
- res.VitalProductData.Serial,
- Motherboard_map_name
- );
-
+ len = sprintf(buffer,"machine\t\t: PReP %s\n",Motherboard_map_name);
+
+ if ( res.ResidualLength == 0 )
+ return len;
+
/* print info about SIMMs */
len += sprintf(buffer+len,"simms\t\t: ");
for ( i = 0 ; (res.ActualNumMemories) && (i < MAX_MEMS) ; i++ )
{
if ( res.Memories[i].SIMMSize != 0 )
- len += sprintf(buffer+len,"%d:%dM ",i,
+ len += sprintf(buffer+len,"%d:%ldM ",i,
(res.Memories[i].SIMMSize > 1024) ?
res.Memories[i].SIMMSize>>20 :
res.Memories[i].SIMMSize);
@@ -148,11 +111,11 @@ prep_get_cpuinfo(char *buffer)
switch(res.VitalProductData.TLBAttrib)
{
case CombinedTLB:
- len += sprintf(buffer+len," %d entries\n",
+ len += sprintf(buffer+len," %ld entries\n",
res.VitalProductData.TLBSize);
break;
case SplitTLB:
- len += sprintf(buffer+len," (split I/D) %d/%d entries\n",
+ len += sprintf(buffer+len," (split I/D) %ld/%ld entries\n",
res.VitalProductData.I_TLBSize,
res.VitalProductData.D_TLBSize);
break;
@@ -166,12 +129,12 @@ prep_get_cpuinfo(char *buffer)
switch(res.VitalProductData.CacheAttrib)
{
case CombinedCAC:
- len += sprintf(buffer+len,"%dkB LineSize\n",
+ len += sprintf(buffer+len,"%ldkB LineSize %ldB\n",
res.VitalProductData.CacheSize,
res.VitalProductData.CacheLineSize);
break;
case SplitCAC:
- len += sprintf(buffer+len,"(split I/D) %dkB/%dkB Linesize %dB/%dB\n",
+ len += sprintf(buffer+len,"(split I/D) %ldkB/%ldkB Linesize %ldB/%ldB\n",
res.VitalProductData.I_CacheSize,
res.VitalProductData.D_CacheSize,
res.VitalProductData.D_CacheLineSize,
@@ -194,55 +157,18 @@ prep_get_cpuinfo(char *buffer)
len += sprintf(buffer+len,"l2\t\t: not present\n");
}
-
- len += sprintf(buffer+len, "bogomips\t: %lu.%02lu\n",
- CD(loops_per_sec+2500)/500000,
- (CD(loops_per_sec+2500)/5000) % 100);
-
- /*
- * Ooh's and aah's info about zero'd pages in idle task
- */
- {
- extern unsigned int zerocount, zerototal, zeropage_hits,zeropage_calls;
- len += sprintf(buffer+len,"zero pages\t: total %u (%uKb) "
- "current: %u (%uKb) hits: %u/%u (%lu%%)\n",
- zerototal, (zerototal*PAGE_SIZE)>>10,
- zerocount, (zerocount*PAGE_SIZE)>>10,
- zeropage_hits,zeropage_calls,
- /* : 1 below is so we don't div by zero */
- (zeropage_hits*100) /
- ((zeropage_calls)?zeropage_calls:1));
- }
return len;
}
__initfunc(void
-prep_setup_arch(char **cmdline_p, unsigned long * memory_start_p,
- unsigned long * memory_end_p))
+prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
{
extern char cmd_line[];
- extern char _etext[], _edata[], _end[];
- extern int panic_timeout;
unsigned char reg;
- /* Save unparsed command line copy for /proc/cmdline */
- strcpy( saved_command_line, cmd_line );
- *cmdline_p = cmd_line;
-
- *memory_start_p = (unsigned long) Hash+Hash_size;
- (unsigned long *)*memory_end_p = (unsigned long *)(res.TotalMemory+KERNELBASE);
-
/* init to some ~sane value until calibrate_delay() runs */
loops_per_sec = 50000000;
- /* 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) _end;
-
aux_device_present = 0xaa;
/* Set up floppy in PS/2 mode */
outb(0x09, SIO_CONFIG_RA);
@@ -250,24 +176,19 @@ prep_setup_arch(char **cmdline_p, unsigned long * memory_start_p,
reg = (reg & 0x3F) | 0x40;
outb(reg, SIO_CONFIG_RD);
outb(reg, SIO_CONFIG_RD); /* Have to write twice to change! */
-
- switch ( _machine )
+
+ /* we should determine this according to what we find! -- Cort */
+ switch ( _prep_type )
{
- case _MACH_IBM:
+ case _PREP_IBM:
ROOT_DEV = to_kdev_t(0x0301); /* hda1 */
break;
- case _MACH_Motorola:
+ case _PREP_Motorola:
ROOT_DEV = to_kdev_t(0x0801); /* sda1 */
break;
}
#ifdef CONFIG_BLK_DEV_RAM
-#if 0
- ROOT_DEV = to_kdev_t(0x0200); /* floppy */
- rd_prompt = 1;
- rd_doload = 1;
- rd_image_start = 0;
-#endif
/* initrd_start and size are setup by boot/head.S and kernel/head.S */
if ( initrd_start )
{
@@ -282,13 +203,62 @@ prep_setup_arch(char **cmdline_p, unsigned long * memory_start_p,
#endif
printk("Boot arguments: %s\n", cmd_line);
+
+#ifdef CONFIG_CS4232
+ /*
+ * setup proper values for the cs4232 driver so we don't have
+ * to recompile for the motorola or ibm workstations sound systems.
+ * This is a really nasty hack, but unless we change the driver
+ * it's the only way to support both addrs from one binary.
+ * -- Cort
+ */
+ if ( is_prep )
+ {
+ extern struct card_info snd_installed_cards[];
+ struct card_info *snd_ptr;
- print_residual_device_info();
+ for ( snd_ptr = snd_installed_cards;
+ snd_ptr < &snd_installed_cards[num_sound_cards];
+ snd_ptr++ )
+ {
+ if ( snd_ptr->card_type == SNDCARD_CS4232 )
+ {
+ if ( _prep_type == _PREP_Motorola )
+ {
+ snd_ptr->config.io_base = 0x830;
+ snd_ptr->config.irq = 10;
+ snd_ptr->config.dma = ppc_cs4232_dma = 6;
+ snd_ptr->config.dma2 = ppc_cs4232_dma2 = 7;
+ }
+ if ( _prep_type == _PREP_IBM )
+ {
+ snd_ptr->config.io_base = 0x530;
+ snd_ptr->config.irq = 5;
+ snd_ptr->config.dma = ppc_cs4232_dma = 1;
+ /* this is wrong - but leave it for now */
+ snd_ptr->config.dma2 = ppc_cs4232_dma2 = 7;
+ }
+ }
+ }
+ }
+#endif /* CONFIG_CS4232 */
- request_region(0x20,0x20,"pic1");
+
+ /*print_residual_device_info();*/
+ request_region(0x20,0x20,"pic1");
request_region(0xa0,0x20,"pic2");
request_region(0x00,0x20,"dma1");
request_region(0x40,0x20,"timer");
request_region(0x80,0x10,"dma page reg");
request_region(0xc0,0x20,"dma2");
+
+#ifdef CONFIG_ABSTRACT_CONSOLE
+#ifdef CONFIG_VGA_CONSOLE
+ conswitchp = &vga_con;
+#endif
+#ifdef CONFIG_FB
+ /* Frame buffer device based console */
+ conswitchp = &fb_con;
+#endif
+#endif
}
diff --git a/arch/ppc/kernel/prep_time.c b/arch/ppc/kernel/prep_time.c
index da0151ede..4c3a91f91 100644
--- a/arch/ppc/kernel/prep_time.c
+++ b/arch/ppc/kernel/prep_time.c
@@ -56,9 +56,9 @@ unsigned int clock_transl[] = { MOTO_RTC_SECONDS,0 /* alarm */,
int prep_cmos_clock_read(int addr)
{
- if ( _machine == _MACH_IBM )
+ if ( _prep_type == _PREP_IBM )
return CMOS_READ(addr);
- else if ( _machine == _MACH_Motorola )
+ else if ( _prep_type == _PREP_Motorola )
{
outb(clock_transl[addr]>>8, NVRAM_AS1);
outb(clock_transl[addr], NVRAM_AS0);
@@ -71,12 +71,12 @@ int prep_cmos_clock_read(int addr)
void prep_cmos_clock_write(unsigned long val, int addr)
{
- if ( _machine == _MACH_IBM )
+ if ( _prep_type == _PREP_IBM )
{
CMOS_WRITE(val,addr);
return;
}
- else if ( _machine == _MACH_Motorola )
+ else if ( _prep_type == _PREP_Motorola )
{
outb(clock_transl[addr]>>8, NVRAM_AS1);
outb(clock_transl[addr], NVRAM_AS0);
diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
index 5e194fedb..b2a1478cb 100644
--- a/arch/ppc/kernel/process.c
+++ b/arch/ppc/kernel/process.c
@@ -1,15 +1,16 @@
+
/*
* linux/arch/ppc/kernel/process.c
*
- * PowerPC version
- * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *
* Derived from "arch/i386/kernel/process.c"
* Copyright (C) 1995 Linus Torvalds
*
* Updated and modified by Cort Dougan (cort@cs.nmt.edu) and
* Paul Mackerras (paulus@cs.anu.edu.au)
*
+ * PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
* 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
@@ -29,7 +30,6 @@
#include <linux/malloc.h>
#include <linux/user.h>
#include <linux/elf.h>
-#include <linux/config.h>
#include <linux/elf.h>
#include <asm/pgtable.h>
@@ -38,15 +38,17 @@
#include <asm/io.h>
#include <asm/smp_lock.h>
#include <asm/processor.h>
+#include <asm/mmu.h>
+#include <asm/prom.h>
int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs);
void switch_to(struct task_struct *, struct task_struct *);
-extern unsigned long _get_SP(void);
+extern unsigned long _get_SP(void);
+extern spinlock_t scheduler_lock;
#undef SHOW_TASK_SWITCHES 1
#undef CHECK_STACK 1
-#undef IDLE_ZERO 1
unsigned long
kernel_stack_top(struct task_struct *tsk)
@@ -68,6 +70,9 @@ static struct signal_struct init_signals = INIT_SIGNALS;
struct mm_struct init_mm = INIT_MM;
union task_union init_task_union = { INIT_TASK };
+/* only used to get secondary processor up */
+struct task_struct *current_set[NR_CPUS] = {&init_task, };
+
int
dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
{
@@ -145,17 +150,30 @@ switch_to(struct task_struct *prev, struct task_struct *new)
{
struct thread_struct *new_tss, *old_tss;
int s = _disable_interrupts();
-
#if CHECK_STACK
check_stack(prev);
check_stack(new);
#endif
#ifdef SHOW_TASK_SWITCHES
- printk("%s/%d (%x) -> %s/%d (%x) ctx %x\n",
- prev->comm,prev->pid,prev->tss.regs->nip,
- new->comm,new->pid,new->tss.regs->nip,new->mm->context);
+ printk("%s/%d -> %s/%d cpu %d\n",
+ prev->comm,prev->pid,
+ new->comm,new->pid,new->processor);
#endif
+#ifdef __SMP__
+ /* bad news if last_task_used_math changes processors right now -- Cort */
+ if ( (last_task_used_math == new) &&
+ (new->processor != new->last_processor) )
+ panic("last_task_used_math switched processors");
+ /* be noisy about processor changes for debugging -- Cort */
+ if ( new->last_processor != new->processor )
+ printk("switch_to(): changing cpu's %d -> %d %s/%d\n",
+ new->last_processor,new->processor,
+ new->comm,new->pid);
+
+ prev->last_processor = prev->processor;
+ current_set[smp_processor_id()] = new;
+#endif /* __SMP__ */
new_tss = &new->tss;
old_tss = &current->tss;
_switch(old_tss, new_tss, new->mm->context);
@@ -181,7 +199,13 @@ void show_regs(struct pt_regs * regs)
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("\nlast math %p\n", last_task_used_math);
+ printk("\nlast math %p", last_task_used_math);
+
+#ifdef __SMP__
+ printk(" CPU: %d last CPU: %d", current->processor,current->last_processor);
+#endif /* __SMP__ */
+
+ printk("\n");
for (i = 0; i < 32; i++)
{
long r;
@@ -226,7 +250,7 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
struct task_struct * p, struct pt_regs * regs)
{
struct pt_regs * childregs;
-
+
/* Copy registers */
childregs = ((struct pt_regs *)
((unsigned long)p + sizeof(union task_union)
@@ -245,7 +269,6 @@ 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;
/*
@@ -321,6 +344,10 @@ asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
lock_kernel();
ret = do_fork(SIGCHLD, regs->gpr[1], regs);
+#if 0/*def __SMP__*/
+ if ( ret ) /* drop scheduler lock in child */
+ scheduler_lock.lock = 0L;
+#endif /* __SMP__ */
unlock_kernel();
return ret;
}
@@ -332,6 +359,7 @@ asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
int error;
char * filename;
+ lock_kernel();
filename = getname((char *) a0);
error = PTR_ERR(filename);
if (IS_ERR(filename))
@@ -353,6 +381,16 @@ asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
lock_kernel();
res = do_fork(clone_flags, regs->gpr[1], regs);
+#ifdef __SMP__
+ /* When we clone the idle task we keep the same pid but
+ * the return value of 0 for both causes problems.
+ * -- Cort
+ */
+ if ((current->pid == 0) && (current == &init_task))
+ res = 1;
+ if ( 0 /*res*/ ) /* drop scheduler lock in child */
+ scheduler_lock.lock = 0L;
+#endif /* __SMP__ */
unlock_kernel();
return res;
}
@@ -377,7 +415,6 @@ print_backtrace(unsigned long *sp)
printk("\n");
}
-#if 0
/*
* Low level print for debugging - Cort
*/
@@ -394,15 +431,37 @@ int ll_printk(const char *fmt, ...)
return i;
}
-char *vidmem = (char *)0xC00B8000;
int lines = 24, cols = 80;
int orig_x = 0, orig_y = 0;
void ll_puts(const char *s)
{
int x,y;
+ char *vidmem = (char *)(_ISA_MEM_BASE + 0xB8000) /*0xC00B8000*/;
char c;
+ extern int mem_init_done;
+
+ if ( mem_init_done ) /* assume this means we can printk */
+ {
+ printk(s);
+ return;
+ }
+
+#if 0
+ if ( have_of )
+ {
+ prom_print(s);
+ return;
+ }
+#endif
+ /*
+ * can't ll_puts on chrp without openfirmware yet.
+ * vidmem just needs to be setup for it.
+ * -- Cort
+ */
+ if ( ! is_prep )
+ return;
x = orig_x;
y = orig_y;
@@ -430,4 +489,3 @@ void ll_puts(const char *s)
orig_x = x;
orig_y = y;
}
-#endif /* CONFIG_PREP */
diff --git a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c
index c7a566a14..121ffea73 100644
--- a/arch/ppc/kernel/prom.c
+++ b/arch/ppc/kernel/prom.c
@@ -8,33 +8,28 @@
* Paul Mackerras August 1996.
* Copyright (C) 1996 Paul Mackerras.
*/
-
#include <stdarg.h>
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/blk.h>
+#include <linux/init.h>
#include <asm/prom.h>
#include <asm/page.h>
#include <asm/processor.h>
-#define getpromprop(node, name, buf, len) \
- ((int)call_prom("getprop", 4, 1, (node), (name), (buf), (len)))
-
-ihandle prom_stdout;
-ihandle prom_chosen;
-
-char command_line[256];
-int screen_initialized = 0;
-
-char prom_display_path[128];
+/*
+ * Properties whose value is longer than this get excluded from our
+ * copy of the device tree. This way we don't waste space storing
+ * things like "driver,AAPL,MacOS,PowerPC" properties.
+ */
+#define MAX_PROPERTY_LENGTH 1024
struct prom_args {
const char *service;
int nargs;
int nret;
void *args[10];
-} prom_args;
+};
struct pci_address {
unsigned a_hi;
@@ -55,39 +50,83 @@ struct pci_range {
unsigned size_lo;
};
-void (*prom_entry)(void *);
-extern int prom_trashed;
+char *prom_display_paths[FB_MAX] __initdata = { 0, };
+unsigned int prom_num_displays = 0;
+
+prom_entry prom = 0;
+ihandle prom_chosen = 0, prom_stdout = 0;
+
+extern char *klimit;
+char *bootpath = 0;
+char *bootdevice = 0;
+
+unsigned int rtas_data = 0;
+unsigned int rtas_entry = 0;
-static int prom_callback(struct prom_args *);
+static struct device_node *allnodes = 0;
+
+static void *call_prom(const char *service, int nargs, int nret, ...);
+static void prom_print(const char *msg);
+static void prom_exit(void);
+static unsigned long copy_device_tree(unsigned long, unsigned long);
static unsigned long inspect_node(phandle, struct device_node *, unsigned long,
- unsigned long, unsigned long);
-static void check_display(void);
+ unsigned long, struct device_node ***);
+static unsigned long finish_node(struct device_node *, unsigned long,
+ unsigned long);
+static unsigned long check_display(unsigned long);
static int prom_next_node(phandle *);
-extern int pmac_display_supported(const char *);
-extern void enter_prom(void *);
+extern void enter_rtas(void *);
+extern unsigned long reloc_offset(void);
-void
+/*
+ * prom_init() is called very early on, before the kernel text
+ * and data have been mapped to KERNELBASE. At this point the code
+ * is running at whatever address it has been loaded at, so
+ * references to extern and static variables must be relocated
+ * explicitly. The procedure reloc_offset() returns the the address
+ * we're currently running at minus the address we were linked at.
+ * (Note that strings count as static variables.)
+ *
+ * Because OF may have mapped I/O devices into the area starting at
+ * KERNELBASE, particularly on CHRP machines, we can't safely call
+ * OF once the kernel has been mapped to KERNELBASE. Therefore all
+ * OF calls should be done within prom_init(), and prom_init()
+ * and all routines called within it must be careful to relocate
+ * references as necessary.
+ *
+ * Note that the bss is cleared *after* prom_init runs, so we have
+ * to make sure that any static or extern variables it accesses
+ * are put in the data segment.
+ */
+#define PTRRELOC(x) ((typeof(x))((unsigned long)(x) + offset))
+#define PTRUNRELOC(x) ((typeof(x))((unsigned long)(x) - offset))
+#define RELOC(x) (*PTRRELOC(&(x)))
+
+#define ALIGN(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long))
+
+static void
prom_exit()
{
struct prom_args args;
+ unsigned long offset = reloc_offset();
args.service = "exit";
args.nargs = 0;
args.nret = 0;
- enter_prom(&args);
+ RELOC(prom)(&args);
for (;;) /* should never get here */
;
}
-void *
+static void *
call_prom(const char *service, int nargs, int nret, ...)
{
va_list list;
int i;
+ unsigned long offset = reloc_offset();
+ struct prom_args prom_args;
- if (prom_trashed)
- panic("prom called after its memory was reclaimed");
prom_args.service = service;
prom_args.nargs = nargs;
prom_args.nret = nret;
@@ -97,26 +136,26 @@ call_prom(const char *service, int nargs, int nret, ...)
va_end(list);
for (i = 0; i < nret; ++i)
prom_args.args[i + nargs] = 0;
- enter_prom(&prom_args);
+ RELOC(prom)(&prom_args);
return prom_args.args[nargs];
}
-void
+static void
prom_print(const char *msg)
{
const char *p, *q;
- const char *crlf = "\r\n";
+ unsigned long offset = reloc_offset();
- if (screen_initialized)
- return;
for (p = msg; *p != 0; p = q) {
for (q = p; *q != 0 && *q != '\n'; ++q)
;
if (q > p)
- call_prom("write", 3, 1, prom_stdout, p, q - p);
+ call_prom(RELOC("write"), 3, 1, RELOC(prom_stdout),
+ p, q - p);
if (*q != 0) {
++q;
- call_prom("write", 3, 1, prom_stdout, crlf, 2);
+ call_prom(RELOC("write"), 3, 1, RELOC(prom_stdout),
+ RELOC("\r\n"), 2);
}
}
}
@@ -126,285 +165,311 @@ prom_print(const char *msg)
* handling exceptions and the MMU hash table for us.
*/
void
-prom_init(char *params, int unused, void (*pp)(void *))
+prom_init(int r3, int r4, prom_entry pp)
{
+ unsigned long mem;
+ ihandle prom_rtas;
+ unsigned int rtas_size;
+ unsigned long offset = reloc_offset();
+ int l;
+ char *p, *d;
+
/* First get a handle for the stdout device */
- if ( ! have_of() )
- return;
- prom_entry = pp;
- prom_chosen = call_prom("finddevice", 1, 1, "/chosen");
- if (prom_chosen == (void *)-1)
+ RELOC(prom) = pp;
+ RELOC(prom_chosen) = call_prom(RELOC("finddevice"), 1, 1,
+ RELOC("/chosen"));
+ if (RELOC(prom_chosen) == (void *)-1)
prom_exit();
- call_prom("getprop", 4, 1, prom_chosen, "stdout", &prom_stdout,
- (void *) sizeof(prom_stdout));
-
- /*
- * If we were booted via quik, params points to the physical address
- * of the command-line parameters.
- * If we were booted from an xcoff image (i.e. netbooted or
- * booted from floppy), we get the command line from the bootargs
- * property of the /chosen node. If an initial ramdisk is present,
- * params and unused are used for initrd_start and initrd_size,
- * otherwise they contain 0xdeadbeef.
- */
- command_line[0] = 0;
- if ((unsigned long) params >= 0x4000
- && (unsigned long) params < 0x800000
- && unused == 0) {
- strncpy(command_line, params+KERNELBASE, sizeof(command_line));
- } else {
-#ifdef CONFIG_BLK_DEV_INITRD
- if ((unsigned long) params - KERNELBASE < 0x800000
- && unused != 0 && unused != 0xdeadbeef) {
- initrd_start = (unsigned long) params;
- initrd_end = initrd_start + unused;
- ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+ if ((int) call_prom(RELOC("getprop"), 4, 1, RELOC(prom_chosen),
+ RELOC("stdout"), &RELOC(prom_stdout),
+ sizeof(prom_stdout)) <= 0)
+ prom_exit();
+
+ /* Get the boot device and translate it to a full OF pathname. */
+ mem = (unsigned long) RELOC(klimit) + offset;
+ p = (char *) mem;
+ l = (int) call_prom(RELOC("getprop"), 4, 1, RELOC(prom_chosen),
+ RELOC("bootpath"), p, 1<<20);
+ if (l > 0) {
+ p[l] = 0; /* should already be null-terminated */
+ RELOC(bootpath) = PTRUNRELOC(p);
+ mem += l + 1;
+ d = (char *) mem;
+ *d = 0;
+ call_prom(RELOC("canon"), 3, 1, p, d, 1<<20);
+ RELOC(bootdevice) = PTRUNRELOC(d);
+ mem = ALIGN(mem + strlen(d) + 1);
+ }
+
+ mem = check_display(mem);
+
+ prom_print(RELOC("copying OF device tree..."));
+ mem = copy_device_tree(mem, mem + (1<<20));
+ prom_print(RELOC("done\n"));
+
+ prom_rtas = call_prom(RELOC("finddevice"), 1, 1, RELOC("/rtas"));
+ if (prom_rtas != (void *) -1) {
+ rtas_size = 0;
+ call_prom(RELOC("getprop"), 4, 1, prom_rtas,
+ RELOC("rtas-size"), &rtas_size, sizeof(rtas_size));
+ prom_print(RELOC("instantiating rtas..."));
+ if (rtas_size == 0) {
+ RELOC(rtas_data) = 0;
+ } else {
+ mem = (mem + 4095) & -4096; /* round to page bdry */
+ RELOC(rtas_data) = mem - KERNELBASE;
+ mem += rtas_size;
}
-#endif
- call_prom("getprop", 4, 1, prom_chosen, "bootargs",
- command_line, sizeof(command_line));
+ RELOC(rtas_entry) = (unsigned int)
+ call_prom(RELOC("instantiate-rtas"), 1, 1,
+ RELOC(rtas_data));
+ if (RELOC(rtas_entry) == -1)
+ prom_print(RELOC(" failed\n"));
+ else
+ prom_print(RELOC(" done\n"));
}
- command_line[sizeof(command_line) - 1] = 0;
- check_display();
+ RELOC(klimit) = (char *) (mem - offset);
}
/*
* If we have a display that we don't know how to drive,
* we will want to try to execute OF's open method for it
- * later. However, OF may fall over if we do that after
- * we've taken over the MMU and done set_prom_callback.
+ * later. However, OF will probably fall over if we do that
+ * we've taken over the MMU.
* So we check whether we will need to open the display,
* and if so, open it now.
*/
-static void
-check_display()
+static unsigned long
+check_display(unsigned long mem)
{
phandle node;
ihandle ih;
- char type[16], name[64], path[128];
+ unsigned long offset = reloc_offset();
+ char type[16], *path;
for (node = 0; prom_next_node(&node); ) {
type[0] = 0;
- getpromprop(node, "device_type", type, sizeof(type));
- if (strcmp(type, "display") != 0)
- continue;
- name[0] = 0;
- getpromprop(node, "name", name, sizeof(name));
- if (pmac_display_supported(name))
- /* we have a supported display */
- return;
- }
- printk(KERN_INFO "No supported display found\n");
- for (node = 0; prom_next_node(&node); ) {
- type[0] = 0;
- getpromprop(node, "device_type", type, sizeof(type));
- if (strcmp(type, "display") != 0)
+ call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"),
+ type, sizeof(type));
+ if (strcmp(type, RELOC("display")) != 0)
continue;
/* It seems OF doesn't null-terminate the path :-( */
- memset(path, 0, sizeof(path));
- if ((int) call_prom("package-to-path", 3, 1,
- node, path, sizeof(path) - 1) < 0) {
- printk(KERN_WARNING "can't get path for display %p\n",
- node);
+ path = (char *) mem;
+ memset(path, 0, 256);
+ if ((int) call_prom(RELOC("package-to-path"), 3, 1,
+ node, path, 255) < 0)
continue;
- }
- ih = call_prom("open", 1, 1, path);
+ prom_print(RELOC("opening display "));
+ prom_print(path);
+ ih = call_prom(RELOC("open"), 1, 1, path);
if (ih == 0 || ih == (ihandle) -1) {
- printk(KERN_WARNING "couldn't open display %s\n",
- path);
+ prom_print(RELOC("... failed\n"));
continue;
}
- printk(KERN_INFO "Opened display device %s using "
- "Open Firmware\n", path);
- strcpy(prom_display_path, path);
- break;
+ prom_print(RELOC("... ok\n"));
+ mem += strlen(path) + 1;
+ RELOC(prom_display_paths[RELOC(prom_num_displays)++])
+ = PTRUNRELOC(path);
+ if (RELOC(prom_num_displays) >= FB_MAX)
+ break;
}
+ return ALIGN(mem);
}
static int
prom_next_node(phandle *nodep)
{
phandle node;
+ unsigned long offset = reloc_offset();
if ((node = *nodep) != 0
- && (*nodep = call_prom("child", 1, 1, node)) != 0)
+ && (*nodep = call_prom(RELOC("child"), 1, 1, node)) != 0)
return 1;
- if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
+ if ((*nodep = call_prom(RELOC("peer"), 1, 1, node)) != 0)
return 1;
for (;;) {
- if ((node = call_prom("parent", 1, 1, node)) == 0)
+ if ((node = call_prom(RELOC("parent"), 1, 1, node)) == 0)
return 0;
- if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
+ if ((*nodep = call_prom(RELOC("peer"), 1, 1, node)) != 0)
return 1;
}
}
/*
- * Callback routine for the PROM to call us.
- * No services are implemented yet :-)
- */
-static int
-prom_callback(struct prom_args *argv)
-{
- printk("uh oh, prom callback '%s' (%d/%d)\n", argv->service,
- argv->nargs, argv->nret);
- return -1;
-}
-
-/*
- * Register a callback with the Open Firmware PROM so it can ask
- * us to map/unmap memory, etc.
- */
-void
-set_prom_callback()
-{
- call_prom("set-callback", 1, 1, prom_callback);
-}
-
-void
-abort()
-{
-#ifdef CONFIG_XMON
- xmon(0);
-#endif
- prom_exit();
-}
-
-/*
* Make a copy of the device tree from the PROM.
*/
-
-static struct device_node *allnodes;
-static struct device_node **allnextp;
-
-#define ALIGN(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long))
-
-unsigned long
+static unsigned long
copy_device_tree(unsigned long mem_start, unsigned long mem_end)
{
phandle root;
+ unsigned long new_start;
+ struct device_node **allnextp;
+ unsigned long offset = reloc_offset();
- root = call_prom("peer", 1, 1, (phandle)0);
- if (root == (phandle)0)
- panic("couldn't get device tree root\n");
- allnextp = &allnodes;
- mem_start = inspect_node(root, 0, 0, mem_start, mem_end);
+ root = call_prom(RELOC("peer"), 1, 1, (phandle)0);
+ if (root == (phandle)0) {
+ prom_print(RELOC("couldn't get device tree root\n"));
+ prom_exit();
+ }
+ allnextp = &RELOC(allnodes);
+ mem_start = ALIGN(mem_start);
+ new_start = inspect_node(root, 0, mem_start, mem_end, &allnextp);
*allnextp = 0;
- return mem_start;
+ return new_start;
}
static unsigned long
-inspect_node(phandle node, struct device_node *dad, unsigned long base_address,
- unsigned long mem_start, unsigned long mem_end)
+inspect_node(phandle node, struct device_node *dad,
+ unsigned long mem_start, unsigned long mem_end,
+ struct device_node ***allnextpp)
{
- struct reg_property *reg, *rp;
- struct pci_reg_property *pci_addrs;
- int l, i;
+ int l;
phandle child;
struct device_node *np;
struct property *pp, **prev_propp;
- char *prev_name;
+ char *prev_name, *namep;
+ unsigned char *valp;
+ unsigned long offset = reloc_offset();
np = (struct device_node *) mem_start;
mem_start += sizeof(struct device_node);
memset(np, 0, sizeof(*np));
np->node = node;
- *allnextp = np;
- allnextp = &np->allnext;
- np->parent = dad;
+ **allnextpp = PTRUNRELOC(np);
+ *allnextpp = &np->allnext;
if (dad != 0) {
+ np->parent = PTRUNRELOC(dad);
/* we temporarily use the `next' field as `last_child'. */
if (dad->next == 0)
- dad->child = np;
+ dad->child = PTRUNRELOC(np);
else
- dad->next->sibling = np;
+ dad->next->sibling = PTRUNRELOC(np);
dad->next = np;
}
/* get and store all properties */
prev_propp = &np->properties;
- prev_name = 0;
+ prev_name = RELOC("");
for (;;) {
pp = (struct property *) mem_start;
- pp->name = (char *) (pp + 1);
- if ((int) call_prom("nextprop", 3, 1, node, prev_name,
- pp->name) <= 0)
+ namep = (char *) (pp + 1);
+ pp->name = PTRUNRELOC(namep);
+ if ((int) call_prom(RELOC("nextprop"), 3, 1, node, prev_name,
+ namep) <= 0)
break;
- mem_start = ALIGN((unsigned long)pp->name
- + strlen(pp->name) + 1);
- pp->value = (unsigned char *) mem_start;
+ mem_start = ALIGN((unsigned long)namep + strlen(namep) + 1);
+ prev_name = namep;
+ valp = (unsigned char *) mem_start;
+ pp->value = PTRUNRELOC(valp);
pp->length = (int)
- call_prom("getprop", 4, 1, node, pp->name, pp->value,
- mem_end - mem_start);
+ call_prom(RELOC("getprop"), 4, 1, node, namep,
+ valp, mem_end - mem_start);
if (pp->length < 0)
- panic("hey, where did property %s go?", pp->name);
+ continue;
+#ifdef MAX_PROPERTY_LENGTH
+ if (pp->length > MAX_PROPERTY_LENGTH)
+ continue; /* ignore this property */
+#endif
mem_start = ALIGN(mem_start + pp->length);
- prev_name = pp->name;
- *prev_propp = pp;
+ *prev_propp = PTRUNRELOC(pp);
prev_propp = &pp->next;
}
*prev_propp = 0;
+ /* get the node's full name */
+ l = (int) call_prom(RELOC("package-to-path"), 3, 1, node,
+ (char *) mem_start, mem_end - mem_start);
+ if (l >= 0) {
+ np->full_name = PTRUNRELOC((char *) mem_start);
+ *(char *)(mem_start + l) = 0;
+ mem_start = ALIGN(mem_start + l + 1);
+ }
+
+ /* do all our children */
+ child = call_prom(RELOC("child"), 1, 1, node);
+ while (child != (void *)0) {
+ mem_start = inspect_node(child, np, mem_start, mem_end,
+ allnextpp);
+ child = call_prom(RELOC("peer"), 1, 1, child);
+ }
+
+ return mem_start;
+}
+
+void
+finish_device_tree(void)
+{
+ unsigned long mem = (unsigned long) klimit;
+
+ mem = finish_node(allnodes, mem, 0UL);
+ printk(KERN_INFO "device tree used %lu bytes\n",
+ mem - (unsigned long) allnodes);
+ klimit = (char *) mem;
+}
+
+static unsigned long
+finish_node(struct device_node *np, unsigned long mem_start,
+ unsigned long base_address)
+{
+ struct reg_property *rp;
+ struct pci_reg_property *pci_addrs;
+ struct address_range *adr;
+ struct device_node *child;
+ int i, l;
+
np->name = get_property(np, "name", 0);
np->type = get_property(np, "device_type", 0);
/* get all the device addresses and interrupts */
- reg = (struct reg_property *) mem_start;
+ adr = (struct address_range *) mem_start;
pci_addrs = (struct pci_reg_property *)
get_property(np, "assigned-addresses", &l);
i = 0;
if (pci_addrs != 0) {
while ((l -= sizeof(struct pci_reg_property)) >= 0) {
/* XXX assumes PCI addresses mapped 1-1 to physical */
- reg[i].address = pci_addrs[i].addr.a_lo;
- reg[i].size = pci_addrs[i].size_lo;
+ adr[i].space = pci_addrs[i].addr.a_hi;
+ adr[i].address = pci_addrs[i].addr.a_lo;
+ adr[i].size = pci_addrs[i].size_lo;
++i;
}
} else {
rp = (struct reg_property *) get_property(np, "reg", &l);
if (rp != 0) {
while ((l -= sizeof(struct reg_property)) >= 0) {
- reg[i].address = rp[i].address + base_address;
- reg[i].size = rp[i].size;
+ adr[i].space = 0;
+ adr[i].address = rp[i].address + base_address;
+ adr[i].size = rp[i].size;
++i;
}
}
}
if (i > 0) {
- np->addrs = reg;
+ np->addrs = adr;
np->n_addrs = i;
- mem_start += i * sizeof(struct reg_property);
+ mem_start += i * sizeof(struct address_range);
}
np->intrs = (int *) get_property(np, "AAPL,interrupts", &l);
+ if (np->intrs == 0)
+ np->intrs = (int *) get_property(np, "interrupts", &l);
if (np->intrs != 0)
np->n_intrs = l / sizeof(int);
- /* get the node's full name */
- l = (int) call_prom("package-to-path", 3, 1, node,
- (char *) mem_start, mem_end - mem_start);
- if (l >= 0) {
- np->full_name = (char *) mem_start;
- np->full_name[l] = 0;
- mem_start = ALIGN(mem_start + l + 1);
- }
-
- if (np->type != 0 && strcmp(np->type, "dbdma") == 0 && np->n_addrs > 0)
+ if (np->type != 0 && np->n_addrs > 0
+ && (strcmp(np->type, "dbdma") == 0
+ || strcmp(np->type, "mac-io") == 0))
base_address = np->addrs[0].address;
- child = call_prom("child", 1, 1, node);
- while (child != (void *)0) {
- mem_start = inspect_node(child, np, base_address,
- mem_start, mem_end);
- child = call_prom("peer", 1, 1, child);
- }
+ for (child = np->child; child != NULL; child = child->sibling)
+ mem_start = finish_node(child, mem_start, base_address);
return mem_start;
}
/*
- * Construct a return a list of the device_nodes with a given name.
+ * Construct and return a list of the device_nodes with a given name.
*/
struct device_node *
find_devices(const char *name)
@@ -423,7 +488,7 @@ find_devices(const char *name)
}
/*
- * Construct a return a list of the device_nodes with a given type.
+ * Construct and return a list of the device_nodes with a given type.
*/
struct device_node *
find_type_devices(const char *type)
@@ -442,6 +507,31 @@ find_type_devices(const char *type)
}
/*
+ * Construct and return a list of the device_nodes with a given type
+ * and compatible property.
+ */
+struct device_node *
+find_compatible_devices(const char *type, const char *compat)
+{
+ struct device_node *head, **prevp, *np;
+ const char *cp;
+
+ prevp = &head;
+ for (np = allnodes; np != 0; np = np->allnext) {
+ if (type != NULL
+ && !(np->type != 0 && strcasecmp(np->type, type) == 0))
+ continue;
+ cp = (char *) get_property(np, "compatible", NULL);
+ if (cp != NULL && strcasecmp(cp, compat) == 0) {
+ *prevp = np;
+ prevp = &np->next;
+ }
+ }
+ *prevp = 0;
+ return head;
+}
+
+/*
* Find the device_node with a given full_name.
*/
struct device_node *
@@ -456,6 +546,20 @@ find_path_device(const char *path)
}
/*
+ * Find the device_node with a given phandle.
+ */
+struct device_node *
+find_phandle(phandle ph)
+{
+ struct device_node *np;
+
+ for (np = allnodes; np != 0; np = np->allnext)
+ if (np->node == ph)
+ return np;
+ return NULL;
+}
+
+/*
* Find a property with a given name for a given node
* and return the value.
*/
@@ -522,3 +626,48 @@ print_properties(struct device_node *np)
}
}
}
+
+int
+call_rtas(const char *service, int nargs, int nret,
+ unsigned long *outputs, ...)
+{
+ va_list list;
+ int i;
+ struct device_node *rtas;
+ int *tokp;
+ union {
+ unsigned long words[16];
+ double align;
+ } u;
+
+ rtas = find_devices("rtas");
+ if (rtas == NULL)
+ return -1;
+ tokp = (int *) get_property(rtas, service, NULL);
+ if (tokp == NULL) {
+ printk(KERN_ERR "No RTAS service called %s\n", service);
+ return -1;
+ }
+ u.words[0] = *tokp;
+ u.words[1] = nargs;
+ u.words[2] = nret;
+ va_start(list, outputs);
+ for (i = 0; i < nargs; ++i)
+ u.words[i+3] = va_arg(list, unsigned long);
+ va_end(list);
+ enter_rtas(&u);
+ if (nret > 1 && outputs != NULL)
+ for (i = 0; i < nret-1; ++i)
+ outputs[i] = u.words[i+nargs+4];
+ return u.words[nargs+3];
+}
+
+void
+abort()
+{
+#ifdef CONFIG_XMON
+ extern void xmon(void *);
+ xmon(0);
+#endif
+ prom_exit();
+}
diff --git a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c
index 8a5839d1f..4f6068c6d 100644
--- a/arch/ppc/kernel/ptrace.c
+++ b/arch/ppc/kernel/ptrace.c
@@ -32,6 +32,11 @@
#include <asm/system.h>
/*
+ * Set of msr bits that gdb can change on behalf of a process.
+ */
+#define MSR_DEBUGCHANGE (MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1)
+
+/*
* does not yet catch signals sent when the child dies.
* in exit.c or in signal.c.
*/
@@ -41,7 +46,7 @@
*/
static inline long get_reg(struct task_struct *task, int regno)
{
- if (regno <= PT_CCR)
+ if (regno <= PT_MQ)
return ((unsigned long *)task->tss.regs)[regno];
return (0);
}
@@ -52,7 +57,10 @@ static inline long get_reg(struct task_struct *task, int regno)
static inline int put_reg(struct task_struct *task, int regno,
unsigned long data)
{
- if (regno <= PT_CCR) {
+ 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;
return 0;
}
@@ -408,13 +416,6 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
if (addr == PT_ORIG_R3)
goto out;
-#if 0 /* Let this check be in 'put_reg' */
- if (addr == PT_SR) {
- data &= SR_MASK;
- data <<= 16;
- data |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
- }
-#endif
if (addr < PT_FPR0) {
if (put_reg(child, addr, data))
goto out;
@@ -433,7 +434,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
case PTRACE_CONT: { /* restart after signal. */
ret = -EIO;
- if ((unsigned long) data >= NSIG)
+ if ((unsigned long) data >= _NSIG)
goto out;
if (request == PTRACE_SYSCALL)
child->flags |= PF_TRACESYS;
@@ -465,7 +466,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
case PTRACE_SINGLESTEP: { /* set the trap flag. */
ret = -EIO;
- if ((unsigned long) data >= NSIG)
+ if ((unsigned long) data >= _NSIG)
goto out;
child->flags &= ~PF_TRACESYS;
set_single_step(child);
@@ -478,7 +479,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
case PTRACE_DETACH: { /* detach a process that was attached. */
ret = -EIO;
- if ((unsigned long) data >= NSIG)
+ if ((unsigned long) data >= _NSIG)
goto out;
child->flags &= ~(PF_PTRACED|PF_TRACESYS);
wake_up_process(child);
@@ -516,9 +517,10 @@ asmlinkage void syscall_trace(void)
* for normal use. strace only continues with a signal if the
* stopping signal is not SIGTRAP. -brl
*/
- if (current->exit_code)
- current->signal |= (1 << (current->exit_code - 1));
- current->exit_code = 0;
+ if (current->exit_code) {
+ send_sig(current->exit_code, current, 1);
+ current->exit_code = 0;
+ }
out:
unlock_kernel();
}
diff --git a/arch/ppc/kernel/residual.c b/arch/ppc/kernel/residual.c
index 4084f9f62..fdf62e921 100644
--- a/arch/ppc/kernel/residual.c
+++ b/arch/ppc/kernel/residual.c
@@ -1,12 +1,12 @@
/*
- * $Id: residual.c,v 1.2 1997/08/25 06:54:56 cort Exp $
+ * $Id: residual.c,v 1.5 1997/10/30 21:25:19 cort Exp $
*
* Code to deal with the PReP residual data.
*
* Written by: Cort Dougan (cort@cs.nmt.edu)
+ * Improved _greatly_ and rewritten by Gabriel Paubert (paubert@iram.es)
*/
-
-#include <linux/config.h>
+#if 0
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -35,9 +35,585 @@
#include <asm/pnp.h>
+const char * PnP_BASE_TYPES[]= {
+ "Reserved",
+ "MassStorageDevice",
+ "NetworkInterfaceController",
+ "DisplayController",
+ "MultimediaController",
+ "MemoryController",
+ "BridgeController",
+ "CommunicationsDevice",
+ "SystemPeripheral",
+ "InputDevice",
+ "ServiceProcessor"
+ };
+
+/* Device Sub Type Codes */
+
+const unsigned char * PnP_SUB_TYPES[] = {
+ "\001\000SCSIController",
+ "\001\001IDEController",
+ "\001\002FloppyController",
+ "\001\003IPIController",
+ "\001\200OtherMassStorageController",
+ "\002\000EthernetController",
+ "\002\001TokenRingController",
+ "\002\002FDDIController",
+ "\002\0x80OtherNetworkController",
+ "\003\000VGAController",
+ "\003\001SVGAController",
+ "\003\002XGAController",
+ "\003\200OtherDisplayController",
+ "\004\000VideoController",
+ "\004\001AudioController",
+ "\004\200OtherMultimediaController",
+ "\005\000RAM",
+ "\005\001FLASH",
+ "\005\200OtherMemoryDevice",
+ "\006\000HostProcessorBridge",
+ "\006\001ISABridge",
+ "\006\002EISABridge",
+ "\006\003MicroChannelBridge",
+ "\006\004PCIBridge",
+ "\006\005PCMCIABridge",
+ "\006\006VMEBridge",
+ "\006\200OtherBridgeDevice",
+ "\007\000RS232Device",
+ "\007\001ATCompatibleParallelPort",
+ "\007\200OtherCommunicationsDevice",
+ "\010\000ProgrammableInterruptController",
+ "\010\001DMAController",
+ "\010\002SystemTimer",
+ "\010\003RealTimeClock",
+ "\010\004L2Cache",
+ "\010\005NVRAM",
+ "\010\006PowerManagement",
+ "\010\007CMOS",
+ "\010\010OperatorPanel",
+ "\010\011ServiceProcessorClass1",
+ "\010\012ServiceProcessorClass2",
+ "\010\013ServiceProcessorClass3",
+ "\010\014GraphicAssist",
+ "\010\017SystemPlanar",
+ "\010\200OtherSystemPeripheral",
+ "\011\000KeyboardController",
+ "\011\001Digitizer",
+ "\011\002MouseController",
+ "\011\003TabletController",
+ "\011\0x80OtherInputController",
+ "\012\000GeneralMemoryController",
+ NULL
+};
+
+/* Device Interface Type Codes */
+
+const unsigned char * PnP_INTERFACES[]= {
+ "\000\000\000General",
+ "\001\000\000GeneralSCSI",
+ "\001\001\000GeneralIDE",
+ "\001\001\001ATACompatible",
+
+ "\001\002\000GeneralFloppy",
+ "\001\002\001Compatible765",
+ "\001\002\002NS398_Floppy", /* NS Super I/O wired to use index
+ register at port 398 and data
+ register at port 399 */
+ "\001\002\003NS26E_Floppy", /* Ports 26E and 26F */
+ "\001\002\004NS15C_Floppy", /* Ports 15C and 15D */
+ "\001\002\005NS2E_Floppy", /* Ports 2E and 2F */
+ "\001\002\006CHRP_Floppy", /* CHRP Floppy in PR*P system */
+
+ "\001\003\000GeneralIPI",
+
+ "\002\000\000GeneralEther",
+ "\002\001\000GeneralToken",
+ "\002\002\000GeneralFDDI",
+
+ "\003\000\000GeneralVGA",
+ "\003\001\000GeneralSVGA",
+ "\003\002\000GeneralXGA",
+
+ "\004\000\000GeneralVideo",
+ "\004\001\000GeneralAudio",
+ "\004\001\001CS4232Audio", /* CS 4232 Plug 'n Play Configured */
+
+ "\005\000\000GeneralRAM",
+ /* This one is obviously wrong ! */
+ "\005\000\000PCIMemoryController", /* PCI Config Method */
+ "\005\000\001RS6KMemoryController", /* RS6K Config Method */
+ "\005\001\000GeneralFLASH",
+
+ "\006\000\000GeneralHostBridge",
+ "\006\001\000GeneralISABridge",
+ "\006\002\000GeneralEISABridge",
+ "\006\003\000GeneralMCABridge",
+ /* GeneralPCIBridge = 0, */
+ "\006\004\000PCIBridgeDirect",
+ "\006\004\001PCIBridgeIndirect",
+ "\006\004\002PCIBridgeRS6K",
+ "\006\005\000GeneralPCMCIABridge",
+ "\006\006\000GeneralVMEBridge",
+
+ "\007\000\000GeneralRS232",
+ "\007\000\001COMx",
+ "\007\000\002Compatible16450",
+ "\007\000\003Compatible16550",
+ "\007\000\004NS398SerPort", /* NS Super I/O wired to use index
+ register at port 398 and data
+ register at port 399 */
+ "\007\000\005NS26ESerPort", /* Ports 26E and 26F */
+ "\007\000\006NS15CSerPort", /* Ports 15C and 15D */
+ "\007\000\007NS2ESerPort", /* Ports 2E and 2F */
+
+ "\007\001\000GeneralParPort",
+ "\007\001\001LPTx",
+ "\007\001\002NS398ParPort", /* NS Super I/O wired to use index
+ register at port 398 and data
+ register at port 399 */
+ "\007\001\003NS26EParPort", /* Ports 26E and 26F */
+ "\007\001\004NS15CParPort", /* Ports 15C and 15D */
+ "\007\001\005NS2EParPort", /* Ports 2E and 2F */
+
+ "\010\000\000GeneralPIC",
+ "\010\000\001ISA_PIC",
+ "\010\000\002EISA_PIC",
+ "\010\000\003MPIC",
+ "\010\000\004RS6K_PIC",
+
+ "\010\001\000GeneralDMA",
+ "\010\001\001ISA_DMA",
+ "\010\001\002EISA_DMA",
+
+ "\010\002\000GeneralTimer",
+ "\010\002\001ISA_Timer",
+ "\010\002\002EISA_Timer",
+ "\010\003\000GeneralRTC",
+ "\010\003\001ISA_RTC",
+
+ "\010\004\001StoreThruOnly",
+ "\010\004\002StoreInEnabled",
+ "\010\004\003RS6KL2Cache",
+
+ "\010\005\000IndirectNVRAM", /* Indirectly addressed */
+ "\010\005\001DirectNVRAM", /* Memory Mapped */
+ "\010\005\002IndirectNVRAM24", /* Indirectly addressed - 24 bit */
+
+ "\010\006\000GeneralPowerManagement",
+ "\010\006\001EPOWPowerManagement",
+ "\010\006\002PowerControl", // d1378
+
+ "\010\007\000GeneralCMOS",
+
+ "\010\010\000GeneralOPPanel",
+ "\010\010\001HarddiskLight",
+ "\010\010\002CDROMLight",
+ "\010\010\003PowerLight",
+ "\010\010\004KeyLock",
+ "\010\010\005ANDisplay", /* AlphaNumeric Display */
+ "\010\010\006SystemStatusLED", /* 3 digit 7 segment LED */
+ "\010\010\007CHRP_SystemStatusLED", /* CHRP LEDs in PR*P system */
+
+ "\010\011\000GeneralServiceProcessor",
+ "\010\012\000GeneralServiceProcessor",
+ "\010\013\000GeneralServiceProcessor",
+
+ "\010\014\001TransferData",
+ "\010\014\002IGMC32",
+ "\010\014\003IGMC64",
+
+ "\010\017\000GeneralSystemPlanar", /* 10/5/95 */
+ NULL
+ };
+
+static const unsigned char *PnP_SUB_TYPE_STR(unsigned char BaseType,
+ unsigned char SubType) {
+ const unsigned char ** s=PnP_SUB_TYPES;
+ while (*s && !((*s)[0]==BaseType
+ && (*s)[1]==SubType)) s++;
+ if (*s) return *s+2;
+ else return("Unknown !");
+};
+
+static const unsigned char *PnP_INTERFACE_STR(unsigned char BaseType,
+ unsigned char SubType,
+ unsigned char Interface) {
+ const unsigned char ** s=PnP_INTERFACES;
+ while (*s && !((*s)[0]==BaseType
+ && (*s)[1]==SubType
+ && (*s)[2]==Interface)) s++;
+ if (*s) return *s+3;
+ else return NULL;
+};
+
+static void printsmallvendor(PnP_TAG_PACKET *pkt, int size) {
+ int i, c;
+ char decomp[4];
+#define p pkt->S14_Pack.S14_Data.S14_PPCPack
+ switch(p.Type) {
+ case 1:
+ /* Decompress first 3 chars */
+ c = *(unsigned short *)p.PPCData;
+ decomp[0]='A'-1+((c>>10)&0x1F);
+ decomp[1]='A'-1+((c>>5)&0x1F);
+ decomp[2]='A'-1+(c&0x1F);
+ decomp[3]=0;
+ printk(" Chip identification: %s%4.4X\n",
+ decomp, ld_le16((unsigned short *)(p.PPCData+2)));
+ break;
+ default:
+ printk(" Small vendor item type 0x%2.2x, data (hex): ",
+ p.Type);
+ for(i=0; i<size-2; i++) printk("%2.2x ", p.PPCData[i]);
+ printk("\n");
+ break;
+ }
+#undef p
+}
+
+static void printsmallpacket(PnP_TAG_PACKET * pkt, int size) {
+ static const unsigned char * intlevel[] = {"high", "low"};
+ static const unsigned char * intsense[] = {"edge", "level"};
+
+ switch (tag_small_item_name(pkt->S1_Pack.Tag)) {
+ case PnPVersion:
+ printk(" PnPversion 0x%x.%x\n",
+ pkt->S1_Pack.Version[0], /* How to interpret version ? */
+ pkt->S1_Pack.Version[1]);
+ break;
+// case Logicaldevice:
+ break;
+// case CompatibleDevice:
+ break;
+ case IRQFormat:
+#define p pkt->S4_Pack
+ printk(" IRQ Mask 0x%4.4x, %s %s sensitive\n",
+ ld_le16((unsigned short *)p.IRQMask),
+ intlevel[(size>3) ? !(p.IRQInfo&0x05) : 0],
+ intsense[(size>3) ? !(p.IRQInfo&0x03) : 0]);
+#undef p
+ break;
+ case DMAFormat:
+#define p pkt->S5_Pack
+ printk(" DMA channel mask 0x%2.2x, info 0x%2.2x\n",
+ p.DMAMask, p.DMAInfo);
+#undef p
+ break;
+ case StartDepFunc:
+ printk("Start dependent function:\n");
+ break;
+ case EndDepFunc:
+ printk("End dependent function\n");
+ break;
+ case IOPort:
+#define p pkt->S8_Pack
+ printk(" Variable (%d decoded bits) I/O port\n"
+ " from 0x%4.4x to 0x%4.4x, alignment %d, %d ports\n",
+ p.IOInfo&ISAAddr16bit?16:10,
+ ld_le16((unsigned short *)p.RangeMin),
+ ld_le16((unsigned short *)p.RangeMax),
+ p.IOAlign, p.IONum);
+#undef p
+ break;
+ case FixedIOPort:
+#define p pkt->S9_Pack
+ printk(" Fixed (10 decoded bits) I/O port from %3.3x to %3.3x\n",
+ (p.Range[1]<<8)|p.Range[0],
+ ((p.Range[1]<<8)|p.Range[0])+p.IONum-1);
+#undef p
+ break;
+ case Res1:
+ case Res2:
+ case Res3:
+ printk(" Undefined packet type %d!\n",
+ tag_small_item_name(pkt->S1_Pack.Tag));
+ break;
+ case SmallVendorItem:
+ printsmallvendor(pkt,size);
+ break;
+ default:
+ printk(" Type 0x2.2x%d, size=%d\n",
+ pkt->S1_Pack.Tag, size);
+ break;
+ }
+}
+
+static void printlargevendor(PnP_TAG_PACKET * pkt, int size) {
+ static const unsigned char * addrtype[] = {"I/O", "Memory", "System"};
+ static const unsigned char * inttype[] = {"8259", "MPIC", "RS6k BUID %d"};
+ static const unsigned char * convtype[] = {"Bus Memory", "Bus I/O", "DMA"};
+ static const unsigned char * transtype[] = {"direct", "mapped", "direct-store segment"};
+ static const unsigned char * L2type[] = {"WriteThru", "CopyBack"};
+ static const unsigned char * L2assoc[] = {"DirectMapped", "2-way set"};
+
+ int i;
+ char tmpstr[30], *t;
+#define p pkt->L4_Pack.L4_Data.L4_PPCPack
+ switch(p.Type) {
+ case 2:
+ printk(" %d K %s %s L2 cache, %d/%d bytes line/sector size\n",
+ ld_le32((unsigned int *)p.PPCData),
+ L2type[p.PPCData[10]-1],
+ L2assoc[p.PPCData[4]-1],
+ ld_le16((unsigned short *)p.PPCData+3),
+ ld_le16((unsigned short *)p.PPCData+4));
+ break;
+ case 3:
+ printk(" PCI Bridge parameters\n"
+ " ConfigBaseAddress %0x\n"
+ " ConfigBaseData %0x\n"
+ " Bus number %d\n",
+ ld_le32((unsigned int *)p.PPCData),
+ ld_le32((unsigned int *)(p.PPCData+8)),
+ p.PPCData[16]);
+ for(i=20; i<size-4; i+=12) {
+ int j, first;
+ if(p.PPCData[i]) printk(" PCI Slot %d", p.PPCData[i]);
+ else printk (" Integrated PCI device");
+ for(j=0, first=1, t=tmpstr; j<4; j++) {
+ int line=ld_le16((unsigned short *)(p.PPCData+i+4)+j);
+ if(line!=0xffff){
+ if(first) first=0; else *t++='/';
+ *t++='A'+j;
+ }
+ }
+ *t='\0';
+ printk(" DevFunc 0x%x interrupt line(s) %s routed to",
+ p.PPCData[i+1],tmpstr);
+ sprintf(tmpstr,
+ inttype[p.PPCData[i+2]-1],
+ p.PPCData[i+3]);
+ printk(" %s line(s) ",
+ tmpstr);
+ for(j=0, first=1, t=tmpstr; j<4; j++) {
+ int line=ld_le16((unsigned short *)(p.PPCData+i+4)+j);
+ if(line!=0xffff){
+ if(first) first=0; else *t++='/';
+ t+=sprintf(t,"%d(%c)",
+ line&0x7fff,
+ line&0x8000?'E':'L');
+ }
+ }
+ printk("%s\n",tmpstr);
+ }
+ break;
+ case 5:
+ printk(" Bridge address translation, %s decoding:\n"
+ " Processor Bus Size Conversion Translation\n"
+ " 0x%8.8x 0x%8.8x 0x%8.8x %s %s\n",
+ p.PPCData[0]&1 ? "positive" : "subtractive",
+ ld_le32((unsigned int *)p.PPCData+1),
+ ld_le32((unsigned int *)p.PPCData+3),
+ ld_le32((unsigned int *)p.PPCData+5),
+ convtype[p.PPCData[2]-1],
+ transtype[p.PPCData[1]-1]);
+ break;
+ case 6:
+ printk(" Bus speed %d Hz, %d slot(s)\n",
+ ld_le32((unsigned int *)p.PPCData),
+ p.PPCData[4]);
+ break;
+ case 7:
+ printk(" SCSI buses: %d, id(s):", p.PPCData[0]);
+ for(i=1; i<=p.PPCData[0]; i++)
+ printk(" %d%c", p.PPCData[i], i==p.PPCData[0] ? '\n' : ',');
+ break;
+ case 9:
+ printk(" %s address (%d bits), at 0x%x size 0x%x bytes\n",
+ addrtype[p.PPCData[0]-1],
+ p.PPCData[1],
+ ld_le32((unsigned int *)(p.PPCData+4)),
+ ld_le32((unsigned int *)(p.PPCData+12)));
+ break;
+ case 10:
+ sprintf(tmpstr,
+ inttype[p.PPCData[0]-1],
+ p.PPCData[1]);
+
+ printk(" ISA interrupts routed to %s\n"
+ " lines",
+ tmpstr);
+ for(i=0; i<16; i++) {
+ int line=ld_le16((unsigned short *)p.PPCData+i+1);
+ if (line!=0xffff) printk(" %d(IRQ%d)", line, i);
+ }
+ printk("\n");
+ break;
+ default:
+ printk(" Large vendor item type 0x%2.2x\n Data (hex):",
+ p.Type);
+ for(i=0; i<size-4; i++) printk(" %2.2x", p.PPCData[i]);
+ printk("\n");
+#undef p
+ }
+}
+
+static void printlargepacket(PnP_TAG_PACKET * pkt, int size) {
+ int i;
+
+ switch (tag_large_item_name(pkt->S1_Pack.Tag)) {
+ case LargeVendorItem:
+ printlargevendor(pkt, size);
+ break;
+ default:
+ printk(" Type 0x2.2x%d, size=%d\n",
+ pkt->S1_Pack.Tag, size);
+ break;
+ }
+}
+static void printpackets(PnP_TAG_PACKET * pkt, const char * cat) {
+ PnP_TAG_PACKET tmp;
+ if (pkt->S1_Pack.Tag== END_TAG) {
+ printk(" No packets describing %s resources.\n", cat);
+ return;
+ }
+ printk( " Packets describing %s resources:\n",cat);
+ do {
+ int size;
+ if (tag_type(pkt->S1_Pack.Tag)) {
+ size= 3 +
+ pkt->L1_Pack.Count0 +
+ pkt->L1_Pack.Count1*256;
+ printlargepacket(pkt, size);
+ } else {
+ size=tag_small_count(pkt->S1_Pack.Tag)+1;
+ printsmallpacket(pkt, size);
+ }
+ (unsigned char *) pkt+=size;
+ } while (pkt->S1_Pack.Tag != END_TAG);
+}
+
+void print_residual_device_info(void)
+{
+ int i;
+ union _PnP_TAG_PACKET *pkt;
+ PPC_DEVICE *dev;
+#define did dev->DeviceId
+return;
+
+ /* make sure we have residual data first */
+ if ( res.ResidualLength == 0 )
+ return;
+
+ printk("Residual: %ld devices\n", res.ActualNumDevices);
+ for ( i = 0;
+ i < res.ActualNumDevices ;
+ i++)
+ {
+ char decomp[4], sn[20];
+ const char * s;
+ dev = &res.Devices[i];
+ s = PnP_INTERFACE_STR(did.BaseType, did.SubType,
+ did.Interface);
+ if(!s) {
+ sprintf(sn, "interface %d", did.Interface);
+ s=sn;
+ }
+ if ( did.BusId & PCIDEVICE )
+ printk("PCI Device, Bus %d, DevFunc 0x%x:",
+ dev->BusAccess.PCIAccess.BusNumber,
+ dev->BusAccess.PCIAccess.DevFuncNumber);
+ if ( did.BusId & PNPISADEVICE ) printk("PNPISA Device:");
+ if ( did.BusId & ISADEVICE )
+ printk("ISA Device, Slot %d, LogicalDev %d:",
+ dev->BusAccess.ISAAccess.SlotNumber,
+ dev->BusAccess.ISAAccess.LogicalDevNumber);
+ if ( did.BusId & EISADEVICE ) printk("EISA Device:");
+ if ( did.BusId & PROCESSORDEVICE )
+ printk("ProcBus Device, Bus %d, BUID %d: ",
+ dev->BusAccess.ProcBusAccess.BusNumber,
+ dev->BusAccess.ProcBusAccess.BUID);
+ if ( did.BusId & PCMCIADEVICE ) printk("PCMCIA ");
+ if ( did.BusId & VMEDEVICE ) printk("VME ");
+ if ( did.BusId & MCADEVICE ) printk("MCA ");
+ if ( did.BusId & MXDEVICE ) printk("MX ");
+ /* Decompress first 3 chars */
+ decomp[0]='A'-1+((did.DevId>>26)&0x1F);
+ decomp[1]='A'-1+((did.DevId>>21)&0x1F);
+ decomp[2]='A'-1+((did.DevId>>16)&0x1F);
+ decomp[3]=0;
+ printk(" %s%4.4lX, %s, %s, %s\n",
+ decomp, did.DevId&0xffff,
+ PnP_BASE_TYPES[did.BaseType],
+ PnP_SUB_TYPE_STR(did.BaseType,did.SubType),
+ s);
+ printpackets( (union _PnP_TAG_PACKET *)
+ &res.DevicePnPHeap[dev->AllocatedOffset], "allocated");
+ printpackets( (union _PnP_TAG_PACKET *)
+ &res.DevicePnPHeap[dev->PossibleOffset], "possible");
+ printpackets( (union _PnP_TAG_PACKET *)
+ &res.DevicePnPHeap[dev->CompatibleOffset], "compatible");
+ }
+}
+
+
+
+static void printVPD(void) {
+#define vpd res.VitalProductData
+ int ps=vpd.PageSize, i, j;
+ static const char* Usage[]={
+ "FirmwareStack", "FirmwareHeap", "FirmwareCode", "BootImage",
+ "Free", "Unpopulated", "ISAAddr", "PCIConfig",
+ "IOMemory", "SystemIO", "SystemRegs", "PCIAddr",
+ "UnPopSystemRom", "SystemROM", "ResumeBlock", "Other"
+ };
+ static const unsigned char *FWMan[]={
+ "IBM", "Motorola", "FirmWorks", "Bull"
+ };
+ static const unsigned char *FWFlags[]={
+ "Conventional", "OpenFirmware", "Diagnostics", "LowDebug",
+ "MultiBoot", "LowClient", "Hex41", "FAT",
+ "ISO9660", "SCSI_ID_Override", "Tape_Boot", "FW_Boot_Path"
+ };
+ static const unsigned char *ESM[]={
+ "Port92", "PCIConfigA8", "FF001030", "????????"
+ };
+ static const unsigned char *SIOM[]={
+ "Port850", "????????", "PCIConfigA8", "????????"
+ };
+
+ printk("Model: %s\n",vpd.PrintableModel);
+ printk("Serial: %s\n", vpd.Serial);
+ printk("FirmwareSupplier: %s\n", FWMan[vpd.FirmwareSupplier]);
+ printk("FirmwareFlags:");
+ for(j=0; j<12; j++) {
+ if (vpd.FirmwareSupports & (1<<j)) {
+ printk(" %s%c", FWFlags[j],
+ vpd.FirmwareSupports&(-2<<j) ? ',' : '\n');
+ }
+ }
+ printk("NVRamSize: %ld\n", vpd.NvramSize);
+ printk("SIMMslots: %ld\n", vpd.NumSIMMSlots);
+ printk("EndianSwitchMethod: %s\n",
+ ESM[vpd.EndianSwitchMethod>2 ? 2 : vpd.EndianSwitchMethod]);
+ printk("SpreadIOMethod: %s\n",
+ SIOM[vpd.SpreadIOMethod>3 ? 3 : vpd.SpreadIOMethod]);
+ printk("Processor/Bus frequencies (Hz): %ld/%ld\n",
+ vpd.ProcessorHz, vpd.ProcessorBusHz);
+ printk("Time Base Divisor: %ld\n", vpd.TimeBaseDivisor);
+ printk("WordWidth, PageSize: %ld, %d\n", vpd.WordWidth, ps);
+ printk("Cache sector size, Lock granularity: %ld, %ld\n",
+ vpd.CoherenceBlockSize, vpd.GranuleSize);
+ for (i=0; i<res.ActualNumMemSegs; i++) {
+ int mask=res.Segs[i].Usage, first, j;
+ printk("%8.8lx-%8.8lx ",
+ res.Segs[i].BasePage*ps,
+ (res.Segs[i].PageCount+res.Segs[i].BasePage)*ps-1);
+ for(j=15, first=1; j>=0; j--) {
+ if (mask&(1<<j)) {
+ if (first) first=0;
+ else printk(", ");
+ printk("%s", Usage[j]);
+ }
+ }
+ printk("\n");
+ }
+}
+
/*
* Spit out some info about residual data
*/
+#if 0
void print_residual_device_info(void)
{
int i;
@@ -48,7 +624,6 @@ void print_residual_device_info(void)
/* make sure we have residual data first */
if ( res.ResidualLength == 0 )
return;
-
printk("Residual: %ld devices\n", res.ActualNumDevices);
for ( i = 0;
i < res.ActualNumDevices ;
@@ -136,9 +711,6 @@ void print_residual_device_info(void)
did.BusId);
}
}
+#endif
-
-
-
-
-
+#endif /* 0 */
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index f3769cad0..86407e273 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -1,6 +1,6 @@
/*
- * $Id: setup.c,v 1.16 1997/08/27 22:06:54 cort Exp $
- * Common prep/pmac boot and setup code.
+ * $Id: setup.c,v 1.48 1998/01/01 10:04:44 paulus Exp $
+ * Common prep/pmac/chrp boot and setup code.
*/
#include <linux/config.h>
@@ -8,19 +8,31 @@
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/reboot.h>
-#include <linux/openpic.h>
+#include <linux/delay.h>
+#include <linux/blk.h>
+#include <asm/adb.h>
#include <asm/cuda.h>
#include <asm/residual.h>
#include <asm/io.h>
#include <asm/ide.h>
+#include <asm/prom.h>
+extern char cmd_line[512];
char saved_command_line[256];
unsigned char aux_device_present;
+#if !defined(CONFIG_MACH_SPECIFIC)
+unsigned long ISA_DMA_THRESHOLD;
+unsigned long DMA_MODE_READ, DMA_MODE_WRITE;
+int _machine;
+#endif /* ! CONFIG_MACH_SPECIFIC */
+
/* copy of the residual data */
RESIDUAL res;
-int _machine;
+int _prep_type;
+/* if we have openfirmware */
+unsigned long have_of;
/*
* Perhaps we can put the pmac screen_info[] here
@@ -28,7 +40,7 @@ int _machine;
* Until we get multiple-console support in here
* that is. -- Cort
*/
-#if defined(CONFIG_CHRP) || defined(CONFIG_PREP )
+#if !defined(CONFIG_PMAC_CONSOLE)
struct screen_info screen_info = {
0, 25, /* orig-x, orig-y */
{ 0, 0 }, /* unused */
@@ -48,94 +60,20 @@ int pmac_display_supported(char *name)
{
return 0;
}
-int sd_find_target(void *a, int b)
-{
- return 0;
-}
void pmac_find_display(void)
{
}
-
#endif
-/*
- * Find out what kind of machine we're on and save any data we need
- * from the early boot process (devtree is copied on pmac by prom_init() )
- */
-unsigned long identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7)
-{
- extern unsigned long initrd_start, initrd_end;
- extern char cmd_line[256];
-#ifdef CONFIG_PMAC /* cheat for now - perhaps a check for OF could tell us */
- _machine = _MACH_Pmac;
-#endif /* CONFIG_PMAC */
-#ifdef CONFIG_PREP
- /* make a copy of residual data */
- if ( r3 )
- memcpy( (void *)&res,(void *)(r3+KERNELBASE), sizeof(RESIDUAL) );
- if (!strncmp(res.VitalProductData.PrintableModel,"IBM",3))
- _machine = _MACH_IBM;
- else
- _machine = _MACH_Motorola;
-#endif /* CONFIG_PREP */
-#ifdef CONFIG_CHRP
- _machine = _MACH_chrp;
-#endif /* CONFIG_CHRP */
-
- switch (_machine)
- {
- case _MACH_Pmac:
- io_base = 0;
- pci_dram_offset = 0;
- break;
- case _MACH_IBM:
- case _MACH_Motorola:
- io_base = 0x80000000;
- pci_dram_offset = 0x80000000;
-#ifdef CONFIG_BLK_DEV_RAM
- /* take care of initrd if we have one */
- if ( r4 )
- {
- initrd_start = r4 + KERNELBASE;
- initrd_end = r5 + KERNELBASE;
- }
-#endif /* CONFIG_BLK_DEV_RAM */
- /* take care of cmd line */
- if ( r6 )
- {
-
- *(char *)(r7+KERNELBASE) = 0;
- strcpy(cmd_line, (char *)(r6+KERNELBASE));
- }
- break;
- case _MACH_chrp:
- /* LongTrail */
- io_base = 0xf8000000;
- pci_dram_offset = 0;
- /* take care of initrd if we have one */
- if ( r4 ) {
- initrd_start = r4 + KERNELBASE;
- initrd_end = r5 + KERNELBASE;
- }
- /* take care of cmd line */
- if ( r6 ) {
- *(char *)(r7+KERNELBASE) = 0;
- strcpy(cmd_line, (char *)(r6+KERNELBASE));
- }
- break;
- default:
- printk("Unknown machine type in identify_machine!\n");
- }
- return 0;
-}
-
/* cmd is ignored for now... */
void machine_restart(char *cmd)
{
- struct cuda_request req;
+ struct adb_request req;
unsigned long flags;
unsigned long i = 10000;
+#if 0
+ int err;
+#endif
switch(_machine)
{
@@ -144,8 +82,14 @@ void machine_restart(char *cmd)
for (;;)
cuda_poll();
break;
- case _MACH_IBM:
- case _MACH_Motorola:
+ case _MACH_chrp:
+#if 0 /* RTAS doesn't seem to work on Longtrail.
+ For now, do it the same way as the PReP. */
+ err = call_rtas("system-reboot", 0, 1, NULL);
+ printk("RTAS system-reboot returned %d\n", err);
+ for (;;);
+#endif
+ case _MACH_prep:
_disable_interrupts();
/* set exception prefix high - to the prom */
@@ -160,25 +104,29 @@ void machine_restart(char *cmd)
while ( i != 0 ) i++;
panic("restart failed\n");
break;
-
- case _MACH_chrp:
- openpic_init_processor(1<<0);
- break;
}
}
void machine_power_off(void)
{
- struct cuda_request req;
+ struct adb_request req;
+#if 0
+ int err;
+#endif
- if ( _machine == _MACH_Pmac )
- {
+ switch (_machine) {
+ case _MACH_Pmac:
cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_POWERDOWN);
for (;;)
cuda_poll();
- }
- else /* prep or chrp */
- {
+ case _MACH_chrp:
+#if 0 /* RTAS doesn't seem to work on Longtrail.
+ For now, do it the same way as the PReP. */
+ err = call_rtas("power-off", 2, 1, NULL, 0, 0);
+ printk("RTAS system-reboot returned %d\n", err);
+ for (;;);
+#endif
+ case _MACH_prep:
machine_restart(NULL);
}
}
@@ -202,38 +150,328 @@ void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
{
if ( _machine == _MACH_Pmac )
pmac_ide_init_hwif_ports(p,base,irq);
- else /* prep */
+ else /* prep or chrp */
prep_ide_init_hwif_ports(p,base,irq);
}
-/*
- * Will merge more into here later -- Cort
- */
int get_cpuinfo(char *buffer)
{
extern int pmac_get_cpuinfo(char *);
extern int chrp_get_cpuinfo(char *);
extern int prep_get_cpuinfo(char *);
+ unsigned long len = 0;
+ unsigned long bogosum = 0;
+ unsigned long i;
+#ifdef __SMP__
+ extern unsigned long cpu_present_map;
+ extern struct cpuinfo_PPC cpu_data[NR_CPUS];
+#define GET_PVR ((long int)(cpu_data[i].pvr))
+#define CD(x) (cpu_data[i].x)
+#else
+#define cpu_present_map 1L
+#define smp_num_cpus 1
+#define GET_PVR ((long int)_get_PVR())
+#define CD(x) (x)
+#endif
+
+ for ( i = 0; i < smp_num_cpus ; i++ )
+ {
+ if ( ! ( cpu_present_map & (1<<i) ) )
+ continue;
+ if ( i )
+ len += sprintf(len+buffer,"\n");
+ len += sprintf(len+buffer,"processor\t: %lu\n",i);
+ len += sprintf(len+buffer,"cpu\t\t: ");
+ switch (GET_PVR >> 16)
+ {
+ case 1:
+ len += sprintf(len+buffer, "601\n");
+ break;
+ case 3:
+ len += sprintf(len+buffer, "603\n");
+ break;
+ case 4:
+ len += sprintf(len+buffer, "604\n");
+ break;
+ case 6:
+ len += sprintf(len+buffer, "603e\n");
+ break;
+ case 7:
+ len += sprintf(len+buffer, "603ev\n");
+ break;
+ case 8:
+ len += sprintf(len+buffer, "750 (Arthur)\n");
+ break;
+ case 9:
+ len += sprintf(len+buffer, "604e\n");
+ break;
+ case 10:
+ len += sprintf(len+buffer, "604ev5 (MachV)\n");
+ break;
+ default:
+ len += sprintf(len+buffer, "unknown (%lu)\n",
+ GET_PVR>>16);
+ break;
+ }
+
+ /*
+ * Assume here that all clock rates are the same in a
+ * smp system. -- Cort
+ */
+ if ( have_of )
+ {
+ struct device_node *cpu_node;
+ int *fp;
+
+ cpu_node = find_type_devices("cpu");
+ if ( !cpu_node ) break;
+ fp = (int *) get_property(cpu_node, "clock-frequency", NULL);
+ if ( !fp ) break;
+ len += sprintf(len+buffer, "clock\t\t: %dMHz\n",
+ *fp / 1000000);
+ }
+
+ /* PREP's without residual data for some reason will give
+ incorrect values here */
+ if ( is_prep )
+ {
+ len += sprintf(len+buffer, "clock\t\t: ");
+ if ( res.ResidualLength )
+ len += sprintf(len+buffer, "%ldMHz\n",
+ (res.VitalProductData.ProcessorHz > 1024) ?
+ res.VitalProductData.ProcessorHz>>20 :
+ res.VitalProductData.ProcessorHz);
+ else
+ len += sprintf(len+buffer, "???\n");
+ }
+
+ len += sprintf(len+buffer, "revision\t: %ld.%ld\n",
+ (GET_PVR & 0xff00) >> 8, GET_PVR & 0xff);
+
+ len += sprintf(buffer+len, "bogomips\t: %lu.%02lu\n",
+ (CD(loops_per_sec)+2500)/500000,
+ (CD(loops_per_sec)+2500)/5000 % 100);
+ bogosum += CD(loops_per_sec);
+ }
+
+#ifdef __SMP__
+ if ( i )
+ len += sprintf(buffer+len, "\n");
+ len += sprintf(buffer+len,"total bogomips\t: %lu.%02lu\n",
+ (bogosum+2500)/500000,
+ (bogosum+2500)/5000 % 100);
+#endif /* __SMP__ */
+
+ /*
+ * Ooh's and aah's info about zero'd pages in idle task
+ */
+ {
+ extern unsigned int zerocount, zerototal, zeropage_hits,zeropage_calls;
+ len += sprintf(buffer+len,"zero pages\t: total %u (%luKb) "
+ "current: %u (%luKb) hits: %u/%u (%u%%)\n",
+ zerototal, (zerototal*PAGE_SIZE)>>10,
+ zerocount, (zerocount*PAGE_SIZE)>>10,
+ zeropage_hits,zeropage_calls,
+ /* : 1 below is so we don't div by zero */
+ (zeropage_hits*100) /
+ ((zeropage_calls)?zeropage_calls:1));
+ }
switch (_machine)
{
case _MACH_Pmac:
- return pmac_get_cpuinfo(buffer);
+ len += pmac_get_cpuinfo(buffer+len);
break;
- case _MACH_Motorola:
- case _MACH_IBM:
- return prep_get_cpuinfo(buffer);
+ case _MACH_prep:
+ len += prep_get_cpuinfo(buffer+len);
break;
case _MACH_chrp:
- return chrp_get_cpuinfo(buffer);
+ len += chrp_get_cpuinfo(buffer+len);
break;
}
- printk("Unknown machine %d in get_cpuinfo()\n",_machine);
- return 0;
+ return len;
}
+/*
+ * Find out what kind of machine we're on and save any data we need
+ * from the early boot process (devtree is copied on pmac by prom_init() )
+ */
+__initfunc(unsigned long
+identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7))
+{
+ extern unsigned long initrd_start, initrd_end;
+ extern setup_pci_ptrs(void);
+ unsigned long boot_sdr1;
+ ihandle prom_root;
+ unsigned char type[16], model[16];
+
+ asm("mfspr %0,25\n\t" :"=r" (boot_sdr1));
+
+ /*
+ * if we have a sdr1 then we have openfirmware
+ * and can ask it what machine we are (chrp/pmac/prep).
+ * otherwise we're definitely prep. -- Cort
+ */
+ if ( !boot_sdr1 )
+ {
+ /* we know for certain we're prep if no OF */
+ have_of = 0;
+ /* make a copy of residual data */
+ if ( r3 )
+ memcpy((void *)&res,(void *)(r3+KERNELBASE),
+ sizeof(RESIDUAL));
+#ifndef CONFIG_MACH_SPECIFIC
+ _machine = _MACH_prep;
+#endif /* CONFIG_MACH_SPECIFIC */
+ }
+ else
+ {
+ /*
+ * init prom here, then ask the openfirmware
+ * what machine we are (prep/chrp/pmac). We don't use
+ * OF on prep just yet. -- Cort
+ */
+#ifndef CONFIG_PREP /* don't use OF on prep yet */
+ have_of = 1;
+ /* prom_init has already been called from __start */
+ finish_device_tree();
+
+ /*
+ * If we were booted via quik, r3 points to the physical
+ * address of the command-line parameters.
+ * If we were booted from an xcoff image (i.e. netbooted or
+ * booted from floppy), we get the command line from the
+ * bootargs property of the /chosen node.
+ * If an initial ramdisk is present, r3 and r4
+ * are used for initrd_start and initrd_size,
+ * otherwise they contain 0xdeadbeef.
+ */
+ cmd_line[0] = 0;
+ if (r3 >= 0x4000 && r3 < 0x800000 && r4 == 0) {
+ strncpy(cmd_line, (char *)r3 + KERNELBASE,
+ sizeof(cmd_line));
+ } else {
+ struct device_node *chosen;
+ char *p;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (r3 - KERNELBASE < 0x800000
+ && r4 != 0 && r4 != 0xdeadbeef) {
+ initrd_start = r3;
+ initrd_end = r3 + r4;
+ ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+ }
+#endif
+ chosen = find_path_device("/chosen");
+ if (chosen != NULL) {
+ p = get_property(chosen, "bootargs", NULL);
+ if (p != NULL)
+ strncpy(cmd_line, p, sizeof(cmd_line));
+ }
+ }
+ cmd_line[sizeof(cmd_line) - 1] = 0;
+#endif /* CONFIG_PREP */
+
+#ifndef CONFIG_MACH_SPECIFIC
+#if 0
+ prom_root = call_prom("finddevice", 1, 1, "/");
+ call_prom("getprop", 4, 1, prom_root, "device_type", &type,
+ (void *) sizeof(type));
+ call_prom("getprop", 4, 1, prom_root, "model", &type,
+ (void *) sizeof(model));
+ if ( !strncmp("chrp", type,4) )
+ {
+ _machine = _MACH_chrp;
+ }
+ else
+ {
+ /*if ( !strncmp("Power Macintosh", type,15) )*/
+ _machine = _MACH_Pmac;
+ }
+#else
+
+#ifdef CONFIG_CHRP
+ _machine = _MACH_chrp;
+#endif /* CONFIG_CHRP */
+#ifdef CONFIG_PMAC
+ _machine = _MACH_Pmac;
+#endif /* CONFIG_PMAC */
+#ifdef CONFIG_PREP
+ _machine = _MACH_Prep;
+#endif /* CONFIG_PREP */
+#endif /* #if */
+#endif /* CONFIG_MACH_SPECIFIC */
+ }
+
+ /* so that pmac/chrp can use pci to find its console -- Cort */
+ setup_pci_ptrs();
+
+ switch (_machine)
+ {
+ case _MACH_Pmac:
+#if !defined(CONFIG_MACH_SPECIFIC)
+ isa_io_base = PMAC_ISA_IO_BASE;
+ isa_mem_base = PMAC_ISA_MEM_BASE;
+ pci_dram_offset = PMAC_PCI_DRAM_OFFSET;
+ ISA_DMA_THRESHOLD = ~0L;
+ DMA_MODE_READ = 1;
+ DMA_MODE_WRITE = 2;
+#endif /* ! CONFIG_MACH_SPECIFIC */
+ break;
+ case _MACH_prep:
+#if !defined(CONFIG_MACH_SPECIFIC)
+ isa_io_base = PREP_ISA_IO_BASE;
+ isa_mem_base = PREP_ISA_MEM_BASE;
+ pci_dram_offset = PREP_PCI_DRAM_OFFSET;
+ ISA_DMA_THRESHOLD = 0x00ffffff;
+ DMA_MODE_READ = 0x44;
+ DMA_MODE_WRITE = 0x48;
+#endif /* ! CONFIG_MACH_SPECIFIC */
+ /* figure out what kind of prep workstation we are */
+ if ( res.ResidualLength != 0 )
+ {
+ if ( !strncmp(res.VitalProductData.PrintableModel,"IBM",3) )
+ _prep_type = 0x00;
+ else
+ _prep_type = 0x01;
+ }
+ else /* assume motorola if no residual (netboot?) */
+ _prep_type = _PREP_Motorola;
+
+#ifdef CONFIG_BLK_DEV_RAM
+ /* take care of initrd if we have one */
+ if ( r4 )
+ {
+ initrd_start = r4 + KERNELBASE;
+ initrd_end = r5 + KERNELBASE;
+ }
+#endif /* CONFIG_BLK_DEV_RAM */
+ /* take care of cmd line */
+ if ( r6 )
+ {
+ *(char *)(r7+KERNELBASE) = 0;
+ strcpy(cmd_line, (char *)(r6+KERNELBASE));
+ }
+ break;
+ case _MACH_chrp:
+ /* LongTrail */
+#if !defined(CONFIG_MACH_SPECIFIC)
+ isa_io_base = CHRP_ISA_IO_BASE;
+ isa_mem_base = CHRP_ISA_MEM_BASE;
+ pci_dram_offset = CHRP_PCI_DRAM_OFFSET;
+ ISA_DMA_THRESHOLD = ~0L;
+ DMA_MODE_READ = 0x44;
+ DMA_MODE_WRITE = 0x48;
+#endif /* ! CONFIG_MACH_SPECIFIC */
+ break;
+ default:
+ printk("Unknown machine type in identify_machine!\n");
+ }
+ return 0;
+}
__initfunc(unsigned long
bios32_init(unsigned long memory_start, unsigned long memory_end))
@@ -244,25 +482,41 @@ bios32_init(unsigned long memory_start, unsigned long memory_end))
__initfunc(void setup_arch(char **cmdline_p,
unsigned long * memory_start_p, unsigned long * memory_end_p))
{
- extern void pmac_setup_arch(char **, unsigned long *, unsigned long *);
- extern void chrp_setup_arch(char **, unsigned long *, unsigned long *);
- extern void prep_setup_arch(char **, unsigned long *, unsigned long *);
+ extern void pmac_setup_arch(unsigned long *, unsigned long *);
+ extern void chrp_setup_arch(unsigned long *, unsigned long *);
+ extern void prep_setup_arch(unsigned long *, unsigned long *);
+ extern int panic_timeout;
+ extern char _etext[], _edata[];
+ extern char *klimit;
+ extern unsigned long find_available_memory(void);
+ extern unsigned long *end_of_DRAM;
+
+ /* reboot on panic */
+ panic_timeout = 180;
- switch (_machine)
- {
+ 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;
+
+ /* Save unparsed command line copy for /proc/cmdline */
+ strcpy(saved_command_line, cmd_line);
+ *cmdline_p = cmd_line;
+
+ *memory_start_p = find_available_memory();
+ *memory_end_p = (unsigned long) end_of_DRAM;
+
+ switch (_machine) {
case _MACH_Pmac:
- pmac_setup_arch(cmdline_p,memory_start_p,memory_end_p);
+ pmac_setup_arch(memory_start_p, memory_end_p);
break;
- case _MACH_Motorola:
- case _MACH_IBM:
- prep_setup_arch(cmdline_p,memory_start_p,memory_end_p);
+ case _MACH_prep:
+ prep_setup_arch(memory_start_p, memory_end_p);
break;
case _MACH_chrp:
- return chrp_setup_arch(cmdline_p,memory_start_p,memory_end_p);
+ chrp_setup_arch(memory_start_p, memory_end_p);
break;
+ default:
+ printk("Unknown machine %d in setup_arch()\n", _machine);
}
- printk("Unknown machine %d in setup_arch()\n",_machine);
}
-
-
-
diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c
index 3151d266a..ae6d3c5aa 100644
--- a/arch/ppc/kernel/signal.c
+++ b/arch/ppc/kernel/signal.c
@@ -6,12 +6,12 @@
*
* Derived from "arch/i386/kernel/signal.c"
* Copyright (C) 1991, 1992 Linus Torvalds
+ * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
*
* 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>
@@ -24,45 +24,59 @@
#include <linux/wait.h>
#include <linux/ptrace.h>
#include <linux/unistd.h>
+#include <linux/stddef.h>
#include <linux/elf.h>
+#include <asm/ucontext.h>
#include <asm/uaccess.h>
+#include <asm/pgtable.h>
-#define _S(nr) (1<<((nr)-1))
-
-#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
-
-#define DEBUG_SIGNALS
-#undef DEBUG_SIGNALS
+#define DEBUG_SIG 0
-#define PAUSE_AFTER_SIGNAL
-#undef PAUSE_AFTER_SIGNAL
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
#ifndef MIN
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
-asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
+#define GP_REGS_SIZE MIN(sizeof(elf_gregset_t), sizeof(struct pt_regs))
+
+/*
+ * These are the flags in the MSR that the user is allowed to change
+ * by modifying the saved value of the MSR on the stack. SE and BE
+ * should not be in this list since gdb may want to change these. I.e,
+ * you should be able to step out of a signal handler to see what
+ * instruction executes next after the signal handler completes.
+ * Alternately, if you stepped into a signal handler, you should be
+ * able to continue 'til the next breakpoint from within the signal
+ * handler, even if the handler returns.
+ */
+#define MSR_USERCHANGE (MSR_FE0 | MSR_FE1)
+
+int do_signal(sigset_t *oldset, struct pt_regs *regs);
+extern int sys_wait4(pid_t pid, unsigned long *stat_addr,
+ int options, unsigned long *ru);
/*
- * atomically swap in the new signal mask, and wait for a signal.
+ * Atomically swap in the new signal mask, and wait for a signal.
*/
-asmlinkage int sys_sigsuspend(unsigned long set, int p2, int p3, int p4, int p6, int p7, struct pt_regs *regs)
+int
+sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7,
+ struct pt_regs *regs)
{
- unsigned long mask;
+ sigset_t saveset;
+ mask &= _BLOCKABLE;
spin_lock_irq(&current->sigmask_lock);
- mask = current->blocked;
- current->blocked = set & _BLOCKABLE;
+ saveset = current->blocked;
+ siginitset(&current->blocked, mask);
+ recalc_sigpending(current);
spin_unlock_irq(&current->sigmask_lock);
regs->gpr[3] = -EINTR;
-#ifdef DEBUG_SIGNALS
-printk("Task: %x[%d] - SIGSUSPEND at %x, Mask: %x\n", current, current->pid, regs->nip, set);
-#endif
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
- if (do_signal(mask,regs)) {
+ if (do_signal(&saveset, regs))
/*
* If a signal handler needs to be called,
* do_signal() has set R3 to the signal number (the
@@ -72,64 +86,134 @@ printk("Task: %x[%d] - SIGSUSPEND at %x, Mask: %x\n", current, current->pid, reg
* R3, so it's still set to -EINTR (see above).
*/
return regs->gpr[3];
- }
}
}
-/*
- * These are the flags in the MSR that the user is allowed to change
- * by modifying the saved value of the MSR on the stack. SE and BE
- * should not be in this list since gdb may want to change these. I.e,
- * you should be able to step out of a signal handler to see what
- * instruction executes next after the signal handler completes.
- * Alternately, if you stepped into a signal handler, you should be
- * able to continue 'til the next breakpoint from within the signal
- * handler, even if the handler returns.
+int
+sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, int p3, int p4, int p6,
+ int p7, struct pt_regs *regs)
+{
+ sigset_t saveset, newset;
+
+ /* XXX: Don't preclude handling different sized sigset_t's. */
+ if (sigsetsize != sizeof(sigset_t))
+ return -EINVAL;
+
+ if (copy_from_user(&newset, unewset, sizeof(newset)))
+ return -EFAULT;
+ sigdelsetmask(&newset, ~_BLOCKABLE);
+
+ spin_lock_irq(&current->sigmask_lock);
+ saveset = current->blocked;
+ current->blocked = newset;
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+
+ regs->gpr[3] = -EINTR;
+ while (1) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ if (do_signal(&saveset, regs))
+ return regs->gpr[3];
+ }
+}
+
+int
+sys_sigaction(int sig, const struct old_sigaction *act,
+ struct old_sigaction *oact)
+{
+ struct k_sigaction new_ka, old_ka;
+ int ret;
+
+ if (act) {
+ old_sigset_t mask;
+ if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+ __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+ __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+ return -EFAULT;
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags);
+ __get_user(mask, &act->sa_mask);
+ siginitset(&new_ka.sa.sa_mask, mask);
+ }
+
+ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+ if (!ret && oact) {
+ if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+ __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+ __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+ return -EFAULT;
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+ }
+
+ return ret;
+}
+
+/*
+ * When we have signals to deliver, we set up on the
+ * user stack, going down from the original stack pointer:
+ * a sigregs struct
+ * one or more sigcontext structs
+ * a gap of __SIGNAL_FRAMESIZE bytes
+ *
+ * Each of these things must be a multiple of 16 bytes in size.
+ *
+ * XXX ultimately we will have to stack up a siginfo and ucontext
+ * for each rt signal.
*/
-#define MSR_USERCHANGE (MSR_FE0 | MSR_FE1)
+struct sigregs {
+ elf_gregset_t gp_regs;
+ double fp_regs[ELF_NFPREG];
+ unsigned long tramp[2];
+ /* Programs using the rs6000/xcoff abi can save up to 19 gp regs
+ and 18 fp regs below sp before decrementing it. */
+ int abigap[56];
+};
/*
- * This sets regs->esp even though we don't actually use sigstacks yet..
+ * Do a signal return; undo the signal stack.
*/
-asmlinkage int sys_sigreturn(struct pt_regs *regs)
+int sys_sigreturn(struct pt_regs *regs)
{
struct sigcontext_struct *sc, sigctx;
+ struct sigregs *sr;
int ret;
elf_gregset_t saved_regs; /* an array of ELF_NGREG unsigned longs */
+ sigset_t set;
+ unsigned long prevsp;
sc = (struct sigcontext_struct *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
goto badframe;
- current->blocked = sigctx.oldmask & _BLOCKABLE;
- sc++; /* Pop signal 'context' */
-#ifdef DEBUG_SIGNALS
- printk("Sig return - Regs: %p, sc: %p, sig: %d\n", sigctx.regs, sc,
- sigctx.signal);
+
+ set.sig[0] = sigctx.oldmask;
+#if _NSIG_WORDS > 1
+ set.sig[1] = sigctx._unused[3];
#endif
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sigmask_lock);
+ current->blocked = set;
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+
+ sc++; /* Look at next sigcontext */
if (sc == (struct sigcontext_struct *)(sigctx.regs)) {
/* Last stacked signal - restore registers */
+ sr = (struct sigregs *) sigctx.regs;
if (last_task_used_math == current)
giveup_fpu();
- if (copy_from_user(saved_regs, sigctx.regs, sizeof(saved_regs)))
+ if (copy_from_user(saved_regs, &sr->gp_regs,
+ sizeof(sr->gp_regs)))
goto badframe;
saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
| (saved_regs[PT_MSR] & MSR_USERCHANGE);
- memcpy(regs, saved_regs,
- MIN(sizeof(elf_gregset_t),sizeof(struct pt_regs)));
+ memcpy(regs, saved_regs, GP_REGS_SIZE);
- if (copy_from_user(current->tss.fpr,
- (unsigned long *)sigctx.regs + ELF_NGREG,
- ELF_NFPREG * sizeof(double)))
+ if (copy_from_user(current->tss.fpr, &sr->fp_regs,
+ sizeof(sr->fp_regs)))
goto badframe;
- if (regs->trap == 0x0C00 /* System Call! */ &&
- ((int)regs->result == -ERESTARTNOHAND ||
- (int)regs->result == -ERESTARTSYS ||
- (int)regs->result == -ERESTARTNOINTR)) {
- regs->gpr[3] = regs->orig_gpr3;
- regs->nip -= 4; /* Back up & retry system call */
- regs->result = 0;
- }
ret = regs->result;
} else {
@@ -137,87 +221,193 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs)
regs->gpr[1] = (unsigned long)sc - __SIGNAL_FRAMESIZE;
if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
goto badframe;
+ sr = (struct sigregs *) sigctx.regs;
regs->gpr[3] = ret = sigctx.signal;
- regs->gpr[4] = (unsigned long) sigctx.regs;
- regs->link = regs->gpr[4] + ELF_NGREG * sizeof(unsigned long)
- + ELF_NFPREG * sizeof(double);
+ regs->gpr[4] = (unsigned long) sr;
+ regs->link = (unsigned long) &sr->tramp;
regs->nip = sigctx.handler;
+
+ if (get_user(prevsp, &sr->gp_regs[PT_R1])
+ || put_user(prevsp, (unsigned long *) regs->gpr[1]))
+ goto badframe;
}
return ret;
badframe:
lock_kernel();
do_exit(SIGSEGV);
- unlock_kernel();
- return -EFAULT;
+}
+
+/*
+ * Set up a signal frame.
+ */
+static void
+setup_frame(struct pt_regs *regs, struct sigregs *frame,
+ unsigned long newsp)
+{
+ struct sigcontext_struct *sc = (struct sigcontext_struct *) newsp;
+
+ if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
+ goto badframe;
+ if (last_task_used_math == current)
+ giveup_fpu();
+ if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE)
+ || __copy_to_user(&frame->fp_regs, current->tss.fpr,
+ ELF_NFPREG * sizeof(double))
+ || __put_user(0x38007777UL, &frame->tramp[0]) /* li r0,0x7777 */
+ || __put_user(0x44000002UL, &frame->tramp[1])) /* sc */
+ goto badframe;
+ flush_icache_range((unsigned long) &frame->tramp[0],
+ (unsigned long) &frame->tramp[2]);
+
+ newsp -= __SIGNAL_FRAMESIZE;
+ if (put_user(regs->gpr[1], (unsigned long *)newsp)
+ || get_user(regs->nip, &sc->handler)
+ || get_user(regs->gpr[3], &sc->signal))
+ goto badframe;
+ regs->gpr[1] = newsp;
+ regs->gpr[4] = (unsigned long) frame;
+ regs->link = (unsigned long) frame->tramp;
+
+ return;
+
+badframe:
+#if DEBUG_SIG
+ printk("badframe in setup_frame, regs=%p frame=%p newsp=%lx\n",
+ regs, frame, newsp);
+#endif
+ lock_kernel();
+ do_exit(SIGSEGV);
}
+/*
+ * OK, we're invoking a handler
+ */
+static void
+handle_signal(unsigned long sig, struct k_sigaction *ka,
+ siginfo_t *info, sigset_t *oldset, struct pt_regs * regs,
+ unsigned long *newspp, unsigned long frame)
+{
+ struct sigcontext_struct *sc;
+
+ if (regs->trap == 0x0C00 /* System Call! */
+ && ((int)regs->result == -ERESTARTNOHAND ||
+ ((int)regs->result == -ERESTARTSYS &&
+ !(ka->sa.sa_flags & SA_RESTART))))
+ regs->result = -EINTR;
+
+ /* Put another sigcontext on the stack */
+ *newspp -= sizeof(*sc);
+ sc = (struct sigcontext_struct *) *newspp;
+ if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
+ goto badframe;
+
+ if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler)
+ || __put_user(oldset->sig[0], &sc->oldmask)
+#if _NSIG_WORDS > 1
+ || __put_user(oldset->sig[1], &sc->_unused[3])
+#endif
+ || __put_user((struct pt_regs *)frame, &sc->regs)
+ || __put_user(sig, &sc->signal))
+ goto badframe;
+
+ if (ka->sa.sa_flags & SA_ONESHOT)
+ ka->sa.sa_handler = SIG_DFL;
+
+ if (!(ka->sa.sa_flags & SA_NODEFER)) {
+ spin_lock_irq(&current->sigmask_lock);
+ sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+ sigaddset(&current->blocked,sig);
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+ }
+ return;
+
+badframe:
+#if DEBUG_SIG
+ printk("badframe in handle_signal, regs=%p frame=%lx newsp=%lx\n",
+ regs, frame, *newspp);
+ printk("sc=%p sig=%d ka=%p info=%p oldset=%p\n", sc, sig, ka, info, oldset);
+#endif
+ lock_kernel();
+ do_exit(SIGSEGV);
+}
/*
* Note that 'init' is a special process: it doesn't get signals it doesn't
* want to handle. Thus you cannot kill init even with a SIGKILL even by
* mistake.
- *
- * Note that we go through the signals twice: once to check the signals that
- * the kernel can handle, and then we build all the user-level signal handling
- * stack-frames in one go after that.
*/
-asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
+int do_signal(sigset_t *oldset, struct pt_regs *regs)
{
- unsigned long mask;
- unsigned long handler_signal = 0;
- unsigned long *frame = NULL;
- unsigned long *trampoline;
- unsigned long *regs_ptr;
- double *fpregs_ptr;
- unsigned long nip = 0;
- unsigned long signr;
- struct sigcontext_struct *sc;
- struct sigaction * sa;
- int bitno;
-
- mask = ~current->blocked;
- while ((signr = current->signal & mask)) {
-#if 0
- signr = ffz(~signr); /* Compute bit # */
-#else
- for (bitno = 0; bitno < 32; bitno++)
- if (signr & (1<<bitno))
- break;
- signr = bitno;
-#endif
- current->signal &= ~(1<<signr); /* Clear bit */
- sa = current->sig->action + signr;
- signr++;
+ siginfo_t info;
+ struct k_sigaction *ka;
+ unsigned long frame, newsp;
+
+ if (!oldset)
+ oldset = &current->blocked;
+
+ newsp = frame = regs->gpr[1] - sizeof(struct sigregs);
+
+ for (;;) {
+ unsigned long signr;
+
+ spin_lock_irq(&current->sigmask_lock);
+ signr = dequeue_signal(&current->blocked, &info);
+ spin_unlock_irq(&current->sigmask_lock);
+
+ if (!signr)
+ break;
+
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
+ /* Let the debugger run. */
current->exit_code = signr;
current->state = TASK_STOPPED;
notify_parent(current, SIGCHLD);
schedule();
+
+ /* We're back. Did the debugger cancel the sig? */
if (!(signr = current->exit_code))
continue;
current->exit_code = 0;
+
+ /* The debugger continued. Ignore SIGSTOP. */
if (signr == SIGSTOP)
continue;
- if (_S(signr) & current->blocked) {
- current->signal |= _S(signr);
- spin_lock_irq(&current->sigmask_lock);
- spin_unlock_irq(&current->sigmask_lock);
+
+ /* Update the siginfo structure. Is this good? */
+ if (signr != info.si_signo) {
+ info.si_signo = signr;
+ info.si_errno = 0;
+ info.si_code = SI_USER;
+ info.si_pid = current->p_pptr->pid;
+ info.si_uid = current->p_pptr->uid;
+ }
+
+ /* If the (new) signal is now blocked, requeue it. */
+ if (sigismember(&current->blocked, signr)) {
+ send_sig_info(signr, &info, current);
continue;
}
- sa = current->sig->action + signr - 1;
}
- if (sa->sa_handler == SIG_IGN) {
+
+ ka = &current->sig->action[signr-1];
+ if (ka->sa.sa_handler == SIG_IGN) {
if (signr != SIGCHLD)
continue;
- /* check for SIGCHLD: it's special */
- while (sys_waitpid(-1,NULL,WNOHANG) > 0)
+ /* Check for SIGCHLD: it's special. */
+ while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
/* nothing */;
continue;
}
- if (sa->sa_handler == SIG_DFL) {
+
+ if (ka->sa.sa_handler == SIG_DFL) {
+ int exit_code = signr;
+
+ /* Init gets no signals it doesn't want. */
if (current->pid == 1)
continue;
+
switch (signr) {
case SIGCONT: case SIGCHLD: case SIGWINCH:
continue;
@@ -225,49 +415,37 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
case SIGTSTP: case SIGTTIN: case SIGTTOU:
if (is_orphaned_pgrp(current->pgrp))
continue;
+ /* FALLTHRU */
+
case SIGSTOP:
- if (current->flags & PF_PTRACED)
- continue;
current->state = TASK_STOPPED;
current->exit_code = signr;
- if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
- SA_NOCLDSTOP))
+ if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
notify_parent(current, SIGCHLD);
schedule();
continue;
case SIGQUIT: case SIGILL: case SIGTRAP:
- case SIGIOT: case SIGFPE: case SIGSEGV:
+ case SIGABRT: case SIGFPE: case SIGSEGV:
lock_kernel();
- if (current->binfmt && current->binfmt->core_dump) {
- if (current->binfmt->core_dump(signr, regs))
- signr |= 0x80;
- }
+ if (current->binfmt
+ && current->binfmt->core_dump
+ && current->binfmt->core_dump(signr, regs))
+ exit_code |= 0x80;
unlock_kernel();
- /* fall through */
- default:
- spin_lock_irq(&current->sigmask_lock);
- current->signal |= _S(signr & 0x7f);
- spin_unlock_irq(&current->sigmask_lock);
+ /* FALLTHRU */
+ default:
+ lock_kernel();
+ sigaddset(&current->signal, signr);
current->flags |= PF_SIGNALED;
-
- lock_kernel(); /* 8-( */
- do_exit(signr);
- unlock_kernel();
+ do_exit(exit_code);
+ /* NOTREACHED */
}
}
- /*
- * OK, we're invoking a handler
- */
- if (regs->trap == 0x0C00 /* System Call! */) {
- if ((int)regs->result == -ERESTARTNOHAND ||
- ((int)regs->result == -ERESTARTSYS &&
- !(sa->sa_flags & SA_RESTART)))
- (int)regs->result = -EINTR;
- }
- handler_signal |= 1 << (signr-1);
- mask &= ~sa->sa_mask;
+
+ /* Whee! Actually deliver the signal. */
+ handle_signal(signr, ka, &info, oldset, regs, &newsp, frame);
}
if (regs->trap == 0x0C00 /* System Call! */ &&
@@ -275,91 +453,13 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
(int)regs->result == -ERESTARTSYS ||
(int)regs->result == -ERESTARTNOINTR)) {
regs->gpr[3] = regs->orig_gpr3;
- regs->nip -= 4; /* Back up & retry system call */
+ regs->nip -= 4; /* Back up & retry system call */
regs->result = 0;
}
- if (!handler_signal) /* no handler will be called - return 0 */
- return 0;
-
- nip = regs->nip;
- frame = (unsigned long *) regs->gpr[1];
-
- /*
- * Build trampoline code on stack, and save gp and fp regs.
- * The 56 word hole is because programs using the rs6000/xcoff
- * style calling sequence can save up to 19 gp regs and 18 fp regs
- * on the stack before decrementing sp.
- */
- frame -= 2 + 56;
- trampoline = frame;
- frame -= ELF_NFPREG * sizeof(double) / sizeof(unsigned long);
- fpregs_ptr = (double *) frame;
- frame -= ELF_NGREG;
- regs_ptr = frame;
- /* verify stack is valid for writing to */
- if (verify_area(VERIFY_WRITE, frame,
- (ELF_NGREG + 2) * sizeof(long)
- + ELF_NFPREG * sizeof(double)))
- goto badframe;
- if (last_task_used_math == current)
- giveup_fpu();
- if (__copy_to_user(regs_ptr, regs,
- MIN(sizeof(elf_gregset_t),sizeof(struct pt_regs)))
- || __copy_to_user(fpregs_ptr, current->tss.fpr,
- ELF_NFPREG * sizeof(double))
- || __put_user(0x38007777UL, trampoline) /* li r0,0x7777 */
- || __put_user(0x44000002UL, trampoline+1)) /* sc */
- goto badframe;
-
- signr = 1;
- sa = current->sig->action;
-
- for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
- if (mask > handler_signal)
- break;
- if (!(mask & handler_signal))
- continue;
+ if (newsp == frame)
+ return 0; /* no signals delivered */
- frame -= sizeof(struct sigcontext_struct) / sizeof(long);
- if (verify_area(VERIFY_WRITE, frame,
- sizeof(struct sigcontext_struct)))
- goto badframe;
- sc = (struct sigcontext_struct *)frame;
- nip = (unsigned long) sa->sa_handler;
- if (sa->sa_flags & SA_ONESHOT)
- sa->sa_handler = NULL;
- if (__put_user(nip, &sc->handler)
- || __put_user(oldmask, &sc->oldmask)
- || __put_user(regs_ptr, &sc->regs)
- || __put_user(signr, &sc->signal))
- goto badframe;
- current->blocked |= sa->sa_mask;
- regs->gpr[3] = signr;
- regs->gpr[4] = (unsigned long) regs_ptr;
- }
-
- frame -= __SIGNAL_FRAMESIZE / sizeof(unsigned long);
- if (put_user(regs->gpr[1], frame))
- goto badframe;
- regs->link = (unsigned long)trampoline;
- regs->nip = nip;
- regs->gpr[1] = (unsigned long) frame;
-
- /* The DATA cache must be flushed here to insure coherency */
- /* between the DATA & INSTRUCTION caches. Since we just */
- /* created an instruction stream using the DATA [cache] space */
- /* and since the instruction cache will not look in the DATA */
- /* cache for new data, we have to force the data to go on to */
- /* memory and flush the instruction cache to force it to look */
- /* there. The following function performs this magic */
- flush_icache_range((unsigned long) trampoline,
- (unsigned long) (trampoline + 2));
+ setup_frame(regs, (struct sigregs *) frame, newsp);
return 1;
-
-badframe:
- lock_kernel();
- do_exit(SIGSEGV);
- unlock_kernel();
- return 0;
}
diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c
new file mode 100644
index 000000000..33d3a23b4
--- /dev/null
+++ b/arch/ppc/kernel/smp.c
@@ -0,0 +1,181 @@
+/*
+ * $Id: smp.c,v 1.8 1998/01/06 06:44:57 cort Exp $
+ *
+ * Smp support for ppc.
+ *
+ * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great
+ * deal of code from the sparc and intel versions.
+ */
+
+
+#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>
+#include <linux/kernel_stat.h>
+#include <linux/delay.h>
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.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>
+
+int smp_threads_ready = 0;
+volatile int smp_commenced = 0;
+int smp_num_cpus = 1;
+unsigned long cpu_present_map = 0;
+volatile int cpu_number_map[NR_CPUS];
+volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
+static unsigned char boot_cpu_id = 0;
+struct cpuinfo_PPC cpu_data[NR_CPUS];
+struct klock_info klock_info = { KLOCK_CLEAR, 0 };
+volatile unsigned char active_kernel_processor = NO_PROC_ID; /* Processor holding kernel spinlock */
+
+volatile unsigned long hash_table_lock;
+
+int start_secondary(void *);
+
+extern void init_IRQ(void);
+extern int cpu_idle(void *unused);
+
+void smp_boot_cpus(void)
+{
+ extern unsigned long secondary_entry[];
+ extern struct task_struct *current_set[NR_CPUS];
+ int i, timeout;
+ struct task_struct *p;
+
+ printk("Entering SMP Mode...\n");
+ cpu_present_map = 0;
+ for(i=0; i < NR_CPUS; i++)
+ cpu_number_map[i] = -1;
+
+ smp_store_cpu_info(boot_cpu_id);
+ active_kernel_processor = boot_cpu_id;
+ current->processor = boot_cpu_id;
+
+ cpu_present_map |= 1;
+ /* assume a 2nd processor for now */
+ cpu_present_map |= (1 << 1);
+ smp_num_cpus = 2;
+ cpu_number_map[boot_cpu_id] = 0;
+
+ /* create a process for second processor */
+ kernel_thread(start_secondary, NULL, CLONE_PID);
+ cpu_number_map[1] = 1;
+ p = task[1];
+ if ( !p )
+ panic("No idle task for secondary processor\n");
+ p->processor = 1;
+ current_set[1] = p;
+ /* setup entry point of secondary processor */
+ *(volatile unsigned long *)(0xf2800000)
+ = (unsigned long)secondary_entry-KERNELBASE;
+ /* interrupt secondary to begin executing code */
+ eieio();
+ *(volatile unsigned long *)(0xf80000c0) = 0;
+ eieio();
+ /* wait to see if the secondary made a callin (is actually up) */
+ for ( timeout = 0; timeout < 1500 ; timeout++ )
+ udelay(100);
+ if(cpu_callin_map[1]) {
+ cpu_number_map[1] = 1;
+ printk("Processor 1 found.\n");
+ } else {
+ smp_num_cpus--;
+ printk("Processor %d is stuck.\n", 1);
+ }
+{
+ extern unsigned long amhere;
+ printk("amhere: %x\n", amhere);
+}
+}
+
+void smp_commence(void)
+{
+ printk("SMP %d: smp_commence()\n",current->processor);
+ /*
+ * Lets the callin's below out of their loop.
+ */
+ local_flush_tlb_all();
+ smp_commenced = 1;
+ local_flush_tlb_all();
+}
+
+/* intel needs this */
+void initialize_secondary(void)
+{
+}
+
+/* Activate a secondary processor. */
+int start_secondary(void *unused)
+{
+ printk("SMP %d: start_secondary()\n",current->processor);
+ smp_callin();
+ return cpu_idle(NULL);
+}
+
+void smp_callin(void)
+{
+ printk("SMP %d: smp_callin()\n",current->processor);
+ /*calibrate_delay();*/
+ smp_store_cpu_info(1);
+
+ /* assume we're just the secondary processor for now */
+ cpu_callin_map[1] = 1;
+ dcbf(&cpu_callin_map[1]);
+
+ 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;
+
+ while(!smp_commenced)
+ barrier();
+ __sti();
+}
+
+void smp_setup(char *str, int *ints)
+{
+ printk("SMP %d: smp_setup()\n",current->processor);
+}
+
+void smp_message_pass(int target, int msg, unsigned long data, int wait)
+{
+ printk("SMP %d: sending smp message\n",current->processor);
+#if 0
+ if ( smp_processor_id() == 0 )
+ {
+ /* interrupt secondary */
+ *(volatile unsigned long *)(0xf80000c0) = 0;
+ }
+ else
+ {
+ /* interrupt primary */
+ *(volatile unsigned long *)(0xf3019000);
+ }
+#endif
+}
+
+int setup_profiling_timer(unsigned int multiplier)
+{
+ return 0;
+}
+
+__initfunc(void smp_store_cpu_info(int id))
+{
+ struct cpuinfo_PPC *c = &cpu_data[id];
+
+ c->loops_per_sec = loops_per_sec;
+ c->pvr = _get_PVR();
+}
+
diff --git a/arch/ppc/kernel/syscalls.c b/arch/ppc/kernel/syscalls.c
index b7bac7a6a..91a8d0ccf 100644
--- a/arch/ppc/kernel/syscalls.c
+++ b/arch/ppc/kernel/syscalls.c
@@ -32,6 +32,8 @@
#include <linux/mman.h>
#include <linux/sys.h>
#include <linux/ipc.h>
+#include <linux/utsname.h>
+
#include <asm/uaccess.h>
#include <asm/ipc.h>
@@ -149,7 +151,7 @@ sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
break;
}
case 1: /* iBCS2 emulator entry point */
- if (get_fs() != get_ds())
+ if (!segment_eq(get_fs(), get_ds()))
break;
ret = sys_shmat (first, (char *) ptr, second,
(ulong *) third);
@@ -206,7 +208,8 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
goto out;
}
- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+
+ /*flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);*/
ret = do_mmap(file, addr, len, prot, flags, offset);
out:
unlock_kernel();
@@ -237,3 +240,41 @@ ppc_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
}
return sys_select(n, inp, outp, exp, tvp);
}
+
+asmlinkage int sys_pause(void)
+{
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ return -ERESTARTNOHAND;
+}
+
+asmlinkage int sys_uname(struct old_utsname * name)
+{
+ if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
+ return 0;
+ return -EFAULT;
+}
+
+asmlinkage int sys_olduname(struct oldold_utsname * name)
+{
+ int error;
+
+ if (!name)
+ return -EFAULT;
+ if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
+ return -EFAULT;
+
+ error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
+ error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
+ error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
+ error -= __put_user(0,name->nodename+__OLD_UTS_LEN);
+ error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
+ error -= __put_user(0,name->release+__OLD_UTS_LEN);
+ error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
+ error -= __put_user(0,name->version+__OLD_UTS_LEN);
+ error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
+ error = __put_user(0,name->machine+__OLD_UTS_LEN);
+ error = error ? -EFAULT : 0;
+
+ return error;
+}
diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c
index fc172d7a7..319db15de 100644
--- a/arch/ppc/kernel/time.c
+++ b/arch/ppc/kernel/time.c
@@ -1,12 +1,11 @@
/*
- * $Id: time.c,v 1.10 1997/08/27 22:06:56 cort Exp $
+ * $Id: time.c,v 1.17 1997/12/28 22:47:21 paulus Exp $
* Common time routines among all ppc machines.
*
* Written by Cort Dougan (cort@cs.nmt.edu) to merge
* Paul Mackerras' version and mine for PReP and Pmac.
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -41,22 +40,6 @@ unsigned decrementer_count; /* count value for 1e6/HZ microseconds */
unsigned count_period_num; /* 1 decrementer count equals */
unsigned count_period_den; /* count_period_num / count_period_den us */
-/* Accessor functions for the decrementer register. */
-inline unsigned long
-get_dec(void)
-{
- int ret;
-
- asm volatile("mfspr %0,22" : "=r" (ret) :);
- return ret;
-}
-
-inline void
-set_dec(int val)
-{
- asm volatile("mtspr 22,%0" : : "r" (val));
-}
-
/*
* timer_interrupt - gets called when the decrementer overflows,
* with interrupts disabled.
@@ -125,22 +108,6 @@ void do_settimeofday(struct timeval *tv)
void
time_init(void)
{
- /* pmac hasn't yet called via_cuda_init() */
- if ( _machine != _MACH_Pmac )
- {
-
- if ( _machine == _MACH_chrp )
- xtime.tv_sec = chrp_get_rtc_time();
- else /* assume prep */
- xtime.tv_sec = prep_get_rtc_time();
- xtime.tv_usec = 0;
- /*
- * mark the rtc/on-chip timer as in sync
- * so we don't update right away
- */
- last_rtc_update = xtime.tv_sec;
- }
-
if ((_get_PVR() >> 16) == 1) {
/* 601 processor: dec counts down by 128 every 128ns */
decrementer_count = DECREMENTER_COUNT_601;
@@ -148,22 +115,35 @@ time_init(void)
count_period_den = COUNT_PERIOD_DEN_601;
}
- switch (_machine)
- {
+ switch (_machine) {
case _MACH_Pmac:
- pmac_calibrate_decr();
+ /* can't call pmac_get_rtc_time() yet,
+ because via-cuda isn't initialized yet. */
+ if ((_get_PVR() >> 16) != 1)
+ pmac_calibrate_decr();
set_rtc_time = pmac_set_rtc_time;
break;
- case _MACH_IBM:
- case _MACH_Motorola:
- prep_calibrate_decr();
- set_rtc_time = prep_set_rtc_time;
- break;
case _MACH_chrp:
- chrp_calibrate_decr();
+ chrp_time_init();
+ xtime.tv_sec = chrp_get_rtc_time();
+ if ((_get_PVR() >> 16) != 1)
+ chrp_calibrate_decr();
set_rtc_time = chrp_set_rtc_time;
break;
+ case _MACH_prep:
+ xtime.tv_sec = prep_get_rtc_time();
+ prep_calibrate_decr();
+ set_rtc_time = prep_set_rtc_time;
+ break;
}
+ xtime.tv_usec = 0;
+
+ /*
+ * mark the rtc/on-chip timer as in sync
+ * so we don't update right away
+ */
+ last_rtc_update = xtime.tv_sec;
+
set_dec(decrementer_count);
}
@@ -180,7 +160,7 @@ void prep_calibrate_decr(void)
unsigned long flags;
save_flags(flags);
-
+
#define TIMER0_COUNT 0x40
#define TIMER_CONTROL 0x43
/* set timer to periodic mode */
@@ -199,7 +179,7 @@ void prep_calibrate_decr(void)
void prep_calibrate_decr_handler(int irq, void *dev, struct pt_regs * regs)
{
- int freq, divisor;
+ unsigned long freq, divisor;
static unsigned long t1 = 0, t2 = 0;
if ( !t1 )
@@ -209,9 +189,14 @@ void prep_calibrate_decr_handler(int irq, void *dev, struct pt_regs * regs)
t2 = get_dec();
t2 = t1-t2; /* decr's in 1/HZ */
t2 = t2*HZ; /* # decrs in 1s - thus in Hz */
+if ( (t2>>20) > 100 )
+{
+ printk("Decrementer frequency too high: %luMHz. Using 15MHz.\n",t2>>20);
+ t2 = 998700000/60;
+}
freq = t2 * 60; /* try to make freq/1e6 an integer */
divisor = 60;
- printk("time_init: decrementer frequency = %d/%d (%luMHz)\n",
+ printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n",
freq, divisor,t2>>20);
decrementer_count = freq / HZ / divisor;
count_period_num = divisor;
@@ -220,19 +205,6 @@ void prep_calibrate_decr_handler(int irq, void *dev, struct pt_regs * regs)
}
}
-void chrp_calibrate_decr(void)
-{
- int freq, fp, divisor;
-
- fp = 16666000; /* hardcoded for now */
- freq = fp*60; /* try to make freq/1e6 an integer */
- divisor = 60;
- printk("time_init: decrementer frequency = %d/%d\n", freq, divisor);
- decrementer_count = freq / HZ / divisor;
- count_period_num = divisor;
- count_period_den = freq / 1000000;
-}
-
/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
* Assumes input in normal date format, i.e. 1980-12-31 23:59:59
@@ -249,9 +221,9 @@ void chrp_calibrate_decr(void)
* machines were long is 32-bit! (However, as time_t is signed, we
* will already get problems at other places on 2038-01-19 03:14:08)
*/
-inline unsigned long mktime(unsigned int year, unsigned int mon,
- unsigned int day, unsigned int hour,
- unsigned int min, unsigned int sec)
+unsigned long mktime(unsigned int year, unsigned int mon,
+ unsigned int day, unsigned int hour,
+ unsigned int min, unsigned int sec)
{
if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */
@@ -266,3 +238,45 @@ inline unsigned long mktime(unsigned int year, unsigned int mon,
)*60 + sec; /* finally seconds */
}
+#define TICK_SIZE tick
+#define FEBRUARY 2
+#define STARTOFTIME 1970
+#define SECDAY 86400L
+#define SECYR (SECDAY * 365)
+#define leapyear(year) ((year) % 4 == 0)
+#define days_in_year(a) (leapyear(a) ? 366 : 365)
+#define days_in_month(a) (month_days[(a) - 1])
+
+static int month_days[12] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+void to_tm(int tim, struct rtc_time * tm)
+{
+ register int i;
+ register long hms, day;
+
+ day = tim / SECDAY;
+ hms = tim % SECDAY;
+
+ /* Hours, minutes, seconds are easy */
+ tm->tm_hour = hms / 3600;
+ tm->tm_min = (hms % 3600) / 60;
+ tm->tm_sec = (hms % 3600) % 60;
+
+ /* Number of years in days */
+ for (i = STARTOFTIME; day >= days_in_year(i); i++)
+ day -= days_in_year(i);
+ tm->tm_year = i;
+
+ /* Number of months in days left */
+ if (leapyear(tm->tm_year))
+ days_in_month(FEBRUARY) = 29;
+ for (i = 1; day >= days_in_month(i); i++)
+ day -= days_in_month(i);
+ days_in_month(FEBRUARY) = 28;
+ tm->tm_mon = i;
+
+ /* Days are what is left over (+1) from all that. */
+ tm->tm_mday = day + 1;
+}
diff --git a/arch/ppc/kernel/time.h b/arch/ppc/kernel/time.h
index 9ce5921dc..538ac7bb1 100644
--- a/arch/ppc/kernel/time.h
+++ b/arch/ppc/kernel/time.h
@@ -1,5 +1,5 @@
/*
- * $Id: time.h,v 1.5 1997/08/27 22:06:58 cort Exp $
+ * $Id: time.h,v 1.7 1997/12/28 22:47:24 paulus Exp $
* Common time prototypes and such for all ppc machines.
*
* Written by Cort Dougan (cort@cs.nmt.edu) to merge
@@ -9,17 +9,16 @@
#include <linux/mc146818rtc.h>
/* time.c */
-__inline__ unsigned long get_dec(void);
-__inline__ void set_dec(int val);
void prep_calibrate_decr_handler(int, void *,struct pt_regs *);
void prep_calibrate_decr(void);
void pmac_calibrate_decr(void);
-void chrp_calibrate_decr(void);
extern unsigned decrementer_count;
extern unsigned count_period_num;
extern unsigned count_period_den;
extern unsigned long mktime(unsigned int, unsigned int,unsigned int,
- 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;
/* pmac/prep/chrp_time.c */
unsigned long prep_get_rtc_time(void);
@@ -29,46 +28,19 @@ int prep_set_rtc_time(unsigned long nowtime);
int pmac_set_rtc_time(unsigned long nowtime);
int chrp_set_rtc_time(unsigned long nowtime);
void pmac_read_rtc_time(void);
+void chrp_calibrate_decr(void);
+void chrp_time_init(void);
-#define TICK_SIZE tick
-#define FEBRUARY 2
-#define STARTOFTIME 1970
-#define SECDAY 86400L
-#define SECYR (SECDAY * 365)
-#define leapyear(year) ((year) % 4 == 0)
-#define days_in_year(a) (leapyear(a) ? 366 : 365)
-#define days_in_month(a) (month_days[(a) - 1])
-
-static int month_days[12] = {
- 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
-};
-
-extern void inline to_tm(int tim, struct rtc_time * tm)
+/* Accessor functions for the decrementer register. */
+static __inline__ unsigned int get_dec(void)
{
- register int i;
- register long hms, day;
-
- day = tim / SECDAY;
- hms = tim % SECDAY;
+ unsigned int ret;
- /* Hours, minutes, seconds are easy */
- tm->tm_hour = hms / 3600;
- tm->tm_min = (hms % 3600) / 60;
- tm->tm_sec = (hms % 3600) % 60;
-
- /* Number of years in days */
- for (i = STARTOFTIME; day >= days_in_year(i); i++)
- day -= days_in_year(i);
- tm->tm_year = i;
-
- /* Number of months in days left */
- if (leapyear(tm->tm_year))
- days_in_month(FEBRUARY) = 29;
- for (i = 1; day >= days_in_month(i); i++)
- day -= days_in_month(i);
- days_in_month(FEBRUARY) = 28;
- tm->tm_mon = i;
+ asm volatile("mfspr %0,22" : "=r" (ret) :);
+ return ret;
+}
- /* Days are what is left over (+1) from all that. */
- tm->tm_mday = day + 1;
+static __inline__ void set_dec(unsigned int val)
+{
+ asm volatile("mtspr 22,%0" : : "r" (val));
}
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
index edfcb4d63..7199dd5c1 100644
--- a/arch/ppc/kernel/traps.c
+++ b/arch/ppc/kernel/traps.c
@@ -61,10 +61,10 @@ _exception(int signr, struct pt_regs *regs)
if (!user_mode(regs))
{
show_regs(regs);
- print_backtrace((unsigned long *)regs->gpr[1]);
#ifdef CONFIG_XMON
xmon(regs);
#endif
+ print_backtrace((unsigned long *)regs->gpr[1]);
panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
}
force_sig(signr, current);
@@ -103,10 +103,10 @@ MachineCheckException(struct pt_regs *regs)
printk("Unknown values in msr\n");
}
show_regs(regs);
- print_backtrace((unsigned long *)regs->gpr[1]);
#ifdef CONFIG_XMON
xmon(regs);
#endif
+ print_backtrace((unsigned long *)regs->gpr[1]);
panic("machine check");
}
_exception(SIGSEGV, regs);
@@ -186,15 +186,16 @@ AlignmentException(struct pt_regs *regs)
}
void
-PromException(struct pt_regs *regs, int trap)
+StackOverflow(struct pt_regs *regs)
{
- regs->trap = trap;
+ printk(KERN_CRIT "Kernel stack overflow in process %p, r1=%lx\n",
+ current, regs->gpr[1]);
#ifdef CONFIG_XMON
xmon(regs);
#endif
- printk("Exception %lx in prom at PC: %lx, SR: %lx\n",
- regs->trap, regs->nip, regs->msr);
- /* probably should turn up the toes here */
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("kernel stack overflow");
}
void