diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-01-04 16:03:48 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-01-04 16:03:48 +0000 |
commit | 78c388aed2b7184182c08428db1de6c872d815f5 (patch) | |
tree | 4b2003b1b4ceb241a17faa995da8dd1004bb8e45 /arch/ppc/kernel | |
parent | eb7a5bf93aaa4be1d7c6181100ab7639e74d67f7 (diff) |
Merge with Linux 2.1.131 and more MIPS goodies.
(Did I mention that CVS is buggy ...)
Diffstat (limited to 'arch/ppc/kernel')
29 files changed, 2853 insertions, 912 deletions
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index 6f1060560..4846d5ebb 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -11,11 +11,11 @@ $(CC) $(CFLAGS) -D__ASSEMBLY__ -c $< -o $*.o O_TARGET := kernel.o -OX_OBJS := ppc_ksyms.o +OX_OBJS := ppc_ksyms.o setup.o O_OBJS := traps.o irq.o idle.o time.o process.o signal.o syscalls.o misc.o \ - bitops.o setup.o ptrace.o align.o ppc_htab.o + bitops.o ptrace.o align.o ppc_htab.o feature.o ifdef CONFIG_PCI O_OBJS += pci.o @@ -23,6 +23,9 @@ endif ifdef CONFIG_KGDB O_OBJS += ppc-stub.o endif +ifdef CONFIG_TOTALMP +O_OBJS += totalmp.o +endif ifeq ($(CONFIG_MBX),y) O_OBJS += mbx_setup.o mbx_pci.o softemu8xx.o @@ -31,10 +34,10 @@ ifeq ($(CONFIG_APUS),y) O_OBJS += apus_setup.o prom.o openpic.o else O_OBJS += prep_time.o pmac_time.o chrp_time.o \ - pmac_setup.o pmac_support.o chrp_setup.o \ + pmac_setup.o pmac_support.o \ prep_pci.o pmac_pci.o chrp_pci.o \ residual.o prom.o openpic.o -OX_OBJS += prep_setup.o +OX_OBJS += chrp_setup.o prep_setup.o endif endif diff --git a/arch/ppc/kernel/align.c b/arch/ppc/kernel/align.c index 70284674b..83ee7756d 100644 --- a/arch/ppc/kernel/align.c +++ b/arch/ppc/kernel/align.c @@ -265,7 +265,7 @@ fix_alignment(struct pt_regs *regs) #else giveup_fpu(); #endif - cvt_fd(&data.f, ¤t->tss.fpr[reg]); + cvt_fd(&data.f, ¤t->tss.fpr[reg], ¤t->tss.fpscr); /* current->tss.fpr[reg] = data.f; */ break; case ST+F+S: @@ -275,7 +275,7 @@ fix_alignment(struct pt_regs *regs) #else giveup_fpu(); #endif - cvt_df(¤t->tss.fpr[reg], &data.f); + cvt_df(¤t->tss.fpr[reg], &data.f, ¤t->tss.fpscr); /* data.f = current->tss.fpr[reg]; */ break; default: diff --git a/arch/ppc/kernel/apus_setup.c b/arch/ppc/kernel/apus_setup.c index ea2bc5690..93c2fe2d1 100644 --- a/arch/ppc/kernel/apus_setup.c +++ b/arch/ppc/kernel/apus_setup.c @@ -19,6 +19,7 @@ #include <asm/amigahw.h> #include <asm/amigappc.h> #include <asm/pgtable.h> +#include <asm/io.h> unsigned long m68k_machtype; char debug_device[6] = ""; @@ -60,6 +61,8 @@ extern struct mem_info memory[NUM_MEMINFO];/* memory description */ extern void amiga_floppy_setup(char *, int *); extern void config_amiga(void); +static int __60nsram = 0; + /*********************************************************** SETUP */ /* From arch/m68k/kernel/setup.c. */ __initfunc(void apus_setup_arch(unsigned long * memory_start_p, @@ -75,10 +78,17 @@ __initfunc(void apus_setup_arch(unsigned long * memory_start_p, for( p = cmd_line; p && *p; ) { i = 0; if (!strncmp( p, "debug=", 6 )) { - strncpy( debug_device, p+6, sizeof(debug_device)-1 ); - debug_device[sizeof(debug_device)-1] = 0; - if ((q = strchr( debug_device, ' ' ))) *q = 0; - i = 1; + strncpy( debug_device, p+6, sizeof(debug_device)-1 ); + debug_device[sizeof(debug_device)-1] = 0; + if ((q = strchr( debug_device, ' ' ))) *q = 0; + i = 1; + } else if (!strncmp( p, "60nsram", 7 )) { + APUS_WRITE (APUS_REG_WAITSTATE, + REGWAITSTATE_SETRESET + |REGWAITSTATE_PPCR + |REGWAITSTATE_PPCW); + __60nsram = 1; + i = 1; } if (i) { @@ -95,63 +105,85 @@ __initfunc(void apus_setup_arch(unsigned long * memory_start_p, config_amiga(); } + +void get_current_tb(unsigned long long *time) +{ + __asm __volatile ("1:mftbu 4 \n\t" + " mftb 5 \n\t" + " mftbu 6 \n\t" + " cmpw 4,6 \n\t" + " bne 1b \n\t" + " stw 4,0(%0)\n\t" + " stw 5,4(%0)\n\t" + : + : "r" (time) + : "r4", "r5", "r6"); +} + + void apus_calibrate_decr(void) { int freq, divisor; - unsigned char c = *(unsigned char*)ZTWO_VADDR(0xf00011); - switch (c) + /* This algorithm for determining the bus speed was + contributed by Ralph Schmidt. */ + unsigned long long start, stop; + int bus_speed; + { - case 'A': - case 'B': - if (amiga_model == AMI_1200 || amiga_model == AMI_2000){ - freq = 1; - } else { - freq = 0; - } - break; - case 'C': - if (amiga_model == AMI_1200 || amiga_model == AMI_2000){ - freq = 0; - } else { - freq = 1; + unsigned long loop = amiga_eclock / 10; + + get_current_tb (&start); + while (loop--) { + unsigned char tmp; + + tmp = ciaa.pra; } - break; - case 'D': - freq = 1; - break; - default: - freq = 0; - printk (" *Unknown CPU speed ID ('%c')* ", c); - break; + get_current_tb (&stop); + } + + bus_speed = (((unsigned long)(stop-start))*10*4) / 1000000; + if (AMI_1200 == amiga_model) + bus_speed /= 2; + + if ((bus_speed >= 47) && (bus_speed < 53)) { + bus_speed = 50; + freq = 12500000; + } else if ((bus_speed >= 57) && (bus_speed < 63)) { + bus_speed = 60; + freq = 15000000; + } else if ((bus_speed >= 63) && (bus_speed < 69)) { + bus_speed = 66; + freq = 16500000; + } else { + printk ("APUS: Unable to determine bus speed (%d). " + "Defaulting to 50MHz", bus_speed); + bus_speed = 50; + freq = 12500000; } + /* Ease diagnostics... */ { - int speed; - switch (freq) - { - case 0: - freq = 15000000; - speed = 60; - - /* Use status of left mouse button to select - RAM speed. */ - if (!(ciaa.pra & 0x40)) - { - APUS_WRITE (APUS_REG_WAITSTATE, - REGWAITSTATE_SETRESET - |REGWAITSTATE_PPCR - |REGWAITSTATE_PPCW); - printk (" [RAM R/W waitstate removed. " - "(expecting 60ns RAM).] "); + extern int __map_without_bats; + + printk ("APUS: BATs=%d, BUS=%dMHz, RAM=%dns\n", + (__map_without_bats) ? 0 : 1, + bus_speed, + (__60nsram) ? 60 : 70); + + /* print a bit more if asked politely... */ + if (!(ciaa.pra & 0x40)){ + extern unsigned int bat_addrs[4][3]; + int b; + for (b = 0; b < 4; ++b) { + printk ("APUS: BAT%d ", b); + printk ("%08x-%08x -> %08x\n", + bat_addrs[b][0], + bat_addrs[b][1], + bat_addrs[b][2]); } - break; - case 1: - freq = 16500000; - speed = 66; - break; } - printk ("PowerUp Bus Speed: %dMHz\n", speed); + } freq *= 60; /* try to make freq/1e6 an integer */ @@ -222,7 +254,72 @@ unsigned long kernel_map (unsigned long phys_addr, unsigned long size, } return v_ret; } - + +/* From pgtable.h */ +extern __inline__ pte_t *my_find_pte(struct mm_struct *mm,unsigned long va) +{ + pgd_t *dir = 0; + pmd_t *pmd = 0; + pte_t *pte = 0; + + va &= PAGE_MASK; + + dir = pgd_offset( mm, va ); + if (dir) + { + pmd = pmd_offset(dir, va & PAGE_MASK); + if (pmd && pmd_present(*pmd)) + { + pte = pte_offset(pmd, va); + } + } + return pte; +} + + +/* Again simulating an m68k/mm/kmap.c function. */ +void kernel_set_cachemode( unsigned long address, unsigned long size, + unsigned int cmode ) +{ + int mask, flags; + + switch (cmode) + { + case KERNELMAP_FULL_CACHING: + mask = ~(_PAGE_NO_CACHE | _PAGE_GUARDED); + flags = 0; + break; + case KERNELMAP_NOCACHE_SER: + mask = ~0; + flags = (_PAGE_NO_CACHE | _PAGE_GUARDED); + break; + default: + panic ("kernel_set_cachemode() doesn't support mode %d\n", + cmode); + break; + } + + size /= PAGE_SIZE; + address &= PAGE_MASK; + while (size--) + { + pte_t *pte; + + pte = my_find_pte(init_task.mm, address); + if ( !pte ) + { + printk("pte NULL in kernel_set_cachemode()\n"); + return; + } + + pte_val (*pte) &= mask; + pte_val (*pte) |= flags; + flush_tlb_page(find_vma(init_task.mm,address),address); + + address += PAGE_SIZE; + } +} + unsigned long mm_ptov (unsigned long paddr) { unsigned long ret; diff --git a/arch/ppc/kernel/chrp_setup.c b/arch/ppc/kernel/chrp_setup.c index 748a78e00..5b373c876 100644 --- a/arch/ppc/kernel/chrp_setup.c +++ b/arch/ppc/kernel/chrp_setup.c @@ -11,6 +11,7 @@ */ #include <linux/config.h> +#include <linux/module.h> #include <linux/errno.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -29,6 +30,7 @@ #include <linux/blk.h> #include <linux/ioport.h> #include <linux/console.h> +#include <linux/pci.h> #include <asm/mmu.h> #include <asm/processor.h> @@ -37,6 +39,7 @@ #include <asm/ide.h> #include <asm/prom.h> #include <asm/gg2.h> +#include <asm/pci-bridge.h> extern void hydra_init(void); extern void w83c553f_init(void); @@ -189,7 +192,15 @@ chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)) aux_device_present = 0xaa; - ROOT_DEV = to_kdev_t(0x0802); /* sda2 (sda1 is for the kernel) */ +#ifdef CONFIG_BLK_DEV_INITRD + /* this is fine for chrp */ + initrd_below_start_ok = 1; + + if (initrd_start) + ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); + else +#endif + ROOT_DEV = to_kdev_t(0x0802); /* sda2 (sda1 is for the kernel) */ printk("Boot arguments: %s\n", cmd_line); @@ -203,7 +214,6 @@ chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)) /* 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 @@ -215,8 +225,54 @@ chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)) * Fix the Super I/O configuration */ sio_init(); - #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; #endif + /* my starmax 6000 needs this but the longtrail shouldn't do it -- Cort */ + if ( !strncmp("MOT", get_property(find_path_device("/"), + "model", NULL),3) ) + *memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p); +} + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) + +unsigned int chrp_ide_irq = 0; +int chrp_ide_ports_known = 0; +ide_ioreg_t chrp_ide_regbase[MAX_HWIFS]; +ide_ioreg_t chrp_idedma_regbase; + +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++ = port; + if (irq != NULL) + *irq = chrp_ide_irq; } + +void chrp_ide_probe(void) { + + struct pci_dev *pdev = pci_find_device(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, NULL); + + chrp_ide_ports_known = 1; + + if(pdev) { + chrp_ide_regbase[0]=pdev->base_address[0] & + PCI_BASE_ADDRESS_IO_MASK; + chrp_ide_regbase[1]=pdev->base_address[2] & + PCI_BASE_ADDRESS_IO_MASK; + chrp_idedma_regbase=pdev->base_address[4] & + PCI_BASE_ADDRESS_IO_MASK; + chrp_ide_irq=pdev->irq; + } +} + +EXPORT_SYMBOL(chrp_ide_irq); +EXPORT_SYMBOL(chrp_ide_ports_known); +EXPORT_SYMBOL(chrp_ide_regbase); +EXPORT_SYMBOL(chrp_ide_probe); + +#endif diff --git a/arch/ppc/kernel/feature.c b/arch/ppc/kernel/feature.c new file mode 100644 index 000000000..48d8bcb39 --- /dev/null +++ b/arch/ppc/kernel/feature.c @@ -0,0 +1,249 @@ +/* + * arch/ppc/kernel/feature.c + * + * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) + * + * 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/types.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <asm/errno.h> +#include <asm/ohare.h> +#include <asm/io.h> +#include <asm/prom.h> +#include <asm/feature.h> + +#define MAX_FEATURE_REGS 2 +#undef DEBUG_FEATURE + +static u32 feature_bits_pbook[] = { + 0, /* FEATURE_null */ + OH_SCC_RESET, /* FEATURE_Serial_reset */ + OH_SCC_ENABLE, /* FEATURE_Serial_enable */ + OH_SCCA_IO, /* FEATURE_Serial_IO_A */ + OH_SCCB_IO, /* FEATURE_Serial_IO_B */ + OH_FLOPPY_ENABLE, /* FEATURE_SWIM3_enable */ + OH_MESH_ENABLE, /* FEATURE_MESH_enable */ + OH_IDE_ENABLE, /* FEATURE_IDE_enable */ + OH_VIA_ENABLE, /* FEATURE_VIA_enable */ + OH_IDECD_POWER, /* FEATURE_CD_power */ + OH_BAY_RESET, /* FEATURE_Mediabay_reset */ + OH_BAY_ENABLE, /* FEATURE_Mediabay_enable */ + OH_BAY_PCI_ENABLE, /* FEATURE_Mediabay_PCI_enable */ + OH_BAY_IDE_ENABLE, /* FEATURE_Mediabay_IDE_enable */ + OH_BAY_FLOPPY_ENABLE, /* FEATURE_Mediabay_floppy_enable */ + 0, /* FEATURE_BMac_reset */ + 0, /* FEATURE_BMac_IO_enable */ + 0, /* FEATURE_Modem_PowerOn -> guess...*/ + 0 /* FEATURE_Modem_Reset -> guess...*/ +}; + +/* assume these are the same as the ohare until proven otherwise */ +static u32 feature_bits_heathrow[] = { + 0, /* FEATURE_null */ + OH_SCC_RESET, /* FEATURE_Serial_reset */ + OH_SCC_ENABLE, /* FEATURE_Serial_enable */ + OH_SCCA_IO, /* FEATURE_Serial_IO_A */ + OH_SCCB_IO, /* FEATURE_Serial_IO_B */ + OH_FLOPPY_ENABLE, /* FEATURE_SWIM3_enable */ + OH_MESH_ENABLE, /* FEATURE_MESH_enable */ + OH_IDE_ENABLE, /* FEATURE_IDE_enable */ + OH_VIA_ENABLE, /* FEATURE_VIA_enable */ + OH_IDECD_POWER, /* FEATURE_CD_power */ + OH_BAY_RESET, /* FEATURE_Mediabay_reset */ + OH_BAY_ENABLE, /* FEATURE_Mediabay_enable */ + OH_BAY_PCI_ENABLE, /* FEATURE_Mediabay_PCI_enable */ + OH_BAY_IDE_ENABLE, /* FEATURE_Mediabay_IDE_enable */ + OH_BAY_FLOPPY_ENABLE, /* FEATURE_Mediabay_floppy_enable */ + 0x80000000, /* FEATURE_BMac_reset */ + 0x60000000, /* FEATURE_BMac_IO_enable */ + 0x02000000, /* FEATURE_Modem_PowerOn -> guess...*/ + 0x07000000 /* FEATURE_Modem_Reset -> guess...*/ +}; + +/* definition of a feature controller object */ +struct feature_controller +{ + u32* bits; + volatile u32* reg; + struct device_node* device; +}; + +/* static functions */ +static void +feature_add_controller(struct device_node *controller_device, u32* bits); + +static int +feature_lookup_controller(struct device_node *device); + +/* static varialbles */ +static struct feature_controller controllers[MAX_FEATURE_REGS]; +static int controller_count = 0; + + +void +feature_init(void) +{ + struct device_node *np; + + np = find_devices("mac-io"); + while (np != NULL) + { + feature_add_controller(np, feature_bits_heathrow); + np = np->next; + } + if (controller_count == 0) + { + np = find_devices("ohare"); + if (np) + { + if (find_devices("via-pmu") != NULL) + feature_add_controller(np, feature_bits_pbook); + else + /* else not sure; maybe this is a Starmax? */ + feature_add_controller(np, NULL); + } + } + + if (controller_count) + printk(KERN_INFO "Registered %d feature controller(s)\n", controller_count); +} + +static void +feature_add_controller(struct device_node *controller_device, u32* bits) +{ + struct feature_controller* controller; + + if (controller_count >= MAX_FEATURE_REGS) + { + printk(KERN_INFO "Feature controller %s skipped(MAX:%d)\n", + controller_device->full_name, MAX_FEATURE_REGS); + return; + } + controller = &controllers[controller_count]; + + controller->bits = bits; + controller->device = controller_device; + if (controller_device->n_addrs == 0) { + printk(KERN_ERR "No addresses for %s\n", + controller_device->full_name); + return; + } + + controller->reg = (volatile u32 *)ioremap( + controller_device->addrs[0].address + OHARE_FEATURE_REG, 4); + + if (bits == NULL) { + printk(KERN_INFO "Twiddling the magic ohare bits\n"); + out_le32(controller->reg, STARMAX_FEATURES); + return; + } + + controller_count++; +} + +static int +feature_lookup_controller(struct device_node *device) +{ + int i; + + if (device == NULL) + return -EINVAL; + + while(device) + { + for (i=0; i<controller_count; i++) + if (device == controllers[i].device) + return i; + device = device->parent; + } + +#ifdef DEBUG_FEATURE + printk("feature: <%s> not found on any controller\n", + device->name); +#endif + + return -ENODEV; +} + +int +feature_set(struct device_node* device, enum system_feature f) +{ + int controller; + unsigned long flags; + + if (f >= FEATURE_last) + return -EINVAL; + + controller = feature_lookup_controller(device); + if (controller < 0) + return controller; + +#ifdef DEBUG_FEATURE + printk("feature: <%s> setting feature %d in controller @0x%x\n", + device->name, (int)f, (unsigned int)controllers[controller].reg); +#endif + + save_flags(flags); + cli(); + st_le32( controllers[controller].reg, + ld_le32(controllers[controller].reg) | + controllers[controller].bits[f]); + restore_flags(flags); + udelay(10); + + return 0; +} + +int +feature_clear(struct device_node* device, enum system_feature f) +{ + int controller; + unsigned long flags; + + if (f >= FEATURE_last) + return -EINVAL; + + controller = feature_lookup_controller(device); + if (controller < 0) + return controller; + +#ifdef DEBUG_FEATURE + printk("feature: <%s> clearing feature %d in controller @0x%x\n", + device->name, (int)f, (unsigned int)controllers[controller].reg); +#endif + + save_flags(flags); + cli(); + st_le32( controllers[controller].reg, + ld_le32(controllers[controller].reg) & + ~(controllers[controller].bits[f])); + restore_flags(flags); + udelay(10); + + return 0; +} + +int +feature_test(struct device_node* device, enum system_feature f) +{ + int controller; + + if (f >= FEATURE_last) + return -EINVAL; + + controller = feature_lookup_controller(device); + if (controller < 0) + return controller; + + return (ld_le32(controllers[controller].reg) & + controllers[controller].bits[f]) != 0; +} + diff --git a/arch/ppc/kernel/find_name.c b/arch/ppc/kernel/find_name.c index d5d88bff7..3c0fa8e0c 100644 --- a/arch/ppc/kernel/find_name.c +++ b/arch/ppc/kernel/find_name.c @@ -16,7 +16,7 @@ int main(int argc, char **argv) if ( argc < 2 ) { fprintf(stderr, "Usage: %s <address>\n", argv[0]); - exit(-1); + return -1; } for ( i = 1 ; argv[i] ; i++ ) @@ -41,7 +41,7 @@ int main(int argc, char **argv) strcpy( last, s); } - printf( "%s", last); + printf( "%s%s", last, s ); } fclose(f); return 0; diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index a257e7762..4c528beb8 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -1,7 +1,7 @@ /* * arch/ppc/kernel/head.S * - * $Id: head.S,v 1.98 1998/07/26 21:28:48 geert Exp $ + * $Id: head.S,v 1.111 1998/11/10 01:10:32 paulus Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -93,15 +93,18 @@ LG_CACHE_LINE_SIZE = 5 bdnz 0b #endif +/* 601 only have IBAT cr0.eq is set on 601 when using this macro */ #define LOAD_BAT(n, offset, reg, RA, RB) \ lwz RA,offset+0(reg); \ lwz RB,offset+4(reg); \ mtspr IBAT##n##U,RA; \ mtspr IBAT##n##L,RB; \ + beq 1f; \ lwz RA,offset+8(reg); \ lwz RB,offset+12(reg); \ mtspr DBAT##n##U,RA; \ - mtspr DBAT##n##L,RB + mtspr DBAT##n##L,RB; \ +1: #ifndef CONFIG_APUS #define tophys(rd,rs,rt) addis rd,rs,-KERNELBASE@h @@ -139,6 +142,12 @@ _start: * pointer (r1) points to just below the end of the half-meg region * from 0x380000 - 0x400000, which is mapped in already. * + * If we are booted from MacOS via BootX, we enter with the kernel + * image loaded somewhere, and the following values in registers: + * r3: 'BooX' (0x426f6f58) + * r4: virtual address of boot_infos_t + * r5: 0 + * * 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 @@ -201,7 +210,8 @@ __start: mr r27,r7 #ifndef CONFIG_8xx bl prom_init - + .globl __secondary_start +__secondary_start: /* * Use the first pair of BAT registers to map the 1st 16MB * of RAM to KERNELBASE. From this point on we can't safely @@ -213,33 +223,45 @@ __start: lis r11,KERNELBASE@h bne 4f ori r11,r11,4 /* set up BAT registers for 601 */ - li r8,0x7f + li r8,0x7f /* valid, block length = 8MB */ 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 IBAT0U,r11 /* N.B. 601 has valid bit in */ + mtspr IBAT0L,r8 /* lower BAT register */ mtspr IBAT1U,r9 mtspr IBAT1L,r10 b 5f 4: #ifndef CONFIG_APUS - ori r11,r11,0x1ff /* set up BAT registers for 604 */ - li r8,2 + ori r11,r11,0x1fe /* set up BAT registers for 604 */ + li r8,2 /* R/W access */ #else - ori r11,r11,0xff /* set up an 8MB mapping */ + ori r11,r11,0xfe /* set up an 8MB mapping */ lis r8,CYBERBASEp@h lwz r8,0(r8) addis r8,r8,KERNELBASE@h addi r8,r8,2 #endif -5: mtspr DBAT0U,r11 - mtspr DBAT0L,r8 - mtspr IBAT0U,r11 + mtspr DBAT0L,r8 /* N.B. 6xx (not 601) have valid */ + mtspr DBAT0U,r11 /* bit in upper BAT register */ mtspr IBAT0L,r8 - isync + mtspr IBAT0U,r11 +5: isync #ifdef CONFIG_APUS /* Unfortunately the APUS specific instructions bloat the * code so it cannot fit in the 0x100 bytes available. We have * to do it the crude way. */ + + /* Map 0xfff00000 so we can access VTOP/PTOV constant when + MMU is enabled. */ + lis r8,0xfff0 + ori r11,r8,0x2 /* r/w */ + ori r8,r8,0x2 /* 128KB, supervisor */ + mtspr DBAT3U,r8 + mtspr DBAT3L,r11 + + /* Copy exception code to exception vector base. */ lis r3,KERNELBASE@h tophys(r4,r3,r5) lis r3,0xfff0 /* Copy to 0xfff00000 on APUS */ @@ -263,23 +285,10 @@ __start: li r3,0 mfmsr r0 andi. r0,r0,MSR_DR /* MMU enabled? */ - beq 7f + beq relocate_kernel lis r3,KERNELBASE@h /* if so, are we */ cmpw 0,r4,r3 /* already running at KERNELBASE? */ - beq 2f - rlwinm r4,r4,0,8,31 /* translate source address */ - add r4,r4,r3 /* to region mapped with BATs */ -7: addis r9,r26,klimit@ha /* fetch klimit */ - lwz r25,klimit@l(r9) - addis r25,r25,-KERNELBASE@h - li r6,0 /* Destination */ - li r5,0x4000 /* # bytes of memory to copy */ - bl copy_and_flush /* copy the first 0x4000 bytes */ - addi r0,r3,4f@l /* jump to the address of 4f */ - mtctr r0 /* in copy and do the rest. */ - bctr /* jump to the copy */ -4: mr r5,r25 - bl copy_and_flush /* copy the rest */ + bne relocate_kernel 2: #endif /* CONFIG_APUS */ /* @@ -356,6 +365,7 @@ __start: */ #endif /* CONFIG_8xx */ +turn_on_mmu: mfmsr r0 ori r0,r0,MSR_DR|MSR_IR mtspr SRR1,r0 @@ -364,7 +374,7 @@ __start: mtspr SRR0,r0 SYNC rfi /* enables MMU */ - + /* * GCC sometimes accesses words at negative offsets from the stack * pointer, although the SysV ABI says it shouldn't. To cope with @@ -506,7 +516,7 @@ HardwareInterrupt: li r20,(IPLEMU_SETRESET|IPLEMU_DISABLEINT) stb r20,APUS_IPL_EMU@l(r3) - sync + eieio lbz r3,APUS_IPL_EMU@l(r3) @@ -1386,15 +1396,13 @@ hash_page_out: next_slot: .long 0 -/* - * FPU stuff for the 6xx/7xx follows - * -- Cort - */ load_up_fpu: /* * 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. + * On SMP we know the fpu is free, since we give it up every + * switch. -- Cort */ #ifndef CONFIG_APUS lis r6,-KERNELBASE@h @@ -1402,28 +1410,23 @@ load_up_fpu: 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 */ -#ifndef __SMP__ - SYNC - cmpi 0,r4,0 - beq 1f -#else /* * All the saving of last_task_used_math is handled * by a switch_to() call to smp_giveup_fpu() in SMP so * last_task_used_math is not used. - * - * We should never be herre on SMP anyway, sinc ethe fpu should - * always be on. * -- Cort */ - b 1f -#endif +#ifndef __SMP__ + 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) @@ -1432,22 +1435,20 @@ load_up_fpu: lwz r5,PT_REGS(r4) add r5,r5,r6 lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) - li r20,MSR_FP + li r20,MSR_FP|MSR_FE0|MSR_FE1 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 */ +#endif /* __SMP__ */ +1: ori r23,r23,MSR_FP|MSR_FE0|MSR_FE1 /* 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) -/* - * on SMP we don't really use last_task_used_math but set it - * here anyway to avoid the ifdef's -- Cort - */ subi r4,r5,TSS sub r4,r4,r6 +#ifndef __SMP__ stw r4,last_task_used_math@l(r3) +#endif /* __SMP__ */ /* restore registers and return */ lwz r3,_CCR(r21) lwz r4,_LINK(r21) @@ -1507,14 +1508,16 @@ giveup_fpu: cmpi 0,r4,0 beqlr- /* if no previous owner, done */ addi r4,r4,TSS /* want TSS of last_task_used_math */ +#ifndef __SMP__ li r5,0 stw r5,last_task_used_math@l(r3) +#endif /* __SMP__ */ SAVE_32FPRS(0, r4) mffs fr0 stfd fr0,TSS_FPSCR-4(r4) lwz r5,PT_REGS(r4) lwz r3,_MSR-STACK_FRAME_OVERHEAD(r5) - li r4,MSR_FP + li r4,MSR_FP|MSR_FE0|MSR_FE1 andc r3,r3,r4 /* disable FP for previous task */ stw r3,_MSR-STACK_FRAME_OVERHEAD(r5) #else /* CONFIG_8xx */ @@ -1522,7 +1525,31 @@ giveup_fpu: giveup_fpu: #endif /* CONFIG_8xx */ blr - + +/* + * This code is jumped to from the startup code to copy + * the kernel image to physical address 0. + */ +relocate_kernel: + lis r9,0x426f /* if booted from BootX, don't */ + addi r9,r9,0x6f58 /* translate source addr */ + cmpw r31,r9 /* (we have to on chrp) */ + beq 7f + rlwinm r4,r4,0,8,31 /* translate source address */ + add r4,r4,r3 /* to region mapped with BATs */ +7: addis r9,r26,klimit@ha /* fetch klimit */ + lwz r25,klimit@l(r9) + addis r25,r25,-KERNELBASE@h + li r6,0 /* Destination offset */ + li r5,0x4000 /* # bytes of memory to copy */ + bl copy_and_flush /* copy the first 0x4000 bytes */ + addi r0,r3,4f@l /* jump to the address of 4f */ + mtctr r0 /* in copy and do the rest. */ + bctr /* jump to the copy */ +4: mr r5,r25 + bl copy_and_flush /* copy the rest */ + b turn_on_mmu + /* * Copy routine used to copy the kernel to start at physical address 0 * and flush and invalidate the caches as needed. @@ -1577,11 +1604,6 @@ start_here: 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 mtspr HID0,r8 /* enable and invalidate caches */ sync @@ -1600,14 +1622,27 @@ start_here: 5: mtspr HID0,r11 /* superscalar exec & br history tbl */ 4: #endif /* CONFIG_8xx */ +#ifdef __SMP__ + /* if we're the second cpu stack and r2 are different + * and we want to not clear the bss -- Cort */ + lis r5,first_cpu_booted@h + ori r5,r5,first_cpu_booted@l + lwz r5,0(r5) + cmpi 0,r5,0 + beq 99f + + /* get current */ + lis r2,current_set@h + ori r2,r2,current_set@l + addi r2,r2,4 + lwz r2,0(r2) + + b 10f +99: +#endif /* __SMP__ */ /* ptr to current */ lis r2,init_task_union@h ori r2,r2,init_task_union@l - /* stack */ - addi r1,r2,TASK_UNION_SIZE - li r0,0 - stwu r0,-STACK_FRAME_OVERHEAD(r1) - /* Clear out the BSS */ lis r11,_end@ha addi r11,r11,_end@l @@ -1623,6 +1658,15 @@ start_here: 3: stwu r0,4(r8) bdnz 3b 2: +#ifdef __SMP__ +10: +#endif /* __SMP__ */ + + /* stack */ + addi r1,r2,TASK_UNION_SIZE + li r0,0 + stwu r0,-STACK_FRAME_OVERHEAD(r1) + /* * Decide what sort of machine this is and initialize the MMU. */ @@ -1633,6 +1677,7 @@ start_here: mr r7,r27 bl identify_machine bl MMU_init + /* * Go back to running unmapped so we can load up new values * for SDR1 (hash table pointer) and the segment registers @@ -1674,9 +1719,11 @@ start_here: addi r3,r3,1 /* increment VSID */ addis r4,r4,0x1000 /* address of next segment */ bdnz 3b - /* Load the BAT registers with the values set up by MMU_init. MMU_init takes care of whether we're on a 601 or not. */ + mfpvr r3 + srwi r3,r3,16 + cmpwi r3,1 lis r3,BATS@ha addi r3,r3,BATS@l tophys(r3,r3,r4) @@ -1696,6 +1743,20 @@ start_here: li r4,MSR_KERNEL lis r3,start_kernel@h ori r3,r3,start_kernel@l +#ifdef __SMP__ + /* the second time through here we go to + * start_secondary(). -- Cort + */ + lis r5,first_cpu_booted@h + ori r5,r5,first_cpu_booted@l + tophys(r5,r5,r3) + lwz r5,0(r5) + cmpi 0,r5,0 + beq 10f + lis r3,start_secondary@h + ori r3,r3,start_secondary@l +10: +#endif /* __SMP__ */ mtspr SRR0,r3 mtspr SRR1,r4 rfi /* enable MMU and jump to start_kernel */ @@ -1954,6 +2015,8 @@ int_return: beq+ 1f addi r3,r1,STACK_FRAME_OVERHEAD bl do_IRQ + .globl lost_irq_ret +lost_irq_ret: b 3b 1: lis r4,bh_mask@ha lwz r4,bh_mask@l(r4) @@ -1962,6 +2025,8 @@ int_return: and. r4,r4,r5 beq+ 2f bl do_bottom_half + .globl do_bottom_half_ret +do_bottom_half_ret: SYNC mtmsr r30 /* disable interrupts again */ SYNC @@ -1979,6 +2044,8 @@ int_return: li r3,0 addi r4,r1,STACK_FRAME_OVERHEAD bl do_signal + .globl do_signal_ret +do_signal_ret: b 0b 8: addi r4,r1,INT_FRAME_SIZE+STACK_UNDERHEAD /* size of frame */ stw r4,TSS+KSP(r2) /* save kernel stack pointer */ @@ -2221,173 +2288,6 @@ _GLOBAL(flush_hash_page) _GLOBAL(__main) blr -#ifdef __SMP__ -/* - * Secondary processor begins executing here. - */ - .globl secondary_entry -secondary_entry: - /* 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 - 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 */ - bne 2,5f - ori r11,r11,HID0_BTCD -5: mtspr HID0,r11 /* superscalar exec & br history tbl */ -4: -/* - * 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: - /* get ptr to current */ - lis r2,current_set@h - ori r2,r2,current_set@l - /* assume we're second processor for now */ - tophys(r2,r2,r10) - lwz r2,4(r2) - /* stack */ - addi r1,r2,TASK_UNION_SIZE - li r0,0 - tophys(r3,r1,r10) - stwu r0,-STACK_FRAME_OVERHEAD(r3) - - 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__ */ - /* * PROM code for specific machines follows. Put it * here so it's easy to add arch-specific sections later. diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c index bd7980678..b6c338946 100644 --- a/arch/ppc/kernel/idle.c +++ b/arch/ppc/kernel/idle.c @@ -1,5 +1,5 @@ /* - * $Id: idle.c,v 1.48 1998/07/30 11:29:22 davem Exp $ + * $Id: idle.c,v 1.56 1998/10/13 19:14:36 paulus Exp $ * * Idle daemon for PowerPC. Idle daemon will handle any action * that needs to be taken when the system becomes idle. @@ -11,8 +11,6 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ -#define __KERNEL_SYSCALLS__ - #include <linux/config.h> #include <linux/errno.h> #include <linux/sched.h> @@ -32,9 +30,6 @@ #include <asm/processor.h> #include <asm/mmu.h> #include <asm/cache.h> -#ifdef CONFIG_PMAC -#include <asm/mediabay.h> -#endif void zero_paged(void); void power_save(void); @@ -53,22 +48,15 @@ int idled(void *unused) __sti(); /* endless loop with no priority at all */ - current->priority = -100; - current->counter = -100; + current->priority = 0; + current->counter = 0; check_pgt_cache(); if ( !current->need_resched && zero_paged_on ) zero_paged(); if ( !current->need_resched && htab_reclaim_on ) htab_reclaim(); - - /* - * Only processor 1 may sleep now since processor 2 would - * never wake up. Need to add timer code for processor 2 - * then it can sleep. -- Cort - */ -#ifndef __SMP__ if ( !current->need_resched ) power_save(); -#endif /* __SMP__ */ + run_task_queue(&tq_scheduler); schedule(); } ret = 0; @@ -92,15 +80,9 @@ int cpu_idle(void *unused) */ asmlinkage int sys_idle(void) { - extern int media_bay_task(void *); if(current->pid != 0) return -EPERM; -#ifdef CONFIG_PMAC - if (media_bay_present) - kernel_thread(media_bay_task, NULL, 0); -#endif - idled(NULL); return 0; /* should never execute this but it makes gcc happy -- Cort */ } diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c index cb4d0872e..a180e5f0a 100644 --- a/arch/ppc/kernel/irq.c +++ b/arch/ppc/kernel/irq.c @@ -9,7 +9,7 @@ * Adapted for Power Macintosh by Paul Mackerras * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). - * + * * This file contains the code used by various IRQ handling routines: * asking for different IRQ's should be done through these routines * instead of just grabbing them. Thus setups with different IRQ numbers @@ -50,55 +50,29 @@ #include <asm/gg2.h> #include <asm/cache.h> #include <asm/prom.h> +#include <asm/amigaints.h> +#include <asm/amigahw.h> +#include <asm/amigappc.h> #ifdef CONFIG_8xx #include <asm/8xx_immap.h> #include <asm/mbx.h> #endif -#include <asm/amigaints.h> -#include <asm/amigahw.h> -#include <asm/amigappc.h> -#define VEC_SPUR (24) extern void process_int(unsigned long vec, struct pt_regs *fp); extern void apus_init_IRQ(void); extern void amiga_disable_irq(unsigned int irq); extern void amiga_enable_irq(unsigned int irq); +static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { } +static volatile unsigned char *chrp_int_ack_special; +extern volatile unsigned long ipi_count; +static void pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base); + #ifdef CONFIG_APUS /* Rename a few functions. Requires the CONFIG_APUS protection. */ #define request_irq nop_ppc_request_irq #define free_irq nop_ppc_free_irq #define get_irq_list nop_get_irq_list #endif - -#undef SHOW_IRQ - -#define NR_MASK_WORDS ((NR_IRQS + 31) / 32) - -int max_irqs; -unsigned int local_irq_count[NR_CPUS]; -static struct irqaction *irq_action[NR_IRQS]; -static int spurious_interrupts = 0; -static unsigned int cached_irq_mask[NR_MASK_WORDS]; -unsigned int lost_interrupts[NR_MASK_WORDS]; -atomic_t n_lost_interrupts; - -static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { } - -/*spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED;*/ -#ifdef __SMP__ -atomic_t __ppc_bh_counter = ATOMIC_INIT(0); -#else -int __ppc_bh_counter = 0; -#endif -static volatile unsigned char *gg2_int_ack_special; -extern volatile unsigned long ipi_count; - -#define cached_21 (((char *)(cached_irq_mask))[3]) -#define cached_A1 (((char *)(cached_irq_mask))[2]) - -/* - * These are set to the appropriate functions by init_IRQ() - */ #ifndef CONFIG_8xx void (*mask_and_ack_irq)(int irq_nr); void (*mask_irq)(unsigned int irq_nr); @@ -113,10 +87,24 @@ void (*unmask_irq)(unsigned int irq_nr); #define unmask_irq(irq) mbx_unmask_irq(irq) #endif /* CONFIG_8xx */ - -/* prep */ +#define VEC_SPUR (24) +#undef SHOW_IRQ +#undef SHOW_GATWICK_IRQS +#define NR_MASK_WORDS ((NR_IRQS + 31) / 32) +#define cached_21 (((char *)(cached_irq_mask))[3]) +#define cached_A1 (((char *)(cached_irq_mask))[2]) #define PREP_IRQ_MASK (((unsigned int)cached_A1)<<8) | (unsigned int)cached_21 +unsigned int local_bh_count[NR_CPUS]; +unsigned int local_irq_count[NR_CPUS]; +int max_irqs; +int max_real_irqs; +static struct irqaction *irq_action[NR_IRQS]; +static int spurious_interrupts = 0; +static unsigned int cached_irq_mask[NR_MASK_WORDS]; +unsigned int lost_interrupts[NR_MASK_WORDS]; +atomic_t n_lost_interrupts; + /* pmac */ struct pmac_irq_hw { unsigned int flag; @@ -126,13 +114,32 @@ struct pmac_irq_hw { }; /* XXX these addresses should be obtained from the device tree */ -volatile struct pmac_irq_hw *pmac_irq_hw[2] = { +volatile struct pmac_irq_hw *pmac_irq_hw[4] = { (struct pmac_irq_hw *) 0xf3000020, (struct pmac_irq_hw *) 0xf3000010, + (struct pmac_irq_hw *) 0xf4000020, + (struct pmac_irq_hw *) 0xf4000010, }; -#define KEYBOARD_IRQ 20 /* irq number for command-power interrupt */ +/* This is the interrupt used on the main controller for the secondary + controller. Happens on PowerBooks G3 Series (a second mac-io) + -- BenH + */ +static int second_irq = -999; + +/* Returns the number of 0's to the left of the most significant 1 bit */ +static inline int cntlzw(int bits) +{ + int lz; + + asm ("cntlzw %0,%1" : "=r" (lz) : "r" (bits)); + return lz; +} +static inline void sync(void) +{ + asm volatile ("sync"); +} /* nasty hack for shared irq's since we need to do kmalloc calls but * can't very very early in the boot when we need to do a request irq. @@ -190,12 +197,12 @@ void i8259_mask_and_ack_irq(int irq_nr) /* spin_unlock(&irq_controller_lock);*/ } -void pmac_mask_and_ack_irq(int irq_nr) +void __pmac pmac_mask_and_ack_irq(int irq_nr) { unsigned long bit = 1UL << (irq_nr & 0x1f); int i = irq_nr >> 5; - if (irq_nr >= max_irqs) + if ((unsigned)irq_nr >= max_irqs) return; /*spin_lock(&irq_controller_lock);*/ @@ -205,13 +212,15 @@ void pmac_mask_and_ack_irq(int irq_nr) out_le32(&pmac_irq_hw[i]->ack, bit); out_le32(&pmac_irq_hw[i]->enable, cached_irq_mask[i]); out_le32(&pmac_irq_hw[i]->ack, bit); + /* make sure ack gets to controller before we enable interrupts */ + sync(); /*spin_unlock(&irq_controller_lock);*/ /*if ( irq_controller_lock.lock ) panic("irq controller lock still held in mask and ack\n");*/ } -void chrp_mask_and_ack_irq(int irq_nr) +void __openfirmware chrp_mask_and_ack_irq(int irq_nr) { /* spinlocks are done by i8259_mask_and_ack() - Cort */ if (is_8259_irq(irq_nr)) @@ -228,12 +237,12 @@ static void i8259_set_irq_mask(int irq_nr) } } -static void pmac_set_irq_mask(int irq_nr) +static void __pmac pmac_set_irq_mask(int irq_nr) { unsigned long bit = 1UL << (irq_nr & 0x1f); int i = irq_nr >> 5; - if (irq_nr >= max_irqs) + if ((unsigned)irq_nr >= max_irqs) return; /* enable unmasked interrupts */ @@ -268,19 +277,20 @@ static void i8259_unmask_irq(unsigned int irq_nr) i8259_set_irq_mask(irq_nr); } -static void pmac_mask_irq(unsigned int irq_nr) +static void __pmac pmac_mask_irq(unsigned int irq_nr) { clear_bit(irq_nr, cached_irq_mask); pmac_set_irq_mask(irq_nr); + sync(); } -static void pmac_unmask_irq(unsigned int irq_nr) +static void __pmac pmac_unmask_irq(unsigned int irq_nr) { set_bit(irq_nr, cached_irq_mask); pmac_set_irq_mask(irq_nr); } -static void chrp_mask_irq(unsigned int irq_nr) +static void __openfirmware chrp_mask_irq(unsigned int irq_nr) { if (is_8259_irq(irq_nr)) i8259_mask_irq(irq_nr); @@ -288,7 +298,7 @@ static void chrp_mask_irq(unsigned int irq_nr) openpic_disable_irq(irq_to_openpic(irq_nr)); } -static void chrp_unmask_irq(unsigned int irq_nr) +static void __openfirmware chrp_unmask_irq(unsigned int irq_nr) { if (is_8259_irq(irq_nr)) i8259_unmask_irq(irq_nr); @@ -342,7 +352,7 @@ int get_irq_list(char *buf) for (i = 0 ; i < NR_IRQS ; i++) { action = irq_action[i]; - if (!action || !action->handler) + if ((!action || !action->handler) && (i != second_irq)) continue; len += sprintf(buf+len, "%3d: ", i); #ifdef __SMP__ @@ -358,7 +368,10 @@ int get_irq_list(char *buf) len += sprintf(buf+len, " 82c59 "); break; case _MACH_Pmac: - len += sprintf(buf+len, " PMAC-PIC "); + if (i < 64) + len += sprintf(buf+len, " PMAC-PIC "); + else + len += sprintf(buf+len, " GATWICK "); break; case _MACH_chrp: if ( is_8259_irq(i) ) @@ -371,83 +384,132 @@ int get_irq_list(char *buf) break; } - len += sprintf(buf+len, " %s",action->name); - for (action=action->next; action; action = action->next) { - len += sprintf(buf+len, ", %s", action->name); - } - len += sprintf(buf+len, "\n"); + if (i != second_irq) { + len += sprintf(buf+len, " %s",action->name); + for (action=action->next; action; action = action->next) { + len += sprintf(buf+len, ", %s", action->name); + } + len += sprintf(buf+len, "\n"); + } else + len += sprintf(buf+len, " Gatwick secondary IRQ controller\n"); } #ifdef __SMP__ /* should this be per processor send/receive? */ - len += sprintf(buf+len, "IPI: %10lu\n", ipi_count); + len += sprintf(buf+len, "IPI: %10lu", ipi_count); for ( i = 0 ; i <= smp_num_cpus-1; i++ ) len += sprintf(buf+len," "); - len += sprintf(buf+len, " interprocessor messages received\n"); + len += sprintf(buf+len, " interprocessor messages received\n"); #endif len += sprintf(buf+len, "BAD: %10u",spurious_interrupts); for ( i = 0 ; i <= smp_num_cpus-1; i++ ) len += sprintf(buf+len," "); - len += sprintf(buf+len, " spurious or short\n"); + len += sprintf(buf+len, " spurious or short\n"); return len; } +/* + * Global interrupt locks for SMP. Allow interrupts to come in on any + * CPU, yet make cli/sti act globally to protect critical regions.. + */ #ifdef __SMP__ -/* Who has global_irq_lock. */ unsigned char global_irq_holder = NO_PROC_ID; +unsigned volatile int global_irq_lock; +atomic_t global_irq_count; -/* This protects IRQ's. */ -spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED; -unsigned long previous_irqholder; +atomic_t global_bh_count; +atomic_t global_bh_lock; -/* This protects BH software state (masks, things like that). */ -spinlock_t global_bh_lock = SPIN_LOCK_UNLOCKED; +static void show(char * str) +{ + int i; + unsigned long *stack; + int cpu = smp_processor_id(); -/* Global IRQ locking depth. */ -atomic_t global_irq_count = ATOMIC_INIT(0); + printk("\n%s, CPU %d:\n", str, cpu); + printk("irq: %d [%d %d]\n", + atomic_read(&global_irq_count), local_irq_count[0], local_irq_count[1]); + printk("bh: %d [%d %d]\n", + atomic_read(&global_bh_count), local_bh_count[0], local_bh_count[1]); + stack = (unsigned long *) &str; + for (i = 40; i ; i--) { + unsigned long x = *++stack; + if (x > (unsigned long) &init_task_union && x < (unsigned long) &vsprintf) { + printk("<[%08lx]> ", x); + } + } +} -#undef INIT_STUCK -#define INIT_STUCK 100000000 +#define MAXCOUNT 100000000 +static inline void wait_on_bh(void) +{ + int count = MAXCOUNT; + do { + if (!--count) { + show("wait_on_bh"); + count = ~0; + } + /* nothing .. wait for the other bh's to go away */ + } while (atomic_read(&global_bh_count) != 0); +} -#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) +#define MAXCOUNT 100000000 +static inline void wait_on_irq(int cpu) { - int stuck = INIT_STUCK; - int local_count = local_irq_count[cpu]; + int count = MAXCOUNT; - /* 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); + for (;;) { /* - * Wait for everybody else to go away and release - * their things before trying to get the lock again. + * Wait until all interrupts are gone. Wait + * for bottom half handlers unless we're + * already executing in one.. */ + if (!atomic_read(&global_irq_count)) { + if (local_bh_count[cpu] || !atomic_read(&global_bh_count)) + break; + } + + /* Duh, we have to loop. Release the lock to avoid deadlocks */ + clear_bit(0,&global_irq_lock); + for (;;) { - STUCK; + if (!--count) { + show("wait_on_irq"); + count = ~0; + } + __sti(); + /* don't worry about the lock race Linus found + * on intel here. -- Cort + */ + __cli(); if (atomic_read(&global_irq_count)) continue; - if (*((unsigned char *)&global_irq_lock)) + if (global_irq_lock) continue; - if (spin_trylock(&global_irq_lock)) + if (!local_bh_count[cpu] && atomic_read(&global_bh_count)) + continue; + if (!test_and_set_bit(0,&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 + * bottom half handlers. We need to wait until + * no other CPU is executing any bottom half handler. + * + * Don't wait if we're already running in an interrupt + * context or are inside a bh handler. + */ +void synchronize_bh(void) +{ + if (atomic_read(&global_bh_count) && !in_interrupt()) + wait_on_bh(); +} + /* * This is called when we want to synchronize with @@ -455,97 +517,125 @@ void wait_on_irq(int cpu, unsigned long where) * 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 */ + if (atomic_read(&global_irq_count)) { + /* Stupid approach */ 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) +static inline void get_irqlock(int cpu) { - int stuck = INIT_STUCK; - if (!spin_trylock(&global_irq_lock)) { + if (test_and_set_bit(0,&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)); + + } while (test_bit(0,&global_irq_lock)); + } while (test_and_set_bit(0,&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 + /* + * We also to make sure that nobody else is running * in an interrupt context. */ - wait_on_irq(cpu, where); + wait_on_irq(cpu); + /* - * Finally. + * Ok, finally.. */ global_irq_holder = cpu; - previous_irqholder = where; } +/* + * A global "cli()" while in an interrupt context + * turns into just a local cli(). Interrupts + * should use spinlocks for the (very unlikely) + * case that they ever want to protect against + * each other. + * + * If we already have local interrupts disabled, + * this will not turn a local disable into a + * global one (problems with spinlocks: this makes + * save_flags+cli+sti usable inside a spinlock). + */ 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); + unsigned int flags; + + __save_flags(flags); + if (flags & (1 << 15)) { + int cpu = smp_processor_id(); + __cli(); + if (!local_irq_count[cpu]) + get_irqlock(cpu); + } } void __global_sti(void) { - release_irqlock(smp_processor_id()); + int cpu = smp_processor_id(); + + if (!local_irq_count[cpu]) + release_irqlock(cpu); __sti(); } +/* + * SMP flags value to restore to: + * 0 - global cli + * 1 - global sti + * 2 - local cli + * 3 - local sti + */ unsigned long __global_save_flags(void) { - return global_irq_holder == (unsigned char) smp_processor_id(); + int retval; + int local_enabled; + unsigned long flags; + + __save_flags(flags); + local_enabled = (flags >> 15) & 1; + /* default to local */ + retval = 2 + local_enabled; + + /* check for global flags if we're not in an interrupt */ + if (!local_irq_count[smp_processor_id()]) { + if (local_enabled) + retval = 1; + if (global_irq_holder == (unsigned char) smp_processor_id()) + retval = 0; + } + return retval; } void __global_restore_flags(unsigned long flags) { switch (flags) { case 0: - release_irqlock(smp_processor_id()); - __sti(); + __global_cli(); break; case 1: - __global_cli(); + __global_sti(); + break; + case 2: + __cli(); + break; + case 3: + __sti(); break; default: printk("global_restore_flags: %08lx (%08lx)\n", flags, (&flags)[-1]); } } -#endif /* __SMP__ */ +#endif /* __SMP__ */ asmlinkage void do_IRQ(struct pt_regs *regs) { @@ -569,9 +659,6 @@ asmlinkage void do_IRQ(struct pt_regs *regs) if (!atomic_read(&n_lost_interrupts)) { extern void smp_message_recv(void); - goto out; - - ipi_count++; smp_message_recv(); goto out; } @@ -584,20 +671,48 @@ asmlinkage void do_IRQ(struct pt_regs *regs) switch ( _machine ) { case _MACH_Pmac: - for (irq = max_irqs - 1; irq > 0; irq -= 32) { - int i = irq >> 5, lz; + for (irq = max_real_irqs - 1; irq > 0; irq -= 32) { + int i = irq >> 5; bits = ld_le32(&pmac_irq_hw[i]->flag) | lost_interrupts[i]; if (bits == 0) continue; - /* lz = number of 0 bits to left of most sig. 1 */ - asm ("cntlzw %0,%1" : "=r" (lz) : "r" (bits)); - irq -= lz; + irq -= cntlzw(bits); break; } + + /* Here, we handle interrupts coming from Gatwick, + * normal interrupt code will take care of acking and + * masking the irq on Gatwick itself but we ack&mask + * the Gatwick main interrupt on Heathrow now. It's + * unmasked later, after interrupt handling. -- BenH + */ + if (irq == second_irq) { + mask_and_ack_irq(second_irq); + for (irq = max_irqs - 1; irq > max_real_irqs; irq -= 32) { + int i = irq >> 5; + bits = ld_le32(&pmac_irq_hw[i]->flag) + | lost_interrupts[i]; + if (bits == 0) + continue; + irq -= cntlzw(bits); + break; + } + /* If not found, on exit, irq is 63 (128-1-32-32). + * We set it to -1 and revalidate second controller + */ + if (irq < max_real_irqs) { + irq = -1; + unmask_irq(second_irq); + } +#ifdef SHOW_GATWICK_IRQS + printk("Gatwick irq %d (i:%d, bits:0x%08lx\n", irq, i, bits); +#endif + } + break; case _MACH_chrp: - irq = openpic_irq(0); + irq = openpic_irq(0); if (irq == IRQ_8259_CASCADE) { /* @@ -605,7 +720,7 @@ asmlinkage void do_IRQ(struct pt_regs *regs) * * This should go in the above mask/ack code soon. -- Cort */ - irq = *gg2_int_ack_special; + irq = *chrp_int_ack_special; /* * Acknowledge as soon as possible to allow i8259 * interrupt nesting @@ -682,11 +797,13 @@ apus_out: } #endif } - + if (irq < 0) { - printk(KERN_DEBUG "Bogus interrupt from PC = %lx\n", regs->nip); + printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n", + irq, regs->nip); + spurious_interrupts++; goto out; - } + } #else /* CONFIG_8xx */ /* For MPC8xx, read the SIVEC register and shift the bits down @@ -695,9 +812,7 @@ apus_out: bits = ((immap_t *)MBX_IMAP_ADDR)->im_siu_conf.sc_sivec; irq = bits >> 26; #endif /* CONFIG_8xx */ - mask_and_ack_irq(irq); - status = 0; action = irq_action[irq]; kstat.irqs[cpu][irq]++; @@ -707,14 +822,10 @@ apus_out: do { status |= action->flags; action->handler(irq, action->dev_id, regs); - /*if (status & SA_SAMPLE_RANDOM) - add_interrupt_randomness(irq);*/ action = action->next; } while ( action ); __cli(); - /* spin_lock(&irq_controller_lock);*/ unmask_irq(irq); - /* spin_unlock(&irq_controller_lock);*/ } else { #ifndef CONFIG_8xx if ( irq == 7 ) /* i8259 gives us irq 7 on 'short' intrs */ @@ -723,8 +834,13 @@ apus_out: disable_irq( irq ); } + /* This was a gatwick sub-interrupt, we re-enable them on Heathrow + now */ + if (_machine == _MACH_Pmac && irq >= max_real_irqs) + unmask_irq(second_irq); + /* make sure we don't miss any cascade intrs due to eoi-ing irq 2 */ -#ifndef CONFIG_8xx +#ifndef CONFIG_8xx if ( is_prep && (irq > 7) ) goto retry_cascade; /* do_bottom_half is called if necessary from int_return in head.S */ @@ -750,12 +866,16 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *) #ifdef SHOW_IRQ printk("request_irq(): irq %d handler %08x name %s dev_id %04x\n", - irq,handler,devname,dev_id); + irq,(int)handler,devname,(int)dev_id); #endif /* SHOW_IRQ */ if (irq >= NR_IRQS) return -EINVAL; + /* Cannot allocate second controller IRQ */ + if (irq == second_irq) + return -EBUSY; + if (!handler) { /* Free */ @@ -780,7 +900,7 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *) cli(); action->handler = handler; - action->flags = irqflags; + action->flags = irqflags; action->mask = 0; action->name = devname; action->dev_id = dev_id; @@ -851,6 +971,9 @@ __initfunc(void init_IRQ(void)) { extern void xmon_irq(int, void *, struct pt_regs *); int i; + struct device_node *irqctrler; + unsigned long addr; + struct device_node *np; #ifndef CONFIG_8xx switch (_machine) @@ -860,23 +983,77 @@ __initfunc(void init_IRQ(void)) mask_irq = pmac_mask_irq; unmask_irq = pmac_unmask_irq; - /* G3 powermacs have 64 interrupts, others have 32 */ - max_irqs = (find_devices("mac-io") ? 64 : 32); - printk("System has %d possible interrupts\n", max_irqs); + /* G3 powermacs have 64 interrupts, G3 Series PowerBook have 128, + others have 32 */ + max_irqs = max_real_irqs = 32; + irqctrler = find_devices("mac-io"); + if (irqctrler) + { + max_real_irqs = 64; + if (irqctrler->next) + max_irqs = 128; + else + max_irqs = 64; + } + + /* get addresses of first controller */ + if (irqctrler) { + if (irqctrler->n_addrs > 0) { + addr = (unsigned long) + ioremap(irqctrler->addrs[0].address, 0x40); + for (i = 0; i < 2; ++i) + pmac_irq_hw[i] = (volatile struct pmac_irq_hw*) + (addr + (2 - i) * 0x10); + } + + /* get addresses of second controller */ + irqctrler = (irqctrler->next) ? irqctrler->next : NULL; + if (irqctrler && irqctrler->n_addrs > 0) { + addr = (unsigned long) + ioremap(irqctrler->addrs[0].address, 0x40); + for (i = 2; i < 4; ++i) + pmac_irq_hw[i] = (volatile struct pmac_irq_hw*) + (addr + (4 - i) * 0x10); + } + } + /* disable all interrupts in all controllers */ for (i = 0; i * 32 < max_irqs; ++i) out_le32(&pmac_irq_hw[i]->enable, 0); + + + /* get interrupt line of secondary interrupt controller */ + if (irqctrler) { + second_irq = irqctrler->intrs[0].line; + printk(KERN_INFO "irq: secondary controller on irq %d\n", + (int)second_irq); + if (device_is_compatible(irqctrler, "gatwick")) + pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs); + enable_irq(second_irq); + } + printk("System has %d possible interrupts\n", max_irqs); + if (max_irqs != max_real_irqs) + printk(KERN_DEBUG "%d interrupts on main controller\n", + max_real_irqs); + #ifdef CONFIG_XMON - request_irq(KEYBOARD_IRQ, xmon_irq, 0, "NMI", 0); + request_irq(20, xmon_irq, 0, "NMI", 0); #endif /* CONFIG_XMON */ break; case _MACH_chrp: mask_and_ack_irq = chrp_mask_and_ack_irq; mask_irq = chrp_mask_irq; unmask_irq = chrp_unmask_irq; - gg2_int_ack_special = (volatile unsigned char *) - ioremap(GG2_INT_ACK_SPECIAL, 1); - openpic_init(); + + if ( !(np = find_devices("pci") ) ) + printk("Cannot find pci to get ack address\n"); + else + { + chrp_int_ack_special = (volatile unsigned char *) + (*(unsigned long *)get_property(np, + "8259-interrupt-acknowledge", NULL)); + } + openpic_init(1); i8259_init(); cached_irq_mask[0] = cached_irq_mask[1] = ~0UL; #ifdef CONFIG_XMON @@ -935,3 +1112,61 @@ __initfunc(void init_IRQ(void)) } #endif /* CONFIG_8xx */ } + +/* This routine will fix some missing interrupt values in the device tree + * on the gatwick mac-io controller used by some PowerBooks + */ +__pmac +static void pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base) +{ + struct device_node *node; + static struct interrupt_info int_pool[4]; + + memset(int_pool, 0, sizeof(int_pool)); + node = gw->child; + while(node) + { + /* Fix SCC */ + if (strcasecmp(node->name, "escc") == 0) + if (node->child && node->child->n_intrs == 0) + { + node->child->n_intrs = 1; + node->child->intrs = &int_pool[0]; + int_pool[0].line = 15+irq_base; + printk(KERN_INFO "irq: fixed SCC on second controller (%d)\n", + int_pool[0].line); + } + /* Fix media-bay & left SWIM */ + if (strcasecmp(node->name, "media-bay") == 0) + { + struct device_node* ya_node; + + if (node->n_intrs == 0) + { + node->n_intrs = 1; + node->intrs = &int_pool[1]; + int_pool[1].line = 29+irq_base; + printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n", + int_pool[1].line); + } + ya_node = node->child; + while(ya_node) + { + if ((strcasecmp(ya_node->name, "floppy") == 0) && + ya_node->n_intrs == 0) + { + ya_node->n_intrs = 2; + ya_node->intrs = &int_pool[2]; + int_pool[2].line = 19+irq_base; + int_pool[3].line = 1+irq_base; + printk(KERN_INFO "irq: fixed floppy on second controller (%d,%d)\n", + int_pool[2].line, int_pool[3].line); + } + ya_node = ya_node->sibling; + } + } + node = node->sibling; + } + +} + diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index de55ceaa3..f13508d96 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -363,22 +363,62 @@ _GLOBAL(_get_THRM1) mfspr r3,THRM1 blr +_GLOBAL(_get_THRM2) + mfspr r3,THRM2 + blr + +_GLOBAL(_get_THRM3) + mfspr r3,THRM3 + blr + _GLOBAL(_set_THRM1) mtspr THRM1,r3 blr + +_GLOBAL(_set_THRM2) + mtspr THRM2,r3 + blr + +_GLOBAL(_set_THRM3) + mtspr THRM3,r3 + blr _GLOBAL(_get_L2CR) mfspr r3,L2CR blr - + +_GLOBAL(_set_L2CR) + mtspr L2CR,r3 + blr + _GLOBAL(_get_PVR) mfspr r3,PVR blr +/* + * These are used in the alignment trap handler when emulating + * single-precision loads and stores. + * We restore and save the fpscr so the task gets the same result + * and exceptions as if the cpu had performed the load or store. + */ _GLOBAL(cvt_fd) cvt_fd: + lfd 0,-4(r5) /* load up fpscr value */ + mtfsf 0xff,0 lfs 0,0(r3) stfd 0,0(r4) + mffs 0 /* save new fpscr value */ + stfd 0,-4(r5) + blr + +_GLOBAL(cvt_df) +cvt_df: + lfd 0,-4(r5) /* load up fpscr value */ + mtfsf 0xff,0 + lfd 0,0(r3) + stfs 0,0(r4) + mffs 0 /* save new fpscr value */ + stfd 0,-4(r5) blr /* @@ -390,12 +430,6 @@ _GLOBAL(get_SR) mr r3,r4 blr -_GLOBAL(cvt_df) -cvt_df: - lfd 0,0(r3) - stfs 0,0(r4) - blr - /* * Create a kernel thread * __kernel_thread(flags, fn, arg) @@ -435,7 +469,6 @@ _GLOBAL(name) \ #define __NR__exit __NR_exit SYSCALL(idle) -SYSCALL(setup) SYSCALL(sync) SYSCALL(setsid) SYSCALL(write) @@ -455,7 +488,7 @@ SYSCALL(read) .align 4 .globl sys_call_table sys_call_table: - .long sys_setup /* 0 */ + .long sys_ni_syscall /* 0 - old "setup()" system call */ .long sys_exit .long sys_fork .long sys_read @@ -472,12 +505,12 @@ sys_call_table: .long sys_mknod .long sys_chmod /* 15 */ .long sys_lchown - .long sys_ni_syscall + .long sys_ni_syscall /* old break syscall holder */ .long sys_stat .long sys_lseek .long sys_getpid /* 20 */ .long sys_mount - .long sys_umount + .long sys_oldumount .long sys_setuid .long sys_getuid .long sys_stime /* 25 */ @@ -486,11 +519,11 @@ sys_call_table: .long sys_fstat .long sys_pause .long sys_utime /* 30 */ - .long /*sys_stty*/ sys_ni_syscall - .long /*sys_gtty*/ sys_ni_syscall + .long sys_ni_syscall /* old stty syscall holder */ + .long sys_ni_syscall /* old gtty syscall holder */ .long sys_access .long sys_nice - .long /*sys_ftime*/ sys_ni_syscall /* 35 */ + .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */ .long sys_sync .long sys_kill .long sys_rename @@ -499,7 +532,7 @@ sys_call_table: .long sys_dup .long sys_pipe .long sys_times - .long /*sys_prof*/ sys_ni_syscall + .long sys_ni_syscall /* old prof syscall holder */ .long sys_brk /* 45 */ .long sys_setgid .long sys_getgid @@ -507,13 +540,13 @@ sys_call_table: .long sys_geteuid .long sys_getegid /* 50 */ .long sys_acct - .long /*sys_phys*/ sys_ni_syscall - .long /*sys_lock*/ sys_ni_syscall + .long sys_umount /* recycled never used phys() */ + .long sys_ni_syscall /* old lock syscall holder */ .long sys_ioctl .long sys_fcntl /* 55 */ - .long /*sys_mpx*/ sys_ni_syscall + .long sys_ni_syscall /* old mpx syscall holder */ .long sys_setpgid - .long /*sys_ulimit*/ sys_ni_syscall + .long sys_ni_syscall /* old ulimit syscall holder */ .long sys_olduname .long sys_umask /* 60 */ .long sys_chroot @@ -544,7 +577,7 @@ sys_call_table: .long sys_uselib .long sys_swapon .long sys_reboot - .long old_readdir /* was sys_readdir */ + .long old_readdir .long sys_mmap /* 90 */ .long sys_munmap .long sys_truncate @@ -553,7 +586,7 @@ sys_call_table: .long sys_fchown /* 95 */ .long sys_getpriority .long sys_setpriority - .long /*sys_profil*/ sys_ni_syscall + .long sys_ni_syscall /* old profil syscall holder */ .long sys_statfs .long sys_fstatfs /* 100 */ .long sys_ioperm @@ -592,7 +625,7 @@ sys_call_table: .long sys_bdflush .long sys_sysfs /* 135 */ .long sys_personality - .long 0 /* for afs_syscall */ + .long sys_ni_syscall /* for afs_syscall */ .long sys_setfsuid .long sys_setfsgid .long sys_llseek /* 140 */ @@ -620,22 +653,28 @@ sys_call_table: .long sys_nanosleep .long sys_mremap .long sys_setresuid - .long sys_getresuid /* 165 */ + .long sys_getresuid /* 165 */ .long sys_query_module .long sys_poll .long sys_nfsservctl - .long sys_setresgid - .long sys_getresgid /* 170 */ + .long sys_setresgid + .long sys_getresgid /* 170 */ .long sys_prctl .long sys_rt_sigreturn .long sys_rt_sigaction .long sys_rt_sigprocmask - .long sys_rt_sigpending /* 175 */ + .long sys_rt_sigpending /* 175 */ .long sys_rt_sigtimedwait .long sys_rt_sigqueueinfo .long sys_rt_sigsuspend .long sys_pread - .long sys_pwrite /* 180 */ + .long sys_pwrite /* 180 */ .long sys_chown .long sys_getcwd + .long sys_capget + .long sys_capset + .long sys_sigaltstack /* 185 */ + .long sys_sendfile + .long sys_ni_syscall /* streams1 */ + .long sys_ni_syscall /* streams2 */ .space (NR_syscalls-183)*4 diff --git a/arch/ppc/kernel/openpic.c b/arch/ppc/kernel/openpic.c index fd104ae9f..ec60ca5a6 100644 --- a/arch/ppc/kernel/openpic.c +++ b/arch/ppc/kernel/openpic.c @@ -133,7 +133,7 @@ static inline u_int openpic_readfield(volatile u_int *addr, u_int mask) return val & mask; } -static inline void openpic_writefield(volatile u_int *addr, u_int mask, +inline void openpic_writefield(volatile u_int *addr, u_int mask, u_int field) { u_int val = openpic_read(addr); @@ -173,7 +173,7 @@ static void openpic_safe_writefield(volatile u_int *addr, u_int mask, * Initialize the OpenPIC */ -__initfunc(void openpic_init(void)) +__initfunc(void openpic_init(int main_pic)) { u_int t, i; u_int vendorid, devid, stepping, timerfreq; @@ -233,41 +233,44 @@ __initfunc(void openpic_init(void)) else printk("not set\n"); - /* Initialize timer interrupts */ - for (i = 0; i < OPENPIC_NUM_TIMERS; i++) { - /* Disabled, Priority 0 */ - openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i); - /* No processor */ - openpic_maptimer(i, 0); + if ( main_pic ) + { + /* Initialize timer interrupts */ + for (i = 0; i < OPENPIC_NUM_TIMERS; i++) { + /* Disabled, Priority 0 */ + openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i); + /* No processor */ + openpic_maptimer(i, 0); + } + + /* Initialize IPI interrupts */ + for (i = 0; i < OPENPIC_NUM_IPI; i++) { + /* Disabled, Priority 0 */ + openpic_initipi(i, 0, OPENPIC_VEC_IPI+i); + } + + /* Initialize external interrupts */ + /* SIOint (8259 cascade) is special */ + openpic_initirq(0, 8, OPENPIC_VEC_SOURCE, 1, 1); + /* Processor 0 */ + openpic_mapirq(0, 1<<0); + for (i = 1; i < NumSources; i++) { + /* Enabled, Priority 8 */ + openpic_initirq(i, 8, OPENPIC_VEC_SOURCE+i, 0, + i < OpenPIC_NumInitSenses ? OpenPIC_InitSenses[i] : 1); + /* Processor 0 */ + openpic_mapirq(i, 1<<0); + } + + /* Initialize the spurious interrupt */ + openpic_set_spurious(OPENPIC_VEC_SPURIOUS); + + if (request_irq(IRQ_8259_CASCADE, no_action, SA_INTERRUPT, + "82c59 cascade", NULL)) + printk("Unable to get OpenPIC IRQ 0 for cascade\n"); + openpic_set_priority(0, 0); + openpic_disable_8259_pass_through(); } - - /* Initialize IPI interrupts */ - for (i = 0; i < OPENPIC_NUM_IPI; i++) { - /* Disabled, Priority 0 */ - openpic_initipi(i, 0, OPENPIC_VEC_IPI+i); - } - - /* Initialize external interrupts */ - /* SIOint (8259 cascade) is special */ - openpic_initirq(0, 8, OPENPIC_VEC_SOURCE, 1, 1); - /* Processor 0 */ - openpic_mapirq(0, 1<<0); - for (i = 1; i < NumSources; i++) { - /* Enabled, Priority 8 */ - openpic_initirq(i, 8, OPENPIC_VEC_SOURCE+i, 0, - i < OpenPIC_NumInitSenses ? OpenPIC_InitSenses[i] : 1); - /* Processor 0 */ - openpic_mapirq(i, 1<<0); - } - - /* Initialize the spurious interrupt */ - openpic_set_spurious(OPENPIC_VEC_SPURIOUS); - - if (request_irq(IRQ_8259_CASCADE, no_action, SA_INTERRUPT, - "82c59 cascade", NULL)) - printk("Unable to get OpenPIC IRQ 0 for cascade\n"); - openpic_set_priority(0, 0); - openpic_disable_8259_pass_through(); } @@ -529,5 +532,3 @@ void openpic_set_sense(u_int irq, int sense) OPENPIC_SENSE_LEVEL, (sense ? OPENPIC_SENSE_LEVEL : 0)); } - - diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index 235365f5e..359446f4f 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -1,5 +1,5 @@ /* - * $Id: pci.c,v 1.36 1998/08/02 23:22:11 paulus Exp $ + * $Id: pci.c,v 1.39 1998/10/13 20:59:04 cort Exp $ * Common pmac/prep/chrp pci routines. -- Cort */ @@ -164,7 +164,7 @@ __initfunc(void get_property(find_path_device("/"), "model", NULL),3) ) { isa_io_base = 0xfe000000; - set_config_access_method(raven); + set_config_access_method(grackle); } else { @@ -201,8 +201,22 @@ __initfunc(void pcibios_fixup(void)) route_pci_interrupts(); for(dev=pci_devices; dev; dev=dev->next) { + /* + * Use our old hard-coded kludge to figure out what + * irq this device uses. This is necessary on things + * without residual data. -- Cort + */ unsigned char d = PCI_SLOT(dev->devfn); dev->irq = Motherboard_routes[Motherboard_map[d]]; +#if 0 + /* + * If we have residual data and if it knows about this + * device ask it what the irq is. + * -- Cort + */ + ppcd = residual_find_device_id( ~0L, dev->device, + -1,-1,-1, 0); +#endif } break; case _MACH_chrp: diff --git a/arch/ppc/kernel/pmac_pci.c b/arch/ppc/kernel/pmac_pci.c index 481f69e2c..7763059f7 100644 --- a/arch/ppc/kernel/pmac_pci.c +++ b/arch/ppc/kernel/pmac_pci.c @@ -40,7 +40,6 @@ static void add_bridges(struct device_node *dev, unsigned long *mem_ptr); #define BANDIT_COHERENT 0x40 __pmac - void *pci_io_base(unsigned int bus) { struct bridge_data *bp; @@ -50,6 +49,7 @@ void *pci_io_base(unsigned int bus) return bp->io_base; } +__pmac int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr, unsigned char *devfn_ptr) { @@ -68,6 +68,7 @@ int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr, return 0; } +__pmac int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned char *val) { @@ -90,6 +91,7 @@ int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, return PCIBIOS_SUCCESSFUL; } +__pmac int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned short *val) { @@ -114,6 +116,7 @@ int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, return PCIBIOS_SUCCESSFUL; } +__pmac int pmac_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned int *val) { @@ -138,6 +141,7 @@ int pmac_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, return PCIBIOS_SUCCESSFUL; } +__pmac int pmac_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned char val) { @@ -159,6 +163,7 @@ int pmac_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, return PCIBIOS_SUCCESSFUL; } +__pmac int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned short val) { @@ -182,6 +187,7 @@ int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, return PCIBIOS_SUCCESSFUL; } +__pmac int pmac_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned int val) { @@ -406,7 +412,7 @@ __initfunc(static void add_bridges(struct device_node *dev, unsigned long *mem_p ioremap(0xfec00000, 0x1000); bp->cfg_data = (volatile unsigned char *) ioremap(0xfee00000, 0x1000); - bp->io_base = (void *) ioremap(0xfe000000, 0x10000); + bp->io_base = (void *) ioremap(0xfe000000, 0x20000); } if (isa_io_base == 0) isa_io_base = (unsigned long) bp->io_base; diff --git a/arch/ppc/kernel/pmac_setup.c b/arch/ppc/kernel/pmac_setup.c index 7e44b404c..499e8b6a5 100644 --- a/arch/ppc/kernel/pmac_setup.c +++ b/arch/ppc/kernel/pmac_setup.c @@ -38,6 +38,7 @@ #include <linux/delay.h> #include <linux/ioport.h> #include <linux/major.h> +#include <linux/blk.h> #include <linux/vt_kern.h> #include <linux/console.h> #include <asm/prom.h> @@ -48,28 +49,89 @@ #include <asm/adb.h> #include <asm/cuda.h> #include <asm/pmu.h> -#include <asm/mediabay.h> #include <asm/ohare.h> #include <asm/mediabay.h> +#include <asm/feature.h> #include "time.h" -extern int root_mountflags; - unsigned char drive_info; +extern char saved_command_line[]; + #define DEFAULT_ROOT_DEVICE 0x0801 /* sda1 - slightly silly choice */ extern void zs_kgdb_hook(int tty_num); static void ohare_init(void); __pmac - int pmac_get_cpuinfo(char *buffer) { int len; - /* should find motherboard type here as well */ - len = sprintf(buffer,"machine\t\t: PowerMac\n"); + struct device_node *np; + char *pp; + int plen; + + /* find motherboard type */ + len = sprintf(buffer, "machine\t\t: "); + np = find_devices("device-tree"); + if (np != NULL) { + pp = (char *) get_property(np, "model", NULL); + if (pp != NULL) + len += sprintf(buffer+len, "%s\n", pp); + else + len += sprintf(buffer+len, "PowerMac\n"); + pp = (char *) get_property(np, "compatible", &plen); + if (pp != NULL) { + len += sprintf(buffer+len, "motherboard\t:"); + while (plen > 0) { + int l = strlen(pp) + 1; + len += sprintf(buffer+len, " %s", pp); + plen -= l; + pp += l; + } + buffer[len++] = '\n'; + } + } else + len += sprintf(buffer+len, "PowerMac\n"); + + /* find l2 cache info */ + np = find_devices("l2-cache"); + if (np == 0) + np = find_type_devices("cache"); + if (np != 0) { + unsigned int *ic = (unsigned int *) + get_property(np, "i-cache-size", NULL); + unsigned int *dc = (unsigned int *) + get_property(np, "d-cache-size", NULL); + len += sprintf(buffer+len, "L2 cache\t:"); + if (get_property(np, "cache-unified", NULL) != 0 && dc) { + len += sprintf(buffer+len, " %dK unified", *dc / 1024); + } else { + if (ic) + len += sprintf(buffer+len, " %dK instruction", + *ic / 1024); + if (dc) + len += sprintf(buffer+len, "%s %dK data", + (ic? " +": ""), *dc / 1024); + } + pp = get_property(np, "ram-type", NULL); + if (pp) + len += sprintf(buffer+len, " %s", pp); + buffer[len++] = '\n'; + } + + /* find ram info */ + np = find_devices("memory"); + if (np != 0) { + struct reg_property *reg = (struct reg_property *) + get_property(np, "reg", NULL); + if (reg != 0) { + len += sprintf(buffer+len, "memory\t\t: %dMB\n", + reg->size >> 20); + } + } + return len; } @@ -82,6 +144,13 @@ pmac_get_cpuinfo(char *buffer) #include "../../../drivers/scsi/sd.h" #include "../../../drivers/scsi/hosts.h" +#define SD_MAJOR(i) (!(i) ? SCSI_DISK0_MAJOR : SCSI_DISK1_MAJOR-1+(i)) +#define SD_MAJOR_NUMBER(i) SD_MAJOR((i) >> 8) +#define SD_MINOR_NUMBER(i) ((i) & 255) +#define MKDEV_SD_PARTITION(i) MKDEV(SD_MAJOR_NUMBER(i), SD_MINOR_NUMBER(i)) +#define MKDEV_SD(index) MKDEV_SD_PARTITION((index) << 4) + +__init kdev_t sd_find_target(void *host, int tgt) { Scsi_Disk *dp; @@ -90,7 +159,7 @@ kdev_t sd_find_target(void *host, int tgt) 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 MKDEV_SD(i); return 0; } #endif @@ -99,13 +168,13 @@ kdev_t sd_find_target(void *host, int tgt) * Dummy mksound function that does nothing. * The real one is in the dmasound driver. */ +__pmac static void pmac_mksound(unsigned int hz, unsigned int ticks) { } static volatile u32 *sysctrl_regs; -static volatile u32 *feature_addr; __initfunc(void pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p)) @@ -137,10 +206,11 @@ pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p)) and some registers used by smp boards */ sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000); __ioremap(0xffc00000, 0x400000, pgprot_val(PAGE_READONLY)); + ohare_init(); *memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p); - ohare_init(); + feature_init(); #ifdef CONFIG_KGDB zs_kgdb_hook(0); @@ -154,43 +224,30 @@ pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p)) #endif kd_mksound = pmac_mksound; + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); + else +#endif + ROOT_DEV = to_kdev_t(DEFAULT_ROOT_DEVICE); } __initfunc(static void ohare_init(void)) { - struct device_node *np; - - np = find_devices("ohare"); - if (np == 0) - return; - if (np->next != 0) - printk(KERN_WARNING "only using the first ohare\n"); - if (np->n_addrs == 0) { - printk(KERN_ERR "No addresses for %s\n", np->full_name); - return; - } - feature_addr = (volatile u32 *) - ioremap(np->addrs[0].address + OHARE_FEATURE_REG, 4); - - if (find_devices("via-pmu") == 0) { - printk(KERN_INFO "Twiddling the magic ohare bits\n"); - out_le32(feature_addr, STARMAX_FEATURES); - } else { - out_le32(feature_addr, in_le32(feature_addr) | PBOOK_FEATURES); - printk(KERN_DEBUG "feature reg = %x\n", in_le32(feature_addr)); - } - /* * Turn on the L2 cache. * We assume that we have a PSX memory controller iff * we have an ohare I/O controller. */ - if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) { - if (sysctrl_regs[4] & 0x10) - sysctrl_regs[4] |= 0x04000020; - else - sysctrl_regs[4] |= 0x04000000; - printk(KERN_INFO "Level 2 cache enabled\n"); + if (find_devices("ohare") != NULL) { + if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) { + if (sysctrl_regs[4] & 0x10) + sysctrl_regs[4] |= 0x04000020; + else + sysctrl_regs[4] |= 0x04000000; + printk(KERN_INFO "Level 2 cache enabled\n"); + } } } @@ -201,8 +258,10 @@ int boot_target; int boot_part; kdev_t boot_dev; -__initfunc(void powermac_init(void)) +void __init powermac_init(void) { + if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) ) + return; adb_init(); pmac_nvram_init(); if (_machine == _MACH_Pmac) { @@ -210,6 +269,7 @@ __initfunc(void powermac_init(void)) } } +#ifdef CONFIG_SCSI __initfunc(void note_scsi_host(struct device_node *node, void *host)) { @@ -238,28 +298,67 @@ note_scsi_host(struct device_node *node, void *host)) } } } +#endif -__initfunc(void find_boot_device(void)) +#ifdef CONFIG_BLK_DEV_IDE_PMAC +extern int pmac_ide_count; +extern struct device_node *pmac_ide_node[]; +static int ide_majors[] = { 3, 22, 33, 34, 56, 57 }; + +__initfunc(kdev_t find_ide_boot(void)) { - kdev_t dev; + char *p; + int i, n; - if (kdev_t_to_nr(ROOT_DEV) != 0) - return; - ROOT_DEV = to_kdev_t(DEFAULT_ROOT_DEVICE); - if (boot_host == NULL) - return; + if (bootdevice == NULL) + return 0; + p = strrchr(bootdevice, '/'); + if (p == NULL) + return 0; + n = p - bootdevice; + + /* + * Look through the list of IDE interfaces for this one. + */ + for (i = 0; i < pmac_ide_count; ++i) { + char *name = pmac_ide_node[i]->full_name; + if (memcmp(name, bootdevice, n) == 0 && name[n] == 0) { + /* XXX should cope with the 2nd drive as well... */ + return MKDEV(ide_majors[i], 0); + } + } + + return 0; +} +#endif /* CONFIG_BLK_DEV_IDE_PMAC */ + +__initfunc(void find_boot_device(void)) +{ #ifdef CONFIG_SCSI - dev = sd_find_target(boot_host, boot_target); - if (dev == 0) - return; - boot_dev = MKDEV(MAJOR(dev), MINOR(dev) + boot_part); + if (boot_host != NULL) { + boot_dev = sd_find_target(boot_host, boot_target); + if (boot_dev != 0) + return; + } +#endif +#ifdef CONFIG_BLK_DEV_IDE_PMAC + boot_dev = find_ide_boot(); #endif - /* XXX should cope with booting from IDE also */ } -__initfunc(void note_bootable_part(kdev_t dev, int part)) +/* can't be initfunc - can be called whenever a disk is first accessed */ +__pmac +void note_bootable_part(kdev_t dev, int part) { static int found_boot = 0; + char *p; + + /* Do nothing if the root has been set already. */ + if (ROOT_DEV != to_kdev_t(DEFAULT_ROOT_DEVICE)) + return; + p = strstr(saved_command_line, "root="); + if (p != NULL && (p == saved_command_line || p[-1] == ' ')) + return; if (!found_boot) { find_boot_device(); diff --git a/arch/ppc/kernel/pmac_support.c b/arch/ppc/kernel/pmac_support.c index c88c8bae9..0196c5eb6 100644 --- a/arch/ppc/kernel/pmac_support.c +++ b/arch/ppc/kernel/pmac_support.c @@ -25,8 +25,7 @@ static int nvram_mult; #define NVRAM_SIZE 0x2000 /* 8kB of non-volatile RAM */ -__pmac - +__init void pmac_nvram_init(void) { struct device_node *dp; diff --git a/arch/ppc/kernel/ppc_defs.h b/arch/ppc/kernel/ppc_defs.h new file mode 100644 index 000000000..83315a2ae --- /dev/null +++ b/arch/ppc/kernel/ppc_defs.h @@ -0,0 +1,69 @@ +/* + * WARNING! This file is automatically generated - DO NOT EDIT! + */ +#define KERNELBASE -1073741824 +#define STATE 0 +#define NEXT_TASK 48 +#define COUNTER 24 +#define PROCESSOR 36 +#define SIGPENDING 8 +#define TSS 568 +#define MM 872 +#define TASK_STRUCT_SIZE 912 +#define KSP 0 +#define PG_TABLES 4 +#define PGD 8 +#define LAST_SYSCALL 20 +#define PT_REGS 12 +#define PF_TRACESYS 32 +#define TASK_FLAGS 4 +#define NEED_RESCHED 20 +#define TSS_FPR0 24 +#define TSS_FPSCR 284 +#define TSS_SMP_FORK_RET 288 +#define TASK_UNION_SIZE 8192 +#define STACK_FRAME_OVERHEAD 16 +#define INT_FRAME_SIZE 192 +#define GPR0 16 +#define GPR1 20 +#define GPR2 24 +#define GPR3 28 +#define GPR4 32 +#define GPR5 36 +#define GPR6 40 +#define GPR7 44 +#define GPR8 48 +#define GPR9 52 +#define GPR10 56 +#define GPR11 60 +#define GPR12 64 +#define GPR13 68 +#define GPR14 72 +#define GPR15 76 +#define GPR16 80 +#define GPR17 84 +#define GPR18 88 +#define GPR19 92 +#define GPR20 96 +#define GPR21 100 +#define GPR22 104 +#define GPR23 108 +#define GPR24 112 +#define GPR25 116 +#define GPR26 120 +#define GPR27 124 +#define GPR28 128 +#define GPR29 132 +#define GPR30 136 +#define GPR31 140 +#define _NIP 144 +#define _MSR 148 +#define _CTR 156 +#define _LINK 160 +#define _CCR 168 +#define _XER 164 +#define _DAR 180 +#define _DSISR 184 +#define ORIG_GPR3 152 +#define RESULT 188 +#define TRAP 176 diff --git a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c index c1445d393..3aa0534ea 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.21 1998/05/13 22:34:55 cort Exp $ + * $Id: ppc_htab.c,v 1.25 1998/08/26 10:28:26 davem Exp $ * * PowerPC hash table management proc entry. Will show information * about the current hash table and will allow changes to it. @@ -17,6 +17,8 @@ #include <linux/sched.h> #include <linux/proc_fs.h> #include <linux/stat.h> +#include <linux/sysctl.h> +#include <linux/ctype.h> #include <asm/uaccess.h> #include <asm/bitops.h> @@ -31,6 +33,8 @@ static ssize_t ppc_htab_read(struct file * file, char * buf, 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); +int proc_dol2crvec(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp); extern PTE *Hash, *Hash_end; extern unsigned long Hash_size, Hash_mask; @@ -519,3 +523,147 @@ ppc_htab_lseek(struct file * file, loff_t offset, int orig) return(-EINVAL); } } + +int proc_dol2crvec(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + int vleft, first=1, len, left, val; + #define TMPBUFLEN 256 + char buf[TMPBUFLEN], *p; + + if ( (_get_PVR() >> 16) != 8) return -EFAULT; + + if ( /*!table->maxlen ||*/ (filp->f_pos && !write)) { + *lenp = 0; + return 0; + } + + vleft = table->maxlen / sizeof(int); + left = *lenp; + + for (; left /*&& vleft--*/; first=0) { + if (write) { + while (left) { + char c; + if(get_user(c,(char *) buffer)) + return -EFAULT; + if (!isspace(c)) + break; + left--; + ((char *) buffer)++; + } + if (!left) + break; + len = left; + if (len > TMPBUFLEN-1) + len = TMPBUFLEN-1; + if(copy_from_user(buf, buffer, len)) + return -EFAULT; + buf[len] = 0; + p = buf; + if (*p < '0' || *p > '9') + break; + val = simple_strtoul(p, &p, 0); + len = p-buf; + if ((len < left) && *p && !isspace(*p)) + break; + buffer += len; + left -= len; + _set_L2CR(val); + while ( _get_L2CR() & 0x1 ) + /* wait for invalidate to finish */; + + } else { + p = buf; + if (!first) + *p++ = '\t'; + val = _get_L2CR(); + p += sprintf(p, "%08x: ", val); + p += sprintf(p, " %s", + (val&0x80000000)?"enabled":"disabled"); + p += sprintf(p,",%sparity",(val&0x40000000)?"":"no "); + + switch( (val >> 28) & 0x3 ) + { + case 1: p += sprintf(p,",256Kb"); + break; + case 2: p += sprintf(p,",512Kb"); + break; + case 3: p += sprintf(p,",1M"); + break; + default: p += sprintf(p,",unknown size"); + break; + } + + + switch( (val >> 25) & 0x7 ) + { + case 0: p += sprintf(p,",clock disabled"); + break; + case 1: p += sprintf(p,",+1 clock"); + break; + case 2: p += sprintf(p,",+1.5 clock"); + break; + case 7: + case 3: p += sprintf(p,",reserved clock"); + break; + case 4: p += sprintf(p,",+2 clock"); + break; + case 5: p += sprintf(p,",+2.5 clock"); + break; + case 6: p += sprintf(p,",+3 clock"); + break; + } + + switch( (val >> 23) & 0x2 ) + { + case 0: p += sprintf(p,",flow-through burst SRAM"); + break; + case 1: p += sprintf(p,",reserved SRAM"); + break; + case 2: p += sprintf(p,",pipelined burst SRAM"); + break; + case 3: p += sprintf(p,",pipelined late-write SRAM"); + break; + } + + p += sprintf(p,"%s",(val>>22)?"":",data only"); + p += sprintf(p,"%s",(val>>20)?",ZZ enabled":""); + p += sprintf(p,",%s",(val>>19)?"write-through":"copy-back"); + p += sprintf(p,",%sns hold",(val>>16)?"1.0":"0.5"); + + p += sprintf(p,"\n"); + + len = strlen(buf); + if (len > left) + len = left; + if(copy_to_user(buffer, buf, len)) + return -EFAULT; + left -= len; + buffer += len; + break; + } + } + + if (!write && !first && left) { + if(put_user('\n', (char *) buffer)) + return -EFAULT; + left--, buffer++; + } + if (write) { + p = (char *) buffer; + while (left) { + char c; + if(get_user(c, p++)) + return -EFAULT; + if (!isspace(c)) + break; + left--; + } + } + if (write && first) + return -EINVAL; + *lenp -= left; + filp->f_pos += *lenp; + return 0; +} diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index e869a31dd..ea5f6db0d 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -11,6 +11,7 @@ #include <asm/semaphore.h> #include <asm/processor.h> #include <asm/uaccess.h> +#include <asm/ide.h> #include <asm/io.h> #include <asm/atomic.h> #include <asm/bitops.h> @@ -23,6 +24,7 @@ #include <asm/system.h> #include <asm/pci-bridge.h> #include <asm/irq.h> +#include <asm/feature.h> #define __KERNEL_SYSCALLS__ #include <linux/unistd.h> @@ -56,10 +58,10 @@ EXPORT_SYMBOL(SingleStepException); EXPORT_SYMBOL(sys_sigreturn); EXPORT_SYMBOL(n_lost_interrupts); EXPORT_SYMBOL(do_lost_interrupts); -EXPORT_SYMBOL(__ppc_bh_counter); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(local_irq_count); +EXPORT_SYMBOL(local_bh_count); EXPORT_SYMBOL(isa_io_base); EXPORT_SYMBOL(isa_mem_base); @@ -138,11 +140,12 @@ EXPORT_SYMBOL(ioremap); EXPORT_SYMBOL(__ioremap); EXPORT_SYMBOL(iounmap); +EXPORT_SYMBOL(ide_insw); +EXPORT_SYMBOL(ide_outsw); + EXPORT_SYMBOL(start_thread); EXPORT_SYMBOL(__kernel_thread); -EXPORT_SYMBOL(__down_interruptible); - EXPORT_SYMBOL(__cli); EXPORT_SYMBOL(__sti); /*EXPORT_SYMBOL(__restore_flags);*/ @@ -154,6 +157,10 @@ EXPORT_SYMBOL(giveup_fpu); EXPORT_SYMBOL(flush_icache_range); EXPORT_SYMBOL(xchg_u32); +#ifndef CONFIG_MACH_SPECIFIC +EXPORT_SYMBOL(_machine); +#endif + EXPORT_SYMBOL(adb_request); EXPORT_SYMBOL(adb_autopoll); EXPORT_SYMBOL(adb_register); @@ -169,10 +176,15 @@ EXPORT_SYMBOL(sleep_notifier_list); EXPORT_SYMBOL(abort); EXPORT_SYMBOL(find_devices); EXPORT_SYMBOL(find_type_devices); +EXPORT_SYMBOL(find_compatible_devices); EXPORT_SYMBOL(find_path_device); +EXPORT_SYMBOL(find_phandle); EXPORT_SYMBOL(get_property); EXPORT_SYMBOL(pci_io_base); EXPORT_SYMBOL(pci_device_loc); +EXPORT_SYMBOL(feature_set); +EXPORT_SYMBOL(feature_clear); +EXPORT_SYMBOL(feature_test); EXPORT_SYMBOL(note_scsi_host); EXPORT_SYMBOL(kd_mksound); #ifdef CONFIG_PMAC diff --git a/arch/ppc/kernel/prep_pci.c b/arch/ppc/kernel/prep_pci.c index 7f45756cb..b7d94d208 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.20 1998/06/19 16:48:45 cort Exp $ + * $Id: prep_pci.c,v 1.23 1998/10/21 10:52:24 cort Exp $ * PReP pci functions. * Originally by Gary Thomas * rewritten and updated by Cort Dougan (cort@cs.nmt.edu) @@ -234,6 +234,44 @@ static char ibm8xx_pci_IRQ_routes[] __prepdata = { 15, /* Line 4 */ }; +/* + * a 6015 ibm board + * -- Cort + */ +static char ibm6015_pci_IRQ_map[23] __prepdata = { + 0, /* Slot 0 - unused */ + 0, /* Slot 1 - unused */ + 0, /* Slot 2 - unused */ + 0, /* Slot 3 - unused */ + 0, /* Slot 4 - unused */ + 0, /* Slot 5 - unused */ + 0, /* Slot 6 - unused */ + 0, /* Slot 7 - unused */ + 0, /* Slot 8 - unused */ + 0, /* Slot 9 - unused */ + 0, /* Slot 10 - unused */ + 0, /* Slot 11 - */ + 1, /* Slot 12 - SCSI */ + 2, /* Slot 13 - */ + 2, /* Slot 14 - */ + 1, /* Slot 15 - */ + 1, /* Slot 16 - */ + 0, /* Slot 17 - */ + 2, /* Slot 18 - */ + 0, /* Slot 19 - */ + 0, /* Slot 20 - */ + 0, /* Slot 21 - */ + 2, /* Slot 22 - */ +}; +static char ibm6015_pci_IRQ_routes[] __prepdata = { + 0, /* Line 0 - unused */ + 13, /* Line 1 */ + 10, /* Line 2 */ + 15, /* Line 3 */ + 15, /* Line 4 */ +}; + + /* IBM Nobis and 850 */ static char Nobis_pci_IRQ_map[23] __prepdata ={ 0, /* Slot 0 - unused */ @@ -424,6 +462,11 @@ __initfunc(unsigned long route_pci_interrupts(void)) Motherboard_map = Utah_pci_IRQ_map; Motherboard_routes = Utah_pci_IRQ_routes; break; + case 0xE0: /* MTX -- close enough?? to Genesis, so reuse it */ + Motherboard_map_name = "Motorola MTX"; + Motherboard_map = Genesis_pci_IRQ_map; + Motherboard_routes = Genesis_pci_IRQ_routes; + break; case 0x40: /* PowerStack */ default: /* Can't hurt, can it? */ Motherboard_map_name = "Blackhawk (Powerstack)"; @@ -434,16 +477,31 @@ __initfunc(unsigned long route_pci_interrupts(void)) } else if ( _prep_type == _PREP_IBM ) { unsigned char pl_id; - - if (inb(0x0852) == 0xFF) { + /* + * my carolina is 0xf0 + * 6015 has 0xfc + * -- Cort + */ + printk("IBM ID: %08x\n", inb(0x0852)); + switch(inb(0x0852)) + { + case 0xff: Motherboard_map_name = "IBM 850/860 Portable\n"; Motherboard_map = Nobis_pci_IRQ_map; Motherboard_routes = Nobis_pci_IRQ_routes; - } else { + break; + case 0xfc: + Motherboard_map_name = "IBM 6015"; + Motherboard_map = ibm6015_pci_IRQ_map; + Motherboard_routes = ibm6015_pci_IRQ_routes; + break; + default: Motherboard_map_name = "IBM 8xx (Carolina)"; Motherboard_map = ibm8xx_pci_IRQ_map; Motherboard_routes = ibm8xx_pci_IRQ_routes; + break; } + /*printk("Changing IRQ mode\n");*/ pl_id=inb(0x04d0); /*printk("Low mask is %#0x\n", pl_id);*/ diff --git a/arch/ppc/kernel/prep_setup.c b/arch/ppc/kernel/prep_setup.c index 406c18281..e596f9ea5 100644 --- a/arch/ppc/kernel/prep_setup.c +++ b/arch/ppc/kernel/prep_setup.c @@ -76,26 +76,70 @@ prep_get_cpuinfo(char *buffer) #endif len = sprintf(buffer,"machine\t\t: PReP %s\n",Motherboard_map_name); + - len += sprintf(buffer+len,"L2\t\t: "); - switch(*((unsigned char *)CACHECRBA) & L2CACHE_MASK) + switch ( _prep_type ) { - case L2CACHE_512KB: - len += sprintf(buffer+len,"512Kb\n"); - break; - case L2CACHE_256KB: - len += sprintf(buffer+len,"256Kb\n"); - break; - case L2CACHE_1MB: - len += sprintf(buffer+len,"1MB\n"); + case _PREP_IBM: + if ((*(unsigned char *)0x8000080c) & (1<<6)) + len += sprintf(buffer+len,"Upgrade CPU\n"); + len += sprintf(buffer+len,"L2\t\t: "); + if ((*(unsigned char *)0x8000080c) & (1<<7)) + { + len += sprintf(buffer+len,"not present\n"); + goto no_l2; + } + len += sprintf(buffer+len,"%sKb,", + (((*(unsigned char *)0x8000080d)>>2)&1)?"512":"256"); + len += sprintf(buffer+len,"%sync\n", + ((*(unsigned char *)0x8000080d)>>7) ? "":"a"); break; - case L2CACHE_NONE: - len += sprintf(buffer+len,"none\n"); + case _PREP_Motorola: + len += sprintf(buffer+len,"L2\t\t: "); + switch(*((unsigned char *)CACHECRBA) & L2CACHE_MASK) + { + case L2CACHE_512KB: + len += sprintf(buffer+len,"512Kb"); + break; + case L2CACHE_256KB: + len += sprintf(buffer+len,"256Kb"); + break; + case L2CACHE_1MB: + len += sprintf(buffer+len,"1MB"); + break; + case L2CACHE_NONE: + len += sprintf(buffer+len,"none\n"); + goto no_l2; + break; + default: + len += sprintf(buffer+len, "%x\n", + *((unsigned char *)CACHECRBA)); + } + + len += sprintf(buffer+len,",parity %s", + (*((unsigned char *)CACHECRBA) & L2CACHE_PARITY) ? + "enabled" : "disabled"); + + len += sprintf(buffer+len, " SRAM:"); + + switch ( ((*((unsigned char *)CACHECRBA) & 0xf0) >> 4) & ~(0x3) ) + { + case 1: len += sprintf(buffer+len, + "synchronous,parity,flow-through\n"); + break; + case 2: len += sprintf(buffer+len,"asynchronous,no parity\n"); + break; + case 3: len += sprintf(buffer+len,"asynchronous,parity\n"); + break; + default:len += sprintf(buffer+len, + "synchronous,pipelined,no parity\n"); + break; + } break; - default: - len += sprintf(buffer+len,"%x\n", *((unsigned char *)CACHECRBA)); } - + + +no_l2: if ( res->ResidualLength == 0 ) return len; @@ -111,20 +155,6 @@ prep_get_cpuinfo(char *buffer) } len += sprintf(buffer+len,"\n"); -#if 0 - /* L2 */ - if ( (inb(IBM_EQUIP_PRESENT) & 1) == 0) /* l2 present */ - { - len += sprintf(buffer+len,"l2\t\t: %dkB %s\n", - ((inb(IBM_L2_STATUS) >> 5) & 1) ? 512 : 256, - (inb(IBM_SYS_CTL) & 64) ? "enabled" : "disabled"); - } - else - { - len += sprintf(buffer+len,"l2\t\t: not present\n"); - } -#endif - return len; } @@ -155,6 +185,9 @@ prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)) ROOT_DEV = to_kdev_t(0x0801); /* sda1 */ break; } + + /* Enable L2. Assume we don't need to flush -- Cort*/ + *(unsigned char *)(0x8000081c) = *(unsigned char *)(0x8000081c)|3; /* make the serial port the console */ /* strcat(cmd_line,"console=ttyS0,9600n8"); */ @@ -163,7 +196,7 @@ prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)) sprintf(cmd_line,"%s console=tty0 console=ttyS0,9600n8", cmd_line); printk("Boot arguments: %s\n", cmd_line); -#ifdef CONFIG_CS4232 +#ifdef CONFIG_SOUND_CS4232 /* * setup proper values for the cs4232 driver so we don't have * to recompile for the motorola or ibm workstations sound systems. @@ -200,8 +233,7 @@ prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)) } } } -#endif /* CONFIG_CS4232 */ - +#endif /* CONFIG_SOUND_CS4232 */ /*print_residual_device_info();*/ request_region(0x20,0x20,"pic1"); diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c index 9cf88c8a4..5ea55cee9 100644 --- a/arch/ppc/kernel/process.c +++ b/arch/ppc/kernel/process.c @@ -163,14 +163,19 @@ switch_to(struct task_struct *prev, struct task_struct *new) #endif #ifdef SHOW_TASK_SWITCHES - printk("%s/%d -> %s/%d NIP %08lx cpu %d sfr %d lock %x\n", + printk("%s/%d -> %s/%d NIP %08lx cpu %d lock %x root %x/%x\n", prev->comm,prev->pid, new->comm,new->pid,new->tss.regs->nip,new->processor, - new->tss.smp_fork_ret,scheduler_lock.lock); + scheduler_lock.lock,new->fs->root,prev->fs->root); #endif #ifdef __SMP__ /* avoid complexity of lazy save/restore of fpu - * by just saving it every time we switch out -- Cort + * by just saving it every time we switch out if + * this task used the fpu during the last quantum. + * + * If it tries to use the fpu again, it'll trap and + * reload its fp regs. + * -- Cort */ if ( prev->tss.regs->msr & MSR_FP ) smp_giveup_fpu(prev); @@ -349,6 +354,9 @@ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp) regs->gpr[1] = sp; regs->msr = MSR_USER; shove_aux_table(sp); + if (last_task_used_math == current) + last_task_used_math = 0; + current->tss.fpscr = 0; } asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, @@ -380,6 +388,7 @@ asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, { int res; + lock_kernel(); res = do_fork(SIGCHLD, regs->gpr[1], regs); /* only parent returns here */ @@ -401,18 +410,23 @@ 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)) goto out; +#ifdef __SMP__ + if ( regs->msr & MSR_FP ) + smp_giveup_fpu(current); +#else if ( last_task_used_math == current ) - last_task_used_math = NULL; + giveup_fpu(); +#endif error = do_execve(filename, (char **) a1, (char **) a2, regs); putname(filename); out: unlock_kernel(); + return error; } @@ -446,7 +460,7 @@ __initfunc(int ll_printk(const char *fmt, ...)) int i; va_start(args, fmt); - i=sprintf(buf,fmt,args); + i=vsprintf(buf,fmt,args); ll_puts(buf); va_end(args); return i; @@ -455,6 +469,19 @@ __initfunc(int ll_printk(const char *fmt, ...)) int lines = 24, cols = 80; int orig_x = 0, orig_y = 0; +void puthex(unsigned long val) +{ + unsigned char buf[10]; + int i; + for (i = 7; i >= 0; i--) + { + buf[i] = "0123456789ABCDEF"[val & 0x0F]; + val >>= 4; + } + buf[8] = '\0'; + prom_print(buf); +} + __initfunc(void ll_puts(const char *s)) { int x,y; diff --git a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c index 047d590ed..da9d7a04c 100644 --- a/arch/ppc/kernel/prom.c +++ b/arch/ppc/kernel/prom.c @@ -1,5 +1,5 @@ /* - * $Id: prom.c,v 1.32 1998/07/28 20:28:46 geert Exp $ + * $Id: prom.c,v 1.46 1998/11/11 03:55:09 paulus Exp $ * * Procedures for interfacing to the Open Firmware PROM on * Power Macintosh computers. @@ -15,11 +15,14 @@ #include <linux/kernel.h> #include <linux/string.h> #include <linux/init.h> +#include <linux/version.h> #include <asm/prom.h> #include <asm/page.h> #include <asm/processor.h> #include <asm/irq.h> #include <asm/io.h> +#include <asm/smp.h> +#include <asm/bootx.h> /* * Properties whose value is longer than this get excluded from our @@ -60,6 +63,13 @@ struct isa_reg_property { unsigned size; }; +struct pci_intr_map { + struct pci_address addr; + unsigned dunno; + phandle int_ctrler; + unsigned intr; +}; + typedef unsigned long interpret_func(struct device_node *, unsigned long); static interpret_func interpret_pci_props; static interpret_func interpret_dbdma_props; @@ -67,8 +77,12 @@ static interpret_func interpret_isa_props; static interpret_func interpret_macio_props; static interpret_func interpret_root_props; +#ifndef FB_MAX /* avoid pulling in all of the fb stuff */ +#define FB_MAX 8 +#endif char *prom_display_paths[FB_MAX] __initdata = { 0, }; unsigned int prom_num_displays = 0; +char *of_stdout_device = 0; prom_entry prom = 0; ihandle prom_chosen = 0, prom_stdout = 0; @@ -84,20 +98,49 @@ unsigned int old_rtas = 0; static struct device_node *allnodes = 0; +static void clearscreen(void); + +#ifdef CONFIG_BOOTX_TEXT + +static void drawchar(char c); +static void drawstring(const char *c); +static void scrollscreen(void); + +static void draw_byte(unsigned char c, long locX, long locY); +static void draw_byte_32(unsigned char *bits, unsigned long *base); +static void draw_byte_16(unsigned char *bits, unsigned long *base); +static void draw_byte_8(unsigned char *bits, unsigned long *base); + +static long g_loc_X; +static long g_loc_Y; +static long g_max_loc_X; +static long g_max_loc_Y; + +#define cmapsz (16*256) + +static unsigned char vga_font[cmapsz]; + +#endif + + static void *call_prom(const char *service, int nargs, int nret, ...); - 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, struct device_node ***); static unsigned long finish_node(struct device_node *, unsigned long, interpret_func *); +static void relocate_nodes(void); static unsigned long check_display(unsigned long); static int prom_next_node(phandle *); +static void *early_get_property(unsigned long, unsigned long, char *); extern void enter_rtas(void *); extern unsigned long reloc_offset(void); +extern char cmd_line[512]; /* XXX */ +boot_infos_t *boot_infos = 0; /* init it so it's in data segment not bss */ + /* * prom_init() is called very early on, before the kernel text * and data have been mapped to KERNELBASE. At this point the code @@ -124,7 +167,7 @@ extern unsigned long reloc_offset(void); #define ALIGN(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long)) -__openfirmware +__init static void prom_exit() { @@ -139,7 +182,7 @@ prom_exit() ; } -__openfirmware +__init void prom_enter(void) { @@ -152,7 +195,7 @@ prom_enter(void) RELOC(prom)(&args); } -__openfirmware +__init static void * call_prom(const char *service, int nargs, int nret, ...) { @@ -174,13 +217,23 @@ call_prom(const char *service, int nargs, int nret, ...) return prom_args.args[nargs]; } -__openfirmware +__init void prom_print(const char *msg) { const char *p, *q; unsigned long offset = reloc_offset(); + if (RELOC(prom_stdout) == 0) + { +#ifdef CONFIG_BOOTX_TEXT + if (RELOC(boot_infos) != 0) + drawstring(msg); +#endif + return; + } + + for (p = msg; *p != 0; p = q) { for (q = p; *q != 0 && *q != '\n'; ++q) ; @@ -199,7 +252,7 @@ prom_print(const char *msg) * We enter here early on, when the Open Firmware prom is still * handling exceptions and the MMU hash table for us. */ -__openfirmware +__init void prom_init(int r3, int r4, prom_entry pp) { @@ -208,13 +261,59 @@ prom_init(int r3, int r4, prom_entry pp) unsigned long offset = reloc_offset(); int l; char *p, *d; + + /* check if we're apus, return if we are */ + if ( r3 == 0x61707573 ) + return; + + /* If we came here from BootX, clear the screen, + * set up some pointers and return. */ + if (r3 == 0x426f6f58 && pp == NULL) { + boot_infos_t *bi = (boot_infos_t *) r4; + unsigned long space; + unsigned long ptr, x; + char *model; + + RELOC(boot_infos) = PTRUNRELOC(bi); + + clearscreen(); + +#ifdef CONFIG_BOOTX_TEXT + RELOC(g_loc_X) = 0; + RELOC(g_loc_Y) = 0; + RELOC(g_max_loc_X) = (bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) / 8; + RELOC(g_max_loc_Y) = (bi->dispDeviceRect[3] - bi->dispDeviceRect[1]) / 16; + prom_print(RELOC("Welcome to Linux, kernel " UTS_RELEASE " booting...\n")); +#endif + + /* + * XXX If this is an iMac, turn off the USB controller. + */ + model = (char *) early_get_property + (r4 + bi->deviceTreeOffset, 4, RELOC("model")); + if (model && strcmp(model, RELOC("iMac,1")) == 0) { + out_le32((unsigned *)0x80880008, 1); /* XXX */ + } + + space = bi->deviceTreeOffset + bi->deviceTreeSize; + if (bi->ramDisk) + space = bi->ramDisk + bi->ramDiskSize; + RELOC(klimit) = PTRUNRELOC((char *) bi + space); + + /* + * Touch each page to make sure the PTEs for them + * are in the hash table - the aim is to try to avoid + * getting DSI exceptions while copying the kernel image. + */ + for (ptr = (KERNELBASE + offset) & PAGE_MASK; + ptr < (unsigned long)bi + space; ptr += PAGE_SIZE) + x = *(volatile unsigned long *)ptr; - /* check if we're prep, return if we are */ - if ( *(unsigned long *)(0) == 0xdeadc0de ) return; + } - /* check if we're apus, return if we are */ - if ( r3 == 0x61707573 ) + /* check if we're prep, return if we are */ + if ( *(unsigned long *)(0) == 0xdeadc0de ) return; /* First get a handle for the stdout device */ @@ -228,9 +327,16 @@ prom_init(int r3, int r4, prom_entry pp) sizeof(prom_stdout)) <= 0) prom_exit(); - /* Get the boot device and translate it to a full OF pathname. */ + /* Get the full OF pathname of the stdout device */ mem = (unsigned long) RELOC(klimit) + offset; p = (char *) mem; + memset(p, 0, 256); + call_prom(RELOC("instance-to-path"), 3, 1, RELOC(prom_stdout), p, 255); + RELOC(of_stdout_device) = PTRUNRELOC(p); + mem += strlen(p) + 1; + + /* Get the boot device and translate it to a full OF pathname. */ + p = (char *) mem; l = (int) call_prom(RELOC("getprop"), 4, 1, RELOC(prom_chosen), RELOC("bootpath"), p, 1<<20); if (l > 0) { @@ -297,14 +403,15 @@ prom_init(int r3, int r4, prom_entry pp) * So we check whether we will need to open the display, * and if so, open it now. */ -__openfirmware +__init static unsigned long check_display(unsigned long mem) { phandle node; ihandle ih; + int i; unsigned long offset = reloc_offset(); - char type[16], name[16], *path; + char type[16], *path; for (node = 0; prom_next_node(&node); ) { type[0] = 0; @@ -323,27 +430,30 @@ check_display(unsigned long mem) ih = call_prom(RELOC("open"), 1, 1, path); if (ih == 0 || ih == (ihandle) -1) { prom_print(RELOC("... failed\n")); - /* platinum kludge. platinum is a valid display, - * but not handled by OF. Make sure prom_num_display - * is incremented anyway - */ - call_prom(RELOC("getprop"), 4, 1, node, RELOC("name"), - name, sizeof(name)); - if (strncmp(name, RELOC("platinum"), 8)) - continue; - } else { - prom_print(RELOC("... ok\n")); + continue; } + prom_print(RELOC("... ok\n")); + + /* + * If this display is the device that OF is using for stdout, + * move it to the front of the list. + */ mem += strlen(path) + 1; - RELOC(prom_display_paths[RELOC(prom_num_displays)++]) - = PTRUNRELOC(path); + i = RELOC(prom_num_displays)++; + if (RELOC(of_stdout_device) != 0 && i > 0 + && strcmp(PTRRELOC(RELOC(of_stdout_device)), path) == 0) { + for (; i > 0; --i) + RELOC(prom_display_paths[i]) + = RELOC(prom_display_paths[i-1]); + } + RELOC(prom_display_paths[i]) = PTRUNRELOC(path); if (RELOC(prom_num_displays) >= FB_MAX) break; } return ALIGN(mem); } -__openfirmware +__init static int prom_next_node(phandle *nodep) { @@ -366,7 +476,7 @@ prom_next_node(phandle *nodep) /* * Make a copy of the device tree from the PROM. */ -__openfirmware +__init static unsigned long copy_device_tree(unsigned long mem_start, unsigned long mem_end) { @@ -387,7 +497,7 @@ copy_device_tree(unsigned long mem_start, unsigned long mem_end) return new_start; } -__openfirmware +__init static unsigned long inspect_node(phandle node, struct device_node *dad, unsigned long mem_start, unsigned long mem_end, @@ -472,19 +582,41 @@ inspect_node(phandle node, struct device_node *dad, * It traverses the device tree and fills in the name, type, * {n_}addrs and {n_}intrs fields of each node. */ -__openfirmware +__init void finish_device_tree(void) { unsigned long mem = (unsigned long) klimit; + if (boot_infos) + relocate_nodes(); mem = finish_node(allnodes, mem, NULL); printk(KERN_INFO "device tree used %lu bytes\n", mem - (unsigned long) allnodes); klimit = (char *) mem; } -__openfirmware +/* + * early_get_property is used to access the device tree image prepared + * by BootX very early on, before the pointers in it have been relocated. + */ +__init void * +early_get_property(unsigned long base, unsigned long node, char *prop) +{ + struct device_node *np = (struct device_node *)(base + node); + struct property *pp; + + for (pp = np->properties; pp != 0; pp = pp->next) { + pp = (struct property *) (base + (unsigned long)pp); + if (strcmp((char *)((unsigned long)pp->name + base), + prop) == 0) { + return (void *)((unsigned long)pp->value + base); + } + } + return 0; +} + +__init static unsigned long finish_node(struct device_node *np, unsigned long mem_start, interpret_func *ifunc) @@ -505,31 +637,79 @@ finish_node(struct device_node *np, unsigned long mem_start, ifunc = NULL; else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci")) ifunc = interpret_pci_props; - else if (!strcmp(np->type, "dbdma") - || (ifunc == interpret_dbdma_props - && (!strcmp(np->type, "escc") - || !strcmp(np->type, "media-bay")))) + else if (!strcmp(np->type, "dbdma")) ifunc = interpret_dbdma_props; - else if (!strcmp(np->type, "mac-io")) + else if (!strcmp(np->type, "mac-io") + || ifunc == interpret_macio_props) ifunc = interpret_macio_props; else if (!strcmp(np->type, "isa")) ifunc = interpret_isa_props; - else + else if (!((ifunc == interpret_dbdma_props + || ifunc == interpret_macio_props) + && (!strcmp(np->type, "escc") + || !strcmp(np->type, "media-bay")))) ifunc = NULL; + /* if we were booted from BootX, convert the full name */ + if (boot_infos + && strncmp(np->full_name, "Devices:device-tree", 19) == 0) { + if (np->full_name[19] == 0) { + strcpy(np->full_name, "/"); + } else if (np->full_name[19] == ':') { + char *p = np->full_name + 19; + np->full_name = p; + for (; *p; ++p) + if (*p == ':') + *p = '/'; + } + } + for (child = np->child; child != NULL; child = child->sibling) mem_start = finish_node(child, mem_start, ifunc); return mem_start; } -__openfirmware +/* + * When BootX makes a copy of the device tree from the MacOS + * Name Registry, it is in the format we use but all of the pointers + * are offsets from the start of the tree. + * This procedure updates the pointers. + */ +__init +static void relocate_nodes(void) +{ + unsigned long base; + struct device_node *np; + struct property *pp; + +#define ADDBASE(x) (x = (x)? ((typeof (x))((unsigned long)(x) + base)): 0) + + base = (unsigned long) boot_infos + boot_infos->deviceTreeOffset; + allnodes = (struct device_node *)(base + 4); + for (np = allnodes; np != 0; np = np->allnext) { + ADDBASE(np->full_name); + ADDBASE(np->properties); + ADDBASE(np->parent); + ADDBASE(np->child); + ADDBASE(np->sibling); + ADDBASE(np->allnext); + for (pp = np->properties; pp != 0; pp = pp->next) { + ADDBASE(pp->name); + ADDBASE(pp->value); + ADDBASE(pp->next); + } + } +} + +__init static unsigned long interpret_pci_props(struct device_node *np, unsigned long mem_start) { struct address_range *adr; struct pci_reg_property *pci_addrs; - int i, l, *ip; + int i, l, *ip, ml; + struct pci_intr_map *imp; pci_addrs = (struct pci_reg_property *) get_property(np, "assigned-addresses", &l); @@ -548,6 +728,30 @@ interpret_pci_props(struct device_node *np, unsigned long mem_start) mem_start += i * sizeof(struct address_range); } + /* + * If the pci host bridge has an interrupt-map property, + * look for our node in it. + */ + if (np->parent != 0 && pci_addrs != 0 + && (imp = (struct pci_intr_map *) + get_property(np->parent, "interrupt-map", &ml)) != 0 + && (ip = (int *) get_property(np, "interrupts", &l)) != 0) { + unsigned int busdevfn = pci_addrs[0].addr.a_hi & 0xffff00; + np->n_intrs = 0; + np->intrs = (struct interrupt_info *) mem_start; + for (i = 0; (ml -= sizeof(struct pci_intr_map)) >= 0; ++i) { + if (imp[i].addr.a_hi == busdevfn) { + np->intrs[np->n_intrs].line = imp[i].intr; + np->intrs[np->n_intrs].sense = 0; + ++np->n_intrs; + } + } + if (np->n_intrs == 0) + np->intrs = 0; + mem_start += np->n_intrs * sizeof(struct interrupt_info); + return mem_start; + } + ip = (int *) get_property(np, "AAPL,interrupts", &l); if (ip == 0) ip = (int *) get_property(np, "interrupts", &l); @@ -564,7 +768,7 @@ interpret_pci_props(struct device_node *np, unsigned long mem_start) return mem_start; } -__openfirmware +__init static unsigned long interpret_dbdma_props(struct device_node *np, unsigned long mem_start) { @@ -613,7 +817,7 @@ interpret_dbdma_props(struct device_node *np, unsigned long mem_start) return mem_start; } -__openfirmware +__init static unsigned long interpret_macio_props(struct device_node *np, unsigned long mem_start) { @@ -651,18 +855,28 @@ interpret_macio_props(struct device_node *np, unsigned long mem_start) ip = (int *) get_property(np, "AAPL,interrupts", &l); if (ip != 0) { np->intrs = (struct interrupt_info *) mem_start; - np->n_intrs = l / (2 * sizeof(int)); - mem_start += np->n_intrs * sizeof(struct interrupt_info); - for (i = 0; i < np->n_intrs; ++i) { - np->intrs[i].line = openpic_to_irq(*ip++); - np->intrs[i].sense = *ip++; + if (_machine == _MACH_Pmac) { + /* for the iMac */ + np->n_intrs = l / sizeof(int); + for (i = 0; i < np->n_intrs; ++i) { + np->intrs[i].line = *ip++; + np->intrs[i].sense = 0; + } + } else { + /* CHRP machines */ + np->n_intrs = l / (2 * sizeof(int)); + for (i = 0; i < np->n_intrs; ++i) { + np->intrs[i].line = openpic_to_irq(*ip++); + np->intrs[i].sense = *ip++; + } } + mem_start += np->n_intrs * sizeof(struct interrupt_info); } return mem_start; } -__openfirmware +__init static unsigned long interpret_isa_props(struct device_node *np, unsigned long mem_start) { @@ -700,7 +914,7 @@ interpret_isa_props(struct device_node *np, unsigned long mem_start) return mem_start; } -__openfirmware +__init static unsigned long interpret_root_props(struct device_node *np, unsigned long mem_start) { @@ -779,6 +993,30 @@ find_type_devices(const char *type) return head; } +/* Checks if the given "compat" string matches one of the strings in + * the device's "compatible" property + */ +__openfirmware +int +device_is_compatible(struct device_node *device, const char *compat) +{ + const char* cp; + int cplen, l; + + cp = (char *) get_property(device, "compatible", &cplen); + if (cp == NULL) + return 0; + while (cplen > 0) { + if (strcasecmp(cp, compat) == 0) + return 1; + l = strlen(cp) + 1; + cp += l; + cplen -= l; + } + + return 0; +} + /* * Construct and return a list of the device_nodes with a given type * and compatible property. @@ -788,15 +1026,13 @@ 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) { + if (device_is_compatible(np, compat)) { *prevp = np; prevp = &np->next; } @@ -854,6 +1090,7 @@ get_property(struct device_node *np, const char *name, int *lenp) return 0; } +#if 0 __openfirmware void print_properties(struct device_node *np) @@ -904,7 +1141,9 @@ print_properties(struct device_node *np) } } } +#endif +/* this can be called after setup -- Cort */ __openfirmware int call_rtas(const char *service, int nargs, int nret, @@ -941,7 +1180,7 @@ call_rtas(const char *service, int nargs, int nret, return u.words[nargs+3]; } -__openfirmware +__init void abort() { @@ -951,3 +1190,563 @@ abort() #endif prom_exit(); } + +#define CALC_BASE(y) (bi->dispDeviceBase + bi->dispDeviceRect[0] * \ + (bi->dispDeviceDepth >> 3) + bi->dispDeviceRowBytes * (y)) + +__init +static void +clearscreen(void) +{ + unsigned long offset = reloc_offset(); + boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); + unsigned long *base = (unsigned long *)CALC_BASE(0); + unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * + (bi->dispDeviceDepth >> 3)) >> 2; + int i,j; + + for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1]); i++) + { + unsigned long *ptr = base; + for(j=width; j; --j) + *(ptr++) = 0; + base += (bi->dispDeviceRowBytes >> 2); + } +} + +#ifdef CONFIG_BOOTX_TEXT + +__init +static void +scrollscreen(void) +{ + unsigned long offset = reloc_offset(); + boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); + unsigned long *src = (unsigned long *)CALC_BASE(16); + unsigned long *dst = (unsigned long *)CALC_BASE(0); + unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * + (bi->dispDeviceDepth >> 3)) >> 2; + int i,j; + + for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1] - 16); i++) + { + unsigned long *src_ptr = src; + unsigned long *dst_ptr = dst; + for(j=width; j; --j) + *(dst_ptr++) = *(src_ptr++); + src += (bi->dispDeviceRowBytes >> 2); + dst += (bi->dispDeviceRowBytes >> 2); + } + for (i=0; i<16; i++) + { + unsigned long *dst_ptr = dst; + for(j=width; j; --j) + *(dst_ptr++) = 0; + dst += (bi->dispDeviceRowBytes >> 2); + } +} + +__init +static void +drawchar(char c) +{ + unsigned long offset = reloc_offset(); + + switch(c) + { + case '\r': RELOC(g_loc_X) = 0; break; + case '\n': RELOC(g_loc_X) = 0; RELOC(g_loc_Y)++; break; + default: + draw_byte(c, RELOC(g_loc_X)++, RELOC(g_loc_Y)); + if (RELOC(g_loc_X) >= RELOC(g_max_loc_X)) + { + RELOC(g_loc_X) = 0; + RELOC(g_loc_Y)++; + } + } + while (RELOC(g_loc_Y) >= RELOC(g_max_loc_Y)) + { + scrollscreen(); + RELOC(g_loc_Y)--; + } +} + +__init +static void +drawstring(const char *c) +{ + while(*c) + drawchar(*(c++)); +} + +__init +static void +draw_byte(unsigned char c, long locX, long locY) +{ + unsigned long offset = reloc_offset(); + boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); + unsigned char *base = bi->dispDeviceBase + + (bi->dispDeviceRowBytes * ((locY * 16) + bi->dispDeviceRect[1])) + + (bi->dispDeviceDepth >> 3) * ((locX * 8) + bi->dispDeviceRect[0]); + unsigned char *font = &RELOC(vga_font)[((unsigned long)c) * 16]; + + switch(bi->dispDeviceDepth) + { + case 32: + draw_byte_32(font, (unsigned long *)base); + break; + case 16: + draw_byte_16(font, (unsigned long *)base); + break; + case 8: + draw_byte_8(font, (unsigned long *)base); + break; + default: + break; + } +} + +__init +static unsigned long expand_bits_8[16] = { + 0x00000000, + 0x000000ff, + 0x0000ff00, + 0x0000ffff, + 0x00ff0000, + 0x00ff00ff, + 0x00ffff00, + 0x00ffffff, + 0xff000000, + 0xff0000ff, + 0xff00ff00, + 0xff00ffff, + 0xffff0000, + 0xffff00ff, + 0xffffff00, + 0xffffffff +}; + +__init +static unsigned long expand_bits_16[4] = { + 0x00000000, + 0x0000ffff, + 0xffff0000, + 0xffffffff +}; + + +__init +static void +draw_byte_32(unsigned char *font, unsigned long *base) +{ + unsigned long offset = reloc_offset(); + boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); + int l, bits; + int fg = 0xFFFFFFFFUL; + int bg = 0x00000000UL; + + + for (l = 0; l < 16; ++l) + { + bits = *font++; + base[0] = (-(bits >> 7) & fg) ^ bg; + base[1] = (-((bits >> 6) & 1) & fg) ^ bg; + base[2] = (-((bits >> 5) & 1) & fg) ^ bg; + base[3] = (-((bits >> 4) & 1) & fg) ^ bg; + base[4] = (-((bits >> 3) & 1) & fg) ^ bg; + base[5] = (-((bits >> 2) & 1) & fg) ^ bg; + base[6] = (-((bits >> 1) & 1) & fg) ^ bg; + base[7] = (-(bits & 1) & fg) ^ bg; + base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes); + } +} + +__init +static void +draw_byte_16(unsigned char *font, unsigned long *base) +{ + unsigned long offset = reloc_offset(); + boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); + int l, bits; + int fg = 0xFFFFFFFFUL; + int bg = 0x00000000UL; + unsigned long *eb = RELOC(expand_bits_16); + + for (l = 0; l < 16; ++l) + { + bits = *font++; + base[0] = (eb[bits >> 6] & fg) ^ bg; + base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg; + base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg; + base[3] = (eb[bits & 3] & fg) ^ bg; + base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes); + } +} + +__init +static void +draw_byte_8(unsigned char *font, unsigned long *base) +{ + unsigned long offset = reloc_offset(); + boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); + int l, bits; + int fg = 0x0F0F0F0FUL; + int bg = 0x00000000UL; + unsigned long *eb = RELOC(expand_bits_8); + + for (l = 0; l < 16; ++l) + { + bits = *font++; + base[0] = (eb[bits >> 4] & fg) ^ bg; + base[1] = (eb[bits & 0xf] & fg) ^ bg; + base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes); + } +} + +__init +static unsigned char vga_font[cmapsz] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, +0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff, +0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, +0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, +0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, +0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, +0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, +0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e, +0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, +0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63, +0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, +0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e, +0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, +0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb, +0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, +0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, +0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, +0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, +0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, +0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, +0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, +0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, +0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, +0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, +0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, +0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, +0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, +0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, +0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, +0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, +0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, +0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, +0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, +0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, +0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde, +0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, +0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, +0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c, +0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, +0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, +0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c, +0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, +0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7, +0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, +0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, +0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, +0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, +0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, +0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, +0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, +0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, +0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, +0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, +0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60, +0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, +0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60, +0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, +0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60, +0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, +0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, +0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, +0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, +0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, +0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, +0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, +0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, +0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, +0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, +0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, +0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, +0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, +0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, +0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, +0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, +0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, +0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, +0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, +0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, +0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, +0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, +0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00, +0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, +0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, +0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c, +0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, +0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, +0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, +0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, +0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, +0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, +0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, +0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, +0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, +0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, +0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, +0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00, +0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, +0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, +0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, +0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, +0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, +0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, +0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, +0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, +0x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, +0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, +0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, +0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44, +0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, +0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, +0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, +0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, +0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, +0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, +0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, +0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, +0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, +0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, +0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, +0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, +0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, +0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, +0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, +0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, +0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, +0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, +0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, +0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, +0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, +0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +}; + +#endif /* CONFIG_BOOTX_TEXT */ diff --git a/arch/ppc/kernel/residual.c b/arch/ppc/kernel/residual.c index b2e198f68..83333f660 100644 --- a/arch/ppc/kernel/residual.c +++ b/arch/ppc/kernel/residual.c @@ -1,5 +1,5 @@ /* - * $Id: residual.c,v 1.10 1998/07/09 22:23:18 cort Exp $ + * $Id: residual.c,v 1.14 1998/10/11 17:38:10 cort Exp $ * * Code to deal with the PReP residual data. * @@ -23,7 +23,6 @@ #include <asm/pnp.h> #include <asm/byteorder.h> -#if 0 #include <linux/errno.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -50,7 +49,7 @@ #include <asm/ide.h> -const char * PnP_BASE_TYPES[]= { +const char * PnP_BASE_TYPES[] __initdata = { "Reserved", "MassStorageDevice", "NetworkInterfaceController", @@ -66,7 +65,7 @@ const char * PnP_BASE_TYPES[]= { /* Device Sub Type Codes */ -const unsigned char * PnP_SUB_TYPES[] = { +const unsigned char * PnP_SUB_TYPES[] __initdata = { "\001\000SCSIController", "\001\001IDEController", "\001\002FloppyController", @@ -123,7 +122,7 @@ const unsigned char * PnP_SUB_TYPES[] = { /* Device Interface Type Codes */ -const unsigned char * PnP_INTERFACES[]= { +const unsigned char * PnP_INTERFACES[] __initdata = { "\000\000\000General", "\001\000\000GeneralSCSI", "\001\001\000GeneralIDE", @@ -241,7 +240,7 @@ const unsigned char * PnP_INTERFACES[]= { NULL }; -static const unsigned char *PnP_SUB_TYPE_STR(unsigned char BaseType, +static const unsigned char __init *PnP_SUB_TYPE_STR(unsigned char BaseType, unsigned char SubType) { const unsigned char ** s=PnP_SUB_TYPES; while (*s && !((*s)[0]==BaseType @@ -250,7 +249,7 @@ static const unsigned char *PnP_SUB_TYPE_STR(unsigned char BaseType, else return("Unknown !"); }; -static const unsigned char *PnP_INTERFACE_STR(unsigned char BaseType, +static const unsigned char __init *PnP_INTERFACE_STR(unsigned char BaseType, unsigned char SubType, unsigned char Interface) { const unsigned char ** s=PnP_INTERFACES; @@ -261,7 +260,7 @@ static const unsigned char *PnP_INTERFACE_STR(unsigned char BaseType, else return NULL; }; -static void printsmallvendor(PnP_TAG_PACKET *pkt, int size) { +static void __init printsmallvendor(PnP_TAG_PACKET *pkt, int size) { int i, c; char decomp[4]; #define p pkt->S14_Pack.S14_Data.S14_PPCPack @@ -286,7 +285,7 @@ static void printsmallvendor(PnP_TAG_PACKET *pkt, int size) { #undef p } -static void printsmallpacket(PnP_TAG_PACKET * pkt, int size) { +static void __init printsmallpacket(PnP_TAG_PACKET * pkt, int size) { static const unsigned char * intlevel[] = {"high", "low"}; static const unsigned char * intsense[] = {"edge", "level"}; @@ -353,7 +352,7 @@ static void printsmallpacket(PnP_TAG_PACKET * pkt, int size) { } } -static void printlargevendor(PnP_TAG_PACKET * pkt, int size) { +static void __init 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"}; @@ -463,9 +462,7 @@ static void printlargevendor(PnP_TAG_PACKET * pkt, int size) { } } -static void printlargepacket(PnP_TAG_PACKET * pkt, int size) { - int i; - +static void __init printlargepacket(PnP_TAG_PACKET * pkt, int size) { switch (tag_large_item_name(pkt->S1_Pack.Tag)) { case LargeVendorItem: printlargevendor(pkt, size); @@ -476,8 +473,7 @@ static void printlargepacket(PnP_TAG_PACKET * pkt, int size) { break; } } -static void printpackets(PnP_TAG_PACKET * pkt, const char * cat) { - PnP_TAG_PACKET tmp; +static void __init printpackets(PnP_TAG_PACKET * pkt, const char * cat) { if (pkt->S1_Pack.Tag== END_TAG) { printk(" No packets describing %s resources.\n", cat); return; @@ -498,13 +494,11 @@ static void printpackets(PnP_TAG_PACKET * pkt, const char * cat) { } while (pkt->S1_Pack.Tag != END_TAG); } -void print_residual_device_info(void) +void __init 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 ) @@ -552,18 +546,24 @@ return; 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"); + if ( dev->AllocatedOffset ) + printpackets( (union _PnP_TAG_PACKET *) + &res->DevicePnPHeap[dev->AllocatedOffset], + "allocated"); + if ( dev->PossibleOffset ) + printpackets( (union _PnP_TAG_PACKET *) + &res->DevicePnPHeap[dev->PossibleOffset], + "possible"); + if ( dev->CompatibleOffset ) + printpackets( (union _PnP_TAG_PACKET *) + &res->DevicePnPHeap[dev->CompatibleOffset], + "compatible"); } } - -static void printVPD(void) { +#if 0 +static void __init printVPD(void) { #define vpd res->VitalProductData int ps=vpd.PageSize, i, j; static const char* Usage[]={ @@ -628,7 +628,6 @@ static void printVPD(void) { /* * Spit out some info about residual data */ -#if 0 void print_residual_device_info(void) { int i; @@ -728,7 +727,6 @@ void print_residual_device_info(void) } #endif -#endif /* 0 */ /* Returns the device index in the residual data, any of the search items may be set as -1 for wildcard, DevID number field (second halfword) is big endian ! @@ -765,7 +763,7 @@ in this rarely used area we unencode and compare */ little endian in the heap, so we use two parameters to avoid writing two very similar functions */ -static int same_DevID(unsigned short vendor, +static int __init same_DevID(unsigned short vendor, unsigned short Number, char * str) { @@ -781,7 +779,7 @@ static int same_DevID(unsigned short vendor, return 0; } -PPC_DEVICE *residual_find_device(unsigned long BusMask, +PPC_DEVICE __init *residual_find_device(unsigned long BusMask, unsigned char * DevID, int BaseType, int SubType, @@ -804,6 +802,28 @@ PPC_DEVICE *residual_find_device(unsigned long BusMask, return 0; } +PPC_DEVICE __init *residual_find_device_id(unsigned long BusMask, + unsigned short DevID, + int BaseType, + int SubType, + int Interface, + int n) +{ + int i; + if ( !res->ResidualLength ) return NULL; + for (i=0; i<res->ActualNumDevices; i++) { +#define Dev res->Devices[i].DeviceId + if ( (Dev.BusId&BusMask) && + (BaseType==-1 || Dev.BaseType==BaseType) && + (SubType==-1 || Dev.SubType==SubType) && + (Interface==-1 || Dev.Interface==Interface) && + (DevID==0xffff || (Dev.DevId&0xffff) == DevID) && + !(n--) ) return res->Devices+i; +#undef Dev + } + return 0; +} + PnP_TAG_PACKET *PnP_find_packet(unsigned char *p, unsigned packet_tag, int n) @@ -823,7 +843,7 @@ PnP_TAG_PACKET *PnP_find_packet(unsigned char *p, return 0; /* not found */ } -PnP_TAG_PACKET *PnP_find_small_vendor_packet(unsigned char *p, +PnP_TAG_PACKET __init *PnP_find_small_vendor_packet(unsigned char *p, unsigned packet_type, int n) { @@ -837,7 +857,7 @@ PnP_TAG_PACKET *PnP_find_small_vendor_packet(unsigned char *p, return 0; /* not found */ } -PnP_TAG_PACKET *PnP_find_large_vendor_packet(unsigned char *p, +PnP_TAG_PACKET __init *PnP_find_large_vendor_packet(unsigned char *p, unsigned packet_type, int n) { @@ -850,4 +870,3 @@ PnP_TAG_PACKET *PnP_find_large_vendor_packet(unsigned char *p, }; return 0; /* not found */ } - diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 7ea277866..706c1dde2 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -1,9 +1,10 @@ /* - * $Id: setup.c,v 1.95 1998/07/20 19:03:47 geert Exp $ + * $Id: setup.c,v 1.117 1998/11/09 19:55:53 geert Exp $ * Common prep/pmac/chrp boot and setup code. */ #include <linux/config.h> +#include <linux/module.h> #include <linux/string.h> #include <linux/sched.h> #include <linux/init.h> @@ -23,15 +24,22 @@ #include <asm/bootinfo.h> #include <asm/setup.h> #include <asm/amigappc.h> +#include <asm/smp.h> #ifdef CONFIG_MBX #include <asm/mbx.h> #endif +#include <asm/bootx.h> /* APUS defs */ extern unsigned long m68k_machtype; -extern struct mem_info ramdisk; extern int parse_bootinfo(const struct bi_record *); extern char _end[]; +#ifdef CONFIG_APUS +struct mem_info ramdisk; +unsigned long isa_io_base; +unsigned long isa_mem_base; +unsigned long pci_dram_offset; +#endif /* END APUS defs */ extern char cmd_line[512]; @@ -52,6 +60,8 @@ RESIDUAL *res = (RESIDUAL *)&__res; int _prep_type; +extern boot_infos_t *boot_infos; + /* * Perhaps we can put the pmac screen_info[] here * on pmac as well so we don't need the ifdef's. @@ -122,9 +132,7 @@ void machine_restart(char *cmd) cuda_poll(); break; case ADB_VIAPMU: - pmu_request(&req, NULL, 1, PMU_RESET); - for (;;) - pmu_poll(); + pmu_restart(); break; default: } @@ -197,10 +205,7 @@ void machine_power_off(void) cuda_poll(); break; case ADB_VIAPMU: - pmu_request(&req, NULL, 5, PMU_SHUTDOWN, - 'M', 'A', 'T', 'T'); - for (;;) - pmu_poll(); + pmu_shutdown(); break; default: } @@ -217,10 +222,7 @@ void machine_power_off(void) case _MACH_prep: machine_restart(NULL); case _MACH_apus: -#if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF) - apm_set_power_state(APM_STATE_OFF); for (;;); -#endif } for (;;); #else /* CONFIG_MBX */ @@ -239,14 +241,16 @@ void machine_halt(void) } -#ifdef CONFIG_BLK_DEV_IDE +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq) { #if !defined(CONFIG_MBX) && !defined(CONFIG_APUS) switch (_machine) { +#if defined(CONFIG_BLK_DEV_IDE_PMAC) case _MACH_Pmac: - pmac_ide_init_hwif_ports(p,base,irq); + pmac_ide_init_hwif_ports(p,base,irq); break; +#endif case _MACH_chrp: chrp_ide_init_hwif_ports(p,base,irq); break; @@ -256,72 +260,36 @@ void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq) } #endif } +EXPORT_SYMBOL(ide_init_hwif_ports); #endif unsigned long cpu_temp(void) { -#if 0 - unsigned long i, temp, thrm1, dir; - int sanity; + unsigned char thres = 0; - /* - * setup thrm3 - need to give TAU at least 20us - * to do the compare so assume a 300MHz clock. - * We need 300*20 ticks then. - * -- Cort - */ - asm("mtspr 1020, %1\n\t" - "mtspr 1021, %1\n\t" - "mtspr 1022, %0\n\t":: - "r" ( ((300*20)<<18) | THRM3_E), "r" (0) ); - #if 0 - for ( i = 127 ; i >= 0 ; i-- ) - { - asm("mtspr 1020, %0\n\t":: - "r" (THRM1_TID|THRM1_V|(i<<2)) ); - /* check value */ - while ( !( thrm1 & THRM1_TIV) ) - asm("mfspr %0, 1020 \n\t": "=r" (thrm1) ); - if ( thrm1 & THRM1_TIN ) - { - printk("tin set: %x tiv %x\n", thrm1,thrm1&THRM1_TIV); - goto out; - } - - } + /* disable thrm2 */ + _set_THRM2( 0 ); + /* threshold 0 C, tid: exceeding threshold, tie: don't generate interrupt */ + _set_THRM1( THRM1_V ); + + /* we need 20us to do the compare - assume 300MHz processor clock */ + _set_THRM3(0); + _set_THRM3(THRM3_E | (300*30)<<18 ); + + udelay(100); + /* wait for the compare to complete */ + /*while ( !(_get_THRM1() & THRM1_TIV) ) ;*/ + if ( !(_get_THRM1() & THRM1_TIV) ) + printk("no tiv\n"); + if ( _get_THRM1() & THRM1_TIN ) + printk("crossed\n"); + /* turn everything off */ + _set_THRM3(0); + _set_THRM1(0); #endif -#if 0 - i = 32; /* increment */ - dir = 1; /* direction we're checking 0=up 1=down */ - temp = 64; /* threshold checking against */ - while ( i ) - { - _set_THRM1((1<<29) | THRM1_V | (temp<<2) ); - printk("checking %d in dir %d thrm set to %x/%x\n", temp,dir, - ( (1<<29) | THRM1_V | (temp<<2)),_get_THRM1()); - /* check value */ - sanity = 0x0fffffff; - while ( (!( thrm1 & THRM1_TIV)) && (sanity--) ) - thrm1 = _get_THRM1(); - /*asm("mfspr %0, 1020 \n\t": "=r" (thrm1) );*/ - if ( ! sanity || sanity==0xffffffff ) printk("no sanity\n"); - /* temp is not in that direction */ - if ( !(thrm1 & THRM1_TIN) ) - { - printk("not in that dir thrm1 %x\n",thrm1); - if ( dir == 0 ) dir = 1; - else dir = 0; - } - if ( dir ) temp -= i; - else temp += i; - i /= 2; - } - asm("mtspr 1020, %0\n\t" - "mtspr 1022, %0\n\t" ::"r" (0) ); -#endif -#endif - return 0; + + return thres; } int get_cpuinfo(char *buffer) @@ -333,14 +301,13 @@ int get_cpuinfo(char *buffer) unsigned long len = 0; unsigned long bogosum = 0; unsigned long i; - unsigned long cr; + #ifdef __SMP__ - extern unsigned long cpu_present_map; - extern struct cpuinfo_PPC cpu_data[NR_CPUS]; +#define CPU_PRESENT(x) (cpu_callin_map[(x)]) #define GET_PVR ((long int)(cpu_data[i].pvr)) #define CD(x) (cpu_data[i].x) #else -#define cpu_present_map 1L +#define CPU_PRESENT(x) ((x)==0) #define smp_num_cpus 1 #define GET_PVR ((long int)_get_PVR()) #define CD(x) (x) @@ -348,7 +315,7 @@ int get_cpuinfo(char *buffer) for ( i = 0; i < smp_num_cpus ; i++ ) { - if ( ! ( cpu_present_map & (1<<i) ) ) + if ( !CPU_PRESENT(i) ) continue; if ( i ) len += sprintf(len+buffer,"\n"); @@ -374,14 +341,6 @@ int get_cpuinfo(char *buffer) break; case 8: len += sprintf(len+buffer, "750\n"); - cr = _get_L2CR(); - if ( cr & (0x1<<28)) cr = 256; - else if ( cr & (0x2<<28)) cr = 512; - else if ( cr & (0x3<<28)) cr = 1024; - else cr = 0; - len += sprintf(len+buffer, "on-chip l2\t: " - "%ld KB (%s)\n", - cr,(_get_L2CR()&0x80000000) ? "on" : "off"); len += sprintf(len+buffer, "temperature \t: %lu C\n", cpu_temp()); break; @@ -436,9 +395,9 @@ int get_cpuinfo(char *buffer) #else /* CONFIG_MBX */ { bd_t *bp; - extern RESIDUAL res; + extern RESIDUAL *res; - bp = (bd_t *)&res; + bp = (bd_t *)res; len += sprintf(len+buffer,"clock\t\t: %dMHz\n" "bus clock\t: %dMHz\n", @@ -510,30 +469,41 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7)) { extern void setup_pci_ptrs(void); + +#ifdef __SMP__ + if ( first_cpu_booted ) return 0; +#endif /* __SMP__ */ + #ifndef CONFIG_MBX #ifndef CONFIG_MACH_SPECIFIC - char *model; - /* prep boot loader tells us if we're prep or not */ - if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) ) - { - _machine = _MACH_prep; - have_of = 0; - } /* boot loader will tell us if we're APUS */ - else if ( r3 == 0x61707573 ) + if ( r3 == 0x61707573 ) { _machine = _MACH_apus; have_of = 0; r3 = 0; - } else - { + } + /* prep boot loader tells us if we're prep or not */ + else if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) ) { + _machine = _MACH_prep; + have_of = 0; + } else { + char *model; + have_of = 1; /* ask the OF info if we're a chrp or pmac */ - model = get_property(find_path_device("/"), "type", NULL); - if ( !strncmp("chrp",model,4) ) + model = get_property(find_path_device("/"), "device_type", NULL); + if ( model && !strncmp("chrp",model,4) ) _machine = _MACH_chrp; - else - _machine = _MACH_Pmac; + else + { + model = get_property(find_path_device("/"), + "model", NULL); + if ( model && !strncmp(model, "IBM", 3)) + _machine = _MACH_chrp; + else + _machine = _MACH_Pmac; + } } #endif /* CONFIG_MACH_SPECIFIC */ @@ -556,6 +526,20 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5, if (r3 >= 0x4000 && r3 < 0x800000 && r4 == 0) { strncpy(cmd_line, (char *)r3 + KERNELBASE, sizeof(cmd_line)); + } else if (boot_infos != 0) { + /* booted by BootX - check for ramdisk */ + if (boot_infos->kernelParamsOffset != 0) + strncpy(cmd_line, (char *) boot_infos + + boot_infos->kernelParamsOffset, + sizeof(cmd_line)); +#ifdef CONFIG_BLK_DEV_INITRD + if (boot_infos->ramDisk) { + initrd_start = (unsigned long) boot_infos + + boot_infos->ramDisk; + initrd_end = initrd_start + boot_infos->ramDiskSize; + initrd_below_start_ok = 1; + } +#endif } else { struct device_node *chosen; char *p; @@ -568,6 +552,7 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5, ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); } #endif + cmd_line[0] = 0; chosen = find_devices("chosen"); if (chosen != NULL) { p = get_property(chosen, "bootargs", NULL); @@ -652,7 +637,6 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5, break; #ifdef CONFIG_APUS case _MACH_apus: - setup_pci_ptrs(); /* Parse bootinfo. The bootinfo is located right after the kernel bss */ parse_bootinfo((const struct bi_record *)&_end); @@ -677,6 +661,7 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5, default: printk("Unknown machine type in identify_machine!\n"); } + #else /* CONFIG_MBX */ if ( r3 ) @@ -702,6 +687,12 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5, strcpy(cmd_line, (char *)(r6+KERNELBASE)); } #endif /* CONFIG_MBX */ + + /* Check for nobats option (used in mapin_ram). */ + if (strstr(cmd_line, "nobats")) { + extern int __map_without_bats; + __map_without_bats = 1; + } return 0; } @@ -722,6 +713,8 @@ __initfunc(void setup_arch(char **cmdline_p, #ifdef CONFIG_XMON extern void xmon_map_scc(void); xmon_map_scc(); + if (strstr(cmd_line, "xmon")) + xmon(0); #endif /* CONFIG_XMON */ /* reboot on panic */ @@ -739,20 +732,6 @@ __initfunc(void setup_arch(char **cmdline_p, *memory_start_p = find_available_memory(); *memory_end_p = (unsigned long) end_of_DRAM; -#ifdef CONFIG_BLK_DEV_INITRD - /* initrd_start and size are setup by boot/head.S and kernel/head.S */ - if ( initrd_start ) - { - if (initrd_end > *memory_end_p) - { - printk("initrd extends beyond end of memory " - "(0x%08lx > 0x%08lx)\ndisabling initrd\n", - initrd_end,*memory_end_p); - initrd_start = 0; - } - } -#endif - #ifdef CONFIG_MBX mbx_setup_arch(memory_start_p,memory_end_p); #else /* CONFIG_MBX */ @@ -771,7 +750,7 @@ __initfunc(void setup_arch(char **cmdline_p, m68k_machtype = MACH_AMIGA; apus_setup_arch(memory_start_p,memory_end_p); break; -#endif +#endif default: printk("Unknown machine %d in setup_arch()\n", _machine); } diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c index 6d2d4279e..3ffb7981e 100644 --- a/arch/ppc/kernel/signal.c +++ b/arch/ppc/kernel/signal.c @@ -1,7 +1,7 @@ /* * linux/arch/ppc/kernel/signal.c * - * $Id: signal.c,v 1.16 1998/06/16 23:34:10 cort Exp $ + * $Id: signal.c,v 1.21 1998/10/22 19:37:49 paulus Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -128,6 +128,13 @@ asmlinkage int sys_rt_sigreturn(unsigned long __unused) do_exit(SIGSEGV); } +asmlinkage int +sys_sigaltstack(const stack_t *uss, stack_t *uoss) +{ + struct pt_regs *regs = (struct pt_regs *) &uss; + return do_sigaltstack(uss, uoss, regs->gpr[1]); +} + int sys_sigaction(int sig, const struct old_sigaction *act, struct old_sigaction *oact) @@ -238,7 +245,7 @@ int sys_sigreturn(struct pt_regs *regs) goto badframe; sr = (struct sigregs *) sigctx.regs; regs->gpr[3] = ret = sigctx.signal; - regs->gpr[4] = (unsigned long) sr; + regs->gpr[4] = (unsigned long) sc; regs->link = (unsigned long) &sr->tramp; regs->nip = sigctx.handler; @@ -286,7 +293,7 @@ setup_frame(struct pt_regs *regs, struct sigregs *frame, || get_user(regs->gpr[3], &sc->signal)) goto badframe; regs->gpr[1] = newsp; - regs->gpr[4] = (unsigned long) frame; + regs->gpr[4] = (unsigned long) sc; regs->link = (unsigned long) frame->tramp; return; @@ -483,3 +490,4 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) setup_frame(regs, (struct sigregs *) frame, newsp); return 1; } + diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c index ca8d81de1..75445925f 100644 --- a/arch/ppc/kernel/smp.c +++ b/arch/ppc/kernel/smp.c @@ -1,5 +1,5 @@ /* - * $Id: smp.c,v 1.28 1998/08/04 04:47:45 cort Exp $ + * $Id: smp.c,v 1.36 1998/10/08 01:17:48 cort Exp $ * * Smp support for ppc. * @@ -35,22 +35,20 @@ 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,}; -volatile int __cpu_logical_map[NR_CPUS]; -static unsigned char boot_cpu_id = 0; struct cpuinfo_PPC cpu_data[NR_CPUS]; struct klock_info_struct klock_info = { KLOCK_CLEAR, 0 }; volatile unsigned char active_kernel_processor = NO_PROC_ID; /* Processor holding kernel spinlock */ volatile unsigned long ipi_count; spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; - unsigned int prof_multiplier[NR_CPUS]; unsigned int prof_counter[NR_CPUS]; +int first_cpu_booted = 0; -int start_secondary(void *); +/* all cpu mappings are 1-1 -- Cort */ +int cpu_number_map[NR_CPUS] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,}; +volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; +int start_secondary(void *); extern int cpu_idle(void *unused); void smp_local_timer_interrupt(struct pt_regs * regs) @@ -58,7 +56,6 @@ void smp_local_timer_interrupt(struct pt_regs * regs) int cpu = smp_processor_id(); extern void update_one_process(struct task_struct *,unsigned long, unsigned long,unsigned long,int); - if (!--prof_counter[cpu]) { int user=0,system=0; struct task_struct * p = current; @@ -104,7 +101,7 @@ void smp_local_timer_interrupt(struct pt_regs * regs) * Right now it only works for stop cpu's but will be setup * later for more general message passing. * - * As it is now, if we're sending two message as the same time + * As it is now, if we're sending two message at the same time * we have race conditions. I avoided doing locks here since * all that works right now is the stop cpu message. * @@ -115,17 +112,25 @@ void smp_message_recv(void) { int msg = smp_message[smp_processor_id()]; - printk("SMP %d: smp_message_recv() msg %x\n", smp_processor_id(),msg); + /* clear interrupt */ + *(volatile unsigned long *)(0xf80000c0) = ~0L; + eieio(); /* make sure msg is for us */ if ( msg == -1 ) return; -printk("recv after msg check\n"); + + ipi_count++; + /*printk("SMP %d: smp_message_recv() msg %x\n", smp_processor_id(),msg);*/ + switch( msg ) { case MSG_STOP_CPU: __cli(); while (1) ; break; + case MSG_RESCHEDULE: + current->need_resched = 1; + break; case 0xf0f0: /* syncing time bases - just return */ break; default: @@ -139,19 +144,17 @@ printk("recv after msg check\n"); void smp_send_reschedule(int cpu) { - /* for now, nothing */ + smp_message_pass(cpu, MSG_RESCHEDULE, 0, 0); } - spinlock_t mesg_pass_lock = SPIN_LOCK_UNLOCKED; void smp_message_pass(int target, int msg, unsigned long data, int wait) { - printk("SMP %d: sending smp message\n", current->processor); - - spin_lock(&mesg_pass_lock); if ( _machine != _MACH_Pmac ) return; - + /*printk("SMP %d: sending smp message\n", current->processor);*/ +if (smp_processor_id() ) printk("pass from cpu 1\n"); + spin_lock(&mesg_pass_lock); #define OTHER (~smp_processor_id() & 1) switch( target ) @@ -167,9 +170,10 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait) break; } /* interrupt secondary processor */ - /**(volatile unsigned long *)(0xf80000c0) = 0xffffffff; - eieio();*/ - *(volatile unsigned long *)(0xf80000c0) = 0; + *(volatile unsigned long *)(0xf80000c0) = ~0L; + eieio(); + *(volatile unsigned long *)(0xf80000c0) = 0L; + eieio(); /* interrupt primary */ /**(volatile unsigned long *)(0xf3019000);*/ spin_unlock(&mesg_pass_lock); @@ -177,29 +181,25 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait) __initfunc(void smp_boot_cpus(void)) { - extern unsigned long secondary_entry[]; extern struct task_struct *current_set[NR_CPUS]; - int i, timeout; + extern void __secondary_start(void); + int i; struct task_struct *p; printk("Entering SMP Mode...\n"); + + first_cpu_booted = 1; + dcbf(&first_cpu_booted); for (i = 0; i < NR_CPUS; i++) { - cpu_number_map[i] = -1; prof_counter[i] = 1; prof_multiplier[i] = 1; } - - cpu_present_map = 0; - for(i=0; i < NR_CPUS; i++) - __cpu_logical_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; - cpu_number_map[boot_cpu_id] = 0; - __cpu_logical_map[0] = boot_cpu_id; + cpu_callin_map[0] = 1; + smp_store_cpu_info(0); + active_kernel_processor = 0; + current->processor = 0; if ( _machine != _MACH_Pmac ) { @@ -207,10 +207,6 @@ __initfunc(void smp_boot_cpus(void)) return; } - /* assume a 2nd processor for now */ - cpu_present_map |= (1 << 1); - smp_num_cpus = 2; - /* create a process for second processor */ kernel_thread(start_secondary, NULL, CLONE_PID); p = task[1]; @@ -218,14 +214,16 @@ __initfunc(void smp_boot_cpus(void)) panic("No idle task for secondary processor\n"); p->processor = 1; current_set[1] = p; + /* need to flush here since secondary bat's aren't setup */ - dcbf((volatile unsigned long *)¤t_set[1]); - + dcbf((void *)¤t_set[1]); /* setup entry point of secondary processor */ - *(volatile unsigned long *)(0xf2800000) - = (unsigned long)secondary_entry-KERNELBASE; + *(volatile unsigned long *)(0xf2800000) = + (unsigned long)__secondary_start-KERNELBASE; eieio(); /* interrupt secondary to begin executing code */ + *(volatile unsigned long *)(0xf80000c0) = ~0L; + eieio(); *(volatile unsigned long *)(0xf80000c0) = 0L; eieio(); /* @@ -234,24 +232,23 @@ __initfunc(void smp_boot_cpus(void)) * calibrate_delay() so use this value that I found through * experimentation. -- Cort */ - udelay(1); + for ( i = 1000; i && !cpu_callin_map[1] ; i-- ) + udelay(100); + if(cpu_callin_map[1]) { - cpu_number_map[1] = 1; - __cpu_logical_map[i] = 1; - printk("Processor 1 found.\n"); - + printk("Processor %d found.\n", smp_num_cpus); + smp_num_cpus++; #if 0 /* this sync's the decr's, but we don't want this now -- Cort */ set_dec(decrementer_count); #endif - /* interrupt secondary to start decr's again */ - smp_message_pass(1,0xf0f0, 0, 0); - /* interrupt secondary to begin executing code */ - /**(volatile unsigned long *)(0xf80000c0) = 0L; - eieio();*/ } else { - smp_num_cpus--; - printk("Processor %d is stuck.\n", 1); + printk("Processor %d is stuck. \n", smp_num_cpus); } + /* reset the entry point so if we get another intr we won't + * try to startup again */ + *(volatile unsigned long *)(0xf2800000) = 0x100; + /* send interrupt to other processors to start decr's on all cpus */ + smp_message_pass(1,0xf0f0, 0, 0); } __initfunc(void smp_commence(void)) @@ -271,7 +268,7 @@ __initfunc(void initialize_secondary(void)) } /* Activate a secondary processor. */ -__initfunc(int start_secondary(void *unused)) +asmlinkage int __init start_secondary(void *unused) { printk("SMP %d: start_secondary()\n",current->processor); smp_callin(); @@ -281,16 +278,14 @@ __initfunc(int start_secondary(void *unused)) __initfunc(void smp_callin(void)) { printk("SMP %d: smp_callin()\n",current->processor); - smp_store_cpu_info(1); + smp_store_cpu_info(current->processor); set_dec(decrementer_count); 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; - - /* assume we're just the secondary processor for now */ - cpu_callin_map[1] = 1; + cpu_callin_map[current->processor] = current->processor; while(!smp_commenced) barrier(); __sti(); @@ -310,6 +305,7 @@ __initfunc(void smp_store_cpu_info(int id)) { struct cpuinfo_PPC *c = &cpu_data[id]; + /* assume bogomips are same for everything */ 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 91a8d0ccf..b97456226 100644 --- a/arch/ppc/kernel/syscalls.c +++ b/arch/ppc/kernel/syscalls.c @@ -209,7 +209,7 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, goto out; } - /*flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);*/ + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); ret = do_mmap(file, addr, len, prot, flags, offset); out: unlock_kernel(); diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c index 0857c2633..8bada0e69 100644 --- a/arch/ppc/kernel/time.c +++ b/arch/ppc/kernel/time.c @@ -1,5 +1,5 @@ /* - * $Id: time.c,v 1.35 1998/07/24 11:05:47 geert Exp $ + * $Id: time.c,v 1.36 1998/10/10 12:16:08 geert Exp $ * Common time routines among all ppc machines. * * Written by Cort Dougan (cort@cs.nmt.edu) to merge @@ -106,7 +106,12 @@ void timer_interrupt(struct pt_regs * regs) #ifdef __SMP__ smp_local_timer_interrupt(regs); #endif - +#ifdef CONFIG_APUS + { + extern void apus_heartbeat (void); + apus_heartbeat (); + } +#endif hardirq_exit(cpu); /* restore the HID0 in case dcache was off - see idle.c * this hack should leave for a better solution -- Cort */ diff --git a/arch/ppc/kernel/totalmp.c b/arch/ppc/kernel/totalmp.c new file mode 100644 index 000000000..5f87755a7 --- /dev/null +++ b/arch/ppc/kernel/totalmp.c @@ -0,0 +1,109 @@ +/* + * $Id: totalmp.c,v 1.5 1998/08/26 13:58:50 cort Exp $ + * + * Support for Total Impact's TotalMP PowerPC accelerator board. + * + * Written by Cort Dougan (cort@cs.nmt.edu) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/openpic.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/mm.h> + +#include <asm/io.h> + +extern void totalmp_init(void); + +extern inline void openpic_writefield(volatile u_int *addr, u_int mask, + u_int field); +__initfunc(void totalmp_init(void)) +{ + struct pci_dev *dev; + u32 val; + unsigned long ctl_area, ctl_area_phys; + + /* it's a pci card */ + if ( !pci_present() ) return; + + /* search for a MPIC. For now, we assume + * only one TotalMP card installed. -- Cort + */ + for(dev=pci_devices; dev; dev=dev->next) + { + if ( (dev->vendor == PCI_VENDOR_ID_IBM) + && ((dev->device == PCI_DEVICE_ID_IBM_MPIC) + || (dev->device==PCI_DEVICE_ID_IBM_MPIC_2)) ) + { + break; + } + } + + if ( !dev ) return; + + OpenPIC = (struct OpenPIC *)bus_to_virt(dev->base_address[0]); +#if 0 + if ( (ulong)OpenPIC > 0x10000000 ) + { + printk("TotalMP: relocating base %lx -> %lx\n", + (ulong)OpenPIC, ((ulong)OpenPIC & 0x00FFFFFF) | 0x01000000); + OpenPIC = (struct OpenPIC *)(((ulong)OpenPIC & 0x00FFFFFF) | 0x01000000); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, (ulong)OpenPIC); + }*/ +#endif + OpenPIC = (struct OpenPIC *)((ulong)OpenPIC + _IO_BASE); + + openpic_init(0); + + /* put openpic in 8259-cascade mode */ + openpic_writefield(&OpenPIC->Global.Global_Configuration0, 0, 0x20000000); + /* set ipi to highest priority */ + openpic_writefield(&OpenPIC->Global._IPI_Vector_Priority[0].Reg, 0, 0x000f0000); + + /* allocate and remap the control area to be no-cache */ + ctl_area = __get_free_pages(GFP_ATOMIC, 3); + ctl_area_phys = (unsigned long) virt_to_phys((void *)ctl_area); + ctl_area = (unsigned long)ioremap(ctl_area, 0x8000); + + /* soft reset cpu 0 */ + pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &val); + openpic_writefield(&OpenPIC->Global._Processor_Initialization.Reg, 0, 0x1); + + /* wait for base address reg to change, signaling that cpu 0 is done */ +#define wait_for(where) { \ + udelay(100); \ + pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &val); \ + if ( val != 0x77700000 ) \ + { \ + printk("TotalMP: CPU0 did not respond: val %x %d\n", val, where); \ + /*free_pages((ulong)phys_to_virt(ctl_area_phys),1);*/ \ + return; \ + } } + + /* tell cpu0 where the control area is */ + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0,(~val) >> 16); + wait_for(0); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, + ((ulong)ctl_area & 0xff000000)>>20); + wait_for(1); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, + ((ulong)ctl_area & 0x00ff0000)>>12); + wait_for(2); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, + ((ulong)ctl_area & 0x0000ff00)>>4); + wait_for(3); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, + ((ulong)ctl_area & 0x000000ff)<<4); + wait_for(4); +#undef wait_for + /* wait for cpu0 to "sign-on" */ +} + |