diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-03-17 22:05:47 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-03-17 22:05:47 +0000 |
commit | 27cfca1ec98e91261b1a5355d10a8996464b63af (patch) | |
tree | 8e895a53e372fa682b4c0a585b9377d67ed70d0e /arch/ppc/kernel | |
parent | 6a76fb7214c477ccf6582bd79c5b4ccc4f9c41b1 (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')
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 = ¤t->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(¤t->sigmask_lock); - mask = current->blocked; - current->blocked = set & _BLOCKABLE; + saveset = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(current); spin_unlock_irq(¤t->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(¤t->sigmask_lock); + saveset = current->blocked; + current->blocked = newset; + recalc_sigpending(current); + spin_unlock_irq(¤t->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(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->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(¤t->sigmask_lock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigaddset(¤t->blocked,sig); + recalc_sigpending(current); + spin_unlock_irq(¤t->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 = ¤t->blocked; + + newsp = frame = regs->gpr[1] - sizeof(struct sigregs); + + for (;;) { + unsigned long signr; + + spin_lock_irq(¤t->sigmask_lock); + signr = dequeue_signal(¤t->blocked, &info); + spin_unlock_irq(¤t->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(¤t->sigmask_lock); - spin_unlock_irq(¤t->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(¤t->blocked, signr)) { + send_sig_info(signr, &info, current); continue; } - sa = current->sig->action + signr - 1; } - if (sa->sa_handler == SIG_IGN) { + + ka = ¤t->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(¤t->sigmask_lock); - current->signal |= _S(signr & 0x7f); - spin_unlock_irq(¤t->sigmask_lock); + /* FALLTHRU */ + default: + lock_kernel(); + sigaddset(¤t->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 |