diff options
| author | Paul Mackerras <paulus@tango.paulus.ozlabs.org> | 2002-02-11 20:41:44 +1100 |
|---|---|---|
| committer | Paul Mackerras <paulus@tango.paulus.ozlabs.org> | 2002-02-11 20:41:44 +1100 |
| commit | db7bfdb0276574b29618179004ced1de8dcf40c0 (patch) | |
| tree | f65179bd228616f902065bc92a96ad394f4b0097 /arch/ppc/kernel | |
| parent | 0dc68d77428413d0f417df3a378f857a2e798ebf (diff) | |
Import arch/ppc and include/asm-ppc changes from linuxppc_2_5 tree
Diffstat (limited to 'arch/ppc/kernel')
99 files changed, 11750 insertions, 16789 deletions
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index 59236099d7a9..d00aacf316d8 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.Makefile 1.34 10/16/01 15:58:42 trini +# BK Id: %F% %I% %G% %U% %#% # # # Makefile for the linux kernel. @@ -14,17 +14,24 @@ USE_STANDARD_AS_RULE := true ifdef CONFIG_PPC64BRIDGE EXTRA_AFLAGS := -Wa,-mppc64bridge endif +ifdef CONFIG_4xx +EXTRA_AFLAGS := -Wa,-m405 +endif + +CFLAGS_prom_init.o += -mrelocatable-lib +CFLAGS_btext.o += -mrelocatable-lib # Start off with 'head.o', change as needed. HEAD-y := head.o HEAD-$(CONFIG_4xx) := head_4xx.o HEAD-$(CONFIG_8xx) := head_8xx.o +HEAD-$(CONFIG_PPC_ISERIES) := iSeries_head.o all: $(HEAD-y) kernel.o O_TARGET := kernel.o -export-objs := ppc_ksyms.o prep_setup.o time.o +export-objs := ppc_ksyms.o time.o ppc405_dma.o obj-y := entry.o traps.o irq.o idle.o time.o misc.o \ process.o signal.o ptrace.o align.o \ @@ -32,16 +39,20 @@ obj-y := entry.o traps.o irq.o idle.o time.o misc.o \ cputable.o ppc_htab.o obj-$(CONFIG_6xx) += l2cr.o obj-$(CONFIG_MODULES) += ppc_ksyms.o -obj-$(CONFIG_POWER4) += xics.o -obj-$(CONFIG_PCI) += pci.o pci-dma.o +obj-$(CONFIG_PCI) += pci.o +ifneq ($(CONFIG_PPC_ISERIES),y) +obj-$(CONFIG_PCI) += pci-dma.o +endif obj-$(CONFIG_KGDB) += ppc-stub.o obj-$(CONFIG_SMP) += smp.o -obj-$(CONFIG_4xx) += ppc4xx_pic.o -obj-$(CONFIG_OAK) += oak_setup.o -obj-$(CONFIG_WALNUT) += walnut_setup.o obj-$(CONFIG_TAU) += temp.o -ifeq ($(CONFIG_WALNUT),y) -obj-$(CONFIG_PCI) += galaxy_pci.o +ifeq ($(CONFIG_4xx),y) +obj-$(CONFIG_4xx) += ppc4xx_setup.o ppc4xx_pic.o ppc4xx_serial.o +obj-$(CONFIG_PPC_RTC) += todc_time.o +obj-$(CONFIG_KGDB) += ppc4xx_kgdb.o +obj-$(CONFIG_405_DMA) += ppc405_dma.o +obj-$(CONFIG_PCI) += ppc405_pci.o indirect_pci.o pci_auto.o +obj-$(CONFIG_PM) += ppc4xx_pm.o endif obj-$(CONFIG_8xx) += m8xx_setup.o ppc8xx_pic.o ifeq ($(CONFIG_8xx),y) @@ -51,28 +62,41 @@ obj-y += softemu8xx.o endif endif obj-$(CONFIG_MBX) += i8259.o -obj-$(CONFIG_APUS) += apus_setup.o -ifeq ($(CONFIG_APUS),y) -obj-$(CONFIG_PCI) += apus_pci.o -endif -obj-$(CONFIG_ALL_PPC) += pmac_pic.o pmac_setup.o pmac_time.o prom.o \ - feature.o pmac_pci.o chrp_setup.o \ - chrp_time.o chrp_pci.o open_pic.o \ - indirect_pci.o i8259.o prep_pci.o \ - prep_time.o prep_nvram.o prep_setup.o -obj-$(CONFIG_NVRAM) += pmac_nvram.o -obj-$(CONFIG_PMAC_BACKLIGHT) += pmac_backlight.o -obj-$(CONFIG_PMAC_PBOOK) += sleep.o -obj-$(CONFIG_PREP_RESIDUAL) += residual.o -obj-$(CONFIG_PPC_RTAS) += error_log.o proc_rtas.o -obj-$(CONFIG_GEMINI) += gemini_prom.o gemini_pci.o gemini_setup.o \ - open_pic.o +obj-$(CONFIG_ALL_PPC) += prom_init.o prom.o open_pic.o \ + indirect_pci.o i8259.o +obj-$(CONFIG_ADIR) += i8259.o indirect_pci.o pci_auto.o \ + todc_time.o +obj-$(CONFIG_EV64260) += gt64260_common.o gt64260_pic.o \ + indirect_pci.o todc_time.o pci_auto.o +obj-$(CONFIG_GEMINI) += open_pic.o +obj-$(CONFIG_K2) += i8259.o indirect_pci.o todc_time.o \ + pci_auto.o +obj-$(CONFIG_LOPEC) += mpc10x_common.o indirect_pci.o pci_auto.o \ + open_pic.o i8259.o todc_time.o +obj-$(CONFIG_MCPN765) += todc_time.o indirect_pci.o pci_auto.o \ + open_pic.o i8259.o pplus_common.o +obj-$(CONFIG_MENF1) += todc_time.o i8259.o mpc10x_common.o \ + pci_auto.o indirect_pci.o +obj-$(CONFIG_MVME5100) += open_pic.o todc_time.o indirect_pci.o \ + i8259.o pci_auto.o pplus_common.o +obj-$(CONFIG_PCORE) += mpc10x_common.o todc_time.o i8259.o \ + indirect_pci.o pci_auto.o +obj-$(CONFIG_POWERPMC250) += open_pic.o mpc10x_common.o \ + indirect_pci.o pci_auto.o +obj-$(CONFIG_PPLUS) += pplus_common.o open_pic.o i8259.o \ + indirect_pci.o todc_time.o pci_auto.o +obj-$(CONFIG_PRPMC750) += open_pic.o indirect_pci.o pci_auto.o \ + pplus_common.o +obj-$(CONFIG_PRPMC800) += open_pic.o indirect_pci.o pci_auto.o \ + pplus_common.o harrier.o +obj-$(CONFIG_SANDPOINT) += i8259.o open_pic.o mpc10x_common.o \ + pci_auto.o indirect_pci.o todc_time.o +obj-$(CONFIG_SPRUCE) += indirect_pci.o pci_auto.o todc_time.o +obj-$(CONFIG_ZX4500) += indirect_pci.o pci_auto.o mpc10x_common.o \ + i8259.o open_pic.o obj-$(CONFIG_8260) += m8260_setup.o ppc8260_pic.o obj-$(CONFIG_BOOTX_TEXT) += btext.o - -ifeq ($(CONFIG_SMP),y) -obj-$(CONFIG_ALL_PPC) += pmac_smp.o chrp_smp.o -endif +obj-$(CONFIG_PPC_ISERIES) += iSeries_misc.o include $(TOPDIR)/Rules.make @@ -82,7 +106,8 @@ l2cr.o: l2cr.S ppc_defs.h head.o: head.S ppc_defs.h head_4xx.o: head_4xx.S ppc_defs.h head_8xx.o: head_8xx.S ppc_defs.h -gemini_prom.o: gemini_prom.S ppc_defs.h +iSeries_head.o: iSeries_head.S ppc_defs.h +iSeries_misc.o: iSeries_misc.S ppc_defs.h ppc_defs.h: mk_defs.c ppc_defs.head \ $(TOPDIR)/include/asm/mmu.h \ @@ -102,4 +127,3 @@ find_name : find_name.c checks: checks.c $(HOSTCC) -I$(HPATH) $(HOSTCFLAGS) -D__KERNEL__ -fno-builtin -o checks checks.c ./checks - diff --git a/arch/ppc/kernel/align.c b/arch/ppc/kernel/align.c index 4edb4616848c..0f8dbd1cb585 100644 --- a/arch/ppc/kernel/align.c +++ b/arch/ppc/kernel/align.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.align.c 1.5 05/17/01 18:14:21 cort + * BK Id: %F% %I% %G% %U% %#% */ /* * align.c - handle alignment exceptions for the Power PC. @@ -24,7 +24,7 @@ struct aligninfo { unsigned char flags; }; -#if defined(CONFIG_4xx) || defined(CONFIG_POWER4) +#if defined(CONFIG_4xx) #define OPCD(inst) (((inst) & 0xFC000000) >> 26) #define RS(inst) (((inst) & 0x03E00000) >> 21) #define RA(inst) (((inst) & 0x001F0000) >> 16) @@ -187,7 +187,7 @@ int fix_alignment(struct pt_regs *regs) { int instr, nb, flags; -#if defined(CONFIG_4xx) || defined(CONFIG_POWER4) +#if defined(CONFIG_4xx) int opcode, f1, f2, f3; #endif int i, t; @@ -200,11 +200,9 @@ fix_alignment(struct pt_regs *regs) unsigned char v[8]; } data; -#if defined(CONFIG_4xx) || defined(CONFIG_POWER4) +#if defined(CONFIG_4xx) /* The 4xx-family processors have no DSISR register, * so we emulate it. - * The POWER4 has a DSISR register but doesn't set it on - * an alignment fault. -- paulus */ instr = *((unsigned int *)regs->nip); diff --git a/arch/ppc/kernel/apus_pci.c b/arch/ppc/kernel/apus_pci.c deleted file mode 100644 index 95367ff771f5..000000000000 --- a/arch/ppc/kernel/apus_pci.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - * BK Id: SCCS/s.apus_pci.c 1.5 09/08/01 15:47:42 paulus - */ -/* - * Copyright (C) Michel Dänzer <michdaen@iiic.ethz.ch> - * - * APUS PCI routines. - * - * Currently, only B/CVisionPPC cards (Permedia2) are supported. - * - * Thanks to Geert Uytterhoeven for the idea: - * Read values from given config space(s) for the first devices, -1 otherwise - * - */ - -#include <linux/config.h> -#ifdef CONFIG_AMIGA - -#include <linux/kernel.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/string.h> - -#include <asm/io.h> -#include <asm/pci-bridge.h> -#include <asm/machdep.h> - -#include "apus_pci.h" - - -/* These definitions are mostly adapted from pm2fb.c */ - -#undef APUS_PCI_MASTER_DEBUG -#ifdef APUS_PCI_MASTER_DEBUG -#define DPRINTK(a,b...) printk(KERN_DEBUG "apus_pci: %s: " a, __FUNCTION__ , ## b) -#else -#define DPRINTK(a,b...) -#endif - -/* - * The _DEFINITIVE_ memory mapping/unmapping functions. - * This is due to the fact that they're changing soooo often... - */ -#define DEFW() wmb() -#define DEFR() rmb() -#define DEFRW() mb() - -#define DEVNO(d) ((d)>>3) -#define FNNO(d) ((d)&7) - - -extern unsigned long powerup_PCI_present; - -static struct pci_controller *apus_hose; - - -void *pci_io_base(unsigned int bus) -{ - return 0; -} - - -#define cfg_read(val, addr, type, op) *val = op((type)(addr)) -#define cfg_write(val, addr, type, op) op((val), (type *)(addr)); DEFW() -#define cfg_read_bad *val = ~0; -#define cfg_write_bad ; -#define cfg_read_val(val) *val -#define cfg_write_val(val) val - -#define APUS_PCI_OP(rw, size, type, op, mask) \ -int \ -apus_pcibios_##rw##_config_##size(struct pci_dev *dev, int offset, type val) \ -{ \ - int fnno = FNNO(dev->devfn); \ - int devno = DEVNO(dev->devfn); \ - \ - if (dev->bus->number > 0 || devno != 1) { \ - cfg_##rw##_bad; \ - return PCIBIOS_DEVICE_NOT_FOUND; \ - } \ - /* base address + function offset + offset ^ endianness conversion */ \ - cfg_##rw(val, apus_hose->cfg_data + (fnno<<5) + (offset ^ mask), \ - type, op); \ - \ - DPRINTK(#op " b: 0x%x, d: 0x%x, f: 0x%x, o: 0x%x, v: 0x%x\n", \ - dev->bus->number, dev->devfn>>3, dev->devfn&7, \ - offset, cfg_##rw##_val(val)); \ - return PCIBIOS_SUCCESSFUL; \ -} - -APUS_PCI_OP(read, byte, u8 *, readb, 3) -APUS_PCI_OP(read, word, u16 *, readw, 2) -APUS_PCI_OP(read, dword, u32 *, readl, 0) -APUS_PCI_OP(write, byte, u8, writeb, 3) -APUS_PCI_OP(write, word, u16, writew, 2) -APUS_PCI_OP(write, dword, u32, writel, 0) - - -static struct pci_ops apus_pci_ops = { - apus_pcibios_read_config_byte, - apus_pcibios_read_config_word, - apus_pcibios_read_config_dword, - apus_pcibios_write_config_byte, - apus_pcibios_write_config_word, - apus_pcibios_write_config_dword -}; - -static struct resource pci_mem = { "B/CVisionPPC PCI mem", CVPPC_FB_APERTURE_ONE, CVPPC_PCI_CONFIG, IORESOURCE_MEM }; - -void __init -apus_pcibios_fixup(void) -{ -/* struct pci_dev *dev = pci_find_slot(0, 1<<3); - unsigned int reg, val, offset;*/ - - /* FIXME: interrupt? */ - /*dev->interrupt = xxx;*/ - - request_resource(&iomem_resource, &pci_mem); - printk("%s: PCI mem resource requested\n", __FUNCTION__); -} - -static void __init apus_pcibios_fixup_bus(struct pci_bus *bus) -{ - bus->resource[1] = &pci_mem; -} - - -/* - * This is from pm2fb.c again - * - * Check if PCI (B/CVisionPPC) is available, initialize it and set up - * the pcibios_* pointers - */ - - -void __init -apus_setup_pci_ptrs(void) -{ - if (!powerup_PCI_present) { - DPRINTK("no PCI bridge detected\n"); - return; - } - DPRINTK("Phase5 B/CVisionPPC PCI bridge detected.\n"); - - apus_hose = pcibios_alloc_controller(); - if (!apus_hose) { - printk("apus_pci: Can't allocate PCI controller structure\n"); - return; - } - - if (!(apus_hose->cfg_data = ioremap(CVPPC_PCI_CONFIG, 256))) { - printk("apus_pci: unable to map PCI config region\n"); - return; - } - - if (!(apus_hose->cfg_addr = ioremap(CSPPC_PCI_BRIDGE, 256))) { - printk("apus_pci: unable to map PCI bridge\n"); - return; - } - - writel(CSPPCF_BRIDGE_BIG_ENDIAN, apus_hose->cfg_addr + CSPPC_BRIDGE_ENDIAN); - DEFW(); - - writel(CVPPC_REGS_REGION, apus_hose->cfg_data+ PCI_BASE_ADDRESS_0); - DEFW(); - writel(CVPPC_FB_APERTURE_ONE, apus_hose->cfg_data + PCI_BASE_ADDRESS_1); - DEFW(); - writel(CVPPC_FB_APERTURE_TWO, apus_hose->cfg_data + PCI_BASE_ADDRESS_2); - DEFW(); - writel(CVPPC_ROM_ADDRESS, apus_hose->cfg_data + PCI_ROM_ADDRESS); - DEFW(); - - writel(0xef000000 | PCI_COMMAND_IO | PCI_COMMAND_MEMORY | - PCI_COMMAND_MASTER, apus_hose->cfg_data + PCI_COMMAND); - DEFW(); - - apus_hose->first_busno = 0; - apus_hose->last_busno = 0; - apus_hose->ops = &apus_pci_ops; - ppc_md.pcibios_fixup = apus_pcibios_fixup; - ppc_md.pcibios_fixup_bus = apus_pcibios_fixup_bus; - - return; -} - -#endif /* CONFIG_AMIGA */ diff --git a/arch/ppc/kernel/apus_pci.h b/arch/ppc/kernel/apus_pci.h deleted file mode 100644 index c245dcfce835..000000000000 --- a/arch/ppc/kernel/apus_pci.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * BK Id: SCCS/s.apus_pci.h 1.4 05/17/01 18:14:21 cort - */ -/* - * Phase5 CybervisionPPC (TVP4020) definitions for the Permedia2 framebuffer - * driver. - * - * Copyright (c) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT) - * -------------------------------------------------------------------------- - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file README.legal in the main directory of this archive - * for more details. - */ - -#ifndef APUS_PCI_H -#define APUS_PCI_H - - -#include "pci.h" - - -#define CSPPC_PCI_BRIDGE 0xfffe0000 -#define CSPPC_BRIDGE_ENDIAN 0x0000 -#define CSPPC_BRIDGE_INT 0x0010 - -#define CVPPC_PCI_CONFIG 0xfffc0000 -#define CVPPC_ROM_ADDRESS 0xe2000001 -#define CVPPC_REGS_REGION 0xef000000 -#define CVPPC_FB_APERTURE_ONE 0xe0000000 -#define CVPPC_FB_APERTURE_TWO 0xe1000000 -#define CVPPC_FB_SIZE 0x00800000 - -/* CVPPC_BRIDGE_ENDIAN */ -#define CSPPCF_BRIDGE_BIG_ENDIAN 0x02 - -/* CVPPC_BRIDGE_INT */ -#define CSPPCF_BRIDGE_ACTIVE_INT2 0x01 - - -#endif /* APUS_PCI_H */ diff --git a/arch/ppc/kernel/apus_setup.c b/arch/ppc/kernel/apus_setup.c deleted file mode 100644 index c3fe77cde972..000000000000 --- a/arch/ppc/kernel/apus_setup.c +++ /dev/null @@ -1,1113 +0,0 @@ -/* - * BK Id: SCCS/s.apus_setup.c 1.24 11/13/01 21:26:07 paulus - */ -/* - * linux/arch/ppc/kernel/apus_setup.c - * - * Copyright (C) 1998, 1999 Jesper Skov - * - * Basically what is needed to replace functionality found in - * arch/m68k allowing Amiga drivers to work under APUS. - * Bits of code and/or ideas from arch/m68k and arch/ppc files. - * - * TODO: - * This file needs a *really* good cleanup. Restructure and optimize. - * Make sure it can be compiled for non-APUS configs. Begin to move - * Amiga specific stuff into mach/amiga. - */ - -#include <linux/config.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/kd.h> -#include <linux/init.h> -#include <linux/hdreg.h> -#include <linux/blk.h> -#include <linux/pci.h> -#include <linux/seq_file.h> - -#ifdef CONFIG_APUS -#include <asm/logging.h> -#endif - -/* Needs INITSERIAL call in head.S! */ -#undef APUS_DEBUG - - -#include <linux/ide.h> -#define T_CHAR (0x0000) /* char: don't touch */ -#define T_SHORT (0x4000) /* short: 12 -> 21 */ -#define T_INT (0x8000) /* int: 1234 -> 4321 */ -#define T_TEXT (0xc000) /* text: 12 -> 21 */ - -#define T_MASK_TYPE (0xc000) -#define T_MASK_COUNT (0x3fff) - -#define D_CHAR(cnt) (T_CHAR | (cnt)) -#define D_SHORT(cnt) (T_SHORT | (cnt)) -#define D_INT(cnt) (T_INT | (cnt)) -#define D_TEXT(cnt) (T_TEXT | (cnt)) - -static u_short driveid_types[] = { - D_SHORT(10), /* config - vendor2 */ - D_TEXT(20), /* serial_no */ - D_SHORT(3), /* buf_type, buf_size - ecc_bytes */ - D_TEXT(48), /* fw_rev - model */ - D_CHAR(2), /* max_multsect - vendor3 */ - D_SHORT(1), /* dword_io */ - D_CHAR(2), /* vendor4 - capability */ - D_SHORT(1), /* reserved50 */ - D_CHAR(4), /* vendor5 - tDMA */ - D_SHORT(4), /* field_valid - cur_sectors */ - D_INT(1), /* cur_capacity */ - D_CHAR(2), /* multsect - multsect_valid */ - D_INT(1), /* lba_capacity */ - D_SHORT(194) /* dma_1word - reservedyy */ -}; - -#define num_driveid_types (sizeof(driveid_types)/sizeof(*driveid_types)) - -#include <asm/bootinfo.h> -#include <asm/setup.h> -#include <asm/amigahw.h> -#include <asm/amigaints.h> -#include <asm/amigappc.h> -#include <asm/pgtable.h> -#include <asm/io.h> -#include <asm/dma.h> -#include <asm/machdep.h> - -#include "local_irq.h" - -unsigned long m68k_machtype; -char debug_device[6] = ""; - -extern void amiga_init_IRQ(void); - -void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initdata = NULL; -/* machine dependent keyboard functions */ -int (*mach_keyb_init) (void) __initdata = NULL; -int (*mach_kbdrate) (struct kbd_repeat *) = NULL; -void (*mach_kbd_leds) (unsigned int) = NULL; -/* machine dependent irq functions */ -void (*mach_init_IRQ) (void) __initdata = NULL; -void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL; -void (*mach_get_model) (char *model) = NULL; -int (*mach_get_hardware_list) (char *buffer) = NULL; -int (*mach_get_irq_list) (struct seq_file *, void *) = NULL; -void (*mach_process_int) (int, struct pt_regs *) = NULL; -/* machine dependent timer functions */ -unsigned long (*mach_gettimeoffset) (void); -void (*mach_gettod) (int*, int*, int*, int*, int*, int*); -int (*mach_hwclk) (int, struct hwclk_time*) = NULL; -int (*mach_set_clock_mmss) (unsigned long) = NULL; -void (*mach_reset)( void ); -long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */ -#if defined(CONFIG_AMIGA_FLOPPY) -void (*mach_floppy_setup) (char *, int *) __initdata = NULL; -#endif -#ifdef CONFIG_HEARTBEAT -void (*mach_heartbeat) (int) = NULL; -extern void apus_heartbeat (void); -#endif - -extern unsigned long amiga_model; -extern unsigned decrementer_count;/* count value for 1e6/HZ microseconds */ -extern unsigned count_period_num; /* 1 decrementer count equals */ -extern unsigned count_period_den; /* count_period_num / count_period_den us */ - -int num_memory = 0; -struct mem_info memory[NUM_MEMINFO];/* memory description */ -/* FIXME: Duplicate memory data to avoid conflicts with m68k shared code. */ -int m68k_realnum_memory = 0; -struct mem_info m68k_memory[NUM_MEMINFO];/* memory description */ - -struct mem_info ramdisk; - -extern void amiga_floppy_setup(char *, int *); -extern void config_amiga(void); - -static int __60nsram = 0; - -/* for cpuinfo */ -static int __bus_speed = 0; -static int __speed_test_failed = 0; - -/********************************************** COMPILE PROTECTION */ -/* Provide some stubs that links to Amiga specific functions. - * This allows CONFIG_APUS to be removed from generic PPC files while - * preventing link errors for other PPC targets. - */ -unsigned long apus_get_rtc_time(void) -{ -#ifdef CONFIG_APUS - extern unsigned long m68k_get_rtc_time(void); - - return m68k_get_rtc_time (); -#else - return 0; -#endif -} - -int apus_set_rtc_time(unsigned long nowtime) -{ -#ifdef CONFIG_APUS - extern int m68k_set_rtc_time(unsigned long nowtime); - - return m68k_set_rtc_time (nowtime); -#else - return 0; -#endif -} - - - -/* Here some functions we don't support, but which the other ports reference */ -int pckbd_setkeycode(unsigned int scancode, unsigned int keycode) -{ - printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n"); - return 0; -} -int pckbd_getkeycode(unsigned int scancode) -{ - printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n"); - return 0; -} -int pckbd_translate(unsigned char scancode, unsigned char *keycode, - char raw_mode) -{ - printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n"); - return 0; -} -char pckbd_unexpected_up(unsigned char keycode) -{ - printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n"); - return 0; -} -void pckbd_leds(unsigned char leds) -{ - printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n"); -} -void pckbd_init_hw(void) -{ - printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n"); -} -unsigned char pckbd_sysrq_xlate[128]; - -struct pci_bus * __init pci_scan_peer_bridge(int bus) -{ - printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n"); - return NULL; -} - -/*********************************************************** SETUP */ -/* From arch/m68k/kernel/setup.c. */ -void __init apus_setup_arch(void) -{ -#ifdef CONFIG_APUS - extern char cmd_line[]; - int i; - char *p, *q; - - /* Let m68k-shared code know it should do the Amiga thing. */ - m68k_machtype = MACH_AMIGA; - - /* Parse the command line for arch-specific options. - * For the m68k, this is currently only "debug=xxx" to enable printing - * certain kernel messages to some machine-specific device. */ - 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; - } else if (!strncmp( p, "60nsram", 7 )) { - APUS_WRITE (APUS_REG_WAITSTATE, - REGWAITSTATE_SETRESET - |REGWAITSTATE_PPCR - |REGWAITSTATE_PPCW); - __60nsram = 1; - i = 1; - } - - if (i) { - /* option processed, delete it */ - if ((q = strchr( p, ' ' ))) - strcpy( p, q+1 ); - else - *p = 0; - } else { - if ((p = strchr( p, ' ' ))) ++p; - } - } - - config_amiga(); - -#if 0 /* Enable for logging - also include logging.o in Makefile rule */ - { -#define LOG_SIZE 4096 - void* base; - - /* Throw away some memory - the P5 firmare stomps on top - * of CHIP memory during bootup. - */ - amiga_chip_alloc(0x1000); - - base = amiga_chip_alloc(LOG_SIZE+sizeof(klog_data_t)); - LOG_INIT(base, base+sizeof(klog_data_t), LOG_SIZE); - } -#endif -#endif -} - -int -apus_show_cpuinfo(struct seq_file *m) -{ - extern int __map_without_bats; - extern unsigned long powerup_PCI_present; - - seq_printf(m, "machine\t\t: Amiga\n"); - seq_printf(m, "bus speed\t: %d%s", __bus_speed, - (__speed_test_failed) ? " [failed]\n" : "\n"); - seq_printf(m, "using BATs\t: %s\n", - (__map_without_bats) ? "No" : "Yes"); - seq_printf(m, "ram speed\t: %dns\n", (__60nsram) ? 60 : 70); - seq_printf(m, "PCI bridge\t: %s\n", - (powerup_PCI_present) ? "Yes" : "No"); - return 0; -} - -static 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) -{ -#ifdef CONFIG_APUS - unsigned long freq; - - /* This algorithm for determining the bus speed was - contributed by Ralph Schmidt. */ - unsigned long long start, stop; - int bus_speed; - int speed_test_failed = 0; - - { - unsigned long loop = amiga_eclock / 10; - - get_current_tb (&start); - while (loop--) { - unsigned char tmp; - - tmp = ciaa.pra; - } - 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 = 67; - freq = 16666667; - } else { - printk ("APUS: Unable to determine bus speed (%d). " - "Defaulting to 50MHz", bus_speed); - bus_speed = 50; - freq = 12500000; - speed_test_failed = 1; - } - - /* Ease diagnostics... */ - { - extern int __map_without_bats; - extern unsigned long powerup_PCI_present; - - printk ("APUS: BATs=%d, BUS=%dMHz", - (__map_without_bats) ? 0 : 1, - bus_speed); - if (speed_test_failed) - printk ("[FAILED - please report]"); - - printk (", RAM=%dns, PCI bridge=%d\n", - (__60nsram) ? 60 : 70, - (powerup_PCI_present) ? 1 : 0); - - /* 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]); - } - } - - } - - printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", - freq/1000000, freq%1000000); - tb_ticks_per_jiffy = freq / HZ; - tb_to_us = mulhwu_scale_factor(freq, 1000000); - - __bus_speed = bus_speed; - __speed_test_failed = speed_test_failed; -#endif -} - -void arch_gettod(int *year, int *mon, int *day, int *hour, - int *min, int *sec) -{ -#ifdef CONFIG_APUS - if (mach_gettod) - mach_gettod(year, mon, day, hour, min, sec); - else - *year = *mon = *day = *hour = *min = *sec = 0; -#endif -} - -/* for "kbd-reset" cmdline param */ -__init -void kbd_reset_setup(char *str, int *ints) -{ -} - -/*********************************************************** FLOPPY */ -#if defined(CONFIG_AMIGA_FLOPPY) -__init -void floppy_setup(char *str, int *ints) -{ - if (mach_floppy_setup) - mach_floppy_setup (str, ints); -} -#endif - -/*********************************************************** MEMORY */ -#define KMAP_MAX 32 -unsigned long kmap_chunks[KMAP_MAX*3]; -int kmap_chunk_count = 0; - -/* From pgtable.h */ -static __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 ) -{ - unsigned long mask, flags; - - switch (cmode) - { - case IOMAP_FULL_CACHING: - mask = ~(_PAGE_NO_CACHE | _PAGE_GUARDED); - flags = 0; - break; - case IOMAP_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_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_mm,address),address); - - address += PAGE_SIZE; - } -} - -unsigned long mm_ptov (unsigned long paddr) -{ - unsigned long ret; - if (paddr < 16*1024*1024) - ret = ZTWO_VADDR(paddr); - else { - int i; - - for (i = 0; i < kmap_chunk_count;){ - unsigned long phys = kmap_chunks[i++]; - unsigned long size = kmap_chunks[i++]; - unsigned long virt = kmap_chunks[i++]; - if (paddr >= phys - && paddr < (phys + size)){ - ret = virt + paddr - phys; - goto exit; - } - } - - ret = (unsigned long) __va(paddr); - } -exit: -#ifdef DEBUGPV - printk ("PTOV(%lx)=%lx\n", paddr, ret); -#endif - return ret; -} - -int mm_end_of_chunk (unsigned long addr, int len) -{ - if (memory[0].addr + memory[0].size == addr + len) - return 1; - return 0; -} - -/*********************************************************** CACHE */ - -#define L1_CACHE_BYTES 32 -#define MAX_CACHE_SIZE 8192 -void cache_push(__u32 addr, int length) -{ - addr = mm_ptov(addr); - - if (MAX_CACHE_SIZE < length) - length = MAX_CACHE_SIZE; - - while(length > 0){ - __asm ("dcbf 0,%0\n\t" - : : "r" (addr)); - addr += L1_CACHE_BYTES; - length -= L1_CACHE_BYTES; - } - /* Also flush trailing block */ - __asm ("dcbf 0,%0\n\t" - "sync \n\t" - : : "r" (addr)); -} - -void cache_clear(__u32 addr, int length) -{ - if (MAX_CACHE_SIZE < length) - length = MAX_CACHE_SIZE; - - addr = mm_ptov(addr); - - __asm ("dcbf 0,%0\n\t" - "sync \n\t" - "icbi 0,%0 \n\t" - "isync \n\t" - : : "r" (addr)); - - addr += L1_CACHE_BYTES; - length -= L1_CACHE_BYTES; - - while(length > 0){ - __asm ("dcbf 0,%0\n\t" - "sync \n\t" - "icbi 0,%0 \n\t" - "isync \n\t" - : : "r" (addr)); - addr += L1_CACHE_BYTES; - length -= L1_CACHE_BYTES; - } - - __asm ("dcbf 0,%0\n\t" - "sync \n\t" - "icbi 0,%0 \n\t" - "isync \n\t" - : : "r" (addr)); -} - -/****************************************************** from setup.c */ -void -apus_restart(char *cmd) -{ - cli(); - - APUS_WRITE(APUS_REG_LOCK, - REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK2); - APUS_WRITE(APUS_REG_LOCK, - REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK3); - APUS_WRITE(APUS_REG_LOCK, - REGLOCK_BLACKMAGICK2|REGLOCK_BLACKMAGICK3); - APUS_WRITE(APUS_REG_SHADOW, REGSHADOW_SELFRESET); - APUS_WRITE(APUS_REG_RESET, REGRESET_AMIGARESET); - for(;;); -} - -void -apus_power_off(void) -{ - for (;;); -} - -void -apus_halt(void) -{ - apus_restart(NULL); -} - -/****************************************************** from setup.c/IDE */ -#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) -/* - * IDE stuff. - */ - -#if 0 /* no longer used -- paulus */ -void -apus_ide_fix_driveid(struct hd_driveid *id) -{ - u_char *p = (u_char *)id; - int i, j, cnt; - u_char t; - - if (!MACH_IS_AMIGA && !MACH_IS_MAC) - return; - for (i = 0; i < num_driveid_types; i++) { - cnt = driveid_types[i] & T_MASK_COUNT; - switch (driveid_types[i] & T_MASK_TYPE) { - case T_CHAR: - p += cnt; - break; - case T_SHORT: - for (j = 0; j < cnt; j++) { - t = p[0]; - p[0] = p[1]; - p[1] = t; - p += 2; - } - break; - case T_INT: - for (j = 0; j < cnt; j++) { - t = p[0]; - p[0] = p[3]; - p[3] = t; - t = p[1]; - p[1] = p[2]; - p[2] = t; - p += 4; - } - break; - case T_TEXT: - for (j = 0; j < cnt; j += 2) { - t = p[0]; - p[0] = p[1]; - p[1] = t; - p += 2; - } - break; - } - } -} -#endif /* 0 */ - -__init -void apus_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, - ide_ioreg_t ctrl_port, int *irq) -{ - if (data_port || ctrl_port) - printk("apus_ide_init_hwif_ports: must not be called\n"); -} -#endif -/****************************************************** IRQ stuff */ - -static unsigned int apus_irq_cannonicalize(unsigned int irq) -{ - return irq; -} - -int show_apus_interrupts(struct seq_file *p, void *v) -{ -#ifdef CONFIG_APUS - extern int show_amiga_interrupts(struct seq_file *p, void *v) - - return show_amiga_interrupts(p, v); -#else - return 0; -#endif -} - -/* IPL must be between 0 and 7 */ -static inline void apus_set_IPL(unsigned long ipl) -{ - APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT); - APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK); - APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | ((~ipl) & IPLEMU_IPLMASK)); - APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT); -} - -static inline unsigned long apus_get_IPL(void) -{ - /* This returns the present IPL emulation level. */ - unsigned long __f; - APUS_READ(APUS_IPL_EMU, __f); - return ((~__f) & IPLEMU_IPLMASK); -} - -static inline unsigned long apus_get_prev_IPL(struct pt_regs* regs) -{ - /* The value saved in mq is the IPL_EMU value at the time of - interrupt. The lower bits are the current interrupt level, - the upper bits the requested level. Thus, to restore the - IPL level to the post-interrupt state, we will need to use - the lower bits. */ - unsigned long __f = regs->mq; - return ((~__f) & IPLEMU_IPLMASK); -} - - -#ifdef CONFIG_APUS -void free_irq(unsigned int irq, void *dev_id) -{ - extern void amiga_free_irq(unsigned int irq, void *dev_id); - - amiga_free_irq (irq, dev_id); -} - -int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, const char * devname, void *dev_id) -{ - extern int amiga_request_irq(unsigned int irq, - void (*handler)(int, void *, - struct pt_regs *), - unsigned long flags, - const char *devname, - void *dev_id); - - return amiga_request_irq (irq, handler, irqflags, devname, dev_id); -} - -/* In Linux/m68k the sys_request_irq deals with vectors 0-7. That's what - callers expect - but on Linux/APUS we actually use the IRQ_AMIGA_AUTO - vectors (24-31), so we put this dummy function in between to adjust - the vector argument (rather have cruft here than in the generic irq.c). */ -int sys_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, const char * devname, void *dev_id) -{ - extern int request_sysirq(unsigned int irq, - void (*handler)(int, void *, - struct pt_regs *), - unsigned long irqflags, - const char * devname, void *dev_id); - return request_sysirq(irq+IRQ_AMIGA_AUTO, handler, irqflags, - devname, dev_id); -} -#endif - -int apus_get_irq(struct pt_regs* regs) -{ -#ifdef CONFIG_APUS - int level = apus_get_IPL(); - -#ifdef __INTERRUPT_DEBUG - printk("<%d:%d>", level, apus_get_prev_IPL(regs)); -#endif - - if (0 == level) - return -8; - if (7 == level) - return -9; - - return level + IRQ_AMIGA_AUTO; -#else - return 0; -#endif -} - -void apus_post_irq(struct pt_regs* regs, int level) -{ -#ifdef __INTERRUPT_DEBUG - printk("{%d}", apus_get_prev_IPL(regs)); -#endif - /* Restore IPL to the previous value */ - apus_set_IPL(apus_get_prev_IPL(regs)); -} - -/****************************************************** keyboard */ -static int apus_kbd_setkeycode(unsigned int scancode, unsigned int keycode) -{ - return -EOPNOTSUPP; -} - -static int apus_kbd_getkeycode(unsigned int scancode) -{ - return scancode > 127 ? -EINVAL : scancode; -} - -static int apus_kbd_translate(unsigned char keycode, unsigned char *keycodep, - char raw_mode) -{ - *keycodep = keycode; - return 1; -} - -static char apus_kbd_unexpected_up(unsigned char keycode) -{ - return 0200; -} - -static void apus_kbd_leds(unsigned char leds) -{ -} - -static void apus_kbd_init_hw(void) -{ -#ifdef CONFIG_APUS - extern int amiga_keyb_init(void); - - amiga_keyb_init(); -#endif -} - - -/****************************************************** debugging */ - -/* some serial hardware definitions */ -#define SDR_OVRUN (1<<15) -#define SDR_RBF (1<<14) -#define SDR_TBE (1<<13) -#define SDR_TSRE (1<<12) - -#define AC_SETCLR (1<<15) -#define AC_UARTBRK (1<<11) - -#define SER_DTR (1<<7) -#define SER_RTS (1<<6) -#define SER_DCD (1<<5) -#define SER_CTS (1<<4) -#define SER_DSR (1<<3) - -static __inline__ void ser_RTSon(void) -{ - ciab.pra &= ~SER_RTS; /* active low */ -} - -int __debug_ser_out( unsigned char c ) -{ - custom.serdat = c | 0x100; - mb(); - while (!(custom.serdatr & 0x2000)) - barrier(); - return 1; -} - -unsigned char __debug_ser_in( void ) -{ - unsigned char c; - - /* XXX: is that ok?? derived from amiga_ser.c... */ - while( !(custom.intreqr & IF_RBF) ) - barrier(); - c = custom.serdatr; - /* clear the interrupt, so that another character can be read */ - custom.intreq = IF_RBF; - return c; -} - -int __debug_serinit( void ) -{ - unsigned long flags; - - save_flags (flags); - cli(); - - /* turn off Rx and Tx interrupts */ - custom.intena = IF_RBF | IF_TBE; - - /* clear any pending interrupt */ - custom.intreq = IF_RBF | IF_TBE; - - restore_flags (flags); - - /* - * set the appropriate directions for the modem control flags, - * and clear RTS and DTR - */ - ciab.ddra |= (SER_DTR | SER_RTS); /* outputs */ - ciab.ddra &= ~(SER_DCD | SER_CTS | SER_DSR); /* inputs */ - -#ifdef CONFIG_KGDB - /* turn Rx interrupts on for GDB */ - custom.intena = IF_SETCLR | IF_RBF; - ser_RTSon(); -#endif - - return 0; -} - -void __debug_print_hex(unsigned long x) -{ - int i; - char hexchars[] = "0123456789ABCDEF"; - - for (i = 0; i < 8; i++) { - __debug_ser_out(hexchars[(x >> 28) & 15]); - x <<= 4; - } - __debug_ser_out('\n'); - __debug_ser_out('\r'); -} - -void __debug_print_string(char* s) -{ - unsigned char c; - while((c = *s++)) - __debug_ser_out(c); - __debug_ser_out('\n'); - __debug_ser_out('\r'); -} - -static void apus_progress(char *s, unsigned short value) -{ - __debug_print_string(s); -} - -/****************************************************** init */ - -/* The number of spurious interrupts */ -volatile unsigned int num_spurious; - -#define NUM_IRQ_NODES 100 -static irq_node_t nodes[NUM_IRQ_NODES]; - -extern void (*amiga_default_handler[AUTO_IRQS])(int, void *, struct pt_regs *); - -static const char *default_names[SYS_IRQS] = { - "spurious int", "int1 handler", "int2 handler", "int3 handler", - "int4 handler", "int5 handler", "int6 handler", "int7 handler" -}; - -irq_node_t *new_irq_node(void) -{ - irq_node_t *node; - short i; - - for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--) - if (!node->handler) - return node; - - printk ("new_irq_node: out of nodes\n"); - return NULL; -} - -extern void amiga_enable_irq(unsigned int irq); -extern void amiga_disable_irq(unsigned int irq); - -struct hw_interrupt_type amiga_irqctrl = { - " Amiga ", - NULL, - NULL, - amiga_enable_irq, - amiga_disable_irq, - 0, - 0 -}; - -#define HARDWARE_MAPPED_SIZE (512*1024) -unsigned long __init apus_find_end_of_memory(void) -{ - int shadow = 0; - unsigned long total; - - /* The memory size reported by ADOS excludes the 512KB - reserved for PPC exception registers and possibly 512KB - containing a shadow of the ADOS ROM. */ - { - unsigned long size = memory[0].size; - - /* If 2MB aligned, size was probably user - specified. We can't tell anything about shadowing - in this case so skip shadow assignment. */ - if (0 != (size & 0x1fffff)){ - /* Align to 512KB to ensure correct handling - of both memfile and system specified - sizes. */ - size = ((size+0x0007ffff) & 0xfff80000); - /* If memory is 1MB aligned, assume - shadowing. */ - shadow = !(size & 0x80000); - } - - /* Add the chunk that ADOS does not see. by aligning - the size to the nearest 2MB limit upwards. */ - memory[0].size = ((size+0x001fffff) & 0xffe00000); - } - - total = memory[0].size; - - /* Remove the memory chunks that are controlled by special - Phase5 hardware. */ - - /* Remove the upper 512KB if it contains a shadow of - the ADOS ROM. FIXME: It might be possible to - disable this shadow HW. Check the booter - (ppc_boot.c) */ - if (shadow) - total -= HARDWARE_MAPPED_SIZE; - - /* Remove the upper 512KB where the PPC exception - vectors are mapped. */ - total -= HARDWARE_MAPPED_SIZE; - - /* Linux/APUS only handles one block of memory -- the one on - the PowerUP board. Other system memory is horrible slow in - comparison. The user can use other memory for swapping - using the z2ram device. */ - ram_phys_base = memory[0].addr; - return total; -} - -static void __init -apus_map_io(void) -{ - /* Map PPC exception vectors. */ - io_block_mapping(0xfff00000, 0xfff00000, 0x00020000, _PAGE_KERNEL); - /* Map chip and ZorroII memory */ - io_block_mapping(zTwoBase, 0x00000000, 0x01000000, _PAGE_IO); -} - -__init -void apus_init_IRQ(void) -{ - int i; - - for ( i = 0 ; i < NR_IRQS ; i++ ) - irq_desc[i].handler = &amiga_irqctrl; - - for (i = 0; i < NUM_IRQ_NODES; i++) - nodes[i].handler = NULL; - - for (i = 0; i < AUTO_IRQS; i++) { - if (amiga_default_handler[i] != NULL) - sys_request_irq(i, amiga_default_handler[i], - 0, default_names[i], NULL); - } - - amiga_init_IRQ(); - -} - -__init -void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - extern int parse_bootinfo(const struct bi_record *); - extern char _end[]; - - /* Parse bootinfo. The bootinfo is located right after - the kernel bss */ - parse_bootinfo((const struct bi_record *)&_end); -#ifdef CONFIG_BLK_DEV_INITRD - /* Take care of initrd if we have one. Use data from - bootinfo to avoid the need to initialize PPC - registers when kernel is booted via a PPC reset. */ - if ( ramdisk.addr ) { - initrd_start = (unsigned long) __va(ramdisk.addr); - initrd_end = (unsigned long) - __va(ramdisk.size + ramdisk.addr); - } -#endif /* CONFIG_BLK_DEV_INITRD */ - - ISA_DMA_THRESHOLD = 0x00ffffff; - - ppc_md.setup_arch = apus_setup_arch; - ppc_md.show_cpuinfo = apus_show_cpuinfo; - ppc_md.irq_cannonicalize = apus_irq_cannonicalize; - ppc_md.init_IRQ = apus_init_IRQ; - ppc_md.get_irq = apus_get_irq; - -#error Should use the ->end() member of irq_desc[x]. -- Cort - /*ppc_md.post_irq = apus_post_irq;*/ - -#ifdef CONFIG_HEARTBEAT - ppc_md.heartbeat = apus_heartbeat; - ppc_md.heartbeat_count = 1; -#endif -#ifdef APUS_DEBUG - __debug_serinit(); - ppc_md.progress = apus_progress; -#endif - ppc_md.init = NULL; - - ppc_md.restart = apus_restart; - ppc_md.power_off = apus_power_off; - ppc_md.halt = apus_halt; - - ppc_md.time_init = NULL; - ppc_md.set_rtc_time = apus_set_rtc_time; - ppc_md.get_rtc_time = apus_get_rtc_time; - ppc_md.calibrate_decr = apus_calibrate_decr; - - ppc_md.find_end_of_memory = apus_find_end_of_memory; - ppc_md.setup_io_mappings = apus_map_io; - - ppc_md.nvram_read_val = NULL; - ppc_md.nvram_write_val = NULL; - - /* These should not be used for the APUS yet, since it uses - the M68K keyboard now. */ - ppc_md.kbd_setkeycode = apus_kbd_setkeycode; - ppc_md.kbd_getkeycode = apus_kbd_getkeycode; - ppc_md.kbd_translate = apus_kbd_translate; - ppc_md.kbd_unexpected_up = apus_kbd_unexpected_up; - ppc_md.kbd_leds = apus_kbd_leds; - ppc_md.kbd_init_hw = apus_kbd_init_hw; - -#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) - ppc_ide_md.ide_init_hwif = apus_ide_init_hwif_ports; -#endif -} - - -/*************************************************** coexistence */ -void __init adbdev_init(void) -{ -} diff --git a/arch/ppc/kernel/bitops.c b/arch/ppc/kernel/bitops.c index eebbab590e0e..e61da0d1e978 100644 --- a/arch/ppc/kernel/bitops.c +++ b/arch/ppc/kernel/bitops.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.bitops.c 1.7 05/17/01 18:14:21 cort + * BK Id: %F% %I% %G% %U% %#% */ /* * Copyright (C) 1996 Paul Mackerras. @@ -21,8 +21,9 @@ void set_bit(int nr, volatile void * addr) __asm__ __volatile__(SMP_WMB "\n\ 1: lwarx %0,0,%3 \n\ - or %0,%0,%2 \n\ - stwcx. %0,0,%3 \n\ + or %0,%0,%2 \n" + PPC405_ERR77(0,%3) +" stwcx. %0,0,%3 \n\ bne 1b" SMP_MB : "=&r" (old), "=m" (*p) @@ -38,8 +39,9 @@ void clear_bit(int nr, volatile void *addr) __asm__ __volatile__(SMP_WMB "\n\ 1: lwarx %0,0,%3 \n\ - andc %0,%0,%2 \n\ - stwcx. %0,0,%3 \n\ + andc %0,%0,%2 \n" + PPC405_ERR77(0,%3) +" stwcx. %0,0,%3 \n\ bne 1b" SMP_MB : "=&r" (old), "=m" (*p) @@ -55,8 +57,9 @@ void change_bit(int nr, volatile void *addr) __asm__ __volatile__(SMP_WMB "\n\ 1: lwarx %0,0,%3 \n\ - xor %0,%0,%2 \n\ - stwcx. %0,0,%3 \n\ + xor %0,%0,%2 \n" + PPC405_ERR77(0,%3) +" stwcx. %0,0,%3 \n\ bne 1b" SMP_MB : "=&r" (old), "=m" (*p) @@ -72,8 +75,9 @@ int test_and_set_bit(int nr, volatile void *addr) __asm__ __volatile__(SMP_WMB "\n\ 1: lwarx %0,0,%4 \n\ - or %1,%0,%3 \n\ - stwcx. %1,0,%4 \n\ + or %1,%0,%3 \n" + PPC405_ERR77(0,%4) +" stwcx. %1,0,%4 \n\ bne 1b" SMP_MB : "=&r" (old), "=&r" (t), "=m" (*p) @@ -91,8 +95,9 @@ int test_and_clear_bit(int nr, volatile void *addr) __asm__ __volatile__(SMP_WMB "\n\ 1: lwarx %0,0,%4 \n\ - andc %1,%0,%3 \n\ - stwcx. %1,0,%4 \n\ + andc %1,%0,%3 \n" + PPC405_ERR77(0,%4) +" stwcx. %1,0,%4 \n\ bne 1b" SMP_MB : "=&r" (old), "=&r" (t), "=m" (*p) @@ -110,8 +115,9 @@ int test_and_change_bit(int nr, volatile void *addr) __asm__ __volatile__(SMP_WMB "\n\ 1: lwarx %0,0,%4 \n\ - xor %1,%0,%3 \n\ - stwcx. %1,0,%4 \n\ + xor %1,%0,%3 \n" + PPC405_ERR77(0,%4) +" stwcx. %1,0,%4 \n\ bne 1b" SMP_MB : "=&r" (old), "=&r" (t), "=m" (*p) diff --git a/arch/ppc/kernel/btext.c b/arch/ppc/kernel/btext.c index 7cd47d953cf8..ec2befee7d33 100644 --- a/arch/ppc/kernel/btext.c +++ b/arch/ppc/kernel/btext.c @@ -44,10 +44,10 @@ unsigned long disp_BAT[2] __initdata = {0, 0}; static unsigned char vga_font[cmapsz]; -int boot_text_mapped = 1; +int boot_text_mapped; +int force_printk_to_btext = 0; -boot_infos_t *disp_bi; -boot_infos_t fake_bi; +boot_infos_t disp_bi; extern char *klimit; @@ -69,48 +69,47 @@ extern char *klimit; void __init btext_init(boot_infos_t *bi) { - unsigned long offset = reloc_offset(); - - 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; - RELOC(disp_bi) = PTRUNRELOC(bi); + g_loc_X = 0; + g_loc_Y = 0; + g_max_loc_X = (bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) / 8; + g_max_loc_Y = (bi->dispDeviceRect[3] - bi->dispDeviceRect[1]) / 16; + disp_bi = *bi; + boot_text_mapped = 1; } void __init -btext_welcome(boot_infos_t* bi) +btext_welcome(void) { - unsigned long offset = reloc_offset(); unsigned long flags; unsigned long pvr; - - btext_drawstring(RELOC("Welcome to Linux, kernel " UTS_RELEASE "\n")); - btext_drawstring(RELOC("\nlinked at : 0x")); + boot_infos_t* bi = &disp_bi; + + btext_drawstring("Welcome to Linux, kernel " UTS_RELEASE "\n"); + btext_drawstring("\nlinked at : 0x"); btext_drawhex(KERNELBASE); - btext_drawstring(RELOC("\nframe buffer at : 0x")); + btext_drawstring("\nframe buffer at : 0x"); btext_drawhex((unsigned long)bi->dispDeviceBase); - btext_drawstring(RELOC(" (phys), 0x")); + btext_drawstring(" (phys), 0x"); btext_drawhex((unsigned long)bi->logicalDisplayBase); - btext_drawstring(RELOC(" (log)")); - btext_drawstring(RELOC("\nklimit : 0x")); - btext_drawhex((unsigned long)RELOC(klimit)); - btext_drawstring(RELOC("\nMSR : 0x")); + btext_drawstring(" (log)"); + btext_drawstring("\nklimit : 0x"); + btext_drawhex((unsigned long)klimit); + btext_drawstring("\nMSR : 0x"); __asm__ __volatile__ ("mfmsr %0" : "=r" (flags)); btext_drawhex(flags); __asm__ __volatile__ ("mfspr %0, 287" : "=r" (pvr)); pvr >>= 16; if (pvr > 1) { - btext_drawstring(RELOC("\nHID0 : 0x")); + btext_drawstring("\nHID0 : 0x"); __asm__ __volatile__ ("mfspr %0, 1008" : "=r" (flags)); btext_drawhex(flags); } if (pvr == 8 || pvr == 12 || pvr == 0x800c) { - btext_drawstring(RELOC("\nICTC : 0x")); + btext_drawstring("\nICTC : 0x"); __asm__ __volatile__ ("mfspr %0, 1019" : "=r" (flags)); btext_drawhex(flags); } - btext_drawstring(RELOC("\n\n")); + btext_drawstring("\n\n"); } /* Calc BAT values for mapping the display and store them @@ -131,28 +130,28 @@ btext_welcome(boot_infos_t* bi) void __init btext_prepare_BAT(void) { - unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(RELOC(disp_bi)); - unsigned long addr = (unsigned long)bi->dispDeviceBase; + boot_infos_t* bi = &disp_bi; unsigned long vaddr = KERNELBASE + 0x10000000; + unsigned long addr; unsigned long lowbits; - if (!RELOC(disp_bi)) { - RELOC(boot_text_mapped) = 0; + addr = (unsigned long)bi->dispDeviceBase; + if (!addr) { + boot_text_mapped = 0; return; } if (PVR_VER(mfspr(PVR)) != 1) { /* 603, 604, G3, G4, ... */ lowbits = addr & ~0xFF000000UL; addr &= 0xFF000000UL; - RELOC(disp_BAT[0]) = vaddr | (BL_16M<<2) | 2; - RELOC(disp_BAT[1]) = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW); + disp_BAT[0] = vaddr | (BL_16M<<2) | 2; + disp_BAT[1] = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW); } else { /* 601 */ lowbits = addr & ~0xFF800000UL; addr &= 0xFF800000UL; - RELOC(disp_BAT[0]) = vaddr | (_PAGE_NO_CACHE | PP_RWXX) | 4; - RELOC(disp_BAT[1]) = addr | BL_8M | 0x40; + disp_BAT[0] = vaddr | (_PAGE_NO_CACHE | PP_RWXX) | 4; + disp_BAT[1] = addr | BL_8M | 0x40; } bi->logicalDisplayBase = (void *) (vaddr + lowbits); } @@ -164,15 +163,12 @@ void __init btext_setup_display(int width, int height, int depth, int pitch, unsigned long address) { - unsigned long offset = reloc_offset(); - boot_infos_t* bi; - - RELOC(disp_bi) = &fake_bi; - bi = PTRRELOC((&fake_bi)); - RELOC(g_loc_X) = 0; - RELOC(g_loc_Y) = 0; - RELOC(g_max_loc_X) = width / 8; - RELOC(g_max_loc_Y) = height / 16; + boot_infos_t* bi = &disp_bi; + + g_loc_X = 0; + g_loc_Y = 0; + g_max_loc_X = width / 8; + g_max_loc_Y = height / 16; bi->logicalDisplayBase = (unsigned char *)address; bi->dispDeviceBase = (unsigned char *)address; bi->dispDeviceRowBytes = pitch; @@ -180,6 +176,7 @@ btext_setup_display(int width, int height, int depth, int pitch, bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0; bi->dispDeviceRect[2] = width; bi->dispDeviceRect[3] = height; + boot_text_mapped = 1; } /* Here's a small text engine to use during early boot @@ -197,16 +194,18 @@ void __openfirmware map_boot_text(void) { unsigned long base, offset, size; - if (disp_bi == 0) + boot_infos_t *bi = &disp_bi; + + if (bi->dispDeviceBase == 0) return; - base = ((unsigned long) disp_bi->dispDeviceBase) & 0xFFFFF000UL; - offset = ((unsigned long) disp_bi->dispDeviceBase) - base; - size = disp_bi->dispDeviceRowBytes * disp_bi->dispDeviceRect[3] + offset - + disp_bi->dispDeviceRect[0]; - disp_bi->logicalDisplayBase = ioremap(base, size); - if (disp_bi->logicalDisplayBase == 0) + base = ((unsigned long) bi->dispDeviceBase) & 0xFFFFF000UL; + offset = ((unsigned long) bi->dispDeviceBase) - base; + size = bi->dispDeviceRowBytes * bi->dispDeviceRect[3] + offset + + bi->dispDeviceRect[0]; + bi->logicalDisplayBase = ioremap(base, size); + if (bi->logicalDisplayBase == 0) return; - disp_bi->logicalDisplayBase += offset; + bi->logicalDisplayBase += offset; boot_text_mapped = 1; } @@ -229,22 +228,24 @@ void btext_update_display(unsigned long phys, int width, int height, int depth, int pitch) { - if (disp_bi == 0) + boot_infos_t *bi = &disp_bi; + + if (bi->dispDeviceBase == 0) return; - /* check it's the same frame buffer (within 64MB) */ - if ((phys ^ (unsigned long)disp_bi->dispDeviceBase) & 0xfc000000) { + + /* check it's the same frame buffer (within 256MB) */ + if ((phys ^ (unsigned long)bi->dispDeviceBase) & 0xf0000000) return; - } - disp_bi->dispDeviceBase = (__u8 *) phys; - disp_bi->dispDeviceRect[0] = 0; - disp_bi->dispDeviceRect[1] = 0; - disp_bi->dispDeviceRect[2] = width; - disp_bi->dispDeviceRect[3] = height; - disp_bi->dispDeviceDepth = depth; - disp_bi->dispDeviceRowBytes = pitch; + bi->dispDeviceBase = (__u8 *) phys; + bi->dispDeviceRect[0] = 0; + bi->dispDeviceRect[1] = 0; + bi->dispDeviceRect[2] = width; + bi->dispDeviceRect[3] = height; + bi->dispDeviceDepth = depth; + bi->dispDeviceRowBytes = pitch; if (boot_text_mapped) { - iounmap(disp_bi->logicalDisplayBase); + iounmap(bi->logicalDisplayBase); boot_text_mapped = 0; } map_boot_text(); @@ -256,8 +257,7 @@ btext_update_display(unsigned long phys, int width, int height, void BTEXT btext_clearscreen(void) { - unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(RELOC(disp_bi)); + boot_infos_t* bi = &disp_bi; unsigned long *base = (unsigned long *)calc_base(bi, 0, 0); unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * (bi->dispDeviceDepth >> 3)) >> 2; @@ -279,8 +279,7 @@ __inline__ void dcbst(const void* addr) void BTEXT btext_flushscreen(void) { - unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(RELOC(disp_bi)); + boot_infos_t* bi = &disp_bi; unsigned long *base = (unsigned long *)calc_base(bi, 0, 0); unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * (bi->dispDeviceDepth >> 3)) >> 2; @@ -301,8 +300,7 @@ void BTEXT btext_flushscreen(void) static BTEXT void scrollscreen(void) { - unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(RELOC(disp_bi)); + boot_infos_t* bi = &disp_bi; unsigned long *src = (unsigned long *)calc_base(bi,0,16); unsigned long *dst = (unsigned long *)calc_base(bi,0,0); unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * @@ -336,49 +334,48 @@ scrollscreen(void) void BTEXT btext_drawchar(char c) { - unsigned long offset = reloc_offset(); int cline = 0, x; - if (!RELOC(boot_text_mapped)) + if (!boot_text_mapped) return; switch (c) { case '\b': - if (RELOC(g_loc_X) > 0) - --RELOC(g_loc_X); + if (g_loc_X > 0) + --g_loc_X; break; case '\t': - RELOC(g_loc_X) = (RELOC(g_loc_X) & -8) + 8; + g_loc_X = (g_loc_X & -8) + 8; break; case '\r': - RELOC(g_loc_X) = 0; + g_loc_X = 0; break; case '\n': - RELOC(g_loc_X) = 0; - RELOC(g_loc_Y)++; + g_loc_X = 0; + g_loc_Y++; cline = 1; break; default: - draw_byte(c, RELOC(g_loc_X)++, RELOC(g_loc_Y)); + draw_byte(c, g_loc_X++, g_loc_Y); } - if (RELOC(g_loc_X) >= RELOC(g_max_loc_X)) { - RELOC(g_loc_X) = 0; - RELOC(g_loc_Y)++; + if (g_loc_X >= g_max_loc_X) { + g_loc_X = 0; + g_loc_Y++; cline = 1; } #ifndef NO_SCROLL - while (RELOC(g_loc_Y) >= RELOC(g_max_loc_Y)) { + while (g_loc_Y >= g_max_loc_Y) { scrollscreen(); - RELOC(g_loc_Y)--; + g_loc_Y--; } #else /* wrap around from bottom to top of screen so we don't waste time scrolling each line. -- paulus. */ - if (RELOC(g_loc_Y) >= RELOC(g_max_loc_Y)) - RELOC(g_loc_Y) = 0; + if (g_loc_Y >= g_max_loc_Y) + g_loc_Y = 0; if (cline) { - for (x = 0; x < RELOC(g_max_loc_X); ++x) - draw_byte(' ', x, RELOC(g_loc_Y)); + for (x = 0; x < g_max_loc_X; ++x) + draw_byte(' ', x, g_loc_Y); } #endif } @@ -386,9 +383,7 @@ void BTEXT btext_drawchar(char c) void BTEXT btext_drawstring(const char *c) { - unsigned long offset = reloc_offset(); - - if (!RELOC(boot_text_mapped)) + if (!boot_text_mapped) return; while (*c) btext_drawchar(*c++); @@ -398,34 +393,34 @@ void BTEXT btext_drawhex(unsigned long v) { static char hex_table[] = "0123456789abcdef"; - unsigned long offset = reloc_offset(); - if (!RELOC(boot_text_mapped)) + if (!boot_text_mapped) return; - btext_drawchar(RELOC(hex_table)[(v >> 28) & 0x0000000FUL]); - btext_drawchar(RELOC(hex_table)[(v >> 24) & 0x0000000FUL]); - btext_drawchar(RELOC(hex_table)[(v >> 20) & 0x0000000FUL]); - btext_drawchar(RELOC(hex_table)[(v >> 16) & 0x0000000FUL]); - btext_drawchar(RELOC(hex_table)[(v >> 12) & 0x0000000FUL]); - btext_drawchar(RELOC(hex_table)[(v >> 8) & 0x0000000FUL]); - btext_drawchar(RELOC(hex_table)[(v >> 4) & 0x0000000FUL]); - btext_drawchar(RELOC(hex_table)[(v >> 0) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 28) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 24) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 20) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 16) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 12) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 8) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 4) & 0x0000000FUL]); + btext_drawchar(hex_table[(v >> 0) & 0x0000000FUL]); btext_drawchar(' '); } static void BTEXT draw_byte(unsigned char c, long locX, long locY) { - unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(RELOC(disp_bi)); + boot_infos_t* bi = &disp_bi; unsigned char *base = calc_base(bi, locX << 3, locY << 4); - unsigned char *font = &RELOC(vga_font)[((unsigned long)c) * 16]; + unsigned char *font = &vga_font[((unsigned long)c) * 16]; int rb = bi->dispDeviceRowBytes; switch(bi->dispDeviceDepth) { + case 24: case 32: draw_byte_32(font, (unsigned long *)base, rb); break; + case 15: case 16: draw_byte_16(font, (unsigned long *)base, rb); break; @@ -490,8 +485,7 @@ draw_byte_16(unsigned char *font, unsigned long *base, int rb) int l, bits; int fg = 0xFFFFFFFFUL; int bg = 0x00000000UL; - unsigned long offset = reloc_offset(); - unsigned long *eb = RELOC(expand_bits_16); + unsigned long *eb = expand_bits_16; for (l = 0; l < 16; ++l) { @@ -510,8 +504,7 @@ draw_byte_8(unsigned char *font, unsigned long *base, int rb) int l, bits; int fg = 0x0F0F0F0FUL; int bg = 0x00000000UL; - unsigned long offset = reloc_offset(); - unsigned long *eb = RELOC(expand_bits_8); + unsigned long *eb = expand_bits_8; for (l = 0; l < 16; ++l) { diff --git a/arch/ppc/kernel/chrp_pci.c b/arch/ppc/kernel/chrp_pci.c deleted file mode 100644 index fae4a2351bf5..000000000000 --- a/arch/ppc/kernel/chrp_pci.c +++ /dev/null @@ -1,330 +0,0 @@ -/* - * BK Id: SCCS/s.chrp_pci.c 1.22 09/08/01 15:47:42 paulus - */ -/* - * CHRP pci routines. - */ - -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/string.h> -#include <linux/init.h> -#include <linux/ide.h> -#include <linux/bootmem.h> - -#include <asm/io.h> -#include <asm/pgtable.h> -#include <asm/irq.h> -#include <asm/hydra.h> -#include <asm/prom.h> -#include <asm/gg2.h> -#include <asm/machdep.h> -#include <asm/sections.h> -#include <asm/pci-bridge.h> - -#include "open_pic.h" -#include "pci.h" - -/* LongTrail */ -unsigned long gg2_pci_config_base; - -#define pci_config_addr(dev, offset) \ -(gg2_pci_config_base | ((dev->bus->number)<<16) | ((dev->devfn)<<8) | (offset)) - -volatile struct Hydra *Hydra = NULL; - -/* - * The VLSI Golden Gate II has only 512K of PCI configuration space, so we - * limit the bus number to 3 bits - */ - -#define cfg_read(val, addr, type, op) *val = op((type)(addr)) -#define cfg_write(val, addr, type, op) op((type *)(addr), (val)) - -#define cfg_read_bad(val, size) *val = bad_##size; -#define cfg_write_bad(val, size) - -#define bad_byte 0xff -#define bad_word 0xffff -#define bad_dword 0xffffffffU - -#define GG2_PCI_OP(rw, size, type, op) \ -int __chrp gg2_##rw##_config_##size(struct pci_dev *dev, int off, type val) \ -{ \ - if (dev->bus->number > 7) { \ - cfg_##rw##_bad(val, size) \ - return PCIBIOS_DEVICE_NOT_FOUND; \ - } \ - cfg_##rw(val, pci_config_addr(dev, off), type, op); \ - return PCIBIOS_SUCCESSFUL; \ -} - -GG2_PCI_OP(read, byte, u8 *, in_8) -GG2_PCI_OP(read, word, u16 *, in_le16) -GG2_PCI_OP(read, dword, u32 *, in_le32) -GG2_PCI_OP(write, byte, u8, out_8) -GG2_PCI_OP(write, word, u16, out_le16) -GG2_PCI_OP(write, dword, u32, out_le32) - -static struct pci_ops gg2_pci_ops = -{ - gg2_read_config_byte, - gg2_read_config_word, - gg2_read_config_dword, - gg2_write_config_byte, - gg2_write_config_word, - gg2_write_config_dword -}; - -/* - * Access functions for PCI config space on IBM "python" host bridges. - */ -#define PYTHON_CFA(b, d, o) (0x80 | ((b) << 8) | ((d) << 16) \ - | (((o) & ~3) << 24)) - -#define PYTHON_PCI_OP(rw, size, type, op, mask) \ -int __chrp \ -python_##rw##_config_##size(struct pci_dev *dev, int offset, type val) \ -{ \ - struct pci_controller *hose = dev->sysdata; \ - \ - out_be32(hose->cfg_addr, \ - PYTHON_CFA(dev->bus->number, dev->devfn, offset)); \ - cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \ - return PCIBIOS_SUCCESSFUL; \ -} - -PYTHON_PCI_OP(read, byte, u8 *, in_8, 3) -PYTHON_PCI_OP(read, word, u16 *, in_le16, 2) -PYTHON_PCI_OP(read, dword, u32 *, in_le32, 0) -PYTHON_PCI_OP(write, byte, u8, out_8, 3) -PYTHON_PCI_OP(write, word, u16, out_le16, 2) -PYTHON_PCI_OP(write, dword, u32, out_le32, 0) - -static struct pci_ops python_pci_ops = -{ - python_read_config_byte, - python_read_config_word, - python_read_config_dword, - python_write_config_byte, - python_write_config_word, - python_write_config_dword -}; - -/* - * Access functions for PCI config space using RTAS calls. - */ -#define RTAS_PCI_READ_OP(size, type, nbytes) \ -int __chrp \ -rtas_read_config_##size(struct pci_dev *dev, int offset, type val) \ -{ \ - unsigned long addr = (offset & 0xff) | ((dev->devfn & 0xff) << 8) \ - | ((dev->bus->number & 0xff) << 16); \ - unsigned long ret = ~0UL; \ - int rval; \ - \ - rval = call_rtas("read-pci-config", 2, 2, &ret, addr, nbytes); \ - *val = ret; \ - return rval? PCIBIOS_DEVICE_NOT_FOUND: PCIBIOS_SUCCESSFUL; \ -} - -#define RTAS_PCI_WRITE_OP(size, type, nbytes) \ -int __chrp \ -rtas_write_config_##size(struct pci_dev *dev, int offset, type val) \ -{ \ - unsigned long addr = (offset & 0xff) | ((dev->devfn & 0xff) << 8) \ - | ((dev->bus->number & 0xff) << 16); \ - int rval; \ - \ - rval = call_rtas("write-pci-config", 3, 1, NULL, \ - addr, nbytes, (ulong)val); \ - return rval? PCIBIOS_DEVICE_NOT_FOUND: PCIBIOS_SUCCESSFUL; \ -} - -RTAS_PCI_READ_OP(byte, u8 *, 1) -RTAS_PCI_READ_OP(word, u16 *, 2) -RTAS_PCI_READ_OP(dword, u32 *, 4) -RTAS_PCI_WRITE_OP(byte, u8, 1) -RTAS_PCI_WRITE_OP(word, u16, 2) -RTAS_PCI_WRITE_OP(dword, u32, 4) - -static struct pci_ops rtas_pci_ops = -{ - rtas_read_config_byte, - rtas_read_config_word, - rtas_read_config_dword, - rtas_write_config_byte, - rtas_write_config_word, - rtas_write_config_dword -}; - - /* - * Temporary fixes for PCI devices. These should be replaced by OF query - * code -- Geert - */ - -static u_char hydra_openpic_initsenses[] __initdata = { - 1, /* HYDRA_INT_SIO */ - 0, /* HYDRA_INT_SCSI_DMA */ - 0, /* HYDRA_INT_SCCA_TX_DMA */ - 0, /* HYDRA_INT_SCCA_RX_DMA */ - 0, /* HYDRA_INT_SCCB_TX_DMA */ - 0, /* HYDRA_INT_SCCB_RX_DMA */ - 1, /* HYDRA_INT_SCSI */ - 1, /* HYDRA_INT_SCCA */ - 1, /* HYDRA_INT_SCCB */ - 1, /* HYDRA_INT_VIA */ - 1, /* HYDRA_INT_ADB */ - 0, /* HYDRA_INT_ADB_NMI */ - /* all others are 1 (= default) */ -}; - -int __init -hydra_init(void) -{ - struct device_node *np; - - np = find_devices("mac-io"); - if (np == NULL || np->n_addrs == 0) { - printk(KERN_WARNING "Warning: no mac-io found\n"); - return 0; - } - Hydra = ioremap(np->addrs[0].address, np->addrs[0].size); - printk("Hydra Mac I/O at %x\n", np->addrs[0].address); - out_le32(&Hydra->Feature_Control, (HYDRA_FC_SCC_CELL_EN | - HYDRA_FC_SCSI_CELL_EN | - HYDRA_FC_SCCA_ENABLE | - HYDRA_FC_SCCB_ENABLE | - HYDRA_FC_ARB_BYPASS | - HYDRA_FC_MPIC_ENABLE | - HYDRA_FC_SLOW_SCC_PCLK | - HYDRA_FC_MPIC_IS_MASTER)); - OpenPIC_Addr = &Hydra->OpenPIC; - OpenPIC_InitSenses = hydra_openpic_initsenses; - OpenPIC_NumInitSenses = sizeof(hydra_openpic_initsenses); - return 1; -} - -void __init -chrp_pcibios_fixup(void) -{ - struct pci_dev *dev; - struct device_node *np; - - /* PCI interrupts are controlled by the OpenPIC */ - pci_for_each_dev(dev) { - np = pci_device_to_OF_node(dev); - if ((np != 0) && (np->n_intrs > 0) && (np->intrs[0].line != 0)) - dev->irq = np->intrs[0].line; - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); - } -} - -void __init -chrp_find_bridges(void) -{ - struct device_node *dev; - int *bus_range; - int len, index = -1; - struct pci_controller *hose; - volatile unsigned char *cfg; - unsigned int *dma; - char *model, *machine; - int is_longtrail = 0, is_mot = 0; - struct device_node *root = find_path_device("/"); -#ifdef CONFIG_POWER3 - unsigned int *opprop = (unsigned int *) - get_property(root, "platform-open-pic", NULL); - int i; -#endif - - /* - * The PCI host bridge nodes on some machines don't have - * properties to adequately identify them, so we have to - * look at what sort of machine this is as well. - */ - machine = get_property(root, "model", NULL); - if (machine != NULL) { - is_longtrail = strncmp(machine, "IBM,LongTrail", 13) == 0; - is_mot = strncmp(machine, "MOT", 3) == 0; - } - for (dev = root->child; dev != NULL; dev = dev->sibling) { - if (dev->type == NULL || strcmp(dev->type, "pci") != 0) - continue; - ++index; - /* The GG2 bridge on the LongTrail doesn't have an address */ - if (dev->n_addrs < 1 && !is_longtrail) { - printk(KERN_WARNING "Can't use %s: no address\n", - dev->full_name); - continue; - } - bus_range = (int *) get_property(dev, "bus-range", &len); - if (bus_range == NULL || len < 2 * sizeof(int)) { - printk(KERN_WARNING "Can't get bus-range for %s\n", - dev->full_name); - continue; - } - if (bus_range[1] == bus_range[0]) - printk(KERN_INFO "PCI bus %d", bus_range[0]); - else - printk(KERN_INFO "PCI buses %d..%d", - bus_range[0], bus_range[1]); - printk(" controlled by %s", dev->type); - if (dev->n_addrs > 0) - printk(" at %x", dev->addrs[0].address); - printk("\n"); - - hose = pcibios_alloc_controller(); - if (!hose) { - printk("Can't allocate PCI controller structure for %s\n", - dev->full_name); - continue; - } - hose->arch_data = dev; - hose->first_busno = bus_range[0]; - hose->last_busno = bus_range[1]; - - model = get_property(dev, "model", NULL); - if (model == NULL) - model = "<none>"; - if (device_is_compatible(dev, "IBM,python")) { - hose->ops = &python_pci_ops; - cfg = ioremap(dev->addrs[0].address + 0xf8000, 0x20); - hose->cfg_addr = (volatile unsigned int *) cfg; - hose->cfg_data = cfg + 0x10; - } else if (is_mot - || strncmp(model, "Motorola, Grackle", 17) == 0) { - setup_grackle(hose); - } else if (is_longtrail) { - hose->ops = &gg2_pci_ops; - gg2_pci_config_base = (unsigned long) - ioremap(GG2_PCI_CONFIG_BASE, 0x80000); - } else { - printk("No methods for %s (model %s), using RTAS\n", - dev->full_name, model); - hose->ops = &rtas_pci_ops; - } - - pci_process_bridge_OF_ranges(hose, dev, index == 0); - -#ifdef CONFIG_POWER3 - if (opprop != NULL) { - i = prom_n_addr_cells(root) * (index + 2) - 1; - openpic_setup_ISU(index, opprop[i]); - } -#endif /* CONFIG_POWER3 */ - - /* check the first bridge for a property that we can - use to set pci_dram_offset */ - dma = (unsigned int *) - get_property(dev, "ibm,dma-ranges", &len); - if (index == 0 && dma != NULL && len >= 6 * sizeof(*dma)) { - pci_dram_offset = dma[2] - dma[3]; - printk("pci_dram_offset = %lx\n", pci_dram_offset); - } - } - - ppc_md.pcibios_fixup = chrp_pcibios_fixup; -} diff --git a/arch/ppc/kernel/chrp_setup.c b/arch/ppc/kernel/chrp_setup.c deleted file mode 100644 index 6fd574cbae84..000000000000 --- a/arch/ppc/kernel/chrp_setup.c +++ /dev/null @@ -1,634 +0,0 @@ -/* - * BK Id: SCCS/s.chrp_setup.c 1.38 11/13/01 21:26:07 paulus - */ -/* - * linux/arch/ppc/kernel/setup.c - * - * Copyright (C) 1995 Linus Torvalds - * Adapted from 'alpha' version by Gary Thomas - * Modified by Cort Dougan (cort@cs.nmt.edu) - */ - -/* - * bootup setup stuff.. - */ - -#include <linux/config.h> -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/stddef.h> -#include <linux/unistd.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/user.h> -#include <linux/a.out.h> -#include <linux/tty.h> -#include <linux/major.h> -#include <linux/interrupt.h> -#include <linux/reboot.h> -#include <linux/init.h> -#include <linux/blk.h> -#include <linux/ioport.h> -#include <linux/console.h> -#include <linux/pci.h> -#include <linux/version.h> -#include <linux/adb.h> -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/ide.h> -#include <linux/seq_file.h> - -#include <asm/mmu.h> -#include <asm/processor.h> -#include <asm/io.h> -#include <asm/pgtable.h> -#include <asm/prom.h> -#include <asm/gg2.h> -#include <asm/pci-bridge.h> -#include <asm/dma.h> -#include <asm/machdep.h> -#include <asm/irq.h> -#include <asm/hydra.h> -#include <asm/keyboard.h> -#include <asm/sections.h> -#include <asm/time.h> -#include <asm/btext.h> - -#include "local_irq.h" -#include "i8259.h" -#include "open_pic.h" -#include "xics.h" - -unsigned long chrp_get_rtc_time(void); -int chrp_set_rtc_time(unsigned long nowtime); -void chrp_calibrate_decr(void); -long chrp_time_init(void); - -void chrp_find_bridges(void); -void chrp_event_scan(void); -void rtas_display_progress(char *, unsigned short); -void rtas_indicator_progress(char *, unsigned short); -void btext_progress(char *, unsigned short); - -extern unsigned long pmac_find_end_of_memory(void); -extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); -extern int pckbd_getkeycode(unsigned int scancode); -extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, - char raw_mode); -extern char pckbd_unexpected_up(unsigned char keycode); -extern void pckbd_leds(unsigned char leds); -extern void pckbd_init_hw(void); -extern unsigned char pckbd_sysrq_xlate[128]; -extern void select_adb_keyboard(void); -extern int of_show_percpuinfo(struct seq_file *, int); - -extern kdev_t boot_dev; - -extern PTE *Hash, *Hash_end; -extern unsigned long Hash_size, Hash_mask; -extern int probingmem; -extern unsigned long loops_per_jiffy; -static int max_width; - -#ifdef CONFIG_SMP -extern struct smp_ops_t chrp_smp_ops; -extern struct smp_ops_t xics_smp_ops; -#endif - -static const char *gg2_memtypes[4] = { - "FPM", "SDRAM", "EDO", "BEDO" -}; -static const char *gg2_cachesizes[4] = { - "256 KB", "512 KB", "1 MB", "Reserved" -}; -static const char *gg2_cachetypes[4] = { - "Asynchronous", "Reserved", "Flow-Through Synchronous", - "Pipelined Synchronous" -}; -static const char *gg2_cachemodes[4] = { - "Disabled", "Write-Through", "Copy-Back", "Transparent Mode" -}; - -int __chrp -chrp_show_cpuinfo(struct seq_file *m) -{ - int i, sdramen; - unsigned int t; - struct device_node *root; - const char *model = ""; - - root = find_path_device("/"); - if (root) - model = get_property(root, "model", NULL); - seq_printf(m, "machine\t\t: CHRP %s\n", model); - - /* longtrail (goldengate) stuff */ - if (!strncmp(model, "IBM,LongTrail", 13)) { - /* VLSI VAS96011/12 `Golden Gate 2' */ - /* Memory banks */ - sdramen = (in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+ - GG2_PCI_DRAM_CTRL)) - >>31) & 1; - for (i = 0; i < (sdramen ? 4 : 6); i++) { - t = in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+ - GG2_PCI_DRAM_BANK0+ - i*4)); - if (!(t & 1)) - continue; - switch ((t>>8) & 0x1f) { - case 0x1f: - model = "4 MB"; - break; - case 0x1e: - model = "8 MB"; - break; - case 0x1c: - model = "16 MB"; - break; - case 0x18: - model = "32 MB"; - break; - case 0x10: - model = "64 MB"; - break; - case 0x00: - model = "128 MB"; - break; - default: - model = "Reserved"; - break; - } - seq_printf(m, "memory bank %d\t: %s %s\n", i, model, - gg2_memtypes[sdramen ? 1 : ((t>>1) & 3)]); - } - /* L2 cache */ - t = in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+GG2_PCI_CC_CTRL)); - seq_printf(m, "board l2\t: %s %s (%s)\n", - gg2_cachesizes[(t>>7) & 3], - gg2_cachetypes[(t>>2) & 3], - gg2_cachemodes[t & 3]); - } - return 0; -} - -/* - * Fixes for the National Semiconductor PC78308VUL SuperI/O - * - * Some versions of Open Firmware incorrectly initialize the IRQ settings - * for keyboard and mouse - */ -static inline void __init sio_write(u8 val, u8 index) -{ - outb(index, 0x15c); - outb(val, 0x15d); -} - -static inline u8 __init sio_read(u8 index) -{ - outb(index, 0x15c); - return inb(0x15d); -} - -static void __init sio_fixup_irq(const char *name, u8 device, u8 level, - u8 type) -{ - u8 level0, type0, active; - - /* select logical device */ - sio_write(device, 0x07); - active = sio_read(0x30); - level0 = sio_read(0x70); - type0 = sio_read(0x71); - if (level0 != level || type0 != type || !active) { - printk(KERN_WARNING "sio: %s irq level %d, type %d, %sactive: " - "remapping to level %d, type %d, active\n", - name, level0, type0, !active ? "in" : "", level, type); - sio_write(0x01, 0x30); - sio_write(level, 0x70); - sio_write(type, 0x71); - } -} - -static void __init sio_init(void) -{ - struct device_node *root; - - if ((root = find_path_device("/")) && - !strncmp(get_property(root, "model", NULL), "IBM,LongTrail", 13)) { - /* logical device 0 (KBC/Keyboard) */ - sio_fixup_irq("keyboard", 0, 1, 2); - /* select logical device 1 (KBC/Mouse) */ - sio_fixup_irq("mouse", 1, 12, 2); - } -} - - -void __init -chrp_setup_arch(void) -{ - struct device_node *device; - - /* init to some ~sane value until calibrate_delay() runs */ - loops_per_jiffy = 50000000/HZ; - -#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) */ - - /* Lookup PCI host bridges */ - chrp_find_bridges(); - -#ifndef CONFIG_PPC64BRIDGE - /* - * Temporary fixes for PCI devices. - * -- Geert - */ - hydra_init(); /* Mac I/O */ - -#endif /* CONFIG_PPC64BRIDGE */ - - /* Some IBM machines don't have the hydra -- Cort */ - if (!OpenPIC_Addr) { - struct device_node *root; - unsigned long *opprop; - int n; - - root = find_path_device("/"); - opprop = (unsigned long *) get_property - (root, "platform-open-pic", NULL); - n = prom_n_addr_cells(root); - if (opprop != 0) { - printk("OpenPIC addrs: %lx %lx %lx\n", - opprop[n-1], opprop[2*n-1], opprop[3*n-1]); - OpenPIC_Addr = ioremap(opprop[n-1], 0x40000); - } - } - - /* - * Fix the Super I/O configuration - */ - sio_init(); - - /* - * Setup the console operations - */ -#ifdef CONFIG_DUMMY_CONSOLE - conswitchp = &dummy_con; -#endif - - /* Get the event scan rate for the rtas so we know how - * often it expects a heartbeat. -- Cort - */ - if ( rtas_data ) { - struct property *p; - device = find_devices("rtas"); - for ( p = device->properties; - p && strncmp(p->name, "rtas-event-scan-rate", 20); - p = p->next ) - /* nothing */ ; - if ( p && *(unsigned long *)p->value ) { - ppc_md.heartbeat = chrp_event_scan; - ppc_md.heartbeat_reset = (HZ/(*(unsigned long *)p->value)*30)-1; - ppc_md.heartbeat_count = 1; - printk("RTAS Event Scan Rate: %lu (%lu jiffies)\n", - *(unsigned long *)p->value, ppc_md.heartbeat_reset ); - } - } -} - -void __chrp -chrp_event_scan(void) -{ - unsigned char log[1024]; - unsigned long ret = 0; - /* XXX: we should loop until the hardware says no more error logs -- Cort */ - call_rtas( "event-scan", 4, 1, &ret, 0xffffffff, 0, - __pa(log), 1024 ); - ppc_md.heartbeat_count = ppc_md.heartbeat_reset; -} - -void __chrp -chrp_restart(char *cmd) -{ - printk("RTAS system-reboot returned %d\n", - call_rtas("system-reboot", 0, 1, NULL)); - for (;;); -} - -void __chrp -chrp_power_off(void) -{ - /* allow power on only with power button press */ - printk("RTAS power-off returned %d\n", - call_rtas("power-off", 2, 1, NULL,0xffffffff,0xffffffff)); - for (;;); -} - -void __chrp -chrp_halt(void) -{ - chrp_power_off(); -} - -u_int __chrp -chrp_irq_cannonicalize(u_int irq) -{ - if (irq == 2) - return 9; - return irq; -} - -void __init chrp_init_IRQ(void) -{ - struct device_node *np; - int i; - unsigned int *addrp; - unsigned char* chrp_int_ack_special = 0; - unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS]; - int nmi_irq = -1; -#if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) && defined(XMON) - struct device_node *kbd; -#endif - - if (!(np = find_devices("pci")) - || !(addrp = (unsigned int *) - get_property(np, "8259-interrupt-acknowledge", NULL))) - printk("Cannot find pci to get ack address\n"); - else - chrp_int_ack_special = (unsigned char *) - ioremap(addrp[prom_n_addr_cells(np)-1], 1); - /* hydra still sets OpenPIC_InitSenses to a static set of values */ - if (OpenPIC_InitSenses == NULL) { - prom_get_irq_senses(init_senses, NUM_8259_INTERRUPTS, NR_IRQS); - OpenPIC_InitSenses = init_senses; - OpenPIC_NumInitSenses = NR_IRQS - NUM_8259_INTERRUPTS; - } - openpic_init(1, NUM_8259_INTERRUPTS, chrp_int_ack_special, nmi_irq); - for ( i = 0 ; i < NUM_8259_INTERRUPTS ; i++ ) - irq_desc[i].handler = &i8259_pic; - i8259_init(); -#if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) && defined(XMON) - /* see if there is a keyboard in the device tree - with a parent of type "adb" */ - for (kbd = find_devices("keyboard"); kbd; kbd = kbd->next) - if (kbd->parent && kbd->parent->type - && strcmp(kbd->parent->type, "adb") == 0) - break; - if (kbd) - request_irq( HYDRA_INT_ADB_NMI, xmon_irq, 0, "XMON break", 0); -#endif -} - -void __init -chrp_init2(void) -{ -#ifdef CONFIG_NVRAM - pmac_nvram_init(); -#endif - - request_region(0x20,0x20,"pic1"); - request_region(0xa0,0x20,"pic2"); - request_region(0x00,0x20,"dma1"); - request_region(0x40,0x20,"timer"); - request_region(0x80,0x10,"dma page reg"); - request_region(0xc0,0x20,"dma2"); - - if (ppc_md.progress) - ppc_md.progress(" Have fun! ", 0x7777); - -#if defined(CONFIG_VT) && (defined(CONFIG_ADB_KEYBOARD) || defined(CONFIG_INPUT)) - /* see if there is a keyboard in the device tree - with a parent of type "adb" */ - { - struct device_node *kbd; - - for (kbd = find_devices("keyboard"); kbd; kbd = kbd->next) { - if (kbd->parent && kbd->parent->type - && strcmp(kbd->parent->type, "adb") == 0) { - select_adb_keyboard(); - break; - } - } - } -#endif /* CONFIG_VT && (CONFIG_ADB_KEYBOARD || CONFIG_INPUT) */ -} - -#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) -/* - * IDE stuff. - */ - -static int __chrp -chrp_ide_check_region(ide_ioreg_t from, unsigned int extent) -{ - return check_region(from, extent); -} - -static void __chrp -chrp_ide_request_region(ide_ioreg_t from, - unsigned int extent, - const char *name) -{ - request_region(from, extent, name); -} - -static void __chrp -chrp_ide_release_region(ide_ioreg_t from, - unsigned int extent) -{ - release_region(from, extent); -} - -static void __chrp -chrp_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) -{ - ide_ioreg_t reg = data_port; - int i; - - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { - hw->io_ports[i] = reg; - reg += 1; - } - hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; -} -#endif - -/* - * One of the main thing these mappings are needed for is so that - * xmon can get to the serial port early on. We probably should - * handle the machines with the mpc106 as well as the python (F50) - * and the GG2 (longtrail). Actually we should look in the device - * tree and do the right thing. - */ -static void __init -chrp_map_io(void) -{ - char *name; - - /* - * The code below tends to get removed, please don't take it out. - * The F50 needs this mapping and it you take it out I'll track you - * down and slap your hands. If it causes problems please email me. - * -- Cort <cort@fsmlabs.com> - */ - name = get_property(find_path_device("/"), "name", NULL); - if (name && strncmp(name, "IBM-70", 6) == 0 - && strstr(name, "-F50")) { - io_block_mapping(0x80000000, 0x80000000, 0x10000000, _PAGE_IO); - io_block_mapping(0x90000000, 0x90000000, 0x10000000, _PAGE_IO); - return; - } else { - io_block_mapping(0xf8000000, 0xf8000000, 0x04000000, _PAGE_IO); - } -} - -void __init -chrp_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ -#ifdef CONFIG_BLK_DEV_INITRD - /* take care of initrd if we have one */ - if ( r6 ) - { - initrd_start = r6 + KERNELBASE; - initrd_end = r6 + r7 + KERNELBASE; - } -#endif /* CONFIG_BLK_DEV_INITRD */ - - ISA_DMA_THRESHOLD = ~0L; - DMA_MODE_READ = 0x44; - DMA_MODE_WRITE = 0x48; - isa_io_base = CHRP_ISA_IO_BASE; /* default value */ - - ppc_md.setup_arch = chrp_setup_arch; - ppc_md.show_percpuinfo = of_show_percpuinfo; - ppc_md.show_cpuinfo = chrp_show_cpuinfo; - ppc_md.irq_cannonicalize = chrp_irq_cannonicalize; -#ifndef CONFIG_POWER4 - ppc_md.init_IRQ = chrp_init_IRQ; - ppc_md.get_irq = openpic_get_irq; -#else - ppc_md.init_IRQ = xics_init_IRQ; - ppc_md.get_irq = xics_get_irq; -#endif /* CONFIG_POWER4 */ - - ppc_md.init = chrp_init2; - - ppc_md.restart = chrp_restart; - ppc_md.power_off = chrp_power_off; - ppc_md.halt = chrp_halt; - - ppc_md.time_init = chrp_time_init; - ppc_md.set_rtc_time = chrp_set_rtc_time; - ppc_md.get_rtc_time = chrp_get_rtc_time; - ppc_md.calibrate_decr = chrp_calibrate_decr; - - ppc_md.find_end_of_memory = pmac_find_end_of_memory; - ppc_md.setup_io_mappings = chrp_map_io; - -#ifdef CONFIG_VT - /* these are adjusted in chrp_init2 if we have an ADB keyboard */ - ppc_md.kbd_setkeycode = pckbd_setkeycode; - ppc_md.kbd_getkeycode = pckbd_getkeycode; - ppc_md.kbd_translate = pckbd_translate; - ppc_md.kbd_unexpected_up = pckbd_unexpected_up; - ppc_md.kbd_leds = pckbd_leds; - ppc_md.kbd_init_hw = pckbd_init_hw; -#ifdef CONFIG_MAGIC_SYSRQ - ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate; - SYSRQ_KEY = 0x54; -#endif /* CONFIG_MAGIC_SYSRQ */ -#endif /* CONFIG_VT */ - - if (rtas_data) { - struct device_node *rtas; - unsigned int *p; - - rtas = find_devices("rtas"); - if (rtas != NULL) { - if (get_property(rtas, "display-character", NULL)) { - ppc_md.progress = rtas_display_progress; - p = (unsigned int *) get_property - (rtas, "ibm,display-line-length", NULL); - if (p) - max_width = *p; - } else if (get_property(rtas, "set-indicator", NULL)) - ppc_md.progress = rtas_indicator_progress; - } - } -#ifdef CONFIG_BOOTX_TEXT - if (ppc_md.progress == NULL && boot_text_mapped) - ppc_md.progress = btext_progress; -#endif - -#ifdef CONFIG_SMP -#ifndef CONFIG_POWER4 - ppc_md.smp_ops = &chrp_smp_ops; -#else - ppc_md.smp_ops = &xics_smp_ops; -#endif /* CONFIG_POWER4 */ -#endif /* CONFIG_SMP */ - -#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) - ppc_ide_md.ide_check_region = chrp_ide_check_region; - ppc_ide_md.ide_request_region = chrp_ide_request_region; - ppc_ide_md.ide_release_region = chrp_ide_release_region; - ppc_ide_md.ide_init_hwif = chrp_ide_init_hwif_ports; -#endif - - /* - * Print the banner, then scroll down so boot progress - * can be printed. -- Cort - */ - if ( ppc_md.progress ) ppc_md.progress("Linux/PPC "UTS_RELEASE"\n", 0x0); -} - -void __chrp -rtas_display_progress(char *s, unsigned short hex) -{ - int width; - char *os = s; - - if ( call_rtas( "display-character", 1, 1, NULL, '\r' ) ) - return; - - width = max_width; - while ( *os ) - { - if ( (*os == '\n') || (*os == '\r') ) - width = max_width; - else - width--; - call_rtas( "display-character", 1, 1, NULL, *os++ ); - /* if we overwrite the screen length */ - if ( width == 0 ) - while ( (*os != 0) && (*os != '\n') && (*os != '\r') ) - os++; - } - - /*while ( width-- > 0 )*/ - call_rtas( "display-character", 1, 1, NULL, ' ' ); -} - -void __chrp -rtas_indicator_progress(char *s, unsigned short hex) -{ - call_rtas("set-indicator", 3, 1, NULL, 6, 0, hex); -} - -#ifdef CONFIG_BOOTX_TEXT -void -btext_progress(char *s, unsigned short hex) -{ - prom_print(s); - prom_print("\n"); -} -#endif /* CONFIG_BOOTX_TEXT */ diff --git a/arch/ppc/kernel/chrp_smp.c b/arch/ppc/kernel/chrp_smp.c deleted file mode 100644 index 505e8587d341..000000000000 --- a/arch/ppc/kernel/chrp_smp.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ -/* - * Smp support for CHRP machines. - * - * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great - * deal of code from the sparc and intel versions. - * - * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu> - * - */ - -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/smp.h> -#include <linux/smp_lock.h> -#include <linux/interrupt.h> -#include <linux/kernel_stat.h> -#include <linux/delay.h> -#define __KERNEL_SYSCALLS__ -#include <linux/unistd.h> -#include <linux/init.h> -#include <linux/spinlock.h> - -#include <asm/ptrace.h> -#include <asm/atomic.h> -#include <asm/irq.h> -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/hardirq.h> -#include <asm/softirq.h> -#include <asm/sections.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/smp.h> -#include <asm/residual.h> -#include <asm/feature.h> -#include <asm/time.h> - -#include "open_pic.h" - -extern unsigned long smp_chrp_cpu_nr; - -static int __init -smp_chrp_probe(void) -{ - if (smp_chrp_cpu_nr > 1) - openpic_request_IPIs(); - - return smp_chrp_cpu_nr; -} - -static void __init -smp_chrp_kick_cpu(int nr) -{ - *(unsigned long *)KERNELBASE = nr; - asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory"); -} - -static void __init -smp_chrp_setup_cpu(int cpu_nr) -{ - static atomic_t ready = ATOMIC_INIT(1); - static volatile int frozen = 0; - - if (cpu_nr == 0) { - /* wait for all the others */ - while (atomic_read(&ready) < smp_num_cpus) - barrier(); - atomic_set(&ready, 1); - /* freeze the timebase */ - call_rtas("freeze-time-base", 0, 1, NULL); - mb(); - frozen = 1; - /* XXX assumes this is not a 601 */ - set_tb(0, 0); - last_jiffy_stamp(0) = 0; - while (atomic_read(&ready) < smp_num_cpus) - barrier(); - /* thaw the timebase again */ - call_rtas("thaw-time-base", 0, 1, NULL); - mb(); - frozen = 0; - smp_tb_synchronized = 1; - } else { - atomic_inc(&ready); - while (!frozen) - barrier(); - set_tb(0, 0); - last_jiffy_stamp(0) = 0; - mb(); - atomic_inc(&ready); - while (frozen) - barrier(); - } - - if (OpenPIC_Addr) - do_openpic_setup_cpu(); -} - -#ifdef CONFIG_POWER4 -static void __chrp -smp_xics_message_pass(int target, int msg, unsigned long data, int wait) -{ - /* for now, only do reschedule messages - since we only have one IPI */ - if (msg != PPC_MSG_RESCHEDULE) - return; - for (i = 0; i < smp_num_cpus; ++i) { - if (target == MSG_ALL || target == i - || (target == MSG_ALL_BUT_SELF - && i != smp_processor_id())) - xics_cause_IPI(i); - } -} - -static int __chrp -smp_xics_probe(void) -{ - return smp_chrp_cpu_nr; -} - -static void __chrp -smp_xics_setup_cpu(int cpu_nr) -{ - if (cpu_nr > 0) - xics_setup_cpu(); -} -#endif /* CONFIG_POWER4 */ - -/* CHRP with openpic */ -struct smp_ops_t chrp_smp_ops __chrpdata = { - smp_openpic_message_pass, - smp_chrp_probe, - smp_chrp_kick_cpu, - smp_chrp_setup_cpu, -}; - -#ifdef CONFIG_POWER4 -/* CHRP with new XICS interrupt controller */ -struct smp_ops_t xics_smp_ops __chrpdata = { - smp_xics_message_pass, - smp_xics_probe, - smp_chrp_kick_cpu, - smp_xics_setup_cpu, -}; -#endif /* CONFIG_POWER4 */ diff --git a/arch/ppc/kernel/chrp_time.c b/arch/ppc/kernel/chrp_time.c deleted file mode 100644 index cb0d96071969..000000000000 --- a/arch/ppc/kernel/chrp_time.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * BK Id: SCCS/s.chrp_time.c 1.10 09/08/01 15:47:42 paulus - */ -/* - * linux/arch/i386/kernel/time.c - * - * Copyright (C) 1991, 1992, 1995 Linus Torvalds - * - * Adapted for PowerPC (PreP) by Gary Thomas - * Modified by Cort Dougan (cort@cs.nmt.edu) - * copied and modified from intel version - * - */ -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/param.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/interrupt.h> -#include <linux/time.h> -#include <linux/timex.h> -#include <linux/kernel_stat.h> -#include <linux/mc146818rtc.h> -#include <linux/init.h> - -#include <asm/segment.h> -#include <asm/io.h> -#include <asm/processor.h> -#include <asm/nvram.h> -#include <asm/prom.h> -#include <asm/sections.h> -#include <asm/time.h> - -extern spinlock_t rtc_lock; - -static int nvram_as1 = NVRAM_AS1; -static int nvram_as0 = NVRAM_AS0; -static int nvram_data = NVRAM_DATA; - -long __init chrp_time_init(void) -{ - struct device_node *rtcs; - int base; - - rtcs = find_compatible_devices("rtc", "pnpPNP,b00"); - if (rtcs == NULL || rtcs->addrs == NULL) - return 0; - base = rtcs->addrs[0].address; - nvram_as1 = 0; - nvram_as0 = base; - nvram_data = base + 1; - - return 0; -} - -int __chrp chrp_cmos_clock_read(int addr) -{ - if (nvram_as1 != 0) - outb(addr>>8, nvram_as1); - outb(addr, nvram_as0); - return (inb(nvram_data)); -} - -void __chrp chrp_cmos_clock_write(unsigned long val, int addr) -{ - if (nvram_as1 != 0) - outb(addr>>8, nvram_as1); - outb(addr, nvram_as0); - outb(val, nvram_data); - return; -} - -/* - * Set the hardware clock. -- Cort - */ -int __chrp chrp_set_rtc_time(unsigned long nowtime) -{ - unsigned char save_control, save_freq_select; - struct rtc_time tm; - - spin_lock(&rtc_lock); - to_tm(nowtime, &tm); - - save_control = chrp_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */ - - chrp_cmos_clock_write((save_control|RTC_SET), RTC_CONTROL); - - save_freq_select = chrp_cmos_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */ - - chrp_cmos_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); - - tm.tm_year -= 1900; - if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { - BIN_TO_BCD(tm.tm_sec); - BIN_TO_BCD(tm.tm_min); - BIN_TO_BCD(tm.tm_hour); - BIN_TO_BCD(tm.tm_mon); - BIN_TO_BCD(tm.tm_mday); - BIN_TO_BCD(tm.tm_year); - } - chrp_cmos_clock_write(tm.tm_sec,RTC_SECONDS); - chrp_cmos_clock_write(tm.tm_min,RTC_MINUTES); - chrp_cmos_clock_write(tm.tm_hour,RTC_HOURS); - chrp_cmos_clock_write(tm.tm_mon,RTC_MONTH); - chrp_cmos_clock_write(tm.tm_mday,RTC_DAY_OF_MONTH); - chrp_cmos_clock_write(tm.tm_year,RTC_YEAR); - - /* The following flags have to be released exactly in this order, - * otherwise the DS12887 (popular MC146818A clone with integrated - * battery and quartz) will not reset the oscillator and will not - * update precisely 500 ms later. You won't find this mentioned in - * the Dallas Semiconductor data sheets, but who believes data - * sheets anyway ... -- Markus Kuhn - */ - chrp_cmos_clock_write(save_control, RTC_CONTROL); - chrp_cmos_clock_write(save_freq_select, RTC_FREQ_SELECT); - - if ( (time_state == TIME_ERROR) || (time_state == TIME_BAD) ) - time_state = TIME_OK; - spin_unlock(&rtc_lock); - return 0; -} - -unsigned long __chrp chrp_get_rtc_time(void) -{ - unsigned int year, mon, day, hour, min, sec; - int uip, i; - - /* The Linux interpretation of the CMOS clock register contents: - * When the Update-In-Progress (UIP) flag goes from 1 to 0, the - * RTC registers show the second which has precisely just started. - * Let's hope other operating systems interpret the RTC the same way. - */ - - /* Since the UIP flag is set for about 2.2 ms and the clock - * is typically written with a precision of 1 jiffy, trying - * to obtain a precision better than a few milliseconds is - * an illusion. Only consistency is interesting, this also - * allows to use the routine for /dev/rtc without a potential - * 1 second kernel busy loop triggered by any reader of /dev/rtc. - */ - - for ( i = 0; i<1000000; i++) { - uip = chrp_cmos_clock_read(RTC_FREQ_SELECT); - sec = chrp_cmos_clock_read(RTC_SECONDS); - min = chrp_cmos_clock_read(RTC_MINUTES); - hour = chrp_cmos_clock_read(RTC_HOURS); - day = chrp_cmos_clock_read(RTC_DAY_OF_MONTH); - mon = chrp_cmos_clock_read(RTC_MONTH); - year = chrp_cmos_clock_read(RTC_YEAR); - uip |= chrp_cmos_clock_read(RTC_FREQ_SELECT); - if ((uip & RTC_UIP)==0) break; - } - - if (!(chrp_cmos_clock_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) - { - BCD_TO_BIN(sec); - BCD_TO_BIN(min); - BCD_TO_BIN(hour); - BCD_TO_BIN(day); - BCD_TO_BIN(mon); - BCD_TO_BIN(year); - } - if ((year += 1900) < 1970) - year += 100; - return mktime(year, mon, day, hour, min, sec); -} - - -void __init chrp_calibrate_decr(void) -{ - struct device_node *cpu; - unsigned int freq, *fp; - - if (via_calibrate_decr()) - return; - - /* - * The cpu node should have a timebase-frequency property - * to tell us the rate at which the decrementer counts. - */ - freq = 16666000; /* hardcoded default */ - cpu = find_type_devices("cpu"); - if (cpu != 0) { - fp = (unsigned int *) - get_property(cpu, "timebase-frequency", NULL); - if (fp != 0) - freq = *fp; - } - printk("time_init: decrementer frequency = %u.%.6u MHz\n", - freq/1000000, freq%1000000); - tb_ticks_per_jiffy = freq / HZ; - tb_to_us = mulhwu_scale_factor(freq, 1000000); -} diff --git a/arch/ppc/kernel/cputable.c b/arch/ppc/kernel/cputable.c index f718c1a91667..d6f8eccb3d76 100644 --- a/arch/ppc/kernel/cputable.c +++ b/arch/ppc/kernel/cputable.c @@ -26,15 +26,14 @@ extern void __setup_cpu_603(int cpu_nr); extern void __setup_cpu_604(int cpu_nr); extern void __setup_cpu_750(int cpu_nr); extern void __setup_cpu_7400(int cpu_nr); +extern void __setup_cpu_7410(int cpu_nr); extern void __setup_cpu_7450(int cpu_nr); extern void __setup_cpu_power3(int cpu_nr); -extern void __setup_cpu_power4(int cpu_nr); extern void __setup_cpu_8xx(int cpu_nr); extern void __setup_cpu_generic(int cpu_nr); -#define CLASSIC_PPC (!defined(CONFIG_8xx) && \ - !defined(CONFIG_4xx) && !defined(CONFIG_POWER3) && \ - !defined(CONFIG_POWER4) && !defined(CONFIG_PPC_ISERIES)) +#define CLASSIC_PPC (!defined(CONFIG_8xx) && !defined(CONFIG_4xx) && \ + !defined(CONFIG_POWER3) && !defined(CONFIG_PPC_ISERIES)) /* This table only contains "desktop" CPUs, it need to be filled with embedded * ones as well... @@ -113,16 +112,40 @@ struct cpu_spec cpu_specs[] = { 32, 32, __setup_cpu_604 }, - { /* 750 (0x4202, don't support TAU ?) */ - 0xffffffff, 0x00084202, "750", + { /* 740/750 (0x4202, don't support TAU ?) */ + 0xffffffff, 0x00084202, "740/750", CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_HPTE_TABLE, COMMON_PPC, 32, 32, __setup_cpu_750 }, - { /* 750CX */ - 0xffffff00, 0x00082200, "750CX", + { /* 745/755 */ + 0xfffff000, 0x00083000, "745/755", + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE, + COMMON_PPC, + 32, 32, + __setup_cpu_750 + }, + { /* 750CX (80100 and 8010x?) */ + 0xfffffff0, 0x00080100, "750CX", + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE, + COMMON_PPC, + 32, 32, + __setup_cpu_750 + }, + { /* 750CX (82201 and 82202) */ + 0xfffffff0, 0x00082200, "750CX", + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE, + COMMON_PPC, + 32, 32, + __setup_cpu_750 + }, + { /* 750CXe (82214) */ + 0xfffffff0, 0x00082210, "750CXe", CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE, COMMON_PPC, @@ -159,9 +182,18 @@ struct cpu_spec cpu_specs[] = { CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE, COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC, 32, 32, - __setup_cpu_7400 + __setup_cpu_7410 }, - { /* 7450 */ + { /* 7450 2.0 - no doze/nap */ + 0xffffffff, 0x80000200, "7450", + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | + CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450, + COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC, + 32, 32, + __setup_cpu_7450 + }, + { /* 7450 others */ 0xffff0000, 0x80000000, "7450", CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | @@ -215,15 +247,6 @@ struct cpu_spec cpu_specs[] = { __setup_cpu_power3 }, #endif /* CONFIG_PPC64BRIDGE */ -#ifdef CONFIG_POWER4 - { /* Power4 */ - 0xffff0000, 0x00350000, "Power4", - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE, - COMMON_PPC | PPC_FEATURE_64, - 128, 128, - __setup_cpu_power4 - }, -#endif /* CONFIG_POWER4 */ #ifdef CONFIG_8xx { /* 8xx */ 0xffff0000, 0x00500000, "8xx", @@ -270,6 +293,20 @@ struct cpu_spec cpu_specs[] = { 32, 32, 0, /*__setup_cpu_405 */ }, + { /* STB 04xxx */ + 0xffff0000, 0x41810000, "STB04xxx", + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB, + PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, + 32, 32, + 0, /*__setup_cpu_405 */ + }, + { /* NP405L */ + 0xffff0000, 0x41610000, "NP405L", + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB, + PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC, + 16, 8, + 0, /*__setup_cpu_405 */ + }, #endif /* CONFIG_4xx */ #if !CLASSIC_PPC { /* default match */ diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S index cb4ff46032f5..70fae23e5ffd 100644 --- a/arch/ppc/kernel/entry.S +++ b/arch/ppc/kernel/entry.S @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.entry.S 1.22 08/15/01 22:43:06 paulus + * BK Id: %F% %I% %G% %U% %#% */ /* * PowerPC version @@ -11,6 +11,7 @@ * rewritten by Paul Mackerras. * Copyright (C) 1996 Paul Mackerras. * MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net). + * Adaptations for iSeries Lpar by Mike Corrigan & Dave Boutcher * * This file contains the system call entry code, context switch * code, and exception/interrupt return code for PowerPC. @@ -22,7 +23,6 @@ * */ -#include "ppc_asm.h" #include <linux/config.h> #include <linux/errno.h> #include <linux/sys.h> @@ -31,6 +31,11 @@ #include <asm/page.h> #include <asm/mmu.h> #include <asm/cputable.h> +#include <asm/ppc_asm.h> +#include "ppc_defs.h" +#ifdef CONFIG_PPC_ISERIES +#include "iSeries_asm.h" +#endif /* CONFIG_PPC_ISERIES */ #undef SHOW_SYSCALLS #undef SHOW_SYSCALLS_TASK @@ -45,6 +50,10 @@ show_syscalls_task: * Handle a system call. */ .text + .stabs "arch/ppc/kernel/",N_SO,0,0,0f + .stabs "entry.S",N_SO,0,0,0f +0: + _GLOBAL(DoSyscall) stw r0,THREAD+LAST_SYSCALL(r2) lwz r11,_CCR(r1) /* Clear SO bit in CR */ @@ -86,8 +95,8 @@ _GLOBAL(DoSyscall) beq- 10f cmpi 0,r0,0x6666 /* Special case for 'sys_rt_sigreturn' */ beq- 16f - lwz r10,TASK_PTRACE(r2) - andi. r10,r10,PT_TRACESYS + lbz r10,SYSCALL_TRACE(r2) + cmpwi r10,0 bne- 50f cmpli 0,r0,NR_syscalls bge- 66f @@ -142,7 +151,7 @@ ret_from_syscall_1: bge ret_from_except b 20b /* Traced system call support */ -50: bl syscall_trace +50: bl do_syscall_trace lwz r0,GPR0(r1) /* Restore original registers */ lwz r3,GPR3(r1) lwz r4,GPR4(r1) @@ -177,7 +186,7 @@ ret_from_syscall_2: oris r10,r10,0x1000 stw r10,_CCR(r1) 60: stw r3,GPR3(r1) /* Update return value */ - bl syscall_trace + bl do_syscall_trace b ret_from_except 66: li r3,ENOSYS b 52b @@ -197,6 +206,9 @@ ret_from_syscall_2: * On entry, r3 points to the THREAD for the current task, r4 * points to the THREAD for the new task. * + * This routine is always called with interrupts disabled + * (soft disabled for iSeries). + * * Note: there are two ways to get to the "going out" portion * of this code; either by coming in via the entry (_switch) * or via "fork" which must set up an environment equivalent @@ -216,6 +228,7 @@ _GLOBAL(_switch) SAVE_8GPRS(14, r1) SAVE_10GPRS(22, r1) mflr r20 /* Return to switch caller */ + stw r20,INT_FRAME_SIZE+4(r1) mfmsr r22 li r0,MSR_FP /* Disable floating-point */ #ifdef CONFIG_ALTIVEC @@ -223,10 +236,12 @@ BEGIN_FTR_SECTION oris r0,r0,MSR_VEC@h /* Disable altivec */ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) #endif /* CONFIG_ALTIVEC */ + and. r0,r0,r22 /* FP or altivec enabled? */ + beq+ 1f andc r22,r22,r0 mtmsr r22 isync - stw r20,_NIP(r1) +1: stw r20,_NIP(r1) stw r22,_MSR(r1) stw r20,_LINK(r1) mfcr r20 @@ -261,9 +276,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) .globl ret_from_fork ret_from_fork: bl schedule_tail -#error lwz r0,TASK_PTRACE(r2) - andi. r0,r0,PT_TRACESYS -#error bnel- syscall_trace + lbz r0,SYSCALL_TRACE(r2) + cmpwi r0,0 + bnel- do_syscall_trace b ret_from_except .globl ret_from_intercept @@ -276,94 +291,115 @@ ret_from_intercept: beq restore .globl ret_from_except ret_from_except: - lwz r3,_MSR(r1) /* Returning to user mode? */ - andi. r3,r3,MSR_PR - beq+ do_signal_ret /* if so, check need_resched and signals */ -#error lwz r3,NEED_RESCHED(r2) - cmpi 0,r3,0 /* check need_resched flag */ - beq+ 7f - bl schedule -#error 7: lwz r5,SIGPENDING(r2) /* Check for pending unblocked signals */ - cmpwi 0,r5,0 - beq+ do_signal_ret - li r3,0 - addi r4,r1,STACK_FRAME_OVERHEAD -#error bl do_signal - .globl do_signal_ret -do_signal_ret: - .globl ret_to_user_hook -ret_to_user_hook: - nop -restore: - lwz r3,_XER(r1) - mtspr XER,r3 - REST_10GPRS(9,r1) - REST_10GPRS(19,r1) - REST_2GPRS(29,r1) + REST_10GPRS(13,r1) + REST_8GPRS(23,r1) REST_GPR(31,r1) - /* make sure we hard disable here, even if rtl is active, to protect - * SRR[01] and SPRG2 -- Cort - */ - mfmsr r0 /* Get current interrupt state */ - rlwinm r0,r0,0,17,15 /* clear MSR_EE in r0 */ + /* Hard-disable interrupts so that current->work can't change + * between when we test it and when we return from the interrupt. */ +recheck: + mfmsr r10 + rlwinm r0,r10,0,17,15 /* clear MSR_EE in r0 */ +#ifdef CONFIG_4xx + rlwinm r0,r0,0,23,21 /* clear MSR_DE in r0 */ +#endif SYNC /* Some chip revs have problems here... */ mtmsr r0 /* Update machine state */ - stwcx. r0,0,r1 /* to clear the reservation */ + lwz r3,_MSR(r1) /* Returning to user mode? */ + andi. r3,r3,MSR_PR + beq+ restore /* if not, just restore regs and return */ + + /* Check current->work */ + lwz r3,TASK_WORK(r2) + rlwinm. r0,r3,0,16,7 /* need_resched, sigpending, notify_resume */ + bne do_work + + .globl ret_to_user_hook +ret_to_user_hook: + nop - /* if returning to user mode, set new sprg2 and save kernel SP */ - lwz r0,_MSR(r1) - andi. r0,r0,MSR_PR - beq+ 1f #ifdef CONFIG_ALTIVEC BEGIN_FTR_SECTION lwz r0,THREAD+THREAD_VRSAVE(r2) mtspr SPRN_VRSAVE,r0 /* if G4, restore VRSAVE reg */ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) #endif /* CONFIG_ALTIVEC */ + addi r0,r1,INT_FRAME_SIZE /* size of frame */ stw r0,THREAD+KSP(r2) /* save kernel stack pointer */ + +#ifndef CONFIG_PPC_ISERIES tophys(r8,r1) CLR_TOP32(r8) mtspr SPRG2,r8 /* phys exception stack pointer */ -1: +#else /* CONFIG_PPC_ISERIES */ + mfspr r2,SPRG1 /* Get Paca address */ + stw r1,PACAKSAVE(r2) /* save exception stack pointer */ +#endif /* CONFIG_PPC_ISERIES */ + + /* interrupts are hard-disabled at this point */ +restore: + REST_8GPRS(4, r1) + REST_GPR(12, r1) + lwz r3,_XER(r1) + mtspr XER,r3 + + PPC405_ERR77(0,r1) + stwcx. r0,0,r1 /* to clear the reservation */ + lwz r3,_CTR(r1) lwz r0,_LINK(r1) mtctr r3 mtlr r0 - REST_4GPRS(3, r1) - REST_2GPRS(7, r1) - /* We have to "dummy" load from the context save area in case - * these instructions cause an MMU fault. If this happens - * after we load SRR0/SRR1, our return context is hosed. -- Dan - */ - lwz r0,GPR0(r1) - lwz r0,GPR2(r1) - lwz r0,GPR1(r1) + lwz r0,_MSR(r1) + lwz r3,_CCR(r1) + FIX_SRR1(r0,r2) + lwz r2,_NIP(r1) + mtcrf 0xFF,r3 - /* We re-use r3,r4 here (the load above was to cause the MMU - * fault if necessary). Using r3,r4 removes the need to "dummy" - * load the CCR and NIP. Since we load them we may as well - * use them. + /* + * We can't afford to take an exception between setting SRR0/1 + * and the rfi. Since GPR0(r1) .. GPR3(r1) are in the same cache + * line, loading r3 here should mean that we should have a HPTE + * (for classic PPC) or TLB entry (for 4xx/8xx) for that cache + * line, even if it isn't covered by a BAT register. + * In addition, the cache line itself will be in L1 cache. + * There is still the possibility of the HPTE getting evicted + * on SMP systems. */ - lwz r3,_CCR(r1) - lwz r4,_NIP(r1) + lwz r3,GPR3(r1) - lwz r0,_MSR(r1) - FIX_SRR1(r0,r2) mtspr SRR1,r0 - mtcrf 0xFF,r3 - mtspr SRR0,r4 + mtspr SRR0,r2 lwz r0,GPR0(r1) lwz r2,GPR2(r1) - lwz r3,GPR3(r1) - lwz r4,GPR4(r1) lwz r1,GPR1(r1) SYNC + PPC405_ERR77_SYNC RFI +do_work: + ori r10,r10,MSR_EE + SYNC + mtmsr r10 /* hard-enable interrupts */ + rlwinm. r0,r3,0,0,7 /* test need_resched */ + beq 1f + bl schedule + b recheck +1: + rlwinm. r0,r3,0,16,23 /* test sigpending */ + beq 2f + li r3,0 + addi r4,r1,STACK_FRAME_OVERHEAD + bl do_signal + b recheck +2: + /* nobody uses work.notify_resume yet */ + li r0,0 + stb r0,NOTIFY_RESUME(r2) + b recheck /* * PROM code for specific machines follows. Put it @@ -375,8 +411,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) * On CHRP, the Run-Time Abstraction Services (RTAS) have to be * called with the MMU off. */ - .globl enter_rtas -enter_rtas: +_GLOBAL(enter_rtas) mflr r0 stw r0,20(r1) lis r4,rtas_data@ha @@ -391,9 +426,9 @@ enter_rtas: mfmsr r9 stw r9,8(r1) li r0,0 - ori r0,r0,MSR_EE|MSR_SE|MSR_BE + ori r0,r0,MSR_EE|MSR_SE|MSR_BE|MSR_FE0|MSR_FE1 andc r0,r9,r0 - li r10,MSR_IR|MSR_DR|MSR_FE0|MSR_FE1|MSR_FP + li r10,MSR_IR|MSR_DR|MSR_FP andc r9,r0,r10 SYNC /* disable interrupts so SRR0/1 */ mtmsr r0 /* don't get trashed */ diff --git a/arch/ppc/kernel/error_log.c b/arch/ppc/kernel/error_log.c deleted file mode 100644 index b414b27fb174..000000000000 --- a/arch/ppc/kernel/error_log.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - * BK Id: SCCS/s.error_log.c 1.6 05/17/01 18:14:21 cort - */ -/* - * arch/ppc/kernel/error_log.c - * - * Copyright (c) 2000 Tilmann Bitterberg - * (tilmann@bitterberg.de) - * - * Error processing of errors found by rtas even-scan routine - * which is done with every heartbeat. (chrp_setup.c) - */ - -#include <linux/sched.h> - -#include <asm/prom.h> - -#include "error_log.h" - -/* ****************************************************************** */ -/* - * EVENT-SCAN - * The whole stuff below here doesn't take any action when it found - * an error, it just prints as much information as possible and - * then its up to the user to decide what to do. - * - * Returns 0 if no errors were found - * Returns 1 if there may be more errors - */ -int ppc_rtas_errorlog_scan(void) -{ -const char *_errlog_severity[] = { -#ifdef VERBOSE_ERRORS - "No Error\n\t\ -Should require no further information", - "Event\n\t\ -This is not really an error, it is an event. I use events\n\t\ -to communicate with RTAS back and forth.", - "Warning\n\t\ -Indicates a non-state-losing error, either fully recovered\n\t\ -by RTAS or not needing recovery. Ignore it.", - "Error sync\n\t\ -May only be fatal to a certain program or thread. Recovery\n\t\ -and continuation is possible, if I only had a handler for\n\t\ -this. Less serious", - "Error\n\t\ -Less serious, but still causing a loss of data and state.\n\t\ -I can't tell you exactly what to do, You have to decide\n\t\ -with help from the target and initiator field, what kind\n\t\ -of further actions may take place.", - "Fatal\n\t\ -Represent a permanent hardware failure and I believe this\n\t\ -affects my overall performance and behaviour. I would not\n\t\ -attempt to continue normal operation." -#else - "No Error", - "Event", - "Warning", - "Error sync", - "Error", - "Fatal" -#endif /* VERBOSE_ERRORS */ -}; - -#if 0 /* unused?? */ -const char *_errlog_disposition[] = { -#ifdef VERBOSE_ERRORS - "Fully recovered\n\t\ -There was an error, but it is fully recovered by RTAS.", - "Limited recovery\n\t\ -RTAS was able to recover the state of the machine, but some\n\t\ -feature of the machine has been disabled or lost (for example\n\t\ -error checking) or performance may suffer.", - "Not recovered\n\t\ -Whether RTAS did not try to recover anything or recovery failed:\n\t\ -HOUSTON, WE HAVE A PROBLEM!" -#else - "Fully recovered", - "Limited recovery", - "Not recovered" -#endif /* VERBOSE_ERRORS */ -}; -#endif - -const char *_errlog_extended[] = { -#ifdef VERBOSE_ERRORS - "Not present\n\t\ -Sad, the RTAS call didn't return an extended error log.", - "Present\n\t\ -The extended log is present and hopefully it contains a lot of\n\t\ -useful information, which leads to the solution of the problem." -#else - "Not present", - "Present" -#endif /* VERBOSE_ERRORS */ -}; - -const char *_errlog_initiator[] = { - "Unknown or not applicable", - "CPU", - "PCI", - "ISA", - "Memory", - "Power management" -}; - -const char *_errlog_target[] = { - "Unknown or not applicable", - "CPU", - "PCI", - "ISA", - "Memory", - "Power management" -}; - rtas_error_log error_log; - char logdata[1024]; - int error; -#if 0 /* unused?? */ - int retries = 0; /* if HW error, try 10 times */ -#endif - - error = call_rtas ("event-scan", 4, 1, (unsigned long *)&error_log, - INTERNAL_ERROR | EPOW_WARNING, - 0, __pa(logdata), 1024); - - if (error == 1) /* no errors found */ - return 0; - - if (error == -1) { - printk(KERN_ERR "Unable to get errors. Do you a favor and throw this box away\n"); - return 0; - } - if (error_log.version != 1) - printk(KERN_WARNING "Unknown version (%d), please implement me\n", - error_log.version); - - switch (error_log.disposition) { - case DISP_FULLY_RECOVERED: - /* there was an error, but everything is fine now */ - return 0; - case DISP_NOT_RECOVERED: - printk("We have a really serious Problem!\n"); - case DISP_LIMITED_RECOVERY: - printk("Error classification\n"); - printk("Severity : %s\n", - ppc_rtas_errorlog_check_severity (error_log)); - printk("Initiator : %s\n", - ppc_rtas_errorlog_check_initiator (error_log)); - printk("Target : %s\n", - ppc_rtas_errorlog_check_target (error_log)); - printk("Type : %s\n", - ppc_rtas_errorlog_check_type (error_log)); - printk("Ext. log : %s\n", - ppc_rtas_errorlog_check_extended (error_log)); - if (error_log.extended) - ppc_rtas_errorlog_disect_extended (logdata); - return 1; - default: - /* nothing */ - break; - } - return 0; -} -/* ****************************************************************** */ -const char * ppc_rtas_errorlog_check_type (rtas_error_log error_log) -{ - const char *_errlog_type[] = { - "unknown type", - "too many tries failed", - "TCE error", - "RTAS device failed", - "target timed out", - "parity error on data", /* 5 */ - "parity error on address", - "parity error on external cache", - "access to invalid address", - "uncorrectable ECC error", - "corrected ECC error" /* 10 */ - }; - if (error_log.type == TYPE_EPOW) - return "EPOW"; - if (error_log.type >= TYPE_PMGM_POWER_SW_ON) - return "PowerMGM Event (not handled right now)"; - return _errlog_type[error_log.type]; -} - diff --git a/arch/ppc/kernel/error_log.h b/arch/ppc/kernel/error_log.h deleted file mode 100644 index bb162a592e3a..000000000000 --- a/arch/ppc/kernel/error_log.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * BK Id: SCCS/s.error_log.h 1.5 05/17/01 18:14:21 cort - */ -#ifndef __ERROR_LOG_H__ -#define __ERROR_LOG_H__ - -#define VERBOSE_ERRORS 1 /* Maybe I enlarge the kernel too much */ -#undef VERBOSE_ERRORS - -/* Event classes */ -/* XXX: Endianess correct? NOW*/ -#define INTERNAL_ERROR 0x80000000 /* set bit 0 */ -#define EPOW_WARNING 0x40000000 /* set bit 1 */ -#define POWERMGM_EVENTS 0x20000000 /* set bit 2 */ - -/* event-scan returns */ -#define SEVERITY_FATAL 0x5 -#define SEVERITY_ERROR 0x4 -#define SEVERITY_ERROR_SYNC 0x3 -#define SEVERITY_WARNING 0x2 -#define SEVERITY_EVENT 0x1 -#define SEVERITY_NO_ERROR 0x0 -#define DISP_FULLY_RECOVERED 0x0 -#define DISP_LIMITED_RECOVERY 0x1 -#define DISP_NOT_RECOVERED 0x2 -#define PART_PRESENT 0x0 -#define PART_NOT_PRESENT 0x1 -#define INITIATOR_UNKNOWN 0x0 -#define INITIATOR_CPU 0x1 -#define INITIATOR_PCI 0x2 -#define INITIATOR_ISA 0x3 -#define INITIATOR_MEMORY 0x4 -#define INITIATOR_POWERMGM 0x5 -#define TARGET_UNKNOWN 0x0 -#define TARGET_CPU 0x1 -#define TARGET_PCI 0x2 -#define TARGET_ISA 0x3 -#define TARGET_MEMORY 0x4 -#define TARGET_POWERMGM 0x5 -#define TYPE_RETRY 0x01 -#define TYPE_TCE_ERR 0x02 -#define TYPE_INTERN_DEV_FAIL 0x03 -#define TYPE_TIMEOUT 0x04 -#define TYPE_DATA_PARITY 0x05 -#define TYPE_ADDR_PARITY 0x06 -#define TYPE_CACHE_PARITY 0x07 -#define TYPE_ADDR_INVALID 0x08 -#define TYPE_ECC_UNCORR 0x09 -#define TYPE_ECC_CORR 0x0a -#define TYPE_EPOW 0x40 -/* I don't add PowerMGM events right now, this is a different topic */ -#define TYPE_PMGM_POWER_SW_ON 0x60 -#define TYPE_PMGM_POWER_SW_OFF 0x61 -#define TYPE_PMGM_LID_OPEN 0x62 -#define TYPE_PMGM_LID_CLOSE 0x63 -#define TYPE_PMGM_SLEEP_BTN 0x64 -#define TYPE_PMGM_WAKE_BTN 0x65 -#define TYPE_PMGM_BATTERY_WARN 0x66 -#define TYPE_PMGM_BATTERY_CRIT 0x67 -#define TYPE_PMGM_SWITCH_TO_BAT 0x68 -#define TYPE_PMGM_SWITCH_TO_AC 0x69 -#define TYPE_PMGM_KBD_OR_MOUSE 0x6a -#define TYPE_PMGM_ENCLOS_OPEN 0x6b -#define TYPE_PMGM_ENCLOS_CLOSED 0x6c -#define TYPE_PMGM_RING_INDICATE 0x6d -#define TYPE_PMGM_LAN_ATTENTION 0x6e -#define TYPE_PMGM_TIME_ALARM 0x6f -#define TYPE_PMGM_CONFIG_CHANGE 0x70 -#define TYPE_PMGM_SERVICE_PROC 0x71 - -typedef struct _rtas_error_log { - unsigned long version:8; /* Architectural version */ - unsigned long severity:3; /* Severity level of error */ - unsigned long disposition:2; /* Degree of recovery */ - unsigned long extended:1; /* extended log present? */ - unsigned long /* reserved */ :2; /* Reserved for future use */ - unsigned long initiator:4; /* Initiator of event */ - unsigned long target:4; /* Target of failed operation */ - unsigned long type:8; /* General event or error*/ - unsigned long extended_log_length:32; /* length in bytes */ -} rtas_error_log; - -/* ****************************************************************** */ -#define ppc_rtas_errorlog_check_severity(x) \ - (_errlog_severity[x.severity]) -#define ppc_rtas_errorlog_check_target(x) \ - (_errlog_target[x.target]) -#define ppc_rtas_errorlog_check_initiator(x) \ - (_errlog_initiator[x.initiator]) -#define ppc_rtas_errorlog_check_extended(x) \ - (_errlog_extended[x.extended]) -#define ppc_rtas_errorlog_disect_extended(x) \ - do { /* implement me */ } while(0) -extern const char * ppc_rtas_errorlog_check_type (rtas_error_log error_log); -extern int ppc_rtas_errorlog_scan(void); - - -#endif /* __ERROR_LOG_H__ */ diff --git a/arch/ppc/kernel/feature.c b/arch/ppc/kernel/feature.c deleted file mode 100644 index 21c1d9e20f2f..000000000000 --- a/arch/ppc/kernel/feature.c +++ /dev/null @@ -1,1300 +0,0 @@ -/* - * BK Id: SCCS/s.feature.c 1.21 09/08/01 15:47:42 paulus - */ -/* - * arch/ppc/kernel/feature.c - * - * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) - * Ben. Herrenschmidt (benh@kernel.crashing.org) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ -#include <linux/config.h> -#include <linux/types.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/spinlock.h> -#include <asm/sections.h> -#include <asm/errno.h> -#include <asm/ohare.h> -#include <asm/heathrow.h> -#include <asm/keylargo.h> -#include <asm/uninorth.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/feature.h> -#include <asm/dbdma.h> -#include <asm/machdep.h> - -#undef DEBUG_FEATURE - -#define MAX_FEATURE_CONTROLLERS 2 -#define FREG(c,r) (&(((c)->reg)[(r)>>2])) - -/* Keylargo reg. access. */ -#define KL_FCR(r) (keylargo_base + ((r) >> 2)) -#define KL_IN(r) (in_le32(KL_FCR(r))) -#define KL_OUT(r,v) (out_le32(KL_FCR(r), (v))) -#define KL_BIS(r,v) (KL_OUT((r), KL_IN(r) | (v))) -#define KL_BIC(r,v) (KL_OUT((r), KL_IN(r) & ~(v))) -#define KL_GPIO_IN(r) (in_8(((volatile u8 *)keylargo_base)+(r))) -#define KL_GPIO_OUT(r,v) (out_8(((volatile u8 *)keylargo_base)+(r), (v))) -#define KL_LOCK() spin_lock_irqsave(&keylargo->lock, flags) -#define KL_UNLOCK() spin_unlock_irqrestore(&keylargo->lock, flags) - -/* Uni-N reg. access. Note that Uni-N regs are big endian */ -#define UN_REG(r) (uninorth_base + ((r) >> 2)) -#define UN_IN(r) (in_be32(UN_REG(r))) -#define UN_OUT(r,v) (out_be32(UN_REG(r), (v))) -#define UN_BIS(r,v) (UN_OUT((r), UN_IN(r) | (v))) -#define UN_BIC(r,v) (UN_OUT((r), UN_IN(r) & ~(v))) - -typedef struct feature_bit { - int reg; /* reg. offset from mac-io base */ - unsigned int polarity; /* 0 = normal, 1 = inverse */ - unsigned int mask; /* bit mask */ -} fbit; - -/* Those features concern for OHare-based PowerBooks (2400, 3400, 3500) - */ -static fbit feature_bits_ohare_pbook[] __pmacdata = { - {0x38,0,0}, /* FEATURE_null */ - {0x38,0,OH_SCC_RESET}, /* FEATURE_Serial_reset */ - {0x38,0,OH_SCC_ENABLE}, /* FEATURE_Serial_enable */ - {0x38,0,OH_SCCA_IO}, /* FEATURE_Serial_IO_A */ - {0x38,0,OH_SCCB_IO}, /* FEATURE_Serial_IO_B */ - {0x38,0,OH_FLOPPY_ENABLE}, /* FEATURE_SWIM3_enable */ - {0x38,0,OH_MESH_ENABLE}, /* FEATURE_MESH_enable */ - {0x38,0,OH_IDE0_ENABLE}, /* FEATURE_IDE0_enable */ - {0x38,1,OH_IDE0_RESET_N}, /* FEATURE_IDE0_reset */ - {0x38,0,OH_IOBUS_ENABLE}, /* FEATURE_IOBUS_enable */ - {0x38,1,OH_BAY_RESET_N}, /* FEATURE_Mediabay_reset */ - {0x38,1,OH_BAY_POWER_N}, /* FEATURE_Mediabay_power */ - {0x38,0,OH_BAY_PCI_ENABLE}, /* FEATURE_Mediabay_PCI_enable */ - {0x38,0,OH_BAY_IDE_ENABLE}, /* FEATURE_IDE1_enable */ - {0x38,1,OH_IDE1_RESET_N}, /* FEATURE_IDE1_reset */ - {0x38,0,OH_BAY_FLOPPY_ENABLE}, /* FEATURE_Mediabay_floppy_enable */ - {0x38,0,0}, /* FEATURE_BMac_reset */ - {0x38,0,0}, /* FEATURE_BMac_IO_enable */ - {0x38,0,0}, /* FEATURE_Modem_power */ - {0x38,0,0}, /* FEATURE_Slow_SCC_PCLK */ - {0x38,0,0}, /* FEATURE_Sound_Power */ - {0x38,0,0}, /* FEATURE_Sound_CLK_Enable */ - {0x38,0,0}, /* FEATURE_IDE2_enable */ - {0x38,0,0}, /* FEATURE_IDE2_reset */ - {0x38,0,0}, /* FEATURE_Mediabay_IDE_switch */ - {0x38,0,0}, /* FEATURE_Mediabay_content */ - {0x38,0,0}, /* FEATURE_Airport_reset */ -}; - -/* Those bits concern heathrow-based desktop machines (Beige G3s). We have removed - * the SCC related bits and init them once. They have proven to occasionally cause - * problems with the desktop units. - */ -static fbit feature_bits_heathrow[] __pmacdata = { - {0x38,0,0}, /* FEATURE_null */ - {0x38,0,0}, /* FEATURE_Serial_reset */ - {0x38,0,0}, /* FEATURE_Serial_enable */ - {0x38,0,0}, /* FEATURE_Serial_IO_A */ - {0x38,0,0}, /* FEATURE_Serial_IO_B */ - {0x38,0,HRW_SWIM_ENABLE}, /* FEATURE_SWIM3_enable */ - {0x38,0,HRW_MESH_ENABLE}, /* FEATURE_MESH_enable */ - {0x38,0,HRW_IDE0_ENABLE}, /* FEATURE_IDE0_enable */ - {0x38,1,HRW_IDE0_RESET_N}, /* FEATURE_IDE0_reset */ - {0x38,0,HRW_IOBUS_ENABLE}, /* FEATURE_IOBUS_enable */ - {0x38,1,0}, /* FEATURE_Mediabay_reset */ - {0x38,1,0}, /* FEATURE_Mediabay_power */ - {0x38,0,0}, /* FEATURE_Mediabay_PCI_enable */ - {0x38,0,HRW_BAY_IDE_ENABLE}, /* FEATURE_IDE1_enable */ - {0x38,1,HRW_IDE1_RESET_N}, /* FEATURE_IDE1_reset */ - {0x38,0,0}, /* FEATURE_Mediabay_floppy_enable */ - {0x38,0,HRW_BMAC_RESET}, /* FEATURE_BMac_reset */ - {0x38,0,HRW_BMAC_IO_ENABLE}, /* FEATURE_BMac_IO_enable */ - {0x38,1,0}, /* FEATURE_Modem_power */ - {0x38,0,HRW_SLOW_SCC_PCLK}, /* FEATURE_Slow_SCC_PCLK */ - {0x38,1,0}, /* FEATURE_Sound_Power */ - {0x38,0,0}, /* FEATURE_Sound_CLK_Enable */ - {0x38,0,0}, /* FEATURE_IDE2_enable */ - {0x38,0,0}, /* FEATURE_IDE2_reset */ - {0x38,0,0}, /* FEATURE_Mediabay_IDE_switch */ - {0x38,0,0}, /* FEATURE_Mediabay_content */ - {0x38,0,0}, /* FEATURE_Airport_reset */ -}; - -/* Those bits concern heathrow-based PowerBooks (wallstreet/mainstreet). - * Heathrow-based desktop macs (Beige G3s) are _not_ handled here - */ -static fbit feature_bits_wallstreet[] __pmacdata = { - {0x38,0,0}, /* FEATURE_null */ - {0x38,0,HRW_RESET_SCC}, /* FEATURE_Serial_reset */ - {0x38,0,HRW_SCC_ENABLE}, /* FEATURE_Serial_enable */ - {0x38,0,HRW_SCCA_IO}, /* FEATURE_Serial_IO_A */ - {0x38,0,HRW_SCCB_IO}, /* FEATURE_Serial_IO_B */ - {0x38,0,HRW_SWIM_ENABLE}, /* FEATURE_SWIM3_enable */ - {0x38,0,HRW_MESH_ENABLE}, /* FEATURE_MESH_enable */ - {0x38,0,HRW_IDE0_ENABLE}, /* FEATURE_IDE0_enable */ - {0x38,1,HRW_IDE0_RESET_N}, /* FEATURE_IDE0_reset */ - {0x38,0,HRW_IOBUS_ENABLE}, /* FEATURE_IOBUS_enable */ - {0x38,1,HRW_BAY_RESET_N}, /* FEATURE_Mediabay_reset */ - {0x38,1,HRW_BAY_POWER_N}, /* FEATURE_Mediabay_power */ - {0x38,0,HRW_BAY_PCI_ENABLE}, /* FEATURE_Mediabay_PCI_enable */ - {0x38,0,HRW_BAY_IDE_ENABLE}, /* FEATURE_IDE1_enable */ - {0x38,1,HRW_IDE1_RESET_N}, /* FEATURE_IDE1_reset */ - {0x38,0,HRW_BAY_FLOPPY_ENABLE}, /* FEATURE_Mediabay_floppy_enable */ - {0x38,0,HRW_BMAC_RESET}, /* FEATURE_BMac_reset */ - {0x38,0,HRW_BMAC_IO_ENABLE}, /* FEATURE_BMac_IO_enable */ - {0x38,1,HRW_MODEM_POWER_N}, /* FEATURE_Modem_power */ - {0x38,0,HRW_SLOW_SCC_PCLK}, /* FEATURE_Slow_SCC_PCLK */ - {0x38,1,HRW_SOUND_POWER_N}, /* FEATURE_Sound_Power */ - {0x38,0,HRW_SOUND_CLK_ENABLE}, /* FEATURE_Sound_CLK_Enable */ - {0x38,0,0}, /* FEATURE_IDE2_enable */ - {0x38,0,0}, /* FEATURE_IDE2_reset */ - {0x38,0,0}, /* FEATURE_Mediabay_IDE_switch */ - {0x38,0,0}, /* FEATURE_Mediabay_content */ - {0x38,0,0}, /* FEATURE_Airport_reset */ -}; - -/* - * Those bits are from a 1999 G3 PowerBook, with a paddington chip. - * Mostly the same as the heathrow. They are used on both PowerBooks - * and desktop machines using the paddington chip - */ -static fbit feature_bits_paddington[] __pmacdata = { - {0x38,0,0}, /* FEATURE_null */ - {0x38,0,PADD_RESET_SCC}, /* FEATURE_Serial_reset */ - {0x38,0,HRW_SCC_ENABLE}, /* FEATURE_Serial_enable */ - {0x38,0,HRW_SCCA_IO}, /* FEATURE_Serial_IO_A */ - {0x38,0,HRW_SCCB_IO}, /* FEATURE_Serial_IO_B */ - {0x38,0,HRW_SWIM_ENABLE}, /* FEATURE_SWIM3_enable */ - {0x38,0,HRW_MESH_ENABLE}, /* FEATURE_MESH_enable */ - {0x38,0,HRW_IDE0_ENABLE}, /* FEATURE_IDE0_enable */ - {0x38,1,HRW_IDE0_RESET_N}, /* FEATURE_IDE0_reset */ - {0x38,0,HRW_IOBUS_ENABLE}, /* FEATURE_IOBUS_enable */ - {0x38,1,HRW_BAY_RESET_N}, /* FEATURE_Mediabay_reset */ - {0x38,1,HRW_BAY_POWER_N}, /* FEATURE_Mediabay_power */ - {0x38,0,HRW_BAY_PCI_ENABLE}, /* FEATURE_Mediabay_PCI_enable */ - {0x38,0,HRW_BAY_IDE_ENABLE}, /* FEATURE_IDE1_enable */ - {0x38,1,HRW_IDE1_RESET_N}, /* FEATURE_IDE1_reset */ - {0x38,0,HRW_BAY_FLOPPY_ENABLE}, /* FEATURE_Mediabay_floppy_enable */ - {0x38,0,HRW_BMAC_RESET}, /* FEATURE_BMac_reset */ - {0x38,0,HRW_BMAC_IO_ENABLE}, /* FEATURE_BMac_IO_enable */ - {0x38,1,PADD_MODEM_POWER_N}, /* FEATURE_Modem_power */ - {0x38,0,HRW_SLOW_SCC_PCLK}, /* FEATURE_Slow_SCC_PCLK */ - {0x38,1,HRW_SOUND_POWER_N}, /* FEATURE_Sound_Power */ - {0x38,0,HRW_SOUND_CLK_ENABLE}, /* FEATURE_Sound_CLK_Enable */ - {0x38,0,0}, /* FEATURE_IDE2_enable */ - {0x38,0,0}, /* FEATURE_IDE2_reset */ - {0x38,0,0}, /* FEATURE_Mediabay_IDE_switch */ - {0x38,0,0}, /* FEATURE_Mediabay_content */ - {0x38,0,0}, /* FEATURE_Airport_reset */ -}; - -/* Those bits are for Core99 machines (iBook,G4,iMacSL/DV,Pismo,...). - * Note: Different sets may be needed for iBook, especially for sound - */ -static fbit feature_bits_keylargo[] __pmacdata = { - {0x38,0,0}, /* FEATURE_null */ - {0x38,0,KL0_SCC_RESET}, /* FEATURE_Serial_reset */ - {0x38,0,KL0_SERIAL_ENABLE}, /* FEATURE_Serial_enable */ - {0x38,0,KL0_SCC_A_INTF_ENABLE}, /* FEATURE_Serial_IO_A */ - {0x38,0,KL0_SCC_B_INTF_ENABLE}, /* FEATURE_Serial_IO_B */ - {0x38,0,0}, /* FEATURE_SWIM3_enable */ - {0x38,0,0}, /* FEATURE_MESH_enable */ - {0x3c,0,KL1_EIDE0_ENABLE}, /* FEATURE_IDE0_enable */ - {0x3c,1,KL1_EIDE0_RESET_N}, /* FEATURE_IDE0_reset */ - {0x38,0,0}, /* FEATURE_IOBUS_enable */ - {0x34,1,KL_MBCR_MB0_DEV_RESET}, /* FEATURE_Mediabay_reset */ - {0x34,1,KL_MBCR_MB0_DEV_POWER}, /* FEATURE_Mediabay_power */ - {0x38,0,0}, /* FEATURE_Mediabay_PCI_enable */ - {0x3c,0,KL1_EIDE1_ENABLE}, /* FEATURE_IDE1_enable */ - {0x3c,1,KL1_EIDE1_RESET_N}, /* FEATURE_IDE1_reset */ - {0x38,0,0}, /* FEATURE_Mediabay_floppy_enable */ - {0x38,0,0}, /* FEATURE_BMac_reset */ - {0x38,0,0}, /* FEATURE_BMac_IO_enable */ - {0x40,1,KL2_MODEM_POWER_N}, /* FEATURE_Modem_power */ - {0x38,0,0}, /* FEATURE_Slow_SCC_PCLK */ - {0x38,0,0}, /* FEATURE_Sound_Power */ - {0x38,0,0}, /* FEATURE_Sound_CLK_Enable */ - {0x3c,0,KL1_UIDE_ENABLE}, /* FEATURE_IDE2_enable */ - {0x3c,1,KL1_UIDE_RESET_N}, /* FEATURE_IDE2_reset */ - {0x34,0,KL_MBCR_MB0_DEV_ENABLE},/* FEATURE_Mediabay_IDE_switch */ - {0x34,0,KL_MBCR_MB0_ENABLE}, /* FEATURE_Mediabay_content */ - {0x40,1,KL2_AIRPORT_RESET_N}, /* FEATURE_Airport_reset */ -}; - -/* definition of a feature controller object */ -struct feature_controller { - fbit* bits; - volatile u32* reg; - struct device_node* device; - spinlock_t lock; -}; - -/* static functions */ -static struct feature_controller* -feature_add_controller(struct device_node *controller_device, fbit* bits); - -static struct feature_controller* -feature_lookup_controller(struct device_node *device); - -static void uninorth_init(void); -static void keylargo_init(void); -#ifdef CONFIG_PMAC_PBOOK -static void heathrow_prepare_for_sleep(struct feature_controller* ctrler); -static void heathrow_wakeup(struct feature_controller* ctrler); -static void core99_prepare_for_sleep(struct feature_controller* ctrler); -static void core99_wake_up(struct feature_controller* ctrler); -#endif /* CONFIG_PMAC_PBOOK */ - -/* static variables */ -static struct feature_controller controllers[MAX_FEATURE_CONTROLLERS]; -static int controller_count = 0; - -/* Core99 stuffs */ -/*static*/ volatile u32* uninorth_base; -static volatile u32* keylargo_base; -static struct feature_controller* keylargo; -static int uninorth_rev; -static int keylargo_rev; -static u32 board_features; -static int airport_pwr_state; -static struct device_node* airport_dev; -static struct device_node* uninorth_fw; - -/* Feature bits for Apple motherboards */ -#define FTR_NEED_OPENPIC_TWEAK 0x00000001 -#define FTR_CAN_NAP 0x00000002 -#define FTR_HAS_FW_POWER 0x00000004 -#define FTR_CAN_SLEEP 0x00000008 - -/* This table currently lacks most oldworld machines, but - * they currently don't need it so... - * - * Todo: The whole feature_xxx mecanism need to be redone - * some way to be able to handle the new kind of features - * exposed by core99. At this point, the main "tables" will - * probably be in this table, which will have to be filled with - * all known machines - */ -/* Warning: Don't change ordering of entries as some machines - * adverstise beeing compatible with several models. In those - * case, the "highest" has to be first - */ -static struct board_features_t { - char* compatible; - u32 features; -} board_features_datas[] __initdata = -{ - { "AAPL,PowerMac G3", 0 }, /* Beige G3 */ - { "iMac,1", 0 }, /* First iMac (gossamer) */ - { "PowerMac1,1", 0 }, /* B&W G3 / Yikes */ - { "PowerMac1,2", 0 }, /* B&W G3 / Yikes */ - { "PowerMac2,1", FTR_CAN_SLEEP }, /* r128 based iMac */ - { "PowerMac2,2", FTR_HAS_FW_POWER|FTR_CAN_SLEEP }, /* Summer 2000 iMac */ - { "PowerMac4,1", FTR_CAN_SLEEP }, /* iMac "Flower Power" */ - { "PowerMac3,1", FTR_NEED_OPENPIC_TWEAK }, /* Sawtooth (G4) */ - { "PowerMac3,2", 0 }, /* G4/Dual G4 */ - { "PowerMac3,3", FTR_NEED_OPENPIC_TWEAK }, /* G4/Dual G4 */ - { "PowerMac3,4", 0 }, /* QuickSilver G4 */ - { "PowerMac3,5", 0 }, /* QuickSilver G4 */ - { "PowerMac5,1", FTR_CAN_NAP }, /* Cube */ - { "AAPL,3400/2400", FTR_CAN_SLEEP }, /* 2400/3400 PowerBook */ - { "AAPL,3500", FTR_CAN_SLEEP }, /* 3500 PowerBook (G3) */ - { "AAPL,PowerBook1998", FTR_CAN_SLEEP }, /* Wallstreet PowerBook */ - { "PowerBook1,1", FTR_CAN_SLEEP }, /* 101 (Lombard) PowerBook */ - { "PowerBook4,1", FTR_CAN_NAP|FTR_CAN_SLEEP| /* New polycarbonate iBook */ - 0/*FTR_HAS_FW_POWER*/ }, - { "PowerBook2,1", FTR_CAN_SLEEP }, /* iBook */ - { "PowerBook2,2", FTR_CAN_SLEEP /*| FTR_CAN_NAP*/ }, /* iBook FireWire */ - { "PowerBook3,1", FTR_CAN_SLEEP|FTR_CAN_NAP| /* PowerBook 2000 (Pismo) */ - FTR_HAS_FW_POWER }, - { "PowerBook3,2", FTR_CAN_NAP|FTR_CAN_SLEEP| /* PowerBook Titanium */ - 0/*FTR_HAS_FW_POWER*/ }, - { NULL, 0 } -}; - -extern unsigned long powersave_nap; - -void __init -feature_init(void) -{ - struct device_node *np; - u32 *rev; - int i; - char* model; - - if (_machine != _MACH_Pmac) - return; - - np = find_path_device("/"); - if (!np) { - printk(KERN_ERR "feature.c: Can't find device-tree root !\n"); - return; - } - model = (char*)get_property(np, "model", NULL); - if (model) { - printk("PowerMac model: %s\n", model); - /* Figure out motherboard type & options */ - for(i=0;board_features_datas[i].compatible;i++) { - if (!strcmp(board_features_datas[i].compatible, model)) { - board_features = board_features_datas[i].features; - break; - } - } - } - - /* Set default value of powersave_nap on machines that support it */ - if (board_features & FTR_CAN_NAP) - powersave_nap = 1; - - /* Track those poor mac-io's */ - np = find_devices("mac-io"); - while (np != NULL) { - /* KeyLargo contains several (5 ?) FCR registers in mac-io, - * plus some gpio's which could eventually be handled here. - */ - if (device_is_compatible(np, "Keylargo")) { - struct feature_controller* ctrler = - feature_add_controller(np, feature_bits_keylargo); - if (ctrler) { - keylargo = ctrler; - keylargo_base = ctrler->reg; - rev = (u32 *)get_property(ctrler->device, "revision-id", NULL); - if (rev) - keylargo_rev = *rev; - - rev = (u32 *)get_property(ctrler->device, "device-id", NULL); - if (rev && (*rev) == 0x0025) - keylargo_rev |= KL_PANGEA_REV; - } - } else if (device_is_compatible(np, "paddington")) { - feature_add_controller(np, feature_bits_paddington); - /* We disable the modem power bit on Yikes as it can - * do bad things (it's the nvram power) - */ - if (machine_is_compatible("PowerMac1,1") || - machine_is_compatible("PowerMac1,2")) { - feature_bits_paddington[FEATURE_Modem_power].mask = 0; - } - } else if (machine_is_compatible("AAPL,PowerBook1998")) { - feature_add_controller(np, feature_bits_wallstreet); - } else { - struct feature_controller* ctrler = - feature_add_controller(np, feature_bits_heathrow); - if (ctrler) - out_le32(FREG(ctrler,HEATHROW_FEATURE_REG), - in_le32(FREG(ctrler,HEATHROW_FEATURE_REG)) | HRW_DEFAULTS); - - } - 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_ohare_pbook); - else - /* else not sure; maybe this is a Starmax? */ - feature_add_controller(np, NULL); - } - } - - /* Locate core99 Uni-N */ - np = find_devices("uni-n"); - if (np && np->n_addrs > 0) { - uninorth_base = ioremap(np->addrs[0].address, 0x1000); - uninorth_rev = in_be32(UN_REG(UNI_N_VERSION)); - printk("Uninorth at 0x%08x\n", np->addrs[0].address); - } - if (uninorth_base && keylargo_base) - printk("Uni-N revision: %d, KeyLargo revision: %d %s\n", - uninorth_rev, keylargo_rev, - (keylargo_rev & KL_PANGEA_REV) ? "(Pangea chipset)" : ""); - - if (uninorth_base) - uninorth_init(); - if (keylargo_base) - keylargo_init(); - - if (controller_count) - printk(KERN_INFO "Registered %d feature controller(s)\n", controller_count); - -#if defined(CONFIG_PMAC_PBOOK) && !defined(CONFIG_DMASOUND_AWACS) - /* On PowerBooks, we disable the sound chip when dmasound is a module - * or not used at all - */ - if (controller_count && find_devices("via-pmu") != NULL) { - feature_clear(controllers[0].device, FEATURE_Sound_power); - feature_clear(controllers[0].device, FEATURE_Sound_CLK_enable); - } -#endif - -#ifdef CONFIG_PMAC_PBOOK - /* On PowerBooks, we disable the serial ports by default, they - * will be re-enabled by the driver - */ -#ifndef CONFIG_XMON - if (controller_count && find_devices("via-pmu") != NULL) { - feature_set_modem_power(NULL, 0); - feature_clear(controllers[0].device, FEATURE_Serial_IO_A); - feature_clear(controllers[0].device, FEATURE_Serial_IO_B); - feature_clear(controllers[0].device, FEATURE_Serial_enable); - if (controller_count > 1) { - feature_clear(controllers[1].device, FEATURE_Serial_IO_A); - feature_clear(controllers[1].device, FEATURE_Serial_IO_B); - feature_clear(controllers[1].device, FEATURE_Serial_enable); - } - } -#endif -#endif -} - -static struct feature_controller __init * -feature_add_controller(struct device_node *controller_device, fbit* bits) -{ - struct feature_controller* controller; - - if (controller_count >= MAX_FEATURE_CONTROLLERS) { - printk(KERN_INFO "Feature controller %s skipped(MAX:%d)\n", - controller_device->full_name, MAX_FEATURE_CONTROLLERS); - return NULL; - } - 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 NULL; - } - - /* We remap the entire mac-io here. Normally, this will just - * give us back our already existing BAT mapping - */ - controller->reg = (volatile u32 *)ioremap( - controller_device->addrs[0].address, - controller_device->addrs[0].size); - - if (bits == NULL) { - printk(KERN_INFO "Twiddling the magic ohare bits\n"); - out_le32(FREG(controller,OHARE_FEATURE_REG), STARMAX_FEATURES); - return NULL; - } - - spin_lock_init(&controller->lock); - - controller_count++; - - return controller; -} - -static struct feature_controller __pmac * -feature_lookup_controller(struct device_node *device) -{ - int i; - - if (device == NULL) - return NULL; - - while(device) - { - for (i=0; i<controller_count; i++) - if (device == controllers[i].device) - return &controllers[i]; - device = device->parent; - } - -#ifdef DEBUG_FEATURE - printk("feature: <%s> not found on any controller\n", - device->name); -#endif - - return NULL; -} - -int __pmac -feature_set(struct device_node* device, enum system_feature f) -{ - struct feature_controller* controller; - unsigned long flags; - unsigned long value; - fbit* bit; - - if (f >= FEATURE_last) - return -EINVAL; - - controller = feature_lookup_controller(device); - if (!controller) - return -ENODEV; - bit = &controller->bits[f]; - if (!bit->mask) - return -EINVAL; - -#ifdef DEBUG_FEATURE - printk("feature: <%s> setting feature %d in controller @0x%x\n", - device->name, (int)f, (unsigned int)controller->reg); -#endif - - spin_lock_irqsave(&controller->lock, flags); - value = in_le32(FREG(controller, bit->reg)); - value = bit->polarity ? (value & ~bit->mask) : (value | bit->mask); - out_le32(FREG(controller, bit->reg), value); - (void)in_le32(FREG(controller, bit->reg)); - spin_unlock_irqrestore(&controller->lock, flags); - - return 0; -} - -int __pmac -feature_clear(struct device_node* device, enum system_feature f) -{ - struct feature_controller* controller; - unsigned long flags; - unsigned long value; - fbit* bit; - - if (f >= FEATURE_last) - return -EINVAL; - - controller = feature_lookup_controller(device); - if (!controller) - return -ENODEV; - bit = &controller->bits[f]; - if (!bit->mask) - return -EINVAL; - -#ifdef DEBUG_FEATURE - printk("feature: <%s> clearing feature %d in controller @0x%x\n", - device->name, (int)f, (unsigned int)controller->reg); -#endif - - spin_lock_irqsave(&controller->lock, flags); - value = in_le32(FREG(controller, bit->reg)); - value = bit->polarity ? (value | bit->mask) : (value & ~bit->mask); - out_le32(FREG(controller, bit->reg), value); - (void)in_le32(FREG(controller, bit->reg)); - spin_unlock_irqrestore(&controller->lock, flags); - - return 0; -} - -int __pmac -feature_test(struct device_node* device, enum system_feature f) -{ - struct feature_controller* controller; - unsigned long value; - fbit* bit; - - if (f >= FEATURE_last) - return -EINVAL; - - controller = feature_lookup_controller(device); - if (!controller) - return -ENODEV; - bit = &controller->bits[f]; - if (!bit->mask) - return -EINVAL; - -#ifdef DEBUG_FEATURE - printk("feature: <%s> clearing feature %d in controller @0x%x\n", - device->name, (int)f, (unsigned int)controller->reg); -#endif - /* If one feature contains several bits, all of them must be set - * for value to be true, or all of them must be 0 if polarity is - * inverse - */ - value = (in_le32(FREG(controller, bit->reg)) & bit->mask); - return bit->polarity ? (value == 0) : (value == bit->mask); -} - -int __pmac -feature_can_sleep(void) -{ - return ((board_features & FTR_CAN_SLEEP) != 0); -} - -/* - * Core99 functions - * - * Note: We currently assume there is _one_ UniN chip and _one_ KeyLargo - * chip, which is the case on all Core99 machines so far - */ - -/* Only one GMAC is assumed */ -void __pmac -feature_set_gmac_power(struct device_node* device, int power) -{ - unsigned long flags; - - if (!uninorth_base || !keylargo) - return; - - /* TODO: Handle save/restore of PCI config space here - */ - - /* XXX We use the keylargo spinlock, but we never - * have uninorth without keylargo, so... - */ - KL_LOCK(); - if (power) - UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC); - else - UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC); - (void)UN_IN(UNI_N_CLOCK_CNTL); - KL_UNLOCK(); - udelay(20); -} - -void __pmac -feature_gmac_phy_reset(struct device_node* device) -{ - unsigned long flags; - - if (!keylargo_base || !keylargo) - return; - - KL_LOCK(); - KL_GPIO_OUT(KL_GPIO_ETH_PHY_RESET, KEYLARGO_GPIO_OUTPUT_ENABLE); - (void)KL_GPIO_IN(KL_GPIO_ETH_PHY_RESET); - KL_UNLOCK(); - mdelay(10); - KL_LOCK(); - KL_GPIO_OUT(KL_GPIO_ETH_PHY_RESET, - KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA); - (void)KL_GPIO_IN(KL_GPIO_ETH_PHY_RESET); - KL_UNLOCK(); - mdelay(10); -} - -/* Pass the node of the correct controller, please */ -void __pmac -feature_set_usb_power(struct device_node* device, int power) -{ - char* prop; - int number; - u32 reg; - - unsigned long flags; - - if (!keylargo_base || !keylargo) - return; - - prop = (char *)get_property(device, "AAPL,clock-id", NULL); - if (!prop) - return; - if (strncmp(prop, "usb0u048", strlen("usb0u048")) == 0) - number = 0; - else if (strncmp(prop, "usb1u148", strlen("usb1u148")) == 0) - number = 2; - else - return; - - KL_LOCK(); - if (power) { - /* Turn ON */ - - if (number == 0) { - KL_BIC(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1)); - (void)KL_IN(KEYLARGO_FCR0); - KL_UNLOCK(); - mdelay(1); - KL_LOCK(); - KL_BIS(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE); - } else { - KL_BIC(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1)); - KL_UNLOCK(); - (void)KL_IN(KEYLARGO_FCR0); - mdelay(1); - KL_LOCK(); - KL_BIS(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE); - } - reg = KL_IN(KEYLARGO_FCR4); - reg &= ~(KL4_SET_PORT_ENABLE(number) | KL4_SET_PORT_RESUME(number) | - KL4_SET_PORT_CONNECT(number) | KL4_SET_PORT_DISCONNECT(number)); - reg &= ~(KL4_SET_PORT_ENABLE(number+1) | KL4_SET_PORT_RESUME(number+1) | - KL4_SET_PORT_CONNECT(number+1) | KL4_SET_PORT_DISCONNECT(number+1)); - KL_OUT(KEYLARGO_FCR4, reg); - (void)KL_IN(KEYLARGO_FCR4); - udelay(10); - } else { - /* Turn OFF */ - - reg = KL_IN(KEYLARGO_FCR4); - reg |= KL4_SET_PORT_ENABLE(number) | KL4_SET_PORT_RESUME(number) | - KL4_SET_PORT_CONNECT(number) | KL4_SET_PORT_DISCONNECT(number); - reg |= KL4_SET_PORT_ENABLE(number+1) | KL4_SET_PORT_RESUME(number+1) | - KL4_SET_PORT_CONNECT(number+1) | KL4_SET_PORT_DISCONNECT(number+1); - KL_OUT(KEYLARGO_FCR4, reg); - (void)KL_IN(KEYLARGO_FCR4); - udelay(1); - if (number == 0) { - KL_BIC(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE); - (void)KL_IN(KEYLARGO_FCR0); - udelay(1); - KL_BIS(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1)); - (void)KL_IN(KEYLARGO_FCR0); - } else { - KL_BIC(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE); - (void)KL_IN(KEYLARGO_FCR0); - udelay(1); - KL_BIS(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1)); - (void)KL_IN(KEYLARGO_FCR0); - } - udelay(1); - } - KL_UNLOCK(); -} - -void __pmac -feature_set_firewire_power(struct device_node* device, int power) -{ - unsigned long flags; - - /* TODO: should probably handle save/restore of PCI config space here - */ - - if (!uninorth_fw || (device && uninorth_fw != device)) - return; - if (!uninorth_base) - return; - - /* XXX We use the keylargo spinlock, but we never - * have uninorth without keylargo, so... - */ - KL_LOCK(); - if (power) - UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW); - else - UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW); - (void)UN_IN(UNI_N_CLOCK_CNTL); - KL_UNLOCK(); - udelay(20); -} - -/* Warning: will kill the PHY.. */ -void __pmac -feature_set_firewire_cable_power(struct device_node* device, int power) -{ - unsigned long flags; - u8 gpioValue = power ? 0 : 4; - - if (!uninorth_fw || (device && uninorth_fw != device)) - return; - if (!keylargo_base || !(board_features & FTR_HAS_FW_POWER)) - return; - KL_LOCK(); - KL_GPIO_OUT(KL_GPIO_FW_CABLE_POWER, gpioValue); - (void)KL_GPIO_IN(KL_GPIO_FW_CABLE_POWER); - KL_UNLOCK(); -} - -void -feature_set_modem_power(struct device_node* device, int power) -{ - unsigned long flags; - - if (!device) { - device = find_devices("ch-a"); - while(device && !device_is_compatible(device, "cobalt")) - device = device->next; - if (!device) - return; - } - if (keylargo && (keylargo_rev & KL_PANGEA_REV)) { - KL_LOCK(); - if (power) { - /* Assert modem reset */ - KL_GPIO_OUT(KL_GPIO_MODEM_RESET, KEYLARGO_GPIO_OUTPUT_ENABLE); - (void)KL_GPIO_IN(KL_GPIO_MODEM_RESET); - udelay(10); - /* Power up modem */ - KL_GPIO_OUT(KL_GPIO_MODEM_POWER, KEYLARGO_GPIO_OUTPUT_ENABLE); - (void)KL_GPIO_IN(KL_GPIO_MODEM_POWER); - udelay(10); - /* Release modem reset */ - KL_GPIO_OUT(KL_GPIO_MODEM_RESET, - KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA); - (void)KL_GPIO_IN(KL_GPIO_MODEM_RESET); - } else { - /* Power down modem */ - KL_GPIO_OUT(KL_GPIO_MODEM_POWER, - KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA); - (void)KL_GPIO_IN(KL_GPIO_MODEM_POWER); - } - KL_UNLOCK(); - } else { - if (power) { - mdelay(300); - feature_set(device, FEATURE_Modem_power); - mdelay(5); - feature_clear(device, FEATURE_Modem_power); - mdelay(10); - feature_set(device, FEATURE_Modem_power); - } else { - feature_clear(device, FEATURE_Modem_power); - mdelay(10); - } - } -} - -#ifdef CONFIG_SMP -void __pmac -feature_core99_kick_cpu(int cpu_nr) -{ - const int reset_lines[] = { KL_GPIO_RESET_CPU0, - KL_GPIO_RESET_CPU1, - KL_GPIO_RESET_CPU2, - KL_GPIO_RESET_CPU3 }; - int reset_io; - unsigned long flags; - - if (!keylargo_base || cpu_nr > 3) - return; - reset_io = reset_lines[cpu_nr]; - - KL_LOCK(); - KL_GPIO_OUT(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE); - (void)KL_GPIO_IN(reset_io); - udelay(1); - KL_GPIO_OUT(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA); - (void)KL_GPIO_IN(reset_io); - KL_UNLOCK(); -} -#endif /* CONFIG_SMP */ - -void __pmac -feature_set_airport_power(struct device_node* device, int power) -{ - unsigned long flags; - - if (!keylargo_base || !airport_dev || airport_dev != device) - return; - if (airport_pwr_state == power) - return; - if (power) { - /* This code is a reproduction of OF enable-cardslot - * and init-wireless methods, slightly hacked until - * I got it working. - */ - KL_LOCK(); - KL_GPIO_OUT(KEYLARGO_GPIO_0+0xf, 5); - (void)KL_GPIO_IN(KEYLARGO_GPIO_0+0xf); - KL_UNLOCK(); - mdelay(10); - KL_LOCK(); - KL_GPIO_OUT(KEYLARGO_GPIO_0+0xf, 4); - (void)KL_GPIO_IN(KEYLARGO_GPIO_0+0xf); - KL_UNLOCK(); - - mdelay(10); - - KL_LOCK(); - KL_BIC(KEYLARGO_FCR2, KL2_AIRPORT_RESET_N); - (void)KL_IN(KEYLARGO_FCR2); - udelay(10); - KL_GPIO_OUT(KEYLARGO_GPIO_EXTINT_0+0xb, 0); - (void)KL_GPIO_IN(KEYLARGO_GPIO_EXTINT_0+0xb); - udelay(10); - KL_GPIO_OUT(KEYLARGO_GPIO_EXTINT_0+0xa, 0x28); - (void)KL_GPIO_IN(KEYLARGO_GPIO_EXTINT_0+0xa); - udelay(10); - KL_GPIO_OUT(KEYLARGO_GPIO_EXTINT_0+0xd, 0x28); - (void)KL_GPIO_IN(KEYLARGO_GPIO_EXTINT_0+0xd); - udelay(10); - KL_GPIO_OUT(KEYLARGO_GPIO_0+0xd, 0x28); - (void)KL_GPIO_IN(KEYLARGO_GPIO_0+0xd); - udelay(10); - KL_GPIO_OUT(KEYLARGO_GPIO_0+0xe, 0x28); - (void)KL_GPIO_IN(KEYLARGO_GPIO_0+0xe); - KL_UNLOCK(); - udelay(10); - KL_OUT(0x1c000, 0); - - mdelay(1); - out_8((volatile u8*)KL_FCR(0x1a3e0), 0x41); - (void)in_8((volatile u8*)KL_FCR(0x1a3e0)); - udelay(10); - KL_LOCK(); - KL_BIS(KEYLARGO_FCR2, KL2_AIRPORT_RESET_N); - (void)KL_IN(KEYLARGO_FCR2); - KL_UNLOCK(); - mdelay(100); - } else { - KL_LOCK(); - KL_BIC(KEYLARGO_FCR2, KL2_AIRPORT_RESET_N); - (void)KL_IN(KEYLARGO_FCR2); - KL_GPIO_OUT(KL_GPIO_AIRPORT_0, 0); - KL_GPIO_OUT(KL_GPIO_AIRPORT_1, 0); - KL_GPIO_OUT(KL_GPIO_AIRPORT_2, 0); - KL_GPIO_OUT(KL_GPIO_AIRPORT_3, 0); - KL_GPIO_OUT(KL_GPIO_AIRPORT_4, 0); - (void)KL_GPIO_IN(KL_GPIO_AIRPORT_4); - KL_UNLOCK(); - } - airport_pwr_state = power; -} - -/* Initialize the Core99 UniNorth host bridge and memory controller - */ -static void __init -uninorth_init(void) -{ - struct device_node* gmac, *fw; - unsigned long actrl; - - /* Set the arbitrer QAck delay according to what Apple does - */ - if (uninorth_rev < 0x10) { - actrl = UN_IN(UNI_N_ARB_CTRL) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK; - actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 : - UNI_N_ARB_CTRL_QACK_DELAY) << UNI_N_ARB_CTRL_QACK_DELAY_SHIFT; - UN_OUT(UNI_N_ARB_CTRL, actrl); - } - - /* Enable GMAC for now for PCI probing. It will be disabled - * later on after PCI probe - */ - gmac = find_devices("ethernet"); - while(gmac) { - if (device_is_compatible(gmac, "gmac")) - break; - gmac = gmac->next; - } - if (gmac) - feature_set_gmac_power(gmac, 1); - - /* Enable FW before PCI probe. Will be disabled later on - */ - fw = find_devices("firewire"); - if (fw && (device_is_compatible(fw, "pci106b,18") || - device_is_compatible(fw, "pci106b,30"))) { - uninorth_fw = fw; - feature_set_firewire_power(fw, 1); - } -} - -/* Initialize the Core99 KeyLargo ASIC. - */ -static void __init -keylargo_init(void) -{ - struct device_node* np; - - KL_BIS(KEYLARGO_FCR2, KL2_MPIC_ENABLE); - - /* Lookup for an airport card, and disable it if found - * to save power (will be re-enabled by driver if used) - */ - np = find_devices("radio"); - if (np && np->parent == keylargo->device) - airport_dev = np; - - if (airport_dev) { - airport_pwr_state = 1; - feature_set_airport_power(airport_dev, 0); - } - -} - -#ifdef CONFIG_PMAC_PBOOK -void __pmac -feature_prepare_for_sleep(void) -{ - /* We assume gatwick is second */ - struct feature_controller* ctrler = &controllers[0]; - - if (controller_count > 1 && - device_is_compatible(ctrler->device, "gatwick")) - ctrler = &controllers[1]; - - if (ctrler->bits == feature_bits_wallstreet || - ctrler->bits == feature_bits_paddington) { - heathrow_prepare_for_sleep(ctrler); - return; - } - if (ctrler->bits == feature_bits_keylargo) { - core99_prepare_for_sleep(ctrler); - return; - } -} - -void __pmac -feature_wake_up(void) -{ - struct feature_controller* ctrler = &controllers[0]; - - if (controller_count > 1 && - device_is_compatible(ctrler->device, "gatwick")) - ctrler = &controllers[1]; - - if (ctrler->bits == feature_bits_wallstreet || - ctrler->bits == feature_bits_paddington) { - heathrow_wakeup(ctrler); - return; - } - if (ctrler->bits == feature_bits_keylargo) { - core99_wake_up(ctrler); - return; - } -} - -static u32 save_fcr[5]; -static u32 save_mbcr; -static u32 save_gpio_levels[2]; -static u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT]; -static u8 save_gpio_normal[KEYLARGO_GPIO_CNT]; -static u32 save_unin_clock_ctl; -static struct dbdma_regs save_dbdma[13]; - -static void __pmac -heathrow_prepare_for_sleep(struct feature_controller* ctrler) -{ - save_mbcr = in_le32(FREG(ctrler, 0x34)); - save_fcr[0] = in_le32(FREG(ctrler, 0x38)); - save_fcr[1] = in_le32(FREG(ctrler, 0x3c)); - - out_le32(FREG(ctrler, 0x38), save_fcr[0] & ~HRW_IOBUS_ENABLE); -} - -static void __pmac -heathrow_wakeup(struct feature_controller* ctrler) -{ - out_le32(FREG(ctrler, 0x38), save_fcr[0]); - out_le32(FREG(ctrler, 0x3c), save_fcr[1]); - out_le32(FREG(ctrler, 0x34), save_mbcr); - mdelay(1); - out_le32(FREG(ctrler, 0x38), save_fcr[0] | HRW_IOBUS_ENABLE); - mdelay(1); -} - -static void __pmac -turn_off_keylargo(void) -{ - u32 temp; - - mdelay(1); - KL_BIS(KEYLARGO_FCR0, KL0_USB_REF_SUSPEND); - (void)KL_IN(KEYLARGO_FCR0); - mdelay(100); - - KL_BIC(KEYLARGO_FCR0, KL0_SCCA_ENABLE | KL0_SCCB_ENABLE | - KL0_SCC_CELL_ENABLE | - KL0_IRDA_ENABLE | KL0_IRDA_CLK32_ENABLE | - KL0_IRDA_CLK19_ENABLE); - - (void)KL_IN(KEYLARGO_FCR0); udelay(10); - KL_BIS(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_ENABLE); - (void)KL_IN(KEYLARGO_MBCR); udelay(10); - - KL_BIC(KEYLARGO_FCR1, - KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT | - KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE | - KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT | - KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE | - KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE | - KL1_EIDE0_ENABLE | KL1_EIDE0_RESET_N | - KL1_EIDE1_ENABLE | KL1_EIDE1_RESET_N | - KL1_UIDE_ENABLE); - (void)KL_IN(KEYLARGO_FCR1); udelay(10); - - KL_BIS(KEYLARGO_FCR2, KL2_MODEM_POWER_N); - udelay(10); - KL_BIC(KEYLARGO_FCR2, KL2_IOBUS_ENABLE); - udelay(10); - temp = KL_IN(KEYLARGO_FCR3); - if (keylargo_rev >= 2) - temp |= (KL3_SHUTDOWN_PLL2X | KL3_SHUTDOWN_PLL_TOTAL); - - temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 | - KL3_SHUTDOWN_PLLKW35 | KL3_SHUTDOWN_PLLKW12; - temp &= ~(KL3_CLK66_ENABLE | KL3_CLK49_ENABLE | KL3_CLK45_ENABLE - | KL3_CLK31_ENABLE | KL3_TIMER_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE - | KL3_I2S0_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE); - KL_OUT(KEYLARGO_FCR3, temp); - (void)KL_IN(KEYLARGO_FCR3); udelay(10); -} - -static void __pmac -turn_off_pangea(void) -{ - u32 temp; - - KL_BIC(KEYLARGO_FCR0, KL0_SCCA_ENABLE | KL0_SCCB_ENABLE | - KL0_SCC_CELL_ENABLE | - KL0_USB0_CELL_ENABLE | KL0_USB1_CELL_ENABLE); - - (void)KL_IN(KEYLARGO_FCR0); udelay(10); - KL_BIS(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_ENABLE); - (void)KL_IN(KEYLARGO_MBCR); udelay(10); - - KL_BIC(KEYLARGO_FCR1, - KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT | - KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE | - KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT | - KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE | - KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE | - KL1_UIDE_ENABLE); - (void)KL_IN(KEYLARGO_FCR1); udelay(10); - - KL_BIS(KEYLARGO_FCR2, KL2_MODEM_POWER_N); - udelay(10); - temp = KL_IN(KEYLARGO_FCR3); - temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 | - KL3_SHUTDOWN_PLLKW35; - temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE - | KL3_CLK31_ENABLE | KL3_TIMER_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE - | KL3_I2S0_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE); - KL_OUT(KEYLARGO_FCR3, temp); - (void)KL_IN(KEYLARGO_FCR3); udelay(10); -} - -static void __pmac -core99_prepare_for_sleep(struct feature_controller* ctrler) -{ - int i; - volatile u8* base8; - - /* - * Save various bits of KeyLargo - */ - - /* We power off the wireless slot in case it was not done - * by the driver. We don't power it on automatically however - */ - feature_set_airport_power(airport_dev, 0); - - /* We power off the FW cable. Should be done by the driver... */ - feature_set_firewire_power(NULL, 0); - feature_set_firewire_cable_power(NULL, 0); - - /* We make sure int. modem is off (in case driver lost it) */ - feature_set_modem_power(NULL, 0); - - /* Save the state of the various GPIOs */ - save_gpio_levels[0] = KL_IN(KEYLARGO_GPIO_LEVELS0); - save_gpio_levels[1] = KL_IN(KEYLARGO_GPIO_LEVELS1); - base8 = ((volatile u8 *)keylargo_base) + KEYLARGO_GPIO_EXTINT_0; - for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++) - save_gpio_extint[i] = in_8(base8+i); - base8 = ((volatile u8 *)keylargo_base) + KEYLARGO_GPIO_0; - for (i=0; i<KEYLARGO_GPIO_CNT; i++) - save_gpio_normal[i] = in_8(base8+i); - - /* Save the FCRs */ - save_mbcr = KL_IN(KEYLARGO_MBCR); - save_fcr[0] = KL_IN(KEYLARGO_FCR0); - save_fcr[1] = KL_IN(KEYLARGO_FCR1); - save_fcr[2] = KL_IN(KEYLARGO_FCR2); - save_fcr[3] = KL_IN(KEYLARGO_FCR3); - save_fcr[4] = KL_IN(KEYLARGO_FCR4); - - /* Save state & config of DBDMA channels */ - for (i=0; i<13; i++) { - volatile struct dbdma_regs* chan = (volatile struct dbdma_regs*) - (keylargo_base + ((0x8000+i*0x100)>>2)); - save_dbdma[i].cmdptr_hi = in_le32(&chan->cmdptr_hi); - save_dbdma[i].cmdptr = in_le32(&chan->cmdptr); - save_dbdma[i].intr_sel = in_le32(&chan->intr_sel); - save_dbdma[i].br_sel = in_le32(&chan->br_sel); - save_dbdma[i].wait_sel = in_le32(&chan->wait_sel); - } - - /* - * Turn off as much as we can - */ - if (keylargo_rev & KL_PANGEA_REV) - turn_off_pangea(); - else - turn_off_keylargo(); - - /* - * Put the host bridge to sleep - */ - - save_unin_clock_ctl = UN_IN(UNI_N_CLOCK_CNTL); - UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl & - ~(UNI_N_CLOCK_CNTL_GMAC|UNI_N_CLOCK_CNTL_FW/*|UNI_N_CLOCK_CNTL_PCI*/)); - udelay(100); - UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING); - UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_SLEEP); - - /* - * FIXME: A bit of black magic with OpenPIC (don't ask me why) - */ - if (board_features & FTR_NEED_OPENPIC_TWEAK) { - KL_BIS(0x506e0, 0x00400000); - KL_BIS(0x506e0, 0x80000000); - } -} - -static void __pmac -core99_wake_up(struct feature_controller* ctrler) -{ - int i; - volatile u8* base8; - - /* - * Wakeup the host bridge - */ - UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL); - udelay(10); - UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING); - udelay(10); - - /* - * Restore KeyLargo - */ - - KL_OUT(KEYLARGO_MBCR, save_mbcr); - (void)KL_IN(KEYLARGO_MBCR); udelay(10); - KL_OUT(KEYLARGO_FCR0, save_fcr[0]); - (void)KL_IN(KEYLARGO_FCR0); udelay(10); - KL_OUT(KEYLARGO_FCR1, save_fcr[1]); - (void)KL_IN(KEYLARGO_FCR1); udelay(10); - KL_OUT(KEYLARGO_FCR2, save_fcr[2]); - (void)KL_IN(KEYLARGO_FCR2); udelay(10); - KL_OUT(KEYLARGO_FCR3, save_fcr[3]); - (void)KL_IN(KEYLARGO_FCR3); udelay(10); - KL_OUT(KEYLARGO_FCR4, save_fcr[4]); - (void)KL_IN(KEYLARGO_FCR4); udelay(10); - - for (i=0; i<13; i++) { - volatile struct dbdma_regs* chan = (volatile struct dbdma_regs*) - (keylargo_base + ((0x8000+i*0x100)>>2)); - out_le32(&chan->control, (ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN)<<16); - while (in_le32(&chan->status) & ACTIVE) - mb(); - out_le32(&chan->cmdptr_hi, save_dbdma[i].cmdptr_hi); - out_le32(&chan->cmdptr, save_dbdma[i].cmdptr); - out_le32(&chan->intr_sel, save_dbdma[i].intr_sel); - out_le32(&chan->br_sel, save_dbdma[i].br_sel); - out_le32(&chan->wait_sel, save_dbdma[i].wait_sel); - } - - KL_OUT(KEYLARGO_GPIO_LEVELS0, save_gpio_levels[0]); - KL_OUT(KEYLARGO_GPIO_LEVELS1, save_gpio_levels[1]); - base8 = ((volatile u8 *)keylargo_base) + KEYLARGO_GPIO_EXTINT_0; - for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++) - out_8(base8+i, save_gpio_extint[i]); - base8 = ((volatile u8 *)keylargo_base) + KEYLARGO_GPIO_0; - for (i=0; i<KEYLARGO_GPIO_CNT; i++) - out_8(base8+i, save_gpio_normal[i]); - - /* FIXME more black magic with OpenPIC ... */ - if (board_features & FTR_NEED_OPENPIC_TWEAK) { - KL_BIC(0x506e0, 0x00400000); - KL_BIC(0x506e0, 0x80000000); - } - - UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl); - udelay(100); -} -#endif /* CONFIG_PMAC_PBOOK */ diff --git a/arch/ppc/kernel/galaxy_pci.c b/arch/ppc/kernel/galaxy_pci.c index afe8ffbe1379..4326a2a76b92 100644 --- a/arch/ppc/kernel/galaxy_pci.c +++ b/arch/ppc/kernel/galaxy_pci.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.galaxy_pci.c 1.7 05/17/01 18:14:21 cort + * BK Id: %F% %I% %G% %U% %#% */ /* * @@ -27,8 +27,7 @@ #include <asm/system.h> #include <asm/io.h> #include <asm/machdep.h> - -#include "pci.h" +#include <asm/pci-bridge.h> /* Preprocessor Defines */ diff --git a/arch/ppc/kernel/gemini_pci.c b/arch/ppc/kernel/gemini_pci.c deleted file mode 100644 index c3d93c483b4d..000000000000 --- a/arch/ppc/kernel/gemini_pci.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * BK Id: SCCS/s.gemini_pci.c 1.6 10/11/01 08:51:46 trini - */ -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <linux/slab.h> - -#include <asm/machdep.h> -#include <asm/gemini.h> -#include <asm/byteorder.h> -#include <asm/io.h> -#include <asm/uaccess.h> -#include <asm/pci-bridge.h> - -#include "pci.h" - -#define pci_config_addr(bus,dev,offset) \ - (0x80000000 | (bus<<16) | (dev<<8) | offset) - - -int -gemini_pcibios_read_config_byte(struct pci_dev *dev, int offset, u8 *val) -{ - unsigned long reg; - reg = grackle_read(pci_config_addr(dev->bus->number, dev->devfn, - (offset & ~(0x3)))); - *val = ((reg >> ((offset & 0x3) << 3)) & 0xff); - return PCIBIOS_SUCCESSFUL; -} - -int -gemini_pcibios_read_config_word(struct pci_dev *dev, int offset, u16 *val) -{ - unsigned long reg; - reg = grackle_read(pci_config_addr(dev->bus->number, dev->devfn, - (offset & ~(0x3)))); - *val = ((reg >> ((offset & 0x3) << 3)) & 0xffff); - return PCIBIOS_SUCCESSFUL; -} - -int -gemini_pcibios_read_config_dword(struct pci_dev *dev, int offset, u32 *val) -{ - *val = grackle_read(pci_config_addr(dev->bus->number, dev->devfn, - (offset & ~(0x3)))); - return PCIBIOS_SUCCESSFUL; -} - -int -gemini_pcibios_write_config_byte(struct pci_dev *dev, int offset, u8 val) -{ - unsigned long reg; - int shifts = offset & 0x3; - unsigned int addr = pci_config_addr(dev->bus->number, dev->devfn, - (offset & ~(0x3))); - - reg = grackle_read(addr); - reg = (reg & ~(0xff << (shifts << 3))) | (val << (shifts << 3)); - grackle_write(addr, reg ); - return PCIBIOS_SUCCESSFUL; -} - -int -gemini_pcibios_write_config_word(struct pci_dev *dev, int offset, u16 val) -{ - unsigned long reg; - int shifts = offset & 0x3; - unsigned int addr = pci_config_addr(dev->bus->number, dev->devfn, - (offset & ~(0x3))); - - reg = grackle_read(addr); - reg = (reg & ~(0xffff << (shifts << 3))) | (val << (shifts << 3)); - grackle_write(addr, reg ); - return PCIBIOS_SUCCESSFUL; -} - -int -gemini_pcibios_write_config_dword(struct pci_dev *dev, int offset, u32 val) -{ - grackle_write(pci_config_addr(dev->bus->number, dev->devfn, - (offset & ~(0x3))), val); - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops gemini_pci_ops = -{ - gemini_pcibios_read_config_byte, - gemini_pcibios_read_config_word, - gemini_pcibios_read_config_dword, - gemini_pcibios_write_config_byte, - gemini_pcibios_write_config_word, - gemini_pcibios_write_config_dword -}; - -void __init gemini_pcibios_fixup(void) -{ - int i; - struct pci_dev *dev; - - pci_for_each_dev(dev) { - for(i = 0; i < 6; i++) { - if (dev->resource[i].flags & IORESOURCE_IO) { - dev->resource[i].start |= (0xfe << 24); - dev->resource[i].end |= (0xfe << 24); - } - } - } -} - - -/* The "bootloader" for Synergy boards does none of this for us, so we need to - lay it all out ourselves... --Dan */ -void __init gemini_find_bridges(void) -{ - struct pci_controller* hose; - - ppc_md.pcibios_fixup = gemini_pcibios_fixup; - - hose = pcibios_alloc_controller(); - if (!hose) - return; - hose->ops = &gemini_pci_ops; -} diff --git a/arch/ppc/kernel/gemini_prom.S b/arch/ppc/kernel/gemini_prom.S deleted file mode 100644 index e2a09b9d89dc..000000000000 --- a/arch/ppc/kernel/gemini_prom.S +++ /dev/null @@ -1,99 +0,0 @@ -/* - * BK Id: SCCS/s.gemini_prom.S 1.5 05/17/01 18:14:21 cort - */ -/* - * arch/ppc/kernel/gemini_prom.S - * - * Not really prom support code (yet), but sort of anti-prom code. The current - * bootloader does a number of things it shouldn't and doesn't do things that it - * should. The stuff in here is mainly a hodge-podge collection of setup code - * to get the board up and running. - * ---Dan - */ - -#include "ppc_asm.tmpl" -#include "ppc_defs.h" -#include <linux/config.h> -#include <asm/processor.h> -#include <asm/page.h> -#include <asm/gemini.h> - -#define HID0_ABE (1<<3) - -/* - * On 750's the MMU is on when Linux is booted, so we need to clear out the - * bootloader's BAT settings, make sure we're in supervisor state (gotcha!), - * and turn off the MMU. - * - */ - -_GLOBAL(gemini_prom_init) -#ifdef CONFIG_SMP - /* Since the MMU's on, get stuff in rom space that we'll need */ - lis r4,GEMINI_CPUSTAT@h - ori r4,r4,GEMINI_CPUSTAT@l - lbz r5,0(r4) - andi. r5,r5,3 - mr r24,r5 /* cpu # used later on */ -#endif - mfmsr r4 - li r3,MSR_PR /* ensure supervisor! */ - ori r3,r3,MSR_IR|MSR_DR - andc r4,r4,r3 - mtmsr r4 - isync -#if 0 - /* zero out the bats now that the MMU is off */ -prom_no_mmu: - li r3,0 - mtspr IBAT0U,r3 - mtspr IBAT0L,r3 - mtspr IBAT1U,r3 - mtspr IBAT1L,r3 - mtspr IBAT2U,r3 - mtspr IBAT2L,r3 - mtspr IBAT3U,r3 - mtspr IBAT3L,r3 - - mtspr DBAT0U,r3 - mtspr DBAT0L,r3 - mtspr DBAT1U,r3 - mtspr DBAT1L,r3 - mtspr DBAT2U,r3 - mtspr DBAT2L,r3 - mtspr DBAT3U,r3 - mtspr DBAT3L,r3 -#endif - - /* the bootloader (as far as I'm currently aware) doesn't mess with page - tables, but since we're already here, might as well zap these, too */ - li r4,0 - mtspr SDR1,r4 - - li r4,16 - mtctr r4 - li r3,0 - li r4,0 -3: mtsrin r3,r4 - addi r3,r3,1 - bdnz 3b - -#ifdef CONFIG_SMP - /* The 750 book (and Mot/IBM support) says that this will "assist" snooping - when in SMP. Not sure yet whether this should stay or leave... */ - mfspr r4,HID0 - ori r4,r4,HID0_ABE - mtspr HID0,r4 - sync -#endif /* CONFIG_SMP */ - blr - -/* apparently, SMon doesn't pay attention to HID0[SRST]. Disable the MMU and - branch to 0xfff00100 */ -_GLOBAL(_gemini_reboot) - lis r5,GEMINI_BOOT_INIT@h - ori r5,r5,GEMINI_BOOT_INIT@l - li r6,MSR_IP - mtspr SRR0,r5 - mtspr SRR1,r6 - rfi diff --git a/arch/ppc/kernel/gemini_setup.c b/arch/ppc/kernel/gemini_setup.c deleted file mode 100644 index e390a83db0e4..000000000000 --- a/arch/ppc/kernel/gemini_setup.c +++ /dev/null @@ -1,584 +0,0 @@ -/* - * BK Id: SCCS/s.gemini_setup.c 1.14 10/18/01 11:16:28 trini - */ -/* - * linux/arch/ppc/kernel/setup.c - * - * Copyright (C) 1995 Linus Torvalds - * Adapted from 'alpha' version by Gary Thomas - * Modified by Cort Dougan (cort@cs.nmt.edu) - * Synergy Microsystems board support by Dan Cox (dan@synergymicro.com) - * - */ - -#include <linux/config.h> -#include <linux/stddef.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/errno.h> -#include <linux/reboot.h> -#include <linux/pci.h> -#include <linux/time.h> -#include <linux/kdev_t.h> -#include <linux/types.h> -#include <linux/major.h> -#include <linux/blk.h> -#include <linux/console.h> -#include <linux/seq_file.h> - -#include <asm/system.h> -#include <asm/pgtable.h> -#include <asm/page.h> -#include <asm/dma.h> -#include <asm/io.h> -#include <asm/m48t35.h> -#include <asm/gemini.h> -#include <asm/time.h> - -#include "local_irq.h" -#include "open_pic.h" - -void gemini_find_bridges(void); -static int gemini_get_clock_speed(void); -extern void gemini_pcibios_fixup(void); - -static char *gemini_board_families[] = { - "VGM", "VSS", "KGM", "VGR", "VCM", "VCS", "KCM", "VCR" -}; -static int gemini_board_count = sizeof(gemini_board_families) / - sizeof(gemini_board_families[0]); - -static unsigned int cpu_7xx[16] = { - 0, 15, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0 -}; -static unsigned int cpu_6xx[16] = { - 0, 0, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 0, 12, 7, 0 -}; - -/* - * prom_init is the Gemini version of prom.c:prom_init. We only need - * the BSS clearing code, so I copied that out of prom.c. This is a - * lot simpler than hacking prom.c so it will build with Gemini. -VAL - */ - -#define PTRRELOC(x) ((typeof(x))((unsigned long)(x) + offset)) - -unsigned long -prom_init(void) -{ - unsigned long offset = reloc_offset(); - unsigned long phys; - extern char __bss_start, _end; - - /* First zero the BSS -- use memset, some arches don't have - * caches on yet */ - memset_io(PTRRELOC(&__bss_start),0 , &_end - &__bss_start); - - /* Default */ - phys = offset + KERNELBASE; - - gemini_prom_init(); - - return phys; -} - -int -gemini_show_cpuinfo(struct seq_file *m) -{ - unsigned char reg, rev; - char *family; - unsigned int type; - - reg = readb(GEMINI_FEAT); - family = gemini_board_families[((reg>>4) & 0xf)]; - if (((reg>>4) & 0xf) > gemini_board_count) - printk(KERN_ERR "cpuinfo(): unable to determine board family\n"); - - reg = readb(GEMINI_BREV); - type = (reg>>4) & 0xf; - rev = reg & 0xf; - - reg = readb(GEMINI_BECO); - - seq_printf(m, "machine\t\t: Gemini %s%d, rev %c, eco %d\n", - family, type, (rev + 'A'), (reg & 0xf)); - - seq_printf(m, "board\t\t: Gemini %s", family); - if (type > 9) - seq_printf(m, "%c", (type - 10) + 'A'); - else - seq_printf(m, "%d", type); - - seq_printf(m, ", rev %c, eco %d\n", (rev + 'A'), (reg & 0xf)); - - seq_printf(m, "clock\t\t: %dMhz\n", gemini_get_clock_speed()); - - return 0; -} - -static u_char gemini_openpic_initsenses[] = { - 1, - 1, - 1, - 1, - 0, - 0, - 1, /* remainder are level-triggered */ -}; - -#define GEMINI_MPIC_ADDR (0xfcfc0000) -#define GEMINI_MPIC_PCI_CFG (0x80005800) - -void __init gemini_openpic_init(void) -{ - - OpenPIC_Addr = (volatile struct OpenPIC *) - grackle_read(GEMINI_MPIC_PCI_CFG + 0x10); - OpenPIC_InitSenses = gemini_openpic_initsenses; - OpenPIC_NumInitSenses = sizeof( gemini_openpic_initsenses ); - - ioremap( GEMINI_MPIC_ADDR, OPENPIC_SIZE); -} - - -extern unsigned long loops_per_jiffy; -extern int root_mountflags; -extern char cmd_line[]; - -void -gemini_heartbeat(void) -{ - static unsigned long led = GEMINI_LEDBASE+(4*8); - static char direction = 8; - - /* We only want to do this on 1 CPU */ - if (smp_processor_id()) - return; - *(char *)led = 0; - if ( (led + direction) > (GEMINI_LEDBASE+(7*8)) || - (led + direction) < (GEMINI_LEDBASE+(4*8)) ) - direction *= -1; - led += direction; - *(char *)led = 0xff; - ppc_md.heartbeat_count = ppc_md.heartbeat_reset; -} - -void __init gemini_setup_arch(void) -{ - extern char cmd_line[]; - - - loops_per_jiffy = 50000000/HZ; - -#ifdef CONFIG_BLK_DEV_INITRD - /* bootable off CDROM */ - if (initrd_start) - ROOT_DEV = MKDEV(SCSI_CDROM_MAJOR, 0); - else -#endif - ROOT_DEV = to_kdev_t(0x0801); - - /* nothing but serial consoles... */ - sprintf(cmd_line, "%s console=ttyS0", cmd_line); - - printk("Boot arguments: %s\n", cmd_line); - - ppc_md.heartbeat = gemini_heartbeat; - ppc_md.heartbeat_reset = HZ/8; - ppc_md.heartbeat_count = 1; - - /* Lookup PCI hosts */ - gemini_find_bridges(); - /* take special pains to map the MPIC, since it isn't mapped yet */ - gemini_openpic_init(); - /* start the L2 */ - gemini_init_l2(); -} - - -int -gemini_get_clock_speed(void) -{ - unsigned long hid1, pvr; - int clock; - - pvr = mfspr(PVR); - hid1 = (mfspr(HID1) >> 28) & 0xf; - if (PVR_VER(pvr) == 8 || - PVR_VER(pvr) == 12) - hid1 = cpu_7xx[hid1]; - else - hid1 = cpu_6xx[hid1]; - - switch((readb(GEMINI_BSTAT) & 0xc) >> 2) { - - case 0: - default: - clock = (hid1*100)/3; - break; - - case 1: - clock = (hid1*125)/3; - break; - - case 2: - clock = (hid1*50); - break; - } - - return clock; -} - -void __init gemini_init_l2(void) -{ - unsigned char reg, brev, fam, creg; - unsigned long cache; - unsigned long pvr; - - reg = readb(GEMINI_L2CFG); - brev = readb(GEMINI_BREV); - fam = readb(GEMINI_FEAT); - pvr = mfspr(PVR); - - switch(PVR_VER(pvr)) { - - case 8: - if (reg & 0xc0) - cache = (((reg >> 6) & 0x3) << 28); - else - cache = 0x3 << 28; - -#ifdef CONFIG_SMP - /* Pre-3.0 processor revs had snooping errata. Leave - their L2's disabled with SMP. -- Dan */ - if (PVR_CFG(pvr) < 3) { - printk("Pre-3.0 750; L2 left disabled!\n"); - return; - } -#endif /* CONFIG_SMP */ - - /* Special case: VGM5-B's came before L2 ratios were set on - the board. Processor speed shouldn't be too high, so - set L2 ratio to 1:1.5. */ - if ((brev == 0x51) && ((fam & 0xa0) >> 4) == 0) - reg |= 1; - - /* determine best cache ratio based upon what the board - tells us (which sometimes _may_ not be true) and - the processor speed. */ - else { - if (gemini_get_clock_speed() > 250) - reg = 2; - } - break; - case 12: - { - static unsigned long l2_size_val = 0; - - if (!l2_size_val) - l2_size_val = _get_L2CR(); - cache = l2_size_val; - break; - } - case 4: - case 9: - creg = readb(GEMINI_CPUSTAT); - if (((creg & 0xc) >> 2) != 1) - printk("Dual-604 boards don't support the use of L2\n"); - else - writeb(1, GEMINI_L2CFG); - return; - default: - printk("Unknown processor; L2 left disabled\n"); - return; - } - - cache |= ((1<<reg) << 25); - cache |= (L2CR_L2RAM_MASK|L2CR_L2CTL|L2CR_L2DO); - _set_L2CR(0); - _set_L2CR(cache | L2CR_L2E); - -} - -void -gemini_restart(char *cmd) -{ - __cli(); - /* make a clean restart, not via the MPIC */ - _gemini_reboot(); - for(;;); -} - -void -gemini_power_off(void) -{ - for(;;); -} - -void -gemini_halt(void) -{ - gemini_restart(NULL); -} - -void __init gemini_init_IRQ(void) -{ - /* gemini has no 8259 */ - openpic_init(1, 0, 0, -1); -} - -#define gemini_rtc_read(x) (readb(GEMINI_RTC+(x))) -#define gemini_rtc_write(val,x) (writeb((val),(GEMINI_RTC+(x)))) - -/* ensure that the RTC is up and running */ -long __init gemini_time_init(void) -{ - unsigned char reg; - - reg = gemini_rtc_read(M48T35_RTC_CONTROL); - - if ( reg & M48T35_RTC_STOPPED ) { - printk(KERN_INFO "M48T35 real-time-clock was stopped. Now starting...\n"); - gemini_rtc_write((reg & ~(M48T35_RTC_STOPPED)), M48T35_RTC_CONTROL); - gemini_rtc_write((reg | M48T35_RTC_SET), M48T35_RTC_CONTROL); - } - return 0; -} - -#undef DEBUG_RTC - -unsigned long -gemini_get_rtc_time(void) -{ - unsigned int year, mon, day, hour, min, sec; - unsigned char reg; - - reg = gemini_rtc_read(M48T35_RTC_CONTROL); - gemini_rtc_write((reg|M48T35_RTC_READ), M48T35_RTC_CONTROL); -#ifdef DEBUG_RTC - printk("get rtc: reg = %x\n", reg); -#endif - - do { - sec = gemini_rtc_read(M48T35_RTC_SECONDS); - min = gemini_rtc_read(M48T35_RTC_MINUTES); - hour = gemini_rtc_read(M48T35_RTC_HOURS); - day = gemini_rtc_read(M48T35_RTC_DOM); - mon = gemini_rtc_read(M48T35_RTC_MONTH); - year = gemini_rtc_read(M48T35_RTC_YEAR); - } while( sec != gemini_rtc_read(M48T35_RTC_SECONDS)); -#ifdef DEBUG_RTC - printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n", - sec, min, hour, day, mon, year); -#endif - - gemini_rtc_write(reg, M48T35_RTC_CONTROL); - - BCD_TO_BIN(sec); - BCD_TO_BIN(min); - BCD_TO_BIN(hour); - BCD_TO_BIN(day); - BCD_TO_BIN(mon); - BCD_TO_BIN(year); - - if ((year += 1900) < 1970) - year += 100; -#ifdef DEBUG_RTC - printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n", - sec, min, hour, day, mon, year); -#endif - - return mktime( year, mon, day, hour, min, sec ); -} - - -int -gemini_set_rtc_time( unsigned long now ) -{ - unsigned char reg; - struct rtc_time tm; - - to_tm( now, &tm ); - - reg = gemini_rtc_read(M48T35_RTC_CONTROL); -#if DEBUG_RTC - printk("set rtc: reg = %x\n", reg); -#endif - - gemini_rtc_write((reg|M48T35_RTC_SET), M48T35_RTC_CONTROL); -#if DEBUG_RTC - printk("set rtc: tm vals - sec=%x, min=%x, hour=%x, mon=%x, mday=%x, year=%x\n", - tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_mday, tm.tm_year); -#endif - - tm.tm_year -= 1900; - BIN_TO_BCD(tm.tm_sec); - BIN_TO_BCD(tm.tm_min); - BIN_TO_BCD(tm.tm_hour); - BIN_TO_BCD(tm.tm_mon); - BIN_TO_BCD(tm.tm_mday); - BIN_TO_BCD(tm.tm_year); -#ifdef DEBUG_RTC - printk("set rtc: tm vals - sec=%x, min=%x, hour=%x, mon=%x, mday=%x, year=%x\n", - tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_mday, tm.tm_year); -#endif - - gemini_rtc_write(tm.tm_sec, M48T35_RTC_SECONDS); - gemini_rtc_write(tm.tm_min, M48T35_RTC_MINUTES); - gemini_rtc_write(tm.tm_hour, M48T35_RTC_HOURS); - gemini_rtc_write(tm.tm_mday, M48T35_RTC_DOM); - gemini_rtc_write(tm.tm_mon, M48T35_RTC_MONTH); - gemini_rtc_write(tm.tm_year, M48T35_RTC_YEAR); - - /* done writing */ - gemini_rtc_write(reg, M48T35_RTC_CONTROL); - - if ((time_state == TIME_ERROR) || (time_state == TIME_BAD)) - time_state = TIME_OK; - - return 0; -} - -/* use the RTC to determine the decrementer count */ -void __init gemini_calibrate_decr(void) -{ - int freq, divisor; - unsigned char reg; - - /* determine processor bus speed */ - reg = readb(GEMINI_BSTAT); - - switch(((reg & 0x0c)>>2)&0x3) { - case 0: - default: - freq = 66667; - break; - case 1: - freq = 83000; - break; - case 2: - freq = 100000; - break; - } - - freq *= 1000; - divisor = 4; - tb_ticks_per_jiffy = freq / HZ / divisor; - tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000); -} - -unsigned long __init gemini_find_end_of_memory(void) -{ - unsigned long total; - unsigned char reg; - - reg = readb(GEMINI_MEMCFG); - total = ((1<<((reg & 0x7) - 1)) * - (8<<((reg >> 3) & 0x7))); - total *= (1024*1024); - return total; -} - -static void __init -gemini_map_io(void) -{ - io_block_mapping(0xf0000000, 0xf0000000, 0x10000000, _PAGE_IO); - io_block_mapping(0x80000000, 0x80000000, 0x10000000, _PAGE_IO); -} - -#ifdef CONFIG_SMP -static int -smp_gemini_probe(void) -{ - int i, nr; - - nr = (readb(GEMINI_CPUSTAT) & GEMINI_CPU_COUNT_MASK) >> 2; - if (nr == 0) - nr = 4; - - if (nr > 1) { - openpic_request_IPIs(); - for (i = 1; i < nr; ++i) - smp_hw_index[i] = i; - } - - return nr; -} - -static void -smp_gemini_kick_cpu(int nr) -{ - openpic_reset_processor_phys(1 << nr); - openpic_reset_processor_phys(0); -} - -static void -smp_gemini_setup_cpu(int cpu_nr) -{ - if (OpenPIC_Addr) - do_openpic_setup_cpu(); - if (cpu_nr > 0) - gemini_init_l2(); -} - -static struct smp_ops_t gemini_smp_ops = { - smp_openpic_message_pass, - smp_gemini_probe, - smp_gemini_kick_cpu, - smp_gemini_setup_cpu, -}; -#endif /* CONFIG_SMP */ - -void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - int i; - - for(i = 0; i < GEMINI_LEDS; i++) - gemini_led_off(i); - - ISA_DMA_THRESHOLD = 0; - DMA_MODE_READ = 0; - DMA_MODE_WRITE = 0; - -#ifdef CONFIG_BLK_DEV_INITRD - if ( r4 ) - { - initrd_start = r4 + KERNELBASE; - initrd_end = r5 + KERNELBASE; - } -#endif - - ppc_md.setup_arch = gemini_setup_arch; - ppc_md.show_cpuinfo = gemini_show_cpuinfo; - ppc_md.irq_cannonicalize = NULL; - ppc_md.init_IRQ = gemini_init_IRQ; - ppc_md.get_irq = openpic_get_irq; - ppc_md.init = NULL; - - ppc_md.restart = gemini_restart; - ppc_md.power_off = gemini_power_off; - ppc_md.halt = gemini_halt; - - ppc_md.time_init = gemini_time_init; - ppc_md.set_rtc_time = gemini_set_rtc_time; - ppc_md.get_rtc_time = gemini_get_rtc_time; - ppc_md.calibrate_decr = gemini_calibrate_decr; - - ppc_md.find_end_of_memory = gemini_find_end_of_memory; - ppc_md.setup_io_mappings = gemini_map_io; - - /* no keyboard/mouse/video stuff yet.. */ - ppc_md.kbd_setkeycode = NULL; - ppc_md.kbd_getkeycode = NULL; - ppc_md.kbd_translate = NULL; - ppc_md.kbd_unexpected_up = NULL; - ppc_md.kbd_leds = NULL; - ppc_md.kbd_init_hw = NULL; - ppc_md.ppc_kbd_sysrq_xlate = NULL; - ppc_md.pcibios_fixup_bus = gemini_pcibios_fixup; - -#ifdef CONFIG_SMP - ppc_md.smp_ops = &gemini_smp_ops; -#endif /* CONFIG_SMP */ -} diff --git a/arch/ppc/kernel/gt64260_common.c b/arch/ppc/kernel/gt64260_common.c new file mode 100644 index 000000000000..4dc0719366cd --- /dev/null +++ b/arch/ppc/kernel/gt64260_common.c @@ -0,0 +1,1666 @@ +/* + * arch/ppc/kernel/gt64260_common.c + * + * Common routines for the Marvell/Galileo GT64260 (Discovery) host bridge, + * interrupt controller, memory controller, serial controller, enet controller, + * etc. + * + * Author: Mark A. Greer <mgreer@mvista.com> + * + * Copyright 2001 MontaVista Software Inc. + * + * 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. + */ + +/* + * The GT64260 port is the result of hard work from many people from + * many companies. In particular, employees of Marvell/Galileo, Mission + * Critical Linux, Xyterra, and MontaVista Software were heavily involved. + */ + +/* + * At last count, the 64260-B-0 has 65 errata and 24 restrictions. The odds of + * you getting it to work well, under stress, for a long period of time are + * low. If nothing else, you will likely run into an interrupt controller + * bug. + * + * The newer 64260A-B-0 is much improved but has its own problems. + * Dave Wilhardt <dwilhardt@zyterra.com> has discovered that you must set + * up your PCI snoop regions to be prefetchable with 4-word bursts AND set the + * "Memory Write and Invalidate bit" (bit 4) in the cmd reg of each PCI device + * before coherency works between PCI and other devices. Many thanks to Dave. + * + * So far this code has been tested on Marvell/Galileo EV-64260-BP and + * an EV-64260A-BP uni-processor boards with 750 and 7400 processors. + * It has not yet been tested with a 7410 or 7450, or on an smp system. + * + * Note: I have not had any luck moving the base register address of the bridge + * with the gt64260_set_base() routine. I move it in the bootloader + * before starting the kernel. I haven't really looked into it so it + * may be an easy fix. -- MAG + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/slab.h> + +#include <asm/byteorder.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> +#include <asm/machdep.h> +#include <asm/pci-bridge.h> +#include <asm/gt64260.h> +#include <asm/delay.h> + + +u32 gt64260_base; /* Virtual base address of 64260's regs */ +u32 gt64260_revision; /* Revision of the chip */ +u8 gt64260_pci_exclude_bridge = TRUE; + + +/* + ***************************************************************************** + * + * Bridge Initialization Routines + * + ***************************************************************************** + */ +static void gt64260_check_errata(struct pci_controller *hose_a, + struct pci_controller *hose_b); + +/* + * Typical '_find_bridges()' routine for boards with a GT64260 bridge. + */ +int __init +gt64260_find_bridges(u32 phys_base_addr, gt64260_bridge_info_t *info, + int ((*map_irq)(struct pci_dev *, unsigned char, unsigned char))) +{ + struct pci_controller *hose_a, *hose_b; + u32 io_base_a, io_base_b; + int rc; + + + gt64260_base = (u32)ioremap(phys_base_addr,GT64260_INTERNAL_SPACE_SIZE); + + hose_a = pcibios_alloc_controller(); + if (!hose_a) + return -1; + + hose_b = pcibios_alloc_controller(); + if (!hose_b) + return -1; + + info->hose_a = hose_a; + info->hose_b = hose_b; + + /* Ends up mapping PCI Config addr/data pairs twice */ + setup_indirect_pci(hose_a, + phys_base_addr + GT64260_PCI_0_CONFIG_ADDR, + phys_base_addr + GT64260_PCI_0_CONFIG_DATA); + + setup_indirect_pci(hose_b, + phys_base_addr + GT64260_PCI_1_CONFIG_ADDR, + phys_base_addr + GT64260_PCI_1_CONFIG_DATA); + + if ((rc = gt64260_bridge_init(info)) != 0) { + iounmap((void *)hose_a->cfg_addr); + iounmap((void *)hose_a->cfg_data); + iounmap((void *)hose_b->cfg_addr); + iounmap((void *)hose_b->cfg_data); + iounmap((void *)gt64260_base); + return rc; + } + + /* ioremap PCI I/O regions */ + io_base_b = (u32)ioremap(info->pci_1_io_start_proc,info->pci_1_io_size); + io_base_a = (u32)ioremap(info->pci_0_io_start_proc,info->pci_0_io_size); + isa_io_base = io_base_a; + + hose_a->first_busno = 0; + hose_a->last_busno = 0xff; + + pci_init_resource(&hose_a->io_resource, + 0, /* really: io_base_a - isa_io_base */ + info->pci_0_io_size - 1, + IORESOURCE_IO, + "host bridge PCI bus 0"); + hose_a->io_space.start = info->pci_0_io_start_pci; + hose_a->io_space.end = info->pci_0_io_start_pci + + info->pci_0_io_size - 1; + hose_a->io_base_virt = (void *)isa_io_base; + + pci_init_resource(&hose_a->mem_resources[0], + info->pci_0_mem_start_proc, + info->pci_0_mem_start_proc + info->pci_0_mem_size - 1, + IORESOURCE_MEM, + "host bridge PCI bus 0"); + hose_a->mem_space.start = info->pci_0_mem_start_pci_lo; + hose_a->mem_space.end = info->pci_0_mem_start_pci_lo + + info->pci_0_mem_size - 1; + hose_a->pci_mem_offset = (info->pci_0_mem_start_proc - + info->pci_0_mem_start_pci_lo); + + hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno); + + + hose_b->first_busno = hose_a->last_busno + 1; + hose_b->bus_offset = hose_b->first_busno; + hose_b->last_busno = 0xff; + + pci_init_resource(&hose_b->io_resource, + io_base_b - isa_io_base, + io_base_b - isa_io_base + info->pci_1_io_size - 1, + IORESOURCE_IO, + "host bridge PCI bus 1"); + hose_b->io_space.start = info->pci_1_io_start_pci; + hose_b->io_space.end = info->pci_1_io_start_pci + + info->pci_1_io_size - 1; + hose_b->io_base_virt = (void *)isa_io_base; + + pci_init_resource(&hose_b->mem_resources[0], + info->pci_1_mem_start_proc, + info->pci_1_mem_start_proc + info->pci_1_mem_size - 1, + IORESOURCE_MEM, + "host bridge PCI bus 1"); + hose_b->mem_space.start = info->pci_1_mem_start_pci_lo; + hose_b->mem_space.end = info->pci_1_mem_start_pci_lo + + info->pci_1_mem_size - 1; + hose_b->pci_mem_offset = (info->pci_1_mem_start_proc - + info->pci_1_mem_start_pci_lo); + + hose_b->last_busno = pciauto_bus_scan(hose_b, hose_b->first_busno); + + + ppc_md.pci_exclude_device = gt64260_pci_exclude_device; + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = map_irq; + + return 0; +} /* gt64260_find_bridges() */ + +/* + * gt64260_bridge_init() + * + * Perform bridge initialization for a "typical" setup for a PPC system. + */ +int __init +gt64260_bridge_init(gt64260_bridge_info_t *info) +{ + int window; + u16 u16_val; + u32 u32_val; + int rc = 0; + u8 save_exclude; + + /* + * Count on firmware to set/clear other bits in this register. + * + * Set CPU CONFIG Reg bit: + * bit 13 - Pipeline + * bit 16 - RdOOO + * + * Clear CPU Config Reg bit: + * bit 12 - endianess + * bit 27 - RemapWrDis + */ + u32_val = gt_read(GT64260_CPU_CONFIG); + u32_val |= ((1<<13) | (1<<16)); + u32_val &= ~((1<<8) | (1<<12) | (1<<27)); + gt_write(GT64260_CPU_CONFIG, u32_val); + + /* PCI 0/1 Timeout and Retry limits */ + u32_val = gt_read(GT64260_PCI_0_TO_RETRY); + u32_val |= 0x0000ffff; + gt_write(GT64260_PCI_0_TO_RETRY, u32_val); + + u32_val = gt_read(GT64260_PCI_1_TO_RETRY); + u32_val |= 0x0000ffff; + gt_write(GT64260_PCI_1_TO_RETRY, u32_val); + + save_exclude = gt64260_pci_exclude_bridge; + gt64260_pci_exclude_bridge = FALSE; + + /* Set class code to indicate host bridge */ + early_read_config_dword(info->hose_a, + info->hose_a->first_busno, + PCI_DEVFN(0,0), + PCI_CLASS_REVISION, + &u32_val); + u32_val &= 0x000000ff; + gt64260_revision = u32_val; /* a 64260 or 64260A? */ + u32_val |= (PCI_CLASS_BRIDGE_HOST << 16); + early_write_config_dword(info->hose_a, + info->hose_a->first_busno, + PCI_DEVFN(0,0), + PCI_CLASS_REVISION, + u32_val); + + early_read_config_dword(info->hose_b, + info->hose_b->first_busno, + PCI_DEVFN(0,0), + PCI_CLASS_REVISION, + &u32_val); + u32_val &= 0x000000ff; + u32_val |= (PCI_CLASS_BRIDGE_HOST << 16); + early_write_config_dword(info->hose_b, + info->hose_b->first_busno, + PCI_DEVFN(0,0), + PCI_CLASS_REVISION, + u32_val); + + /* Enable 64260 to be PCI master & respond to PCI MEM cycles */ + early_read_config_word(info->hose_a, + info->hose_a->first_busno, + PCI_DEVFN(0,0), + PCI_COMMAND, + &u16_val); + u16_val |= (PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); + early_write_config_word(info->hose_a, + info->hose_a->first_busno, + PCI_DEVFN(0,0), + PCI_COMMAND, + u16_val); + + early_read_config_word(info->hose_b, + info->hose_b->first_busno, + PCI_DEVFN(0,0), + PCI_COMMAND, + &u16_val); + u16_val |= (PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); + early_write_config_word(info->hose_b, + info->hose_b->first_busno, + PCI_DEVFN(0,0), + PCI_COMMAND, + u16_val); + + gt64260_pci_exclude_bridge = save_exclude; + + /* + * Disable all CPU windows on the bridge except for SCS 0 which + * is covering all of system memory.: + */ + gt64260_cpu_disable_all_windows(); + + /* + * Set CPU snoop window to indicate all of system memory + * is covered with wirte-back cache. + */ + gt64260_cpu_snoop_set_window(0, + 0x00000000, + info->mem_size, + GT64260_CPU_SNOOP_WB); + + /* + * Set up CPU->PCI mappings (so CPU can get at PCI dev regs/mem). + * Will only use one of the four CPU->PCI MEM windows on each bus. + */ + gt64260_cpu_set_pci_io_window(0, + info->pci_0_io_start_proc, + info->pci_0_io_start_pci, + info->pci_0_io_size, + info->pci_0_io_swap); + + gt64260_cpu_set_pci_mem_window(0, + 0, + info->pci_0_mem_start_proc, + info->pci_0_mem_start_pci_hi, + info->pci_0_mem_start_pci_lo, + info->pci_0_mem_size, + info->pci_0_mem_swap); + + gt64260_cpu_set_pci_io_window(1, + info->pci_1_io_start_proc, + info->pci_1_io_start_pci, + info->pci_1_io_size, + info->pci_1_io_swap); + + gt64260_cpu_set_pci_mem_window(1, + 0, + info->pci_1_mem_start_proc, + info->pci_1_mem_start_pci_hi, + info->pci_1_mem_start_pci_lo, + info->pci_1_mem_size, + info->pci_1_mem_swap); + + /* + * Set up PCI MEM->system memory mapping (bridge slave PCI window). + * + * Set BAR enables to allow only the SCS0 slave window to respond + * to PCI read/write cycles. + */ + gt64260_pci_bar_enable(0, GT64260_PCI_SLAVE_BAR_REG_ENABLES_SCS_0); + gt64260_pci_bar_enable(1, GT64260_PCI_SLAVE_BAR_REG_ENABLES_SCS_0); + + /* + * For virt_to_bus & bus_to_virt to work correctly, this mapping + * must be the same on both PCI buses. + */ + gt64260_pci_slave_scs_set_window(info->hose_a, + 0, + 0x00000000, + 0x00000000, + info->mem_size); + + gt64260_pci_slave_scs_set_window(info->hose_b, + 0, + 0x00000000, + 0x00000000, + info->mem_size); + pci_dram_offset = 0; /* System mem at same addr on PCI & cpu bus */ + + /* Disable all the access control windows */ + for (window=0; window<GT64260_PCI_ACC_CNTL_WINDOWS; window++) { + gt64260_pci_acc_cntl_set_window(0, window, 0, 0, 0, 0); + gt64260_pci_acc_cntl_set_window(1, window, 0, 0, 0, 0); + } + + /* Disable all the PCI snoop regions */ + for (window=0; window<GT64260_PCI_SNOOP_WINDOWS; window++) { + gt64260_pci_snoop_set_window(0, window, 0, 0, 0, 0); + gt64260_pci_snoop_set_window(1, window, 0, 0, 0, 0); + } + + gt64260_pci_acc_cntl_set_window(0, + 0, + 0x00000000, + 0x00000000, + info->mem_size, + (GT64260_PCI_ACC_CNTL_PREFETCHEN | + GT64260_PCI_ACC_CNTL_MBURST_4_WORDS | + GT64260_PCI_ACC_CNTL_SWAP_BYTE)); + + gt64260_pci_acc_cntl_set_window(1, + 0, + 0x00000000, + 0x00000000, + info->mem_size, + (GT64260_PCI_ACC_CNTL_PREFETCHEN | + GT64260_PCI_ACC_CNTL_MBURST_4_WORDS | + GT64260_PCI_ACC_CNTL_SWAP_BYTE)); + + gt64260_pci_snoop_set_window(0, + 0, + 0x00000000, + 0x00000000, + info->mem_size, + GT64260_PCI_SNOOP_WB); + + gt64260_pci_snoop_set_window(1, + 0, + 0x00000000, + 0x00000000, + info->mem_size, + GT64260_PCI_SNOOP_WB); + + gt64260_check_errata(info->hose_a, info->hose_b); + + + /* Set latency timer (to 64) & cacheline size; clear BIST */ + gt64260_pci_exclude_bridge = FALSE; + u32_val = ((0x04 << 8) | (L1_CACHE_LINE_SIZE / 4)); + + early_write_config_dword(info->hose_a, + info->hose_a->first_busno, + PCI_DEVFN(0,0), + PCI_CACHE_LINE_SIZE, + u32_val); + early_write_config_dword(info->hose_b, + info->hose_b->first_busno, + PCI_DEVFN(0,0), + PCI_CACHE_LINE_SIZE, + u32_val); + gt64260_pci_exclude_bridge = TRUE; + + return rc; +} /* gt64260_bridge_init() */ + +/* + * gt64260_check_errata() + * + * Apply applicable errata and restrictions from 0.5 of the + * Errata and Restrictions document from Marvell/Galileo. + */ +static void __init +gt64260_check_errata(struct pci_controller *hose_a, + struct pci_controller *hose_b) +{ + u32 val; + u8 save_exclude; + + /* Currently 2 versions, 64260 and 64260A */ + if (gt64260_revision == GT64260) { + save_exclude = gt64260_pci_exclude_bridge; + gt64260_pci_exclude_bridge = FALSE; + + /* FEr#5, FEr#12 */ + early_read_config_dword(hose_a, + hose_a->first_busno, + PCI_DEVFN(0,0), + PCI_COMMAND, + &val); + val &= ~(PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY); + early_write_config_dword(hose_a, + hose_a->first_busno, + PCI_DEVFN(0,0), + PCI_COMMAND, + val); + + early_read_config_dword(hose_b, + hose_b->first_busno, + PCI_DEVFN(0,0), + PCI_COMMAND, + &val); + val &= ~(PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY); + early_write_config_dword(hose_b, + hose_b->first_busno, + PCI_DEVFN(0,0), + PCI_COMMAND, + val); + gt64260_pci_exclude_bridge = save_exclude; + + /* FEr#12, FEr#13 */ + gt_clr_bits(GT64260_PCI_0_CMD, ((1<<4) | (1<<5) | (1<<9))); + gt_clr_bits(GT64260_PCI_1_CMD, ((1<<4) | (1<<5) | (1<<9))); + + /* FEr#54 */ + gt_clr_bits(GT64260_CPU_SNOOP_BASE_0, 0xfffcf000); + gt_clr_bits(GT64260_CPU_SNOOP_BASE_1, 0xfffcf000); + gt_clr_bits(GT64260_CPU_SNOOP_BASE_2, 0xfffcf000); + gt_clr_bits(GT64260_CPU_SNOOP_BASE_3, 0xfffcf000); + + /* R#18 */ + gt_set_bits(GT64260_SDRAM_CONFIG, (1<<26)); + + } else if (gt64260_revision == GT64260A) { + /* R#18 */ + gt_set_bits(GT64260_SDRAM_CONFIG, (1<<26)); + + /* No longer errata so turn on */ + gt_set_bits(GT64260_PCI_0_CMD, ((1<<4) | (1<<5) | (1<<9))); + gt_set_bits(GT64260_PCI_1_CMD, ((1<<4) | (1<<5) | (1<<9))); + } +} /* gt64260_check_errata() */ + + +/* + ***************************************************************************** + * + * General Window Setting Routines + * + ***************************************************************************** + */ + +static int +gt64260_set_32bit_window(u32 base_addr, + u32 size, + u32 other_bits, + u32 bot_reg, + u32 top_reg) +{ + u32 val; + + if (size > 0) { + /* Set up the window on the CPU side */ + gt_write(bot_reg, (base_addr >> 20) | other_bits); + gt_write(top_reg, (base_addr + size - 1) >> 20); + } else { /* Disable window */ + gt_write(top_reg, 0x00000000); + gt_write(bot_reg, 0x00000fff | other_bits); + } + + val = gt_read(bot_reg); /* Flush FIFO */ + return 0; +} /* gt64260_set_32bit_window() */ + +static int +gt64260_set_64bit_window(u32 base_addr_hi, + u32 base_addr_lo, + u32 size, + u32 other_bits, + u32 bot_reg_hi, + u32 bot_reg_lo, + u32 top_reg) +{ + int rc; + + if ((rc = gt64260_set_32bit_window(base_addr_lo, + size, + other_bits, + bot_reg_lo, + top_reg)) == 0) { + + gt_write(bot_reg_hi, base_addr_hi); + base_addr_hi = gt_read(bot_reg_hi); /* Flush FIFO */ + } + + return rc; +} /* gt64260_set_64bit_window() */ + + +/* + ***************************************************************************** + * + * CPU Configuration Routines + * + ***************************************************************************** + */ + +int +gt64260_cpu_scs_set_window(u32 window, + u32 base_addr, + u32 size) +{ + static u32 + cpu_scs_windows[GT64260_CPU_SCS_DECODE_WINDOWS][2] = { + { GT64260_CPU_SCS_DECODE_0_BOT, GT64260_CPU_SCS_DECODE_0_TOP }, + { GT64260_CPU_SCS_DECODE_1_BOT, GT64260_CPU_SCS_DECODE_1_TOP }, + { GT64260_CPU_SCS_DECODE_2_BOT, GT64260_CPU_SCS_DECODE_2_TOP }, + { GT64260_CPU_SCS_DECODE_3_BOT, GT64260_CPU_SCS_DECODE_3_TOP }, + }; /* cpu_scs_windows[][] */ + int rc = -1; + + if (window < GT64260_CPU_SCS_DECODE_WINDOWS) { + rc = gt64260_set_32bit_window(base_addr, + size, + 0, + cpu_scs_windows[window][0], + cpu_scs_windows[window][1]); + } + + return rc; +} /* gt64260_cpu_scs_set_window() */ + +int +gt64260_cpu_cs_set_window(u32 window, + u32 base_addr, + u32 size) +{ + static u32 + cpu_cs_windows[GT64260_CPU_CS_DECODE_WINDOWS][2] = { + { GT64260_CPU_CS_DECODE_0_BOT, GT64260_CPU_CS_DECODE_0_TOP }, + { GT64260_CPU_CS_DECODE_1_BOT, GT64260_CPU_CS_DECODE_1_TOP }, + { GT64260_CPU_CS_DECODE_2_BOT, GT64260_CPU_CS_DECODE_2_TOP }, + { GT64260_CPU_CS_DECODE_3_BOT, GT64260_CPU_CS_DECODE_3_TOP }, + }; /* cpu_cs_windows[][] */ + int rc = -1; + + if (window < GT64260_CPU_CS_DECODE_WINDOWS) { + rc = gt64260_set_32bit_window(base_addr, + size, + 0, + cpu_cs_windows[window][0], + cpu_cs_windows[window][1]); + } + + return rc; +} /* gt64260_cpu_cs_set_window() */ + +int +gt64260_cpu_boot_set_window(u32 base_addr, + u32 size) +{ + int rc; + + rc = gt64260_set_32bit_window(base_addr, + size, + 0, + GT64260_CPU_BOOT_CS_DECODE_0_BOT, + GT64260_CPU_BOOT_CS_DECODE_0_TOP); + + return rc; +} /* gt64260_cpu_boot_set_window() */ + +/* + * gt64260_cpu_set_pci_io_window() + * + * Set up a CPU window into PCI I/O or MEM space. + * Always do Read/Modify/Write to window regs. + */ +static int +gt64260_cpu_pci_set_window(u32 cpu_base_addr, + u32 pci_base_addr, + u32 size, + u32 other_bits, + u32 bot_reg, + u32 top_reg, + u32 remap_reg) +{ + u32 val; + int rc; + + if ((rc = gt64260_set_32bit_window(cpu_base_addr, + size, + other_bits, + bot_reg, + top_reg)) == 0) { + + /* Set up CPU->PCI remapping (on lower 32 bits) */ + gt_write(remap_reg, pci_base_addr >> 20); + val = gt_read(bot_reg); /* Flush FIFO */ + } + + return rc; +} /* gt64260_cpu_pci_set_window() */ + + +/* + * gt64260_cpu_set_pci_io_window() + * + * Set up a CPU window into PCI I/O space. + * Always do Read/Modify/Write to window regs. + */ +int +gt64260_cpu_set_pci_io_window(u32 pci_bus, + u32 cpu_base_addr, + u32 pci_base_addr, + u32 size, + u32 swap) +{ + /* 2 PCI buses with 1 I/O window each (from CPU point of view) */ + static u32 + cpu_pci_io_windows[GT64260_PCI_BUSES][3] = { + { GT64260_CPU_PCI_0_IO_DECODE_BOT, + GT64260_CPU_PCI_0_IO_DECODE_TOP, + GT64260_CPU_PCI_0_IO_REMAP }, + + { GT64260_CPU_PCI_1_IO_DECODE_BOT, + GT64260_CPU_PCI_1_IO_DECODE_TOP, + GT64260_CPU_PCI_1_IO_REMAP }, + }; /* cpu_pci_io_windows[][] */ + int rc = -1; + + if (pci_bus < GT64260_PCI_BUSES) { + rc = gt64260_cpu_pci_set_window(cpu_base_addr, + pci_base_addr, + size, + swap, + cpu_pci_io_windows[pci_bus][0], + cpu_pci_io_windows[pci_bus][1], + cpu_pci_io_windows[pci_bus][2]); + } + + return rc; +} /* gt64260_cpu_set_pci_io_window() */ + +/* + * gt64260_cpu_set_pci_mem_window() + * + * Set up a CPU window into PCI MEM space (4 PCI MEM windows per PCI bus). + * Always do Read/Modify/Write to window regs. + */ +int +gt64260_cpu_set_pci_mem_window(u32 pci_bus, + u32 window, + u32 cpu_base_addr, + u32 pci_base_addr_hi, + u32 pci_base_addr_lo, + u32 size, + u32 swap_64bit) +{ + /* 2 PCI buses with 4 memory windows each (from CPU point of view) */ + static u32 + cpu_pci_mem_windows[GT64260_PCI_BUSES][GT64260_PCI_MEM_WINDOWS_PER_BUS][4] = { + { /* PCI 0 */ + { GT64260_CPU_PCI_0_MEM_0_DECODE_BOT, + GT64260_CPU_PCI_0_MEM_0_DECODE_TOP, + GT64260_CPU_PCI_0_MEM_0_REMAP_HI, + GT64260_CPU_PCI_0_MEM_0_REMAP_LO }, + + { GT64260_CPU_PCI_0_MEM_1_DECODE_BOT, + GT64260_CPU_PCI_0_MEM_1_DECODE_TOP, + GT64260_CPU_PCI_0_MEM_1_REMAP_HI, + GT64260_CPU_PCI_0_MEM_1_REMAP_LO }, + + { GT64260_CPU_PCI_0_MEM_2_DECODE_BOT, + GT64260_CPU_PCI_0_MEM_2_DECODE_TOP, + GT64260_CPU_PCI_0_MEM_2_REMAP_HI, + GT64260_CPU_PCI_0_MEM_2_REMAP_LO }, + + { GT64260_CPU_PCI_0_MEM_3_DECODE_BOT, + GT64260_CPU_PCI_0_MEM_3_DECODE_TOP, + GT64260_CPU_PCI_0_MEM_3_REMAP_HI, + GT64260_CPU_PCI_0_MEM_3_REMAP_LO } + }, + + { /* PCI 1 */ + { GT64260_CPU_PCI_1_MEM_0_DECODE_BOT, + GT64260_CPU_PCI_1_MEM_0_DECODE_TOP, + GT64260_CPU_PCI_1_MEM_0_REMAP_HI, + GT64260_CPU_PCI_1_MEM_0_REMAP_LO }, + + { GT64260_CPU_PCI_1_MEM_1_DECODE_BOT, + GT64260_CPU_PCI_1_MEM_1_DECODE_TOP, + GT64260_CPU_PCI_1_MEM_1_REMAP_HI, + GT64260_CPU_PCI_1_MEM_1_REMAP_LO }, + + { GT64260_CPU_PCI_1_MEM_2_DECODE_BOT, + GT64260_CPU_PCI_1_MEM_2_DECODE_TOP, + GT64260_CPU_PCI_1_MEM_2_REMAP_HI, + GT64260_CPU_PCI_1_MEM_2_REMAP_LO }, + + { GT64260_CPU_PCI_1_MEM_3_DECODE_BOT, + GT64260_CPU_PCI_1_MEM_3_DECODE_TOP, + GT64260_CPU_PCI_1_MEM_3_REMAP_HI, + GT64260_CPU_PCI_1_MEM_3_REMAP_LO }, + } + }; /* cpu_pci_mem_windows[][][] */ + u32 remap_reg, remap; + int rc = -1; + + if ((pci_bus < GT64260_PCI_BUSES) && + (window < GT64260_PCI_MEM_WINDOWS_PER_BUS)) { + + if (gt64260_cpu_pci_set_window( + cpu_base_addr, + pci_base_addr_lo, + size, + swap_64bit, + cpu_pci_mem_windows[pci_bus][window][0], + cpu_pci_mem_windows[pci_bus][window][1], + cpu_pci_mem_windows[pci_bus][window][3]) == 0) { + + remap_reg = cpu_pci_mem_windows[pci_bus][window][2]; + gt_write(remap_reg, pci_base_addr_hi); + + remap = gt_read(remap_reg); /* Flush FIFO */ + + rc = 0; + } + } + + return rc; +} /* gt64260_cpu_set_pci_mem_window() */ + +int +gt64260_cpu_prot_set_window(u32 window, + u32 base_addr, + u32 size, + u32 access_bits) +{ + static u32 + cpu_prot_windows[GT64260_CPU_PROT_WINDOWS][2] = { + { GT64260_CPU_PROT_BASE_0, GT64260_CPU_PROT_TOP_0 }, + { GT64260_CPU_PROT_BASE_1, GT64260_CPU_PROT_TOP_1 }, + { GT64260_CPU_PROT_BASE_2, GT64260_CPU_PROT_TOP_2 }, + { GT64260_CPU_PROT_BASE_3, GT64260_CPU_PROT_TOP_3 }, + { GT64260_CPU_PROT_BASE_4, GT64260_CPU_PROT_TOP_4 }, + { GT64260_CPU_PROT_BASE_5, GT64260_CPU_PROT_TOP_5 }, + { GT64260_CPU_PROT_BASE_6, GT64260_CPU_PROT_TOP_6 }, + { GT64260_CPU_PROT_BASE_7, GT64260_CPU_PROT_TOP_7 }, + }; /* cpu_prot_windows[][] */ + int rc = -1; + + if (window < GT64260_CPU_PROT_WINDOWS) { + rc = gt64260_set_32bit_window(base_addr, + size, + access_bits, + cpu_prot_windows[window][0], + cpu_prot_windows[window][1]); + } + + return rc; +} /* gt64260_cpu_prot_set_window() */ + +int +gt64260_cpu_snoop_set_window(u32 window, + u32 base_addr, + u32 size, + u32 snoop_type) +{ + static u32 + cpu_snoop_windows[GT64260_CPU_SNOOP_WINDOWS][2] = { + { GT64260_CPU_SNOOP_BASE_0, GT64260_CPU_SNOOP_TOP_0 }, + { GT64260_CPU_SNOOP_BASE_1, GT64260_CPU_SNOOP_TOP_1 }, + { GT64260_CPU_SNOOP_BASE_2, GT64260_CPU_SNOOP_TOP_2 }, + { GT64260_CPU_SNOOP_BASE_3, GT64260_CPU_SNOOP_TOP_3 }, + }; /* cpu_snoop_windows[][] */ + int rc = -1; + + if ((window < GT64260_CPU_SNOOP_WINDOWS) && + (snoop_type <= GT64260_CPU_SNOOP_WB)) { + + rc = gt64260_set_32bit_window(base_addr, + size, + snoop_type, + cpu_snoop_windows[window][0], + cpu_snoop_windows[window][1]); + } + + return rc; +} /* gt64260_cpu_snoop_set_window() */ + +void +gt64260_cpu_disable_all_windows(void) +{ + int pci_bus, window; + + /* Don't disable SCS windows b/c we need to access system memory */ + + for (window=0; window<GT64260_CPU_CS_DECODE_WINDOWS; window++) { + gt64260_cpu_cs_set_window(window, 0, 0); + } + + gt64260_cpu_boot_set_window(0, 0); + + for (pci_bus=0; pci_bus<GT64260_PCI_BUSES; pci_bus++) { + gt64260_cpu_set_pci_io_window(pci_bus, 0, 0, 0, 0); + + for (window=0;window<GT64260_PCI_MEM_WINDOWS_PER_BUS;window++) { + gt64260_cpu_set_pci_mem_window(pci_bus, + window, + 0, 0, 0, 0, 0); + } + } + + for (window=0; window<GT64260_CPU_PROT_WINDOWS; window++) { + gt64260_cpu_prot_set_window(window, 0, 0, 0); + } + + for (window=0; window<GT64260_CPU_SNOOP_WINDOWS; window++) { + gt64260_cpu_snoop_set_window(window, 0, 0, 0); + } + + return; +} /* gt64260_cpu_disable_all_windows() */ + + +/* + ***************************************************************************** + * + * PCI Slave Window Configuration Routines + * + ***************************************************************************** + */ + +int +gt64260_pci_bar_enable(u32 pci_bus, + u32 enable_bits) +{ + u32 reg, val; + int rc = -1; + + if (pci_bus < GT64260_PCI_BUSES) { + reg = (pci_bus == 0) ? GT64260_PCI_0_SLAVE_BAR_REG_ENABLES : + GT64260_PCI_1_SLAVE_BAR_REG_ENABLES; + + + /* Note: '0' enables, '1' disables */ + val = gt_read(reg); + val |= 0xffffffff; /* Disable everything by default */ + val &= ~enable_bits; + gt_write(reg, val); + + gt_read(reg); /* Flush FIFO */ + + rc = 0; + } + + return rc; +} /* gt64260_pci_bar_enable() */ + +static int +gt64260_pci_slave_set_window(struct pci_controller *hose, + u32 pci_base_addr, + u32 cpu_base_addr, + u32 bar_size, + u32 pci_cfg_fcn, + u32 pci_cfg_hdr_offset, + u32 bar_size_reg, + u32 remap_reg) +{ + u32 val; + int devfn; + u8 save_exclude; + + pci_base_addr &= 0xfffff000; + cpu_base_addr &= 0xfffff000; + bar_size &= 0xfffff000; + devfn = PCI_DEVFN(0, pci_cfg_fcn); + + gt_write(bar_size_reg, (bar_size - 1) & 0xfffff000); + gt_write(remap_reg, cpu_base_addr); + gt_read(remap_reg); /* Flush FIFO */ + + save_exclude = gt64260_pci_exclude_bridge; + gt64260_pci_exclude_bridge = FALSE; + early_read_config_dword(hose, + hose->first_busno, + devfn, + pci_cfg_hdr_offset, + &val); + val &= 0x0000000f; + early_write_config_dword(hose, + hose->first_busno, + devfn, + pci_cfg_hdr_offset, + pci_base_addr | val); + gt64260_pci_exclude_bridge = save_exclude; + + return 0; +} /* gt64260_pci_slave_set_window() */ + +int +gt64260_pci_slave_scs_set_window(struct pci_controller *hose, + u32 window, + u32 pci_base_addr, + u32 cpu_base_addr, + u32 size) +{ + static u32 + pci_scs_windows[GT64260_PCI_BUSES][GT64260_PCI_SCS_WINDOWS][4] = { + { /* PCI 0 */ + { 0, 0x10, + GT64260_PCI_0_SLAVE_SCS_0_SIZE, + GT64260_PCI_0_SLAVE_SCS_0_REMAP }, + { 0, 0x14, + GT64260_PCI_0_SLAVE_SCS_1_SIZE, + GT64260_PCI_0_SLAVE_SCS_1_REMAP }, + { 0, 0x18, + GT64260_PCI_0_SLAVE_SCS_2_SIZE, + GT64260_PCI_0_SLAVE_SCS_2_REMAP }, + { 0, 0x1c, + GT64260_PCI_0_SLAVE_SCS_3_SIZE, + GT64260_PCI_0_SLAVE_SCS_3_REMAP }, + }, + { /* PCI 1 */ + { 0, 0x10, + GT64260_PCI_1_SLAVE_SCS_0_SIZE, + GT64260_PCI_1_SLAVE_SCS_0_REMAP }, + { 0, 0x14, + GT64260_PCI_1_SLAVE_SCS_1_SIZE, + GT64260_PCI_1_SLAVE_SCS_1_REMAP }, + { 0, 0x18, + GT64260_PCI_1_SLAVE_SCS_2_SIZE, + GT64260_PCI_1_SLAVE_SCS_2_REMAP }, + { 0, 0x1c, + GT64260_PCI_1_SLAVE_SCS_3_SIZE, + GT64260_PCI_1_SLAVE_SCS_3_REMAP }, + } + }; /* pci_scs_windows[][][] */ + int pci_bus; + int rc = -1; + + if (window < GT64260_PCI_SCS_WINDOWS) { + pci_bus = (hose->first_busno == 0) ? 0 : 1; + + rc = gt64260_pci_slave_set_window( + hose, + pci_base_addr, + cpu_base_addr, + size, + pci_scs_windows[pci_bus][window][0], + pci_scs_windows[pci_bus][window][1], + pci_scs_windows[pci_bus][window][2], + pci_scs_windows[pci_bus][window][3]); + } + + return rc; +} /* gt64260_pci_slave_scs_set_window() */ + +int +gt64260_pci_slave_cs_set_window(struct pci_controller *hose, + u32 window, + u32 pci_base_addr, + u32 cpu_base_addr, + u32 size) +{ + static u32 + pci_cs_windows[GT64260_PCI_BUSES][GT64260_PCI_CS_WINDOWS][4] = { + { /* PCI 0 */ + { 1, 0x10, + GT64260_PCI_0_SLAVE_CS_0_SIZE, + GT64260_PCI_0_SLAVE_CS_0_REMAP }, + { 1, 0x14, + GT64260_PCI_0_SLAVE_CS_1_SIZE, + GT64260_PCI_0_SLAVE_CS_1_REMAP }, + { 1, 0x18, + GT64260_PCI_0_SLAVE_CS_2_SIZE, + GT64260_PCI_0_SLAVE_CS_2_REMAP }, + { 1, 0x1c, + GT64260_PCI_0_SLAVE_CS_3_SIZE, + GT64260_PCI_0_SLAVE_CS_3_REMAP }, + }, + { /* PCI 1 */ + { 1, 0x10, + GT64260_PCI_1_SLAVE_CS_0_SIZE, + GT64260_PCI_1_SLAVE_CS_0_REMAP }, + { 1, 0x14, + GT64260_PCI_1_SLAVE_CS_1_SIZE, + GT64260_PCI_1_SLAVE_CS_1_REMAP }, + { 1, 0x18, + GT64260_PCI_1_SLAVE_CS_2_SIZE, + GT64260_PCI_1_SLAVE_CS_2_REMAP }, + { 1, 0x1c, + GT64260_PCI_1_SLAVE_CS_3_SIZE, + GT64260_PCI_1_SLAVE_CS_3_REMAP }, + } + }; /* pci_cs_windows[][][] */ + int pci_bus; + int rc = -1; + + if (window < GT64260_PCI_CS_WINDOWS) { + pci_bus = (hose->first_busno == 0) ? 0 : 1; + + rc = gt64260_pci_slave_set_window( + hose, + pci_base_addr, + cpu_base_addr, + size, + pci_cs_windows[pci_bus][window][0], + pci_cs_windows[pci_bus][window][1], + pci_cs_windows[pci_bus][window][2], + pci_cs_windows[pci_bus][window][3]); + } + + return rc; +} /* gt64260_pci_slave_cs_set_window() */ + +int +gt64260_pci_slave_boot_set_window(struct pci_controller *hose, + u32 pci_base_addr, + u32 cpu_base_addr, + u32 size) +{ + int rc; + + rc = gt64260_pci_slave_set_window(hose, + pci_base_addr, + cpu_base_addr, + size, + 1, + 0x20, + GT64260_PCI_1_SLAVE_BOOT_SIZE, + GT64260_PCI_1_SLAVE_BOOT_REMAP); + + return rc; +} /* gt64260_pci_slave_boot_set_window() */ + +int +gt64260_pci_slave_p2p_mem_set_window(struct pci_controller *hose, + u32 window, + u32 pci_base_addr, + u32 other_bus_base_addr, + u32 size) +{ + static u32 + pci_p2p_mem_windows[GT64260_PCI_BUSES][GT64260_PCI_P2P_MEM_WINDOWS][4]={ + { /* PCI 0 */ + { 2, 0x10, + GT64260_PCI_0_SLAVE_P2P_MEM_0_SIZE, + GT64260_PCI_0_SLAVE_P2P_MEM_0_REMAP_LO }, + { 2, 0x14, + GT64260_PCI_0_SLAVE_P2P_MEM_1_SIZE, + GT64260_PCI_0_SLAVE_P2P_MEM_1_REMAP_LO }, + }, + { /* PCI 1 */ + { 2, 0x10, + GT64260_PCI_1_SLAVE_P2P_MEM_0_SIZE, + GT64260_PCI_1_SLAVE_P2P_MEM_0_REMAP_LO }, + { 2, 0x14, + GT64260_PCI_1_SLAVE_P2P_MEM_1_SIZE, + GT64260_PCI_1_SLAVE_P2P_MEM_1_REMAP_LO }, + } + }; /* pci_p2p_mem_windows[][][] */ + int pci_bus; + int rc = -1; + + if (window < GT64260_PCI_P2P_MEM_WINDOWS) { + pci_bus = (hose->first_busno == 0) ? 0 : 1; + + rc = gt64260_pci_slave_set_window( + hose, + pci_base_addr, + other_bus_base_addr, + size, + pci_p2p_mem_windows[pci_bus][window][0], + pci_p2p_mem_windows[pci_bus][window][1], + pci_p2p_mem_windows[pci_bus][window][2], + pci_p2p_mem_windows[pci_bus][window][3]); + } + + return rc; +} /* gt64260_pci_slave_p2p_mem_set_window() */ + +int +gt64260_pci_slave_p2p_io_set_window(struct pci_controller *hose, + u32 pci_base_addr, + u32 other_bus_base_addr, + u32 size) +{ + int rc; + + rc = gt64260_pci_slave_set_window(hose, + pci_base_addr, + other_bus_base_addr, + size, + 2, + 0x18, + GT64260_PCI_1_SLAVE_P2P_IO_SIZE, + GT64260_PCI_1_SLAVE_P2P_IO_REMAP); + + return rc; +} /* gt64260_pci_slave_p2p_io_set_window() */ + +int +gt64260_pci_slave_dac_scs_set_window(struct pci_controller *hose, + u32 window, + u32 pci_base_addr_hi, + u32 pci_base_addr_lo, + u32 cpu_base_addr, + u32 size) +{ + static u32 + pci_dac_scs_windows[GT64260_PCI_BUSES][GT64260_PCI_DAC_SCS_WINDOWS][5]={ + { /* PCI 0 */ + { 4, 0x10, 0x14, + GT64260_PCI_0_SLAVE_DAC_SCS_0_SIZE, + GT64260_PCI_0_SLAVE_DAC_SCS_0_REMAP }, + { 4, 0x18, 0x1c, + GT64260_PCI_0_SLAVE_DAC_SCS_1_SIZE, + GT64260_PCI_0_SLAVE_DAC_SCS_1_REMAP }, + { 5, 0x10, 0x14, + GT64260_PCI_0_SLAVE_DAC_SCS_2_SIZE, + GT64260_PCI_0_SLAVE_DAC_SCS_2_REMAP }, + { 5, 0x18, 0x1c, + GT64260_PCI_0_SLAVE_DAC_SCS_3_SIZE, + GT64260_PCI_0_SLAVE_DAC_SCS_3_REMAP }, + }, + { /* PCI 1 */ + { 4, 0x10, 0x14, + GT64260_PCI_1_SLAVE_DAC_SCS_0_SIZE, + GT64260_PCI_1_SLAVE_DAC_SCS_0_REMAP }, + { 4, 0x18, 0x1c, + GT64260_PCI_1_SLAVE_DAC_SCS_1_SIZE, + GT64260_PCI_1_SLAVE_DAC_SCS_1_REMAP }, + { 5, 0x10, 0x14, + GT64260_PCI_1_SLAVE_DAC_SCS_2_SIZE, + GT64260_PCI_1_SLAVE_DAC_SCS_2_REMAP }, + { 5, 0x18, 0x1c, + GT64260_PCI_1_SLAVE_DAC_SCS_3_SIZE, + GT64260_PCI_1_SLAVE_DAC_SCS_3_REMAP }, + } + }; /* pci_dac_scs_windows[][][] */ + int pci_bus; + int rc = -1; + + if (window < GT64260_PCI_DAC_SCS_WINDOWS) { + pci_bus = (hose->first_busno == 0) ? 0 : 1; + + rc = gt64260_pci_slave_set_window( + hose, + pci_base_addr_lo, + cpu_base_addr, + size, + pci_dac_scs_windows[pci_bus][window][0], + pci_dac_scs_windows[pci_bus][window][1], + pci_dac_scs_windows[pci_bus][window][3], + pci_dac_scs_windows[pci_bus][window][4]); + + early_write_config_dword( + hose, + hose->first_busno, + PCI_DEVFN(0, pci_dac_scs_windows[pci_bus][window][0]), + pci_dac_scs_windows[pci_bus][window][2], + pci_base_addr_hi); + } + + return rc; +} /* gt64260_pci_slave_dac_scs_set_window() */ + +int +gt64260_pci_slave_dac_cs_set_window(struct pci_controller *hose, + u32 window, + u32 pci_base_addr_hi, + u32 pci_base_addr_lo, + u32 cpu_base_addr, + u32 size) +{ + static u32 + pci_dac_cs_windows[GT64260_PCI_BUSES][GT64260_PCI_DAC_CS_WINDOWS][5] = { + { /* PCI 0 */ + { 6, 0x10, 0x14, + GT64260_PCI_0_SLAVE_DAC_CS_0_SIZE, + GT64260_PCI_0_SLAVE_DAC_CS_0_REMAP }, + { 6, 0x18, 0x1c, + GT64260_PCI_0_SLAVE_DAC_CS_1_SIZE, + GT64260_PCI_0_SLAVE_DAC_CS_1_REMAP }, + { 6, 0x20, 0x24, + GT64260_PCI_0_SLAVE_DAC_CS_2_SIZE, + GT64260_PCI_0_SLAVE_DAC_CS_2_REMAP }, + { 7, 0x10, 0x14, + GT64260_PCI_0_SLAVE_DAC_CS_3_SIZE, + GT64260_PCI_0_SLAVE_DAC_CS_3_REMAP }, + }, + { /* PCI 1 */ + { 6, 0x10, 0x14, + GT64260_PCI_1_SLAVE_DAC_CS_0_SIZE, + GT64260_PCI_1_SLAVE_DAC_CS_0_REMAP }, + { 6, 0x18, 0x1c, + GT64260_PCI_1_SLAVE_DAC_CS_1_SIZE, + GT64260_PCI_1_SLAVE_DAC_CS_1_REMAP }, + { 6, 0x20, 0x24, + GT64260_PCI_1_SLAVE_DAC_CS_2_SIZE, + GT64260_PCI_1_SLAVE_DAC_CS_2_REMAP }, + { 7, 0x10, 0x14, + GT64260_PCI_1_SLAVE_DAC_CS_3_SIZE, + GT64260_PCI_1_SLAVE_DAC_CS_3_REMAP }, + } + }; /* pci_dac_cs_windows[][][] */ + int pci_bus; + int rc = -1; + + if (window < GT64260_PCI_CS_WINDOWS) { + pci_bus = (hose->first_busno == 0) ? 0 : 1; + + rc = gt64260_pci_slave_set_window( + hose, + pci_base_addr_lo, + cpu_base_addr, + size, + pci_dac_cs_windows[pci_bus][window][0], + pci_dac_cs_windows[pci_bus][window][1], + pci_dac_cs_windows[pci_bus][window][3], + pci_dac_cs_windows[pci_bus][window][4]); + + early_write_config_dword( + hose, + hose->first_busno, + PCI_DEVFN(0, pci_dac_cs_windows[pci_bus][window][0]), + pci_dac_cs_windows[pci_bus][window][2], + pci_base_addr_hi); + } + + return rc; +} /* gt64260_pci_slave_dac_cs_set_window() */ + +int +gt64260_pci_slave_dac_boot_set_window(struct pci_controller *hose, + u32 pci_base_addr_hi, + u32 pci_base_addr_lo, + u32 cpu_base_addr, + u32 size) +{ + int rc; + + rc = gt64260_pci_slave_set_window(hose, + pci_base_addr_lo, + cpu_base_addr, + size, + 7, + 0x18, + GT64260_PCI_1_SLAVE_BOOT_SIZE, + GT64260_PCI_1_SLAVE_BOOT_REMAP); + + early_write_config_dword(hose, + hose->first_busno, + PCI_DEVFN(0, 7), + 0x1c, + pci_base_addr_hi); + + return rc; +} /* gt64260_pci_slave_dac_boot_set_window() */ + +int +gt64260_pci_slave_dac_p2p_mem_set_window(struct pci_controller *hose, + u32 window, + u32 pci_base_addr_hi, + u32 pci_base_addr_lo, + u32 other_bus_base_addr, + u32 size) +{ + static u32 + pci_dac_p2p_mem_windows[GT64260_PCI_BUSES][GT64260_PCI_DAC_P2P_MEM_WINDOWS][5] = { + { /* PCI 0 */ + { 4, 0x20, 0x24, + GT64260_PCI_0_SLAVE_DAC_P2P_MEM_0_SIZE, + GT64260_PCI_0_SLAVE_DAC_P2P_MEM_0_REMAP_LO }, + { 5, 0x20, 0x24, + GT64260_PCI_0_SLAVE_DAC_P2P_MEM_1_SIZE, + GT64260_PCI_0_SLAVE_DAC_P2P_MEM_1_REMAP_LO }, + }, + { /* PCI 1 */ + { 4, 0xa0, 0xa4, + GT64260_PCI_0_SLAVE_DAC_P2P_MEM_0_SIZE, + GT64260_PCI_0_SLAVE_DAC_P2P_MEM_0_REMAP_LO }, + { 5, 0xa0, 0xa4, + GT64260_PCI_0_SLAVE_DAC_P2P_MEM_1_SIZE, + GT64260_PCI_0_SLAVE_DAC_P2P_MEM_1_REMAP_LO }, + } + }; /* pci_dac_p2p_windows[][][] */ + int pci_bus; + int rc = -1; + + if (window < GT64260_PCI_P2P_MEM_WINDOWS) { + pci_bus = (hose->first_busno == 0) ? 0 : 1; + + rc = gt64260_pci_slave_set_window( + hose, + pci_base_addr_lo, + other_bus_base_addr, + size, + pci_dac_p2p_mem_windows[pci_bus][window][0], + pci_dac_p2p_mem_windows[pci_bus][window][1], + pci_dac_p2p_mem_windows[pci_bus][window][3], + pci_dac_p2p_mem_windows[pci_bus][window][4]); + + early_write_config_dword( + hose, + hose->first_busno, + PCI_DEVFN(0, pci_dac_p2p_mem_windows[pci_bus][window][0]), + pci_dac_p2p_mem_windows[pci_bus][window][2], + pci_base_addr_hi); + } + + return rc; +} /* gt64260_pci_slave_dac_p2p_mem_set_window() */ + + +/* + ***************************************************************************** + * + * PCI Control Configuration Routines + * + ***************************************************************************** + */ + + +int +gt64260_pci_acc_cntl_set_window(u32 pci_bus, + u32 window, + u32 base_addr_hi, + u32 base_addr_lo, + u32 size, + u32 features) +{ + static u32 + pci_acc_cntl_windows[GT64260_PCI_BUSES][GT64260_PCI_ACC_CNTL_WINDOWS][3] = { + { /* PCI 0 */ + { GT64260_PCI_0_ACC_CNTL_0_BASE_HI, + GT64260_PCI_0_ACC_CNTL_0_BASE_LO, + GT64260_PCI_0_ACC_CNTL_0_TOP }, + + { GT64260_PCI_0_ACC_CNTL_1_BASE_HI, + GT64260_PCI_0_ACC_CNTL_1_BASE_LO, + GT64260_PCI_0_ACC_CNTL_1_TOP }, + + { GT64260_PCI_0_ACC_CNTL_2_BASE_HI, + GT64260_PCI_0_ACC_CNTL_2_BASE_LO, + GT64260_PCI_0_ACC_CNTL_2_TOP }, + + { GT64260_PCI_0_ACC_CNTL_3_BASE_HI, + GT64260_PCI_0_ACC_CNTL_3_BASE_LO, + GT64260_PCI_0_ACC_CNTL_3_TOP }, + + { GT64260_PCI_0_ACC_CNTL_4_BASE_HI, + GT64260_PCI_0_ACC_CNTL_4_BASE_LO, + GT64260_PCI_0_ACC_CNTL_4_TOP }, + + { GT64260_PCI_0_ACC_CNTL_5_BASE_HI, + GT64260_PCI_0_ACC_CNTL_5_BASE_LO, + GT64260_PCI_0_ACC_CNTL_5_TOP }, + + { GT64260_PCI_0_ACC_CNTL_6_BASE_HI, + GT64260_PCI_0_ACC_CNTL_6_BASE_LO, + GT64260_PCI_0_ACC_CNTL_6_TOP }, + + { GT64260_PCI_0_ACC_CNTL_7_BASE_HI, + GT64260_PCI_0_ACC_CNTL_7_BASE_LO, + GT64260_PCI_0_ACC_CNTL_7_TOP }, + }, + { /* PCI 1 */ + { GT64260_PCI_1_ACC_CNTL_0_BASE_HI, + GT64260_PCI_1_ACC_CNTL_0_BASE_LO, + GT64260_PCI_1_ACC_CNTL_0_TOP }, + + { GT64260_PCI_1_ACC_CNTL_1_BASE_HI, + GT64260_PCI_1_ACC_CNTL_1_BASE_LO, + GT64260_PCI_1_ACC_CNTL_1_TOP }, + + { GT64260_PCI_1_ACC_CNTL_2_BASE_HI, + GT64260_PCI_1_ACC_CNTL_2_BASE_LO, + GT64260_PCI_1_ACC_CNTL_2_TOP }, + + { GT64260_PCI_1_ACC_CNTL_3_BASE_HI, + GT64260_PCI_1_ACC_CNTL_3_BASE_LO, + GT64260_PCI_1_ACC_CNTL_3_TOP }, + + { GT64260_PCI_1_ACC_CNTL_4_BASE_HI, + GT64260_PCI_1_ACC_CNTL_4_BASE_LO, + GT64260_PCI_1_ACC_CNTL_4_TOP }, + + { GT64260_PCI_1_ACC_CNTL_5_BASE_HI, + GT64260_PCI_1_ACC_CNTL_5_BASE_LO, + GT64260_PCI_1_ACC_CNTL_5_TOP }, + + { GT64260_PCI_1_ACC_CNTL_6_BASE_HI, + GT64260_PCI_1_ACC_CNTL_6_BASE_LO, + GT64260_PCI_1_ACC_CNTL_6_TOP }, + + { GT64260_PCI_1_ACC_CNTL_7_BASE_HI, + GT64260_PCI_1_ACC_CNTL_7_BASE_LO, + GT64260_PCI_1_ACC_CNTL_7_TOP }, + } + }; /* pci_acc_cntl_windows[][][] */ + int rc = -1; + + if ((pci_bus < GT64260_PCI_BUSES) && + (window < GT64260_PCI_ACC_CNTL_WINDOWS)) { + + rc = gt64260_set_64bit_window( + base_addr_hi, + base_addr_lo, + size, + features, + pci_acc_cntl_windows[pci_bus][window][0], + pci_acc_cntl_windows[pci_bus][window][1], + pci_acc_cntl_windows[pci_bus][window][2]); + } + + return rc; +} /* gt64260_pci_acc_cntl_set_window() */ + +int +gt64260_pci_snoop_set_window(u32 pci_bus, + u32 window, + u32 base_addr_hi, + u32 base_addr_lo, + u32 size, + u32 snoop_type) +{ + static u32 + pci_snoop_windows[GT64260_PCI_BUSES][GT64260_PCI_SNOOP_WINDOWS][3] = { + { /* PCI 0 */ + { GT64260_PCI_0_SNOOP_0_BASE_HI, + GT64260_PCI_0_SNOOP_0_BASE_LO, + GT64260_PCI_0_SNOOP_0_TOP }, + + { GT64260_PCI_0_SNOOP_1_BASE_HI, + GT64260_PCI_0_SNOOP_1_BASE_LO, + GT64260_PCI_0_SNOOP_1_TOP }, + + { GT64260_PCI_0_SNOOP_2_BASE_HI, + GT64260_PCI_0_SNOOP_2_BASE_LO, + GT64260_PCI_0_SNOOP_2_TOP }, + + { GT64260_PCI_0_SNOOP_3_BASE_HI, + GT64260_PCI_0_SNOOP_3_BASE_LO, + GT64260_PCI_0_SNOOP_3_TOP }, + }, + { /* PCI 1 */ + { GT64260_PCI_1_SNOOP_0_BASE_HI, + GT64260_PCI_1_SNOOP_0_BASE_LO, + GT64260_PCI_1_SNOOP_0_TOP }, + + { GT64260_PCI_1_SNOOP_1_BASE_HI, + GT64260_PCI_1_SNOOP_1_BASE_LO, + GT64260_PCI_1_SNOOP_1_TOP }, + + { GT64260_PCI_1_SNOOP_2_BASE_HI, + GT64260_PCI_1_SNOOP_2_BASE_LO, + GT64260_PCI_1_SNOOP_2_TOP }, + + { GT64260_PCI_1_SNOOP_3_BASE_HI, + GT64260_PCI_1_SNOOP_3_BASE_LO, + GT64260_PCI_1_SNOOP_3_TOP }, + }, + }; /* pci_snoop_windows[][][] */ + int rc = -1; + + if ((pci_bus < GT64260_PCI_BUSES) && + (window < GT64260_PCI_SNOOP_WINDOWS)) { + + rc = gt64260_set_64bit_window( + base_addr_hi, + base_addr_lo, + size, + snoop_type, + pci_snoop_windows[pci_bus][window][0], + pci_snoop_windows[pci_bus][window][1], + pci_snoop_windows[pci_bus][window][2]); + } + + return rc; +} /* gt64260_pci_snoop_set_window() */ + +/* + ***************************************************************************** + * + * 64260's Register Base Address Routines + * + ***************************************************************************** + */ + +/* + * gt64260_remap_bridge_regs() + * + * Move the bridge's register to the specified base address. + * Assume that there are no other windows overlapping this area and that + * all but the highest 3 nibbles are 0. + */ +int +gt64260_set_base(u32 new_base) +{ + u32 val; + int limit = 100000; + int rc = 0; + + val = gt_read(GT64260_INTERNAL_SPACE_DECODE); + val = (new_base >> 20) | (val & 0xffff0000); + gt_write(GT64260_INTERNAL_SPACE_DECODE, val); + + iounmap((void *)gt64260_base); + gt64260_base = (u32)ioremap((new_base & 0xfff00000), + GT64260_INTERNAL_SPACE_SIZE); + + do { /* Wait for bridge to move its regs */ + val = gt_read(GT64260_INTERNAL_SPACE_DECODE); + } while ((val != 0xffffffff) && (limit-- > 0)); + + if (limit <= 0) { + rc = -1; + } + + return rc; +} /* gt64260_remap_bridge_regs() */ + +/* + * gt64260_get_base() + * + * Return the current virtual base address of the 64260's registers. + */ +int +gt64260_get_base(u32 *base) +{ + *base = gt64260_base; + return 0; +} /* gt64260_remap_bridge_regs() */ + +/* + ***************************************************************************** + * + * Exclude PCI config space access to bridge itself + * + ***************************************************************************** + */ + +/* + * gt64260_exclude_pci_device() + * + * This routine causes the PCI subsystem to skip the PCI device in slot 0 + * (which is the 64260 itself) unless explicitly allowed. + */ +int +gt64260_pci_exclude_device(u8 bus, u8 devfn) +{ + struct pci_controller *hose; + + hose = pci_bus_to_hose(bus); + + /* Skip slot 0 and 1 on both hoses */ + if ((gt64260_pci_exclude_bridge == TRUE) && + (PCI_SLOT(devfn) == 0) && + (hose->first_busno == bus)) { + + return PCIBIOS_DEVICE_NOT_FOUND; + } + else { + return PCIBIOS_SUCCESSFUL; + } +} /* gt64260_pci_exclude_device() */ + +#if defined(CONFIG_SERIAL_TEXT_DEBUG) + +/* + * gt64260_putc() + * + * Dump a character out the MPSC port for gt64260_mpsc_progress + * this assumes the baud rate has already been set up and the + * MPSC initialized by the bootloader or firmware. + */ + +static inline void +gt_putc(char c){ + mb(); + gt_write(GT64260_MPSC_0_CHR_1, c); + mb(); + gt_write(GT64260_MPSC_0_CHR_2, 0x200); + mb(); + + udelay(10000); +} + +void +puthex(unsigned long val){ + + int i; + + for (i = 7; i >= 0; i--) { + gt_putc("0123456789ABCDEF"[(val>>28) & 0x0f]); + val <<= 4; + } + gt_putc('\r'); + gt_putc('\n'); + +} + + +void +gt64260_mpsc_progress(char *s, unsigned short hex){ + /* spit stuff out the 64260 mpsc */ + + volatile char c; + while ((c = *s++) != 0){ + gt_putc(c); + if ( c == '\n' ) gt_putc('\r'); + } + gt_putc('\n'); + gt_putc('\r'); + + return; +} + +#endif /* CONFIG_DEBUG_TEXT */ diff --git a/arch/ppc/kernel/gt64260_pic.c b/arch/ppc/kernel/gt64260_pic.c new file mode 100644 index 000000000000..e0b61032586b --- /dev/null +++ b/arch/ppc/kernel/gt64260_pic.c @@ -0,0 +1,245 @@ +/* + * arch/ppc/kernel/gt64260_pic.c + * + * Interrupt controller support for Galileo's GT64260. + * + * Author: Chris Zankel <chris@mvista.com> + * Modified by: Mark A. Greer <mgreer@mvista.com> + * + * Based on sources from Rabeeh Khoury / Galileo Technology + * + * Copyright 2001 MontaVista Software Inc. + * + * 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. + */ + +/* + * This file contains the specific functions to support the GT64260 + * interrupt controller. + * + * The GT64260 has two main interrupt registers (high and low) that + * summarizes the interrupts generated by the units of the GT64260. + * Each bit is assigned to an interrupt number, where the low register + * are assigned from IRQ0 to IRQ31 and the high cause register + * from IRQ32 to IRQ63 + * The GPP (General Purpose Port) interrupts are assigned from IRQ64 (GPP0) + * to IRQ95 (GPP31). + * get_irq() returns the lowest interrupt number that is currently asserted. + * + * Note: + * - This driver does not initialize the GPP when used as an interrupt + * input. + */ + +#include <linux/stddef.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/signal.h> +#include <linux/stddef.h> +#include <linux/delay.h> +#include <linux/irq.h> + +#include <asm/io.h> +#include <asm/processor.h> +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/gt64260.h> + + +/* ========================== forward declaration ========================== */ + +static void gt64260_unmask_irq(unsigned int); +static void gt64260_mask_irq(unsigned int); + +/* ========================== local declarations =========================== */ + +struct hw_interrupt_type gt64260_pic = { + " GT64260_PIC ", /* typename */ + NULL, /* startup */ + NULL, /* shutdown */ + gt64260_unmask_irq, /* enable */ + gt64260_mask_irq, /* disable */ + gt64260_mask_irq, /* ack */ + NULL, /* end */ + NULL /* set_affinity */ +}; + +u32 gt64260_irq_base = 0; /* GT64260 handles the next 96 IRQs from here */ + +/* gt64260_init_irq() + * + * This function initializes the interrupt controller. It assigns + * all interrupts from IRQ0 to IRQ95 to the gt64260 interrupt controller. + * + * Input Variable(s): + * None. + * + * Outpu. Variable(s): + * None. + * + * Returns: + * void + * + * Note: + * We register all GPP inputs as interrupt source, but disable them. + */ + +__init void +gt64260_init_irq(void) +{ + int i; + + if ( ppc_md.progress ) ppc_md.progress("gt64260_init_irq: enter", 0x0); + + ppc_cached_irq_mask[0] = 0; + ppc_cached_irq_mask[1] = 0x0f000000; /* Enable GPP intrs */ + ppc_cached_irq_mask[2] = 0; + + /* disable all interrupts and clear current interrupts */ + gt_write(GT64260_GPP_INTR_MASK, ppc_cached_irq_mask[2]); + gt_write(GT64260_GPP_INTR_CAUSE,0); + gt_write(GT64260_IC_CPU_INTR_MASK_LO, ppc_cached_irq_mask[0]); + gt_write(GT64260_IC_CPU_INTR_MASK_HI, ppc_cached_irq_mask[1]); + + /* use the gt64260 for all (possible) interrupt sources */ + for( i = gt64260_irq_base; i < (gt64260_irq_base + 96); i++ ) { + irq_desc[i].handler = >64260_pic; + } + + if ( ppc_md.progress ) ppc_md.progress("gt64260_init_irq: exit", 0x0); +} + + +/* gt64260_get_irq() + * + * This function returns the lowest interrupt number of all interrupts that + * are currently asserted. + * + * Input Variable(s): + * struct pt_regs* not used + * + * Output Variable(s): + * None. + * + * Returns: + * int <interrupt number> or -2 (bogus interrupt) + * + */ +int +gt64260_get_irq(struct pt_regs *regs) +{ + int irq; + int irq_gpp; + + irq = gt_read(GT64260_IC_MAIN_CAUSE_LO); + irq = __ilog2((irq & 0x3dfffffe) & ppc_cached_irq_mask[0]); + + if (irq == -1) { + irq = gt_read(GT64260_IC_MAIN_CAUSE_HI); + irq = __ilog2((irq & 0x0f000db7) & ppc_cached_irq_mask[1]); + + if (irq == -1) { + irq = -2; /* bogus interrupt, should never happen */ + } else { + if (irq >= 24) { + irq_gpp = gt_read(GT64260_GPP_INTR_CAUSE); + irq_gpp = __ilog2(irq_gpp & + ppc_cached_irq_mask[2]); + + if (irq_gpp == -1) { + irq = -2; + } else { + irq = irq_gpp + 64; + gt_write(GT64260_GPP_INTR_CAUSE, ~(1<<(irq-64))); + } + } else { + irq += 32; + } + } + } + + if( irq < 0 ) { + return( irq ); + } else { + return( gt64260_irq_base + irq ); + } +} + +/* gt64260_unmask_irq() + * + * This function enables an interrupt. + * + * Input Variable(s): + * unsigned int interrupt number (IRQ0...IRQ95). + * + * Output Variable(s): + * None. + * + * Returns: + * void + */ + +static void +gt64260_unmask_irq(unsigned int irq) +{ + irq -= gt64260_irq_base; + if (irq > 31) { + if (irq > 63) { + /* unmask GPP irq */ + gt_write(GT64260_GPP_INTR_MASK, + ppc_cached_irq_mask[2] |= (1<<(irq-64))); + } else { + /* mask high interrupt register */ + gt_write(GT64260_IC_CPU_INTR_MASK_HI, + ppc_cached_irq_mask[1] |= (1<<(irq-32))); + } + } else { + /* mask low interrupt register */ + gt_write(GT64260_IC_CPU_INTR_MASK_LO, + ppc_cached_irq_mask[0] |= (1<<irq)); + } +} + + +/* gt64260_mask_irq() + * + * This funktion disables the requested interrupt. + * + * Input Variable(s): + * unsigned int interrupt number (IRQ0...IRQ95). + * + * Output Variable(s): + * None. + * + * Returns: + * void + */ + +static void +gt64260_mask_irq(unsigned int irq) +{ + irq -= gt64260_irq_base; + if (irq > 31) { + if (irq > 63) { + /* mask GPP irq */ + gt_write(GT64260_GPP_INTR_MASK, + ppc_cached_irq_mask[2] &= ~(1<<(irq-64))); + } else { + /* mask high interrupt register */ + gt_write(GT64260_IC_CPU_INTR_MASK_HI, + ppc_cached_irq_mask[1] &= ~(1<<(irq-32))); + } + } else { + /* mask low interrupt register */ + gt_write(GT64260_IC_CPU_INTR_MASK_LO, + ppc_cached_irq_mask[0] &= ~(1<<irq)); + } + + if (irq == 36) { /* Seems necessary for SDMA interrupts */ + udelay(1); + } +} + diff --git a/arch/ppc/kernel/harrier.c b/arch/ppc/kernel/harrier.c new file mode 100644 index 000000000000..343ada453eac --- /dev/null +++ b/arch/ppc/kernel/harrier.c @@ -0,0 +1,214 @@ +/* + * arch/ppc/kernel/harrier.c + * + * Motorola MCG Harrier northbridge/memory controller support + * + * Author: Dale Farnsworth + * dale.farnsworth@mvista.com + * + * Copyright 2001 MontaVista Software Inc. + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/pci.h> + +#include <asm/byteorder.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/pci.h> +#include <asm/pci-bridge.h> +#include <asm/open_pic.h> +#include <asm/harrier.h> + +/* + * Initialize the Motorola MCG Harrier host bridge. + * + * This means setting up the PPC bus to PCI memory and I/O space mappings, + * setting the PCI memory space address of the MPIC (mapped straight + * through), and ioremap'ing the mpic registers. + * 'OpenPIC_Addr' will be set correctly by this routine. + * This routine will not change the PCI_CONFIG_ADDR or PCI_CONFIG_DATA + * addresses and assumes that the mapping of PCI memory space back to system + * memory is set up correctly by PPCBug. + */ +int __init +harrier_init(struct pci_controller *hose, + uint ppc_reg_base, + ulong processor_pci_mem_start, + ulong processor_pci_mem_end, + ulong processor_pci_io_start, + ulong processor_pci_io_end, + ulong processor_mpic_base) +{ + uint addr, offset; + + /* + * Some sanity checks... + */ + if (((processor_pci_mem_start&0xffff0000) != processor_pci_mem_start) || + ((processor_pci_io_start &0xffff0000) != processor_pci_io_start)) { + printk("harrier_init: %s\n", + "PPC to PCI mappings must start on 64 KB boundaries"); + return -1; + } + + if (((processor_pci_mem_end &0x0000ffff) != 0x0000ffff) || + ((processor_pci_io_end &0x0000ffff) != 0x0000ffff)) { + printk("harrier_init: PPC to PCI mappings %s\n", + "must end just before a 64 KB boundaries"); + return -1; + } + + if (((processor_pci_mem_end - processor_pci_mem_start) != + (hose->mem_space.end - hose->mem_space.start)) || + ((processor_pci_io_end - processor_pci_io_start) != + (hose->io_space.end - hose->io_space.start))) { + printk("harrier_init: %s\n", + "PPC and PCI memory or I/O space sizes don't match"); + return -1; + } + + if ((processor_mpic_base & 0xfffc0000) != processor_mpic_base) { + printk("harrier_init: %s\n", + "MPIC address must start on 256 KB boundary"); + return -1; + } + + if ((pci_dram_offset & 0xffff0000) != pci_dram_offset) { + printk("harrier_init: %s\n", + "pci_dram_offset must be multiple of 64 KB"); + return -1; + } + + /* + * Program the OTAD/OTOF registers to set up the PCI Mem & I/O + * space mappings. These are the mappings going from the processor to + * the PCI bus. + * + * Note: Don't need to 'AND' start/end addresses with 0xffff0000 + * because sanity check above ensures that they are properly + * aligned. + */ + + /* Set up PPC->PCI Mem mapping */ + addr = processor_pci_mem_start | (processor_pci_mem_end >> 16); + offset = (hose->mem_space.start - processor_pci_mem_start) | 0x92; + out_be32((uint *)(ppc_reg_base + HARRIER_OTAD0_OFF), addr); + out_be32((uint *)(ppc_reg_base + HARRIER_OTOF0_OFF), offset); + + /* Set up PPC->PCI I/O mapping -- Contiguous I/O space */ + addr = processor_pci_io_start | (processor_pci_io_end >> 16); + offset = (hose->io_space.start - processor_pci_io_start) | 0x80; + out_be32((uint *)(ppc_reg_base + HARRIER_OTAD1_OFF), addr); + out_be32((uint *)(ppc_reg_base + HARRIER_OTOF1_OFF), offset); + + /* Enable MPIC */ + OpenPIC_Addr = (void *)processor_mpic_base; + addr = (processor_mpic_base >> 16) | 1; + out_be16((ushort *)(ppc_reg_base + HARRIER_MBAR_OFF), addr); + out_8((u_char *)(ppc_reg_base + HARRIER_MPIC_CSR_OFF), + HARRIER_MPIC_OPI_ENABLE); + + return 0; +} + +/* + * Find the amount of RAM present. + * This assumes that PPCBug has initialized the memory controller (SMC) + * on the Harrier correctly (i.e., it does no sanity checking). + * It also assumes that the memory base registers are set to configure the + * memory as contigous starting with "RAM A BASE", "RAM B BASE", etc. + * however, RAM base registers can be skipped (e.g. A, B, C are set, + * D is skipped but E is set is okay). + */ +#define MB (1024*1024UL) + +static uint harrier_size_table[] __initdata = { + 0 * MB, /* 0 ==> 0 MB */ + 32 * MB, /* 1 ==> 32 MB */ + 64 * MB, /* 2 ==> 64 MB */ + 64 * MB, /* 3 ==> 64 MB */ + 128 * MB, /* 4 ==> 128 MB */ + 128 * MB, /* 5 ==> 128 MB */ + 128 * MB, /* 6 ==> 128 MB */ + 256 * MB, /* 7 ==> 256 MB */ + 256 * MB, /* 8 ==> 256 MB */ + 256 * MB, /* 9 ==> 256 MB */ + 512 * MB, /* a ==> 512 MB */ + 512 * MB, /* b ==> 512 MB */ + 512 * MB, /* c ==> 512 MB */ + 1024 * MB, /* d ==> 1024 MB */ + 1024 * MB, /* e ==> 1024 MB */ + 2048 * MB, /* f ==> 2048 MB */ +}; + +/* + * *** WARNING: You MUST have a BAT set up to map in the XCSR regs *** + * + * Read the memory controller's registers to determine the amount of system + * memory. Assumes that the memory controller registers are already mapped + * into virtual memory--too early to use ioremap(). + */ +unsigned long __init +harrier_get_mem_size(uint xcsr_base) +{ + ulong last_addr; + int i; + uint vend_dev_id; + uint *size_table; + uint val; + uint *csrp; + uint size; + int size_table_entries; + + vend_dev_id = in_be32((uint *)xcsr_base + PCI_VENDOR_ID); + + if (((vend_dev_id & 0xffff0000) >> 16) != PCI_VENDOR_ID_MOTOROLA) { + printk("harrier_get_mem_size: %s (0x%x)\n", + "Not a Motorola Memory Controller", vend_dev_id); + return 0; + } + + vend_dev_id &= 0x0000ffff; + + if (vend_dev_id == PCI_DEVICE_ID_MOTOROLA_HARRIER) { + size_table = harrier_size_table; + size_table_entries = sizeof(harrier_size_table) / + sizeof(harrier_size_table[0]); + } + else { + printk("harrier_get_mem_size: %s (0x%x)\n", + "Not a Harrier", vend_dev_id); + return 0; + } + + last_addr = 0; + + csrp = (uint *)(xcsr_base + HARRIER_SDBA_OFF); + for (i=0; i<8; i++) { + val = in_be32(csrp++); + + if (val & 0x100) { /* If enabled */ + size = val >> HARRIER_SDB_SIZE_SHIFT; + size &= HARRIER_SDB_SIZE_MASK; + if (size >= size_table_entries) { + break; /* Register not set correctly */ + } + size = size_table[size]; + + val &= ~(size-1); + val += size; + + if (val > last_addr) { + last_addr = val; + } + } + } + + return last_addr; +} diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index 5e13c0a9257d..6a57fa4dad53 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.head.S 1.31 10/18/01 15:02:09 trini + * BK Id: %F% %I% %G% %U% %#% */ /* * PowerPC version @@ -22,17 +22,18 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. - * + * */ #include <linux/config.h> -#include "ppc_asm.h" #include <asm/processor.h> #include <asm/page.h> #include <asm/mmu.h> #include <asm/pgtable.h> #include <asm/cputable.h> #include <asm/cache.h> +#include <asm/ppc_asm.h> +#include "ppc_defs.h" #ifdef CONFIG_APUS #include <asm/amigappc.h> @@ -48,9 +49,9 @@ ld RB,(n*32)+24(reg); \ mtspr DBAT##n##U,RA; \ mtspr DBAT##n##L,RB; \ - + #else /* CONFIG_PPC64BRIDGE */ - + /* 601 only have IBAT; cr0.eq is set on 601 when using this macro */ #define LOAD_BAT(n, reg, RA, RB) \ /* see the comment for clear_bats() -- Cort */ \ @@ -66,10 +67,13 @@ lwz RB,(n*16)+12(reg); \ mtspr DBAT##n##U,RA; \ mtspr DBAT##n##L,RB; \ -1: +1: #endif /* CONFIG_PPC64BRIDGE */ .text + .stabs "arch/ppc/kernel/",N_SO,0,0,0f + .stabs "head.S",N_SO,0,0,0f +0: .globl _stext _stext: @@ -86,8 +90,8 @@ _start: * but we're always started by some kind of bootloader now. * -- Cort */ - nop - nop + nop /* used by __secondary_hold on prep (mtx) and chrp smp */ + nop /* used by __secondary_hold on prep (mtx) and chrp smp */ nop /* PMAC @@ -113,7 +117,7 @@ _start: * PREP * This is jumped to on prep systems right after the kernel is relocated * to its proper place in memory by the boot loader. The expected layout - * of the regs is: + * of the regs is: * r3: ptr to residual data * r4: initrd_start or if no initrd then 0 * r5: initrd_end - unused if r4 is 0 @@ -124,7 +128,7 @@ _start: * start_here() to do the real work. * -- Cort */ - + .globl __start __start: /* @@ -153,7 +157,6 @@ __start: bl fix_mem_constants #endif /* CONFIG_APUS */ -#ifndef CONFIG_GEMINI /* Switch MMU off, clear BATs and flush TLB. At this point, r3 contains * the physical address we are running at, returned by early_init() */ @@ -161,28 +164,11 @@ __start: __after_mmu_off: bl clear_bats bl flush_tlbs -#endif -#ifndef CONFIG_POWER4 - /* POWER4 doesn't have BATs */ bl initial_bats #if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) bl setup_disp_bat #endif -#else /* CONFIG_POWER4 */ -/* - * Load up the SDR1 and segment register values now - * since we don't have the BATs. - */ - bl reloc_offset - addis r4,r3,_SDR1@ha /* get the value from _SDR1 */ - lwz r4,_SDR1@l(r4) /* assume hash table below 4GB */ - mtspr SDR1,r4 - slbia - lis r5,0x2000 /* set pseudo-segment reg 12 */ - ori r5,r5,0x0ccc - mtsr 12,r5 -#endif /* CONFIG_POWER4 */ #ifndef CONFIG_APUS /* @@ -217,11 +203,17 @@ turn_on_mmu: SYNC RFI /* enables MMU */ -#ifdef CONFIG_SMP +/* + * We need __secondary_hold as a place to hold the other cpus on + * an SMP machine, even when we are running a UP kernel. + */ + . = 0xc0 /* for prep bootloader */ + li r3,1 /* MTX only has 1 cpu */ .globl __secondary_hold __secondary_hold: /* tell the master we're here */ stw r3,4(0) +#ifdef CONFIG_SMP 100: lwz r4,0(0) /* wait until we're told to start */ cmpw 0,r4,r3 @@ -229,7 +221,9 @@ __secondary_hold: /* our cpu # was at addr 0 - go */ mr r24,r3 /* cpu # */ b __secondary_start -#endif +#else + b . +#endif /* CONFIG_SMP */ /* * Exception entry code. This code runs with address translation @@ -289,13 +283,11 @@ i##n: \ .long ret_from_except /* System reset */ -#ifdef CONFIG_SMP /* MVME/MTX and gemini start the secondary here */ -#ifdef CONFIG_GEMINI +/* core99 pmac starts the seconary here by changing the vector, and + putting it back to what it was (UnknownException) when done. */ +#if defined(CONFIG_GEMINI) && defined(CONFIG_SMP) . = 0x100 b __secondary_start_gemini -#else /* CONFIG_GEMINI */ - STD_EXCEPTION(0x100, Reset, __secondary_start_psurge) -#endif /* CONFIG_GEMINI */ #else STD_EXCEPTION(0x100, Reset, UnknownException) #endif @@ -388,16 +380,12 @@ HardwareInterrupt: EXCEPTION_PROLOG; addi r3,r1,STACK_FRAME_OVERHEAD li r20,MSR_KERNEL -#ifndef CONFIG_APUS li r4,0 bl transfer_to_handler .globl do_IRQ_intercept do_IRQ_intercept: .long do_IRQ; .long ret_from_intercept -#else - bl apus_interrupt_entry -#endif /* CONFIG_APUS */ /* Alignment exception */ . = 0x600 @@ -487,7 +475,7 @@ trap_0f_cont: Trap_0f: EXCEPTION_PROLOG b trap_0f_cont - + /* * Handle TLB miss for instruction on 603/603e. * Note: we get an alternate set of r0 - r3 to use automatically. @@ -636,7 +624,7 @@ DataAddressInvalid: mtcrf 0x80,r3 /* Restore CR0 */ mtmsr r0 b DataAccess - + /* * Handle TLB miss for DATA Store on 603/603e */ @@ -809,11 +797,11 @@ stack_ovf: RFI /* - * Disable FP for the task which had the FPU previously, + * This task wants to use the FPU now. + * On UP, 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 + * Load up this task's FP registers from its thread_struct, + * enable the FPU for the current task and return to the task. */ load_up_fpu: mfmsr r5 @@ -830,14 +818,13 @@ load_up_fpu: * to another. Instead we call giveup_fpu in switch_to. */ #ifndef CONFIG_SMP - lis r6,0 /* get __pa constant */ - tophys(r6,r6) + tophys(r6,0) /* get __pa constant */ addis r3,r6,last_task_used_math@ha lwz r4,last_task_used_math@l(r3) cmpi 0,r4,0 beq 1f add r4,r4,r6 - addi r4,r4,THREAD /* want THREAD of last_task_used_math */ + addi r4,r4,THREAD /* want last_task_used_math->thread */ SAVE_32FPRS(0, r4) mffs fr0 stfd fr0,THREAD_FPSCR-4(r4) @@ -850,8 +837,10 @@ load_up_fpu: 1: #endif /* CONFIG_SMP */ /* enable use of FP after return */ - ori r23,r23,MSR_FP|MSR_FE0|MSR_FE1 mfspr r5,SPRG3 /* current task's THREAD (phys) */ + lwz r4,THREAD_FPEXC_MODE(r5) + ori r23,r23,MSR_FP /* enable FP for current */ + or r23,r23,r4 lfd fr0,THREAD_FPSCR-4(r5) mtfsf 0xff,fr0 REST_32FPRS(0, r5) @@ -875,7 +864,7 @@ load_up_fpu: lwz r21,GPR21(r21) SYNC RFI - + /* * FP unavailable trap from kernel - print a message, but let * the task use FP in the kernel until it returns to user mode. @@ -1020,7 +1009,7 @@ giveup_altivec: #endif /* CONFIG_SMP */ blr #endif /* CONFIG_ALTIVEC */ - + /* * giveup_fpu(tsk) * Disable FP for the task given as the argument, @@ -1031,9 +1020,10 @@ giveup_altivec: giveup_fpu: mfmsr r5 ori r5,r5,MSR_FP - SYNC + SYNC_601 + ISYNC_601 mtmsr r5 /* enable use of fpu now */ - SYNC + SYNC_601 isync cmpi 0,r3,0 beqlr- /* if no previous owner, done */ @@ -1172,62 +1162,6 @@ fix_mem_constants: sync /* additional sync needed on g4 */ isync /* No speculative loading until now */ blr - -apus_interrupt_entry: - /* This is horrible, but there's no way around it. Enable the - * data cache so the IRQ hardware register can be accessed - * without cache intervention. Then disable interrupts and get - * the current emulated m68k IPL value. - */ - - mfmsr 20 - xori r20,r20,MSR_DR - SYNC - mtmsr r20 - isync - - lis r4,APUS_IPL_EMU@h - - li r20,(IPLEMU_SETRESET|IPLEMU_DISABLEINT) - stb r20,APUS_IPL_EMU@l(r4) - eieio - - lbz r3,APUS_IPL_EMU@l(r4) - - li r2,IPLEMU_IPLMASK - rlwinm. r20,r3,32-3,29,31 - bne 2f - mr r20,r2 /* lvl7! Need to reset state machine. */ - b 3f -2: cmp 0,r20,r2 - beq 1f -3: eieio - stb r2,APUS_IPL_EMU@l(r4) - ori r20,r20,IPLEMU_SETRESET - eieio - stb r20,APUS_IPL_EMU@l(r4) -1: eieio - li r20,IPLEMU_DISABLEINT - stb r20,APUS_IPL_EMU@l(r4) - - /* At this point we could do some magic to avoid the overhead - * of calling the C interrupt handler in case of a spurious - * interrupt. Could not get a simple hack to work though. - */ - - mfmsr r20 - xori r20,r20,MSR_DR - SYNC - mtmsr r20 - isync - - stw r3,(_CCR+4)(r21); - - addi r3,r1,STACK_FRAME_OVERHEAD; - li r20,MSR_KERNEL; - bl transfer_to_handler; - .long do_IRQ; - .long ret_from_except /*********************************************************************** * Please note that on APUS the exception handlers are located at the @@ -1247,10 +1181,9 @@ __secondary_start_gemini: andc r4,r4,r3 mtspr HID0,r4 sync - bl prom_init + bl gemini_prom_init b __secondary_start #endif /* CONFIG_GEMINI */ - .globl __secondary_start_psurge __secondary_start_psurge: li r24,1 /* cpu # */ @@ -1310,7 +1243,6 @@ __secondary_start: mtspr SPRG3,r4 li r3,0 mtspr SPRG2,r3 /* 0 => r1 has kernel sp */ - stw r3,PT_REGS(r4) /* set thread.regs to 0 for kernel thread */ /* enable MMU and jump to start_secondary */ li r4,MSR_KERNEL @@ -1347,12 +1279,22 @@ _GLOBAL(__setup_cpu_7400) bl setup_750_7400_hid0 mtlr r4 blr +_GLOBAL(__setup_cpu_7410) + mflr r4 + bl setup_common_caches + bl setup_750_7400_hid0 + li r3,0 + mtspr SPRN_L2CR2,r3 + mtlr r4 + blr _GLOBAL(__setup_cpu_7450) + mflr r4 + bl setup_common_caches + bl setup_7450_hid0 + mtlr r4 blr _GLOBAL(__setup_cpu_power3) blr -_GLOBAL(__setup_cpu_power4) - blr _GLOBAL(__setup_cpu_generic) blr @@ -1407,6 +1349,47 @@ setup_750_7400_hid0: isync blr +/* 7450 + * Enable Store Gathering (SGE), Branch Folding (FOLD) + * Branch History Table (BHTE), Branch Target ICache (BTIC) + * Dynamic Power Management (DPM), Speculative (SPD) + * Ensure our data cache instructions really operate. + * Timebase has to be running or we wouldn't have made it here, + * just ensure we don't disable it. + * Clear Instruction cache throttling (ICTC) + */ +setup_7450_hid0: + /* We check for the presence of an L3 cache setup by + * the firmware. If any, we disable DOZE capability + */ + mfspr r11,SPRN_L3CR + andis. r11,r11,L3CR_L3E@h + beq 1f + li r7,CPU_FTR_CAN_DOZE + lwz r6,CPU_SPEC_FEATURES(r5) + andc r6,r6,r7 + stw r6,CPU_SPEC_FEATURES(r5) +1: + mfspr r11,HID0 + + /* All of the bits we have to set..... + */ + ori r11,r11,HID0_SGE | HID0_FOLD | HID0_BHTE | HID0_BTIC + oris r11,r11,HID0_DPM@h /* enable dynamic power mgmt */ + + /* All of the bits we have to clear.... + */ + li r3,HID0_SPD | HID0_NOPDST | HID0_NOPTI + andc r11,r11,r3 /* clear SPD: enable speculative */ + li r3,0 + + mtspr ICTC,r3 /* Instruction Cache Throttling off */ + isync + mtspr HID0,r11 + sync + isync + blr + /* * Load stuff into the MMU. Intended to be called with * IR=0 and DR=0. @@ -1417,7 +1400,7 @@ load_up_mmu: tophys(r6,r6) lwz r6,_SDR1@l(r6) mtspr SDR1,r6 -#ifdef CONFIG_PPC64BRIDGE +#ifdef CONFIG_PPC64BRIDGE /* clear the ASR so we only use the pseudo-segment registers. */ li r6,0 mtasr r6 @@ -1430,7 +1413,6 @@ load_up_mmu: addi r3,r3,0x111 /* increment VSID */ addis r4,r4,0x1000 /* address of next segment */ bdnz 3b -#ifndef CONFIG_POWER4 /* 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 @@ -1443,7 +1425,6 @@ load_up_mmu: LOAD_BAT(1,r3,r4,r5) LOAD_BAT(2,r3,r4,r5) LOAD_BAT(3,r3,r4,r5) -#endif /* CONFIG_POWER4 */ blr /* @@ -1519,6 +1500,19 @@ start_here: TLBSYNC /* ... on all CPUs */ bl load_up_mmu + + /* Add helper information for the Abatron bdiGDB debugger. + * We do this here because we know the mmu is disabled, and + * will be enabled for real in just a few instructions. + */ + lis r5, abatron_pteptrs@h + ori r5, r5, abatron_pteptrs@l + stw r5, 0xf0(r0) /* This much match your Abatron config */ + lis r6, swapper_pg_dir@h + ori r6, r6, swapper_pg_dir@l + tophys(r5, r5) + stw r6, 0(r5) + /* Now turn on the MMU for real! */ li r4,MSR_KERNEL FIX_SRR1(r4,r5) @@ -1538,6 +1532,15 @@ _GLOBAL(set_context) addis r3,r3,0x6000 /* Set Ks, Ku bits */ li r0,NUM_USER_SEGMENTS mtctr r0 + +#ifdef CONFIG_BDI_SWITCH + /* Context switch the PTE pointer for the Abatron BDI2000. + * The PGDIR is passed as second argument. + */ + lis r5, KERNELBASE@h + lwz r5, 0xf0(r5) + stw r4, 0x4(r5) +#endif li r4,0 3: #ifdef CONFIG_PPC64BRIDGE @@ -1561,22 +1564,21 @@ _GLOBAL(set_context) * -- Cort */ clear_bats: -#if !defined(CONFIG_GEMINI) li r20,0 mfspr r9,PVR rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ cmpwi r9, 1 beq 1f - + mtspr DBAT0U,r20 - mtspr DBAT0L,r20 + mtspr DBAT0L,r20 mtspr DBAT1U,r20 mtspr DBAT1L,r20 mtspr DBAT2U,r20 - mtspr DBAT2L,r20 + mtspr DBAT2L,r20 mtspr DBAT3U,r20 mtspr DBAT3L,r20 -1: +1: mtspr IBAT0U,r20 mtspr IBAT0L,r20 mtspr IBAT1U,r20 @@ -1585,10 +1587,8 @@ clear_bats: mtspr IBAT2L,r20 mtspr IBAT3U,r20 mtspr IBAT3L,r20 -#endif /* !defined(CONFIG_GEMINI) */ blr -#ifndef CONFIG_GEMINI flush_tlbs: lis r20, 0x40 1: addic. r20, r20, -0x1000 @@ -1607,9 +1607,7 @@ mmu_off: mtspr SRR1,r3 sync RFI -#endif -#ifndef CONFIG_POWER4 /* * Use the first pair of BAT registers to map the 1st 16MB * of RAM to KERNELBASE. From this point on we can't safely @@ -1645,7 +1643,7 @@ initial_bats: #else ori r11,r11,BL_256M<<2|0x2 /* set up BAT registers for 604 */ #endif /* CONFIG_APUS */ - + #ifdef CONFIG_PPC64BRIDGE /* clear out the high 32 bits in the BAT */ clrldi r11,r11,32 @@ -1682,7 +1680,6 @@ setup_disp_bat: blr #endif /* !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) */ -#endif /* CONFIG_POWER4 */ #ifdef CONFIG_8260 /* Jump into the system reset for the rom. @@ -1734,12 +1731,12 @@ empty_zero_page: .globl swapper_pg_dir swapper_pg_dir: - .space 4096 + .space 4096 /* * This space gets a copy of optional info passed to us by the bootstrap * Used to pass parameters into the kernel like root=/dev/sda1, etc. - */ + */ .globl cmd_line cmd_line: .space 512 @@ -1752,3 +1749,9 @@ intercept_table: .long 0, 0, 0, 0, 0, 0, 0, 0 .long 0, 0, 0, 0, 0, 0, 0, 0 .long 0, 0, 0, 0, 0, 0, 0, 0 + +/* Room for two PTE pointers, usually the kernel and current user pointers + * to their respective root page table. + */ +abatron_pteptrs: + .space 8 diff --git a/arch/ppc/kernel/head_4xx.S b/arch/ppc/kernel/head_4xx.S index 35e17f1df41c..39553b2363e4 100644 --- a/arch/ppc/kernel/head_4xx.S +++ b/arch/ppc/kernel/head_4xx.S @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.head_4xx.S 1.6 05/21/01 11:50:00 paulus - */ -/* * Copyright (c) 1995-1996 Gary Thomas <gdt@linuxppc.org> * Initial PowerPC version. * Copyright (c) 1996 Cort Dougan <cort@cs.nmt.edu> @@ -14,6 +11,13 @@ * PowerPC 403GCX modifications. * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu> * PowerPC 403GCX/405GP modifications. + * Copyright 2000 MontaVista Software Inc. + * PPC405 modifications + * PowerPC 403GCX/405GP modifications. + * Author: MontaVista Software, Inc. + * frank_rowand@mvista.com or source@mvista.com + * debbie_chu@mvista.com + * * * Module name: head_4xx.S * @@ -28,139 +32,91 @@ */ #include <linux/config.h> - #include <asm/processor.h> #include <asm/page.h> -#include <asm/pgtable.h> #include <asm/mmu.h> - -#include "ppc_asm.h" - +#include <asm/pgtable.h> +#include <asm/ibm4xx.h> +#include <asm/cputable.h> +#include <asm/ppc_asm.h> +#include "ppc_defs.h" /* Preprocessor Defines */ #define STND_EXC 0 #define CRIT_EXC 1 -### -### Check to make sure the right processor has been defined. -### - -#if !defined(CONFIG_4xx) -#error "This file is only appropriate for kernels supporting the PPC4xx." -#endif - -### -### Execution entry point. -### - -### -### As with the other PowerPC ports, it is expected that when code -### execution begins here, the following registers contain valid, yet -### optional, information: -### -### r3 - Board info structure pointer (DRAM, frequency, MAC address, etc.) -### r4 - Starting address of the init RAM disk -### r5 - Ending address of the init RAM disk -### r6 - Start of kernel command line string (e.g. "mem=96m") -### r7 - End of kernel command line string -### - +/* As with the other PowerPC ports, it is expected that when code + * execution begins here, the following registers contain valid, yet + * optional, information: + * + * r3 - Board info structure pointer (DRAM, frequency, MAC address, etc.) + * r4 - Starting address of the init RAM disk + * r5 - Ending address of the init RAM disk + * r6 - Start of kernel command line string (e.g. "mem=96m") + * r7 - End of kernel command line string + * + * This is all going to change RSN when we add bi_recs....... -- Dan + */ .text _GLOBAL(_stext) _GLOBAL(_start) - ## Save residual data, init RAM disk, and command line parameters - + + /* Save parameters we are passed. + */ mr r31,r3 mr r30,r4 mr r29,r5 mr r28,r6 mr r27,r7 + li r24,0 /* CPU number */ - ## Set the ID for this CPU - - li r24,0 - - ## Invalidate all TLB entries + /* We have to turn on the MMU right away so we get cache modes + * set correctly. + */ + bl initial_mmu - tlbia - - ## We should still be executing code at physical address 0x0000xxxx - ## at this point. However, start_here is at virtual address - ## 0xC000xxxx. So, set up a TLB mapping to cover this once - ## translation is enabled. - - lis r3,KERNELBASE@h # Load the kernel virtual address - ori r3,r3,KERNELBASE@l - tophys(r4,r3) # Load the kernel physical address - - ## Save the existing PID and load the kernel PID. - - mfspr r7,SPRN_PID # Save the old PID - li r0,0 - mtspr SPRN_PID,r0 # Load the kernel PID - - ## Configure and load entry into TLB slot 0. - - clrrwi r4,r4,10 # Mask off the real page number - ori r4,r4,(TLB_WR | TLB_EX) # Set the write and execute bits - - clrrwi r3,r3,10 # Mask off the effective page number - ori r3,r3,(TLB_VALID | TLB_PAGESZ(PAGESZ_16M)) - - tlbwe r4,r0,TLB_DATA # Load the data portion of the entry - tlbwe r3,r0,TLB_TAG # Load the tag portion of the entry - isync - - mtspr SPRN_PID,r7 # Restore the existing PID - - ## Establish the exception vector base - - lis r4,KERNELBASE@h # EVPR only uses the high 16-bits - tophys(r0,r4) # Use the physical address - mtspr SPRN_EVPR,r0 - - ## Enable the MMU and jump to the main PowerPC kernel start-up code - - mfmsr r0 # Get the machine state register - ori r0,r0,(MSR_DR | MSR_IR) # Enable data and instr. translation - mtspr SPRN_SRR1,r0 # Set up the new machine state register - lis r0,start_here@h - ori r0,r0,start_here@l - mtspr SPRN_SRR0,r0 # Set up the new instruction pointer - rfi # Jump to start_here w/ translation on - - -### -### Exception vector entry code. This code runs with address translation -### turned off (i.e. using physical addresses). We assume SPRG3 has the -### physical address of the current task thread_struct. -### - - ## Common exception code for all exception types. - -#define COMMON_PROLOG \ -0: mtspr SPRN_SPRG0,r20; /* We need r20, move it to SPRG0 */\ - mtspr SPRN_SPRG1,r21; /* We need r21, move it to SPRG1 */\ - mfcr r20; /* We need the CR, move it to r20 */\ - mfspr r21,SPRN_SPRG2; /* Exception stack to use */\ - cmpwi cr0,r21,0; /* From user mode or RTAS? */\ - bne 1f; /* Not RTAS, branch */\ - tophys(r21, r1); /* Convert vka in r1 to pka in r21 */\ - subi r21,r21,INT_FRAME_SIZE; /* Allocate an exception frame */\ -1: stw r20,_CCR(r21); /* Save CR on the stack */\ - stw r22,GPR22(r21); /* Save r22 on the stack */\ - stw r23,GPR23(r21); /* r23 Save on the stack */\ - mfspr r20,SPRN_SPRG0; /* Get r20 back out of SPRG0 */\ - stw r20,GPR20(r21); /* Save r20 on the stack */\ - mfspr r22,SPRN_SPRG1; /* Get r21 back out of SPRG0 */\ - stw r22,GPR21(r21); /* Save r21 on the stack */\ - mflr r20; \ - stw r20,_LINK(r21); /* Save LR on the stack */\ - mfctr r22; \ - stw r22,_CTR(r21); /* Save CTR on the stack */\ - mfspr r20,XER; \ - stw r20,_XER(r21); /* Save XER on the stack */ +/* We now have the lower 16 Meg mapped into TLB entries, and the caches + * ready to work. + */ +turn_on_mmu: + li r0,MSR_KERNEL + mtspr SRR1,r0 + lis r0,start_here@h + ori r0,r0,start_here@l + mtspr SRR0,r0 + SYNC + rfi /* enables MMU */ + +/* Exception vector entry code. This code runs with address translation + * turned off (i.e. using physical addresses). We assume SPRG3 has the + * physical address of the current task thread_struct. + */ + +#define COMMON_PROLOG(n) \ +0: mtspr SPRN_SPRG0,r20; /* We need r20, move it to SPRG0 */\ + mtspr SPRN_SPRG1,r21; /* We need r21, move it to SPRG1 */\ + mfcr r20; /* We need the CR, move it to r20 */\ + mfspr r21,SPRN_SPRG2; /* Exception stack to use */\ + cmpwi cr0,r21,0; /* From user mode or RTAS? */\ + bne 1f; /* Not RTAS, branch */\ + tophys(r21, r1); /* Convert vka in r1 to pka in r21 */\ + subi r21,r21,INT_FRAME_SIZE; /* Allocate an exception frame */\ +1: stw r20,_CCR(r21); /* Save CR on the stack */\ + stw r22,GPR22(r21); /* Save r22 on the stack */\ + stw r23,GPR23(r21); /* r23 Save on the stack */\ + mfspr r20,SPRN_SPRG0; /* Get r20 back out of SPRG0 */\ + stw r20,GPR20(r21); /* Save r20 on the stack */\ + mfspr r22,SPRN_SPRG1; /* Get r21 back out of SPRG0 */\ + stw r22,GPR21(r21); /* Save r21 on the stack */\ + mflr r20; \ + stw r20,_LINK(r21); /* Save LR on the stack */\ + mfctr r22; \ + stw r22,_CTR(r21); /* Save CTR on the stack */\ + mfspr r20,XER; \ + stw r20,_XER(r21); /* Save XER on the stack */\ + mfspr r20,SPRN_DBCR0; \ + stw r20,_DBCR0(r21); /* Save Debug Control on the stack */ #define COMMON_EPILOG \ stw r0,GPR0(r21); /* Save r0 on the stack */\ @@ -171,25 +127,22 @@ _GLOBAL(_start) SAVE_4GPRS(3, r21); /* Save r3 through r6 on the stack */\ SAVE_GPR(7, r21); /* Save r7 on the stack */ - ## Common exception code for standard (non-critical) exceptions. - -#define STND_EXCEPTION_PROLOG \ - COMMON_PROLOG; \ +#define STND_EXCEPTION_PROLOG(n) \ + COMMON_PROLOG(n); \ mfspr r22,SPRN_SRR0; /* Faulting instruction address */\ + lis r20,MSR_WE@h; \ mfspr r23,SPRN_SRR1; /* MSR at the time of fault */\ + andc r23,r23,r20; /* disable processor wait state */\ COMMON_EPILOG; - ## Common exception code for critical exceptions. - -#define CRIT_EXCEPTION_PROLOG \ - COMMON_PROLOG; \ +#define CRIT_EXCEPTION_PROLOG(n) \ + COMMON_PROLOG(n); \ mfspr r22,SPRN_SRR2; /* Faulting instruction address */\ + lis r20,MSR_WE@h; \ mfspr r23,SPRN_SRR3; /* MSR at the time of fault */\ + andc r23,r23,r20; /* disable processor wait state */\ COMMON_EPILOG; -### -### Macros for specific exception types -### #define START_EXCEPTION(n, label) \ . = n; \ @@ -200,68 +153,213 @@ label: bl transfer_to_handler; \ .long func; \ .long ret_from_except - - + + #define STND_EXCEPTION(n, label, func) \ START_EXCEPTION(n, label); \ - STND_EXCEPTION_PROLOG; \ + STND_EXCEPTION_PROLOG(n); \ addi r3,r1,STACK_FRAME_OVERHEAD; \ li r7,STND_EXC; \ li r20,MSR_KERNEL; \ FINISH_EXCEPTION(func) - + #define CRIT_EXCEPTION(n, label, func) \ START_EXCEPTION(n, label); \ - CRIT_EXCEPTION_PROLOG; \ + CRIT_EXCEPTION_PROLOG(n); \ addi r3,r1,STACK_FRAME_OVERHEAD; \ li r7,CRIT_EXC; \ li r20,MSR_KERNEL; \ FINISH_EXCEPTION(func) - -### -### Exception vectors. -### - -### 0x0100 - Critical Interrupt Exception +/* Exception vectors. +*/ + +/* 0x0100 - Critical Interrupt Exception +*/ CRIT_EXCEPTION(0x0100, CriticalInterrupt, UnknownException) -### 0x0200 - Machine Check Exception - +/* 0x0200 - Machine Check Exception +*/ +#if 0 CRIT_EXCEPTION(0x0200, MachineCheck, MachineCheckException) +#else + START_EXCEPTION(0x0200, MachineCheck) + CRIT_EXCEPTION_PROLOG(0x0200) + + /* + lis r4,0x0400 + mtdcr DCRN_POB0_BESR0,r4 + */ +#ifdef DCRN_POB0_BEAR + mfdcr r4,DCRN_POB0_BEAR + mfdcr r4,DCRN_POB0_BESR0 + mfdcr r4,DCRN_POB0_BESR1 +#endif -### 0x0300 - Data Storage Exception +#ifdef DCRN_PLB0_BEAR + mfdcr r4,DCRN_PLB0_ACR + mfdcr r4,DCRN_PLB0_BEAR + mfdcr r4,DCRN_PLB0_BESR +#endif - START_EXCEPTION(0x0300, DataAccess) - STND_EXCEPTION_PROLOG - mfspr r5,SPRN_ESR # Grab the ESR, save it, pass as arg3 - stw r5,_ESR(r21) - mfspr r4,SPRN_DEAR # Grab the DEAR, save it, pass as arg2 - stw r4,_DEAR(r21) addi r3,r1,STACK_FRAME_OVERHEAD - li r7,STND_EXC # This is a standard exception + li r7,CRIT_EXC li r20,MSR_KERNEL - rlwimi r20,r23,0,16,16 # Copy EE bit from the saved MSR - FINISH_EXCEPTION(do_page_fault) # do_page_fault(regs, ESR, DEAR) - -### 0x0400 - Instruction Storage Exception + FINISH_EXCEPTION(MachineCheckException) +#endif + +/* 0x0300 - Data Storage Exception + * This happens for just a few reasons. U0 set (but we don't do that), + * or zone protection fault (user violation, write to protected page). + * If this is just an update of modified status, we do that quickly + * and exit. Otherwise, we call heavywight functions to do the work. + */ + START_EXCEPTION(0x0300, DataStore) + mtspr SPRG0, r20 /* Save some working registers */ + mtspr SPRG1, r21 +#ifdef CONFIG_403GCX + stw r22, 0(r0) + stw r23, 4(r0) + mfcr r21 + mfspr r22, SPRN_PID + stw r21, 8(r0) + stw r22, 12(r0) +#else + mtspr SPRG4, r22 + mtspr SPRG5, r23 + mfcr r21 + mfspr r22, SPRN_PID + mtspr SPRG7, r21 + mtspr SPRG6, r22 +#endif + + /* First, check if it was a zone fault (which means a user + * tried to access a kernel or read-protected page - always + * a SEGV). All other faults here must be stores, so no + * need to check ESR_DST as well. */ + mfspr r20, SPRN_ESR + andis. r20, r20, ESR_DIZ@h + bne 2f + + mfspr r20, SPRN_DEAR /* Get faulting address */ + + /* If we are faulting a kernel address, we have to use the + * kernel page tables. + */ + andis. r21, r20, 0x8000 + beq 3f + lis r21, swapper_pg_dir@h + ori r21, r21, swapper_pg_dir@l + li r23, 0 + mtspr SPRN_PID, r23 /* TLB will have 0 TID */ + b 4f + + /* Get the PGD for the current thread. + */ +3: + mfspr r21,SPRG3 + lwz r21,PGDIR(r21) +4: + tophys(r21, r21) + rlwimi r21, r20, 12, 20, 29 /* Create L1 (pgdir/pmd) address */ + lwz r21, 0(r21) /* Get L1 entry */ + rlwinm. r22, r21, 0, 0, 19 /* Extract L2 (pte) base address */ + beq 2f /* Bail if no table */ + + tophys(r22, r22) + rlwimi r22, r20, 22, 20, 29 /* Compute PTE address */ + lwz r21, 0(r22) /* Get Linux PTE */ + + andi. r23, r21, _PAGE_RW /* Is it writeable? */ + beq 2f /* Bail if not */ + + /* Update 'changed'. + */ + ori r21, r21, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE + stw r21, 0(r22) /* Update Linux page table */ + + /* Most of the Linux PTE is ready to load into the TLB LO. + * We set ZSEL, where only the LS-bit determines user access. + * We set execute, because we don't have the granularity to + * properly set this at the page level (Linux problem). + * If shared is set, we cause a zero PID->TID load. + * Many of these bits are software only. Bits we don't set + * here we (properly should) assume have the appropriate value. + */ + li r22, 0x0ce2 + andc r21, r21, r22 /* Make sure 20, 21 are zero */ + + /* find the TLB index that caused the fault. It has to be here. + */ + tlbsx r23, 0, r20 + + tlbwe r21, r23, TLB_DATA /* Load TLB LO */ + + /* Done...restore registers and get out of here. + */ +#ifdef CONFIG_403GCX + lwz r22, 12(r0) + lwz r21, 8(r0) + mtspr SPRN_PID, r22 + mtcr r21 + lwz r23, 4(r0) + lwz r22, 0(r0) +#else + mfspr r22, SPRG6 + mfspr r21, SPRG7 + mtspr SPRN_PID, r22 + mtcr r21 + mfspr r23, SPRG5 + mfspr r22, SPRG4 +#endif + mfspr r21, SPRG1 + mfspr r20, SPRG0 + PPC405_ERR77_SYNC + rfi /* Should sync shadow TLBs */ + +2: + /* The bailout. Restore registers to pre-exception conditions + * and call the heavyweights to help us out. + */ +#ifdef CONFIG_403GCX + lwz r22, 12(r0) + lwz r21, 8(r0) + mtspr SPRN_PID, r22 + mtcr r21 + lwz r23, 4(r0) + lwz r22, 0(r0) +#else + mfspr r22, SPRG6 + mfspr r21, SPRG7 + mtspr SPRN_PID, r22 + mtcr r21 + mfspr r23, SPRG5 + mfspr r22, SPRG4 +#endif + mfspr r21, SPRG1 + mfspr r20, SPRG0 + b DataAccess +/* 0x0400 - Instruction Storage Exception + * I don't know why it is called "Storage"....This is caused by a fetch + * from non-execute or guarded pages. + */ START_EXCEPTION(0x0400, InstructionAccess) - STND_EXCEPTION_PROLOG - mr r4,r22 # Pass SRR0 as arg2 - mr r5,r23 # Pass SRR1 as arg3 + STND_EXCEPTION_PROLOG(0x0400) + mr r4,r22 /* Pass SRR0 as arg2 */ + li r5,0 /* Pass zero as arg3 */ addi r3,r1,STACK_FRAME_OVERHEAD - li r7,STND_EXC # This is a standard exception + li r7,STND_EXC li r20,MSR_KERNEL - rlwimi r20,r23,0,16,16 # Copy EE bit from the saved MSR - FINISH_EXCEPTION(do_page_fault) # do_page_fault(regs, SRR0, SRR1) - -### 0x0500 - External Interrupt Exception + rlwimi r20,r23,0,16,16 /* Copy EE bit from the saved MSR */ + FINISH_EXCEPTION(do_page_fault) /* do_page_fault(regs, SRR0, SRR1) */ +/* 0x0500 - External Interrupt Exception +*/ START_EXCEPTION(0x0500, HardwareInterrupt) - STND_EXCEPTION_PROLOG + STND_EXCEPTION_PROLOG(0x0500) addi r3,r1,STACK_FRAME_OVERHEAD li r7,STND_EXC li r20,MSR_KERNEL @@ -271,54 +369,70 @@ _GLOBAL(do_IRQ_intercept) .long do_IRQ .long ret_from_intercept -### 0x0600 - Alignment Exception - +/* 0x0600 - Alignment Exception +*/ START_EXCEPTION(0x0600, Alignment) - STND_EXCEPTION_PROLOG - mfspr r4,SPRN_DEAR # Grab the DEAR and save it + STND_EXCEPTION_PROLOG(0x0600) + mfspr r4,SPRN_DEAR /* Grab the DEAR and save it */ stw r4,_DEAR(r21) addi r3,r1,STACK_FRAME_OVERHEAD - li r7,STND_EXC # This is a standard exception + li r7,STND_EXC li r20,MSR_KERNEL - rlwimi r20,r23,0,16,16 # Copy EE bit from the saved MSR + rlwimi r20,r23,0,16,16 /* Copy EE bit from the saved MSR */ FINISH_EXCEPTION(AlignmentException) -### 0x0700 - Program Exception - +/* 0x0700 - Program Exception +*/ START_EXCEPTION(0x0700, ProgramCheck) - STND_EXCEPTION_PROLOG + STND_EXCEPTION_PROLOG(0x0700) addi r3,r1,STACK_FRAME_OVERHEAD - li r7,STND_EXC # This is a standard exception + li r7,STND_EXC li r20,MSR_KERNEL - rlwimi r20,r23,0,16,16 # Copy EE bit from the saved MSR + rlwimi r20,r23,0,16,16 /* Copy EE bit from the saved MSR */ FINISH_EXCEPTION(ProgramCheckException) - - STND_EXCEPTION(0x0800, Trap_08, UnknownException) + + +/* I'm stealing this unused vector location to build a standard exception + * frame for Data TLB Access errors. The other Data TLB exceptions will bail + * out to this point if they can't resolve the lightweight TLB fault. + */ + START_EXCEPTION(0x0800, DataAccess) + STND_EXCEPTION_PROLOG(0x0800) + mfspr r5,SPRN_ESR /* Grab the ESR, save it, pass arg3 */ + stw r5,_ESR(r21) + mfspr r4,SPRN_DEAR /* Grab the DEAR, save it, pass arg2 */ + stw r4,_DEAR(r21) + addi r3,r1,STACK_FRAME_OVERHEAD + li r7,STND_EXC + li r20,MSR_KERNEL + rlwimi r20,r23,0,16,16 /* Copy EE bit from the saved MSR */ + FINISH_EXCEPTION(do_page_fault) /* do_page_fault(regs, ESR, DEAR) */ + STND_EXCEPTION(0x0900, Trap_09, UnknownException) STND_EXCEPTION(0x0A00, Trap_0A, UnknownException) - STND_EXCEPTION(0x0B00, Trap_0B, UnknownException) -### 0x0C00 - System Call Exception - + STND_EXCEPTION(0x0B00, Trap_0B, UnknownException) +/* 0x0C00 - System Call Exception +*/ START_EXCEPTION(0x0C00, SystemCall) - STND_EXCEPTION_PROLOG + STND_EXCEPTION_PROLOG(0x0C00) stw r3,ORIG_GPR3(r21) - li r7,STND_EXC # This is a standard exception + li r7,STND_EXC li r20,MSR_KERNEL - rlwimi r20,r23,0,16,16 # Copy EE bit from the saved MSR + rlwimi r20,r23,0,16,16 /* Copy EE bit from the saved MSR */ FINISH_EXCEPTION(DoSyscall) STND_EXCEPTION(0x0D00, Trap_0D, UnknownException) STND_EXCEPTION(0x0E00, Trap_0E, UnknownException) STND_EXCEPTION(0x0F00, Trap_0F, UnknownException) -### 0x1000 - Programmable Interval Timer (PIT) Exception - +/* 0x1000 - Programmable Interval Timer (PIT) Exception +*/ START_EXCEPTION(0x1000, Decrementer) - STND_EXCEPTION_PROLOG - lis r0,TSR_PIS@h # Set-up the PIT exception mask - mtspr SPRN_TSR,r0 # Clear the PIT exception + STND_EXCEPTION_PROLOG(0x1000) + lis r0,TSR_PIS@h /* Set-up the PIT exception mask */ + mtspr SPRN_TSR,r0 /* Clear the PIT exception */ addi r3,r1,STACK_FRAME_OVERHEAD - li r7,STND_EXC # This is a standard exception + li r7,STND_EXC li r20,MSR_KERNEL bl transfer_to_handler _GLOBAL(timer_interrupt_intercept) @@ -326,28 +440,239 @@ _GLOBAL(timer_interrupt_intercept) .long ret_from_intercept #if 0 -### 0x1010 - Fixed Interval Timer (FIT) Exception - +/* NOTE: + * FIT and WDT handlers are not implemented yet. + */ + +/* 0x1010 - Fixed Interval Timer (FIT) Exception +*/ STND_EXCEPTION(0x1010, FITException, UnknownException) -### 0x1020 - Watchdog Timer (WDT) Exception +/* 0x1020 - Watchdog Timer (WDT) Exception +*/ CRIT_EXCEPTION(0x1020, WDTException, UnknownException) #endif -### 0x1100 - Data TLB Miss Exception +/* 0x1100 - Data TLB Miss Exception + * As the name implies, translation is not in the MMU, so search the + * page tables and fix it. The only purpose of this function is to + * load TLB entries from the page table if they exist. + */ + START_EXCEPTION(0x1100, DTLBMiss) + mtspr SPRG0, r20 /* Save some working registers */ + mtspr SPRG1, r21 +#ifdef CONFIG_403GCX + stw r22, 0(r0) + stw r23, 4(r0) + mfcr r21 + mfspr r22, SPRN_PID + stw r21, 8(r0) + stw r22, 12(r0) +#else + mtspr SPRG4, r22 + mtspr SPRG5, r23 + mfcr r21 + mfspr r22, SPRN_PID + mtspr SPRG7, r21 + mtspr SPRG6, r22 +#endif + mfspr r20, SPRN_DEAR /* Get faulting address */ + + /* If we are faulting a kernel address, we have to use the + * kernel page tables. + */ + andis. r21, r20, 0x8000 + beq 3f + lis r21, swapper_pg_dir@h + ori r21, r21, swapper_pg_dir@l + li r23, 0 + mtspr SPRN_PID, r23 /* TLB will have 0 TID */ + b 4f + + /* Get the PGD for the current thread. + */ +3: + mfspr r21,SPRG3 + lwz r21,PGDIR(r21) +4: + tophys(r21, r21) + rlwimi r21, r20, 12, 20, 29 /* Create L1 (pgdir/pmd) address */ + lwz r21, 0(r21) /* Get L1 entry */ + rlwinm. r22, r21, 0, 0, 19 /* Extract L2 (pte) base address */ + beq 2f /* Bail if no table */ + + tophys(r22, r22) + rlwimi r22, r20, 22, 20, 29 /* Compute PTE address */ + lwz r21, 0(r22) /* Get Linux PTE */ + andi. r23, r21, _PAGE_PRESENT + beq 2f - STND_EXCEPTION(0x1100, DTLBMiss, PPC4xx_dtlb_miss) + ori r21, r21, _PAGE_ACCESSED + stw r21, 0(r22) + + /* Most of the Linux PTE is ready to load into the TLB LO. + * We set ZSEL, where only the LS-bit determines user access. + * We set execute, because we don't have the granularity to + * properly set this at the page level (Linux problem). + * If shared is set, we cause a zero PID->TID load. + * Many of these bits are software only. Bits we don't set + * here we (properly should) assume have the appropriate value. + */ + li r22, 0x0ce2 + andc r21, r21, r22 /* Make sure 20, 21 are zero */ + + b finish_tlb_load + + +2: + /* The bailout. Restore registers to pre-exception conditions + * and call the heavyweights to help us out. + */ +#ifdef CONFIG_403GCX + lwz r22, 12(r0) + lwz r21, 8(r0) + mtspr SPRN_PID, r22 + mtcr r21 + lwz r23, 4(r0) + lwz r22, 0(r0) +#else + mfspr r22, SPRG6 + mfspr r21, SPRG7 + mtspr SPRN_PID, r22 + mtcr r21 + mfspr r23, SPRG5 + mfspr r22, SPRG4 +#endif + mfspr r21, SPRG1 + mfspr r20, SPRG0 + b DataAccess -### 0x1200 - Instruction TLB Miss Exception +/* 0x1200 - Instruction TLB Miss Exception + * Nearly the same as above, except we get our information from different + * registers and bailout to a different point. + */ + START_EXCEPTION(0x1200, ITLBMiss) + mtspr SPRG0, r20 /* Save some working registers */ + mtspr SPRG1, r21 +#ifdef CONFIG_403GCX + stw r22, 0(r0) + stw r23, 4(r0) + mfcr r21 + mfspr r22, SPRN_PID + stw r21, 8(r0) + stw r22, 12(r0) +#else + mtspr SPRG4, r22 + mtspr SPRG5, r23 + mfcr r21 + mfspr r22, SPRN_PID + mtspr SPRG7, r21 + mtspr SPRG6, r22 +#endif + mfspr r20, SRR0 /* Get faulting address */ + + /* If we are faulting a kernel address, we have to use the + * kernel page tables. + */ + andis. r21, r20, 0x8000 + beq 3f + lis r21, swapper_pg_dir@h + ori r21, r21, swapper_pg_dir@l + li r23, 0 + mtspr SPRN_PID, r23 /* TLB will have 0 TID */ + b 4f + + /* Get the PGD for the current thread. + */ +3: + mfspr r21,SPRG3 + lwz r21,PGDIR(r21) +4: + tophys(r21, r21) + rlwimi r21, r20, 12, 20, 29 /* Create L1 (pgdir/pmd) address */ + lwz r21, 0(r21) /* Get L1 entry */ + rlwinm. r22, r21, 0, 0, 19 /* Extract L2 (pte) base address */ + beq 2f /* Bail if no table */ + + tophys(r22, r22) + rlwimi r22, r20, 22, 20, 29 /* Compute PTE address */ + lwz r21, 0(r22) /* Get Linux PTE */ + andi. r23, r21, _PAGE_PRESENT + beq 2f - STND_EXCEPTION(0x1200, ITLBMiss, PPC4xx_itlb_miss) + ori r21, r21, _PAGE_ACCESSED + stw r21, 0(r22) + + /* Most of the Linux PTE is ready to load into the TLB LO. + * We set ZSEL, where only the LS-bit determines user access. + * We set execute, because we don't have the granularity to + * properly set this at the page level (Linux problem). + * If shared is set, we cause a zero PID->TID load. + * Many of these bits are software only. Bits we don't set + * here we (properly should) assume have the appropriate value. + */ + li r22, 0x0ce2 + andc r21, r21, r22 /* Make sure 20, 21 are zero */ + + b finish_tlb_load + + /* Done...restore registers and get out of here. + */ +#ifdef CONFIG_403GCX + lwz r22, 12(r0) + lwz r21, 8(r0) + mtspr SPRN_PID, r22 + mtcr r21 + lwz r23, 4(r0) + lwz r22, 0(r0) +#else + mfspr r22, SPRG6 + mfspr r21, SPRG7 + mtspr SPRN_PID, r22 + mtcr r21 + mfspr r23, SPRG5 + mfspr r22, SPRG4 +#endif + mfspr r21, SPRG1 + mfspr r20, SPRG0 + PPC405_ERR77_SYNC + rfi /* Should sync shadow TLBs */ + +2: + /* The bailout. Restore registers to pre-exception conditions + * and call the heavyweights to help us out. + */ +#ifdef CONFIG_403GCX + lwz r22, 12(r0) + lwz r21, 8(r0) + mtspr SPRN_PID, r22 + mtcr r21 + lwz r23, 4(r0) + lwz r22, 0(r0) +#else + mfspr r22, SPRG6 + mfspr r21, SPRG7 + mtspr SPRN_PID, r22 + mtcr r21 + mfspr r23, SPRG5 + mfspr r22, SPRG4 +#endif + mfspr r21, SPRG1 + mfspr r20, SPRG0 + b InstructionAccess STND_EXCEPTION(0x1300, Trap_13, UnknownException) STND_EXCEPTION(0x1400, Trap_14, UnknownException) STND_EXCEPTION(0x1500, Trap_15, UnknownException) STND_EXCEPTION(0x1600, Trap_16, UnknownException) +#ifdef CONFIG_IBM405_ERR51 + /* 405GP errata 51 */ + START_EXCEPTION(0x1700, Trap_17) + b DTLBMiss +#else STND_EXCEPTION(0x1700, Trap_17, UnknownException) +#endif STND_EXCEPTION(0x1800, Trap_18, UnknownException) STND_EXCEPTION(0x1900, Trap_19, UnknownException) STND_EXCEPTION(0x1A00, Trap_1A, UnknownException) @@ -356,73 +681,217 @@ _GLOBAL(timer_interrupt_intercept) STND_EXCEPTION(0x1D00, Trap_1D, UnknownException) STND_EXCEPTION(0x1E00, Trap_1E, UnknownException) STND_EXCEPTION(0x1F00, Trap_1F, UnknownException) - -### 0x2000 - Debug Exception - - CRIT_EXCEPTION(0x2000, DebugTrap, UnknownException) -### -### Other PowerPC processors, namely those derived from the 6xx-series -### have vectors from 0x2100 through 0x2F00 defined, but marked as reserved. -### However, for the 4xx-series processors these are neither defined nor -### reserved. -### +/* 0x2000 - Debug Exception +*/ + START_EXCEPTION(0x2000, DebugTrap) + b check_single_step_in_exception +ret_to_debug_exception: + CRIT_EXCEPTION_PROLOG(0x2000) + addi r3,r1,STACK_FRAME_OVERHEAD + li r7,CRIT_EXC; + li r20,MSR_KERNEL + FINISH_EXCEPTION(DebugException) -### -### This code finishes saving the registers to the exception frame -### and jumps to the appropriate handler for the exception, turning -### on address translation. -### +/* Make sure the final interrupt handler has not spilled past the + * end of its allotted space. + */ + .=0x2100 +/* Check for a single step debug exception while in an exception + * handler before state has been saved. This is to catch the case + * where an instruction that we are trying to single step causes + * an exception (eg ITLB miss) and thus the first instruction of + * the exception handler generates a single step debug exception. + * + * If we get a debug trap on the first instruction of an exception handler, + * we reset the MSR_DE in the _exception handlers_ MSR (the debug trap is + * a critical exception, so we are using SPRN_SRR3 to manipulate the MSR). + * The exception handler was handling a non-critical interrupt, so it will + * save (and later restore) the MSR via SPRN_SRR1, which will still have + * the MSR_DE bit set. + */ +check_single_step_in_exception: + + /* This first instruction was already executed by the exception + * handler and must be the first instruction of every exception + * handler. + */ + mtspr SPRN_SPRG0,r20 /* Save some working registers... */ + mtspr SPRN_SPRG1,r21 + mfcr r20 /* ..and the cr because we change it */ + + mfspr r21,SPRN_SRR3 /* MSR at the time of fault */ + andi. r21,r21,MSR_PR + bne+ 2f /* trapped from problem state */ + + mfspr r21,SPRN_SRR2 /* Faulting instruction address */ + cmplwi r21,0x2100 + bgt+ 2f /* address above exception vectors */ + + lis r21,DBSR_IC@h /* Remove the trap status */ + mtspr SPRN_DBSR,r21 + + mfspr r21,SPRN_SRR3 + rlwinm r21,r21,0,23,21 /* clear MSR_DE */ + mtspr SPRN_SRR3, r21 /* restore MSR at rcfi without DE */ + + mtcrf 0xff,r20 /* restore registers */ + mfspr r21,SPRN_SPRG1 + mfspr r20,SPRN_SPRG0 + + sync + rfci /* return to the exception handler */ + +2: + mtcrf 0xff,r20 /* restore registers */ + mfspr r21,SPRN_SPRG1 + mfspr r20,SPRN_SPRG0 + b ret_to_debug_exception + +/* Other PowerPC processors, namely those derived from the 6xx-series + * have vectors from 0x2100 through 0x2F00 defined, but marked as reserved. + * However, for the 4xx-series processors these are neither defined nor + * reserved. + */ + + /* Damn, I came up one instruction too many to fit into the + * exception space :-). Both the instruction and data TLB + * miss get to this point to load the TLB. + * r20 - EA of fault + * r21 - TLB LO (info from Linux PTE) + * r22, r23 - avilable to use + * PID - loaded with proper value when we get here + * Upon exit, we reload everything and RFI. + * Actually, it will fit now, but oh well.....a common place + * to load the TLB. + */ +finish_tlb_load: + + /* Since it has a unified TLB, and we can take data faults on + * instruction pages by copying data, we have to check if the + * EPN is already in the TLB. + */ + tlbsx. r23, 0, r20 + beq 6f + + /* load the next available TLB index. + */ + lis r22, tlb_4xx_index@h + ori r22, r22, tlb_4xx_index@l + tophys(r22, r22) + lwz r23, 0(r22) + addi r23, r23, 1 +#ifdef CONFIG_PIN_TLB + cmpwi 0, r23, 61 /* reserve entries 62, 63 for kernel */ + ble 7f + li r23, 0 +7: +#else + andi. r23, r23, (PPC4XX_TLB_SIZE-1) +#endif + stw r23, 0(r22) + +6: + tlbwe r21, r23, TLB_DATA /* Load TLB LO */ + + /* Create EPN. This is the faulting address plus a static + * set of bits. These are size, valid, E, U0, and ensure + * bits 20 and 21 are zero. + */ + li r22, 0x00c0 + rlwimi r20, r22, 0, 20, 31 + tlbwe r20, r23, TLB_TAG /* Load TLB HI */ + + /* Done...restore registers and get out of here. + */ +#ifdef CONFIG_403GCX + lwz r22, 12(r0) + lwz r21, 8(r0) + mtspr SPRN_PID, r22 + mtcr r21 + lwz r23, 4(r0) + lwz r22, 0(r0) +#else + mfspr r22, SPRG6 + mfspr r21, SPRG7 + mtspr SPRN_PID, r22 + mtcr r21 + mfspr r23, SPRG5 + mfspr r22, SPRG4 +#endif + mfspr r21, SPRG1 + mfspr r20, SPRG0 + PPC405_ERR77_SYNC + rfi /* Should sync shadow TLBs */ + +/* This code finishes saving the registers to the exception frame + * and jumps to the appropriate handler for the exception, turning + * on address translation. + */ _GLOBAL(transfer_to_handler) - stw r22,_NIP(r21) # Save the faulting IP on the stack - stw r23,_MSR(r21) # Save the exception MSR on the stack - SAVE_4GPRS(8, r21) # Save r8 through r11 on the stack - SAVE_8GPRS(12, r21) # Save r12 through r19 on the stack - SAVE_8GPRS(24, r21) # Save r24 through r31 on the stack - andi. r23,r23,MSR_PR # Is this from user space? - mfspr r23,SPRN_SPRG3 # If from user, fix up THREAD.regs - beq 2f # No, it is from the kernel; branch. + stw r22,_NIP(r21) /* Save the faulting IP on the stack */ + stw r23,_MSR(r21) /* Save the exception MSR on stack */ + SAVE_4GPRS(8, r21) /* Save r8 through r11 on the stack */ + SAVE_8GPRS(12, r21) /* Save r12 through r19 on the stack */ + SAVE_8GPRS(24, r21) /* Save r24 through r31 on the stack */ + andi. r23,r23,MSR_PR /* Is this from user space? */ + mfspr r23,SPRN_SPRG3 /* If from user, fix up THREAD.regs */ + beq 2f /* No, it is from the kernel; branch. */ addi r24,r1,STACK_FRAME_OVERHEAD - stw r24,PT_REGS(r23) # -2: addi r2,r23,-THREAD # Set r2 to current thread + stw r24,PT_REGS(r23) +2: addi r2,r23,-THREAD /* Set r2 to current thread */ tovirt(r2,r2) mflr r23 - andi. r24,r23,0x3f00 # Get vector offset + andi. r24,r23,0x3f00 /* Get vector offset */ stw r24,TRAP(r21) + li r22,RESULT + /* No need to put an erratum #77 workaround here + because interrupts are currently disabled */ + stwcx. r22,r22,r21 /* Clear the reservation */ li r22,0 stw r22,RESULT(r21) - mtspr SPRN_SPRG2,r22 # r1 is now the kernel stack pointer - addi r24,r2,TASK_STRUCT_SIZE # Check for kernel stack overflow + mtspr SPRN_SPRG2,r22 /* r1 is now the kernel stack pointer */ + addi r24,r2,TASK_STRUCT_SIZE /* Check for kernel stack overflow */ cmplw cr0,r1,r2 cmplw cr1,r1,r24 crand cr1,cr1,cr4 - bgt- stack_ovf # If r2 < r1 < r2 + TASK_STRUCT_SIZE - lwz r24,0(r23) # Virtual address of the handler - lwz r23,4(r23) # Handler return pointer - cmpwi cr0,r7,STND_EXC # What type of exception is this? - bne 3f # It is a critical exception... - - ## Standard exception jump path - - mtspr SPRN_SRR0,r24 # Set up the instruction pointer - mtspr SPRN_SRR1,r20 # Set up the machine state register - mtlr r23 # Set up the return pointer + bgt- stack_ovf /* If r2 < r1 < r2 + TASK_STRUCT_SIZE */ + lwz r24,0(r23) /* Virtual address of the handler */ + lwz r23,4(r23) /* Handler return pointer */ + cmpwi cr0,r7,STND_EXC /* What type of exception is this? */ + bne 3f /* It is a critical exception... */ + + /* Standard exception jump path + */ + + /* We have to recover r7 from the register save stack. + * It was used to indicate standard/critical exception. In + * the case of a standard exception that is the system call + * trap, it may have originally contained one of the syscall + * parameters and we have to get it back now. + */ + lwz r7,GPR7(r21) + mtspr SPRN_SRR0,r24 /* Set up the instruction pointer */ + mtspr SPRN_SRR1,r20 /* Set up the machine state register */ + mtlr r23 /* Set up the return pointer */ SYNC - rfi # Enable the MMU, jump to the handler + /* We shouldn't need a 405 erratum #77 workaround here, because we're not + * actually returning to the interrupted instruction yet. */ + rfi - ## Critical exception jump path + /* Critical exception jump path + */ -3: mtspr SPRN_SRR2,r24 # Set up the instruction pointer - mtspr SPRN_SRR3,r20 # Set up the machine state register - mtlr r23 # Set up the return pointer +3: mtspr SPRN_SRR2,r24 /* Set up the instruction pointer */ + mtspr SPRN_SRR3,r20 /* Set up the machine state register */ + mtlr r23 /* Set up the return pointer */ SYNC - rfci # Enable the MMU, jump to the handler + rfci -### -### On kernel stack overlow, load up an initial stack pointer and call -### StackOverflow(regs), which should NOT return. -### +/* On kernel stack overlow, load up an initial stack pointer and call + * StackOverflow(regs), which should NOT return. + */ stack_ovf: addi r3,r1,STACK_FRAME_OVERHEAD @@ -432,143 +901,198 @@ stack_ovf: lis r24,StackOverflow@ha addi r24,r24,StackOverflow@l li r20,MSR_KERNEL - mtspr SPRN_SRR0,r24 # Set up the instruction pointer - mtspr SPRN_SRR1,r20 # Set up the machine state register + mtspr SPRN_SRR0,r24 + mtspr SPRN_SRR1,r20 SYNC - rfi # Enable the MMU, jump to StackOverflow - -### -### extern void giveup_altivec(struct task_struct *prev) -### -### The PowerPC 4xx family of processors do not have AltiVec capabilities, so -### this just returns. -### + rfi +/* extern void giveup_altivec(struct task_struct *prev) + * + * The PowerPC 4xx family of processors do not have AltiVec capabilities, so + * this just returns. + */ _GLOBAL(giveup_altivec) blr - -### -### extern void giveup_fpu(struct task_struct *prev) -### -### The PowerPC 4xx family of processors do not have an FPU, so this just -### returns. -### +/* extern void giveup_fpu(struct task_struct *prev) + * + * The PowerPC 4xx family of processors do not have an FPU, so this just + * returns. + */ _GLOBAL(giveup_fpu) blr -### -### extern void abort(void) -### -### At present, this routine just applies a system reset. -### - +/* extern void abort(void) + * + * At present, this routine just applies a system reset. + */ _GLOBAL(abort) - mfspr r13,SPRN_DBCR - oris r13,r13,DBCR_RST(DBCR_RST_SYSTEM)@h - mtspr SPRN_DBCR,r13 - + mfspr r13,SPRN_DBCR0 + oris r13,r13,DBCR_RST(DBCR_RST_SYSTEM)@h + mtspr SPRN_DBCR0,r13 -### -### This is where the main kernel code starts. -### +/* This is where the main kernel code starts. + */ start_here: - ## Establish a pointer to the current task - + + /* ptr to current */ lis r2,init_task_union@h ori r2,r2,init_task_union@l - - ## Clear out the BSS as per ANSI C requirements - - lis r7,_end@ha - addi r7,r7,_end@l - lis r8,__bss_start@ha - addi r8,r8,__bss_start@l - subf r7,r8,r7 - addi r7,r7,3 - srwi. r7,r7,2 - beq 2f - addi r8,r8,-4 - mtctr r7 - li r0,0 -3: stwu r0,4(r8) - bdnz 3b - ## Stack - -2: addi r1,r2,TASK_UNION_SIZE + /* ptr to phys current thread */ + tophys(r4,r2) + addi r4,r4,THREAD /* init task's THREAD */ + mtspr SPRG3,r4 + li r3,0 + mtspr SPRG2,r3 /* 0 => r1 has kernel sp */ + + /* stack */ + addi r1,r2,TASK_UNION_SIZE li r0,0 stwu r0,-STACK_FRAME_OVERHEAD(r1) - ## Determine what type of platform this is. + bl early_init /* We have to do this with MMU on */ +/* + * Decide what sort of machine this is and initialize the MMU. + */ mr r3,r31 mr r4,r30 mr r5,r29 mr r6,r28 mr r7,r27 - bl identify_machine - - ## Initialize the memory management unit. - + bl machine_init bl MMU_init - ## Go back to running unmapped so that we can change to our - ## exception vectors. - +/* Go back to running unmapped so we can load up new values + * and change to using our exception vectors. + * On the 4xx, all we have to do is invalidate the TLB to clear + * the old 16M byte TLB mappings. + */ lis r4,2f@h ori r4,r4,2f@l tophys(r4,r4) li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR) - mtspr SPRN_SRR0,r4 # Set up the instruction pointer - mtspr SPRN_SRR1,r3 # Set up the machine state register + mtspr SRR0,r4 + mtspr SRR1,r3 rfi - ## Load up the kernel context - -2: SYNC # Force all PTE updates to finish -# tlbia # Clear all TLB entries -# sync # Wait for tlbia to finish... - - ## Set up for using our exception vectors - - tophys(r4,r2) # Pointer to physical current thread - addi r4,r4,THREAD # The init task thread - mtspr SPRN_SPRG3,r4 # Save it for exceptions later - li r3,0 # - mtspr SPRN_SPRG2,r3 # 0 implies r1 has kernel stack pointer - - ## Really turn on the MMU and jump into the kernel - - lis r4,MSR_KERNEL@h - ori r4,r4,MSR_KERNEL@l - lis r3,start_kernel@h - ori r3,r3,start_kernel@l - mtspr SPRN_SRR0,r3 # Set up the instruction pointer - mtspr SPRN_SRR1,r4 # Set up the machine state register - rfi # Enable the MMU, jump to the kernel +/* Load up the kernel context */ +2: + SYNC /* Force all PTE updates to finish */ +#ifndef CONFIG_PIN_TLB + tlbia /* Clear all TLB entries */ + sync /* wait for tlbia/tlbie to finish */ +#endif + + /* set up the PTE pointers for the Abatron bdiGDB. + */ + lis r6, swapper_pg_dir@h + ori r6, r6, swapper_pg_dir@l + lis r5, abatron_pteptrs@h + ori r5, r5, abatron_pteptrs@l + stw r5, 0xf0(r0) /* Must match your Abatron config file */ + tophys(r5,r5) + stw r6, 0(r5) + +/* Now turn on the MMU for real! */ + li r4,MSR_KERNEL + lis r3,start_kernel@h + ori r3,r3,start_kernel@l + mtspr SRR0,r3 + mtspr SRR1,r4 + rfi /* enable MMU and jump to start_kernel */ + +/* Set up the initial MMU state so we can do the first level of + * kernel initialization. This maps the first 16 MBytes of memory 1:1 + * virtual to physical and more importantly sets the cache mode. + */ +initial_mmu: + tlbia /* Invalidate all TLB entries */ + sync + + /* We should still be executing code at physical address 0x0000xxxx + * at this point. However, start_here is at virtual address + * 0xC000xxxx. So, set up a TLB mapping to cover this once + * translation is enabled. + */ + + lis r3,KERNELBASE@h /* Load the kernel virtual address */ + ori r3,r3,KERNELBASE@l + tophys(r4,r3) /* Load the kernel physical address */ + + /* Load the kernel PID. + */ + li r0,0 + mtspr SPRN_PID,r0 + sync + + /* Configure and load two entries into TLB slots 62 and 63. + * In case we are pinning TLBs, these are reserved in by the + * other TLB functions. If not reserving, then it doesn't + * matter where they are loaded. + */ + clrrwi r4,r4,10 /* Mask off the real page number */ + ori r4,r4,(TLB_WR | TLB_EX) /* Set the write and execute bits */ + + clrrwi r3,r3,10 /* Mask off the effective page number */ + ori r3,r3,(TLB_VALID | TLB_PAGESZ(PAGESZ_16M)) + + li r0,62 /* TLB slot 62 */ + + tlbwe r4,r0,TLB_DATA /* Load the data portion of the entry */ + tlbwe r3,r0,TLB_TAG /* Load the tag portion of the entry */ + + addis r4, r4, 0x0100 /* Map next 16 M entries */ + addis r3, r3, 0x0100 + + li r0,63 /* TLB slot 63 */ + + tlbwe r4,r0,TLB_DATA + tlbwe r3,r0,TLB_TAG + isync + + /* Establish the exception vector base + */ + lis r4,KERNELBASE@h /* EVPR only uses the high 16-bits */ + tophys(r0,r4) /* Use the physical address */ + mtspr SPRN_EVPR,r0 + + blr + _GLOBAL(set_context) + +#ifdef CONFIG_BDI_SWITCH + /* Context switch the PTE pointer for the Abatron BDI2000. + * The PGDIR is the second parameter. + */ + lis r5, KERNELBASE@h + lwz r5, 0xf0(r5) + stw r4, 0x4(r5) +#endif mtspr SPRN_PID,r3 blr -### -### We put a few things here that have to be page-aligned. This stuff -### goes at the beginning of the data segment, which is page-aligned. -### - +/* We put a few things here that have to be page-aligned. This stuff + * goes at the beginning of the data segment, which is page-aligned. + */ .data _GLOBAL(sdata) _GLOBAL(empty_zero_page) .space 4096 _GLOBAL(swapper_pg_dir) - .space 4096 - -### -### This space gets a copy of optional info passed to us by the bootstrap -### which is used to pass parameters into the kernel like root=/dev/sda1, etc. -### + .space 4096 +/* This space gets a copy of optional info passed to us by the bootstrap + * which is used to pass parameters into the kernel like root=/dev/sda1, etc. + */ _GLOBAL(cmd_line) .space 512 + +/* Room for two PTE pointers, usually the kernel and current user pointers + * to their respective root page table. + */ +abatron_pteptrs: + .space 8 diff --git a/arch/ppc/kernel/head_8xx.S b/arch/ppc/kernel/head_8xx.S index 542a2bc32dc4..766a59507e29 100644 --- a/arch/ppc/kernel/head_8xx.S +++ b/arch/ppc/kernel/head_8xx.S @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.head_8xx.S 1.23 09/16/01 19:32:54 trini + * BK Id: %F% %I% %G% %U% %#% */ /* * arch/ppc/kernel/except_8xx.S @@ -24,14 +24,15 @@ * */ -#include "ppc_asm.h" +#include <linux/config.h> #include <asm/processor.h> #include <asm/page.h> -#include <linux/config.h> #include <asm/mmu.h> #include <asm/cache.h> #include <asm/pgtable.h> #include <asm/cputable.h> +#include <asm/ppc_asm.h> +#include "ppc_defs.h" .text .globl _stext @@ -334,7 +335,7 @@ InstructionTLBMiss: beq 2f /* If zero, don't try to find a pte */ /* We have a pte table, so load the MI_TWC with the attributes - * for this page, which has only bit 31 set. + * for this "segment." */ tophys(r21,r21) ori r21,r21,1 /* Set valid bit */ @@ -343,7 +344,7 @@ InstructionTLBMiss: stw r3, 12(r0) lwz r3, 12(r0) #endif - mtspr MI_TWC, r21 /* Set page attributes */ + mtspr MI_TWC, r21 /* Set segment attributes */ #ifdef CONFIG_8xx_CPU6 li r3, 0x3b80 stw r3, 12(r0) @@ -362,8 +363,6 @@ InstructionTLBMiss: * set. All other Linux PTE bits control the behavior * of the MMU. */ - li r21, 0x0600 - andc r20, r20, r21 /* Clear 21, 22 */ li r21, 0x00f0 rlwimi r20, r21, 0, 24, 28 /* Set 24-27, clear 28 */ @@ -456,8 +455,6 @@ DataStoreTLBMiss: * set. All other Linux PTE bits control the behavior * of the MMU. */ - li r21, 0x0600 - andc r20, r20, r21 /* Clear 21, 22 */ li r21, 0x00f0 rlwimi r20, r21, 0, 24, 28 /* Set 24-27, clear 28 */ @@ -521,6 +518,34 @@ DataTLBError: andis. r21, r20, 0x0200 /* If set, indicates store op */ beq 2f + /* The EA of a data TLB miss is automatically stored in the MD_EPN + * register. The EA of a data TLB error is automatically stored in + * the DAR, but not the MD_EPN register. We must copy the 20 most + * significant bits of the EA from the DAR to MD_EPN before we + * start walking the page tables. We also need to copy the CASID + * value from the M_CASID register. + * Addendum: The EA of a data TLB error is _supposed_ to be stored + * in DAR, but it seems that this doesn't happen in some cases, such + * as when the error is due to a dcbi instruction to a page with a + * TLB that doesn't have the changed bit set. In such cases, there + * does not appear to be any way to recover the EA of the error + * since it is neither in DAR nor MD_EPN. As a workaround, the + * _PAGE_HWWRITE bit is set for all kernel data pages when the PTEs + * are initialized in mapin_ram(). This will avoid the problem, + * assuming we only use the dcbi instruction on kernel addresses. + */ + mfspr r20, DAR + rlwinm r21, r20, 0, 0, 19 + ori r21, r21, MD_EVALID + mfspr r20, M_CASID + rlwimi r21, r20, 0, 28, 31 +#ifdef CONFIG_8xx_CPU6 + li r3, 0x3780 + stw r3, 12(r0) + lwz r3, 12(r0) +#endif + mtspr MD_EPN, r21 + mfspr r20, M_TWB /* Get level 1 table entry address */ /* If we are faulting a kernel address, we have to use the @@ -564,8 +589,6 @@ DataTLBError: * set. All other Linux PTE bits control the behavior * of the MMU. */ - li r21, 0x0600 - andc r20, r20, r21 /* Clear 21, 22 */ li r21, 0x00f0 rlwimi r20, r21, 0, 24, 28 /* Set 24-27, clear 28 */ @@ -769,16 +792,31 @@ start_here: * kernel initialization. This maps the first 8 MBytes of memory 1:1 * virtual to physical. Also, set the cache mode since that is defined * by TLB entries and perform any additional mapping (like of the IMMR). + * If configured to pin some TLBs, we pin the first 8 Mbytes of kernel, + * 24 Mbytes of data, and the 8M IMMR space. Anything not covered by + * these mappings is mapped by page tables. */ initial_mmu: tlbia /* Invalidate all TLB entries */ +#ifdef CONFIG_PIN_TLB + lis r8, MI_RSV4I@h + ori r8, r8, 0x1c00 +#else li r8, 0 - mtspr MI_CTR, r8 /* Set instruction control to zero */ - lis r8, MD_RESETVAL@h +#endif + mtspr MI_CTR, r8 /* Set instruction MMU control */ + +#ifdef CONFIG_PIN_TLB + lis r10, (MD_RSV4I | MD_RESETVAL)@h + ori r10, r10, 0x1c00 + mr r8, r10 +#else + lis r10, MD_RESETVAL@h +#endif #ifndef CONFIG_8xx_COPYBACK - oris r8, r8, MD_WTDEF@h + oris r10, r10, MD_WTDEF@h #endif - mtspr MD_CTR, r8 /* Set data TLB control */ + mtspr MD_CTR, r10 /* Set data TLB control */ /* Now map the lower 8 Meg into the TLBs. For this quick hack, * we can load the instruction and data TLB registers with the @@ -802,6 +840,10 @@ initial_mmu: /* Map another 8 MByte at the IMMR to get the processor * internal registers (among other things). */ +#ifdef CONFIG_PIN_TLB + addi r10, r10, 0x0100 + mtspr MD_CTR, r10 +#endif mfspr r9, 638 /* Get current IMMR */ andis. r9, r9, 0xff80 /* Get 8Mbyte boundary */ @@ -815,6 +857,30 @@ initial_mmu: ori r8, r8, MI_BOOTINIT|0x2 /* Inhibit cache -- Cort */ mtspr MD_RPN, r8 +#ifdef CONFIG_PIN_TLB + /* Map two more 8M kernel data pages. + */ + addi r10, r10, 0x0100 + mtspr MD_CTR, r10 + + lis r8, KERNELBASE@h /* Create vaddr for TLB */ + addis r8, r8, 0x0080 /* Add 8M */ + ori r8, r8, MI_EVALID /* Mark it valid */ + mtspr MD_EPN, r8 + li r9, MI_PS8MEG /* Set 8M byte page */ + ori r9, r9, MI_SVALID /* Make it valid */ + mtspr MD_TWC, r9 + li r11, MI_BOOTINIT /* Create RPN for address 0 */ + addis r11, r11, 0x0080 /* Add 8M */ + mtspr MD_RPN, r8 + + addis r8, r8, 0x0080 /* Add 8M */ + mtspr MD_EPN, r8 + mtspr MD_TWC, r9 + addis r11, r11, 0x0080 /* Add 8M */ + mtspr MD_RPN, r8 +#endif + /* Since the cache is enabled according to the information we * just loaded into the TLB, invalidate and enable the caches here. * We should probably check/set other modes....later. diff --git a/arch/ppc/kernel/i8259.c b/arch/ppc/kernel/i8259.c index 3f5bed25ea58..bc9d5d069523 100644 --- a/arch/ppc/kernel/i8259.c +++ b/arch/ppc/kernel/i8259.c @@ -1,13 +1,17 @@ /* - * BK Id: SCCS/s.i8259.c 1.7 05/17/01 18:14:21 cort + * BK Id: %F% %I% %G% %U% %#% */ #include <linux/stddef.h> #include <linux/init.h> +#include <linux/irq.h> +#include <linux/ioport.h> #include <linux/sched.h> #include <linux/signal.h> #include <asm/io.h> -#include "i8259.h" +#include <asm/i8259.h> + +static volatile char *pci_intack; /* RO, gives us the irq vector */ unsigned char cached_8259[2] = { 0xff, 0xff }; #define cached_A1 (cached_8259[0]) @@ -17,32 +21,56 @@ static spinlock_t i8259_lock = SPIN_LOCK_UNLOCKED; int i8259_pic_irq_offset; -int i8259_irq(int cpu) +/* Acknowledge the irq using the PCI host bridge's interrupt acknowledge + * feature. (Polling is somehow broken on some IBM and Motorola PReP boxes.) + */ +int i8259_irq(void) { int irq; - + spin_lock/*_irqsave*/(&i8259_lock/*, flags*/); - /* - * Perform an interrupt acknowledge cycle on controller 1 - */ - outb(0x0C, 0x20); - irq = inb(0x20) & 7; - if (irq == 2) - { - /* - * Interrupt is cascaded so perform interrupt - * acknowledge on controller 2 - */ - outb(0x0C, 0xA0); - irq = (inb(0xA0) & 7) + 8; - } - else if (irq==7) - { - /* - * This may be a spurious interrupt - * - * Read the interrupt status register. If the most - * significant bit is not set then there is no valid + + irq = *pci_intack & 0xff; + if (irq==7) { + /* + * This may be a spurious interrupt. + * + * Read the interrupt status register (ISR). If the most + * significant bit is not set then there is no valid + * interrupt. + */ + if(~inb(0x20)&0x80) { + irq = -1; + } + } + spin_unlock/*_irqrestore*/(&i8259_lock/*, flags*/); + return irq; +} + +/* Poke the 8259's directly using poll commands. */ +int i8259_poll(void) +{ + int irq; + + spin_lock/*_irqsave*/(&i8259_lock/*, flags*/); + /* + * Perform an interrupt acknowledge cycle on controller 1 + */ + outb(0x0C, 0x20); /* prepare for poll */ + irq = inb(0x20) & 7; + if (irq == 2) { + /* + * Interrupt is cascaded so perform interrupt + * acknowledge on controller 2 + */ + outb(0x0C, 0xA0); /* prepare for poll */ + irq = (inb(0xA0) & 7) + 8; + } else if (irq==7) { + /* + * This may be a spurious interrupt + * + * Read the interrupt status register. If the most + * significant bit is not set then there is no valid * interrupt */ outb(0x0b, 0x20); @@ -58,44 +86,44 @@ int i8259_irq(int cpu) static void i8259_mask_and_ack_irq(unsigned int irq_nr) { unsigned long flags; - + spin_lock_irqsave(&i8259_lock, flags); - if ( irq_nr >= i8259_pic_irq_offset ) - irq_nr -= i8259_pic_irq_offset; - - if (irq_nr > 7) { - cached_A1 |= 1 << (irq_nr-8); - inb(0xA1); /* DUMMY */ - outb(cached_A1,0xA1); - outb(0x20,0xA0); /* Non-specific EOI */ - outb(0x20,0x20); /* Non-specific EOI to cascade */ - } else { - cached_21 |= 1 << irq_nr; - inb(0x21); /* DUMMY */ - outb(cached_21,0x21); - outb(0x20,0x20); /* Non-specific EOI */ - } + if ( irq_nr >= i8259_pic_irq_offset ) + irq_nr -= i8259_pic_irq_offset; + + if (irq_nr > 7) { + cached_A1 |= 1 << (irq_nr-8); + inb(0xA1); /* DUMMY */ + outb(cached_A1,0xA1); + outb(0x20,0xA0); /* Non-specific EOI */ + outb(0x20,0x20); /* Non-specific EOI to cascade */ + } else { + cached_21 |= 1 << irq_nr; + inb(0x21); /* DUMMY */ + outb(cached_21,0x21); + outb(0x20,0x20); /* Non-specific EOI */ + } spin_unlock_irqrestore(&i8259_lock, flags); } static void i8259_set_irq_mask(int irq_nr) { - outb(cached_A1,0xA1); - outb(cached_21,0x21); + outb(cached_A1,0xA1); + outb(cached_21,0x21); } - + static void i8259_mask_irq(unsigned int irq_nr) { unsigned long flags; spin_lock_irqsave(&i8259_lock, flags); - if ( irq_nr >= i8259_pic_irq_offset ) - irq_nr -= i8259_pic_irq_offset; - if ( irq_nr < 8 ) - cached_21 |= 1 << irq_nr; - else - cached_A1 |= 1 << (irq_nr-8); - i8259_set_irq_mask(irq_nr); + if ( irq_nr >= i8259_pic_irq_offset ) + irq_nr -= i8259_pic_irq_offset; + if ( irq_nr < 8 ) + cached_21 |= 1 << irq_nr; + else + cached_A1 |= 1 << (irq_nr-8); + i8259_set_irq_mask(irq_nr); spin_unlock_irqrestore(&i8259_lock, flags); } @@ -104,13 +132,13 @@ static void i8259_unmask_irq(unsigned int irq_nr) unsigned long flags; spin_lock_irqsave(&i8259_lock, flags); - if ( irq_nr >= i8259_pic_irq_offset ) - irq_nr -= i8259_pic_irq_offset; - if ( irq_nr < 8 ) - cached_21 &= ~(1 << irq_nr); - else - cached_A1 &= ~(1 << (irq_nr-8)); - i8259_set_irq_mask(irq_nr); + if ( irq_nr >= i8259_pic_irq_offset ) + irq_nr -= i8259_pic_irq_offset; + if ( irq_nr < 8 ) + cached_21 &= ~(1 << irq_nr); + else + cached_A1 &= ~(1 << (irq_nr-8)); + i8259_set_irq_mask(irq_nr); spin_unlock_irqrestore(&i8259_lock, flags); } @@ -121,36 +149,62 @@ static void i8259_end_irq(unsigned int irq) } struct hw_interrupt_type i8259_pic = { - " i8259 ", - NULL, - NULL, - i8259_unmask_irq, - i8259_mask_irq, - i8259_mask_and_ack_irq, - i8259_end_irq, - NULL + " i8259 ", + NULL, + NULL, + i8259_unmask_irq, + i8259_mask_irq, + i8259_mask_and_ack_irq, + i8259_end_irq, + NULL }; -void __init i8259_init(void) +static struct resource pic1_iores = { + "8259 (master)", 0x20, 0x21, IORESOURCE_BUSY +}; + +static struct resource pic2_iores = { + "8259 (slave)", 0xa0, 0xa1, IORESOURCE_BUSY +}; + +static struct resource pic_edgectrl_iores = { + "8259 edge control", 0x4d0, 0x4d1, IORESOURCE_BUSY +}; + +void __init i8259_init(long intack_addr) { unsigned long flags; - + spin_lock_irqsave(&i8259_lock, flags); - /* init master interrupt controller */ - outb(0x11, 0x20); /* Start init sequence */ - outb(0x00, 0x21); /* Vector base */ - outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */ - outb(0x01, 0x21); /* Select 8086 mode */ - outb(0xFF, 0x21); /* Mask all */ - /* init slave interrupt controller */ - outb(0x11, 0xA0); /* Start init sequence */ - outb(0x08, 0xA1); /* Vector base */ - outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */ - outb(0x01, 0xA1); /* Select 8086 mode */ - outb(0xFF, 0xA1); /* Mask all */ - outb(cached_A1, 0xA1); - outb(cached_21, 0x21); + /* init master interrupt controller */ + outb(0x11, 0x20); /* Start init sequence */ + outb(0x00, 0x21); /* Vector base */ + outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */ + outb(0x01, 0x21); /* Select 8086 mode */ + + /* init slave interrupt controller */ + outb(0x11, 0xA0); /* Start init sequence */ + outb(0x08, 0xA1); /* Vector base */ + outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */ + outb(0x01, 0xA1); /* Select 8086 mode */ + + /* always read ISR */ + outb(0x0B, 0x20); + outb(0x0B, 0xA0); + + /* Mask all interrupts */ + outb(cached_A1, 0xA1); + outb(cached_21, 0x21); + spin_unlock_irqrestore(&i8259_lock, flags); - request_irq( i8259_pic_irq_offset + 2, no_action, SA_INTERRUPT, - "82c59 secondary cascade", NULL ); + + /* reserve our resources */ + request_irq( i8259_pic_irq_offset + 2, no_action, SA_INTERRUPT, + "82c59 secondary cascade", NULL ); + request_resource(&ioport_resource, &pic1_iores); + request_resource(&ioport_resource, &pic2_iores); + request_resource(&ioport_resource, &pic_edgectrl_iores); + + if (intack_addr) + pci_intack = ioremap(intack_addr, 1); } diff --git a/arch/ppc/kernel/i8259.h b/arch/ppc/kernel/i8259.h deleted file mode 100644 index c23eadfe3c95..000000000000 --- a/arch/ppc/kernel/i8259.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * BK Id: SCCS/s.i8259.h 1.5 05/17/01 18:14:21 cort - */ - -#ifndef _PPC_KERNEL_i8259_H -#define _PPC_KERNEL_i8259_H - -#include "local_irq.h" - -extern struct hw_interrupt_type i8259_pic; - -void i8259_init(void); -int i8259_irq(int); - -#endif /* _PPC_KERNEL_i8259_H */ diff --git a/arch/ppc/kernel/iSeries_asm.h b/arch/ppc/kernel/iSeries_asm.h new file mode 100644 index 000000000000..098a5980fa5a --- /dev/null +++ b/arch/ppc/kernel/iSeries_asm.h @@ -0,0 +1,62 @@ +/* + * BK Id: %F% %I% %G% %U% %#% + */ +/* + * arch/ppc/kernel/iSeries_asm.h + * + * Definitions used by various bits of low-level assembly code on iSeries. + * + * Copyright (C) 2001 IBM Corp. + * + * 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. + */ + +#define CHECKLPQUEUE(ra,rb,rc) \ + mfspr rb,SPRG1; /* Get Paca address */\ + lbz ra,PACALPPACA+LPPACAIPIINT(rb); /* Get IPI int flag */\ + cmpi 0,ra,0; /* IPI occurred in hypervisor ? */\ + bne 99f; /* If so, skip rest */\ + lwz ra,PACALPQUEUE(rb); /* Get LpQueue address */\ + cmpi 0,ra,0; /* Does LpQueue exist? */\ + beq 99f; /* If not skip rest */\ + lbz rb,LPQINUSEWORD(ra); /* Test for LpQueue recursion */\ + cmpi 0,rb,1; /* If we are about to recurse */\ + beq 99f; /* If so, skip rest */\ + lwz rb,LPQCUREVENTPTR(ra); /* Get current LpEvent */\ + lbz rb,LPEVENTFLAGS(rb); /* Get Valid bit */\ + lbz rc,LPQOVERFLOW(ra); /* Get LpQueue overflow */\ + andi. ra,rb,0x0080; /* Isolate Valid bit */\ + or. ra,ra,rc; /* 0 == no pending events */\ +99: + +#define CHECKDECR(ra,rb) \ + mfspr rb,SPRG1; /* Get Paca address */\ + lbz ra,PACALPPACA+LPPACADECRINT(rb); /* Get DECR int flag */\ + cmpi 0,ra,0; /* DECR occurred in hypervisor ? */\ + beq 99f; /* If not, skip rest */\ + xor ra,ra,ra; \ + stb ra,PACALPPACA+LPPACADECRINT(rb); /* Clear DECR int flag */\ +99: + +#define CHECKANYINT(ra,rb,rc) \ + mfspr rb,SPRG1; /* Get Paca address */\ + ld ra,PACALPPACA+LPPACAANYINT(rb); /* Get all interrupt flags */\ + /* Note use of ld, protected by soft/hard disabled */\ + cmpldi 0,ra,0; /* Any interrupt occurred while soft disabled? */\ + bne 99f; /* If so, skip rest */\ + lwz ra,PACALPQUEUE(rb); /* Get LpQueue address */\ + cmpi 0,ra,0; /* Does LpQueue exist? */\ + beq 99f; /* If not skip rest */\ + lwz rb,LPQINUSEWORD(ra); /* Test for LpQueue recursion */\ + cmpi 0,rb,1; /* If we are about to recurse */\ + beq 99f; /* If so, skip rest */\ + lwz rb,LPQCUREVENTPTR(ra); /* Get current LpEvent */\ + lbz rb,LPEVENTFLAGS(rb); /* Get Valid bit */\ + lbz rc,LPQOVERFLOW(ra); /* Get LpQueue overflow */\ + andi. ra,rb,0x0080; /* Isolate Valid bit */\ + or. ra,ra,rc; /* 0 == no pending events */\ +99: + diff --git a/arch/ppc/kernel/iSeries_head.S b/arch/ppc/kernel/iSeries_head.S new file mode 100644 index 000000000000..46765589e983 --- /dev/null +++ b/arch/ppc/kernel/iSeries_head.S @@ -0,0 +1,1512 @@ +/* + * arch/ppc/kernel/iSeries_head.S + * + * Adapted from arch/ppc/kernel/head.S + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP + * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu> + * Adapted for Power Macintosh by Paul Mackerras. + * Low-level exception handlers and MMU support + * rewritten by Paul Mackerras. + * Copyright (C) 1996 Paul Mackerras. + * Adapted for iSeries by Mike Corrigan + * Updated by Dave Boutcher + * + * This file contains the low-level support and setup for the + * iSeries LPAR platform. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include <linux/config.h> +#include <asm/processor.h> +#include <asm/page.h> +#include <asm/mmu.h> +#include <asm/pgtable.h> +#include <asm/ppc_asm.h> +#include "ppc_defs.h" +#include "iSeries_asm.h" + + + .text + .globl _stext +_stext: + +/* iSeries LPAR + * + * In an iSeries partition, the operating system has no direct access + * to the hashed page table. The iSeries hypervisor manages the + * hashed page table, and is directed by the operating system in the + * partition. The partition, Linux in this case, always runs with + * MSR.IR and MSR.DR equal to 1. The hypervisor establishes + * addressibility for the first 64 MB of memory at 0xC0000000 by + * building a hashed page table and setting segment register 12. + * + * The partition memory is not physically contiguous, nor necessarily + * addressable with a 32-bit address. The hypervisor provides functions + * which the kernel can use to discover the layout of memory. The + * iSeries LPAR specific code in the kernel will build a table that maps + * contiguous pseudo-real addresses starting at zero to the actual + * physical addresses owned by this partition. In 32-bit mode we will + * restrict ourselves to no more than 768 MB (or maybe 1 GB) + * + * When Linux interrupt handlers get control, the hypervisor has + * already saved SRR0 and SRR1 into a control block shared between + * the hypervisor and Linux. This is know as the ItLpPaca. The values + * in the actual SRR0 and SRR1 are not valid. This requires a change in + * the way the SPRG registers are used. The definitions are: + * + * Register old definition new definition + * + * SPRG0 temp - used to save gpr reserved for hypervisor + * SPRG1 temp - used to save gpr addr of Paca + * SPRG2 0 or kernel stack frame temp - used to save gpr + * SPRG3 Linux thread Linux thread + * + * The Paca contains the address of the ItLpPaca. The Paca is known only + * to Linux, while the ItLpPaca is shared between Linux and the + * hypervisor. + * + * The value that used to be in SPRG2 will now be saved in the Paca, + * as will at least one GPR. + */ + + .globl __start +__start: + b start_here + + + . = 0x020 + + /* iSeries LPAR hypervisor expects a 64-bit offset of + the hvReleaseData structure (see HvReleaseData.h) + at offset 0x20. This is the base for all common + control blocks between the hypervisor and the kernel + */ + + .long 0 + .long hvReleaseData-KERNELBASE + .long 0 + .long msChunks-KERNELBASE + .long 0 + .long pidhash-KERNELBASE + /* Pointer to start of embedded System.map */ + .long 0 + .globl embedded_sysmap_start +embedded_sysmap_start: + .long 0 + /* Pointer to end of embedded System.map */ + .long 0 + .globl embedded_sysmap_end +embedded_sysmap_end: + .long 0 + + + . = 0x060 + + .globl ste_fault_count +ste_fault_count: + .long 0 + .globl set_context_count +set_context_count: + .long 0 + .globl yield_count +yield_count: + .long 0 + .globl update_times_count +update_times_count: + .long 0 + .globl update_wall_jiffies_count +update_wall_jiffies_count: + .long 0 + .globl update_wall_jiffies_ticks +update_wall_jiffies_ticks: + .long 0 + + +/* + * We assume SPRG1 has the address of the Paca and SPRG3 + * has the address of the task's thread_struct. + * SPRG2 is used as a scratch register (as required by the + * hypervisor). SPRG0 is reserved for the hypervisor. + * + * The ItLpPaca has the values of SRR0 and SRR1 that the + * hypervisor saved at the point of the actual interrupt. + * + * The Paca contains the value that the non-LPAR PPC Linux Kernel + * keeps in SPRG2, which is either zero (if the interrupt + * occurred in the kernel) or the address of the available + * space on the kernel stack (if the interrupt occurred + * in user code). +*/ +#define EXCEPTION_PROLOG_1 \ + mtspr SPRG2,r20; /* use SPRG2 as scratch reg */\ + mfspr r20,SPRG1; /* get Paca */\ + /* must do std not stw because soft disable protects \ + * 64-bit register use (in HvCall, maybe others) \ + */\ + std r21,PACAR21(r20); /* Save GPR21 in Paca */\ + std r22,PACAR22(r20); /* Save GPR22 in Paca */\ + mfcr r22 /* Get CR */ + +#define EXCEPTION_PROLOG_2 \ + lwz r21,PACAKSAVE(r20); /* exception stack to use */\ + cmpwi 0,r21,0; /* user mode or kernel */\ + bne 1f; /* 0 -> r1, else use PACAKSAVE */\ + subi r21,r1,INT_FRAME_SIZE; /* alloc exc. frame */\ +1: stw r1,GPR1(r21); \ + mr r1,r21; \ + stw r22,_CCR(r1); /* save CR in stackframe */ \ + mflr r22; \ + stw r22,_LINK(r1); /* Save LR in stackframe */ \ + bl save_regs; /* now save everything else */ \ + ld r22,PACALPPACA+LPPACASRR0(r20); /* Get SRR0 from ItLpPaca */\ + ld r23,PACALPPACA+LPPACASRR1(r20) /* Get SRR1 from ItLpPaca */ + +#define EXCEPTION_PROLOG_EXIT \ + mtcrf 0xff,r22; \ + ld r22,PACALPPACA+LPPACASRR0(r20); \ + ld r21,PACALPPACA+LPPACASRR1(r20); \ + mtspr SRR0,r22; \ + mtspr SRR1,r21; \ + ld r22,PACAR22(r20); \ + ld r21,PACAR21(r20); \ + mfspr r20,SPRG2; \ + RFI + +#define EXCEPTION_PROLOG \ + EXCEPTION_PROLOG_1; \ + EXCEPTION_PROLOG_2 + + +/* + * Note: code which follows this uses cr0.eq (set if from kernel), + * r21, r22 (SRR0), and r23 (SRR1). + */ + +/* + * Exception vectors. + */ +#define STD_EXCEPTION(n, label, hdlr) \ + . = n; \ +label: \ + EXCEPTION_PROLOG; \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + li r20,0; /* soft disabled */\ + bl transfer_to_handler; \ + .long hdlr; \ + .long ret_from_except + +/* System reset */ + . = 0x100 +SystemReset: + mfspr r3,SPRG3 /* Get Paca address */ + mtspr SPRG1,r3 /* Set Linux SPRG1 -> Paca */ + lhz r24,PACAPACAINDEX(r3) /* Get processor # */ + cmpi 0,r24,0 /* Are we processor 0? */ + beq start_here /* Start up the first processor */ + mfspr r4,CTRLF + li r5,RUNLATCH + andc r4,r4,r5 /* Turn off the run light */ + mtspr CTRLT,r4 +1: + HMT_LOW +#ifdef CONFIG_SMP + lbz r23,PACAPROCSTART(r3) /* Test if this processor + * should start */ + cmpi 0,r23,0 + bne secondary_start +secondary_smp_loop: + /* Let the Hypervisor know we are alive */ + /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ + lis r3,0x8002 + rldicr r0,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */ + rldicl r3,r3,0,48 /* r3 = r3 & 0x000000000000ffff */ + or r3,r3,r0 /* r3 = r3 | r0 */ +#else /* CONFIG_SMP */ + /* Yield the processor. This is required for non-SMP kernels + which are running on multi-threaded machines. */ + lis r3,0x8000 + rldicr r3,r3,32,15 /* r3 = (r3 << 32) & 0xffff000000000000 */ + addi r3,r3,18 /* r3 = 0x8000000000000012 which is "yield" */ + li r4,0 /* "yield timed" */ + li r5,-1 /* "yield forever" */ +#endif /* CONFIG_SMP */ + li r0,-1 /* r0=-1 indicates a Hypervisor call */ + sc /* Invoke the hypervisor via a system call */ + mfspr r3,SPRG1 /* Put r3 back */ + b 1b /* If SMP not configured, secondaries + * loop forever */ + +/* Machine check */ + STD_EXCEPTION(0x200, MachineCheck, MachineCheckException) + +/* Data access exception. */ + . = 0x300 +DataAccess: + EXCEPTION_PROLOG + mfspr r4,DAR + stw r4,_DAR(r1) + mfspr r5,DSISR + stw r5,_DSISR(r1) + + andis. r0,r5,0x0020 /* Is this a segment fault? */ + bne ste_fault /* Yes - go reload segment regs */ + + /* This should and with 0xd7ff */ + andis. r0,r5,0xa470 /* Can we handle as little fault? */ + bne 1f /* */ + + rlwinm r3,r5,32-15,21,21 /* DSISR_STORE -> _PAGE_RW */ + + /* + * r3 contains the required access permissions + * r4 contains the faulting address + */ + + stw r22,_NIP(r1) /* Help with debug if dsi loop */ + bl hash_page /* Try to handle as hpte fault */ + lwz r4,_DAR(r1) /* Get original DAR */ + lwz r5,_DSISR(r1) /* and original DSISR */ + +1: addi r3,r1,STACK_FRAME_OVERHEAD + lwz r20,_SOFTE(r1) + bl transfer_to_handler + .long do_page_fault + .long ret_from_except + + +/* Instruction access exception. */ + . = 0x400 +InstructionAccess: + EXCEPTION_PROLOG + mr r4,r22 + mr r5,r23 + + andis. r0,r23,0x0020 /* Is this a segment fault? */ + bne ste_fault /* Yes - go reload segment regs */ + + andis. r0,r23,0x4000 /* no pte found? */ + beq 1f /* if so, try to put a PTE */ + + li r3,0 + bl hash_page /* Try to handle as hpte fault */ + mr r4,r22 + mr r5,r23 + +1: addi r3,r1,STACK_FRAME_OVERHEAD + lwz r20,_SOFTE(r1) + bl transfer_to_handler + .long do_page_fault + .long ret_from_except + +/* External interrupt */ + . = 0x500; +HardwareInterrupt: + EXCEPTION_PROLOG_1 + lbz r21,PACAPROCENABLED(r20) + cmpi 0,r21,0 + bne 1f + EXCEPTION_PROLOG_EXIT +1: EXCEPTION_PROLOG_2 +do_pending_int: + addi r3,r1,STACK_FRAME_OVERHEAD + li r4,0 + li r20,0 /* Soft disabled */ + bl transfer_to_handler + .globl do_IRQ_intercept +do_IRQ_intercept: + .long do_IRQ; + .long ret_from_intercept + +/* Alignment exception */ + . = 0x600 +Alignment: + EXCEPTION_PROLOG + mfspr r4,DAR + stw r4,_DAR(r1) + mfspr r5,DSISR + stw r5,_DSISR(r1) + addi r3,r1,STACK_FRAME_OVERHEAD + lbz r20,PACAPROCENABLED(r20) /* preserve soft en/disabled */ + bl transfer_to_handler + .long AlignmentException + .long ret_from_except + +/* Program check exception */ + . = 0x700 +ProgramCheck: + EXCEPTION_PROLOG + addi r3,r1,STACK_FRAME_OVERHEAD + lbz r20,PACAPROCENABLED(r20) /* preserve soft en/disabled */ + bl transfer_to_handler + .long ProgramCheckException + .long ret_from_except + +/* Floating-point unavailable */ + . = 0x800 +FPUnavailable: + EXCEPTION_PROLOG + lwz r3,PACAKSAVE(r20) + cmpwi 0,r3,0 + beq 1f + b load_up_fpu +1: + li r20,0 /* soft disabled */ + bl transfer_to_handler /* if from kernel, take a trap */ + .long KernelFP + .long ret_from_except + + . = 0x900 +Decrementer: + EXCEPTION_PROLOG_1 + lbz r21,PACAPROCENABLED(r20) + cmpi 0,r21,0 + bne 1f + + li r21,1 + stb r21,PACALPPACA+LPPACADECRINT(r20) + lwz r21,PACADEFAULTDECR(r20) + mtspr DEC,r21 + EXCEPTION_PROLOG_EXIT +1: EXCEPTION_PROLOG_2 + addi r3,r1,STACK_FRAME_OVERHEAD + li r20,0 /* Soft disabled */ + bl transfer_to_handler + .globl timer_interrupt_intercept +timer_interrupt_intercept: + .long timer_interrupt + .long ret_from_intercept + + STD_EXCEPTION(0xa00, Trap_0a, UnknownException) + STD_EXCEPTION(0xb00, Trap_0b, UnknownException) + +/* System call */ + . = 0xc00 +SystemCall: + EXCEPTION_PROLOG + /* Store r3 to the kernel stack */ + stw r3,ORIG_GPR3(r1) + lbz r20,PACAPROCENABLED(r20) /* preserve soft en/disabled */ + bl transfer_to_handler + .long DoSyscall + .long ret_from_except + +/* Single step - not used on 601 */ + STD_EXCEPTION(0xd00, SingleStep, SingleStepException) +/* + STD_EXCEPTION(0xe00, Trap_0e, UnknownException) + STD_EXCEPTION(0xf00, Trap_0f, UnknownException) +*/ + STD_EXCEPTION(0x1300, Trap_13, InstructionBreakpoint) +/* + STD_EXCEPTION(0x1400, SMI, SMIException) + STD_EXCEPTION(0x1500, Trap_15, UnknownException) + STD_EXCEPTION(0x1600, Trap_16, UnknownException) + STD_EXCEPTION(0x1700, Trap_17, TAUException) + STD_EXCEPTION(0x1800, Trap_18, UnknownException) + STD_EXCEPTION(0x1900, Trap_19, UnknownException) + STD_EXCEPTION(0x1a00, Trap_1a, UnknownException) + STD_EXCEPTION(0x1b00, Trap_1b, UnknownException) + STD_EXCEPTION(0x1c00, Trap_1c, UnknownException) + STD_EXCEPTION(0x1d00, Trap_1d, UnknownException) + STD_EXCEPTION(0x1e00, Trap_1e, UnknownException) + STD_EXCEPTION(0x1f00, Trap_1f, UnknownException) + STD_EXCEPTION(0x2000, RunMode, RunModeException) + STD_EXCEPTION(0x2100, Trap_21, UnknownException) + STD_EXCEPTION(0x2200, Trap_22, UnknownException) + STD_EXCEPTION(0x2300, Trap_23, UnknownException) + STD_EXCEPTION(0x2400, Trap_24, UnknownException) + STD_EXCEPTION(0x2500, Trap_25, UnknownException) + STD_EXCEPTION(0x2600, Trap_26, UnknownException) + STD_EXCEPTION(0x2700, Trap_27, UnknownException) + STD_EXCEPTION(0x2800, Trap_28, UnknownException) + STD_EXCEPTION(0x2900, Trap_29, UnknownException) + STD_EXCEPTION(0x2a00, Trap_2a, UnknownException) + STD_EXCEPTION(0x2b00, Trap_2b, UnknownException) + STD_EXCEPTION(0x2c00, Trap_2c, UnknownException) + STD_EXCEPTION(0x2d00, Trap_2d, UnknownException) + STD_EXCEPTION(0x2e00, Trap_2e, UnknownException) + STD_EXCEPTION(0x2f00, Trap_2f, UnknownException) +*/ + . = 0x3000 + + /* This code saves: CTR, XER, DAR, DSISR, SRR0, SRR1, */ + /* r0, r2-r13, r20-r24 */ + /* It uses R22 as a scratch register */ +save_regs: + ld r22,PACAR21(r20) /* Get GPR21 from Paca */ + stw r22,GPR21(r1) /* Save GPR21 in stackframe */ + ld r22,PACAR22(r20) /* Get GPR22 from Paca */ + stw r22,GPR22(r1) /* Save GPR22 in stackframe */ + stw r23,GPR23(r1) /* Save GPR23 in stackframe */ + stw r24,GPR24(r1) /* Save GPR24 in stackframe */ + mfspr r22,SPRG2 /* Get GPR20 from SPRG2 */ + stw r22,GPR20(r1) /* Save GPR20 in stackframe */ + mfctr r22 + stw r22,_CTR(r1) + mfspr r22,XER + stw r22,_XER(r1) + lbz r22,PACAPROCENABLED(r20)/* Get soft enabled/disabled */ + stw r22,_SOFTE(r1) + stw r0,GPR0(r1) + SAVE_8GPRS(2, r1) + SAVE_4GPRS(10, r1) + blr + +ste_fault: + bl set_kernel_segregs + + mfspr r3,SPRG1 + li r4,0 + stb r4,PACAPROCENABLED(r3) /* Soft disable prevents going to */ + /* do_pending_int on recursive fault */ + + lis r3,ste_fault_count@ha + lwz r4,ste_fault_count@l(r3) + addi r4,r4,1 + stw r4,ste_fault_count@l(r3) + + mfspr r3,SPRG3 /* get thread */ + addi r3,r3,-THREAD /* get 'current' */ + lwz r3,MM(r3) /* get mm */ + cmpi 0,r3,0 /* if no mm */ + beq 1f /* then use context 0 (kernel) */ + lwz r3,CONTEXT(r3) /* get context */ +1: + /* set_context kills r0, r3, r4 and CTR */ + bl set_context + + lwz r3,_SOFTE(r1) + cmpi 0,r3,0 + beq 5f /* skip checks if restoring disabled */ + + CHECKANYINT(r4,r5,r6) /* if pending interrupts, process them */ + bne- do_pending_int +5: + mfspr r4,SPRG1 + stb r3,PACAPROCENABLED(r4) /* Restore enabled/disabled */ + + b fault_exit + +/* + * This code finishes saving the registers to the exception frame + * and jumps to the appropriate handler for the exception, turning + * on address translation. + * + * At this point r0-r13, r20-r24, CCR, CTR, LINK, XER, DAR and DSISR + * are saved on a stack. SRR0 is in r22, SRR1 is in r23 + * r1 points to the stackframe, r1 points to the kernel stackframe + * We no longer have any dependency on data saved in the PACA, SRR0, SRR1 + * DAR or DSISR. We now copy the registers to the kernel stack (which + * might cause little faults). Any little fault will be handled without + * saving state. Thus when the little fault is completed, it will rfi + * back to the original faulting instruction. + */ + .globl transfer_to_handler +transfer_to_handler: + + mfspr r6,SPRG1 + li r7,0 + stw r7,PACAKSAVE(r6) /* Force new frame for recursive fault */ + + /* Restore the regs used above -- parameters to syscall */ + lwz r6,GPR6(r1) + lwz r7,GPR7(r1) + + stw r22,_NIP(r1) + stw r23,_MSR(r1) + SAVE_4GPRS(14, r1) + SAVE_2GPRS(18, r1) + SAVE_4GPRS(25, r1) + SAVE_2GPRS(29, r1) + SAVE_GPR(31, r1) + + andi. r23,r23,MSR_PR + mfspr r23,SPRG3 /* if from user, fix up THREAD.regs */ + beq 2f + addi r24,r1,STACK_FRAME_OVERHEAD + stw r24,PT_REGS(r23) +2: addi r2,r23,-THREAD /* set r2 to current */ + li r22,RESULT + stwcx. r22,r22,r1 /* to clear the reservation */ + li r22,0 + stw r22,RESULT(r1) + mfspr r23,SPRG1 /* Get Paca address */ + stb r20,PACAPROCENABLED(r23) /* soft enable or disabled */ + mflr r23 + andi. r24,r23,0x3f00 /* get vector offset */ + stw r24,TRAP(r1) + addi r24,r2,TASK_STRUCT_SIZE /* check for kernel stack overflow */ + cmplw 0,r1,r2 + cmplw 1,r1,r24 + crand 1,1,4 + bgt- stack_ovf /* if r2 < r1 < r2+TASK_STRUCT_SIZE */ + lwz r24,0(r23) /* virtual address of handler */ + lwz r23,4(r23) /* where to go when done */ + li r20,MSR_KERNEL + ori r20,r20,MSR_EE /* Always hard enabled */ + FIX_SRR1(r20,r22) + mtspr SRR0,r24 + mtspr SRR1,r20 + mtlr r23 + RFI /* jump to handler, enable MMU */ + +/* + * On kernel stack overflow, load up an initial stack pointer + * and call StackOverflow(regs), which should not return. + */ +stack_ovf: + addi r3,r1,STACK_FRAME_OVERHEAD + lis r1,init_task_union@ha + addi r1,r1,init_task_union@l + addi r1,r1,TASK_UNION_SIZE-STACK_FRAME_OVERHEAD + mfspr r24,SPRG1 + li r20,0 + stb r20,PACAPROCENABLED(r24) /* soft disable */ + lis r24,StackOverflow@ha + addi r24,r24,StackOverflow@l + li r20,MSR_KERNEL + ori r20,r20,MSR_EE /* Always hard enabled */ + FIX_SRR1(r20,r22) + mtspr SRR0,r24 + mtspr SRR1,r20 + RFI + +/* + * 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 + * Assume r20 points to PACA on entry + */ +load_up_fpu: + mfmsr r5 + ori r5,r5,MSR_FP + SYNC + MTMSRD(r5) /* enable use of fpu now */ + isync +/* + * For SMP, we don't do lazy FPU switching because it just gets too + * horrendously complex, especially when a task switches from one CPU + * to another. Instead we call giveup_fpu in switch_to. + */ +#ifndef CONFIG_SMP + lis r3,last_task_used_math@ha + lwz r4,last_task_used_math@l(r3) + cmpi 0,r4,0 + beq 1f + addi r4,r4,THREAD /* want last_task_used_math->thread */ + SAVE_32FPRS(0, r4) + mffs fr0 + stfd fr0,THREAD_FPSCR-4(r4) + lwz r5,PT_REGS(r4) + lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) + 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: +#endif /* CONFIG_SMP */ + /* enable use of FP after return */ + ori r23,r23,MSR_FP|MSR_FE0|MSR_FE1 + mfspr r5,SPRG3 /* current task's THREAD (phys) */ + lfd fr0,THREAD_FPSCR-4(r5) + mtfsf 0xff,fr0 + REST_32FPRS(0, r5) +#ifndef CONFIG_SMP + subi r4,r5,THREAD + stw r4,last_task_used_math@l(r3) +#endif /* CONFIG_SMP */ + /* restore registers and return */ + lwz r3,_CCR(r21) + lwz r4,_LINK(r21) + mtcrf 0xff,r3 + mtlr r4 + REST_GPR(1, r21) + REST_4GPRS(3, r21) + /* we haven't used ctr or xer */ + mtspr SRR1,r23 + mtspr SRR0,r22 + + REST_GPR(20, r21) + REST_2GPRS(22, r21) + lwz r21,GPR21(r21) + SYNC + RFI + +/* + * FP unavailable trap from kernel - print a message, but let + * the task use FP in the kernel until it returns to user mode. + */ +KernelFP: + lwz r3,_MSR(r1) + ori r3,r3,MSR_FP + stw r3,_MSR(r1) /* enable use of FP after return */ + lis r3,86f@h + ori r3,r3,86f@l + mr r4,r2 /* current */ + lwz r5,_NIP(r1) + bl printk + b ret_from_except +86: .string "floating point used in kernel (task=%p, pc=%x)\n" + .align 4 + +/* + * giveup_fpu(tsk) + * Disable FP for the task given as the argument, + * and save the floating-point registers in its thread_struct. + * Enables the FPU for use in the kernel on return. + */ + .globl giveup_fpu +giveup_fpu: + mfmsr r5 + ori r5,r5,MSR_FP + mtmsr r5 /* enable use of fpu now */ + cmpi 0,r3,0 + beqlr- /* if no previous owner, done */ + addi r3,r3,THREAD /* want THREAD of task */ + lwz r5,PT_REGS(r3) + cmpi 0,r5,0 + SAVE_32FPRS(0, r3) + mffs fr0 + stfd fr0,THREAD_FPSCR-4(r3) + beq 1f + lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) + li r3,MSR_FP|MSR_FE0|MSR_FE1 + andc r4,r4,r3 /* disable FP for previous task */ + stw r4,_MSR-STACK_FRAME_OVERHEAD(r5) +1: +#ifndef CONFIG_SMP + li r5,0 + lis r4,last_task_used_math@ha + stw r5,last_task_used_math@l(r4) +#endif /* CONFIG_SMP */ + blr + +#ifdef CONFIG_SMP +secondary_start: + lis r3,0, + mr r4,r24 + bl identify_cpu + bl call_setup_cpu /* Call setup_cpu for this CPU */ + + /* get current */ + HMT_MEDIUM /* Set thread priority to MEDIUM */ + lis r2,current_set@h + ori r2,r2,current_set@l + slwi r24,r24,2 /* get current_set[cpu#] */ + lwzx r2,r2,r24 + + /* stack */ + addi r1,r2,TASK_UNION_SIZE-STACK_FRAME_OVERHEAD + li r0,0 + stw r0,0(r1) + + /* load up the MMU */ + bl load_up_mmu + + /* ptr to phys current thread */ + addi r4,r2,THREAD /* phys address of our thread_struct */ + rlwinm r4,r4,0,0,31 + mtspr SPRG3,r4 + + /* Set up address of Paca in current thread */ + lis r23,xPaca@ha + addi r23,r23,xPaca@l + /* r24 has CPU # * 4 at this point. The Paca is 2048 bytes + long so multiply r24 by 512 to index into the array of Pacas */ + slwi r24,r24,9 + add r23,r23,r24 + rlwinm r23,r23,0,0,31 + mtspr SPRG1,r23 + + li r3,0 + stw r3,PACAKSAVE(r23) /* 0 => r1 has kernel sp */ + + stb r3,PACAPROCENABLED(r23) /* Soft disabled */ + + /* enable MMU and jump to start_secondary */ + + li r4,MSR_KERNEL + ori r4,r4,MSR_EE /* Hard enabled */ + lis r3,start_secondary@h + ori r3,r3,start_secondary@l + mtspr SRR0,r3 + FIX_SRR1(r4,r3) + mtspr SRR1,r4 + RFI +#endif /* CONFIG_SMP */ + +/* + * Load stuff into the MMU. Intended to be called with + * IR=0 and DR=0. + */ +load_up_mmu: + 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,0x111 /* increment VSID */ + addis r4,r4,0x1000 /* address of next segment */ + bdnz 3b + blr + +/* + * This is where the main kernel code starts. + */ +start_here: + + /* ptr to current */ + + lis r2,init_task_union@h + ori r2,r2,init_task_union@l + + /* Set up for using our exception vectors */ + + addi r4,r2,THREAD /* init task's THREAD */ + rlwinm r4,r4,0,0,31 + mtspr SPRG3,r4 + + /* Get address of Paca for processor 0 */ + lis r11,xPaca@ha + addi r11,r11,xPaca@l + rlwinm r11,r11,0,0,31 + mtspr SPRG1,r11 + + li r3,0 + stw r3,PACAKSAVE(r11) /* 0 => r1 has kernel sp */ + + stb r3,PACAPROCENABLED(r11) /* Soft disabled */ + + addi r1,r2,TASK_UNION_SIZE + li r0,0 + stwu r0,-STACK_FRAME_OVERHEAD(r1) + + /* fix klimit for system map */ + lis r6,embedded_sysmap_end@ha + lwz r7,embedded_sysmap_end@l(r6) + + cmpi 0,r7,0 + beq 5f + + lis r6, KERNELBASE@h + add r7,r7,r6 + addi r7,r7,4095 + li r6,0x0FFF + andc r7,r7,r6 + + lis r6,klimit@ha + stw r7,klimit@l(r6) +5: + +/* + * Decide what sort of machine this is and initialize the MMU. + */ + bl early_init /* We have to do this with MMU on */ + + mr r3,r31 + mr r4,r30 + mr r5,r29 + mr r6,r28 + mr r7,r27 + li r6,0 /* No cmdline parameters */ + bl platform_init + bl MMU_init + + bl load_up_mmu + + li r4,MSR_KERNEL + ori r4,r4,MSR_EE /* Hard enabled */ + FIX_SRR1(r4,r5) + lis r3,start_kernel@h + ori r3,r3,start_kernel@l + mtspr SRR0,r3 + mtspr SRR1,r4 + RFI /* ensure correct MSR and jump to + start_kernel */ +hash_page: + mflr r21 /* Save LR in r21 */ + + /* + * We hard enable here (but first soft disable) so that the hash_page + * code can spin on the hash_table_lock without problem on a shared + * processor + */ + li r0,0 + stb r0,PACAPROCENABLED(r20) /* Soft disable */ + + mfmsr r0 + ori r0,r0,MSR_EE + mtmsr r0 /* Hard enable */ + + bl create_hpte /* add the hash table entry */ + /* + * Now go back to hard disabled + */ + mfmsr r0 + li r4,0 + ori r4,r4,MSR_EE + andc r0,r0,r4 + mtmsr r0 /* Hard disable */ + + lwz r0,_SOFTE(r1) + mtlr r21 /* restore LR */ + mr r21,r1 /* restore r21 */ + + cmpi 0,r0,0 /* See if we will soft enable in */ + /* fault_exit */ + beq 5f /* if not, skip checks */ + + CHECKANYINT(r4,r5,r6) /* if pending interrupts, process them */ + bne- do_pending_int + +5: stb r0,PACAPROCENABLED(r20) /* Restore soft enable/disable */ + + cmpi 0,r3,0 /* check return code form create_hpte */ + bnelr + +/* + * htab_reloads counts the number of times we have to fault an + * HPTE into the hash table. This should only happen after a + * fork (because fork does a flush_tlb_mm) or a vmalloc or ioremap. + * Where a page is faulted into a process's address space, + * update_mmu_cache gets called to put the HPTE into the hash table + * and those are counted as preloads rather than reloads. + */ + lis r2,htab_reloads@ha + lwz r3,htab_reloads@l(r2) + addi r3,r3,1 + stw r3,htab_reloads@l(r2) + +fault_exit: + + lwz r3,_CCR(r1) + lwz r4,_LINK(r1) + lwz r5,_CTR(r1) + lwz r6,_XER(r1) + + mtcrf 0xff,r3 + mtlr r4 + mtctr r5 + mtspr XER,r6 + + lwz r0,GPR0(r1) + REST_8GPRS(2, r1) + REST_4GPRS(10, r1) + FIX_SRR1(r23,r20) + mtspr SRR1,r23 + mtspr SRR0,r22 + REST_4GPRS(20, r1) + + lwz r1,GPR1(r1) + RFI + +/* + * Set up the segment registers for a new context. + * context in r3 + */ +_GLOBAL(set_context) + mulli r3,r3,897 /* multiply context by skew factor */ + rlwinm r3,r3,4,8,27 /* VSID = (context & 0xfffff) << 4 */ + addis r3,r3,0x6000 /* Set Ks, Ku bits */ + li r0,NUM_USER_SEGMENTS + mtctr r0 + + li r4,0 +3: + mtsrin r3,r4 + addi r3,r3,0x111 /* next VSID */ + rlwinm r3,r3,0,8,3 /* clear out any overflow from VSID field */ + addis r4,r4,0x1000 /* address of next segment */ + bdnz 3b + isync + +set_kernel_segregs: + +/* + * Reload the last four segment registers because they + * might have been clobbered by the hypervisor if we + * are running on a shared processor + */ + lis r3,0x2000 /* Set Ku = 1 */ + addi r3,r3,0xCCC /* Set VSID = CCC */ + lis r4,0xC000 /* Set SR = C */ + li r0,4 /* Load regs C, D, E and F */ + mtctr r0 +4: mtsrin r3,r4 + addi r3,r3,0x111 /* increment VSID */ + addis r4,r4,0x1000 /* address of next segment */ + bdnz 4b + isync + + blr + + +/* Hypervisor call + * + * Invoke the iSeries hypervisor (PLIC) via the System Call instruction. + * Parameters are passed to this routine in registers r3 - r10 and are + * converted to 64-bit by combining registers. eg. r3 <- r3 + * r4 <- r5,r6, r5 <- r7,r8, r6 <- r9,r10 + * + * r3 contains the HV function to be called + * r5,r6 contain the first 64-bit operand + * r7,r8 contain the second 64-bit operand + * r9,r10 contain the third 64-bit operand + * caller's stack frame +8 contains the fourth 64-bit operand + * caller's stack frame +16 contains the fifth 64-bit operand + * caller's stack frame +24 contains the sixth 64-bit operand + * caller's stack frame +32 contains the seventh 64-bit operand + * + */ + +_GLOBAL(HvCall) +_GLOBAL(HvCall0) +_GLOBAL(HvCall1) +_GLOBAL(HvCall2) +_GLOBAL(HvCall3) +_GLOBAL(HvCall4) +_GLOBAL(HvCall5) +_GLOBAL(HvCall6) +_GLOBAL(HvCall7) + /* + * Stack a frame and save one reg so we can hang on to + * the old MSR + */ + stwu r1,-64(r1) + stw r31,60(r1) + + stw r22,24(r1) + stw r23,28(r1) + stw r24,32(r1) + stw r25,36(r1) + stw r26,40(r1) + stw r27,44(r1) + stw r28,48(r1) + stw r29,52(r1) + + /* + * The hypervisor assumes CR fields 0-4 are volatile, but + * gcc assumes CR fields 2-7 are non-volatile. + * We must save and restore the CR here + */ + mfcr r31 + stw r31,20(r1) + + /* Before we can convert to using 64-bit registers we must + * soft disable external interrupts as the interrupt handlers + * don't preserve the high half of the registers + */ + + mfspr r11,SPRG1 /* Get the Paca pointer */ + lbz r31,PACAPROCENABLED(r11) /* Get soft enable/disable flag */ + li r0,0 + stb r0,PACAPROCENABLED(r11) /* Soft disable */ + + /* Get parameters four through seven */ + + lwz r22,72(r1) + lwz r23,76(r1) + lwz r24,80(r1) + lwz r25,84(r1) + lwz r26,88(r1) + lwz r27,92(r1) + lwz r28,96(r1) + lwz r29,100(r1) + /* Now it is safe to operate on 64-bit registers + * + * Format the operands into the 64-bit registers + * + */ + rldicr r5,r5,32,31 /* r5 = r5 << 32 */ + rldicl r6,r6,0,32 /* r6 = r6 & 0x00000000ffffffff */ + or r4,r5,r6 /* r4 = r5 | r6 */ + rldicr r7,r7,32,31 /* r7 = r7 << 32 */ + rldicl r8,r8,0,32 /* r8 = r8 & 0x00000000ffffffff */ + or r5,r7,r8 /* r5 = r7 | r8 */ + rldicr r9,r9,32,31 /* r9 = r9 << 32 */ + rldicl r10,r10,0,32 /* r10 = r10 & 0x00000000ffffffff */ + or r6,r9,r10 /* r6 = r9 | r10 */ + rldicr r22,r22,32,31 /* r22 = r22 << 32 */ + rldicl r23,r23,0,32 /* r23 = r23 & 0x00000000ffffffff */ + or r7,r22,r23 /* r7 = r22 | r23 */ + rldicr r24,r24,32,31 /* r24 = r24 << 32 */ + rldicl r25,r25,0,32 /* r25 = r25 & 0x00000000ffffffff */ + or r8,r24,r25 /* r8 = r24 | r25 */ + rldicr r26,r26,32,31 /* r26 = r26 << 32 */ + rldicl r27,r27,0,32 /* r27 = r27 & 0x00000000ffffffff */ + or r9,r26,r27 /* r9 = r26 | r27 */ + rldicr r28,r28,32,31 /* r28 = r28 << 32 */ + rldicl r29,r29,0,32 /* r29 = r29 & 0x00000000ffffffff */ + or r10,r28,r29 /* r10 = r28 | r29 */ + + /* + * Extract the hypervisor function call number from R3 + * and format it into the 64-bit R3. + */ + rldicr r0,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */ + rldicl r3,r3,0,48 /* r3 = r3 & 0x000000000000ffff */ + or r3,r3,r0 /* r3 = r3 | r0 */ + + /* + * r0 = 0xffffffffffffffff indicates a hypervisor call + */ + li r0,-1 /* r1 = 0xffffffffffffffff */ + + /* Invoke the hypervisor via the System Call instruction */ + + sc + + HMT_MEDIUM + + /* Return value in 64-bit R3 + * format it into R3 and R4 + */ + rldicl r4,r3,0,32 /* r4 = r3 & 0x00000000ffffffff */ + rldicl r3,r3,32,32 /* r3 = (r3 >> 32) & 0x00000000ffffffff */ + + /* We are now done with 64-bit registers it is safe to touch + * the stack again. + */ + lwz r22,24(r1) + lwz r23,28(r1) + lwz r24,32(r1) + lwz r25,36(r1) + lwz r26,40(r1) + lwz r27,44(r1) + lwz r28,48(r1) + lwz r29,52(r1) + + /* While we were running in the hypervisor, a decrementer or + * external interrupt may have occured. If we are about to + * enable here, we must check for these and process them + */ + + cmpi 0,r31,0 /* check if going to enable */ + beq 1f /* skip checks if staying disabled */ + + /* Save r3, r4 and LR */ + stw r3,52(r1) + stw r4,48(r1) + mflr r3 + stw r3,44(r1) + + /* enable and check for decrementers/lpEvents */ + mr r3,r31 + bl __restore_flags + + /* Restore r3, r4 and LR */ + lwz r3,44(r1) + mtlr r3 + lwz r3,52(r1) + lwz r4,48(r1) + +1: + /* + * Unstack the frame and restore r31 and the CR + */ + lwz r31,20(r1) + mtcrf 0xff,r31 + lwz r31,60(r1) + lwz r1,0(r1) + + blr + +/* Hypervisor call with return data + * + * Invoke the iSeries hypervisor (PLIC) via the System Call instruction. + * The Hv function ID is passed in r3 + * The address of the return data structure is passed in r4 + * Parameters are passed to this routine in registers r5 - r10 and are + * converted to 64-bit by combining registers. eg. r3 <- r3 + * r4 <- r5,r6, r5 <- r7,r8, r6 <- r9,r10 + * + * r3 contains the HV function to be called + * r4 contains the address of the return data structure + * r5,r6 contain the first 64-bit operand + * r7,r8 contain the second 64-bit operand + * r9,r10 contain the third 64-bit operand + * caller's stack frame +8 contains the fourth 64-bit operand + * caller's stack frame +16 contains the fifth 64-bit operand + * caller's stack frame +24 contains the sixth 64-bit operand + * caller's stack frame +32 contains the seventh 64-bit operand + * + */ + +_GLOBAL(HvCallRet16) +_GLOBAL(HvCall0Ret16) +_GLOBAL(HvCall1Ret16) +_GLOBAL(HvCall2Ret16) +_GLOBAL(HvCall3Ret16) +_GLOBAL(HvCall4Ret16) +_GLOBAL(HvCall5Ret16) +_GLOBAL(HvCall6Ret16) +_GLOBAL(HvCall7Ret16) + + /* + * Stack a frame and save some regs + */ + stwu r1,-64(r1) + stw r31,60(r1) + stw r30,56(r1) + + stw r22,24(r1) + stw r23,28(r1) + stw r24,32(r1) + stw r25,36(r1) + stw r26,40(r1) + stw r27,44(r1) + stw r28,48(r1) + stw r29,52(r1) + + mr r30,r4 /* Save return data address */ + + /* + * The hypervisor assumes CR fields 0-4 are volatile, but + * gcc assumes CR fields 2-7 are non-volatile. + * We must save and restore the CR here + */ + mfcr r31 + stw r31,20(r1) + + /* Before we can convert to using 64-bit registers we must + * soft disable external interrupts as the interrupt handlers + * don't preserve the high half of the registers + */ + + mfspr r11,SPRG1 /* Get the Paca pointer */ + lbz r31,PACAPROCENABLED(r11) /* Get soft enable/disable flag */ + li r0,0 + stb r0,PACAPROCENABLED(r11) /* Soft disable */ + + /* Get parameters four through seven */ + + lwz r22,76(r1) + lwz r23,80(r1) + lwz r24,84(r1) + lwz r25,88(r1) + lwz r26,92(r1) + lwz r27,96(r1) + lwz r28,100(r1) + lwz r29,104(r1) + + /* Now it is safe to operate on 64-bit registers + * + */ + + /* + * Format the operands into the 64-bit registers + */ + + rldicr r5,r5,32,31 /* r5 = r5 << 32 */ + rldicl r6,r6,0,32 /* r6 = r6 & 0x00000000ffffffff */ + or r4,r5,r6 /* r4 = r5 | r6 */ + rldicr r7,r7,32,31 /* r7 = r7 << 32 */ + rldicl r8,r8,0,32 /* r8 = r8 & 0x00000000ffffffff */ + or r5,r7,r8 /* r5 = r7 | r8 */ + rldicr r9,r9,32,31 /* r9 = r9 << 32 */ + rldicl r10,r10,0,32 /* r10 = r10 & 0x00000000ffffffff */ + or r6,r9,r10 /* r6 = r9 | r10 */ + rldicr r22,r22,32,31 /* r22 = r22 << 32 */ + rldicl r23,r23,0,32 /* r23 = r23 & 0x00000000ffffffff */ + or r7,r22,r23 /* r7 = r22 | r23 */ + rldicr r24,r24,32,31 /* r24 = r24 << 32 */ + rldicl r25,r25,0,32 /* r25 = r25 & 0x00000000ffffffff */ + or r8,r24,r25 /* r8 = r24 | r25 */ + rldicr r26,r26,32,31 /* r26 = r26 << 32 */ + rldicl r27,r27,0,32 /* r27 = r27 & 0x00000000ffffffff */ + or r9,r26,r27 /* r9 = r26 | r27 */ + rldicr r28,r28,32,31 /* r28 = r28 << 32 */ + rldicl r29,r29,0,32 /* r29 = r29 & 0x00000000ffffffff */ + or r10,r28,r29 /* r10 = r28 | r29 */ + /* + * Extract the hypervisor function call number from R3 + * and format it into the 64-bit R3. + */ + rldicr r0,r3,32,15 /* r4 = (r3 << 32) & 0xffff000000000000 */ + rldicl r3,r3,0,48 /* r3 = r3 & 0x000000000000ffff */ + or r3,r3,r0 /* r3 = r3 | r4 */ + + /* + * r0 = 0xffffffffffffffff indicates a hypervisor call + */ + li r0,-1 /* r1 = 0xffffffffffffffff */ + + /* Invoke the hypervisor via the System Call instruction */ + + sc + + HMT_MEDIUM + + /* Return values in 64-bit R3, R4, R5 and R6 + * place R3 and R4 into data structure, R5 into R3,R4 + */ + rldicl r6,r3,32,32 /* r6 = (r3 >> 32) & 0x00000000ffffffff */ + rldicl r7,r3,0,32 /* r7 = r3 & 0x00000000ffffffff */ + rldicl r8,r4,32,32 /* r8 = (r4 >> 32) & 0x00000000ffffffff */ + rldicl r9,r4,0,32 /* r9 = r4 & 0x00000000ffffffff */ + + rldicl r4,r5,0,32 /* r4 = r5 & 0x00000000ffffffff */ + rldicl r3,r5,32,32 /* r3 = (r5 >> 32) & 0x00000000ffffffff */ + + /* We are now done with 64-bit registers it is safe to touch + * the stack again. + */ + stw r6,0(r30) /* Save returned data */ + stw r7,4(r30) + stw r8,8(r30) + stw r9,12(r30) + + lwz r22,24(r1) + lwz r23,28(r1) + lwz r24,32(r1) + lwz r25,36(r1) + lwz r26,40(r1) + lwz r27,44(r1) + lwz r28,48(r1) + lwz r29,52(r1) + + /* While we were running in the hypervisor, a decrementer or + * external interrupt may have occured. If we are about to + * enable here, we must check for these and process them + */ + + cmpi 0,r31,0 /* check if going to enable */ + beq 1f /* skip checks if staying disabled */ + + /* Save r3, r4 and LR */ + stw r3,48(r1) + stw r4,44(r1) + mflr r3 + stw r3,40(r1) + + /* enable and check for decrementers/lpEvents */ + mr r3,r31 + bl __restore_flags + + lwz r3,40(r1) + mtlr r3 + lwz r3,48(r1) + lwz r4,44(r1) + +1: + /* + * Unstack the frame and restore r30, r31 and CR + */ + lwz r31,20(r1) + mtcrf 0xff,r31 + lwz r30,56(r1) + lwz r31,60(r1) + lwz r1,0(r1) + + blr + + +/* Hypervisor call (use no stack) + * + * These functions must be called with interrupts soft disabled. + * The caller is responsible for saving the non-volatile CR + * The operands should already be formatted into the 64-bit registers + * + * Invoke the iSeries hypervisor (PLIC) via the System Call instruction. + * + * r3 contains the HV function to be called + * r4 contains the first 64-bit operand + * r5 contains the second 64-bit operand + * r6 contains the third 64-bit operand + * r7 contains the fourth 64-bit operand + * r8 contains the fifth 64-bit operand + * r9 contains the sixth 64-bit operand + * r10 contains the seventh 64-bit operand + * + * data is returned in 64-bit registers r3-r6 + * + */ + +_GLOBAL(HvXCall) +_GLOBAL(HvXCall0) +_GLOBAL(HvXCall1) +_GLOBAL(HvXCall2) +_GLOBAL(HvXCall3) + /* + * Extract the hypervisor function call number from R3 + * and format it into the 64-bit R3. + */ + rldicr r0,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */ + rldicl r3,r3,0,48 /* r3 = r3 & 0x000000000000ffff */ + or r3,r3,r0 /* r3 = r3 | r0 */ + + /* + * r0 = 0xffffffffffffffff indicates a hypervisor call + */ + li r0,-1 /* r1 = 0xffffffffffffffff */ + + /* Invoke the hypervisor via the System Call instruction */ + + sc + + blr + +_GLOBAL(__setup_cpu_power3) + blr +_GLOBAL(__setup_cpu_power4) + blr +_GLOBAL(__setup_cpu_generic) + blr + +_GLOBAL(iSeries_check_intr) + mflr r31 + lwz r5,_SOFTE(r1) + cmpi 0,r5,0 + beqlr + mfspr r5,SPRG1 + lbz r5,PACAPROCENABLED(r5) + cmpi 0,r5,0 + bnelr + /* Check for lost decrementer interrupts. + * (If decrementer popped while we were in the hypervisor) + * (calls timer_interrupt if so) + */ +3: CHECKDECR(r4,r5) + /* Check for pending interrupts. If no interrupts pending, + * then CR0 = "eq" and r4 == 0 + * (kills registers r5 and r6) + */ + beq+ 1f + addi r3,r1,STACK_FRAME_OVERHEAD + bl timer_interrupt +1: + CHECKLPQUEUE(r4,r5,r6) + beq+ 2f + addi r3,r1,STACK_FRAME_OVERHEAD + bl do_IRQ + b 3b + +2: mtlr r31 + blr + +/* + * Fake an interrupt from kernel mode. + * This is used when enable_irq loses an interrupt. + * We only fill in the stack frame minimally. + */ +_GLOBAL(fake_interrupt) + mflr r0 + stw r0,4(r1) + stwu r1,-INT_FRAME_SIZE(r1) + stw r0,_NIP(r1) + stw r0,_LINK(r1) + mfmsr r3 + stw r3,_MSR(r1) + li r0,0x0fac + stw r0,TRAP(r1) + addi r3,r1,STACK_FRAME_OVERHEAD + li r4,1 + bl do_IRQ + addi r1,r1,INT_FRAME_SIZE + lwz r0,4(r1) + + mtlr r0 + blr + +/* + * Fake a decrementer from kernel mode. + * This is used when the decrementer pops in + * the hypervisor. We only fill in the stack + * frame minimally + */ +_GLOBAL(fake_decrementer) + mflr r0 + stw r0,4(r1) + stwu r1,-INT_FRAME_SIZE(r1) + stw r0,_NIP(r1) + stw r0,_LINK(r1) + mfmsr r3 + stw r3,_MSR(r1) + li r0,0x0fac + stw r0,TRAP(r1) + addi r3,r1,STACK_FRAME_OVERHEAD + bl timer_interrupt + addi r1,r1,INT_FRAME_SIZE + lwz r0,4(r1) + + mtlr r0 + blr + +_GLOBAL(create_hpte) + stwu r1,-INT_FRAME_SIZE(r1) + stw r0,GPR0(r1) + lwz r0,0(r1) + stw r0,GPR1(r1) + /* r3-r13 are caller saved */ + stw r2,GPR2(r1) + SAVE_8GPRS(4, r1) + SAVE_2GPRS(12, r1) + SAVE_4GPRS(20,r1) + mfspr r20,XER + mfctr r22 + stw r20,_XER(r1) + stw r22,_CTR(r1) + mflr r20 + mfmsr r22 + stw r20,_NIP(r1) + stw r22,_MSR(r1) + stw r20,_LINK(r1) + bl iSeries_create_hpte + lwz r0,GPR0(r1) + lwz r2,GPR2(r1) + REST_8GPRS(4, r1) + REST_2GPRS(12, r1) + lwz r20,_NIP(r1) + lwz r22,_XER(r1) + mtlr r20 + mtspr XER,r22 + lwz r20,_CTR(r1) + mtctr r20 + + REST_4GPRS(20,r1) + addi r1,r1,INT_FRAME_SIZE + blr + +### +### extern void abort(void) +### +### Invoke the hypervisor to kill the partition. +### + +_GLOBAL(abort) + + +/* + * We put a few things here that have to be page-aligned. + * This stuff goes at the beginning of the data segment, + * which is page-aligned. + */ + .data + .globl sdata +sdata: + + .globl empty_zero_page +empty_zero_page: + .space 4096 + + .globl swapper_pg_dir +swapper_pg_dir: + .space 4096 + +/* + * This space gets a copy of optional info passed to us by the bootstrap + * Used to pass parameters into the kernel like root=/dev/sda1, etc. + */ + .globl cmd_line +cmd_line: + .space 512 diff --git a/arch/ppc/kernel/iSeries_misc.S b/arch/ppc/kernel/iSeries_misc.S new file mode 100644 index 000000000000..983611b80276 --- /dev/null +++ b/arch/ppc/kernel/iSeries_misc.S @@ -0,0 +1,469 @@ + /* + * This file contains miscellaneous low-level functions. + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Largely rewritten by Cort Dougan (cort@cs.nmt.edu) + * and Paul Mackerras. + * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com) + * updated by Dave Boutcher (boutcher@us.ibm.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include <linux/config.h> +#include <linux/sys.h> +#include <asm/unistd.h> +#include <asm/errno.h> +#include <asm/processor.h> +#include <asm/page.h> +#include <asm/cache.h> +#include <asm/ppc_asm.h> +#include "ppc_defs.h" +#include "iSeries_asm.h" + + .text + .align 5 + +#ifdef CONFIG_SMP + .comm hash_table_lock,4 +#endif /* CONFIG_SMP */ + +_GLOBAL(is_msr_enabled) + mfmsr r3 + andi. r3,r3,MSR_EE + beqlr /* Return r3=0 indicating disabled */ + li r3,1 + blr /* Return r3=1 indicating enabled */ + +_GLOBAL(is_soft_enabled) + mfspr r3,SPRG1 + lbz r3,PACAPROCENABLED(r3) + blr + +_GLOBAL(get_tb64) + /* hard disable because we are using a 64-bit register + * and we don't want it to get trashed in an interrupt + * handler + */ + + mfmsr r5 + rlwinm r0,r5,0,17,15 /* clear MSR_EE in r0 */ + mtmsr r0 /* hard disable */ + + mftb r3 + rldicl r4,r3,0,32 + rldicl r3,r3,32,32 + + mtmsr r5 /* restore MSR_EE */ + blr + +/* void __save_flags(unsigned long *flags) */ +_GLOBAL(__save_flags_ptr) + mfspr r4,SPRG1 /* Get Paca pointer */ + lbz r4,PACAPROCENABLED(r4) + stw r4,0(r3) + blr +_GLOBAL(__save_flags_ptr_end) + +/* void __restore_flags(unsigned long flags) */ +_GLOBAL(__restore_flags) + cmpi 0,r3,0 /* Are we enabling? */ + beq 0f /* No - then skip interrupt checks */ + +3: + mfspr r4,SPRG1 + lbz r4,PACAPROCENABLED(r4) + cmpi 0,r4,0 /* Are we already enabled? */ + bne 0f /* Yes - then skip interrupt checks */ + + CHECKDECR(r4,r5) + bne- do_fake_decrementer + + CHECKLPQUEUE(r4,r5,r6) + bne- do_lost_interrupts +2: + mfmsr r0 + rlwinm r0,r0,0,17,15 /* hard disable */ + mtmsr r0 + + CHECKANYINT(r4,r5,r6) + ori r0,r0,MSR_EE + beq 1f + mtmsr r0 /* hard enable */ + b 3b /* process more interrupts */ +1: + mfspr r4,SPRG1 + stb r3,PACAPROCENABLED(r4) + mtmsr r0 /* hard enable */ + blr +0: + mfspr r4,SPRG1 + stb r3,PACAPROCENABLED(r4) + blr +_GLOBAL(__restore_flags_end) + +_GLOBAL(__cli) + mfspr r4,SPRG1 + li r3,0 + stb r3,PACAPROCENABLED(r4) + blr /* Done */ +_GLOBAL(__cli_end) + +_GLOBAL(__sti) + li r3,1 + b __restore_flags +_GLOBAL(__sti_end) + +/* + * We were about to enable interrupts but we have to simulate + * some interrupts that were lost by enable_irq first. + */ +_GLOBAL(do_lost_interrupts) + stwu r1,-32(r1) + mflr r0 + stw r0,36(r1) + stw r3,28(r1) +1: bl fake_interrupt + bl check_softirqs + mfmsr r0 + rlwinm r0,r0,0,17,15 /* hard disable */ + mtmsr r0 + + CHECKANYINT(r4,r5,r6) + ori r0,r0,MSR_EE + beq 2f + mtmsr r0 /* hard enable */ + b 1b /* process more interrupts */ + +2: lwz r3,28(r1) + mfspr r4,SPRG1 + stb r3,PACAPROCENABLED(r4) /* restore soft interrupt state */ + mtmsr r0 /* hard enable */ + lwz r0,36(r1) + mtlr r0 + + addi r1,r1,32 + blr + +/* + * Simulate a decrementer interrupt + */ +do_fake_decrementer: + stwu r1,-32(r1) + mflr r0 + stw r0,36(r1) + stw r3,28(r1) + bl fake_decrementer + bl check_softirqs + lwz r0,36(r1) + mtlr r0 + + lwz r3,28(r1) + addi r1,r1,32 + + mfmsr r0 /* hard disable */ + rlwinm r0,r0,0,17,15 + mtmsr r0 + + CHECKANYINT(r4,r5,r6) /* Check for any interrupts pending */ + ori r0,r0,MSR_EE + beq 1f + mtmsr r0 /* hard enable */ + b do_lost_interrupts /* Handle more interrupts */ + +1: mfspr r4,SPRG1 + stb r3,PACAPROCENABLED(r4) /* soft enable */ + mtmsr r0 /* hard enable */ + blr + +/* + * do softirqs if necessary + */ +check_softirqs: + stwu r1,-32(r1) + mflr r0 + stw r0,36(r1) + + lis r4,irq_stat@ha + addi r4,r4,irq_stat@l +#ifdef CONFIG_SMP + lwz r3,CPU(r2) + slwi r3,r3,7 + add r4,r4,r3 +#endif + lwz r5,0(r4) + lwz r4,4(r4) + and. r5,r5,r4 + beq+ 2f + bl do_softirq +2: + lwz r0,36(r1) + mtlr r0 + + addi r1,r1,32 + blr + + +/* + * Write any modified data cache blocks out to memory + * and invalidate the corresponding instruction cache blocks. + * + * flush_icache_range(unsigned long start, unsigned long stop) + */ + +_GLOBAL(flush_icache_range) + + +/* + * Flush the data cache to memory + * + * Different models of iSeries's have different cache line sizes + * and in some cases i-cache and d-cache line sizes differ from + * each other. + */ + + lis r7,iSeries_dcache_line_size@ha + lhz r7,iSeries_dcache_line_size@l(r7) + addi r5,r7,-1 + andc r6,r3,r5 /* round low to line bdy */ + subf r8,r6,r4 /* compute length */ + add r8,r8,r5 /* ensure we get enough */ + lis r9,iSeries_log_dcache_line_size@ha + lhz r9,iSeries_log_dcache_line_size@l(r9) + srw. r8,r8,r9 /* compute line count */ + beqlr /* nothing to do? */ + mtctr r8 +1: dcbst 0,r6 + add r6,r6,r7 + bdnz 1b + sync + +/* Now invalidate the instruction cache */ + + lis r7,iSeries_icache_line_size@ha + lhz r7,iSeries_icache_line_size@l(r7) + addi r5,r7,-1 + andc r6,r3,r5 /* round low to line bdy */ + subf r8,r6,r4 /* compute length */ + add r8,r8,r5 + lis r9,iSeries_log_icache_line_size@ha + lhz r9,iSeries_log_icache_line_size@l(r9) + srw. r8,r8,r9 /* compute line count */ + beqlr /* nothing to do? */ + mtctr r8 +2: icbi 0,r6 + add r6,r6,r7 + bdnz 2b + sync + isync + blr + + +/* + * Like above, but only do the D-cache. + * + * flush_dcache_range(unsigned long start, unsigned long stop) + */ +_GLOBAL(flush_dcache_range) + +/* + * Flush the data cache to memory + * + * Different models of iSeries's have different cache line sizes + */ + + lis r7,iSeries_dcache_line_size@ha + lhz r7,iSeries_dcache_line_size@l(r7) + addi r5,r7,-1 + andc r6,r3,r5 /* round low to line bdy */ + subf r8,r6,r4 /* compute length */ + add r8,r8,r5 /* ensure we get enough */ + lis r9,iSeries_log_dcache_line_size@ha + lhz r9,iSeries_log_dcache_line_size@l(r9) + srw. r8,r8,r9 /* compute line count */ + beqlr /* nothing to do? */ + mtctr r8 +0: dcbst 0,r6 + add r6,r6,r7 + bdnz 0b + sync + blr + + +/* + * Flush a particular page from the data cache to RAM. + * Note: this is necessary because the instruction cache does *not* + * snoop from the data cache. + * + * void __flush_page_to_ram(void *page) + * void __flush_dcache_icache(void *page) + */ +_GLOBAL(__flush_page_to_ram) +_GLOBAL(__flush_dcache_icache) + +/* + * Flush the data cache to memory + * + * Different models of iSeries's have different cache line sizes + */ + +/* Flush the dcache */ + + rlwinm r3,r3,0,0,19 /* Page align */ + lis r4,iSeries_dcache_lines_per_page@ha + lhz r4,iSeries_dcache_lines_per_page@l(r4) + lis r5,iSeries_dcache_line_size@ha + lhz r5,iSeries_dcache_line_size@l(r5) + mr r6,r3 + mtctr r4 +0: dcbst 0,r6 + add r6,r6,r5 + bdnz 0b + sync + +/* Now invalidate the icache */ + + lis r4,iSeries_icache_lines_per_page@ha + lhz r4,iSeries_icache_lines_per_page@l(r4) + lis r5,iSeries_icache_line_size@ha + lhz r5,iSeries_icache_line_size@l(r5) + mtctr r4 +1: icbi 0,r3 + add r3,r3,r5 + bdnz 1b + sync + isync + blr + + +/* + * Flush a particular page from the instruction cache. + * Note: this is necessary because the instruction cache does *not* + * snoop from the data cache. + * + * void __flush_icache_page(void *page) + */ +_GLOBAL(__flush_icache_page) + + +/* + * Different models of iSeries's have different cache line sizes + */ + +/* Invalidate the icache */ + + rlwinm r3,r3,0,0,19 /* Page align */ + lis r4,iSeries_icache_lines_per_page@ha + lhz r4,iSeries_icache_lines_per_page@l(r4) + lis r5,iSeries_icache_line_size@ha + lhz r5,iSeries_icache_line_size@l(r5) + mtctr r4 +1: icbi 0,r3 + add r3,r3,r5 + bdnz 1b + sync + isync + blr + +/* + * Clear a page using the dcbz instruction, which doesn't cause any + * memory traffic (except to write out any cache lines which get + * displaced). This only works on cacheable memory. + */ +_GLOBAL(clear_page) + + rlwinm r3,r3,0,0,19 /* Page align */ + lis r4,iSeries_dcache_lines_per_page@ha + lhz r4,iSeries_dcache_lines_per_page@l(r4) + lis r5,iSeries_dcache_line_size@ha + lhz r5,iSeries_dcache_line_size@l(r5) + mtctr r4 +0: dcbz 0,r3 + add r3,r3,r5 + bdnz 0b + blr + + +/* + * Copy a whole page. We use the dcbz instruction on the destination + * to reduce memory traffic (it eliminates the unnecessary reads of + * the destination into cache). This requires that the destination + * is cacheable. + */ +#define COPY_16_BYTES \ + lwz r6,4(r4); \ + lwz r7,8(r4); \ + lwz r8,12(r4); \ + lwzu r9,16(r4); \ + stw r6,4(r3); \ + stw r7,8(r3); \ + stw r8,12(r3); \ + stwu r9,16(r3) + +_GLOBAL(copy_page) + + rlwinm r3,r3,0,0,19 /* Page align */ + rlwinm r4,r4,0,0,19 + lis r5,iSeries_dcache_lines_per_page@ha + lhz r5,iSeries_dcache_lines_per_page@l(r5) + lis r6,iSeries_dcache_line_size@ha + lhz r0,iSeries_dcache_line_size@l(r6) + mtctr r5 + addi r3,r3,-4 + addi r4,r4,-4 + li r10,4 + + cmpi 0,r0,32 + beq do_32_byte_line + cmpi 0,r0,64 + beq do_64_byte_line + cmpi 0,r0,128 + beq do_128_byte_line + + /* We don't have code specifically for this cache line size */ + /* Assume that the cache line size is at least 16 (and of */ + /* course a multiple of 16) */ + /* This code will work for all power-of-2 cache line sizes */ + /* from 16 to 4096 */ + +1: mr r5,r0 + dcbz r10,r3 +0: COPY_16_BYTES + addi r5,r5,-16 + or. r5,r5,r5 + bne 0b + bdnz 1b + blr + +do_32_byte_line: + dcbz r10,r3 + COPY_16_BYTES + COPY_16_BYTES + bdnz do_32_byte_line + blr + +do_64_byte_line: + dcbz r10,r3 + COPY_16_BYTES + COPY_16_BYTES + COPY_16_BYTES + COPY_16_BYTES + bdnz do_64_byte_line + blr + +do_128_byte_line: + dcbz r10,r3 + COPY_16_BYTES + COPY_16_BYTES + COPY_16_BYTES + COPY_16_BYTES + COPY_16_BYTES + COPY_16_BYTES + COPY_16_BYTES + COPY_16_BYTES + bdnz do_128_byte_line + blr diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c index 2d93e549ccea..e6f2230d835f 100644 --- a/arch/ppc/kernel/idle.c +++ b/arch/ppc/kernel/idle.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.idle.c 1.16 10/16/01 15:58:42 trini + * BK Id: %F% %I% %G% %U% %#% */ /* * Idle daemon for PowerPC. Idle daemon will handle any action @@ -32,6 +32,20 @@ #include <asm/mmu.h> #include <asm/cache.h> #include <asm/cputable.h> +#ifdef CONFIG_PPC_ISERIES +#include <asm/time.h> +#include <asm/iSeries/LparData.h> +#include <asm/iSeries/HvCall.h> +#include <asm/hardirq.h> + +static void yield_shared_processor(void); +static void run_light_on(int on); + +extern unsigned long yield_count; + +#else /* CONFIG_PPC_ISERIES */ +#define run_light_on(x) do { } while (0) +#endif /* CONFIG_PPC_ISERIES */ void zero_paged(void); void power_save(void); @@ -53,21 +67,27 @@ int idled(void) do_power_save = 1; /* endless loop with no priority at all */ - current->nice = 20; - init_idle(); for (;;) { +#ifdef CONFIG_PPC_ISERIES + if (!current->need_resched) { + /* Turn off the run light */ + run_light_on(0); + yield_shared_processor(); + } + HMT_low(); +#endif #ifdef CONFIG_SMP - if (!do_power_save) { /* * Deal with another CPU just having chosen a thread to * run here: */ - int oldval = xchg(¤t->need_resched, -1); + unsigned long oldval; - if (!oldval) { - while (need_resched()) - barrier(); /* Do Nothing */ + oldval = xchg(¤t->work, 0xff000000); + if (!(oldval & 0xff000000)) { + while (current->work.need_resched == -1) + barrier(); /* Do Nothing */ } } #endif @@ -75,9 +95,17 @@ int idled(void) power_save(); if (need_resched()) { + run_light_on(1); schedule(); check_pgt_cache(); } +#ifdef CONFIG_PPC_ISERIES + else { + run_light_on(0); + yield_shared_processor(); + HMT_low(); + } +#endif /* CONFIG_PPC_ISERIES */ } return 0; } @@ -108,6 +136,7 @@ unsigned long get_zero_page_fast(void) register unsigned long tmp; asm ( "101:lwarx %1,0,%3\n" /* reserve zero_cache */ " lwz %0,0(%1)\n" /* get next -- new zero_cache */ + PPC405_ERR77(0,%3) " stwcx. %0,0,%3\n" /* update zero_cache */ " bne- 101b\n" /* if lost reservation try again */ : "=&r" (tmp), "=&r" (page), "+m" (zero_cache) @@ -205,6 +234,7 @@ void zero_paged(void) #ifdef CONFIG_SMP " sync\n" /* let store settle */ #endif + PPC405_ERR77(0,%2) " stwcx. %3,0,%2\n" /* update zero_cache in mem */ " bne- 101b\n" /* if lost reservation try again */ : "=&r" (tmp), "+m" (zero_quicklist) @@ -228,6 +258,13 @@ void zero_paged(void) void power_save(void) { unsigned long hid0; + int nap = powersave_nap; + + /* 7450 has no DOZE mode mode, we return if powersave_nap + * isn't enabled + */ + if (!nap && cur_cpu_spec[smp_processor_id()]->cpu_features & CPU_FTR_SPEC7450) + return; /* * Disable interrupts to prevent a lost wakeup * when going to sleep. This is necessary even with @@ -255,3 +292,64 @@ void power_save(void) _nmask_and_or_msr(0, MSR_EE); } +#ifdef CONFIG_PPC_ISERIES + +extern void fake_interrupt(void); +extern u64 get_tb64(void); + +void run_light_on(int on) +{ + unsigned long CTRL; + + CTRL = mfspr(CTRLF); + CTRL = on? (CTRL | RUNLATCH): (CTRL & ~RUNLATCH); + mtspr(CTRLT, CTRL); +} + +void yield_shared_processor(void) +{ + struct Paca *paca; + u64 tb; + + /* Poll for I/O events */ + __cli(); + __sti(); + + paca = (struct Paca *)mfspr(SPRG1); + if ( paca->xLpPaca.xSharedProc ) { + HvCall_setEnabledInterrupts( HvCall_MaskIPI | + HvCall_MaskLpEvent | + HvCall_MaskLpProd | + HvCall_MaskTimeout ); + + /* + * Check here for any of the above pending... + * IPI and Decrementers are indicated in ItLpPaca + * LpEvents are indicated on the LpQueue + * + * Disabling/enabling will check for LpEvents, IPIs + * and decrementers + */ + __cli(); + __sti(); + + ++yield_count; + + /* Get current tb value */ + tb = get_tb64(); + /* Compute future tb value when yield will expire */ + tb += tb_ticks_per_jiffy; + HvCall_yieldProcessor( HvCall_YieldTimed, tb ); + + /* Check here for any of the above pending or timeout expired*/ + __cli(); + /* + * The decrementer stops during the yield. Just force + * a fake decrementer now and the timer_interrupt + * code will straighten it all out + */ + paca->xLpPaca.xDecrInt = 1; + __sti(); + } +} +#endif /* CONFIG_PPC_ISERIES */ diff --git a/arch/ppc/kernel/indirect_pci.c b/arch/ppc/kernel/indirect_pci.c index b79ceee3c5db..0addbd871bef 100644 --- a/arch/ppc/kernel/indirect_pci.c +++ b/arch/ppc/kernel/indirect_pci.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.indirect_pci.c 1.10 09/08/01 15:47:42 paulus + * BK Id: %F% %I% %G% %U% %#% */ /* * Support for indirect PCI bridges. @@ -24,8 +24,6 @@ #include <asm/pci-bridge.h> #include <asm/machdep.h> -#include "pci.h" - #define cfg_read(val, addr, type, op) *val = op((type)(addr)) #define cfg_write(val, addr, type, op) op((type *)(addr), (val)) @@ -35,9 +33,13 @@ indirect_##rw##_config_##size(struct pci_dev *dev, int offset, type val) \ { \ struct pci_controller *hose = dev->sysdata; \ \ + if (ppc_md.pci_exclude_device) \ + if (ppc_md.pci_exclude_device(dev->bus->number, dev->devfn)) \ + return PCIBIOS_DEVICE_NOT_FOUND; \ + \ out_be32(hose->cfg_addr, \ ((offset & 0xfc) << 24) | (dev->devfn << 16) \ - | (dev->bus->number << 8) | 0x80); \ + | ((dev->bus->number - hose->bus_offset) << 8) | 0x80); \ cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \ return PCIBIOS_SUCCESSFUL; \ } diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c index c5f422016adf..5c5e37aabb0e 100644 --- a/arch/ppc/kernel/irq.c +++ b/arch/ppc/kernel/irq.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.irq.c 1.32 08/24/01 20:07:37 paulus + * BK Id: %F% %I% %G% %U% %#% */ /* * arch/ppc/kernel/irq.c @@ -51,20 +51,15 @@ #include <asm/uaccess.h> #include <asm/bitops.h> -#include <asm/hydra.h> #include <asm/system.h> #include <asm/io.h> #include <asm/pgtable.h> #include <asm/irq.h> -#include <asm/gg2.h> #include <asm/cache.h> #include <asm/prom.h> -#include <asm/amigaints.h> -#include <asm/amigahw.h> -#include <asm/amigappc.h> #include <asm/ptrace.h> -#include "local_irq.h" +#define NR_MASK_WORDS ((NR_IRQS + 31) / 32) extern atomic_t ipi_recv; extern atomic_t ipi_sent; @@ -190,9 +185,6 @@ setup_irq(unsigned int irq, struct irqaction * new) * now, this is what I need. -- Dan */ #define request_irq request_8xxirq -#elif defined(CONFIG_APUS) -#define request_irq request_sysirq -#define free_irq sys_free_irq #endif void free_irq(unsigned int irq, void* dev_id) @@ -374,15 +366,12 @@ void enable_irq(unsigned int irq) int show_interrupts(struct seq_file *p, void *v) { -#ifdef CONFIG_APUS - return show_apus_interrupts(p, v); -#else int i, j; struct irqaction * action; seq_puts(p, " "); for (j=0; j<smp_num_cpus; j++) - seq_printf(p, "CPU%d ",j); + seq_printf(p, "CPU%d ", j); seq_putc(p, '\n'); for (i = 0 ; i < NR_IRQS ; i++) { @@ -393,38 +382,35 @@ int show_interrupts(struct seq_file *p, void *v) #ifdef CONFIG_SMP for (j = 0; j < smp_num_cpus; j++) seq_printf(p, "%10u ", - kstat.irqs[cpu_logical_map(j)][i]); + kstat.irqs[cpu_logical_map(j)][i]); #else seq_printf(p, "%10u ", kstat_irqs(i)); #endif /* CONFIG_SMP */ - if ( irq_desc[i].handler ) - seq_printf(p, " %s ", irq_desc[i].handler->typename ); + if (irq_desc[i].handler) + seq_printf(p, " %s ", irq_desc[i].handler->typename); else seq_puts(p, " None "); seq_printf(p, "%s", (irq_desc[i].status & IRQ_LEVEL) ? "Level " : "Edge "); - seq_printf(p, " %s",action->name); - for (action=action->next; action; action = action->next) { + seq_printf(p, " %s", action->name); + for (action = action->next; action; action = action->next) seq_printf(p, ", %s", action->name); - } seq_putc(p, '\n'); } #ifdef CONFIG_TAU_INT if (tau_initialized){ seq_puts(p, "TAU: "); for (j = 0; j < smp_num_cpus; j++) - seq_printf(p, "%10u ", - tau_interrupts(j)); + seq_printf(p, "%10u ", tau_interrupts(j)); seq_puts(p, " PowerPC Thermal Assist (cpu temp)\n"); } #endif #ifdef CONFIG_SMP /* should this be per processor send/receive? */ seq_printf(p, "IPI (recv/sent): %10u/%u\n", - atomic_read(&ipi_recv), atomic_read(&ipi_sent)); + atomic_read(&ipi_recv), atomic_read(&ipi_sent)); #endif seq_printf(p, "BAD: %10u\n", ppc_spurious_interrupts); return 0; -#endif /* CONFIG_APUS */ } static inline void @@ -535,31 +521,35 @@ out: spin_unlock(&desc->lock); } +#ifndef CONFIG_PPC_ISERIES /* iSeries version is in iSeries_pic.c */ int do_IRQ(struct pt_regs *regs) { int cpu = smp_processor_id(); - int irq; - hardirq_enter(cpu); - - /* every arch is required to have a get_irq -- Cort */ - irq = ppc_md.get_irq(regs); - - if (irq >= 0) { - ppc_irq_dispatch_handler( regs, irq ); - } else if (irq != -2) { - /* -2 means ignore, already handled */ - if (ppc_spurious_interrupts < 10) - printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n", - irq, regs->nip); + int irq, first = 1; + hardirq_enter( cpu ); + + /* + * Every platform is required to implement ppc_md.get_irq. + * This function will either return an irq number or -1 to + * indicate there are no more pending. But the first time + * through the loop this means there wasn't and IRQ pending. + * The value -2 is for buggy hardware and means that this IRQ + * has already been handled. -- Tom + */ + while ((irq = ppc_md.get_irq(regs)) >= 0) { + ppc_irq_dispatch_handler(regs, irq); + first = 0; + } + if (irq != -2 && first) /* That's not SMP safe ... but who cares ? */ ppc_spurious_interrupts++; - } hardirq_exit( cpu ); if (softirq_pending(cpu)) do_softirq(); return 1; /* lets ret_from_int know we can do checks */ } +#endif /* CONFIG_PPC_ISERIES */ unsigned long probe_irq_on (void) { @@ -591,7 +581,6 @@ void __init init_IRQ(void) #ifdef CONFIG_SMP unsigned char global_irq_holder = NO_PROC_ID; unsigned volatile long global_irq_lock; /* pendantic :long for set_bit--RR*/ -atomic_t global_irq_count; atomic_t global_bh_count; @@ -602,8 +591,7 @@ static void show(char * str) int cpu = smp_processor_id(); printk("\n%s, CPU %d:\n", str, cpu); - printk("irq: %d [%d %d]\n", - atomic_read(&global_irq_count), + printk("irq: [%d %d]\n", local_irq_count(0), local_irq_count(1)); printk("bh: %d [%d %d]\n", @@ -643,11 +631,9 @@ static inline void wait_on_irq(int cpu) * 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; - } + if (!irqs_running()) + if (local_bh_count(cpu) || !spin_is_locked(&global_bh_lock)) + break; /* Duh, we have to loop. Release the lock to avoid deadlocks */ clear_bit(0,&global_irq_lock); @@ -658,16 +644,19 @@ static inline void wait_on_irq(int cpu) count = ~0; } __sti(); - /* don't worry about the lock race Linus found - * on intel here. -- Cort + /* + * We have to allow irqs to arrive between __sti and __cli + * Some cpus apparently won't cause the interrupt + * for several instructions. We hope that isync will + * catch this --Troy */ + __asm__ __volatile__ ("isync"); __cli(); - if (atomic_read(&global_irq_count)) + if (irqs_running()) continue; if (global_irq_lock) continue; - if (!local_bh_count(cpu) - && atomic_read(&global_bh_count)) + if (!local_bh_count(cpu) && spin_is_locked(&global_bh_lock)) continue; if (!test_and_set_bit(0,&global_irq_lock)) break; @@ -698,7 +687,7 @@ void synchronize_bh(void) */ void synchronize_irq(void) { - if (atomic_read(&global_irq_count)) { + if (irqs_running()) { /* Stupid approach */ cli(); sti(); diff --git a/arch/ppc/kernel/l2cr.S b/arch/ppc/kernel/l2cr.S index d208577bca00..b3ec25cca703 100644 --- a/arch/ppc/kernel/l2cr.S +++ b/arch/ppc/kernel/l2cr.S @@ -30,13 +30,19 @@ *********** Thu, July 13, 2000. - Terry: Added isync to correct for an errata. + + 22 August 2001. + - DanM: Finally added the 7450 patch I've had for the past + several months. The L2CR is similar, but I'm going + to assume the user of this functions knows what they + are doing. Author: Terry Greeniaus (tgree@phys.ualberta.ca) Please e-mail updates to this file to me, thanks! */ #include <asm/processor.h> #include <asm/cputable.h> -#include "ppc_asm.h" +#include <asm/ppc_asm.h> /* Usage: @@ -71,6 +77,15 @@ features, such as L2DO which caches only data, or L2TS which causes cache pushes from the L1 cache to go to the L2 cache instead of to main memory. + +IMPORTANT: + Starting with the 7450, the bits in this register have moved + or behave differently. The Enable, Parity Enable, Size, + and L2 Invalidate are the only bits that have not moved. + The size is read-only for these processors with internal L2 + cache, and the invalidate is a control as well as status. + -- Dan + */ /* * Summary: this procedure ignores the L2I bit in the value passed in, @@ -115,6 +130,8 @@ END_FTR_SECTION_IFCLR(CPU_FTR_L2CR) /**** Might be a good idea to set L2DO here - to prevent instructions from getting into the cache. But since we invalidate the next time we enable the cache it doesn't really matter. + Don't do this unless you accomodate all processor variations. + The bit moved on the 7450..... ****/ lis r4,0x0002 @@ -159,12 +176,21 @@ END_FTR_SECTION_IFCLR(CPU_FTR_L2CR) sync isync /* For errata */ +BEGIN_FTR_SECTION + /* On the 7450, we wait for the L2I bit to clear...... + */ +10: mfspr r3,L2CR + andis. r4,r3,0x0020 + bne 10b + b 11f +END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450) + /* Wait for the invalidation to complete */ 3: mfspr r3,L2CR rlwinm. r4,r3,0,31,31 bne 3b - rlwinm r3,r3,0,11,9 /* Turn off the L2I bit */ +11: rlwinm r3,r3,0,11,9 /* Turn off the L2I bit */ sync mtspr L2CR,r3 sync diff --git a/arch/ppc/kernel/local_irq.h b/arch/ppc/kernel/local_irq.h deleted file mode 100644 index 045e864a476d..000000000000 --- a/arch/ppc/kernel/local_irq.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * BK Id: SCCS/s.local_irq.h 1.7 05/17/01 18:14:21 cort - */ - -#ifndef _PPC_KERNEL_LOCAL_IRQ_H -#define _PPC_KERNEL_LOCAL_IRQ_H - -#include <linux/kernel_stat.h> -#include <linux/interrupt.h> -#include <linux/cache.h> -#include <linux/spinlock.h> -#include <linux/irq.h> - -void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq); - -#define NR_MASK_WORDS ((NR_IRQS + 31) / 32) - -extern int ppc_spurious_interrupts; -extern int ppc_second_irq; -extern struct irqaction *ppc_irq_action[NR_IRQS]; - -#endif /* _PPC_KERNEL_LOCAL_IRQ_H */ diff --git a/arch/ppc/kernel/m8260_setup.c b/arch/ppc/kernel/m8260_setup.c index dfdfb004dadd..a05530474cfd 100644 --- a/arch/ppc/kernel/m8260_setup.c +++ b/arch/ppc/kernel/m8260_setup.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.m8260_setup.c 1.30 11/13/01 21:26:07 paulus + * BK Id: %F% %I% %G% %U% %#% */ /* * linux/arch/ppc/kernel/setup.c @@ -45,8 +45,9 @@ #include <asm/mpc8260.h> #include <asm/immap_8260.h> #include <asm/machdep.h> - +#include <asm/bootinfo.h> #include <asm/time.h> + #include "ppc8260_pic.h" static int m8260_set_rtc_time(unsigned long time); @@ -98,17 +99,25 @@ static uint rtc_time; static static int m8260_set_rtc_time(unsigned long time) { +#ifdef CONFIG_TQM8260 + ((immap_t *)IMAP_ADDR)->im_sit.sit_tmcnt = time; + ((immap_t *)IMAP_ADDR)->im_sit.sit_tmcntsc = 0x3; +#else rtc_time = time; +#endif return(0); } static unsigned long m8260_get_rtc_time(void) { - +#ifdef CONFIG_TQM8260 + return ((immap_t *)IMAP_ADDR)->im_sit.sit_tmcnt; +#else /* Get time from the RTC. */ return((unsigned long)rtc_time); +#endif } static void @@ -121,8 +130,11 @@ m8260_restart(char *cmd) * of the reset vector. If that doesn't work for you, change this * or the reboot program to send a proper address. */ +#ifdef CONFIG_TQM8260 + startaddr = 0x40000104; +#else startaddr = 0xff000104; - +#endif if (cmd != NULL) { if (!strncmp(cmd, "startaddr=", 10)) startaddr = simple_strtoul(&cmd[10], NULL, 0); @@ -150,14 +162,13 @@ m8260_show_percpuinfo(struct seq_file *m, int i) bd_t *bp; bp = (bd_t *)__res; - + seq_printf(m, "core clock\t: %d MHz\n" "CPM clock\t: %d MHz\n" "bus clock\t: %d MHz\n", bp->bi_intfreq / 1000000, bp->bi_cpmfreq / 1000000, bp->bi_busfreq / 1000000); - return 0; } @@ -178,7 +189,7 @@ m8260_init_IRQ(void) #endif for ( i = 0 ; i < NR_SIU_INTS ; i++ ) irq_desc[i].handler = &ppc8260_pic; - + /* Initialize the default interrupt mapping priorities, * in case the boot rom changed something on us. */ @@ -197,7 +208,7 @@ m8260_find_end_of_memory(void) { bd_t *binfo; extern unsigned char __res[]; - + binfo = (bd_t *)__res; return binfo->bi_memsize; @@ -219,22 +230,20 @@ void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) { + parse_bootinfo(find_bootinfo()); if ( r3 ) memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) ); - + #ifdef CONFIG_BLK_DEV_INITRD /* take care of initrd if we have one */ - if ( r4 ) - { + if ( r4 ) { initrd_start = r4 + KERNELBASE; initrd_end = r5 + KERNELBASE; } #endif /* CONFIG_BLK_DEV_INITRD */ /* take care of cmd line */ - if ( r6 ) - { - + if ( r6 ) { *(char *)(r7+KERNELBASE) = 0; strcpy(cmd_line, (char *)(r6+KERNELBASE)); } diff --git a/arch/ppc/kernel/m8xx_setup.c b/arch/ppc/kernel/m8xx_setup.c index ace85d3dcf69..dade12003a8a 100644 --- a/arch/ppc/kernel/m8xx_setup.c +++ b/arch/ppc/kernel/m8xx_setup.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.m8xx_setup.c 1.40 11/13/01 21:26:07 paulus + * BK Id: %F% %I% %G% %U% %#% * * linux/arch/ppc/kernel/setup.c * @@ -43,8 +43,9 @@ #include <asm/mpc8xx.h> #include <asm/8xx_immap.h> #include <asm/machdep.h> - +#include <asm/bootinfo.h> #include <asm/time.h> + #include "ppc8xx_pic.h" static int m8xx_set_rtc_time(unsigned long time); @@ -57,25 +58,30 @@ extern void m8xx_ide_init(void); extern unsigned long find_available_memory(void); extern void m8xx_cpm_reset(uint); +extern void rpxfb_alloc_pages(void); void __init m8xx_setup_arch(void) { int cpm_page; - + cpm_page = (int) alloc_bootmem_pages(PAGE_SIZE); - + /* Reset the Communication Processor Module. */ m8xx_cpm_reset(cpm_page); +#ifdef CONFIG_FB_RPX + rpxfb_alloc_pages(); +#endif + #ifdef notdef ROOT_DEV = to_kdev_t(0x0301); /* hda1 */ #endif - + #ifdef CONFIG_BLK_DEV_INITRD #if 0 - ROOT_DEV = to_kdev_t(0x0200); /* floppy */ + ROOT_DEV = to_kdev_t(0x0200); /* floppy */ rd_prompt = 1; rd_doload = 1; rd_image_start = 0; @@ -105,6 +111,9 @@ abort(void) xmon(0); #endif machine_restart(NULL); + + /* not reached */ + for (;;); } /* A place holder for time base interrupts, if they are ever enabled. */ @@ -217,7 +226,7 @@ m8xx_restart(char *cmd) __asm__("mtmsr %0" : : "r" (msr) ); dummy = ((immap_t *)IMAP_ADDR)->im_clkrst.res[0]; - printk("Restart failed\n"); + printk("Restart failed\n"); while(1); } @@ -240,9 +249,9 @@ m8xx_show_percpuinfo(struct seq_file *m, int i) bd_t *bp; bp = (bd_t *)__res; - - seq_printf(m, "clock\t\t: %ldMHz\n" - "bus clock\t: %ldMHz\n", + + seq_printf(m, "clock\t\t: %dMHz\n" + "bus clock\t: %dMHz\n", bp->bi_intfreq / 1000000, bp->bi_busfreq / 1000000); @@ -263,7 +272,7 @@ m8xx_init_IRQ(void) for ( i = 0 ; i < NR_SIU_INTS ; i++ ) irq_desc[i].handler = &ppc8xx_pic; - + /* We could probably incorporate the CPM into the multilevel * interrupt structure. */ @@ -296,7 +305,7 @@ m8xx_find_end_of_memory(void) { bd_t *binfo; extern unsigned char __res[]; - + binfo = (bd_t *)__res; return binfo->bi_memsize; @@ -343,9 +352,11 @@ void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) { + parse_bootinfo(find_bootinfo()); + if ( r3 ) memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) ); - + #ifdef CONFIG_PCI m8xx_setup_pci_ptrs(); #endif @@ -360,7 +371,7 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, #endif /* CONFIG_BLK_DEV_INITRD */ /* take care of cmd line */ if ( r6 ) - { + { *(char *)(r7+KERNELBASE) = 0; strcpy(cmd_line, (char *)(r6+KERNELBASE)); } @@ -394,5 +405,5 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) m8xx_ide_init(); -#endif +#endif } diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index 376fa23dc4b2..6e01a5c36d52 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.misc.S 1.32 10/18/01 17:29:53 trini + * BK Id: %F% %I% %G% %U% %#% */ /* * This file contains miscellaneous low-level functions. @@ -23,7 +23,9 @@ #include <asm/page.h> #include <asm/cache.h> #include <asm/cputable.h> -#include "ppc_asm.h" +#include <asm/mmu.h> +#include <asm/ppc_asm.h> +#include "ppc_defs.h" .text @@ -39,7 +41,6 @@ _GLOBAL(__delay) * Returns (address we're running at) - (address we were linked at) * for use before the text and data are mapped to KERNELBASE. */ - _GLOBAL(reloc_offset) mflr r0 bl 1f @@ -51,6 +52,62 @@ _GLOBAL(reloc_offset) blr /* + * add_reloc_offset(x) returns x + reloc_offset(). + */ +_GLOBAL(add_reloc_offset) + mflr r0 + bl 1f +1: mflr r5 + lis r4,1b@ha + addi r4,r4,1b@l + subf r5,r4,r5 + add r3,r3,r5 + mtlr r0 + blr + +/* + * sub_reloc_offset(x) returns x - reloc_offset(). + */ +_GLOBAL(sub_reloc_offset) + mflr r0 + bl 1f +1: mflr r5 + lis r4,1b@ha + addi r4,r4,1b@l + subf r5,r4,r5 + subf r3,r5,r3 + mtlr r0 + blr + +/* + * reloc_got2 runs through the .got2 section adding an offset + * to each entry. + */ +_GLOBAL(reloc_got2) + mflr r11 + lis r7,__got2_start@ha + addi r7,r7,__got2_start@l + lis r8,__got2_end@ha + addi r8,r8,__got2_end@l + subf r8,r7,r8 + srwi. r8,r8,2 + beqlr + mtctr r8 + bl 1f +1: mflr r0 + lis r4,1b@ha + addi r4,r4,1b@l + subf r0,r4,r0 + add r7,r0,r7 +2: lwz r0,0(r7) + add r0,r0,r3 + stw r0,0(r7) + addi r7,r7,4 + bdnz 2b + mtlr r11 + blr + +/* * identify_cpu, * called with r3 = data offset and r4 = CPU number * doesn't change r3 @@ -81,6 +138,7 @@ _GLOBAL(identify_cpu) * r3 = data offset (not changed) */ _GLOBAL(do_cpu_ftr_fixups) +#ifndef CONFIG_PPC_ISERIES /* Get CPU 0 features */ addis r6,r3,cur_cpu_spec@ha addi r6,r6,cur_cpu_spec@l @@ -124,10 +182,16 @@ _GLOBAL(do_cpu_ftr_fixups) sync /* additional sync needed on g4 */ isync b 1b +#else /* CONFIG_PPC_ISERIES */ + blr +#endif /* CONFIG_PPC_ISERIES */ /* * call_setup_cpu - call the setup_cpu function for this cpu * r3 = data offset, r24 = cpu number + * + * Don't change register layout, the setup function may rely + * on r5 containing a relocated pointer to the current cpu spec. */ _GLOBAL(call_setup_cpu) addis r5,r3,cur_cpu_spec@ha @@ -141,6 +205,7 @@ _GLOBAL(call_setup_cpu) mr r3,r24 bctr +#ifndef CONFIG_PPC_ISERIES /* iSeries version is in iSeries_misc.S */ /* void __save_flags_ptr(unsigned long *flags) */ _GLOBAL(__save_flags_ptr) mfmsr r4 @@ -268,7 +333,7 @@ _GLOBAL(__sti) nop nop _GLOBAL(__sti_end) - +#endif /* CONFIG_PPC_ISERIES */ /* * complement mask on the msr then "or" some values on. @@ -288,6 +353,20 @@ _GLOBAL(_nmask_and_or_msr) * Flush MMU TLB */ _GLOBAL(_tlbia) +#if defined(CONFIG_4xx) && defined(CONFIG_PIN_TLB) + /* This needs to be coordinated with other pinning functions since + * we don't keep a memory location of number of entries to reduce + * cache pollution during these operations. + */ + lis r3, 0 + sync +1: + tlbwe r3, r3, TLB_TAG /* just ensure V is clear */ + addi r3, r3, 1 /* so r3 works fine for that */ + cmpwi 0, r3, 61 /* reserve last two entries */ + ble 1b + isync +#else #if defined(CONFIG_SMP) mfmsr r10 SYNC @@ -296,11 +375,12 @@ _GLOBAL(_tlbia) SYNC lis r9,hash_table_lock@h ori r9,r9,hash_table_lock@l - lwz r8,PROCESSOR(r2) + lwz r8,CPU(r2) oris r8,r8,10 10: lwarx r7,0,r9 cmpi 0,r7,0 bne- 10b + /* No 405 Erratum 77 fix needed here, because 4xx can't do SMP */ stwcx. r8,0,r9 bne- 10b #endif /* CONFIG_SMP */ @@ -314,12 +394,24 @@ _GLOBAL(_tlbia) mtmsr r10 SYNC #endif +#endif blr /* * Flush MMU TLB for a particular address */ _GLOBAL(_tlbie) +#ifdef CONFIG_4xx + tlbsx. r3, 0, r3 + bne 10f + sync + /* There are only 64 TLB entries, so r3 < 64, which means bit 25, is clear. + * Since 25 is the V bit in the TLB_TAG, loading this value will invalidate + * the TLB entry. */ + tlbwe r3, r3, TLB_TAG + isync +10: +#else #if defined(CONFIG_SMP) mfmsr r10 SYNC @@ -328,11 +420,12 @@ _GLOBAL(_tlbie) SYNC lis r9,hash_table_lock@h ori r9,r9,hash_table_lock@l - lwz r8,PROCESSOR(r2) + lwz r8,CPU(r2) oris r8,r8,11 10: lwarx r7,0,r9 cmpi 0,r7,0 bne- 10b + PPC405_ERR77(0,r9) stwcx. r8,0,r9 bne- 10b eieio @@ -346,6 +439,7 @@ _GLOBAL(_tlbie) mtmsr r10 SYNC #endif +#endif /* CONFIG_4xx */ blr /* @@ -358,8 +452,17 @@ _GLOBAL(flush_instruction_cache) lis r5, IDC_INVALL@h mtspr IC_CST, r5 #elif defined(CONFIG_4xx) +#ifdef CONFIG_403GCX + li r3, 512 + mtctr r3 + lis r4, KERNELBASE@h +1: iccci 0, r4 + addi r4, r4, 16 + bdnz 1b +#else lis r3, KERNELBASE@h iccci 0,r3 +#endif #else mfspr r3,PVR rlwinm r3,r3,16,16,31 @@ -369,10 +472,11 @@ _GLOBAL(flush_instruction_cache) mfspr r3,HID0 ori r3,r3,HID0_ICFI mtspr HID0,r3 -#endif /* CONFIG_8xx */ +#endif /* CONFIG_8xx/4xx */ isync blr +#ifndef CONFIG_PPC_ISERIES /* iSeries version is in iSeries_misc.S */ /* * Write any modified data cache blocks out to memory * and invalidate the corresponding instruction cache blocks. @@ -469,15 +573,40 @@ _GLOBAL(invalidate_dcache_range) sync /* wait for dcbi's to get to ram */ blr +#ifdef CONFIG_NOT_COHERENT_CACHE +/* This is a bad one....It is used by 'consistent_sync' functions when + * there isn't any handle on the virtual address needed by the usual + * cache flush instructions. On the MPC8xx, we can use the cache line + * flush command, on others all we can do is read enough data to completely + * reload the cache, flushing old data out. + */ + +/* Cache organization. The 4xx has a 8K (128 line) cache, and the 8xx + * has 1, 2, 4, 8K variants. For now, cover worst case. When we can + * deteremine actual size, we will use that later. + */ +#define CACHE_NWAYS 2 +#define CACHE_NLINES 128 + +_GLOBAL(flush_dcache_all) + li r4, (CACHE_NWAYS * CACHE_NLINES) + mtctr r4 + lis r5, KERNELBASE@h +1: lwz r3, 0(r5) /* Load one word from every line */ + addi r5, r5, L1_CACHE_LINE_SIZE + bdnz 1b + blr +#endif /* CONFIG_NOT_COHERENT_CACHE */ + /* * Flush a particular page from the data cache to RAM. * Note: this is necessary because the instruction cache does *not* * snoop from the data cache. * This is a no-op on the 601 which has a unified cache. * - * void __flush_page_to_ram(void *page) + * void __flush_dcache_icache(void *page) */ -_GLOBAL(__flush_page_to_ram) +_GLOBAL(__flush_dcache_icache) mfspr r5,PVR rlwinm r5,r5,16,16,31 cmpi 0,r5,1 @@ -497,28 +626,6 @@ _GLOBAL(__flush_page_to_ram) sync isync blr - -/* - * Flush a particular page from the instruction cache. - * Note: this is necessary because the instruction cache does *not* - * snoop from the data cache. - * This is a no-op on the 601 which has a unified cache. - * - * void __flush_icache_page(void *page) - */ -_GLOBAL(__flush_icache_page) - mfspr r5,PVR - rlwinm r5,r5,16,16,31 - cmpi 0,r5,1 - beqlr /* for 601, do nothing */ - li r4,4096/L1_CACHE_LINE_SIZE /* Number of lines in a page */ - mtctr r4 -1: icbi 0,r3 - addi r3,r3,L1_CACHE_LINE_SIZE - bdnz 1b - sync - isync - blr /* * Clear a page using the dcbz instruction, which doesn't cause any @@ -563,8 +670,8 @@ _GLOBAL(copy_page) li r5,4 #ifndef CONFIG_8xx -#if MAX_L1_COPY_PREFETCH > 1 - li r0,MAX_L1_COPY_PREFETCH +#if MAX_COPY_PREFETCH > 1 + li r0,MAX_COPY_PREFETCH li r11,4 mtctr r0 11: dcbt r11,r4 @@ -599,6 +706,7 @@ _GLOBAL(copy_page) #endif bdnz 1b blr +#endif /* CONFIG_PPC_ISERIES */ /* * Atomic [test&set] exchange @@ -610,6 +718,7 @@ _GLOBAL(copy_page) _GLOBAL(xchg_u32) mr r5,r3 /* Save pointer */ 10: lwarx r3,0,r5 /* Fetch old value & reserve */ + PPC405_ERR77(0,r5) stwcx. r4,0,r5 /* Update with new value */ bne- 10b /* Retry if "reservation" (i.e. lock) lost */ blr @@ -621,12 +730,14 @@ _GLOBAL(xchg_u32) _GLOBAL(atomic_clear_mask) 10: lwarx r5,0,r4 andc r5,r5,r3 + PPC405_ERR77(0,r4) stwcx. r5,0,r4 bne- 10b blr _GLOBAL(atomic_set_mask) 10: lwarx r5,0,r4 or r5,r5,r3 + PPC405_ERR77(0,r4) stwcx. r5,0,r4 bne- 10b blr @@ -866,10 +977,8 @@ _GLOBAL(kernel_thread) sc cmpi 0,r3,0 /* parent or child? */ bnelr /* return if parent */ - li r0,0 /* clear out p->thread.regs */ - stw r0,THREAD+PT_REGS(r2) /* since we don't have user ctx */ - addi r1,r2,TASK_UNION_SIZE-STACK_FRAME_OVERHEAD - stw r0,0(r1) + li r0,0 /* make top-level stack frame */ + stwu r0,-16(r1) mtlr r6 /* fn addr in lr */ mr r3,r4 /* load arg and call fn */ blrl diff --git a/arch/ppc/kernel/mk_defs.c b/arch/ppc/kernel/mk_defs.c index 2ff838e89c04..cdc35c4d363e 100644 --- a/arch/ppc/kernel/mk_defs.c +++ b/arch/ppc/kernel/mk_defs.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.mk_defs.c 1.11 08/19/01 22:43:23 paulus + * BK Id: %F% %I% %G% %U% %#% */ /* * This program is used to generate definitions needed by @@ -28,6 +28,13 @@ #include <asm/processor.h> #include <asm/cputable.h> +#ifdef CONFIG_PPC_ISERIES +#include <asm/iSeries/Paca.h> +#include <asm/iSeries/ItLpPaca.h> +#include <asm/iSeries/ItLpQueue.h> +#include <asm/iSeries/HvLpEvent.h> +#endif /* CONFIG_PPC_ISERIES */ + #define DEFINE(sym, val) \ asm volatile("\n#define\t" #sym "\t%0" : : "i" (val)) @@ -37,10 +44,8 @@ main(void) /*DEFINE(KERNELBASE, KERNELBASE);*/ DEFINE(STATE, offsetof(struct task_struct, state)); DEFINE(NEXT_TASK, offsetof(struct task_struct, next_task)); - DEFINE(COUNTER, offsetof(struct task_struct, counter)); - DEFINE(PROCESSOR, offsetof(struct task_struct, processor)); -#error DEFINE(SIGPENDING, offsetof(struct task_struct, sigpending)); DEFINE(THREAD, offsetof(struct task_struct, thread)); + DEFINE(CPU, offsetof(struct task_struct, cpu)); DEFINE(MM, offsetof(struct task_struct, mm)); DEFINE(ACTIVE_MM, offsetof(struct task_struct, active_mm)); DEFINE(TASK_STRUCT_SIZE, sizeof(struct task_struct)); @@ -48,10 +53,13 @@ main(void) DEFINE(PGDIR, offsetof(struct thread_struct, pgdir)); DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall)); DEFINE(PT_REGS, offsetof(struct thread_struct, regs)); - DEFINE(PT_TRACESYS, PT_TRACESYS); DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags)); -#error DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace)); -#error DEFINE(NEED_RESCHED, offsetof(struct task_struct, need_resched)); + DEFINE(TASK_WORK, offsetof(struct task_struct, work)); + DEFINE(NEED_RESCHED, offsetof(struct task_struct, work.need_resched)); + DEFINE(SYSCALL_TRACE, offsetof(struct task_struct, work.syscall_trace)); + DEFINE(SIGPENDING, offsetof(struct task_struct, work.sigpending)); + DEFINE(NOTIFY_RESUME, offsetof(struct task_struct, work.notify_resume)); + DEFINE(THREAD_FPEXC_MODE, offsetof(struct thread_struct, fpexc_mode)); DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0])); DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr)); #ifdef CONFIG_ALTIVEC @@ -127,6 +135,35 @@ main(void) DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features)); DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup)); +#ifdef CONFIG_PPC_ISERIES + DEFINE(PACAPROCENABLED, offsetof(struct Paca, xProcEnabled)); + DEFINE(PACAPACAINDEX, offsetof(struct Paca, xPacaIndex)); + DEFINE(PACAPROCSTART, offsetof(struct Paca, xProcStart)); + DEFINE(PACAKSAVE, offsetof(struct Paca, xKsave)); + DEFINE(PACASAVEDMSR, offsetof(struct Paca, xSavedMsr)); + DEFINE(PACASAVEDLR, offsetof(struct Paca, xSavedLr)); + DEFINE(PACACONTEXTOVERFLOW, offsetof(struct Paca, xContextOverflow)); + DEFINE(PACAR21, offsetof(struct Paca, xR21)); + DEFINE(PACAR22, offsetof(struct Paca, xR22)); + DEFINE(PACALPQUEUE, offsetof(struct Paca, lpQueuePtr)); + DEFINE(PACALPPACA, offsetof(struct Paca, xLpPaca)); + DEFINE(PACA_STRUCT_SIZE, sizeof(struct Paca)); + DEFINE(LPREGSAV, offsetof(struct Paca, xRegSav)); + DEFINE(PACADEFAULTDECR, offsetof(struct Paca, default_decr)); + DEFINE(LPPACAANYINT, offsetof(struct ItLpPaca, xRsvd)); + DEFINE(LPPACASRR0, offsetof(struct ItLpPaca, xSavedSrr0)); + DEFINE(LPPACASRR1, offsetof(struct ItLpPaca, xSavedSrr1)); + DEFINE(LPPACADECRINT, offsetof(struct ItLpPaca, xDecrInt)); + DEFINE(LPPACAIPIINT, offsetof(struct ItLpPaca, xIpiCnt)); + DEFINE(LPQCUREVENTPTR, offsetof(struct ItLpQueue, xSlicCurEventPtr)); + DEFINE(LPQOVERFLOW, offsetof(struct ItLpQueue, xPlicOverflowIntPending)); + DEFINE(LPQINUSEWORD, offsetof(struct ItLpQueue, xInUseWord)); + DEFINE(LPEVENTFLAGS, offsetof(struct HvLpEvent, xFlags)); + DEFINE(CONTEXT, offsetof(struct mm_struct, context)); + DEFINE(_SOFTE, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, mq)); + DEFINE(PACA_EXT_INTS, offsetof(struct Paca, ext_ints)); +#endif /* CONFIG_PPC_ISERIES */ + DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28); return 0; } diff --git a/arch/ppc/kernel/mpc10x_common.c b/arch/ppc/kernel/mpc10x_common.c new file mode 100644 index 000000000000..facbf56019d7 --- /dev/null +++ b/arch/ppc/kernel/mpc10x_common.c @@ -0,0 +1,378 @@ + +/* + * arch/ppc/kernel/mpc10x_common.c + * + * Common routines for the Motorola SPS MPC106, MPC107 and MPC8240 Host bridge, + * Mem ctlr, EPIC, etc. + * + * Author: Mark A. Greer + * mgreer@mvista.com + * + * Copyright 2001 MontaVista Software Inc. + * + * 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. + */ + +/* + * *** WARNING - A BAT MUST be set to access the PCI config addr/data regs *** + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/slab.h> + +#include <asm/byteorder.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> +#include <asm/machdep.h> +#include <asm/pci-bridge.h> +#include <asm/open_pic.h> +#include <asm/mpc10x.h> + + +/* Set resources to match bridge memory map */ +void __init +mpc10x_bridge_set_resources(int map, struct pci_controller *hose) +{ + + switch (map) { + case MPC10X_MEM_MAP_A: + pci_init_resource(&hose->io_resource, + 0x00000000, + 0x3f7fffff, + IORESOURCE_IO, + "PCI host bridge"); + + pci_init_resource (&hose->mem_resources[0], + 0xc0000000, + 0xfeffffff, + IORESOURCE_MEM, + "PCI host bridge"); + break; + case MPC10X_MEM_MAP_B: + pci_init_resource(&hose->io_resource, + 0x00000000, + 0x00bfffff, + IORESOURCE_IO, + "PCI host bridge"); + + pci_init_resource (&hose->mem_resources[0], + 0x80000000, + 0xfcffffff, + IORESOURCE_MEM, + "PCI host bridge"); + break; + default: + printk("mpc10x_bridge_set_resources: " + "Invalid map specified\n"); + if (ppc_md.progress) + ppc_md.progress("mpc10x:exit1", 0x100); + } +} +/* + * Do some initialization and put the EUMB registers at the specified address + * (also map the EPIC registers into virtual space--OpenPIC_Addr will be set). + * + * The EPIC is not on the 106, only the 8240 and 107. + */ +int __init +mpc10x_bridge_init(struct pci_controller *hose, + uint current_map, + uint new_map, + uint phys_eumb_base) +{ + int host_bridge, picr1, picr1_bit; + ulong pci_config_addr, pci_config_data; + u_char pir, byte; + + if (ppc_md.progress) ppc_md.progress("mpc10x:enter", 0x100); + + /* Set up for current map so we can get at config regs */ + switch (current_map) { + case MPC10X_MEM_MAP_A: + setup_indirect_pci(hose, + MPC10X_MAPA_CNFG_ADDR, + MPC10X_MAPA_CNFG_DATA); + break; + case MPC10X_MEM_MAP_B: + setup_indirect_pci(hose, + MPC10X_MAPB_CNFG_ADDR, + MPC10X_MAPB_CNFG_DATA); + break; + default: + printk("mpc10x_bridge_init: %s\n", + "Invalid current map specified"); + if (ppc_md.progress) + ppc_md.progress("mpc10x:exit1", 0x100); + return -1; + } + + /* Make sure its a supported bridge */ + early_read_config_dword(hose, + 0, + PCI_DEVFN(0,0), + PCI_VENDOR_ID, + &host_bridge); + + switch (host_bridge) { + case MPC10X_BRIDGE_106: + case MPC10X_BRIDGE_8240: + case MPC10X_BRIDGE_107: + case MPC10X_BRIDGE_8245: + break; + default: + if (ppc_md.progress) + ppc_md.progress("mpc10x:exit2", 0x100); + return -1; + } + + switch (new_map) { + case MPC10X_MEM_MAP_A: + MPC10X_SETUP_HOSE(hose, A); + pci_config_addr = MPC10X_MAPA_CNFG_ADDR; + pci_config_data = MPC10X_MAPA_CNFG_DATA; + picr1_bit = MPC10X_CFG_PICR1_ADDR_MAP_A; + break; + case MPC10X_MEM_MAP_B: + MPC10X_SETUP_HOSE(hose, B); + pci_config_addr = MPC10X_MAPB_CNFG_ADDR; + pci_config_data = MPC10X_MAPB_CNFG_DATA; + picr1_bit = MPC10X_CFG_PICR1_ADDR_MAP_B; + break; + default: + printk("mpc10x_bridge_init: %s\n", + "Invalid new map specified"); + if (ppc_md.progress) + ppc_md.progress("mpc10x:exit3", 0x100); + return -1; + } + + /* Make bridge use the 'new_map', if not already usng it */ + if (current_map != new_map) { + early_read_config_dword(hose, + 0, + PCI_DEVFN(0,0), + MPC10X_CFG_PICR1_REG, + &picr1); + + picr1 = (picr1 & ~MPC10X_CFG_PICR1_ADDR_MAP_MASK) | + picr1_bit; + + early_write_config_dword(hose, + 0, + PCI_DEVFN(0,0), + MPC10X_CFG_PICR1_REG, + picr1); + + asm volatile("sync"); + + /* Undo old mappings & map in new cfg data/addr regs */ + iounmap((void *)hose->cfg_addr); + iounmap((void *)hose->cfg_data); + + setup_indirect_pci(hose, + pci_config_addr, + pci_config_data); + } + + /* Setup resources to match map */ + mpc10x_bridge_set_resources(new_map, hose); + + /* + * Want processor accesses of 0xFDxxxxxx to be mapped + * to PCI memory space at 0x00000000. Do not want + * host bridge to respond to PCI memory accesses of + * 0xFDxxxxxx. Do not want host bridge to respond + * to PCI memory addresses 0xFD000000-0xFDFFFFFF; + * want processor accesses from 0x000A0000-0x000BFFFF + * to be forwarded to system memory. + * + * Only valid if not in agent mode and using MAP B. + */ + if (new_map == MPC10X_MEM_MAP_B) { + early_read_config_byte(hose, + 0, + PCI_DEVFN(0,0), + MPC10X_CFG_MAPB_OPTIONS_REG, + &byte); + + byte &= ~(MPC10X_CFG_MAPB_OPTIONS_PFAE | + MPC10X_CFG_MAPB_OPTIONS_PCICH | + MPC10X_CFG_MAPB_OPTIONS_PROCCH); + + if (host_bridge != MPC10X_BRIDGE_106) { + byte |= MPC10X_CFG_MAPB_OPTIONS_CFAE; + } + + early_write_config_byte(hose, + 0, + PCI_DEVFN(0,0), + MPC10X_CFG_MAPB_OPTIONS_REG, + byte); + } + + if (host_bridge != MPC10X_BRIDGE_106) { + early_read_config_byte(hose, + 0, + PCI_DEVFN(0,0), + MPC10X_CFG_PIR_REG, + &pir); + + if (pir != MPC10X_CFG_PIR_HOST_BRIDGE) { + printk("Host bridge in Agent mode\n"); + /* Read or Set LMBAR & PCSRBAR? */ + } + + /* Set base addr of the 8240/107 EUMB. */ + early_write_config_dword(hose, + 0, + PCI_DEVFN(0,0), + MPC10X_CFG_EUMBBAR, + phys_eumb_base); + + /* Map EPIC register part of EUMB into vitual memory */ + OpenPIC_Addr = + ioremap(phys_eumb_base + MPC10X_EUMB_EPIC_OFFSET, + MPC10X_EUMB_EPIC_SIZE); + } + +#ifdef CONFIG_MPC10X_STORE_GATHERING + mpc10x_enable_store_gathering(hose); +#endif + + if (ppc_md.progress) ppc_md.progress("mpc10x:exit", 0x100); + return 0; +} + +/* + * Need to make our own PCI config space access macros because + * mpc10x_get_mem_size() is called before the data structures are set up for + * the 'early_xxx' and 'indirect_xxx' routines to work. + * Assumes bus 0. + */ +#define MPC10X_CFG_read(val, addr, type, op) *val = op((type)(addr)) +#define MPC10X_CFG_write(val, addr, type, op) op((type *)(addr), (val)) + +#define MPC10X_PCI_OP(rw, size, type, op, mask) \ +static void \ +mpc10x_##rw##_config_##size(uint *cfg_addr, uint *cfg_data, int devfn, int offset, type val) \ +{ \ + out_be32(cfg_addr, \ + ((offset & 0xfc) << 24) | (devfn << 16) \ + | (0 << 8) | 0x80); \ + MPC10X_CFG_##rw(val, cfg_data + (offset & mask), type, op); \ + return; \ +} + +MPC10X_PCI_OP(read, byte, u8 *, in_8, 3) +MPC10X_PCI_OP(read, dword, u32 *, in_le32, 0) +#if 0 /* Not used */ +MPC10X_PCI_OP(write, byte, u8, out_8, 3) +MPC10X_PCI_OP(read, word, u16 *, in_le16, 2) +MPC10X_PCI_OP(write, word, u16, out_le16, 2) +MPC10X_PCI_OP(write, dword, u32, out_le32, 0) +#endif + +/* + * Read the memory controller registers to determine the amount of memory in + * the system. This assumes that the firmware has correctly set up the memory + * controller registers. + */ +unsigned long __init +mpc10x_get_mem_size(uint mem_map) +{ + uint *config_addr, *config_data, val; + ulong start, end, total, offset; + int i; + u_char bank_enables; + + switch (mem_map) { + case MPC10X_MEM_MAP_A: + config_addr = (uint *)MPC10X_MAPA_CNFG_ADDR; + config_data = (uint *)MPC10X_MAPA_CNFG_DATA; + break; + case MPC10X_MEM_MAP_B: + config_addr = (uint *)MPC10X_MAPB_CNFG_ADDR; + config_data = (uint *)MPC10X_MAPB_CNFG_DATA; + break; + default: + return 0; + } + + mpc10x_read_config_byte(config_addr, + config_data, + PCI_DEVFN(0,0), + MPC10X_MCTLR_MEM_BANK_ENABLES, + &bank_enables); + + total = 0; + + for (i=0; i<8; i++) { + if (bank_enables & (1 << i)) { + offset = MPC10X_MCTLR_MEM_START_1 + ((i > 3) ? 4 : 0); + mpc10x_read_config_dword(config_addr, + config_data, + PCI_DEVFN(0,0), + offset, + &val); + start = (val >> ((i & 3) << 3)) & 0xff; + + offset = MPC10X_MCTLR_EXT_MEM_START_1 + ((i>3) ? 4 : 0); + mpc10x_read_config_dword(config_addr, + config_data, + PCI_DEVFN(0,0), + offset, + &val); + val = (val >> ((i & 3) << 3)) & 0x03; + start = (val << 28) | (start << 20); + + offset = MPC10X_MCTLR_MEM_END_1 + ((i > 3) ? 4 : 0); + mpc10x_read_config_dword(config_addr, + config_data, + PCI_DEVFN(0,0), + offset, + &val); + end = (val >> ((i & 3) << 3)) & 0xff; + + offset = MPC10X_MCTLR_EXT_MEM_END_1 + ((i > 3) ? 4 : 0); + mpc10x_read_config_dword(config_addr, + config_data, + PCI_DEVFN(0,0), + offset, + &val); + val = (val >> ((i & 3) << 3)) & 0x03; + end = (val << 28) | (end << 20) | 0xfffff; + + total += (end - start + 1); + } + } + + return total; +} + +int __init +mpc10x_enable_store_gathering(struct pci_controller *hose) +{ + uint picr1; + + early_read_config_dword(hose, + 0, + PCI_DEVFN(0,0), + MPC10X_CFG_PICR1_REG, + &picr1); + + picr1 |= MPC10X_CFG_PICR1_ST_GATH_EN; + + early_write_config_dword(hose, + 0, + PCI_DEVFN(0,0), + MPC10X_CFG_PICR1_REG, + picr1); + + return 0; +} diff --git a/arch/ppc/kernel/oak_setup.c b/arch/ppc/kernel/oak_setup.c deleted file mode 100644 index 8d49dbbefff5..000000000000 --- a/arch/ppc/kernel/oak_setup.c +++ /dev/null @@ -1,297 +0,0 @@ -/* - * BK Id: SCCS/s.oak_setup.c 1.12 11/13/01 21:26:07 paulus - */ -/* - * - * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu> - * - * Module name: oak_setup.c - * - * Description: - * Architecture- / platform-specific boot-time initialization code for - * the IBM PowerPC 403GCX "Oak" evaluation board. Adapted from original - * code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek - * <dan@net4x.com>. - * - */ - -#include <linux/config.h> -#include <linux/init.h> -#include <linux/smp.h> -#include <linux/threads.h> -#include <linux/interrupt.h> -#include <linux/param.h> -#include <linux/string.h> -#include <linux/blk.h> -#include <linux/seq_file.h> - -#include <asm/processor.h> -#include <asm/board.h> -#include <asm/machdep.h> -#include <asm/page.h> - -#include "local_irq.h" -#include "ppc4xx_pic.h" -#include <asm/time.h> -#include "oak_setup.h" - - - - - - - -/* Function Prototypes */ - -extern void abort(void); - -/* Global Variables */ - -unsigned char __res[sizeof(bd_t)]; - - -/* - * void __init oak_init() - * - * Description: - * This routine... - * - * Input(s): - * r3 - Optional pointer to a board information structure. - * r4 - Optional pointer to the physical starting address of the init RAM - * disk. - * r5 - Optional pointer to the physical ending address of the init RAM - * disk. - * r6 - Optional pointer to the physical starting address of any kernel - * command-line parameters. - * r7 - Optional pointer to the physical ending address of any kernel - * command-line parameters. - * - * Output(s): - * N/A - * - * Returns: - * N/A - * - */ -void __init -platform_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - /* - * If we were passed in a board information, copy it into the - * residual data area. - */ - if (r3) { - memcpy((void *)__res, (void *)(r3 + KERNELBASE), sizeof(bd_t)); - } - -#if defined(CONFIG_BLK_DEV_INITRD) - /* - * If the init RAM disk has been configured in, and there's a valid - * starting address for it, set it up. - */ - if (r4) { - initrd_start = r4 + KERNELBASE; - initrd_end = r5 + KERNELBASE; - } -#endif /* CONFIG_BLK_DEV_INITRD */ - - /* Copy the kernel command line arguments to a safe place. */ - - if (r6) { - *(char *)(r7 + KERNELBASE) = 0; - strcpy(cmd_line, (char *)(r6 + KERNELBASE)); - } - - /* Initialize machine-dependency vectors */ - - ppc_md.setup_arch = oak_setup_arch; - ppc_md.show_percpuinfo = oak_show_percpuinfo; - ppc_md.irq_cannonicalize = NULL; - ppc_md.init_IRQ = oak_init_IRQ; - ppc_md.get_irq = oak_get_irq; - ppc_md.init = NULL; - - ppc_md.restart = oak_restart; - ppc_md.power_off = oak_power_off; - ppc_md.halt = oak_halt; - - ppc_md.time_init = oak_time_init; - ppc_md.set_rtc_time = oak_set_rtc_time; - ppc_md.get_rtc_time = oak_get_rtc_time; - ppc_md.calibrate_decr = oak_calibrate_decr; - - ppc_md.kbd_setkeycode = NULL; - ppc_md.kbd_getkeycode = NULL; - ppc_md.kbd_translate = NULL; - ppc_md.kbd_unexpected_up = NULL; - ppc_md.kbd_leds = NULL; - ppc_md.kbd_init_hw = NULL; - ppc_md.ppc_kbd_sysrq_xlate = NULL; -} - -/* - * Document me. - */ -void __init -oak_setup_arch(void) -{ - /* XXX - Implement me */ -} - -/* - * int oak_show_percpuinfo() - * - * Description: - * This routine pretty-prints the platform's internal CPU and bus clock - * frequencies into the buffer for usage in /proc/cpuinfo. - * - * Input(s): - * *buffer - Buffer into which CPU and bus clock frequencies are to be - * printed. - * - * Output(s): - * *buffer - Buffer with the CPU and bus clock frequencies. - * - * Returns: - * The number of bytes copied into 'buffer' if OK, otherwise zero or less - * on error. - */ -int -oak_show_percpuinfo(struct seq_file *m, int i) -{ - bd_t *bp = (bd_t *)__res; - - seq_printf(m, "clock\t\t: %dMHz\n" - "bus clock\t\t: %dMHz\n", - bp->bi_intfreq / 1000000, - bp->bi_busfreq / 1000000); - - return 0; -} - -/* - * Document me. - */ -void __init -oak_init_IRQ(void) -{ - int i; - - ppc4xx_pic_init(); - - for (i = 0; i < NR_IRQS; i++) { - irq_desc[i].handler = ppc4xx_pic; - } - - return; -} - -/* - * Document me. - */ -int -oak_get_irq(struct pt_regs *regs) -{ - return (ppc4xx_pic_get_irq(regs)); -} - -/* - * Document me. - */ -void -oak_restart(char *cmd) -{ - abort(); -} - -/* - * Document me. - */ -void -oak_power_off(void) -{ - oak_restart(NULL); -} - -/* - * Document me. - */ -void -oak_halt(void) -{ - oak_restart(NULL); -} - -/* - * Document me. - */ -long __init -oak_time_init(void) -{ - /* XXX - Implement me */ - return 0; -} - -/* - * Document me. - */ -int __init -oak_set_rtc_time(unsigned long time) -{ - /* XXX - Implement me */ - - return (0); -} - -/* - * Document me. - */ -unsigned long __init -oak_get_rtc_time(void) -{ - /* XXX - Implement me */ - - return (0); -} - -/* - * void __init oak_calibrate_decr() - * - * Description: - * This routine retrieves the internal processor frequency from the board - * information structure, sets up the kernel timer decrementer based on - * that value, enables the 403 programmable interval timer (PIT) and sets - * it up for auto-reload. - * - * Input(s): - * N/A - * - * Output(s): - * N/A - * - * Returns: - * N/A - * - */ -void __init -oak_calibrate_decr(void) -{ - unsigned int freq; - bd_t *bip = (bd_t *)__res; - - freq = bip->bi_intfreq; - - decrementer_count = freq / HZ; - count_period_num = 1; - count_period_den = freq; - - /* Enable the PIT and set auto-reload of its value */ - - mtspr(SPRN_TCR, TCR_PIE | TCR_ARE); - - /* Clear any pending timer interrupts */ - - mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_PIS | TSR_FIS); -} diff --git a/arch/ppc/kernel/oak_setup.h b/arch/ppc/kernel/oak_setup.h deleted file mode 100644 index c51e15ec6b0c..000000000000 --- a/arch/ppc/kernel/oak_setup.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * BK Id: SCCS/s.oak_setup.h 1.5 05/17/01 18:14:21 cort - */ -/* - * - * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu> - * - * Module name: oak_setup.h - * - * Description: - * Architecture- / platform-specific boot-time initialization code for - * the IBM PowerPC 403GCX "Oak" evaluation board. Adapted from original - * code by Gary Thomas, Cort Dougan <cort@cs.nmt.edu>, and Dan Malek - * <dan@netx4.com>. - * - */ - -#ifndef __OAK_SETUP_H__ -#define __OAK_SETUP_H__ - -#include <asm/ptrace.h> -#include <asm/board.h> - - -#ifdef __cplusplus -extern "C" { -#endif - -extern unsigned char __res[sizeof(bd_t)]; - -extern void oak_init(unsigned long r3, - unsigned long ird_start, - unsigned long ird_end, - unsigned long cline_start, - unsigned long cline_end); -extern void oak_setup_arch(void); -extern int oak_setup_residual(char *buffer); -extern void oak_init_IRQ(void); -extern int oak_get_irq(struct pt_regs *regs); -extern void oak_restart(char *cmd); -extern void oak_power_off(void); -extern void oak_halt(void); -extern void oak_time_init(void); -extern int oak_set_rtc_time(unsigned long now); -extern unsigned long oak_get_rtc_time(void); -extern void oak_calibrate_decr(void); - - -#ifdef __cplusplus -} -#endif - -#endif /* __OAK_SETUP_H__ */ diff --git a/arch/ppc/kernel/open_pic.c b/arch/ppc/kernel/open_pic.c index c5c8a7e155f0..676d97101e9b 100644 --- a/arch/ppc/kernel/open_pic.c +++ b/arch/ppc/kernel/open_pic.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.open_pic.c 1.31 10/11/01 12:09:11 trini + * BK Id: %F% %I% %G% %U% %#% */ /* * arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling @@ -17,40 +17,40 @@ #include <linux/sched.h> #include <linux/init.h> #include <linux/irq.h> -#include <linux/init.h> #include <asm/ptrace.h> #include <asm/signal.h> #include <asm/io.h> #include <asm/irq.h> #include <asm/prom.h> #include <asm/sections.h> +#include <asm/open_pic.h> +#include <asm/i8259.h> -#include "local_irq.h" -#include "open_pic.h" #include "open_pic_defs.h" +#ifdef CONFIG_PRPMC800 +#define OPENPIC_BIG_ENDIAN +#endif + void* OpenPIC_Addr; static volatile struct OpenPIC *OpenPIC = NULL; u_int OpenPIC_NumInitSenses __initdata = 0; u_char *OpenPIC_InitSenses __initdata = NULL; extern int use_of_interrupt_tree; -void find_ISUs(void); - static u_int NumProcessors; static u_int NumSources; -#ifdef CONFIG_POWER3 -static int NumISUs; -#endif static int open_pic_irq_offset; static volatile unsigned char* chrp_int_ack_special; - -OpenPIC_SourcePtr ISU[OPENPIC_MAX_ISU]; +static volatile OpenPIC_Source *ISR[NR_IRQS]; /* Global Operations */ static void openpic_disable_8259_pass_through(void); static void openpic_set_priority(u_int pri); static void openpic_set_spurious(u_int vector); +static void openpic_enable_sie(void); +static void openpic_eicr_set_clk(u_int clkval); +static void openpic_eicr_set_clk(u_int clkval); #ifdef CONFIG_SMP /* Interprocessor Interrupts */ @@ -67,7 +67,7 @@ static void openpic_enable_irq(u_int irq); static void openpic_disable_irq(u_int irq); static void openpic_initirq(u_int irq, u_int pri, u_int vector, int polarity, int is_level); -static void openpic_mapirq(u_int irq, u_int cpumask); +static void openpic_mapirq(u_int irq, u_int cpumask, u_int keepmask); /* * These functions are not used but the code is kept here @@ -150,7 +150,8 @@ struct hw_interrupt_type open_pic_ipi = { */ extern unsigned long* _get_SP(void); #define check_arg_irq(irq) \ - if (irq < open_pic_irq_offset || irq >= (NumSources+open_pic_irq_offset)){ \ + if (irq < open_pic_irq_offset || irq >= NumSources+open_pic_irq_offset \ + || ISR[irq - open_pic_irq_offset] == 0) { \ printk("open_pic.c:%d: illegal irq %d\n", __LINE__, irq); \ print_backtrace(_get_SP()); } #define check_arg_cpu(cpu) \ @@ -166,23 +167,25 @@ extern unsigned long* _get_SP(void); #define check_arg_cpu(cpu) do {} while (0) #endif -#ifdef CONFIG_POWER3 - #define GET_ISU(source) ISU[(source) >> 4][(source) & 0xf] -#else - #define GET_ISU(source) ISU[0][(source)] -#endif - u_int openpic_read(volatile u_int *addr) { u_int val; +#ifdef OPENPIC_BIG_ENDIAN + val = in_be32(addr); +#else val = in_le32(addr); +#endif return val; } static inline void openpic_write(volatile u_int *addr, u_int val) { +#ifdef OPENPIC_BIG_ENDIAN + out_be32(addr, val); +#else out_le32(addr, val); +#endif } static inline u_int openpic_readfield(volatile u_int *addr, u_int mask) @@ -221,7 +224,7 @@ static void openpic_safe_writefield(volatile u_int *addr, u_int mask, u_int openpic_read_IPI(volatile u_int* addr) { u_int val = 0; -#ifdef CONFIG_POWER3 +#if defined(OPENPIC_BIG_ENDIAN) || defined(CONFIG_POWER3) val = in_be32(addr); #else val = in_le32(addr); @@ -260,6 +263,20 @@ static void openpic_safe_writefield_IPI(volatile u_int *addr, u_int mask, u_int } #endif /* CONFIG_SMP */ +void openpic_set_sources(int first_irq, int num_irqs, void *first_ISR) +{ + volatile OpenPIC_Source *src = first_ISR; + int i, last_irq; + + last_irq = first_irq + num_irqs; + if (last_irq > NumSources) + NumSources = last_irq; + if (src == 0) + src = &((struct OpenPIC *)OpenPIC_Addr)->Source[first_irq]; + for (i = first_irq; i < last_irq; ++i, ++src) + ISR[i] = src; +} + void __init openpic_init(int main_pic, int offset, unsigned char* chrp_ack, int programmer_switch_irq) { @@ -273,7 +290,13 @@ void __init openpic_init(int main_pic, int offset, unsigned char* chrp_ack, } OpenPIC = (volatile struct OpenPIC *)OpenPIC_Addr; - if ( ppc_md.progress ) ppc_md.progress("openpic enter",0x122); +#ifdef CONFIG_EPIC_SERIAL_MODE + /* Have to start from ground zero. + */ + openpic_reset(); +#endif + + if (ppc_md.progress) ppc_md.progress("openpic enter", 0x122); t = openpic_read(&OpenPIC->Global.Feature_Reporting0); switch (t & OPENPIC_FEATURE_VERSION_MASK) { @@ -292,8 +315,11 @@ void __init openpic_init(int main_pic, int offset, unsigned char* chrp_ack, } NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >> OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1; - NumSources = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >> - OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1; + if (NumSources == 0) + openpic_set_sources(0, + ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >> + OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1, + NULL); printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n", version, NumProcessors, NumSources, OpenPIC); timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency); @@ -328,8 +354,6 @@ void __init openpic_init(int main_pic, int offset, unsigned char* chrp_ack, } #endif - find_ISUs(); - /* Initialize external interrupts */ if (ppc_md.progress) ppc_md.progress("openpic ext",0x3bc); @@ -338,13 +362,16 @@ void __init openpic_init(int main_pic, int offset, unsigned char* chrp_ack, /* SIOint (8259 cascade) is special */ if (offset) { openpic_initirq(0, 8, offset, 1, 1); - openpic_mapirq(0, 1<<0); + openpic_mapirq(0, 1<<0, 0); } /* Init all external sources */ for (i = 1; i < NumSources; i++) { int pri, sense; + if (ISR[i] == 0) + continue; + /* the bootloader may have left it enabled (bad !) */ openpic_disable_irq(i+offset); @@ -356,7 +383,7 @@ void __init openpic_init(int main_pic, int offset, unsigned char* chrp_ack, /* Enabled, Priority 8 or 9 */ openpic_initirq(i, pri, i+offset, !sense, sense); /* Processor 0 */ - openpic_mapirq(i, 1<<0); + openpic_mapirq(i, 1<<0, 0); } /* Init descriptors */ @@ -373,43 +400,17 @@ void __init openpic_init(int main_pic, int offset, unsigned char* chrp_ack, "82c59 cascade", NULL)) printk("Unable to get OpenPIC IRQ 0 for cascade\n"); } +#ifdef CONFIG_EPIC_SERIAL_MODE + openpic_disable_8259_pass_through(); + openpic_eicr_set_clk(7); /* Slowest value until we know better */ + openpic_enable_sie(); openpic_set_priority(0); - openpic_disable_8259_pass_through(); - - if (ppc_md.progress) ppc_md.progress("openpic exit",0x222); -} - -#ifdef CONFIG_POWER3 -void openpic_setup_ISU(int isu_num, unsigned long addr) -{ - if (isu_num >= OPENPIC_MAX_ISU) - return; - ISU[isu_num] = (OpenPIC_SourcePtr) ioremap(addr, 0x400); - if (isu_num >= NumISUs) - NumISUs = isu_num + 1; -} -#endif - -void find_ISUs(void) -{ -#ifdef CONFIG_POWER3 - /* Use /interrupt-controller/reg and - * /interrupt-controller/interrupt-ranges from OF device tree - * the ISU array is setup in chrp_pci.c in ibm_add_bridges - * as a result - * -- tgall - */ - - /* basically each ISU is a bus, and this assumes that - * open_pic_isu_count interrupts per bus are possible - * ISU == Interrupt Source - */ - NumSources = NumISUs * 0x10; - #else - /* for non-distributed OpenPIC implementations it's in the IDU -- Cort */ - ISU[0] = (OpenPIC_Source *)OpenPIC->Source; + openpic_disable_8259_pass_through(); + openpic_set_priority(0); #endif + + if (ppc_md.progress) ppc_md.progress("openpic exit",0x222); } static void openpic_reset(void) @@ -421,6 +422,18 @@ static void openpic_reset(void) mb(); } +static void openpic_enable_sie(void) +{ + openpic_setfield(&OpenPIC->Global.Global_Configuration1, + OPENPIC_EICR_SIE); +} + +static void openpic_eicr_set_clk(u_int clkval) +{ + openpic_writefield(&OpenPIC->Global.Global_Configuration1, + OPENPIC_EICR_S_CLK_MASK, (clkval << 28)); +} + #ifdef notused static void openpic_enable_8259_pass_through(void) { @@ -602,8 +615,8 @@ void __init do_openpic_setup_cpu(void) * we should make sure we also change the default values of irq_affinity * in irq.c. */ - for (i = 0; i < NumSources ; i++) - openpic_mapirq(i, openpic_read(&GET_ISU(i).Destination) | msk); + for (i = 0; i < NumSources; i++) + openpic_mapirq(i, msk, ~0U); #endif /* CONFIG_IRQ_ALL_CPUS */ openpic_set_priority(0); @@ -653,26 +666,29 @@ static void __init openpic_maptimer(u_int timer, u_int cpumask) */ static void openpic_enable_irq(u_int irq) { + volatile u_int *vpp; + check_arg_irq(irq); - openpic_clearfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, OPENPIC_MASK); + vpp = &ISR[irq - open_pic_irq_offset]->Vector_Priority; + openpic_clearfield(vpp, OPENPIC_MASK); /* make sure mask gets to controller before we return to user */ do { mb(); /* sync is probably useless here */ - } while(openpic_readfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, - OPENPIC_MASK)); + } while (openpic_readfield(vpp, OPENPIC_MASK)); } static void openpic_disable_irq(u_int irq) { + volatile u_int *vpp; u32 vp; check_arg_irq(irq); - openpic_setfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, OPENPIC_MASK); + vpp = &ISR[irq - open_pic_irq_offset]->Vector_Priority; + openpic_setfield(vpp, OPENPIC_MASK); /* make sure mask gets to controller before we return to user */ do { mb(); /* sync is probably useless here */ - vp = openpic_readfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, - OPENPIC_MASK | OPENPIC_ACTIVITY); + vp = openpic_readfield(vpp, OPENPIC_MASK | OPENPIC_ACTIVITY); } while((vp & OPENPIC_ACTIVITY) && !(vp & OPENPIC_MASK)); } @@ -709,7 +725,7 @@ void openpic_disable_ipi(u_int irq) */ static void openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense) { - openpic_safe_writefield(&GET_ISU(irq).Vector_Priority, + openpic_safe_writefield(&ISR[irq]->Vector_Priority, OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK | OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK, (pri << OPENPIC_PRIORITY_SHIFT) | vec | @@ -721,9 +737,13 @@ static void openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense) /* * Map an interrupt source to one or more CPUs */ -static void openpic_mapirq(u_int irq, u_int physmask) +static void openpic_mapirq(u_int irq, u_int physmask, u_int keepmask) { - openpic_write(&GET_ISU(irq).Destination, physmask); + if (ISR[irq] == 0) + return; + if (keepmask != 0) + physmask |= openpic_read(&ISR[irq]->Destination) & keepmask; + openpic_write(&ISR[irq]->Destination, physmask); } #ifdef notused @@ -734,9 +754,10 @@ static void openpic_mapirq(u_int irq, u_int physmask) */ static void openpic_set_sense(u_int irq, int sense) { - openpic_safe_writefield(&GET_ISU(irq).Vector_Priority, - OPENPIC_SENSE_LEVEL, - (sense ? OPENPIC_SENSE_LEVEL : 0)); + if (ISR[irq] != 0) + openpic_safe_writefield(&ISR[irq]->Vector_Priority, + OPENPIC_SENSE_LEVEL, + (sense ? OPENPIC_SENSE_LEVEL : 0)); } #endif /* notused */ @@ -757,7 +778,7 @@ static void openpic_end_irq(unsigned int irq_nr) static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask) { - openpic_mapirq(irq_nr - open_pic_irq_offset, physmask(cpumask)); + openpic_mapirq(irq_nr - open_pic_irq_offset, physmask(cpumask), 0); } #ifdef CONFIG_SMP @@ -784,9 +805,6 @@ openpic_get_irq(struct pt_regs *regs) /* * Clean up needed. -VAL */ -#ifndef CONFIG_GEMINI - extern int i8259_irq(int cpu); -#endif int irq = openpic_irq(); /* Management of the cascade should be moved out of here */ @@ -801,7 +819,7 @@ openpic_get_irq(struct pt_regs *regs) irq = *chrp_int_ack_special; #ifndef CONFIG_GEMINI else - irq = i8259_irq( smp_processor_id() ); + irq = i8259_poll(); #endif openpic_eoi(); } @@ -858,9 +876,11 @@ openpic_sleep_save_intrs(void) for (i=0; i<OPENPIC_NUM_IPI; i++) save_ipi_vp[i] = openpic_read(&OpenPIC->Global.IPI_Vector_Priority(i)); for (i=0; i<NumSources; i++) { - save_irq_src_vp[i] = openpic_read(&OpenPIC->Source[i].Vector_Priority) + if (ISR[i] == 0) + continue; + save_irq_src_vp[i] = openpic_read(&ISR[i]->Vector_Priority) & ~OPENPIC_ACTIVITY; - save_irq_src_dest[i] = openpic_read(&OpenPIC->Source[i].Destination); + save_irq_src_dest[i] = openpic_read(&ISR[i]->Destination); } spin_unlock_irqrestore(&openpic_setup_lock, flags); } @@ -876,15 +896,19 @@ openpic_sleep_restore_intrs(void) openpic_reset(); for (i=0; i<OPENPIC_NUM_IPI; i++) - openpic_write(&OpenPIC->Global.IPI_Vector_Priority(i), save_ipi_vp[i]); + openpic_write(&OpenPIC->Global.IPI_Vector_Priority(i), + save_ipi_vp[i]); for (i=0; i<NumSources; i++) { - openpic_write(&OpenPIC->Source[i].Vector_Priority, save_irq_src_vp[i]); - openpic_write(&OpenPIC->Source[i].Destination, save_irq_src_dest[i]); + if (ISR[i] == 0) + continue; + openpic_write(&ISR[i]->Vector_Priority, save_irq_src_vp[i]); + openpic_write(&ISR[i]->Destination, save_irq_src_dest[i]); } openpic_set_spurious(OPENPIC_VEC_SPURIOUS+open_pic_irq_offset); openpic_disable_8259_pass_through(); for (i=0; i<NumProcessors; i++) - openpic_write(&OpenPIC->Processor[i].Current_Task_Priority, save_cpu_task_pri[i]); + openpic_write(&OpenPIC->Processor[i].Current_Task_Priority, + save_cpu_task_pri[i]); spin_unlock_irqrestore(&openpic_setup_lock, flags); } diff --git a/arch/ppc/kernel/open_pic.h b/arch/ppc/kernel/open_pic.h deleted file mode 100644 index 0e236c0b3848..000000000000 --- a/arch/ppc/kernel/open_pic.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * BK Id: SCCS/s.open_pic.h 1.14 10/11/01 12:09:12 trini - */ -/* - * arch/ppc/kernel/open_pic.h -- OpenPIC Interrupt Handling - * - * Copyright (C) 1997 Geert Uytterhoeven - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - * - */ - -#ifndef _PPC_KERNEL_OPEN_PIC_H -#define _PPC_KERNEL_OPEN_PIC_H - -#include <linux/config.h> - -#define OPENPIC_SIZE 0x40000 - -/* - * Non-offset'ed vector numbers - */ - -#define OPENPIC_VEC_TIMER 64 /* and up */ -#define OPENPIC_VEC_IPI 72 /* and up */ -#define OPENPIC_VEC_SPURIOUS 127 - -/* OpenPIC IRQ controller structure */ -extern struct hw_interrupt_type open_pic; - -/* OpenPIC IPI controller structure */ -#ifdef CONFIG_SMP -extern struct hw_interrupt_type open_pic_ipi; -#endif /* CONFIG_SMP */ - -extern u_int OpenPIC_NumInitSenses; -extern u_char *OpenPIC_InitSenses; -extern void* OpenPIC_Addr; - -/* Exported functions */ -extern void openpic_init(int, int, unsigned char *, int); -extern u_int openpic_irq(void); -extern void openpic_eoi(void); -extern void openpic_request_IPIs(void); -extern void do_openpic_setup_cpu(void); -extern int openpic_get_irq(struct pt_regs *regs); -extern void openpic_reset_processor_phys(u_int cpumask); -extern void openpic_setup_ISU(int isu_num, unsigned long addr); -extern void openpic_cause_IPI(u_int ipi, u_int cpumask); -extern void smp_openpic_message_pass(int target, int msg, unsigned long data, - int wait); - -extern inline int openpic_to_irq(int irq) -{ - /* IRQ 0 usually means 'disabled'.. don't mess with it - * exceptions to this (sandpoint maybe?) - * shouldn't use openpic_to_irq - */ - if (irq != 0){ - return irq += NUM_8259_INTERRUPTS; - } else { - return 0; - } -} -/*extern int open_pic_irq_offset;*/ -#endif /* _PPC_KERNEL_OPEN_PIC_H */ diff --git a/arch/ppc/kernel/open_pic_defs.h b/arch/ppc/kernel/open_pic_defs.h index 56497f9579ac..753461a5e8e7 100644 --- a/arch/ppc/kernel/open_pic_defs.h +++ b/arch/ppc/kernel/open_pic_defs.h @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.open_pic_defs.h 1.8 08/20/01 22:33:28 paulus + * BK Id: %F% %I% %G% %U% %#% */ /* * linux/openpic.h -- OpenPIC definitions @@ -209,6 +209,14 @@ extern volatile struct OpenPIC *OpenPIC; #define OPENPIC_CONFIG_BASE_MASK 0x000fffff /* + * Global Configuration Register 1 + * This is the EICR on EPICs. + */ + +#define OPENPIC_EICR_S_CLK_MASK 0x70000000 +#define OPENPIC_EICR_SIE 0x08000000 + + /* * Vendor Identification Register */ diff --git a/arch/ppc/kernel/pci-dma.c b/arch/ppc/kernel/pci-dma.c index 1a7b56b89e82..2e37b3117585 100644 --- a/arch/ppc/kernel/pci-dma.c +++ b/arch/ppc/kernel/pci-dma.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.pci-dma.c 1.5 05/17/01 18:14:21 cort + * BK Id: %F% %I% %G% %U% %#% */ /* * Copyright (C) 2000 Ani Joshi <ajoshi@unixbox.com> @@ -25,7 +25,11 @@ void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, if (hwdev == NULL || hwdev->dma_mask != 0xffffffff) gfp |= GFP_DMA; +#ifdef CONFIG_NOT_COHERENT_CACHE + ret = consistent_alloc(gfp, size, dma_handle); +#else ret = (void *)__get_free_pages(gfp, get_order(size)); +#endif if (ret != NULL) { memset(ret, 0, size); @@ -37,5 +41,9 @@ void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) { +#ifdef CONFIG_NOT_COHERENT_CACHE + consistent_free(vaddr); +#else free_pages((unsigned long)vaddr, get_order(size)); +#endif } diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index 57c4223a482f..77e1de956a6b 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.pci.c 1.35 11/13/01 08:19:57 trini + * BK Id: %F% %I% %G% %U% %#% */ /* * Common pmac/prep/chrp pci routines. -- Cort @@ -19,16 +19,13 @@ #include <asm/processor.h> #include <asm/io.h> #include <asm/prom.h> +#include <asm/sections.h> #include <asm/pci-bridge.h> -#include <asm/residual.h> #include <asm/byteorder.h> #include <asm/irq.h> -#include <asm/gg2.h> #include <asm/uaccess.h> -#include "pci.h" - -#define DEBUG +#undef DEBUG #ifdef DEBUG #define DBG(x...) printk(x) @@ -42,8 +39,13 @@ unsigned long pci_dram_offset = 0; void pcibios_make_OF_bus_map(void); +static int pci_relocate_bridge_resource(struct pci_bus *bus, int i); +static int probe_resource(struct pci_bus *parent, struct resource *pr, + struct resource *res, struct resource **conflict); +static void update_bridge_base(struct pci_bus *bus, int i); static void pcibios_fixup_resources(struct pci_dev* dev); static void fixup_broken_pcnet32(struct pci_dev* dev); +static int reparent_resources(struct resource *parent, struct resource *res); static void fixup_rev1_53c810(struct pci_dev* dev); #ifdef CONFIG_ALL_PPC static void pcibios_fixup_cardbus(struct pci_dev* dev); @@ -66,7 +68,7 @@ struct pci_fixup pcibios_fixups[] = { { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources }, #ifdef CONFIG_ALL_PPC /* We should add per-machine fixup support in xxx_setup.c or xxx_pci.c */ - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1211, pcibios_fixup_cardbus }, + { PCI_FIXUP_FINAL, PCI_VENDOR_ID_TI, PCI_ANY_ID, pcibios_fixup_cardbus }, #endif /* CONFIG_ALL_PPC */ { 0 } }; @@ -96,7 +98,7 @@ fixup_broken_pcnet32(struct pci_dev* dev) void pcibios_update_resource(struct pci_dev *dev, struct resource *root, - struct resource *res, int resource) + struct resource *res, int resource) { u32 new, check; int reg; @@ -104,6 +106,7 @@ pcibios_update_resource(struct pci_dev *dev, struct resource *root, unsigned long io_offset; new = res->start; + res->flags &= ~IORESOURCE_UNSET; if (hose && res->flags & IORESOURCE_IO) { io_offset = (unsigned long)hose->io_base_virt - isa_io_base; new -= io_offset; @@ -128,6 +131,9 @@ pcibios_update_resource(struct pci_dev *dev, struct resource *root, "%s/%d (%08x != %08x)\n", dev->slot_name, resource, new, check); } + printk(KERN_INFO "PCI: moved device %s resource %d (%lx) to %x\n", + dev->slot_name, resource, res->flags, + new & ~PCI_REGION_FLAG_MASK); } static void @@ -143,13 +149,14 @@ pcibios_fixup_resources(struct pci_dev *dev) } for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { struct resource *res = dev->resource + i; - if (!res->start || !res->flags) + if (!res->flags) continue; - if (res->end == 0xffffffff) { + if (!res->start || res->end == 0xffffffff) { DBG("PCI:%s Resource %d [%08lx-%08lx] is unassigned\n", dev->slot_name, i, res->start, res->end); res->end -= res->start; res->start = 0; + res->flags |= IORESOURCE_UNSET; continue; } offset = 0; @@ -169,24 +176,35 @@ pcibios_fixup_resources(struct pci_dev *dev) #endif } } + + /* Call machine specific resource fixup */ + if (ppc_md.pcibios_fixup_resources) + ppc_md.pcibios_fixup_resources(dev); } #ifdef CONFIG_ALL_PPC static void pcibios_fixup_cardbus(struct pci_dev* dev) { + if (_machine != _MACH_Pmac) + return; /* * Fix the interrupt routing on the TI1211 chip on the 1999 * G3 powerbook, which doesn't get initialized properly by OF. + * Same problem with the 1410 of the new titanium pbook which + * has the same register. */ if (dev->vendor == PCI_VENDOR_ID_TI - && dev->device == PCI_DEVICE_ID_TI_1211) { - u32 val; + && (dev->device == PCI_DEVICE_ID_TI_1211 || + dev->device == PCI_DEVICE_ID_TI_1410)) { + u8 val; /* 0x8c == TI122X_IRQMUX, 2 says to route the INTA signal out the MFUNC0 pin */ - if (pci_read_config_dword(dev, 0x8c, &val) == 0 - && val == 0) - pci_write_config_dword(dev, 0x8c, 2); + if (pci_read_config_byte(dev, 0x8c, &val) == 0) + pci_write_config_byte(dev, 0x8c, (val & ~0x0f) | 2); + /* Disable ISA interrupt mode */ + if (pci_read_config_byte(dev, 0x92, &val) == 0) + pci_write_config_byte(dev, 0x92, val & ~0x06); } } #endif /* CONFIG_ALL_PPC */ @@ -271,25 +289,245 @@ pcibios_allocate_bus_resources(struct list_head *bus_list) for (ln = bus_list->next; ln != bus_list; ln=ln->next) { bus = pci_bus_b(ln); for (i = 0; i < 4; ++i) { - if ((res = bus->resource[i]) == NULL || !res->flags) + if ((res = bus->resource[i]) == NULL || !res->flags + || res->start > res->end) continue; if (bus->parent == NULL) pr = (res->flags & IORESOURCE_IO)? &ioport_resource: &iomem_resource; - else + else { pr = pci_find_parent_resource(bus->self, res); + if (pr == res) { + /* this happens when the generic PCI + * code (wrongly) decides that this + * bridge is transparent -- paulus + */ + continue; + } + } - if (pr && request_resource(pr, res) == 0) - continue; + DBG("PCI: bridge rsrc %lx..%lx (%lx), parent %p\n", + res->start, res->end, res->flags, pr); + if (pr) { + if (request_resource(pr, res) == 0) + continue; + /* + * Must be a conflict with an existing entry. + * Move that entry (or entries) under the + * bridge resource and try again. + */ + if (reparent_resources(pr, res) == 0) + continue; + } printk(KERN_ERR "PCI: Cannot allocate resource region " "%d of PCI bridge %d\n", i, bus->number); - DBG("PCI: resource is %lx..%lx (%lx), parent %p\n", - res->start, res->end, res->flags, pr); + if (pci_relocate_bridge_resource(bus, i)) + bus->resource[i] = NULL; } pcibios_allocate_bus_resources(&bus->children); } } +/* + * Reparent resource children of pr that conflict with res + * under res, and make res replace those children. + */ +static int __init +reparent_resources(struct resource *parent, struct resource *res) +{ + struct resource *p, **pp; + struct resource **firstpp = NULL; + + for (pp = &parent->child; (p = *pp) != NULL; pp = &p->sibling) { + if (p->end < res->start) + continue; + if (res->end < p->start) + break; + if (p->start < res->start || p->end > res->end) + return -1; /* not completely contained */ + if (firstpp == NULL) + firstpp = pp; + } + if (firstpp == NULL) + return -1; /* didn't find any conflicting entries? */ + res->parent = parent; + res->child = *firstpp; + res->sibling = *pp; + *firstpp = res; + *pp = NULL; + for (p = res->child; p != NULL; p = p->sibling) { + p->parent = res; + DBG(KERN_INFO "PCI: reparented %s [%lx..%lx] under %s\n", + p->name, p->start, p->end, res->name); + } + return 0; +} + +/* + * A bridge has been allocated a range which is outside the range + * of its parent bridge, so it needs to be moved. + */ +static int __init +pci_relocate_bridge_resource(struct pci_bus *bus, int i) +{ + struct resource *res, *pr, *conflict; + unsigned long try, size; + int j; + struct pci_bus *parent = bus->parent; + + if (parent == NULL) { + /* shouldn't ever happen */ + printk(KERN_ERR "PCI: can't move host bridge resource\n"); + return -1; + } + res = bus->resource[i]; + pr = NULL; + for (j = 0; j < 4; j++) { + struct resource *r = parent->resource[j]; + if (!r) + continue; + if ((res->flags ^ r->flags) & (IORESOURCE_IO | IORESOURCE_MEM)) + continue; + if (!((res->flags ^ r->flags) & IORESOURCE_PREFETCH)) { + pr = r; + break; + } + if (res->flags & IORESOURCE_PREFETCH) + pr = r; + } + if (pr == NULL) + return -1; + size = res->end - res->start; + if (pr->start > pr->end || size > pr->end - pr->start) + return -1; + try = pr->end; + for (;;) { + res->start = try - size; + res->end = try; + if (probe_resource(bus->parent, pr, res, &conflict) == 0) + break; + if (conflict->start <= pr->start + size) + return -1; + try = conflict->start - 1; + } + if (request_resource(pr, res)) { + DBG(KERN_ERR "PCI: huh? couldn't move to %lx..%lx\n", + res->start, res->end); + return -1; /* "can't happen" */ + } + update_bridge_base(bus, i); + printk(KERN_INFO "PCI: bridge %d resource %d moved to %lx..%lx\n", + bus->number, i, res->start, res->end); + return 0; +} + +static int __init +probe_resource(struct pci_bus *parent, struct resource *pr, + struct resource *res, struct resource **conflict) +{ + struct pci_bus *bus; + struct pci_dev *dev; + struct resource *r; + struct list_head *ln; + int i; + + for (r = pr->child; r != NULL; r = r->sibling) { + if (r->end >= res->start && res->end >= r->start) { + *conflict = r; + return 1; + } + } + for (ln = parent->children.next; ln != &parent->children; + ln = ln->next) { + bus = pci_bus_b(ln); + for (i = 0; i < 4; ++i) { + if ((r = bus->resource[i]) == NULL) + continue; + if (!r->flags || r->start > r->end || r == res) + continue; + if (pci_find_parent_resource(bus->self, r) != pr) + continue; + if (r->end >= res->start && res->end >= r->start) { + *conflict = r; + return 1; + } + } + } + for (ln = parent->devices.next; ln != &parent->devices; ln=ln->next) { + dev = pci_dev_b(ln); + for (i = 0; i < 6; ++i) { + r = &dev->resource[i]; + if (!r->flags || (r->flags & IORESOURCE_UNSET)) + continue; + if (pci_find_parent_resource(bus->self, r) != pr) + continue; + if (r->end >= res->start && res->end >= r->start) { + *conflict = r; + return 1; + } + } + } + return 0; +} + +static void __init +update_bridge_base(struct pci_bus *bus, int i) +{ + struct resource *res = bus->resource[i]; + u8 io_base_lo, io_limit_lo; + u16 mem_base, mem_limit; + u16 cmd; + unsigned long start, end, off; + struct pci_dev *dev = bus->self; + struct pci_controller *hose = dev->sysdata; + + if (!hose) { + printk("update_bridge_base: no hose?\n"); + return; + } + pci_read_config_word(dev, PCI_COMMAND, &cmd); + pci_write_config_word(dev, PCI_COMMAND, + cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY)); + if (res->flags & IORESOURCE_IO) { + off = (unsigned long) hose->io_base_virt - isa_io_base; + start = res->start - off; + end = res->end - off; + io_base_lo = (start >> 8) & PCI_IO_RANGE_MASK; + io_limit_lo = (end >> 8) & PCI_IO_RANGE_MASK; + if (end > 0xffff) { + pci_write_config_word(dev, PCI_IO_BASE_UPPER16, + start >> 16); + pci_write_config_word(dev, PCI_IO_LIMIT_UPPER16, + end >> 16); + io_base_lo |= PCI_IO_RANGE_TYPE_32; + } else + io_base_lo |= PCI_IO_RANGE_TYPE_16; + pci_write_config_byte(dev, PCI_IO_BASE, io_base_lo); + pci_write_config_byte(dev, PCI_IO_LIMIT, io_limit_lo); + + } else if ((res->flags & (IORESOURCE_MEM | IORESOURCE_PREFETCH)) + == IORESOURCE_MEM) { + off = hose->pci_mem_offset; + mem_base = ((res->start - off) >> 16) & PCI_MEMORY_RANGE_MASK; + mem_limit = ((res->end - off) >> 16) & PCI_MEMORY_RANGE_MASK; + pci_write_config_word(dev, PCI_MEMORY_BASE, mem_base); + pci_write_config_word(dev, PCI_MEMORY_LIMIT, mem_limit); + + } else if ((res->flags & (IORESOURCE_MEM | IORESOURCE_PREFETCH)) + == (IORESOURCE_MEM | IORESOURCE_PREFETCH)) { + off = hose->pci_mem_offset; + mem_base = ((res->start - off) >> 16) & PCI_PREF_RANGE_MASK; + mem_limit = ((res->end - off) >> 16) & PCI_PREF_RANGE_MASK; + pci_write_config_word(dev, PCI_PREF_MEMORY_BASE, mem_base); + pci_write_config_word(dev, PCI_PREF_MEMORY_LIMIT, mem_limit); + + } else { + DBG(KERN_ERR "PCI: ugh, bridge %s res %d has flags=%lx\n", + dev->slot_name, i, res->flags); + } + pci_write_config_word(dev, PCI_COMMAND, cmd); +} + static inline void alloc_resource(struct pci_dev *dev, int idx) { struct resource *pr, *r = &dev->resource[idx]; @@ -304,6 +542,7 @@ static inline void alloc_resource(struct pci_dev *dev, int idx) DBG("PCI: parent is %p: %08lx-%08lx (f=%lx)\n", pr, pr->start, pr->end, pr->flags); /* We'll assign a new address later */ + r->flags |= IORESOURCE_UNSET; r->end -= r->start; r->start = 0; } @@ -323,8 +562,8 @@ pcibios_allocate_resources(int pass) r = &dev->resource[idx]; if (r->parent) /* Already allocated */ continue; - if (!r->start) /* Not assigned at all */ - continue; + if (!r->flags || (r->flags & IORESOURCE_UNSET)) + continue; /* Not assigned at all */ if (r->flags & IORESOURCE_IO) disabled = !(command & PCI_COMMAND_IO); else @@ -370,7 +609,7 @@ pcibios_assign_resources(void) * or because we have decided the old address was * unusable for some reason. */ - if (!r->start && r->end && + if ((r->flags & IORESOURCE_UNSET) && r->end && (!ppc_md.pcibios_enable_device_hook || !ppc_md.pcibios_enable_device_hook(dev, 1))) pci_assign_resource(dev, idx); @@ -396,9 +635,9 @@ pcibios_enable_resources(struct pci_dev *dev) pci_read_config_word(dev, PCI_COMMAND, &cmd); old_cmd = cmd; - for(idx=0; idx<6; idx++) { + for (idx=0; idx<6; idx++) { r = &dev->resource[idx]; - if (!r->start && r->end) { + if (r->flags & IORESOURCE_UNSET) { printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name); return -EINVAL; } @@ -438,7 +677,7 @@ pcibios_alloc_controller(void) /* * Functions below are used on OpenFirmware machines. */ -static void +static void __openfirmware make_one_node_map(struct device_node* node, u8 pci_bus) { int *bus_range; @@ -449,7 +688,7 @@ make_one_node_map(struct device_node* node, u8 pci_bus) bus_range = (int *) get_property(node, "bus-range", &len); if (bus_range == NULL || len < 2 * sizeof(int)) { printk(KERN_WARNING "Can't get bus-range for %s\n", - node->full_name); + node->full_name); return; } pci_to_OF_bus_map[pci_bus] = bus_range[0]; @@ -472,7 +711,7 @@ make_one_node_map(struct device_node* node, u8 pci_bus) } } -void +void __openfirmware pcibios_make_OF_bus_map(void) { int i; @@ -512,17 +751,17 @@ pcibios_make_OF_bus_map(void) #endif } -static struct device_node* -scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn) +typedef int (*pci_OF_scan_iterator)(struct device_node* node, void* data); + +static struct device_node* __openfirmware +scan_OF_pci_childs(struct device_node* node, pci_OF_scan_iterator filter, void* data) { struct device_node* sub_node; for (; node != 0;node = node->sibling) { - unsigned int *class_code, *reg; + unsigned int *class_code; - reg = (unsigned int *) get_property(node, "reg", 0); - if (reg && ((reg[0] >> 8) & 0xff) == dev_fn - && ((reg[0] >> 16) & 0xff) == bus) + if (filter(node, data)) return node; /* For PCI<->PCI bridges or CardBus bridges, we go down @@ -535,13 +774,34 @@ scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn) (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) && strcmp(node->name, "multifunc-device")) continue; - sub_node = scan_OF_childs_for_device(node->child, bus, dev_fn); + sub_node = scan_OF_pci_childs(node->child, filter, data); if (sub_node) return sub_node; } return NULL; } +static int +scan_OF_pci_childs_iterator(struct device_node* node, void* data) +{ + unsigned int *reg; + u8* fdata = (u8*)data; + + reg = (unsigned int *) get_property(node, "reg", 0); + if (reg && ((reg[0] >> 8) & 0xff) == fdata[1] + && ((reg[0] >> 16) & 0xff) == fdata[0]) + return 1; + return 0; +} + +static struct device_node* __openfirmware +scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn) +{ + u8 filter_data[2] = {bus, dev_fn}; + + return scan_OF_pci_childs(node, scan_OF_pci_childs_iterator, filter_data); +} + /* * Scans the OF tree for a device node matching a PCI device */ @@ -598,6 +858,12 @@ pci_find_hose_for_OF_device(struct device_node* node) return NULL; } +static int __openfirmware +find_OF_pci_device_filter(struct device_node* node, void* data) +{ + return ((void *)node == data); +} + /* * Returns the PCI device matching a given OF node */ @@ -605,21 +871,40 @@ int pci_device_from_OF_node(struct device_node* node, u8* bus, u8* devfn) { unsigned int *reg; - int i; + struct pci_controller* hose; + struct pci_dev* dev; if (!have_of) return -ENODEV; + /* Make sure it's really a PCI device */ + hose = pci_find_hose_for_OF_device(node); + if (!hose || !hose->arch_data) + return -ENODEV; + if (!scan_OF_pci_childs(((struct device_node*)hose->arch_data)->child, + find_OF_pci_device_filter, (void *)node)) + return -ENODEV; reg = (unsigned int *) get_property(node, "reg", 0); if (!reg) return -ENODEV; *bus = (reg[0] >> 16) & 0xff; - for (i=0; pci_to_OF_bus_map && i<pci_bus_count; i++) - if (pci_to_OF_bus_map[i] == *bus) { - *bus = i; - break; - } *devfn = ((reg[0] >> 8) & 0xff); - return 0; + + /* Ok, here we need some tweak. If we have already renumbered + * all busses, we can't rely on the OF bus number any more. + * the pci_to_OF_bus_map is not enough as several PCI busses + * may match the same OF bus number. + */ + if (!pci_to_OF_bus_map) + return 0; + pci_for_each_dev(dev) { + if (pci_to_OF_bus_map[dev->bus->number] != *bus) + continue; + if (dev->devfn != *devfn) + continue; + *bus = dev->bus->number; + return 0; + } + return -ENODEV; } void __init @@ -709,6 +994,24 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose, ranges += np; } } + +/* We create the "pci-OF-bus-map" property now so it appears in the + * /proc device tree + */ +void __init +pci_create_OF_bus_map(void) +{ + struct property* of_prop; + + of_prop = (struct property*) alloc_bootmem(sizeof(struct property) + 256); + if (of_prop && find_path_device("/")) { + memset(of_prop, -1, sizeof(struct property) + 256); + of_prop->name = "pci-OF-bus-map"; + of_prop->length = 256; + of_prop->value = (unsigned char *)&of_prop[1]; + prom_add_property(find_path_device("/"), of_prop); + } +} #endif /* CONFIG_ALL_PPC */ void __init @@ -739,6 +1042,10 @@ pcibios_init(void) if (pci_assign_all_busses && have_of) pcibios_make_OF_bus_map(); + /* Do machine dependent PCI interrupt routing */ + if (ppc_md.pci_swizzle && ppc_md.pci_map_irq) + pci_fixup_irqs(ppc_md.pci_swizzle, ppc_md.pci_map_irq); + /* Call machine dependant fixup */ if (ppc_md.pcibios_fixup) ppc_md.pcibios_fixup(); @@ -754,10 +1061,23 @@ pcibios_init(void) ppc_md.pcibios_after_init(); } -int __init -pcibios_assign_all_busses(void) +unsigned char __init +common_swizzle(struct pci_dev *dev, unsigned char *pinp) { - return pci_assign_all_busses; + struct pci_controller *hose = dev->sysdata; + + if (dev->bus->number != hose->first_busno) { + u8 pin = *pinp; + do { + pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); + /* Move up the chain of bridges. */ + dev = dev->bus->self; + } while (dev->bus->self); + *pinp = pin; + + /* The slot is the idsel of the last bridge. */ + } + return PCI_SLOT(dev->devfn); } void __init @@ -863,7 +1183,7 @@ int pcibios_enable_device(struct pci_dev *dev) old_cmd = cmd; for (idx=0; idx<6; idx++) { r = &dev->resource[idx]; - if (!r->start && r->end) { + if (r->flags & IORESOURCE_UNSET) { printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name); return -EINVAL; } @@ -1152,6 +1472,19 @@ sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn) return result; } +void __init +pci_init_resource(struct resource *res, unsigned long start, unsigned long end, + int flags, char *name) +{ + res->start = start; + res->end = end; + res->flags = flags; + res->name = name; + res->parent = NULL; + res->sibling = NULL; + res->child = NULL; +} + /* * Null PCI config access functions, for the case when we can't * find a hose. diff --git a/arch/ppc/kernel/pci.h b/arch/ppc/kernel/pci.h deleted file mode 100644 index 61b2e187c331..000000000000 --- a/arch/ppc/kernel/pci.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * BK Id: SCCS/s.pci.h 1.10 08/08/01 16:35:43 paulus - */ - -#ifndef __PPC_KERNEL_PCI_H__ -#define __PPC_KERNEL_PCI_H__ - -/* Configure those in your xxx_init() or xxx_setup_arch() function */ -extern unsigned long isa_io_base; -extern unsigned long isa_mem_base; -extern unsigned long pci_dram_offset; - -/* Set this to 1 if you want the kernel to re-assign all PCI - * bus numbers - */ -extern int pci_assign_all_busses; - - -extern struct pci_controller* pcibios_alloc_controller(void); -extern struct pci_controller* pci_find_hose_for_OF_device( - struct device_node* node); - -extern void setup_indirect_pci(struct pci_controller* hose, - u32 cfg_addr, u32 cfg_data); -extern void setup_grackle(struct pci_controller *hose); - -#endif /* __PPC_KERNEL_PCI_H__ */ diff --git a/arch/ppc/kernel/pci_auto.c b/arch/ppc/kernel/pci_auto.c new file mode 100644 index 000000000000..1f716f296802 --- /dev/null +++ b/arch/ppc/kernel/pci_auto.c @@ -0,0 +1,519 @@ +/* + * arch/ppc/kernel/pci_auto.c + * + * PCI autoconfiguration library + * + * Author: Matt Porter <mporter@mvista.com> + * + * Copyright 2001 MontaVista Software Inc. + * + * 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. + */ + +/* + * The CardBus support is very preliminary. Preallocating space is + * the way to go but will require some change in card services to + * make it useful. Eventually this will ensure that we can put + * multiple CB bridges behind multiple P2P bridges. For now, at + * least it ensures that we place the CB bridge BAR and assigned + * initial bus numbers. I definitely need to do something about + * the lack of 16-bit I/O support. -MDP + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/pci.h> + +#include <asm/pci-bridge.h> + +#define PCIAUTO_IDE_MODE_MASK 0x05 + +#undef DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif /* DEBUG */ + +static int pciauto_upper_iospc; +static int pciauto_upper_memspc; + +void __init pciauto_setup_bars(struct pci_controller *hose, + int current_bus, + int pci_devfn, + int bar_limit) +{ + int bar_response, bar_size, bar_value; + int bar, addr_mask; + int * upper_limit; + int found_mem64 = 0; + + DBG("PCI Autoconfig: Found Bus %d, Device %d, Function %d\n", + current_bus, PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn) ); + + for (bar = PCI_BASE_ADDRESS_0; bar <= bar_limit; bar+=4) { + /* Tickle the BAR and get the response */ + early_write_config_dword(hose, + current_bus, + pci_devfn, + bar, + 0xffffffff); + early_read_config_dword(hose, + current_bus, + pci_devfn, + bar, + &bar_response); + + /* If BAR is not implemented go to the next BAR */ + if (!bar_response) + continue; + + /* Check the BAR type and set our address mask */ + if (bar_response & PCI_BASE_ADDRESS_SPACE) { + addr_mask = PCI_BASE_ADDRESS_IO_MASK; + upper_limit = &pciauto_upper_iospc; + DBG("PCI Autoconfig: BAR 0x%x, I/O, ", bar); + } else { + if ( (bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == + PCI_BASE_ADDRESS_MEM_TYPE_64) + found_mem64 = 1; + + addr_mask = PCI_BASE_ADDRESS_MEM_MASK; + upper_limit = &pciauto_upper_memspc; + DBG("PCI Autoconfig: BAR 0x%x, Mem ", bar); + } + + /* Calculate requested size */ + bar_size = ~(bar_response & addr_mask) + 1; + + /* Allocate a base address */ + bar_value = (*upper_limit - bar_size) & ~(bar_size - 1); + + /* Write it out and update our limit */ + early_write_config_dword(hose, + current_bus, + pci_devfn, + bar, + bar_value); + + *upper_limit = bar_value; + + /* + * If we are a 64-bit decoder then increment to the + * upper 32 bits of the bar and force it to locate + * in the lower 4GB of memory. + */ + if (found_mem64) { + bar += 4; + early_write_config_dword(hose, + current_bus, + pci_devfn, + bar, + 0x00000000); + found_mem64 = 0; + } + + DBG("size=0x%x, address=0x%x\n", + bar_size, bar_value); + } + +} + +void __init pciauto_prescan_setup_bridge(struct pci_controller *hose, + int current_bus, + int pci_devfn, + int sub_bus, + int *iosave, + int *memsave) +{ + /* Configure bus number registers */ + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_PRIMARY_BUS, + current_bus); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_SECONDARY_BUS, + sub_bus + 1); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_SUBORDINATE_BUS, + 0xff); + + /* Round memory allocator to 1MB boundary */ + pciauto_upper_memspc &= ~(0x100000 - 1); + *memsave = pciauto_upper_memspc; + + /* Round I/O allocator to 4KB boundary */ + pciauto_upper_iospc &= ~(0x1000 - 1); + *iosave = pciauto_upper_iospc; + + /* Set up memory and I/O filter limits, assume 32-bit I/O space */ + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_MEMORY_LIMIT, + ((pciauto_upper_memspc - 1) & 0xfff00000) >> 16); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_IO_LIMIT, + ((pciauto_upper_iospc - 1) & 0x0000f000) >> 8); + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_IO_LIMIT_UPPER16, + ((pciauto_upper_iospc - 1) & 0xffff0000) >> 16); + + /* Zero upper 32 bits of prefetchable base/limit */ + early_write_config_dword(hose, + current_bus, + pci_devfn, + PCI_PREF_BASE_UPPER32, + 0); + early_write_config_dword(hose, + current_bus, + pci_devfn, + PCI_PREF_LIMIT_UPPER32, + 0); +} + +void __init pciauto_postscan_setup_bridge(struct pci_controller *hose, + int current_bus, + int pci_devfn, + int sub_bus, + int *iosave, + int *memsave) +{ + int cmdstat; + + /* Configure bus number registers */ + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_SUBORDINATE_BUS, + sub_bus); + + /* + * Round memory allocator to 1MB boundary. + * If no space used, allocate minimum. + */ + pciauto_upper_memspc &= ~(0x100000 - 1); + if (*memsave == pciauto_upper_memspc) + pciauto_upper_memspc -= 0x00100000; + + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_MEMORY_BASE, + pciauto_upper_memspc >> 16); + + /* Allocate 1MB for pre-fretch */ + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_PREF_MEMORY_LIMIT, + ((pciauto_upper_memspc - 1) & 0xfff00000) >> 16); + + pciauto_upper_memspc -= 0x100000; + + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_PREF_MEMORY_BASE, + pciauto_upper_memspc >> 16); + + /* Round I/O allocator to 4KB boundary */ + pciauto_upper_iospc &= ~(0x1000 - 1); + if (*iosave == pciauto_upper_iospc) + pciauto_upper_iospc -= 0x1000; + + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_IO_BASE, + (pciauto_upper_iospc & 0x0000f000) >> 8); + early_write_config_word(hose, + current_bus, + pci_devfn, + PCI_IO_BASE_UPPER16, + pciauto_upper_iospc >> 16); + + /* Enable memory and I/O accesses, enable bus master */ + early_read_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + &cmdstat); + early_write_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + cmdstat | + PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER); +} + +void __init pciauto_prescan_setup_cardbus_bridge(struct pci_controller *hose, + int current_bus, + int pci_devfn, + int sub_bus, + int *iosave, + int *memsave) +{ + /* Configure bus number registers */ + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_PRIMARY_BUS, + current_bus); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_SECONDARY_BUS, + sub_bus + 1); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_SUBORDINATE_BUS, + 0xff); + + /* Round memory allocator to 4KB boundary */ + pciauto_upper_memspc &= ~(0x1000 - 1); + *memsave = pciauto_upper_memspc; + + /* Round I/O allocator to 4 byte boundary */ + pciauto_upper_iospc &= ~(0x4 - 1); + *iosave = pciauto_upper_iospc; + + /* Set up memory and I/O filter limits, assume 32-bit I/O space */ + early_write_config_dword(hose, + current_bus, + pci_devfn, + 0x20, + pciauto_upper_memspc - 1); + early_write_config_dword(hose, + current_bus, + pci_devfn, + 0x30, + pciauto_upper_iospc - 1); +} + +void __init pciauto_postscan_setup_cardbus_bridge(struct pci_controller *hose, + int current_bus, + int pci_devfn, + int sub_bus, + int *iosave, + int *memsave) +{ + int cmdstat; + + /* + * Configure subordinate bus number. The PCI subsystem + * bus scan will renumber buses (reserving three additional + * for this PCI<->CardBus bridge for the case where a CardBus + * adapter contains a P2P or CB2CB bridge. + */ + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_SUBORDINATE_BUS, + sub_bus); + + /* + * Reserve an additional 4MB for mem space and 16KB for + * I/O space. This should cover any additional space + * requirement of unusual CardBus devices with + * additional bridges that can consume more address space. + * + * Although pcmcia-cs currently will reprogram bridge + * windows, the goal is to add an option to leave them + * alone and use the bridge window ranges as the regions + * that are searched for free resources upon hot-insertion + * of a device. This will allow a PCI<->CardBus bridge + * configured by this routine to happily live behind a + * P2P bridge in a system. + */ + pciauto_upper_memspc -= 0x00400000; + pciauto_upper_iospc -= 0x00004000; + + /* Round memory allocator to 4KB boundary */ + pciauto_upper_memspc &= ~(0x1000 - 1); + + early_write_config_dword(hose, + current_bus, + pci_devfn, + 0x1c, + pciauto_upper_memspc); + + /* Round I/O allocator to 4 byte boundary */ + pciauto_upper_iospc &= ~(0x4 - 1); + early_write_config_dword(hose, + current_bus, + pci_devfn, + 0x2c, + pciauto_upper_iospc); + + /* Enable memory and I/O accesses, enable bus master */ + early_read_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + &cmdstat); + early_write_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + cmdstat | + PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER); +} + +int __init pciauto_bus_scan(struct pci_controller *hose, int current_bus) +{ + int sub_bus, pci_devfn, pci_class, cmdstat, found_multi = 0; + unsigned short vid; + unsigned char header_type; + + /* + * Fetch our I/O and memory space upper boundaries used + * to allocated base addresses on this hose. + */ + if (current_bus == hose->first_busno) { + pciauto_upper_iospc = hose->io_space.end + 1; + pciauto_upper_memspc = hose->mem_space.end + 1; + } + + sub_bus = current_bus; + + for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) { + /* Skip our host bridge */ + if ( (current_bus == hose->first_busno) && (pci_devfn == 0) ) + continue; + + if (PCI_FUNC(pci_devfn) && !found_multi) + continue; + + /* If config space read fails from this device, move on */ + if (early_read_config_byte(hose, + current_bus, + pci_devfn, + PCI_HEADER_TYPE, + &header_type)) + continue; + + if (!PCI_FUNC(pci_devfn)) + found_multi = header_type & 0x80; + + early_read_config_word(hose, + current_bus, + pci_devfn, + PCI_VENDOR_ID, + &vid); + + if (vid != 0xffff) { + early_read_config_dword(hose, + current_bus, + pci_devfn, + PCI_CLASS_REVISION, &pci_class); + if ( (pci_class >> 16) == PCI_CLASS_BRIDGE_PCI ) { + int iosave, memsave; + + DBG("PCI Autoconfig: Found P2P bridge, device %d\n", PCI_SLOT(pci_devfn)); + /* Allocate PCI I/O and/or memory space */ + pciauto_setup_bars(hose, + current_bus, + pci_devfn, + PCI_BASE_ADDRESS_1); + + pciauto_prescan_setup_bridge(hose, + current_bus, + pci_devfn, + sub_bus, + &iosave, + &memsave); + sub_bus = pciauto_bus_scan(hose, sub_bus+1); + pciauto_postscan_setup_bridge(hose, + current_bus, + pci_devfn, + sub_bus, + &iosave, + &memsave); + } else if ((pci_class >> 16) == PCI_CLASS_BRIDGE_CARDBUS) { + int iosave, memsave; + + DBG("PCI Autoconfig: Found CardBus bridge, device %d function %d\n", PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn)); + /* Place CardBus Socket/ExCA registers */ + pciauto_setup_bars(hose, + current_bus, + pci_devfn, + PCI_BASE_ADDRESS_0); + + pciauto_prescan_setup_cardbus_bridge(hose, + current_bus, + pci_devfn, + sub_bus, + &iosave, + &memsave); + sub_bus = pciauto_bus_scan(hose, sub_bus+1); + pciauto_postscan_setup_cardbus_bridge(hose, + current_bus, + pci_devfn, + sub_bus, + &iosave, + &memsave); + } else { + if ((pci_class >> 16) == PCI_CLASS_STORAGE_IDE) { + unsigned char prg_iface; + + early_read_config_byte(hose, + current_bus, + pci_devfn, + PCI_CLASS_PROG, + &prg_iface); + if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) { + DBG("PCI Autoconfig: Skipping legacy mode IDE controller\n"); + continue; + } + } + /* Allocate PCI I/O and/or memory space */ + pciauto_setup_bars(hose, + current_bus, + pci_devfn, + PCI_BASE_ADDRESS_5); + + /* + * Enable some standard settings + */ + early_read_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + &cmdstat); + early_write_config_dword(hose, + current_bus, + pci_devfn, + PCI_COMMAND, + cmdstat | + PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER); + early_write_config_byte(hose, + current_bus, + pci_devfn, + PCI_LATENCY_TIMER, + 0x80); + } + } + } + return sub_bus; +} diff --git a/arch/ppc/kernel/pmac_backlight.c b/arch/ppc/kernel/pmac_backlight.c deleted file mode 100644 index 63c8a8646e58..000000000000 --- a/arch/ppc/kernel/pmac_backlight.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * BK Id: SCCS/s.pmac_backlight.c 1.8 09/08/01 15:47:42 paulus - */ -/* - * Miscellaneous procedures for dealing with the PowerMac hardware. - * Contains support for the backlight. - * - * Copyright (C) 2000 Benjamin Herrenschmidt - * - */ - -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/stddef.h> -#include <linux/reboot.h> -#include <linux/nvram.h> -#include <asm/sections.h> -#include <asm/ptrace.h> -#include <asm/io.h> -#include <asm/pgtable.h> -#include <asm/system.h> -#include <asm/prom.h> -#include <asm/machdep.h> -#include <asm/nvram.h> -#include <asm/backlight.h> - -#include <linux/adb.h> -#include <linux/pmu.h> - -static struct backlight_controller *backlighter = NULL; -static void* backlighter_data = NULL; -static int backlight_autosave = 0; -static int backlight_level = BACKLIGHT_MAX; -static int backlight_enabled = 1; - -void __pmac -register_backlight_controller(struct backlight_controller *ctrler, void *data, char *type) -{ - struct device_node* bk_node; - char *prop; - int valid = 0; - - bk_node = find_devices("backlight"); - -#ifdef CONFIG_ADB_PMU - /* Special case for the old PowerBook since I can't test on it */ - backlight_autosave = machine_is_compatible("AAPL,3400/2400") - || machine_is_compatible("AAPL,3500"); - if ((backlight_autosave - || machine_is_compatible("AAPL,PowerBook1998") - || machine_is_compatible("PowerBook1,1")) - && !strcmp(type, "pmu")) - valid = 1; -#endif - if (bk_node) { - prop = get_property(bk_node, "backlight-control", NULL); - if (prop && !strncmp(prop, type, strlen(type))) - valid = 1; - } - if (!valid) - return; - backlighter = ctrler; - backlighter_data = data; - - if (bk_node && !backlight_autosave) - prop = get_property(bk_node, "bklt", NULL); - else - prop = NULL; - if (prop) { - backlight_level = ((*prop)+1) >> 1; - if (backlight_level > BACKLIGHT_MAX) - backlight_level = BACKLIGHT_MAX; - } - -#ifdef CONFIG_ADB_PMU - if (backlight_autosave) { - struct adb_request req; - pmu_request(&req, NULL, 2, 0xd9, 0); - while (!req.complete) - pmu_poll(); - backlight_level = req.reply[1] >> 4; - } -#endif - if (!backlighter->set_enable(1, backlight_level, data)) - backlight_enabled = 1; - - printk(KERN_INFO "Registered \"%s\" backlight controller, level: %d/15\n", - type, backlight_level); -} - -void __pmac -unregister_backlight_controller(struct backlight_controller *ctrler, void *data) -{ - /* We keep the current backlight level (for now) */ - if (ctrler == backlighter && data == backlighter_data) - backlighter = NULL; -} - -int __pmac -set_backlight_enable(int enable) -{ - int rc; - - if (!backlighter) - return -ENODEV; - rc = backlighter->set_enable(enable, backlight_level, backlighter_data); - if (!rc) - backlight_enabled = enable; - return rc; -} - -int __pmac -get_backlight_enable(void) -{ - if (!backlighter) - return -ENODEV; - return backlight_enabled; -} - -int __pmac -set_backlight_level(int level) -{ - int rc = 0; - - if (!backlighter) - return -ENODEV; - if (level < BACKLIGHT_MIN) - level = BACKLIGHT_OFF; - if (level > BACKLIGHT_MAX) - level = BACKLIGHT_MAX; - if (backlight_enabled) - rc = backlighter->set_level(level, backlighter_data); - if (!rc) - backlight_level = level; - if (!rc && !backlight_autosave) { - level <<=1; - if (level & 0x10) - level |= 0x01; - // -- todo: save to property "bklt" - } - return rc; -} - -int __pmac -get_backlight_level(void) -{ - if (!backlighter) - return -ENODEV; - return backlight_level; -} diff --git a/arch/ppc/kernel/pmac_nvram.c b/arch/ppc/kernel/pmac_nvram.c deleted file mode 100644 index 54c83ef97450..000000000000 --- a/arch/ppc/kernel/pmac_nvram.c +++ /dev/null @@ -1,402 +0,0 @@ -/* - * BK Id: SCCS/s.pmac_nvram.c 1.15 09/08/01 15:47:42 paulus - */ -/* - * Miscellaneous procedures for dealing with the PowerMac hardware. - */ -#include <linux/config.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/stddef.h> -#include <linux/nvram.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <asm/sections.h> -#include <asm/io.h> -#include <asm/system.h> -#include <asm/prom.h> -#include <asm/machdep.h> -#include <asm/nvram.h> -#include <linux/adb.h> -#include <linux/pmu.h> - -#undef DEBUG - -#define NVRAM_SIZE 0x2000 /* 8kB of non-volatile RAM */ - -#define CORE99_SIGNATURE 0x5a -#define CORE99_ADLER_START 0x14 - -/* Core99 nvram is a flash */ -#define CORE99_FLASH_STATUS_DONE 0x80 -#define CORE99_FLASH_STATUS_ERR 0x38 -#define CORE99_FLASH_CMD_ERASE_CONFIRM 0xd0 -#define CORE99_FLASH_CMD_ERASE_SETUP 0x20 -#define CORE99_FLASH_CMD_RESET 0xff -#define CORE99_FLASH_CMD_WRITE_SETUP 0x40 - -/* CHRP NVRAM header */ -struct chrp_header { - u8 signature; - u8 cksum; - u16 len; - char name[12]; - u8 data[0]; -}; - -struct core99_header { - struct chrp_header hdr; - u32 adler; - u32 generation; - u32 reserved[2]; -}; - -/* - * Read and write the non-volatile RAM on PowerMacs and CHRP machines. - */ -static int nvram_naddrs; -static volatile unsigned char *nvram_addr; -static volatile unsigned char *nvram_data; -static int nvram_mult, is_core_99; -static int core99_bank = 0; -static int nvram_partitions[3]; - -/* FIXME: kmalloc fails to allocate the image now that I had to move it - * before time_init(). For now, I allocate a static buffer here - * but it's a waste of space on all but core99 machines - */ -#if 0 -static char* nvram_image; -#else -static char nvram_image[NVRAM_SIZE] __pmacdata; -#endif - -extern int pmac_newworld; - -static u8 __openfirmware -chrp_checksum(struct chrp_header* hdr) -{ - u8 *ptr; - u16 sum = hdr->signature; - for (ptr = (u8 *)&hdr->len; ptr < hdr->data; ptr++) - sum += *ptr; - while (sum > 0xFF) - sum = (sum & 0xFF) + (sum>>8); - return sum; -} - -static u32 __pmac -core99_calc_adler(u8 *buffer) -{ - int cnt; - u32 low, high; - - buffer += CORE99_ADLER_START; - low = 1; - high = 0; - for (cnt=0; cnt<(NVRAM_SIZE-CORE99_ADLER_START); cnt++) { - if ((cnt % 5000) == 0) { - high %= 65521UL; - high %= 65521UL; - } - low += buffer[cnt]; - high += low; - } - low %= 65521UL; - high %= 65521UL; - - return (high << 16) | low; -} - -static u32 __pmac -core99_check(u8* datas) -{ - struct core99_header* hdr99 = (struct core99_header*)datas; - - if (hdr99->hdr.signature != CORE99_SIGNATURE) { -#ifdef DEBUG - printk("Invalid signature\n"); -#endif - return 0; - } - if (hdr99->hdr.cksum != chrp_checksum(&hdr99->hdr)) { -#ifdef DEBUG - printk("Invalid checksum\n"); -#endif - return 0; - } - if (hdr99->adler != core99_calc_adler(datas)) { -#ifdef DEBUG - printk("Invalid adler\n"); -#endif - return 0; - } - return hdr99->generation; -} - -static int __pmac -core99_erase_bank(int bank) -{ - int stat, i; - - u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE; - - out_8(base, CORE99_FLASH_CMD_ERASE_SETUP); - out_8(base, CORE99_FLASH_CMD_ERASE_CONFIRM); - do { stat = in_8(base); } - while(!(stat & CORE99_FLASH_STATUS_DONE)); - out_8(base, CORE99_FLASH_CMD_RESET); - if (stat & CORE99_FLASH_STATUS_ERR) { - printk("nvram: flash error 0x%02x on erase !\n", stat); - return -ENXIO; - } - for (i=0; i<NVRAM_SIZE; i++) - if (base[i] != 0xff) { - printk("nvram: flash erase failed !\n"); - return -ENXIO; - } - return 0; -} - -static int __pmac -core99_write_bank(int bank, u8* datas) -{ - int i, stat = 0; - - u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE; - - for (i=0; i<NVRAM_SIZE; i++) { - out_8(base+i, CORE99_FLASH_CMD_WRITE_SETUP); - out_8(base+i, datas[i]); - do { stat = in_8(base); } - while(!(stat & CORE99_FLASH_STATUS_DONE)); - if (stat & CORE99_FLASH_STATUS_ERR) - break; - } - out_8(base, CORE99_FLASH_CMD_RESET); - if (stat & CORE99_FLASH_STATUS_ERR) { - printk("nvram: flash error 0x%02x on write !\n", stat); - return -ENXIO; - } - for (i=0; i<NVRAM_SIZE; i++) - if (base[i] != datas[i]) { - printk("nvram: flash write failed !\n"); - return -ENXIO; - } - return 0; -} - -static void __init -lookup_partitions(void) -{ - u8 buffer[17]; - int i, offset; - struct chrp_header* hdr; - - if (pmac_newworld) { - nvram_partitions[pmac_nvram_OF] = -1; - nvram_partitions[pmac_nvram_XPRAM] = -1; - nvram_partitions[pmac_nvram_NR] = -1; - hdr = (struct chrp_header *)buffer; - - offset = 0; - buffer[16] = 0; - do { - for (i=0;i<16;i++) - buffer[i] = nvram_read_byte(offset+i); - if (!strcmp(hdr->name, "common")) - nvram_partitions[pmac_nvram_OF] = offset + 0x10; - if (!strcmp(hdr->name, "APL,MacOS75")) { - nvram_partitions[pmac_nvram_XPRAM] = offset + 0x10; - nvram_partitions[pmac_nvram_NR] = offset + 0x110; - } - offset += (hdr->len * 0x10); - } while(offset < NVRAM_SIZE); - } else { - nvram_partitions[pmac_nvram_OF] = 0x1800; - nvram_partitions[pmac_nvram_XPRAM] = 0x1300; - nvram_partitions[pmac_nvram_NR] = 0x1400; - } -#ifdef DEBUG - printk("nvram: OF partition at 0x%x\n", nvram_partitions[pmac_nvram_OF]); - printk("nvram: XP partition at 0x%x\n", nvram_partitions[pmac_nvram_XPRAM]); - printk("nvram: NR partition at 0x%x\n", nvram_partitions[pmac_nvram_NR]); -#endif -} - -void __init -pmac_nvram_init(void) -{ - struct device_node *dp; - - nvram_naddrs = 0; - - dp = find_devices("nvram"); - if (dp == NULL) { - printk(KERN_ERR "Can't find NVRAM device\n"); - return; - } - nvram_naddrs = dp->n_addrs; - is_core_99 = device_is_compatible(dp, "nvram,flash"); - if (is_core_99) { - int i; - u32 gen_bank0, gen_bank1; - - if (nvram_naddrs < 1) { - printk(KERN_ERR "nvram: no address\n"); - return; - } -#if 0 - nvram_image = kmalloc(NVRAM_SIZE, GFP_KERNEL); - if (!nvram_image) { - printk(KERN_ERR "nvram: can't allocate image\n"); - return; - } -#endif - nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2); -#ifdef DEBUG - printk("nvram: Checking bank 0...\n"); -#endif - gen_bank0 = core99_check((u8 *)nvram_data); - gen_bank1 = core99_check((u8 *)nvram_data + NVRAM_SIZE); - core99_bank = (gen_bank0 < gen_bank1) ? 1 : 0; -#ifdef DEBUG - printk("nvram: gen0=%d, gen1=%d\n", gen_bank0, gen_bank1); - printk("nvram: Active bank is: %d\n", core99_bank); -#endif - for (i=0; i<NVRAM_SIZE; i++) - nvram_image[i] = nvram_data[i + core99_bank*NVRAM_SIZE]; - } else if (_machine == _MACH_chrp && nvram_naddrs == 1) { - nvram_data = ioremap(dp->addrs[0].address + isa_mem_base, - dp->addrs[0].size); - nvram_mult = 1; - } else if (nvram_naddrs == 1) { - nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size); - nvram_mult = (dp->addrs[0].size + NVRAM_SIZE - 1) / NVRAM_SIZE; - } else if (nvram_naddrs == 2) { - nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size); - nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size); - } else if (nvram_naddrs == 0 && sys_ctrler == SYS_CTRLER_PMU) { - nvram_naddrs = -1; - } else { - printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n", - nvram_naddrs); - } - lookup_partitions(); -} - -void __pmac -pmac_nvram_update(void) -{ - struct core99_header* hdr99; - - if (!is_core_99 || !nvram_data || !nvram_image) - return; - if (!memcmp(nvram_image, (u8*)nvram_data + core99_bank*NVRAM_SIZE, - NVRAM_SIZE)) - return; -#ifdef DEBUG - printk("Updating nvram...\n"); -#endif - hdr99 = (struct core99_header*)nvram_image; - hdr99->generation++; - hdr99->hdr.signature = CORE99_SIGNATURE; - hdr99->hdr.cksum = chrp_checksum(&hdr99->hdr); - hdr99->adler = core99_calc_adler(nvram_image); - core99_bank = core99_bank ? 0 : 1; - if (core99_erase_bank(core99_bank)) { - printk("nvram: Error erasing bank %d\n", core99_bank); - return; - } - if (core99_write_bank(core99_bank, nvram_image)) - printk("nvram: Error writing bank %d\n", core99_bank); -} - -unsigned char __openfirmware -nvram_read_byte(int addr) -{ - switch (nvram_naddrs) { -#ifdef CONFIG_ADB_PMU - case -1: { - struct adb_request req; - - if (pmu_request(&req, NULL, 3, PMU_READ_NVRAM, - (addr >> 8) & 0xff, addr & 0xff)) - break; - while (!req.complete) - pmu_poll(); - return req.reply[1]; - } -#endif - case 1: - if (is_core_99) - return nvram_image[addr]; - return nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult]; - case 2: - *nvram_addr = addr >> 5; - eieio(); - return nvram_data[(addr & 0x1f) << 4]; - } - return 0; -} - -void __openfirmware -nvram_write_byte(unsigned char val, int addr) -{ - switch (nvram_naddrs) { -#ifdef CONFIG_ADB_PMU - case -1: { - struct adb_request req; - - if (pmu_request(&req, NULL, 4, PMU_WRITE_NVRAM, - (addr >> 8) & 0xff, addr & 0xff, val)) - break; - while (!req.complete) - pmu_poll(); - break; - } -#endif - case 1: - if (is_core_99) { - nvram_image[addr] = val; - break; - } - nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult] = val; - break; - case 2: - *nvram_addr = addr >> 5; - eieio(); - nvram_data[(addr & 0x1f) << 4] = val; - break; - } - eieio(); -} - -int __pmac -pmac_get_partition(int partition) -{ - return nvram_partitions[partition]; -} - -u8 __pmac -pmac_xpram_read(int xpaddr) -{ - int offset = nvram_partitions[pmac_nvram_XPRAM]; - - if (offset < 0) - return 0; - - return nvram_read_byte(xpaddr + offset); -} - -void __pmac -pmac_xpram_write(int xpaddr, u8 data) -{ - int offset = nvram_partitions[pmac_nvram_XPRAM]; - - if (offset < 0) - return; - - nvram_write_byte(xpaddr + offset, data); -} diff --git a/arch/ppc/kernel/pmac_pci.c b/arch/ppc/kernel/pmac_pci.c deleted file mode 100644 index 4693731798fe..000000000000 --- a/arch/ppc/kernel/pmac_pci.c +++ /dev/null @@ -1,626 +0,0 @@ -/* - * BK Id: SCCS/s.pmac_pci.c 1.27 09/08/01 15:47:42 paulus - */ -/* - * Support for PCI bridges found on Power Macintoshes. - * At present the "bandit" and "chaos" bridges are supported. - * Fortunately you access configuration space in the same - * way with either bridge. - * - * Copyright (C) 1997 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/kernel.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/string.h> -#include <linux/init.h> -#include <linux/bootmem.h> - -#include <asm/sections.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/pci-bridge.h> -#include <asm/machdep.h> -#include <asm/feature.h> - -#include "pci.h" - -#undef DEBUG - -static void add_bridges(struct device_node *dev); - -/* XXX Could be per-controller, but I don't think we risk anything by - * assuming we won't have both UniNorth and Bandit */ -static int has_uninorth; - -/* - * Magic constants for enabling cache coherency in the bandit/PSX bridge. - */ -#define BANDIT_DEVID_2 8 -#define BANDIT_REVID 3 - -#define BANDIT_DEVNUM 11 -#define BANDIT_MAGIC 0x50 -#define BANDIT_COHERENT 0x40 - -static int __init -fixup_one_level_bus_range(struct device_node *node, int higher) -{ - for (; node != 0;node = node->sibling) { - int * bus_range; - unsigned int *class_code; - int len; - - /* For PCI<->PCI bridges or CardBus bridges, we go down */ - class_code = (unsigned int *) get_property(node, "class-code", 0); - if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI && - (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) - continue; - bus_range = (int *) get_property(node, "bus-range", &len); - if (bus_range != NULL && len > 2 * sizeof(int)) { - if (bus_range[1] > higher) - higher = bus_range[1]; - } - higher = fixup_one_level_bus_range(node->child, higher); - } - return higher; -} - -/* This routine fixes the "bus-range" property of all bridges in the - * system since they tend to have their "last" member wrong on macs - * - * Note that the bus numbers manipulated here are OF bus numbers, they - * are not Linux bus numbers. - */ -static void __init -fixup_bus_range(struct device_node *bridge) -{ - int * bus_range; - int len; - - /* Lookup the "bus-range" property for the hose */ - bus_range = (int *) get_property(bridge, "bus-range", &len); - if (bus_range == NULL || len < 2 * sizeof(int)) { - printk(KERN_WARNING "Can't get bus-range for %s\n", - bridge->full_name); - return; - } - bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]); -} - -/* - * Apple MacRISC (UniNorth, Bandit, Chaos) PCI controllers. - * - * The "Bandit" version is present in all early PCI PowerMacs, - * and up to the first ones using Grackle. Some machines may - * have 2 bandit controllers (2 PCI busses). - * - * "Chaos" is used in some "Bandit"-type machines as a bridge - * for the separate display bus. It is accessed the same - * way as bandit, but cannot be probed for devices. It therefore - * has its own config access functions. - * - * The "UniNorth" version is present in all Core99 machines - * (iBook, G4, new IMacs, and all the recent Apple machines). - * It contains 3 controllers in one ASIC. - */ - -#define MACRISC_CFA0(devfn, off) \ - ((1 << (unsigned long)PCI_SLOT(dev_fn)) \ - | (((unsigned long)PCI_FUNC(dev_fn)) << 8) \ - | (((unsigned long)(off)) & 0xFCUL)) - -#define MACRISC_CFA1(bus, devfn, off) \ - ((((unsigned long)(bus)) << 16) \ - |(((unsigned long)(devfn)) << 8) \ - |(((unsigned long)(off)) & 0xFCUL) \ - |1UL) - -static unsigned int __pmac -macrisc_cfg_access(struct pci_controller* hose, u8 bus, u8 dev_fn, u8 offset) -{ - unsigned int caddr; - - if (bus == hose->first_busno) { - if (dev_fn < (11 << 3)) - return 0; - caddr = MACRISC_CFA0(dev_fn, offset); - } else - caddr = MACRISC_CFA1(bus, dev_fn, offset); - - /* Uninorth will return garbage if we don't read back the value ! */ - do { - out_le32(hose->cfg_addr, caddr); - } while(in_le32(hose->cfg_addr) != caddr); - - offset &= has_uninorth ? 0x07 : 0x03; - return (unsigned int)(hose->cfg_data) + (unsigned int)offset; -} - -#define cfg_read(val, addr, type, op, op2) \ - *val = op((type)(addr)) -#define cfg_write(val, addr, type, op, op2) \ - op((type *)(addr), (val)); (void) op2((type *)(addr)) - -#define cfg_read_bad(val, size) *val = bad_##size; -#define cfg_write_bad(val, size) - -#define bad_byte 0xff -#define bad_word 0xffff -#define bad_dword 0xffffffffU - -#define MACRISC_PCI_OP(rw, size, type, op, op2) \ -static int __pmac \ -macrisc_##rw##_config_##size(struct pci_dev *dev, int off, type val) \ -{ \ - struct pci_controller *hose = dev->sysdata; \ - unsigned int addr; \ - \ - addr = macrisc_cfg_access(hose, dev->bus->number, dev->devfn, off); \ - if (!addr) { \ - cfg_##rw##_bad(val, size) \ - return PCIBIOS_DEVICE_NOT_FOUND; \ - } \ - cfg_##rw(val, addr, type, op, op2); \ - return PCIBIOS_SUCCESSFUL; \ -} - -MACRISC_PCI_OP(read, byte, u8 *, in_8, x) -MACRISC_PCI_OP(read, word, u16 *, in_le16, x) -MACRISC_PCI_OP(read, dword, u32 *, in_le32, x) -MACRISC_PCI_OP(write, byte, u8, out_8, in_8) -MACRISC_PCI_OP(write, word, u16, out_le16, in_le16) -MACRISC_PCI_OP(write, dword, u32, out_le32, in_le32) - -static struct pci_ops macrisc_pci_ops = -{ - macrisc_read_config_byte, - macrisc_read_config_word, - macrisc_read_config_dword, - macrisc_write_config_byte, - macrisc_write_config_word, - macrisc_write_config_dword -}; - -/* - * Verifiy that a specific (bus, dev_fn) exists on chaos - */ -static int __pmac -chaos_validate_dev(struct pci_dev *dev, int offset) -{ - if(pci_device_to_OF_node(dev) == 0) - return PCIBIOS_DEVICE_NOT_FOUND; - if((dev->vendor == 0x106b) && (dev->device == 3) && (offset >= 0x10) && - (offset != 0x14) && (offset != 0x18) && (offset <= 0x24)) { - return PCIBIOS_BAD_REGISTER_NUMBER; - } - return PCIBIOS_SUCCESSFUL; -} - -#define CHAOS_PCI_OP(rw, size, type) \ -static int __pmac \ -chaos_##rw##_config_##size(struct pci_dev *dev, int off, type val) \ -{ \ - int result = chaos_validate_dev(dev, off); \ - if(result == PCIBIOS_BAD_REGISTER_NUMBER) { \ - cfg_##rw##_bad(val, size) \ - return PCIBIOS_BAD_REGISTER_NUMBER; \ - } \ - if(result == PCIBIOS_SUCCESSFUL) \ - return macrisc_##rw##_config_##size(dev, off, val); \ - return result; \ -} - -CHAOS_PCI_OP(read, byte, u8 *) -CHAOS_PCI_OP(read, word, u16 *) -CHAOS_PCI_OP(read, dword, u32 *) -CHAOS_PCI_OP(write, byte, u8) -CHAOS_PCI_OP(write, word, u16) -CHAOS_PCI_OP(write, dword, u32) - -static struct pci_ops chaos_pci_ops = -{ - chaos_read_config_byte, - chaos_read_config_word, - chaos_read_config_dword, - chaos_write_config_byte, - chaos_write_config_word, - chaos_write_config_dword -}; - - -/* - * For a bandit bridge, turn on cache coherency if necessary. - * N.B. we could clean this up using the hose ops directly. - */ -static void __init -init_bandit(struct pci_controller *bp) -{ - unsigned int vendev, magic; - int rev; - - /* read the word at offset 0 in config space for device 11 */ - out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_VENDOR_ID); - udelay(2); - vendev = in_le32((volatile unsigned int *)bp->cfg_data); - if (vendev == (PCI_DEVICE_ID_APPLE_BANDIT << 16) + - PCI_VENDOR_ID_APPLE) { - /* read the revision id */ - out_le32(bp->cfg_addr, - (1UL << BANDIT_DEVNUM) + PCI_REVISION_ID); - udelay(2); - rev = in_8(bp->cfg_data); - if (rev != BANDIT_REVID) - printk(KERN_WARNING - "Unknown revision %d for bandit at %08lx\n", - rev, bp->io_base_phys); - } else if (vendev != (BANDIT_DEVID_2 << 16) + PCI_VENDOR_ID_APPLE) { - printk(KERN_WARNING "bandit isn't? (%x)\n", vendev); - return; - } - - /* read the revision id */ - out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_REVISION_ID); - udelay(2); - rev = in_8(bp->cfg_data); - if (rev != BANDIT_REVID) - printk(KERN_WARNING "Unknown revision %d for bandit at %08lx\n", - rev, bp->io_base_phys); - - /* read the word at offset 0x50 */ - out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + BANDIT_MAGIC); - udelay(2); - magic = in_le32((volatile unsigned int *)bp->cfg_data); - if ((magic & BANDIT_COHERENT) != 0) - return; - magic |= BANDIT_COHERENT; - udelay(2); - out_le32((volatile unsigned int *)bp->cfg_data, magic); - printk(KERN_INFO "Cache coherency enabled for bandit/PSX at %08lx\n", - bp->io_base_phys); -} - - -/* - * Tweak the PCI-PCI bridge chip on the blue & white G3s. - */ -static void __init -init_p2pbridge(void) -{ - struct device_node *p2pbridge; - struct pci_controller* hose; - u8 bus, devfn; - u16 val; - - /* XXX it would be better here to identify the specific - PCI-PCI bridge chip we have. */ - if ((p2pbridge = find_devices("pci-bridge")) == 0 - || p2pbridge->parent == NULL - || strcmp(p2pbridge->parent->name, "pci") != 0) - return; - if (pci_device_from_OF_node(p2pbridge, &bus, &devfn) < 0) { -#ifdef DEBUG - printk("Can't find PCI infos for PCI<->PCI bridge\n"); -#endif - return; - } - /* Warning: At this point, we have not yet renumbered all busses. - * So we must use OF walking to find out hose - */ - hose = pci_find_hose_for_OF_device(p2pbridge); - if (!hose) { -#ifdef DEBUG - printk("Can't find hose for PCI<->PCI bridge\n"); -#endif - return; - } - if (early_read_config_word(hose, bus, devfn, - PCI_BRIDGE_CONTROL, &val) < 0) { - printk(KERN_ERR "init_p2pbridge: couldn't read bridge control\n"); - return; - } - val &= ~PCI_BRIDGE_CTL_MASTER_ABORT; - early_write_config_word(hose, bus, devfn, PCI_BRIDGE_CONTROL, val); -} - -void __init -pmac_find_bridges(void) -{ - add_bridges(find_devices("bandit")); - add_bridges(find_devices("chaos")); - add_bridges(find_devices("pci")); - init_p2pbridge(); -} - -#define GRACKLE_CFA(b, d, o) (0x80 | ((b) << 8) | ((d) << 16) \ - | (((o) & ~3) << 24)) - -#define GRACKLE_PICR1_STG 0x00000040 -#define GRACKLE_PICR1_LOOPSNOOP 0x00000010 - -/* N.B. this is called before bridges is initialized, so we can't - use grackle_pcibios_{read,write}_config_dword. */ -static inline void grackle_set_stg(struct pci_controller* bp, int enable) -{ - unsigned int val; - - out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8)); - val = in_le32((volatile unsigned int *)bp->cfg_data); - val = enable? (val | GRACKLE_PICR1_STG) : - (val & ~GRACKLE_PICR1_STG); - out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8)); - out_le32((volatile unsigned int *)bp->cfg_data, val); - (void)in_le32((volatile unsigned int *)bp->cfg_data); -} - -static inline void grackle_set_loop_snoop(struct pci_controller *bp, int enable) -{ - unsigned int val; - - out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8)); - val = in_le32((volatile unsigned int *)bp->cfg_data); - val = enable? (val | GRACKLE_PICR1_LOOPSNOOP) : - (val & ~GRACKLE_PICR1_LOOPSNOOP); - out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8)); - out_le32((volatile unsigned int *)bp->cfg_data, val); - (void)in_le32((volatile unsigned int *)bp->cfg_data); -} - -static int __init -setup_uninorth(struct pci_controller* hose, struct reg_property* addr) -{ - pci_assign_all_busses = 1; - has_uninorth = 1; - hose->ops = ¯isc_pci_ops; - hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000); - hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000); - /* We "know" that the bridge at f2000000 has the PCI slots. */ - return addr->address == 0xf2000000; -} - -static void __init -setup_bandit(struct pci_controller* hose, struct reg_property* addr) -{ - hose->ops = ¯isc_pci_ops; - hose->cfg_addr = (volatile unsigned int *) - ioremap(addr->address + 0x800000, 0x1000); - hose->cfg_data = (volatile unsigned char *) - ioremap(addr->address + 0xc00000, 0x1000); - init_bandit(hose); -} - -static void __init -setup_chaos(struct pci_controller* hose, struct reg_property* addr) -{ - /* assume a `chaos' bridge */ - hose->ops = &chaos_pci_ops; - hose->cfg_addr = (volatile unsigned int *) - ioremap(addr->address + 0x800000, 0x1000); - hose->cfg_data = (volatile unsigned char *) - ioremap(addr->address + 0xc00000, 0x1000); -} - -void __init -setup_grackle(struct pci_controller *hose) -{ - setup_indirect_pci(hose, 0xfec00000, 0xfee00000); - if (machine_is_compatible("AAPL,PowerBook1998")) - grackle_set_loop_snoop(hose, 1); -#if 0 /* Disabled for now, HW problems ??? */ - grackle_set_stg(hose, 1); -#endif -} - -/* - * We assume that if we have a G3 powermac, we have one bridge called - * "pci" (a MPC106) and no bandit or chaos bridges, and contrariwise, - * if we have one or more bandit or chaos bridges, we don't have a MPC106. - */ -static void __init -add_bridges(struct device_node *dev) -{ - int len; - struct pci_controller *hose; - struct reg_property *addr; - char* disp_name; - int *bus_range; - int first = 1, primary; - - for (; dev != NULL; dev = dev->next) { - addr = (struct reg_property *) get_property(dev, "reg", &len); - if (addr == NULL || len < sizeof(*addr)) { - printk(KERN_WARNING "Can't use %s: no address\n", - dev->full_name); - continue; - } - bus_range = (int *) get_property(dev, "bus-range", &len); - if (bus_range == NULL || len < 2 * sizeof(int)) { - printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n", - dev->full_name); - } - - hose = pcibios_alloc_controller(); - if (!hose) - continue; - hose->arch_data = dev; - hose->first_busno = bus_range ? bus_range[0] : 0; - hose->last_busno = bus_range ? bus_range[1] : 0xff; - - disp_name = NULL; - primary = first; - if (device_is_compatible(dev, "uni-north")) { - primary = setup_uninorth(hose, addr); - disp_name = "UniNorth"; - } else if (strcmp(dev->name, "pci") == 0) { - /* XXX assume this is a mpc106 (grackle) */ - setup_grackle(hose); - disp_name = "Grackle (MPC106)"; - } else if (strcmp(dev->name, "bandit") == 0) { - setup_bandit(hose, addr); - disp_name = "Bandit"; - } else if (strcmp(dev->name, "chaos") == 0) { - setup_chaos(hose, addr); - disp_name = "Chaos"; - primary = 0; - } - printk(KERN_INFO "Found %s PCI host bridge at 0x%08x. Firmware bus number: %d->%d\n", - disp_name, addr->address, hose->first_busno, hose->last_busno); -#ifdef DEBUG - printk(" ->Hose at 0x%08lx, cfg_addr=0x%08lx,cfg_data=0x%08lx\n", - hose, hose->cfg_addr, hose->cfg_data); -#endif - - /* Interpret the "ranges" property */ - /* This also maps the I/O region and sets isa_io/mem_base */ - pci_process_bridge_OF_ranges(hose, dev, primary); - - /* Fixup "bus-range" OF property */ - fixup_bus_range(dev); - - first &= !primary; - } -} - -static void __init -pcibios_fixup_OF_interrupts(void) -{ - struct pci_dev* dev; - - pci_for_each_dev(dev) - { - /* - * Open Firmware often doesn't initialize the, - * PCI_INTERRUPT_LINE config register properly, so we - * should find the device node and se if it has an - * AAPL,interrupts property. - */ - unsigned char pin; - struct device_node* node; - - if (pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin) || !pin) - continue; /* No interrupt generated -> no fixup */ - node = pci_device_to_OF_node(dev); - if (!node) { - printk("No OF node for device %x:%x\n", dev->bus->number, dev->devfn >> 3); - continue; - } - /* this is the node, see if it has interrupts */ - if (node->n_intrs > 0) - dev->irq = node->intrs[0].line; - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); - } -} - -void __init -pmac_pcibios_fixup(void) -{ - /* Fixup interrupts according to OF tree */ - pcibios_fixup_OF_interrupts(); -} - -int __pmac -pmac_pci_enable_device_hook(struct pci_dev *dev, int initial) -{ - struct device_node* node; - int updatecfg = 0; - - node = pci_device_to_OF_node(dev); - - /* We don't want to enable USB controllers absent from the OF tree - * (iBook second controller) - */ - if (dev->vendor == PCI_VENDOR_ID_APPLE - && dev->device == PCI_DEVICE_ID_APPLE_KL_USB && !node) - return -EINVAL; - - /* Firewire & GMAC were disabled after PCI probe, the driver is - * claiming them, we must re-enable them now. - */ - if (node && !strcmp(node->name, "firewire") && - (device_is_compatible(node, "pci106b,18") || - device_is_compatible(node, "pci106b,30"))) { - feature_set_firewire_cable_power(node, 1); - feature_set_firewire_power(node, 1); - updatecfg = 1; - } - if (node && !strcmp(node->name, "ethernet") && - device_is_compatible(node, "gmac")) { - feature_set_gmac_power(node, 1); - updatecfg = 1; - } - - if (updatecfg) { - u16 cmd; - - /* - * Make sure PCI is correctly configured - * - * We use old pci_bios versions of the function since, by - * default, gmac is not powered up, and so will be absent - * from the kernel initial PCI lookup. - * - * Should be replaced by 2.4 new PCI mecanisms and really - * regiser the device. - */ - pci_read_config_word(dev, PCI_COMMAND, &cmd); - cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE; - pci_write_config_word(dev, PCI_COMMAND, cmd); - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 16); - pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 8); - } - - return 0; -} - -/* We power down some devices after they have been probed. They'll - * be powered back on later on - */ -void __init -pmac_pcibios_after_init(void) -{ - struct device_node* nd; - -#ifdef CONFIG_BLK_DEV_IDE - struct pci_dev *dev; - - /* OF fails to initialize IDE controllers on macs - * (and maybe other machines) - * - * Ideally, this should be moved to the IDE layer, but we need - * to check specifically with Andre Hedrick how to do it cleanly - * since the common IDE code seem to care about the fact that the - * BIOS may have disabled a controller. - * - * -- BenH - */ - pci_for_each_dev(dev) { - if ((dev->class >> 16) == PCI_BASE_CLASS_STORAGE) - pci_enable_device(dev); - } -#endif /* CONFIG_BLK_DEV_IDE */ - - nd = find_devices("firewire"); - while (nd) { - if (nd->parent && (device_is_compatible(nd, "pci106b,18") || - device_is_compatible(nd, "pci106b,30")) - && device_is_compatible(nd->parent, "uni-north")) { - feature_set_firewire_power(nd, 0); - feature_set_firewire_cable_power(nd, 0); - } - nd = nd->next; - } - nd = find_devices("ethernet"); - while (nd) { - if (nd->parent && device_is_compatible(nd, "gmac") - && device_is_compatible(nd->parent, "uni-north")) - feature_set_gmac_power(nd, 0); - nd = nd->next; - } -} - diff --git a/arch/ppc/kernel/pmac_pic.c b/arch/ppc/kernel/pmac_pic.c deleted file mode 100644 index 295e4a44b870..000000000000 --- a/arch/ppc/kernel/pmac_pic.c +++ /dev/null @@ -1,496 +0,0 @@ -/* - * BK Id: SCCS/s.pmac_pic.c 1.20 09/08/01 15:47:42 paulus - */ -#include <linux/config.h> -#include <linux/stddef.h> -#include <linux/init.h> -#include <linux/sched.h> -#include <linux/signal.h> -#include <linux/pci.h> - -#include <asm/sections.h> -#include <asm/io.h> -#include <asm/smp.h> -#include <asm/prom.h> -#include <asm/pci-bridge.h> -#include <asm/time.h> - -#include "pmac_pic.h" -#include "open_pic.h" - -/* pmac */struct pmac_irq_hw { - unsigned int flag; - unsigned int enable; - unsigned int ack; - unsigned int level; -}; - -/* XXX these addresses should be obtained from the device tree */ -static 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, -}; - -static int max_irqs; -static int max_real_irqs; - -static spinlock_t pmac_pic_lock = SPIN_LOCK_UNLOCKED; - - -#define GATWICK_IRQ_POOL_SIZE 10 -static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE]; - -/* - * Mark an irq as "lost". This is only used on the pmac - * since it can lose interrupts (see pmac_set_irq_mask). - * -- Cort - */ -void __pmac __set_lost(unsigned long irq_nr) -{ - if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) { - atomic_inc(&ppc_n_lost_interrupts); - set_dec(1); - } -} - -static void __pmac pmac_mask_and_ack_irq(unsigned int irq_nr) -{ - unsigned long bit = 1UL << (irq_nr & 0x1f); - int i = irq_nr >> 5; - unsigned long flags; - - if ((unsigned)irq_nr >= max_irqs) - return; - - clear_bit(irq_nr, ppc_cached_irq_mask); - if (test_and_clear_bit(irq_nr, ppc_lost_interrupts)) - atomic_dec(&ppc_n_lost_interrupts); - spin_lock_irqsave(&pmac_pic_lock, flags); - out_le32(&pmac_irq_hw[i]->ack, bit); - out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]); - out_le32(&pmac_irq_hw[i]->ack, bit); - do { - /* make sure ack gets to controller before we enable - interrupts */ - mb(); - } while(in_le32(&pmac_irq_hw[i]->flag) & bit); - spin_unlock_irqrestore(&pmac_pic_lock, flags); -} - -static void __pmac pmac_set_irq_mask(unsigned int irq_nr) -{ - unsigned long bit = 1UL << (irq_nr & 0x1f); - int i = irq_nr >> 5; - unsigned long flags; - - if ((unsigned)irq_nr >= max_irqs) - return; - - spin_lock_irqsave(&pmac_pic_lock, flags); - /* enable unmasked interrupts */ - out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]); - - do { - /* make sure mask gets to controller before we - return to user */ - mb(); - } while((in_le32(&pmac_irq_hw[i]->enable) & bit) - != (ppc_cached_irq_mask[i] & bit)); - - /* - * Unfortunately, setting the bit in the enable register - * when the device interrupt is already on *doesn't* set - * the bit in the flag register or request another interrupt. - */ - if ((bit & ppc_cached_irq_mask[i]) - && (ld_le32(&pmac_irq_hw[i]->level) & bit) - && !(ld_le32(&pmac_irq_hw[i]->flag) & bit)) - __set_lost((ulong)irq_nr); - spin_unlock_irqrestore(&pmac_pic_lock, flags); -} - -static void __pmac pmac_mask_irq(unsigned int irq_nr) -{ - clear_bit(irq_nr, ppc_cached_irq_mask); - pmac_set_irq_mask(irq_nr); - mb(); -} - -static void __pmac pmac_unmask_irq(unsigned int irq_nr) -{ - set_bit(irq_nr, ppc_cached_irq_mask); - pmac_set_irq_mask(irq_nr); -} - -static void __pmac pmac_end_irq(unsigned int irq_nr) -{ - if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { - set_bit(irq_nr, ppc_cached_irq_mask); - pmac_set_irq_mask(irq_nr); - } -} - - -struct hw_interrupt_type pmac_pic = { - " PMAC-PIC ", - NULL, - NULL, - pmac_unmask_irq, - pmac_mask_irq, - pmac_mask_and_ack_irq, - pmac_end_irq, - NULL -}; - -struct hw_interrupt_type gatwick_pic = { - " GATWICK ", - NULL, - NULL, - pmac_unmask_irq, - pmac_mask_irq, - pmac_mask_and_ack_irq, - pmac_end_irq, - NULL -}; - -static void gatwick_action(int cpl, void *dev_id, struct pt_regs *regs) -{ - int irq, bits; - - for (irq = max_irqs; (irq -= 32) >= max_real_irqs; ) { - int i = irq >> 5; - bits = ld_le32(&pmac_irq_hw[i]->flag) - | ppc_lost_interrupts[i]; - if (bits == 0) - continue; - irq += __ilog2(bits); - break; - } - /* The previous version of this code allowed for this case, we - * don't. Put this here to check for it. - * -- Cort - */ - if ( irq_desc[irq].handler != &gatwick_pic ) - printk("gatwick irq not from gatwick pic\n"); - else - ppc_irq_dispatch_handler( regs, irq ); -} - -int -pmac_get_irq(struct pt_regs *regs) -{ - int irq; - unsigned long bits = 0; - -#ifdef CONFIG_SMP - void psurge_smp_message_recv(struct pt_regs *); - - /* IPI's are a hack on the powersurge -- Cort */ - if ( smp_processor_id() != 0 ) { - psurge_smp_message_recv(regs); - return -2; /* ignore, already handled */ - } -#endif /* CONFIG_SMP */ - for (irq = max_real_irqs; (irq -= 32) >= 0; ) { - int i = irq >> 5; - bits = ld_le32(&pmac_irq_hw[i]->flag) - | ppc_lost_interrupts[i]; - if (bits == 0) - continue; - irq += __ilog2(bits); - break; - } - - return irq; -} - -/* This routine will fix some missing interrupt values in the device tree - * on the gatwick mac-io controller used by some PowerBooks - */ -static void __init -pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base) -{ - struct device_node *node; - int count; - - memset(gatwick_int_pool, 0, sizeof(gatwick_int_pool)); - node = gw->child; - count = 0; - while(node) - { - /* Fix SCC */ - if (strcasecmp(node->name, "escc") == 0) - if (node->child) { - if (node->child->n_intrs < 3) { - node->child->intrs = &gatwick_int_pool[count]; - count += 3; - } - node->child->n_intrs = 3; - node->child->intrs[0].line = 15+irq_base; - node->child->intrs[1].line = 4+irq_base; - node->child->intrs[2].line = 5+irq_base; - printk(KERN_INFO "irq: fixed SCC on second controller (%d,%d,%d)\n", - node->child->intrs[0].line, - node->child->intrs[1].line, - node->child->intrs[2].line); - } - /* Fix media-bay & left SWIM */ - if (strcasecmp(node->name, "media-bay") == 0) { - struct device_node* ya_node; - - if (node->n_intrs == 0) - node->intrs = &gatwick_int_pool[count++]; - node->n_intrs = 1; - node->intrs[0].line = 29+irq_base; - printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n", - node->intrs[0].line); - - ya_node = node->child; - while(ya_node) - { - if (strcasecmp(ya_node->name, "floppy") == 0) { - if (ya_node->n_intrs < 2) { - ya_node->intrs = &gatwick_int_pool[count]; - count += 2; - } - ya_node->n_intrs = 2; - ya_node->intrs[0].line = 19+irq_base; - ya_node->intrs[1].line = 1+irq_base; - printk(KERN_INFO "irq: fixed floppy on second controller (%d,%d)\n", - ya_node->intrs[0].line, ya_node->intrs[1].line); - } - if (strcasecmp(ya_node->name, "ata4") == 0) { - if (ya_node->n_intrs < 2) { - ya_node->intrs = &gatwick_int_pool[count]; - count += 2; - } - ya_node->n_intrs = 2; - ya_node->intrs[0].line = 14+irq_base; - ya_node->intrs[1].line = 3+irq_base; - printk(KERN_INFO "irq: fixed ide on second controller (%d,%d)\n", - ya_node->intrs[0].line, ya_node->intrs[1].line); - } - ya_node = ya_node->sibling; - } - } - node = node->sibling; - } - if (count > 10) { - printk("WARNING !! Gatwick interrupt pool overflow\n"); - printk(" GATWICK_IRQ_POOL_SIZE = %d\n", GATWICK_IRQ_POOL_SIZE); - printk(" requested = %d\n", count); - } -} - -/* - * The PowerBook 3400/2400/3500 can have a combo ethernet/modem - * card which includes an ohare chip that acts as a second interrupt - * controller. If we find this second ohare, set it up and fix the - * interrupt value in the device tree for the ethernet chip. - */ -static int __init enable_second_ohare(void) -{ - unsigned char bus, devfn; - unsigned short cmd; - unsigned long addr; - struct device_node *irqctrler = find_devices("pci106b,7"); - struct device_node *ether; - - if (irqctrler == NULL || irqctrler->n_addrs <= 0) - return -1; - addr = (unsigned long) ioremap(irqctrler->addrs[0].address, 0x40); - pmac_irq_hw[1] = (volatile struct pmac_irq_hw *)(addr + 0x20); - max_irqs = 64; - if (pci_device_from_OF_node(irqctrler, &bus, &devfn) == 0) { - struct pci_controller* hose = pci_find_hose_for_OF_device(irqctrler); - if (!hose) - printk(KERN_ERR "Can't find PCI hose for OHare2 !\n"); - else { - early_read_config_word(hose, bus, devfn, PCI_COMMAND, &cmd); - cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; - cmd &= ~PCI_COMMAND_IO; - early_write_config_word(hose, bus, devfn, PCI_COMMAND, cmd); - } - } - - /* Fix interrupt for the modem/ethernet combo controller. The number - in the device tree (27) is bogus (correct for the ethernet-only - board but not the combo ethernet/modem board). - The real interrupt is 28 on the second controller -> 28+32 = 60. - */ - ether = find_devices("pci1011,14"); - if (ether && ether->n_intrs > 0) { - ether->intrs[0].line = 60; - printk(KERN_INFO "irq: Fixed ethernet IRQ to %d\n", - ether->intrs[0].line); - } - - /* Return the interrupt number of the cascade */ - return irqctrler->intrs[0].line; -} - -void __init -pmac_pic_init(void) -{ - int i; - struct device_node *irqctrler; - unsigned long addr; - int irq_cascade = -1; - - /* We first try to detect Apple's new Core99 chipset, since mac-io - * is quite different on those machines and contains an IBM MPIC2. - */ - irqctrler = find_type_devices("open-pic"); - if (irqctrler != NULL) - { - printk("PowerMac using OpenPIC irq controller\n"); - if (irqctrler->n_addrs > 0) - { - int nmi_irq = -1; - unsigned char senses[NR_IRQS]; -#ifdef CONFIG_XMON - struct device_node* pswitch; - - pswitch = find_devices("programmer-switch"); - if (pswitch && pswitch->n_intrs) - nmi_irq = pswitch->intrs[0].line; -#endif /* CONFIG_XMON */ - prom_get_irq_senses(senses, 0, NR_IRQS); - OpenPIC_InitSenses = senses; - OpenPIC_NumInitSenses = NR_IRQS; - ppc_md.get_irq = openpic_get_irq; - OpenPIC_Addr = ioremap(irqctrler->addrs[0].address, - irqctrler->addrs[0].size); - openpic_init(1, 0, 0, nmi_irq); -#ifdef CONFIG_XMON - if (nmi_irq >= 0) - request_irq(nmi_irq, xmon_irq, 0, - "NMI - XMON", 0); -#endif /* CONFIG_XMON */ - return; - } - irqctrler = NULL; - } - - /* - * G3 powermacs and 1999 G3 PowerBooks have 64 interrupts, - * 1998 G3 Series PowerBooks have 128, - * other powermacs have 32. - * The combo ethernet/modem card for the Powerstar powerbooks - * (2400/3400/3500, ohare based) has a second ohare chip - * effectively making a total of 64. - */ - 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; - } - for ( i = 0; i < max_real_irqs ; i++ ) - irq_desc[i].handler = &pmac_pic; - - /* 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; - 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); - irq_cascade = irqctrler->intrs[0].line; - if (device_is_compatible(irqctrler, "gatwick")) - pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs); - } - } else { - /* older powermacs have a GC (grand central) or ohare at - f3000000, with interrupt control registers at f3000020. */ - addr = (unsigned long) ioremap(0xf3000000, 0x40); - pmac_irq_hw[0] = (volatile struct pmac_irq_hw *) (addr + 0x20); - } - - /* PowerBooks 3400 and 3500 can have a second controller in a second - ohare chip, on the combo ethernet/modem card */ - if (machine_is_compatible("AAPL,3400/2400") - || machine_is_compatible("AAPL,3500")) - irq_cascade = enable_second_ohare(); - - /* 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 (irq_cascade >= 0) { - printk(KERN_INFO "irq: secondary controller on irq %d\n", - (int)irq_cascade); - for ( i = max_real_irqs ; i < max_irqs ; i++ ) - irq_desc[i].handler = &gatwick_pic; - request_irq( irq_cascade, gatwick_action, SA_INTERRUPT, - "cascade", 0 ); - } - 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(20, xmon_irq, 0, "NMI - XMON", 0); -#endif /* CONFIG_XMON */ -} - -#ifdef CONFIG_PMAC_PBOOK -/* - * These procedures are used in implementing sleep on the powerbooks. - * sleep_save_intrs() saves the states of all interrupt enables - * and disables all interrupts except for the nominated one. - * sleep_restore_intrs() restores the states of all interrupt enables. - */ -unsigned int sleep_save_mask[2]; - -void __pmac -pmac_sleep_save_intrs(int viaint) -{ - sleep_save_mask[0] = ppc_cached_irq_mask[0]; - sleep_save_mask[1] = ppc_cached_irq_mask[1]; - ppc_cached_irq_mask[0] = 0; - ppc_cached_irq_mask[1] = 0; - if (viaint > 0) - set_bit(viaint, ppc_cached_irq_mask); - out_le32(&pmac_irq_hw[0]->enable, ppc_cached_irq_mask[0]); - if (max_real_irqs > 32) - out_le32(&pmac_irq_hw[1]->enable, ppc_cached_irq_mask[1]); - (void)in_le32(&pmac_irq_hw[0]->flag); - /* make sure mask gets to controller before we return to caller */ - mb(); - (void)in_le32(&pmac_irq_hw[0]->enable); -} - -void __pmac -pmac_sleep_restore_intrs(void) -{ - int i; - - out_le32(&pmac_irq_hw[0]->enable, 0); - if (max_real_irqs > 32) - out_le32(&pmac_irq_hw[1]->enable, 0); - mb(); - for (i = 0; i < max_real_irqs; ++i) - if (test_bit(i, sleep_save_mask)) - pmac_unmask_irq(i); -} -#endif /* CONFIG_PMAC_PBOOK */ diff --git a/arch/ppc/kernel/pmac_pic.h b/arch/ppc/kernel/pmac_pic.h deleted file mode 100644 index 2e27ea202b2b..000000000000 --- a/arch/ppc/kernel/pmac_pic.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * BK Id: SCCS/s.pmac_pic.h 1.9 08/19/01 22:23:04 paulus - */ -#ifndef _PPC_KERNEL_PMAC_PIC_H -#define _PPC_KERNEL_PMAC_PIC_H - -#include "local_irq.h" - -extern struct hw_interrupt_type pmac_pic; - -void pmac_pic_init(void); -int pmac_get_irq(struct pt_regs *regs); - -#endif /* _PPC_KERNEL_PMAC_PIC_H */ diff --git a/arch/ppc/kernel/pmac_setup.c b/arch/ppc/kernel/pmac_setup.c deleted file mode 100644 index ad11963bda86..000000000000 --- a/arch/ppc/kernel/pmac_setup.c +++ /dev/null @@ -1,838 +0,0 @@ -/* - * BK Id: SCCS/s.pmac_setup.c 1.43 11/13/01 21:26:07 paulus - */ -/* - * linux/arch/ppc/kernel/setup.c - * - * PowerPC version - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * - * Adapted for Power Macintosh by Paul Mackerras - * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) - * - * Derived from "arch/alpha/kernel/setup.c" - * Copyright (C) 1995 Linus Torvalds - * - * 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. - * - */ - -/* - * bootup setup stuff.. - */ - -#include <linux/config.h> -#include <linux/init.h> -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/stddef.h> -#include <linux/unistd.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/user.h> -#include <linux/a.out.h> -#include <linux/tty.h> -#include <linux/string.h> -#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 <linux/ide.h> -#include <linux/pci.h> -#include <linux/adb.h> -#include <linux/cuda.h> -#include <linux/pmu.h> -#include <linux/seq_file.h> - -#include <asm/processor.h> -#include <asm/sections.h> -#include <asm/prom.h> -#include <asm/system.h> -#include <asm/pgtable.h> -#include <asm/bitops.h> -#include <asm/io.h> -#include <asm/pci-bridge.h> -#include <asm/ohare.h> -#include <asm/mediabay.h> -#include <asm/feature.h> -#include <asm/machdep.h> -#include <asm/keyboard.h> -#include <asm/dma.h> -#include <asm/bootx.h> -#include <asm/cputable.h> -#include <asm/btext.h> - -#include <asm/time.h> -#include "local_irq.h" -#include "pmac_pic.h" -#include "../mm/mem_pieces.h" - -#undef SHOW_GATWICK_IRQS - -extern long pmac_time_init(void); -extern unsigned long pmac_get_rtc_time(void); -extern int pmac_set_rtc_time(unsigned long nowtime); -extern void pmac_read_rtc_time(void); -extern void pmac_calibrate_decr(void); -extern void pmac_pcibios_fixup(void); -extern void pmac_find_bridges(void); - -extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode); -extern int mackbd_getkeycode(unsigned int scancode); -extern int mackbd_translate(unsigned char keycode, unsigned char *keycodep, - char raw_mode); -extern char mackbd_unexpected_up(unsigned char keycode); -extern void mackbd_leds(unsigned char leds); -extern void __init mackbd_init_hw(void); -extern int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode, - char raw_mode); -extern char mac_hid_kbd_unexpected_up(unsigned char keycode); -extern void mac_hid_init_hw(void); -extern unsigned char mac_hid_kbd_sysrq_xlate[]; -extern unsigned char pckbd_sysrq_xlate[]; -extern unsigned char mackbd_sysrq_xlate[]; -extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); -extern int pckbd_getkeycode(unsigned int scancode); -extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, - char raw_mode); -extern char pckbd_unexpected_up(unsigned char keycode); -extern int keyboard_sends_linux_keycodes; -extern void pmac_nvram_update(void); - -extern int pmac_pci_enable_device_hook(struct pci_dev *dev, int initial); -extern void pmac_pcibios_after_init(void); - -struct device_node *memory_node; - -unsigned char drive_info; - -int ppc_override_l2cr = 0; -int ppc_override_l2cr_value; -int has_l2cache = 0; - -static int current_root_goodness = -1; - -extern char saved_command_line[]; - -extern int pmac_newworld; - -#define DEFAULT_ROOT_DEVICE 0x0801 /* sda1 - slightly silly choice */ - -extern void zs_kgdb_hook(int tty_num); -static void ohare_init(void); -#ifdef CONFIG_BOOTX_TEXT -void pmac_progress(char *s, unsigned short hex); -#endif - -sys_ctrler_t sys_ctrler = SYS_CTRLER_UNKNOWN; - -#ifdef CONFIG_SMP -extern struct smp_ops_t psurge_smp_ops; -extern struct smp_ops_t core99_smp_ops; - -volatile static long int core99_l2_cache; -void __init -core99_init_l2(void) -{ - int cpu = smp_processor_id(); - - if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR)) - return; - - if (cpu == 0){ - core99_l2_cache = _get_L2CR(); - printk("CPU0: L2CR is %lx\n", core99_l2_cache); - } else { - printk("CPU%d: L2CR was %lx\n", cpu, _get_L2CR()); - _set_L2CR(0); - _set_L2CR(core99_l2_cache); - printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache); - } -} -#endif /* CONFIG_SMP */ - -/* - * Assume here that all clock rates are the same in a - * smp system. -- Cort - */ -int __openfirmware -of_show_percpuinfo(struct seq_file *m, int i) -{ - struct device_node *cpu_node; - int *fp, s; - - cpu_node = find_type_devices("cpu"); - if (!cpu_node) - return 0; - for (s = 0; s < i && cpu_node->next; s++) - cpu_node = cpu_node->next; - fp = (int *) get_property(cpu_node, "clock-frequency", NULL); - if (fp) - seq_printf(m, "clock\t\t: %dMHz\n", *fp / 1000000); - return 0; -} - -int __pmac -pmac_show_cpuinfo(struct seq_file *m) -{ - struct device_node *np; - char *pp; - int plen; - - /* find motherboard type */ - seq_printf(m, "machine\t\t: "); - np = find_devices("device-tree"); - if (np != NULL) { - pp = (char *) get_property(np, "model", NULL); - if (pp != NULL) - seq_printf(m, "%s\n", pp); - else - seq_printf(m, "PowerMac\n"); - pp = (char *) get_property(np, "compatible", &plen); - if (pp != NULL) { - seq_printf(m, "motherboard\t:"); - while (plen > 0) { - int l = strlen(pp) + 1; - seq_printf(m, " %s", pp); - plen -= l; - pp += l; - } - seq_printf(m, "\n"); - } - } else - seq_printf(m, "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); - seq_printf(m, "L2 cache\t:"); - has_l2cache = 1; - if (get_property(np, "cache-unified", NULL) != 0 && dc) { - seq_printf(m, " %dK unified", *dc / 1024); - } else { - if (ic) - seq_printf(m, " %dK instruction", *ic / 1024); - if (dc) - seq_printf(m, "%s %dK data", - (ic? " +": ""), *dc / 1024); - } - pp = get_property(np, "ram-type", NULL); - if (pp) - seq_printf(m, " %s", pp); - seq_printf(m, "\n"); - } - - /* find ram info */ - np = find_devices("memory"); - if (np != 0) { - int n; - struct reg_property *reg = (struct reg_property *) - get_property(np, "reg", &n); - - if (reg != 0) { - unsigned long total = 0; - - for (n /= sizeof(struct reg_property); n > 0; --n) - total += (reg++)->size; - seq_printf(m, "memory\t\t: %luMB\n", total >> 20); - } - } - - /* Checks "l2cr-value" property in the registry */ - np = find_devices("cpus"); - if (np == 0) - np = find_type_devices("cpu"); - if (np != 0) { - unsigned int *l2cr = (unsigned int *) - get_property(np, "l2cr-value", NULL); - if (l2cr != 0) { - seq_printf(m, "l2cr override\t: 0x%x\n", *l2cr); - } - } - - /* Indicate newworld/oldworld */ - seq_printf(m, "pmac-generation\t: %s\n", - pmac_newworld ? "NewWorld" : "OldWorld"); - - - return 0; -} - -#ifdef CONFIG_SCSI -/* Find the device number for the disk (if any) at target tgt - on host adaptor host. We just need to get the prototype from - sd.h */ -#include <linux/blkdev.h> -#include "../../../drivers/scsi/scsi.h" -#include "../../../drivers/scsi/sd.h" - -#endif - -#ifdef CONFIG_VT -/* - * Dummy mksound function that does nothing. - * The real one is in the dmasound driver. - */ -static void __pmac -pmac_mksound(unsigned int hz, unsigned int ticks) -{ -} -#endif /* CONFIG_VT */ - -static volatile u32 *sysctrl_regs; - -void __init -pmac_setup_arch(void) -{ - struct device_node *cpu; - int *fp; - unsigned long pvr; - - pvr = PVR_VER(mfspr(PVR)); - - /* Set loops_per_jiffy to a half-way reasonable value, - for use until calibrate_delay gets called. */ - cpu = find_type_devices("cpu"); - if (cpu != 0) { - fp = (int *) get_property(cpu, "clock-frequency", NULL); - if (fp != 0) { - if (pvr == 4 || pvr >= 8) - /* 604, G3, G4 etc. */ - loops_per_jiffy = *fp / HZ; - else - /* 601, 603, etc. */ - loops_per_jiffy = *fp / (2*HZ); - } else - loops_per_jiffy = 50000000 / HZ; - } - - /* this area has the CPU identification register - and some registers used by smp boards */ - sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000); - ohare_init(); - - /* Lookup PCI hosts */ - pmac_find_bridges(); - - /* Checks "l2cr-value" property in the registry */ - if (cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR) { - struct device_node *np = find_devices("cpus"); - if (np == 0) - np = find_type_devices("cpu"); - if (np != 0) { - unsigned int *l2cr = (unsigned int *) - get_property(np, "l2cr-value", NULL); - if (l2cr != 0) { - ppc_override_l2cr = 1; - ppc_override_l2cr_value = *l2cr; - _set_L2CR(0); - _set_L2CR(ppc_override_l2cr_value); - } - } - } - - if (ppc_override_l2cr) - printk(KERN_INFO "L2CR overriden (0x%x), backside cache is %s\n", - ppc_override_l2cr_value, (ppc_override_l2cr_value & 0x80000000) - ? "enabled" : "disabled"); - -#ifdef CONFIG_SMP - /* somewhat of a hack */ - core99_init_l2(); -#endif - -#ifdef CONFIG_KGDB - zs_kgdb_hook(0); -#endif - -#ifdef CONFIG_ADB_CUDA - find_via_cuda(); -#else - if (find_devices("via-cuda")) { - printk("WARNING ! Your machine is Cuda based but your kernel\n"); - printk(" wasn't compiled with CONFIG_ADB_CUDA option !\n"); - } -#endif -#ifdef CONFIG_ADB_PMU - find_via_pmu(); -#else - if (find_devices("via-pmu")) { - printk("WARNING ! Your machine is PMU based but your kernel\n"); - printk(" wasn't compiled with CONFIG_ADB_PMU option !\n"); - } -#endif -#ifdef CONFIG_NVRAM - pmac_nvram_init(); -#endif -#ifdef CONFIG_DUMMY_CONSOLE - conswitchp = &dummy_con; -#endif -#ifdef CONFIG_VT - kd_mksound = pmac_mksound; -#endif -#ifdef CONFIG_BLK_DEV_INITRD - if (initrd_start) - ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); - else -#endif - ROOT_DEV = to_kdev_t(DEFAULT_ROOT_DEVICE); - -#ifdef CONFIG_SMP - /* Check for Core99 */ - if (find_devices("uni-n")) - ppc_md.smp_ops = &core99_smp_ops; - else - ppc_md.smp_ops = &psurge_smp_ops; -#endif /* CONFIG_SMP */ -} - -static void __init ohare_init(void) -{ - /* - * Turn on the L2 cache. - * We assume that we have a PSX memory controller iff - * we have an ohare I/O controller. - */ - 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; - if(has_l2cache) - printk(KERN_INFO "Level 2 cache enabled\n"); - } - } -} - -extern char *bootpath; -extern char *bootdevice; -void *boot_host; -int boot_target; -int boot_part; -extern kdev_t boot_dev; - -void __init -pmac_init2(void) -{ -#ifdef CONFIG_ADB_PMU - via_pmu_start(); -#endif -#ifdef CONFIG_ADB_CUDA - via_cuda_start(); -#endif -#ifdef CONFIG_PMAC_PBOOK - media_bay_init(); -#endif -} - -#ifdef CONFIG_SCSI -void __init -note_scsi_host(struct device_node *node, void *host) -{ - int l; - char *p; - - l = strlen(node->full_name); - if (bootpath != NULL && bootdevice != NULL - && strncmp(node->full_name, bootdevice, l) == 0 - && (bootdevice[l] == '/' || bootdevice[l] == 0)) { - boot_host = host; - /* - * There's a bug in OF 1.0.5. (Why am I not surprised.) - * If you pass a path like scsi/sd@1:0 to canon, it returns - * something like /bandit@F2000000/gc@10/53c94@10000/sd@0,0 - * That is, the scsi target number doesn't get preserved. - * So we pick the target number out of bootpath and use that. - */ - p = strstr(bootpath, "/sd@"); - if (p != NULL) { - p += 4; - boot_target = simple_strtoul(p, NULL, 10); - p = strchr(p, ':'); - if (p != NULL) - boot_part = simple_strtoul(p + 1, NULL, 10); - } - } -} -#endif - -#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) -kdev_t __init -find_ide_boot(void) -{ - char *p; - int n; - kdev_t __init pmac_find_ide_boot(char *bootdevice, int n); - - if (bootdevice == NULL) - return 0; - p = strrchr(bootdevice, '/'); - if (p == NULL) - return 0; - n = p - bootdevice; - - return pmac_find_ide_boot(bootdevice, n); -} -#endif /* CONFIG_BLK_DEV_IDE && CONFIG_BLK_DEV_IDE_PMAC */ - -void __init -find_boot_device(void) -{ -#if defined(CONFIG_SCSI) && defined(CONFIG_BLK_DEV_SD) - if (boot_host != NULL) { - boot_dev = sd_find_target(boot_host, boot_target); - if (boot_dev != 0) - return; - } -#endif -#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) - boot_dev = find_ide_boot(); -#endif -} - -/* can't be __init - can be called whenever a disk is first accessed */ -void __pmac -note_bootable_part(kdev_t dev, int part, int goodness) -{ - static int found_boot = 0; - char *p; - - /* Do nothing if the root has been mounted already. */ - if (init_task.fs->rootmnt != NULL) - return; - if ((goodness <= current_root_goodness) && - (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(); - found_boot = 1; - } - if (boot_dev == 0 || dev == boot_dev) { - ROOT_DEV = MKDEV(MAJOR(dev), MINOR(dev) + part); - boot_dev = NODEV; - current_root_goodness = goodness; - } -} - -void __pmac -pmac_restart(char *cmd) -{ -#ifdef CONFIG_ADB_CUDA - struct adb_request req; -#endif /* CONFIG_ADB_CUDA */ - -#ifdef CONFIG_NVRAM - pmac_nvram_update(); -#endif - - switch (sys_ctrler) { -#ifdef CONFIG_ADB_CUDA - case SYS_CTRLER_CUDA: - cuda_request(&req, NULL, 2, CUDA_PACKET, - CUDA_RESET_SYSTEM); - for (;;) - cuda_poll(); - break; -#endif /* CONFIG_ADB_CUDA */ -#ifdef CONFIG_ADB_PMU - case SYS_CTRLER_PMU: - pmu_restart(); - break; -#endif /* CONFIG_ADB_PMU */ - default: ; - } -} - -void __pmac -pmac_power_off(void) -{ -#ifdef CONFIG_ADB_CUDA - struct adb_request req; -#endif /* CONFIG_ADB_CUDA */ - -#ifdef CONFIG_NVRAM - pmac_nvram_update(); -#endif - - switch (sys_ctrler) { -#ifdef CONFIG_ADB_CUDA - case SYS_CTRLER_CUDA: - cuda_request(&req, NULL, 2, CUDA_PACKET, - CUDA_POWERDOWN); - for (;;) - cuda_poll(); - break; -#endif /* CONFIG_ADB_CUDA */ -#ifdef CONFIG_ADB_PMU - case SYS_CTRLER_PMU: - pmu_shutdown(); - break; -#endif /* CONFIG_ADB_PMU */ - default: ; - } -} - -void __pmac -pmac_halt(void) -{ - pmac_power_off(); -} - - -#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) -/* - * IDE stuff. - */ -static int __pmac -pmac_ide_check_region(ide_ioreg_t from, unsigned int extent) -{ - /* - * We only do the check_region if `from' looks like a genuine - * I/O port number. If it actually refers to a memory-mapped - * register, it should be OK. - */ - if (from < ~_IO_BASE) - return check_region(from, extent); - return 0; -} - -static void __pmac -pmac_ide_request_region(ide_ioreg_t from, - unsigned int extent, - const char *name) -{ - if (from < ~_IO_BASE) - request_region(from, extent, name); -} - -static void __pmac -pmac_ide_release_region(ide_ioreg_t from, - unsigned int extent) -{ - if (from < ~_IO_BASE) - release_region(from, extent); -} - -/* - * This is only used if we have a PCI IDE controller, not - * for the IDE controller in the ohare/paddington/heathrow/keylargo. - */ -static void __pmac -pmac_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, - ide_ioreg_t ctrl_port, int *irq) -{ - ide_ioreg_t reg = data_port; - int i; - - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { - hw->io_ports[i] = reg; - reg += 1; - } - hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; -} -#endif - -/* - * Read in a property describing some pieces of memory. - */ - -static void __init -get_mem_prop(char *name, struct mem_pieces *mp) -{ - struct reg_property *rp; - int i, s; - unsigned int *ip; - int nac = prom_n_addr_cells(memory_node); - int nsc = prom_n_size_cells(memory_node); - - ip = (unsigned int *) get_property(memory_node, name, &s); - if (ip == NULL) { - printk(KERN_ERR "error: couldn't get %s property on /memory\n", - name); - abort(); - } - s /= (nsc + nac) * 4; - rp = mp->regions; - for (i = 0; i < s; ++i, ip += nac+nsc) { - if (nac >= 2 && ip[nac-2] != 0) - continue; - rp->address = ip[nac-1]; - if (nsc >= 2 && ip[nac+nsc-2] != 0) - rp->size = ~0U; - else - rp->size = ip[nac+nsc-1]; - ++rp; - } - mp->n_regions = rp - mp->regions; - - /* Make sure the pieces are sorted. */ - mem_pieces_sort(mp); - mem_pieces_coalesce(mp); -} - -/* - * On systems with Open Firmware, collect information about - * physical RAM and which pieces are already in use. - * At this point, we have (at least) the first 8MB mapped with a BAT. - * Our text, data, bss use something over 1MB, starting at 0. - * Open Firmware may be using 1MB at the 4MB point. - */ -unsigned long __init -pmac_find_end_of_memory(void) -{ - unsigned long a, total; - struct mem_pieces phys_mem; - - memory_node = find_devices("memory"); - if (memory_node == NULL) { - printk(KERN_ERR "can't find memory node\n"); - abort(); - } - - /* - * Find out where physical memory is, and check that it - * starts at 0 and is contiguous. It seems that RAM is - * always physically contiguous on Power Macintoshes. - * - * Supporting discontiguous physical memory isn't hard, - * it just makes the virtual <-> physical mapping functions - * more complicated (or else you end up wasting space - * in mem_map). - */ - get_mem_prop("reg", &phys_mem); - if (phys_mem.n_regions == 0) - panic("No RAM??"); - a = phys_mem.regions[0].address; - if (a != 0) - panic("RAM doesn't start at physical address 0"); - total = phys_mem.regions[0].size; - - if (phys_mem.n_regions > 1) { - printk("RAM starting at 0x%x is not contiguous\n", - phys_mem.regions[1].address); - printk("Using RAM from 0 to 0x%lx\n", total-1); - } - - return total; -} - -void __init -select_adb_keyboard(void) -{ -#ifdef CONFIG_VT -#ifdef CONFIG_INPUT - ppc_md.kbd_init_hw = mac_hid_init_hw; - ppc_md.kbd_translate = mac_hid_kbd_translate; - ppc_md.kbd_unexpected_up = mac_hid_kbd_unexpected_up; - ppc_md.kbd_setkeycode = 0; - ppc_md.kbd_getkeycode = 0; - ppc_md.kbd_leds = 0; -#ifdef CONFIG_MAGIC_SYSRQ -#ifdef CONFIG_MAC_ADBKEYCODES - if (!keyboard_sends_linux_keycodes) { - ppc_md.ppc_kbd_sysrq_xlate = mac_hid_kbd_sysrq_xlate; - SYSRQ_KEY = 0x69; - } else -#endif /* CONFIG_MAC_ADBKEYCODES */ - { - ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate; - SYSRQ_KEY = 0x54; - } -#endif /* CONFIG_MAGIC_SYSRQ */ -#elif defined(CONFIG_ADB_KEYBOARD) - ppc_md.kbd_setkeycode = mackbd_setkeycode; - ppc_md.kbd_getkeycode = mackbd_getkeycode; - ppc_md.kbd_translate = mackbd_translate; - ppc_md.kbd_unexpected_up = mackbd_unexpected_up; - ppc_md.kbd_leds = mackbd_leds; - ppc_md.kbd_init_hw = mackbd_init_hw; -#ifdef CONFIG_MAGIC_SYSRQ - ppc_md.ppc_kbd_sysrq_xlate = mackbd_sysrq_xlate; - SYSRQ_KEY = 0x69; -#endif /* CONFIG_MAGIC_SYSRQ */ -#endif /* CONFIG_INPUT_ADBHID/CONFIG_ADB_KEYBOARD */ -#endif /* CONFIG_VT */ -} - -void __init -pmac_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - /* isa_io_base gets set in pmac_find_bridges */ - isa_mem_base = PMAC_ISA_MEM_BASE; - pci_dram_offset = PMAC_PCI_DRAM_OFFSET; - ISA_DMA_THRESHOLD = ~0L; - DMA_MODE_READ = 1; - DMA_MODE_WRITE = 2; - - ppc_md.setup_arch = pmac_setup_arch; - ppc_md.show_cpuinfo = pmac_show_cpuinfo; - ppc_md.show_percpuinfo = of_show_percpuinfo; - ppc_md.irq_cannonicalize = NULL; - ppc_md.init_IRQ = pmac_pic_init; - ppc_md.get_irq = pmac_get_irq; /* Changed later on ... */ - ppc_md.init = pmac_init2; - - ppc_md.pcibios_fixup = pmac_pcibios_fixup; - ppc_md.pcibios_enable_device_hook = pmac_pci_enable_device_hook; - ppc_md.pcibios_after_init = pmac_pcibios_after_init; - - ppc_md.restart = pmac_restart; - ppc_md.power_off = pmac_power_off; - ppc_md.halt = pmac_halt; - - ppc_md.time_init = pmac_time_init; - ppc_md.set_rtc_time = pmac_set_rtc_time; - ppc_md.get_rtc_time = pmac_get_rtc_time; - ppc_md.calibrate_decr = pmac_calibrate_decr; - - ppc_md.find_end_of_memory = pmac_find_end_of_memory; - - select_adb_keyboard(); - -#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) - ppc_ide_md.ide_check_region = pmac_ide_check_region; - ppc_ide_md.ide_request_region = pmac_ide_request_region; - ppc_ide_md.ide_release_region = pmac_ide_release_region; - ppc_ide_md.ide_init_hwif = pmac_ide_init_hwif_ports; -#endif /* CONFIG_BLK_DEV_IDE && CONFIG_BLK_DEV_IDE_PMAC */ - -#ifdef CONFIG_BOOTX_TEXT - ppc_md.progress = pmac_progress; -#endif /* CONFIG_BOOTX_TEXT */ - - if (ppc_md.progress) ppc_md.progress("pmac_init(): exit", 0); - -} - -#ifdef CONFIG_BOOTX_TEXT -extern void drawchar(char c); -extern void drawstring(const char *c); -extern boot_infos_t *disp_bi; -void __init -pmac_progress(char *s, unsigned short hex) -{ - if (disp_bi == 0) - return; - btext_drawstring(s); - btext_drawchar('\n'); -} -#endif /* CONFIG_BOOTX_TEXT */ diff --git a/arch/ppc/kernel/pmac_smp.c b/arch/ppc/kernel/pmac_smp.c deleted file mode 100644 index 9c28cdde79ee..000000000000 --- a/arch/ppc/kernel/pmac_smp.c +++ /dev/null @@ -1,489 +0,0 @@ -/* - * BK Id: %F% %I% %G% %U% %#% - */ -/* - * SMP support for power macintosh. - * - * We support both the old "powersurge" SMP architecture - * and the current Core99 (G4 PowerMac) machines. - * - * Support Macintosh G4 SMP by Troy Benjegerdes (hozer@drgw.net) - * and Ben Herrenschmidt <benh@kernel.crashing.org>. - * - * Support for DayStar quad CPU cards - * Copyright (C) XLR8, Inc. 1994-2000 - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/smp.h> -#include <linux/smp_lock.h> -#include <linux/interrupt.h> -#include <linux/kernel_stat.h> -#include <linux/delay.h> -#define __KERNEL_SYSCALLS__ -#include <linux/unistd.h> -#include <linux/init.h> -#include <linux/spinlock.h> - -#include <asm/ptrace.h> -#include <asm/atomic.h> -#include <asm/irq.h> -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/hardirq.h> -#include <asm/softirq.h> -#include <asm/sections.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/smp.h> -#include <asm/residual.h> -#include <asm/feature.h> -#include <asm/time.h> -#include <asm/gemini.h> - -#include "open_pic.h" - -/* - * Powersurge (old powermac SMP) support. - */ - -extern void __secondary_start_psurge(void); -extern void __secondary_start_psurge2(void); /* Temporary horrible hack */ -extern void __secondary_start_psurge3(void); /* Temporary horrible hack */ - -/* Addresses for powersurge registers */ -#define HAMMERHEAD_BASE 0xf8000000 -#define HHEAD_CONFIG 0x90 -#define HHEAD_SEC_INTR 0xc0 - -/* register for interrupting the primary processor on the powersurge */ -/* N.B. this is actually the ethernet ROM! */ -#define PSURGE_PRI_INTR 0xf3019000 - -/* register for storing the start address for the secondary processor */ -/* N.B. this is the PCI config space address register for the 1st bridge */ -#define PSURGE_START 0xf2800000 - -/* Daystar/XLR8 4-CPU card */ -#define PSURGE_QUAD_REG_ADDR 0xf8800000 - -#define PSURGE_QUAD_IRQ_SET 0 -#define PSURGE_QUAD_IRQ_CLR 1 -#define PSURGE_QUAD_IRQ_PRIMARY 2 -#define PSURGE_QUAD_CKSTOP_CTL 3 -#define PSURGE_QUAD_PRIMARY_ARB 4 -#define PSURGE_QUAD_BOARD_ID 6 -#define PSURGE_QUAD_WHICH_CPU 7 -#define PSURGE_QUAD_CKSTOP_RDBK 8 -#define PSURGE_QUAD_RESET_CTL 11 - -#define PSURGE_QUAD_OUT(r, v) (out_8(quad_base + ((r) << 4) + 4, (v))) -#define PSURGE_QUAD_IN(r) (in_8(quad_base + ((r) << 4) + 4) & 0x0f) -#define PSURGE_QUAD_BIS(r, v) (PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) | (v))) -#define PSURGE_QUAD_BIC(r, v) (PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) & ~(v))) - -/* virtual addresses for the above */ -static volatile u8 *hhead_base; -static volatile u8 *quad_base; -static volatile u32 *psurge_pri_intr; -static volatile u8 *psurge_sec_intr; -static volatile u32 *psurge_start; - -/* what sort of powersurge board we have */ -static int psurge_type; - -/* values for psurge_type */ -#define PSURGE_DUAL 0 -#define PSURGE_QUAD_OKEE 1 -#define PSURGE_QUAD_COTTON 2 -#define PSURGE_QUAD_ICEGRASS 3 - -/* l2 cache stuff for dual G4 macs */ -extern void core99_init_l2(void); - -/* - * Set and clear IPIs for powersurge. - */ -static inline void psurge_set_ipi(int cpu) -{ - if (cpu == 0) - in_be32(psurge_pri_intr); - else if (psurge_type == PSURGE_DUAL) - out_8(psurge_sec_intr, 0); - else - PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_SET, 1 << cpu); -} - -static inline void psurge_clr_ipi(int cpu) -{ - if (cpu > 0) { - if (psurge_type == PSURGE_DUAL) - out_8(psurge_sec_intr, ~0); - else - PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, 1 << cpu); - } -} - -/* - * On powersurge (old SMP powermac architecture) we don't have - * separate IPIs for separate messages like openpic does. Instead - * we have a bitmap for each processor, where a 1 bit means that - * the corresponding message is pending for that processor. - * Ideally each cpu's entry would be in a different cache line. - * -- paulus. - */ -static unsigned long psurge_smp_message[NR_CPUS]; - -void __pmac -psurge_smp_message_recv(struct pt_regs *regs) -{ - int cpu = smp_processor_id(); - int msg; - - /* clear interrupt */ - psurge_clr_ipi(cpu); - - if (smp_num_cpus < 2) - return; - - /* make sure there is a message there */ - for (msg = 0; msg < 4; msg++) - if (test_and_clear_bit(msg, &psurge_smp_message[cpu])) - smp_message_recv(msg, regs); -} - -void __pmac -psurge_primary_intr(int irq, void *d, struct pt_regs *regs) -{ - psurge_smp_message_recv(regs); -} - -static void __pmac -smp_psurge_message_pass(int target, int msg, unsigned long data, int wait) -{ - int i; - - if (smp_num_cpus < 2) - return; - - for (i = 0; i < smp_num_cpus; i++) { - if (target == MSG_ALL - || (target == MSG_ALL_BUT_SELF && i != smp_processor_id()) - || target == i) { - set_bit(msg, &psurge_smp_message[i]); - psurge_set_ipi(i); - } - } -} - -/* - * Determine a quad card presence. We read the board ID register, we - * force the data bus to change to something else, and we read it again. - * It it's stable, then the register probably exist (ugh !) - */ -static int __init psurge_quad_probe(void) -{ - int type; - unsigned int i; - - type = PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID); - if (type < PSURGE_QUAD_OKEE || type > PSURGE_QUAD_ICEGRASS - || type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID)) - return PSURGE_DUAL; - - /* looks OK, try a slightly more rigorous test */ - /* bogus is not necessarily cacheline-aligned, - though I don't suppose that really matters. -- paulus */ - for (i = 0; i < 100; i++) { - volatile u32 bogus[8]; - bogus[(0+i)%8] = 0x00000000; - bogus[(1+i)%8] = 0x55555555; - bogus[(2+i)%8] = 0xFFFFFFFF; - bogus[(3+i)%8] = 0xAAAAAAAA; - bogus[(4+i)%8] = 0x33333333; - bogus[(5+i)%8] = 0xCCCCCCCC; - bogus[(6+i)%8] = 0xCCCCCCCC; - bogus[(7+i)%8] = 0x33333333; - wmb(); - asm volatile("dcbf 0,%0" : : "r" (bogus) : "memory"); - mb(); - if (type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID)) - return PSURGE_DUAL; - } - return type; -} - -static void __init psurge_quad_init(void) -{ - int procbits; - - if (ppc_md.progress) ppc_md.progress("psurge_quad_init", 0x351); - procbits = ~PSURGE_QUAD_IN(PSURGE_QUAD_WHICH_CPU); - if (psurge_type == PSURGE_QUAD_ICEGRASS) - PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits); - else - PSURGE_QUAD_BIC(PSURGE_QUAD_CKSTOP_CTL, procbits); - mdelay(33); - out_8(psurge_sec_intr, ~0); - PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, procbits); - PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits); - if (psurge_type != PSURGE_QUAD_ICEGRASS) - PSURGE_QUAD_BIS(PSURGE_QUAD_CKSTOP_CTL, procbits); - PSURGE_QUAD_BIC(PSURGE_QUAD_PRIMARY_ARB, procbits); - mdelay(33); - PSURGE_QUAD_BIC(PSURGE_QUAD_RESET_CTL, procbits); - mdelay(33); - PSURGE_QUAD_BIS(PSURGE_QUAD_PRIMARY_ARB, procbits); - mdelay(33); -} - -static int __init smp_psurge_probe(void) -{ - int i, ncpus; - - /* We don't do SMP on the PPC601 -- paulus */ - if (PVR_VER(mfspr(PVR)) == 1) - return 1; - - /* - * The powersurge cpu board can be used in the generation - * of powermacs that have a socket for an upgradeable cpu card, - * including the 7500, 8500, 9500, 9600. - * The device tree doesn't tell you if you have 2 cpus because - * OF doesn't know anything about the 2nd processor. - * Instead we look for magic bits in magic registers, - * in the hammerhead memory controller in the case of the - * dual-cpu powersurge board. -- paulus. - */ - if (find_devices("hammerhead") == NULL) - return 1; - - hhead_base = ioremap(HAMMERHEAD_BASE, 0x800); - quad_base = ioremap(PSURGE_QUAD_REG_ADDR, 1024); - psurge_sec_intr = hhead_base + HHEAD_SEC_INTR; - - psurge_type = psurge_quad_probe(); - if (psurge_type != PSURGE_DUAL) { - psurge_quad_init(); - /* All released cards using this HW design have 4 CPUs */ - ncpus = 4; - } else { - iounmap((void *) quad_base); - if ((in_8(hhead_base + HHEAD_CONFIG) & 0x02) == 0) { - /* not a dual-cpu card */ - iounmap((void *) hhead_base); - return 1; - } - ncpus = 2; - } - - psurge_start = ioremap(PSURGE_START, 4); - psurge_pri_intr = ioremap(PSURGE_PRI_INTR, 4); - - /* this is not actually strictly necessary -- paulus. */ - for (i = 1; i < ncpus; ++i) - smp_hw_index[i] = i; - - if (ppc_md.progress) ppc_md.progress("smp_psurge_probe - done", 0x352); - - return ncpus; -} - -static void __init smp_psurge_kick_cpu(int nr) -{ - void (*start)(void) = __secondary_start_psurge; - unsigned long a; - - /* may need to flush here if secondary bats aren't setup */ - for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32) - asm volatile("dcbf 0,%0" : : "r" (a) : "memory"); - asm volatile("sync"); - - if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu", 0x353); - - /* setup entry point of secondary processor */ - switch (nr) { - case 2: - start = __secondary_start_psurge2; - break; - case 3: - start = __secondary_start_psurge3; - break; - } - - out_be32(psurge_start, __pa(start)); - mb(); - - psurge_set_ipi(nr); - udelay(10); - psurge_clr_ipi(nr); - - if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu - done", 0x354); -} - -/* - * With the dual-cpu powersurge board, the decrementers and timebases - * of both cpus are frozen after the secondary cpu is started up, - * until we give the secondary cpu another interrupt. This routine - * uses this to get the timebases synchronized. - * -- paulus. - */ -static void __init psurge_dual_sync_tb(int cpu_nr) -{ - static volatile int sec_tb_reset = 0; - int t; - - set_dec(tb_ticks_per_jiffy); - set_tb(0, 0); - last_jiffy_stamp(cpu_nr) = 0; - - if (cpu_nr > 0) { - mb(); - sec_tb_reset = 1; - return; - } - - /* wait for the secondary to have reset its TB before proceeding */ - for (t = 10000000; t > 0 && !sec_tb_reset; --t) - ; - - /* now interrupt the secondary, starting both TBs */ - psurge_set_ipi(1); - - smp_tb_synchronized = 1; -} - -static void __init -smp_psurge_setup_cpu(int cpu_nr) -{ - - if (cpu_nr == 0) { - if (smp_num_cpus < 2) - return; - /* reset the entry point so if we get another intr we won't - * try to startup again */ - out_be32(psurge_start, 0x100); - if (request_irq(30, psurge_primary_intr, 0, "primary IPI", 0)) - printk(KERN_ERR "Couldn't get primary IPI interrupt"); - } - - if (psurge_type == PSURGE_DUAL) - psurge_dual_sync_tb(cpu_nr); -} - -static int __init -smp_core99_probe(void) -{ - struct device_node *cpus; - int i, ncpus = 1; - - if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345); - cpus = find_type_devices("cpu"); - if (cpus) - while ((cpus = cpus->next) != NULL) - ++ncpus; - printk("smp_core99_probe: found %d cpus\n", ncpus); - if (ncpus > 1) { - openpic_request_IPIs(); - for (i = 1; i < ncpus; ++i) - smp_hw_index[i] = i; - } - - return ncpus; -} - -static void __init -smp_core99_kick_cpu(int nr) -{ - unsigned long save_vector, new_vector; - unsigned long flags; -#if 1 /* New way... */ - volatile unsigned long *vector - = ((volatile unsigned long *)(KERNELBASE+0x100)); - if (nr < 1 || nr > 3) - return; -#else - volatile unsigned long *vector - = ((volatile unsigned long *)(KERNELBASE+0x500)); - if (nr != 1) - return; -#endif - if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346); - - local_irq_save(flags); - local_irq_disable(); - - /* Save reset vector */ - save_vector = *vector; - - /* Setup fake reset vector that does - * b __secondary_start_psurge - KERNELBASE - */ - switch(nr) { - case 1: - new_vector = (unsigned long)__secondary_start_psurge; - break; - case 2: - new_vector = (unsigned long)__secondary_start_psurge2; - break; - case 3: - new_vector = (unsigned long)__secondary_start_psurge3; - break; - } - *vector = 0x48000002 + new_vector - KERNELBASE; - - /* flush data cache and inval instruction cache */ - flush_icache_range((unsigned long) vector, (unsigned long) vector + 4); - - /* Put some life in our friend */ - feature_core99_kick_cpu(nr); - - /* FIXME: We wait a bit for the CPU to take the exception, I should - * instead wait for the entry code to set something for me. Well, - * ideally, all that crap will be done in prom.c and the CPU left - * in a RAM-based wait loop like CHRP. - */ - mdelay(1); - - /* Restore our exception vector */ - *vector = save_vector; - flush_icache_range((unsigned long) vector, (unsigned long) vector + 4); - - local_irq_restore(flags); - if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347); -} - -static void __init -smp_core99_setup_cpu(int cpu_nr) -{ - /* Setup openpic */ - do_openpic_setup_cpu(); - - /* Setup L2 */ - if (cpu_nr != 0) - core99_init_l2(); - else - if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349); -} - -/* PowerSurge-style Macs */ -struct smp_ops_t psurge_smp_ops __pmacdata = { - smp_psurge_message_pass, - smp_psurge_probe, - smp_psurge_kick_cpu, - smp_psurge_setup_cpu, -}; - -/* Core99 Macs (dual G4s) */ -struct smp_ops_t core99_smp_ops __pmacdata = { - smp_openpic_message_pass, - smp_core99_probe, - smp_core99_kick_cpu, - smp_core99_setup_cpu, -}; diff --git a/arch/ppc/kernel/pmac_time.c b/arch/ppc/kernel/pmac_time.c deleted file mode 100644 index ba7260441eb2..000000000000 --- a/arch/ppc/kernel/pmac_time.c +++ /dev/null @@ -1,286 +0,0 @@ -/* - * BK Id: SCCS/s.pmac_time.c 1.16 09/08/01 15:47:42 paulus - */ -/* - * Support for periodic interrupts (100 per second) and for getting - * the current time from the RTC on Power Macintoshes. - * - * We use the decrementer register for our periodic interrupts. - * - * Paul Mackerras August 1996. - * Copyright (C) 1996 Paul Mackerras. - */ -#include <linux/config.h> -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/param.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/init.h> -#include <linux/adb.h> -#include <linux/cuda.h> -#include <linux/pmu.h> - -#include <asm/sections.h> -#include <asm/prom.h> -#include <asm/system.h> -#include <asm/io.h> -#include <asm/pgtable.h> -#include <asm/machdep.h> -#include <asm/hardirq.h> -#include <asm/time.h> -#include <asm/nvram.h> - -extern rwlock_t xtime_lock; - -/* Apparently the RTC stores seconds since 1 Jan 1904 */ -#define RTC_OFFSET 2082844800 - -/* - * Calibrate the decrementer frequency with the VIA timer 1. - */ -#define VIA_TIMER_FREQ_6 4700000 /* time 1 frequency * 6 */ - -/* VIA registers */ -#define RS 0x200 /* skip between registers */ -#define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */ -#define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */ -#define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */ -#define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */ -#define ACR (11*RS) /* Auxiliary control register */ -#define IFR (13*RS) /* Interrupt flag register */ - -/* Bits in ACR */ -#define T1MODE 0xc0 /* Timer 1 mode */ -#define T1MODE_CONT 0x40 /* continuous interrupts */ - -/* Bits in IFR and IER */ -#define T1_INT 0x40 /* Timer 1 interrupt */ - -extern struct timezone sys_tz; - -long __init -pmac_time_init(void) -{ -#ifdef CONFIG_NVRAM - s32 delta = 0; - int dst; - - delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16; - delta |= ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xa)) << 8; - delta |= pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xb); - if (delta & 0x00800000UL) - delta |= 0xFF000000UL; - dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0); - printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60, - dst ? "on" : "off"); - return delta; -#else - return 0; -#endif -} - -unsigned long __pmac -pmac_get_rtc_time(void) -{ -#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU) - struct adb_request req; - unsigned long now; -#endif - - /* Get the time from the RTC */ - switch (sys_ctrler) { -#ifdef CONFIG_ADB_CUDA - case SYS_CTRLER_CUDA: - if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0) - return 0; - while (!req.complete) - cuda_poll(); - if (req.reply_len != 7) - printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n", - req.reply_len); - now = (req.reply[3] << 24) + (req.reply[4] << 16) - + (req.reply[5] << 8) + req.reply[6]; - return now - RTC_OFFSET; -#endif /* CONFIG_ADB_CUDA */ -#ifdef CONFIG_ADB_PMU - case SYS_CTRLER_PMU: - if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0) - return 0; - while (!req.complete) - pmu_poll(); - if (req.reply_len != 5) - printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n", - req.reply_len); - now = (req.reply[1] << 24) + (req.reply[2] << 16) - + (req.reply[3] << 8) + req.reply[4]; - return now - RTC_OFFSET; -#endif /* CONFIG_ADB_PMU */ - default: ; - } - return 0; -} - -int __pmac -pmac_set_rtc_time(unsigned long nowtime) -{ -#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU) - struct adb_request req; -#endif - - nowtime += RTC_OFFSET; - - switch (sys_ctrler) { -#ifdef CONFIG_ADB_CUDA - case SYS_CTRLER_CUDA: - if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME, - nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0) - return 0; - while (!req.complete) - cuda_poll(); - if ((req.reply_len != 3) && (req.reply_len != 7)) - printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n", - req.reply_len); - return 1; -#endif /* CONFIG_ADB_CUDA */ -#ifdef CONFIG_ADB_PMU - case SYS_CTRLER_PMU: - if (pmu_request(&req, NULL, 5, PMU_SET_RTC, - nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0) - return 0; - while (!req.complete) - pmu_poll(); - if (req.reply_len != 0) - printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n", - req.reply_len); - return 1; -#endif /* CONFIG_ADB_PMU */ - default: - return 0; - } -} - -/* - * Calibrate the decrementer register using VIA timer 1. - * This is used both on powermacs and CHRP machines. - */ -int __init -via_calibrate_decr(void) -{ - struct device_node *vias; - volatile unsigned char *via; - int count = VIA_TIMER_FREQ_6 / HZ; - unsigned int dstart, dend; - - vias = find_devices("via-cuda"); - if (vias == 0) - vias = find_devices("via-pmu"); - if (vias == 0) - vias = find_devices("via"); - if (vias == 0 || vias->n_addrs == 0) - return 0; - via = (volatile unsigned char *) - ioremap(vias->addrs[0].address, vias->addrs[0].size); - - /* set timer 1 for continuous interrupts */ - out_8(&via[ACR], (via[ACR] & ~T1MODE) | T1MODE_CONT); - /* set the counter to a small value */ - out_8(&via[T1CH], 2); - /* set the latch to `count' */ - out_8(&via[T1LL], count); - out_8(&via[T1LH], count >> 8); - /* wait until it hits 0 */ - while ((in_8(&via[IFR]) & T1_INT) == 0) - ; - dstart = get_dec(); - /* clear the interrupt & wait until it hits 0 again */ - in_8(&via[T1CL]); - while ((in_8(&via[IFR]) & T1_INT) == 0) - ; - dend = get_dec(); - - tb_ticks_per_jiffy = (dstart - dend) / 6; - tb_to_us = mulhwu_scale_factor(dstart - dend, 60000); - - printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %u (%u ticks)\n", - tb_ticks_per_jiffy, dstart - dend); - - return 1; -} - -#ifdef CONFIG_PMAC_PBOOK -/* - * Reset the time after a sleep. - */ -static int __pmac -time_sleep_notify(struct pmu_sleep_notifier *self, int when) -{ - static unsigned long time_diff; - unsigned long flags; - - switch (when) { - case PBOOK_SLEEP_NOW: - read_lock_irqsave(&xtime_lock, flags); - time_diff = xtime.tv_sec - pmac_get_rtc_time(); - read_unlock_irqrestore(&xtime_lock, flags); - break; - case PBOOK_WAKE: - write_lock_irqsave(&xtime_lock, flags); - xtime.tv_sec = pmac_get_rtc_time() + time_diff; - set_dec(tb_ticks_per_jiffy); - /* No currently-supported powerbook has a 601, - so use get_tbl, not native */ - last_jiffy_stamp(0) = tb_last_stamp = get_tbl(); - xtime.tv_usec = 0; - last_rtc_update = xtime.tv_sec; - write_unlock_irqrestore(&xtime_lock, flags); - break; - } - return PBOOK_SLEEP_OK; -} - -static struct pmu_sleep_notifier time_sleep_notifier __pmacdata = { - time_sleep_notify, SLEEP_LEVEL_MISC, -}; -#endif /* CONFIG_PMAC_PBOOK */ - -/* - * Query the OF and get the decr frequency. - * This was taken from the pmac time_init() when merging the prep/pmac - * time functions. - */ -void __init -pmac_calibrate_decr(void) -{ - struct device_node *cpu; - unsigned int freq, *fp; - -#ifdef CONFIG_PMAC_PBOOK - pmu_register_sleep_notifier(&time_sleep_notifier); -#endif /* CONFIG_PMAC_PBOOK */ - - /* We assume MacRISC2 machines have correct device-tree - * calibration. That's better since the VIA itself seems - * to be slightly off. --BenH - */ - if (!machine_is_compatible("MacRISC2")) - if (via_calibrate_decr()) - return; - - /* - * The cpu node should have a timebase-frequency property - * to tell us the rate at which the decrementer counts. - */ - cpu = find_type_devices("cpu"); - if (cpu == 0) - panic("can't find cpu node in time_init"); - fp = (unsigned int *) get_property(cpu, "timebase-frequency", NULL); - if (fp == 0) - panic("can't get cpu timebase frequency"); - freq = *fp; - printk("time_init: decrementer frequency = %u.%.6u MHz\n", - freq/1000000, freq%1000000); - tb_ticks_per_jiffy = freq / HZ; - tb_to_us = mulhwu_scale_factor(freq, 1000000); -} diff --git a/arch/ppc/kernel/ppc-stub.c b/arch/ppc/kernel/ppc-stub.c index 5ace6d58bc38..aa79ba92390b 100644 --- a/arch/ppc/kernel/ppc-stub.c +++ b/arch/ppc/kernel/ppc-stub.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ppc-stub.c 1.6 05/17/01 18:14:21 cort + * BK Id: %F% %I% %G% %U% %#% */ /* * ppc-stub.c: KGDB support for the Linux kernel. @@ -61,7 +61,7 @@ * * The following gdb commands are supported: * - * command function Return value + * command function Return value * * g return the value of the CPU registers hex data or ENN * G set the value of the CPU registers OK or ENN @@ -131,12 +131,16 @@ static int kgdb_started; static u_int fault_jmp_buf[100]; static int kdebug; + static const char hexchars[]="0123456789abcdef"; /* Place where we save old trap entries for restoration - sparc*/ /* struct tt_entry kgdb_savettable[256]; */ /* typedef void (*trapfunc_t)(void); */ +static void kgdb_fault_handler(struct pt_regs *regs); +static void handle_exception (struct pt_regs *regs); + #if 0 /* Install an exception handler for kgdb */ static void exceptionHandler(int tnum, unsigned int *tfunc) @@ -188,14 +192,45 @@ static unsigned char * mem2hex(char *mem, char *buf, int count) { unsigned char ch; + unsigned short tmp_s; + unsigned long tmp_l; if (kgdb_setjmp((long*)fault_jmp_buf) == 0) { debugger_fault_handler = kgdb_fault_handler; - while (count-- > 0) { - ch = *mem++; - *buf++ = hexchars[ch >> 4]; - *buf++ = hexchars[ch & 0xf]; + + /* Accessing 16 bit and 32 bit objects in a single + ** load instruction is required to avoid bad side + ** effects for some IO registers. + */ + + if ((count == 2) && (((long)mem & 1) == 0)) { + tmp_s = *(unsigned short *)mem; + mem += 2; + *buf++ = hexchars[(tmp_s >> 12) & 0xf]; + *buf++ = hexchars[(tmp_s >> 8) & 0xf]; + *buf++ = hexchars[(tmp_s >> 4) & 0xf]; + *buf++ = hexchars[tmp_s & 0xf]; + + } else if ((count == 4) && (((long)mem & 3) == 0)) { + tmp_l = *(unsigned int *)mem; + mem += 4; + *buf++ = hexchars[(tmp_l >> 28) & 0xf]; + *buf++ = hexchars[(tmp_l >> 24) & 0xf]; + *buf++ = hexchars[(tmp_l >> 20) & 0xf]; + *buf++ = hexchars[(tmp_l >> 16) & 0xf]; + *buf++ = hexchars[(tmp_l >> 12) & 0xf]; + *buf++ = hexchars[(tmp_l >> 8) & 0xf]; + *buf++ = hexchars[(tmp_l >> 4) & 0xf]; + *buf++ = hexchars[tmp_l & 0xf]; + + } else { + while (count-- > 0) { + ch = *mem++; + *buf++ = hexchars[ch >> 4]; + *buf++ = hexchars[ch & 0xf]; + } } + } else { /* error condition */ } @@ -210,17 +245,58 @@ mem2hex(char *mem, char *buf, int count) static char * hex2mem(char *buf, char *mem, int count) { - int i; unsigned char ch; + int i; + char *orig_mem; + unsigned short tmp_s; + unsigned long tmp_l; + + orig_mem = mem; if (kgdb_setjmp((long*)fault_jmp_buf) == 0) { debugger_fault_handler = kgdb_fault_handler; - for (i=0; i<count; i++) { - ch = hex(*buf++) << 4; - ch |= hex(*buf++); - *mem++ = ch; + + /* Accessing 16 bit and 32 bit objects in a single + ** store instruction is required to avoid bad side + ** effects for some IO registers. + */ + + if ((count == 2) && (((long)mem & 1) == 0)) { + tmp_s = hex(*buf++) << 12; + tmp_s |= hex(*buf++) << 8; + tmp_s |= hex(*buf++) << 4; + tmp_s |= hex(*buf++); + + *(unsigned short *)mem = tmp_s; + mem += 2; + + } else if ((count == 4) && (((long)mem & 3) == 0)) { + tmp_l = hex(*buf++) << 28; + tmp_l |= hex(*buf++) << 24; + tmp_l |= hex(*buf++) << 20; + tmp_l |= hex(*buf++) << 16; + tmp_l |= hex(*buf++) << 12; + tmp_l |= hex(*buf++) << 8; + tmp_l |= hex(*buf++) << 4; + tmp_l |= hex(*buf++); + + *(unsigned long *)mem = tmp_l; + mem += 4; + + } else { + for (i=0; i<count; i++) { + ch = hex(*buf++) << 4; + ch |= hex(*buf++); + *mem++ = ch; + } } - flush_icache_range((int)mem, (int)mem+count); + + + /* + ** Flush the data cache, invalidate the instruction cache. + */ + flush_icache_range((int)orig_mem, (int)orig_mem + count - 1); + } else { /* error condition */ } @@ -253,14 +329,14 @@ hexToInt(char **ptr, int *intValue) (*ptr)++; } } else { - /* error condition */ + /* error condition */ } debugger_fault_handler = 0; return (numChars); } -/* scan for the sequence $<data>#<checksum> */ +/* scan for the sequence $<data>#<checksum> */ static void getpacket(char *buffer) { @@ -316,14 +392,14 @@ getpacket(char *buffer) } while (checksum != xmitcsum); } -/* send the packet in buffer. */ +/* send the packet in buffer. */ static void putpacket(unsigned char *buffer) { unsigned char checksum; int count; unsigned char ch, recv; - /* $<packet info>#<checksum>. */ + /* $<packet info>#<checksum>. */ do { putDebugChar('$'); checksum = 0; @@ -428,7 +504,7 @@ int kgdb_dabr_match(struct pt_regs *regs) return 1; } -/* Convert the SPARC hardware trap type code to a unix signal number. */ +/* Convert the hardware trap type code to a unix signal number. */ /* * This table contains the mapping between PowerPC hardware trap types, and * signals, which are primarily what GDB understands. @@ -438,20 +514,47 @@ static struct hard_trap_info unsigned int tt; /* Trap type code for powerpc */ unsigned char signo; /* Signal that we map this trap into */ } hard_trap_info[] = { - { 0x200, SIGSEGV }, /* machine check */ - { 0x300, SIGSEGV }, /* address error (store) */ - { 0x400, SIGBUS }, /* instruction bus error */ - { 0x500, SIGINT }, /* interrupt */ - { 0x600, SIGBUS }, /* alingment */ - { 0x700, SIGTRAP }, /* breakpoint trap */ - { 0x800, SIGFPE }, /* fpu unavail */ - { 0x900, SIGALRM }, /* decrementer */ - { 0xa00, SIGILL }, /* reserved */ - { 0xb00, SIGILL }, /* reserved */ - { 0xc00, SIGCHLD }, /* syscall */ - { 0xd00, SIGTRAP }, /* single-step/watch */ - { 0xe00, SIGFPE }, /* fp assist */ +#if defined(CONFIG_4xx) + { 0x100, SIGINT }, /* critical input interrupt */ + { 0x200, SIGSEGV }, /* machine check */ + { 0x300, SIGSEGV }, /* data storage */ + { 0x400, SIGBUS }, /* instruction storage */ + { 0x500, SIGINT }, /* interrupt */ + { 0x600, SIGBUS }, /* alignment */ + { 0x700, SIGILL }, /* program */ + { 0x800, SIGILL }, /* reserved */ + { 0x900, SIGILL }, /* reserved */ + { 0xa00, SIGILL }, /* reserved */ + { 0xb00, SIGILL }, /* reserved */ + { 0xc00, SIGCHLD }, /* syscall */ + { 0xd00, SIGILL }, /* reserved */ + { 0xe00, SIGILL }, /* reserved */ + { 0xf00, SIGILL }, /* reserved */ + /* + ** 0x1000 PIT + ** 0x1010 FIT + ** 0x1020 watchdog + ** 0x1100 data TLB miss + ** 0x1200 instruction TLB miss + */ + { 0x2000, SIGTRAP}, /* debug */ +#else + { 0x200, SIGSEGV }, /* machine check */ + { 0x300, SIGSEGV }, /* address error (store) */ + { 0x400, SIGBUS }, /* instruction bus error */ + { 0x500, SIGINT }, /* interrupt */ + { 0x600, SIGBUS }, /* alingment */ + { 0x700, SIGTRAP }, /* breakpoint trap */ + { 0x800, SIGFPE }, /* fpu unavail */ + { 0x900, SIGALRM }, /* decrementer */ + { 0xa00, SIGILL }, /* reserved */ + { 0xb00, SIGILL }, /* reserved */ + { 0xc00, SIGCHLD }, /* syscall */ + { 0xd00, SIGTRAP }, /* single-step/watch */ + { 0xe00, SIGFPE }, /* fp assist */ +#endif { 0, 0} /* Must be last */ + }; static int computeSignal(unsigned int tt) @@ -462,7 +565,7 @@ static int computeSignal(unsigned int tt) if (ht->tt == tt) return ht->signo; - return SIGHUP; /* default for things we don't know about */ + return SIGHUP; /* default for things we don't know about */ } #define PC_REGNUM 64 @@ -493,7 +596,7 @@ handle_exception (struct pt_regs *regs) #ifdef KGDB_DEBUG printk("kgdb: entering handle_exception; trap [0x%x]\n", - (unsigned int)regs->trap); + (unsigned int)regs->trap); #endif kgdb_interruptible(0); @@ -510,7 +613,7 @@ handle_exception (struct pt_regs *regs) sigval = computeSignal(regs->trap); ptr = remcomOutBuffer; -#if 0 +#if defined(CONFIG_4xx) *ptr++ = 'S'; *ptr++ = hexchars[sigval >> 4]; *ptr++ = hexchars[sigval & 0xf]; @@ -533,6 +636,8 @@ handle_exception (struct pt_regs *regs) *ptr++ = 0; putpacket(remcomOutBuffer); + if (kdebug) + printk("remcomOutBuffer: %s\n", remcomOutBuffer); /* XXX We may want to add some features dealing with poking the * XXX page tables, ... (look at sparc-stub.c for more info) @@ -544,7 +649,7 @@ handle_exception (struct pt_regs *regs) getpacket(remcomInBuffer); switch (remcomInBuffer[0]) { - case '?': /* report most recent signal */ + case '?': /* report most recent signal */ remcomOutBuffer[0] = 'S'; remcomOutBuffer[1] = hexchars[sigval >> 4]; remcomOutBuffer[2] = hexchars[sigval & 0xf]; @@ -601,7 +706,7 @@ handle_exception (struct pt_regs *regs) } break; - case 'G': /* set the value of the CPU registers */ + case 'G': /* set the value of the CPU registers */ { ptr = &remcomInBuffer[1]; @@ -639,15 +744,14 @@ handle_exception (struct pt_regs *regs) ptr = &remcomInBuffer[1]; - if (hexToInt(&ptr, &addr) - && *ptr++ == ',' - && hexToInt(&ptr, &length)) { - if (mem2hex((char *)addr, remcomOutBuffer,length)) + if (hexToInt(&ptr, &addr) && *ptr++ == ',' + && hexToInt(&ptr, &length)) { + if (mem2hex((char *)addr, remcomOutBuffer, + length)) break; - strcpy (remcomOutBuffer, "E03"); - } else { - strcpy(remcomOutBuffer,"E01"); - } + strcpy(remcomOutBuffer, "E03"); + } else + strcpy(remcomOutBuffer, "E01"); break; case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ @@ -655,50 +759,63 @@ handle_exception (struct pt_regs *regs) ptr = &remcomInBuffer[1]; - if (hexToInt(&ptr, &addr) - && *ptr++ == ',' - && hexToInt(&ptr, &length) - && *ptr++ == ':') { - if (hex2mem(ptr, (char *)addr, length)) { + if (hexToInt(&ptr, &addr) && *ptr++ == ',' + && hexToInt(&ptr, &length) + && *ptr++ == ':') { + if (hex2mem(ptr, (char *)addr, length)) strcpy(remcomOutBuffer, "OK"); - } else { + else strcpy(remcomOutBuffer, "E03"); - } flush_icache_range(addr, addr+length); - } else { + } else strcpy(remcomOutBuffer, "E02"); - } break; - case 'k': /* kill the program, actually just continue */ - case 'c': /* cAA..AA Continue; address AA..AA optional */ + case 'k': /* kill the program, actually just continue */ + case 'c': /* cAA..AA Continue; address AA..AA optional */ /* try to read optional parameter, pc unchanged if no parm */ ptr = &remcomInBuffer[1]; - if (hexToInt(&ptr, &addr)) { + if (hexToInt(&ptr, &addr)) regs->nip = addr; - } /* Need to flush the instruction cache here, as we may have deposited a * breakpoint, and the icache probably has no way of knowing that a data ref to * some location may have changed something that is in the instruction cache. */ kgdb_flush_cache_all(); +#if defined(CONFIG_4xx) + strcpy(remcomOutBuffer, "OK"); + putpacket(remcomOutBuffer); +#endif set_msr(msr); + kgdb_interruptible(1); unlock_kernel(); kgdb_active = 0; + if (kdebug) { + printk("remcomInBuffer: %s\n", remcomInBuffer); + printk("remcomOutBuffer: %s\n", remcomOutBuffer); + } return; case 's': kgdb_flush_cache_all(); +#if defined(CONFIG_4xx) + regs->msr |= MSR_DE; + regs->dbcr0 |= (DBCR0_IDM | DBCR0_IC); + set_msr(msr); +#else regs->msr |= MSR_SE; -#if 0 set_msr(msr | MSR_SE); #endif unlock_kernel(); kgdb_active = 0; + if (kdebug) { + printk("remcomInBuffer: %s\n", remcomInBuffer); + printk("remcomOutBuffer: %s\n", remcomOutBuffer); + } return; case 'r': /* Reset (if user process..exit ???)*/ @@ -729,7 +846,7 @@ breakpoint(void) asm(" .globl breakinst breakinst: .long 0x7d821008 - "); + "); } /* Output string in GDB O-packet format if GDB has connected. If nothing @@ -739,24 +856,23 @@ kgdb_output_string (const char* s, unsigned int count) { char buffer[512]; - if (!kgdb_started) - return 0; + if (!kgdb_started) + return 0; - count = (count <= (sizeof(buffer) / 2 - 2)) + count = (count <= (sizeof(buffer) / 2 - 2)) ? count : (sizeof(buffer) / 2 - 2); buffer[0] = 'O'; mem2hex (s, &buffer[1], count); putpacket(buffer); - return 1; + return 1; } -#ifndef CONFIG_8xx +#if defined(CONFIG_6xx) || defined(CONFIG_POWER3) || defined(CONFIG_ISERIES) -/* I don't know why other platforms don't need this. The function for - * the 8xx is found in arch/ppc/8xx_io/uart.c. -- Dan - */ +/* This is used on arches which don't have a serial driver that maps + * the ports for us */ void kgdb_map_scc(void) { diff --git a/arch/ppc/kernel/ppc405_dma.c b/arch/ppc/kernel/ppc405_dma.c new file mode 100755 index 000000000000..8cec3683a926 --- /dev/null +++ b/arch/ppc/kernel/ppc405_dma.c @@ -0,0 +1,511 @@ +/* + * linux/arch/ppc/kernel/ppc405_dma.c + * + * BRIEF MODULE DESCRIPTION + * IBM 405 DMA Controller Functions + * + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * + * 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. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <asm/system.h> +#include <asm/io.h> +#include <linux/mm.h> +#include <linux/miscdevice.h> +#include <linux/init.h> +#include <linux/module.h> + +#include <asm/ppc405_dma.h> + + +/* + * Function prototypes + */ + +int hw_init_dma_channel(unsigned int, ppc_dma_ch_t *); +int init_dma_channel(unsigned int); +int get_channel_config(unsigned int, ppc_dma_ch_t *); +int set_channel_priority(unsigned int, unsigned int); +unsigned int get_peripheral_width(unsigned int); +int alloc_dma_handle(sgl_handle_t *, unsigned int, unsigned int); +void free_dma_handle(sgl_handle_t); + + +ppc_dma_ch_t dma_channels[MAX_405GP_DMA_CHANNELS]; + +/* + * Configures a DMA channel, including the peripheral bus width, if a + * peripheral is attached to the channel, the polarity of the DMAReq and + * DMAAck signals, etc. This information should really be setup by the boot + * code, since most likely the configuration won't change dynamically. + * If the kernel has to call this function, it's recommended that it's + * called from platform specific init code. The driver should not need to + * call this function. + */ +int hw_init_dma_channel(unsigned int dmanr, ppc_dma_ch_t *p_init) +{ + unsigned int polarity; + uint32_t control = 0; + ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr]; + +#ifdef DEBUG_405DMA + if (!p_init) { + printk("hw_init_dma_channel: NULL p_init\n"); + return DMA_STATUS_NULL_POINTER; + } + if (dmanr >= MAX_405GP_DMA_CHANNELS) { + printk("hw_init_dma_channel: bad channel %d\n", dmanr); + return DMA_STATUS_BAD_CHANNEL; + } +#endif + +#if DCRN_POL > 0 + polarity = mfdcr(DCRN_POL); +#else + polarity = 0; +#endif + + /* Setup the control register based on the values passed to + * us in p_init. Then, over-write the control register with this + * new value. + */ + + control |= ( + SET_DMA_CIE_ENABLE(p_init->int_enable) | /* interrupt enable */ + SET_DMA_BEN(p_init->buffer_enable) | /* buffer enable */ + SET_DMA_ETD(p_init->etd_output) | /* end of transfer pin */ + SET_DMA_TCE(p_init->tce_enable) | /* terminal count enable */ + SET_DMA_PL(p_init->pl) | /* peripheral location */ + SET_DMA_DAI(p_init->dai) | /* dest addr increment */ + SET_DMA_SAI(p_init->sai) | /* src addr increment */ + SET_DMA_PRIORITY(p_init->cp) | /* channel priority */ + SET_DMA_PW(p_init->pwidth) | /* peripheral/bus width */ + SET_DMA_PSC(p_init->psc) | /* peripheral setup cycles */ + SET_DMA_PWC(p_init->pwc) | /* peripheral wait cycles */ + SET_DMA_PHC(p_init->phc) | /* peripheral hold cycles */ + SET_DMA_PREFETCH(p_init->pf) /* read prefetch */ + ); + + switch (dmanr) { + case 0: + /* clear all polarity signals and then "or" in new signal levels */ + polarity &= ~(DMAReq0_ActiveLow | DMAAck0_ActiveLow | EOT0_ActiveLow); + polarity |= p_dma_ch->polarity; +#if DCRN_POL > 0 + mtdcr(DCRN_POL, polarity); +#endif + mtdcr(DCRN_DMACR0, control); + break; + case 1: + polarity &= ~(DMAReq1_ActiveLow | DMAAck1_ActiveLow | EOT1_ActiveLow); + polarity |= p_dma_ch->polarity; +#if DCRN_POL > 0 + mtdcr(DCRN_POL, polarity); +#endif + mtdcr(DCRN_DMACR1, control); + break; + case 2: + polarity &= ~(DMAReq2_ActiveLow | DMAAck2_ActiveLow | EOT2_ActiveLow); + polarity |= p_dma_ch->polarity; +#if DCRN_POL > 0 + mtdcr(DCRN_POL, polarity); +#endif + mtdcr(DCRN_DMACR2, control); + break; + case 3: + polarity &= ~(DMAReq3_ActiveLow | DMAAck3_ActiveLow | EOT3_ActiveLow); + polarity |= p_dma_ch->polarity; +#if DCRN_POL > 0 + mtdcr(DCRN_POL, polarity); +#endif + mtdcr(DCRN_DMACR3, control); + break; + default: + return DMA_STATUS_BAD_CHANNEL; + } + + /* save these values in our dma channel structure */ + memcpy(p_dma_ch, p_init, sizeof(ppc_dma_ch_t)); + + /* + * The peripheral width values written in the control register are: + * PW_8 0 + * PW_16 1 + * PW_32 2 + * PW_64 3 + * + * Since the DMA count register takes the number of "transfers", + * we need to divide the count sent to us in certain + * functions by the appropriate number. It so happens that our + * right shift value is equal to the peripheral width value. + */ + p_dma_ch->shift = p_init->pwidth; + + /* + * Save the control word for easy access. + */ + p_dma_ch->control = control; + + mtdcr(DCRN_DMASR, 0xffffffff); /* clear status register */ + return DMA_STATUS_GOOD; +} + + + + +/* + * This function returns the channel configuration. + */ +int get_channel_config(unsigned int dmanr, ppc_dma_ch_t *p_dma_ch) +{ + unsigned int polarity; + unsigned int control; + +#if DCRN_POL > 0 + polarity = mfdcr(DCRN_POL); +#else + polarity = 0; +#endif + + switch (dmanr) { + case 0: + p_dma_ch->polarity = + polarity & (DMAReq0_ActiveLow | DMAAck0_ActiveLow | EOT0_ActiveLow); + control = mfdcr(DCRN_DMACR0); + break; + case 1: + p_dma_ch->polarity = + polarity & (DMAReq1_ActiveLow | DMAAck1_ActiveLow | EOT1_ActiveLow); + control = mfdcr(DCRN_DMACR1); + break; + case 2: + p_dma_ch->polarity = + polarity & (DMAReq2_ActiveLow | DMAAck2_ActiveLow | EOT2_ActiveLow); + control = mfdcr(DCRN_DMACR2); + break; + case 3: + p_dma_ch->polarity = + polarity & (DMAReq3_ActiveLow | DMAAck3_ActiveLow | EOT3_ActiveLow); + control = mfdcr(DCRN_DMACR3); + break; + default: + return DMA_STATUS_BAD_CHANNEL; + } + + p_dma_ch->cp = GET_DMA_PRIORITY(control); + p_dma_ch->pwidth = GET_DMA_PW(control); + p_dma_ch->psc = GET_DMA_PSC(control); + p_dma_ch->pwc = GET_DMA_PWC(control); + p_dma_ch->phc = GET_DMA_PHC(control); + p_dma_ch->pf = GET_DMA_PREFETCH(control); + p_dma_ch->int_enable = GET_DMA_CIE_ENABLE(control); + p_dma_ch->shift = GET_DMA_PW(control); + + return DMA_STATUS_GOOD; +} + +/* + * Sets the priority for the DMA channel dmanr. + * Since this is setup by the hardware init function, this function + * can be used to dynamically change the priority of a channel. + * + * Acceptable priorities: + * + * PRIORITY_LOW + * PRIORITY_MID_LOW + * PRIORITY_MID_HIGH + * PRIORITY_HIGH + * + */ +int set_channel_priority(unsigned int dmanr, unsigned int priority) +{ + unsigned int control; + +#ifdef DEBUG_405DMA + if ( (priority != PRIORITY_LOW) && + (priority != PRIORITY_MID_LOW) && + (priority != PRIORITY_MID_HIGH) && + (priority != PRIORITY_HIGH)) { + printk("set_channel_priority: bad priority: 0x%x\n", priority); + } +#endif + + switch (dmanr) { + case 0: + control = mfdcr(DCRN_DMACR0); + control|= SET_DMA_PRIORITY(priority); + mtdcr(DCRN_DMACR0, control); + break; + case 1: + control = mfdcr(DCRN_DMACR1); + control|= SET_DMA_PRIORITY(priority); + mtdcr(DCRN_DMACR1, control); + break; + case 2: + control = mfdcr(DCRN_DMACR2); + control|= SET_DMA_PRIORITY(priority); + mtdcr(DCRN_DMACR2, control); + break; + case 3: + control = mfdcr(DCRN_DMACR3); + control|= SET_DMA_PRIORITY(priority); + mtdcr(DCRN_DMACR3, control); + break; + default: +#ifdef DEBUG_405DMA + printk("set_channel_priority: bad channel: %d\n", dmanr); +#endif + return DMA_STATUS_BAD_CHANNEL; + } + return DMA_STATUS_GOOD; +} + + + +/* + * Returns the width of the peripheral attached to this channel. This assumes + * that someone who knows the hardware configuration, boot code or some other + * init code, already set the width. + * + * The return value is one of: + * PW_8 + * PW_16 + * PW_32 + * PW_64 + * + * The function returns 0 on error. + */ +unsigned int get_peripheral_width(unsigned int dmanr) +{ + unsigned int control; + + switch (dmanr) { + case 0: + control = mfdcr(DCRN_DMACR0); + break; + case 1: + control = mfdcr(DCRN_DMACR1); + break; + case 2: + control = mfdcr(DCRN_DMACR2); + break; + case 3: + control = mfdcr(DCRN_DMACR3); + break; + default: +#ifdef DEBUG_405DMA + printk("get_peripheral_width: bad channel: %d\n", dmanr); +#endif + return 0; + } + return(GET_DMA_PW(control)); +} + + + + +/* + * Create a scatter/gather list handle. This is simply a structure which + * describes a scatter/gather list. + * + * A handle is returned in "handle" which the driver should save in order to + * be able to access this list later. A chunk of memory will be allocated + * to be used by the API for internal management purposes, including managing + * the sg list and allocating memory for the sgl descriptors. One page should + * be more than enough for that purpose. Perhaps it's a bit wasteful to use + * a whole page for a single sg list, but most likely there will be only one + * sg list per channel. + * + * Interrupt notes: + * Each sgl descriptor has a copy of the DMA control word which the DMA engine + * loads in the control register. The control word has a "global" interrupt + * enable bit for that channel. Interrupts are further qualified by a few bits + * in the sgl descriptor count register. In order to setup an sgl, we have to + * know ahead of time whether or not interrupts will be enabled at the completion + * of the transfers. Thus, enable_dma_interrupt()/disable_dma_interrupt() MUST + * be called before calling alloc_dma_handle(). If the interrupt mode will never + * change after powerup, then enable_dma_interrupt()/disable_dma_interrupt() + * do not have to be called -- interrupts will be enabled or disabled based + * on how the channel was configured after powerup by the hw_init_dma_channel() + * function. Each sgl descriptor will be setup to interrupt if an error occurs; + * however, only the last descriptor will be setup to interrupt. Thus, an + * interrupt will occur (if interrupts are enabled) only after the complete + * sgl transfer is done. + */ +int alloc_dma_handle(sgl_handle_t *phandle, unsigned int mode, unsigned int dmanr) +{ + sgl_list_info_t *psgl; + dma_addr_t dma_addr; + ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr]; + uint32_t sg_command; + void *ret; + +#ifdef DEBUG_405DMA + if (!phandle) { + printk("alloc_dma_handle: null handle pointer\n"); + return DMA_STATUS_NULL_POINTER; + } + switch (mode) { + case DMA_MODE_READ: + case DMA_MODE_WRITE: + case DMA_MODE_MM: + case DMA_MODE_MM_DEVATSRC: + case DMA_MODE_MM_DEVATDST: + break; + default: + printk("alloc_dma_handle: bad mode 0x%x\n", mode); + return DMA_STATUS_BAD_MODE; + } + if (dmanr >= MAX_405GP_DMA_CHANNELS) { + printk("alloc_dma_handle: invalid channel 0x%x\n", dmanr); + return DMA_STATUS_BAD_CHANNEL; + } +#endif + + /* Get a page of memory, which is zeroed out by pci_alloc_consistent() */ + +/* wrong not a pci device - armin */ + /* psgl = (sgl_list_info_t *) pci_alloc_consistent(NULL, SGL_LIST_SIZE, &dma_addr); +*/ + + ret = consistent_alloc(GFP_ATOMIC |GFP_DMA, SGL_LIST_SIZE, &dma_addr); + if (ret != NULL) { + memset(ret, 0,SGL_LIST_SIZE ); + psgl = (sgl_list_info_t *) ret; + } + + + if (psgl == NULL) { + *phandle = (sgl_handle_t)NULL; + return DMA_STATUS_OUT_OF_MEMORY; + } + + psgl->dma_addr = dma_addr; + psgl->dmanr = dmanr; + + /* + * Modify and save the control word. These word will get written to each sgl + * descriptor. The DMA engine then loads this control word into the control + * register every time it reads a new descriptor. + */ + psgl->control = p_dma_ch->control; + psgl->control &= ~(DMA_TM_MASK | DMA_TD); /* clear all "mode" bits first */ + psgl->control |= (mode | DMA_CH_ENABLE); /* save the control word along with the mode */ + + if (p_dma_ch->int_enable) { + psgl->control |= DMA_CIE_ENABLE; /* channel interrupt enabled */ + } + else { + psgl->control &= ~DMA_CIE_ENABLE; + } + +#if DCRN_ASGC > 0 + sg_command = mfdcr(DCRN_ASGC); + switch (dmanr) { + case 0: + sg_command |= SSG0_MASK_ENABLE; + break; + case 1: + sg_command |= SSG1_MASK_ENABLE; + break; + case 2: + sg_command |= SSG2_MASK_ENABLE; + break; + case 3: + sg_command |= SSG3_MASK_ENABLE; + break; + default: +#ifdef DEBUG_405DMA + printk("alloc_dma_handle: bad channel: %d\n", dmanr); +#endif + free_dma_handle((sgl_handle_t)psgl); + *phandle = (sgl_handle_t)NULL; + return DMA_STATUS_BAD_CHANNEL; + } + + mtdcr(DCRN_ASGC, sg_command); /* enable writing to this channel's sgl control bits */ +#else + (void)sg_command; +#endif + psgl->sgl_control = SG_ERI_ENABLE | SG_LINK; /* sgl descriptor control bits */ + + if (p_dma_ch->int_enable) { + if (p_dma_ch->tce_enable) + psgl->sgl_control |= SG_TCI_ENABLE; + else + psgl->sgl_control |= SG_ETI_ENABLE; + } + + *phandle = (sgl_handle_t)psgl; + return DMA_STATUS_GOOD; +} + + + +/* + * Destroy a scatter/gather list handle that was created by alloc_dma_handle(). + * The list must be empty (contain no elements). + */ +void free_dma_handle(sgl_handle_t handle) +{ + sgl_list_info_t *psgl = (sgl_list_info_t *)handle; + + if (!handle) { +#ifdef DEBUG_405DMA + printk("free_dma_handle: got NULL\n"); +#endif + return; + } + else if (psgl->phead) { +#ifdef DEBUG_405DMA + printk("free_dma_handle: list not empty\n"); +#endif + return; + } + else if (!psgl->dma_addr) { /* should never happen */ +#ifdef DEBUG_405DMA + printk("free_dma_handle: no dma address\n"); +#endif + return; + } + + /* wrong not a PCI device -armin */ + /* pci_free_consistent(NULL, SGL_LIST_SIZE, (void *)psgl, psgl->dma_addr); */ + // free_pages((unsigned long)psgl, get_order(SGL_LIST_SIZE)); + consistent_free((void *)psgl); + + +} + + +EXPORT_SYMBOL(hw_init_dma_channel); +EXPORT_SYMBOL(get_channel_config); +EXPORT_SYMBOL(set_channel_priority); +EXPORT_SYMBOL(get_peripheral_width); +EXPORT_SYMBOL(alloc_dma_handle); +EXPORT_SYMBOL(free_dma_handle); +EXPORT_SYMBOL(dma_channels); diff --git a/arch/ppc/kernel/ppc405_pci.c b/arch/ppc/kernel/ppc405_pci.c new file mode 100755 index 000000000000..2e0bd345f4c9 --- /dev/null +++ b/arch/ppc/kernel/ppc405_pci.c @@ -0,0 +1,207 @@ +/* + * FILE NAME: ppc405_pci.c + * + * BRIEF MODULE DESCRIPTION: + * Based on arch/ppc/kernel/indirect.c, Copyright (C) 1998 Gabriel Paubert. + * + * Author: MontaVista Software, Inc. <source@mvista.com> + * Frank Rowand <frank_rowand@mvista.com> + * Debbie Chu <debbie_chu@mvista.com> + * + * Copyright 2000 MontaVista Software Inc. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/pci.h> +#include <asm/io.h> +#include <asm/system.h> +#include <asm/machdep.h> +#include <linux/init.h> +#include <asm/ibm4xx.h> +#include <asm/pci-bridge.h> +#include <platforms/ibm_ocp.h> + +#ifdef CONFIG_DEBUG_BRINGUP +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +extern void bios_fixup(struct pci_controller *, void *); +extern int ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, + unsigned char pin); +extern struct pcil0_regs *PCIL_ADDR[]; + +void +ppc405_pcibios_fixup_resources(struct pci_dev *dev) +{ + int i; + unsigned long max_host_addr; + unsigned long min_host_addr; + struct resource *res; + + /* + * openbios puts some graphics cards in the same range as the host + * controller uses to map to SDRAM. Fix it. + */ + + min_host_addr = 0; + max_host_addr = PPC405_PCI_MEM_BASE - 1; + + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { + res = dev->resource + i; + if (!res->start) + continue; + if ((res->flags & IORESOURCE_MEM) && + (((res->start >= min_host_addr) + && (res->start <= max_host_addr)) + || ((res->end >= min_host_addr) + && (res->end <= max_host_addr)) + || ((res->start < min_host_addr) + && (res->end > max_host_addr)) + ) + ) { + + DBG(KERN_ERR "PCI: 0x%lx <= resource[%d] <= 0x%lx" + ", bus 0x%x dev 0x%2.2x.%1.1x,\n" + KERN_ERR " %s\n" + KERN_ERR " fixup will be attempted later\n", + min_host_addr, i, max_host_addr, + dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), dev->name); + + /* force pcibios_assign_resources() to assign a new address */ + res->end -= res->start; + res->start = 0; + } + } +} + +static int +ppc4xx_exclude_device(unsigned char bus, unsigned char devfn) +{ + /* We prevent us from seeing ourselves to avoid having + * the kernel try to remap our BAR #1 and fuck up bus + * master from external PCI devices + */ + return (bus == 0 && devfn == 0); +} + +void +ppc4xx_find_bridges(void) +{ + struct pci_controller *hose_a; + struct pcil0_regs *pcip; + unsigned int tmp_addr; + unsigned int tmp_size; + unsigned int reg_index; + unsigned int new_pmm_max; + unsigned int new_pmm_min; + + isa_io_base = 0; + isa_mem_base = 0; + pci_dram_offset = 0; + + /* Check if running in slave mode */ + if ((mfdcr(DCRN_CHPSR) & PSR_PCI_ARBIT_EN) == 0) { + printk("Running as PCI slave, kernel PCI disabled !\n"); + return; + } + /* Setup PCI32 hose */ + hose_a = pcibios_alloc_controller(); + if (!hose_a) + return; + setup_indirect_pci(hose_a, PPC405_PCI_CONFIG_ADDR, + PPC405_PCI_CONFIG_DATA); + pcip = ioremap((unsigned long) PCIL_ADDR[0], PAGE_SIZE); + if (pcip != NULL) { + +#if defined(CONFIG_BIOS_FIXUP) + bios_fixup(hose_a, pcip); +#endif + new_pmm_min = 0xffffffff; + for (reg_index = 0; reg_index < 3; reg_index++) { + tmp_size = in_le32((void *) &(pcip->pmm[reg_index].ma)); // *_PMM0MA + if (tmp_size & 0x1) { + tmp_addr = in_le32((void *) &(pcip->pmm[reg_index].pcila)); // *_PMM0PCILA + if (tmp_addr < PPC405_PCI_PHY_MEM_BASE) { + printk(KERN_DEBUG + "Disabling mapping to PCI mem addr 0x%8.8x\n", + tmp_addr); + out_le32((void *) &(pcip->pmm[reg_index].ma), tmp_size & ~1); // *_PMMOMA + } else { + tmp_addr = in_le32((void *) &(pcip->pmm[reg_index].la)); // *_PMMOLA + if (tmp_addr < new_pmm_min) + new_pmm_min = tmp_addr; + tmp_addr = + tmp_addr + (0xffffffff - + (tmp_size & + 0xffffc000)); + if (tmp_addr > PPC405_PCI_UPPER_MEM) { + new_pmm_max = tmp_addr; // PPC405_PCI_UPPER_MEM + } else { + new_pmm_max = + PPC405_PCI_UPPER_MEM; + } + } + } + + } // for + + iounmap(pcip); + } + hose_a->first_busno = 0; + hose_a->last_busno = 0xff; + hose_a->pci_mem_offset = 0; + + /* Setup bridge memory/IO ranges & resources + * TODO: Handle firmwares setting up a legacy ISA mem base + */ + hose_a->io_space.start = PPC405_PCI_LOWER_IO; + hose_a->io_space.end = PPC405_PCI_UPPER_IO; + hose_a->mem_space.start = new_pmm_min; + hose_a->mem_space.end = new_pmm_max; + hose_a->io_base_phys = PPC405_PCI_PHY_IO_BASE; + hose_a->io_base_virt = ioremap(hose_a->io_base_phys, 0x10000); + hose_a->io_resource.start = 0; + hose_a->io_resource.end = PPC405_PCI_UPPER_IO-PPC405_PCI_LOWER_IO; + hose_a->io_resource.flags = IORESOURCE_IO; + hose_a->io_resource.name = "PCI I/O"; + hose_a->mem_resources[0].start = new_pmm_min; + hose_a->mem_resources[0].end = new_pmm_max; + hose_a->mem_resources[0].flags = IORESOURCE_MEM; + hose_a->mem_resources[0].name = "PCI Memory"; + isa_io_base = (int)hose_a->io_base_virt; + isa_mem_base = 0; /* ISA not implemented */ + ISA_DMA_THRESHOLD = 0x00ffffff; /* ??? ISA not implemented */ + + /* Scan busses & initial setup by pci_auto */ + hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno); + hose_a->last_busno = 0; + + /* Setup ppc_md */ + ppc_md.pcibios_fixup = NULL; + ppc_md.pci_exclude_device = ppc4xx_exclude_device; + ppc_md.pcibios_fixup_resources = ppc405_pcibios_fixup_resources; + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = ppc405_map_irq; +} diff --git a/arch/ppc/kernel/ppc4xx_kgdb.c b/arch/ppc/kernel/ppc4xx_kgdb.c new file mode 100644 index 000000000000..810a0310a1e8 --- /dev/null +++ b/arch/ppc/kernel/ppc4xx_kgdb.c @@ -0,0 +1,124 @@ +#include <linux/config.h> +#include <linux/types.h> +#include <asm/ibm4xx.h> +#include <linux/kernel.h> + + + +#define LSR_DR 0x01 /* Data ready */ +#define LSR_OE 0x02 /* Overrun */ +#define LSR_PE 0x04 /* Parity error */ +#define LSR_FE 0x08 /* Framing error */ +#define LSR_BI 0x10 /* Break */ +#define LSR_THRE 0x20 /* Xmit holding register empty */ +#define LSR_TEMT 0x40 /* Xmitter empty */ +#define LSR_ERR 0x80 /* Error */ + +#include <platforms/ibm_ocp.h> + +extern struct NS16550* COM_PORTS[]; +#ifndef NULL +#define NULL 0x00 +#endif + +static volatile struct NS16550 *kgdb_debugport = NULL; + +volatile struct NS16550 * +NS16550_init(int chan) +{ + volatile struct NS16550 *com_port; + int quot; +#ifdef BASE_BAUD + quot = BASE_BAUD / 9600; +#else + quot = 0x000c; /* 0xc = 9600 baud (on a pc) */ +#endif + + com_port = (struct NS16550 *) COM_PORTS[chan]; + + com_port->lcr = 0x00; + com_port->ier = 0xFF; + com_port->ier = 0x00; + com_port->lcr = com_port->lcr | 0x80; /* Access baud rate */ + com_port->dll = ( quot & 0x00ff ); /* 0xc = 9600 baud */ + com_port->dlm = ( quot & 0xff00 ) >> 8; + com_port->lcr = 0x03; /* 8 data, 1 stop, no parity */ + com_port->mcr = 0x00; /* RTS/DTR */ + com_port->fcr = 0x07; /* Clear & enable FIFOs */ + + return( com_port ); +} + + +void +NS16550_putc(volatile struct NS16550 *com_port, unsigned char c) +{ + while ((com_port->lsr & LSR_THRE) == 0) + ; + com_port->thr = c; + return; +} + +unsigned char +NS16550_getc(volatile struct NS16550 *com_port) +{ + while ((com_port->lsr & LSR_DR) == 0) + ; + return (com_port->rbr); +} + +unsigned char +NS16550_tstc(volatile struct NS16550 *com_port) +{ + return ((com_port->lsr & LSR_DR) != 0); +} + + +#if defined(CONFIG_KGDB_TTYS0) +#define KGDB_PORT 0 +#elif defined(CONFIG_KGDB_TTYS1) +#define KGDB_PORT 1 +#elif defined(CONFIG_KGDB_TTYS2) +#define KGDB_PORT 2 +#elif defined(CONFIG_KGDB_TTYS3) +#define KGDB_PORT 3 +#else +#error "invalid kgdb_tty port" +#endif + +void putDebugChar( unsigned char c ) +{ + if ( kgdb_debugport == NULL ) + kgdb_debugport = NS16550_init(KGDB_PORT); + NS16550_putc( kgdb_debugport, c ); +} + +int getDebugChar( void ) +{ + if (kgdb_debugport == NULL) + kgdb_debugport = NS16550_init(KGDB_PORT); + + return(NS16550_getc(kgdb_debugport)); +} + +void kgdb_interruptible(int enable) +{ + return; +} + +void putDebugString(char* str) +{ + while (*str != '\0') { + putDebugChar(*str); + str++; + } + putDebugChar('\r'); + return; +} + +void +kgdb_map_scc(void) +{ + printk("kgdb init \n"); + kgdb_debugport = NS16550_init(KGDB_PORT); +} diff --git a/arch/ppc/kernel/ppc4xx_pic.c b/arch/ppc/kernel/ppc4xx_pic.c index e4fcd971717f..ae96d1c722e9 100644 --- a/arch/ppc/kernel/ppc4xx_pic.c +++ b/arch/ppc/kernel/ppc4xx_pic.c @@ -1,7 +1,4 @@ /* - * BK Id: SCCS/s.ppc4xx_pic.c 1.5 05/17/01 18:14:21 cort - */ -/* * * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu> * @@ -33,25 +30,29 @@ #include <asm/processor.h> #include <asm/system.h> #include <asm/irq.h> - -#include "local_irq.h" -#include "ppc4xx_pic.h" - +#include <asm/ibm4xx.h> +#include <asm/ppc4xx_pic.h> /* Global Variables */ struct hw_interrupt_type *ppc4xx_pic; +/* Six of one, half dozen of the other....#ifdefs, separate files, + * other tricks..... + * + * There are basically two types of interrupt controllers, the 403 AIC + * and the "others" with UIC. I just kept them both here separated + * with #ifdefs, but it seems to change depending upon how supporting + * files (like ppc4xx.h) change. -- Dan. + */ -/* Function Prototypes */ +#ifdef CONFIG_403 -static void ppc403_aic_enable(unsigned int irq); -static void ppc403_aic_disable(unsigned int irq); -static void ppc403_aic_disable_and_ack(unsigned int irq); +/* Function Prototypes */ -static void ppc405_uic_enable(unsigned int irq); -static void ppc405_uic_disable(unsigned int irq); -static void ppc405_uic_disable_and_ack(unsigned int irq); +static void ppc403_aic_enable(unsigned int irq); +static void ppc403_aic_disable(unsigned int irq); +static void ppc403_aic_disable_and_ack(unsigned int irq); static struct hw_interrupt_type ppc403_aic = { "403GC AIC", @@ -63,55 +64,11 @@ static struct hw_interrupt_type ppc403_aic = { 0 }; -static struct hw_interrupt_type ppc405_uic = { - "405GP UIC", - NULL, - NULL, - ppc405_uic_enable, - ppc405_uic_disable, - ppc405_uic_disable_and_ack, - 0 -}; - -/* - * Document me. - */ -void __init -ppc4xx_pic_init(void) -{ - unsigned long ver = PVR_VER(mfspr(SPRN_PVR)); - - switch (ver) { - - case PVR_VER(PVR_403GC): - /* - * Disable all external interrupts until they are - * explicity requested. - */ - ppc_cached_irq_mask[0] = 0; - mtdcr(DCRN_EXIER, 0); - - ppc4xx_pic = &ppc403_aic; - break; - - case PVR_VER(PVR_405GP): - ppc4xx_pic = &ppc405_uic; - break; - } - - return; -} - -/* - * XXX - Currently 403-specific! - * - * Document me. - */ int -ppc4xx_pic_get_irq(struct pt_regs *regs) +ppc403_pic_get_irq(struct pt_regs *regs) { int irq; - unsigned long bits, mask = (1 << 31); + unsigned long bits; /* * Only report the status of those interrupts that are actually @@ -123,19 +80,17 @@ ppc4xx_pic_get_irq(struct pt_regs *regs) /* * Walk through the interrupts from highest priority to lowest, and * report the first pending interrupt found. + * We want PPC, not C bit numbering, so just subtract the ffs() + * result from 32. */ + irq = 32 - ffs(bits); - for (irq = 0; irq < NR_IRQS; irq++, mask >>= 1) { - if (bits & mask) - break; - } + if (irq == NR_AIC_IRQS) + irq = -1; return (irq); } -/* - * Document me. - */ static void ppc403_aic_enable(unsigned int irq) { @@ -148,9 +103,6 @@ ppc403_aic_enable(unsigned int irq) mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]); } -/* - * Document me. - */ static void ppc403_aic_disable(unsigned int irq) { @@ -163,9 +115,6 @@ ppc403_aic_disable(unsigned int irq) mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]); } -/* - * Document me. - */ static void ppc403_aic_disable_and_ack(unsigned int irq) { @@ -179,29 +128,131 @@ ppc403_aic_disable_and_ack(unsigned int irq) mtdcr(DCRN_EXISR, (1 << (31 - bit))); } -/* - * Document me. - */ +#else /* !CONFIG_403 */ + static void ppc405_uic_enable(unsigned int irq) { - /* XXX - Implement me. */ + int bit, word; + + bit = irq & 0x1f; + word = irq >> 5; + + ppc_cached_irq_mask[word] |= 1 << (31 - bit); + mtdcr(DCRN_UIC0_ER, ppc_cached_irq_mask[word]); } -/* - * Document me. - */ static void ppc405_uic_disable(unsigned int irq) { - /* XXX - Implement me. */ + int bit, word; + + bit = irq & 0x1f; + word = irq >> 5; + + ppc_cached_irq_mask[word] &= ~(1 << (31 - bit)); + mtdcr(DCRN_UIC0_ER, ppc_cached_irq_mask[word]); } -/* - * Document me. - */ static void ppc405_uic_disable_and_ack(unsigned int irq) { - /* XXX - Implement me. */ + int bit, word; + + bit = irq & 0x1f; + word = irq >> 5; + + ppc_cached_irq_mask[word] &= ~(1 << (31 - bit)); + mtdcr(DCRN_UIC0_ER, ppc_cached_irq_mask[word]); + mtdcr(DCRN_UIC0_SR, (1 << (31 - bit))); +} + +static void +ppc405_uic_end(unsigned int irq) +{ + int bit, word; + unsigned int tr_bits; + + bit = irq & 0x1f; + word = irq >> 5; + + tr_bits = mfdcr(DCRN_UIC0_TR); + if ((tr_bits & (1 << (31 - bit))) == 0) { + /* level trigger */ + mtdcr(DCRN_UIC0_SR, 1 << (31 - bit)); + } + + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) { + ppc_cached_irq_mask[word] |= 1 << (31 - bit); + mtdcr(DCRN_UIC0_ER, ppc_cached_irq_mask[word]); + } +} + +static struct hw_interrupt_type ppc405_uic = { +#if defined (CONFIG_405GP) + "405GP UIC", +#else + "NP405 UIC", +#endif + NULL, + NULL, + ppc405_uic_enable, + ppc405_uic_disable, + ppc405_uic_disable_and_ack, + ppc405_uic_end, + 0 +}; + +int +ppc405_pic_get_irq(struct pt_regs *regs) +{ + int irq; + unsigned long bits; + + /* + * Only report the status of those interrupts that are actually + * enabled. + */ + + bits = mfdcr(DCRN_UIC0_MSR); + + /* + * Walk through the interrupts from highest priority to lowest, and + * report the first pending interrupt found. + * We want PPC, not C bit numbering, so just subtract the ffs() + * result from 32. + */ + irq = 32 - ffs(bits); + + if (irq == NR_AIC_IRQS) + irq = -1; + + return (irq); +} +#endif + +void __init +ppc4xx_pic_init(void) +{ + /* + * Disable all external interrupts until they are + * explicity requested. + */ + ppc_cached_irq_mask[0] = 0; + +#ifdef CONFIG_403 + mtdcr(DCRN_EXIER, ppc_cached_irq_mask[0]); + + ppc4xx_pic = &ppc403_aic; + ppc_md.get_irq = ppc403_pic_get_irq; +#else + mtdcr(DCRN_UIC0_ER, ppc_cached_irq_mask[0]); + + /* Set all interrupts to non-critical. + */ + mtdcr(DCRN_UIC0_CR, 0); + + ppc4xx_pic = &ppc405_uic; + ppc_md.get_irq = ppc405_pic_get_irq; +#endif } diff --git a/arch/ppc/kernel/ppc4xx_pic.h b/arch/ppc/kernel/ppc4xx_pic.h deleted file mode 100644 index ebb63a7f36d4..000000000000 --- a/arch/ppc/kernel/ppc4xx_pic.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * BK Id: SCCS/s.ppc4xx_pic.h 1.8 06/15/01 13:56:56 paulus - */ -/* - * - * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu> - * - * Module name: ppc4xx_pic.h - * - * Description: - * Interrupt controller driver for PowerPC 4xx-based processors. - */ - -#ifndef __PPC4XX_PIC_H__ -#define __PPC4XX_PIC_H__ - -#include <linux/config.h> -#include "local_irq.h" - -/* External Global Variables */ - -extern struct hw_interrupt_type *ppc4xx_pic; - - -/* Function Prototypes */ - -extern void ppc4xx_pic_init(void); -extern int ppc4xx_pic_get_irq(struct pt_regs *regs); - -#endif /* __PPC4XX_PIC_H__ */ diff --git a/arch/ppc/kernel/ppc4xx_pm.c b/arch/ppc/kernel/ppc4xx_pm.c new file mode 100644 index 000000000000..1f49c1f5e1f6 --- /dev/null +++ b/arch/ppc/kernel/ppc4xx_pm.c @@ -0,0 +1,75 @@ +/* + * file: ppc4xx_pm.c + * + * This an attempt to get Power Management going for the IBM 4xx processor. + * This was derived from the ppc4xx._setup.c file + * + * Armin Kuster akuster@mvista.com + * Jan 2002 + * + * + * Copyright 2002 MontaVista Softare Inc. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Version 1.0 (02/14/01) - A. Kuster + * Initial version - moved pm code from ppc4xx_setup.c + * + * 1.1 02/21/01 - A. Kuster + * minor fixes, init value to 0 & += to &= + * added stb03 ifdef for 2nd i2c device + */ + +#include <linux/config.h> +#include <linux/init.h> + +#include <asm/ibm4xx.h> + +void __init +ppc4xx_pm_init(void) +{ + + unsigned int value = 0; + + /* turn off unused hardware to save power */ +#ifdef CONFIG_405GP + value |= CPM_DCP; /* CodePack */ +#endif + +#if !defined(CONFIG_IBM_OCP_GPIO) + value |= CPM_GPIO0; +#endif + +#if !defined(CONFIG_PPC405_I2C_ADAP) + value |= CPM_IIC0; +#ifdef CONFIG_STB03xxx + value |= CPM_IIC1; +#endif +#endif + + +#if !defined(CONFIG_405_DMA) + value |= CPM_DMA; +#endif + + mtdcr(DCRN_CPMFR, value); + +} diff --git a/arch/ppc/kernel/ppc4xx_serial.c b/arch/ppc/kernel/ppc4xx_serial.c new file mode 100755 index 000000000000..54defaf2a92c --- /dev/null +++ b/arch/ppc/kernel/ppc4xx_serial.c @@ -0,0 +1,190 @@ + +/* + * linux/arch/ppc/kernel/ppc405_serial.c + * + * This is a fairly standard 165xx type device that will eventually + * be merged with other similar processor/boards. -- Dan + * + * BRIEF MODULE DESCRIPTION + * Console I/O support for Early kernel bringup. + * + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * frank_rowand@mvista.com or source@mvista.com + * debbie_chu@mvista.com + * + * + * 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. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/config.h> + +#if defined(CONFIG_IBM405GP) || defined(CONFIG_IBM405CR) + +#ifdef CONFIG_KGDB +#include <asm/kgdb.h> +#include <linux/init.h> +#endif + +#ifdef CONFIG_DEBUG_BRINGUP + +#include <linux/console.h> + +extern void ftr_reset_preferred_console(void); + + +static int ppc405_sercons_setup(struct console *co, char *options) +{ +#ifdef CONFIG_UART0_DEBUG_CONSOLE + volatile unsigned char *uart_dll = (char *)0xef600300; + volatile unsigned char *uart_fcr = (char *)0xef600302; + volatile unsigned char *uart_lcr = (char *)0xef600303; +#endif + +#ifdef CONFIG_UART1_DEBUG_CONSOLE + volatile unsigned char *uart_dll = (char *)0xef600400; + volatile unsigned char *uart_fcr = (char *)0xef600402; + volatile unsigned char *uart_lcr = (char *)0xef600403; +#endif + + *uart_lcr = *uart_lcr | 0x80; /* DLAB on */ + +/* ftr revisit - there is no config option for this +** also see include/asm-ppc/ppc405_serial.h +** +** #define CONFIG_IBM405GP_INTERNAL_CLOCK +*/ + + +#ifdef CONFIG_IBM405GP_INTERNAL_CLOCK + /* ftr revisit + ** why is bit 19 of chcr0 (0x1000) being set? + */ + /* 0x2a results in data corruption, kgdb works with 0x28 */ + *uart_dll = 0x28; /* 9600 baud */ + _put_CHCR0((_get_CHCR0() & 0xffffe000) | 0x103e); +#else + *uart_dll = 0x48; /* 9600 baud */ +#endif + *uart_lcr = *uart_lcr & 0x7f; /* DLAB off */ + + return 0; +} + + +/* + * This is a bringup hack, writing directly to uart0 or uart1 + */ + +static void +ppc405_sercons_write(struct console *co, const char *ptr, + unsigned nb) +{ + int i; + +#ifdef CONFIG_UART0_DEBUG_CONSOLE + volatile unsigned char *uart_xmit = (char *)0xef600300; + volatile unsigned char *uart_lsr = (char *)0xef600305; +#endif + +#ifdef CONFIG_UART1_DEBUG_CONSOLE + volatile unsigned char *uart_xmit = (char *)0xef600400; + volatile unsigned char *uart_lsr = (char *)0xef600405; +#endif + + for (i = 0; i < nb; ++i) { + + /* wait for transmit reg (possibly fifo) to empty */ + while ((*uart_lsr & 0x40) == 0) + ; + + *uart_xmit = (ptr[i] & 0xff); + + if (ptr[i] == '\n') { + + /* add a carriage return */ + + /* wait for transmit reg (possibly fifo) to empty */ + while ((*uart_lsr & 0x40) == 0) + ; + + *uart_xmit = '\r'; + } + } + + return; +} + + +static int +ppc405_sercons_read(struct console *co, char *ptr, unsigned nb) +{ +#ifdef CONFIG_UART0_DEBUG_CONSOLE + volatile unsigned char *uart_rcv = (char *)0xef600300; + volatile unsigned char *uart_lsr = (char *)0xef600305; +#endif + +#ifdef CONFIG_UART1_DEBUG_CONSOLE + volatile unsigned char *uart_rcv = (char *)0xef600400; + volatile unsigned char *uart_lsr = (char *)0xef600405; +#endif + + + /* ftr revisit: not tested */ + + if (nb == 0) + return(0); + + if (!ptr) + return(-1); + + /* wait for receive reg (possibly fifo) to contain data */ + while ((*uart_lsr & 0x01) == 0) + ; + + *ptr = *uart_rcv; + + return(1); +} + +static struct console ppc405_sercons = { + name: "dbg_cons", + write: ppc405_console_write, + setup: ppc405_console_setup, + flags: CON_PRINTBUFFER, + index: -1, +}; + +void +register_debug_console(void) +{ + register_console(&ppc405_sercons); +} + +void +unregister_debug_console(void) +{ + unregister_console(&ppc405_sercons); +} + +#endif /* CONFIG_DEBUG_BRINGUP */ + +#endif /* #if defined(CONFIG_IBM405GP) || defined(CONFIG_IBM405CR) */ diff --git a/arch/ppc/kernel/ppc4xx_setup.c b/arch/ppc/kernel/ppc4xx_setup.c new file mode 100755 index 000000000000..f086c14e7907 --- /dev/null +++ b/arch/ppc/kernel/ppc4xx_setup.c @@ -0,0 +1,415 @@ +/* + * + * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu> + * + * Copyright 2000-2001 MontaVista Software Inc. + * Completed implementation. + * Author: MontaVista Software, Inc. <source@mvista.com> + * Frank Rowand <frank_rowand@mvista.com> + * Debbie Chu <debbie_chu@mvista.com> + * + * Module name: ppc4xx_setup.c + * + * Description: + * Architecture- / platform-specific boot-time initialization code for + * IBM PowerPC 4xx based boards. Adapted from original + * code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek + * <dan@net4x.com>. + * + * History: 11/09/2001 - armin + * rename board_setup_nvram_access to board_init. board_init is + * used for all other board specific instructions needed during + * platform_init. + * moved RTC to board.c files + * moved VT/FB to board.c files + * moved r/w4 ide to redwood.c + * + */ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/smp.h> +#include <linux/threads.h> +#include <linux/spinlock.h> +#include <linux/irq.h> +#include <linux/reboot.h> +#include <linux/param.h> +#include <linux/string.h> +#include <linux/blk.h> +#include <linux/pci.h> +#include <linux/rtc.h> +#include <linux/console.h> +#include <linux/ide.h> +#include <linux/serial_reg.h> +#include <linux/seq_file.h> + +#include <asm/system.h> +#include <asm/processor.h> +#include <asm/machdep.h> +#include <asm/page.h> +#include <asm/kgdb.h> +#include <asm/ibm4xx.h> +#include <asm/time.h> +#include <asm/todc.h> +#include <asm/ppc4xx_pic.h> +#include <asm/pci-bridge.h> +#include <asm/bootinfo.h> + +/* Function Prototypes */ +extern void abort(void); +extern void ppc4xx_find_bridges(void); + +extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); +extern int pckbd_getkeycode(unsigned int scancode); +extern int pckbd_pretranslate(unsigned char scancode, char raw_mode); +extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode); +extern char pckbd_unexpected_up(unsigned char keycode); +extern void pckbd_leds(unsigned char leds); +extern void pckbd_init_hw(void); + +extern int nonpci_ide_default_irq(ide_ioreg_t base); +extern void nonpci_ide_init_hwif_ports(hw_regs_t * hw, ide_ioreg_t data_port, + ide_ioreg_t ctrl_port, int *irq); + +extern void ppc4xx_wdt_heartbeat(void); +extern int wdt_enable; +extern unsigned long wdt_period; + +/* Board specific functions */ +extern void board_setup_arch(void); +extern void board_io_mapping(void); +extern void board_setup_irq(void); +extern void board_init(void); + +/* Global Variables */ +unsigned char __res[sizeof (bd_t)]; + +static void __init +ppc4xx_setup_arch(void) +{ + + /* Setup PCI host bridges */ + +#ifdef CONFIG_PCI + ppc4xx_find_bridges(); +#endif + +#if defined(CONFIG_FB) + conswitchp = &dummy_con; +#endif + + board_setup_arch(); +} + +/* + * This routine pretty-prints the platform's internal CPU clock + * frequencies into the buffer for usage in /proc/cpuinfo. + */ + +static int +ppc4xx_show_percpuinfo(struct seq_file *m, int i) +{ + bd_t *bip = (bd_t *) __res; + + seq_printf(m, "clock\t\t: %ldMHz\n", (long) bip->bi_intfreq / 1000000); + + return 0; +} + +/* + * This routine pretty-prints the platform's internal bus clock + * frequencies into the buffer for usage in /proc/cpuinfo. + */ +static int +ppc4xx_show_cpuinfo(struct seq_file *m) +{ + bd_t *bip = (bd_t *) __res; + + seq_printf(m, "machine\t\t: %s\n", PPC4xx_MACHINE_NAME); + seq_printf(m, "plb bus clock\t: %ldMHz\n", + (long) bip->bi_busfreq / 1000000); +#ifdef CONFIG_PCI + seq_printf(m, "pci bus clock\t: %dMHz\n", + bip->bi_pci_busfreq / 1000000); +#endif + + return 0; +} + +/* + * Return the virtual address representing the top of physical RAM. + */ +static unsigned long __init +ppc4xx_find_end_of_memory(void) +{ + bd_t *bip = (bd_t *) __res; + + return ((unsigned long) bip->bi_memsize); +} + +static void __init +m4xx_map_io(void) +{ + io_block_mapping(PPC4xx_ONB_IO_VADDR, + PPC4xx_ONB_IO_PADDR, PPC4xx_ONB_IO_SIZE, _PAGE_IO); +#ifdef CONFIG_PCI + io_block_mapping(PPC4xx_PCI_IO_VADDR, + PPC4xx_PCI_IO_PADDR, PPC4xx_PCI_IO_SIZE, _PAGE_IO); + io_block_mapping(PPC4xx_PCI_CFG_VADDR, + PPC4xx_PCI_CFG_PADDR, PPC4xx_PCI_CFG_SIZE, _PAGE_IO); + io_block_mapping(PPC4xx_PCI_LCFG_VADDR, + PPC4xx_PCI_LCFG_PADDR, PPC4xx_PCI_LCFG_SIZE, _PAGE_IO); +#endif + board_io_mapping(); +} + +static void __init +ppc4xx_init_IRQ(void) +{ + int i; + + ppc4xx_pic_init(); + + for (i = 0; i < NR_IRQS; i++) + irq_desc[i].handler = ppc4xx_pic; + + /* give board specific code a chance to setup things */ + board_setup_irq(); + return; +} + +static void +ppc4xx_restart(char *cmd) +{ + printk("%s\n", cmd); + abort(); +} + +static void +ppc4xx_power_off(void) +{ + printk("System Halted\n"); + __cli(); + while (1) ; +} + +static void +ppc4xx_halt(void) +{ + printk("System Halted\n"); + __cli(); + while (1) ; +} + +/* + * This routine retrieves the internal processor frequency from the board + * information structure, sets up the kernel timer decrementer based on + * that value, enables the 4xx programmable interval timer (PIT) and sets + * it up for auto-reload. + */ +static void __init +ppc4xx_calibrate_decr(void) +{ + unsigned int freq; + bd_t *bip = (bd_t *) __res; + +#if defined(CONFIG_WALNUT) || defined(CONFIG_CEDER) + /* Walnut boot rom sets DCR CHCR1 (aka CPC0_CR1) bit CETE to 1 */ + mtdcr(DCRN_CHCR1, mfdcr(DCRN_CHCR1) & ~CHR1_CETE); +#endif +#ifdef CONFIG_REDWOOD_5 + freq = bip->bi_tbfreq; +#else + freq = bip->bi_intfreq; + +#endif + + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); + + /* Set the time base to zero. + ** At 200 Mhz, time base will rollover in ~2925 years. + */ + + mtspr(SPRN_TBWL, 0); + mtspr(SPRN_TBWU, 0); + + /* Clear any pending timer interrupts */ + + mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_PIS | TSR_FIS); + mtspr(SPRN_TCR, TCR_PIE | TCR_ARE); + + /* Set the PIT reload value and just let it run. */ + mtspr(SPRN_PIT, tb_ticks_per_jiffy); +} + +#ifdef CONFIG_DEBUG_TEXT +static void +ppc4xx_progress(char *s, unsigned short hex) +{ + printk("%s\n\r", s); +} +#endif + +/* + * IDE stuff. + * should be generic for every IDE PCI chipset + */ +#if defined(CONFIG_BLK_DEV_IDE) +static int +ppc4xx_ide_check_region(ide_ioreg_t from, unsigned int extent) +{ + return check_region(from, extent); +} + +static void +ppc4xx_ide_request_region(ide_ioreg_t from, unsigned int extent, + const char *name) +{ + request_region(from, extent, name); + return; +} + +static void +ppc4xx_ide_release_region(ide_ioreg_t from, unsigned int extent) +{ + release_region(from, extent); + return; +} +#endif + +#if defined(CONFIG_BLK_DEV_IDEPCI) +static void +ppc4xx_ide_init_hwif_ports(hw_regs_t * hw, ide_ioreg_t data_port, + ide_ioreg_t ctrl_port, int *irq) +{ + int i; + + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; ++i) + hw->io_ports[i] = data_port + i - IDE_DATA_OFFSET; + + hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; +} +#endif + +TODC_ALLOC(); + +/* + * Input(s): + * r3 - Optional pointer to a board information structure. + * r4 - Optional pointer to the physical starting address of the init RAM + * disk. + * r5 - Optional pointer to the physical ending address of the init RAM + * disk. + * r6 - Optional pointer to the physical starting address of any kernel + * command-line parameters. + * r7 - Optional pointer to the physical ending address of any kernel + * command-line parameters. + */ +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + parse_bootinfo(find_bootinfo()); + + /* + * If we were passed in a board information, copy it into the + * residual data area. + */ + if (r3) { + memcpy((void *) __res, (void *) (r3 + KERNELBASE), + sizeof (bd_t)); + + } +#if defined(CONFIG_BLK_DEV_INITRD) + /* + * If the init RAM disk has been configured in, and there's a valid + * starting address for it, set it up. + */ + if (r4) { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif /* CONFIG_BLK_DEV_INITRD */ + + /* Copy the kernel command line arguments to a safe place. */ + + if (r6) { + *(char *) (r7 + KERNELBASE) = 0; + strcpy(cmd_line, (char *) (r6 + KERNELBASE)); + } +#if defined(CONFIG_PPC405_WDT) +/* Look for wdt= option on command line */ + if (strstr(cmd_line, "wdt=")) { + int valid_wdt = 0; + char *p, *q; + for (q = cmd_line; (p = strstr(q, "wdt=")) != 0;) { + q = p + 4; + if (p > cmd_line && p[-1] != ' ') + continue; + wdt_period = simple_strtoul(q, &q, 0); + valid_wdt = 1; + ++q; + } + wdt_enable = valid_wdt; + } +#endif + + /* Initialize machine-dependency vectors */ + + ppc_md.setup_arch = ppc4xx_setup_arch; + ppc_md.show_percpuinfo = ppc4xx_show_percpuinfo; + ppc_md.show_cpuinfo = ppc4xx_show_cpuinfo; + ppc_md.init_IRQ = ppc4xx_init_IRQ; + + ppc_md.restart = ppc4xx_restart; + ppc_md.power_off = ppc4xx_power_off; + ppc_md.halt = ppc4xx_halt; + + ppc_md.calibrate_decr = ppc4xx_calibrate_decr; + +#ifdef CONFIG_PPC405_WDT + ppc_md.heartbeat = ppc4xx_wdt_heartbeat; +#endif + ppc_md.heartbeat_count = 0; + + ppc_md.find_end_of_memory = ppc4xx_find_end_of_memory; + ppc_md.setup_io_mappings = m4xx_map_io; + +#ifdef CONFIG_DEBUG_TEXT + ppc_md.progress = ppc4xx_progress; +#endif + +#if defined(CONFIG_VT) && defined(CONFIG_PC_KEYBOARD) +#if defined(CONFIG_REDWOOD_4) && defined(CONFIG_STB_KB) + redwood_irkb_init(); +#else + ppc_md.kbd_setkeycode = pckbd_setkeycode; + ppc_md.kbd_getkeycode = pckbd_getkeycode; + ppc_md.kbd_translate = pckbd_translate; + ppc_md.kbd_unexpected_up = pckbd_unexpected_up; + ppc_md.kbd_leds = pckbd_leds; + ppc_md.kbd_init_hw = pckbd_init_hw; +#endif +#endif + +/* +** m8xx_setup.c, prep_setup.c use +** defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) +*/ +#if defined (CONFIG_IDE) + ppc_ide_md.ide_request_region = ppc4xx_ide_request_region; + ppc_ide_md.ide_release_region = ppc4xx_ide_release_region; + ppc_ide_md.ide_check_region = ppc4xx_ide_check_region; +#if defined(CONFIG_BLK_DEV_IDEPCI) + ppc_ide_md.ide_init_hwif = ppc4xx_ide_init_hwif_ports; +#elif defined (CONFIG_DMA_NONPCI) /* ON board IDE */ + ppc_ide_md.default_irq = nonpci_ide_default_irq; + ppc_ide_md.ide_init_hwif = nonpci_ide_init_hwif_ports; +#endif +#endif + board_init(); + + return; +} diff --git a/arch/ppc/kernel/ppc8260_pic.c b/arch/ppc/kernel/ppc8260_pic.c index b829116f78a0..b2ae5e951aef 100644 --- a/arch/ppc/kernel/ppc8260_pic.c +++ b/arch/ppc/kernel/ppc8260_pic.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ppc8260_pic.c 1.5 05/17/01 18:14:21 cort + * BK Id: %F% %I% %G% %U% %#% */ #include <linux/stddef.h> @@ -85,6 +85,22 @@ static void m8260_mask_and_ack(unsigned int irq_nr) sipnr[word] = 1 << (31 - bit); } +static void m8260_end_irq(unsigned int irq_nr) +{ + int bit, word; + volatile uint *simr; + + if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { + + bit = irq_to_siubit[irq_nr]; + word = irq_to_siureg[irq_nr]; + + simr = &(immr->im_intctl.ic_simrh); + ppc_cached_irq_mask[word] |= (1 << (31 - bit)); + simr[word] = ppc_cached_irq_mask[word]; + } +} + struct hw_interrupt_type ppc8260_pic = { " 8260 SIU ", NULL, @@ -92,6 +108,7 @@ struct hw_interrupt_type ppc8260_pic = { m8260_unmask_irq, m8260_mask_irq, m8260_mask_and_ack, + m8260_end_irq, 0 }; @@ -106,6 +123,9 @@ m8260_get_irq(struct pt_regs *regs) * to get the irq number. */ bits = immr->im_intctl.ic_sivec; irq = bits >> 26; + + if (irq == 0) + return(-1); #if 0 irq += ppc8260_pic.irq_offset; #endif diff --git a/arch/ppc/kernel/ppc8260_pic.h b/arch/ppc/kernel/ppc8260_pic.h index dd415f4995bf..40e70f82a8b8 100644 --- a/arch/ppc/kernel/ppc8260_pic.h +++ b/arch/ppc/kernel/ppc8260_pic.h @@ -1,11 +1,11 @@ /* - * BK Id: SCCS/s.ppc8260_pic.h 1.7 05/17/01 18:14:21 cort + * BK Id: %F% %I% %G% %U% %#% */ #ifndef _PPC_KERNEL_PPC8260_H #define _PPC_KERNEL_PPC8260_H -#include "local_irq.h" +#include <linux/irq.h> extern struct hw_interrupt_type ppc8260_pic; diff --git a/arch/ppc/kernel/ppc8xx_pic.c b/arch/ppc/kernel/ppc8xx_pic.c index b01669fe60df..a952d85ea01a 100644 --- a/arch/ppc/kernel/ppc8xx_pic.c +++ b/arch/ppc/kernel/ppc8xx_pic.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ppc8xx_pic.c 1.10 05/17/01 18:14:21 cort + * BK Id: %F% %I% %G% %U% %#% */ #include <linux/config.h> #include <linux/stddef.h> @@ -44,6 +44,21 @@ static void m8xx_unmask_irq(unsigned int irq_nr) ppc_cached_irq_mask[word]; } +static void m8xx_end_irq(unsigned int irq_nr) +{ + if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { + int bit, word; + + bit = irq_nr & 0x1f; + word = irq_nr >> 5; + + ppc_cached_irq_mask[word] |= (1 << (31-bit)); + ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = + ppc_cached_irq_mask[word]; + } +} + + static void m8xx_mask_and_ack(unsigned int irq_nr) { int bit, word; @@ -64,6 +79,7 @@ struct hw_interrupt_type ppc8xx_pic = { m8xx_unmask_irq, m8xx_mask_irq, m8xx_mask_and_ack, + m8xx_end_irq, 0 }; @@ -97,19 +113,26 @@ m8xx_do_IRQ(struct pt_regs *regs, #endif +/* + * We either return a valid interrupt or -1 if there is nothing pending + */ int m8xx_get_irq(struct pt_regs *regs) { int irq; - unsigned long bits = 0; - /* For MPC8xx, read the SIVEC register and shift the bits down - * to get the irq number. */ - bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec; - irq = bits >> 26; -#if 0 - irq += ppc8xx_pic.irq_offset; -#endif + /* For MPC8xx, read the SIVEC register and shift the bits down + * to get the irq number. + */ + irq = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec >> 26; + + /* + * When we read the sivec without an interrupt to process, we will + * get back SIU_LEVEL7. In this case, return -1 + */ + if (irq == SIU_LEVEL7) + return -1; + return irq; } diff --git a/arch/ppc/kernel/ppc8xx_pic.h b/arch/ppc/kernel/ppc8xx_pic.h index 1253d31c28a3..9cbf0d6eec4a 100644 --- a/arch/ppc/kernel/ppc8xx_pic.h +++ b/arch/ppc/kernel/ppc8xx_pic.h @@ -1,11 +1,11 @@ /* - * BK Id: SCCS/s.ppc8xx_pic.h 1.7 05/17/01 18:14:21 cort + * BK Id: %F% %I% %G% %U% %#% */ #ifndef _PPC_KERNEL_PPC8xx_H #define _PPC_KERNEL_PPC8xx_H #include <linux/config.h> -#include "local_irq.h" +#include <linux/irq.h> extern struct hw_interrupt_type ppc8xx_pic; @@ -15,7 +15,7 @@ void m8xx_do_IRQ(struct pt_regs *regs, int m8xx_get_irq(struct pt_regs *regs); #ifdef CONFIG_MBX -#include "i8259.h" +#include <asm/i8259.h> #include <asm/io.h> void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs); #endif diff --git a/arch/ppc/kernel/ppc_asm.h b/arch/ppc/kernel/ppc_asm.h deleted file mode 100644 index ea28f75d9acc..000000000000 --- a/arch/ppc/kernel/ppc_asm.h +++ /dev/null @@ -1,158 +0,0 @@ -/* - * BK Id: SCCS/s.ppc_asm.h 1.18 10/18/01 15:02:09 trini - */ -/* - * arch/ppc/kernel/ppc_asm.h - * - * Definitions used by various bits of low-level assembly code on PowerPC. - * - * Copyright (C) 1995-1999 Gary Thomas, Paul Mackerras, Cort Dougan. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include <linux/config.h> - -#include "ppc_asm.tmpl" -#include "ppc_defs.h" - -/* - * Macros for storing registers into and loading registers from - * exception frames. - */ -#define SAVE_GPR(n, base) stw n,GPR0+4*(n)(base) -#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base) -#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base) -#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base) -#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base) -#define REST_GPR(n, base) lwz n,GPR0+4*(n)(base) -#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base) -#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base) -#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base) -#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base) - -#define SAVE_FPR(n, base) stfd n,THREAD_FPR0+8*(n)(base) -#define SAVE_2FPRS(n, base) SAVE_FPR(n, base); SAVE_FPR(n+1, base) -#define SAVE_4FPRS(n, base) SAVE_2FPRS(n, base); SAVE_2FPRS(n+2, base) -#define SAVE_8FPRS(n, base) SAVE_4FPRS(n, base); SAVE_4FPRS(n+4, base) -#define SAVE_16FPRS(n, base) SAVE_8FPRS(n, base); SAVE_8FPRS(n+8, base) -#define SAVE_32FPRS(n, base) SAVE_16FPRS(n, base); SAVE_16FPRS(n+16, base) -#define REST_FPR(n, base) lfd n,THREAD_FPR0+8*(n)(base) -#define REST_2FPRS(n, base) REST_FPR(n, base); REST_FPR(n+1, base) -#define REST_4FPRS(n, base) REST_2FPRS(n, base); REST_2FPRS(n+2, base) -#define REST_8FPRS(n, base) REST_4FPRS(n, base); REST_4FPRS(n+4, base) -#define REST_16FPRS(n, base) REST_8FPRS(n, base); REST_8FPRS(n+8, base) -#define REST_32FPRS(n, base) REST_16FPRS(n, base); REST_16FPRS(n+16, base) - -/* - * Once a version of gas that understands the AltiVec instructions - * is freely available, we can do this the normal way... - paulus - */ -#define LVX(r,a,b) .long (31<<26)+((r)<<21)+((a)<<16)+((b)<<11)+(103<<1) -#define STVX(r,a,b) .long (31<<26)+((r)<<21)+((a)<<16)+((b)<<11)+(231<<1) -#define MFVSCR(r) .long (4<<26)+((r)<<21)+(770<<1) -#define MTVSCR(r) .long (4<<26)+((r)<<11)+(802<<1) - -#define SAVE_VR(n,b,base) li b,THREAD_VR0+(16*(n)); STVX(n,b,base) -#define SAVE_2VR(n,b,base) SAVE_VR(n,b,base); SAVE_VR(n+1,b,base) -#define SAVE_4VR(n,b,base) SAVE_2VR(n,b,base); SAVE_2VR(n+2,b,base) -#define SAVE_8VR(n,b,base) SAVE_4VR(n,b,base); SAVE_4VR(n+4,b,base) -#define SAVE_16VR(n,b,base) SAVE_8VR(n,b,base); SAVE_8VR(n+8,b,base) -#define SAVE_32VR(n,b,base) SAVE_16VR(n,b,base); SAVE_16VR(n+16,b,base) -#define REST_VR(n,b,base) li b,THREAD_VR0+(16*(n)); LVX(n,b,base) -#define REST_2VR(n,b,base) REST_VR(n,b,base); REST_VR(n+1,b,base) -#define REST_4VR(n,b,base) REST_2VR(n,b,base); REST_2VR(n+2,b,base) -#define REST_8VR(n,b,base) REST_4VR(n,b,base); REST_4VR(n+4,b,base) -#define REST_16VR(n,b,base) REST_8VR(n,b,base); REST_8VR(n+8,b,base) -#define REST_32VR(n,b,base) REST_16VR(n,b,base); REST_16VR(n+16,b,base) - -#ifdef CONFIG_PPC601_SYNC_FIX -#define SYNC \ -BEGIN_FTR_SECTION \ - sync; \ - isync; \ -END_FTR_SECTION_IFSET(CPU_FTR_601) -#define SYNC_601 \ -BEGIN_FTR_SECTION \ - sync; \ -END_FTR_SECTION_IFSET(CPU_FTR_601) -#define ISYNC_601 \ -BEGIN_FTR_SECTION \ - isync; \ -END_FTR_SECTION_IFSET(CPU_FTR_601) -#else -#define SYNC -#define SYNC_601 -#define ISYNC_601 -#endif - -#ifndef CONFIG_SMP -#define TLBSYNC -#else /* CONFIG_SMP */ -/* tlbsync is not implemented on 601 */ -#define TLBSYNC \ -BEGIN_FTR_SECTION \ - tlbsync; \ - sync; \ -END_FTR_SECTION_IFCLR(CPU_FTR_601) -#endif - -/* - * This instruction is not implemented on the PPC 603 or 601; however, on - * the 403GCX and 405GP tlbia IS defined and tlbie is not. - * All of these instructions exist in the 8xx, they have magical powers, - * and they must be used. - */ - -#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) -#define tlbia \ - li r4,1024; \ - mtctr r4; \ - lis r4,KERNELBASE@h; \ -0: tlbie r4; \ - addi r4,r4,0x1000; \ - bdnz 0b -#endif - -/* - * On APUS (Amiga PowerPC cpu upgrade board), we don't know the - * physical base address of RAM at compile time. - */ -#define tophys(rd,rs) \ -0: addis rd,rs,-KERNELBASE@h; \ - .section ".vtop_fixup","aw"; \ - .align 1; \ - .long 0b; \ - .previous - -#define tovirt(rd,rs) \ -0: addis rd,rs,KERNELBASE@h; \ - .section ".ptov_fixup","aw"; \ - .align 1; \ - .long 0b; \ - .previous - -/* - * On 64-bit cpus, we use the rfid instruction instead of rfi, but - * we then have to make sure we preserve the top 32 bits except for - * the 64-bit mode bit, which we clear. - */ -#ifdef CONFIG_PPC64BRIDGE -#define FIX_SRR1(ra, rb) \ - mr rb,ra; \ - mfmsr ra; \ - clrldi ra,ra,1; /* turn off 64-bit mode */ \ - rldimi ra,rb,0,32 -#define RFI .long 0x4c000024 /* rfid instruction */ -#define MTMSRD(r) .long (0x7c000164 + ((r) << 21)) /* mtmsrd */ -#define CLR_TOP32(r) rlwinm (r),(r),0,0,31 /* clear top 32 bits */ - -#else -#define FIX_SRR1(ra, rb) -#define RFI rfi -#define MTMSRD(r) mtmsr r -#define CLR_TOP32(r) -#endif /* CONFIG_PPC64BRIDGE */ diff --git a/arch/ppc/kernel/ppc_asm.tmpl b/arch/ppc/kernel/ppc_asm.tmpl deleted file mode 100644 index c35192bb4fe6..000000000000 --- a/arch/ppc/kernel/ppc_asm.tmpl +++ /dev/null @@ -1,115 +0,0 @@ -/* Condition Register Bit Fields */ - -#define cr0 0 -#define cr1 1 -#define cr2 2 -#define cr3 3 -#define cr4 4 -#define cr5 5 -#define cr6 6 -#define cr7 7 - - -/* General Purpose Registers (GPRs) */ - -#define r0 0 -#define r1 1 -#define r2 2 -#define r3 3 -#define r4 4 -#define r5 5 -#define r6 6 -#define r7 7 -#define r8 8 -#define r9 9 -#define r10 10 -#define r11 11 -#define r12 12 -#define r13 13 -#define r14 14 -#define r15 15 -#define r16 16 -#define r17 17 -#define r18 18 -#define r19 19 -#define r20 20 -#define r21 21 -#define r22 22 -#define r23 23 -#define r24 24 -#define r25 25 -#define r26 26 -#define r27 27 -#define r28 28 -#define r29 29 -#define r30 30 -#define r31 31 - - -/* Floating Point Registers (FPRs) */ - -#define fr0 0 -#define fr1 1 -#define fr2 2 -#define fr3 3 -#define fr4 4 -#define fr5 5 -#define fr6 6 -#define fr7 7 -#define fr8 8 -#define fr9 9 -#define fr10 10 -#define fr11 11 -#define fr12 12 -#define fr13 13 -#define fr14 14 -#define fr15 15 -#define fr16 16 -#define fr17 17 -#define fr18 18 -#define fr19 19 -#define fr20 20 -#define fr21 21 -#define fr22 22 -#define fr23 23 -#define fr24 24 -#define fr25 25 -#define fr26 26 -#define fr27 27 -#define fr28 28 -#define fr29 29 -#define fr30 30 -#define fr31 31 - -#define vr0 0 -#define vr1 1 -#define vr2 2 -#define vr3 3 -#define vr4 4 -#define vr5 5 -#define vr6 6 -#define vr7 7 -#define vr8 8 -#define vr9 9 -#define vr10 10 -#define vr11 11 -#define vr12 12 -#define vr13 13 -#define vr14 14 -#define vr15 15 -#define vr16 16 -#define vr17 17 -#define vr18 18 -#define vr19 19 -#define vr20 20 -#define vr21 21 -#define vr22 22 -#define vr23 23 -#define vr24 24 -#define vr25 25 -#define vr26 26 -#define vr27 27 -#define vr28 28 -#define vr29 29 -#define vr30 30 -#define vr31 31 diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index 805c7fbd1383..2649b327c7f2 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ppc_ksyms.c 1.59 11/04/01 22:58:20 paulus + * BK Id: %F% %I% %G% %U% %#% */ #include <linux/config.h> #include <linux/module.h> @@ -12,18 +12,17 @@ #include <linux/tty.h> #include <linux/vt_kern.h> #include <linux/nvram.h> -#include <linux/spinlock.h> #include <linux/console.h> #include <linux/irq.h> #include <linux/pci.h> #include <linux/delay.h> +#include <linux/ide.h> #include <asm/page.h> #include <asm/semaphore.h> #include <asm/processor.h> #include <asm/uaccess.h> #include <asm/io.h> -#include <linux/ide.h> #include <asm/ide.h> #include <asm/atomic.h> #include <asm/bitops.h> @@ -36,7 +35,7 @@ #include <asm/system.h> #include <asm/pci-bridge.h> #include <asm/irq.h> -#include <asm/feature.h> +#include <asm/pmac_feature.h> #include <asm/dma.h> #include <asm/machdep.h> #include <asm/hw_irq.h> @@ -60,7 +59,7 @@ extern void ppc_generic_ide_fix_driveid(struct hd_driveid *id); extern void transfer_to_handler(void); -extern void syscall_trace(void); +extern void do_syscall_trace(void); extern void do_IRQ(struct pt_regs *regs); extern void MachineCheckException(struct pt_regs *regs); extern void AlignmentException(struct pt_regs *regs); @@ -82,7 +81,7 @@ extern unsigned long mm_ptov (unsigned long paddr); EXPORT_SYMBOL(clear_page); EXPORT_SYMBOL(do_signal); -EXPORT_SYMBOL(syscall_trace); +EXPORT_SYMBOL(do_syscall_trace); EXPORT_SYMBOL(transfer_to_handler); EXPORT_SYMBOL(do_IRQ); EXPORT_SYMBOL(MachineCheckException); @@ -161,14 +160,18 @@ EXPORT_SYMBOL(_insw_ns); EXPORT_SYMBOL(_outsw_ns); EXPORT_SYMBOL(_insl_ns); EXPORT_SYMBOL(_outsl_ns); +EXPORT_SYMBOL(iopa); +EXPORT_SYMBOL(mm_ptov); +#ifndef CONFIG_PPC_ISERIES EXPORT_SYMBOL(ioremap); EXPORT_SYMBOL(__ioremap); EXPORT_SYMBOL(iounmap); -EXPORT_SYMBOL(iopa); -EXPORT_SYMBOL(mm_ptov); +#endif +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) EXPORT_SYMBOL(ppc_ide_md); EXPORT_SYMBOL(ppc_generic_ide_fix_driveid); +#endif #ifdef CONFIG_PCI EXPORT_SYMBOL_NOVERS(isa_io_base); @@ -176,19 +179,32 @@ EXPORT_SYMBOL_NOVERS(isa_mem_base); EXPORT_SYMBOL_NOVERS(pci_dram_offset); EXPORT_SYMBOL(pci_alloc_consistent); EXPORT_SYMBOL(pci_free_consistent); +EXPORT_SYMBOL(pci_bus_io_base); +EXPORT_SYMBOL(pci_bus_io_base_phys); +EXPORT_SYMBOL(pci_bus_mem_base_phys); +EXPORT_SYMBOL(pci_bus_to_hose); +EXPORT_SYMBOL(pci_resource_to_bus); +EXPORT_SYMBOL(pci_phys_to_bus); +EXPORT_SYMBOL(pci_bus_to_phys); #endif /* CONFIG_PCI */ +#ifdef CONFIG_NOT_COHERENT_CACHE +EXPORT_SYMBOL(consistent_alloc); +EXPORT_SYMBOL(consistent_free); +EXPORT_SYMBOL(consistent_sync); +#endif + EXPORT_SYMBOL(start_thread); EXPORT_SYMBOL(kernel_thread); -/*EXPORT_SYMBOL(__restore_flags);*/ -/*EXPORT_SYMBOL(_disable_interrupts); - EXPORT_SYMBOL(_enable_interrupts);*/ EXPORT_SYMBOL(flush_instruction_cache); EXPORT_SYMBOL(giveup_fpu); EXPORT_SYMBOL(enable_kernel_fp); EXPORT_SYMBOL(flush_icache_range); EXPORT_SYMBOL(flush_dcache_range); +EXPORT_SYMBOL(flush_icache_user_range); +EXPORT_SYMBOL(flush_icache_page); +EXPORT_SYMBOL(flush_dcache_page); EXPORT_SYMBOL(xchg_u32); #ifdef CONFIG_ALTIVEC EXPORT_SYMBOL(last_task_used_altivec); @@ -196,7 +212,6 @@ EXPORT_SYMBOL(giveup_altivec); #endif /* CONFIG_ALTIVEC */ #ifdef CONFIG_SMP EXPORT_SYMBOL(global_irq_lock); -EXPORT_SYMBOL(global_irq_count); EXPORT_SYMBOL(global_irq_holder); EXPORT_SYMBOL(__global_cli); EXPORT_SYMBOL(__global_sti); @@ -247,26 +262,11 @@ EXPORT_SYMBOL(device_is_compatible); EXPORT_SYMBOL(machine_is_compatible); EXPORT_SYMBOL(find_all_nodes); EXPORT_SYMBOL(get_property); -EXPORT_SYMBOL(pci_bus_io_base); -EXPORT_SYMBOL(pci_bus_io_base_phys); -EXPORT_SYMBOL(pci_bus_mem_base_phys); +EXPORT_SYMBOL(request_OF_resource); +EXPORT_SYMBOL(release_OF_resource); EXPORT_SYMBOL(pci_device_to_OF_node); EXPORT_SYMBOL(pci_device_from_OF_node); -EXPORT_SYMBOL(pci_bus_to_hose); -EXPORT_SYMBOL(pci_resource_to_bus); -EXPORT_SYMBOL(pci_phys_to_bus); -EXPORT_SYMBOL(pci_bus_to_phys); EXPORT_SYMBOL(pmac_newworld); -EXPORT_SYMBOL(feature_set); -EXPORT_SYMBOL(feature_clear); -EXPORT_SYMBOL(feature_test); -EXPORT_SYMBOL(feature_set_gmac_power); -EXPORT_SYMBOL(feature_gmac_phy_reset); -EXPORT_SYMBOL(feature_set_usb_power); -EXPORT_SYMBOL(feature_set_firewire_power); -EXPORT_SYMBOL(feature_set_firewire_cable_power); -EXPORT_SYMBOL(feature_set_modem_power); -EXPORT_SYMBOL(feature_set_airport_power); #endif /* defined(CONFIG_ALL_PPC) */ #if defined(CONFIG_BOOTX_TEXT) EXPORT_SYMBOL(btext_update_display); @@ -293,14 +293,16 @@ EXPORT_SYMBOL_NOVERS(memset); EXPORT_SYMBOL_NOVERS(memmove); EXPORT_SYMBOL_NOVERS(memscan); EXPORT_SYMBOL_NOVERS(memcmp); +EXPORT_SYMBOL_NOVERS(memchr); EXPORT_SYMBOL(abs); -#ifdef CONFIG_VGA_CONSOLE +#if defined(CONFIG_FB_VGA16_MODULE) EXPORT_SYMBOL(screen_info); #endif EXPORT_SYMBOL(__delay); +#ifndef INLINE_IRQS EXPORT_SYMBOL(__sti); EXPORT_SYMBOL(__sti_end); EXPORT_SYMBOL(__cli); @@ -309,6 +311,7 @@ EXPORT_SYMBOL(__save_flags_ptr); EXPORT_SYMBOL(__save_flags_ptr_end); EXPORT_SYMBOL(__restore_flags); EXPORT_SYMBOL(__restore_flags_end); +#endif EXPORT_SYMBOL(timer_interrupt_intercept); EXPORT_SYMBOL(timer_interrupt); EXPORT_SYMBOL(do_IRQ_intercept); @@ -319,7 +322,9 @@ EXPORT_SYMBOL(tb_ticks_per_jiffy); EXPORT_SYMBOL(get_wchan); EXPORT_SYMBOL(console_drivers); #ifdef CONFIG_XMON +extern void xmon_printf(char *fmt, ...); EXPORT_SYMBOL(xmon); +EXPORT_SYMBOL(xmon_printf); #endif EXPORT_SYMBOL(__up); EXPORT_SYMBOL(__down); @@ -343,10 +348,12 @@ EXPORT_SYMBOL(debugger_fault_handler); #ifdef CONFIG_8xx EXPORT_SYMBOL(__res); -EXPORT_SYMBOL(request_8xxirq); EXPORT_SYMBOL(cpm_install_handler); EXPORT_SYMBOL(cpm_free_handler); #endif /* CONFIG_8xx */ +#if defined(CONFIG_8xx) || defined(CONFIG_8260) +EXPORT_SYMBOL(request_8xxirq); +#endif EXPORT_SYMBOL(ret_to_user_hook); EXPORT_SYMBOL(next_mmu_context); @@ -361,3 +368,7 @@ EXPORT_SYMBOL(intercept_table); extern long *ret_from_intercept; EXPORT_SYMBOL(ret_from_intercept); EXPORT_SYMBOL(cur_cpu_spec); +#if defined(CONFIG_ALL_PPC) +extern unsigned long agp_special_page; +EXPORT_SYMBOL_NOVERS(agp_special_page); +#endif /* defined(CONFIG_ALL_PPC) */ diff --git a/arch/ppc/kernel/pplus_common.c b/arch/ppc/kernel/pplus_common.c new file mode 100644 index 000000000000..df3c2ca61f1d --- /dev/null +++ b/arch/ppc/kernel/pplus_common.c @@ -0,0 +1,317 @@ +/* + * arch/ppc/kernel/pplus_common.c + * + * Common Motorola PowerPlus Platform--really Falcon/Raven or HAWK. + * + * Author: Mark A. Greer + * mgreer@mvista.com + * + * Copyright 2001 MontaVista Software Inc. + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/pci.h> + +#include <asm/byteorder.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/pci.h> +#include <asm/pci-bridge.h> +#include <asm/open_pic.h> +#include <asm/pplus.h> + +/* + * The Falcon/Raven and HAWK has 4 sets of registers: + * 1) PPC Registers which define the mappings from PPC bus to PCI bus, + * etc. + * 2) PCI Registers which define the mappings from PCI bus to PPC bus and the + * MPIC base address. + * 3) MPIC registers. + * 4) System Memory Controller (SMC) registers. + */ + +/* + * Initialize the Motorola MCG Raven or HAWK host bridge. + * + * This means setting up the PPC bus to PCI memory and I/O space mappings, + * setting the PCI memory space address of the MPIC (mapped straight + * through), and ioremap'ing the mpic registers. + * This routine will set the PCI_CONFIG_ADDR or PCI_CONFIG_DATA + * addresses based on the PCI I/O address that is passed in. + * 'OpenPIC_Addr' will be set correctly by this routine. + */ +int __init +pplus_init(struct pci_controller *hose, + uint ppc_reg_base, + ulong processor_pci_mem_start, + ulong processor_pci_mem_end, + ulong processor_pci_io_start, + ulong processor_pci_io_end, + ulong processor_mpic_base) +{ + uint addr, offset; + + /* + * Some sanity checks... + */ + if (((processor_pci_mem_start&0xffff0000) != processor_pci_mem_start) || + ((processor_pci_io_start &0xffff0000) != processor_pci_io_start)) { + printk("pplus_init: %s\n", + "PPC to PCI mappings must start on 64 KB boundaries"); + return -1; + } + + if (((processor_pci_mem_end &0x0000ffff) != 0x0000ffff) || + ((processor_pci_io_end &0x0000ffff) != 0x0000ffff)) { + printk("pplus_init: PPC to PCI mappings %s\n", + "must end just before a 64 KB boundaries"); + return -1; + } + + if (((processor_pci_mem_end - processor_pci_mem_start) != + (hose->mem_space.end - hose->mem_space.start)) || + ((processor_pci_io_end - processor_pci_io_start) != + (hose->io_space.end - hose->io_space.start))) { + printk("pplus_init: %s\n", + "PPC and PCI memory or I/O space sizes don't match"); + return -1; + } + + if ((processor_mpic_base & 0xfffc0000) != processor_mpic_base) { + printk("pplus_init: %s\n", + "MPIC address must start on 256 MB boundary"); + return -1; + } + + if ((pci_dram_offset & 0xffff0000) != pci_dram_offset) { + printk("pplus_init: %s\n", + "pci_dram_offset must be multiple of 64 KB"); + return -1; + } + + /* + * Disable previous PPC->PCI mappings. + */ + out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF0_OFF), 0x00000000); + out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF1_OFF), 0x00000000); + out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF2_OFF), 0x00000000); + out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF3_OFF), 0x00000000); + + /* + * Program the XSADD/XSOFF registers to set up the PCI Mem & I/O + * space mappings. These are the mappings going from the processor to + * the PCI bus. + * + * Note: Don't need to 'AND' start/end addresses with 0xffff0000 + * because sanity check above ensures that they are properly + * aligned. + */ + + /* Set up PPC->PCI Mem mapping */ + addr = processor_pci_mem_start | (processor_pci_mem_end >> 16); + offset = (hose->mem_space.start - processor_pci_mem_start) | 0xd2; + out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSADD0_OFF), addr); + out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF0_OFF), offset); + + /* Set up PPC->MPIC mapping on the bridge */ + addr = processor_mpic_base | + (((processor_mpic_base + PPLUS_MPIC_SIZE) >> 16) - 1); + offset = 0xc2; /* No write posting for this PCI Mem space */ + out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSADD1_OFF), addr); + out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF1_OFF), offset); + + /* Set up PPC->PCI I/O mapping -- Contiguous I/O space */ + addr = processor_pci_io_start | (processor_pci_io_end >> 16); + offset = (hose->io_space.start - processor_pci_io_start) | 0xc0; + out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSADD3_OFF), addr); + out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF3_OFF), offset); + + hose->io_base_virt = (void *)ioremap(processor_pci_io_start, + (processor_pci_io_end - processor_pci_io_start + 1)); + + /* + * Set up the indirect method of accessing PCI config space. + * The PCI config addr/data pair based on start addr of PCI I/O space. + */ + setup_indirect_pci(hose, + processor_pci_io_start + PPLUS_PCI_CONFIG_ADDR_OFF, + processor_pci_io_start + PPLUS_PCI_CONFIG_DATA_OFF); + + /* + * Disable previous PCI->PPC mappings. + */ + + /* XXXX Put in mappings from PCI bus to processor bus XXXX */ + + /* + * Disable MPIC response to PCI I/O space (BAR 0). + * Make MPIC respond to PCI Mem space at specified address. + * (BAR 1). + */ + early_write_config_dword(hose, + 0, + PCI_DEVFN(0,0), + PCI_BASE_ADDRESS_0, + 0x00000000 | 0x1); + + early_write_config_dword(hose, + 0, + PCI_DEVFN(0,0), + PCI_BASE_ADDRESS_1, + processor_mpic_base | 0x0); + + /* Map MPIC into vitual memory */ + OpenPIC_Addr = ioremap(processor_mpic_base, PPLUS_MPIC_SIZE); + + return 0; +} + +/* + * Find the amount of RAM present. + * This assumes that PPCBug has initialized the memory controller (SMC) + * on the Falcon/HAWK correctly (i.e., it does no sanity checking). + * It also assumes that the memory base registers are set to configure the + * memory as contigous starting with "RAM A BASE", "RAM B BASE", etc. + * however, RAM base registers can be skipped (e.g. A, B, C are set, + * D is skipped but E is set is okay). + */ +#define MB (1024*1024) + +static uint reg_offset_table[] __initdata = { + PPLUS_SMC_RAM_A_SIZE_REG_OFF, + PPLUS_SMC_RAM_B_SIZE_REG_OFF, + PPLUS_SMC_RAM_C_SIZE_REG_OFF, + PPLUS_SMC_RAM_D_SIZE_REG_OFF, + PPLUS_SMC_RAM_E_SIZE_REG_OFF, + PPLUS_SMC_RAM_F_SIZE_REG_OFF, + PPLUS_SMC_RAM_G_SIZE_REG_OFF, + PPLUS_SMC_RAM_H_SIZE_REG_OFF +}; + +static uint falcon_size_table[] __initdata = { + 0 * MB, /* 0 ==> 0 MB */ + 16 * MB, /* 1 ==> 16 MB */ + 32 * MB, /* 2 ==> 32 MB */ + 64 * MB, /* 3 ==> 64 MB */ + 128 * MB, /* 4 ==> 128 MB */ + 256 * MB, /* 5 ==> 256 MB */ + 1024 * MB, /* 6 ==> 1024 MB (1 GB) */ +}; + +static uint hawk_size_table[] __initdata = { + 0 * MB, /* 0 ==> 0 MB */ + 32 * MB, /* 1 ==> 32 MB */ + 64 * MB, /* 2 ==> 64 MB */ + 64 * MB, /* 3 ==> 64 MB */ + 128 * MB, /* 4 ==> 128 MB */ + 128 * MB, /* 5 ==> 128 MB */ + 128 * MB, /* 6 ==> 128 MB */ + 256 * MB, /* 7 ==> 256 MB */ + 256 * MB, /* 8 ==> 256 MB */ + 512 * MB, /* 9 ==> 512 MB */ +}; + +/* + * *** WARNING: You MUST have a BAT set up to map in the SMC regs *** + * + * Read the memory controller's registers to determine the amount of system + * memory. Assumes that the memory controller registers are already mapped + * into virtual memory--too early to use ioremap(). + */ +unsigned long __init +pplus_get_mem_size(uint smc_base) +{ + unsigned long total; + int i, size_table_entries, reg_limit; + uint vend_dev_id; + uint *size_table; + u_char val; + + + vend_dev_id = in_be32((uint *)smc_base + PCI_VENDOR_ID); + + if (((vend_dev_id & 0xffff0000) >> 16) != PCI_VENDOR_ID_MOTOROLA) { + printk("pplus_get_mem_size: %s (0x%x)\n", + "Not a Motorola Memory Controller", vend_dev_id); + return 0; + } + + vend_dev_id &= 0x0000ffff; + + if (vend_dev_id == PCI_DEVICE_ID_MOTOROLA_FALCON) { + size_table = falcon_size_table; + size_table_entries = sizeof(falcon_size_table) / + sizeof(falcon_size_table[0]); + + reg_limit = PPLUS_FALCON_SMC_REG_COUNT; + } + else if (vend_dev_id == PCI_DEVICE_ID_MOTOROLA_HAWK) { + size_table = hawk_size_table; + size_table_entries = sizeof(hawk_size_table) / + sizeof(hawk_size_table[0]); + reg_limit = PPLUS_HAWK_SMC_REG_COUNT; + } + else { + printk("pplus_get_mem_size: %s (0x%x)\n", + "Not a Falcon or HAWK", vend_dev_id); + return 0; + } + + total = 0; + + /* Check every reg because PPCBug may skip some */ + for (i=0; i<reg_limit; i++) { + val = in_8((u_char *)(smc_base + reg_offset_table[i])); + + if (val & 0x80) { /* If enabled */ + val &= 0x0f; + + /* Don't go past end of size_table */ + if (val < size_table_entries) { + total += size_table[val]; + } + else { /* Register not set correctly */ + break; + } + } + } + + return total; +} + +int __init +pplus_mpic_init(unsigned int pci_mem_offset) +{ + unsigned short devid; + unsigned int pci_membase; + + /* Check the first PCI device to see if it is a Raven or Hawk. */ + early_read_config_word(0, 0, 0, PCI_DEVICE_ID, &devid); + + switch (devid) { + case PCI_DEVICE_ID_MOTOROLA_RAVEN: + case PCI_DEVICE_ID_MOTOROLA_HAWK: + break; + default: + OpenPIC_Addr = NULL; + return 1; + } + + /* Read the memory base register. */ + early_read_config_dword(0, 0, 0, PCI_BASE_ADDRESS_1, &pci_membase); + + if (pci_membase == 0) { + OpenPIC_Addr = NULL; + return 1; + } + + /* Map the MPIC registers to virtual memory. */ + OpenPIC_Addr = ioremap(pci_membase + pci_mem_offset, 0x22000); + + return 0; +} diff --git a/arch/ppc/kernel/prep_nvram.c b/arch/ppc/kernel/prep_nvram.c deleted file mode 100644 index 0049e1b0ffb9..000000000000 --- a/arch/ppc/kernel/prep_nvram.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * BK Id: SCCS/s.prep_nvram.c 1.12 09/08/01 15:47:42 paulus - */ -/* - * linux/arch/ppc/kernel/prep_nvram.c - * - * Copyright (C) 1998 Corey Minyard - * - */ -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/slab.h> -#include <linux/ioport.h> - -#include <asm/sections.h> -#include <asm/segment.h> -#include <asm/io.h> -#include <asm/processor.h> -#include <asm/machdep.h> -#include <asm/prep_nvram.h> - -static char nvramData[MAX_PREP_NVRAM]; -static NVRAM_MAP *nvram=(NVRAM_MAP *)&nvramData[0]; - -unsigned char __prep prep_nvram_read_val(int addr) -{ - outb(addr, PREP_NVRAM_AS0); - outb(addr>>8, PREP_NVRAM_AS1); - return inb(PREP_NVRAM_DATA); -} - -void __prep prep_nvram_write_val(int addr, - unsigned char val) -{ - outb(addr, PREP_NVRAM_AS0); - outb(addr>>8, PREP_NVRAM_AS1); - outb(val, PREP_NVRAM_DATA); -} - -void __init init_prep_nvram(void) -{ - unsigned char *nvp; - int i; - int nvramSize; - - /* - * The following could fail if the NvRAM were corrupt but - * we expect the boot firmware to have checked its checksum - * before boot - */ - nvp = (char *) &nvram->Header; - for (i=0; i<sizeof(HEADER); i++) - { - *nvp = ppc_md.nvram_read_val(i); - nvp++; - } - - /* - * The PReP NvRAM may be any size so read in the header to - * determine how much we must read in order to get the complete - * GE area - */ - nvramSize=(int)nvram->Header.GEAddress+nvram->Header.GELength; - if(nvramSize>MAX_PREP_NVRAM) - { - /* - * NvRAM is too large - */ - nvram->Header.GELength=0; - return; - } - - /* - * Read the remainder of the PReP NvRAM - */ - nvp = (char *) &nvram->GEArea[0]; - for (i=sizeof(HEADER); i<nvramSize; i++) - { - *nvp = ppc_md.nvram_read_val(i); - nvp++; - } -} - -__prep -char __prep *prep_nvram_get_var(const char *name) -{ - char *cp; - int namelen; - - namelen = strlen(name); - cp = prep_nvram_first_var(); - while (cp != NULL) { - if ((strncmp(name, cp, namelen) == 0) - && (cp[namelen] == '=')) - { - return cp+namelen+1; - } - cp = prep_nvram_next_var(cp); - } - - return NULL; -} - -__prep -char __prep *prep_nvram_first_var(void) -{ - if (nvram->Header.GELength == 0) { - return NULL; - } else { - return (((char *)nvram) - + ((unsigned int) nvram->Header.GEAddress)); - } -} - -__prep -char __prep *prep_nvram_next_var(char *name) -{ - char *cp; - - - cp = name; - while (((cp - ((char *) nvram->GEArea)) < nvram->Header.GELength) - && (*cp != '\0')) - { - cp++; - } - - /* Skip over any null characters. */ - while (((cp - ((char *) nvram->GEArea)) < nvram->Header.GELength) - && (*cp == '\0')) - { - cp++; - } - - if ((cp - ((char *) nvram->GEArea)) < nvram->Header.GELength) { - return cp; - } else { - return NULL; - } -} - - - diff --git a/arch/ppc/kernel/prep_pci.c b/arch/ppc/kernel/prep_pci.c deleted file mode 100644 index 0db1fde7c06e..000000000000 --- a/arch/ppc/kernel/prep_pci.c +++ /dev/null @@ -1,1249 +0,0 @@ -/* - * BK Id: SCCS/s.prep_pci.c 1.31 10/05/01 17:48:18 trini - */ -/* - * PReP pci functions. - * Originally by Gary Thomas - * rewritten and updated by Cort Dougan (cort@cs.nmt.edu) - * - * The motherboard routes/maps will disappear shortly. -- Cort - */ - -#include <linux/config.h> -#include <linux/types.h> -#include <linux/pci.h> -#include <linux/kernel.h> -#include <linux/init.h> - -#include <asm/sections.h> -#include <asm/byteorder.h> -#include <asm/io.h> -#include <asm/ptrace.h> -#include <asm/prom.h> -#include <asm/pci-bridge.h> -#include <asm/residual.h> -#include <asm/processor.h> -#include <asm/irq.h> -#include <asm/machdep.h> - -#include "pci.h" -#include "open_pic.h" - -#define MAX_DEVNR 22 - -/* Which PCI interrupt line does a given device [slot] use? */ -/* Note: This really should be two dimensional based in slot/pin used */ -static unsigned char *Motherboard_map; -unsigned char *Motherboard_map_name; - -/* How is the 82378 PIRQ mapping setup? */ -static unsigned char *Motherboard_routes; - -static void (*Motherboard_non0)(struct pci_dev *); - -static void Powerplus_Map_Non0(struct pci_dev *); - -/* Used for Motorola to store system config register */ -static unsigned long *ProcInfo; - -/* Tables for known hardware */ - -/* Motorola PowerStackII - Utah */ -static char Utah_pci_IRQ_map[23] __prepdata = -{ - 0, /* Slot 0 - unused */ - 0, /* Slot 1 - unused */ - 5, /* Slot 2 - SCSI - NCR825A */ - 0, /* Slot 3 - unused */ - 1, /* Slot 4 - Ethernet - DEC2114x */ - 0, /* Slot 5 - unused */ - 3, /* Slot 6 - PCI Card slot #1 */ - 4, /* Slot 7 - PCI Card slot #2 */ - 5, /* Slot 8 - PCI Card slot #3 */ - 5, /* Slot 9 - PCI Bridge */ - /* added here in case we ever support PCI bridges */ - /* Secondary PCI bus cards are at slot-9,6 & slot-9,7 */ - 0, /* Slot 10 - unused */ - 0, /* Slot 11 - unused */ - 5, /* Slot 12 - SCSI - NCR825A */ - 0, /* Slot 13 - unused */ - 3, /* Slot 14 - enet */ - 0, /* Slot 15 - unused */ - 2, /* Slot 16 - unused */ - 3, /* Slot 17 - unused */ - 5, /* Slot 18 - unused */ - 0, /* Slot 19 - unused */ - 0, /* Slot 20 - unused */ - 0, /* Slot 21 - unused */ - 0, /* Slot 22 - unused */ -}; - -static char Utah_pci_IRQ_routes[] __prepdata = -{ - 0, /* Line 0 - Unused */ - 9, /* Line 1 */ - 10, /* Line 2 */ - 11, /* Line 3 */ - 14, /* Line 4 */ - 15, /* Line 5 */ -}; - -/* Motorola PowerStackII - Omaha */ -/* no integrated SCSI or ethernet */ -static char Omaha_pci_IRQ_map[23] __prepdata = -{ - 0, /* Slot 0 - unused */ - 0, /* Slot 1 - unused */ - 3, /* Slot 2 - Winbond EIDE */ - 0, /* Slot 3 - unused */ - 0, /* Slot 4 - unused */ - 0, /* Slot 5 - unused */ - 1, /* Slot 6 - PCI slot 1 */ - 2, /* Slot 7 - PCI slot 2 */ - 3, /* Slot 8 - PCI slot 3 */ - 4, /* Slot 9 - PCI slot 4 */ /* needs indirect access */ - 0, /* Slot 10 - unused */ - 0, /* Slot 11 - unused */ - 0, /* Slot 12 - unused */ - 0, /* Slot 13 - unused */ - 0, /* Slot 14 - unused */ - 0, /* Slot 15 - unused */ - 1, /* Slot 16 - PCI slot 1 */ - 2, /* Slot 17 - PCI slot 2 */ - 3, /* Slot 18 - PCI slot 3 */ - 4, /* Slot 19 - PCI slot 4 */ /* needs indirect access */ - 0, - 0, - 0, -}; - -static char Omaha_pci_IRQ_routes[] __prepdata = -{ - 0, /* Line 0 - Unused */ - 9, /* Line 1 */ - 11, /* Line 2 */ - 14, /* Line 3 */ - 15 /* Line 4 */ -}; - -/* Motorola PowerStack */ -static char Blackhawk_pci_IRQ_map[19] __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 - unused */ - 3, /* Slot 12 - SCSI */ - 0, /* Slot 13 - unused */ - 1, /* Slot 14 - Ethernet */ - 0, /* Slot 15 - unused */ - 1, /* Slot P7 */ - 2, /* Slot P6 */ - 3, /* Slot P5 */ -}; - -static char Blackhawk_pci_IRQ_routes[] __prepdata = -{ - 0, /* Line 0 - Unused */ - 9, /* Line 1 */ - 11, /* Line 2 */ - 15, /* Line 3 */ - 15 /* Line 4 */ -}; - -/* Motorola Mesquite */ -static char Mesquite_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 - unused */ - 0, /* Slot 12 - unused */ - 0, /* Slot 13 - unused */ - 2, /* Slot 14 - Ethernet */ - 0, /* Slot 15 - unused */ - 3, /* Slot 16 - PMC */ - 0, /* Slot 17 - unused */ - 0, /* Slot 18 - unused */ - 0, /* Slot 19 - unused */ - 0, /* Slot 20 - unused */ - 0, /* Slot 21 - unused */ - 0, /* Slot 22 - unused */ -}; - -/* Motorola Sitka */ -static char Sitka_pci_IRQ_map[21] __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 - unused */ - 0, /* Slot 12 - unused */ - 0, /* Slot 13 - unused */ - 2, /* Slot 14 - Ethernet */ - 0, /* Slot 15 - unused */ - 9, /* Slot 16 - PMC 1 */ - 12, /* Slot 17 - PMC 2 */ - 0, /* Slot 18 - unused */ - 0, /* Slot 19 - unused */ - 4, /* Slot 20 - NT P2P bridge */ -}; - -/* Motorola MTX */ -static char MTX_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 - unused */ - 3, /* Slot 12 - SCSI */ - 0, /* Slot 13 - unused */ - 2, /* Slot 14 - Ethernet */ - 0, /* Slot 15 - unused */ - 9, /* Slot 16 - PCI/PMC slot 1 */ - 10, /* Slot 17 - PCI/PMC slot 2 */ - 11, /* Slot 18 - PCI slot 3 */ - 0, /* Slot 19 - unused */ - 0, /* Slot 20 - unused */ - 0, /* Slot 21 - unused */ - 0, /* Slot 22 - unused */ -}; - -/* Motorola MTX Plus */ -/* Secondary bus interrupt routing is not supported yet */ -static char MTXplus_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 - unused */ - 3, /* Slot 12 - SCSI */ - 0, /* Slot 13 - unused */ - 2, /* Slot 14 - Ethernet 1 */ - 0, /* Slot 15 - unused */ - 9, /* Slot 16 - PCI slot 1P */ - 10, /* Slot 17 - PCI slot 2P */ - 11, /* Slot 18 - PCI slot 3P */ - 10, /* Slot 19 - Ethernet 2 */ - 0, /* Slot 20 - P2P Bridge */ - 0, /* Slot 21 - unused */ - 0, /* Slot 22 - unused */ -}; - -static char Raven_pci_IRQ_routes[] __prepdata = -{ - 0, /* This is a dummy structure */ -}; - -/* Motorola MVME16xx */ -static char Genesis_pci_IRQ_map[16] __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 - unused */ - 3, /* Slot 12 - SCSI */ - 0, /* Slot 13 - unused */ - 1, /* Slot 14 - Ethernet */ - 0, /* Slot 15 - unused */ -}; - -static char Genesis_pci_IRQ_routes[] __prepdata = -{ - 0, /* Line 0 - Unused */ - 10, /* Line 1 */ - 11, /* Line 2 */ - 14, /* Line 3 */ - 15 /* Line 4 */ -}; - -static char Genesis2_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 - Ethernet */ - 0, /* Slot 11 - Universe PCI - VME Bridge */ - 3, /* Slot 12 - unused */ - 0, /* Slot 13 - unused */ - 2, /* Slot 14 - SCSI */ - 0, /* Slot 15 - unused */ - 9, /* Slot 16 - PMC 1 */ - 12, /* Slot 17 - pci */ - 11, /* Slot 18 - pci */ - 10, /* Slot 19 - pci */ - 0, /* Slot 20 - pci */ - 0, /* Slot 21 - unused */ - 0, /* Slot 22 - unused */ -}; - -/* Motorola Series-E */ -static char Comet_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 - unused */ - 3, /* Slot 12 - SCSI */ - 0, /* Slot 13 - unused */ - 1, /* Slot 14 - Ethernet */ - 0, /* Slot 15 - unused */ - 1, /* Slot 16 - PCI slot 1 */ - 2, /* Slot 17 - PCI slot 2 */ - 3, /* Slot 18 - PCI slot 3 */ - 4, /* Slot 19 - PCI bridge */ - 0, - 0, - 0, -}; - -static char Comet_pci_IRQ_routes[] __prepdata = -{ - 0, /* Line 0 - Unused */ - 10, /* Line 1 */ - 11, /* Line 2 */ - 14, /* Line 3 */ - 15 /* Line 4 */ -}; - -/* Motorola Series-EX */ -static char Comet2_pci_IRQ_map[23] __prepdata = -{ - 0, /* Slot 0 - unused */ - 0, /* Slot 1 - unused */ - 3, /* Slot 2 - SCSI - NCR825A */ - 0, /* Slot 3 - unused */ - 1, /* Slot 4 - Ethernet - DEC2104X */ - 0, /* Slot 5 - unused */ - 1, /* Slot 6 - PCI slot 1 */ - 2, /* Slot 7 - PCI slot 2 */ - 3, /* Slot 8 - PCI slot 3 */ - 4, /* Slot 9 - PCI bridge */ - 0, /* Slot 10 - unused */ - 0, /* Slot 11 - unused */ - 3, /* Slot 12 - SCSI - NCR825A */ - 0, /* Slot 13 - unused */ - 1, /* Slot 14 - Ethernet - DEC2104X */ - 0, /* Slot 15 - unused */ - 1, /* Slot 16 - PCI slot 1 */ - 2, /* Slot 17 - PCI slot 2 */ - 3, /* Slot 18 - PCI slot 3 */ - 4, /* Slot 19 - PCI bridge */ - 0, - 0, - 0, -}; - -static char Comet2_pci_IRQ_routes[] __prepdata = -{ - 0, /* Line 0 - Unused */ - 10, /* Line 1 */ - 11, /* Line 2 */ - 14, /* Line 3 */ - 15, /* Line 4 */ -}; - -/* - * ibm 830 (and 850?). - * This is actually based on the Carolina motherboard - * -- Cort - */ -static char ibm8xx_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 - FireCoral */ - 4, /* Slot 12 - Ethernet PCIINTD# */ - 2, /* Slot 13 - PCI Slot #2 */ - 2, /* Slot 14 - S3 Video PCIINTD# */ - 0, /* Slot 15 - onboard SCSI (INDI) [1] */ - 3, /* Slot 16 - NCR58C810 RS6000 Only PCIINTC# */ - 0, /* Slot 17 - unused */ - 2, /* Slot 18 - PCI Slot 2 PCIINTx# (See below) */ - 0, /* Slot 19 - unused */ - 0, /* Slot 20 - unused */ - 0, /* Slot 21 - unused */ - 2, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */ -}; - -static char ibm8xx_pci_IRQ_routes[] __prepdata = { - 0, /* Line 0 - unused */ - 15, /* Line 1 */ - 15, /* Line 2 */ - 15, /* Line 3 */ - 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 */ - 15, /* Line 2 */ - 15, /* Line 3 */ - 15, /* Line 4 */ -}; - - -/* IBM Nobis and Thinkpad 850 */ -static char Nobis_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 - unused */ - 3, /* Slot 12 - SCSI */ - 0, /* Slot 13 - unused */ - 0, /* Slot 14 - unused */ - 0, /* Slot 15 - unused */ -}; - -static char Nobis_pci_IRQ_routes[] __prepdata = { - 0, /* Line 0 - Unused */ - 13, /* Line 1 */ - 13, /* Line 2 */ - 13, /* Line 3 */ - 13 /* Line 4 */ -}; - -/* - * IBM RS/6000 43p/140 -- paulus - * XXX we should get all this from the residual data - */ -static char ibm43p_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 - FireCoral ISA bridge */ - 6, /* Slot 12 - Ethernet */ - 0, /* Slot 13 - openpic */ - 0, /* Slot 14 - unused */ - 0, /* Slot 15 - unused */ - 7, /* Slot 16 - NCR58C825a onboard scsi */ - 0, /* Slot 17 - unused */ - 2, /* Slot 18 - PCI Slot 2 PCIINTx# (See below) */ - 0, /* Slot 19 - unused */ - 0, /* Slot 20 - unused */ - 0, /* Slot 21 - unused */ - 1, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */ -}; - -static char ibm43p_pci_IRQ_routes[] __prepdata = { - 0, /* Line 0 - unused */ - 15, /* Line 1 */ - 15, /* Line 2 */ - 15, /* Line 3 */ - 15, /* Line 4 */ -}; - -/* Motorola PowerPlus architecture PCI IRQ tables */ -/* Interrupt line values for INTA-D on primary/secondary MPIC inputs */ - -struct powerplus_irq_list -{ - unsigned char primary[4]; /* INT A-D */ - unsigned char secondary[4]; /* INT A-D */ -}; - -/* - * For standard PowerPlus boards, bus 0 PCI INTs A-D are routed to - * OpenPIC inputs 9-12. PCI INTs A-D from the on board P2P bridge - * are routed to OpenPIC inputs 5-8. These values are offset by - * 16 in the table to reflect the Linux kernel interrupt value. - */ -struct powerplus_irq_list Powerplus_pci_IRQ_list __prepdata = -{ - {25, 26, 27, 28}, - {21, 22, 23, 24} -}; - -/* - * For the MCP750 (system slot board), cPCI INTs A-D are routed to - * OpenPIC inputs 8-11 and the PMC INTs A-D are routed to OpenPIC - * input 3. On a hot swap MCP750, the companion card PCI INTs A-D - * are routed to OpenPIC inputs 12-15. These values are offset by - * 16 in the table to reflect the Linux kernel interrupt value. - */ -struct powerplus_irq_list Mesquite_pci_IRQ_list __prepdata = -{ - {24, 25, 26, 27}, - {28, 29, 30, 31} -}; - -/* - * This table represents the standard PCI swizzle defined in the - * PCI bus specification. - */ -static unsigned char prep_pci_intpins[4][4] __prepdata = -{ - { 1, 2, 3, 4}, /* Buses 0, 4, 8, ... */ - { 2, 3, 4, 1}, /* Buses 1, 5, 9, ... */ - { 3, 4, 1, 2}, /* Buses 2, 6, 10 ... */ - { 4, 1, 2, 3}, /* Buses 3, 7, 11 ... */ -}; - -/* We have to turn on LEVEL mode for changed IRQ's */ -/* All PCI IRQ's need to be level mode, so this should be something - * other than hard-coded as well... IRQ's are individually mappable - * to either edge or level. - */ - -/* - * 8259 edge/level control definitions - */ -#define ISA8259_M_ELCR 0x4d0 -#define ISA8259_S_ELCR 0x4d1 - -#define ELCRS_INT15_LVL 0x80 -#define ELCRS_INT14_LVL 0x40 -#define ELCRS_INT12_LVL 0x10 -#define ELCRS_INT11_LVL 0x08 -#define ELCRS_INT10_LVL 0x04 -#define ELCRS_INT9_LVL 0x02 -#define ELCRS_INT8_LVL 0x01 -#define ELCRM_INT7_LVL 0x80 -#define ELCRM_INT5_LVL 0x20 - -#define CFGPTR(dev) (0x80800000 | (1<<(dev>>3)) | ((dev&7)<<8) | offset) -#define DEVNO(dev) (dev>>3) - -#define cfg_read(val, addr, type, op) *val = op((type)(addr)) -#define cfg_write(val, addr, type, op) op((type *)(addr), (val)) - -#define cfg_read_bad(val, size) *val = bad_##size; -#define cfg_write_bad(val, size) - -#define bad_byte 0xff -#define bad_word 0xffff -#define bad_dword 0xffffffffU - -#define PREP_PCI_OP(rw, size, type, op) \ -static int __prep \ -prep_##rw##_config_##size(struct pci_dev *dev, int offset, type val) \ -{ \ - if ((dev->bus->number != 0) || (DEVNO(dev->devfn) > MAX_DEVNR)) \ - { \ - cfg_##rw##_bad(val, size) \ - return PCIBIOS_DEVICE_NOT_FOUND; \ - } \ - cfg_##rw(val, CFGPTR(dev->devfn), type, op); \ - return PCIBIOS_SUCCESSFUL; \ -} - -PREP_PCI_OP(read, byte, u8 *, in_8) -PREP_PCI_OP(read, word, u16 *, in_le16) -PREP_PCI_OP(read, dword, u32 *, in_le32) -PREP_PCI_OP(write, byte, u8, out_8) -PREP_PCI_OP(write, word, u16, out_le16) -PREP_PCI_OP(write, dword, u32, out_le32) - -static struct pci_ops prep_pci_ops = -{ - prep_read_config_byte, - prep_read_config_word, - prep_read_config_dword, - prep_write_config_byte, - prep_write_config_word, - prep_write_config_dword -}; - -#define MOTOROLA_CPUTYPE_REG 0x800 -#define MOTOROLA_BASETYPE_REG 0x803 -#define MPIC_RAVEN_ID 0x48010000 -#define MPIC_HAWK_ID 0x48030000 -#define MOT_PROC2_BIT 0x800 - -static u_char mvme2600_openpic_initsenses[] __initdata = { - 1, /* MVME2600_INT_SIO */ - 0, /* MVME2600_INT_FALCN_ECC_ERR */ - 1, /* MVME2600_INT_PCI_ETHERNET */ - 1, /* MVME2600_INT_PCI_SCSI */ - 1, /* MVME2600_INT_PCI_GRAPHICS */ - 1, /* MVME2600_INT_PCI_VME0 */ - 1, /* MVME2600_INT_PCI_VME1 */ - 1, /* MVME2600_INT_PCI_VME2 */ - 1, /* MVME2600_INT_PCI_VME3 */ - 1, /* MVME2600_INT_PCI_INTA */ - 1, /* MVME2600_INT_PCI_INTB */ - 1, /* MVME2600_INT_PCI_INTC */ - 1, /* MVME2600_INT_PCI_INTD */ - 1, /* MVME2600_INT_LM_SIG0 */ - 1, /* MVME2600_INT_LM_SIG1 */ -}; - -#define MOT_RAVEN_PRESENT 0x1 -#define MOT_HAWK_PRESENT 0x2 - -int mot_entry = -1; -int prep_keybd_present = 1; -int MotMPIC; -int mot_multi; - -int __init -raven_init(void) -{ - unsigned int devid; - unsigned int pci_membase; - unsigned char base_mod; - - /* Check to see if the Raven chip exists. */ - if ( _prep_type != _PREP_Motorola) { - OpenPIC_Addr = NULL; - return 0; - } - - /* Check to see if this board is a type that might have a Raven. */ - if ((inb(MOTOROLA_CPUTYPE_REG) & 0xF0) != 0xE0) { - OpenPIC_Addr = NULL; - return 0; - } - - /* Check the first PCI device to see if it is a Raven. */ - early_read_config_dword(0, 0, 0, PCI_VENDOR_ID, &devid); - - switch (devid & 0xffff0000) { - case MPIC_RAVEN_ID: - MotMPIC = MOT_RAVEN_PRESENT; - break; - case MPIC_HAWK_ID: - MotMPIC = MOT_HAWK_PRESENT; - break; - default: - OpenPIC_Addr = NULL; - return 0; - } - - - /* Read the memory base register. */ - early_read_config_dword(0, 0, 0, PCI_BASE_ADDRESS_1, &pci_membase); - - if (pci_membase == 0) { - OpenPIC_Addr = NULL; - return 0; - } - - /* Map the Raven MPIC registers to virtual memory. */ - OpenPIC_Addr = ioremap(pci_membase+0xC0000000, 0x22000); - - OpenPIC_InitSenses = mvme2600_openpic_initsenses; - OpenPIC_NumInitSenses = sizeof(mvme2600_openpic_initsenses); - - ppc_md.get_irq = openpic_get_irq; - - /* If raven is present on Motorola store the system config register - * for later use. - */ - ProcInfo = (unsigned long *)ioremap(0xfef80400, 4); - - /* Indicate to system if this is a multiprocessor board */ - if (!(*ProcInfo & MOT_PROC2_BIT)) { - mot_multi = 1; - } - - /* This is a hack. If this is a 2300 or 2400 mot board then there is - * no keyboard controller and we have to indicate that. - */ - base_mod = inb(MOTOROLA_BASETYPE_REG); - if ((MotMPIC == MOT_HAWK_PRESENT) || (base_mod == 0xF9) || - (base_mod == 0xFA) || (base_mod == 0xE1)) - prep_keybd_present = 0; - - return 1; -} - -struct mot_info { - int cpu_type; /* 0x100 mask assumes for Raven and Hawk boards that the level/edge are set */ - /* 0x200 if this board has a Hawk chip. */ - int base_type; - int max_cpu; /* ored with 0x80 if this board should be checked for multi CPU */ - const char *name; - unsigned char *map; - unsigned char *routes; - void (*map_non0_bus)(struct pci_dev *); /* For boards with more than bus 0 devices. */ - struct powerplus_irq_list *pci_irq_list; /* List of PCI MPIC inputs */ - unsigned char secondary_bridge_devfn; /* devfn of secondary bus transparent bridge */ -} mot_info[] __prepdata = { - {0x300, 0x00, 0x00, "MVME 2400", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, - {0x010, 0x00, 0x00, "Genesis", Genesis_pci_IRQ_map, Genesis_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00}, - {0x020, 0x00, 0x00, "Powerstack (Series E)", Comet_pci_IRQ_map, Comet_pci_IRQ_routes, NULL, NULL, 0x00}, - {0x040, 0x00, 0x00, "Blackhawk (Powerstack)", Blackhawk_pci_IRQ_map, Blackhawk_pci_IRQ_routes, NULL, NULL, 0x00}, - {0x050, 0x00, 0x00, "Omaha (PowerStack II Pro3000)", Omaha_pci_IRQ_map, Omaha_pci_IRQ_routes, NULL, NULL, 0x00}, - {0x060, 0x00, 0x00, "Utah (Powerstack II Pro4000)", Utah_pci_IRQ_map, Utah_pci_IRQ_routes, NULL, NULL, 0x00}, - {0x0A0, 0x00, 0x00, "Powerstack (Series EX)", Comet2_pci_IRQ_map, Comet2_pci_IRQ_routes, NULL, NULL, 0x00}, - {0x1E0, 0xE0, 0x00, "Mesquite cPCI (MCP750)", Mesquite_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Mesquite_pci_IRQ_list, 0xFF}, - {0x1E0, 0xE1, 0x00, "Sitka cPCI (MCPN750)", Sitka_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, - {0x1E0, 0xE2, 0x00, "Mesquite cPCI (MCP750) w/ HAC", Mesquite_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Mesquite_pci_IRQ_list, 0xC0}, - {0x1E0, 0xF6, 0x80, "MTX Plus", MTXplus_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xA0}, - {0x1E0, 0xF6, 0x81, "Dual MTX Plus", MTXplus_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xA0}, - {0x1E0, 0xF7, 0x80, "MTX wo/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00}, - {0x1E0, 0xF7, 0x81, "Dual MTX wo/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00}, - {0x1E0, 0xF8, 0x80, "MTX w/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00}, - {0x1E0, 0xF8, 0x81, "Dual MTX w/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00}, - {0x1E0, 0xF9, 0x00, "MVME 2300", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, - {0x1E0, 0xFA, 0x00, "MVME 2300SC/2600", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, - {0x1E0, 0xFB, 0x00, "MVME 2600 with MVME712M", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, - {0x1E0, 0xFC, 0x00, "MVME 2600/2700 with MVME761", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, - {0x1E0, 0xFD, 0x80, "MVME 3600 with MVME712M", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00}, - {0x1E0, 0xFD, 0x81, "MVME 4600 with MVME712M", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, - {0x1E0, 0xFE, 0x80, "MVME 3600 with MVME761", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, - {0x1E0, 0xFE, 0x81, "MVME 4600 with MVME761", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, - {0x1E0, 0xFF, 0x00, "MVME 1600-001 or 1600-011", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, - {0x000, 0x00, 0x00, "", NULL, NULL, NULL, NULL, 0x00} -}; - -void __init -ibm_prep_init(void) -{ - u32 addr; -#ifdef CONFIG_PREP_RESIDUAL - PPC_DEVICE *mpic; -#endif - - if (inb(0x0852) == 0xd5) { - /* This is for the 43p-140 */ - early_read_config_dword(0, 0, PCI_DEVFN(13, 0), - PCI_BASE_ADDRESS_0, &addr); - if (addr != 0xffffffff - && !(addr & PCI_BASE_ADDRESS_SPACE_IO) - && (addr &= PCI_BASE_ADDRESS_MEM_MASK) != 0) { - addr += PREP_ISA_MEM_BASE; - OpenPIC_Addr = ioremap(addr, 0x40000); - ppc_md.get_irq = openpic_get_irq; - } - } - -#ifdef CONFIG_PREP_RESIDUAL - mpic = residual_find_device(-1, NULL, SystemPeripheral, - ProgrammableInterruptController, MPIC, 0); - if (mpic != NULL) - printk("mpic = %p\n", mpic); -#endif -} - -static void __init -ibm43p_pci_map_non0(struct pci_dev *dev) -{ - unsigned char intpin; - static unsigned char bridge_intrs[4] = { 3, 4, 5, 8 }; - - if (dev == NULL) - return; - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &intpin); - if (intpin < 1 || intpin > 4) - return; - intpin = (PCI_SLOT(dev->devfn) + intpin - 1) & 3; - dev->irq = openpic_to_irq(bridge_intrs[intpin]); - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); -} - -void __init -prep_route_pci_interrupts(void) -{ - unsigned char *ibc_pirq = (unsigned char *)0x80800860; - unsigned char *ibc_pcicon = (unsigned char *)0x80800840; - int i; - - if ( _prep_type == _PREP_Motorola) - { - unsigned short irq_mode; - unsigned char cpu_type; - unsigned char base_mod; - int entry; - - cpu_type = inb(MOTOROLA_CPUTYPE_REG) & 0xF0; - base_mod = inb(MOTOROLA_BASETYPE_REG); - - for (entry = 0; mot_info[entry].cpu_type != 0; entry++) { - if (mot_info[entry].cpu_type & 0x200) { /* Check for Hawk chip */ - if (!(MotMPIC & MOT_HAWK_PRESENT)) - continue; - } else { /* Check non hawk boards */ - if ((mot_info[entry].cpu_type & 0xff) != cpu_type) - continue; - - if (mot_info[entry].base_type == 0) { - mot_entry = entry; - break; - } - - if (mot_info[entry].base_type != base_mod) - continue; - } - - if (!(mot_info[entry].max_cpu & 0x80)) { - mot_entry = entry; - break; - } - - /* processor 1 not present and max processor zero indicated */ - if ((*ProcInfo & MOT_PROC2_BIT) && !(mot_info[entry].max_cpu & 0x7f)) { - mot_entry = entry; - break; - } - - /* processor 1 present and max processor zero indicated */ - if (!(*ProcInfo & MOT_PROC2_BIT) && (mot_info[entry].max_cpu & 0x7f)) { - mot_entry = entry; - break; - } - } - - if (mot_entry == -1) /* No particular cpu type found - assume Blackhawk */ - mot_entry = 3; - - Motherboard_map_name = (unsigned char *)mot_info[mot_entry].name; - Motherboard_map = mot_info[mot_entry].map; - Motherboard_routes = mot_info[mot_entry].routes; - Motherboard_non0 = mot_info[mot_entry].map_non0_bus; - - if (!(mot_info[entry].cpu_type & 0x100)) { - /* AJF adjust level/edge control according to routes */ - irq_mode = 0; - for (i = 1; i <= 4; i++) - irq_mode |= ( 1 << Motherboard_routes[i] ); - outb( irq_mode & 0xff, 0x4d0 ); - outb( (irq_mode >> 8) & 0xff, 0x4d1 ); - } - } else if ( _prep_type == _PREP_IBM ) { - unsigned char planar_id = inb(0x0852); - unsigned char irq_edge_mask_lo, irq_edge_mask_hi; - - printk("IBM ID: %08x\n", planar_id); - switch(planar_id) { - case 0xff: - Motherboard_map_name = "IBM Thinkpad 850/860"; - Motherboard_map = Nobis_pci_IRQ_map; - Motherboard_routes = Nobis_pci_IRQ_routes; - irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */ - irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */ - break; - case 0xfc: - Motherboard_map_name = "IBM 6015/7020 (Sandalfoot/Sandalbow)"; - Motherboard_map = ibm6015_pci_IRQ_map; - Motherboard_routes = ibm6015_pci_IRQ_routes; - irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */ - irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */ - break; - case 0xd5: - Motherboard_map_name = "IBM 43P-140 (Tiger1)"; - Motherboard_map = ibm43p_pci_IRQ_map; - Motherboard_routes = ibm43p_pci_IRQ_routes; - Motherboard_non0 = ibm43p_pci_map_non0; - irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */ - irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */ - break; - default: - printk(KERN_ERR "Unknown IBM motherboard! Defaulting to Carolina.\n"); - case 0xf0: /* PowerSeries 830/850 */ - case 0xf1: /* PowerSeries 830/850 */ - case 0xf2: /* PowerSeries 830/850 */ - case 0xf4: /* 7248-43P */ - case 0xf5: /* 7248-43P */ - case 0xf6: /* 7248-43P */ - case 0xf7: /* 7248-43P (missing from Carolina Tech Spec) */ - Motherboard_map_name = "IBM PS830/PS850/7248 (Carolina)"; - Motherboard_map = ibm8xx_pci_IRQ_map; - Motherboard_routes = ibm8xx_pci_IRQ_routes; - irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */ - irq_edge_mask_hi = 0xA4; /* irq's 10, 13, 15 level-triggered */ - break; - } - - outb(inb(0x04d0)|irq_edge_mask_lo, 0x04d0); /* primary 8259 */ - outb(inb(0x04d1)|irq_edge_mask_hi, 0x04d1); /* cascaded 8259 */ - } else { - printk("No known machine pci routing!\n"); - return; - } - - /* Set up mapping from slots */ - for (i = 1; i <= 4; i++) - ibc_pirq[i-1] = Motherboard_routes[i]; - /* Enable PCI interrupts */ - *ibc_pcicon |= 0x20; -} - -void __init -prep_pib_init(void) -{ - unsigned char reg; - unsigned short short_reg; - - struct pci_dev *dev = NULL; - - if (( _prep_type == _PREP_Motorola) && (OpenPIC_Addr)) { - /* - * Perform specific configuration for the Via Tech or - * or Winbond PCI-ISA-Bridge part. - */ - if ((dev = pci_find_device(PCI_VENDOR_ID_VIA, - PCI_DEVICE_ID_VIA_82C586_1, dev))) { - /* - * PPCBUG does not set the enable bits - * for the IDE device. Force them on here. - */ - pci_read_config_byte(dev, 0x40, ®); - - reg |= 0x03; /* IDE: Chip Enable Bits */ - pci_write_config_byte(dev, 0x40, reg); - } - if ((dev = pci_find_device(PCI_VENDOR_ID_VIA, - PCI_DEVICE_ID_VIA_82C586_2, - dev)) && (dev->devfn = 0x5a)) { - /* Force correct USB interrupt */ - dev->irq = 11; - pci_write_config_byte(dev, - PCI_INTERRUPT_LINE, - dev->irq); - } - if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND, - PCI_DEVICE_ID_WINBOND_83C553, dev))) { - /* Clear PCI Interrupt Routing Control Register. */ - short_reg = 0x0000; - pci_write_config_word(dev, 0x44, short_reg); - if (OpenPIC_Addr){ - /* Route IDE interrupts to IRQ 14 */ - reg = 0xEE; - pci_write_config_byte(dev, 0x43, reg); - } - } - } - - if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND, - PCI_DEVICE_ID_WINBOND_82C105, dev))){ - if (OpenPIC_Addr){ - /* - * Disable LEGIRQ mode so PCI INTS are routed - * directly to the 8259 and enable both channels - */ - pci_write_config_dword(dev, 0x40, 0x10ff0033); - - /* Force correct IDE interrupt */ - dev->irq = 14; - pci_write_config_byte(dev, - PCI_INTERRUPT_LINE, - dev->irq); - } else { - /* Enable LEGIRQ for PCI INT -> 8259 IRQ routing */ - pci_write_config_dword(dev, 0x40, 0x10ff08a1); - } - } -} - -static void __init -Powerplus_Map_Non0(struct pci_dev *dev) -{ - struct pci_bus *pbus; /* Parent bus structure pointer */ - struct pci_dev *tdev = dev; /* Temporary device structure */ - unsigned int devnum; /* Accumulated device number */ - unsigned char intline; /* Linux interrupt value */ - unsigned char intpin; /* PCI interrupt pin */ - - /* Check for valid PCI dev pointer */ - if (dev == NULL) return; - - /* Initialize bridge IDSEL variable */ - devnum = PCI_SLOT(tdev->devfn); - - /* Read the interrupt pin of the device and adjust for indexing */ - pcibios_read_config_byte(dev->bus->number, dev->devfn, - PCI_INTERRUPT_PIN, &intpin); - - /* If device doesn't request an interrupt, return */ - if ( (intpin < 1) || (intpin > 4) ) - return; - - intpin--; - - /* - * Walk up to bus 0, adjusting the interrupt pin for the standard - * PCI bus swizzle. - */ - do { - intpin = (prep_pci_intpins[devnum % 4][intpin]) - 1; - pbus = tdev->bus; /* up one level */ - tdev = pbus->self; - devnum = PCI_SLOT(tdev->devfn); - } while(tdev->bus->number); - - /* Use the primary interrupt inputs by default */ - intline = mot_info[mot_entry].pci_irq_list->primary[intpin]; - - /* - * If the board has secondary interrupt inputs, walk the bus and - * note the devfn of the bridge from bus 0. If it is the same as - * the devfn of the bus bridge with secondary inputs, use those. - * Otherwise, assume it's a PMC site and get the interrupt line - * value from the interrupt routing table. - */ - if (mot_info[mot_entry].secondary_bridge_devfn) { - pbus = dev->bus; - - while (pbus->primary != 0) - pbus = pbus->parent; - - if ((pbus->self)->devfn != 0xA0) { - if ((pbus->self)->devfn == mot_info[mot_entry].secondary_bridge_devfn) - intline = mot_info[mot_entry].pci_irq_list->secondary[intpin]; - else { - if ((char *)(mot_info[mot_entry].map) == (char *)Mesquite_pci_IRQ_map) - intline = mot_info[mot_entry].map[((pbus->self)->devfn)/8] + 16; - else { - int i; - for (i=0;i<3;i++) - intpin = (prep_pci_intpins[devnum % 4][intpin]) - 1; - intline = mot_info[mot_entry].pci_irq_list->primary[intpin]; - } - } - } - } - - /* Write calculated interrupt value to header and device list */ - dev->irq = intline; - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, (u8)dev->irq); -} - -void __init -prep_pcibios_fixup(void) -{ - struct pci_dev *dev; - extern unsigned char *Motherboard_map; - extern unsigned char *Motherboard_routes; - unsigned char i; - - prep_route_pci_interrupts(); - - printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name); - if (OpenPIC_Addr) { - /* PCI interrupts are controlled by the OpenPIC */ - pci_for_each_dev(dev) { - if (dev->bus->number == 0) { - dev->irq = openpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]); - pcibios_write_config_byte(dev->bus->number, dev->devfn, PCI_INTERRUPT_LINE, dev->irq); - } else { - if (Motherboard_non0 != NULL) - Motherboard_non0(dev); - } - } - - /* Setup the Winbond or Via PIB */ - prep_pib_init(); - - return; - } - - pci_for_each_dev(dev) { - /* - * 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]]; - - for ( i = 0 ; i <= 5 ; i++ ) { - /* - * Relocate PCI I/O resources if necessary so the - * standard 256MB BAT covers them. - */ - if ( (pci_resource_flags(dev, i) & IORESOURCE_IO) && - (dev->resource[i].start > 0x10000000)) { - printk("Relocating PCI address %lx -> %lx\n", - dev->resource[i].start, - (dev->resource[i].start & - 0x00FFFFFF)| 0x01000000); - dev->resource[i].start = - (dev->resource[i].start & 0x00FFFFFF) - | 0x01000000; - pci_write_config_dword(dev, - PCI_BASE_ADDRESS_0 + (i*0x4), - dev->resource[i].start); - dev->resource[i].end = - (dev->resource[i].end & 0x00FFFFFF) - | 0x01000000; - } - } -#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 - } -} - -static void __init -prep_init_resource(struct resource *res, unsigned long start, - unsigned long end, int flags) -{ - res->flags = flags; - res->start = start; - res->end = end; - res->name = "PCI host bridge"; - res->parent = NULL; - res->sibling = NULL; - res->child = NULL; -} - -void __init -prep_find_bridges(void) -{ - struct pci_controller* hose; - - hose = pcibios_alloc_controller(); - if (!hose) - return; - - hose->first_busno = 0; - hose->last_busno = 0xff; - hose->pci_mem_offset = PREP_ISA_MEM_BASE; - hose->io_base_phys = PREP_ISA_IO_BASE; - hose->io_base_virt = (void *)0x80000000; /* see prep_map_io() */ - prep_init_resource(&hose->io_resource, 0, 0x0fffffff, IORESOURCE_IO); - prep_init_resource(&hose->mem_resources[0], 0xc0000000, 0xfeffffff, - IORESOURCE_MEM); - - printk("PReP architecture\n"); - { -#ifdef CONFIG_PREP_RESIDUAL - PPC_DEVICE *hostbridge; - - hostbridge = residual_find_device(PROCESSORDEVICE, NULL, - BridgeController, PCIBridge, -1, 0); - if (hostbridge && - hostbridge->DeviceId.Interface == PCIBridgeIndirect) { - PnP_TAG_PACKET * pkt; - pkt = PnP_find_large_vendor_packet( - res->DevicePnPHeap+hostbridge->AllocatedOffset, - 3, 0); - if(pkt) { -#define p pkt->L4_Pack.L4_Data.L4_PPCPack - setup_indirect_pci(hose, - ld_le32((unsigned *) (p.PPCData)), - ld_le32((unsigned *) (p.PPCData+8))); - } else - setup_indirect_pci(hose, 0x80000cf8, 0x80000cfc); - } else -#endif /* CONFIG_PREP_RESIDUAL */ - hose->ops = &prep_pci_ops; - } - - ppc_md.pcibios_fixup = prep_pcibios_fixup; -} diff --git a/arch/ppc/kernel/prep_setup.c b/arch/ppc/kernel/prep_setup.c deleted file mode 100644 index cf8ecaae9bcb..000000000000 --- a/arch/ppc/kernel/prep_setup.c +++ /dev/null @@ -1,927 +0,0 @@ -/* - * BK Id: SCCS/s.prep_setup.c 1.44 11/13/01 21:26:07 paulus - */ -/* - * linux/arch/ppc/kernel/setup.c - * - * Copyright (C) 1995 Linus Torvalds - * Adapted from 'alpha' version by Gary Thomas - * Modified by Cort Dougan (cort@cs.nmt.edu) - * - * Support for PReP (Motorola MTX/MVME) - * by Troy Benjegerdes (hozer@drgw.net) - */ - -/* - * bootup setup stuff.. - */ - -#include <linux/config.h> -#include <linux/delay.h> -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/stddef.h> -#include <linux/unistd.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/user.h> -#include <linux/a.out.h> -#include <linux/tty.h> -#include <linux/major.h> -#include <linux/interrupt.h> -#include <linux/reboot.h> -#include <linux/init.h> -#include <linux/blk.h> -#include <linux/ioport.h> -#include <linux/console.h> -#include <linux/timex.h> -#include <linux/pci.h> -#include <linux/ide.h> -#include <linux/seq_file.h> - -#include <asm/sections.h> -#include <asm/mmu.h> -#include <asm/processor.h> -#include <asm/residual.h> -#include <asm/io.h> -#include <asm/pgtable.h> -#include <asm/cache.h> -#include <asm/dma.h> -#include <asm/machdep.h> -#include <asm/mk48t59.h> -#include <asm/prep_nvram.h> -#include <asm/raven.h> -#include <asm/keyboard.h> -#include <asm/vga.h> -#include <asm/time.h> - -#include "local_irq.h" -#include "i8259.h" -#include "open_pic.h" - -#if defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE) -#include <../drivers/sound/sound_config.h> -#include <../drivers/sound/dev_table.h> -#endif - -unsigned char ucSystemType; -unsigned char ucBoardRev; -unsigned char ucBoardRevMaj, ucBoardRevMin; - -extern unsigned long mc146818_get_rtc_time(void); -extern int mc146818_set_rtc_time(unsigned long nowtime); -extern unsigned long mk48t59_get_rtc_time(void); -extern int mk48t59_set_rtc_time(unsigned long nowtime); - -extern unsigned char prep_nvram_read_val(int addr); -extern void prep_nvram_write_val(int addr, - unsigned char val); -extern unsigned char rs_nvram_read_val(int addr); -extern void rs_nvram_write_val(int addr, - unsigned char val); -extern void ibm_prep_init(void); - -extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); -extern int pckbd_getkeycode(unsigned int scancode); -extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, - char raw_mode); -extern char pckbd_unexpected_up(unsigned char keycode); -extern void pckbd_leds(unsigned char leds); -extern void pckbd_init_hw(void); -extern unsigned char pckbd_sysrq_xlate[]; - -extern void prep_find_bridges(void); -extern char saved_command_line[]; - -int _prep_type; - -#define cached_21 (((char *)(ppc_cached_irq_mask))[3]) -#define cached_A1 (((char *)(ppc_cached_irq_mask))[2]) - -/* for the mac fs */ -kdev_t boot_dev; -/* used in nasty hack for sound - see prep_setup_arch() -- Cort */ -long ppc_cs4232_dma, ppc_cs4232_dma2; - -extern PTE *Hash, *Hash_end; -extern unsigned long Hash_size, Hash_mask; -extern int probingmem; -extern unsigned long loops_per_jiffy; - -#ifdef CONFIG_SOUND_MODULE -EXPORT_SYMBOL(ppc_cs4232_dma); -EXPORT_SYMBOL(ppc_cs4232_dma2); -#endif - -static int __prep -prep_show_cpuinfo(struct seq_file *m) -{ - extern char *Motherboard_map_name; - int cachew; -#ifdef CONFIG_PREP_RESIDUAL - int i; -#endif - - seq_printf(m, "machine\t\t: PReP %s\n", Motherboard_map_name); - - switch ( _prep_type ) { - case _PREP_IBM: - cachew = inw(0x80c); - if (cachew & (1<<6)) - seq_printf(m, "Upgrade CPU\n"); - seq_printf(m, "L2\t\t: "); - if (cachew & (1<<7)) { - seq_printf(m, "not present\n"); - goto no_l2; - } - seq_printf(m, "%sKb,", (cachew & (1 << 10))? "512" : "256"); - seq_printf(m, "%ssync\n", (cachew & (1 << 15))? "" : "a"); - break; - case _PREP_Motorola: - cachew = *((unsigned char *)CACHECRBA); - seq_printf(m, "L2\t\t: "); - switch (cachew & L2CACHE_MASK) { - case L2CACHE_512KB: - seq_printf(m, "512Kb"); - break; - case L2CACHE_256KB: - seq_printf(m, "256Kb"); - break; - case L2CACHE_1MB: - seq_printf(m, "1MB"); - break; - case L2CACHE_NONE: - seq_printf(m, "none\n"); - goto no_l2; - break; - default: - seq_printf(m, "%x\n", cachew); - } - - seq_printf(m, ", parity %s", - (cachew & L2CACHE_PARITY)? "enabled" : "disabled"); - - seq_printf(m, " SRAM:"); - - switch ( ((cachew & 0xf0) >> 4) & ~(0x3) ) { - case 1: seq_printf(m, "synchronous,parity,flow-through\n"); - break; - case 2: seq_printf(m, "asynchronous,no parity\n"); - break; - case 3: seq_printf(m, "asynchronous,parity\n"); - break; - default:seq_printf(m, "synchronous,pipelined,no parity\n"); - break; - } - break; - default: - break; - } - -no_l2: -#ifdef CONFIG_PREP_RESIDUAL - if (res->ResidualLength == 0) { - /* print info about SIMMs */ - seq_printf(m, "simms\t\t: "); - for (i = 0; (res->ActualNumMemories) && (i < MAX_MEMS); i++) { - if (res->Memories[i].SIMMSize != 0) - seq_printf(m, "%d:%ldM ", i, - (res->Memories[i].SIMMSize > 1024) ? - res->Memories[i].SIMMSize>>20 : - res->Memories[i].SIMMSize); - } - seq_printf(m, "\n"); - } -#endif - - return 0; -} - -static int __prep -prep_show_percpuinfo(struct seq_file *m, int i) -{ - int len = 0; - - /* PREP's without residual data will give incorrect values here */ - seq_printf(m, "clock\t\t: "); -#ifdef CONFIG_PREP_RESIDUAL - if (res->ResidualLength) - seq_printf(m, "%ldMHz\n", - (res->VitalProductData.ProcessorHz > 1024) ? - res->VitalProductData.ProcessorHz>>20 : - res->VitalProductData.ProcessorHz); - else -#endif /* CONFIG_PREP_RESIDUAL */ - seq_printf(m, "???\n"); - - return 0; -} - -static void __init -prep_setup_arch(void) -{ - unsigned char reg; -#if 0 /* unused?? */ - unsigned char ucMothMemType; - unsigned char ucEquipPres1; -#endif - - /* init to some ~sane value until calibrate_delay() runs */ - loops_per_jiffy = 50000000; - - /* Lookup PCI host bridges */ - prep_find_bridges(); - - /* Set up floppy in PS/2 mode */ - outb(0x09, SIO_CONFIG_RA); - reg = inb(SIO_CONFIG_RD); - reg = (reg & 0x3F) | 0x40; - outb(reg, SIO_CONFIG_RD); - outb(reg, SIO_CONFIG_RD); /* Have to write twice to change! */ - - /* - * We need to set up the NvRAM access routines early as prep_init - * has yet to be called - */ - ppc_md.nvram_read_val = prep_nvram_read_val; - ppc_md.nvram_write_val = prep_nvram_write_val; - - /* we should determine this according to what we find! -- Cort */ - switch ( _prep_type ) - { - case _PREP_IBM: - /* Enable L2. Assume we don't need to flush -- Cort*/ - *(unsigned char *)(0x8000081c) |= 3; - ROOT_DEV = to_kdev_t(0x0301); /* hda1 */ - break; - case _PREP_Motorola: - /* Enable L2. Assume we don't need to flush -- Cort*/ - *(unsigned char *)(0x8000081c) |= 3; -#ifdef CONFIG_BLK_DEV_INITRD - if (initrd_start) - ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); /* /dev/ram */ - else -#endif -#ifdef CONFIG_ROOT_NFS - ROOT_DEV = to_kdev_t(0x00ff); /* /dev/nfs */ -#else - ROOT_DEV = to_kdev_t(0x0802); /* /dev/sda2 */ -#endif - break; - } - - /* Read in NVRAM data */ - init_prep_nvram(); - - /* if no bootargs, look in NVRAM */ - if ( cmd_line[0] == '\0' ) { - char *bootargs; - bootargs = prep_nvram_get_var("bootargs"); - if (bootargs != NULL) { - strcpy(cmd_line, bootargs); - /* again.. */ - strcpy(saved_command_line, cmd_line); - } - } - -#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. - * This is a really nasty hack, but unless we change the driver - * it's the only way to support both addrs from one binary. - * -- Cort - */ - if ( _machine == _MACH_prep ) - { - extern struct card_info snd_installed_cards[]; - struct card_info *snd_ptr; - - for ( snd_ptr = snd_installed_cards; - snd_ptr < &snd_installed_cards[num_sound_cards]; - snd_ptr++ ) - { - if ( snd_ptr->card_type == SNDCARD_CS4232 ) - { - if ( _prep_type == _PREP_Motorola ) - { - snd_ptr->config.io_base = 0x830; - snd_ptr->config.irq = 10; - snd_ptr->config.dma = ppc_cs4232_dma = 6; - snd_ptr->config.dma2 = ppc_cs4232_dma2 = 7; - } - if ( _prep_type == _PREP_IBM ) - { - snd_ptr->config.io_base = 0x530; - snd_ptr->config.irq = 5; - snd_ptr->config.dma = ppc_cs4232_dma = 1; - /* this is wrong - but leave it for now */ - snd_ptr->config.dma2 = ppc_cs4232_dma2 = 7; - } - } - } - } -#endif /* CONFIG_SOUND_CS4232 */ - - /*print_residual_device_info();*/ - - switch (_prep_type) { - case _PREP_Motorola: - raven_init(); - break; - case _PREP_IBM: - ibm_prep_init(); - break; - } - -#ifdef CONFIG_VGA_CONSOLE - /* remap the VGA memory */ - vgacon_remap_base = 0xf0000000; - /*vgacon_remap_base = ioremap(0xc0000000, 0xba000);*/ - conswitchp = &vga_con; -#elif defined(CONFIG_DUMMY_CONSOLE) - conswitchp = &dummy_con; -#endif -} - -/* - * Determine the decrementer frequency from the residual data - * This allows for a faster boot as we do not need to calibrate the - * decrementer against another clock. This is important for embedded systems. - */ -static int __init -prep_res_calibrate_decr(void) -{ -#ifdef CONFIG_PREP_RESIDUAL - unsigned long freq, divisor = 4; - - if ( res->VitalProductData.ProcessorBusHz ) { - freq = res->VitalProductData.ProcessorBusHz; - printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", - (freq/divisor)/1000000, - (freq/divisor)%1000000); - tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000); - tb_ticks_per_jiffy = freq / HZ / divisor; - return 0; - } else -#endif - return 1; -} - -/* - * Uses the on-board timer to calibrate the on-chip decrementer register - * for prep systems. On the pmac the OF tells us what the frequency is - * but on prep we have to figure it out. - * -- Cort - */ -/* Done with 3 interrupts: the first one primes the cache and the - * 2 following ones measure the interval. The precision of the method - * is still doubtful due to the short interval sampled. - */ -static volatile int calibrate_steps __initdata = 3; -static unsigned tbstamp __initdata = 0; - -static void __init -prep_calibrate_decr_handler(int irq, void *dev, struct pt_regs *regs) -{ - unsigned long t, freq; - int step=--calibrate_steps; - - t = get_tbl(); - if (step > 0) { - tbstamp = t; - } else { - freq = (t - tbstamp)*HZ; - printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", - freq/1000000, freq%1000000); - tb_ticks_per_jiffy = freq / HZ; - tb_to_us = mulhwu_scale_factor(freq, 1000000); - } -} - -static void __init -prep_calibrate_decr(void) -{ - int res; - - /* Try and get this from the residual data. */ - res = prep_res_calibrate_decr(); - - /* If we didn't get it from the residual data, try this. */ - if ( res ) { - unsigned long flags; - - save_flags(flags); - -#define TIMER0_COUNT 0x40 -#define TIMER_CONTROL 0x43 - /* set timer to periodic mode */ - outb_p(0x34,TIMER_CONTROL);/* binary, mode 2, LSB/MSB, ch 0 */ - /* set the clock to ~100 Hz */ - outb_p(LATCH & 0xff , TIMER0_COUNT); /* LSB */ - outb(LATCH >> 8 , TIMER0_COUNT); /* MSB */ - - if (request_irq(0, prep_calibrate_decr_handler, 0, "timer", NULL) != 0) - panic("Could not allocate timer IRQ!"); - __sti(); - /* wait for calibrate */ - while ( calibrate_steps ) - ; - restore_flags(flags); - free_irq( 0, NULL); - } -} - -static long __init -mk48t59_init(void) { - unsigned char tmp; - - tmp = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB); - if (tmp & MK48T59_RTC_CB_STOP) { - printk("Warning: RTC was stopped, date will be wrong.\n"); - ppc_md.nvram_write_val(MK48T59_RTC_CONTROLB, - tmp & ~MK48T59_RTC_CB_STOP); - /* Low frequency crystal oscillators may take a very long - * time to startup and stabilize. For now just ignore the - * the issue, but attempting to calibrate the decrementer - * from the RTC just after this wakeup is likely to be very - * inaccurate. Firmware should not allow to load - * the OS with the clock stopped anyway... - */ - } - /* Ensure that the clock registers are updated */ - tmp = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA); - tmp &= ~(MK48T59_RTC_CA_READ | MK48T59_RTC_CA_WRITE); - ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, tmp); - return 0; -} - -/* We use the NVRAM RTC to time a second to calibrate the decrementer, - * the RTC registers have just been set up in the right state by the - * preceding routine. - */ -static void __init -mk48t59_calibrate_decr(void) -{ - unsigned long freq; - unsigned long t1; - unsigned char save_control; - long i; - unsigned char sec; - - - /* Make sure the time is not stopped. */ - save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB); - - ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, - (save_control & (~MK48T59_RTC_CB_STOP))); - - /* Now make sure the read bit is off so the value will change. */ - save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA); - save_control &= ~MK48T59_RTC_CA_READ; - ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control); - - - /* Read the seconds value to see when it changes. */ - sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS); - /* Actually this is bad for precision, we should have a loop in - * which we only read the seconds counter. nvram_read_val writes - * the address bytes on every call and this takes a lot of time. - * Perhaps an nvram_wait_change method returning a time - * stamp with a loop count as parameter would be the solution. - */ - for (i = 0 ; i < 1000000 ; i++) { /* may take up to 1 second... */ - t1 = get_tbl(); - if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) { - break; - } - } - - sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS); - for (i = 0 ; i < 1000000 ; i++) { /* Should take up 1 second... */ - freq = get_tbl()-t1; - if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) - break; - } - - printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", - freq/1000000, freq%1000000); - tb_ticks_per_jiffy = freq / HZ; - tb_to_us = mulhwu_scale_factor(freq, 1000000); -} - -static void __prep -prep_restart(char *cmd) -{ - unsigned long i = 10000; - - __cli(); - - /* set exception prefix high - to the prom */ - _nmask_and_or_msr(0, MSR_IP); - - /* make sure bit 0 (reset) is a 0 */ - outb( inb(0x92) & ~1L , 0x92 ); - /* signal a reset to system control port A - soft reset */ - outb( inb(0x92) | 1 , 0x92 ); - - while ( i != 0 ) i++; - panic("restart failed\n"); -} - -static void __prep -prep_halt(void) -{ - unsigned long flags; - __cli(); - /* set exception prefix high - to the prom */ - save_flags( flags ); - restore_flags( flags|MSR_IP ); - - /* make sure bit 0 (reset) is a 0 */ - outb( inb(0x92) & ~1L , 0x92 ); - /* signal a reset to system control port A - soft reset */ - outb( inb(0x92) | 1 , 0x92 ); - - while ( 1 ) ; - /* - * Not reached - */ -} - -/* - * On IBM PReP's, power management is handled by a Signetics 87c750 behind the - * Utah component on the ISA bus. To access the 750 you must write a series of - * nibbles to port 0x82a (decoded by the Utah). This is described somewhat in - * the IBM Carolina Technical Specification. - * -Hollis - */ -static void __prep -utah_sig87c750_setbit(unsigned int bytenum, unsigned int bitnum, int value) -{ - /* - * byte1: 0 0 0 1 0 d a5 a4 - * byte2: 0 0 0 1 a3 a2 a1 a0 - * - * d = the bit's value, enabled or disabled - * (a5 a4 a3) = the byte number, minus 20 - * (a2 a1 a0) = the bit number - * - * example: set the 5th bit of byte 21 (21.5) - * a5 a4 a3 = 001 (byte 1) - * a2 a1 a0 = 101 (bit 5) - * - * byte1 = 0001 0100 (0x14) - * byte2 = 0001 1101 (0x1d) - */ - unsigned char byte1=0x10, byte2=0x10; - const unsigned int pm_reg_1=0x82a; /* ISA address */ - - /* the 750's '20.0' is accessed as '0.0' through Utah (which adds 20) */ - bytenum -= 20; - - byte1 |= (!!value) << 2; /* set d */ - byte1 |= (bytenum >> 1) & 0x3; /* set a5, a4 */ - - byte2 |= (bytenum & 0x1) << 3; /* set a3 */ - byte2 |= bitnum & 0x7; /* set a2, a1, a0 */ - - outb(byte1, pm_reg_1); /* first nibble */ - mb(); - udelay(100); /* important: let controller recover */ - - outb(byte2, pm_reg_1); /* second nibble */ - mb(); - udelay(100); /* important: let controller recover */ -} - -static void __prep -prep_power_off(void) -{ - if ( _prep_type == _PREP_IBM) { - /* tested on: - * Carolina's: 7248-43P, 6070 (PowerSeries 850) - * should work on: - * Carolina: 6050 (PowerSeries 830) - * 7043-140 (Tiger 1) - */ - unsigned long flags; - __cli(); - /* set exception prefix high - to the prom */ - save_flags( flags ); - restore_flags( flags|MSR_IP ); - - utah_sig87c750_setbit(21, 5, 1); /* set bit 21.5, "PMEXEC_OFF" */ - - while ( 1 ) ; - /* not reached */ - } else { - prep_halt(); - } -} - -static unsigned int __prep -prep_irq_cannonicalize(u_int irq) -{ - if (irq == 2) - { - return 9; - } - else - { - return irq; - } -} - -static int __prep -prep_get_irq(struct pt_regs *regs) -{ - return i8259_irq(smp_processor_id()); -} - -static void __init -prep_init_IRQ(void) -{ - int i; - - if (OpenPIC_Addr != NULL) - openpic_init(1, NUM_8259_INTERRUPTS, 0, -1); - for ( i = 0 ; i < NUM_8259_INTERRUPTS ; i++ ) - irq_desc[i].handler = &i8259_pic; - i8259_init(); -} - -#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) -/* - * IDE stuff. - */ -static int __prep -prep_ide_default_irq(ide_ioreg_t base) -{ - switch (base) { - case 0x1f0: return 13; - case 0x170: return 13; - case 0x1e8: return 11; - case 0x168: return 10; - case 0xfff0: return 14; /* MCP(N)750 ide0 */ - case 0xffe0: return 15; /* MCP(N)750 ide1 */ - default: return 0; - } -} - -static ide_ioreg_t __prep -prep_ide_default_io_base(int index) -{ - switch (index) { - case 0: return 0x1f0; - case 1: return 0x170; - case 2: return 0x1e8; - case 3: return 0x168; - default: - return 0; - } -} - -static int __prep -prep_ide_check_region(ide_ioreg_t from, unsigned int extent) -{ - return check_region(from, extent); -} - -static void __prep -prep_ide_request_region(ide_ioreg_t from, - unsigned int extent, - const char *name) -{ - request_region(from, extent, name); -} - -static void __prep -prep_ide_release_region(ide_ioreg_t from, - unsigned int extent) -{ - release_region(from, extent); -} - -static void __init -prep_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) -{ - ide_ioreg_t reg = data_port; - int i; - - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { - hw->io_ports[i] = reg; - reg += 1; - } - if (ctrl_port) { - hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; - } else { - hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206; - } - if (irq != NULL) - *irq = 0; -} -#endif - -#ifdef CONFIG_SMP -/* PReP (MTX) support */ -static int __init -smp_prep_probe(void) -{ - extern int mot_multi; - - if (mot_multi) { - openpic_request_IPIs(); - smp_hw_index[1] = 1; - return 2; - } - - return 1; -} - -static void __init -smp_prep_kick_cpu(int nr) -{ - *(unsigned long *)KERNELBASE = nr; - asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory"); - printk("CPU1 reset, waiting\n"); -} - -static void __init -smp_prep_setup_cpu(int cpu_nr) -{ - if (OpenPIC_Addr) - do_openpic_setup_cpu(); -} - -static struct smp_ops_t prep_smp_ops __prepdata = { - smp_openpic_message_pass, - smp_prep_probe, - smp_prep_kick_cpu, - smp_prep_setup_cpu, -}; -#endif /* CONFIG_SMP */ - -/* - * This finds the amount of physical ram and does necessary - * setup for prep. This is pretty architecture specific so - * this will likely stay separate from the pmac. - * -- Cort - */ -static unsigned long __init -prep_find_end_of_memory(void) -{ - unsigned long total = 0; - extern unsigned int boot_mem_size; - -#ifdef CONFIG_PREP_RESIDUAL - total = res->TotalMemory; -#endif - - if (total == 0 && boot_mem_size != 0) - total = boot_mem_size; - else if (total == 0) { - /* - * I need a way to probe the amount of memory if the residual - * data doesn't contain it. -- Cort - */ - total = 0x02000000; - printk(KERN_INFO "Ramsize from residual data was 0" - " -- defaulting to %ldM\n", total>>20); - } - - return (total); -} - -/* - * Setup the bat mappings we're going to load that cover - * the io areas. RAM was mapped by mapin_ram(). - * -- Cort - */ -static void __init -prep_map_io(void) -{ - io_block_mapping(0x80000000, PREP_ISA_IO_BASE, 0x10000000, _PAGE_IO); - io_block_mapping(0xf0000000, PREP_ISA_MEM_BASE, 0x08000000, _PAGE_IO); -} - -static void __init -prep_init2(void) -{ -#ifdef CONFIG_NVRAM - request_region(PREP_NVRAM_AS0, 0x8, "nvram"); -#endif - request_region(0x20,0x20,"pic1"); - request_region(0xa0,0x20,"pic2"); - request_region(0x00,0x20,"dma1"); - request_region(0x40,0x20,"timer"); - request_region(0x80,0x10,"dma page reg"); - request_region(0xc0,0x20,"dma2"); -} - -void __init -prep_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ -#ifdef CONFIG_PREP_RESIDUAL - /* make a copy of residual data */ - if ( r3 ) { - memcpy((void *)res,(void *)(r3+KERNELBASE), - sizeof(RESIDUAL)); - } -#endif - -#ifdef CONFIG_BLK_DEV_INITRD - if ( r4 ) - { - initrd_start = r4 + KERNELBASE; - initrd_end = r5 + KERNELBASE; - } -#endif /* CONFIG_BLK_DEV_INITRD */ - - /* Copy cmd_line parameters */ - if ( r6 ) - { - *(char *)(r7 + KERNELBASE) = 0; - strcpy(cmd_line, (char *)(r6 + KERNELBASE)); - } - - isa_io_base = PREP_ISA_IO_BASE; - isa_mem_base = PREP_ISA_MEM_BASE; - pci_dram_offset = PREP_PCI_DRAM_OFFSET; - ISA_DMA_THRESHOLD = 0x00ffffff; - DMA_MODE_READ = 0x44; - DMA_MODE_WRITE = 0x48; - - /* figure out what kind of prep workstation we are */ -#ifdef CONFIG_PREP_RESIDUAL - if ( res->ResidualLength != 0 ) - { - if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) ) - _prep_type = _PREP_IBM; - else - _prep_type = _PREP_Motorola; - } - else /* assume motorola if no residual (netboot?) */ -#endif - { - _prep_type = _PREP_Motorola; - } - - ppc_md.setup_arch = prep_setup_arch; - ppc_md.show_percpuinfo = prep_show_percpuinfo; - ppc_md.show_cpuinfo = prep_show_cpuinfo; - ppc_md.irq_cannonicalize = prep_irq_cannonicalize; - ppc_md.init_IRQ = prep_init_IRQ; - /* this gets changed later on if we have an OpenPIC -- Cort */ - ppc_md.get_irq = prep_get_irq; - ppc_md.init = prep_init2; - - ppc_md.restart = prep_restart; - ppc_md.power_off = prep_power_off; - ppc_md.halt = prep_halt; - - ppc_md.time_init = NULL; - if (_prep_type == _PREP_IBM) { - ppc_md.set_rtc_time = mc146818_set_rtc_time; - ppc_md.get_rtc_time = mc146818_get_rtc_time; - ppc_md.calibrate_decr = prep_calibrate_decr; - } else { - ppc_md.set_rtc_time = mk48t59_set_rtc_time; - ppc_md.get_rtc_time = mk48t59_get_rtc_time; - ppc_md.calibrate_decr = mk48t59_calibrate_decr; - ppc_md.time_init = mk48t59_init; - } - - ppc_md.find_end_of_memory = prep_find_end_of_memory; - ppc_md.setup_io_mappings = prep_map_io; - -#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) - ppc_ide_md.default_irq = prep_ide_default_irq; - ppc_ide_md.default_io_base = prep_ide_default_io_base; - ppc_ide_md.ide_check_region = prep_ide_check_region; - ppc_ide_md.ide_request_region = prep_ide_request_region; - ppc_ide_md.ide_release_region = prep_ide_release_region; - ppc_ide_md.ide_init_hwif = prep_ide_init_hwif_ports; -#endif - -#ifdef CONFIG_VT - ppc_md.kbd_setkeycode = pckbd_setkeycode; - ppc_md.kbd_getkeycode = pckbd_getkeycode; - ppc_md.kbd_translate = pckbd_translate; - ppc_md.kbd_unexpected_up = pckbd_unexpected_up; - ppc_md.kbd_leds = pckbd_leds; - ppc_md.kbd_init_hw = pckbd_init_hw; -#ifdef CONFIG_MAGIC_SYSRQ - ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate; - SYSRQ_KEY = 0x54; -#endif -#endif - -#ifdef CONFIG_SMP - ppc_md.smp_ops = &prep_smp_ops; -#endif /* CONFIG_SMP */ -} diff --git a/arch/ppc/kernel/prep_time.c b/arch/ppc/kernel/prep_time.c deleted file mode 100644 index 2e51b272ddf7..000000000000 --- a/arch/ppc/kernel/prep_time.c +++ /dev/null @@ -1,228 +0,0 @@ -/* - * BK Id: SCCS/s.prep_time.c 1.10 09/08/01 15:47:42 paulus - */ -/* - * linux/arch/i386/kernel/time.c - * - * Copyright (C) 1991, 1992, 1995 Linus Torvalds - * - * Adapted for PowerPC (PreP) by Gary Thomas - * Modified by Cort Dougan (cort@cs.nmt.edu) - * copied and modified from intel version - * - */ -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/param.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/interrupt.h> -#include <linux/time.h> -#include <linux/timex.h> -#include <linux/kernel_stat.h> -#include <linux/init.h> - -#include <asm/sections.h> -#include <asm/segment.h> -#include <asm/io.h> -#include <asm/processor.h> -#include <asm/machdep.h> -#include <asm/prep_nvram.h> -#include <asm/mk48t59.h> - -#include <asm/time.h> - -extern spinlock_t rtc_lock; - -/* - * The motorola uses the m48t18 rtc (includes DS1643) whose registers - * are at a higher end of nvram (1ff8-1fff) than the ibm mc146818 - * rtc (ds1386) which has regs at addr 0-d). The intel gets - * past this because the bios emulates the mc146818. - * - * Why in the world did they have to use different clocks? - * - * Right now things are hacked to check which machine we're on then - * use the appropriate macro. This is very very ugly and I should - * probably have a function that checks which machine we're on then - * does things correctly transparently or a function pointer which - * is setup at boot time to use the correct addresses. - * -- Cort - */ - -/* - * Set the hardware clock. -- Cort - */ -__prep -int mc146818_set_rtc_time(unsigned long nowtime) -{ - unsigned char save_control, save_freq_select; - struct rtc_time tm; - - spin_lock(&rtc_lock); - to_tm(nowtime, &tm); - - /* tell the clock it's being set */ - save_control = CMOS_READ(RTC_CONTROL); - - CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); - - /* stop and reset prescaler */ - save_freq_select = CMOS_READ(RTC_FREQ_SELECT); - - CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); - - tm.tm_year = (tm.tm_year - 1900) % 100; - if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { - BIN_TO_BCD(tm.tm_sec); - BIN_TO_BCD(tm.tm_min); - BIN_TO_BCD(tm.tm_hour); - BIN_TO_BCD(tm.tm_mon); - BIN_TO_BCD(tm.tm_mday); - BIN_TO_BCD(tm.tm_year); - } - CMOS_WRITE(tm.tm_sec, RTC_SECONDS); - CMOS_WRITE(tm.tm_min, RTC_MINUTES); - CMOS_WRITE(tm.tm_hour, RTC_HOURS); - CMOS_WRITE(tm.tm_mon, RTC_MONTH); - CMOS_WRITE(tm.tm_mday, RTC_DAY_OF_MONTH); - CMOS_WRITE(tm.tm_year, RTC_YEAR); - - /* The following flags have to be released exactly in this order, - * otherwise the DS12887 (popular MC146818A clone with integrated - * battery and quartz) will not reset the oscillator and will not - * update precisely 500 ms later. You won't find this mentioned in - * the Dallas Semiconductor data sheets, but who believes data - * sheets anyway ... -- Markus Kuhn - */ - CMOS_WRITE(save_control, RTC_CONTROL); - CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); - spin_unlock(&rtc_lock); - - return 0; -} - -__prep -unsigned long mc146818_get_rtc_time(void) -{ - unsigned int year, mon, day, hour, min, sec; - int uip, i; - - /* The Linux interpretation of the CMOS clock register contents: - * When the Update-In-Progress (UIP) flag goes from 1 to 0, the - * RTC registers show the second which has precisely just started. - * Let's hope other operating systems interpret the RTC the same way. - */ - - /* Since the UIP flag is set for about 2.2 ms and the clock - * is typically written with a precision of 1 jiffy, trying - * to obtain a precision better than a few milliseconds is - * an illusion. Only consistency is interesting, this also - * allows to use the routine for /dev/rtc without a potential - * 1 second kernel busy loop triggered by any reader of /dev/rtc. - */ - - for ( i = 0; i<1000000; i++) { - uip = CMOS_READ(RTC_FREQ_SELECT); - sec = CMOS_READ(RTC_SECONDS); - min = CMOS_READ(RTC_MINUTES); - hour = CMOS_READ(RTC_HOURS); - day = CMOS_READ(RTC_DAY_OF_MONTH); - mon = CMOS_READ(RTC_MONTH); - year = CMOS_READ(RTC_YEAR); - uip |= CMOS_READ(RTC_FREQ_SELECT); - if ((uip & RTC_UIP)==0) break; - } - - if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) - || RTC_ALWAYS_BCD) - { - BCD_TO_BIN(sec); - BCD_TO_BIN(min); - BCD_TO_BIN(hour); - BCD_TO_BIN(day); - BCD_TO_BIN(mon); - BCD_TO_BIN(year); - } - if ((year += 1900) < 1970) - year += 100; - return mktime(year, mon, day, hour, min, sec); -} - -__prep -int mk48t59_set_rtc_time(unsigned long nowtime) -{ - unsigned char save_control; - struct rtc_time tm; - - spin_lock(&rtc_lock); - to_tm(nowtime, &tm); - - /* tell the clock it's being written */ - save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA); - - ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, - (save_control | MK48T59_RTC_CA_WRITE)); - - tm.tm_year = (tm.tm_year - 1900) % 100; - BIN_TO_BCD(tm.tm_sec); - BIN_TO_BCD(tm.tm_min); - BIN_TO_BCD(tm.tm_hour); - BIN_TO_BCD(tm.tm_mon); - BIN_TO_BCD(tm.tm_mday); - BIN_TO_BCD(tm.tm_year); - - ppc_md.nvram_write_val(MK48T59_RTC_SECONDS, tm.tm_sec); - ppc_md.nvram_write_val(MK48T59_RTC_MINUTES, tm.tm_min); - ppc_md.nvram_write_val(MK48T59_RTC_HOURS, tm.tm_hour); - ppc_md.nvram_write_val(MK48T59_RTC_MONTH, tm.tm_mon); - ppc_md.nvram_write_val(MK48T59_RTC_DAY_OF_MONTH, tm.tm_mday); - ppc_md.nvram_write_val(MK48T59_RTC_YEAR, tm.tm_year); - - /* Turn off the write bit. */ - ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control); - spin_unlock(&rtc_lock); - - return 0; -} - -__prep -unsigned long mk48t59_get_rtc_time(void) -{ - unsigned char save_control; - unsigned int year, mon, day, hour, min, sec; - - /* Simple: freeze the clock, read it and allow updates again */ - save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA); - save_control &= ~MK48T59_RTC_CA_READ; - ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control); - - /* Set the register to read the value. */ - ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, - (save_control | MK48T59_RTC_CA_READ)); - - sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS); - min = ppc_md.nvram_read_val(MK48T59_RTC_MINUTES); - hour = ppc_md.nvram_read_val(MK48T59_RTC_HOURS); - day = ppc_md.nvram_read_val(MK48T59_RTC_DAY_OF_MONTH); - mon = ppc_md.nvram_read_val(MK48T59_RTC_MONTH); - year = ppc_md.nvram_read_val(MK48T59_RTC_YEAR); - - /* Let the time values change again. */ - ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control); - - BCD_TO_BIN(sec); - BCD_TO_BIN(min); - BCD_TO_BIN(hour); - BCD_TO_BIN(day); - BCD_TO_BIN(mon); - BCD_TO_BIN(year); - - year = year + 1900; - if (year < 1970) { - year += 100; - } - - return mktime(year, mon, day, hour, min, sec); -} diff --git a/arch/ppc/kernel/proc_rtas.c b/arch/ppc/kernel/proc_rtas.c deleted file mode 100644 index b893044fdb5d..000000000000 --- a/arch/ppc/kernel/proc_rtas.c +++ /dev/null @@ -1,787 +0,0 @@ -/* - * BK Id: SCCS/s.proc_rtas.c 1.5 05/17/01 18:14:22 cort - */ -/* - * arch/ppc/kernel/proc_rtas.c - * Copyright (C) 2000 Tilmann Bitterberg - * (tilmann@bitterberg.de) - * - * RTAS (Runtime Abstraction Services) stuff - * Intention is to provide a clean user interface - * to use the RTAS. - * - * TODO: - * Split off a header file and maybe move it to a different - * location. Write Documentation on what the /proc/rtas/ entries - * actually do. - */ - -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/proc_fs.h> -#include <linux/stat.h> -#include <linux/ctype.h> -#include <linux/time.h> -#include <linux/string.h> - -#include <asm/uaccess.h> -#include <asm/bitops.h> -#include <asm/processor.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/machdep.h> /* for ppc_md */ -#include <asm/time.h> - -/* Token for Sensors */ -#define KEY_SWITCH 0x0001 -#define ENCLOSURE_SWITCH 0x0002 -#define THERMAL_SENSOR 0x0003 -#define LID_STATUS 0x0004 -#define POWER_SOURCE 0x0005 -#define BATTERY_VOLTAGE 0x0006 -#define BATTERY_REMAINING 0x0007 -#define BATTERY_PERCENTAGE 0x0008 -#define EPOW_SENSOR 0x0009 -#define BATTERY_CYCLESTATE 0x000a -#define BATTERY_CHARGING 0x000b - -/* IBM specific sensors */ -#define IBM_SURVEILLANCE 0x2328 /* 9000 */ -#define IBM_FANRPM 0x2329 /* 9001 */ -#define IBM_VOLTAGE 0x232a /* 9002 */ -#define IBM_DRCONNECTOR 0x232b /* 9003 */ -#define IBM_POWERSUPPLY 0x232c /* 9004 */ -#define IBM_INTQUEUE 0x232d /* 9005 */ - -/* Status return values */ -#define SENSOR_CRITICAL_HIGH 13 -#define SENSOR_WARNING_HIGH 12 -#define SENSOR_NORMAL 11 -#define SENSOR_WARNING_LOW 10 -#define SENSOR_CRITICAL_LOW 9 -#define SENSOR_SUCCESS 0 -#define SENSOR_HW_ERROR -1 -#define SENSOR_BUSY -2 -#define SENSOR_NOT_EXIST -3 -#define SENSOR_DR_ENTITY -9000 - -/* Location Codes */ -#define LOC_SCSI_DEV_ADDR 'A' -#define LOC_SCSI_DEV_LOC 'B' -#define LOC_CPU 'C' -#define LOC_DISKETTE 'D' -#define LOC_ETHERNET 'E' -#define LOC_FAN 'F' -#define LOC_GRAPHICS 'G' -/* reserved / not used 'H' */ -#define LOC_IO_ADAPTER 'I' -/* reserved / not used 'J' */ -#define LOC_KEYBOARD 'K' -#define LOC_LCD 'L' -#define LOC_MEMORY 'M' -#define LOC_NV_MEMORY 'N' -#define LOC_MOUSE 'O' -#define LOC_PLANAR 'P' -#define LOC_OTHER_IO 'Q' -#define LOC_PARALLEL 'R' -#define LOC_SERIAL 'S' -#define LOC_DEAD_RING 'T' -#define LOC_RACKMOUNTED 'U' /* for _u_nit is rack mounted */ -#define LOC_VOLTAGE 'V' -#define LOC_SWITCH_ADAPTER 'W' -#define LOC_OTHER 'X' -#define LOC_FIRMWARE 'Y' -#define LOC_SCSI 'Z' - -/* Tokens for indicators */ -#define TONE_FREQUENCY 0x0001 /* 0 - 1000 (HZ)*/ -#define TONE_VOLUME 0x0002 /* 0 - 100 (%) */ -#define SYSTEM_POWER_STATE 0x0003 -#define WARNING_LIGHT 0x0004 -#define DISK_ACTIVITY_LIGHT 0x0005 -#define HEX_DISPLAY_UNIT 0x0006 -#define BATTERY_WARNING_TIME 0x0007 -#define CONDITION_CYCLE_REQUEST 0x0008 -#define SURVEILLANCE_INDICATOR 0x2328 /* 9000 */ -#define DR_ACTION 0x2329 /* 9001 */ -#define DR_INDICATOR 0x232a /* 9002 */ -/* 9003 - 9004: Vendor specific */ -#define GLOBAL_INTERRUPT_QUEUE 0x232d /* 9005 */ -/* 9006 - 9999: Vendor specific */ - -/* other */ -#define MAX_SENSORS 17 /* I only know of 17 sensors */ -#define MAX_LINELENGTH 256 -#define SENSOR_PREFIX "ibm,sensor-" -#define cel_to_fahr(x) ((x*9/5)+32) - - -/* Globals */ -static struct proc_dir_entry *proc_rtas; -static struct rtas_sensors sensors; -static struct device_node *rtas; -static unsigned long power_on_time = 0; /* Save the time the user set */ -static char progress_led[MAX_LINELENGTH]; - -static unsigned long rtas_tone_frequency = 1000; -static unsigned long rtas_tone_volume = 0; - -/* ****************STRUCTS******************************************* */ -struct individual_sensor { - unsigned int token; - unsigned int quant; -}; - -struct rtas_sensors { - struct individual_sensor sensor[MAX_SENSORS]; - unsigned int quant; -}; - -/* ****************************************************************** */ -/* Declarations */ -static int ppc_rtas_sensor_read(char * buf, char ** start, off_t off, - int count, int *eof, void *data); -static ssize_t ppc_rtas_clock_read(struct file * file, char * buf, - size_t count, loff_t *ppos); -static ssize_t ppc_rtas_clock_write(struct file * file, const char * buf, - size_t count, loff_t *ppos); -static ssize_t ppc_rtas_progress_read(struct file * file, char * buf, - size_t count, loff_t *ppos); -static ssize_t ppc_rtas_progress_write(struct file * file, const char * buf, - size_t count, loff_t *ppos); -static ssize_t ppc_rtas_poweron_read(struct file * file, char * buf, - size_t count, loff_t *ppos); -static ssize_t ppc_rtas_poweron_write(struct file * file, const char * buf, - size_t count, loff_t *ppos); - -static ssize_t ppc_rtas_tone_freq_write(struct file * file, const char * buf, - size_t count, loff_t *ppos); -static ssize_t ppc_rtas_tone_freq_read(struct file * file, char * buf, - size_t count, loff_t *ppos); -static ssize_t ppc_rtas_tone_volume_write(struct file * file, const char * buf, - size_t count, loff_t *ppos); -static ssize_t ppc_rtas_tone_volume_read(struct file * file, char * buf, - size_t count, loff_t *ppos); - -struct file_operations ppc_rtas_poweron_operations = { - read: ppc_rtas_poweron_read, - write: ppc_rtas_poweron_write -}; -struct file_operations ppc_rtas_progress_operations = { - read: ppc_rtas_progress_read, - write: ppc_rtas_progress_write -}; - -struct file_operations ppc_rtas_clock_operations = { - read: ppc_rtas_clock_read, - write: ppc_rtas_clock_write -}; - -struct file_operations ppc_rtas_tone_freq_operations = { - read: ppc_rtas_tone_freq_read, - write: ppc_rtas_tone_freq_write -}; -struct file_operations ppc_rtas_tone_volume_operations = { - read: ppc_rtas_tone_volume_read, - write: ppc_rtas_tone_volume_write -}; - -int ppc_rtas_find_all_sensors (void); -int ppc_rtas_process_sensor(struct individual_sensor s, int state, - int error, char * buf); -char * ppc_rtas_process_error(int error); -int get_location_code(struct individual_sensor s, char * buf); -int check_location_string (char *c, char * buf); -int check_location (char *c, int idx, char * buf); - -/* ****************************************************************** */ -/* MAIN */ -/* ****************************************************************** */ -void proc_rtas_init(void) -{ - struct proc_dir_entry *entry; - - rtas = find_devices("rtas"); - if ((rtas == 0) || (_machine != _MACH_chrp)) { - return; - } - - proc_rtas = proc_mkdir("rtas", 0); - if (proc_rtas == 0) - return; - - /* /proc/rtas entries */ - - entry = create_proc_entry("progress", S_IRUGO|S_IWUSR, proc_rtas); - if (entry) entry->proc_fops = &ppc_rtas_progress_operations; - - entry = create_proc_entry("clock", S_IRUGO|S_IWUSR, proc_rtas); - if (entry) entry->proc_fops = &ppc_rtas_clock_operations; - - entry = create_proc_entry("poweron", S_IWUSR|S_IRUGO, proc_rtas); - if (entry) entry->proc_fops = &ppc_rtas_poweron_operations; - - create_proc_read_entry("sensors", S_IRUGO, proc_rtas, - ppc_rtas_sensor_read, NULL); - - entry = create_proc_entry("frequency", S_IWUSR|S_IRUGO, proc_rtas); - if (entry) entry->proc_fops = &ppc_rtas_tone_freq_operations; - - entry = create_proc_entry("volume", S_IWUSR|S_IRUGO, proc_rtas); - if (entry) entry->proc_fops = &ppc_rtas_tone_volume_operations; -} - -/* ****************************************************************** */ -/* POWER-ON-TIME */ -/* ****************************************************************** */ -static ssize_t ppc_rtas_poweron_write(struct file * file, const char * buf, - size_t count, loff_t *ppos) -{ - struct rtc_time tm; - unsigned long nowtime; - char *dest; - int error; - - nowtime = simple_strtoul(buf, &dest, 10); - if (*dest != '\0' && *dest != '\n') { - printk("ppc_rtas_poweron_write: Invalid time\n"); - return count; - } - power_on_time = nowtime; /* save the time */ - - to_tm(nowtime, &tm); - - error = call_rtas("set-time-for-power-on", 7, 1, NULL, - tm.tm_year, tm.tm_mon, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec, 0 /* nano */); - if (error != 0) - printk(KERN_WARNING "error: setting poweron time returned: %s\n", - ppc_rtas_process_error(error)); - return count; -} -/* ****************************************************************** */ -static ssize_t ppc_rtas_poweron_read(struct file * file, char * buf, - size_t count, loff_t *ppos) -{ - int n; - if (power_on_time == 0) - n = sprintf(buf, "Power on time not set\n"); - else - n = sprintf(buf, "%lu\n", power_on_time); - - if (*ppos >= strlen(buf)) - return 0; - if (n > strlen(buf) - *ppos) - n = strlen(buf) - *ppos; - if (n > count) - n = count; - *ppos += n; - return n; -} - -/* ****************************************************************** */ -/* PROGRESS */ -/* ****************************************************************** */ -static ssize_t ppc_rtas_progress_write(struct file * file, const char * buf, - size_t count, loff_t *ppos) -{ - unsigned long hex; - - strcpy(progress_led, buf); /* save the string */ - /* Lets see if the user passed hexdigits */ - hex = simple_strtoul(buf, NULL, 10); - - ppc_md.progress ((char *)buf, hex); - return count; - - /* clear the line */ /* ppc_md.progress(" ", 0xffff);*/ -} -/* ****************************************************************** */ -static ssize_t ppc_rtas_progress_read(struct file * file, char * buf, - size_t count, loff_t *ppos) -{ - int n = 0; - if (progress_led != NULL) - n = sprintf (buf, "%s\n", progress_led); - if (*ppos >= strlen(buf)) - return 0; - if (n > strlen(buf) - *ppos) - n = strlen(buf) - *ppos; - if (n > count) - n = count; - *ppos += n; - return n; -} - -/* ****************************************************************** */ -/* CLOCK */ -/* ****************************************************************** */ -static ssize_t ppc_rtas_clock_write(struct file * file, const char * buf, - size_t count, loff_t *ppos) -{ - struct rtc_time tm; - unsigned long nowtime; - char *dest; - int error; - - nowtime = simple_strtoul(buf, &dest, 10); - if (*dest != '\0' && *dest != '\n') { - printk("ppc_rtas_clock_write: Invalid time\n"); - return count; - } - - to_tm(nowtime, &tm); - error = call_rtas("set-time-of-day", 7, 1, NULL, - tm.tm_year, tm.tm_mon, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec, 0); - if (error != 0) - printk(KERN_WARNING "error: setting the clock returned: %s\n", - ppc_rtas_process_error(error)); - return count; -} -/* ****************************************************************** */ -static ssize_t ppc_rtas_clock_read(struct file * file, char * buf, - size_t count, loff_t *ppos) -{ - unsigned int year, mon, day, hour, min, sec; - unsigned long *ret = kmalloc(4*8, GFP_KERNEL); - int n, error; - - error = call_rtas("get-time-of-day", 0, 8, ret); - - year = ret[0]; mon = ret[1]; day = ret[2]; - hour = ret[3]; min = ret[4]; sec = ret[5]; - - if (error != 0){ - printk(KERN_WARNING "error: reading the clock returned: %s\n", - ppc_rtas_process_error(error)); - n = sprintf (buf, "0"); - } else { - n = sprintf (buf, "%lu\n", mktime(year, mon, day, hour, min, sec)); - } - kfree(ret); - - if (*ppos >= strlen(buf)) - return 0; - if (n > strlen(buf) - *ppos) - n = strlen(buf) - *ppos; - if (n > count) - n = count; - *ppos += n; - return n; -} - -/* ****************************************************************** */ -/* SENSOR STUFF */ -/* ****************************************************************** */ -static int ppc_rtas_sensor_read(char * buf, char ** start, off_t off, - int count, int *eof, void *data) -{ - int i,j,n; - unsigned long ret; - int state, error; - char buffer[MAX_LINELENGTH*MAX_SENSORS]; /* May not be enough */ - - if (count < 0) - return -EINVAL; - - n = sprintf ( buffer , "RTAS (RunTime Abstraction Services) Sensor Information\n"); - n += sprintf ( buffer+n, "Sensor\t\tValue\t\tCondition\tLocation\n"); - n += sprintf ( buffer+n, "********************************************************\n"); - - if (ppc_rtas_find_all_sensors() != 0) { - n += sprintf ( buffer+n, "\nNo sensors are available\n"); - goto return_string; - } - - for (i=0; i<sensors.quant; i++) { - j = sensors.sensor[i].quant; - /* A sensor may have multiple instances */ - while (j >= 0) { - error = call_rtas("get-sensor-state", 2, 2, &ret, - sensors.sensor[i].token, sensors.sensor[i].quant-j); - state = (int) ret; - n += ppc_rtas_process_sensor(sensors.sensor[i], state, error, buffer+n ); - n += sprintf (buffer+n, "\n"); - j--; - } /* while */ - } /* for */ - -return_string: - if (off >= strlen(buffer)) { - *eof = 1; - return 0; - } - if (n > strlen(buffer) - off) - n = strlen(buffer) - off; - if (n > count) - n = count; - else - *eof = 1; - memcpy(buf, buffer + off, n); - *start = buf; - return n; -} - -/* ****************************************************************** */ - -int ppc_rtas_find_all_sensors (void) -{ - unsigned long *utmp; - int len, i, j; - - utmp = (unsigned long *) get_property(rtas, "rtas-sensors", &len); - if (utmp == NULL) { - printk (KERN_ERR "error: could not get rtas-sensors\n"); - return 1; - } - - sensors.quant = len / 8; /* int + int */ - - for (i=0, j=0; j<sensors.quant; i+=2, j++) { - sensors.sensor[j].token = utmp[i]; - sensors.sensor[j].quant = utmp[i+1]; - } - return 0; -} - -/* ****************************************************************** */ -/* - * Builds a string of what rtas returned - */ -char * ppc_rtas_process_error(int error) -{ - switch (error) { - case SENSOR_CRITICAL_HIGH: - return "(critical high)"; - case SENSOR_WARNING_HIGH: - return "(warning high)"; - case SENSOR_NORMAL: - return "(normal)"; - case SENSOR_WARNING_LOW: - return "(warning low)"; - case SENSOR_CRITICAL_LOW: - return "(critical low)"; - case SENSOR_SUCCESS: - return "(read ok)"; - case SENSOR_HW_ERROR: - return "(hardware error)"; - case SENSOR_BUSY: - return "(busy)"; - case SENSOR_NOT_EXIST: - return "(non existant)"; - case SENSOR_DR_ENTITY: - return "(dr entity removed)"; - default: - return "(UNKNOWN)"; - } -} - -/* ****************************************************************** */ -/* - * Builds a string out of what the sensor said - */ - -int ppc_rtas_process_sensor(struct individual_sensor s, int state, - int error, char * buf) -{ - /* Defined return vales */ - const char * key_switch[] = { "Off\t", "Normal\t", "Secure\t", "Mainenance" }; - const char * enclosure_switch[] = { "Closed", "Open" }; - const char * lid_status[] = { " ", "Open", "Closed" }; - const char * power_source[] = { "AC\t", "Battery", "AC & Battery" }; - const char * battery_remaining[] = { "Very Low", "Low", "Mid", "High" }; - const char * epow_sensor[] = { - "EPOW Reset", "Cooling warning", "Power warning", - "System shutdown", "System halt", "EPOW main enclosure", - "EPOW power off" }; - const char * battery_cyclestate[] = { "None", "In progress", "Requested" }; - const char * battery_charging[] = { "Charging", "Discharching", "No current flow" }; - const char * ibm_drconnector[] = { "Empty", "Present" }; - const char * ibm_intqueue[] = { "Disabled", "Enabled" }; - - int have_strings = 0; - int temperature = 0; - int unknown = 0; - int n = 0; - - /* What kind of sensor do we have here? */ - switch (s.token) { - case KEY_SWITCH: - n += sprintf(buf+n, "Key switch:\t"); - n += sprintf(buf+n, "%s\t", key_switch[state]); - have_strings = 1; - break; - case ENCLOSURE_SWITCH: - n += sprintf(buf+n, "Enclosure switch:\t"); - n += sprintf(buf+n, "%s\t", enclosure_switch[state]); - have_strings = 1; - break; - case THERMAL_SENSOR: - n += sprintf(buf+n, "Temp. (°C/°F):\t"); - temperature = 1; - break; - case LID_STATUS: - n += sprintf(buf+n, "Lid status:\t"); - n += sprintf(buf+n, "%s\t", lid_status[state]); - have_strings = 1; - break; - case POWER_SOURCE: - n += sprintf(buf+n, "Power source:\t"); - n += sprintf(buf+n, "%s\t", power_source[state]); - have_strings = 1; - break; - case BATTERY_VOLTAGE: - n += sprintf(buf+n, "Battery voltage:\t"); - break; - case BATTERY_REMAINING: - n += sprintf(buf+n, "Battery remaining:\t"); - n += sprintf(buf+n, "%s\t", battery_remaining[state]); - have_strings = 1; - break; - case BATTERY_PERCENTAGE: - n += sprintf(buf+n, "Battery percentage:\t"); - break; - case EPOW_SENSOR: - n += sprintf(buf+n, "EPOW Sensor:\t"); - n += sprintf(buf+n, "%s\t", epow_sensor[state]); - have_strings = 1; - break; - case BATTERY_CYCLESTATE: - n += sprintf(buf+n, "Battery cyclestate:\t"); - n += sprintf(buf+n, "%s\t", battery_cyclestate[state]); - have_strings = 1; - break; - case BATTERY_CHARGING: - n += sprintf(buf+n, "Battery Charging:\t"); - n += sprintf(buf+n, "%s\t", battery_charging[state]); - have_strings = 1; - break; - case IBM_SURVEILLANCE: - n += sprintf(buf+n, "Surveillance:\t"); - break; - case IBM_FANRPM: - n += sprintf(buf+n, "Fan (rpm):\t"); - break; - case IBM_VOLTAGE: - n += sprintf(buf+n, "Voltage (mv):\t"); - break; - case IBM_DRCONNECTOR: - n += sprintf(buf+n, "DR connector:\t"); - n += sprintf(buf+n, "%s\t", ibm_drconnector[state]); - have_strings = 1; - break; - case IBM_POWERSUPPLY: - n += sprintf(buf+n, "Powersupply:\t"); - break; - case IBM_INTQUEUE: - n += sprintf(buf+n, "Interrupt queue:\t"); - n += sprintf(buf+n, "%s\t", ibm_intqueue[state]); - have_strings = 1; - break; - default: - n += sprintf(buf+n, "Unkown sensor (type %d), ignoring it\n", - s.token); - unknown = 1; - have_strings = 1; - break; - } - if (have_strings == 0) { - if (temperature) { - n += sprintf(buf+n, "%4d /%4d\t", state, cel_to_fahr(state)); - } else - n += sprintf(buf+n, "%10d\t", state); - } - if (unknown == 0) { - n += sprintf ( buf+n, "%s\t", ppc_rtas_process_error(error)); - n += get_location_code(s, buf+n); - } - return n; -} - -/* ****************************************************************** */ - -int check_location (char *c, int idx, char * buf) -{ - int n = 0; - - switch (*(c+idx)) { - case LOC_PLANAR: - n += sprintf ( buf, "Planar #%c", *(c+idx+1)); - break; - case LOC_CPU: - n += sprintf ( buf, "CPU #%c", *(c+idx+1)); - break; - case LOC_FAN: - n += sprintf ( buf, "Fan #%c", *(c+idx+1)); - break; - case LOC_RACKMOUNTED: - n += sprintf ( buf, "Rack #%c", *(c+idx+1)); - break; - case LOC_VOLTAGE: - n += sprintf ( buf, "Voltage #%c", *(c+idx+1)); - break; - case LOC_LCD: - n += sprintf ( buf, "LCD #%c", *(c+idx+1)); - break; - case '.': - n += sprintf ( buf, "- %c", *(c+idx+1)); - default: - n += sprintf ( buf, "Unknown location"); - break; - } - return n; -} - - -/* ****************************************************************** */ -/* - * Format: - * ${LETTER}${NUMBER}[[-/]${LETTER}${NUMBER} [ ... ] ] - * the '.' may be an abbrevation - */ -int check_location_string (char *c, char *buf) -{ - int n=0,i=0; - - while (c[i]) { - if (isalpha(c[i]) || c[i] == '.') { - n += check_location(c, i, buf+n); - } - else if (c[i] == '/' || c[i] == '-') - n += sprintf(buf+n, " at "); - i++; - } - return n; -} - - -/* ****************************************************************** */ - -int get_location_code(struct individual_sensor s, char * buffer) -{ - char rstr[512], tmp[10], tmp2[10]; - int n=0, i=0, llen, len; - /* char *buf = kmalloc(MAX_LINELENGTH, GFP_KERNEL); */ - char *ret; - - static int pos = 0; /* remember position where buffer was */ - - /* construct the sensor number like 0003 */ - /* fill with zeros */ - n = sprintf(tmp, "%d", s.token); - len = strlen(tmp); - while (strlen(tmp) < 4) - n += sprintf (tmp+n, "0"); - - /* invert the string */ - while (tmp[i]) { - if (i<len) - tmp2[4-len+i] = tmp[i]; - else - tmp2[3-i] = tmp[i]; - i++; - } - tmp2[4] = '\0'; - - sprintf (rstr, SENSOR_PREFIX"%s", tmp2); - - ret = (char *) get_property(rtas, rstr, &llen); - - n=0; - if (ret[0] == '\0') - n += sprintf ( buffer+n, "--- ");/* does not have a location */ - else { - char t[50]; - ret += pos; - - n += check_location_string(ret, buffer + n); - n += sprintf ( buffer+n, " "); - /* see how many characters we have printed */ - sprintf ( t, "%s ", ret); - - pos += strlen(t); - if (pos >= llen) pos=0; - } - return n; -} -/* ****************************************************************** */ -/* INDICATORS - Tone Frequency */ -/* ****************************************************************** */ -static ssize_t ppc_rtas_tone_freq_write(struct file * file, const char * buf, - size_t count, loff_t *ppos) -{ - unsigned long freq; - char *dest; - int error; - freq = simple_strtoul(buf, &dest, 10); - if (*dest != '\0' && *dest != '\n') { - printk("ppc_rtas_tone_freq_write: Invalid tone freqency\n"); - return count; - } - if (freq < 0) freq = 0; - rtas_tone_frequency = freq; /* save it for later */ - error = call_rtas("set-indicator", 3, 1, NULL, - TONE_FREQUENCY, 0, freq); - if (error != 0) - printk(KERN_WARNING "error: setting tone frequency returned: %s\n", - ppc_rtas_process_error(error)); - return count; -} -/* ****************************************************************** */ -static ssize_t ppc_rtas_tone_freq_read(struct file * file, char * buf, - size_t count, loff_t *ppos) -{ - int n; - n = sprintf(buf, "%lu\n", rtas_tone_frequency); - - if (*ppos >= strlen(buf)) - return 0; - if (n > strlen(buf) - *ppos) - n = strlen(buf) - *ppos; - if (n > count) - n = count; - *ppos += n; - return n; -} -/* ****************************************************************** */ -/* INDICATORS - Tone Volume */ -/* ****************************************************************** */ -static ssize_t ppc_rtas_tone_volume_write(struct file * file, const char * buf, - size_t count, loff_t *ppos) -{ - unsigned long volume; - char *dest; - int error; - volume = simple_strtoul(buf, &dest, 10); - if (*dest != '\0' && *dest != '\n') { - printk("ppc_rtas_tone_volume_write: Invalid tone volume\n"); - return count; - } - if (volume < 0) volume = 0; - if (volume > 100) volume = 100; - - rtas_tone_volume = volume; /* save it for later */ - error = call_rtas("set-indicator", 3, 1, NULL, - TONE_VOLUME, 0, volume); - if (error != 0) - printk(KERN_WARNING "error: setting tone volume returned: %s\n", - ppc_rtas_process_error(error)); - return count; -} -/* ****************************************************************** */ -static ssize_t ppc_rtas_tone_volume_read(struct file * file, char * buf, - size_t count, loff_t *ppos) -{ - int n; - n = sprintf(buf, "%lu\n", rtas_tone_volume); - - if (*ppos >= strlen(buf)) - return 0; - if (n > strlen(buf) - *ppos) - n = strlen(buf) - *ppos; - if (n > count) - n = count; - *ppos += n; - return n; -} diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c index eca832613eb8..9a00a0efb999 100644 --- a/arch/ppc/kernel/process.c +++ b/arch/ppc/kernel/process.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.process.c 1.31 10/02/01 09:51:41 paulus + * BK Id: %F% %I% %G% %U% %#% */ /* * linux/arch/ppc/kernel/process.c @@ -34,6 +34,8 @@ #include <linux/user.h> #include <linux/elf.h> #include <linux/init.h> +#include <linux/prctl.h> +#include <linux/init_task.h> #include <asm/pgtable.h> #include <asm/uaccess.h> @@ -42,20 +44,26 @@ #include <asm/processor.h> #include <asm/mmu.h> #include <asm/prom.h> +#ifdef CONFIG_PPC_ISERIES +#include <asm/iSeries/Paca.h> +#endif int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs); extern unsigned long _get_SP(void); struct task_struct *last_task_used_math = NULL; struct task_struct *last_task_used_altivec = NULL; + static struct fs_struct init_fs = INIT_FS; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM(init_mm); + /* this is 16-byte aligned because it has a stack in it */ union task_union __attribute((aligned(16))) init_task_union = { INIT_TASK(init_task_union.task) }; + /* only used to get secondary processor up */ struct task_struct *current_set[NR_CPUS] = {&init_task, }; @@ -260,7 +268,7 @@ void show_regs(struct pt_regs * regs) printk("\nlast math %p last altivec %p", last_task_used_math, last_task_used_altivec); -#ifdef CONFIG_4xx +#if defined(CONFIG_4xx) && defined(DCRN_PLB0_BEAR) printk("\nPLB0: bear= 0x%8.8x acr= 0x%8.8x besr= 0x%8.8x\n", mfdcr(DCRN_POB0_BEAR), mfdcr(DCRN_PLB0_ACR), mfdcr(DCRN_PLB0_BESR)); @@ -336,9 +344,10 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp, /* for kernel thread, set `current' and stackptr in new task */ childregs->gpr[1] = sp + sizeof(struct pt_regs); childregs->gpr[2] = (unsigned long) p; - } + p->thread.regs = NULL; /* no user register state */ + } else + p->thread.regs = childregs; childregs->gpr[3] = 0; /* Result from fork() */ - p->thread.regs = childregs; sp -= STACK_FRAME_OVERHEAD; childframe = sp; @@ -355,6 +364,9 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp, sp -= STACK_FRAME_OVERHEAD; p->thread.ksp = sp; kregs->nip = (unsigned long)ret_from_fork; +#ifdef CONFIG_PPC_ISERIES + kregs->softEnable = ((struct Paca *)mfspr(SPRG1))->xProcEnabled; +#endif /* * copy fpu info - assume lazy fpu switch now always @@ -391,7 +403,10 @@ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp) { set_fs(USER_DS); memset(regs->gpr, 0, sizeof(regs->gpr)); - memset(®s->ctr, 0, 5 * sizeof(regs->ctr)); + regs->ctr = 0; + regs->link = 0; + regs->xer = 0; + regs->ccr = 0; regs->nip = nip; regs->gpr[1] = sp; regs->msr = MSR_USER; @@ -399,8 +414,29 @@ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp) last_task_used_math = 0; if (last_task_used_altivec == current) last_task_used_altivec = 0; + memset(current->thread.fpr, 0, sizeof(current->thread.fpr)); current->thread.fpscr = 0; +#ifdef CONFIG_ALTIVEC + memset(current->thread.vr, 0, sizeof(current->thread.vr)); + memset(¤t->thread.vscr, 0, sizeof(current->thread.vscr)); + current->thread.vrsave = 0; +#endif /* CONFIG_ALTIVEC */ +} + +#if 0 +int set_fpexc_mode(struct task_struct *tsk, unsigned int val) +{ + struct pt_regs *regs = tsk->thread.regs; + + if (val > PR_FP_EXC_PRECISE) + return -EINVAL; + tsk->thread.fpexc_mode = __pack_fe01(val); + if (regs != NULL && (regs->msr & MSR_FP) != 0) + regs->msr = (regs->msr & ~(MSR_FE0|MSR_FE1)) + | tsk->thread.fpexc_mode; + return 0; } +#endif int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, struct pt_regs *regs) @@ -465,6 +501,27 @@ print_backtrace(unsigned long *sp) printk("\n"); } +void show_trace_task(struct task_struct *tsk) +{ + unsigned long stack_top = (unsigned long) tsk + THREAD_SIZE; + unsigned long sp, prev_sp; + int count = 0; + + if (tsk == NULL) + return; + sp = (unsigned long) &tsk->thread.ksp; + do { + prev_sp = sp; + sp = *(unsigned long *)sp; + if (sp <= prev_sp || sp >= stack_top || (sp & 3) != 0) + break; + if (count > 0) + printk("[%08lx] ", *(unsigned long *)(sp + 4)); + } while (++count < 16); + if (count > 1) + printk("\n"); +} + #if 0 /* * Low level print for debugging - Cort diff --git a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c index f0daf9d5f54a..f9c94da5cd2f 100644 --- a/arch/ppc/kernel/prom.c +++ b/arch/ppc/kernel/prom.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.prom.c 1.42 09/08/01 15:47:42 paulus + * BK Id: %F% %I% %G% %U% %#% */ /* * Procedures for interfacing to the Open Firmware PROM on @@ -19,6 +19,9 @@ #include <linux/version.h> #include <linux/threads.h> #include <linux/spinlock.h> +#include <linux/ioport.h> +#include <linux/pci.h> +#include <linux/slab.h> #include <asm/sections.h> #include <asm/prom.h> @@ -34,28 +37,13 @@ #include <asm/bitops.h> #include <asm/bootinfo.h> #include <asm/btext.h> -#include "open_pic.h" +#include <asm/pci-bridge.h> +#include <asm/open_pic.h> #ifdef CONFIG_FB #include <asm/linux_logo.h> #endif -/* - * Properties whose value is longer than this get excluded from our - * copy of the device tree. This way we don't waste space storing - * things like "driver,AAPL,MacOS,PowerPC" properties. But this value - * does need to be big enough to ensure that we don't lose things - * like the interrupt-map property on a PCI-PCI bridge. - */ -#define MAX_PROPERTY_LENGTH 4096 - -struct prom_args { - const char *service; - int nargs; - int nret; - void *args[10]; -}; - struct pci_address { unsigned a_hi; unsigned a_mid; @@ -68,26 +56,12 @@ struct pci_reg_property { unsigned size_lo; }; -struct pci_range { - struct pci_address addr; - unsigned phys; - unsigned size_hi; - unsigned size_lo; -}; - struct isa_reg_property { unsigned space; unsigned address; 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, int, int); static interpret_func interpret_pci_props; @@ -96,27 +70,7 @@ 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, }; -phandle prom_display_nodes[FB_MAX] __initdata; -unsigned int prom_num_displays __initdata = 0; -char *of_stdout_device __initdata = 0; -ihandle prom_disp_node __initdata = 0; - -prom_entry prom __initdata = 0; -ihandle prom_chosen __initdata = 0; -ihandle prom_stdout __initdata = 0; - extern char *klimit; -char *bootpath; -char *bootdevice; - -unsigned int rtas_data; /* physical pointer */ -unsigned int rtas_entry; /* physical pointer */ -unsigned int rtas_size; -unsigned int old_rtas; /* Set for a newworld or CHRP machine */ int use_of_interrupt_tree; @@ -125,553 +79,30 @@ int num_interrupt_controllers; int pmac_newworld; -static struct device_node *allnodes; +extern unsigned int rtas_entry; /* physical pointer */ + +extern struct device_node *allnodes; -static void *call_prom(const char *service, int nargs, int nret, ...); -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 *, int, int); static unsigned long finish_node_interrupts(struct device_node *, unsigned long); -static unsigned long check_display(unsigned long); -static int prom_next_node(phandle *); -static void *early_get_property(unsigned long, unsigned long, char *); static struct device_node *find_phandle(phandle); -#ifdef CONFIG_BOOTX_TEXT -static void setup_disp_fake_bi(ihandle dp); -#endif - extern void enter_rtas(void *); void phys_call_rtas(int, int, int, ...); extern char cmd_line[512]; /* XXX */ -boot_infos_t *boot_infos; +extern boot_infos_t *boot_infos; unsigned long dev_tree_size; -#define ALIGN(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long)) - -/* Is boot-info compatible ? */ -#define BOOT_INFO_IS_COMPATIBLE(bi) ((bi)->compatible_version <= BOOT_INFO_VERSION) -#define BOOT_INFO_IS_V2_COMPATIBLE(bi) ((bi)->version >= 2) -#define BOOT_INFO_IS_V4_COMPATIBLE(bi) ((bi)->version >= 4) - -/* - * Note that prom_init() and anything called from prom_init() must - * use the RELOC/PTRRELOC macros to access any static data in - * memory, since the kernel may be running at an address that is - * different from the address that it was linked at. - * (Note that strings count as static variables.) - */ - -static void __init -prom_exit() -{ - struct prom_args args; - unsigned long offset = reloc_offset(); - - args.service = "exit"; - args.nargs = 0; - args.nret = 0; - RELOC(prom)(&args); - for (;;) /* should never get here */ - ; -} - -void __init -prom_enter(void) -{ - struct prom_args args; - unsigned long offset = reloc_offset(); - - args.service = RELOC("enter"); - args.nargs = 0; - args.nret = 0; - RELOC(prom)(&args); -} - -static void * __init -call_prom(const char *service, int nargs, int nret, ...) -{ - va_list list; - int i; - unsigned long offset = reloc_offset(); - struct prom_args prom_args; - - prom_args.service = service; - prom_args.nargs = nargs; - prom_args.nret = nret; - va_start(list, nret); - for (i = 0; i < nargs; ++i) - prom_args.args[i] = va_arg(list, void *); - va_end(list); - for (i = 0; i < nret; ++i) - prom_args.args[i + nargs] = 0; - RELOC(prom)(&prom_args); - return prom_args.args[nargs]; -} - -void __init -prom_print(const char *msg) -{ - const char *p, *q; - unsigned long offset = reloc_offset(); - - if (RELOC(prom_stdout) == 0) - return; - - for (p = msg; *p != 0; p = q) { - for (q = p; *q != 0 && *q != '\n'; ++q) - ; - if (q > p) - call_prom(RELOC("write"), 3, 1, RELOC(prom_stdout), - p, q - p); - if (*q != 0) { - ++q; - call_prom(RELOC("write"), 3, 1, RELOC(prom_stdout), - RELOC("\r\n"), 2); - } - } -} - -static void __init -prom_print_hex(unsigned int v) -{ - char buf[16]; - int i, c; - - for (i = 0; i < 8; ++i) { - c = (v >> ((7-i)*4)) & 0xf; - c += (c >= 10)? ('a' - 10): '0'; - buf[i] = c; - } - buf[i] = ' '; - buf[i+1] = 0; - prom_print(buf); -} - -unsigned long smp_chrp_cpu_nr __initdata = 0; - -#ifdef CONFIG_SMP -/* - * With CHRP SMP we need to use the OF to start the other - * processors so we can't wait until smp_boot_cpus (the OF is - * trashed by then) so we have to put the processors into - * a holding pattern controlled by the kernel (not OF) before - * we destroy the OF. - * - * This uses a chunk of high memory, puts some holding pattern - * code there and sends the other processors off to there until - * smp_boot_cpus tells them to do something. We do that by using - * physical address 0x0. The holding pattern checks that address - * until its cpu # is there, when it is that cpu jumps to - * __secondary_start(). smp_boot_cpus() takes care of setting those - * values. - * - * We also use physical address 0x4 here to tell when a cpu - * is in its holding pattern code. - * - * -- Cort - */ -static void __init -prom_hold_cpus(unsigned long mem) -{ - extern void __secondary_hold(void); - unsigned long i; - int cpu; - phandle node; - unsigned long offset = reloc_offset(); - char type[16], *path; - unsigned int reg; - - /* - * XXX: hack to make sure we're chrp, assume that if we're - * chrp we have a device_type property -- Cort - */ - node = call_prom(RELOC("finddevice"), 1, 1, RELOC("/")); - if ( (int)call_prom(RELOC("getprop"), 4, 1, node, - RELOC("device_type"),type, sizeof(type)) <= 0) - return; - - /* copy the holding pattern code to someplace safe (0) */ - /* the holding pattern is now within the first 0x100 - bytes of the kernel image -- paulus */ - memcpy((void *)0, (void *)(KERNELBASE + offset), 0x100); - flush_icache_range(0, 0x100); - - /* look for cpus */ - *(unsigned long *)(0x0) = 0; - asm volatile("dcbf 0,%0": : "r" (0) : "memory"); - for (node = 0; prom_next_node(&node); ) { - type[0] = 0; - call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"), - type, sizeof(type)); - if (strcmp(type, RELOC("cpu")) != 0) - continue; - path = (char *) mem; - memset(path, 0, 256); - if ((int) call_prom(RELOC("package-to-path"), 3, 1, - node, path, 255) < 0) - continue; - reg = -1; - call_prom(RELOC("getprop"), 4, 1, node, RELOC("reg"), - ®, sizeof(reg)); - cpu = RELOC(smp_chrp_cpu_nr)++; - RELOC(smp_hw_index)[cpu] = reg; - /* XXX: hack - don't start cpu 0, this cpu -- Cort */ - if (cpu == 0) - continue; - prom_print(RELOC("starting cpu ")); - prom_print(path); - *(ulong *)(0x4) = 0; - call_prom(RELOC("start-cpu"), 3, 0, node, - __pa(__secondary_hold), cpu); - prom_print(RELOC("...")); - for ( i = 0 ; (i < 10000) && (*(ulong *)(0x4) == 0); i++ ) - ; - if (*(ulong *)(0x4) == cpu) - prom_print(RELOC("ok\n")); - else { - prom_print(RELOC("failed: ")); - prom_print_hex(*(ulong *)0x4); - prom_print(RELOC("\n")); - } - } -} -#endif /* CONFIG_SMP */ - -void __init -bootx_init(unsigned long r4, unsigned long phys) -{ - boot_infos_t *bi = (boot_infos_t *) r4; - unsigned long space; - unsigned long ptr, x; - char *model; - unsigned long offset = reloc_offset(); - - RELOC(boot_infos) = PTRUNRELOC(bi); - if (!BOOT_INFO_IS_V2_COMPATIBLE(bi)) - bi->logicalDisplayBase = 0; - -#ifdef CONFIG_BOOTX_TEXT - btext_init(bi); - - /* - * Test if boot-info is compatible. Done only in config - * CONFIG_BOOTX_TEXT since there is nothing much we can do - * with an incompatible version, except display a message - * and eventually hang the processor... - * - * I'll try to keep enough of boot-info compatible in the - * future to always allow display of this message; - */ - if (!BOOT_INFO_IS_COMPATIBLE(bi)) { - btext_drawstring(RELOC(" !!! WARNING - Incompatible version of BootX !!!\n\n\n")); - btext_flushscreen(); - } -#endif /* CONFIG_BOOTX_TEXT */ - - /* New BootX enters kernel with MMU off, i/os are not allowed - here. This hack will have been done by the boostrap anyway. - */ - if (bi->version < 4) { - /* - * 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 - || strcmp(model, RELOC("PowerMac1,1")) == 0)) { - out_le32((unsigned *)0x80880008, 1); /* XXX */ - } - } - - /* Move klimit to enclose device tree, args, ramdisk, etc... */ - if (bi->version < 5) { - space = bi->deviceTreeOffset + bi->deviceTreeSize; - if (bi->ramDisk) - space = bi->ramDisk + bi->ramDiskSize; - } else - space = bi->totalParamsSize; - RELOC(klimit) = PTRUNRELOC((char *) bi + space); - - /* New BootX will have flushed all TLBs and enters kernel with - MMU switched OFF, so this should not be useful anymore. - */ - if (bi->version < 4) { - /* - * 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; - } - -#ifdef CONFIG_BOOTX_TEXT - /* - * Note that after we call prepare_disp_BAT, we can't do - * prom_draw*, flushscreen or clearscreen until we turn the MMU - * on, since prepare_disp_BAT sets disp_bi->logicalDisplayBase - * to a virtual address. - */ - btext_prepare_BAT(); -#endif -} - -#ifdef CONFIG_PPC64BRIDGE -/* - * Set up a hash table with a set of entries in it to map the - * first 64MB of RAM. This is used on 64-bit machines since - * some of them don't have BATs. - * We assume the PTE will fit in the primary PTEG. - */ - -static inline void make_pte(unsigned long htab, unsigned int hsize, - unsigned int va, unsigned int pa, int mode) -{ - unsigned int *pteg; - unsigned int hash, i, vsid; - - vsid = ((va >> 28) * 0x111) << 12; - hash = ((va ^ vsid) >> 5) & 0x7fff80; - pteg = (unsigned int *)(htab + (hash & (hsize - 1))); - for (i = 0; i < 8; ++i, pteg += 4) { - if ((pteg[1] & 1) == 0) { - pteg[1] = vsid | ((va >> 16) & 0xf80) | 1; - pteg[3] = pa | mode; - break; - } - } -} - -extern unsigned long _SDR1; -extern PTE *Hash; -extern unsigned long Hash_size; - -static void __init -prom_alloc_htab(void) -{ - unsigned int hsize; - unsigned long htab; - unsigned int addr; - unsigned long offset = reloc_offset(); - - /* - * Because of OF bugs we can't use the "claim" client - * interface to allocate memory for the hash table. - * This code is only used on 64-bit PPCs, and the only - * 64-bit PPCs at the moment are RS/6000s, and their - * OF is based at 0xc00000 (the 12M point), so we just - * arbitrarily use the 0x800000 - 0xc00000 region for the - * hash table. - * -- paulus. - */ -#ifdef CONFIG_POWER4 - hsize = 4 << 20; /* POWER4 has no BATs */ -#else - hsize = 2 << 20; -#endif /* CONFIG_POWER4 */ - htab = (8 << 20); - RELOC(Hash) = (void *)(htab + KERNELBASE); - RELOC(Hash_size) = hsize; - RELOC(_SDR1) = htab + __ilog2(hsize) - 18; - - /* - * Put in PTEs for the first 64MB of RAM - */ - cacheable_memzero((void *)htab, hsize); - for (addr = 0; addr < 0x4000000; addr += 0x1000) - make_pte(htab, hsize, addr + KERNELBASE, addr, - _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX); -} -#endif /* CONFIG_PPC64BRIDGE */ - -static void __init -prom_instantiate_rtas(void) -{ - ihandle prom_rtas; - unsigned int i; - struct prom_args prom_args; - unsigned long offset = reloc_offset(); - - prom_rtas = call_prom(RELOC("finddevice"), 1, 1, RELOC("/rtas")); - if (prom_rtas == (void *) -1) - return; - - RELOC(rtas_size) = 0; - call_prom(RELOC("getprop"), 4, 1, prom_rtas, - RELOC("rtas-size"), &RELOC(rtas_size), sizeof(rtas_size)); - prom_print(RELOC("instantiating rtas")); - if (RELOC(rtas_size) == 0) { - RELOC(rtas_data) = 0; - } else { - /* - * Ask OF for some space for RTAS. - * Actually OF has bugs so we just arbitrarily - * use memory at the 6MB point. - */ - RELOC(rtas_data) = 6 << 20; - prom_print(RELOC(" at ")); - prom_print_hex(RELOC(rtas_data)); - } - - prom_rtas = call_prom(RELOC("open"), 1, 1, RELOC("/rtas")); - prom_print(RELOC("...")); - prom_args.service = RELOC("call-method"); - prom_args.nargs = 3; - prom_args.nret = 2; - prom_args.args[0] = RELOC("instantiate-rtas"); - prom_args.args[1] = prom_rtas; - prom_args.args[2] = (void *) RELOC(rtas_data); - RELOC(prom)(&prom_args); - i = 0; - if (prom_args.args[3] == 0) - i = (unsigned int)prom_args.args[4]; - RELOC(rtas_entry) = i; - if ((RELOC(rtas_entry) == -1) || (RELOC(rtas_entry) == 0)) - prom_print(RELOC(" failed\n")); - else - prom_print(RELOC(" done\n")); -} - -/* - * We enter here early on, when the Open Firmware prom is still - * handling exceptions and the MMU hash table for us. - */ -unsigned long __init -prom_init(int r3, int r4, prom_entry pp) -{ - unsigned long mem; - ihandle prom_mmu; - unsigned long offset = reloc_offset(); - int l; - char *p, *d; - unsigned long phys; - - /* Default */ - phys = offset + KERNELBASE; - - /* First get a handle for the stdout device */ - RELOC(prom) = pp; - RELOC(prom_chosen) = call_prom(RELOC("finddevice"), 1, 1, - RELOC("/chosen")); - if (RELOC(prom_chosen) == (void *)-1) - prom_exit(); - if ((int) call_prom(RELOC("getprop"), 4, 1, RELOC(prom_chosen), - RELOC("stdout"), &RELOC(prom_stdout), - sizeof(prom_stdout)) <= 0) - prom_exit(); - - /* 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) { - p[l] = 0; /* should already be null-terminated */ - RELOC(bootpath) = PTRUNRELOC(p); - mem += l + 1; - d = (char *) mem; - *d = 0; - call_prom(RELOC("canon"), 3, 1, p, d, 1<<20); - RELOC(bootdevice) = PTRUNRELOC(d); - mem = ALIGN(mem + strlen(d) + 1); - } - - prom_instantiate_rtas(); - -#ifdef CONFIG_PPC64BRIDGE - /* - * Find out how much memory we have and allocate a - * suitably-sized hash table. - */ - prom_alloc_htab(); -#endif - - mem = check_display(mem); - - prom_print(RELOC("copying OF device tree...")); - mem = copy_device_tree(mem, mem + (1<<20)); - prom_print(RELOC("done\n")); - -#ifdef CONFIG_SMP - prom_hold_cpus(mem); -#endif - - RELOC(klimit) = (char *) (mem - offset); - - /* If we are already running at 0xc0000000, we assume we were loaded by - * an OF bootloader which did set a BAT for us. This breaks OF translate - * so we force phys to be 0 - */ - if (offset == 0) - phys = 0; - else { - if ((int) call_prom(RELOC("getprop"), 4, 1, RELOC(prom_chosen), - RELOC("mmu"), &prom_mmu, sizeof(prom_mmu)) <= 0) { - prom_print(RELOC(" no MMU found\n")); - } else { - int nargs; - struct prom_args prom_args; - nargs = 4; - prom_args.service = RELOC("call-method"); - prom_args.nargs = nargs; - prom_args.nret = 4; - prom_args.args[0] = RELOC("translate"); - prom_args.args[1] = prom_mmu; - prom_args.args[2] = (void *)(offset + KERNELBASE); - prom_args.args[3] = (void *)1; - RELOC(prom)(&prom_args); - - /* We assume the phys. address size is 3 cells */ - if (prom_args.args[nargs] != 0) - prom_print(RELOC(" (translate failed)\n")); - else - phys = (unsigned long)prom_args.args[nargs+3]; - } - } - -#ifdef CONFIG_BOOTX_TEXT - if (RELOC(prom_disp_node) != 0) - setup_disp_fake_bi(RELOC(prom_disp_node)); -#endif - - /* Use quiesce call to get OF to shut down any devices it's using */ - prom_print(RELOC("Calling quiesce ...\n")); - call_prom(RELOC("quiesce"), 0, 0); - -#ifdef CONFIG_BOOTX_TEXT - btext_prepare_BAT(); -#endif - - prom_print(RELOC("returning ")); - prom_print_hex(phys); - prom_print(RELOC(" from prom_init\n")); - RELOC(prom_stdout) = 0; - - return phys; -} - -void phys_call_rtas(int service, int nargs, int nret, ...) +void __openfirmware +phys_call_rtas(int service, int nargs, int nret, ...) { va_list list; union { unsigned long words[16]; double align; } u; - unsigned long offset = reloc_offset(); void (*rtas)(void *, unsigned long); int i; @@ -683,340 +114,8 @@ void phys_call_rtas(int service, int nargs, int nret, ...) u.words[i+3] = va_arg(list, unsigned long); va_end(list); - rtas = (void (*)(void *, unsigned long)) RELOC(rtas_entry); - rtas(&u, RELOC(rtas_data)); -} - -static int __init -prom_set_color(ihandle ih, int i, int r, int g, int b) -{ - struct prom_args prom_args; - unsigned long offset = reloc_offset(); - - prom_args.service = RELOC("call-method"); - prom_args.nargs = 6; - prom_args.nret = 1; - prom_args.args[0] = RELOC("color!"); - prom_args.args[1] = ih; - prom_args.args[2] = (void *) i; - prom_args.args[3] = (void *) b; - prom_args.args[4] = (void *) g; - prom_args.args[5] = (void *) r; - RELOC(prom)(&prom_args); - return (int) prom_args.args[6]; -} - -/* - * If we have a display that we don't know how to drive, - * we will want to try to execute OF's open method for it - * later. However, OF will probably fall over if we do that - * we've taken over the MMU. - * So we check whether we will need to open the display, - * and if so, open it now. - */ -static unsigned long __init -check_display(unsigned long mem) -{ - phandle node; - ihandle ih; - int i; - unsigned long offset = reloc_offset(); - char type[16], *path; - static unsigned char default_colors[] = { - 0x00, 0x00, 0x00, - 0x00, 0x00, 0xaa, - 0x00, 0xaa, 0x00, - 0x00, 0xaa, 0xaa, - 0xaa, 0x00, 0x00, - 0xaa, 0x00, 0xaa, - 0xaa, 0xaa, 0x00, - 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, - 0x55, 0x55, 0xff, - 0x55, 0xff, 0x55, - 0x55, 0xff, 0xff, - 0xff, 0x55, 0x55, - 0xff, 0x55, 0xff, - 0xff, 0xff, 0x55, - 0xff, 0xff, 0xff - }; - - RELOC(prom_disp_node) = 0; - - for (node = 0; prom_next_node(&node); ) { - type[0] = 0; - call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"), - type, sizeof(type)); - if (strcmp(type, RELOC("display")) != 0) - continue; - /* It seems OF doesn't null-terminate the path :-( */ - path = (char *) mem; - memset(path, 0, 256); - if ((int) call_prom(RELOC("package-to-path"), 3, 1, - node, path, 255) < 0) - continue; - - /* - * If this display is the device that OF is using for stdout, - * move it to the front of the list. - */ - mem += strlen(path) + 1; - 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_nodes[i]) - = RELOC(prom_display_nodes[i-1]); - } - } - RELOC(prom_display_paths[i]) = PTRUNRELOC(path); - RELOC(prom_display_nodes[i]) = node; - if (i == 0) - RELOC(prom_disp_node) = node; - if (RELOC(prom_num_displays) >= FB_MAX) - break; - } - -try_again: - /* - * Open the first display and set its colormap. - */ - if (RELOC(prom_num_displays) > 0) { - path = PTRRELOC(RELOC(prom_display_paths[0])); - prom_print(RELOC("opening display ")); - prom_print(path); - ih = call_prom(RELOC("open"), 1, 1, path); - if (ih == 0 || ih == (ihandle) -1) { - prom_print(RELOC("... failed\n")); - for (i=1; i<RELOC(prom_num_displays); i++) { - RELOC(prom_display_paths[i-1]) = RELOC(prom_display_paths[i]); - RELOC(prom_display_nodes[i-1]) = RELOC(prom_display_nodes[i]); - } - if (--RELOC(prom_num_displays) > 0) - RELOC(prom_disp_node) = RELOC(prom_display_nodes[0]); - else - RELOC(prom_disp_node) = NULL; - goto try_again; - } else { - prom_print(RELOC("... ok\n")); - /* - * Setup a usable color table when the appropriate - * method is available. - * Should update this to use set-colors. - */ - for (i = 0; i < 32; i++) - if (prom_set_color(ih, i, RELOC(default_colors)[i*3], - RELOC(default_colors)[i*3+1], - RELOC(default_colors)[i*3+2]) != 0) - break; - -#ifdef CONFIG_FB - for (i = 0; i < LINUX_LOGO_COLORS; i++) - if (prom_set_color(ih, i + 32, - RELOC(linux_logo_red)[i], - RELOC(linux_logo_green)[i], - RELOC(linux_logo_blue)[i]) != 0) - break; -#endif /* CONFIG_FB */ - } - } - - return ALIGN(mem); -} - -/* This function will enable the early boot text when doing OF booting. This - * way, xmon output should work too - */ -#ifdef CONFIG_BOOTX_TEXT -static void __init -setup_disp_fake_bi(ihandle dp) -{ - int width = 640, height = 480, depth = 8, pitch; - unsigned address; - unsigned long offset = reloc_offset(); - struct pci_reg_property addrs[8]; - int i, naddrs; - char name[32]; - char *getprop = RELOC("getprop"); - - prom_print(RELOC("Initializing fake screen: ")); - - memset(name, 0, sizeof(name)); - call_prom(getprop, 4, 1, dp, RELOC("name"), name, sizeof(name)); - name[sizeof(name)-1] = 0; - prom_print(name); - prom_print(RELOC("\n")); - call_prom(getprop, 4, 1, dp, RELOC("width"), &width, sizeof(width)); - call_prom(getprop, 4, 1, dp, RELOC("height"), &height, sizeof(height)); - call_prom(getprop, 4, 1, dp, RELOC("depth"), &depth, sizeof(depth)); - pitch = width * ((depth + 7) / 8); - call_prom(getprop, 4, 1, dp, RELOC("linebytes"), - &pitch, sizeof(pitch)); - if (pitch == 1) - pitch = 0x1000; /* for strange IBM display */ - address = 0; - call_prom(getprop, 4, 1, dp, RELOC("address"), - &address, sizeof(address)); - if (address == 0) { - /* look for an assigned address with a size of >= 1MB */ - naddrs = (int) call_prom(getprop, 4, 1, dp, - RELOC("assigned-addresses"), - addrs, sizeof(addrs)); - naddrs /= sizeof(struct pci_reg_property); - for (i = 0; i < naddrs; ++i) { - if (addrs[i].size_lo >= (1 << 20)) { - address = addrs[i].addr.a_lo; - /* use the BE aperture if possible */ - if (addrs[i].size_lo >= (16 << 20)) - address += (8 << 20); - break; - } - } - if (address == 0) { - prom_print(RELOC("Failed to get address\n")); - return; - } - } - /* kludge for valkyrie */ - if (strcmp(name, RELOC("valkyrie")) == 0) - address += 0x1000; - - btext_setup_display(width, height, depth, pitch, address); -} -#endif - -static int __init -prom_next_node(phandle *nodep) -{ - phandle node; - unsigned long offset = reloc_offset(); - - if ((node = *nodep) != 0 - && (*nodep = call_prom(RELOC("child"), 1, 1, node)) != 0) - return 1; - if ((*nodep = call_prom(RELOC("peer"), 1, 1, node)) != 0) - return 1; - for (;;) { - if ((node = call_prom(RELOC("parent"), 1, 1, node)) == 0) - return 0; - if ((*nodep = call_prom(RELOC("peer"), 1, 1, node)) != 0) - return 1; - } -} - -/* - * Make a copy of the device tree from the PROM. - */ -static unsigned long __init -copy_device_tree(unsigned long mem_start, unsigned long mem_end) -{ - phandle root; - unsigned long new_start; - struct device_node **allnextp; - unsigned long offset = reloc_offset(); - - root = call_prom(RELOC("peer"), 1, 1, (phandle)0); - if (root == (phandle)0) { - prom_print(RELOC("couldn't get device tree root\n")); - prom_exit(); - } - allnextp = &RELOC(allnodes); - mem_start = ALIGN(mem_start); - new_start = inspect_node(root, 0, mem_start, mem_end, &allnextp); - *allnextp = 0; - return new_start; -} - -static unsigned long __init -inspect_node(phandle node, struct device_node *dad, - unsigned long mem_start, unsigned long mem_end, - struct device_node ***allnextpp) -{ - int l; - phandle child; - struct device_node *np; - struct property *pp, **prev_propp; - char *prev_name, *namep; - unsigned char *valp; - unsigned long offset = reloc_offset(); - - np = (struct device_node *) mem_start; - mem_start += sizeof(struct device_node); - memset(np, 0, sizeof(*np)); - np->node = node; - **allnextpp = PTRUNRELOC(np); - *allnextpp = &np->allnext; - if (dad != 0) { - np->parent = PTRUNRELOC(dad); - /* we temporarily use the `next' field as `last_child'. */ - if (dad->next == 0) - dad->child = PTRUNRELOC(np); - else - dad->next->sibling = PTRUNRELOC(np); - dad->next = np; - } - - /* get and store all properties */ - prev_propp = &np->properties; - prev_name = RELOC(""); - for (;;) { - pp = (struct property *) mem_start; - namep = (char *) (pp + 1); - pp->name = PTRUNRELOC(namep); - if ((int) call_prom(RELOC("nextprop"), 3, 1, node, prev_name, - namep) <= 0) - break; - mem_start = ALIGN((unsigned long)namep + strlen(namep) + 1); - prev_name = namep; - valp = (unsigned char *) mem_start; - pp->value = PTRUNRELOC(valp); - pp->length = (int) - call_prom(RELOC("getprop"), 4, 1, node, namep, - valp, mem_end - mem_start); - if (pp->length < 0) - continue; -#ifdef MAX_PROPERTY_LENGTH - if (pp->length > MAX_PROPERTY_LENGTH) - continue; /* ignore this property */ -#endif - mem_start = ALIGN(mem_start + pp->length); - *prev_propp = PTRUNRELOC(pp); - prev_propp = &pp->next; - } - if (np->node != NULL) { - /* Add a "linux,phandle" property" */ - pp = (struct property *) mem_start; - *prev_propp = PTRUNRELOC(pp); - prev_propp = &pp->next; - namep = (char *) (pp + 1); - pp->name = PTRUNRELOC(namep); - strcpy(namep, RELOC("linux,phandle")); - mem_start = ALIGN((unsigned long)namep + strlen(namep) + 1); - pp->value = (unsigned char *) PTRUNRELOC(&np->node); - pp->length = sizeof(np->node); - } - *prev_propp = NULL; - - /* get the node's full name */ - l = (int) call_prom(RELOC("package-to-path"), 3, 1, node, - (char *) mem_start, mem_end - mem_start); - if (l >= 0) { - np->full_name = PTRUNRELOC((char *) mem_start); - *(char *)(mem_start + l) = 0; - mem_start = ALIGN(mem_start + l + 1); - } - - /* do all our children */ - child = call_prom(RELOC("child"), 1, 1, node); - while (child != (void *)0) { - mem_start = inspect_node(child, np, mem_start, mem_end, - allnextpp); - child = call_prom(RELOC("peer"), 1, 1, child); - } - - return mem_start; + rtas = (void (*)(void *, unsigned long)) rtas_entry; + rtas(&u, rtas_data); } /* @@ -1081,26 +180,6 @@ finish_device_tree(void) klimit = (char *) mem; } -/* - * 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. - */ -static void * __init -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; -} - static unsigned long __init finish_node(struct device_node *np, unsigned long mem_start, interpret_func *ifunc, int naddrc, int nsizec) @@ -1111,10 +190,15 @@ finish_node(struct device_node *np, unsigned long mem_start, np->name = get_property(np, "name", 0); np->type = get_property(np, "device_type", 0); + if (!np->name) + np->name = "<NULL>"; + if (!np->type) + np->type = "<NULL>"; + /* get the device addresses and interrupts */ - if (ifunc != NULL) { + if (ifunc != NULL) mem_start = ifunc(np, mem_start, naddrc, nsizec); - } + if (use_of_interrupt_tree) mem_start = finish_node_interrupts(np, mem_start); @@ -1126,12 +210,6 @@ finish_node(struct device_node *np, unsigned long mem_start, if (ip != NULL) nsizec = *ip; - /* the f50 sets the name to 'display' and 'compatible' to what we - * expect for the name -- Cort - */ - if (!strcmp(np->name, "display")) - np->name = get_property(np, "compatible", 0); - if (np->parent == NULL) ifunc = interpret_root_props; else if (np->type == 0) @@ -1145,6 +223,8 @@ finish_node(struct device_node *np, unsigned long mem_start, ifunc = interpret_macio_props; else if (!strcmp(np->type, "isa")) ifunc = interpret_isa_props; + else if (!strcmp(np->name, "uni-n")) + ifunc = interpret_root_props; else if (!((ifunc == interpret_dbdma_props || ifunc == interpret_macio_props) && (!strcmp(np->type, "escc") @@ -1508,7 +588,7 @@ interpret_dbdma_props(struct device_node *np, unsigned long mem_start, i = 0; adr = (struct address_range *) mem_start; while ((l -= sizeof(struct reg_property)) >= 0) { - adr[i].space = 0; + adr[i].space = 2; adr[i].address = rp[i].address + base_address; adr[i].size = rp[i].size; ++i; @@ -1544,14 +624,13 @@ interpret_macio_props(struct device_node *np, unsigned long mem_start, struct reg_property *rp; struct address_range *adr; unsigned long base_address; - int i, l, keylargo, *ip; + int i, l, *ip; struct device_node *db; base_address = 0; for (db = np->parent; db != NULL; db = db->parent) { if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) { base_address = db->addrs[0].address; - keylargo = device_is_compatible(db, "Keylargo"); break; } } @@ -1561,7 +640,7 @@ interpret_macio_props(struct device_node *np, unsigned long mem_start, i = 0; adr = (struct address_range *) mem_start; while ((l -= sizeof(struct reg_property)) >= 0) { - adr[i].space = 0; + adr[i].space = 2; adr[i].address = rp[i].address + base_address; adr[i].size = rp[i].size; ++i; @@ -1616,7 +695,7 @@ interpret_isa_props(struct device_node *np, unsigned long mem_start, if (use_of_interrupt_tree) return mem_start; - + ip = (int *) get_property(np, "interrupts", &l); if (ip != 0) { np->intrs = (struct interrupt_info *) mem_start; @@ -1645,7 +724,7 @@ interpret_root_props(struct device_node *np, unsigned long mem_start, i = 0; adr = (struct address_range *) mem_start; while ((l -= rpsize) >= 0) { - adr[i].space = (naddrc >= 2? rp[naddrc-2]: 0); + adr[i].space = (naddrc >= 2? rp[naddrc-2]: 2); adr[i].address = rp[naddrc - 1]; adr[i].size = rp[naddrc + nsizec - 1]; ++i; @@ -1786,7 +865,7 @@ int machine_is_compatible(const char *compat) { struct device_node *root; - + root = find_path_device("/"); if (root == 0) return 0; @@ -1870,12 +949,178 @@ prom_add_property(struct device_node* np, struct property* prop) { struct property **next = &np->properties; - prop->next = NULL; + prop->next = NULL; while (*next) next = &(*next)->next; *next = prop; } +/* I quickly hacked that one, check against spec ! */ +static inline unsigned long __openfirmware +bus_space_to_resource_flags(unsigned int bus_space) +{ + u8 space = (bus_space >> 24) & 0xf; + if (space == 0) + space = 0x02; + if (space == 0x02) + return IORESOURCE_MEM; + else if (space == 0x01) + return IORESOURCE_IO; + else { + printk(KERN_WARNING "prom.c: bus_space_to_resource_flags(), space: %x\n", + bus_space); + return 0; + } +} + +static struct resource* __openfirmware +find_parent_pci_resource(struct pci_dev* pdev, struct address_range *range) +{ + unsigned long mask; + int i; + + /* Check this one */ + mask = bus_space_to_resource_flags(range->space); + for (i=0; i<DEVICE_COUNT_RESOURCE; i++) { + if ((pdev->resource[i].flags & mask) == mask && + pdev->resource[i].start <= range->address && + pdev->resource[i].end > range->address) { + if ((range->address + range->size - 1) > pdev->resource[i].end) { + /* Add better message */ + printk(KERN_WARNING "PCI/OF resource overlap !\n"); + return NULL; + } + break; + } + } + if (i == DEVICE_COUNT_RESOURCE) + return NULL; + return &pdev->resource[i]; +} + +/* + * Request an OF device resource. Currently handles child of PCI devices, + * or other nodes attached to the root node. Ultimately, put some + * link to resources in the OF node. + * WARNING: out_resource->name should be initialized before calling this + * function. + */ +struct resource* __openfirmware +request_OF_resource(struct device_node* node, int index, const char* name_postfix) +{ + struct pci_dev* pcidev; + u8 pci_bus, pci_devfn; + unsigned long iomask; + struct device_node* nd; + struct resource* parent; + struct resource *res = NULL; + int nlen, plen; + + if (index >= node->n_addrs) + goto fail; + + /* Sanity check on bus space */ + iomask = bus_space_to_resource_flags(node->addrs[index].space); + if (iomask & IORESOURCE_MEM) + parent = &iomem_resource; + else if (iomask & IORESOURCE_IO) + parent = &ioport_resource; + else + goto fail; + + /* Find a PCI parent if any */ + nd = node; + pcidev = NULL; + while(nd) { + if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn)) + pcidev = pci_find_slot(pci_bus, pci_devfn); + if (pcidev) break; + nd = nd->parent; + } + if (pcidev) + parent = find_parent_pci_resource(pcidev, &node->addrs[index]); + if (!parent) { + printk(KERN_WARNING "request_OF_resource(%s), parent not found\n", + node->name); + goto fail; + } + + res = __request_region(parent, node->addrs[index].address, node->addrs[index].size, NULL); + if (!res) + goto fail; + nlen = strlen(node->name); + plen = name_postfix ? strlen(name_postfix) : 0; + res->name = (const char *)kmalloc(nlen+plen+1, GFP_KERNEL); + if (res->name) { + strcpy((char *)res->name, node->name); + if (plen) + strcpy((char *)res->name+nlen, name_postfix); + } + return res; +fail: + return NULL; +} + +int __openfirmware +release_OF_resource(struct device_node* node, int index) +{ + struct pci_dev* pcidev; + u8 pci_bus, pci_devfn; + unsigned long iomask; + struct device_node* nd; + struct resource* parent; + struct resource *res = NULL; + + if (index >= node->n_addrs) + return -EINVAL; + + /* Sanity check on bus space */ + iomask = bus_space_to_resource_flags(node->addrs[index].space); + if (iomask & IORESOURCE_MEM) + parent = &iomem_resource; + else if (iomask & IORESOURCE_IO) + parent = &ioport_resource; + else + return -EINVAL; + + /* Find a PCI parent if any */ + nd = node; + pcidev = NULL; + while(nd) { + if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn)) + pcidev = pci_find_slot(pci_bus, pci_devfn); + if (pcidev) break; + nd = nd->parent; + } + if (pcidev) + parent = find_parent_pci_resource(pcidev, &node->addrs[index]); + if (!parent) { + printk(KERN_WARNING "request_OF_resource(%s), parent not found\n", + node->name); + return -ENODEV; + } + + /* Find us in the parent */ + res = parent->child; + while (res) { + if (res->start == node->addrs[index].address && + res->end == (res->start + node->addrs[index].size - 1)) + break; + res = res->sibling; + } + if (!res) + return -ENODEV; + + if (res->name) { + kfree(res->name); + res->name = NULL; + } + release_resource(res); + kfree(res); + + return 0; +} + #if 0 void __openfirmware print_properties(struct device_node *np) @@ -1961,11 +1206,11 @@ call_rtas(const char *service, int nargs, int nret, u.words[i+3] = va_arg(list, unsigned long); va_end(list); - /* Shouldn't we enable kernel FP here ? enter_rtas will play - * with MSR_FE0|MSR_FE1|MSR_FP so I assume rtas might use - * floating points. If that's the case, then we need to make - * sure any lazy FP context is backed up - * --BenH + /* + * RTAS doesn't use floating point. + * Or at least, according to the CHRP spec we enter RTAS + * with FP disabled, and it doesn't change the FP registers. + * -- paulus. */ spin_lock_irqsave(&rtas_lock, s); enter_rtas((void *)__pa(&u)); @@ -1976,13 +1221,3 @@ call_rtas(const char *service, int nargs, int nret, outputs[i] = u.words[i+nargs+4]; return u.words[nargs+3]; } - -void __init -abort() -{ -#ifdef CONFIG_XMON - xmon(NULL); -#endif - for (;;) - prom_exit(); -} diff --git a/arch/ppc/kernel/prom_init.c b/arch/ppc/kernel/prom_init.c new file mode 100644 index 000000000000..fea41427aa29 --- /dev/null +++ b/arch/ppc/kernel/prom_init.c @@ -0,0 +1,899 @@ +/* + * Note that prom_init() and anything called from prom_init() + * may be running at an address that is different from the address + * that it was linked at. References to static data items are + * handled by compiling this file with -mrelocatable-lib. + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/init.h> +#include <linux/version.h> +#include <linux/threads.h> +#include <linux/spinlock.h> +#include <linux/ioport.h> +#include <linux/pci.h> +#include <linux/slab.h> + +#include <asm/sections.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> +#include <asm/system.h> +#include <asm/mmu.h> +#include <asm/pgtable.h> +#include <asm/bitops.h> +#include <asm/bootinfo.h> +#include <asm/btext.h> +#include <asm/pci-bridge.h> +#include <asm/open_pic.h> + +#ifdef CONFIG_FB +#include <asm/linux_logo.h> +#endif + +/* + * Properties whose value is longer than this get excluded from our + * copy of the device tree. This way we don't waste space storing + * things like "driver,AAPL,MacOS,PowerPC" properties. But this value + * does need to be big enough to ensure that we don't lose things + * like the interrupt-map property on a PCI-PCI bridge. + */ +#define MAX_PROPERTY_LENGTH 4096 + +#ifndef FB_MAX /* avoid pulling in all of the fb stuff */ +#define FB_MAX 8 +#endif + +#define ALIGN(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long)) + +struct prom_args { + const char *service; + int nargs; + int nret; + void *args[10]; +}; + +struct pci_address { + unsigned a_hi; + unsigned a_mid; + unsigned a_lo; +}; + +struct pci_reg_property { + struct pci_address addr; + unsigned size_hi; + unsigned size_lo; +}; + +struct pci_range { + struct pci_address addr; + unsigned phys; + unsigned size_hi; + unsigned size_lo; +}; + +struct isa_reg_property { + unsigned space; + unsigned address; + unsigned size; +}; + +struct pci_intr_map { + struct pci_address addr; + unsigned dunno; + phandle int_ctrler; + unsigned intr; +}; + +static void prom_exit(void); +static void *call_prom(const char *service, int nargs, int nret, ...); +static void *call_prom_ret(const char *service, int nargs, int nret, + void **rets, ...); +static void prom_print_hex(unsigned int v); +static int prom_set_color(ihandle ih, int i, int r, int g, int b); +static int prom_next_node(phandle *nodep); +static unsigned long check_display(unsigned long mem); +static void setup_disp_fake_bi(ihandle dp); +static unsigned long copy_device_tree(unsigned long mem_start, + unsigned long mem_end); +static unsigned long inspect_node(phandle node, struct device_node *dad, + unsigned long mem_start, unsigned long mem_end, + struct device_node ***allnextpp); +static void prom_hold_cpus(unsigned long mem); +static void prom_instantiate_rtas(void); +static void * early_get_property(unsigned long base, unsigned long node, + char *prop); + +prom_entry prom __initdata = 0; +ihandle prom_chosen __initdata = 0; +ihandle prom_stdout __initdata = 0; + +char *prom_display_paths[FB_MAX] __initdata = { 0, }; +phandle prom_display_nodes[FB_MAX] __initdata; +unsigned int prom_num_displays __initdata = 0; +static char *of_stdout_device __initdata = 0; +static ihandle prom_disp_node __initdata = 0; + +unsigned int rtas_data; /* physical pointer */ +unsigned int rtas_entry; /* physical pointer */ +unsigned int rtas_size; +unsigned int old_rtas; + +boot_infos_t *boot_infos; +char *bootpath; +char *bootdevice; +struct device_node *allnodes; + +extern char *klimit; +extern char _stext; + +static void __init +prom_exit(void) +{ + struct prom_args args; + + args.service = "exit"; + args.nargs = 0; + args.nret = 0; + prom(&args); + for (;;) /* should never get here */ + ; +} + +static void * __init +call_prom(const char *service, int nargs, int nret, ...) +{ + va_list list; + int i; + struct prom_args prom_args; + + prom_args.service = service; + prom_args.nargs = nargs; + prom_args.nret = nret; + va_start(list, nret); + for (i = 0; i < nargs; ++i) + prom_args.args[i] = va_arg(list, void *); + va_end(list); + for (i = 0; i < nret; ++i) + prom_args.args[i + nargs] = 0; + prom(&prom_args); + return prom_args.args[nargs]; +} + +static void * __init +call_prom_ret(const char *service, int nargs, int nret, void **rets, ...) +{ + va_list list; + int i; + struct prom_args prom_args; + + prom_args.service = service; + prom_args.nargs = nargs; + prom_args.nret = nret; + va_start(list, rets); + for (i = 0; i < nargs; ++i) + prom_args.args[i] = va_arg(list, void *); + va_end(list); + for (i = 0; i < nret; ++i) + prom_args.args[i + nargs] = 0; + prom(&prom_args); + for (i = 1; i < nret; ++i) + rets[i-1] = prom_args.args[nargs + i]; + return prom_args.args[nargs]; +} + +void __init +prom_print(const char *msg) +{ + const char *p, *q; + + if (prom_stdout == 0) + return; + + for (p = msg; *p != 0; p = q) { + for (q = p; *q != 0 && *q != '\n'; ++q) + ; + if (q > p) + call_prom("write", 3, 1, prom_stdout, p, q - p); + if (*q != 0) { + ++q; + call_prom("write", 3, 1, prom_stdout, "\r\n", 2); + } + } +} + +static void __init +prom_print_hex(unsigned int v) +{ + char buf[16]; + int i, c; + + for (i = 0; i < 8; ++i) { + c = (v >> ((7-i)*4)) & 0xf; + c += (c >= 10)? ('a' - 10): '0'; + buf[i] = c; + } + buf[i] = ' '; + buf[i+1] = 0; + prom_print(buf); +} + +static int __init +prom_set_color(ihandle ih, int i, int r, int g, int b) +{ + struct prom_args prom_args; + + prom_args.service = "call-method"; + prom_args.nargs = 6; + prom_args.nret = 1; + prom_args.args[0] = "color!"; + prom_args.args[1] = ih; + prom_args.args[2] = (void *) i; + prom_args.args[3] = (void *) b; + prom_args.args[4] = (void *) g; + prom_args.args[5] = (void *) r; + prom(&prom_args); + return (int) prom_args.args[6]; +} + +static int __init +prom_next_node(phandle *nodep) +{ + phandle node; + + if ((node = *nodep) != 0 + && (*nodep = call_prom("child", 1, 1, node)) != 0) + return 1; + if ((*nodep = call_prom("peer", 1, 1, node)) != 0) + return 1; + for (;;) { + if ((node = call_prom("parent", 1, 1, node)) == 0) + return 0; + if ((*nodep = call_prom("peer", 1, 1, node)) != 0) + return 1; + } +} + +/* + * If we have a display that we don't know how to drive, + * we will want to try to execute OF's open method for it + * later. However, OF will probably fall over if we do that + * we've taken over the MMU. + * So we check whether we will need to open the display, + * and if so, open it now. + */ +static unsigned long __init +check_display(unsigned long mem) +{ + phandle node; + ihandle ih; + int i; + char type[16], *path; + static unsigned char default_colors[] = { + 0x00, 0x00, 0x00, + 0x00, 0x00, 0xaa, + 0x00, 0xaa, 0x00, + 0x00, 0xaa, 0xaa, + 0xaa, 0x00, 0x00, + 0xaa, 0x00, 0xaa, + 0xaa, 0xaa, 0x00, + 0xaa, 0xaa, 0xaa, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0xff, + 0x55, 0xff, 0x55, + 0x55, 0xff, 0xff, + 0xff, 0x55, 0x55, + 0xff, 0x55, 0xff, + 0xff, 0xff, 0x55, + 0xff, 0xff, 0xff + }; + + prom_disp_node = 0; + + for (node = 0; prom_next_node(&node); ) { + type[0] = 0; + call_prom("getprop", 4, 1, node, "device_type", + type, sizeof(type)); + if (strcmp(type, "display") != 0) + continue; + /* It seems OF doesn't null-terminate the path :-( */ + path = (char *) mem; + memset(path, 0, 256); + if ((int) call_prom("package-to-path", 3, 1, + node, path, 255) < 0) + continue; + + /* + * If this display is the device that OF is using for stdout, + * move it to the front of the list. + */ + mem += strlen(path) + 1; + i = prom_num_displays++; + if (of_stdout_device != 0 && i > 0 + && strcmp(of_stdout_device, path) == 0) { + for (; i > 0; --i) { + prom_display_paths[i] + = prom_display_paths[i-1]; + prom_display_nodes[i] + = prom_display_nodes[i-1]; + } + } + prom_display_paths[i] = path; + prom_display_nodes[i] = node; + if (i == 0) + prom_disp_node = node; + if (prom_num_displays >= FB_MAX) + break; + } + +try_again: + /* + * Open the first display and set its colormap. + */ + if (prom_num_displays > 0) { + path = prom_display_paths[0]; + prom_print("opening display "); + prom_print(path); + ih = call_prom("open", 1, 1, path); + if (ih == 0 || ih == (ihandle) -1) { + prom_print("... failed\n"); + for (i=1; i<prom_num_displays; i++) { + prom_display_paths[i-1] = prom_display_paths[i]; + prom_display_nodes[i-1] = prom_display_nodes[i]; + } + if (--prom_num_displays > 0) + prom_disp_node = prom_display_nodes[0]; + else + prom_disp_node = NULL; + goto try_again; + } else { + prom_print("... ok\n"); + /* + * Setup a usable color table when the appropriate + * method is available. + * Should update this to use set-colors. + */ + for (i = 0; i < 32; i++) + if (prom_set_color(ih, i, default_colors[i*3], + default_colors[i*3+1], + default_colors[i*3+2]) != 0) + break; + +#ifdef CONFIG_FB + for (i = 0; i < LINUX_LOGO_COLORS; i++) + if (prom_set_color(ih, i + 32, + linux_logo_red[i], + linux_logo_green[i], + linux_logo_blue[i]) != 0) + break; +#endif /* CONFIG_FB */ + } + } + + return ALIGN(mem); +} + +/* This function will enable the early boot text when doing OF booting. This + * way, xmon output should work too + */ +static void __init +setup_disp_fake_bi(ihandle dp) +{ +#ifdef CONFIG_BOOTX_TEXT + int width = 640, height = 480, depth = 8, pitch; + unsigned address; + struct pci_reg_property addrs[8]; + int i, naddrs; + char name[32]; + char *getprop = "getprop"; + + prom_print("Initializing fake screen: "); + + memset(name, 0, sizeof(name)); + call_prom(getprop, 4, 1, dp, "name", name, sizeof(name)); + name[sizeof(name)-1] = 0; + prom_print(name); + prom_print("\n"); + call_prom(getprop, 4, 1, dp, "width", &width, sizeof(width)); + call_prom(getprop, 4, 1, dp, "height", &height, sizeof(height)); + call_prom(getprop, 4, 1, dp, "depth", &depth, sizeof(depth)); + pitch = width * ((depth + 7) / 8); + call_prom(getprop, 4, 1, dp, "linebytes", + &pitch, sizeof(pitch)); + if (pitch == 1) + pitch = 0x1000; /* for strange IBM display */ + address = 0; + call_prom(getprop, 4, 1, dp, "address", + &address, sizeof(address)); + if (address == 0) { + /* look for an assigned address with a size of >= 1MB */ + naddrs = (int) call_prom(getprop, 4, 1, dp, + "assigned-addresses", + addrs, sizeof(addrs)); + naddrs /= sizeof(struct pci_reg_property); + for (i = 0; i < naddrs; ++i) { + if (addrs[i].size_lo >= (1 << 20)) { + address = addrs[i].addr.a_lo; + /* use the BE aperture if possible */ + if (addrs[i].size_lo >= (16 << 20)) + address += (8 << 20); + break; + } + } + if (address == 0) { + prom_print("Failed to get address\n"); + return; + } + } + /* kludge for valkyrie */ + if (strcmp(name, "valkyrie") == 0) + address += 0x1000; + + btext_setup_display(width, height, depth, pitch, address); + + btext_prepare_BAT(); +#endif /* CONFIG_BOOTX_TEXT */ +} + +/* + * Make a copy of the device tree from the PROM. + */ +static unsigned long __init +copy_device_tree(unsigned long mem_start, unsigned long mem_end) +{ + phandle root; + unsigned long new_start; + struct device_node **allnextp; + + root = call_prom("peer", 1, 1, (phandle)0); + if (root == (phandle)0) { + prom_print("couldn't get device tree root\n"); + prom_exit(); + } + allnextp = &allnodes; + mem_start = ALIGN(mem_start); + new_start = inspect_node(root, 0, mem_start, mem_end, &allnextp); + *allnextp = 0; + return new_start; +} + +static unsigned long __init +inspect_node(phandle node, struct device_node *dad, + unsigned long mem_start, unsigned long mem_end, + struct device_node ***allnextpp) +{ + int l; + phandle child; + struct device_node *np; + struct property *pp, **prev_propp; + char *prev_name, *namep; + unsigned char *valp; + + np = (struct device_node *) mem_start; + mem_start += sizeof(struct device_node); + memset(np, 0, sizeof(*np)); + np->node = node; + **allnextpp = PTRUNRELOC(np); + *allnextpp = &np->allnext; + if (dad != 0) { + np->parent = PTRUNRELOC(dad); + /* we temporarily use the `next' field as `last_child'. */ + if (dad->next == 0) + dad->child = PTRUNRELOC(np); + else + dad->next->sibling = PTRUNRELOC(np); + dad->next = np; + } + + /* get and store all properties */ + prev_propp = &np->properties; + prev_name = ""; + for (;;) { + pp = (struct property *) mem_start; + namep = (char *) (pp + 1); + pp->name = PTRUNRELOC(namep); + if ((int) call_prom("nextprop", 3, 1, node, prev_name, + namep) <= 0) + break; + mem_start = ALIGN((unsigned long)namep + strlen(namep) + 1); + prev_name = namep; + valp = (unsigned char *) mem_start; + pp->value = PTRUNRELOC(valp); + pp->length = (int) + call_prom("getprop", 4, 1, node, namep, + valp, mem_end - mem_start); + if (pp->length < 0) + continue; +#ifdef MAX_PROPERTY_LENGTH + if (pp->length > MAX_PROPERTY_LENGTH) + continue; /* ignore this property */ +#endif + mem_start = ALIGN(mem_start + pp->length); + *prev_propp = PTRUNRELOC(pp); + prev_propp = &pp->next; + } + if (np->node != NULL) { + /* Add a "linux,phandle" property" */ + pp = (struct property *) mem_start; + *prev_propp = PTRUNRELOC(pp); + prev_propp = &pp->next; + namep = (char *) (pp + 1); + pp->name = PTRUNRELOC(namep); + strcpy(namep, "linux,phandle"); + mem_start = ALIGN((unsigned long)namep + strlen(namep) + 1); + pp->value = (unsigned char *) PTRUNRELOC(&np->node); + pp->length = sizeof(np->node); + } + *prev_propp = NULL; + + /* get the node's full name */ + l = (int) call_prom("package-to-path", 3, 1, node, + (char *) mem_start, mem_end - mem_start); + if (l >= 0) { + np->full_name = PTRUNRELOC((char *) mem_start); + *(char *)(mem_start + l) = 0; + mem_start = ALIGN(mem_start + l + 1); + } + + /* do all our children */ + child = call_prom("child", 1, 1, node); + while (child != (void *)0) { + mem_start = inspect_node(child, np, mem_start, mem_end, + allnextpp); + child = call_prom("peer", 1, 1, child); + } + + return mem_start; +} + +unsigned long smp_chrp_cpu_nr __initdata = 0; + +/* + * With CHRP SMP we need to use the OF to start the other + * processors so we can't wait until smp_boot_cpus (the OF is + * trashed by then) so we have to put the processors into + * a holding pattern controlled by the kernel (not OF) before + * we destroy the OF. + * + * This uses a chunk of high memory, puts some holding pattern + * code there and sends the other processors off to there until + * smp_boot_cpus tells them to do something. We do that by using + * physical address 0x0. The holding pattern checks that address + * until its cpu # is there, when it is that cpu jumps to + * __secondary_start(). smp_boot_cpus() takes care of setting those + * values. + * + * We also use physical address 0x4 here to tell when a cpu + * is in its holding pattern code. + * + * -- Cort + * + * Note that we have to do this if we have more than one CPU, + * even if this is a UP kernel. Otherwise when we trash OF + * the other CPUs will start executing some random instructions + * and crash the system. -- paulus + */ +static void __init +prom_hold_cpus(unsigned long mem) +{ + extern void __secondary_hold(void); + unsigned long i; + int cpu; + phandle node; + char type[16], *path; + unsigned int reg; + + /* + * XXX: hack to make sure we're chrp, assume that if we're + * chrp we have a device_type property -- Cort + */ + node = call_prom("finddevice", 1, 1, "/"); + if ((int)call_prom("getprop", 4, 1, node, + "device_type",type, sizeof(type)) <= 0) + return; + + /* copy the holding pattern code to someplace safe (0) */ + /* the holding pattern is now within the first 0x100 + bytes of the kernel image -- paulus */ + memcpy((void *)0, &_stext, 0x100); + flush_icache_range(0, 0x100); + + /* look for cpus */ + *(unsigned long *)(0x0) = 0; + asm volatile("dcbf 0,%0": : "r" (0) : "memory"); + for (node = 0; prom_next_node(&node); ) { + type[0] = 0; + call_prom("getprop", 4, 1, node, "device_type", + type, sizeof(type)); + if (strcmp(type, "cpu") != 0) + continue; + path = (char *) mem; + memset(path, 0, 256); + if ((int) call_prom("package-to-path", 3, 1, + node, path, 255) < 0) + continue; + reg = -1; + call_prom("getprop", 4, 1, node, "reg", ®, sizeof(reg)); + cpu = smp_chrp_cpu_nr++; +#ifdef CONFIG_SMP + smp_hw_index[cpu] = reg; +#endif /* CONFIG_SMP */ + /* XXX: hack - don't start cpu 0, this cpu -- Cort */ + if (cpu == 0) + continue; + prom_print("starting cpu "); + prom_print(path); + *(ulong *)(0x4) = 0; + call_prom("start-cpu", 3, 0, node, + (char *)__secondary_hold - &_stext, cpu); + prom_print("..."); + for ( i = 0 ; (i < 10000) && (*(ulong *)(0x4) == 0); i++ ) + ; + if (*(ulong *)(0x4) == cpu) + prom_print("ok\n"); + else { + prom_print("failed: "); + prom_print_hex(*(ulong *)0x4); + prom_print("\n"); + } + } +} + +static void __init +prom_instantiate_rtas(void) +{ + ihandle prom_rtas; + unsigned int i; + struct prom_args prom_args; + + prom_rtas = call_prom("finddevice", 1, 1, "/rtas"); + if (prom_rtas == (void *) -1) + return; + + rtas_size = 0; + call_prom("getprop", 4, 1, prom_rtas, + "rtas-size", &rtas_size, sizeof(rtas_size)); + prom_print("instantiating rtas"); + if (rtas_size == 0) { + rtas_data = 0; + } else { + /* + * Ask OF for some space for RTAS. + * Actually OF has bugs so we just arbitrarily + * use memory at the 6MB point. + */ + rtas_data = 6 << 20; + prom_print(" at "); + prom_print_hex(rtas_data); + } + + prom_rtas = call_prom("open", 1, 1, "/rtas"); + prom_print("..."); + prom_args.service = "call-method"; + prom_args.nargs = 3; + prom_args.nret = 2; + prom_args.args[0] = "instantiate-rtas"; + prom_args.args[1] = prom_rtas; + prom_args.args[2] = (void *) rtas_data; + prom(&prom_args); + i = 0; + if (prom_args.args[3] == 0) + i = (unsigned int)prom_args.args[4]; + rtas_entry = i; + if ((rtas_entry == -1) || (rtas_entry == 0)) + prom_print(" failed\n"); + else + prom_print(" done\n"); +} + +/* + * We enter here early on, when the Open Firmware prom is still + * handling exceptions and the MMU hash table for us. + */ +unsigned long __init +prom_init(int r3, int r4, prom_entry pp) +{ + unsigned long mem; + ihandle prom_mmu; + unsigned long offset = reloc_offset(); + int i, l; + char *p, *d; + unsigned long phys; + void *result[3]; + + /* Default */ + phys = (unsigned long) &_stext; + + /* First get a handle for the stdout device */ + prom = pp; + prom_chosen = call_prom("finddevice", 1, 1, + "/chosen"); + if (prom_chosen == (void *)-1) + prom_exit(); + if ((int) call_prom("getprop", 4, 1, prom_chosen, + "stdout", &prom_stdout, + sizeof(prom_stdout)) <= 0) + prom_exit(); + + /* Get the full OF pathname of the stdout device */ + mem = (unsigned long) klimit + offset; + p = (char *) mem; + memset(p, 0, 256); + call_prom("instance-to-path", 3, 1, prom_stdout, p, 255); + of_stdout_device = p; + mem += strlen(p) + 1; + + /* Get the boot device and translate it to a full OF pathname. */ + p = (char *) mem; + l = (int) call_prom("getprop", 4, 1, prom_chosen, + "bootpath", p, 1<<20); + if (l > 0) { + p[l] = 0; /* should already be null-terminated */ + bootpath = PTRUNRELOC(p); + mem += l + 1; + d = (char *) mem; + *d = 0; + call_prom("canon", 3, 1, p, d, 1<<20); + bootdevice = PTRUNRELOC(d); + mem = ALIGN(mem + strlen(d) + 1); + } + + prom_instantiate_rtas(); + + mem = check_display(mem); + + prom_print("copying OF device tree..."); + mem = copy_device_tree(mem, mem + (1<<20)); + prom_print("done\n"); + + prom_hold_cpus(mem); + + klimit = (char *) (mem - offset); + + /* If we are already running at 0xc0000000, we assume we were + * loaded by an OF bootloader which did set a BAT for us. + * This breaks OF translate so we force phys to be 0. + */ + if (offset == 0) + phys = 0; + else if ((int) call_prom("getprop", 4, 1, prom_chosen, "mmu", + &prom_mmu, sizeof(prom_mmu)) <= 0) { + prom_print(" no MMU found\n"); + } else if ((int)call_prom_ret("call-method", 4, 4, result, "translate", + prom_mmu, &_stext, 1) != 0) { + prom_print(" (translate failed)\n"); + } else { + /* We assume the phys. address size is 3 cells */ + phys = (unsigned long)result[2]; + } + + if (prom_disp_node != 0) + setup_disp_fake_bi(prom_disp_node); + + /* Use quiesce call to get OF to shut down any devices it's using */ + prom_print("Calling quiesce ...\n"); + call_prom("quiesce", 0, 0); + + /* Relocate various pointers which will be used once the + kernel is running at the address it was linked at. */ + for (i = 0; i < prom_num_displays; ++i) + prom_display_paths[i] = PTRUNRELOC(prom_display_paths[i]); + + prom_print("returning 0x"); + prom_print_hex(phys); + prom_print("from prom_init\n"); + prom_stdout = 0; + + return phys; +} + +/* + * 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. + */ +static void * __init +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; +} + +/* Is boot-info compatible ? */ +#define BOOT_INFO_IS_COMPATIBLE(bi) ((bi)->compatible_version <= BOOT_INFO_VERSION) +#define BOOT_INFO_IS_V2_COMPATIBLE(bi) ((bi)->version >= 2) +#define BOOT_INFO_IS_V4_COMPATIBLE(bi) ((bi)->version >= 4) + +void __init +bootx_init(unsigned long r4, unsigned long phys) +{ + boot_infos_t *bi = (boot_infos_t *) r4; + unsigned long space; + unsigned long ptr, x; + char *model; + + boot_infos = PTRUNRELOC(bi); + if (!BOOT_INFO_IS_V2_COMPATIBLE(bi)) + bi->logicalDisplayBase = 0; + +#ifdef CONFIG_BOOTX_TEXT + btext_init(bi); + + /* + * Test if boot-info is compatible. Done only in config + * CONFIG_BOOTX_TEXT since there is nothing much we can do + * with an incompatible version, except display a message + * and eventually hang the processor... + * + * I'll try to keep enough of boot-info compatible in the + * future to always allow display of this message; + */ + if (!BOOT_INFO_IS_COMPATIBLE(bi)) { + btext_drawstring(" !!! WARNING - Incompatible version of BootX !!!\n\n\n"); + btext_flushscreen(); + } +#endif /* CONFIG_BOOTX_TEXT */ + + /* New BootX enters kernel with MMU off, i/os are not allowed + here. This hack will have been done by the boostrap anyway. + */ + if (bi->version < 4) { + /* + * XXX If this is an iMac, turn off the USB controller. + */ + model = (char *) early_get_property + (r4 + bi->deviceTreeOffset, 4, "model"); + if (model + && (strcmp(model, "iMac,1") == 0 + || strcmp(model, "PowerMac1,1") == 0)) { + out_le32((unsigned *)0x80880008, 1); /* XXX */ + } + } + + /* Move klimit to enclose device tree, args, ramdisk, etc... */ + if (bi->version < 5) { + space = bi->deviceTreeOffset + bi->deviceTreeSize; + if (bi->ramDisk) + space = bi->ramDisk + bi->ramDiskSize; + } else + space = bi->totalParamsSize; + klimit = PTRUNRELOC((char *) bi + space); + + /* New BootX will have flushed all TLBs and enters kernel with + MMU switched OFF, so this should not be useful anymore. + */ + if (bi->version < 4) { + /* + * 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 = ((unsigned long) &_stext) & PAGE_MASK; + ptr < (unsigned long)bi + space; ptr += PAGE_SIZE) + x = *(volatile unsigned long *)ptr; + } + +#ifdef CONFIG_BOOTX_TEXT + /* + * Note that after we call btext_prepare_BAT, we can't do + * prom_draw*, flushscreen or clearscreen until we turn the MMU + * on, since btext_prepare_BAT sets disp_bi.logicalDisplayBase + * to a virtual address. + */ + btext_prepare_BAT(); +#endif +} diff --git a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c index 993068c91ce2..f806de5d7184 100644 --- a/arch/ppc/kernel/ptrace.c +++ b/arch/ppc/kernel/ptrace.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ptrace.c 1.8 07/07/01 17:00:08 paulus + * BK Id: %F% %I% %G% %U% %#% */ /* * linux/arch/ppc/kernel/ptrace.c @@ -71,6 +71,64 @@ static inline int put_reg(struct task_struct *task, int regno, return -EIO; } +#ifdef CONFIG_ALTIVEC +/* + * Get contents of AltiVec register state in task TASK + */ +static inline int get_vrregs(unsigned long *data, struct task_struct *task) +{ + int i, j; + + if (!access_ok(VERIFY_WRITE, data, 133 * sizeof(unsigned long))) + return -EFAULT; + + /* copy AltiVec registers VR[0] .. VR[31] */ + for (i = 0; i < 32; i++) + for (j = 0; j < 4; j++, data++) + if (__put_user(task->thread.vr[i].u[j], data)) + return -EFAULT; + + /* copy VSCR */ + for (i = 0; i < 4; i++, data++) + if (__put_user(task->thread.vscr.u[i], data)) + return -EFAULT; + + /* copy VRSAVE */ + if (__put_user(task->thread.vrsave, data)) + return -EFAULT; + + return 0; +} + +/* + * Write contents of AltiVec register state into task TASK. + */ +static inline int set_vrregs(struct task_struct *task, unsigned long *data) +{ + int i, j; + + if (!access_ok(VERIFY_READ, data, 133 * sizeof(unsigned long))) + return -EFAULT; + + /* copy AltiVec registers VR[0] .. VR[31] */ + for (i = 0; i < 32; i++) + for (j = 0; j < 4; j++, data++) + if (__get_user(task->thread.vr[i].u[j], data)) + return -EFAULT; + + /* copy VSCR */ + for (i = 0; i < 4; i++, data++) + if (__get_user(task->thread.vscr.u[i], data)) + return -EFAULT; + + /* copy VRSAVE */ + if (__get_user(task->thread.vrsave, data)) + return -EFAULT; + + return 0; +} +#endif + static inline void set_single_step(struct task_struct *task) { @@ -132,14 +190,9 @@ int sys_ptrace(long request, long pid, long addr, long data) ret = ptrace_attach(child); goto out_tsk; } - ret = -ESRCH; - if (!(child->ptrace & PT_PTRACED)) - goto out_tsk; - if (child->state != TASK_STOPPED) { - if (request != PTRACE_KILL) - goto out_tsk; - } - if (child->p_pptr != current) + + ret = ptrace_check_attach(child, request == PTRACE_KILL); + if (ret < 0) goto out_tsk; switch (request) { @@ -219,10 +272,17 @@ int sys_ptrace(long request, long pid, long addr, long data) ret = -EIO; if ((unsigned long) data > _NSIG) break; - if (request == PTRACE_SYSCALL) - child->ptrace |= PT_TRACESYS; - else - child->ptrace &= ~PT_TRACESYS; + if (request == PTRACE_SYSCALL) { + if (!(child->ptrace & PT_SYSCALLTRACE)) { + child->ptrace |= PT_SYSCALLTRACE; + child->work.syscall_trace++; + } + } else { + if (child->ptrace & PT_SYSCALLTRACE) { + child->ptrace &= ~PT_SYSCALLTRACE; + child->work.syscall_trace--; + } + } child->exit_code = data; /* make sure the single step bit is not set. */ clear_single_step(child); @@ -251,7 +311,10 @@ int sys_ptrace(long request, long pid, long addr, long data) ret = -EIO; if ((unsigned long) data > _NSIG) break; - child->ptrace &= ~PT_TRACESYS; + if (child->ptrace & PT_SYSCALLTRACE) { + child->ptrace &= ~PT_SYSCALLTRACE; + child->work.syscall_trace--; + } set_single_step(child); child->exit_code = data; /* give it a chance to run. */ @@ -264,6 +327,24 @@ int sys_ptrace(long request, long pid, long addr, long data) ret = ptrace_detach(child, data); break; +#ifdef CONFIG_ALTIVEC + case PTRACE_GETVRREGS: + /* Get the child altivec register state. */ + if (child->thread.regs->msr & MSR_VEC) + giveup_altivec(child); + ret = get_vrregs((unsigned long *)data, child); + break; + + case PTRACE_SETVRREGS: + /* Set the child altivec register state. */ + /* this is to clear the MSR_VEC bit to force a reload + * of register state from memory */ + if (child->thread.regs->msr & MSR_VEC) + giveup_altivec(child); + ret = set_vrregs(child, (unsigned long *)data); + break; +#endif + default: ret = -EIO; break; @@ -275,10 +356,10 @@ out: return ret; } -void syscall_trace(void) +void do_syscall_trace(void) { - if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) - != (PT_PTRACED|PT_TRACESYS)) + if ((current->ptrace & (PT_PTRACED|PT_SYSCALLTRACE)) + != (PT_PTRACED|PT_SYSCALLTRACE)) return; current->exit_code = SIGTRAP; current->state = TASK_STOPPED; diff --git a/arch/ppc/kernel/qspan_pci.c b/arch/ppc/kernel/qspan_pci.c index f5d19ff85a18..49dc9c04586b 100644 --- a/arch/ppc/kernel/qspan_pci.c +++ b/arch/ppc/kernel/qspan_pci.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.qspan_pci.c 1.5 05/17/01 18:14:22 cort + * BK Id: %F% %I% %G% %U% %#% */ /* * QSpan pci routines. @@ -29,8 +29,7 @@ #include <asm/mpc8xx.h> #include <asm/system.h> #include <asm/machdep.h> - -#include "pci.h" +#include <asm/pci-bridge.h> /* diff --git a/arch/ppc/kernel/residual.c b/arch/ppc/kernel/residual.c deleted file mode 100644 index cae870a305ca..000000000000 --- a/arch/ppc/kernel/residual.c +++ /dev/null @@ -1,878 +0,0 @@ -/* - * BK Id: SCCS/s.residual.c 1.13 09/11/01 16:54:34 trini - */ -/* - * Code to deal with the PReP residual data. - * - * Written by: Cort Dougan (cort@cs.nmt.edu) - * Improved _greatly_ and rewritten by Gabriel Paubert (paubert@iram.es) - * - * This file is based on the following documentation: - * - * IBM Power Personal Systems Architecture - * Residual Data - * Document Number: PPS-AR-FW0001 - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - * - */ - -#include <linux/string.h> -#include <asm/residual.h> -#include <asm/pnp.h> -#include <asm/byteorder.h> - -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/stddef.h> -#include <linux/unistd.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/user.h> -#include <linux/a.out.h> -#include <linux/tty.h> -#include <linux/major.h> -#include <linux/interrupt.h> -#include <linux/reboot.h> -#include <linux/init.h> -#include <linux/blk.h> -#include <linux/ioport.h> -#include <linux/pci.h> -#include <linux/ide.h> - -#include <asm/sections.h> -#include <asm/mmu.h> -#include <asm/processor.h> -#include <asm/io.h> -#include <asm/pgtable.h> -#include <asm/ide.h> - - -unsigned char __res[sizeof(RESIDUAL)] __prepdata = {0,}; -RESIDUAL *res = (RESIDUAL *)&__res; - -char * PnP_BASE_TYPES[] __initdata = { - "Reserved", - "MassStorageDevice", - "NetworkInterfaceController", - "DisplayController", - "MultimediaController", - "MemoryController", - "BridgeController", - "CommunicationsDevice", - "SystemPeripheral", - "InputDevice", - "ServiceProcessor" - }; - -/* Device Sub Type Codes */ - -unsigned char * PnP_SUB_TYPES[] __initdata = { - "\001\000SCSIController", - "\001\001IDEController", - "\001\002FloppyController", - "\001\003IPIController", - "\001\200OtherMassStorageController", - "\002\000EthernetController", - "\002\001TokenRingController", - "\002\002FDDIController", - "\002\0x80OtherNetworkController", - "\003\000VGAController", - "\003\001SVGAController", - "\003\002XGAController", - "\003\200OtherDisplayController", - "\004\000VideoController", - "\004\001AudioController", - "\004\200OtherMultimediaController", - "\005\000RAM", - "\005\001FLASH", - "\005\200OtherMemoryDevice", - "\006\000HostProcessorBridge", - "\006\001ISABridge", - "\006\002EISABridge", - "\006\003MicroChannelBridge", - "\006\004PCIBridge", - "\006\005PCMCIABridge", - "\006\006VMEBridge", - "\006\200OtherBridgeDevice", - "\007\000RS232Device", - "\007\001ATCompatibleParallelPort", - "\007\200OtherCommunicationsDevice", - "\010\000ProgrammableInterruptController", - "\010\001DMAController", - "\010\002SystemTimer", - "\010\003RealTimeClock", - "\010\004L2Cache", - "\010\005NVRAM", - "\010\006PowerManagement", - "\010\007CMOS", - "\010\010OperatorPanel", - "\010\011ServiceProcessorClass1", - "\010\012ServiceProcessorClass2", - "\010\013ServiceProcessorClass3", - "\010\014GraphicAssist", - "\010\017SystemPlanar", - "\010\200OtherSystemPeripheral", - "\011\000KeyboardController", - "\011\001Digitizer", - "\011\002MouseController", - "\011\003TabletController", - "\011\0x80OtherInputController", - "\012\000GeneralMemoryController", - NULL -}; - -/* Device Interface Type Codes */ - -unsigned char * PnP_INTERFACES[] __initdata = { - "\000\000\000General", - "\001\000\000GeneralSCSI", - "\001\001\000GeneralIDE", - "\001\001\001ATACompatible", - - "\001\002\000GeneralFloppy", - "\001\002\001Compatible765", - "\001\002\002NS398_Floppy", /* NS Super I/O wired to use index - register at port 398 and data - register at port 399 */ - "\001\002\003NS26E_Floppy", /* Ports 26E and 26F */ - "\001\002\004NS15C_Floppy", /* Ports 15C and 15D */ - "\001\002\005NS2E_Floppy", /* Ports 2E and 2F */ - "\001\002\006CHRP_Floppy", /* CHRP Floppy in PR*P system */ - - "\001\003\000GeneralIPI", - - "\002\000\000GeneralEther", - "\002\001\000GeneralToken", - "\002\002\000GeneralFDDI", - - "\003\000\000GeneralVGA", - "\003\001\000GeneralSVGA", - "\003\002\000GeneralXGA", - - "\004\000\000GeneralVideo", - "\004\001\000GeneralAudio", - "\004\001\001CS4232Audio", /* CS 4232 Plug 'n Play Configured */ - - "\005\000\000GeneralRAM", - /* This one is obviously wrong ! */ - "\005\000\000PCIMemoryController", /* PCI Config Method */ - "\005\000\001RS6KMemoryController", /* RS6K Config Method */ - "\005\001\000GeneralFLASH", - - "\006\000\000GeneralHostBridge", - "\006\001\000GeneralISABridge", - "\006\002\000GeneralEISABridge", - "\006\003\000GeneralMCABridge", - /* GeneralPCIBridge = 0, */ - "\006\004\000PCIBridgeDirect", - "\006\004\001PCIBridgeIndirect", - "\006\004\002PCIBridgeRS6K", - "\006\005\000GeneralPCMCIABridge", - "\006\006\000GeneralVMEBridge", - - "\007\000\000GeneralRS232", - "\007\000\001COMx", - "\007\000\002Compatible16450", - "\007\000\003Compatible16550", - "\007\000\004NS398SerPort", /* NS Super I/O wired to use index - register at port 398 and data - register at port 399 */ - "\007\000\005NS26ESerPort", /* Ports 26E and 26F */ - "\007\000\006NS15CSerPort", /* Ports 15C and 15D */ - "\007\000\007NS2ESerPort", /* Ports 2E and 2F */ - - "\007\001\000GeneralParPort", - "\007\001\001LPTx", - "\007\001\002NS398ParPort", /* NS Super I/O wired to use index - register at port 398 and data - register at port 399 */ - "\007\001\003NS26EParPort", /* Ports 26E and 26F */ - "\007\001\004NS15CParPort", /* Ports 15C and 15D */ - "\007\001\005NS2EParPort", /* Ports 2E and 2F */ - - "\010\000\000GeneralPIC", - "\010\000\001ISA_PIC", - "\010\000\002EISA_PIC", - "\010\000\003MPIC", - "\010\000\004RS6K_PIC", - - "\010\001\000GeneralDMA", - "\010\001\001ISA_DMA", - "\010\001\002EISA_DMA", - - "\010\002\000GeneralTimer", - "\010\002\001ISA_Timer", - "\010\002\002EISA_Timer", - "\010\003\000GeneralRTC", - "\010\003\001ISA_RTC", - - "\010\004\001StoreThruOnly", - "\010\004\002StoreInEnabled", - "\010\004\003RS6KL2Cache", - - "\010\005\000IndirectNVRAM", /* Indirectly addressed */ - "\010\005\001DirectNVRAM", /* Memory Mapped */ - "\010\005\002IndirectNVRAM24", /* Indirectly addressed - 24 bit */ - - "\010\006\000GeneralPowerManagement", - "\010\006\001EPOWPowerManagement", - "\010\006\002PowerControl", // d1378 - - "\010\007\000GeneralCMOS", - - "\010\010\000GeneralOPPanel", - "\010\010\001HarddiskLight", - "\010\010\002CDROMLight", - "\010\010\003PowerLight", - "\010\010\004KeyLock", - "\010\010\005ANDisplay", /* AlphaNumeric Display */ - "\010\010\006SystemStatusLED", /* 3 digit 7 segment LED */ - "\010\010\007CHRP_SystemStatusLED", /* CHRP LEDs in PR*P system */ - - "\010\011\000GeneralServiceProcessor", - "\010\012\000GeneralServiceProcessor", - "\010\013\000GeneralServiceProcessor", - - "\010\014\001TransferData", - "\010\014\002IGMC32", - "\010\014\003IGMC64", - - "\010\017\000GeneralSystemPlanar", /* 10/5/95 */ - NULL - }; - -static const unsigned char __init *PnP_SUB_TYPE_STR(unsigned char BaseType, - unsigned char SubType) { - unsigned char ** s=PnP_SUB_TYPES; - while (*s && !((*s)[0]==BaseType - && (*s)[1]==SubType)) s++; - if (*s) return *s+2; - else return("Unknown !"); -}; - -static const unsigned char __init *PnP_INTERFACE_STR(unsigned char BaseType, - unsigned char SubType, - unsigned char Interface) { - unsigned char ** s=PnP_INTERFACES; - while (*s && !((*s)[0]==BaseType - && (*s)[1]==SubType - && (*s)[2]==Interface)) s++; - if (*s) return *s+3; - else return NULL; -}; - -static void __init printsmallvendor(PnP_TAG_PACKET *pkt, int size) { - int i, c; - char decomp[4]; -#define p pkt->S14_Pack.S14_Data.S14_PPCPack - switch(p.Type) { - case 1: - /* Decompress first 3 chars */ - c = *(unsigned short *)p.PPCData; - decomp[0]='A'-1+((c>>10)&0x1F); - decomp[1]='A'-1+((c>>5)&0x1F); - decomp[2]='A'-1+(c&0x1F); - decomp[3]=0; - printk(" Chip identification: %s%4.4X\n", - decomp, ld_le16((unsigned short *)(p.PPCData+2))); - break; - default: - printk(" Small vendor item type 0x%2.2x, data (hex): ", - p.Type); - for(i=0; i<size-2; i++) printk("%2.2x ", p.PPCData[i]); - printk("\n"); - break; - } -#undef p -} - -static void __init printsmallpacket(PnP_TAG_PACKET * pkt, int size) { - static const unsigned char * intlevel[] = {"high", "low"}; - static const unsigned char * intsense[] = {"edge", "level"}; - - switch (tag_small_item_name(pkt->S1_Pack.Tag)) { - case PnPVersion: - printk(" PnPversion 0x%x.%x\n", - pkt->S1_Pack.Version[0], /* How to interpret version ? */ - pkt->S1_Pack.Version[1]); - break; -// case Logicaldevice: - break; -// case CompatibleDevice: - break; - case IRQFormat: -#define p pkt->S4_Pack - printk(" IRQ Mask 0x%4.4x, %s %s sensitive\n", - ld_le16((unsigned short *)p.IRQMask), - intlevel[(size>3) ? !(p.IRQInfo&0x05) : 0], - intsense[(size>3) ? !(p.IRQInfo&0x03) : 0]); -#undef p - break; - case DMAFormat: -#define p pkt->S5_Pack - printk(" DMA channel mask 0x%2.2x, info 0x%2.2x\n", - p.DMAMask, p.DMAInfo); -#undef p - break; - case StartDepFunc: - printk("Start dependent function:\n"); - break; - case EndDepFunc: - printk("End dependent function\n"); - break; - case IOPort: -#define p pkt->S8_Pack - printk(" Variable (%d decoded bits) I/O port\n" - " from 0x%4.4x to 0x%4.4x, alignment %d, %d ports\n", - p.IOInfo&ISAAddr16bit?16:10, - ld_le16((unsigned short *)p.RangeMin), - ld_le16((unsigned short *)p.RangeMax), - p.IOAlign, p.IONum); -#undef p - break; - case FixedIOPort: -#define p pkt->S9_Pack - printk(" Fixed (10 decoded bits) I/O port from %3.3x to %3.3x\n", - (p.Range[1]<<8)|p.Range[0], - ((p.Range[1]<<8)|p.Range[0])+p.IONum-1); -#undef p - break; - case Res1: - case Res2: - case Res3: - printk(" Undefined packet type %d!\n", - tag_small_item_name(pkt->S1_Pack.Tag)); - break; - case SmallVendorItem: - printsmallvendor(pkt,size); - break; - default: - printk(" Type 0x2.2x%d, size=%d\n", - pkt->S1_Pack.Tag, size); - break; - } -} - -static void __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"}; - static const unsigned char * transtype[] = {"direct", "mapped", "direct-store segment"}; - static const unsigned char * L2type[] = {"WriteThru", "CopyBack"}; - static const unsigned char * L2assoc[] = {"DirectMapped", "2-way set"}; - - int i; - char tmpstr[30], *t; -#define p pkt->L4_Pack.L4_Data.L4_PPCPack - switch(p.Type) { - case 2: - printk(" %d K %s %s L2 cache, %d/%d bytes line/sector size\n", - ld_le32((unsigned int *)p.PPCData), - L2type[p.PPCData[10]-1], - L2assoc[p.PPCData[4]-1], - ld_le16((unsigned short *)p.PPCData+3), - ld_le16((unsigned short *)p.PPCData+4)); - break; - case 3: - printk(" PCI Bridge parameters\n" - " ConfigBaseAddress %0x\n" - " ConfigBaseData %0x\n" - " Bus number %d\n", - ld_le32((unsigned int *)p.PPCData), - ld_le32((unsigned int *)(p.PPCData+8)), - p.PPCData[16]); - for(i=20; i<size-4; i+=12) { - int j, first; - if(p.PPCData[i]) printk(" PCI Slot %d", p.PPCData[i]); - else printk (" Integrated PCI device"); - for(j=0, first=1, t=tmpstr; j<4; j++) { - int line=ld_le16((unsigned short *)(p.PPCData+i+4)+j); - if(line!=0xffff){ - if(first) first=0; else *t++='/'; - *t++='A'+j; - } - } - *t='\0'; - printk(" DevFunc 0x%x interrupt line(s) %s routed to", - p.PPCData[i+1],tmpstr); - sprintf(tmpstr, - inttype[p.PPCData[i+2]-1], - p.PPCData[i+3]); - printk(" %s line(s) ", - tmpstr); - for(j=0, first=1, t=tmpstr; j<4; j++) { - int line=ld_le16((unsigned short *)(p.PPCData+i+4)+j); - if(line!=0xffff){ - if(first) first=0; else *t++='/'; - t+=sprintf(t,"%d(%c)", - line&0x7fff, - line&0x8000?'E':'L'); - } - } - printk("%s\n",tmpstr); - } - break; - case 5: - printk(" Bridge address translation, %s decoding:\n" - " Processor Bus Size Conversion Translation\n" - " 0x%8.8x 0x%8.8x 0x%8.8x %s %s\n", - p.PPCData[0]&1 ? "positive" : "subtractive", - ld_le32((unsigned int *)p.PPCData+1), - ld_le32((unsigned int *)p.PPCData+3), - ld_le32((unsigned int *)p.PPCData+5), - convtype[p.PPCData[2]-1], - transtype[p.PPCData[1]-1]); - break; - case 6: - printk(" Bus speed %d Hz, %d slot(s)\n", - ld_le32((unsigned int *)p.PPCData), - p.PPCData[4]); - break; - case 7: - printk(" SCSI buses: %d, id(s):", p.PPCData[0]); - for(i=1; i<=p.PPCData[0]; i++) - printk(" %d%c", p.PPCData[i], i==p.PPCData[0] ? '\n' : ','); - break; - case 9: - printk(" %s address (%d bits), at 0x%x size 0x%x bytes\n", - addrtype[p.PPCData[0]-1], - p.PPCData[1], - ld_le32((unsigned int *)(p.PPCData+4)), - ld_le32((unsigned int *)(p.PPCData+12))); - break; - case 10: - sprintf(tmpstr, - inttype[p.PPCData[0]-1], - p.PPCData[1]); - - printk(" ISA interrupts routed to %s\n" - " lines", - tmpstr); - for(i=0; i<16; i++) { - int line=ld_le16((unsigned short *)p.PPCData+i+1); - if (line!=0xffff) printk(" %d(IRQ%d)", line, i); - } - printk("\n"); - break; - default: - printk(" Large vendor item type 0x%2.2x\n Data (hex):", - p.Type); - for(i=0; i<size-4; i++) printk(" %2.2x", p.PPCData[i]); - printk("\n"); -#undef p - } -} - -static void __init printlargepacket(PnP_TAG_PACKET * pkt, int size) { - switch (tag_large_item_name(pkt->S1_Pack.Tag)) { - case LargeVendorItem: - printlargevendor(pkt, size); - break; - default: - printk(" Type 0x2.2x%d, size=%d\n", - pkt->S1_Pack.Tag, size); - break; - } -} -static void __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; - } - printk( " Packets describing %s resources:\n",cat); - do { - int size; - if (tag_type(pkt->S1_Pack.Tag)) { - size= 3 + - pkt->L1_Pack.Count0 + - pkt->L1_Pack.Count1*256; - printlargepacket(pkt, size); - } else { - size=tag_small_count(pkt->S1_Pack.Tag)+1; - printsmallpacket(pkt, size); - } - (unsigned char *) pkt+=size; - } while (pkt->S1_Pack.Tag != END_TAG); -} - -void __init print_residual_device_info(void) -{ - int i; - PPC_DEVICE *dev; -#define did dev->DeviceId - - /* make sure we have residual data first */ - if ( res->ResidualLength == 0 ) - return; - - printk("Residual: %ld devices\n", res->ActualNumDevices); - for ( i = 0; - i < res->ActualNumDevices ; - i++) - { - char decomp[4], sn[20]; - const char * s; - dev = &res->Devices[i]; - s = PnP_INTERFACE_STR(did.BaseType, did.SubType, - did.Interface); - if(!s) { - sprintf(sn, "interface %d", did.Interface); - s=sn; - } - if ( did.BusId & PCIDEVICE ) - printk("PCI Device, Bus %d, DevFunc 0x%x:", - dev->BusAccess.PCIAccess.BusNumber, - dev->BusAccess.PCIAccess.DevFuncNumber); - if ( did.BusId & PNPISADEVICE ) printk("PNPISA Device:"); - if ( did.BusId & ISADEVICE ) - printk("ISA Device, Slot %d, LogicalDev %d:", - dev->BusAccess.ISAAccess.SlotNumber, - dev->BusAccess.ISAAccess.LogicalDevNumber); - if ( did.BusId & EISADEVICE ) printk("EISA Device:"); - if ( did.BusId & PROCESSORDEVICE ) - printk("ProcBus Device, Bus %d, BUID %d: ", - dev->BusAccess.ProcBusAccess.BusNumber, - dev->BusAccess.ProcBusAccess.BUID); - if ( did.BusId & PCMCIADEVICE ) printk("PCMCIA "); - if ( did.BusId & VMEDEVICE ) printk("VME "); - if ( did.BusId & MCADEVICE ) printk("MCA "); - if ( did.BusId & MXDEVICE ) printk("MX "); - /* Decompress first 3 chars */ - decomp[0]='A'-1+((did.DevId>>26)&0x1F); - decomp[1]='A'-1+((did.DevId>>21)&0x1F); - decomp[2]='A'-1+((did.DevId>>16)&0x1F); - decomp[3]=0; - printk(" %s%4.4lX, %s, %s, %s\n", - decomp, did.DevId&0xffff, - PnP_BASE_TYPES[did.BaseType], - PnP_SUB_TYPE_STR(did.BaseType,did.SubType), - s); - 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"); - } -} - - -#if 0 -static void __init printVPD(void) { -#define vpd res->VitalProductData - int ps=vpd.PageSize, i, j; - static const char* Usage[]={ - "FirmwareStack", "FirmwareHeap", "FirmwareCode", "BootImage", - "Free", "Unpopulated", "ISAAddr", "PCIConfig", - "IOMemory", "SystemIO", "SystemRegs", "PCIAddr", - "UnPopSystemRom", "SystemROM", "ResumeBlock", "Other" - }; - static const unsigned char *FWMan[]={ - "IBM", "Motorola", "FirmWorks", "Bull" - }; - static const unsigned char *FWFlags[]={ - "Conventional", "OpenFirmware", "Diagnostics", "LowDebug", - "MultiBoot", "LowClient", "Hex41", "FAT", - "ISO9660", "SCSI_ID_Override", "Tape_Boot", "FW_Boot_Path" - }; - static const unsigned char *ESM[]={ - "Port92", "PCIConfigA8", "FF001030", "????????" - }; - static const unsigned char *SIOM[]={ - "Port850", "????????", "PCIConfigA8", "????????" - }; - - printk("Model: %s\n",vpd.PrintableModel); - printk("Serial: %s\n", vpd.Serial); - printk("FirmwareSupplier: %s\n", FWMan[vpd.FirmwareSupplier]); - printk("FirmwareFlags:"); - for(j=0; j<12; j++) { - if (vpd.FirmwareSupports & (1<<j)) { - printk(" %s%c", FWFlags[j], - vpd.FirmwareSupports&(-2<<j) ? ',' : '\n'); - } - } - printk("NVRamSize: %ld\n", vpd.NvramSize); - printk("SIMMslots: %ld\n", vpd.NumSIMMSlots); - printk("EndianSwitchMethod: %s\n", - ESM[vpd.EndianSwitchMethod>2 ? 2 : vpd.EndianSwitchMethod]); - printk("SpreadIOMethod: %s\n", - SIOM[vpd.SpreadIOMethod>3 ? 3 : vpd.SpreadIOMethod]); - printk("Processor/Bus frequencies (Hz): %ld/%ld\n", - vpd.ProcessorHz, vpd.ProcessorBusHz); - printk("Time Base Divisor: %ld\n", vpd.TimeBaseDivisor); - printk("WordWidth, PageSize: %ld, %d\n", vpd.WordWidth, ps); - printk("Cache sector size, Lock granularity: %ld, %ld\n", - vpd.CoherenceBlockSize, vpd.GranuleSize); - for (i=0; i<res->ActualNumMemSegs; i++) { - int mask=res->Segs[i].Usage, first, j; - printk("%8.8lx-%8.8lx ", - res->Segs[i].BasePage*ps, - (res->Segs[i].PageCount+res->Segs[i].BasePage)*ps-1); - for(j=15, first=1; j>=0; j--) { - if (mask&(1<<j)) { - if (first) first=0; - else printk(", "); - printk("%s", Usage[j]); - } - } - printk("\n"); - } -} - -/* - * Spit out some info about residual data - */ -void print_residual_device_info(void) -{ - int i; - union _PnP_TAG_PACKET *pkt; - PPC_DEVICE *dev; -#define did dev->DeviceId - - /* make sure we have residual data first */ - if ( res->ResidualLength == 0 ) - return; - printk("Residual: %ld devices\n", res->ActualNumDevices); - for ( i = 0; - i < res->ActualNumDevices ; - i++) - { - dev = &res->Devices[i]; - /* - * pci devices - */ - if ( did.BusId & PCIDEVICE ) - { - printk("PCI Device:"); - /* unknown vendor */ - if ( !strncmp( "Unknown", pci_strvendor(did.DevId>>16), 7) ) - printk(" id %08lx types %d/%d", did.DevId, - did.BaseType, did.SubType); - /* known vendor */ - else - printk(" %s %s", - pci_strvendor(did.DevId>>16), - pci_strdev(did.DevId>>16, - did.DevId&0xffff) - ); - - if ( did.BusId & PNPISADEVICE ) - { - printk(" pnp:"); - /* get pnp info on the device */ - pkt = (union _PnP_TAG_PACKET *) - &res->DevicePnPHeap[dev->AllocatedOffset]; - for (; pkt->S1_Pack.Tag != DF_END_TAG; - pkt++ ) - { - if ( (pkt->S1_Pack.Tag == S4_Packet) || - (pkt->S1_Pack.Tag == S4_Packet_flags) ) - printk(" irq %02x%02x", - pkt->S4_Pack.IRQMask[0], - pkt->S4_Pack.IRQMask[1]); - } - } - printk("\n"); - continue; - } - /* - * isa devices - */ - if ( did.BusId & ISADEVICE ) - { - printk("ISA Device: basetype: %d subtype: %d", - did.BaseType, did.SubType); - printk("\n"); - continue; - } - /* - * eisa devices - */ - if ( did.BusId & EISADEVICE ) - { - printk("EISA Device: basetype: %d subtype: %d", - did.BaseType, did.SubType); - printk("\n"); - continue; - } - /* - * proc bus devices - */ - if ( did.BusId & PROCESSORDEVICE ) - { - printk("ProcBus Device: basetype: %d subtype: %d", - did.BaseType, did.SubType); - printk("\n"); - continue; - } - /* - * pcmcia devices - */ - if ( did.BusId & PCMCIADEVICE ) - { - printk("PCMCIA Device: basetype: %d subtype: %d", - did.BaseType, did.SubType); - printk("\n"); - continue; - } - printk("Unknown bus access device: busid %lx\n", - did.BusId); - } -} -#endif - -/* 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 ! - - Examples: - - search for the Interrupt controller (8259 type), 2 methods: - 1) i8259 = residual_find_device(~0, - NULL, - SystemPeripheral, - ProgrammableInterruptController, - ISA_PIC, - 0); - 2) i8259 = residual_find_device(~0, "PNP0000", -1, -1, -1, 0) - - - search for the first two serial devices, whatever their type) - iserial1 = residual_find_device(~0,NULL, - CommunicationsDevice, - RS232Device, - -1, 0) - iserial2 = residual_find_device(~0,NULL, - CommunicationsDevice, - RS232Device, - -1, 1) - - but search for typical COM1 and COM2 is not easy due to the - fact that the interface may be anything and the name "PNP0500" or - "PNP0501". Quite bad. - -*/ - -/* devid are easier to uncompress than to compress, so to minimize bloat -in this rarely used area we unencode and compare */ - -/* in residual data number is big endian in the device table and -little endian in the heap, so we use two parameters to avoid writing -two very similar functions */ - -static int __init same_DevID(unsigned short vendor, - unsigned short Number, - char * str) -{ - static unsigned const char hexdigit[]="0123456789ABCDEF"; - if (strlen(str)!=7) return 0; - if ( ( ((vendor>>10)&0x1f)+'A'-1 == str[0]) && - ( ((vendor>>5)&0x1f)+'A'-1 == str[1]) && - ( (vendor&0x1f)+'A'-1 == str[2]) && - (hexdigit[(Number>>12)&0x0f] == str[3]) && - (hexdigit[(Number>>8)&0x0f] == str[4]) && - (hexdigit[(Number>>4)&0x0f] == str[5]) && - (hexdigit[Number&0x0f] == str[6]) ) return 1; - return 0; -} - -PPC_DEVICE __init *residual_find_device(unsigned long BusMask, - unsigned char * 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==NULL || same_DevID((Dev.DevId>>16)&0xffff, - Dev.DevId&0xffff, DevID)) && - !(n--) ) return res->Devices+i; -#undef Dev - } - 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) -{ - unsigned mask, masked_tag, size; - if(!p) return 0; - if (tag_type(packet_tag)) mask=0xff; else mask=0xF8; - masked_tag = packet_tag&mask; - for(; *p != END_TAG; p+=size) { - if ((*p & mask) == masked_tag && !(n--)) - return (PnP_TAG_PACKET *) p; - if (tag_type(*p)) - size=ld_le16((unsigned short *)(p+1))+3; - else - size=tag_small_count(*p)+1; - } - return 0; /* not found */ -} - -PnP_TAG_PACKET __init *PnP_find_small_vendor_packet(unsigned char *p, - unsigned packet_type, - int n) -{ - int next=0; - while (p) { - p = (unsigned char *) PnP_find_packet(p, 0x70, next); - if (p && p[1]==packet_type && !(n--)) - return (PnP_TAG_PACKET *) p; - next = 1; - }; - return 0; /* not found */ -} - -PnP_TAG_PACKET __init *PnP_find_large_vendor_packet(unsigned char *p, - unsigned packet_type, - int n) -{ - int next=0; - while (p) { - p = (unsigned char *) PnP_find_packet(p, 0x84, next); - if (p && p[3]==packet_type && !(n--)) - return (PnP_TAG_PACKET *) p; - next = 1; - }; - return 0; /* not found */ -} diff --git a/arch/ppc/kernel/semaphore.c b/arch/ppc/kernel/semaphore.c index ac7589238ea2..5eb1ccbe4fae 100644 --- a/arch/ppc/kernel/semaphore.c +++ b/arch/ppc/kernel/semaphore.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.semaphore.c 1.12 05/17/01 18:14:22 cort + * BK Id: %F% %I% %G% %U% %#% */ /* * PowerPC-specific semaphore code. @@ -39,6 +39,7 @@ static inline int __sem_update_count(struct semaphore *sem, int incr) " srawi %1,%0,31\n" " andc %1,%0,%1\n" " add %1,%1,%4\n" + PPC405_ERR77(0,%3) " stwcx. %1,0,%3\n" " bne 1b" : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count) diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index a8765201c99a..da82585918a1 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.setup.c 1.65 11/18/01 20:57:25 trini + * BK Id: %F% %I% %G% %U% %#% */ /* * Common prep/pmac/chrp boot and setup code. @@ -29,35 +29,32 @@ #include <asm/smp.h> #include <asm/elf.h> #include <asm/cputable.h> -#ifdef CONFIG_8xx -#include <asm/mpc8xx.h> -#include <asm/8xx_immap.h> -#endif -#ifdef CONFIG_8260 -#include <asm/mpc8260.h> -#include <asm/immap_8260.h> -#endif -#ifdef CONFIG_4xx -#include <asm/ppc4xx.h> -#endif #include <asm/bootx.h> #include <asm/btext.h> #include <asm/machdep.h> -#include <asm/feature.h> #include <asm/uaccess.h> #include <asm/system.h> +#include <asm/pmac_feature.h> + +#if defined CONFIG_KGDB +#include <asm/kgdb.h> +#endif extern void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7); extern void bootx_init(unsigned long r4, unsigned long phys); -extern unsigned long reloc_offset(void); extern void identify_cpu(unsigned long offset, unsigned long cpu); extern void do_cpu_ftr_fixups(unsigned long offset); +extern void reloc_got2(unsigned long offset); #ifdef CONFIG_XMON extern void xmon_map_scc(void); #endif +#ifdef CONFIG_KGDB +extern void kgdb_map_scc(void); +#endif + extern boot_infos_t *boot_infos; char saved_command_line[256]; unsigned char aux_device_present; @@ -69,8 +66,6 @@ unsigned long sysmap_size; size value reported by the boot loader. */ unsigned int boot_mem_size; -int parse_bootinfo(void); - unsigned long ISA_DMA_THRESHOLD; unsigned long DMA_MODE_READ, DMA_MODE_WRITE; @@ -103,7 +98,8 @@ int dcache_bsize; int icache_bsize; int ucache_bsize; -#ifdef CONFIG_VGA_CONSOLE +#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_FB_VGA16) || \ + defined(CONFIG_FB_VGA16_MODULE) || defined(CONFIG_FB_VESA) struct screen_info screen_info = { 0, 25, /* orig-x, orig-y */ 0, /* unused */ @@ -115,7 +111,7 @@ struct screen_info screen_info = { 1, /* orig-video-isVGA */ 16 /* orig-video-points */ }; -#endif /* CONFIG_VGA_CONSOLE */ +#endif /* CONFIG_VGA_CONSOLE || CONFIG_FB_VGA16 || CONFIG_FB_VESA */ void machine_restart(char *cmd) { @@ -291,22 +287,22 @@ early_init(int r3, int r4, int r5) do_cpu_ftr_fixups(offset); #if defined(CONFIG_ALL_PPC) + reloc_got2(offset); + /* If we came here from BootX, clear the screen, * set up some pointers and return. */ - if ((r3 == 0x426f6f58) && (r5 == 0)) { + if ((r3 == 0x426f6f58) && (r5 == 0)) bootx_init(r4, phys); - return phys; - } - - /* check if we're prep, return if we are */ - if ( *(unsigned long *)(0) == 0xdeadc0de ) - return phys; - /* + /* + * don't do anything on prep * for now, don't use bootinfo because it breaks yaboot 0.5 * and assume that if we didn't find a magic number, we have OF */ - phys = prom_init(r3, r4, (prom_entry)r5); + else if (*(unsigned long *)(0) != 0xdeadc0de) + phys = prom_init(r3, r4, (prom_entry)r5); + + reloc_got2(-offset); #endif return phys; @@ -343,14 +339,14 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) { #ifdef CONFIG_BOOTX_TEXT - extern boot_infos_t *disp_bi; - - if (disp_bi) { + if (boot_text_mapped) { btext_clearscreen(); - btext_welcome(disp_bi); + btext_welcome(); } #endif + parse_bootinfo(find_bootinfo()); + /* if we didn't get any bootinfo telling us what we are... */ if (_machine == 0) { /* prep boot loader tells us if we're prep or not */ @@ -409,15 +405,14 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, char *p; #ifdef CONFIG_BLK_DEV_INITRD - if (r3 && r4 && r4 != 0xdeadbeef) - { - if (r3 < KERNELBASE) - r3 += KERNELBASE; - initrd_start = r3; - initrd_end = r3 + r4; - ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); - initrd_below_start_ok = 1; - } + if (r3 && r4 && r4 != 0xdeadbeef) { + if (r3 < KERNELBASE) + r3 += KERNELBASE; + initrd_start = r3; + initrd_end = r3 + r4; + ROOT_DEV = mk_kdev(RAMDISK_MAJOR, 0); + initrd_below_start_ok = 1; + } #endif chosen = find_devices("chosen"); if (chosen != NULL) { @@ -429,6 +424,12 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, } } cmd_line[sizeof(cmd_line) - 1] = 0; +#ifdef CONFIG_ADB + if (strstr(cmd_line, "adb_sync")) { + extern int __adb_probe_sync; + __adb_probe_sync = 1; + } +#endif /* CONFIG_ADB */ switch (_machine) { case _MACH_Pmac: @@ -441,7 +442,7 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, } #endif /* CONFIG_ALL_PPC */ -int parse_bootinfo(void) +struct bi_record *find_bootinfo(void) { struct bi_record *rec; extern char __bss_start[]; @@ -455,11 +456,16 @@ int parse_bootinfo(void) */ rec = (struct bi_record *)_ALIGN((ulong)__bss_start+0x10000+(1<<20)-1,(1<<20)); if ( rec->tag != BI_FIRST ) - return -1; + return NULL; } - for ( ; rec->tag != BI_LAST ; - rec = (struct bi_record *)((ulong)rec + rec->size) ) - { + return rec; +} + +void parse_bootinfo(struct bi_record *rec) +{ + if (rec == NULL || rec->tag != BI_FIRST) + return; + while (rec->tag != BI_LAST) { ulong *data = rec->data; switch (rec->tag) { case BI_CMD_LINE: @@ -485,9 +491,8 @@ int parse_bootinfo(void) boot_mem_size = data[0]; break; } + rec = (struct bi_record *)((ulong)rec + rec->size); } - - return 0; } /* @@ -504,8 +509,6 @@ machine_init(unsigned long r3, unsigned long r4, unsigned long r5, strcpy(cmd_line, CONFIG_CMDLINE); #endif /* CONFIG_CMDLINE */ - parse_bootinfo(); - platform_init(r3, r4, r5, r6, r7); if (ppc_md.progress) @@ -525,7 +528,7 @@ int __init ppc_setup_l2cr(char *str) } __setup("l2cr=", ppc_setup_l2cr); -void __init ppc_init(void) +int __init ppc_init(void) { /* clear the progress line */ if ( ppc_md.progress ) ppc_md.progress(" ", 0xffff); @@ -533,9 +536,10 @@ void __init ppc_init(void) if (ppc_md.init != NULL) { ppc_md.init(); } + init_crc32(); } -subsys_initcall(ppc_init); +arch_initcall(ppc_init); /* Warning, IO base is not yet inited */ void __init setup_arch(char **cmdline_p) @@ -549,8 +553,13 @@ void __init setup_arch(char **cmdline_p) loops_per_jiffy = 500000000 / HZ; #ifdef CONFIG_ALL_PPC - feature_init(); -#endif + /* This could be called "early setup arch", it must be done + * now because xmon need it + */ + if (_machine == _MACH_Pmac) + pmac_feature_init(); /* New cool way */ +#endif /* CONFIG_ALL_PPC */ + #ifdef CONFIG_XMON xmon_map_scc(); if (strstr(cmd_line, "xmon")) @@ -561,7 +570,12 @@ void __init setup_arch(char **cmdline_p) #if defined(CONFIG_KGDB) kgdb_map_scc(); set_debug_traps(); - breakpoint(); + if (strstr(cmd_line, "nokgdb")) + printk("kgdb default breakpoint deactivated on command line\n"); + else { + printk("kgdb default breakpoint activated\n"); + breakpoint(); + } #endif /* @@ -596,24 +610,6 @@ void __init setup_arch(char **cmdline_p) ppc_md.setup_arch(); if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab); -#if defined(CONFIG_PCI) && defined(CONFIG_ALL_PPC) - /* We create the "pci-OF-bus-map" property now so it appear in the - * /proc device tree - */ - if (have_of) { - struct property* of_prop; - - of_prop = (struct property*)alloc_bootmem(sizeof(struct property) + 256); - if (of_prop && find_path_device("/")) { - memset(of_prop, -1, sizeof(struct property) + 256); - of_prop->name = "pci-OF-bus-map"; - of_prop->length = 256; - of_prop->value = (unsigned char *)&of_prop[1]; - prom_add_property(find_path_device("/"), of_prop); - } - } -#endif /* CONFIG_PCI && CONFIG_ALL_PPC */ - paging_init(); sort_exception_table(); @@ -621,6 +617,7 @@ void __init setup_arch(char **cmdline_p) ppc_md.ppc_machine = _machine; } +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) /* Convert the shorts/longs in hd_driveid from little to big endian; * chars are endian independant, of course, but strings need to be flipped. * (Despite what it says in drivers/block/ide.h, they come up as little @@ -715,3 +712,4 @@ void ppc_generic_ide_fix_driveid(struct hd_driveid *id) id->words206_254[i] = __le16_to_cpu(id->words206_254[i]); id->integrity_word = __le16_to_cpu(id->integrity_word); } +#endif diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c index 58ad86fa0c53..394d8abb05dc 100644 --- a/arch/ppc/kernel/signal.c +++ b/arch/ppc/kernel/signal.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.signal.c 1.7 05/17/01 18:14:22 cort + * BK Id: %F% %I% %G% %U% %#% */ /* * linux/arch/ppc/kernel/signal.c @@ -29,6 +29,7 @@ #include <linux/unistd.h> #include <linux/stddef.h> #include <linux/elf.h> +#include <linux/tty.h> #include <asm/ucontext.h> #include <asm/uaccess.h> #include <asm/pgtable.h> @@ -180,7 +181,7 @@ sys_sigaction(int sig, const struct old_sigaction *act, siginitset(&new_ka.sa.sa_mask, mask); } - ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + ret = do_sigaction(sig, (act? &new_ka: NULL), (oact? &old_ka: NULL)); if (!ret && oact) { if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || @@ -254,6 +255,8 @@ int sys_rt_sigreturn(struct pt_regs *regs) current->blocked = set; recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); + if (regs->msr & MSR_FP) + giveup_fpu(current); rt_sf++; /* Look at next rt_sigframe */ if (rt_sf == (struct rt_sigframe *)(sigctx.regs)) { @@ -263,8 +266,6 @@ int sys_rt_sigreturn(struct pt_regs *regs) * see handle_signal() */ sr = (struct sigregs *) sigctx.regs; - if (regs->msr & MSR_FP ) - giveup_fpu(current); if (copy_from_user(saved_regs, &sr->gp_regs, sizeof(sr->gp_regs))) goto badframe; @@ -298,6 +299,7 @@ int sys_rt_sigreturn(struct pt_regs *regs) if (get_user(prevsp, &sr->gp_regs[PT_R1]) || put_user(prevsp, (unsigned long *) regs->gpr[1])) goto badframe; + current->thread.fpscr = 0; } return ret; @@ -328,6 +330,7 @@ setup_rt_frame(struct pt_regs *regs, struct sigregs *frame, goto badframe; flush_icache_range((unsigned long) &frame->tramp[0], (unsigned long) &frame->tramp[2]); + current->thread.fpscr = 0; /* turn off all fp exceptions */ /* Retrieve rt_sigframe from stack and set up registers for signal handler @@ -379,13 +382,13 @@ int sys_sigreturn(struct pt_regs *regs) current->blocked = set; recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); + if (regs->msr & MSR_FP ) + giveup_fpu(current); sc++; /* Look at next sigcontext */ if (sc == (struct sigcontext_struct *)(sigctx.regs)) { /* Last stacked signal - restore registers */ sr = (struct sigregs *) sigctx.regs; - if (regs->msr & MSR_FP ) - giveup_fpu(current); if (copy_from_user(saved_regs, &sr->gp_regs, sizeof(sr->gp_regs))) goto badframe; @@ -413,6 +416,7 @@ int sys_sigreturn(struct pt_regs *regs) if (get_user(prevsp, &sr->gp_regs[PT_R1]) || put_user(prevsp, (unsigned long *) regs->gpr[1])) goto badframe; + current->thread.fpscr = 0; } return ret; @@ -431,8 +435,8 @@ setup_frame(struct pt_regs *regs, struct sigregs *frame, if (verify_area(VERIFY_WRITE, frame, sizeof(*frame))) goto badframe; - if (regs->msr & MSR_FP) - giveup_fpu(current); + if (regs->msr & MSR_FP) + giveup_fpu(current); if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE) || __copy_to_user(&frame->fp_regs, current->thread.fpr, ELF_NFPREG * sizeof(double)) @@ -441,6 +445,7 @@ setup_frame(struct pt_regs *regs, struct sigregs *frame, goto badframe; flush_icache_range((unsigned long) &frame->tramp[0], (unsigned long) &frame->tramp[2]); + current->thread.fpscr = 0; /* turn off all fp exceptions */ newsp -= __SIGNAL_FRAMESIZE; if (put_user(regs->gpr[1], (unsigned long *)newsp) diff --git a/arch/ppc/kernel/sleep.S b/arch/ppc/kernel/sleep.S deleted file mode 100644 index 153e358c124a..000000000000 --- a/arch/ppc/kernel/sleep.S +++ /dev/null @@ -1,366 +0,0 @@ -/* - * BK Id: SCCS/s.sleep.S 1.13 08/19/01 22:23:04 paulus - */ -/* - * This file contains sleep low-level functions for PowerBook G3. - * Copyright (C) 1999 Benjamin Herrenschmidt (benh@kernel.crashing.org) - * and Paul Mackerras (paulus@samba.org). - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#include "ppc_asm.tmpl" -#include <asm/processor.h> -#include <asm/page.h> - -#define MAGIC 0x4c617273 /* 'Lars' */ - -/* - * Structure for storing CPU registers on the stack. - */ -#define SL_SP 0 -#define SL_PC 4 -#define SL_MSR 8 -#define SL_SDR1 0xc -#define SL_SPRG0 0x10 /* 4 sprg's */ -#define SL_DBAT0 0x20 -#define SL_IBAT0 0x28 -#define SL_DBAT1 0x30 -#define SL_IBAT1 0x38 -#define SL_DBAT2 0x40 -#define SL_IBAT2 0x48 -#define SL_DBAT3 0x50 -#define SL_IBAT3 0x58 -#define SL_TB 0x60 -#define SL_HID0 0x68 -#define SL_R2 0x6c -#define SL_R12 0x70 /* r12 to r31 */ -#define SL_SIZE (SL_R12 + 80) - -#define tophys(rd,rs) addis rd,rs,-KERNELBASE@h -#define tovirt(rd,rs) addis rd,rs,KERNELBASE@h - - .text - .align 5 - -/* This gets called by via-pmu.c late during the sleep process. - * The PMU was already send the sleep command and will shut us down - * soon. We need to save all that is needed and setup the wakeup - * vector that will be called by the ROM on wakeup - */ -_GLOBAL(low_sleep_handler) - mflr r0 - stw r0,4(r1) - stwu r1,-SL_SIZE(r1) - stw r2,SL_R2(r1) - stmw r12,SL_R12(r1) - - /* Save MSR & SDR1 */ - mfmsr r4 - stw r4,SL_MSR(r1) - mfsdr1 r4 - stw r4,SL_SDR1(r1) - - /* Get a stable timebase and save it */ -1: mftbu r4 - stw r4,SL_TB(r1) - mftb r5 - stw r5,SL_TB+4(r1) - mftbu r3 - cmpw r3,r4 - bne 1b - - /* Save SPRGs */ - mfsprg r4,0 - stw r4,SL_SPRG0(r1) - mfsprg r4,1 - stw r4,SL_SPRG0+4(r1) - mfsprg r4,2 - stw r4,SL_SPRG0+8(r1) - mfsprg r4,3 - stw r4,SL_SPRG0+12(r1) - - /* Save BATs */ - mfdbatu r4,0 - stw r4,SL_DBAT0(r1) - mfdbatl r4,0 - stw r4,SL_DBAT0+4(r1) - mfdbatu r4,1 - stw r4,SL_DBAT1(r1) - mfdbatl r4,1 - stw r4,SL_DBAT1+4(r1) - mfdbatu r4,2 - stw r4,SL_DBAT2(r1) - mfdbatl r4,2 - stw r4,SL_DBAT2+4(r1) - mfdbatu r4,3 - stw r4,SL_DBAT3(r1) - mfdbatl r4,3 - stw r4,SL_DBAT3+4(r1) - mfibatu r4,0 - stw r4,SL_IBAT0(r1) - mfibatl r4,0 - stw r4,SL_IBAT0+4(r1) - mfibatu r4,1 - stw r4,SL_IBAT1(r1) - mfibatl r4,1 - stw r4,SL_IBAT1+4(r1) - mfibatu r4,2 - stw r4,SL_IBAT2(r1) - mfibatl r4,2 - stw r4,SL_IBAT2+4(r1) - mfibatu r4,3 - stw r4,SL_IBAT3(r1) - mfibatl r4,3 - stw r4,SL_IBAT3+4(r1) - - /* Save HID0 */ - mfspr r4,HID0 - stw r4,SL_HID0(r1) - - /* The ROM can wake us up via 2 different vectors: - * - On wallstreet & lombard, we must write a magic - * value 'Lars' at address 4 and a pointer to a - * memory location containing the PC to resume from - * at address 0. - * - On Core99, we must store the wakeup vector at - * address 0x80 and eventually it's parameters - * at address 0x84. I've have some trouble with those - * parameters however and I no longer use them. - */ - lis r5,grackle_wake_up@ha - addi r5,r5,grackle_wake_up@l - tophys(r5,r5) - stw r5,SL_PC(r1) - lis r4,KERNELBASE@h - tophys(r5,r1) - addi r5,r5,SL_PC - lis r6,MAGIC@ha - addi r6,r6,MAGIC@l - stw r5,0(r4) - stw r6,4(r4) - /* Setup stuffs at 0x80-0x84 for Core99 */ - lis r3,core99_wake_up@ha - addi r3,r3,core99_wake_up@l - tophys(r3,r3) - stw r3,0x80(r4) - stw r5,0x84(r4) - /* Store a pointer to our backup storage into - * a kernel global - */ - lis r3,sleep_storage@ha - addi r3,r3,sleep_storage@l - stw r5,0(r3) - - -/* - * Flush the L1 data cache by reading the first 128kB of RAM - * and then flushing the same area with the dcbf instruction. - * The L2 cache has already been disabled. - */ - li r4,0x1000 /* 128kB / 32B */ - mtctr r4 - lis r4,KERNELBASE@h -1: - lwz r0,0(r4) - addi r4,r4,0x0020 /* Go to start of next cache line */ - bdnz 1b - sync - - li r4,0x1000 /* 128kB / 32B */ - mtctr r4 - lis r4,KERNELBASE@h -1: - dcbf r0,r4 - addi r4,r4,0x0020 /* Go to start of next cache line */ - bdnz 1b - sync - -/* - * Set the HID0 and MSR for sleep. - */ - mfspr r2,HID0 - rlwinm r2,r2,0,10,7 /* clear doze, nap */ - oris r2,r2,HID0_SLEEP@h - sync - mtspr HID0,r2 - sync - -/* This loop puts us back to sleep in case we have a spurrious - * wakeup so that the host bridge properly stays asleep. The - * CPU will be turned off, either after a known time (about 1 - * second) on wallstreet & lombard, or as soon as the CPU enters - * SLEEP mode on core99 - */ - mfmsr r2 - oris r2,r2,MSR_POW@h -1: sync - mtmsr r2 - isync - b 1b - -/* - * Here is the resume code. - */ - - -/* - * Core99 machines resume here - * r4 has the physical address of SL_PC(sp) (unused) - */ -_GLOBAL(core99_wake_up) - /* Make sure HID0 no longer contains any sleep bit */ - mfspr r3,HID0 - rlwinm r3,r3,0,11,7 /* clear SLEEP, NAP, DOZE bits */ - mtspr HID0,r3 - sync - isync - - /* Won't that cause problems on CPU that doesn't support it ? */ - lis r3, 0 - mtspr SPRN_MMCR0, r3 - - /* sanitize MSR */ - mfmsr r3 - ori r3,r3,MSR_EE|MSR_IP - xori r3,r3,MSR_EE|MSR_IP - sync - isync - mtmsr r3 - sync - isync - - /* Recover sleep storage */ - lis r3,sleep_storage@ha - addi r3,r3,sleep_storage@l - tophys(r3,r3) - lwz r1,0(r3) - - /* Pass thru to older resume code ... */ -/* - * Here is the resume code for older machines. - * r1 has the physical address of SL_PC(sp). - */ - -grackle_wake_up: - /* Enable and then Flash inval the instruction & data cache */ - mfspr r3,HID0 - ori r3,r3, HID0_ICE|HID0_ICFI|HID0_DCE|HID0_DCI - sync - isync - mtspr HID0,r3 - xori r3,r3, HID0_ICFI|HID0_DCI - mtspr HID0,r3 - sync - - /* Restore the remaining bits of the HID0 register. */ - subi r1,r1,SL_PC - lwz r3,SL_HID0(r1) - sync - isync - mtspr HID0,r3 - sync - isync - - /* Restore the kernel's segment registers, the - BATs, and SDR1. Then we can turn on the MMU. */ - 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,0x111 /* increment VSID */ - addis r4,r4,0x1000 /* address of next segment */ - bdnz 3b - - lwz r4,SL_SDR1(r1) - mtsdr1 r4 - lwz r4,SL_SPRG0(r1) - mtsprg 0,r4 - lwz r4,SL_SPRG0+4(r1) - mtsprg 1,r4 - lwz r4,SL_SPRG0+8(r1) - mtsprg 2,r4 - lwz r4,SL_SPRG0+12(r1) - mtsprg 3,r4 - - lwz r4,SL_DBAT0(r1) - mtdbatu 0,r4 - lwz r4,SL_DBAT0+4(r1) - mtdbatl 0,r4 - lwz r4,SL_DBAT1(r1) - mtdbatu 1,r4 - lwz r4,SL_DBAT1+4(r1) - mtdbatl 1,r4 - lwz r4,SL_DBAT2(r1) - mtdbatu 2,r4 - lwz r4,SL_DBAT2+4(r1) - mtdbatl 2,r4 - lwz r4,SL_DBAT3(r1) - mtdbatu 3,r4 - lwz r4,SL_DBAT3+4(r1) - mtdbatl 3,r4 - lwz r4,SL_IBAT0(r1) - mtibatu 0,r4 - lwz r4,SL_IBAT0+4(r1) - mtibatl 0,r4 - lwz r4,SL_IBAT1(r1) - mtibatu 1,r4 - lwz r4,SL_IBAT1+4(r1) - mtibatl 1,r4 - lwz r4,SL_IBAT2(r1) - mtibatu 2,r4 - lwz r4,SL_IBAT2+4(r1) - mtibatl 2,r4 - lwz r4,SL_IBAT3(r1) - mtibatu 3,r4 - lwz r4,SL_IBAT3+4(r1) - mtibatl 3,r4 - - /* Flush all TLBs */ - lis r4,0x1000 -1: addic. r4,r4,-0x1000 - tlbie r4 - blt 1b - sync - - /* restore the MSR and turn on the MMU */ - lwz r3,SL_MSR(r1) - bl turn_on_mmu - - /* get back the stack pointer */ - tovirt(r1,r1) - - /* Restore TB */ - li r3,0 - mttbl r3 - lwz r3,SL_TB(r1) - lwz r4,SL_TB+4(r1) - mttbu r3 - mttbl r4 - - /* Restore the callee-saved registers and return */ - lwz r2,SL_R2(r1) - lmw r12,SL_R12(r1) - addi r1,r1,SL_SIZE - lwz r0,4(r1) - mtlr r0 - blr - -turn_on_mmu: - mflr r4 - tovirt(r4,r4) - mtsrr0 r4 - mtsrr1 r3 - sync - isync - rfi - - .data - .globl sleep_storage -sleep_storage: - .long 0 diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c index e5e3247924d3..221fee33e251 100644 --- a/arch/ppc/kernel/smp.c +++ b/arch/ppc/kernel/smp.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.smp.c 1.34 10/11/01 12:06:01 trini + * BK Id: %F% %I% %G% %U% %#% */ /* * Smp support for ppc. @@ -38,8 +38,6 @@ #include <asm/residual.h> #include <asm/time.h> -#include "open_pic.h" - int smp_threads_ready; volatile int smp_commenced; int smp_num_cpus = 1; @@ -69,6 +67,10 @@ extern int cpu_idle(void *unused); void smp_call_function_interrupt(void); void smp_message_pass(int target, int msg, unsigned long data, int wait); +#ifdef CONFIG_PPC_ISERIES +extern void smp_iSeries_space_timers( unsigned nr ); +#endif + /* Since OpenPIC has only 4 IPIs, we use slightly different message numbers. * * Make sure this matches openpic_request_IPIs in open_pic.c, or what shows up @@ -290,9 +292,7 @@ void __init smp_boot_cpus(void) * cpu 0, the master -- Cort */ cpu_callin_map[0] = 1; - current->processor = 0; - - init_idle(); + current->cpu = 0; for (i = 0; i < NR_CPUS; i++) { prof_counter[i] = 1; @@ -320,37 +320,26 @@ void __init smp_boot_cpus(void) */ if (cpu_nr > max_cpus) cpu_nr = max_cpus; +#ifdef CONFIG_PPC_ISERIES + smp_iSeries_space_timers( cpu_nr ); +#endif for (i = 1; i < cpu_nr; i++) { int c; struct pt_regs regs; /* create a process for the processor */ - /* we don't care about the values in regs since we'll - never reschedule the forked task. */ - /* We DO care about one bit in the pt_regs we - pass to do_fork. That is the MSR_FP bit in - regs.msr. If that bit is on, then do_fork - (via copy_thread) will call giveup_fpu. - giveup_fpu will get a pointer to our (current's) - last register savearea via current->thread.regs - and using that pointer will turn off the MSR_FP, - MSR_FE0 and MSR_FE1 bits. At this point, this - pointer is pointing to some arbitrary point within - our stack. */ - + /* only regs.msr is actually used, and 0 is OK for it */ memset(®s, 0, sizeof(struct pt_regs)); - if (do_fork(CLONE_VM|CLONE_PID, 0, ®s, 0) < 0) panic("failed fork for CPU %d", i); p = init_task.prev_task; if (!p) panic("No idle task for CPU %d", i); - del_from_runqueue(p); + init_idle(p, i); unhash_process(p); - init_tasks[i] = p; - p->processor = i; - p->cpus_runnable = 1 << i; /* we schedule the first task manually */ + p->cpu = i; + p->cpus_allowed = 1 << i; /* we schedule the first task manually */ current_set[i] = p; /* @@ -507,8 +496,6 @@ void __init smp_callin(void) smp_ops->setup_cpu(cpu); - init_idle(); - /* * This cpu is now "online". Only set them online * before they enter the loop below since write access diff --git a/arch/ppc/kernel/softemu8xx.c b/arch/ppc/kernel/softemu8xx.c index f71da553e183..40a17dc20219 100644 --- a/arch/ppc/kernel/softemu8xx.c +++ b/arch/ppc/kernel/softemu8xx.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.softemu8xx.c 1.8 05/17/01 18:14:22 cort + * BK Id: %F% %I% %G% %U% %#% */ /* * Software emulation of some PPC instructions for the 8xx core. @@ -35,6 +35,11 @@ #include <asm/io.h> #include <asm/processor.h> +extern void +print_8xx_pte(struct mm_struct *mm, unsigned long addr); +extern int +get_8xx_pte(struct mm_struct *mm, unsigned long addr); + /* Eventually we may need a look-up table, but this works for now. */ #define LFS 48 @@ -117,7 +122,7 @@ Soft_emulate_8xx(struct pt_regs *regs) default: retval = 1; printk("Bad emulation %s/%d\n" - " NIP: %08x instruction: %08x opcode: %x " + " NIP: %08lx instruction: %08x opcode: %x " "A: %x B: %x C: %x code: %x rc: %x\n", current->comm,current->pid, regs->nip, diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c index 381f1833339c..260345226022 100644 --- a/arch/ppc/kernel/time.c +++ b/arch/ppc/kernel/time.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.time.c 1.26 10/05/01 08:29:42 trini + * BK Id: %F% %I% %G% %U% %#% */ /* * Common time routines among all ppc machines. @@ -87,6 +87,11 @@ unsigned tb_last_stamp; extern unsigned long wall_jiffies; +#ifdef CONFIG_PPC_ISERIES +extern u64 get_tb64(void); +extern u64 next_jiffy_update_tb[]; +#endif + static long time_offset; spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; @@ -106,6 +111,8 @@ static inline int tb_delta(unsigned *jiffy_stamp) { return delta; } +#ifndef CONFIG_PPC_ISERIES /* iSeries version is in iSeries_time.c */ + extern unsigned long prof_cpu_mask; extern unsigned int * prof_buffer; extern unsigned long prof_len; @@ -181,7 +188,7 @@ int timer_interrupt(struct pt_regs * regs) * We should have an rtc call that only sets the minutes and * seconds like on Intel to avoid problems with non UTC clocks. */ - if ( (time_status & STA_UNSYNC) == 0 && + if ( ppc_md.set_rtc_time && (time_status & STA_UNSYNC) == 0 && xtime.tv_sec - last_rtc_update >= 659 && abs(xtime.tv_usec - (1000000-1000000/HZ)) < 500000/HZ && jiffies - wall_jiffies == 1) { @@ -211,6 +218,7 @@ int timer_interrupt(struct pt_regs * regs) return 1; /* lets ret_from_int know we can do checks */ } +#endif /* CONFIG_PPC_ISERIES */ /* * This version of gettimeofday has microsecond resolution. @@ -223,7 +231,11 @@ void do_gettimeofday(struct timeval *tv) read_lock_irqsave(&xtime_lock, flags); sec = xtime.tv_sec; usec = xtime.tv_usec; +#ifdef CONFIG_PPC_ISERIES + delta = tb_ticks_per_jiffy - ( next_jiffy_update_tb[0] - get_tb64() ); +#else delta = tb_ticks_since(tb_last_stamp); +#endif #ifdef CONFIG_SMP /* As long as timebases are not in sync, gettimeofday can only * have jiffy resolution on SMP. @@ -354,11 +366,10 @@ void __init time_init(void) } } -#define TICK_SIZE tick -#define FEBRUARY 2 -#define STARTOFTIME 1970 -#define SECDAY 86400L -#define SECYR (SECDAY * 365) +#define FEBRUARY 2 +#define STARTOFTIME 1970 +#define SECDAY 86400L +#define SECYR (SECDAY * 365) #define leapyear(year) ((year) % 4 == 0) #define days_in_year(a) (leapyear(a) ? 366 : 365) #define days_in_month(a) (month_days[(a) - 1]) @@ -367,55 +378,12 @@ static int month_days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; -/* - * This only works for the Gregorian calendar - i.e. after 1752 (in the UK) - */ -void GregorianDay(struct rtc_time * tm) -{ - int leapsToDate; - int lastYear; - int day; - int MonthOffset[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; - - lastYear=tm->tm_year-1; - - /* - * Number of leap corrections to apply up to end of last year - */ - leapsToDate = lastYear/4 - lastYear/100 + lastYear/400; - - /* - * This year is a leap year if it is divisible by 4 except when it is - * divisible by 100 unless it is divisible by 400 - * - * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 will be - */ - if((tm->tm_year%4==0) && - ((tm->tm_year%100!=0) || (tm->tm_year%400==0)) && - (tm->tm_mon>2)) - { - /* - * We are past Feb. 29 in a leap year - */ - day=1; - } - else - { - day=0; - } - - day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + - tm->tm_mday; - - tm->tm_wday=day%7; -} - void to_tm(int tim, struct rtc_time * tm) { - register int i; - register long hms, day; + register int i; + register long hms, day, gday; - day = tim / SECDAY; + gday = day = tim / SECDAY; hms = tim % SECDAY; /* Hours, minutes, seconds are easy */ @@ -440,9 +408,9 @@ void to_tm(int tim, struct rtc_time * tm) tm->tm_mday = day + 1; /* - * Determine the day of week + * Determine the day of week. Jan. 1, 1970 was a Thursday. */ - GregorianDay(tm); + tm->tm_wday = (gday + 4) % 7; } /* Auxiliary function to compute scaling factors */ diff --git a/arch/ppc/kernel/todc_time.c b/arch/ppc/kernel/todc_time.c new file mode 100644 index 000000000000..9591c7ee0eef --- /dev/null +++ b/arch/ppc/kernel/todc_time.c @@ -0,0 +1,456 @@ +/* + * arch/ppc/kernel/todc_time.c + * + * Time of Day Clock support for the M48T35, M48T37, M48T59, and MC146818 + * Real Time Clocks/Timekeepers. + * + * Author: Mark A. Greer + * mgreer@mvista.com + * + * Copyright 2001 MontaVista Software Inc. + * + * 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/errno.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/time.h> +#include <linux/timex.h> + +#include <asm/machdep.h> +#include <asm/io.h> +#include <asm/time.h> +#include <asm/todc.h> + +/* + * Depending on the hardware on your board and your board design, the + * RTC/NVRAM may be accessed either directly (like normal memory) or via + * address/data registers. If your board uses the direct method, set + * 'nvram_data' to the base address of your nvram and leave 'nvram_as0' and + * 'nvram_as1' NULL. If your board uses address/data regs to access nvram, + * set 'nvram_as0' to the address of the lower byte, set 'nvram_as1' to the + * address of the upper byte (leave NULL if using mv146818), and set + * 'nvram_data' to the address of the 8-bit data register. + * + * You also need to set 'ppc_md.nvram_read_val' and 'ppc_md.nvram_write_val' to + * the proper routines. There are standard ones defined further down in + * this file that you can use. + * + * There is a built in assumption that the RTC and NVRAM are accessed by the + * same mechanism (i.e., ppc_md.nvram_read_val, etc works for both). + * + * Note: Even though the documentation for the various RTC chips say that it + * take up to a second before it starts updating once the 'R' bit is + * cleared, they always seem to update even though we bang on it many + * times a second. This is true, except for the Dallas Semi 1746/1747 + * (possibly others). Those chips seem to have a real problem whenever + * we set the 'R' bit before reading them, they basically stop counting. + * --MAG + */ + +/* + * 'todc_info' should be initialized in your *_setup.c file to + * point to a fully initialized 'todc_info_t' structure. + * This structure holds all the register offsets for your particular + * TODC/RTC chip. + * TODC_ALLOC()/TODC_INIT() will allocate and initialize this table for you. + */ + +#ifdef RTC_FREQ_SELECT +#undef RTC_FREQ_SELECT +#define RTC_FREQ_SELECT control_b /* Register A */ +#endif + +#ifdef RTC_CONTROL +#undef RTC_CONTROL +#define RTC_CONTROL control_a /* Register B */ +#endif + +#ifdef RTC_INTR_FLAGS +#undef RTC_INTR_FLAGS +#define RTC_INTR_FLAGS watchdog /* Register C */ +#endif + +#ifdef RTC_VALID +#undef RTC_VALID +#define RTC_VALID interrupts /* Register D */ +#endif + +/* Access routines when RTC accessed directly (like normal memory) */ +u_char +todc_direct_read_val(int addr) +{ + return readb(todc_info->nvram_data + addr); +} + +void +todc_direct_write_val(int addr, unsigned char val) +{ + writeb(val, todc_info->nvram_data + addr); + return; +} + +/* Access routines for accessing m48txx type chips via addr/data regs */ +u_char +todc_m48txx_read_val(int addr) +{ + outb(addr, todc_info->nvram_as0); + outb(addr>>todc_info->as0_bits, todc_info->nvram_as1); + return inb(todc_info->nvram_data); +} + +void +todc_m48txx_write_val(int addr, unsigned char val) +{ + outb(addr, todc_info->nvram_as0); + outb(addr>>todc_info->as0_bits, todc_info->nvram_as1); + outb(val, todc_info->nvram_data); + return; +} + +/* Access routines for accessing mc146818 type chips via addr/data regs */ +u_char +todc_mc146818_read_val(int addr) +{ + outb(addr, todc_info->nvram_as0); + return inb(todc_info->nvram_data); +} + +void +todc_mc146818_write_val(int addr, unsigned char val) +{ + outb(addr, todc_info->nvram_as0); + outb(val, todc_info->nvram_data); + return; +} + +/* + * TODC routines + * + * There is some ugly stuff in that there are assumptions for the mc146818. + * + * Assumptions: + * - todc_info->control_a has the offset as mc146818 Register B reg + * - todc_info->control_b has the offset as mc146818 Register A reg + * - m48txx control reg's write enable or 'W' bit is same as + * mc146818 Register B 'SET' bit (i.e., 0x80) + * + * These assumptions were made to make the code simpler. + */ +long __init +todc_time_init(void) +{ + static u_char not_initialized = 1; + + /* Make sure clocks are running */ + if (not_initialized) { + u_char cntl_b; + + cntl_b = ppc_md.nvram_read_val(todc_info->control_b); + + if (todc_info->rtc_type == TODC_TYPE_MC146818) { + if ((cntl_b & 0x70) != 0x20) { + printk(KERN_INFO "TODC %s %s\n", + "real-time-clock was stopped.", + "Now starting..."); + cntl_b &= ~0x70; + cntl_b |= 0x20; + } + + ppc_md.nvram_write_val(todc_info->control_b, cntl_b); + } + else if (todc_info->rtc_type == TODC_TYPE_DS1501) { + u_char month; + + todc_info->enable_read = TODC_DS1501_CNTL_B_TE; + todc_info->enable_write = TODC_DS1501_CNTL_B_TE; + + month = ppc_md.nvram_read_val(todc_info->month); + + if ((month & 0x80) == 0x80) { + printk(KERN_INFO "TODC %s %s\n", + "real-time-clock was stopped.", + "Now starting..."); + month &= ~0x80; + ppc_md.nvram_write_val(todc_info->month, month); + } + + cntl_b &= ~TODC_DS1501_CNTL_B_TE; + ppc_md.nvram_write_val(todc_info->control_b, cntl_b); + } + else { /* must be a m48txx type */ + u_char cntl_a; + + todc_info->enable_read = TODC_MK48TXX_CNTL_A_R; + todc_info->enable_write = TODC_MK48TXX_CNTL_A_W; + + cntl_a = ppc_md.nvram_read_val(todc_info->control_a); + + /* Check & clear STOP bit in control B register */ + if (cntl_b & TODC_MK48TXX_DAY_CB) { + printk(KERN_INFO "TODC %s %s\n", + "real-time-clock was stopped.", + "Now starting..."); + + cntl_a |= todc_info->enable_write; + cntl_b &= ~TODC_MK48TXX_DAY_CB;/* Start Oscil */ + + ppc_md.nvram_write_val(todc_info->control_a, + cntl_a); + ppc_md.nvram_write_val(todc_info->control_b, + cntl_b); + } + + /* Make sure READ & WRITE bits are cleared. */ + cntl_a &= ~(todc_info->enable_write | + todc_info->enable_read); + ppc_md.nvram_write_val(todc_info->control_a, cntl_a); + } + + not_initialized = 0; + } + + + return 0; +} + +/* + * There is some ugly stuff in that there are assumptions that for a mc146818, + * the todc_info->control_a has the offset of the mc146818 Register B reg and + * that the register'ss 'SET' bit is the same as the m48txx's write enable + * bit in the control register of the m48txx (i.e., 0x80). + * + * It was done to make the code look simpler. + */ +ulong +todc_get_rtc_time(void) +{ + uint year, mon, day, hour, min, sec; + uint limit, i; + u_char save_control, uip; + + save_control = ppc_md.nvram_read_val(todc_info->control_a); + + if (todc_info->rtc_type != TODC_TYPE_MC146818) { + limit = 1; + + switch (todc_info->rtc_type) { + case TODC_TYPE_DS1557: + case TODC_TYPE_DS1746: /* XXXX BAD HACK -> FIX */ + case TODC_TYPE_DS1747: + break; + default: + ppc_md.nvram_write_val(todc_info->control_a, + (save_control | todc_info->enable_read)); + } + } + else { + limit = 100000000; + } + + for (i=0; i<limit; i++) { + if (todc_info->rtc_type == TODC_TYPE_MC146818) { + uip = ppc_md.nvram_read_val(todc_info->RTC_FREQ_SELECT); + } + + sec = ppc_md.nvram_read_val(todc_info->seconds) & 0x7f; + min = ppc_md.nvram_read_val(todc_info->minutes) & 0x7f; + hour = ppc_md.nvram_read_val(todc_info->hours) & 0x3f; + day = ppc_md.nvram_read_val(todc_info->day_of_month) & 0x3f; + mon = ppc_md.nvram_read_val(todc_info->month) & 0x1f; + year = ppc_md.nvram_read_val(todc_info->year) & 0xff; + + if (todc_info->rtc_type == TODC_TYPE_MC146818) { + uip |= ppc_md.nvram_read_val( + todc_info->RTC_FREQ_SELECT); + if ((uip & RTC_UIP) == 0) break; + } + } + + if (todc_info->rtc_type != TODC_TYPE_MC146818) { + switch (todc_info->rtc_type) { + case TODC_TYPE_DS1557: + case TODC_TYPE_DS1746: /* XXXX BAD HACK -> FIX */ + case TODC_TYPE_DS1747: + break; + default: + save_control &= ~(todc_info->enable_read); + ppc_md.nvram_write_val(todc_info->control_a, + save_control); + } + } + + if ((todc_info->rtc_type != TODC_TYPE_MC146818) || + ((save_control & RTC_DM_BINARY) == 0) || + RTC_ALWAYS_BCD) { + + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + } + + year = year + 1900; + if (year < 1970) { + year += 100; + } + + return mktime(year, mon, day, hour, min, sec); +} + +int +todc_set_rtc_time(unsigned long nowtime) +{ + struct rtc_time tm; + u_char save_control, save_freq_select; + + to_tm(nowtime, &tm); + + save_control = ppc_md.nvram_read_val(todc_info->control_a); + + /* Assuming MK48T59_RTC_CA_WRITE & RTC_SET are equal */ + ppc_md.nvram_write_val(todc_info->control_a, + (save_control | todc_info->enable_write)); + save_control &= ~(todc_info->enable_write); /* in case it was set */ + + if (todc_info->rtc_type == TODC_TYPE_MC146818) { + save_freq_select = + ppc_md.nvram_read_val(todc_info->RTC_FREQ_SELECT); + ppc_md.nvram_write_val(todc_info->RTC_FREQ_SELECT, + save_freq_select | RTC_DIV_RESET2); + } + + + tm.tm_year = (tm.tm_year - 1900) % 100; + + if ((todc_info->rtc_type != TODC_TYPE_MC146818) || + ((save_control & RTC_DM_BINARY) == 0) || + RTC_ALWAYS_BCD) { + + BIN_TO_BCD(tm.tm_sec); + BIN_TO_BCD(tm.tm_min); + BIN_TO_BCD(tm.tm_hour); + BIN_TO_BCD(tm.tm_mon); + BIN_TO_BCD(tm.tm_mday); + BIN_TO_BCD(tm.tm_year); + } + + ppc_md.nvram_write_val(todc_info->seconds, tm.tm_sec); + ppc_md.nvram_write_val(todc_info->minutes, tm.tm_min); + ppc_md.nvram_write_val(todc_info->hours, tm.tm_hour); + ppc_md.nvram_write_val(todc_info->month, tm.tm_mon); + ppc_md.nvram_write_val(todc_info->day_of_month, tm.tm_mday); + ppc_md.nvram_write_val(todc_info->year, tm.tm_year); + + ppc_md.nvram_write_val(todc_info->control_a, save_control); + + if (todc_info->rtc_type == TODC_TYPE_MC146818) { + ppc_md.nvram_write_val(todc_info->RTC_FREQ_SELECT, + save_freq_select); + } + + return 0; +} + +/* + * Manipulates read bit to reliably read seconds at a high rate. + */ +static unsigned char __init todc_read_timereg(int addr) +{ + unsigned char save_control, val; + + switch (todc_info->rtc_type) { + case TODC_TYPE_DS1557: + case TODC_TYPE_DS1746: /* XXXX BAD HACK -> FIX */ + case TODC_TYPE_DS1747: + case TODC_TYPE_MC146818: + break; + default: + save_control = + ppc_md.nvram_read_val(todc_info->control_a); + ppc_md.nvram_write_val(todc_info->control_a, + (save_control | todc_info->enable_read)); + } + val = ppc_md.nvram_read_val(addr); + + switch (todc_info->rtc_type) { + case TODC_TYPE_DS1557: + case TODC_TYPE_DS1746: /* XXXX BAD HACK -> FIX */ + case TODC_TYPE_DS1747: + case TODC_TYPE_MC146818: + break; + default: + save_control &= ~(todc_info->enable_read); + ppc_md.nvram_write_val(todc_info->control_a, + save_control); + } + + return val; +} + +/* + * This was taken from prep_setup.c + * Use the NVRAM RTC to time a second to calibrate the decrementer. + */ +void __init +todc_calibrate_decr(void) +{ + ulong freq; + ulong tbl, tbu; + long i, loop_count; + u_char sec; + + todc_time_init(); + + /* + * Actually this is bad for precision, we should have a loop in + * which we only read the seconds counter. nvram_read_val writes + * the address bytes on every call and this takes a lot of time. + * Perhaps an nvram_wait_change method returning a time + * stamp with a loop count as parameter would be the solution. + */ + /* + * Need to make sure the tbl doesn't roll over so if tbu increments + * during this test, we need to do it again. + */ + loop_count = 0; + + sec = todc_read_timereg(todc_info->seconds) & 0x7f; + + do { + tbu = get_tbu(); + + for (i = 0 ; i < 10000000 ; i++) {/* may take up to 1 second */ + tbl = get_tbl(); + + if ((todc_read_timereg(todc_info->seconds) & 0x7f) != sec) { + break; + } + } + + sec = todc_read_timereg(todc_info->seconds) & 0x7f; + + for (i = 0 ; i < 10000000 ; i++) { /* Should take 1 second */ + freq = get_tbl(); + + if ((todc_read_timereg(todc_info->seconds) & 0x7f) != sec) { + break; + } + } + + freq -= tbl; + } while ((get_tbu() != tbu) && (++loop_count < 2)); + + printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", + freq/1000000, freq%1000000); + + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); + + return; +} diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index fdd5289bebbf..c2265a8afcc8 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.traps.c 1.22 10/11/01 10:33:09 paulus + * BK Id: %F% %I% %G% %U% %#% */ /* * linux/arch/ppc/kernel/traps.c @@ -38,6 +38,9 @@ #include <asm/system.h> #include <asm/io.h> #include <asm/processor.h> +#ifdef CONFIG_PMAC_BACKLIGHT +#include <asm/backlight.h> +#endif extern int fix_alignment(struct pt_regs *); extern void bad_page_fault(struct pt_regs *, unsigned long, int sig); @@ -66,6 +69,13 @@ int (*debugger_sstep)(struct pt_regs *regs); int (*debugger_iabr_match)(struct pt_regs *regs); int (*debugger_dabr_match)(struct pt_regs *regs); void (*debugger_fault_handler)(struct pt_regs *regs); +#else +#define debugger(regs) do { } while (0) +#define debugger_bpt(regs) 0 +#define debugger_sstep(regs) 0 +#define debugger_iabr_match(regs) 0 +#define debugger_dabr_match(regs) 0 +#define debugger_fault_handler ((void (*)(struct pt_regs *))0) #endif #endif @@ -74,15 +84,19 @@ void (*debugger_fault_handler)(struct pt_regs *regs); */ -spinlock_t oops_lock = SPIN_LOCK_UNLOCKED; +spinlock_t die_lock = SPIN_LOCK_UNLOCKED; void die(const char * str, struct pt_regs * fp, long err) { console_verbose(); - spin_lock_irq(&oops_lock); + spin_lock_irq(&die_lock); +#ifdef CONFIG_PMAC_BACKLIGHT + set_backlight_enable(1); + set_backlight_level(BACKLIGHT_MAX); +#endif printk("Oops: %s, sig: %ld\n", str, err); show_regs(fp); - spin_unlock_irq(&oops_lock); + spin_unlock_irq(&die_lock); /* do_exit() should take care of panic'ing from an interrupt * context so we don't handle it here */ @@ -94,9 +108,7 @@ _exception(int signr, struct pt_regs *regs) { if (!user_mode(regs)) { -#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) debugger(regs); -#endif die("Exception in kernel mode", regs, signr); } force_sig(signr, current); @@ -111,7 +123,7 @@ MachineCheckException(struct pt_regs *regs) unsigned long msr = regs->msr; if (user_mode(regs)) { - _exception(SIGSEGV, regs); + _exception(SIGSEGV, regs); return; } @@ -120,12 +132,10 @@ MachineCheckException(struct pt_regs *regs) bad_page_fault(regs, regs->dar, SIGBUS); return; #endif -#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) if (debugger_fault_handler) { debugger_fault_handler(regs); return; } -#endif #ifdef CONFIG_ALL_PPC /* @@ -135,7 +145,7 @@ MachineCheckException(struct pt_regs *regs) * table. * Note that the 601 only takes a machine check on TEA * (transfer error ack) signal assertion, and does not - * set of the top 16 bits of SRR1. + * set any of the top 16 bits of SRR1. * -- paulus. */ if (((msr & 0xffff0000) == 0 || (msr & (0x80000 | 0x40000))) @@ -169,12 +179,13 @@ MachineCheckException(struct pt_regs *regs) #endif /* CONFIG_ALL_PPC */ printk("Machine check in kernel mode.\n"); printk("Caused by (from SRR1=%lx): ", msr); - switch (msr & 0xF0000) { + switch (msr & 0x601F0000) { case 0x80000: printk("Machine check signal\n"); break; case 0: /* for 601 */ case 0x40000: + case 0x140000: /* 7450 MSS error and TEA */ printk("Transfer error ack signal\n"); break; case 0x20000: @@ -183,26 +194,30 @@ MachineCheckException(struct pt_regs *regs) case 0x10000: printk("Address parity error signal\n"); break; + case 0x20000000: + printk("L1 Data Cache error\n"); + break; + case 0x40000000: + printk("L1 Instruction Cache error\n"); + break; + case 0x00100000: + printk("L2 data cache parity error\n"); + break; default: printk("Unknown values in msr\n"); } -#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) debugger(regs); -#endif die("machine check", regs, SIGBUS); } void SMIException(struct pt_regs *regs) { -#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) - { - debugger(regs); - return; - } -#endif + debugger(regs); +#if !(defined(CONFIG_XMON) || defined(CONFIG_KGDB)) show_regs(regs); panic("System Management Interrupt"); +#endif } void @@ -210,23 +225,21 @@ UnknownException(struct pt_regs *regs) { printk("Bad trap at PC: %lx, SR: %lx, vector=%lx %s\n", regs->nip, regs->msr, regs->trap, print_tainted()); - _exception(SIGTRAP, regs); + _exception(SIGTRAP, regs); } void InstructionBreakpoint(struct pt_regs *regs) { -#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) if (debugger_iabr_match(regs)) return; -#endif _exception(SIGTRAP, regs); } void RunModeException(struct pt_regs *regs) { - _exception(SIGTRAP, regs); + _exception(SIGTRAP, regs); } /* Illegal instruction emulation support. Originally written to @@ -272,51 +285,54 @@ emulate_instruction(struct pt_regs *regs) void ProgramCheckException(struct pt_regs *regs) { + int errcode; + #if defined(CONFIG_4xx) unsigned int esr = mfspr(SPRN_ESR); + int isbpt = esr & ESR_PTR; + extern int do_mathemu(struct pt_regs *regs); + + if (isbpt) + mtspr(SPRN_DBSR, DBSR_TIE); +#ifdef CONFIG_MATH_EMULATION + if (!isbpt && do_mathemu(regs) == 0) + return; +#endif /* CONFIG_MATH_EMULATION */ + +#else /* ! CONFIG_4xx */ + int isbpt = regs->msr & 0x20000; - if (esr & ESR_PTR) { -#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) - if (debugger_bpt(regs)) - return; -#endif - _exception(SIGTRAP, regs); - } else { - _exception(SIGILL, regs); - } -#else if (regs->msr & 0x100000) { /* IEEE FP exception */ _exception(SIGFPE, regs); - } else if (regs->msr & 0x20000) { + return; + } +#endif /* ! CONFIG_4xx */ + + if (isbpt) { /* trap exception */ -#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) if (debugger_bpt(regs)) return; -#endif _exception(SIGTRAP, regs); - } else { - /* Try to emulate it if we should. */ - int errcode; - if ((errcode = emulate_instruction(regs))) { - if (errcode == -EFAULT) - _exception(SIGBUS, regs); - else - _exception(SIGILL, regs); - } + return; + } + + /* Try to emulate it if we should. */ + if ((errcode = emulate_instruction(regs))) { + if (errcode == -EFAULT) + _exception(SIGBUS, regs); + else + _exception(SIGILL, regs); } -#endif } void SingleStepException(struct pt_regs *regs) { regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */ -#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) if (debugger_sstep(regs)) return; -#endif - _exception(SIGTRAP, regs); + _exception(SIGTRAP, regs); } void @@ -337,7 +353,7 @@ AlignmentException(struct pt_regs *regs) bad_page_fault(regs, regs->dar, SIGSEGV); return; } - _exception(SIGBUS, regs); + _exception(SIGBUS, regs); } void @@ -345,9 +361,7 @@ StackOverflow(struct pt_regs *regs) { printk(KERN_CRIT "Kernel stack overflow in process %p, r1=%lx\n", current, regs->gpr[1]); -#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) debugger(regs); -#endif show_regs(regs); panic("kernel stack overflow"); } @@ -365,20 +379,20 @@ void SoftwareEmulation(struct pt_regs *regs) { extern int do_mathemu(struct pt_regs *); + extern int Soft_emulate_8xx(struct pt_regs *); int errcode; if (!user_mode(regs)) { -#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) debugger(regs); -#endif die("Kernel Mode Software FPU Emulation", regs, SIGFPE); } #ifdef CONFIG_MATH_EMULATION - if ((errcode = do_mathemu(regs))) { + errcode = do_mathemu(regs); #else - if ((errcode = Soft_emulate_8xx(regs))) { + errcode = Soft_emulate_8xx(regs); #endif + if (errcode) { if (errcode > 0) _exception(SIGFPE, regs); else if (errcode == -EFAULT) @@ -387,7 +401,36 @@ SoftwareEmulation(struct pt_regs *regs) _exception(SIGILL, regs); } } -#endif +#endif /* CONFIG_8xx */ + +#if defined(CONFIG_4xx) + +void DebugException(struct pt_regs *regs) +{ + unsigned long debug_status; + + debug_status = mfspr(SPRN_DBSR); + + regs->msr &= ~MSR_DE; /* Turn off 'debug' bit */ + if (debug_status & DBSR_TIE) { /* trap instruction*/ + + mtspr(SPRN_DBSR, DBSR_TIE); + + if (!user_mode(regs) && debugger_bpt(regs)) + return; + _exception(SIGTRAP, regs); + + } else if (debug_status & DBSR_IC) { /* instruction completion */ + + mtspr(SPRN_DBSR, DBSR_IC); + regs->dbcr0 &= ~DBCR0_IC; + + if (!user_mode(regs) && debugger_sstep(regs)) + return; + _exception(SIGTRAP, regs); + } +} +#endif /* CONFIG_4xx */ #if !defined(CONFIG_TAU_INT) void diff --git a/arch/ppc/kernel/walnut_setup.c b/arch/ppc/kernel/walnut_setup.c deleted file mode 100644 index 99bdcf7a38f1..000000000000 --- a/arch/ppc/kernel/walnut_setup.c +++ /dev/null @@ -1,292 +0,0 @@ -/* - * BK Id: SCCS/s.walnut_setup.c 1.10 11/13/01 21:26:07 paulus - */ -/* - * - * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu> - * - * Module name: walnut_setup.c - * - * Description: - * Architecture- / platform-specific boot-time initialization code for - * the IBM PowerPC 403GP "Walnut" evaluation board. Adapted from original - * code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek - * <dan@net4x.com>. - * - */ - -#include <linux/config.h> -#include <linux/init.h> -#include <linux/smp.h> -#include <linux/threads.h> -#include <linux/interrupt.h> -#include <linux/param.h> -#include <linux/string.h> -#include <linux/blk.h> -#include <linux/seq_file.h> - -#include <asm/processor.h> -#include <asm/board.h> -#include <asm/machdep.h> -#include <asm/page.h> - -#include "local_irq.h" -#include "ppc4xx_pic.h" -#include <asm/time.h> -#include "walnut_setup.h" - - -/* Function Prototypes */ - -extern void abort(void); - -/* Global Variables */ - -unsigned char __res[sizeof(bd_t)]; - - -/* - * void __init walnut_init() - * - * Description: - * This routine... - * - * Input(s): - * r3 - Optional pointer to a board information structure. - * r4 - Optional pointer to the physical starting address of the init RAM - * disk. - * r5 - Optional pointer to the physical ending address of the init RAM - * disk. - * r6 - Optional pointer to the physical starting address of any kernel - * command-line parameters. - * r7 - Optional pointer to the physical ending address of any kernel - * command-line parameters. - * - * Output(s): - * N/A - * - * Returns: - * N/A - * - */ -void __init -walnut_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - /* - * If we were passed in a board information, copy it into the - * residual data area. - */ - if (r3) { - memcpy((void *)__res, (void *)(r3 + KERNELBASE), sizeof(bd_t)); - } - -#if defined(CONFIG_BLK_DEV_INITRD) - /* - * If the init RAM disk has been configured in, and there's a valid - * starting address for it, set it up. - */ - if (r4) { - initrd_start = r4 + KERNELBASE; - initrd_end = r5 + KERNELBASE; - } -#endif /* CONFIG_BLK_DEV_INITRD */ - - /* Copy the kernel command line arguments to a safe place. */ - - if (r6) { - *(char *)(r7 + KERNELBASE) = 0; - strcpy(cmd_line, (char *)(r6 + KERNELBASE)); - } - - /* Initialize machine-dependency vectors */ - - ppc_md.setup_arch = walnut_setup_arch; - ppc_md.show_percpuinfo = walnut_show_percpuinfo; - ppc_md.irq_cannonicalize = NULL; - ppc_md.init_IRQ = walnut_init_IRQ; - ppc_md.get_irq = walnut_get_irq; - ppc_md.init = NULL; - - ppc_md.restart = walnut_restart; - ppc_md.power_off = walnut_power_off; - ppc_md.halt = walnut_halt; - - ppc_md.time_init = walnut_time_init; - ppc_md.set_rtc_time = walnut_set_rtc_time; - ppc_md.get_rtc_time = walnut_get_rtc_time; - ppc_md.calibrate_decr = walnut_calibrate_decr; - - ppc_md.kbd_setkeycode = NULL; - ppc_md.kbd_getkeycode = NULL; - ppc_md.kbd_translate = NULL; - ppc_md.kbd_unexpected_up = NULL; - ppc_md.kbd_leds = NULL; - ppc_md.kbd_init_hw = NULL; - ppc_md.ppc_kbd_sysrq_xlate = NULL; -} - -/* - * Document me. - */ -void __init -walnut_setup_arch(void) -{ - /* XXX - Implement me */ -} - -/* - * int walnut_show_percpuinfo() - * - * Description: - * This routine pretty-prints the platform's internal CPU and bus clock - * frequencies into the buffer for usage in /proc/cpuinfo. - * - * Input(s): - * *buffer - Buffer into which CPU and bus clock frequencies are to be - * printed. - * - * Output(s): - * *buffer - Buffer with the CPU and bus clock frequencies. - * - * Returns: - * The number of bytes copied into 'buffer' if OK, otherwise zero or less - * on error. - */ -int -walnut_show_percpuinfo(struct seq_file *m) -{ - bd_t *bp = (bd_t *)__res; - - seq_printf(m, "clock\t\t: %dMHz\n" - "bus clock\t\t: %dMHz\n", - bp->bi_intfreq / 1000000, - bp->bi_busfreq / 1000000); - - return 0; -} - -/* - * Document me. - */ -void __init -walnut_init_IRQ(void) -{ - int i; - - ppc4xx_pic_init(); - - for (i = 0; i < NR_IRQS; i++) { - irq_desc[i].handler = ppc4xx_pic; - } - - return; -} - -/* - * Document me. - */ -int -walnut_get_irq(struct pt_regs *regs) -{ - return (ppc4xx_pic_get_irq(regs)); -} - -/* - * Document me. - */ -void -walnut_restart(char *cmd) -{ - abort(); -} - -/* - * Document me. - */ -void -walnut_power_off(void) -{ - walnut_restart(NULL); -} - -/* - * Document me. - */ -void -walnut_halt(void) -{ - walnut_restart(NULL); -} - -/* - * Document me. - */ -long __init -walnut_time_init(void) -{ - /* XXX - Implement me */ - return 0; -} - -/* - * Document me. - */ -int __init -walnut_set_rtc_time(unsigned long time) -{ - /* XXX - Implement me */ - - return (0); -} - -/* - * Document me. - */ -unsigned long __init -walnut_get_rtc_time(void) -{ - /* XXX - Implement me */ - - return (0); -} - -/* - * void __init walnut_calibrate_decr() - * - * Description: - * This routine retrieves the internal processor frequency from the board - * information structure, sets up the kernel timer decrementer based on - * that value, enables the 403 programmable interval timer (PIT) and sets - * it up for auto-reload. - * - * Input(s): - * N/A - * - * Output(s): - * N/A - * - * Returns: - * N/A - * - */ -void __init -walnut_calibrate_decr(void) -{ - unsigned int freq; - bd_t *bip = (bd_t *)__res; - - freq = bip->bi_intfreq; - - decrementer_count = freq / HZ; - count_period_num = 1; - count_period_den = freq; - - /* Enable the PIT and set auto-reload of its value */ - - mtspr(SPRN_TCR, TCR_PIE | TCR_ARE); - - /* Clear any pending timer interrupts */ - - mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_PIS | TSR_FIS); -} diff --git a/arch/ppc/kernel/walnut_setup.h b/arch/ppc/kernel/walnut_setup.h deleted file mode 100644 index 2c142f031ebd..000000000000 --- a/arch/ppc/kernel/walnut_setup.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * BK Id: SCCS/s.walnut_setup.h 1.5 05/17/01 18:14:22 cort - */ -/* - * - * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu> - * - * Module name: walnut_setup.c - * - * Description: - * Architecture- / platform-specific boot-time initialization code for - * the IBM PowerPC 405GP "Walnut" evaluation board. Adapted from original - * code by Gary Thomas, Cort Dougan <cort@cs.nmt.edu>, and Dan Malek - * <dan@netx4.com>. - * - */ - -#ifndef __WALNUT_SETUP_H__ -#define __WALNUT_SETUP_H__ - -#include <asm/ptrace.h> -#include <asm/board.h> - - -#ifdef __cplusplus -extern "C" { -#endif - -extern unsigned char __res[sizeof(bd_t)]; - -extern void walnut_init(unsigned long r3, - unsigned long ird_start, - unsigned long ird_end, - unsigned long cline_start, - unsigned long cline_end); -extern void walnut_setup_arch(void); -extern int walnut_setup_residual(char *buffer); -extern void walnut_init_IRQ(void); -extern int walnut_get_irq(struct pt_regs *regs); -extern void walnut_restart(char *cmd); -extern void walnut_power_off(void); -extern void walnut_halt(void); -extern void walnut_time_init(void); -extern int walnut_set_rtc_time(unsigned long now); -extern unsigned long walnut_get_rtc_time(void); -extern void walnut_calibrate_decr(void); - - -#ifdef __cplusplus -} -#endif - -#endif /* __WALNUT_SETUP_H__ */ diff --git a/arch/ppc/kernel/xics.c b/arch/ppc/kernel/xics.c deleted file mode 100644 index 7b3f047cccaf..000000000000 --- a/arch/ppc/kernel/xics.c +++ /dev/null @@ -1,217 +0,0 @@ -/* - * BK Id: SCCS/s.xics.c 1.5 05/17/01 18:14:22 cort - */ -/* - * arch/ppc/kernel/xics.c - * - * Copyright 2000 IBM Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include <linux/config.h> -#include <linux/types.h> -#include <linux/threads.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <asm/prom.h> -#include <asm/io.h> -#include "i8259.h" -#include "xics.h" - -void xics_enable_irq(u_int irq); -void xics_disable_irq(u_int irq); -void xics_mask_and_ack_irq(u_int irq); -void xics_end_irq(u_int irq); - -struct hw_interrupt_type xics_pic = { - " XICS ", - NULL, - NULL, - xics_enable_irq, - xics_disable_irq, - xics_mask_and_ack_irq, - xics_end_irq -}; - -struct hw_interrupt_type xics_8259_pic = { - " XICS/8259", - NULL, - NULL, - NULL, - NULL, - xics_mask_and_ack_irq, - NULL -}; - -#define XICS_IPI 2 -#define XICS_IRQ_8259_CASCADE 0x2c -#define XICS_IRQ_OFFSET 16 -#define XICS_IRQ_SPURIOUS 0 - -#define DEFAULT_SERVER 0 -#define DEFAULT_PRIORITY 0 - -struct xics_ipl { - union { - u32 word; - u8 bytes[4]; - } xirr_poll; - union { - u32 word; - u8 bytes[4]; - } xirr; - u32 dummy; - union { - u32 word; - u8 bytes[4]; - } qirr; -}; - -struct xics_info { - volatile struct xics_ipl * per_cpu[NR_CPUS]; -}; - -struct xics_info xics_info; - -#define xirr_info(n_cpu) (xics_info.per_cpu[n_cpu]->xirr.word) -#define cppr_info(n_cpu) (xics_info.per_cpu[n_cpu]->xirr.bytes[0]) -#define poll_info(n_cpu) (xics_info.per_cpu[n_cpu]->xirr_poll.word) -#define qirr_info(n_cpu) (xics_info.per_cpu[n_cpu]->qirr.bytes[0]) - -void -xics_enable_irq( - u_int irq - ) -{ - int status; - int call_status; - - irq -= XICS_IRQ_OFFSET; - if (irq == XICS_IPI) - return; - call_status = call_rtas("ibm,set-xive", 3, 1, (ulong*)&status, - irq, DEFAULT_SERVER, DEFAULT_PRIORITY); - if( call_status != 0 ) { - printk("xics_enable_irq: irq=%x: call_rtas failed; retn=%x, status=%x\n", - irq, call_status, status); - return; - } -} - -void -xics_disable_irq( - u_int irq - ) -{ - int status; - int call_status; - - irq -= XICS_IRQ_OFFSET; - call_status = call_rtas("ibm,int-off", 1, 1, (ulong*)&status, irq); - if( call_status != 0 ) { - printk("xics_disable_irq: irq=%x: call_rtas failed, retn=%x\n", - irq, call_status); - return; - } -} - -void -xics_end_irq( - u_int irq - ) -{ - int cpu = smp_processor_id(); - - cppr_info(cpu) = 0; /* actually the value overwritten by ack */ - xirr_info(cpu) = (0xff<<24) | (irq-XICS_IRQ_OFFSET); -} - -void -xics_mask_and_ack_irq( - u_int irq - ) -{ - int cpu = smp_processor_id(); - - if( irq < XICS_IRQ_OFFSET ) { - i8259_pic.ack(irq); - xirr_info(cpu) = (0xff<<24) | XICS_IRQ_8259_CASCADE; - } - else { - cppr_info(cpu) = 0xff; - } -} - -int -xics_get_irq(struct pt_regs *regs) -{ - u_int cpu = smp_processor_id(); - u_int vec; - int irq; - - vec = xirr_info(cpu); - /* (vec >> 24) == old priority */ - vec &= 0x00ffffff; - /* for sanity, this had better be < NR_IRQS - 16 */ - if( vec == XICS_IRQ_8259_CASCADE ) - irq = i8259_irq(cpu); - else if( vec == XICS_IRQ_SPURIOUS ) - irq = -1; - else - irq = vec + XICS_IRQ_OFFSET; - return irq; -} - -#ifdef CONFIG_SMP -void xics_ipi_action(int irq, void *dev_id, struct pt_regs *regs) -{ - qirr_info(smp_processor_id()) = 0xff; - smp_message_recv(MSG_RESCHEDULE, regs); -} - -void xics_cause_IPI(int cpu) -{ - qirr_info(cpu) = 0; -} - -void xics_setup_cpu(void) -{ - int cpu = smp_processor_id(); - - cppr_info(cpu) = 0xff; -} -#endif /* CONFIG_SMP */ - -void -xics_init_IRQ( void ) -{ - int i; - extern unsigned long smp_chrp_cpu_nr; - -#ifdef CONFIG_SMP - for (i = 0; i < smp_chrp_cpu_nr; ++i) - xics_info.per_cpu[i] = - ioremap(0xfe000000 + smp_hw_index[i] * 0x1000, 0x20); -#else - xics_info.per_cpu[0] = ioremap(0xfe000000, 0x20); -#endif /* CONFIG_SMP */ - xics_8259_pic.enable = i8259_pic.enable; - xics_8259_pic.disable = i8259_pic.disable; - for (i = 0; i < 16; ++i) - irq_desc[i].handler = &xics_8259_pic; - for (; i < NR_IRQS; ++i) - irq_desc[i].handler = &xics_pic; - - cppr_info(0) = 0xff; - if (request_irq(XICS_IRQ_8259_CASCADE + XICS_IRQ_OFFSET, no_action, - 0, "8259 cascade", 0)) - printk(KERN_ERR "xics_init_IRQ: couldn't get 8259 cascade\n"); - i8259_init(); - -#ifdef CONFIG_SMP - request_irq(XICS_IPI + XICS_IRQ_OFFSET, xics_ipi_action, 0, "IPI", 0); -#endif -} diff --git a/arch/ppc/kernel/xics.h b/arch/ppc/kernel/xics.h deleted file mode 100644 index dd0a591b834f..000000000000 --- a/arch/ppc/kernel/xics.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * BK Id: SCCS/s.xics.h 1.5 05/17/01 18:14:22 cort - */ -/* - * arch/ppc/kernel/xics.h - * - * Copyright 2000 IBM Corporation. - * - * 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. - */ - -#ifndef _PPC_KERNEL_XICS_H -#define _PPC_KERNEL_XICS_H - -#include "local_irq.h" - -extern struct hw_interrupt_type xics_pic; -extern struct hw_interrupt_type xics_8259_pic; - -void xics_init_IRQ(void); -int xics_get_irq(struct pt_regs *); - -#endif /* _PPC_KERNEL_XICS_H */ |
