summaryrefslogtreecommitdiffstats
path: root/arch/ppc/kernel
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-06-13 16:29:25 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-06-13 16:29:25 +0000
commitdb7d4daea91e105e3859cf461d7e53b9b77454b2 (patch)
tree9bb65b95440af09e8aca63abe56970dd3360cc57 /arch/ppc/kernel
parent9c1c01ead627bdda9211c9abd5b758d6c687d8ac (diff)
Merge with Linux 2.2.8.
Diffstat (limited to 'arch/ppc/kernel')
-rw-r--r--arch/ppc/kernel/Makefile5
-rw-r--r--arch/ppc/kernel/align.c24
-rw-r--r--arch/ppc/kernel/apus_setup.c231
-rw-r--r--arch/ppc/kernel/chrp_pci.c343
-rw-r--r--arch/ppc/kernel/chrp_setup.c578
-rw-r--r--arch/ppc/kernel/chrp_time.c6
-rw-r--r--arch/ppc/kernel/feature.c4
-rw-r--r--arch/ppc/kernel/head.S454
-rw-r--r--arch/ppc/kernel/i8259.c130
-rw-r--r--arch/ppc/kernel/i8259.h12
-rw-r--r--arch/ppc/kernel/idle.c32
-rw-r--r--arch/ppc/kernel/indirect_pci.c121
-rw-r--r--arch/ppc/kernel/irq.c1012
-rw-r--r--arch/ppc/kernel/local_irq.h45
-rw-r--r--arch/ppc/kernel/mbx_pci.c17
-rw-r--r--arch/ppc/kernel/mbx_setup.c377
-rw-r--r--arch/ppc/kernel/misc.S71
-rw-r--r--arch/ppc/kernel/mk_defs.c3
-rw-r--r--arch/ppc/kernel/open_pic.c48
-rw-r--r--arch/ppc/kernel/open_pic.h11
-rw-r--r--arch/ppc/kernel/openpic.c35
-rw-r--r--arch/ppc/kernel/pci.c254
-rw-r--r--arch/ppc/kernel/pci.h36
-rw-r--r--arch/ppc/kernel/pmac_pci.c69
-rw-r--r--arch/ppc/kernel/pmac_pic.c362
-rw-r--r--arch/ppc/kernel/pmac_pic.h15
-rw-r--r--arch/ppc/kernel/pmac_setup.c245
-rw-r--r--arch/ppc/kernel/ppc8xx_pic.c49
-rw-r--r--arch/ppc/kernel/ppc8xx_pic.h9
-rw-r--r--arch/ppc/kernel/ppc_defs.h69
-rw-r--r--arch/ppc/kernel/ppc_ksyms.c30
-rw-r--r--arch/ppc/kernel/prep_nvram.c173
-rw-r--r--arch/ppc/kernel/prep_pci.c738
-rw-r--r--arch/ppc/kernel/prep_setup.c597
-rw-r--r--arch/ppc/kernel/prep_time.c220
-rw-r--r--arch/ppc/kernel/process.c126
-rw-r--r--arch/ppc/kernel/prom.c263
-rw-r--r--arch/ppc/kernel/ptrace.c19
-rw-r--r--arch/ppc/kernel/setup.c600
-rw-r--r--arch/ppc/kernel/signal.c29
-rw-r--r--arch/ppc/kernel/smp.c249
-rw-r--r--arch/ppc/kernel/softemu8xx.c19
-rw-r--r--arch/ppc/kernel/syscalls.c5
-rw-r--r--arch/ppc/kernel/time.c284
-rw-r--r--arch/ppc/kernel/time.h21
-rw-r--r--arch/ppc/kernel/traps.c9
46 files changed, 5419 insertions, 2630 deletions
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
index d047c2086..5c8b44a90 100644
--- a/arch/ppc/kernel/Makefile
+++ b/arch/ppc/kernel/Makefile
@@ -27,7 +27,7 @@ O_OBJS += totalmp.o
endif
ifeq ($(CONFIG_MBX),y)
-O_OBJS += mbx_setup.o mbx_pci.o softemu8xx.o
+O_OBJS += mbx_setup.o mbx_pci.o softemu8xx.o i8259.o ppc8xx_pic.o
else
ifeq ($(CONFIG_APUS),y)
O_OBJS += apus_setup.o prom.o openpic.o
@@ -36,7 +36,8 @@ ifneq ($(CONFIG_MBX),y)
O_OBJS += prep_time.o pmac_time.o chrp_time.o \
pmac_setup.o pmac_support.o \
prep_pci.o pmac_pci.o chrp_pci.o \
- residual.o prom.o openpic.o feature.o
+ residual.o prom.o openpic.o feature.o \
+ prep_nvram.o open_pic.o i8259.o pmac_pic.o indirect_pci.o
OX_OBJS += chrp_setup.o prep_setup.o
endif
endif
diff --git a/arch/ppc/kernel/align.c b/arch/ppc/kernel/align.c
index 83ee7756d..cf5fcffd3 100644
--- a/arch/ppc/kernel/align.c
+++ b/arch/ppc/kernel/align.c
@@ -194,13 +194,8 @@ fix_alignment(struct pt_regs *regs)
return -EFAULT; /* bad address */
}
-#ifdef __SMP__
- if ((flags & F) && (regs->msr & MSR_FP) )
- smp_giveup_fpu(current);
-#else
- if ((flags & F) && last_task_used_math == current)
- giveup_fpu();
-#endif
+ if ((flags & F) && (regs->msr & MSR_FP))
+ giveup_fpu(current);
if (flags & M)
return 0; /* too hard for now */
@@ -254,27 +249,16 @@ fix_alignment(struct pt_regs *regs)
data.d = current->tss.fpr[reg];
break;
/* these require some floating point conversions... */
- /* note that giveup_fpu enables the FPU for the kernel */
/* we'd like to use the assignment, but we have to compile
* the kernel with -msoft-float so it doesn't use the
* fp regs for copying 8-byte objects. */
case LD+F+S:
-#ifdef __SMP__
- if (regs->msr & MSR_FP )
- smp_giveup_fpu(current);
-#else
- giveup_fpu();
-#endif
+ enable_kernel_fp();
cvt_fd(&data.f, &current->tss.fpr[reg], &current->tss.fpscr);
/* current->tss.fpr[reg] = data.f; */
break;
case ST+F+S:
-#ifdef __SMP__
- if (regs->msr & MSR_FP )
- smp_giveup_fpu(current);
-#else
- giveup_fpu();
-#endif
+ enable_kernel_fp();
cvt_df(&current->tss.fpr[reg], &data.f, &current->tss.fpscr);
/* data.f = current->tss.fpr[reg]; */
break;
diff --git a/arch/ppc/kernel/apus_setup.c b/arch/ppc/kernel/apus_setup.c
index c3a81ad3e..55e57fc5b 100644
--- a/arch/ppc/kernel/apus_setup.c
+++ b/arch/ppc/kernel/apus_setup.c
@@ -14,12 +14,50 @@
#include <linux/sched.h>
#include <linux/kd.h>
#include <linux/init.h>
+#include <linux/hdreg.h>
+
+/* Get the IDE stuff from the 68k file */
+#define ide_init_hwif_ports m68k_ide_init_hwif_ports
+#define ide_default_irq m68k_ide_default_irq
+#define ide_default_io_base m68k_ide_default_io_base
+#define ide_check_region m68k_ide_check_region
+#define ide_request_region m68k_ide_request_region
+#define ide_release_region m68k_ide_release_region
+#define ide_fix_driveid m68k_ide_fix_driveid
+#include <asm-m68k/ide.h>
+#undef ide_init_hwif_ports
+#define ide_default_irq
+#define ide_default_io_base
+#define ide_check_region
+#define ide_request_region
+#define ide_release_region
+#define ide_fix_driveid
+
#include <asm/setup.h>
#include <asm/amigahw.h>
#include <asm/amigappc.h>
#include <asm/pgtable.h>
#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/ide.h>
+
+#include "time.h"
+#include "local_irq.h"
+
+unsigned long apus_get_rtc_time(void);
+int apus_set_rtc_time(unsigned long nowtime);
+
+/* APUS defs */
+extern int parse_bootinfo(const struct bi_record *);
+extern char _end[];
+#ifdef CONFIG_APUS
+struct mem_info ramdisk;
+unsigned long isa_io_base;
+unsigned long isa_mem_base;
+unsigned long pci_dram_offset;
+#endif
+/* END APUS defs */
unsigned long m68k_machtype;
char debug_device[6] = "";
@@ -72,6 +110,8 @@ __initfunc(void apus_setup_arch(unsigned long * memory_start_p,
int i;
char *p, *q;
+ 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. */
@@ -409,3 +449,194 @@ void cache_clear(__u32 addr, int length)
"isync \n\t"
: : "r" (addr));
}
+
+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);
+}
+
+void
+apus_do_IRQ(struct pt_regs *regs,
+ int cpu,
+ int isfake)
+{
+ int old_level, new_level;
+
+ /* I don't think we need SMP code here - Corey */
+
+ old_level = ~(regs->mq) & IPLEMU_IPLMASK;
+ new_level = (~(regs->mq) >> 3) & IPLEMU_IPLMASK;
+ if (new_level != 0)
+ {
+ APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
+ APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET
+ | (~(new_level) & IPLEMU_IPLMASK)));
+ APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
+
+ process_int (VEC_SPUR+new_level, regs);
+ APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT);
+ APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
+ APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET
+ | (~(old_level) & IPLEMU_IPLMASK)));
+ }
+ APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+void
+apus_ide_insw(ide_ioreg_t port, void *buf, int ns)
+{
+ ide_insw(port, buf, ns);
+}
+
+void
+apus_ide_outsw(ide_ioreg_t port, void *buf, int ns)
+{
+ ide_outsw(port, buf, ns);
+}
+
+int
+apus_ide_default_irq(ide_ioreg_t base)
+{
+ m68k_ide_default_irq(base);
+}
+
+ide_ioreg_t
+apus_ide_default_io_base(int index)
+{
+ m68k_ide_default_io_base(index);
+}
+
+int
+apus_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+ return m68k_ide_check_region(from, extent);
+}
+
+void
+apus_ide_request_region(ide_ioreg_t from,
+ unsigned int extent,
+ const char *name)
+{
+ m68k_ide_request_region(from, extent, name);
+}
+
+void
+apus_ide_release_region(ide_ioreg_t from,
+ unsigned int extent)
+{
+ m68k_ide_release_region(from, extent);
+}
+
+void
+apus_ide_fix_driveid(struct hd_driveid *id)
+{
+ m68k_ide_fix_driveid(id);
+}
+
+__initfunc(void
+apus_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq))
+{
+ m68k_ide_init_hwif_ports(p, base, irq);
+}
+#endif
+
+__initfunc(void
+apus_local_init_IRQ(void))
+{
+ ppc_md.mask_irq = amiga_disable_irq;
+ ppc_md.unmask_irq = amiga_enable_irq;
+ apus_init_IRQ();
+}
+
+__initfunc(void
+apus_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7))
+{
+ /* 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);
+ }
+ /* Make sure code below is not executed. */
+ r4 = 0;
+ r6 = 0;
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+ ISA_DMA_THRESHOLD = 0x00ffffff;
+
+ ppc_md.setup_arch = apus_setup_arch;
+ ppc_md.setup_residual = NULL;
+ ppc_md.get_cpuinfo = apus_get_cpuinfo;
+ ppc_md.irq_cannonicalize = NULL;
+ ppc_md.init_IRQ = apus_init_IRQ;
+ ppc_md.do_IRQ = apus_do_IRQ;
+ ppc_md.get_irq_source = NULL;
+ 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;
+
+ /* These should not be used for the APUS yet, since it uses
+ the M68K keyboard now. */
+ 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.kbd_sysrq_xlate = NULL;
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+ ppc_ide_md.insw = apus_ide_insw;
+ ppc_ide_md.outsw = apus_ide_outsw;
+ ppc_ide_md.default_irq = apus_ide_default_irq;
+ ppc_ide_md.default_io_base = apus_ide_default_io_base;
+ ppc_ide_md.check_region = apus_ide_check_region;
+ ppc_ide_md.request_region = apus_ide_request_region;
+ ppc_ide_md.release_region = apus_ide_release_region;
+ ppc_ide_md.fix_driveid = apus_ide_fix_driveid;
+ ppc_ide_md.ide_init_hwif = apus_ide_init_hwif_ports;
+
+ ppc_ide_md.io_base = _IO_BASE;
+#endif
+}
diff --git a/arch/ppc/kernel/chrp_pci.c b/arch/ppc/kernel/chrp_pci.c
index 98a3e182e..fa4dda10b 100644
--- a/arch/ppc/kernel/chrp_pci.c
+++ b/arch/ppc/kernel/chrp_pci.c
@@ -15,10 +15,14 @@
#include <asm/hydra.h>
#include <asm/prom.h>
#include <asm/gg2.h>
+#include <asm/ide.h>
+#include <asm/machdep.h>
+
+#include "pci.h"
/* LongTrail */
#define pci_config_addr(bus, dev, offset) \
- (GG2_PCI_CONFIG_BASE | ((bus)<<16) | ((dev)<<8) | (offset))
+(GG2_PCI_CONFIG_BASE | ((bus)<<16) | ((dev)<<8) | (offset))
volatile struct Hydra *Hydra = NULL;
@@ -30,144 +34,136 @@ volatile struct Hydra *Hydra = NULL;
int gg2_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned char *val)
{
- if (bus > 7) {
- *val = 0xff;
- return PCIBIOS_DEVICE_NOT_FOUND;
- }
- *val = in_8((unsigned char *)pci_config_addr(bus, dev_fn, offset));
- return PCIBIOS_SUCCESSFUL;
+ if (bus > 7) {
+ *val = 0xff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ *val = in_8((unsigned char *)pci_config_addr(bus, dev_fn, offset));
+ return PCIBIOS_SUCCESSFUL;
}
int gg2_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned short *val)
{
- if (bus > 7) {
- *val = 0xffff;
- return PCIBIOS_DEVICE_NOT_FOUND;
- }
- *val = in_le16((unsigned short *)pci_config_addr(bus, dev_fn, offset));
- return PCIBIOS_SUCCESSFUL;
+ if (bus > 7) {
+ *val = 0xffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ *val = in_le16((unsigned short *)pci_config_addr(bus, dev_fn, offset));
+ return PCIBIOS_SUCCESSFUL;
}
int gg2_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned int *val)
{
- if (bus > 7) {
- *val = 0xffffffff;
- return PCIBIOS_DEVICE_NOT_FOUND;
- }
- *val = in_le32((unsigned int *)pci_config_addr(bus, dev_fn, offset));
- return PCIBIOS_SUCCESSFUL;
+ if (bus > 7) {
+ *val = 0xffffffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ *val = in_le32((unsigned int *)pci_config_addr(bus, dev_fn, offset));
+ return PCIBIOS_SUCCESSFUL;
}
int gg2_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned char val)
{
- if (bus > 7)
- return PCIBIOS_DEVICE_NOT_FOUND;
- out_8((unsigned char *)pci_config_addr(bus, dev_fn, offset), val);
- return PCIBIOS_SUCCESSFUL;
+ if (bus > 7)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_8((unsigned char *)pci_config_addr(bus, dev_fn, offset), val);
+ return PCIBIOS_SUCCESSFUL;
}
int gg2_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned short val)
{
- if (bus > 7)
- return PCIBIOS_DEVICE_NOT_FOUND;
- out_le16((unsigned short *)pci_config_addr(bus, dev_fn, offset), val);
- return PCIBIOS_SUCCESSFUL;
+ if (bus > 7)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le16((unsigned short *)pci_config_addr(bus, dev_fn, offset), val);
+ return PCIBIOS_SUCCESSFUL;
}
int gg2_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned int val)
{
- if (bus > 7)
- return PCIBIOS_DEVICE_NOT_FOUND;
- out_le32((unsigned int *)pci_config_addr(bus, dev_fn, offset), val);
- return PCIBIOS_SUCCESSFUL;
+ if (bus > 7)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32((unsigned int *)pci_config_addr(bus, dev_fn, offset), val);
+ return PCIBIOS_SUCCESSFUL;
}
-extern volatile unsigned int *pci_config_address;
-extern volatile unsigned char *pci_config_data;
-
-#define DEV_FN_MAX (31<<3)
+#define python_config_address(bus) (unsigned *)((0xfef00000+0xf8000)-(bus*0x100000))
+#define python_config_data(bus) ((0xfef00000+0xf8010)-(bus*0x100000))
+#define PYTHON_CFA(b, d, o) (0x80 | ((b<<6) << 8) | ((d) << 16) \
+ | (((o) & ~3) << 24))
+unsigned int python_busnr = 1;
-int raven_pcibios_read_config_byte(unsigned char bus,
- unsigned char dev_fn,
- unsigned char offset,
- unsigned char *val)
+int python_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char *val)
{
- if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
- out_be32(pci_config_address,
- 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
- *val = in_8(pci_config_data+(offset&3));
- return PCIBIOS_SUCCESSFUL;
+ if (bus > python_busnr) {
+ *val = 0xff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
+ *val = in_8((unsigned char *)python_config_data(bus) + (offset&3));
+ return PCIBIOS_SUCCESSFUL;
}
-int raven_pcibios_read_config_word(unsigned char bus,
- unsigned char dev_fn,
- unsigned char offset,
- unsigned short *val)
+int python_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val)
{
- if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
- if (offset&1)return PCIBIOS_BAD_REGISTER_NUMBER;
- out_be32(pci_config_address,
- 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
- *val = in_le16((volatile unsigned short *)
- (pci_config_data+(offset&3)));
- return PCIBIOS_SUCCESSFUL;
+ if (bus > python_busnr) {
+ *val = 0xffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
+ *val = in_le16((unsigned short *)(python_config_data(bus) + (offset&3)));
+ return PCIBIOS_SUCCESSFUL;
}
-int raven_pcibios_read_config_dword(unsigned char bus,
- unsigned char dev_fn,
- unsigned char offset,
- unsigned int *val)
+
+int python_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int *val)
{
- if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
- if (offset&3)return PCIBIOS_BAD_REGISTER_NUMBER;
- out_be32(pci_config_address,
- 0x80|(bus<<8)|(dev_fn<<16)|(offset<<24));
- *val = in_le32((volatile unsigned int *)(pci_config_data));
- return PCIBIOS_SUCCESSFUL;
+ if (bus > python_busnr) {
+ *val = 0xffffffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
+ *val = in_le32((unsigned *)python_config_data(bus));
+ return PCIBIOS_SUCCESSFUL;
}
-int raven_pcibios_write_config_byte(unsigned char bus,
- unsigned char dev_fn,
- unsigned char offset,
- unsigned char val)
+int python_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char val)
{
- if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
- out_be32(pci_config_address,
- 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
- out_8(pci_config_data+(offset&3),val);
- return PCIBIOS_SUCCESSFUL;
+ if (bus > python_busnr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
+ out_8((volatile unsigned char *)python_config_data(bus) + (offset&3), val);
+ return PCIBIOS_SUCCESSFUL;
}
-int raven_pcibios_write_config_word(unsigned char bus,
- unsigned char dev_fn,
- unsigned char offset,
- unsigned short val)
+int python_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val)
{
- if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
- if (offset&1)return PCIBIOS_BAD_REGISTER_NUMBER;
- out_be32(pci_config_address,
- 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
- out_le16((volatile unsigned short *)(pci_config_data+(offset&3)),val);
- return PCIBIOS_SUCCESSFUL;
+ if (bus > python_busnr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
+ out_le16((volatile unsigned short *)python_config_data(bus) + (offset&3),
+ val);
+ return PCIBIOS_SUCCESSFUL;
}
-int raven_pcibios_write_config_dword(unsigned char bus,
- unsigned char dev_fn,
- unsigned char offset,
- unsigned int val)
+int python_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int val)
{
- if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
- if (offset&3)return PCIBIOS_BAD_REGISTER_NUMBER;
- out_be32(pci_config_address,
- 0x80|(bus<<8)|(dev_fn<<16)|(offset<<24));
- out_le32((volatile unsigned int *)pci_config_data,val);
- return PCIBIOS_SUCCESSFUL;
+ if (bus > python_busnr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
+ out_le32((unsigned *)python_config_data(bus) + (offset&3), val);
+ return PCIBIOS_SUCCESSFUL;
}
/*
@@ -191,7 +187,8 @@ static u_char hydra_openpic_initsenses[] __initdata = {
/* all others are 1 (= default) */
};
-__initfunc(int hydra_init(void))
+int __init
+hydra_init(void)
{
struct device_node *np;
@@ -216,75 +213,95 @@ __initfunc(int hydra_init(void))
return 1;
}
-
-extern int chrp_ide_irq;
-
-__initfunc(int w83c553f_init(void))
+void __init
+chrp_pcibios_fixup(void)
{
- u_char bus, dev;
-#if 0
- unsigned char t8;
- unsigned short t16;
-#endif
- unsigned int t32;
- struct pci_dev *pdev;
- if ((pdev = pci_find_device(PCI_VENDOR_ID_WINBOND,
- PCI_DEVICE_ID_WINBOND_83C553, NULL))) {
- bus = pdev->bus->number;
- dev = pdev->devfn + 1;
- pcibios_read_config_dword(bus, dev, PCI_VENDOR_ID, &t32);
- if (t32 == (PCI_DEVICE_ID_WINBOND_82C105<<16) + PCI_VENDOR_ID_WINBOND) {
-#if 0
- printk("Enabling SL82C105 IDE on W83C553F\n");
- /*
- * FIXME: this doesn't help :-(
- */
-
- /* I/O mapping */
- pcibios_read_config_word(bus, dev, PCI_COMMAND, &t16);
- t16 |= PCI_COMMAND_IO;
- pcibios_write_config_word(bus, dev, PCI_COMMAND, t16);
-
- /* Standard IDE registers */
- pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_0,
- 0xffffffff);
- pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32);
- pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_0,
- 0x000001f0 | 1);
- pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_1,
- 0xffffffff);
- pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_1, &t32);
- pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_1,
- 0x000003f4 | 1);
- pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_2,
- 0xffffffff);
- pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_2, &t32);
- pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_2,
- 0x00000170 | 1);
- pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_3,
- 0xffffffff);
- pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_3, &t32);
- pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_3,
- 0x00000374 | 1);
+ struct pci_dev *dev;
+
+ /* some of IBM chrps have > 1 bus */
+ if ( !strncmp("IBM", get_property(find_path_device("/"),
+ "name", NULL),3) )
+ {
+ pci_scan_peer_bridge(1);
+ pci_scan_peer_bridge(2);
+ }
+
+ /* PCI interrupts are controlled by the OpenPIC */
+ for( dev=pci_devices ; dev; dev=dev->next )
+ {
+ if ( dev->irq )
+ dev->irq = openpic_to_irq( dev->irq );
+ /* adjust the io_port for the NCR cards for busses other than 0 -- Cort */
+ if ( (dev->bus->number > 0) && (dev->vendor == PCI_VENDOR_ID_NCR) )
+ dev->base_address[0] += (dev->bus->number*0x08000000);
+ /* these need to be absolute addrs for OF and Matrox FB -- Cort */
+ if ( dev->vendor == PCI_VENDOR_ID_MATROX )
+ {
+ if ( dev->base_address[0] < isa_mem_base )
+ dev->base_address[0] += isa_mem_base;
+ if ( dev->base_address[1] < isa_mem_base )
+ dev->base_address[1] += isa_mem_base;
+ }
+ /* the F50 identifies the amd as a trident */
+ if ( (dev->vendor == PCI_VENDOR_ID_TRIDENT) &&
+ (dev->class == PCI_CLASS_NETWORK_ETHERNET) )
+ {
+ dev->vendor = PCI_VENDOR_ID_AMD;
+ pcibios_write_config_word(dev->bus->number, dev->devfn,
+ PCI_VENDOR_ID, PCI_VENDOR_ID_AMD);
+ }
+ }
+}
- /* IDE Bus Master Control */
- pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_4,
- 0xffffffff);
- pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_4, &t32);
- pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_4,
- 0x1000 | 1);
- pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_5,
- 0xffffffff);
- pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_5, &t32);
- pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_5,
- 0x1010 | 1);
+decl_config_access_method(grackle);
+decl_config_access_method(indirect);
- /* IDE Interrupt */
- pcibios_read_config_byte(bus, dev, PCI_INTERRUPT_LINE, &t8);
- chrp_ide_irq = t8;
-#endif
- return 1;
- }
- }
- return 0;
+void __init
+chrp_setup_pci_ptrs(void)
+{
+ struct device_node *py;
+
+ if ( !strncmp("MOT",
+ get_property(find_path_device("/"), "model", NULL),3) )
+ {
+ pci_dram_offset = 0;
+ isa_mem_base = 0xf7000000;
+ isa_io_base = 0xfe000000;
+ set_config_access_method(grackle);
+ }
+ else
+ {
+ if ( (py = find_compatible_devices( "pci", "IBM,python" )) )
+ {
+ /* find out how many pythons */
+ while ( (py = py->next) ) python_busnr++;
+ set_config_access_method(python);
+ /*
+ * We base these values on the machine type but should
+ * try to read them from the python controller itself.
+ * -- Cort
+ */
+ if ( !strncmp("IBM,7025-F50", get_property(find_path_device("/"), "name", NULL),12) )
+ {
+ pci_dram_offset = 0x80000000;
+ isa_mem_base = 0xa0000000;
+ isa_io_base = 0x88000000;
+ } else if ( !strncmp("IBM,7043-260",
+ get_property(find_path_device("/"), "name", NULL),12) )
+ {
+ pci_dram_offset = 0x80000000;
+ isa_mem_base = 0xc0000000;
+ isa_io_base = 0xf8000000;
+ }
+ }
+ else
+ {
+ pci_dram_offset = 0;
+ isa_mem_base = 0xf7000000;
+ isa_io_base = 0xf8000000;
+ set_config_access_method(gg2);
+ }
+ }
+
+ ppc_md.pcibios_fixup = chrp_pcibios_fixup;
}
diff --git a/arch/ppc/kernel/chrp_setup.c b/arch/ppc/kernel/chrp_setup.c
index 5b373c876..2c652f049 100644
--- a/arch/ppc/kernel/chrp_setup.c
+++ b/arch/ppc/kernel/chrp_setup.c
@@ -31,6 +31,7 @@
#include <linux/ioport.h>
#include <linux/console.h>
#include <linux/pci.h>
+#include <linux/openpic.h>
#include <asm/mmu.h>
#include <asm/processor.h>
@@ -40,9 +41,50 @@
#include <asm/prom.h>
#include <asm/gg2.h>
#include <asm/pci-bridge.h>
-
-extern void hydra_init(void);
-extern void w83c553f_init(void);
+#include <asm/dma.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+#include <asm/adb.h>
+#include <asm/hydra.h>
+
+#include "time.h"
+#include "local_irq.h"
+#include "i8259.h"
+#include "open_pic.h"
+
+/* Fixme - need to move these into their own .c and .h file */
+extern void i8259_mask_and_ack_irq(unsigned int irq_nr);
+extern void i8259_set_irq_mask(unsigned int irq_nr);
+extern void i8259_mask_irq(unsigned int irq_nr);
+extern void i8259_unmask_irq(unsigned int irq_nr);
+extern void i8259_init(void);
+
+/* Fixme - remove this when it is fixed. - Corey */
+extern volatile unsigned char *chrp_int_ack_special;
+
+unsigned long chrp_get_rtc_time(void);
+int chrp_set_rtc_time(unsigned long nowtime);
+void chrp_calibrate_decr(void);
+void chrp_time_init(void);
+
+void chrp_setup_pci_ptrs(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 int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int mackbd_getkeycode(unsigned int scancode);
+extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode);
+extern char mackbd_unexpected_up(unsigned char keycode);
+extern void mackbd_leds(unsigned char leds);
+extern void mackbd_init_hw(void);
+extern unsigned char mackbd_sysrq_xlate[128];
/* for the mac fs */
kdev_t boot_dev;
@@ -53,7 +95,6 @@ extern int probingmem;
extern unsigned long loops_per_sec;
unsigned long empty_zero_page[1024];
-extern unsigned char aux_device_present;
#ifdef CONFIG_BLK_DEV_RAM
extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */
@@ -62,17 +103,17 @@ extern int rd_image_start; /* starting block # of image */
#endif
static const char *gg2_memtypes[4] = {
- "FPM", "SDRAM", "EDO", "BEDO"
+ "FPM", "SDRAM", "EDO", "BEDO"
};
static const char *gg2_cachesizes[4] = {
- "256 KB", "512 KB", "1 MB", "Reserved"
+ "256 KB", "512 KB", "1 MB", "Reserved"
};
static const char *gg2_cachetypes[4] = {
- "Asynchronous", "Reserved", "Flow-Through Synchronous",
- "Pipelined Synchronous"
+ "Asynchronous", "Reserved", "Flow-Through Synchronous",
+ "Pipelined Synchronous"
};
static const char *gg2_cachemodes[4] = {
- "Disabled", "Write-Through", "Copy-Back", "Transparent Mode"
+ "Disabled", "Write-Through", "Copy-Back", "Transparent Mode"
};
int
@@ -85,53 +126,60 @@ chrp_get_cpuinfo(char *buffer)
root = find_path_device("/");
if (root)
- model = get_property(root, "model", NULL);
+ model = get_property(root, "model", NULL);
len = sprintf(buffer,"machine\t\t: CHRP %s\n", model);
- /* VLSI VAS96011/12 `Golden Gate 2' */
- /* Memory banks */
- sdramen = (in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+GG2_PCI_DRAM_CTRL))
- >>31) & 1;
- for (i = 0; i < (sdramen ? 4 : 6); i++) {
- t = in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+GG2_PCI_DRAM_BANK0+
- i*4));
- if (!(t & 1))
- continue;
- switch ((t>>8) & 0x1f) {
- case 0x1f:
- model = "4 MB";
- break;
- case 0x1e:
- model = "8 MB";
- break;
- case 0x1c:
- model = "16 MB";
- break;
- case 0x18:
- model = "32 MB";
- break;
- case 0x10:
- model = "64 MB";
- break;
- case 0x00:
- model = "128 MB";
- break;
- default:
- model = "Reserved";
- break;
- }
- len += sprintf(buffer+len, "memory bank %d\t: %s %s\n", i, model,
- gg2_memtypes[sdramen ? 1 : ((t>>1) & 3)]);
+ /* longtrail (goldengate) stuff */
+ if ( !strncmp( model, "IBM,LongTrail", 9 ) )
+ {
+ /* VLSI VAS96011/12 `Golden Gate 2' */
+ /* Memory banks */
+ sdramen = (in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+
+ GG2_PCI_DRAM_CTRL))
+ >>31) & 1;
+ for (i = 0; i < (sdramen ? 4 : 6); i++) {
+ t = in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+
+ GG2_PCI_DRAM_BANK0+
+ i*4));
+ if (!(t & 1))
+ continue;
+ switch ((t>>8) & 0x1f) {
+ case 0x1f:
+ model = "4 MB";
+ break;
+ case 0x1e:
+ model = "8 MB";
+ break;
+ case 0x1c:
+ model = "16 MB";
+ break;
+ case 0x18:
+ model = "32 MB";
+ break;
+ case 0x10:
+ model = "64 MB";
+ break;
+ case 0x00:
+ model = "128 MB";
+ break;
+ default:
+ model = "Reserved";
+ break;
+ }
+ len += sprintf(buffer+len, "memory bank %d\t: %s %s\n", i, model,
+ gg2_memtypes[sdramen ? 1 : ((t>>1) & 3)]);
+ }
+ /* L2 cache */
+ t = in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+GG2_PCI_CC_CTRL));
+ len += sprintf(buffer+len, "board l2\t: %s %s (%s)\n",
+ gg2_cachesizes[(t>>7) & 3],
+ gg2_cachetypes[(t>>2) & 3],
+ gg2_cachemodes[t & 3]);
}
- /* L2 cache */
- t = in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+GG2_PCI_CC_CTRL));
- len += sprintf(buffer+len, "board l2\t: %s %s (%s)\n",
- gg2_cachesizes[(t>>7) & 3], gg2_cachetypes[(t>>2) & 3],
- gg2_cachemodes[t & 3]);
return len;
}
- /*
+/*
* Fixes for the National Semiconductor PC78308VUL SuperI/O
*
* Some versions of Open Firmware incorrectly initialize the IRQ settings
@@ -140,57 +188,55 @@ chrp_get_cpuinfo(char *buffer)
__initfunc(static inline void sio_write(u8 val, u8 index))
{
- outb(index, 0x15c);
- outb(val, 0x15d);
+ outb(index, 0x15c);
+ outb(val, 0x15d);
}
__initfunc(static inline u8 sio_read(u8 index))
{
- outb(index, 0x15c);
- return inb(0x15d);
+ outb(index, 0x15c);
+ return inb(0x15d);
}
__initfunc(static void 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);
- printk("sio: %s irq level %d, type %d, %sactive: ", name, level0, type0,
- !active ? "in" : "");
- if (level0 == level && type0 == type && active)
- printk("OK\n");
- else {
- printk("remapping to level %d, type %d, active\n", level, type);
- sio_write(0x01, 0x30);
- sio_write(level, 0x70);
- sio_write(type, 0x71);
- }
+ u8 level0, type0, active;
+
+ /* select logical device */
+ sio_write(device, 0x07);
+ active = sio_read(0x30);
+ level0 = sio_read(0x70);
+ type0 = sio_read(0x71);
+ printk("sio: %s irq level %d, type %d, %sactive: ", name, level0, type0,
+ !active ? "in" : "");
+ if (level0 == level && type0 == type && active)
+ printk("OK\n");
+ else {
+ printk("remapping to level %d, type %d, active\n", level, type);
+ sio_write(0x01, 0x30);
+ sio_write(level, 0x70);
+ sio_write(type, 0x71);
+ }
}
__initfunc(static void sio_init(void))
{
- /* 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);
+ /* 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);
}
__initfunc(void
-chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
+ chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
{
extern char cmd_line[];
/* init to some ~sane value until calibrate_delay() runs */
loops_per_sec = 50000000;
-
- aux_device_present = 0xaa;
#ifdef CONFIG_BLK_DEV_INITRD
/* this is fine for chrp */
@@ -219,8 +265,15 @@ chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
* -- Geert
*/
hydra_init(); /* Mac I/O */
- w83c553f_init(); /* PCI-ISA bridge and IDE */
+ /* Some IBM machines don't have the hydra -- Cort */
+ if ( !OpenPIC )
+ {
+ OpenPIC = (struct OpenPIC *)*(unsigned long *)get_property(
+ find_path_device("/"), "platform-open-pic", NULL);
+ OpenPIC = ioremap((unsigned long)OpenPIC, sizeof(struct OpenPIC));
+ }
+
/*
* Fix the Super I/O configuration
*/
@@ -232,27 +285,210 @@ chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
if ( !strncmp("MOT", get_property(find_path_device("/"),
"model", NULL),3) )
*memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p);
+ /*
+ * The f50 has a lot of IO space - we need to map some in that
+ * isn't covered by the BAT mappings in MMU_init() -- Cort
+ */
+ if ( !strncmp("F5", get_property(find_path_device("/"),
+ "ibm,model-class", NULL),2) )
+ {
+#if 0
+ /*
+ * This ugly hack allows us to force ioremap() to
+ * create a 1-to-1 mapping for us, even though
+ * the address is < ioremap_base. This is necessary
+ * since we want our PCI IO space to have contiguous
+ * virtual addresses and I think it's worse to have
+ * calls to map_page() here.
+ * -- Cort
+ */
+ unsigned long hold = ioremap_base;
+ ioremap_base = 0;
+ __ioremap(0x90000000, 0x10000000, _PAGE_NO_CACHE);
+ ioremap_base = hold;
+#endif
+ }
}
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+void
+chrp_restart(char *cmd)
+{
+#if 0
+ extern unsigned int rtas_entry, rtas_data, rtas_size;
+ printk("RTAS system-reboot returned %d\n",
+ call_rtas("system-reboot", 0, 1, NULL));
+ printk("rtas_entry: %08lx rtas_data: %08lx rtas_size: %08lx\n",
+ rtas_entry,rtas_data,rtas_size);
+ for (;;);
+#else
+ printk("System Halted\n");
+ while(1);
+#endif
+}
-unsigned int chrp_ide_irq = 0;
-int chrp_ide_ports_known = 0;
-ide_ioreg_t chrp_ide_regbase[MAX_HWIFS];
-ide_ioreg_t chrp_idedma_regbase;
+void
+chrp_power_off(void)
+{
+ /* RTAS doesn't seem to work on Longtrail.
+ For now, do it the same way as the PReP. */
+#if 0
+ extern unsigned int rtas_entry, rtas_data, rtas_size;
+ printk("RTAS power-off returned %d\n",
+ call_rtas("power-off", 2, 1, NULL, 0, 0));
+ printk("rtas_entry: %08lx rtas_data: %08lx rtas_size: %08lx\n",
+ rtas_entry,rtas_data,rtas_size);
+ for (;;);
+#else
+ chrp_restart(NULL);
+#endif
+}
-void chrp_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+void
+chrp_halt(void)
{
- ide_ioreg_t port = base;
- int i = 8;
+ chrp_restart(NULL);
+}
- while (i--)
- *p++ = port++;
- *p++ = port;
- if (irq != NULL)
- *irq = chrp_ide_irq;
+u_int
+chrp_irq_cannonicalize(u_int irq)
+{
+ if (irq == 2)
+ {
+ return 9;
+ }
+ else
+ {
+ return irq;
+ }
+}
+
+void
+chrp_do_IRQ(struct pt_regs *regs,
+ int cpu,
+ int isfake)
+{
+ int irq;
+ unsigned long bits = 0;
+ int openpic_eoi_done = 0;
+
+#ifdef __SMP__
+ {
+ unsigned int loops = 1000000;
+ while (test_bit(0, &global_irq_lock)) {
+ if (smp_processor_id() == global_irq_holder) {
+ printk("uh oh, interrupt while we hold global irq lock!\n");
+#ifdef CONFIG_XMON
+ xmon(0);
+#endif
+ break;
+ }
+ if (loops-- == 0) {
+ printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder);
+#ifdef CONFIG_XMON
+ xmon(0);
+#endif
+ }
+ }
+ }
+#endif /* __SMP__ */
+
+ irq = openpic_irq(0);
+ if (irq == IRQ_8259_CASCADE)
+ {
+ /*
+ * This magic address generates a PCI IACK cycle.
+ *
+ * This should go in the above mask/ack code soon. -- Cort
+ */
+ if ( chrp_int_ack_special )
+ irq = *chrp_int_ack_special;
+ else
+ irq = i8259_irq(0);
+ /*
+ * Acknowledge as soon as possible to allow i8259
+ * interrupt nesting */
+ openpic_eoi(0);
+ openpic_eoi_done = 1;
+ }
+ if (irq == OPENPIC_VEC_SPURIOUS)
+ {
+ /*
+ * Spurious interrupts should never be
+ * acknowledged
+ */
+ ppc_spurious_interrupts++;
+ openpic_eoi_done = 1;
+ goto out;
+ }
+ bits = 1UL << irq;
+
+ if (irq < 0)
+ {
+ printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
+ irq, regs->nip);
+ ppc_spurious_interrupts++;
+ }
+ else
+ {
+ ppc_irq_dispatch_handler( regs, irq );
+ }
+out:
+ if (!openpic_eoi_done)
+ openpic_eoi(0);
}
+__initfunc(void
+ chrp_init_IRQ(void))
+{
+ struct device_node *np;
+ int i;
+
+ if ( !(np = find_devices("pci") ) )
+ printk("Cannot find pci to get ack address\n");
+ else
+ {
+ chrp_int_ack_special = (volatile unsigned char *)
+ (*(unsigned long *)get_property(np,
+ "8259-interrupt-acknowledge", NULL));
+ }
+ for ( i = 16 ; i < NR_IRQS ; i++ )
+ irq_desc[i].ctl = &open_pic;
+ /* openpic knows that it's at irq 16 offset
+ * so we don't need to set it in the pic structure
+ * -- Cort
+ */
+ openpic_init(1);
+ for ( i = 0 ; i < 16 ; i++ )
+ irq_desc[i].ctl = &i8259_pic;
+ i8259_init();
+#ifdef CONFIG_XMON
+ request_irq(openpic_to_irq(HYDRA_INT_ADB_NMI),
+ xmon_irq, 0, "NMI", 0);
+#endif /* CONFIG_XMON */
+#ifdef __SMP__
+ request_irq(openpic_to_irq(OPENPIC_VEC_IPI),
+ openpic_ipi_action, 0, "IPI0", 0);
+#endif /* __SMP__ */
+}
+
+__initfunc(void
+ chrp_init2(void))
+{
+ adb_init();
+
+ /* Should this be here? - Corey */
+ pmac_nvram_init();
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+unsigned int chrp_ide_irq = 0;
+int chrp_ide_ports_known = 0;
+ide_ioreg_t chrp_ide_regbase[MAX_HWIFS];
+ide_ioreg_t chrp_idedma_regbase;
+
void chrp_ide_probe(void) {
struct pci_dev *pdev = pci_find_device(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, NULL);
@@ -270,9 +506,167 @@ void chrp_ide_probe(void) {
}
}
+void
+chrp_ide_insw(ide_ioreg_t port, void *buf, int ns)
+{
+ ide_insw(port+_IO_BASE, buf, ns);
+}
+
+void
+chrp_ide_outsw(ide_ioreg_t port, void *buf, int ns)
+{
+ ide_outsw(port+_IO_BASE, buf, ns);
+}
+
+int
+chrp_ide_default_irq(ide_ioreg_t base)
+{
+ if (chrp_ide_ports_known == 0)
+ chrp_ide_probe();
+ return chrp_ide_irq;
+}
+
+ide_ioreg_t
+chrp_ide_default_io_base(int index)
+{
+ if (chrp_ide_ports_known == 0)
+ chrp_ide_probe();
+ return chrp_ide_regbase[index];
+}
+
+int
+chrp_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+ return check_region(from, extent);
+}
+
+void
+chrp_ide_request_region(ide_ioreg_t from,
+ unsigned int extent,
+ const char *name)
+{
+ request_region(from, extent, name);
+}
+
+void
+chrp_ide_release_region(ide_ioreg_t from,
+ unsigned int extent)
+{
+ release_region(from, extent);
+}
+
+void
+chrp_ide_fix_driveid(struct hd_driveid *id)
+{
+ ppc_generic_ide_fix_driveid(id);
+}
+
+void chrp_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+{
+ ide_ioreg_t port = base;
+ int i = 8;
+
+ while (i--)
+ *p++ = port++;
+ *p++ = port;
+ if (irq != NULL)
+ *irq = chrp_ide_irq;
+}
+
EXPORT_SYMBOL(chrp_ide_irq);
EXPORT_SYMBOL(chrp_ide_ports_known);
EXPORT_SYMBOL(chrp_ide_regbase);
EXPORT_SYMBOL(chrp_ide_probe);
#endif
+
+__initfunc(void
+ chrp_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7))
+{
+ chrp_setup_pci_ptrs();
+#ifdef CONFIG_BLK_DEV_INITRD
+ /* take care of initrd if we have one */
+ if ( r3 )
+ {
+ initrd_start = r3 + KERNELBASE;
+ initrd_end = r3 + r4 + KERNELBASE;
+ }
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+ /* pci_dram_offset/isa_io_base/isa_mem_base set by setup_pci_ptrs() */
+ ISA_DMA_THRESHOLD = ~0L;
+ DMA_MODE_READ = 0x44;
+ DMA_MODE_WRITE = 0x48;
+
+ ppc_md.setup_arch = chrp_setup_arch;
+ ppc_md.setup_residual = NULL;
+ ppc_md.get_cpuinfo = chrp_get_cpuinfo;
+ ppc_md.irq_cannonicalize = chrp_irq_cannonicalize;
+ ppc_md.init_IRQ = chrp_init_IRQ;
+ ppc_md.do_IRQ = chrp_do_IRQ;
+
+ 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;
+
+#ifdef CONFIG_VT
+#ifdef CONFIG_MAC_KEYBOAD
+ if ( adb_hardware == ADB_NONE )
+ {
+ 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.kbd_sysrq_xlate = pckbd_sysrq_xlate;
+#endif
+ }
+ else
+ {
+ 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.kbd_sysrq_xlate = mackbd_sysrq_xlate;
+#endif
+ }
+#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;
+#ifdef CONFIG_MAGIC_SYSRQ
+ ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate;
+#endif
+#endif
+#endif
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+ ppc_ide_md.insw = chrp_ide_insw;
+ ppc_ide_md.outsw = chrp_ide_outsw;
+ ppc_ide_md.default_irq = chrp_ide_default_irq;
+ ppc_ide_md.default_io_base = chrp_ide_default_io_base;
+ ppc_ide_md.check_region = chrp_ide_check_region;
+ ppc_ide_md.request_region = chrp_ide_request_region;
+ ppc_ide_md.release_region = chrp_ide_release_region;
+ ppc_ide_md.fix_driveid = chrp_ide_fix_driveid;
+ ppc_ide_md.ide_init_hwif = chrp_ide_init_hwif_ports;
+
+ ppc_ide_md.io_base = _IO_BASE;
+#endif
+}
diff --git a/arch/ppc/kernel/chrp_time.c b/arch/ppc/kernel/chrp_time.c
index 7a2ea7b26..c374c9bd1 100644
--- a/arch/ppc/kernel/chrp_time.c
+++ b/arch/ppc/kernel/chrp_time.c
@@ -154,7 +154,8 @@ unsigned long chrp_get_rtc_time(void)
__initfunc(void chrp_calibrate_decr(void))
{
struct device_node *cpu;
- int freq, *fp, divisor;
+ int *fp, divisor;
+ unsigned long freq;
if (via_calibrate_decr())
return;
@@ -170,10 +171,9 @@ __initfunc(void chrp_calibrate_decr(void))
if (fp != 0)
freq = *fp;
}
-
freq *= 60; /* try to make freq/1e6 an integer */
divisor = 60;
- printk("time_init: decrementer frequency = %d/%d\n", freq, divisor);
+ printk("time_init: decrementer frequency = %lu/%d\n", freq, divisor);
decrementer_count = freq / HZ / divisor;
count_period_num = divisor;
count_period_den = freq / 1000000;
diff --git a/arch/ppc/kernel/feature.c b/arch/ppc/kernel/feature.c
index 48d8bcb39..25ee3424b 100644
--- a/arch/ppc/kernel/feature.c
+++ b/arch/ppc/kernel/feature.c
@@ -41,7 +41,6 @@ static u32 feature_bits_pbook[] = {
OH_BAY_FLOPPY_ENABLE, /* FEATURE_Mediabay_floppy_enable */
0, /* FEATURE_BMac_reset */
0, /* FEATURE_BMac_IO_enable */
- 0, /* FEATURE_Modem_PowerOn -> guess...*/
0 /* FEATURE_Modem_Reset -> guess...*/
};
@@ -64,8 +63,7 @@ static u32 feature_bits_heathrow[] = {
OH_BAY_FLOPPY_ENABLE, /* FEATURE_Mediabay_floppy_enable */
0x80000000, /* FEATURE_BMac_reset */
0x60000000, /* FEATURE_BMac_IO_enable */
- 0x02000000, /* FEATURE_Modem_PowerOn -> guess...*/
- 0x07000000 /* FEATURE_Modem_Reset -> guess...*/
+ 0x02000000 /* FEATURE_Modem_Reset -> guess...*/
};
/* definition of a feature controller object */
diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
index d7b791387..b9ecc2dcc 100644
--- a/arch/ppc/kernel/head.S
+++ b/arch/ppc/kernel/head.S
@@ -1,7 +1,7 @@
/*
* arch/ppc/kernel/head.S
*
- * $Id: head.S,v 1.114 1998/12/28 10:28:45 paulus Exp $
+ * $Id: head.S,v 1.130 1999/05/09 19:16:43 cort Exp $
*
* PowerPC version
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -44,8 +44,13 @@
/* optimization for 603 to load the tlb directly from the linux table */
#define NO_RELOAD_HTAB 1
+#ifndef CONFIG_8xx
CACHE_LINE_SIZE = 32
LG_CACHE_LINE_SIZE = 5
+#else
+CACHE_LINE_SIZE = 16
+LG_CACHE_LINE_SIZE = 4
+#endif
#define TOPHYS(x) (x - KERNELBASE)
@@ -81,13 +86,12 @@ LG_CACHE_LINE_SIZE = 5
sync; \
isync
-/* This instruction is not implemented on the PPC 603 or 601 */
#ifndef CONFIG_8xx
/* This instruction is not implemented on the PPC 603 or 601 */
#define tlbia \
li r4,128; \
mtctr r4; \
- lis r4,0xC000; \
+ lis r4,KERNELBASE@h; \
0: tlbie r4; \
addi r4,r4,0x1000; \
bdnz 0b
@@ -212,6 +216,7 @@ __start:
mr r29,r5
mr r28,r6
mr r27,r7
+ li r24,0 /* cpu # */
#ifndef CONFIG_8xx
bl prom_init
.globl __secondary_start
@@ -236,15 +241,33 @@ __secondary_start:
mtspr IBAT1L,r10
b 5f
4:
-#ifndef CONFIG_APUS
- ori r11,r11,0x1fe /* set up BAT registers for 604 */
- li r8,2 /* R/W access */
-#else
+#ifdef CONFIG_APUS
+ ori r11,r11,BL_8M<<2|0x2 /* set up an 8MB mapping */
ori r11,r11,0xfe /* set up an 8MB mapping */
lis r8,CYBERBASEp@h
lwz r8,0(r8)
addis r8,r8,KERNELBASE@h
addi r8,r8,2
+#else
+ ori r11,r11,BL_256M<<2|0x2 /* set up BAT registers for 604 */
+ li r8,2 /* R/W access */
+ /*
+ * allow secondary cpus to get at all of ram in early bootup
+ * since their init_task may be up there -- Cort
+ */
+ oris r18,r8,0x10000000@h
+ oris r21,r11,(KERNELBASE+0x10000000)@h
+ mtspr DBAT1L,r18 /* N.B. 6xx (not 601) have valid */
+ mtspr DBAT1U,r21 /* bit in upper BAT register */
+ mtspr IBAT1L,r18
+ mtspr IBAT1U,r21
+
+ oris r18,r8,0x20000000@h
+ oris r21,r11,(KERNELBASE+0x20000000)@h
+ mtspr DBAT2L,r18 /* N.B. 6xx (not 601) have valid */
+ mtspr DBAT2U,r21 /* bit in upper BAT register */
+ mtspr IBAT2L,r28
+ mtspr IBAT2U,r21
#endif
mtspr DBAT0L,r8 /* N.B. 6xx (not 601) have valid */
mtspr DBAT0U,r11 /* bit in upper BAT register */
@@ -327,20 +350,28 @@ __secondary_start:
lis r8, MI_Kp@h /* Set the protection mode */
mtspr MI_AP, r8
mtspr MD_AP, r8
-#ifdef CONFIG_MBX
+
+/* We will get these from a configuration file as soon as I verify
+ * the extraneous bits don't cause problems in the TLB.
+ */
+#if defined(CONFIG_MBX) || defined(CONFIG_RPXLITE)
+#define BOOT_IMMR 0xfa000000
+#endif
+#ifdef CONFIG_BSEIP
+#define BOOT_IMMR 0xff000000
+#endif
/* Map another 8 MByte at 0xfa000000 to get the processor
* internal registers (among other things).
*/
- lis r8, 0xfa000000@h /* Create vaddr for TLB */
+ lis r8, BOOT_IMMR@h /* Create vaddr for TLB */
ori r8, r8, MD_EVALID /* Mark it valid */
mtspr MD_EPN, r8
li r8, MD_PS8MEG /* Set 8M byte page */
ori r8, r8, MD_SVALID /* Make it valid */
mtspr MD_TWC, r8
- lis r8, 0xfa000000@h /* Create paddr for TLB */
+ lis r8, BOOT_IMMR@h /* Create paddr for TLB */
ori r8, r8, MI_BOOTINIT|0x2 /* Inhibit cache -- Cort */
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.
@@ -354,9 +385,8 @@ __secondary_start:
#if 0
mtspr DC_CST, r8
#else
- /* I still have a bug somewhere because the Ethernet driver
- * does not want to work with copyback enabled. For now,
- * at least enable write through.
+ /* For a debug option, I left this here to easily enable
+ * the write through cache mode
*/
lis r8, DC_SFWT@h
mtspr DC_CST, r8
@@ -385,7 +415,7 @@ turn_on_mmu:
* this, we leave this much untouched space on the stack on exception
* entry.
*/
-#define STACK_UNDERHEAD 64
+#define STACK_UNDERHEAD 0
/*
* Exception entry code. This code runs with address translation
@@ -442,7 +472,11 @@ label: \
.long int_return
/* System reset */
+#ifdef CONFIG_SMP /* MVME/MTX start the secondary here */
+ STD_EXCEPTION(0x100, Reset, __secondary_start_psurge)
+#else
STD_EXCEPTION(0x100, Reset, UnknownException)
+#endif
/* Machine check */
STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
@@ -1148,6 +1182,8 @@ transfer_to_handler:
mflr r23
andi. r24,r23,0x3f00 /* get vector offset */
stw r24,TRAP(r21)
+ li r22,RESULT
+ stwcx. r22,r22,r21 /* to clear the reservation */
li r22,0
stw r22,RESULT(r21)
mtspr SPRG2,r22 /* r1 is now kernel sp */
@@ -1155,7 +1191,7 @@ transfer_to_handler:
cmplw 0,r1,r2
cmplw 1,r1,r24
crand 1,1,4
- bgt stack_ovf /* if r2 < r1 < r2+TASK_STRUCT_SIZE */
+ bgt- stack_ovf /* if r2 < r1 < r2+TASK_STRUCT_SIZE */
lwz r24,0(r23) /* virtual address of handler */
lwz r23,4(r23) /* where to go when done */
mtspr SRR0,r24
@@ -1204,13 +1240,10 @@ Hash_base = 0x180000
Hash_bits = 12 /* e.g. 256kB hash table */
Hash_msk = (((1 << Hash_bits) - 1) * 64)
- .globl hash_table_lock
-hash_table_lock:
-.long 0
-
.globl hash_page
hash_page:
#ifdef __SMP__
+ eieio
lis r2,hash_table_lock@h
ori r2,r2,hash_table_lock@l
tophys(r2,r2,r6)
@@ -1226,7 +1259,7 @@ hash_page:
12: cmpw r6,r0
bdnzf 2,10b
tw 31,31,31
-11:
+11: eieio
#endif
/* Get PTE (linux-style) and check access */
lwz r5,PG_TABLES(r5)
@@ -1234,13 +1267,25 @@ hash_page:
rlwimi r5,r3,12,20,29 /* insert top 10 bits of address */
lwz r5,0(r5) /* get pmd entry */
rlwinm. r5,r5,0,0,19 /* extract address of pte page */
+#ifdef __SMP__
beq- hash_page_out /* return if no mapping */
+#else
+ /* XXX it seems like the 601 will give a machine fault on the
+ rfi if its alignment is wrong (bottom 4 bits of address are
+ 8 or 0xc) and we have had a not-taken conditional branch
+ to the address following the rfi. */
+ beqlr-
+#endif
tophys(r2,r5,r2)
rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */
lwz r6,0(r2) /* get linux-style pte */
ori r4,r4,1 /* set _PAGE_PRESENT bit in access */
andc. r0,r4,r6 /* check access & ~permission */
+#ifdef __SMP__
bne- hash_page_out /* return if access not permitted */
+#else
+ bnelr-
+#endif
ori r6,r6,0x100 /* set _PAGE_ACCESSED in pte */
rlwinm r5,r4,5,24,24 /* _PAGE_RW access -> _PAGE_DIRTY */
@@ -1257,7 +1302,9 @@ hash_page:
/* Construct the high word of the PPC-style PTE */
mfsrin r5,r3 /* get segment reg for segment */
rlwinm r5,r5,7,1,24 /* put VSID in 0x7fffff80 bits */
+#ifndef __SMP__ /* do this later for SMP */
oris r5,r5,0x8000 /* set V (valid) bit */
+#endif
rlwimi r5,r3,10,26,31 /* put in API (abbrev page index) */
/* Get the address of the primary PTE group in the hash table */
@@ -1274,9 +1321,6 @@ hash_page_patch_A:
li r2,8 /* PTEs/group */
bne 10f /* no PTE: go look for an empty slot */
tlbie r3 /* invalidate TLB entry */
-#ifdef __SMP__
- tlbsync
-#endif
/* Search the primary PTEG for a PTE whose 1st word matches r5 */
mtctr r2
@@ -1345,18 +1389,43 @@ hash_page_patch_C:
addi r4,r4,1
stw r4,0(r2)
+#ifndef __SMP__
/* Store PTE in PTEG */
found_empty:
stw r5,0(r3)
found_slot:
stw r6,4(r3)
- SYNC
+ sync
+
+#else /* __SMP__ */
/*
- * These nop's seem to be necessary to avoid getting a machine
- * check on the rfi on 601 processors.
+ * Between the tlbie above and updating the hash table entry below,
+ * another CPU could read the hash table entry and put it in its TLB.
+ * There are 3 cases:
+ * 1. using an empty slot
+ * 2. updating an earlier entry to change permissions (i.e. enable write)
+ * 3. taking over the PTE for an unrelated address
+ *
+ * In each case it doesn't really matter if the other CPUs have the old
+ * PTE in their TLB. So we don't need to bother with another tlbie here,
+ * which is convenient as we've overwritten the register that had the
+ * address. :-) The tlbie above is mainly to make sure that this CPU comes
+ * and gets the new PTE from the hash table.
+ *
+ * We do however have to make sure that the PTE is never in an invalid
+ * state with the V bit set.
*/
- nop
- nop
+found_empty:
+found_slot:
+ stw r5,0(r3) /* clear V (valid) bit in PTE */
+ sync
+ tlbsync
+ sync
+ stw r6,4(r3) /* put in correct RPN, WIMG, PP bits */
+ sync
+ oris r5,r5,0x8000
+ stw r5,0(r3) /* finally set V bit in PTE */
+#endif /* __SMP__ */
/*
* Update the hash table miss count. We only want misses here
@@ -1380,6 +1449,7 @@ found_slot:
tophys(r2,r2,r6)
li r0,0
stw r0,hash_table_lock@l(r2)
+ eieio
#endif
/* Return from the exception */
@@ -1398,17 +1468,22 @@ found_slot:
REST_GPR(20, r21)
REST_2GPRS(22, r21)
lwz r21,GPR21(r21)
- SYNC
rfi
-hash_page_out:
#ifdef __SMP__
+hash_page_out:
lis r2,hash_table_lock@ha
tophys(r2,r2,r6)
li r0,0
stw r0,hash_table_lock@l(r2)
-#endif
+ eieio
blr
+
+ .globl hash_table_lock
+hash_table_lock:
+ .long 0
+#endif
+
next_slot:
.long 0
@@ -1420,27 +1495,25 @@ load_up_fpu:
* On SMP we know the fpu is free, since we give it up every
* switch. -- Cort
*/
+ mfmsr r5
+ ori r5,r5,MSR_FP
+ SYNC
+ mtmsr r5 /* enable use of fpu now */
+ SYNC
+/*
+ * 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 __SMP__
#ifndef CONFIG_APUS
lis r6,-KERNELBASE@h
#else
lis r6,CYBERBASEp@h
lwz r6,0(r6)
#endif
-
addis r3,r6,last_task_used_math@ha
lwz r4,last_task_used_math@l(r3)
- mfmsr r5
- ori r5,r5,MSR_FP
- SYNC
- mtmsr r5 /* enable use of fpu now */
-/*
- * All the saving of last_task_used_math is handled
- * by a switch_to() call to smp_giveup_fpu() in SMP so
- * last_task_used_math is not used.
- * -- Cort
- */
-#ifndef __SMP__
- SYNC
cmpi 0,r4,0
beq 1f
add r4,r4,r6
@@ -1454,15 +1527,17 @@ load_up_fpu:
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 /* __SMP__ */
-1: ori r23,r23,MSR_FP|MSR_FE0|MSR_FE1 /* enable use of FP after return */
+ /* enable use of FP after return */
+ ori r23,r23,MSR_FP|MSR_FE0|MSR_FE1
mfspr r5,SPRG3 /* current task's TSS (phys) */
lfd fr0,TSS_FPSCR-4(r5)
mtfsf 0xff,fr0
REST_32FPRS(0, r5)
+#ifndef __SMP__
subi r4,r5,TSS
sub r4,r4,r6
-#ifndef __SMP__
stw r4,last_task_used_math@l(r3)
#endif /* __SMP__ */
/* restore registers and return */
@@ -1499,48 +1574,44 @@ KernelFP:
.align 4
/*
- * Disable FP for the task which had the FPU previously,
- * and save its floating-point registers in its thread_struct.
+ * 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.
*/
-/* smp_giveup_fpu() takes an arg to tell it where to save the fpu
- * regs since last_task_used_math can't be trusted (many many race
- * conditions). -- Cort
- */
- .globl smp_giveup_fpu
-smp_giveup_fpu:
- mr r4,r3
- b 12f
.globl giveup_fpu
giveup_fpu:
- lis r3,last_task_used_math@ha
- lwz r4,last_task_used_math@l(r3)
-12:
mfmsr r5
ori r5,r5,MSR_FP
SYNC
mtmsr r5 /* enable use of fpu now */
SYNC
- cmpi 0,r4,0
+ cmpi 0,r3,0
beqlr- /* if no previous owner, done */
- addi r4,r4,TSS /* want TSS of last_task_used_math */
+ addi r3,r3,TSS /* want TSS of task */
+ lwz r5,PT_REGS(r3)
+ cmpi 0,r5,0
+ SAVE_32FPRS(0, r3)
+ mffs fr0
+ stfd fr0,TSS_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 __SMP__
li r5,0
- stw r5,last_task_used_math@l(r3)
+ lis r4,last_task_used_math@ha
+ stw r5,last_task_used_math@l(r4)
#endif /* __SMP__ */
- SAVE_32FPRS(0, r4)
- mffs fr0
- stfd fr0,TSS_FPSCR-4(r4)
- lwz r5,PT_REGS(r4)
- lwz r3,_MSR-STACK_FRAME_OVERHEAD(r5)
- li r4,MSR_FP|MSR_FE0|MSR_FE1
- andc r3,r3,r4 /* disable FP for previous task */
- stw r3,_MSR-STACK_FRAME_OVERHEAD(r5)
+ blr
+
#else /* CONFIG_8xx */
.globl giveup_fpu
giveup_fpu:
-#endif /* CONFIG_8xx */
blr
+#endif /* CONFIG_8xx */
/*
* This code is jumped to from the startup code to copy
@@ -1600,10 +1671,38 @@ copy_and_flush:
. = 0x4000
#endif
+#ifdef CONFIG_SMP
+ .globl __secondary_start_psurge
+__secondary_start_psurge:
+ li r24,1 /* cpu # */
+ b __secondary_start
+
+ .globl __secondary_hold
+__secondary_hold:
+ /* tell the master we're here */
+ lis r5,0x4@h
+ ori r5,r5,0x4@l
+ stw r3,0(r5)
+ dcbf 0,r5
+100:
+ lis r5,0
+ dcbi 0,r5
+ lwz r4,0(r5)
+ /* wait until we're told to start */
+ cmp 0,r4,r3
+ bne 100b
+ /* our cpu # was at addr 0 - go */
+ lis r5,__secondary_start@h
+ ori r5,r5,__secondary_start@l
+ tophys(r5,r5,r4)
+ mtlr r5
+ mr r24,r3 /* cpu # */
+ blr
+#endif /* CONFIG_SMP */
+
/*
* This is where the main kernel code starts.
*/
-
start_here:
#ifndef CONFIG_8xx
/*
@@ -1650,9 +1749,9 @@ start_here:
/* get current */
lis r2,current_set@h
ori r2,r2,current_set@l
- addi r2,r2,4
+ slwi r24,r24,2 /* cpu # to current_set[cpu#] */
+ add r2,r2,r24
lwz r2,0(r2)
-
b 10f
99:
#endif /* __SMP__ */
@@ -1677,12 +1776,10 @@ start_here:
#ifdef __SMP__
10:
#endif /* __SMP__ */
-
/* stack */
addi r1,r2,TASK_UNION_SIZE
li r0,0
stwu r0,-STACK_FRAME_OVERHEAD(r1)
-
/*
* Decide what sort of machine this is and initialize the MMU.
*/
@@ -1693,7 +1790,6 @@ start_here:
mr r7,r27
bl identify_machine
bl MMU_init
-
/*
* Go back to running unmapped so we can load up new values
* for SDR1 (hash table pointer) and the segment registers
@@ -1725,8 +1821,10 @@ start_here:
2:
SYNC /* Force all PTE updates to finish */
tlbia /* Clear all TLB entries */
+ sync /* wait for tlbia/tlbie to finish */
#ifdef __SMP__
- tlbsync
+ tlbsync /* ... on all CPUs */
+ sync
#endif
#ifndef CONFIG_8xx
mtspr SDR1,r6
@@ -1947,8 +2045,9 @@ _GLOBAL(_switch)
stw r0,GPR0(r1)
lwz r0,0(r1)
stw r0,GPR1(r1)
- SAVE_10GPRS(2, r1)
- SAVE_10GPRS(12, r1)
+ /* r3-r13 are caller saved -- Cort */
+ SAVE_GPR(2, r1)
+ SAVE_8GPRS(14, r1)
SAVE_10GPRS(22, r1)
mflr r20 /* Return to switch caller */
mfmsr r22
@@ -1971,46 +2070,71 @@ _GLOBAL(_switch)
mtspr SPRG3,r0 /* Update current TSS phys addr */
SYNC
lwz r1,KSP(r4) /* Load new stack pointer */
+ /* save the old current 'last' for return value */
+ mr r3,r2
addi r2,r4,-TSS /* Update current */
#ifndef CONFIG_8xx
/* Set up segment registers for new task */
rlwinm r5,r5,4,8,27 /* VSID = context << 4 */
addis r5,r5,0x6000 /* Set Ks, Ku bits */
- li r0,8 /* TASK_SIZE / SEGMENT_SIZE */
+ li r0,12 /* TASK_SIZE / SEGMENT_SIZE */
mtctr r0
- li r3,0
-3: mtsrin r5,r3
+ li r9,0
+3: mtsrin r5,r9
addi r5,r5,1 /* next VSID */
- addis r3,r3,0x1000 /* address of next segment */
+ addis r9,r9,0x1000 /* address of next segment */
bdnz 3b
#else
/* On the MPC8xx, we place the physical address of the new task
* page directory loaded into the MMU base register, and set the
* ASID compare register with the new "context".
*/
- lwz r3,MM-TSS(r4) /* Get virtual address of mm */
- lwz r3,PGD(r3) /* get new->mm->pgd */
- addis r3,r3,-KERNELBASE@h /* convert to phys addr */
- mtspr M_TWB, r3 /* Update MMU base address */
+ lwz r9,MM-TSS(r4) /* Get virtual address of mm */
+ lwz r9,PGD(r9) /* get new->mm->pgd */
+ addis r9,r9,-KERNELBASE@h /* convert to phys addr */
+ mtspr M_TWB, r9 /* Update MMU base address */
mtspr M_CASID, r5 /* Update context */
tlbia
#endif
SYNC
-
-/* FALL THROUGH into int_return */
-#ifdef __SMP__
- /* call schedule_tail if this is the first time for a child process */
- lwz r5,TSS_SMP_FORK_RET(r4)
- cmpi 0,r5,0
- beq+ int_return
- li r3,0
- stw r3,TSS_SMP_FORK_RET(r4)
- bl schedule_tail
-#endif /* __SMP__ */
+2: lwz r9,_MSR(r1) /* Returning to user mode? */
+ andi. r9,r9,MSR_PR
+ beq+ 10f /* if not, don't adjust kernel stack */
+8: addi r4,r1,INT_FRAME_SIZE+STACK_UNDERHEAD /* size of frame */
+ stw r4,TSS+KSP(r2) /* save kernel stack pointer */
+ tophys(r9,r1,r9)
+ mtspr SPRG2,r9 /* phys exception stack pointer */
+10: lwz r2,_CTR(r1)
+ lwz r0,_LINK(r1)
+ mtctr r2
+ mtlr r0
+ lwz r2,_XER(r1)
+ lwz r0,_CCR(r1)
+ mtspr XER,r2
+ mtcrf 0xFF,r0
+ /* r3-r13 are destroyed -- Cort */
+ REST_GPR(14, r1)
+ REST_8GPRS(15, r1)
+ REST_8GPRS(23, r1)
+ REST_GPR(31, r1)
+ lwz r2,_NIP(r1) /* Restore environment */
+ lwz r0,_MSR(r1)
+ mtspr SRR0,r2
+ mtspr SRR1,r0
+ lwz r0,GPR0(r1)
+ lwz r2,GPR2(r1)
+ lwz r1,GPR1(r1)
+ SYNC
+ rfi
/*
* Trap exit.
*/
+#ifdef __SMP__
+ .globl ret_from_smpfork
+ret_from_smpfork:
+ bl schedule_tail
+#endif
.globl ret_from_syscall
ret_from_syscall:
.globl int_return
@@ -2025,8 +2149,8 @@ int_return:
lwz r5,_MSR(r1)
and. r5,r5,r4
beq 2f
-3: lis r4,n_lost_interrupts@ha
- lwz r4,n_lost_interrupts@l(r4)
+3: lis r4,ppc_n_lost_interrupts@ha
+ lwz r4,ppc_n_lost_interrupts@l(r4)
cmpi 0,r4,0
beq+ 1f
addi r3,r1,STACK_FRAME_OVERHEAD
@@ -2118,7 +2242,7 @@ _GLOBAL(fake_interrupt)
_GLOBAL(set_context)
rlwinm r3,r3,4,8,27 /* VSID = context << 4 */
addis r3,r3,0x6000 /* Set Ks, Ku bits */
- li r0,8 /* TASK_SIZE / SEGMENT_SIZE */
+ li r0,12 /* TASK_SIZE / SEGMENT_SIZE */
mtctr r0
li r4,0
3: mtsrin r3,r4
@@ -2177,6 +2301,27 @@ _GLOBAL(flush_icache_range)
blr
/*
+ * Like above, but only do the D-cache. This is used by the 8xx
+ * to push the cache so the CPM doesn't get stale data.
+ *
+ * flush_dcache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(flush_dcache_range)
+ li r5,CACHE_LINE_SIZE-1
+ andc r3,r3,r5
+ subf r4,r3,r4
+ add r4,r4,r5
+ srwi. r4,r4,LG_CACHE_LINE_SIZE
+ beqlr
+ mtctr r4
+
+1: dcbst 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 1b
+ sync /* wait for dcbst's to get to ram */
+ blr
+
+/*
* Flush a particular page from the DATA cache
* Note: this is necessary because the instruction cache does *not*
* snoop from the data cache.
@@ -2207,25 +2352,35 @@ _GLOBAL(flush_page_to_ram)
blr
/*
+ * Clear a page using the dcbz instruction, which doesn't cause any
+ * memory traffic (except to write out any cache lines which get
+ * displaced). This only works on cacheable memory.
+ */
+_GLOBAL(clear_page)
+ li r0,4096/CACHE_LINE_SIZE
+ mtctr r0
+1: dcbz 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 1b
+ blr
+
+/*
* Flush entries from the hash table with VSIDs in the range
* given.
*/
#ifndef CONFIG_8xx
_GLOBAL(flush_hash_segments)
+ lis r5,Hash@ha
+ lwz r5,Hash@l(r5) /* base of hash table */
#ifdef NO_RELOAD_HTAB
-/*
- * Bitmask of PVR numbers of 603-like chips,
- * for which we don't use the hash table at all.
- */
-#define PVR_603_LIKE 0x13000000 /* bits 3, 6, 7 set */
-
- mfspr r0,PVR
- rlwinm r0,r0,16,27,31
- lis r9,PVR_603_LIKE@h
- rlwnm. r0,r9,r0,0,0
- beq+ 99f
+ cmpwi 0,r5,0
+ bne+ 99f
tlbia
- isync
+ sync
+#ifdef __SMP__
+ tlbsync
+ sync
+#endif
blr
99:
#endif /* NO_RELOAD_HTAB */
@@ -2247,14 +2402,13 @@ _GLOBAL(flush_hash_segments)
bne- 10b
stwcx. r8,0,r9
bne- 10b
+ eieio
#endif
rlwinm r3,r3,7,1,24 /* put VSID lower limit in position */
oris r3,r3,0x8000 /* set V bit */
rlwinm r4,r4,7,1,24 /* put VSID upper limit in position */
oris r4,r4,0x8000
ori r4,r4,0x7f
- lis r5,Hash@ha
- lwz r5,Hash@l(r5) /* base of hash table */
lis r6,Hash_size@ha
lwz r6,Hash_size@l(r6) /* size in bytes */
srwi r6,r6,3 /* # PTEs */
@@ -2270,11 +2424,11 @@ _GLOBAL(flush_hash_segments)
2: bdnz 1b /* continue with loop */
sync
tlbia
- isync
+ sync
#ifdef __SMP__
tlbsync
+ sync
lis r3,hash_table_lock@ha
- li r0,0
stw r0,hash_table_lock@l(r3)
mtmsr r10
SYNC
@@ -2287,14 +2441,17 @@ _GLOBAL(flush_hash_segments)
* flush_hash_page(unsigned context, unsigned long va)
*/
_GLOBAL(flush_hash_page)
+ lis r6,Hash@ha
+ lwz r6,Hash@l(r6) /* hash table base */
#ifdef NO_RELOAD_HTAB
- mfspr r0,PVR
- rlwinm r0,r0,16,27,31
- lis r9,PVR_603_LIKE@h
- rlwnm. r0,r9,r0,0,0
- beq+ 99f
+ cmpwi 0,r6,0 /* hash table in use? */
+ bne+ 99f
tlbie r4 /* in hw tlb too */
- isync
+ sync
+#ifdef __SMP__
+ tlbsync
+ sync
+#endif
blr
99:
#endif /* NO_RELOAD_HTAB */
@@ -2311,11 +2468,12 @@ _GLOBAL(flush_hash_page)
ori r9,r9,hash_table_lock@l
lwz r8,PROCESSOR(r2)
oris r8,r8,9
-10: lwarx r6,0,r9
- cmpi 0,r6,0
+10: lwarx r7,0,r9
+ cmpi 0,r7,0
bne- 10b
stwcx. r8,0,r9
bne- 10b
+ eieio
#endif
rlwinm r3,r3,11,1,20 /* put context into vsid */
rlwimi r3,r4,11,21,24 /* put top 4 bits of va into vsid */
@@ -2328,8 +2486,6 @@ _GLOBAL(flush_hash_page)
lwz r5,Hash_mask@l(r5) /* hash mask */
slwi r5,r5,6 /* << 6 */
and r7,r7,r5
- lis r6,Hash@ha
- lwz r6,Hash@l(r6) /* hash table base */
add r6,r6,r7 /* address of primary PTEG */
li r8,8
mtctr r8
@@ -2350,9 +2506,10 @@ _GLOBAL(flush_hash_page)
stw r0,0(r7) /* invalidate entry */
4: sync
tlbie r4 /* in hw tlb too */
- isync
+ sync
#ifdef __SMP__
tlbsync
+ sync
lis r3,hash_table_lock@h
li r0,0
stw r0,hash_table_lock@l(r3)
@@ -2418,30 +2575,27 @@ enter_rtas:
rfi /* return to caller */
#endif /* CONFIG_8xx */
-#ifdef CONFIG_MBX
-/* Jump into the system reset for the MBX rom.
+#ifdef CONFIG_8xx
+/* Jump into the system reset for the rom.
* We first disable the MMU, and then jump to the ROM reset address.
*
- * This does not work, don't bother trying. There is no place in
- * the ROM we can jump to cause a reset. We will have to program
- * a watchdog of some type that we don't service to cause a processor
- * reset.
+ * r3 is the board info structure, r4 is the location for starting.
+ * I use this for building a small kernel that can load other kernels,
+ * rather than trying to write or rely on a rom monitor that can tftp load.
*/
- .globl MBX_gorom
-MBX_gorom:
- li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR)
- lis r4,2f@h
- addis r4,r4,-KERNELBASE@h
- ori r4,r4,2f@l
- mtspr SRR0,r4
- mtspr SRR1,r3
- rfi
+ .globl m8xx_gorom
+m8xx_gorom:
+ li r5,MSR_KERNEL & ~(MSR_IR|MSR_DR)
+ lis r6,2f@h
+ addis r6,r6,-KERNELBASE@h
+ ori r6,r6,2f@l
+ mtspr SRR0,r6
+ mtspr SRR1,r5
+ rfi
2:
- lis r4, 0xfe000000@h
- addi r4, r4, 0xfe000000@l
- mtlr r4
- blr
-#endif /* CONFIG_MBX */
+ mtlr r4
+ blr
+#endif /* CONFIG_8xx */
/*
* We put a few things here that have to be page-aligned.
diff --git a/arch/ppc/kernel/i8259.c b/arch/ppc/kernel/i8259.c
new file mode 100644
index 000000000..4ec6d3e11
--- /dev/null
+++ b/arch/ppc/kernel/i8259.c
@@ -0,0 +1,130 @@
+
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include "i8259.h"
+
+unsigned char cached_8259[2] = { 0xff, 0xff };
+#define cached_A1 (cached_8259[0])
+#define cached_21 (cached_8259[1])
+
+int i8259_irq(int cpu)
+{
+ int irq;
+
+ /*
+ * 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
+ * interrupt
+ */
+ outb(0x0b, 0x20);
+ if(~inb(0x20)&0x80)
+ return -1;
+ }
+ return irq;
+}
+
+static void i8259_mask_and_ack_irq(unsigned int irq_nr)
+{
+ 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 */
+ }
+}
+
+static void i8259_set_irq_mask(int irq_nr)
+{
+ outb(cached_A1,0xA1);
+ outb(cached_21,0x21);
+}
+
+static void i8259_mask_irq(unsigned int 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);
+}
+
+static void i8259_unmask_irq(unsigned int 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);
+}
+
+struct hw_interrupt_type i8259_pic = {
+ " i8259 ",
+ NULL,
+ NULL,
+ NULL,
+ i8259_unmask_irq,
+ i8259_mask_irq,
+ i8259_mask_and_ack_irq,
+ 0
+};
+
+static void
+no_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+}
+
+void __init i8259_init(void)
+{
+ /* 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);
+ request_irq( i8259_pic.irq_offset + 2, no_action, SA_INTERRUPT,
+ "82c59 secondary cascade", NULL );
+ enable_irq(i8259_pic.irq_offset + 2); /* Enable cascade interrupt */
+}
diff --git a/arch/ppc/kernel/i8259.h b/arch/ppc/kernel/i8259.h
new file mode 100644
index 000000000..a1d6df0a1
--- /dev/null
+++ b/arch/ppc/kernel/i8259.h
@@ -0,0 +1,12 @@
+
+#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/idle.c b/arch/ppc/kernel/idle.c
index af163699b..c68d1e63e 100644
--- a/arch/ppc/kernel/idle.c
+++ b/arch/ppc/kernel/idle.c
@@ -1,5 +1,5 @@
/*
- * $Id: idle.c,v 1.57 1998/12/28 10:28:46 paulus Exp $
+ * $Id: idle.c,v 1.61 1999/03/18 04:15:45 cort Exp $
*
* Idle daemon for PowerPC. Idle daemon will handle any action
* that needs to be taken when the system becomes idle.
@@ -39,6 +39,12 @@ unsigned long htab_reclaim_on = 0;
unsigned long zero_paged_on = 0;
unsigned long powersave_nap = 0;
+unsigned long *zero_cache; /* head linked list of pre-zero'd pages */
+unsigned long zero_sz; /* # currently pre-zero'd pages */
+unsigned long zeropage_hits; /* # zero'd pages request that we've done */
+unsigned long zeropage_calls; /* # zero'd pages request that've been made */
+unsigned long zerototal; /* # pages zero'd over time */
+
int idled(void *unused)
{
/* endless loop with no priority at all */
@@ -108,8 +114,6 @@ void inline htab_reclaim(void)
/* if we don't have a htab */
if ( Hash_size == 0 )
return;
- lock_dcache(1);
-
#if 0
/* find a random place in the htab to start each time */
start = &Hash[jiffies%(Hash_size/sizeof(PTE))];
@@ -147,7 +151,6 @@ void inline htab_reclaim(void)
}
out:
if ( current->need_resched ) printk("need_resched: %lx\n", current->need_resched);
- unlock_dcache();
#endif /* CONFIG_8xx */
}
@@ -159,7 +162,7 @@ unsigned long get_zero_page_fast(void)
{
unsigned long page = 0;
- atomic_inc((atomic_t *)&quicklists.zeropage_calls);
+ atomic_inc((atomic_t *)&zero_cache_calls);
if ( zero_quicklist )
{
/* atomically remove this page from the list */
@@ -177,10 +180,10 @@ unsigned long get_zero_page_fast(void)
#endif /* __SMP__ */
/* we can update zerocount after the fact since it is not
* used for anything but control of a loop which doesn't
- * matter since it won't affect anything if it zero's one
+ * matter since it won't affect anything if it zeros one
* less page -- Cort
*/
- atomic_inc((atomic_t *)&quicklists.zeropage_hits);
+ atomic_inc((atomic_t *)&zero_cache_hits);
atomic_dec((atomic_t *)&zero_cache_sz);
/* zero out the pointer to next in the page */
@@ -222,7 +225,6 @@ void zero_paged(void)
/*
* Make the page no cache so we don't blow our cache with 0's
- * We should just turn off the cache instead. -- Cort
*/
pte = find_pte(init_task.mm, pageptr);
if ( !pte )
@@ -254,8 +256,8 @@ void zero_paged(void)
* So we update the list atomically without locking it.
* -- Cort
*/
+
/* turn cache on for this page */
-
pte_cache(*pte);
flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
/* atomically add this page to the list */
@@ -280,7 +282,7 @@ void zero_paged(void)
* reads it. -- Cort
*/
atomic_inc((atomic_t *)&zero_cache_sz);
- atomic_inc((atomic_t *)&quicklists.zerototal);
+ atomic_inc((atomic_t *)&zero_cache_total);
}
}
@@ -301,11 +303,17 @@ void power_save(void)
hid0 &= ~(HID0_NAP | HID0_SLEEP | HID0_DOZE);
hid0 |= (powersave_nap? HID0_NAP: HID0_DOZE) | HID0_DPM;
asm("mtspr 1008,%0" : : "r" (hid0));
- msr |= MSR_POW;
+
+ /* set the POW bit in the MSR, and enable interrupts
+ * so we wake up sometime! */
+ _nmask_and_or_msr(0, MSR_POW | MSR_EE);
+
+ /* Disable interrupts again so restore_flags will
+ * work. */
+ _nmask_and_or_msr(MSR_EE, 0);
}
restore_flags(msr);
default:
return;
}
-
}
diff --git a/arch/ppc/kernel/indirect_pci.c b/arch/ppc/kernel/indirect_pci.c
new file mode 100644
index 000000000..641d77a52
--- /dev/null
+++ b/arch/ppc/kernel/indirect_pci.c
@@ -0,0 +1,121 @@
+/*
+ * Support for indirect PCI bridges.
+ *
+ * Copyright (C) 1998 Gabriel Paubert.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+unsigned int * pci_config_address;
+unsigned char * pci_config_data;
+
+int indirect_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char *val)
+{
+ unsigned flags;
+
+ save_flags(flags); cli();
+
+ out_be32(pci_config_address,
+ ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80);
+
+ *val= in_8(pci_config_data + (offset&3));
+
+ restore_flags(flags);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int indirect_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val)
+{
+ unsigned flags;
+
+ if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ save_flags(flags); cli();
+
+ out_be32(pci_config_address,
+ ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80);
+
+ *val= in_le16((unsigned short *)(pci_config_data + (offset&3)));
+
+ restore_flags(flags);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int indirect_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int *val)
+{
+ unsigned flags;
+
+ if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ save_flags(flags); cli();
+
+ out_be32(pci_config_address,
+ ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80);
+
+ *val= in_le32((unsigned *)pci_config_data);
+
+ restore_flags(flags);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int indirect_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char val)
+{
+ unsigned flags;
+
+ save_flags(flags); cli();
+
+ out_be32(pci_config_address,
+ ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80);
+
+ out_8(pci_config_data + (offset&3), val);
+
+ restore_flags(flags);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int indirect_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val)
+{
+ unsigned flags;
+
+ if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ save_flags(flags); cli();
+
+ out_be32(pci_config_address,
+ ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80);
+
+ out_le16((unsigned short *)(pci_config_data + (offset&3)), val);
+
+ restore_flags(flags);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int indirect_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int val)
+{
+ unsigned flags;
+
+ if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ save_flags(flags); cli();
+
+ out_be32(pci_config_address,
+ ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80);
+
+ out_le32((unsigned *)pci_config_data, val);
+
+ restore_flags(flags);
+ return PCIBIOS_SUCCESSFUL;
+}
diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c
index f4a7c7143..461e51aa1 100644
--- a/arch/ppc/kernel/irq.c
+++ b/arch/ppc/kernel/irq.c
@@ -1,5 +1,5 @@
/*
- * $Id: irq.c,v 1.91 1998/12/28 10:28:47 paulus Exp $
+ * $Id: irq.c,v 1.105 1999/03/25 19:51:51 cort Exp $
*
* arch/ppc/kernel/irq.c
*
@@ -42,6 +42,7 @@
#include <linux/malloc.h>
#include <linux/openpic.h>
#include <linux/pci.h>
+#include <linux/delay.h>
#include <asm/bitops.h>
#include <asm/hydra.h>
@@ -56,101 +57,46 @@
#include <asm/amigaints.h>
#include <asm/amigahw.h>
#include <asm/amigappc.h>
-#ifdef CONFIG_8xx
-#include <asm/8xx_immap.h>
-#include <asm/mbx.h>
-#endif
+#include <asm/ptrace.h>
+
+#include "local_irq.h"
-extern void process_int(unsigned long vec, struct pt_regs *fp);
-extern void apus_init_IRQ(void);
-extern void amiga_disable_irq(unsigned int irq);
-extern void amiga_enable_irq(unsigned int irq);
-static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
-static volatile unsigned char *chrp_int_ack_special;
extern volatile unsigned long ipi_count;
-static void pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base);
+void enable_irq(unsigned int irq_nr);
+void disable_irq(unsigned int irq_nr);
+
+/* Fixme - Need to figure out a way to get rid of this - Corey */
+volatile unsigned char *chrp_int_ack_special;
#ifdef CONFIG_APUS
/* Rename a few functions. Requires the CONFIG_APUS protection. */
#define request_irq nop_ppc_request_irq
#define free_irq nop_ppc_free_irq
#define get_irq_list nop_get_irq_list
-#endif
-#ifndef CONFIG_8xx
-void (*mask_and_ack_irq)(int irq_nr);
-void (*mask_irq)(unsigned int irq_nr);
-void (*unmask_irq)(unsigned int irq_nr);
-#else /* CONFIG_8xx */
-/* init_IRQ() happens too late for the MBX because we initialize the
- * CPM early and it calls request_irq() before we have these function
- * pointers initialized.
- */
-#define mask_and_ack_irq(irq) mbx_mask_irq(irq)
-#define mask_irq(irq) mbx_mask_irq(irq)
-#define unmask_irq(irq) mbx_unmask_irq(irq)
-#endif /* CONFIG_8xx */
-
#define VEC_SPUR (24)
-#undef SHOW_IRQ
-#undef SHOW_GATWICK_IRQS
-#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
-#define cached_21 (((char *)(cached_irq_mask))[3])
-#define cached_A1 (((char *)(cached_irq_mask))[2])
-#define PREP_IRQ_MASK (((unsigned int)cached_A1)<<8) | (unsigned int)cached_21
-
-unsigned int local_bh_count[NR_CPUS];
-unsigned int local_irq_count[NR_CPUS];
-int max_irqs;
-int max_real_irqs;
-static struct irqaction *irq_action[NR_IRQS];
-static int spurious_interrupts = 0;
-static unsigned int cached_irq_mask[NR_MASK_WORDS];
-unsigned int lost_interrupts[NR_MASK_WORDS];
-atomic_t n_lost_interrupts;
-
-/* pmac */
-struct pmac_irq_hw {
- unsigned int flag;
- unsigned int enable;
- unsigned int ack;
- unsigned int level;
-};
+#endif
-/* XXX these addresses should be obtained from the device tree */
-volatile struct pmac_irq_hw *pmac_irq_hw[4] = {
- (struct pmac_irq_hw *) 0xf3000020,
- (struct pmac_irq_hw *) 0xf3000010,
- (struct pmac_irq_hw *) 0xf4000020,
- (struct pmac_irq_hw *) 0xf4000010,
-};
+#define MAXCOUNT 10000000
-/* This is the interrupt used on the main controller for the secondary
- controller. Happens on PowerBooks G3 Series (a second mac-io)
- -- BenH
- */
-static int second_irq = -999;
+#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
-/* Returns the number of 0's to the left of the most significant 1 bit */
-static inline int cntlzw(int bits)
-{
- int lz;
+int ppc_spurious_interrupts = 0;
- asm ("cntlzw %0,%1" : "=r" (lz) : "r" (bits));
- return lz;
-}
+unsigned int ppc_local_bh_count[NR_CPUS];
+unsigned int ppc_local_irq_count[NR_CPUS];
+struct irqaction *ppc_irq_action[NR_IRQS];
+unsigned int ppc_cached_irq_mask[NR_MASK_WORDS];
+unsigned int ppc_lost_interrupts[NR_MASK_WORDS];
+atomic_t ppc_n_lost_interrupts;
-static inline void sync(void)
-{
- asm volatile ("sync");
-}
/* nasty hack for shared irq's since we need to do kmalloc calls but
- * can't very very early in the boot when we need to do a request irq.
+ * can't very early in the boot when we need to do a request irq.
* this needs to be removed.
* -- Cort
*/
static char cache_bitmask = 0;
-static struct irqaction malloc_cache[4];
+static struct irqaction malloc_cache[8];
extern int mem_init_done;
void *irq_kmalloc(size_t size, int pri)
@@ -179,168 +125,80 @@ void irq_kfree(void *ptr)
kfree(ptr);
}
-#ifndef CONFIG_8xx
-void i8259_mask_and_ack_irq(int irq_nr)
-{
- /* spin_lock(&irq_controller_lock);*/
- cached_irq_mask[0] |= 1 << irq_nr;
- if (irq_nr > 7) {
- inb(0xA1); /* DUMMY */
- outb(cached_A1,0xA1);
- outb(0x62,0x20); /* Specific EOI to cascade */
- /*outb(0x20,0xA0);*/
- outb(0x60|(irq_nr-8), 0xA0); /* specific eoi */
- } else {
- inb(0x21); /* DUMMY */
- outb(cached_21,0x21);
- /*outb(0x20,0x20);*/
- outb(0x60|irq_nr,0x20); /* specific eoi */
-
- }
- /* spin_unlock(&irq_controller_lock);*/
-}
-
-void __pmac pmac_mask_and_ack_irq(int irq_nr)
-{
- unsigned long bit = 1UL << (irq_nr & 0x1f);
- int i = irq_nr >> 5;
-
- if ((unsigned)irq_nr >= max_irqs)
- return;
- /*spin_lock(&irq_controller_lock);*/
-
- clear_bit(irq_nr, cached_irq_mask);
- if (test_and_clear_bit(irq_nr, lost_interrupts))
- atomic_dec(&n_lost_interrupts);
- out_le32(&pmac_irq_hw[i]->ack, bit);
- out_le32(&pmac_irq_hw[i]->enable, cached_irq_mask[i]);
- out_le32(&pmac_irq_hw[i]->ack, bit);
- /* make sure ack gets to controller before we enable interrupts */
- sync();
-
- /*spin_unlock(&irq_controller_lock);*/
- /*if ( irq_controller_lock.lock )
- panic("irq controller lock still held in mask and ack\n");*/
-}
+struct irqdesc irq_desc[NR_IRQS] = {{0, 0}, };
-void __openfirmware chrp_mask_and_ack_irq(int irq_nr)
+int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+ unsigned long irqflags, const char * devname, void *dev_id)
{
- /* spinlocks are done by i8259_mask_and_ack() - Cort */
- if (is_8259_irq(irq_nr))
- i8259_mask_and_ack_irq(irq_nr);
-}
-
+ struct irqaction *old, **p, *action;
+ unsigned long flags;
-static void i8259_set_irq_mask(int irq_nr)
-{
- if (irq_nr > 7) {
- outb(cached_A1,0xA1);
- } else {
- outb(cached_21,0x21);
+ if (irq >= NR_IRQS)
+ return -EINVAL;
+ if (!handler)
+ {
+ /* Free */
+ for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next)
+ {
+ /* Found it - now free it */
+ save_flags(flags);
+ cli();
+ *p = action->next;
+ restore_flags(flags);
+ irq_kfree(action);
+ return 0;
+ }
+ return -ENOENT;
}
-}
-
-static void __pmac pmac_set_irq_mask(int irq_nr)
-{
- unsigned long bit = 1UL << (irq_nr & 0x1f);
- int i = irq_nr >> 5;
-
- if ((unsigned)irq_nr >= max_irqs)
- return;
-
- /* enable unmasked interrupts */
- out_le32(&pmac_irq_hw[i]->enable, cached_irq_mask[i]);
-
- /*
- * 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 & cached_irq_mask[i])
- && (ld_le32(&pmac_irq_hw[i]->level) & bit)
- && !(ld_le32(&pmac_irq_hw[i]->flag) & bit)) {
- if (!test_and_set_bit(irq_nr, lost_interrupts))
- atomic_inc(&n_lost_interrupts);
+
+ action = (struct irqaction *)
+ irq_kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+ if (!action)
+ return -ENOMEM;
+
+ save_flags(flags);
+ cli();
+
+ action->handler = handler;
+ action->flags = irqflags;
+ action->mask = 0;
+ action->name = devname;
+ action->dev_id = dev_id;
+ action->next = NULL;
+ enable_irq(irq);
+
+ p = &irq_desc[irq].action;
+
+ if ((old = *p) != NULL) {
+ /* Can't share interrupts unless both agree to */
+ if (!(old->flags & action->flags & SA_SHIRQ))
+ return -EBUSY;
+ /* add new interrupt at end of irq queue */
+ do {
+ p = &old->next;
+ old = *p;
+ } while (old);
}
-}
-
-/*
- * These have to be protected by the spinlock
- * before being called.
- */
-static void i8259_mask_irq(unsigned int irq_nr)
-{
- cached_irq_mask[0] |= 1 << irq_nr;
- i8259_set_irq_mask(irq_nr);
-}
-
-static void i8259_unmask_irq(unsigned int irq_nr)
-{
- cached_irq_mask[0] &= ~(1 << irq_nr);
- i8259_set_irq_mask(irq_nr);
-}
-
-static void __pmac pmac_mask_irq(unsigned int irq_nr)
-{
- clear_bit(irq_nr, cached_irq_mask);
- pmac_set_irq_mask(irq_nr);
- sync();
-}
-
-static void __pmac pmac_unmask_irq(unsigned int irq_nr)
-{
- set_bit(irq_nr, cached_irq_mask);
- pmac_set_irq_mask(irq_nr);
-}
-
-static void __openfirmware chrp_mask_irq(unsigned int irq_nr)
-{
- if (is_8259_irq(irq_nr))
- i8259_mask_irq(irq_nr);
- else
- openpic_disable_irq(irq_to_openpic(irq_nr));
-}
+ *p = action;
-static void __openfirmware chrp_unmask_irq(unsigned int irq_nr)
-{
- if (is_8259_irq(irq_nr))
- i8259_unmask_irq(irq_nr);
- else
- openpic_enable_irq(irq_to_openpic(irq_nr));
-}
-#else /* CONFIG_8xx */
-static void mbx_mask_irq(unsigned int irq_nr)
-{
- cached_irq_mask[0] &= ~(1 << (31-irq_nr));
- ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
- cached_irq_mask[0];
+ restore_flags(flags);
+ return 0;
}
-static void mbx_unmask_irq(unsigned int irq_nr)
+void free_irq(unsigned int irq, void *dev_id)
{
- cached_irq_mask[0] |= (1 << (31-irq_nr));
- ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
- cached_irq_mask[0];
+ request_irq(irq, NULL, 0, NULL, dev_id);
}
-#endif /* CONFIG_8xx */
void disable_irq(unsigned int irq_nr)
{
- /*unsigned long flags;*/
-
- /* spin_lock_irqsave(&irq_controller_lock, flags);*/
mask_irq(irq_nr);
- /* spin_unlock_irqrestore(&irq_controller_lock, flags);*/
synchronize_irq();
}
void enable_irq(unsigned int irq_nr)
{
- /*unsigned long flags;*/
-
- /* spin_lock_irqsave(&irq_controller_lock, flags);*/
unmask_irq(irq_nr);
- /* spin_unlock_irqrestore(&irq_controller_lock, flags);*/
}
int get_irq_list(char *buf)
@@ -354,8 +212,8 @@ int get_irq_list(char *buf)
*(char *)(buf+len++) = '\n';
for (i = 0 ; i < NR_IRQS ; i++) {
- action = irq_action[i];
- if ((!action || !action->handler) && (i != second_irq))
+ action = irq_desc[i].action;
+ if ( !action || !action->handler )
continue;
len += sprintf(buf+len, "%3d: ", i);
#ifdef __SMP__
@@ -365,56 +223,83 @@ int get_irq_list(char *buf)
#else
len += sprintf(buf+len, "%10u ", kstat_irqs(i));
#endif /* __SMP__ */
- switch( _machine )
- {
- case _MACH_prep:
- len += sprintf(buf+len, " 82c59 ");
- break;
- case _MACH_Pmac:
- if (i < 64)
- len += sprintf(buf+len, " PMAC-PIC ");
- else
- len += sprintf(buf+len, " GATWICK ");
- break;
- case _MACH_chrp:
- if ( is_8259_irq(i) )
- len += sprintf(buf+len, " 82c59 ");
- else
- len += sprintf(buf+len, " OpenPIC ");
- break;
- case _MACH_mbx:
- len += sprintf(buf+len, " MPC8xx ");
- break;
+ if ( irq_desc[i].ctl )
+ len += sprintf(buf+len, " %s ", irq_desc[i].ctl->typename );
+ len += sprintf(buf+len, " %s",action->name);
+ for (action=action->next; action; action = action->next) {
+ len += sprintf(buf+len, ", %s", action->name);
}
-
- if (i != second_irq) {
- len += sprintf(buf+len, " %s",action->name);
- for (action=action->next; action; action = action->next) {
- len += sprintf(buf+len, ", %s", action->name);
- }
- len += sprintf(buf+len, "\n");
- } else
- len += sprintf(buf+len, " Gatwick secondary IRQ controller\n");
+ len += sprintf(buf+len, "\n");
}
#ifdef __SMP__
/* should this be per processor send/receive? */
- len += sprintf(buf+len, "IPI: %10lu", ipi_count);
- for ( i = 0 ; i <= smp_num_cpus-1; i++ )
- len += sprintf(buf+len," ");
- len += sprintf(buf+len, " interprocessor messages received\n");
+ len += sprintf(buf+len, "IPI: %10lu\n", ipi_count);
#endif
- len += sprintf(buf+len, "BAD: %10u",spurious_interrupts);
- for ( i = 0 ; i <= smp_num_cpus-1; i++ )
- len += sprintf(buf+len," ");
- len += sprintf(buf+len, " spurious or short\n");
+ len += sprintf(buf+len, "BAD: %10u\n", ppc_spurious_interrupts);
return len;
}
-
/*
- * Global interrupt locks for SMP. Allow interrupts to come in on any
- * CPU, yet make cli/sti act globally to protect critical regions..
+ * Eventually, this should take an array of interrupts and an array size
+ * so it can dispatch multiple interrupts.
*/
+void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq)
+{
+ int status;
+ struct irqaction *action;
+ int cpu = smp_processor_id();
+
+ mask_and_ack_irq(irq);
+ status = 0;
+ action = irq_desc[irq].action;
+ kstat.irqs[cpu][irq]++;
+ if (action && action->handler) {
+ if (!(action->flags & SA_INTERRUPT))
+ __sti();
+ do {
+ status |= action->flags;
+ action->handler(irq, action->dev_id, regs);
+ action = action->next;
+ } while ( action );
+ __cli();
+ unmask_irq(irq);
+ } else {
+ ppc_spurious_interrupts++;
+ disable_irq( irq );
+ }
+}
+
+asmlinkage void do_IRQ(struct pt_regs *regs, int isfake)
+{
+ int cpu = smp_processor_id();
+
+ hardirq_enter(cpu);
+ ppc_md.do_IRQ(regs, cpu, isfake);
+ hardirq_exit(cpu);
+}
+
+unsigned long probe_irq_on (void)
+{
+ return 0;
+}
+
+int probe_irq_off (unsigned long irqs)
+{
+ return 0;
+}
+
+void __init init_IRQ(void)
+{
+ static int once = 0;
+
+ if ( once )
+ return;
+ else
+ once++;
+
+ ppc_md.init_IRQ();
+}
+
#ifdef __SMP__
unsigned char global_irq_holder = NO_PROC_ID;
unsigned volatile int global_irq_lock;
@@ -431,9 +316,13 @@ static void show(char * str)
printk("\n%s, CPU %d:\n", str, cpu);
printk("irq: %d [%d %d]\n",
- atomic_read(&global_irq_count), local_irq_count[0], local_irq_count[1]);
+ atomic_read(&global_irq_count),
+ ppc_local_irq_count[0],
+ ppc_local_irq_count[1]);
printk("bh: %d [%d %d]\n",
- atomic_read(&global_bh_count), local_bh_count[0], local_bh_count[1]);
+ atomic_read(&global_bh_count),
+ ppc_local_bh_count[0],
+ ppc_local_bh_count[1]);
stack = (unsigned long *) &str;
for (i = 40; i ; i--) {
unsigned long x = *++stack;
@@ -443,7 +332,6 @@ static void show(char * str)
}
}
-#define MAXCOUNT 100000000
static inline void wait_on_bh(void)
{
int count = MAXCOUNT;
@@ -469,7 +357,8 @@ static inline void wait_on_irq(int cpu)
* already executing in one..
*/
if (!atomic_read(&global_irq_count)) {
- if (local_bh_count[cpu] || !atomic_read(&global_bh_count))
+ if (ppc_local_bh_count[cpu]
+ || !atomic_read(&global_bh_count))
break;
}
@@ -490,7 +379,8 @@ static inline void wait_on_irq(int cpu)
continue;
if (global_irq_lock)
continue;
- if (!local_bh_count[cpu] && atomic_read(&global_bh_count))
+ if (!ppc_local_bh_count[cpu]
+ && atomic_read(&global_bh_count))
continue;
if (!test_and_set_bit(0,&global_irq_lock))
break;
@@ -512,7 +402,6 @@ void synchronize_bh(void)
wait_on_bh();
}
-
/*
* This is called when we want to synchronize with
* interrupts. We may for example tell a device to
@@ -581,7 +470,7 @@ void __global_cli(void)
if (flags & (1 << 15)) {
int cpu = smp_processor_id();
__cli();
- if (!local_irq_count[cpu])
+ if (!ppc_local_irq_count[cpu])
get_irqlock(cpu);
}
}
@@ -590,7 +479,7 @@ void __global_sti(void)
{
int cpu = smp_processor_id();
- if (!local_irq_count[cpu])
+ if (!ppc_local_irq_count[cpu])
release_irqlock(cpu);
__sti();
}
@@ -614,7 +503,7 @@ unsigned long __global_save_flags(void)
retval = 2 + local_enabled;
/* check for global flags if we're not in an interrupt */
- if (!local_irq_count[smp_processor_id()]) {
+ if (!ppc_local_irq_count[smp_processor_id()]) {
if (local_enabled)
retval = 1;
if (global_irq_holder == (unsigned char) smp_processor_id())
@@ -623,6 +512,31 @@ unsigned long __global_save_flags(void)
return retval;
}
+int
+tb(long vals[],
+ int max_size)
+{
+ register unsigned long *orig_sp __asm__ ("r1");
+ register unsigned long lr __asm__ ("r3");
+ unsigned long *sp;
+ int i;
+
+ asm volatile ("mflr 3");
+ vals[0] = lr;
+ sp = (unsigned long *) *orig_sp;
+ sp = (unsigned long *) *sp;
+ for (i=1; i<max_size; i++) {
+ if (sp == 0) {
+ break;
+ }
+
+ vals[i] = *(sp+1);
+ sp = (unsigned long *) *sp;
+ }
+
+ return i;
+}
+
void __global_restore_flags(unsigned long flags)
{
switch (flags) {
@@ -639,559 +553,21 @@ void __global_restore_flags(unsigned long flags)
__sti();
break;
default:
- printk("global_restore_flags: %08lx (%08lx)\n",
- flags, (&flags)[-1]);
- }
-}
-
-#endif /* __SMP__ */
-
-asmlinkage void do_IRQ(struct pt_regs *regs, int isfake)
-{
- int irq;
- unsigned long bits;
- struct irqaction *action;
- int cpu = smp_processor_id();
- int status;
- int openpic_eoi_done = 0;
-
- /* save the HID0 in case dcache was off - see idle.c
- * this hack should leave for a better solution -- Cort */
- unsigned dcache_locked;
-
- dcache_locked = unlock_dcache();
- hardirq_enter(cpu);
-#ifndef CONFIG_8xx
-#ifdef __SMP__
- if ( cpu != 0 )
- {
- if (!isfake)
- {
- extern void smp_message_recv(void);
-#ifdef CONFIG_XMON
- static int xmon_2nd;
- if (xmon_2nd)
- xmon(regs);
-#endif
- smp_message_recv();
- goto out;
- }
- /* could be here due to a do_fake_interrupt call but we don't
- mess with the controller from the second cpu -- Cort */
- goto out;
- }
-
- {
- unsigned int loops = MAXCOUNT;
- while (test_bit(0, &global_irq_lock)) {
- if (smp_processor_id() == global_irq_holder) {
- printk("uh oh, interrupt while we hold global irq lock!\n");
-#ifdef CONFIG_XMON
- xmon(0);
-#endif
- break;
- }
- if (loops-- == 0) {
- printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder);
-#ifdef CONFIG_XMON
- xmon(0);
-#endif
- }
- }
- }
-#endif /* __SMP__ */
-
- switch ( _machine )
- {
- case _MACH_Pmac:
- for (irq = max_real_irqs - 1; irq > 0; irq -= 32) {
- int i = irq >> 5;
- bits = ld_le32(&pmac_irq_hw[i]->flag)
- | lost_interrupts[i];
- if (bits == 0)
- continue;
- irq -= cntlzw(bits);
- break;
- }
-
- /* Here, we handle interrupts coming from Gatwick,
- * normal interrupt code will take care of acking and
- * masking the irq on Gatwick itself but we ack&mask
- * the Gatwick main interrupt on Heathrow now. It's
- * unmasked later, after interrupt handling. -- BenH
- */
- if (irq == second_irq) {
- mask_and_ack_irq(second_irq);
- for (irq = max_irqs - 1; irq > max_real_irqs; irq -= 32) {
- int i = irq >> 5;
- bits = ld_le32(&pmac_irq_hw[i]->flag)
- | lost_interrupts[i];
- if (bits == 0)
- continue;
- irq -= cntlzw(bits);
- break;
- }
- /* If not found, on exit, irq is 63 (128-1-32-32).
- * We set it to -1 and revalidate second controller
- */
- if (irq < max_real_irqs) {
- irq = -1;
- unmask_irq(second_irq);
- }
-#ifdef SHOW_GATWICK_IRQS
- printk("Gatwick irq %d (i:%d, bits:0x%08lx\n", irq, i, bits);
-#endif
- }
-
- break;
- case _MACH_chrp:
- irq = openpic_irq(0);
- if (irq == IRQ_8259_CASCADE)
- {
- /*
- * This magic address generates a PCI IACK cycle.
- *
- * This should go in the above mask/ack code soon. -- Cort
- */
- irq = *chrp_int_ack_special;
- /*
- * Acknowledge as soon as possible to allow i8259
- * interrupt nesting
- */
- openpic_eoi(0);
- openpic_eoi_done = 1;
- }
- else if (irq >= OPENPIC_VEC_TIMER)
- {
- /*
- * OpenPIC interrupts >64 will be used for other purposes
- * like interprocessor interrupts and hardware errors
- */
- if (irq == OPENPIC_VEC_SPURIOUS) {
- /*
- * Spurious interrupts should never be
- * acknowledged
- */
- spurious_interrupts++;
- openpic_eoi_done = 1;
- } else {
- /*
- * Here we should process IPI timer
- * for now the interrupt is dismissed.
- */
- }
- goto out;
- }
- break;
- case _MACH_prep:
- outb(0x0C, 0x20);
- irq = inb(0x20) & 7;
- if (irq == 2)
- {
-retry_cascade:
- outb(0x0C, 0xA0);
- irq = inb(0xA0);
- /* if no intr left */
- if ( !(irq & 128 ) )
- goto out;
- irq = (irq&7) + 8;
- }
- bits = 1UL << irq;
- break;
-#ifdef CONFIG_APUS
- case _MACH_apus:
{
- int old_level, new_level;
-
- old_level = ~(regs->mq) & IPLEMU_IPLMASK;
- new_level = (~(regs->mq) >> 3) & IPLEMU_IPLMASK;
-
- if (new_level == 0)
- {
- goto apus_out;
- }
-
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
- APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET
- | (~(new_level) & IPLEMU_IPLMASK)));
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
-
- process_int (VEC_SPUR+new_level, regs);
-
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT);
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
- APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET
- | (~(old_level) & IPLEMU_IPLMASK)));
-
-apus_out:
- hardirq_exit(cpu);
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
- goto out2;
- }
-#endif
- }
-
- if (irq < 0) {
- /* we get here with Gatwick but the 'bogus' isn't correct in that case -- Cort */
- if ( irq != second_irq )
- {
- printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
- irq, regs->nip);
- spurious_interrupts++;
- }
- goto out;
- }
-
-#else /* CONFIG_8xx */
- /* For MPC8xx, read the SIVEC register and shift the bits down
- * to get the irq number.
- */
- bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec;
- irq = bits >> 26;
-#endif /* CONFIG_8xx */
- mask_and_ack_irq(irq);
- status = 0;
- action = irq_action[irq];
- kstat.irqs[cpu][irq]++;
- if (action && action->handler) {
- if (!(action->flags & SA_INTERRUPT))
- __sti();
- do {
- status |= action->flags;
- action->handler(irq, action->dev_id, regs);
- action = action->next;
- } while ( action );
- __cli();
- unmask_irq(irq);
- } else {
-#ifndef CONFIG_8xx
- if ( irq == 7 ) /* i8259 gives us irq 7 on 'short' intrs */
-#endif
- spurious_interrupts++;
- disable_irq( irq );
- }
-
- /* This was a gatwick sub-interrupt, we re-enable them on Heathrow
- now */
- if (_machine == _MACH_Pmac && irq >= max_real_irqs)
- unmask_irq(second_irq);
-
- /* make sure we don't miss any cascade intrs due to eoi-ing irq 2 */
-#ifndef CONFIG_8xx
- if ( is_prep && (irq > 7) )
- goto retry_cascade;
- /* do_bottom_half is called if necessary from int_return in head.S */
-out:
- if (_machine == _MACH_chrp && !openpic_eoi_done)
- openpic_eoi(0);
-#endif /* CONFIG_8xx */
- hardirq_exit(cpu);
-
-#ifdef CONFIG_APUS
-out2:
-#endif
- /* restore the HID0 in case dcache was off - see idle.c
- * this hack should leave for a better solution -- Cort */
- lock_dcache(dcache_locked);
-}
-
-int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
- unsigned long irqflags, const char * devname, void *dev_id)
-{
- struct irqaction *old, **p, *action;
- unsigned long flags;
-
-#ifdef SHOW_IRQ
- printk("request_irq(): irq %d handler %08x name %s dev_id %04x\n",
- irq,(int)handler,devname,(int)dev_id);
-#endif /* SHOW_IRQ */
-
- if (irq >= NR_IRQS)
- return -EINVAL;
-
- /* Cannot allocate second controller IRQ */
- if (irq == second_irq)
- return -EBUSY;
+ unsigned long trace[5];
+ int count;
+ int i;
- if (!handler)
- {
- /* Free */
- for (p = irq + irq_action; (action = *p) != NULL; p = &action->next)
- {
- /* Found it - now free it */
- save_flags(flags);
- cli();
- *p = action->next;
- restore_flags(flags);
- irq_kfree(action);
- return 0;
- }
- return -ENOENT;
- }
-
- action = (struct irqaction *)
- irq_kmalloc(sizeof(struct irqaction), GFP_KERNEL);
- if (!action)
- return -ENOMEM;
- save_flags(flags);
- cli();
-
- action->handler = handler;
- action->flags = irqflags;
- action->mask = 0;
- action->name = devname;
- action->dev_id = dev_id;
- action->next = NULL;
- enable_irq(irq);
- p = irq_action + irq;
-
- if ((old = *p) != NULL) {
- /* Can't share interrupts unless both agree to */
- if (!(old->flags & action->flags & SA_SHIRQ))
- return -EBUSY;
- /* add new interrupt at end of irq queue */
- do {
- p = &old->next;
- old = *p;
- } while (old);
- }
- *p = action;
-
- restore_flags(flags);
- return 0;
-}
-
-void free_irq(unsigned int irq, void *dev_id)
-{
- request_irq(irq, NULL, 0, NULL, dev_id);
-}
-
-unsigned long probe_irq_on (void)
-{
- return 0;
-}
-
-int probe_irq_off (unsigned long irqs)
-{
- return 0;
-}
-
-#ifndef CONFIG_8xx
-__initfunc(static void i8259_init(void))
-{
- /* 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);
- if (request_irq(2, no_action, SA_INTERRUPT, "cascade", NULL) != 0)
- panic("Could not allocate cascade IRQ!");
- enable_irq(2); /* Enable cascade interrupt */
-}
-#endif /* CONFIG_8xx */
-
-/* On MBX8xx, the interrupt control (SIEL) was set by EPPC-bug. External
- * interrupts can be either edge or level triggered, but there is no
- * reason for us to change the EPPC-bug values (it would not work if we did).
- */
-__initfunc(void init_IRQ(void))
-{
- extern void xmon_irq(int, void *, struct pt_regs *);
- int i;
- struct device_node *irqctrler;
- unsigned long addr;
- struct device_node *np;
-
-#ifndef CONFIG_8xx
- switch (_machine)
- {
- case _MACH_Pmac:
- mask_and_ack_irq = pmac_mask_and_ack_irq;
- mask_irq = pmac_mask_irq;
- unmask_irq = pmac_unmask_irq;
-
- /* G3 powermacs have 64 interrupts, G3 Series PowerBook have 128,
- others have 32 */
- max_irqs = max_real_irqs = 32;
- irqctrler = find_devices("mac-io");
- if (irqctrler)
- {
- max_real_irqs = 64;
- if (irqctrler->next)
- max_irqs = 128;
- else
- max_irqs = 64;
- }
-
- /* get addresses of first controller */
- if (irqctrler) {
- if (irqctrler->n_addrs > 0) {
- addr = (unsigned long)
- ioremap(irqctrler->addrs[0].address, 0x40);
- for (i = 0; i < 2; ++i)
- pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
- (addr + (2 - i) * 0x10);
- }
-
- /* get addresses of second controller */
- irqctrler = (irqctrler->next) ? irqctrler->next : NULL;
- if (irqctrler && irqctrler->n_addrs > 0) {
- addr = (unsigned long)
- ioremap(irqctrler->addrs[0].address, 0x40);
- for (i = 2; i < 4; ++i)
- pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
- (addr + (4 - i) * 0x10);
- }
- }
-
- /* disable all interrupts in all controllers */
- for (i = 0; i * 32 < max_irqs; ++i)
- out_le32(&pmac_irq_hw[i]->enable, 0);
-
-
- /* get interrupt line of secondary interrupt controller */
- if (irqctrler) {
- second_irq = irqctrler->intrs[0].line;
- printk(KERN_INFO "irq: secondary controller on irq %d\n",
- (int)second_irq);
- if (device_is_compatible(irqctrler, "gatwick"))
- pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs);
- enable_irq(second_irq);
- }
- printk("System has %d possible interrupts\n", max_irqs);
- if (max_irqs != max_real_irqs)
- printk(KERN_DEBUG "%d interrupts on main controller\n",
- max_real_irqs);
-
-#ifdef CONFIG_XMON
- request_irq(20, xmon_irq, 0, "NMI", 0);
-#endif /* CONFIG_XMON */
- break;
- case _MACH_chrp:
- mask_and_ack_irq = chrp_mask_and_ack_irq;
- mask_irq = chrp_mask_irq;
- unmask_irq = chrp_unmask_irq;
-
- if ( !(np = find_devices("pci") ) )
- printk("Cannot find pci to get ack address\n");
- else
- {
- chrp_int_ack_special = (volatile unsigned char *)
- (*(unsigned long *)get_property(np,
- "8259-interrupt-acknowledge", NULL));
- }
- openpic_init(1);
- i8259_init();
- cached_irq_mask[0] = cached_irq_mask[1] = ~0UL;
-#ifdef CONFIG_XMON
- request_irq(openpic_to_irq(HYDRA_INT_ADB_NMI),
- xmon_irq, 0, "NMI", 0);
-#endif /* CONFIG_XMON */
- break;
- case _MACH_prep:
- mask_and_ack_irq = i8259_mask_and_ack_irq;
- mask_irq = i8259_mask_irq;
- unmask_irq = i8259_unmask_irq;
- cached_irq_mask[0] = ~0UL;
-
- i8259_init();
- /*
- * According to the Carolina spec from ibm irqs 0,1,2, and 8
- * must be edge triggered. Also, the pci intrs must be level
- * triggered and _only_ isa intrs can be level sensitive
- * which are 3-7,9-12,14-15. 13 is special - it can be level.
- *
- * power on default is 0's in both regs - all edge.
- *
- * These edge/level control regs allow edge/level status
- * to be decided on a irq basis instead of on a PIC basis.
- * It's still pretty ugly.
- * - Cort
- */
- {
- unsigned char irq_mode1 = 0, irq_mode2 = 0;
- irq_mode1 = 0; /* to get rid of compiler warnings */
- /*
- * On Carolina, irq 15 and 13 must be level (scsi/ide/net).
- */
- if ( _prep_type == _PREP_IBM )
- irq_mode2 |= 0xa0;
+ printk("global_restore_flags: %08lx (%08lx)\n",
+ flags, (&flags)[-1]);
+ count = tb(trace, 5);
+ printk("tb:");
+ for(i=0; i<count; i++) {
+ printk(" %8.8lx", trace[i]);
}
- break;
-#ifdef CONFIG_APUS
- case _MACH_apus:
- mask_irq = amiga_disable_irq;
- unmask_irq = amiga_enable_irq;
- apus_init_IRQ();
- break;
-#endif
+ printk("\n");
}
-#endif /* CONFIG_8xx */
-}
-
-/* This routine will fix some missing interrupt values in the device tree
- * on the gatwick mac-io controller used by some PowerBooks
- */
-static void __init pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
-{
- struct device_node *node;
- static struct interrupt_info int_pool[4];
-
- memset(int_pool, 0, sizeof(int_pool));
- node = gw->child;
- while(node)
- {
- /* Fix SCC */
- if (strcasecmp(node->name, "escc") == 0)
- if (node->child && node->child->n_intrs == 0)
- {
- node->child->n_intrs = 1;
- node->child->intrs = &int_pool[0];
- int_pool[0].line = 15+irq_base;
- printk(KERN_INFO "irq: fixed SCC on second controller (%d)\n",
- int_pool[0].line);
- }
- /* Fix media-bay & left SWIM */
- if (strcasecmp(node->name, "media-bay") == 0)
- {
- struct device_node* ya_node;
-
- if (node->n_intrs == 0)
- {
- node->n_intrs = 1;
- node->intrs = &int_pool[1];
- int_pool[1].line = 29+irq_base;
- printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n",
- int_pool[1].line);
- }
- ya_node = node->child;
- while(ya_node)
- {
- if ((strcasecmp(ya_node->name, "floppy") == 0) &&
- ya_node->n_intrs == 0)
- {
- ya_node->n_intrs = 2;
- ya_node->intrs = &int_pool[2];
- int_pool[2].line = 19+irq_base;
- int_pool[3].line = 1+irq_base;
- printk(KERN_INFO "irq: fixed floppy on second controller (%d,%d)\n",
- int_pool[2].line, int_pool[3].line);
- }
- ya_node = ya_node->sibling;
- }
- }
- node = node->sibling;
}
-
}
+#endif /* __SMP__ */
diff --git a/arch/ppc/kernel/local_irq.h b/arch/ppc/kernel/local_irq.h
new file mode 100644
index 000000000..5149c291a
--- /dev/null
+++ b/arch/ppc/kernel/local_irq.h
@@ -0,0 +1,45 @@
+
+#ifndef _PPC_KERNEL_LOCAL_IRQ_H
+#define _PPC_KERNEL_LOCAL_IRQ_H
+
+#include <linux/kernel_stat.h>
+#include <linux/interrupt.h>
+
+void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq);
+
+/* Structure describing interrupts */
+struct hw_interrupt_type {
+ const char * typename;
+ void (*startup)(unsigned int irq);
+ void (*shutdown)(unsigned int irq);
+ void (*handle)(unsigned int irq, struct pt_regs * regs);
+ void (*enable)(unsigned int irq);
+ void (*disable)(unsigned int irq);
+ void (*mask_and_ack)(unsigned int irq);
+ int irq_offset;
+};
+
+#define mask_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->disable) irq_desc[irq].ctl->disable(irq);})
+#define unmask_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->enable) irq_desc[irq].ctl->enable(irq);})
+#define mask_and_ack_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->mask_and_ack) irq_desc[irq].ctl->mask_and_ack(irq);})
+
+struct irqdesc {
+ struct irqaction *action;
+ struct hw_interrupt_type *ctl;
+};
+
+extern struct irqdesc irq_desc[NR_IRQS];
+
+
+#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];
+extern unsigned int ppc_local_bh_count[NR_CPUS];
+extern unsigned int ppc_local_irq_count[NR_CPUS];
+extern unsigned int ppc_cached_irq_mask[NR_MASK_WORDS];
+extern unsigned int ppc_lost_interrupts[NR_MASK_WORDS];
+extern atomic_t ppc_n_lost_interrupts;
+
+#endif /* _PPC_KERNEL_LOCAL_IRQ_H */
diff --git a/arch/ppc/kernel/mbx_pci.c b/arch/ppc/kernel/mbx_pci.c
index 30b7b1184..5114c3cfb 100644
--- a/arch/ppc/kernel/mbx_pci.c
+++ b/arch/ppc/kernel/mbx_pci.c
@@ -252,3 +252,20 @@ int mbx_pcibios_find_class(unsigned int class_code, unsigned short index,
}
return PCIBIOS_DEVICE_NOT_FOUND;
}
+
+__initfunc(
+void
+mbx_pcibios_fixup(void))
+{
+ /* Nothing to do here? */
+}
+
+__initfunc(
+void
+mbx_setup_pci_ptrs(void))
+{
+ set_config_access_method(mbx);
+
+ ppc_md.pcibios_fixup = mbx_pcibios_fixup;
+}
+
diff --git a/arch/ppc/kernel/mbx_setup.c b/arch/ppc/kernel/mbx_setup.c
index 90647dcd9..0f1eb3eb5 100644
--- a/arch/ppc/kernel/mbx_setup.c
+++ b/arch/ppc/kernel/mbx_setup.c
@@ -1,5 +1,5 @@
/*
- * $Id: mbx_setup.c,v 1.5 1998/12/29 18:55:07 cort Exp $
+ * $Id: mbx_setup.c,v 1.9 1999/04/28 11:54:09 davem Exp $
*
* linux/arch/ppc/kernel/setup.c
*
@@ -39,6 +39,22 @@
#include <asm/pgtable.h>
#include <asm/ide.h>
#include <asm/mbx.h>
+#include <asm/machdep.h>
+
+#include "time.h"
+#include "local_irq.h"
+
+static int mbx_set_rtc_time(unsigned long time);
+unsigned long mbx_get_rtc_time(void);
+void mbx_calibrate_decr(void);
+
+extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int mackbd_getkeycode(unsigned int scancode);
+extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode);
+extern char mackbd_unexpected_up(unsigned char keycode);
+extern void mackbd_leds(unsigned char leds);
+extern void mackbd_init_hw(void);
extern unsigned long loops_per_sec;
@@ -55,35 +71,10 @@ extern char saved_command_line[256];
extern unsigned long find_available_memory(void);
extern void m8xx_cpm_reset(uint);
-/* this really does make things cleaner -- Cort */
-void __init powermac_init(void)
-{
-}
-
void __init adbdev_init(void)
{
}
-void __init mbx_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
-{
- ide_ioreg_t port = base;
- int i = 8;
-
- while (i--)
- *p++ = port++;
- *p++ = base + 0x206;
- if (irq != NULL)
- *irq = 0;
-#ifdef ATA_FLASH
- base = (unsigned long) ioremap(PCMCIA_MEM_ADDR, 0x200);
- for (i = 0; i < 8; ++i)
- *p++ = base++;
- *p = ++base; /* Does not matter */
- if (irq)
- *irq = 13;
-#endif
-}
-
__initfunc(void
mbx_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
{
@@ -145,3 +136,337 @@ abort(void)
#endif
machine_restart(NULL);
}
+
+/* The decrementer counts at the system (internal) clock frequency divided by
+ * sixteen, or external oscillator divided by four. Currently, we only
+ * support the MBX, which is system clock divided by sixteen.
+ */
+__initfunc(void mbx_calibrate_decr(void))
+{
+ bd_t *binfo = (bd_t *)&res;
+ int freq, fp, divisor;
+
+ if ((((immap_t *)MBX_IMAP_ADDR)->im_clkrst.car_sccr & 0x02000000) == 0)
+ printk("WARNING: Wrong decrementer source clock.\n");
+
+ /* The manual says the frequency is in Hz, but it is really
+ * as MHz. The value 'fp' is the number of decrementer ticks
+ * per second.
+ */
+ fp = (binfo->bi_intfreq * 1000000) / 16;
+ freq = fp*60; /* try to make freq/1e6 an integer */
+ divisor = 60;
+ printk("time_init: decrementer frequency = %d/%d\n", freq, divisor);
+ decrementer_count = freq / HZ / divisor;
+ count_period_num = divisor;
+ count_period_den = freq / 1000000;
+}
+
+/* A place holder for time base interrupts, if they are ever enabled.
+*/
+void timebase_interrupt(int irq, void * dev, struct pt_regs * regs)
+{
+ printk("timebase_interrupt()\n");
+}
+
+/* The RTC on the MPC8xx is an internal register.
+ * We want to protect this during power down, so we need to unlock,
+ * modify, and re-lock.
+ */
+static int
+mbx_set_rtc_time(unsigned long time)
+{
+ ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY;
+ ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtc = time;
+ ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY;
+ return(0);
+}
+
+initfunc(unsigned long
+mbx_get_rtc_time(void)
+{
+ /* First, unlock all of the registers we are going to modify.
+ * To protect them from corruption during power down, registers
+ * that are maintained by keep alive power are "locked". To
+ * modify these registers we have to write the key value to
+ * the key location associated with the register.
+ */
+ ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_tbscrk = KAPWR_KEY;
+ ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtcsck = KAPWR_KEY;
+
+
+ /* Disable the RTC one second and alarm interrupts.
+ */
+ ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtcsc &=
+ ~(RTCSC_SIE | RTCSC_ALE);
+
+ /* Enabling the decrementer also enables the timebase interrupts
+ * (or from the other point of view, to get decrementer interrupts
+ * we have to enable the timebase). The decrementer interrupt
+ * is wired into the vector table, nothing to do here for that.
+ */
+ ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_tbscr =
+ ((mk_int_int_mask(DEC_INTERRUPT) << 8) |
+ (TBSCR_TBF | TBSCR_TBE));
+ if (request_irq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint", NULL) != 0)
+ panic("Could not allocate timer IRQ!");
+
+ /* Get time from the RTC.
+ */
+ return ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtc;
+}
+
+void
+mbx_restart(char *cmd)
+{
+ extern void MBX_gorom(void);
+
+ MBX_gorom();
+}
+
+void
+mbx_power_off(void)
+{
+ mbx_restart(NULL);
+}
+
+void
+mbx_halt(void)
+{
+ mbx_restart(NULL)
+}
+
+
+int mbx_setup_residual(char *buffer)
+{
+ int len = 0;
+ bd_t *bp;
+ extern RESIDUAL *res;
+
+ bp = (bd_t *)res;
+
+ len += sprintf(len+buffer,"clock\t\t: %dMHz\n"
+ "bus clock\t: %dMHz\n",
+ bp->bi_intfreq /*/ 1000000*/,
+ bp->bi_busfreq /*/ 1000000*/);
+
+ return len;
+}
+
+void
+mbx_do_IRQ(struct pt_regs *regs,
+ int cpu,
+ int isfake)
+{
+ 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;
+ irq += ppc8xx_pic.irq_offset;
+ bits = 1UL << irq;
+
+ if (irq < 0) {
+ printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
+ irq, regs->nip);
+ spurious_interrupts++;
+ }
+ else {
+ ppc_irq_dispatch_handler( regs, irq );
+ }
+
+}
+
+static void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+ int bits, irq;
+
+ /* A bug in the QSpan chip causes it to give us 0xff always
+ * when doing a character read. So read 32 bits and shift.
+ * This doesn't seem to return useful values anyway, but
+ * read it to make sure things are acked.
+ * -- Cort
+ */
+ irq = (inl(0x508) >> 24)&0xff;
+ if ( irq != 0xff ) printk("iack %d\n", irq);
+
+ outb(0x0C, 0x20);
+ irq = inb(0x20) & 7;
+ if (irq == 2)
+ {
+ outb(0x0C, 0xA0);
+ irq = inb(0xA0);
+ irq = (irq&7) + 8;
+ }
+ bits = 1UL << irq;
+ irq += i8259_pic.irq_offset;
+ ppc_irq_dispatch_handler( regs, irq );
+}
+
+
+/* On MBX8xx, the interrupt control (SIEL) was set by EPPC-bug. External
+ * interrupts can be either edge or level triggered, but there is no
+ * reason for us to change the EPPC-bug values (it would not work if we did).
+ */
+__initfunc(void
+mbx_init_IRQ(void))
+{
+ int i;
+
+ ppc8xx_pic.irq_offset = 16;
+ for ( i = 16 ; i < 32 ; i++ )
+ irq_desc[i].ctl = &ppc8xx_pic;
+ unmask_irq(CPM_INTERRUPT);
+
+ for ( i = 0 ; i < 16 ; i++ )
+ irq_desc[i].ctl = &i8259_pic;
+ i8259_init();
+ request_irq(ISA_BRIDGE_INT, mbx_i8259_action, 0, "8259 cascade", NULL);
+ enable_irq(ISA_BRIDGE_INT);
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+void
+mbx_ide_insw(ide_ioreg_t port, void *buf, int ns)
+{
+ ide_insw(port+_IO_BASE), buf, ns);
+}
+
+void
+mbx_ide_outsw(ide_ioreg_t port, void *buf, int ns)
+{
+ ide_outsw(port+_IO_BASE, buf, ns);
+}
+
+int
+mbx_ide_default_irq(ide_ioreg_t base)
+{
+ return 14;
+}
+
+ide_ioreg_t
+mbx_ide_default_io_base(int index)
+{
+ return index;
+}
+
+int
+mbx_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+ return 0
+}
+
+void
+mbx_ide_request_region(ide_ioreg_t from,
+ unsigned int extent,
+ const char *name)
+{
+}
+
+void
+mbx_ide_release_region(ide_ioreg_t from,
+ unsigned int extent)
+{
+}
+
+void
+mbx_ide_fix_driveid(struct hd_driveid *id)
+{
+ ppc_generic_ide_fix_driveid(id);
+}
+
+void __init mbx_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+{
+ ide_ioreg_t port = base;
+ int i = 8;
+
+ while (i--)
+ *p++ = port++;
+ *p++ = base + 0x206;
+ if (irq != NULL)
+ *irq = 0;
+#ifdef ATA_FLASH
+ base = (unsigned long) ioremap(PCMCIA_MEM_ADDR, 0x200);
+ for (i = 0; i < 8; ++i)
+ *p++ = base++;
+ *p = ++base; /* Does not matter */
+ if (irq)
+ *irq = 13;
+#endif
+}
+#endif
+
+__initfunc(void
+mbx_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7))
+{
+
+ if ( r3 )
+ memcpy( (void *)&res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
+
+#ifdef CONFIG_PCI
+ mbx_setup_pci_ptrs();
+#endif
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ /* take care of initrd if we have one */
+ if ( r4 )
+ {
+ initrd_start = r4 + KERNELBASE;
+ initrd_end = r5 + KERNELBASE;
+ }
+#endif /* CONFIG_BLK_DEV_INITRD */
+ /* take care of cmd line */
+ if ( r6 )
+ {
+
+ *(char *)(r7+KERNELBASE) = 0;
+ strcpy(cmd_line, (char *)(r6+KERNELBASE));
+ }
+
+ ppc_md.setup_arch = mbx_setup_arch;
+ ppc_md.setup_residual = mbx_setup_residual;
+ ppc_md.get_cpuinfo = NULL;
+ ppc_md.irq_cannonicalize = NULL;
+ ppc_md.init_IRQ = mbx_init_IRQ;
+ ppc_md.do_IRQ = mbx_do_IRQ;
+ ppc_md.init = NULL;
+
+ ppc_md.restart = mbx_restart;
+ ppc_md.power_off = mbx_power_off;
+ ppc_md.halt = mbx_halt;
+
+ ppc_md.time_init = NULL;
+ ppc_md.set_rtc_time = mbx_set_rtc_time;
+ ppc_md.get_rtc_time = mbx_get_rtc_time;
+ ppc_md.calibrate_decr = mbx_calibrate_decr;
+
+ 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.kbd_sysrq_xlate = pckbd_sysrq_xlate;
+#endif
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+ ppc_ide_md.insw = mbx_ide_insw;
+ ppc_ide_md.outsw = mbx_ide_outsw;
+ ppc_ide_md.default_irq = mbx_ide_default_irq;
+ ppc_ide_md.default_io_base = mbx_ide_default_io_base;
+ ppc_ide_md.check_region = mbx_ide_check_region;
+ ppc_ide_md.request_region = mbx_ide_request_region;
+ ppc_ide_md.release_region = mbx_ide_release_region;
+ ppc_ide_md.fix_driveid = mbx_ide_fix_driveid;
+ ppc_ide_md.ide_init_hwif = mbx_ide_init_hwif_ports;
+
+ ppc_ide_md.io_base = _IO_BASE;
+#endif
+}
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index e4589b1e0..cbeb4ffce 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -36,6 +36,7 @@
* 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
@@ -72,8 +73,8 @@ _GLOBAL(_enable_interrupts)
beqlr /* nothing to do if state == 0 */
_GLOBAL(__sti)
_GLOBAL(_hard_sti)
- lis r4,n_lost_interrupts@ha
- lwz r4,n_lost_interrupts@l(r4)
+ lis r4,ppc_n_lost_interrupts@ha
+ lwz r4,ppc_n_lost_interrupts@l(r4)
mfmsr r3 /* Get current state */
ori r3,r3,MSR_EE /* Turn on 'EE' bit */
cmpi 0,r4,0 /* lost interrupts to process first? */
@@ -93,8 +94,8 @@ do_lost_interrupts:
stw r0,20(r1)
stw r3,8(r1)
1: bl fake_interrupt
- lis r4,n_lost_interrupts@ha
- lwz r4,n_lost_interrupts@l(r4)
+ lis r4,ppc_n_lost_interrupts@ha
+ lwz r4,ppc_n_lost_interrupts@l(r4)
cmpi 0,r4,0
bne- 1b
lwz r3,8(r1)
@@ -105,11 +106,31 @@ do_lost_interrupts:
addi r1,r1,16
blr
+
+/*
+ * complement mask on the msr then "or" some values on.
+ * _nmask_and_or_msr(nmask, value_to_or)
+ */
+ _GLOBAL(_nmask_and_or_msr)
+ mfmsr r0 /* Get current msr */
+ andc r0,r0,r3 /* And off the bits set in r3 (first parm) */
+ or r0,r0,r4 /* Or on the bits in r4 (second parm) */
+ sync /* Some chip revs have problems here... */
+ mtmsr r0 /* Update machine state */
+ blr /* Done */
+
+
/*
* Flush MMU TLB
*/
_GLOBAL(_tlbia)
+ sync
tlbia
+ sync
+#ifdef __SMP__
+ tlbsync
+ sync
+#endif
blr
/*
@@ -117,11 +138,17 @@ _GLOBAL(_tlbia)
*/
_GLOBAL(_tlbie)
tlbie r3
+ sync
+#ifdef __SMP__
+ tlbsync
+ sync
+#endif
blr
+
/*
* Atomic [test&set] exchange
*
- * void *xchg_u32(void *ptr, unsigned long val)
+ * unsigned long xchg_u32(void *ptr, unsigned long val)
* Changes the memory location '*ptr' to be val and returns
* the previous value stored there.
*/
@@ -133,6 +160,27 @@ _GLOBAL(xchg_u32)
blr
/*
+ * Try to acquire a spinlock.
+ * Only does the stwcx. if the load returned 0 - the Programming
+ * Environments Manual suggests not doing unnecessary stcwx.'s
+ * since they may inhibit forward progress by other CPUs in getting
+ * a lock.
+ */
+_GLOBAL(__spin_trylock)
+ mr r4,r3
+ eieio /* prevent reordering of stores */
+ li r5,-1
+ lwarx r3,0,r4 /* fetch old value, establish reservation */
+ cmpwi 0,r3,0 /* is it 0? */
+ bnelr- /* return failure if not */
+ stwcx. r5,0,r4 /* try to update with new value */
+ bne- 1f /* if we failed */
+ eieio /* prevent reordering of stores */
+ blr
+1: li r3,1 /* return non-zero for failure */
+ blr
+
+/*
* Atomic add/sub/inc/dec operations
*
* void atomic_add(int c, int *v)
@@ -590,6 +638,16 @@ cvt_df:
stfd 0,-4(r5)
blr
+ .globl __clear_msr_me
+__clear_msr_me:
+ mfmsr r0 /* Get current interrupt state */
+ lis r3,0
+ ori r3,r3,MSR_ME
+ andc r0,r0,r3 /* Clears bit in (r4) */
+ sync /* Some chip revs have problems here */
+ mtmsr r0 /* Update machine state */
+ blr
+
/*
* Fetch the current SR register
* get_SR(int index)
@@ -608,6 +666,8 @@ _GLOBAL(__kernel_thread)
sc
cmpi 0,r3,0 /* parent or child? */
bnelr /* return if parent */
+ li r0,0 /* clear out p->tss.regs */
+ stw r0,TSS+PT_REGS(r2) /* since we don't have user ctx */
mtlr r4 /* fn addr in lr */
mr r3,r5 /* load arg and call fn */
blrl
@@ -836,4 +896,5 @@ sys_call_table:
.long sys_sendfile
.long sys_ni_syscall /* streams1 */
.long sys_ni_syscall /* streams2 */
+ .long sys_vfork
.space (NR_syscalls-183)*4
diff --git a/arch/ppc/kernel/mk_defs.c b/arch/ppc/kernel/mk_defs.c
index 9b51a6cc1..b66ccffa8 100644
--- a/arch/ppc/kernel/mk_defs.c
+++ b/arch/ppc/kernel/mk_defs.c
@@ -29,7 +29,7 @@
int
main(void)
{
- DEFINE(KERNELBASE, KERNELBASE);
+ /*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));
@@ -48,7 +48,6 @@ main(void)
DEFINE(NEED_RESCHED, offsetof(struct task_struct, need_resched));
DEFINE(TSS_FPR0, offsetof(struct thread_struct, fpr[0]));
DEFINE(TSS_FPSCR, offsetof(struct thread_struct, fpscr));
- DEFINE(TSS_SMP_FORK_RET, offsetof(struct thread_struct, smp_fork_ret));
/* Interrupt register frame */
DEFINE(TASK_UNION_SIZE, sizeof(union task_union));
DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
diff --git a/arch/ppc/kernel/open_pic.c b/arch/ppc/kernel/open_pic.c
new file mode 100644
index 000000000..2ca879dd8
--- /dev/null
+++ b/arch/ppc/kernel/open_pic.c
@@ -0,0 +1,48 @@
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/openpic.h>
+#include <asm/irq.h>
+#include "open_pic.h"
+#include "i8259.h"
+
+#ifdef __SMP__
+void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+ smp_message_recv();
+}
+#endif /* __SMP__ */
+
+void chrp_mask_and_ack_irq(unsigned int irq_nr)
+{
+ if (is_8259_irq(irq_nr))
+ i8259_pic.mask_and_ack(irq_nr);
+}
+
+static void chrp_mask_irq(unsigned int irq_nr)
+{
+ if (is_8259_irq(irq_nr))
+ i8259_pic.disable(irq_nr);
+ else
+ openpic_disable_irq(irq_to_openpic(irq_nr));
+}
+
+static void chrp_unmask_irq(unsigned int irq_nr)
+{
+ if (is_8259_irq(irq_nr))
+ i8259_pic.enable(irq_nr);
+ else
+ openpic_enable_irq(irq_to_openpic(irq_nr));
+}
+
+struct hw_interrupt_type open_pic = {
+ " OpenPIC ",
+ NULL,
+ NULL,
+ NULL,
+ chrp_unmask_irq,
+ chrp_mask_irq,
+ chrp_mask_and_ack_irq,
+ 0
+};
diff --git a/arch/ppc/kernel/open_pic.h b/arch/ppc/kernel/open_pic.h
new file mode 100644
index 000000000..77b8a46d0
--- /dev/null
+++ b/arch/ppc/kernel/open_pic.h
@@ -0,0 +1,11 @@
+
+#ifndef _PPC_KERNEL_OPEN_PIC_H
+#define _PPC_KERNEL_OPEN_PIC_H
+
+#include "local_irq.h"
+
+extern struct hw_interrupt_type open_pic;
+
+void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs);
+
+#endif /* _PPC_KERNEL_OPEN_PIC_H */
diff --git a/arch/ppc/kernel/openpic.c b/arch/ppc/kernel/openpic.c
index ec60ca5a6..f7893dd79 100644
--- a/arch/ppc/kernel/openpic.c
+++ b/arch/ppc/kernel/openpic.c
@@ -107,7 +107,7 @@ static inline void out_le32(volatile u_int *addr, u_int val)
}
#endif
-static inline u_int openpic_read(volatile u_int *addr)
+u_int openpic_read(volatile u_int *addr)
{
u_int val;
@@ -176,8 +176,8 @@ static void openpic_safe_writefield(volatile u_int *addr, u_int mask,
__initfunc(void openpic_init(int main_pic))
{
u_int t, i;
- u_int vendorid, devid, stepping, timerfreq;
- const char *version, *vendor, *device;
+ u_int timerfreq;
+ const char *version;
if (!OpenPIC)
panic("No OpenPIC found");
@@ -190,6 +190,9 @@ __initfunc(void openpic_init(int main_pic))
case 2:
version = "1.2";
break;
+ case 3:
+ version = "1.3";
+ break;
default:
version = "?";
break;
@@ -200,32 +203,6 @@ __initfunc(void openpic_init(int main_pic))
OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1;
printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n", version,
NumProcessors, NumSources, OpenPIC);
-
- t = openpic_read(&OpenPIC->Global.Vendor_Identification);
- vendorid = t & OPENPIC_VENDOR_ID_VENDOR_ID_MASK;
- devid = (t & OPENPIC_VENDOR_ID_DEVICE_ID_MASK) >>
- OPENPIC_VENDOR_ID_DEVICE_ID_SHIFT;
- stepping = (t & OPENPIC_VENDOR_ID_STEPPING_MASK) >>
- OPENPIC_VENDOR_ID_STEPPING_SHIFT;
- switch (vendorid) {
- case OPENPIC_VENDOR_ID_APPLE:
- vendor = "Apple";
- break;
- default:
- vendor = "Unknown";
- break;
- }
- switch (devid) {
- case OPENPIC_DEVICE_ID_APPLE_HYDRA:
- device = "Hydra";
- break;
- default:
- device = "Unknown";
- break;
- }
- printk("OpenPIC Vendor %d (%s), Device %d (%s), Stepping %d\n", vendorid,
- vendor, devid, device, stepping);
-
timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
printk("OpenPIC timer frequency is ");
if (timerfreq)
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index 1dfa3a6c8..ccef5f36a 100644
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -1,5 +1,5 @@
/*
- * $Id: pci.c,v 1.43 1998/12/29 18:55:11 cort Exp $
+ * $Id: pci.c,v 1.54 1999/03/18 04:16:04 cort Exp $
* Common pmac/prep/chrp pci routines. -- Cort
*/
@@ -21,94 +21,41 @@
#include <asm/irq.h>
#include <asm/gg2.h>
-unsigned long isa_io_base;
-unsigned long isa_mem_base;
-unsigned long pci_dram_offset;
+#include "pci.h"
-unsigned int * pci_config_address;
-unsigned char * pci_config_data;
-
-/*
- * It would be nice if we could create a include/asm/pci.h and have just
- * function ptrs for all these in there, but that isn't the case.
- * We have a function, pcibios_*() which calls the function ptr ptr_pcibios_*()
- * which has been setup by pcibios_init(). This is all to avoid a check
- * for pmac/prep every time we call one of these. It should also make the move
- * to a include/asm/pcibios.h easier, we can drop the ptr_ on these functions
- * and create pci.h
- * -- Cort
- */
-int (*ptr_pcibios_read_config_byte)(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned char *val);
-int (*ptr_pcibios_read_config_word)(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned short *val);
-int (*ptr_pcibios_read_config_dword)(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned int *val);
-int (*ptr_pcibios_write_config_byte)(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned char val);
-int (*ptr_pcibios_write_config_word)(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned short val);
-int (*ptr_pcibios_write_config_dword)(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned int val);
-
-#define decl_config_access_method(name) \
-extern int name##_pcibios_read_config_byte(unsigned char bus, \
- unsigned char dev_fn, unsigned char offset, unsigned char *val); \
-extern int name##_pcibios_read_config_word(unsigned char bus, \
- unsigned char dev_fn, unsigned char offset, unsigned short *val); \
-extern int name##_pcibios_read_config_dword(unsigned char bus, \
- unsigned char dev_fn, unsigned char offset, unsigned int *val); \
-extern int name##_pcibios_write_config_byte(unsigned char bus, \
- unsigned char dev_fn, unsigned char offset, unsigned char val); \
-extern int name##_pcibios_write_config_word(unsigned char bus, \
- unsigned char dev_fn, unsigned char offset, unsigned short val); \
-extern int name##_pcibios_write_config_dword(unsigned char bus, \
- unsigned char dev_fn, unsigned char offset, unsigned int val)
-
-#define set_config_access_method(name) \
- ptr_pcibios_read_config_byte = name##_pcibios_read_config_byte; \
- ptr_pcibios_read_config_word = name##_pcibios_read_config_word; \
- ptr_pcibios_read_config_dword = name##_pcibios_read_config_dword; \
- ptr_pcibios_write_config_byte = name##_pcibios_write_config_byte; \
- ptr_pcibios_write_config_word = name##_pcibios_write_config_word; \
- ptr_pcibios_write_config_dword = name##_pcibios_write_config_dword
-
-decl_config_access_method(pmac);
-decl_config_access_method(grackle);
-decl_config_access_method(gg2);
-decl_config_access_method(raven);
-decl_config_access_method(prep);
-decl_config_access_method(mbx);
+unsigned long isa_io_base = 0;
+unsigned long isa_mem_base = 0;
+unsigned long pci_dram_offset = 0;
int pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned char *val)
{
- return ptr_pcibios_read_config_byte(bus,dev_fn,offset,val);
+ return ppc_md.pcibios_read_config_byte(bus,dev_fn,offset,val);
}
int pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned short *val)
{
- return ptr_pcibios_read_config_word(bus,dev_fn,offset,val);
+ return ppc_md.pcibios_read_config_word(bus,dev_fn,offset,val);
}
int pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned int *val)
{
- return ptr_pcibios_read_config_dword(bus,dev_fn,offset,val);
+ return ppc_md.pcibios_read_config_dword(bus,dev_fn,offset,val);
}
int pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned char val)
{
- return ptr_pcibios_write_config_byte(bus,dev_fn,offset,val);
+ return ppc_md.pcibios_write_config_byte(bus,dev_fn,offset,val);
}
int pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned short val)
{
- return ptr_pcibios_write_config_word(bus,dev_fn,offset,val);
+ return ppc_md.pcibios_write_config_word(bus,dev_fn,offset,val);
}
int pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned int val)
{
- return ptr_pcibios_write_config_dword(bus,dev_fn,offset,val);
+ return ppc_md.pcibios_write_config_dword(bus,dev_fn,offset,val);
}
int pcibios_present(void)
@@ -116,167 +63,46 @@ int pcibios_present(void)
return 1;
}
-__initfunc(void pcibios_init(void))
+void __init pcibios_init(void)
{
}
-__initfunc(void
- setup_pci_ptrs(void))
+
+void __init pcibios_fixup(void)
{
-#ifndef CONFIG_MBX
- PPC_DEVICE *hostbridge;
- switch (_machine) {
- case _MACH_prep:
- hostbridge=residual_find_device(PROCESSORDEVICE, NULL,
- BridgeController, PCIBridge,
- -1, 0);
- if (hostbridge &&
- hostbridge->DeviceId.Interface == PCIBridgeIndirect) {
- PnP_TAG_PACKET * pkt;
- set_config_access_method(raven);
- pkt=PnP_find_large_vendor_packet(
- res->DevicePnPHeap+hostbridge->AllocatedOffset,
- 3, 0);
- if(pkt) {
-#define p pkt->L4_Pack.L4_Data.L4_PPCPack
- pci_config_address= (unsigned *)
- ld_le32((unsigned *) p.PPCData);
- pci_config_data= (unsigned char *)
- ld_le32((unsigned *) (p.PPCData+8));
- } else {/* default values */
- pci_config_address= (unsigned *) 0x80000cf8;
- pci_config_data= (unsigned char *) 0x80000cfc;
- }
- } else {
- set_config_access_method(prep);
- }
- break;
- case _MACH_Pmac:
- if (find_devices("pci") != 0) {
- /* looks like a G3 powermac */
- set_config_access_method(grackle);
- } else {
- set_config_access_method(pmac);
- }
- break;
- case _MACH_chrp:
- if ( !strncmp("MOT",
- get_property(find_path_device("/"), "model", NULL),3) )
- {
- isa_io_base = 0xfe000000;
- set_config_access_method(grackle);
- }
- else
- {
- isa_io_base = GG2_ISA_IO_BASE;
- set_config_access_method(gg2);
- }
- break;
- default:
- printk("setup_pci_ptrs(): unknown machine type!\n");
- }
-#else /* CONFIG_MBX */
- set_config_access_method(mbx);
-#endif /* CONFIG_MBX */
-#undef set_config_access_method
+ ppc_md.pcibios_fixup();
}
-__initfunc(void pcibios_fixup(void))
+void __init pcibios_fixup_bus(struct pci_bus *bus)
{
- extern unsigned long route_pci_interrupts(void);
- struct pci_dev *dev;
- extern struct bridge_data **bridges;
- extern unsigned char *Motherboard_map;
- extern unsigned char *Motherboard_routes;
- unsigned char i;
-#ifndef CONFIG_MBX
- switch (_machine )
- {
- case _MACH_prep:
- route_pci_interrupts();
- for(dev=pci_devices; dev; dev=dev->next)
- {
- /*
- * Use our old hard-coded kludge to figure out what
- * irq this device uses. This is necessary on things
- * without residual data. -- Cort
- */
- unsigned char d = PCI_SLOT(dev->devfn);
- dev->irq = Motherboard_routes[Motherboard_map[d]];
- for ( i = 0 ; i <= 5 ; i++ )
- {
- if ( dev->base_address[i] > 0x10000000 )
- {
- printk("Relocating PCI address %x -> %x\n",
- dev->base_address[i],
- (dev->base_address[i] & 0x00FFFFFF)
- | 0x01000000);
- dev->base_address[i] =
- (dev->base_address[i] & 0x00FFFFFF) | 0x01000000;
- pci_write_config_dword(dev,
- PCI_BASE_ADDRESS_0+(i*0x4),
- dev->base_address[i] );
- }
- }
-#if 0
- /*
- * If we have residual data and if it knows about this
- * device ask it what the irq is.
- * -- Cort
- */
- ppcd = residual_find_device_id( ~0L, dev->device,
- -1,-1,-1, 0);
-#endif
- }
- break;
- case _MACH_chrp:
- /* PCI interrupts are controlled by the OpenPIC */
- for(dev=pci_devices; dev; dev=dev->next)
- if (dev->irq)
- dev->irq = openpic_to_irq(dev->irq);
- break;
- case _MACH_Pmac:
- for(dev=pci_devices; dev; dev=dev->next)
- {
- /*
- * 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.
- */
- struct bridge_data *bp = bridges[dev->bus->number];
- struct device_node *node;
- unsigned int *reg;
- unsigned char pin;
-
- if (pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin) ||
- !pin)
- continue; /* No interrupt generated -> no fixup */
- for (node = bp->node->child; node != 0;
- node = node->sibling) {
- reg = (unsigned int *) get_property(node, "reg", 0);
- if (reg == 0 || ((reg[0] >> 8) & 0xff) != dev->devfn)
- continue;
- /* this is the node, see if it has interrupts */
- if (node->n_intrs > 0)
- dev->irq = node->intrs[0].line;
- break;
- }
- }
- break;
- }
-#else /* CONFIG_MBX */
- for(dev=pci_devices; dev; dev=dev->next)
- {
- }
-#endif /* CONFIG_MBX */
}
-__initfunc(void pcibios_fixup_bus(struct pci_bus *bus))
+char __init *pcibios_setup(char *str)
{
+ return str;
}
-__initfunc(char *pcibios_setup(char *str))
+#ifndef CONFIG_MBX
+/* Recursively searches any node that is of type PCI-PCI bridge. Without
+ * this, the old code would miss children of P2P bridges and hence not
+ * fix IRQ's for cards located behind P2P bridges.
+ * - Ranjit Deshpande, 01/20/99
+ */
+void __init fix_intr(struct device_node *node, struct pci_dev *dev)
{
- return str;
+ unsigned int *reg, *class_code;
+
+ for (; node != 0;node = node->sibling) {
+ class_code = (unsigned int *) get_property(node, "class-code", 0);
+ if((*class_code >> 8) == PCI_CLASS_BRIDGE_PCI)
+ fix_intr(node->child, dev);
+ reg = (unsigned int *) get_property(node, "reg", 0);
+ if (reg == 0 || ((reg[0] >> 8) & 0xff) != dev->devfn)
+ continue;
+ /* this is the node, see if it has interrupts */
+ if (node->n_intrs > 0)
+ dev->irq = node->intrs[0].line;
+ break;
+ }
}
+#endif
diff --git a/arch/ppc/kernel/pci.h b/arch/ppc/kernel/pci.h
new file mode 100644
index 000000000..231f1d952
--- /dev/null
+++ b/arch/ppc/kernel/pci.h
@@ -0,0 +1,36 @@
+
+#ifndef __PPC_KERNEL_PCI_H__
+#define __PPC_KERNEL_PCI_H__
+
+extern unsigned long isa_io_base;
+extern unsigned long isa_mem_base;
+extern unsigned long pci_dram_offset;
+
+extern unsigned int *pci_config_address;
+extern unsigned char *pci_config_data;
+
+void fix_intr(struct device_node *node, struct pci_dev *dev);
+
+#define decl_config_access_method(name) \
+extern int name##_pcibios_read_config_byte(unsigned char bus, \
+ unsigned char dev_fn, unsigned char offset, unsigned char *val); \
+extern int name##_pcibios_read_config_word(unsigned char bus, \
+ unsigned char dev_fn, unsigned char offset, unsigned short *val); \
+extern int name##_pcibios_read_config_dword(unsigned char bus, \
+ unsigned char dev_fn, unsigned char offset, unsigned int *val); \
+extern int name##_pcibios_write_config_byte(unsigned char bus, \
+ unsigned char dev_fn, unsigned char offset, unsigned char val); \
+extern int name##_pcibios_write_config_word(unsigned char bus, \
+ unsigned char dev_fn, unsigned char offset, unsigned short val); \
+extern int name##_pcibios_write_config_dword(unsigned char bus, \
+ unsigned char dev_fn, unsigned char offset, unsigned int val)
+
+#define set_config_access_method(name) \
+ ppc_md.pcibios_read_config_byte = name##_pcibios_read_config_byte; \
+ ppc_md.pcibios_read_config_word = name##_pcibios_read_config_word; \
+ ppc_md.pcibios_read_config_dword = name##_pcibios_read_config_dword; \
+ ppc_md.pcibios_write_config_byte = name##_pcibios_write_config_byte; \
+ ppc_md.pcibios_write_config_word = name##_pcibios_write_config_word; \
+ ppc_md.pcibios_write_config_dword = name##_pcibios_write_config_dword
+
+#endif /* __PPC_KERNEL_PCI_H__ */
diff --git a/arch/ppc/kernel/pmac_pci.c b/arch/ppc/kernel/pmac_pci.c
index 7763059f7..089169e37 100644
--- a/arch/ppc/kernel/pmac_pci.c
+++ b/arch/ppc/kernel/pmac_pci.c
@@ -21,6 +21,9 @@
#include <asm/pgtable.h>
#include <asm/prom.h>
#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+
+#include "pci.h"
struct bridge_data **bridges, *bridge_list;
static int max_bus;
@@ -84,7 +87,12 @@ int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
(1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ (offset & ~3));
} else {
- out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ /* Bus number once again taken into consideration.
+ * Change applied from 2.1.24. This makes devices located
+ * behind PCI-PCI bridges visible.
+ * -Ranjit Deshpande, 01/20/99
+ */
+ out_le32(bp->cfg_addr, (bus << 16) + (dev_fn << 8) + (offset & ~3) + 1);
}
udelay(2);
*val = in_8(bp->cfg_data + (offset & 3));
@@ -109,7 +117,8 @@ int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
(1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ (offset & ~3));
} else {
- out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ /* See pci_read_config_byte */
+ out_le32(bp->cfg_addr, (bus << 16) + (dev_fn << 8) + (offset & ~3) + 1);
}
udelay(2);
*val = in_le16((volatile unsigned short *)(bp->cfg_data + (offset & 3)));
@@ -134,7 +143,8 @@ int pmac_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
(1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ offset);
} else {
- out_le32(bp->cfg_addr, (dev_fn << 8) + offset + 1);
+ /* See pci_read_config_byte */
+ out_le32(bp->cfg_addr, (bus << 16) + (dev_fn << 8) + offset + 1);
}
udelay(2);
*val = in_le32((volatile unsigned int *)bp->cfg_data);
@@ -156,7 +166,8 @@ int pmac_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
(1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ (offset & ~3));
} else {
- out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ /* See pci_read_config_byte */
+ out_le32(bp->cfg_addr, (bus << 16) + (dev_fn << 8) + (offset & ~3) + 1);
}
udelay(2);
out_8(bp->cfg_data + (offset & 3), val);
@@ -180,7 +191,8 @@ int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
(1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ (offset & ~3));
} else {
- out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ /* See pci_read_config_byte */
+ out_le32(bp->cfg_addr, (bus << 16) + (dev_fn << 8) + (offset & ~3) + 1);
}
udelay(2);
out_le16((volatile unsigned short *)(bp->cfg_data + (offset & 3)), val);
@@ -204,7 +216,8 @@ int pmac_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
(1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ offset);
} else {
- out_le32(bp->cfg_addr, (dev_fn << 8) + offset + 1);
+ /* See pci_read_config_byte */
+ out_le32(bp->cfg_addr, (bus << 16) + (dev_fn << 8) + (offset & ~3) + 1);
}
udelay(2);
out_le32((volatile unsigned int *)bp->cfg_data, val);
@@ -429,3 +442,47 @@ __initfunc(static void add_bridges(struct device_node *dev, unsigned long *mem_p
}
}
+__initfunc(
+void
+pmac_pcibios_fixup(void))
+{
+ struct pci_dev *dev;
+
+ /*
+ * FIXME: This is broken: We should not assign IRQ's to IRQless
+ * devices (look at PCI_INTERRUPT_PIN) and we also should
+ * honor the existence of multi-function devices where
+ * different functions have different interrupt pins. [mj]
+ */
+ for(dev=pci_devices; dev; dev=dev->next)
+ {
+ /*
+ * 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.
+ */
+ struct bridge_data *bp = bridges[dev->bus->number];
+ unsigned char pin;
+
+ if (pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin) ||
+ !pin)
+ continue; /* No interrupt generated -> no fixup */
+ fix_intr(bp->node->child, dev);
+ }
+}
+
+__initfunc(
+void
+pmac_setup_pci_ptrs(void))
+{
+ if (find_devices("pci") != 0) {
+ /* looks like a G3 powermac */
+ set_config_access_method(grackle);
+ } else {
+ set_config_access_method(pmac);
+ }
+
+ ppc_md.pcibios_fixup = pmac_pcibios_fixup;
+}
+
diff --git a/arch/ppc/kernel/pmac_pic.c b/arch/ppc/kernel/pmac_pic.c
new file mode 100644
index 000000000..6a49f1405
--- /dev/null
+++ b/arch/ppc/kernel/pmac_pic.c
@@ -0,0 +1,362 @@
+
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/prom.h>
+#include "pmac_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;
+
+#define MAXCOUNT 10000000
+
+#define GATWICK_IRQ_POOL_SIZE 10
+static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE];
+
+static void __pmac pmac_mask_and_ack_irq(unsigned int irq_nr)
+{
+ unsigned long bit = 1UL << (irq_nr & 0x1f);
+ int i = irq_nr >> 5;
+
+ 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);
+ 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);
+}
+
+static void __pmac pmac_set_irq_mask(unsigned int irq_nr)
+{
+ unsigned long bit = 1UL << (irq_nr & 0x1f);
+ int i = irq_nr >> 5;
+
+ if ((unsigned)irq_nr >= max_irqs)
+ return;
+
+ /* 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)) {
+ if (!test_and_set_bit(irq_nr, ppc_lost_interrupts))
+ atomic_inc(&ppc_n_lost_interrupts);
+ }
+}
+
+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);
+}
+
+struct hw_interrupt_type pmac_pic = {
+ " PMAC-PIC ",
+ NULL,
+ NULL,
+ NULL,
+ pmac_unmask_irq,
+ pmac_mask_irq,
+ pmac_mask_and_ack_irq,
+ 0
+};
+
+struct hw_interrupt_type gatwick_pic = {
+ " GATWICK ",
+ NULL,
+ NULL,
+ NULL,
+ pmac_unmask_irq,
+ pmac_mask_irq,
+ pmac_mask_and_ack_irq,
+ 0
+};
+
+static void gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+ int irq, bits;
+
+ for (irq = max_irqs - 1; irq > max_real_irqs; irq -= 32) {
+ int i = irq >> 5;
+ bits = ld_le32(&pmac_irq_hw[i]->flag)
+ | ppc_lost_interrupts[i];
+ if (bits == 0)
+ continue;
+ irq -= cntlzw(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].ctl != &gatwick_pic )
+ printk("gatwick irq not from gatwick pic\n");
+ else
+ ppc_irq_dispatch_handler( regs, irq );
+}
+
+void
+pmac_do_IRQ(struct pt_regs *regs,
+ int cpu,
+ int isfake)
+{
+ int irq;
+ unsigned long bits = 0;
+
+#ifdef __SMP__
+ /* IPI's are a hack on the powersurge -- Cort */
+ if ( cpu != 0 )
+ {
+ if (!isfake)
+ {
+#ifdef CONFIG_XMON
+ static int xmon_2nd;
+ if (xmon_2nd)
+ xmon(regs);
+#endif
+ smp_message_recv();
+ goto out;
+ }
+ /* could be here due to a do_fake_interrupt call but we don't
+ mess with the controller from the second cpu -- Cort */
+ goto out;
+ }
+
+ {
+ unsigned int loops = MAXCOUNT;
+ while (test_bit(0, &global_irq_lock)) {
+ if (smp_processor_id() == global_irq_holder) {
+ printk("uh oh, interrupt while we hold global irq lock!\n");
+#ifdef CONFIG_XMON
+ xmon(0);
+#endif
+ break;
+ }
+ if (loops-- == 0) {
+ printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder);
+#ifdef CONFIG_XMON
+ xmon(0);
+#endif
+ }
+ }
+ }
+#endif /* __SMP__ */
+
+ for (irq = max_real_irqs - 1; irq > 0; irq -= 32) {
+ int i = irq >> 5;
+ bits = ld_le32(&pmac_irq_hw[i]->flag)
+ | ppc_lost_interrupts[i];
+ if (bits == 0)
+ continue;
+ irq -= cntlzw(bits);
+ break;
+ }
+
+ if (irq < 0)
+ {
+ printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
+ irq, regs->nip);
+ ppc_spurious_interrupts++;
+ }
+ else
+ {
+ ppc_irq_dispatch_handler( regs, irq );
+ }
+#ifdef CONFIG_SMP
+out:
+#endif /* CONFIG_SMP */
+}
+
+/* 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);
+ }
+}
+
+__initfunc(void
+pmac_pic_init(void))
+{
+ int i;
+ struct device_node *irqctrler;
+ unsigned long addr;
+ int second_irq = -999;
+
+
+ /* G3 powermacs have 64 interrupts, G3 Series PowerBook have 128,
+ others have 32 */
+ max_irqs = max_real_irqs = 32;
+ irqctrler = find_devices("mac-io");
+ if (irqctrler)
+ {
+ max_real_irqs = 64;
+ if (irqctrler->next)
+ max_irqs = 128;
+ else
+ max_irqs = 64;
+ }
+ for ( i = 0; i < max_real_irqs ; i++ )
+ irq_desc[i].ctl = &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) ? irqctrler->next : NULL;
+ if (irqctrler && irqctrler->n_addrs > 0) {
+ addr = (unsigned long)
+ ioremap(irqctrler->addrs[0].address, 0x40);
+ for (i = 2; i < 4; ++i)
+ pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
+ (addr + (4 - i) * 0x10);
+ }
+ }
+
+ /* disable all interrupts in all controllers */
+ for (i = 0; i * 32 < max_irqs; ++i)
+ out_le32(&pmac_irq_hw[i]->enable, 0);
+
+ /* get interrupt line of secondary interrupt controller */
+ if (irqctrler) {
+ second_irq = irqctrler->intrs[0].line;
+ printk(KERN_INFO "irq: secondary controller on irq %d\n",
+ (int)second_irq);
+ if (device_is_compatible(irqctrler, "gatwick"))
+ pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs);
+ for ( i = max_real_irqs ; i < max_irqs ; i++ )
+ irq_desc[i].ctl = &gatwick_pic;
+ request_irq( second_irq, gatwick_action, SA_INTERRUPT,
+ "gatwick 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 */
+}
diff --git a/arch/ppc/kernel/pmac_pic.h b/arch/ppc/kernel/pmac_pic.h
new file mode 100644
index 000000000..335a9ef69
--- /dev/null
+++ b/arch/ppc/kernel/pmac_pic.h
@@ -0,0 +1,15 @@
+#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);
+void pmac_do_IRQ(struct pt_regs *regs,
+ int cpu,
+ int isfake);
+
+
+#endif /* _PPC_KERNEL_PMAC_PIC_H */
+
diff --git a/arch/ppc/kernel/pmac_setup.c b/arch/ppc/kernel/pmac_setup.c
index 499e8b6a5..9f8638021 100644
--- a/arch/ppc/kernel/pmac_setup.c
+++ b/arch/ppc/kernel/pmac_setup.c
@@ -44,6 +44,7 @@
#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/adb.h>
@@ -52,10 +53,44 @@
#include <asm/ohare.h>
#include <asm/mediabay.h>
#include <asm/feature.h>
+#include <asm/ide.h>
+#include <asm/machdep.h>
+
#include "time.h"
+#include "local_irq.h"
+#include "pmac_pic.h"
+
+#undef SHOW_GATWICK_IRQS
+
+unsigned long pmac_get_rtc_time(void);
+int pmac_set_rtc_time(unsigned long nowtime);
+void pmac_read_rtc_time(void);
+void pmac_calibrate_decr(void);
+void pmac_setup_pci_ptrs(void);
+
+extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int mackbd_getkeycode(unsigned int scancode);
+extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode);
+extern char mackbd_unexpected_up(unsigned char keycode);
+extern void mackbd_leds(unsigned char leds);
+extern void mackbd_init_hw(void);
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned char mackbd_sysrq_xlate[128];
+#endif /* CONFIG_MAGIC_SYSRQ */
+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);
unsigned char drive_info;
+int ppc_override_l2cr = 0;
+int ppc_override_l2cr_value;
+
extern char saved_command_line[];
#define DEFAULT_ROOT_DEVICE 0x0801 /* sda1 - slightly silly choice */
@@ -132,6 +167,16 @@ pmac_get_cpuinfo(char *buffer)
}
}
+ /* Checks "l2cr-value" property in the registry */
+ np = find_devices("cpus");
+ if (np != 0) {
+ unsigned int *l2cr = (unsigned int *)
+ get_property(np, "l2cr-value", NULL);
+ if (l2cr != 0) {
+ len += sprintf(buffer+len, "l2cr override\t: 0x%x\n", *l2cr);
+ }
+ }
+
return len;
}
@@ -210,6 +255,26 @@ pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p))
*memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p);
+ /* Checks "l2cr-value" property in the registry */
+ if ( (_get_PVR() >> 16) == 8) {
+ struct device_node *np = find_devices("cpus");
+ 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");
+
feature_init();
#ifdef CONFIG_KGDB
@@ -258,15 +323,12 @@ int boot_target;
int boot_part;
kdev_t boot_dev;
-void __init powermac_init(void)
+__initfunc(void
+pmac_init2(void))
{
- if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
- return;
adb_init();
pmac_nvram_init();
- if (_machine == _MACH_Pmac) {
- media_bay_init();
- }
+ media_bay_init();
}
#ifdef CONFIG_SCSI
@@ -371,3 +433,174 @@ void note_bootable_part(kdev_t dev, int part)
}
}
+void
+pmac_restart(char *cmd)
+{
+ struct adb_request req;
+
+ switch (adb_hardware) {
+ case ADB_VIACUDA:
+ cuda_request(&req, NULL, 2, CUDA_PACKET,
+ CUDA_RESET_SYSTEM);
+ for (;;)
+ cuda_poll();
+ break;
+
+ case ADB_VIAPMU:
+ pmu_restart();
+ break;
+ default:
+ }
+}
+
+void
+pmac_power_off(void)
+{
+ struct adb_request req;
+
+ switch (adb_hardware) {
+ case ADB_VIACUDA:
+ cuda_request(&req, NULL, 2, CUDA_PACKET,
+ CUDA_POWERDOWN);
+ for (;;)
+ cuda_poll();
+ break;
+
+ case ADB_VIAPMU:
+ pmu_shutdown();
+ break;
+ default:
+ }
+}
+
+void
+pmac_halt(void)
+{
+ pmac_power_off();
+}
+
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+void
+pmac_ide_insw(ide_ioreg_t port, void *buf, int ns)
+{
+ ide_insw(port, buf, ns);
+}
+
+void
+pmac_ide_outsw(ide_ioreg_t port, void *buf, int ns)
+{
+ ide_outsw(port, buf, ns);
+}
+
+int
+pmac_ide_default_irq(ide_ioreg_t base)
+{
+ return 0;
+}
+
+ide_ioreg_t
+pmac_ide_default_io_base(int index)
+{
+#if defined(CONFIG_BLK_DEV_IDE_PMAC)
+ return pmac_ide_regbase[index];
+#else
+ return 0;
+#endif
+}
+
+int
+pmac_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+ return 0;
+}
+
+void
+pmac_ide_request_region(ide_ioreg_t from,
+ unsigned int extent,
+ const char *name)
+{
+}
+
+void
+pmac_ide_release_region(ide_ioreg_t from,
+ unsigned int extent)
+{
+}
+
+/* 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
+ * endian...)
+ *
+ * Changes to linux/hdreg.h may require changes here. */
+void
+pmac_ide_fix_driveid(struct hd_driveid *id)
+{
+ ppc_generic_ide_fix_driveid(id);
+}
+
+/* This is declared in drivers/block/ide-pmac.c */
+void pmac_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq);
+#endif
+
+__initfunc(void
+pmac_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7))
+{
+ pmac_setup_pci_ptrs();
+
+ /* 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.setup_residual = NULL;
+ ppc_md.get_cpuinfo = pmac_get_cpuinfo;
+ ppc_md.irq_cannonicalize = NULL;
+ ppc_md.init_IRQ = pmac_pic_init;
+ ppc_md.do_IRQ = pmac_do_IRQ;
+ ppc_md.init = pmac_init2;
+
+ ppc_md.restart = pmac_restart;
+ ppc_md.power_off = pmac_power_off;
+ ppc_md.halt = pmac_halt;
+
+ ppc_md.time_init = NULL;
+ 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;
+
+#if defined(CONFIG_VT) && defined(CONFIG_MAC_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.kbd_sysrq_xlate = mackbd_sysrq_xlate;
+#endif
+#endif
+
+#if defined(CONFIG_BLK_DEV_IDE_PMAC)
+ ppc_ide_md.insw = pmac_ide_insw;
+ ppc_ide_md.outsw = pmac_ide_outsw;
+ ppc_ide_md.default_irq = pmac_ide_default_irq;
+ ppc_ide_md.default_io_base = pmac_ide_default_io_base;
+ ppc_ide_md.check_region = pmac_ide_check_region;
+ ppc_ide_md.request_region = pmac_ide_request_region;
+ ppc_ide_md.release_region = pmac_ide_release_region;
+ ppc_ide_md.fix_driveid = pmac_ide_fix_driveid;
+ ppc_ide_md.ide_init_hwif = pmac_ide_init_hwif_ports;
+
+ ppc_ide_md.io_base = 0;
+#endif
+}
+
diff --git a/arch/ppc/kernel/ppc8xx_pic.c b/arch/ppc/kernel/ppc8xx_pic.c
new file mode 100644
index 000000000..87bc6d0f8
--- /dev/null
+++ b/arch/ppc/kernel/ppc8xx_pic.c
@@ -0,0 +1,49 @@
+
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <asm/irq.h>
+#include <asm/8xx_immap.h>
+#include <asm/mbx.h>
+#include "ppc8xx_pic.h"
+
+
+static void mbx_mask_irq(unsigned int irq_nr)
+{
+ if ( irq_nr == ISA_BRIDGE_INT ) return;
+ if ( irq_nr >= ppc8xx_pic.irq_offset )
+ irq_nr -= ppc8xx_pic.irq_offset;
+ ppc_cached_irq_mask[0] &= ~(1 << (31-irq_nr));
+ ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = ppc_cached_irq_mask[0];
+}
+
+static void mbx_unmask_irq(unsigned int irq_nr)
+{
+ if ( irq_nr >= ppc8xx_pic.irq_offset )
+ irq_nr -= ppc8xx_pic.irq_offset;
+ ppc_cached_irq_mask[0] |= (1 << (31-irq_nr));
+ ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = ppc_cached_irq_mask[0];
+}
+
+static void mbx_mask_and_ack(unsigned int irq_nr)
+{
+ /* this shouldn't be masked, we mask the 8259 if we need to -- Cort */
+ if ( irq_nr != ISA_BRIDGE_INT )
+ mbx_mask_irq(irq_nr);
+ if ( irq_nr >= ppc8xx_pic.irq_offset )
+ irq_nr -= ppc8xx_pic.irq_offset;
+ /* clear the pending bits */
+ ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend = 1 << (31-irq_nr);
+}
+
+struct hw_interrupt_type ppc8xx_pic = {
+ " 8xx SIU ",
+ NULL,
+ NULL,
+ NULL,
+ mbx_unmask_irq,
+ mbx_mask_irq,
+ mbx_mask_and_ack,
+ 0
+};
diff --git a/arch/ppc/kernel/ppc8xx_pic.h b/arch/ppc/kernel/ppc8xx_pic.h
new file mode 100644
index 000000000..d6b424fec
--- /dev/null
+++ b/arch/ppc/kernel/ppc8xx_pic.h
@@ -0,0 +1,9 @@
+
+#ifndef _PPC_KERNEL_PPC8xx_H
+#define _PPC_KERNEL_PPC8xx_H
+
+#include "local_irq.h"
+
+extern struct hw_interrupt_type ppc8xx_pic;
+
+#endif /* _PPC_KERNEL_PPC8xx_H */
diff --git a/arch/ppc/kernel/ppc_defs.h b/arch/ppc/kernel/ppc_defs.h
deleted file mode 100644
index 83315a2ae..000000000
--- a/arch/ppc/kernel/ppc_defs.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * WARNING! This file is automatically generated - DO NOT EDIT!
- */
-#define KERNELBASE -1073741824
-#define STATE 0
-#define NEXT_TASK 48
-#define COUNTER 24
-#define PROCESSOR 36
-#define SIGPENDING 8
-#define TSS 568
-#define MM 872
-#define TASK_STRUCT_SIZE 912
-#define KSP 0
-#define PG_TABLES 4
-#define PGD 8
-#define LAST_SYSCALL 20
-#define PT_REGS 12
-#define PF_TRACESYS 32
-#define TASK_FLAGS 4
-#define NEED_RESCHED 20
-#define TSS_FPR0 24
-#define TSS_FPSCR 284
-#define TSS_SMP_FORK_RET 288
-#define TASK_UNION_SIZE 8192
-#define STACK_FRAME_OVERHEAD 16
-#define INT_FRAME_SIZE 192
-#define GPR0 16
-#define GPR1 20
-#define GPR2 24
-#define GPR3 28
-#define GPR4 32
-#define GPR5 36
-#define GPR6 40
-#define GPR7 44
-#define GPR8 48
-#define GPR9 52
-#define GPR10 56
-#define GPR11 60
-#define GPR12 64
-#define GPR13 68
-#define GPR14 72
-#define GPR15 76
-#define GPR16 80
-#define GPR17 84
-#define GPR18 88
-#define GPR19 92
-#define GPR20 96
-#define GPR21 100
-#define GPR22 104
-#define GPR23 108
-#define GPR24 112
-#define GPR25 116
-#define GPR26 120
-#define GPR27 124
-#define GPR28 128
-#define GPR29 132
-#define GPR30 136
-#define GPR31 140
-#define _NIP 144
-#define _MSR 148
-#define _CTR 156
-#define _LINK 160
-#define _CCR 168
-#define _XER 164
-#define _DAR 180
-#define _DSISR 184
-#define ORIG_GPR3 152
-#define RESULT 188
-#define TRAP 176
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index 1b7753dd0..834bdf102 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -8,11 +8,12 @@
#include <linux/vt_kern.h>
#include <linux/nvram.h>
+#include <asm/page.h>
#include <asm/semaphore.h>
#include <asm/processor.h>
#include <asm/uaccess.h>
-#include <asm/ide.h>
#include <asm/io.h>
+#include <asm/ide.h>
#include <asm/atomic.h>
#include <asm/bitops.h>
#include <asm/checksum.h>
@@ -26,6 +27,8 @@
#include <asm/irq.h>
#include <asm/feature.h>
#include <asm/spinlock.h>
+#include <asm/dma.h>
+#include <asm/machdep.h>
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>
@@ -39,13 +42,14 @@ extern void AlignmentException(struct pt_regs *regs);
extern void ProgramCheckException(struct pt_regs *regs);
extern void SingleStepException(struct pt_regs *regs);
extern int sys_sigreturn(struct pt_regs *regs);
-extern atomic_t n_lost_interrupts;
+extern atomic_t ppc_n_lost_interrupts;
extern void do_lost_interrupts(unsigned long);
extern int do_signal(sigset_t *, struct pt_regs *);
asmlinkage long long __ashrdi3(long long, int);
asmlinkage int abs(int);
+EXPORT_SYMBOL(clear_page);
EXPORT_SYMBOL(do_signal);
EXPORT_SYMBOL(syscall_trace);
EXPORT_SYMBOL(transfer_to_handler);
@@ -57,16 +61,21 @@ EXPORT_SYMBOL(AlignmentException);
EXPORT_SYMBOL(ProgramCheckException);
EXPORT_SYMBOL(SingleStepException);
EXPORT_SYMBOL(sys_sigreturn);
-EXPORT_SYMBOL(n_lost_interrupts);
+EXPORT_SYMBOL(ppc_n_lost_interrupts);
EXPORT_SYMBOL(do_lost_interrupts);
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
-EXPORT_SYMBOL(local_irq_count);
-EXPORT_SYMBOL(local_bh_count);
+EXPORT_SYMBOL(ppc_local_irq_count);
+EXPORT_SYMBOL(ppc_local_bh_count);
EXPORT_SYMBOL(isa_io_base);
EXPORT_SYMBOL(isa_mem_base);
EXPORT_SYMBOL(pci_dram_offset);
+EXPORT_SYMBOL(ISA_DMA_THRESHOLD);
+EXPORT_SYMBOL(DMA_MODE_READ);
+EXPORT_SYMBOL(DMA_MODE_WRITE);
+EXPORT_SYMBOL(_prep_type);
+EXPORT_SYMBOL(ucSystemType);
EXPORT_SYMBOL(atomic_add);
EXPORT_SYMBOL(atomic_sub);
@@ -155,6 +164,7 @@ EXPORT_SYMBOL(_enable_interrupts);
EXPORT_SYMBOL(flush_instruction_cache);
EXPORT_SYMBOL(_get_PVR);
EXPORT_SYMBOL(giveup_fpu);
+EXPORT_SYMBOL(enable_kernel_fp);
EXPORT_SYMBOL(flush_icache_range);
EXPORT_SYMBOL(xchg_u32);
#ifdef __SMP__
@@ -171,18 +181,14 @@ EXPORT_SYMBOL(_write_lock);
EXPORT_SYMBOL(_write_unlock);
#endif
-#ifndef CONFIG_MACH_SPECIFIC
EXPORT_SYMBOL(_machine);
-#endif
+EXPORT_SYMBOL(ppc_md);
EXPORT_SYMBOL(adb_request);
-EXPORT_SYMBOL(adb_autopoll);
EXPORT_SYMBOL(adb_register);
EXPORT_SYMBOL(cuda_request);
-EXPORT_SYMBOL(cuda_send_request);
EXPORT_SYMBOL(cuda_poll);
EXPORT_SYMBOL(pmu_request);
-EXPORT_SYMBOL(pmu_send_request);
EXPORT_SYMBOL(pmu_poll);
#ifdef CONFIG_PMAC_PBOOK
EXPORT_SYMBOL(sleep_notifier_list);
@@ -194,7 +200,6 @@ EXPORT_SYMBOL(find_compatible_devices);
EXPORT_SYMBOL(find_path_device);
EXPORT_SYMBOL(find_phandle);
EXPORT_SYMBOL(get_property);
-EXPORT_SYMBOL(device_is_compatible);
EXPORT_SYMBOL(pci_io_base);
EXPORT_SYMBOL(pci_device_loc);
EXPORT_SYMBOL(feature_set);
@@ -209,9 +214,8 @@ EXPORT_SYMBOL(nvram_read_byte);
EXPORT_SYMBOL(nvram_write_byte);
#endif /* CONFIG_PMAC */
-#ifdef CONFIG_SOUND_MODULE
EXPORT_SYMBOL(abs);
-#endif
+EXPORT_SYMBOL(device_is_compatible);
/* The following are special because they're not called
explicitly (the C compiler generates them). Fortunately,
diff --git a/arch/ppc/kernel/prep_nvram.c b/arch/ppc/kernel/prep_nvram.c
new file mode 100644
index 000000000..e69563c8a
--- /dev/null
+++ b/arch/ppc/kernel/prep_nvram.c
@@ -0,0 +1,173 @@
+/*
+ * linux/arch/ppc/kernel/prep_nvram.c
+ *
+ * Copyright (C) 1998 Corey Minyard
+ *
+ */
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/machdep.h>
+#include <asm/prep_nvram.h>
+
+/*
+ * Allow for a maximum of 32K of PReP NvRAM data
+ */
+#define MAX_PREP_NVRAM 0x8000
+static char nvramData[MAX_PREP_NVRAM];
+static NVRAM_MAP *nvram=(NVRAM_MAP *)&nvramData[0];
+
+#define PREP_NVRAM_AS0 0x74
+#define PREP_NVRAM_AS1 0x75
+#define PREP_NVRAM_DATA 0x77
+
+unsigned char *rs_pcNvRAM;
+
+unsigned char prep_nvram_read_val(int addr)
+{
+ outb(addr, PREP_NVRAM_AS0);
+ outb(addr>>8, PREP_NVRAM_AS1);
+ return inb(PREP_NVRAM_DATA);
+}
+
+void 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);
+}
+
+/*
+ * Most Radstone boards have NvRAM memory mapped at offset 8M in ISA space
+ */
+unsigned char rs_nvram_read_val(int addr)
+{
+ return rs_pcNvRAM[addr];
+}
+
+void rs_nvram_write_val(int addr,
+ unsigned char val)
+{
+ rs_pcNvRAM[addr]=val;
+}
+
+__initfunc(void init_prep_nvram(void))
+{
+ unsigned char *nvp;
+ int i;
+ int nvramSize;
+
+ /*
+ * I'm making the assumption that 32k will always cover the
+ * nvramsize. If this isn't the case please let me know and we can
+ * map the header, then get the size from the header, then map
+ * the whole size. -- Cort
+ */
+ if ( _prep_type == _PREP_Radstone )
+ rs_pcNvRAM = (unsigned char *)ioremap(_ISA_MEM_BASE+0x00800000,
+ 32<<10);
+ request_region(PREP_NVRAM_AS0, 0x8, "PReP NVRAM");
+ /*
+ * 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_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_nvram_first_var(void)
+{
+ if (nvram->Header.GELength == 0) {
+ return NULL;
+ } else {
+ return (((char *)nvram)
+ + ((unsigned int) nvram->Header.GEAddress));
+ }
+}
+
+__prep
+char *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
index b48f7a1fc..dd7f1eee1 100644
--- a/arch/ppc/kernel/prep_pci.c
+++ b/arch/ppc/kernel/prep_pci.c
@@ -1,5 +1,5 @@
/*
- * $Id: prep_pci.c,v 1.24 1998/12/10 02:39:51 cort Exp $
+ * $Id: prep_pci.c,v 1.33 1999/05/09 20:15:54 cort Exp $
* PReP pci functions.
* Originally by Gary Thomas
* rewritten and updated by Cort Dougan (cort@cs.nmt.edu)
@@ -11,11 +11,19 @@
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/openpic.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"
#define MAX_DEVNR 22
@@ -27,6 +35,9 @@ unsigned char *Motherboard_map_name;
/* How is the 82378 PIRQ mapping setup? */
unsigned char *Motherboard_routes;
+/* Used for Motorola to store system config register */
+static unsigned long *ProcInfo;
+
/* Tables for known hardware */
/* Motorola PowerStackII - Utah */
@@ -34,38 +45,39 @@ static char Utah_pci_IRQ_map[23] __prepdata =
{
0, /* Slot 0 - unused */
0, /* Slot 1 - unused */
- 4, /* Slot 2 - SCSI - NCR825A */
+ 5, /* Slot 2 - SCSI - NCR825A */
0, /* Slot 3 - unused */
1, /* Slot 4 - Ethernet - DEC2114x */
0, /* Slot 5 - unused */
- 2, /* Slot 6 - PCI Card slot #1 */
- 3, /* Slot 7 - PCI Card slot #2 */
- 4, /* Slot 8 - PCI Card slot #3 */
- 4, /* Slot 9 - PCI Bridge */
+ 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 */
- 4, /* Slot 12 - SCSI - NCR825A */
+ 5, /* Slot 12 - SCSI - NCR825A */
0, /* Slot 13 - unused */
- 2, /* Slot 14 - enet */
+ 3, /* Slot 14 - enet */
0, /* Slot 15 - unused */
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
+ 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 */
- 11, /* Line 2 */
- 14, /* Line 3 */
- 15, /* Line 4 */
+ 10, /* Line 2 */
+ 11, /* Line 3 */
+ 14, /* Line 4 */
+ 15, /* Line 5 */
};
/* Motorola PowerStackII - Omaha */
@@ -125,9 +137,9 @@ static char Blackhawk_pci_IRQ_map[19] __prepdata =
0, /* Slot 13 - unused */
1, /* Slot 14 - Ethernet */
0, /* Slot 15 - unused */
- 1, /* Slot P7 */
- 2, /* Slot P6 */
- 3, /* Slot P5 */
+ 1, /* Slot P7 */
+ 2, /* Slot P6 */
+ 3, /* Slot P5 */
};
static char Blackhawk_pci_IRQ_routes[] __prepdata =
@@ -139,6 +151,122 @@ static char Blackhawk_pci_IRQ_routes[] __prepdata =
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 - unxued */
+ 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 - unxued */
+ 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 =
{
@@ -169,8 +297,35 @@ static char Genesis_pci_IRQ_routes[] __prepdata =
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 - graphics on 3600 */
+ 9, /* Slot 16 - PMC */
+ 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[16] __prepdata =
+static char Comet_pci_IRQ_map[23] __prepdata =
{
0, /* Slot 0 - unused */
0, /* Slot 1 - unused */
@@ -188,6 +343,13 @@ static char Comet_pci_IRQ_map[16] __prepdata =
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 =
@@ -199,6 +361,43 @@ static char Comet_pci_IRQ_routes[] __prepdata =
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
@@ -312,22 +511,40 @@ static char Nobis_pci_IRQ_routes[] __prepdata = {
#define CAROLINA_IRQ_EDGE_MASK_LO 0x00 /* IRQ's 0-7 */
#define CAROLINA_IRQ_EDGE_MASK_HI 0xA4 /* IRQ's 8-15 [10,13,15] */
+/*
+ * 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)
+
__prep
int
prep_pcibios_read_config_dword (unsigned char bus,
unsigned char dev, unsigned char offset, unsigned int *val)
{
- unsigned long _val;
+ unsigned long _val;
unsigned long *ptr;
- dev >>= 3;
-
- if ((bus != 0) || (dev > MAX_DEVNR))
- {
+
+ if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
+ {
*val = 0xFFFFFFFF;
- return PCIBIOS_DEVICE_NOT_FOUND;
- } else
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ } else
{
- ptr = (unsigned long *)(0x80800000 | (1<<dev) | offset);
+ ptr = (unsigned long *)CFGPTR(dev);
_val = le32_to_cpu(*ptr);
}
*val = _val;
@@ -339,16 +556,16 @@ int
prep_pcibios_read_config_word (unsigned char bus,
unsigned char dev, unsigned char offset, unsigned short *val)
{
- unsigned short _val;
+ unsigned short _val;
unsigned short *ptr;
- dev >>= 3;
- if ((bus != 0) || (dev > MAX_DEVNR))
- {
- *val = (unsigned short)0xFFFFFFFF;
- return PCIBIOS_DEVICE_NOT_FOUND;
- } else
+
+ if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
+ {
+ *val = 0xFFFF;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ } else
{
- ptr = (unsigned short *)(0x80800000 | (1<<dev) | offset);
+ ptr = (unsigned short *)CFGPTR(dev);
_val = le16_to_cpu(*ptr);
}
*val = _val;
@@ -360,16 +577,16 @@ int
prep_pcibios_read_config_byte (unsigned char bus,
unsigned char dev, unsigned char offset, unsigned char *val)
{
- unsigned char _val;
- volatile unsigned char *ptr;
- dev >>= 3;
- if ((bus != 0) || (dev > MAX_DEVNR))
- {
- *(unsigned long *)val = (unsigned long) 0xFFFFFFFF;
- return PCIBIOS_DEVICE_NOT_FOUND;
- } else
+ unsigned char _val;
+ unsigned char *ptr;
+
+ if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
+ {
+ *val = 0xFF;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ } else
{
- ptr = (unsigned char *)(0x80800000 | (1<<dev) | (offset ^ 1));
+ ptr = (unsigned char *)CFGPTR(dev);
_val = *ptr;
}
*val = _val;
@@ -383,14 +600,14 @@ prep_pcibios_write_config_dword (unsigned char bus,
{
unsigned long _val;
unsigned long *ptr;
- dev >>= 3;
+
_val = le32_to_cpu(val);
- if ((bus != 0) || (dev > MAX_DEVNR))
+ if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
{
return PCIBIOS_DEVICE_NOT_FOUND;
} else
{
- ptr = (unsigned long *)(0x80800000 | (1<<dev) | offset);
+ ptr = (unsigned long *)CFGPTR(dev);
*ptr = _val;
}
return PCIBIOS_SUCCESSFUL;
@@ -403,14 +620,14 @@ prep_pcibios_write_config_word (unsigned char bus,
{
unsigned short _val;
unsigned short *ptr;
- dev >>= 3;
+
_val = le16_to_cpu(val);
- if ((bus != 0) || (dev > MAX_DEVNR))
+ if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
{
return PCIBIOS_DEVICE_NOT_FOUND;
} else
{
- ptr = (unsigned short *)(0x80800000 | (1<<dev) | offset);
+ ptr = (unsigned short *)CFGPTR(dev);
*ptr = _val;
}
return PCIBIOS_SUCCESSFUL;
@@ -423,20 +640,151 @@ prep_pcibios_write_config_byte (unsigned char bus,
{
unsigned char _val;
unsigned char *ptr;
- dev >>= 3;
+
_val = val;
- if ((bus != 0) || (dev > MAX_DEVNR))
+ if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
{
return PCIBIOS_DEVICE_NOT_FOUND;
} else
{
- ptr = (unsigned char *)(0x80800000 | (1<<dev) | (offset^1));
+ ptr = (unsigned char *)CFGPTR(dev);
*ptr = _val;
}
return PCIBIOS_SUCCESSFUL;
}
-__initfunc(unsigned long route_pci_interrupts(void))
+#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 prep_keybd_present = 1;
+int MotMPIC = 0;
+
+__initfunc(int 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 = 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 = NULL;
+ return 0;
+ }
+
+ /* Check the first PCI device to see if it is a Raven. */
+ pcibios_read_config_dword(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 = NULL;
+ return 0;
+ }
+
+
+ /* Read the memory base register. */
+ pcibios_read_config_dword(0, 0, PCI_BASE_ADDRESS_1, &pci_membase);
+
+ if (pci_membase == 0) {
+ OpenPIC = NULL;
+ return 0;
+ }
+
+ /* Map the Raven MPIC registers to virtual memory. */
+ OpenPIC = (struct OpenPIC *)ioremap(pci_membase+0xC0000000, 0x22000);
+
+ OpenPIC_InitSenses = mvme2600_openpic_initsenses;
+ OpenPIC_NumInitSenses = sizeof(mvme2600_openpic_initsenses);
+
+ /* If raven is present on Motorola store the system config register
+ * for later use.
+ */
+ ProcInfo = (unsigned long *)ioremap(0xfef80400, 4);
+
+ /* 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;
+} mot_info[] = {
+ {0x300, 0x00, 0x00, "MVME 2400", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x010, 0x00, 0x00, "Genesis", Genesis_pci_IRQ_map, Genesis_pci_IRQ_routes},
+ {0x020, 0x00, 0x00, "Powerstack (Series E)", Comet_pci_IRQ_map, Comet_pci_IRQ_routes},
+ {0x040, 0x00, 0x00, "Blackhawk (Powerstack)", Blackhawk_pci_IRQ_map, Blackhawk_pci_IRQ_routes},
+ {0x050, 0x00, 0x00, "Omaha (PowerStack II Pro3000)", Omaha_pci_IRQ_map, Omaha_pci_IRQ_routes},
+ {0x060, 0x00, 0x00, "Utah (Powerstack II Pro4000)", Utah_pci_IRQ_map, Utah_pci_IRQ_routes},
+ {0x0A0, 0x00, 0x00, "Powerstack (Series EX)", Comet2_pci_IRQ_map, Comet2_pci_IRQ_routes},
+ {0x1E0, 0xE0, 0x00, "Mesquite cPCI (MCP750)", Mesquite_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xE1, 0x00, "Sitka cPCI (MCPN750)", Sitka_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xE2, 0x00, "Mesquite cPCI (MCP750) w/ HAC", Mesquite_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xF6, 0x80, "MTX Plus", MTXplus_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xF6, 0x81, "Dual MTX Plus", MTXplus_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xF7, 0x80, "MTX wo/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xF7, 0x81, "Dual MTX wo/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xF8, 0x80, "MTX w/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xF8, 0x81, "Dual MTX w/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xF9, 0x00, "MVME 2300", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xFA, 0x00, "MVME 2300SC/2600", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xFB, 0x00, "MVME 2600 with MVME712M", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xFC, 0x00, "MVME 2600/2700 with MVME761", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xFD, 0x80, "MVME 3600 with MVME712M", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xFD, 0x81, "MVME 4600 with MVME712M", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xFE, 0x80, "MVME 3600 with MVME761", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xFE, 0x81, "MVME 4600 with MVME761", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xFF, 0x00, "MVME 1600-001 or 1600-011", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x000, 0x00, 0x00, "", NULL, NULL}
+};
+
+__initfunc(unsigned long prep_route_pci_interrupts(void))
{
unsigned char *ibc_pirq = (unsigned char *)0x80800860;
unsigned char *ibc_pcicon = (unsigned char *)0x80800840;
@@ -445,49 +793,66 @@ __initfunc(unsigned long route_pci_interrupts(void))
if ( _prep_type == _PREP_Motorola)
{
unsigned short irq_mode;
+ unsigned char cpu_type;
+ unsigned char base_mod;
+ int entry;
+ int mot_entry = -1;
- switch (inb(0x800) & 0xF0)
- {
- case 0x10: /* MVME16xx */
- Motherboard_map_name = "Genesis";
- Motherboard_map = Genesis_pci_IRQ_map;
- Motherboard_routes = Genesis_pci_IRQ_routes;
- break;
- case 0x20: /* Series E */
- Motherboard_map_name = "Powerstack (Series E)";
- Motherboard_map = Comet_pci_IRQ_map;
- Motherboard_routes = Comet_pci_IRQ_routes;
- break;
- case 0x50: /* PowerStackII Pro3000 */
- Motherboard_map_name = "Omaha (PowerStack II Pro3000)";
- Motherboard_map = Omaha_pci_IRQ_map;
- Motherboard_routes = Omaha_pci_IRQ_routes;
- break;
- case 0x60: /* PowerStackII Pro4000 */
- Motherboard_map_name = "Utah (Powerstack II Pro4000)";
- Motherboard_map = Utah_pci_IRQ_map;
- Motherboard_routes = Utah_pci_IRQ_routes;
- break;
- case 0xE0: /* MTX -- close enough?? to Genesis, so reuse it */
- Motherboard_map_name = "Motorola MTX";
- Motherboard_map = Genesis_pci_IRQ_map;
- Motherboard_routes = Genesis_pci_IRQ_routes;
- break;
- case 0x40: /* PowerStack */
- default: /* Can't hurt, can it? */
- Motherboard_map_name = "Blackhawk (Powerstack)";
- Motherboard_map = Blackhawk_pci_IRQ_map;
- Motherboard_routes = Blackhawk_pci_IRQ_routes;
- break;
+ 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;
+ }
}
- /* AJF adjust level/edge control according to routes */
- irq_mode = 0;
- for (i = 1; i <= 4; i++)
- {
- irq_mode |= ( 1 << Motherboard_routes[i] );
+
+ 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;
+
+ 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 );
}
- outb( irq_mode & 0xff, 0x4d0 );
- outb( (irq_mode >> 8) & 0xff, 0x4d1 );
} else if ( _prep_type == _PREP_IBM )
{
unsigned char pl_id;
@@ -526,6 +891,71 @@ __initfunc(unsigned long route_pci_interrupts(void))
outb(pl_id|CAROLINA_IRQ_EDGE_MASK_HI, 0x04d1);
pl_id=inb(0x04d1);
/*printk("Hi mask now %#0x\n", pl_id);*/
+ } else if ( _prep_type == _PREP_Radstone )
+ {
+ unsigned char ucElcrM, ucElcrS;
+
+ /*
+ * Set up edge/level
+ */
+ switch(ucSystemType)
+ {
+ case RS_SYS_TYPE_PPC1:
+ {
+ if(ucBoardRevMaj<5)
+ {
+ ucElcrS=ELCRS_INT15_LVL;
+ }
+ else
+ {
+ ucElcrS=ELCRS_INT9_LVL |
+ ELCRS_INT11_LVL |
+ ELCRS_INT14_LVL |
+ ELCRS_INT15_LVL;
+ }
+ ucElcrM=ELCRM_INT5_LVL | ELCRM_INT7_LVL;
+ break;
+ }
+
+ case RS_SYS_TYPE_PPC1a:
+ {
+ ucElcrS=ELCRS_INT9_LVL |
+ ELCRS_INT11_LVL |
+ ELCRS_INT14_LVL |
+ ELCRS_INT15_LVL;
+ ucElcrM=ELCRM_INT5_LVL;
+ break;
+ }
+
+ case RS_SYS_TYPE_PPC2:
+ case RS_SYS_TYPE_PPC2a:
+ case RS_SYS_TYPE_PPC2ep:
+ case RS_SYS_TYPE_PPC4:
+ case RS_SYS_TYPE_PPC4a:
+ default:
+ {
+ ucElcrS=ELCRS_INT9_LVL |
+ ELCRS_INT10_LVL |
+ ELCRS_INT11_LVL |
+ ELCRS_INT14_LVL |
+ ELCRS_INT15_LVL;
+ ucElcrM=ELCRM_INT5_LVL |
+ ELCRM_INT7_LVL;
+ break;
+ }
+ }
+
+ /*
+ * Write edge/level selection
+ */
+ outb(ucElcrS, ISA8259_S_ELCR);
+ outb(ucElcrM, ISA8259_M_ELCR);
+
+ /*
+ * Radstone boards have PCI interrupts all set up
+ * so leave well alone
+ */
+ return 0;
} else
{
printk("No known machine pci routing!\n");
@@ -542,3 +972,117 @@ __initfunc(unsigned long route_pci_interrupts(void))
return 0;
}
+__initfunc(
+void
+prep_pcibios_fixup(void))
+{
+ struct pci_dev *dev;
+ extern unsigned char *Motherboard_map;
+ extern unsigned char *Motherboard_routes;
+ unsigned char i;
+
+ if ( _prep_type == _PREP_Radstone )
+ {
+ printk("Radstone boards require no PCI fixups\n");
+ return;
+ }
+
+ prep_route_pci_interrupts();
+
+ printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name);
+ if (OpenPIC) {
+ /* PCI interrupts are controlled by the OpenPIC */
+ for(dev=pci_devices; dev; dev=dev->next) {
+ 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_PIN, dev->irq);
+ }
+ }
+ return;
+ }
+
+ for(dev=pci_devices; dev; dev=dev->next)
+ {
+ /*
+ * Use our old hard-coded kludge to figure out what
+ * irq this device uses. This is necessary on things
+ * without residual data. -- Cort
+ */
+ unsigned char d = PCI_SLOT(dev->devfn);
+ dev->irq = Motherboard_routes[Motherboard_map[d]];
+
+ for ( i = 0 ; i <= 5 ; i++ )
+ {
+ if ( dev->base_address[i] > 0x10000000 )
+ {
+ printk("Relocating PCI address %lx -> %lx\n",
+ dev->base_address[i],
+ (dev->base_address[i] & 0x00FFFFFF)
+ | 0x01000000);
+ dev->base_address[i] =
+ (dev->base_address[i] & 0x00FFFFFF) | 0x01000000;
+ pci_write_config_dword(dev,
+ PCI_BASE_ADDRESS_0+(i*0x4),
+ dev->base_address[i] );
+ }
+ }
+#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
+ }
+}
+
+decl_config_access_method(indirect);
+
+__initfunc(
+void
+prep_setup_pci_ptrs(void))
+{
+ PPC_DEVICE *hostbridge;
+
+ printk("PReP architecture\n");
+ if ( _prep_type == _PREP_Radstone )
+ {
+ pci_config_address = (unsigned *)0x80000cf8;
+ pci_config_data = (char *)0x80000cfc;
+ set_config_access_method(indirect);
+ }
+ else
+ {
+ hostbridge = residual_find_device(PROCESSORDEVICE, NULL,
+ BridgeController, PCIBridge, -1, 0);
+ if (hostbridge &&
+ hostbridge->DeviceId.Interface == PCIBridgeIndirect) {
+ PnP_TAG_PACKET * pkt;
+ set_config_access_method(indirect);
+ pkt = PnP_find_large_vendor_packet(
+ res->DevicePnPHeap+hostbridge->AllocatedOffset,
+ 3, 0);
+ if(pkt)
+ {
+#define p pkt->L4_Pack.L4_Data.L4_PPCPack
+ pci_config_address= (unsigned *)ld_le32((unsigned *) p.PPCData);
+ pci_config_data= (unsigned char *)ld_le32((unsigned *) (p.PPCData+8));
+ }
+ else
+ {
+ pci_config_address= (unsigned *) 0x80000cf8;
+ pci_config_data= (unsigned char *) 0x80000cfc;
+ }
+ }
+ else
+ {
+ set_config_access_method(prep);
+ }
+
+ }
+
+ ppc_md.pcibios_fixup = prep_pcibios_fixup;
+}
+
diff --git a/arch/ppc/kernel/prep_setup.c b/arch/ppc/kernel/prep_setup.c
index 72752e11f..de18f465a 100644
--- a/arch/ppc/kernel/prep_setup.c
+++ b/arch/ppc/kernel/prep_setup.c
@@ -30,6 +30,9 @@
#include <linux/blk.h>
#include <linux/ioport.h>
#include <linux/console.h>
+#include <linux/timex.h>
+#include <linux/pci.h>
+#include <linux/openpic.h>
#include <asm/mmu.h>
#include <asm/processor.h>
@@ -38,12 +41,57 @@
#include <asm/pgtable.h>
#include <asm/ide.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 "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 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 prep_setup_pci_ptrs(void);
+extern void chrp_do_IRQ(struct pt_regs *regs, int cpu, int isfake);
+extern char saved_command_line[256];
+
+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 */
@@ -54,13 +102,15 @@ extern PTE *Hash, *Hash_end;
extern unsigned long Hash_size, Hash_mask;
extern int probingmem;
extern unsigned long loops_per_sec;
-extern unsigned char aux_device_present;
#ifdef CONFIG_BLK_DEV_RAM
extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */
extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */
extern int rd_image_start; /* starting block # of image */
#endif
+#ifdef CONFIG_VGA_CONSOLE
+unsigned long vgacon_remap_base;
+#endif
__prep
int
@@ -136,6 +186,8 @@ prep_get_cpuinfo(char *buffer)
break;
}
break;
+ default:
+ break;
}
@@ -163,11 +215,12 @@ prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
{
extern char cmd_line[];
unsigned char reg;
+ unsigned char ucMothMemType;
+ unsigned char ucEquipPres1;
/* init to some ~sane value until calibrate_delay() runs */
loops_per_sec = 50000000;
- aux_device_present = 0xaa;
/* Set up floppy in PS/2 mode */
outb(0x09, SIO_CONFIG_RA);
reg = inb(SIO_CONFIG_RD);
@@ -175,20 +228,78 @@ prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
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;
ROOT_DEV = to_kdev_t(0x0801); /* sda1 */
break;
+ case _PREP_Radstone:
+ ROOT_DEV = to_kdev_t(0x0801); /* sda1 */
+
+ /*
+ * Determine system type
+ */
+ ucMothMemType=inb(0x866);
+ ucEquipPres1=inb(0x80c);
+
+ ucSystemType=((ucMothMemType&0x03)<<1) |
+ ((ucEquipPres1&0x80)>>7);
+ ucSystemType^=7;
+
+ /*
+ * Determine board revision for use by
+ * rev. specific code
+ */
+ ucBoardRev=inb(0x854);
+ ucBoardRevMaj=ucBoardRev>>5;
+ ucBoardRevMin=ucBoardRev&0x1f;
+
+ /*
+ * Most Radstone boards have memory mapped NvRAM
+ */
+ if((ucSystemType==RS_SYS_TYPE_PPC1) && (ucBoardRevMaj<5))
+ {
+ ppc_md.nvram_read_val = prep_nvram_read_val;
+ ppc_md.nvram_write_val = prep_nvram_write_val;
+ }
+ else
+ {
+ ppc_md.nvram_read_val = rs_nvram_read_val;
+ ppc_md.nvram_write_val = rs_nvram_write_val;
+ }
+ break;
}
- /* Enable L2. Assume we don't need to flush -- Cort*/
- *(unsigned char *)(0x8000081c) = *(unsigned char *)(0x8000081c)|3;
-
+ /* 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);
+ }
+ }
+
printk("Boot arguments: %s\n", cmd_line);
#ifdef CONFIG_SOUND_CS4232
@@ -238,12 +349,349 @@ prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
request_region(0x80,0x10,"dma page reg");
request_region(0xc0,0x20,"dma2");
+ raven_init();
+
#ifdef CONFIG_VGA_CONSOLE
+ /* remap the VGA memory */
+ vgacon_remap_base = 0xf0000000;
+ /*vgacon_remap_base = ioremap(0xc0000000, 0xba000);*/
conswitchp = &vga_con;
#endif
}
-__initfunc(void prep_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq))
+/*
+ * 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.
+ */
+__initfunc(void prep_res_calibrate_decr(void))
+{
+ int freq, divisor;
+
+ freq = res->VitalProductData.ProcessorBusHz;
+ divisor = 4;
+ printk("time_init: decrementer frequency = %d/%d\n", freq, divisor);
+ decrementer_count = freq / HZ / divisor;
+ count_period_num = divisor;
+ count_period_den = freq / 1000000;
+}
+
+/*
+ * 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
+ */
+int calibrate_done = 0;
+volatile int *done_ptr = &calibrate_done;
+
+__initfunc(void
+prep_calibrate_decr_handler(int irq,
+ void *dev,
+ struct pt_regs *regs))
+{
+ unsigned long freq, divisor;
+ static unsigned long t1 = 0, t2 = 0;
+
+ if ( !t1 )
+ t1 = get_dec();
+ else if (!t2)
+ {
+ t2 = get_dec();
+ t2 = t1-t2; /* decr's in 1/HZ */
+ t2 = t2*HZ; /* # decrs in 1s - thus in Hz */
+ freq = t2 * 60; /* try to make freq/1e6 an integer */
+ divisor = 60;
+ printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n",
+ freq, divisor,t2>>20);
+ decrementer_count = freq / HZ / divisor;
+ count_period_num = divisor;
+ count_period_den = freq / 1000000;
+ *done_ptr = 1;
+ }
+}
+
+__initfunc(void prep_calibrate_decr(void))
+{
+ 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();
+ while ( ! *done_ptr ) /* nothing */; /* wait for calibrate */
+ restore_flags(flags);
+ free_irq( 0, NULL);
+}
+
+
+/* We use the NVRAM RTC to time a second to calibrate the decrementer. */
+__initfunc(void mk48t59_calibrate_decr(void))
+{
+ unsigned long freq, divisor;
+ unsigned long t1, t2;
+ 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);
+ for (i = 0 ; i < 1000000 ; i++) { /* may take up to 1 second... */
+ if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) {
+ break;
+ }
+ }
+ t1 = get_dec();
+
+ sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
+ for (i = 0 ; i < 1000000 ; i++) { /* Should take up 1 second... */
+ if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) {
+ break;
+ }
+ }
+
+ t2 = t1 - get_dec();
+
+ freq = t2 * 60; /* try to make freq/1e6 an integer */
+ divisor = 60;
+ printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n",
+ freq, divisor,t2>>20);
+ decrementer_count = freq / HZ / divisor;
+ count_period_num = divisor;
+ count_period_den = freq / 1000000;
+}
+
+void
+prep_restart(char *cmd)
+{
+ unsigned long i = 10000;
+
+
+ _disable_interrupts();
+
+ /* 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");
+}
+
+/*
+ * This function will restart a board regardless of port 92 functionality
+ */
+void
+prep_direct_restart(char *cmd)
+{
+ u32 jumpaddr=0xfff00100;
+ u32 defaultmsr=MSR_IP;
+
+ /*
+ * This will ALWAYS work regardless of port 92
+ * functionality
+ */
+ _disable_interrupts();
+
+ __asm__ __volatile__("\n\
+ mtspr 26, %1 /* SRR0 */
+ mtspr 27, %0 /* SRR1 */
+ rfi"
+ :
+ : "r" (defaultmsr), "r" (jumpaddr));
+ /*
+ * Not reached
+ */
+}
+
+void
+prep_halt(void)
+{
+ unsigned long flags;
+ _disable_interrupts();
+ /* 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
+ */
+}
+
+void
+prep_power_off(void)
+{
+ prep_halt();
+}
+
+int prep_setup_residual(char *buffer)
+{
+ int len = 0;
+
+
+ /* PREP's without residual data will give incorrect values here */
+ len += sprintf(len+buffer, "clock\t\t: ");
+ if ( res->ResidualLength )
+ len += sprintf(len+buffer, "%ldMHz\n",
+ (res->VitalProductData.ProcessorHz > 1024) ?
+ res->VitalProductData.ProcessorHz>>20 :
+ res->VitalProductData.ProcessorHz);
+ else
+ len += sprintf(len+buffer, "???\n");
+
+ return len;
+}
+
+u_int
+prep_irq_cannonicalize(u_int irq)
+{
+ if (irq == 2)
+ {
+ return 9;
+ }
+ else
+ {
+ return irq;
+ }
+}
+
+void
+prep_do_IRQ(struct pt_regs *regs, int cpu, int isfake)
+{
+ int irq;
+
+ if ( (irq = i8259_irq(0)) < 0 )
+ {
+ printk(KERN_DEBUG "Bogus interrupt from PC = %lx\n",
+ regs->nip);
+ ppc_spurious_interrupts++;
+ return;
+ }
+ ppc_irq_dispatch_handler( regs, irq );
+}
+
+__initfunc(void
+prep_init_IRQ(void))
+{
+ int i;
+
+ if (OpenPIC != NULL) {
+ for ( i = 16 ; i < 36 ; i++ )
+ irq_desc[i].ctl = &open_pic;
+ openpic_init(1);
+ }
+
+ for ( i = 0 ; i < 16 ; i++ )
+ irq_desc[i].ctl = &i8259_pic;
+ i8259_init();
+#ifdef __SMP__
+ request_irq(openpic_to_irq(OPENPIC_VEC_SPURIOUS), openpic_ipi_action,
+ 0, "IPI0", 0);
+#endif /* __SMP__ */
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+void
+prep_ide_insw(ide_ioreg_t port, void *buf, int ns)
+{
+ _insw((unsigned short *)((port)+_IO_BASE), buf, ns);
+}
+
+void
+prep_ide_outsw(ide_ioreg_t port, void *buf, int ns)
+{
+ _outsw((unsigned short *)((port)+_IO_BASE), buf, ns);
+}
+
+int
+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;
+ default:
+ return 0;
+ }
+}
+
+ide_ioreg_t
+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;
+ }
+}
+
+int
+prep_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+ return check_region(from, extent);
+}
+
+void
+prep_ide_request_region(ide_ioreg_t from,
+ unsigned int extent,
+ const char *name)
+{
+ request_region(from, extent, name);
+}
+
+void
+prep_ide_release_region(ide_ioreg_t from,
+ unsigned int extent)
+{
+ release_region(from, extent);
+}
+
+void
+prep_ide_fix_driveid(struct hd_driveid *id)
+{
+}
+
+__initfunc(void
+prep_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq))
{
ide_ioreg_t port = base;
int i = 8;
@@ -254,6 +702,143 @@ __initfunc(void prep_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int
if (irq != NULL)
*irq = 0;
}
+#endif
+
+__initfunc(void
+prep_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7))
+{
+ /* make a copy of residual data */
+ if ( r3 )
+ {
+ memcpy((void *)res,(void *)(r3+KERNELBASE),
+ sizeof(RESIDUAL));
+ }
+
+ 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 */
+ if ( res->ResidualLength != 0 )
+ {
+ if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) )
+ _prep_type = _PREP_IBM;
+ else if (!strncmp(res->VitalProductData.PrintableModel,
+ "Radstone",8))
+ {
+ extern char *Motherboard_map_name;
+
+ _prep_type = _PREP_Radstone;
+ Motherboard_map_name=
+ res->VitalProductData.PrintableModel;
+ }
+ else
+ _prep_type = _PREP_Motorola;
+ }
+ else /* assume motorola if no residual (netboot?) */
+ {
+ _prep_type = _PREP_Motorola;
+ }
+
+ prep_setup_pci_ptrs();
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ /* take care of initrd if we have one */
+ if ( r4 )
+ {
+ initrd_start = r4 + KERNELBASE;
+ initrd_end = r5 + KERNELBASE;
+ }
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+ /* take care of cmd line */
+ if ( r6 && (((char *) r6) != '\0'))
+ {
+ *(char *)(r7+KERNELBASE) = 0;
+ strcpy(cmd_line, (char *)(r6+KERNELBASE));
+ }
+
+ ppc_md.setup_arch = prep_setup_arch;
+ ppc_md.setup_residual = prep_setup_residual;
+ ppc_md.get_cpuinfo = prep_get_cpuinfo;
+ ppc_md.irq_cannonicalize = prep_irq_cannonicalize;
+ ppc_md.init_IRQ = prep_init_IRQ;
+ if ( !OpenPIC )
+ ppc_md.do_IRQ = prep_do_IRQ;
+ else
+ ppc_md.do_IRQ = chrp_do_IRQ;
+ ppc_md.init = NULL;
+
+ 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_Radstone) {
+ /*
+ * We require a direct restart as port 92 does not work on
+ * all Radstone boards
+ */
+ ppc_md.restart = prep_direct_restart;
+ /*
+ * The RTC device used varies according to board type
+ */
+ if(((ucSystemType==RS_SYS_TYPE_PPC1) && (ucBoardRevMaj>=5)) ||
+ (ucSystemType==RS_SYS_TYPE_PPC1a))
+ {
+ ppc_md.set_rtc_time = mk48t59_set_rtc_time;
+ ppc_md.get_rtc_time = mk48t59_get_rtc_time;
+ }
+ else
+ {
+ ppc_md.set_rtc_time = mc146818_set_rtc_time;
+ ppc_md.get_rtc_time = mc146818_get_rtc_time;
+ }
+ /*
+ * Determine the decrementer rate from the residual data
+ */
+ ppc_md.calibrate_decr = prep_res_calibrate_decr;
+ }
+ else 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;
+ }
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+ ppc_ide_md.insw = prep_ide_insw;
+ ppc_ide_md.outsw = prep_ide_outsw;
+ ppc_ide_md.default_irq = prep_ide_default_irq;
+ ppc_ide_md.default_io_base = prep_ide_default_io_base;
+ ppc_ide_md.check_region = prep_ide_check_region;
+ ppc_ide_md.request_region = prep_ide_request_region;
+ ppc_ide_md.release_region = prep_ide_release_region;
+ ppc_ide_md.fix_driveid = prep_ide_fix_driveid;
+ ppc_ide_md.ide_init_hwif = prep_ide_init_hwif_ports;
+#endif
+ ppc_ide_md.io_base = _IO_BASE;
+
+#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.kbd_sysrq_xlate = pckbd_sysrq_xlate;
+#endif
+#endif
+}
#ifdef CONFIG_SOUND_MODULE
EXPORT_SYMBOL(ppc_cs4232_dma);
diff --git a/arch/ppc/kernel/prep_time.c b/arch/ppc/kernel/prep_time.c
index f1dff8f13..5b8873d79 100644
--- a/arch/ppc/kernel/prep_time.c
+++ b/arch/ppc/kernel/prep_time.c
@@ -22,7 +22,9 @@
#include <asm/segment.h>
#include <asm/io.h>
#include <asm/processor.h>
-#include <asm/nvram.h>
+#include <asm/machdep.h>
+#include <asm/prep_nvram.h>
+#include <asm/mk48t59.h>
#include "time.h"
@@ -41,73 +43,29 @@
* is setup at boot time to use the correct addresses.
* -- Cort
*/
-/*
- * translate from mc146818 to m48t18 addresses
- */
-unsigned int clock_transl[] __prepdata = { MOTO_RTC_SECONDS,0 /* alarm */,
- MOTO_RTC_MINUTES,0 /* alarm */,
- MOTO_RTC_HOURS,0 /* alarm */, /* 4,5 */
- MOTO_RTC_DAY_OF_WEEK,
- MOTO_RTC_DAY_OF_MONTH,
- MOTO_RTC_MONTH,
- MOTO_RTC_YEAR, /* 9 */
- MOTO_RTC_CONTROLA, MOTO_RTC_CONTROLB /* 10,11 */
-};
-
-__prep
-int prep_cmos_clock_read(int addr)
-{
- if ( _prep_type == _PREP_IBM )
- return CMOS_READ(addr);
- else if ( _prep_type == _PREP_Motorola )
- {
- outb(clock_transl[addr]>>8, NVRAM_AS1);
- outb(clock_transl[addr], NVRAM_AS0);
- return (inb(NVRAM_DATA));
- }
-
- printk("Unknown machine in prep_cmos_clock_read()!\n");
- return -1;
-}
-
-__prep
-void prep_cmos_clock_write(unsigned long val, int addr)
-{
- if ( _prep_type == _PREP_IBM )
- {
- CMOS_WRITE(val,addr);
- return;
- }
- else if ( _prep_type == _PREP_Motorola )
- {
- outb(clock_transl[addr]>>8, NVRAM_AS1);
- outb(clock_transl[addr], NVRAM_AS0);
- outb(val,NVRAM_DATA);
- return;
- }
- printk("Unknown machine in prep_cmos_clock_write()!\n");
-}
/*
* Set the hardware clock. -- Cort
*/
__prep
-int prep_set_rtc_time(unsigned long nowtime)
+int mc146818_set_rtc_time(unsigned long nowtime)
{
unsigned char save_control, save_freq_select;
struct rtc_time tm;
to_tm(nowtime, &tm);
- save_control = prep_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */
-
- prep_cmos_clock_write((save_control|RTC_SET), RTC_CONTROL);
-
- save_freq_select = prep_cmos_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */
+ /* tell the clock it's being set */
+ save_control = CMOS_READ(RTC_CONTROL);
- prep_cmos_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
-
- tm.tm_year -= 1900;
+ 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);
@@ -116,12 +74,12 @@ int prep_set_rtc_time(unsigned long nowtime)
BIN_TO_BCD(tm.tm_mday);
BIN_TO_BCD(tm.tm_year);
}
- prep_cmos_clock_write(tm.tm_sec,RTC_SECONDS);
- prep_cmos_clock_write(tm.tm_min,RTC_MINUTES);
- prep_cmos_clock_write(tm.tm_hour,RTC_HOURS);
- prep_cmos_clock_write(tm.tm_mon,RTC_MONTH);
- prep_cmos_clock_write(tm.tm_mday,RTC_DAY_OF_MONTH);
- prep_cmos_clock_write(tm.tm_year,RTC_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
@@ -130,16 +88,14 @@ int prep_set_rtc_time(unsigned long nowtime)
* the Dallas Semiconductor data sheets, but who believes data
* sheets anyway ... -- Markus Kuhn
*/
- prep_cmos_clock_write(save_control, RTC_CONTROL);
- prep_cmos_clock_write(save_freq_select, RTC_FREQ_SELECT);
+ CMOS_WRITE(save_control, RTC_CONTROL);
+ CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
- if ( (time_state == TIME_ERROR) || (time_state == TIME_BAD) )
- time_state = TIME_OK;
return 0;
}
__prep
-unsigned long prep_get_rtc_time(void)
+unsigned long mc146818_get_rtc_time(void)
{
unsigned int year, mon, day, hour, min, sec;
int i;
@@ -151,29 +107,123 @@ unsigned long prep_get_rtc_time(void)
*/
/* read RTC exactly on falling edge of update flag */
for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
- if (prep_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP)
+ if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
break;
for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
- if (!(prep_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP))
+ if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
break;
do { /* Isn't this overkill ? UIP above should guarantee consistency */
- sec = prep_cmos_clock_read(RTC_SECONDS);
- min = prep_cmos_clock_read(RTC_MINUTES);
- hour = prep_cmos_clock_read(RTC_HOURS);
- day = prep_cmos_clock_read(RTC_DAY_OF_MONTH);
- mon = prep_cmos_clock_read(RTC_MONTH);
- year = prep_cmos_clock_read(RTC_YEAR);
- } while (sec != prep_cmos_clock_read(RTC_SECONDS));
- if (!(prep_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);
- }
+ 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);
+ } while (sec != CMOS_READ(RTC_SECONDS));
+ 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;
+
+
+ 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);
+
+ return 0;
+}
+
+__prep
+unsigned long mk48t59_get_rtc_time(void)
+{
+ unsigned char save_control;
+ unsigned int year, mon, day, hour, min, sec;
+ int i;
+
+ /* 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);
+
+ /* Wait until the seconds value changes, then read the value. */
+ for (i = 0 ; i < 1000000 ; i++) { /* may take up to 1 second... */
+ if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) {
+ break;
+ }
+ }
+
+ /* 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/process.c b/arch/ppc/kernel/process.c
index ebe64a429..db87c2384 100644
--- a/arch/ppc/kernel/process.c
+++ b/arch/ppc/kernel/process.c
@@ -1,5 +1,5 @@
/*
- * $Id: process.c,v 1.70 1999/01/07 16:28:59 cort Exp $
+ * $Id: process.c,v 1.83 1999/05/10 04:43:43 cort Exp $
*
* linux/arch/ppc/kernel/process.c
*
@@ -43,12 +43,18 @@
#include <asm/prom.h>
int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs);
-void switch_to(struct task_struct *, struct task_struct *);
-
extern unsigned long _get_SP(void);
-extern spinlock_t scheduler_lock;
struct task_struct *last_task_used_math = NULL;
+static struct vm_area_struct init_mmap = INIT_MMAP;
+static struct fs_struct init_fs = INIT_FS;
+static struct file * init_fd_array[NR_OPEN] = { NULL, };
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+struct mm_struct init_mm = INIT_MM;
+union task_union init_task_union = { INIT_TASK };
+/* only used to get secondary processor up */
+struct task_struct *current_set[NR_CPUS] = {&init_task, };
#undef SHOW_TASK_SWITCHES 1
#undef CHECK_STACK 1
@@ -65,32 +71,28 @@ task_top(struct task_struct *tsk)
return ((unsigned long)tsk) + sizeof(struct task_struct);
}
-static struct vm_area_struct init_mmap = INIT_MMAP;
-static struct fs_struct init_fs = INIT_FS;
-static struct file * init_fd_array[NR_OPEN] = { NULL, };
-static struct files_struct init_files = INIT_FILES;
-static struct signal_struct init_signals = INIT_SIGNALS;
-
-struct mm_struct init_mm = INIT_MM;
-union task_union init_task_union = { INIT_TASK };
-
-/* only used to get secondary processor up */
-struct task_struct *current_set[NR_CPUS] = {&init_task, };
-
int
dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
{
-#ifdef __SMP__
- if ( regs->msr & MSR_FP )
- smp_giveup_fpu(current);
-#else
- if (last_task_used_math == current)
- giveup_fpu();
-#endif
+ if (regs->msr & MSR_FP)
+ giveup_fpu(current);
memcpy(fpregs, &current->tss.fpr[0], sizeof(*fpregs));
return 1;
}
+void
+enable_kernel_fp(void)
+{
+#ifdef __SMP__
+ if (current->tss.regs && (current->tss.regs->msr & MSR_FP))
+ giveup_fpu(current);
+ else
+ giveup_fpu(NULL); /* just enables FP for kernel */
+#else
+ giveup_fpu(last_task_used_math);
+#endif /* __SMP__ */
+}
+
/* check to make sure the kernel stack is healthy */
int check_stack(struct task_struct *tsk)
{
@@ -155,7 +157,8 @@ int check_stack(struct task_struct *tsk)
}
void
-switch_to(struct task_struct *prev, struct task_struct *new)
+_switch_to(struct task_struct *prev, struct task_struct *new,
+ struct task_struct **last)
{
struct thread_struct *new_tss, *old_tss;
int s = _disable_interrupts();
@@ -165,10 +168,10 @@ switch_to(struct task_struct *prev, struct task_struct *new)
#endif
#ifdef SHOW_TASK_SWITCHES
- printk("%s/%d -> %s/%d NIP %08lx cpu %d lock %x root %x/%x\n",
+ printk("%s/%d -> %s/%d NIP %08lx cpu %d root %x/%x\n",
prev->comm,prev->pid,
new->comm,new->pid,new->tss.regs->nip,new->processor,
- scheduler_lock.lock,new->fs->root,prev->fs->root);
+ new->fs->root,prev->fs->root);
#endif
#ifdef __SMP__
/* avoid complexity of lazy save/restore of fpu
@@ -176,18 +179,19 @@ switch_to(struct task_struct *prev, struct task_struct *new)
* this task used the fpu during the last quantum.
*
* If it tries to use the fpu again, it'll trap and
- * reload its fp regs.
+ * reload its fp regs. So we don't have to do a restore
+ * every switch, just a save.
* -- Cort
*/
- if ( prev->tss.regs->msr & MSR_FP )
- smp_giveup_fpu(prev);
+ if (prev->tss.regs && (prev->tss.regs->msr & MSR_FP))
+ giveup_fpu(prev);
prev->last_processor = prev->processor;
current_set[smp_processor_id()] = new;
#endif /* __SMP__ */
new_tss = &new->tss;
old_tss = &current->tss;
- _switch(old_tss, new_tss, new->mm->context);
+ *last = _switch(old_tss, new_tss, new->mm->context);
_enable_interrupts(s);
}
@@ -240,7 +244,12 @@ void instruction_dump (unsigned long *pc)
printk("Instruction DUMP:");
for(i = -3; i < 6; i++)
- printk("%c%08lx%c",i?' ':'<',pc[i],i?' ':'>');
+ {
+ unsigned long p;
+ if (__get_user( p, &pc[i] ))
+ break;
+ printk("%c%08lx%c",i?' ':'<',p,i?' ':'>');
+ }
printk("\n");
}
@@ -268,8 +277,12 @@ int
copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
struct task_struct * p, struct pt_regs * regs)
{
- struct pt_regs * childregs;
-
+ struct pt_regs * childregs, *kregs;
+#ifdef __SMP__
+ extern void ret_from_smpfork(void);
+#else
+ extern void ret_from_syscall(void);
+#endif
/* Copy registers */
childregs = ((struct pt_regs *)
((unsigned long)p + sizeof(union task_union)
@@ -278,8 +291,19 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
if ((childregs->msr & MSR_PR) == 0)
childregs->gpr[2] = (unsigned long) p; /* `current' in new task */
childregs->gpr[3] = 0; /* Result from fork() */
+ p->tss.regs = childregs;
p->tss.ksp = (unsigned long) childregs - STACK_FRAME_OVERHEAD;
- p->tss.regs = childregs;
+ p->tss.ksp -= sizeof(struct pt_regs ) + STACK_FRAME_OVERHEAD;
+ kregs = (struct pt_regs *)(p->tss.ksp + STACK_FRAME_OVERHEAD);
+#ifdef __SMP__
+ kregs->nip = (unsigned long)ret_from_smpfork;
+#else
+ kregs->nip = (unsigned long)ret_from_syscall;
+#endif
+ kregs->msr = MSR_KERNEL;
+ kregs->gpr[1] = (unsigned long)childregs - STACK_FRAME_OVERHEAD;
+ kregs->gpr[2] = (unsigned long)p;
+
if (usp >= (unsigned long) regs) {
/* Stack is in kernel space - must adjust */
childregs->gpr[1] = (unsigned long)(childregs + 1);
@@ -293,21 +317,14 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
* copy fpu info - assume lazy fpu switch now always
* -- Cort
*/
-#ifdef __SMP__
- if ( regs->msr & MSR_FP )
- smp_giveup_fpu(current);
-#else
- if ( last_task_used_math == current )
- giveup_fpu();
-#endif
+ if (regs->msr & MSR_FP)
+ giveup_fpu(current);
memcpy(&p->tss.fpr, &current->tss.fpr, sizeof(p->tss.fpr));
p->tss.fpscr = current->tss.fpscr;
childregs->msr &= ~MSR_FP;
#ifdef __SMP__
- if ( (p->pid != 0) || !(clone_flags & CLONE_PID) )
- p->tss.smp_fork_ret = 1;
p->last_processor = NO_PROC_ID;
#endif /* __SMP__ */
return 0;
@@ -374,11 +391,6 @@ asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
int res;
lock_kernel();
res = do_fork(clone_flags, regs->gpr[1], regs);
- /*
- * only parent returns here, child returns to either
- * syscall_ret_1() or kernel_thread()
- * -- Cort
- */
#ifdef __SMP__
/* When we clone the idle task we keep the same pid but
* the return value of 0 for both causes problems.
@@ -397,9 +409,7 @@ asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
int res;
- lock_kernel();
res = do_fork(SIGCHLD, regs->gpr[1], regs);
- /* only parent returns here */
#ifdef __SMP__
/* When we clone the idle task we keep the same pid but
* the return value of 0 for both causes problems.
@@ -408,10 +418,15 @@ asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
if ((current->pid == 0) && (current == &init_task))
res = 1;
#endif /* __SMP__ */
- unlock_kernel();
return res;
}
+asmlinkage int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6,
+ struct pt_regs *regs)
+{
+ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs);
+}
+
asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
unsigned long a3, unsigned long a4, unsigned long a5,
struct pt_regs *regs)
@@ -423,13 +438,8 @@ asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
-#ifdef __SMP__
- if ( regs->msr & MSR_FP )
- smp_giveup_fpu(current);
-#else
- if ( last_task_used_math == current )
- giveup_fpu();
-#endif
+ if (regs->msr & MSR_FP)
+ giveup_fpu(current);
error = do_execve(filename, (char **) a1, (char **) a2, regs);
putname(filename);
out:
diff --git a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c
index da9d7a04c..b2221481a 100644
--- a/arch/ppc/kernel/prom.c
+++ b/arch/ppc/kernel/prom.c
@@ -1,5 +1,5 @@
/*
- * $Id: prom.c,v 1.46 1998/11/11 03:55:09 paulus Exp $
+ * $Id: prom.c,v 1.54 1999/05/10 04:43:46 cort Exp $
*
* Procedures for interfacing to the Open Firmware PROM on
* Power Macintosh computers.
@@ -16,6 +16,7 @@
#include <linux/string.h>
#include <linux/init.h>
#include <linux/version.h>
+#include <asm/spinlock.h>
#include <asm/prom.h>
#include <asm/page.h>
#include <asm/processor.h>
@@ -99,10 +100,12 @@ unsigned int old_rtas = 0;
static struct device_node *allnodes = 0;
static void clearscreen(void);
+static void flushscreen(void);
#ifdef CONFIG_BOOTX_TEXT
static void drawchar(char c);
+static void drawhex(unsigned long v);
static void drawstring(const char *c);
static void scrollscreen(void);
@@ -167,6 +170,11 @@ boot_infos_t *boot_infos = 0; /* init it so it's in data segment not bss */
#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)
+
__init
static void
prom_exit()
@@ -256,6 +264,11 @@ __init
void
prom_init(int r3, int r4, prom_entry pp)
{
+#ifdef CONFIG_SMP
+ int cpu = 0, i;
+ phandle node;
+ char type[16], *path;
+#endif
unsigned long mem;
ihandle prom_rtas;
unsigned long offset = reloc_offset();
@@ -273,6 +286,9 @@ prom_init(int r3, int r4, prom_entry pp)
unsigned long space;
unsigned long ptr, x;
char *model;
+#ifdef CONFIG_BOOTX_TEXT
+ unsigned long flags;
+#endif
RELOC(boot_infos) = PTRUNRELOC(bi);
@@ -283,32 +299,72 @@ prom_init(int r3, int r4, prom_entry pp)
RELOC(g_loc_Y) = 0;
RELOC(g_max_loc_X) = (bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) / 8;
RELOC(g_max_loc_Y) = (bi->dispDeviceRect[3] - bi->dispDeviceRect[1]) / 16;
- prom_print(RELOC("Welcome to Linux, kernel " UTS_RELEASE " booting...\n"));
+
+ /* 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))
+ prom_print(RELOC(" !!! WARNING - Incompatible version of BootX !!!\n\n\n"));
+
+ prom_print(RELOC("Welcome to Linux, kernel " UTS_RELEASE "\n"));
+ prom_print(RELOC("\nstarted at : 0x"));
+ drawhex(reloc_offset() + KERNELBASE);
+ prom_print(RELOC("\nlinked at : 0x"));
+ drawhex(KERNELBASE);
+ prom_print(RELOC("\nframe buffer at : 0x"));
+ drawhex((unsigned long)bi->dispDeviceBase);
+ prom_print(RELOC(" (phys), 0x"));
+ drawhex((unsigned long)bi->logicalDisplayBase);
+ prom_print(RELOC(" (log)"));
+ prom_print(RELOC("\nMSR : 0x"));
+ __asm__ __volatile__ ("mfmsr %0" : "=r" ((flags)) : : "memory");
+ drawhex(flags);
+ prom_print(RELOC("\n\n"));
#endif
-
- /*
- * XXX If this is an iMac, turn off the USB controller.
+ /* Out of the #if/#endif since it flushes the clearscreen too */
+ flushscreen();
+
+ /* New BootX enters kernel with MMU off, i/os are not allowed
+ here. This hack will have been done by the boostrap anyway.
*/
- model = (char *) early_get_property
- (r4 + bi->deviceTreeOffset, 4, RELOC("model"));
- if (model && strcmp(model, RELOC("iMac,1")) == 0) {
- out_le32((unsigned *)0x80880008, 1); /* XXX */
+ 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) {
+ out_le32((unsigned *)0x80880008, 1); /* XXX */
+ }
}
-
+
space = bi->deviceTreeOffset + bi->deviceTreeSize;
if (bi->ramDisk)
space = bi->ramDisk + bi->ramDiskSize;
RELOC(klimit) = PTRUNRELOC((char *) bi + space);
- /*
- * Touch each page to make sure the PTEs for them
- * are in the hash table - the aim is to try to avoid
- * getting DSI exceptions while copying the kernel image.
+ /* New BootX will have flushed all TLBs and enters kernel with
+ MMU switched OFF, so this should not be useful anymore.
*/
- for (ptr = (KERNELBASE + offset) & PAGE_MASK;
- ptr < (unsigned long)bi + space; ptr += PAGE_SIZE)
- x = *(volatile unsigned long *)ptr;
-
+ 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
+ prom_print(RELOC("booting...\n"));
+ flushscreen();
+#endif
return;
}
@@ -379,7 +435,7 @@ prom_init(int r3, int r4, prom_entry pp)
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)-KERNELBASE-offset);
+ prom_args.args[2] = ((void *)(RELOC(rtas_data)-KERNELBASE));
RELOC(prom)(&prom_args);
if (prom_args.args[nargs] != 0)
i = 0;
@@ -393,6 +449,81 @@ prom_init(int r3, int r4, prom_entry pp)
prom_print(RELOC(" done\n"));
}
RELOC(klimit) = (char *) (mem - offset);
+#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
+ */
+ {
+ extern void __secondary_hold(void);
+ unsigned long i;
+ char type[16];
+
+
+ /*
+ * 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 (8M) */
+ memcpy( (void *)(8<<20), RELOC(__secondary_hold), 0x10000 );
+ for (i = 8<<20; i < ((8<<20)+0x10000); i += 32)
+ {
+ asm volatile("dcbf 0,%0" : : "r" (i) : "memory");
+ asm volatile("icbi 0,%0" : : "r" (i) : "memory");
+ }
+ }
+
+ /* look for cpus */
+ 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;
+ /* XXX: hack - don't start cpu 0, this cpu -- Cort */
+ if ( cpu++ == 0 )
+ continue;
+ prom_print(RELOC("starting cpu "));
+ prom_print(path);
+ *(unsigned long *)(0x4) = 0;
+ asm volatile("dcbf 0,%0": : "r" (0x4) : "memory");
+ call_prom(RELOC("start-cpu"), 3, 0, node, 8<<20, cpu-1);
+ for ( i = 0 ; (i < 10000) &&
+ (*(ulong *)(0x4) == (ulong)0); i++ )
+ ;
+ if (*(ulong *)(0x4) == (ulong)cpu-1 )
+ prom_print(RELOC("...ok\n"));
+ else
+ prom_print(RELOC("...failed\n"));
+ }
+#endif
}
/*
@@ -631,6 +762,12 @@ finish_node(struct device_node *np, unsigned long mem_start,
mem_start = ifunc(np, mem_start);
}
+ /* 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 (!strcmp(np->name, "device-tree"))
ifunc = interpret_root_props;
else if (np->type == 0)
@@ -1007,7 +1144,7 @@ device_is_compatible(struct device_node *device, const char *compat)
if (cp == NULL)
return 0;
while (cplen > 0) {
- if (strcasecmp(cp, compat) == 0)
+ if (strncasecmp(cp, compat, strlen(compat)) == 0)
return 1;
l = strlen(cp) + 1;
cp += l;
@@ -1143,6 +1280,8 @@ print_properties(struct device_node *np)
}
#endif
+spinlock_t rtas_lock = SPIN_LOCK_UNLOCKED;
+
/* this can be called after setup -- Cort */
__openfirmware
int
@@ -1173,7 +1312,9 @@ call_rtas(const char *service, int nargs, int nret,
for (i = 0; i < nargs; ++i)
u.words[i+3] = va_arg(list, unsigned long);
va_end(list);
+ spin_lock(&rtas_lock);
enter_rtas((void *)__pa(&u));
+ spin_unlock(&rtas_lock);
if (nret > 1 && outputs != NULL)
for (i = 0; i < nret-1; ++i)
outputs[i] = u.words[i+nargs+4];
@@ -1191,8 +1332,11 @@ abort()
prom_exit();
}
-#define CALC_BASE(y) (bi->dispDeviceBase + bi->dispDeviceRect[0] * \
- (bi->dispDeviceDepth >> 3) + bi->dispDeviceRowBytes * (y))
+/* Calc the base address of a given point (x,y) */
+#define CALC_BASE(x,y) ((BOOT_INFO_IS_V2_COMPATIBLE(bi) ? bi->logicalDisplayBase : \
+ bi->dispDeviceBase) + (bi->dispDeviceRect[0] + (x)) * \
+ (bi->dispDeviceDepth >> 3) + bi->dispDeviceRowBytes * \
+ ((y) + bi->dispDeviceRect[1]))
__init
static void
@@ -1200,7 +1344,7 @@ clearscreen(void)
{
unsigned long offset = reloc_offset();
boot_infos_t* bi = PTRRELOC(RELOC(boot_infos));
- unsigned long *base = (unsigned long *)CALC_BASE(0);
+ unsigned long *base = (unsigned long *)CALC_BASE(0,0);
unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
(bi->dispDeviceDepth >> 3)) >> 2;
int i,j;
@@ -1214,6 +1358,33 @@ clearscreen(void)
}
}
+__inline__ void dcbst(const void* addr)
+{
+ __asm__ __volatile__ ("dcbst 0,%0" :: "r" (addr));
+}
+
+__init
+static void
+flushscreen(void)
+{
+ unsigned long offset = reloc_offset();
+ boot_infos_t* bi = PTRRELOC(RELOC(boot_infos));
+ unsigned long *base = (unsigned long *)CALC_BASE(0,0);
+ unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
+ (bi->dispDeviceDepth >> 3)) >> 2;
+ int i,j;
+
+ for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1]); i++)
+ {
+ unsigned long *ptr = base;
+ for(j=width; j>0; j-=8) {
+ dcbst(ptr);
+ ptr += 8;
+ }
+ base += (bi->dispDeviceRowBytes >> 2);
+ }
+}
+
#ifdef CONFIG_BOOTX_TEXT
__init
@@ -1222,8 +1393,8 @@ scrollscreen(void)
{
unsigned long offset = reloc_offset();
boot_infos_t* bi = PTRRELOC(RELOC(boot_infos));
- unsigned long *src = (unsigned long *)CALC_BASE(16);
- unsigned long *dst = (unsigned long *)CALC_BASE(0);
+ unsigned long *src = (unsigned long *)CALC_BASE(0,16);
+ unsigned long *dst = (unsigned long *)CALC_BASE(0,0);
unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
(bi->dispDeviceDepth >> 3)) >> 2;
int i,j;
@@ -1252,20 +1423,17 @@ drawchar(char c)
{
unsigned long offset = reloc_offset();
- switch(c)
- {
- case '\r': RELOC(g_loc_X) = 0; break;
- case '\n': RELOC(g_loc_X) = 0; RELOC(g_loc_Y)++; break;
+ switch(c) {
+ case '\r': RELOC(g_loc_X) = 0; break;
+ case '\n': RELOC(g_loc_X) = 0; RELOC(g_loc_Y)++; break;
default:
draw_byte(c, RELOC(g_loc_X)++, RELOC(g_loc_Y));
- if (RELOC(g_loc_X) >= RELOC(g_max_loc_X))
- {
+ if (RELOC(g_loc_X) >= RELOC(g_max_loc_X)) {
RELOC(g_loc_X) = 0;
RELOC(g_loc_Y)++;
}
}
- while (RELOC(g_loc_Y) >= RELOC(g_max_loc_Y))
- {
+ while (RELOC(g_loc_Y) >= RELOC(g_max_loc_Y)) {
scrollscreen();
RELOC(g_loc_Y)--;
}
@@ -1281,17 +1449,32 @@ drawstring(const char *c)
__init
static void
+drawhex(unsigned long v)
+{
+ static char hex_table[] = "0123456789abcdef";
+ unsigned long offset = reloc_offset();
+
+ drawchar(RELOC(hex_table)[(v >> 28) & 0x0000000FUL]);
+ drawchar(RELOC(hex_table)[(v >> 24) & 0x0000000FUL]);
+ drawchar(RELOC(hex_table)[(v >> 20) & 0x0000000FUL]);
+ drawchar(RELOC(hex_table)[(v >> 16) & 0x0000000FUL]);
+ drawchar(RELOC(hex_table)[(v >> 12) & 0x0000000FUL]);
+ drawchar(RELOC(hex_table)[(v >> 8) & 0x0000000FUL]);
+ drawchar(RELOC(hex_table)[(v >> 4) & 0x0000000FUL]);
+ drawchar(RELOC(hex_table)[(v >> 0) & 0x0000000FUL]);
+}
+
+
+__init
+static void
draw_byte(unsigned char c, long locX, long locY)
{
unsigned long offset = reloc_offset();
- boot_infos_t* bi = PTRRELOC(RELOC(boot_infos));
- unsigned char *base = bi->dispDeviceBase
- + (bi->dispDeviceRowBytes * ((locY * 16) + bi->dispDeviceRect[1]))
- + (bi->dispDeviceDepth >> 3) * ((locX * 8) + bi->dispDeviceRect[0]);
- unsigned char *font = &RELOC(vga_font)[((unsigned long)c) * 16];
+ boot_infos_t* bi = PTRRELOC(RELOC(boot_infos));
+ unsigned char *base = CALC_BASE(locX << 3, locY << 4);
+ unsigned char *font = &RELOC(vga_font)[((unsigned long)c) * 16];
- switch(bi->dispDeviceDepth)
- {
+ switch(bi->dispDeviceDepth) {
case 32:
draw_byte_32(font, (unsigned long *)base);
break;
diff --git a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c
index e2c6b13a0..b3a25fd2b 100644
--- a/arch/ppc/kernel/ptrace.c
+++ b/arch/ppc/kernel/ptrace.c
@@ -392,14 +392,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
tmp = get_reg(child, addr);
}
else if (addr >= PT_FPR0 && addr <= PT_FPSCR) {
-#ifdef __SMP__
- if (child->tss.regs->msr & MSR_FP )
- smp_giveup_fpu(child);
-#else
- /* only current can be last task to use math on SMP */
- if (last_task_used_math == child)
- giveup_fpu();
-#endif
+ if (child->tss.regs->msr & MSR_FP)
+ giveup_fpu(child);
tmp = ((long *)child->tss.fpr)[addr - PT_FPR0];
}
else
@@ -433,13 +427,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
goto out;
}
if (addr >= PT_FPR0 && addr < PT_FPR0 + 64) {
-#ifndef __SMP__
- if (last_task_used_math == child)
- giveup_fpu();
-#else
- if (child->tss.regs->msr & MSR_FP )
- smp_giveup_fpu(child);
-#endif
+ if (child->tss.regs->msr & MSR_FP)
+ giveup_fpu(child);
((long *)child->tss.fpr)[addr - PT_FPR0] = data;
ret = 0;
goto out;
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index 50cd70889..2d38f3adc 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -1,5 +1,5 @@
/*
- * $Id: setup.c,v 1.122 1998/12/31 20:51:19 cort Exp $
+ * $Id: setup.c,v 1.132 1999/03/24 00:32:19 cort Exp $
* Common prep/pmac/chrp boot and setup code.
*/
@@ -27,40 +27,74 @@
#include <asm/smp.h>
#ifdef CONFIG_MBX
#include <asm/mbx.h>
+#include <asm/8xx_immap.h>
#endif
#include <asm/bootx.h>
+#include <asm/machdep.h>
+#include <asm/ide.h>
-/* APUS defs */
-extern unsigned long m68k_machtype;
-extern int parse_bootinfo(const struct bi_record *);
-extern char _end[];
-#ifdef CONFIG_APUS
-extern struct mem_info ramdisk;
-unsigned long isa_io_base;
-unsigned long isa_mem_base;
-unsigned long pci_dram_offset;
-#endif
-/* END APUS defs */
+extern void pmac_init(unsigned long r3,
+ unsigned long r4,
+ unsigned long r5,
+ unsigned long r6,
+ unsigned long r7);
+
+extern void chrp_init(unsigned long r3,
+ unsigned long r4,
+ unsigned long r5,
+ unsigned long r6,
+ unsigned long r7);
+
+extern void prep_init(unsigned long r3,
+ unsigned long r4,
+ unsigned long r5,
+ unsigned long r6,
+ unsigned long r7);
+
+extern void mbx_init(unsigned long r3,
+ unsigned long r4,
+ unsigned long r5,
+ unsigned long r6,
+ unsigned long r7);
+
+extern void apus_init(unsigned long r3,
+ unsigned long r4,
+ unsigned long r5,
+ unsigned long r6,
+ unsigned long r7);
+extern boot_infos_t *boot_infos;
extern char cmd_line[512];
char saved_command_line[256];
unsigned char aux_device_present;
-#if !defined(CONFIG_MACH_SPECIFIC)
+struct ide_machdep_calls ppc_ide_md;
+
unsigned long ISA_DMA_THRESHOLD;
unsigned long DMA_MODE_READ, DMA_MODE_WRITE;
-int _machine;
-/* if we have openfirmware */
-unsigned long have_of;
-#endif /* ! CONFIG_MACH_SPECIFIC */
+
+/* Temporary hacks until machdep.h is fully done. */
+int _machine = 0;
+/* do we have OF? */
+int have_of = 0;
+int is_prep = 0;
+int is_chrp = 0;
+/* For MTX/MVME boards.. with Raven/Falcon Chipset
+ Real close to CHRP, but boot like PReP (via PPCbug)
+ There's probably a nicer way to do this.. --Troy */
+int is_powerplus = 0;
+
+struct machdep_calls ppc_md;
+
/* copy of the residual data */
+#ifndef CONFIG_MBX
unsigned char __res[sizeof(RESIDUAL)] __prepdata = {0,};
-RESIDUAL *res = (RESIDUAL *)&__res;
-
-int _prep_type;
+#else
+unsigned char __res[sizeof(bd_t)] = {0,};
+#endif
-extern boot_infos_t *boot_infos;
+RESIDUAL *res = (RESIDUAL *)&__res;
/*
* Perhaps we can put the pmac screen_info[] here
@@ -110,160 +144,28 @@ struct screen_info screen_info = {
};
#endif /* CONFIG_MBX */
-/* cmd is ignored for now... */
void machine_restart(char *cmd)
{
-#ifndef CONFIG_MBX
- struct adb_request req;
- unsigned long flags;
- unsigned long i = 10000;
-#if 0
- int err;
-#endif
-
- switch(_machine)
- {
- case _MACH_Pmac:
- switch (adb_hardware) {
- case ADB_VIACUDA:
- cuda_request(&req, NULL, 2, CUDA_PACKET,
- CUDA_RESET_SYSTEM);
- for (;;)
- cuda_poll();
- break;
- case ADB_VIAPMU:
- pmu_restart();
- break;
- default:
- }
- break;
-
- case _MACH_chrp:
-#if 0 /* RTAS doesn't seem to work on Longtrail.
- For now, do it the same way as the PReP. */
- /*err = call_rtas("system-reboot", 0, 1, NULL);
- printk("RTAS system-reboot returned %d\n", err);
- for (;;);*/
-
- {
- extern unsigned int rtas_entry, rtas_data, rtas_size;
- unsigned long status, value;
- printk("rtas_entry: %08x rtas_data: %08x rtas_size: %08x\n",
- rtas_entry,rtas_data,rtas_size);
- }
-#endif
- case _MACH_prep:
- _disable_interrupts();
-
- /* 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 ( i != 0 ) i++;
- panic("restart failed\n");
- break;
- case _MACH_apus:
- 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(;;);
- break;
- }
-#else /* CONFIG_MBX */
- extern void MBX_gorom(void);
- MBX_gorom();
-#endif /* CONFIG_MBX */
+ ppc_md.restart(cmd);
}
-
+
void machine_power_off(void)
{
-#ifndef CONFIG_MBX
- struct adb_request req;
-#if 0
- int err;
-#endif
-
- switch (_machine) {
- case _MACH_Pmac:
- switch (adb_hardware) {
- case ADB_VIACUDA:
- cuda_request(&req, NULL, 2, CUDA_PACKET,
- CUDA_POWERDOWN);
- for (;;)
- cuda_poll();
- break;
- case ADB_VIAPMU:
- pmu_shutdown();
- break;
- default:
- }
- break;
-
- case _MACH_chrp:
-#if 0 /* RTAS doesn't seem to work on Longtrail.
- For now, do it the same way as the PReP. */
- err = call_rtas("power-off", 2, 1, NULL, 0, 0);
- printk("RTAS system-reboot returned %d\n", err);
- for (;;);
-#endif
-
- case _MACH_prep:
- machine_restart(NULL);
- case _MACH_apus:
- for (;;);
- }
- for (;;);
-#else /* CONFIG_MBX */
- machine_restart(NULL);
-#endif /* CONFIG_MBX */
+ ppc_md.power_off();
}
-
+
void machine_halt(void)
{
- if ( _machine == _MACH_Pmac )
- {
- machine_power_off();
- }
- else /* prep, chrp or apus */
- machine_restart(NULL);
-
+ ppc_md.halt();
}
-
+
#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
{
-#if !defined(CONFIG_MBX) && !defined(CONFIG_APUS)
- switch (_machine) {
-#if defined(CONFIG_BLK_DEV_IDE_PMAC)
- case _MACH_Pmac:
- pmac_ide_init_hwif_ports(p,base,irq);
- break;
-#endif
- case _MACH_chrp:
- chrp_ide_init_hwif_ports(p,base,irq);
- break;
- case _MACH_prep:
- prep_ide_init_hwif_ports(p,base,irq);
- break;
+ if (ppc_ide_md.ide_init_hwif != NULL) {
+ ppc_ide_md.ide_init_hwif(p, base, irq);
}
-#endif
-#if defined(CONFIG_MBX)
- mbx_ide_init_hwif_ports(p,base,irq);
-#endif
}
-EXPORT_SYMBOL(ide_init_hwif_ports);
#endif
unsigned long cpu_temp(void)
@@ -297,10 +199,6 @@ unsigned long cpu_temp(void)
int get_cpuinfo(char *buffer)
{
- extern int pmac_get_cpuinfo(char *);
- extern int chrp_get_cpuinfo(char *);
- extern int prep_get_cpuinfo(char *);
- extern int apus_get_cpuinfo(char *);
unsigned long len = 0;
unsigned long bogosum = 0;
unsigned long i;
@@ -364,7 +262,6 @@ int get_cpuinfo(char *buffer)
break;
}
-#ifndef CONFIG_MBX
/*
* Assume here that all clock rates are the same in a
* smp system. -- Cort
@@ -381,33 +278,11 @@ int get_cpuinfo(char *buffer)
len += sprintf(len+buffer, "clock\t\t: %dMHz\n",
*fp / 1000000);
}
-
- /* PREP's without residual data for some reason will give
- incorrect values here */
- if ( is_prep )
- {
- len += sprintf(len+buffer, "clock\t\t: ");
- if ( res->ResidualLength )
- len += sprintf(len+buffer, "%ldMHz\n",
- (res->VitalProductData.ProcessorHz > 1024) ?
- res->VitalProductData.ProcessorHz>>20 :
- res->VitalProductData.ProcessorHz);
- else
- len += sprintf(len+buffer, "???\n");
- }
-#else /* CONFIG_MBX */
+
+ if (ppc_md.setup_residual != NULL)
{
- bd_t *bp;
- extern RESIDUAL *res;
-
- bp = (bd_t *)res;
-
- len += sprintf(len+buffer,"clock\t\t: %dMHz\n"
- "bus clock\t: %dMHz\n",
- bp->bi_intfreq /*/ 1000000*/,
- bp->bi_busfreq /*/ 1000000*/);
+ len += ppc_md.setup_residual(buffer + len);
}
-#endif /* CONFIG_MBX */
len += sprintf(len+buffer, "revision\t: %ld.%ld\n",
(GET_PVR & 0xff00) >> 8, GET_PVR & 0xff);
@@ -422,8 +297,8 @@ int get_cpuinfo(char *buffer)
if ( i )
len += sprintf(buffer+len, "\n");
len += sprintf(buffer+len,"total bogomips\t: %lu.%02lu\n",
- (bogosum+2500)/500000,
- (bogosum+2500)/5000 % 100);
+ (bogosum+2500)/500000,
+ (bogosum+2500)/5000 % 100);
#endif /* __SMP__ */
/*
@@ -432,34 +307,21 @@ int get_cpuinfo(char *buffer)
{
len += sprintf(buffer+len,"zero pages\t: total %lu (%luKb) "
"current: %lu (%luKb) hits: %lu/%lu (%lu%%)\n",
- quicklists.zerototal,
- (quicklists.zerototal*PAGE_SIZE)>>10,
- quicklists.zero_sz,
- (quicklists.zero_sz*PAGE_SIZE)>>10,
- quicklists.zeropage_hits,quicklists.zeropage_calls,
+ zero_cache_total,
+ (zero_cache_total*PAGE_SIZE)>>10,
+ zero_cache_sz,
+ (zero_cache_sz*PAGE_SIZE)>>10,
+ zero_cache_hits,zero_cache_calls,
/* : 1 below is so we don't div by zero */
- (quicklists.zeropage_hits*100) /
- ((quicklists.zeropage_calls)?quicklists.zeropage_calls:1));
+ (zero_cache_hits*100) /
+ ((zero_cache_calls)?zero_cache_calls:1));
}
-#ifndef CONFIG_MBX
- switch (_machine)
+ if (ppc_md.get_cpuinfo != NULL)
{
- case _MACH_Pmac:
- len += pmac_get_cpuinfo(buffer+len);
- break;
- case _MACH_prep:
- len += prep_get_cpuinfo(buffer+len);
- break;
- case _MACH_chrp:
- len += chrp_get_cpuinfo(buffer+len);
- break;
- case _MACH_apus:
- /* Not much point in printing m68k info when it is not
- used. */
- break;
+ len += ppc_md.get_cpuinfo(buffer+len);
}
-#endif /* ndef CONFIG_MBX */
+
return len;
}
@@ -471,25 +333,22 @@ unsigned long __init
identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7)
{
- extern void setup_pci_ptrs(void);
#ifdef __SMP__
if ( first_cpu_booted ) return 0;
#endif /* __SMP__ */
-#ifndef CONFIG_MBX
#ifndef CONFIG_MACH_SPECIFIC
/* boot loader will tell us if we're APUS */
if ( r3 == 0x61707573 )
{
_machine = _MACH_apus;
- have_of = 0;
r3 = 0;
}
/* prep boot loader tells us if we're prep or not */
else if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) ) {
_machine = _MACH_prep;
- have_of = 0;
+ is_prep = 1;
} else {
char *model;
@@ -500,19 +359,49 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
/* ask the OF info if we're a chrp or pmac */
model = get_property(find_path_device("/"), "device_type", NULL);
if ( model && !strncmp("chrp",model,4) )
+ {
_machine = _MACH_chrp;
+ is_chrp = 1;
+ }
else
{
model = get_property(find_path_device("/"),
"model", NULL);
if ( model && !strncmp(model, "IBM", 3))
+ {
_machine = _MACH_chrp;
+ is_chrp = 1;
+ }
else
+ {
_machine = _MACH_Pmac;
+ is_prep = 1;
+ }
}
}
-#endif /* CONFIG_MACH_SPECIFIC */
+#else /* CONFIG_MACH_SPECIFIC */
+
+#ifdef CONFIG_PREP
+ _machine = _MACH_prep;
+ is_prep = 1;
+#elif defined(CONFIG_CHRP)
+ _machine = _MACH_chrp;
+ is_chrp = 1;
+ have_of = 1;
+#elif defined(CONFIG_PMAC)
+ _machine = _MACH_Pmac;
+ have_of = 1;
+#elif defined(CONFIG_MBX)
+ _machine = _MACH_mbx;
+#elif defined(CONFIG_FADS)
+ _machine = _MACH_fads;
+#elif defined(CONFIG_APUS)
+ _machine = _MACH_apus;
+#else
+#error "Machine not defined correctly"
+#endif /* CONFIG_APUS */
+#endif /* CONFIG_MACH_SPECIFIC */
if ( have_of )
{
@@ -571,131 +460,31 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
cmd_line[sizeof(cmd_line) - 1] = 0;
}
-
switch (_machine)
{
case _MACH_Pmac:
- setup_pci_ptrs();
- /* isa_io_base gets set in pmac_find_bridges */
- isa_mem_base = PMAC_ISA_MEM_BASE;
- pci_dram_offset = PMAC_PCI_DRAM_OFFSET;
-#if !defined(CONFIG_MACH_SPECIFIC)
- ISA_DMA_THRESHOLD = ~0L;
- DMA_MODE_READ = 1;
- DMA_MODE_WRITE = 2;
-#endif /* ! CONFIG_MACH_SPECIFIC */
+ pmac_init(r3, r4, r5, r6, r7);
break;
case _MACH_prep:
- /* make a copy of residual data */
- if ( r3 )
- memcpy((void *)res,(void *)(r3+KERNELBASE),
- sizeof(RESIDUAL));
- setup_pci_ptrs();
- isa_io_base = PREP_ISA_IO_BASE;
- isa_mem_base = PREP_ISA_MEM_BASE;
- pci_dram_offset = PREP_PCI_DRAM_OFFSET;
-#if !defined(CONFIG_MACH_SPECIFIC)
- ISA_DMA_THRESHOLD = 0x00ffffff;
- DMA_MODE_READ = 0x44;
- DMA_MODE_WRITE = 0x48;
-#endif /* ! CONFIG_MACH_SPECIFIC */
- /* figure out what kind of prep workstation we are */
- if ( res->ResidualLength != 0 )
- {
- if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) )
- _prep_type = _PREP_IBM;
- else
- _prep_type = _PREP_Motorola;
- }
- else /* assume motorola if no residual (netboot?) */
- _prep_type = _PREP_Motorola;
-#ifdef CONFIG_BLK_DEV_INITRD
- /* take care of initrd if we have one */
- if ( r4 )
- {
- initrd_start = r4 + KERNELBASE;
- initrd_end = r5 + KERNELBASE;
- }
-#endif /* CONFIG_BLK_DEV_INITRD */
- /* take care of cmd line */
- if ( r6 )
- {
- *(char *)(r7+KERNELBASE) = 0;
- strcpy(cmd_line, (char *)(r6+KERNELBASE));
- }
+ prep_init(r3, r4, r5, r6, r7);
break;
case _MACH_chrp:
- setup_pci_ptrs();
-#ifdef CONFIG_BLK_DEV_INITRD
- /* take care of initrd if we have one */
- if ( r3 )
- {
- initrd_start = r3 + KERNELBASE;
- initrd_end = r3 + r4 + KERNELBASE;
- }
-#endif /* CONFIG_BLK_DEV_INITRD */
- /* isa_io_base set by setup_pci_ptrs() */
- isa_mem_base = CHRP_ISA_MEM_BASE;
- pci_dram_offset = CHRP_PCI_DRAM_OFFSET;
-#if !defined(CONFIG_MACH_SPECIFIC)
- ISA_DMA_THRESHOLD = ~0L;
- DMA_MODE_READ = 0x44;
- DMA_MODE_WRITE = 0x48;
-#endif /* ! CONFIG_MACH_SPECIFIC */
+ chrp_init(r3, r4, r5, r6, r7);
break;
-#ifdef CONFIG_APUS
+#ifdef CONFIG_APUS
case _MACH_apus:
- /* 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);
- }
- /* Make sure code below is not executed. */
- r4 = 0;
- r6 = 0;
-#endif /* CONFIG_BLK_DEV_INITRD */
-#if !defined(CONFIG_MACH_SPECIFIC)
- ISA_DMA_THRESHOLD = 0x00ffffff;
-#endif /* ! CONFIG_MACH_SPECIFIC */
+ apus_init(r3, r4, r5, r6, r7);
break;
#endif
+#ifdef CONFIG_MBX
+ case _MACH_mbx:
+ mbx_init(r3, r4, r5, r6, r7);
+ break;
+#endif
default:
printk("Unknown machine type in identify_machine!\n");
}
-#else /* CONFIG_MBX */
-
- if ( r3 )
- memcpy( (void *)res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
-
-#ifdef CONFIG_PCI
- setup_pci_ptrs();
-#endif
-
-#ifdef CONFIG_BLK_DEV_INITRD
- /* take care of initrd if we have one */
- if ( r4 )
- {
- initrd_start = r4 + KERNELBASE;
- initrd_end = r5 + KERNELBASE;
- }
-#endif /* CONFIG_BLK_DEV_INITRD */
- /* take care of cmd line */
- if ( r6 )
- {
-
- *(char *)(r7+KERNELBASE) = 0;
- strcpy(cmd_line, (char *)(r6+KERNELBASE));
- }
-#endif /* CONFIG_MBX */
-
/* Check for nobats option (used in mapin_ram). */
if (strstr(cmd_line, "nobats")) {
extern int __map_without_bats;
@@ -717,14 +506,17 @@ void ppc_setup_l2cr(char *str, int *ints)
}
}
+__initfunc(void
+ ppc_init(void))
+{
+ if (ppc_md.init != NULL) {
+ ppc_md.init();
+ }
+}
+
__initfunc(void setup_arch(char **cmdline_p,
- unsigned long * memory_start_p, unsigned long * memory_end_p))
+ unsigned long * memory_start_p, unsigned long * memory_end_p))
{
- extern void pmac_setup_arch(unsigned long *, unsigned long *);
- extern void chrp_setup_arch(unsigned long *, unsigned long *);
- extern void prep_setup_arch(unsigned long *, unsigned long *);
- extern void mbx_setup_arch(unsigned long *, unsigned long *);
- extern void apus_setup_arch(unsigned long *, unsigned long *);
extern int panic_timeout;
extern char _etext[], _edata[];
extern char *klimit;
@@ -737,7 +529,7 @@ __initfunc(void setup_arch(char **cmdline_p,
if (strstr(cmd_line, "xmon"))
xmon(0);
#endif /* CONFIG_XMON */
-
+
/* reboot on panic */
panic_timeout = 180;
@@ -753,27 +545,113 @@ __initfunc(void setup_arch(char **cmdline_p,
*memory_start_p = find_available_memory();
*memory_end_p = (unsigned long) end_of_DRAM;
-#ifdef CONFIG_MBX
- mbx_setup_arch(memory_start_p,memory_end_p);
-#else /* CONFIG_MBX */
- switch (_machine) {
- case _MACH_Pmac:
- pmac_setup_arch(memory_start_p, memory_end_p);
- break;
- case _MACH_prep:
- prep_setup_arch(memory_start_p, memory_end_p);
- break;
- case _MACH_chrp:
- chrp_setup_arch(memory_start_p, memory_end_p);
- break;
-#ifdef CONFIG_APUS
- case _MACH_apus:
- m68k_machtype = MACH_AMIGA;
- apus_setup_arch(memory_start_p,memory_end_p);
- break;
-#endif
- default:
- printk("Unknown machine %d in setup_arch()\n", _machine);
- }
-#endif /* CONFIG_MBX */
+ ppc_md.setup_arch(memory_start_p, memory_end_p);
+}
+
+void ppc_generic_ide_fix_driveid(struct hd_driveid *id)
+{
+ int i;
+ unsigned short *stringcast;
+
+
+ id->config = __le16_to_cpu(id->config);
+ id->cyls = __le16_to_cpu(id->cyls);
+ id->reserved2 = __le16_to_cpu(id->reserved2);
+ id->heads = __le16_to_cpu(id->heads);
+ id->track_bytes = __le16_to_cpu(id->track_bytes);
+ id->sector_bytes = __le16_to_cpu(id->sector_bytes);
+ id->sectors = __le16_to_cpu(id->sectors);
+ id->vendor0 = __le16_to_cpu(id->vendor0);
+ id->vendor1 = __le16_to_cpu(id->vendor1);
+ id->vendor2 = __le16_to_cpu(id->vendor2);
+ stringcast = (unsigned short *)&id->serial_no[0];
+ for (i=0; i<(20/2); i++)
+ stringcast[i] = __le16_to_cpu(stringcast[i]);
+ id->buf_type = __le16_to_cpu(id->buf_type);
+ id->buf_size = __le16_to_cpu(id->buf_size);
+ id->ecc_bytes = __le16_to_cpu(id->ecc_bytes);
+ stringcast = (unsigned short *)&id->fw_rev[0];
+ for (i=0; i<(8/2); i++)
+ stringcast[i] = __le16_to_cpu(stringcast[i]);
+ stringcast = (unsigned short *)&id->model[0];
+ for (i=0; i<(40/2); i++)
+ stringcast[i] = __le16_to_cpu(stringcast[i]);
+ id->dword_io = __le16_to_cpu(id->dword_io);
+ id->reserved50 = __le16_to_cpu(id->reserved50);
+ id->field_valid = __le16_to_cpu(id->field_valid);
+ id->cur_cyls = __le16_to_cpu(id->cur_cyls);
+ id->cur_heads = __le16_to_cpu(id->cur_heads);
+ id->cur_sectors = __le16_to_cpu(id->cur_sectors);
+ id->cur_capacity0 = __le16_to_cpu(id->cur_capacity0);
+ id->cur_capacity1 = __le16_to_cpu(id->cur_capacity1);
+ id->lba_capacity = __le32_to_cpu(id->lba_capacity);
+ id->dma_1word = __le16_to_cpu(id->dma_1word);
+ id->dma_mword = __le16_to_cpu(id->dma_mword);
+ id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
+ id->eide_dma_min = __le16_to_cpu(id->eide_dma_min);
+ id->eide_dma_time = __le16_to_cpu(id->eide_dma_time);
+ id->eide_pio = __le16_to_cpu(id->eide_pio);
+ id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
+ id->word69 = __le16_to_cpu(id->word69);
+ id->word70 = __le16_to_cpu(id->word70);
+ id->word71 = __le16_to_cpu(id->word71);
+ id->word72 = __le16_to_cpu(id->word72);
+ id->word73 = __le16_to_cpu(id->word73);
+ id->word74 = __le16_to_cpu(id->word74);
+ id->word75 = __le16_to_cpu(id->word75);
+ id->word76 = __le16_to_cpu(id->word76);
+ id->word77 = __le16_to_cpu(id->word77);
+ id->word78 = __le16_to_cpu(id->word78);
+ id->word79 = __le16_to_cpu(id->word79);
+ id->word80 = __le16_to_cpu(id->word80);
+ id->word81 = __le16_to_cpu(id->word81);
+ id->command_sets = __le16_to_cpu(id->command_sets);
+ id->word83 = __le16_to_cpu(id->word83);
+ id->word84 = __le16_to_cpu(id->word84);
+ id->word85 = __le16_to_cpu(id->word85);
+ id->word86 = __le16_to_cpu(id->word86);
+ id->word87 = __le16_to_cpu(id->word87);
+ id->dma_ultra = __le16_to_cpu(id->dma_ultra);
+ id->word89 = __le16_to_cpu(id->word89);
+ id->word90 = __le16_to_cpu(id->word90);
+ id->word91 = __le16_to_cpu(id->word91);
+ id->word92 = __le16_to_cpu(id->word92);
+ id->word93 = __le16_to_cpu(id->word93);
+ id->word94 = __le16_to_cpu(id->word94);
+ id->word95 = __le16_to_cpu(id->word95);
+ id->word96 = __le16_to_cpu(id->word96);
+ id->word97 = __le16_to_cpu(id->word97);
+ id->word98 = __le16_to_cpu(id->word98);
+ id->word99 = __le16_to_cpu(id->word99);
+ id->word100 = __le16_to_cpu(id->word100);
+ id->word101 = __le16_to_cpu(id->word101);
+ id->word102 = __le16_to_cpu(id->word102);
+ id->word103 = __le16_to_cpu(id->word103);
+ id->word104 = __le16_to_cpu(id->word104);
+ id->word105 = __le16_to_cpu(id->word105);
+ id->word106 = __le16_to_cpu(id->word106);
+ id->word107 = __le16_to_cpu(id->word107);
+ id->word108 = __le16_to_cpu(id->word108);
+ id->word109 = __le16_to_cpu(id->word109);
+ id->word110 = __le16_to_cpu(id->word110);
+ id->word111 = __le16_to_cpu(id->word111);
+ id->word112 = __le16_to_cpu(id->word112);
+ id->word113 = __le16_to_cpu(id->word113);
+ id->word114 = __le16_to_cpu(id->word114);
+ id->word115 = __le16_to_cpu(id->word115);
+ id->word116 = __le16_to_cpu(id->word116);
+ id->word117 = __le16_to_cpu(id->word117);
+ id->word118 = __le16_to_cpu(id->word118);
+ id->word119 = __le16_to_cpu(id->word119);
+ id->word120 = __le16_to_cpu(id->word120);
+ id->word121 = __le16_to_cpu(id->word121);
+ id->word122 = __le16_to_cpu(id->word122);
+ id->word123 = __le16_to_cpu(id->word123);
+ id->word124 = __le16_to_cpu(id->word124);
+ id->word125 = __le16_to_cpu(id->word125);
+ id->word126 = __le16_to_cpu(id->word126);
+ id->word127 = __le16_to_cpu(id->word127);
+ id->security = __le16_to_cpu(id->security);
+ for (i=0; i<127; i++)
+ id->reserved[i] = __le16_to_cpu(id->reserved[i]);
}
diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c
index 3ffb7981e..17c0f55d1 100644
--- a/arch/ppc/kernel/signal.c
+++ b/arch/ppc/kernel/signal.c
@@ -1,7 +1,7 @@
/*
* linux/arch/ppc/kernel/signal.c
*
- * $Id: signal.c,v 1.21 1998/10/22 19:37:49 paulus Exp $
+ * $Id: signal.c,v 1.24 1999/04/03 11:25:16 paulus Exp $
*
* PowerPC version
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -218,13 +218,8 @@ int sys_sigreturn(struct pt_regs *regs)
if (sc == (struct sigcontext_struct *)(sigctx.regs)) {
/* Last stacked signal - restore registers */
sr = (struct sigregs *) sigctx.regs;
-#ifdef __SMP__
- if ( regs->msr & MSR_FP )
- smp_giveup_fpu(current);
-#else
- if (last_task_used_math == current)
- giveup_fpu();
-#endif
+ if (regs->msr & MSR_FP )
+ giveup_fpu(current);
if (copy_from_user(saved_regs, &sr->gp_regs,
sizeof(sr->gp_regs)))
goto badframe;
@@ -271,13 +266,8 @@ setup_frame(struct pt_regs *regs, struct sigregs *frame,
if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
goto badframe;
-#ifdef __SMP__
- if ( regs->msr & MSR_FP )
- smp_giveup_fpu(current);
-#else
- if (last_task_used_math == current)
- giveup_fpu();
-#endif
+ if (regs->msr & MSR_FP)
+ giveup_fpu(current);
if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE)
|| __copy_to_user(&frame->fp_regs, current->tss.fpr,
ELF_NFPREG * sizeof(double))
@@ -374,7 +364,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
if (!oldset)
oldset = &current->blocked;
- newsp = frame = regs->gpr[1] - sizeof(struct sigregs);
+ newsp = frame = 0;
for (;;) {
unsigned long signr;
@@ -471,6 +461,13 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
}
}
+ if ( (ka->sa.sa_flags & SA_ONSTACK)
+ && (! on_sig_stack(regs->gpr[1])))
+ newsp = (current->sas_ss_sp + current->sas_ss_size);
+ else
+ newsp = regs->gpr[1];
+ newsp = frame = newsp - sizeof(struct sigregs);
+
/* Whee! Actually deliver the signal. */
handle_signal(signr, ka, &info, oldset, regs, &newsp, frame);
}
diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c
index ba505e133..c38fc3108 100644
--- a/arch/ppc/kernel/smp.c
+++ b/arch/ppc/kernel/smp.c
@@ -1,10 +1,13 @@
/*
- * $Id: smp.c,v 1.39 1998/12/28 10:28:51 paulus Exp $
+ * $Id: smp.c,v 1.49 1999/03/18 04:16:31 cort Exp $
*
* Smp support for ppc.
*
* Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great
* deal of code from the sparc and intel versions.
+ *
+ * Support for PReP (Motorola MTX/MVME) SMP by Troy Benjegerdes
+ * (troy@microux.com, hozer@drgw.net)
*/
#include <linux/kernel.h>
@@ -18,6 +21,7 @@
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>
#include <linux/init.h>
+#include <linux/openpic.h>
#include <asm/ptrace.h>
#include <asm/atomic.h>
@@ -29,9 +33,10 @@
#include <asm/softirq.h>
#include <asm/init.h>
#include <asm/io.h>
+#include <asm/prom.h>
#include "time.h"
-
+int first_cpu_booted = 0;
int smp_threads_ready = 0;
volatile int smp_commenced = 0;
int smp_num_cpus = 1;
@@ -42,7 +47,6 @@ volatile unsigned long ipi_count;
spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
unsigned int prof_multiplier[NR_CPUS];
unsigned int prof_counter[NR_CPUS];
-int first_cpu_booted = 0;
cycles_t cacheflush_time;
/* all cpu mappings are 1-1 -- Cort */
@@ -51,6 +55,10 @@ volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
int start_secondary(void *);
extern int cpu_idle(void *unused);
+u_int openpic_read(volatile u_int *addr);
+
+/* register for interrupting the secondary processor on the powersurge */
+#define PSURGE_INTR ((volatile unsigned *)0xf80000c0)
void smp_local_timer_interrupt(struct pt_regs * regs)
{
@@ -99,29 +107,33 @@ void smp_local_timer_interrupt(struct pt_regs * regs)
/*
* Dirty hack to get smp message passing working.
- * Right now it only works for stop cpu's but will be setup
- * later for more general message passing.
*
* As it is now, if we're sending two message at the same time
- * we have race conditions. I avoided doing locks here since
- * all that works right now is the stop cpu message.
+ * we have race conditions. The PowerSurge doesn't easily
+ * allow us to send IPI messages so we put the messages in
+ * smp_message[].
*
+ * This is because don't have several IPI's on the PowerSurge even though
+ * we do on the chrp. It would be nice to use the actual IPI's on the chrp
+ * rather than this but having two methods of doing IPI isn't a good idea
+ * right now.
* -- Cort
*/
int smp_message[NR_CPUS];
void smp_message_recv(void)
{
int msg = smp_message[smp_processor_id()];
-
- /* clear interrupt */
- *(volatile unsigned long *)(0xf80000c0) = ~0L;
- eieio();
+
+ if ( _machine == _MACH_Pmac )
+ {
+ /* clear interrupt */
+ out_be32(PSURGE_INTR, ~0);
+ }
/* make sure msg is for us */
if ( msg == -1 ) return;
ipi_count++;
- /*printk("SMP %d: smp_message_recv() msg %x\n", smp_processor_id(),msg);*/
switch( msg )
{
@@ -158,12 +170,17 @@ void smp_send_stop(void)
spinlock_t mesg_pass_lock = SPIN_LOCK_UNLOCKED;
void smp_message_pass(int target, int msg, unsigned long data, int wait)
{
- if ( _machine != _MACH_Pmac )
+ int i;
+ if ( !(_machine & (_MACH_Pmac|_MACH_chrp)) )
return;
-printk("SMP %d: sending smp message %x\n", current->processor, msg);
-if (smp_processor_id() ) printk("pass from cpu 1\n");
+
spin_lock(&mesg_pass_lock);
-#define OTHER (~smp_processor_id() & 1)
+
+ /*
+ * We assume here that the msg is not -1. If it is,
+ * the recipient won't know the message was destined
+ * for it. -- Cort
+ */
switch( target )
{
@@ -171,105 +188,180 @@ if (smp_processor_id() ) printk("pass from cpu 1\n");
smp_message[smp_processor_id()] = msg;
/* fall through */
case MSG_ALL_BUT_SELF:
- smp_message[OTHER] = msg;
+ for ( i = 0 ; i < smp_num_cpus ; i++ )
+ if ( i != smp_processor_id () )
+ smp_message[i] = msg;
break;
default:
smp_message[target] = msg;
break;
}
- /* interrupt secondary processor */
- *(volatile unsigned long *)(0xf80000c0) = ~0L;
- eieio();
- *(volatile unsigned long *)(0xf80000c0) = 0L;
- eieio();
- /* interrupt primary */
- /**(volatile unsigned long *)(0xf3019000);*/
- spin_unlock(&mesg_pass_lock);
+
+ if ( _machine == _MACH_Pmac )
+ {
+ /* interrupt secondary processor */
+ out_be32(PSURGE_INTR, ~0);
+ out_be32(PSURGE_INTR, 0);
+ /*
+ * Assume for now that the secondary doesn't send
+ * IPI's -- Cort
+ */
+ /* interrupt primary */
+ /**(volatile unsigned long *)(0xf3019000);*/
+ }
+
+ if ( _machine == _MACH_chrp )
+ {
+ /*
+ * There has to be some way of doing this better -
+ * perhaps a sent-to-all or send-to-all-but-self
+ * in the openpic. This gets us going for now, though.
+ * -- Cort
+ */
+ switch ( target )
+ {
+ case MSG_ALL:
+ for ( i = 0 ; i < smp_num_cpus ; i++ )
+ openpic_cause_IPI(i, 0, 0xffffffff );
+ break;
+ case MSG_ALL_BUT_SELF:
+ for ( i = 0 ; i < smp_num_cpus ; i++ )
+ if ( i != smp_processor_id () )
+ openpic_cause_IPI(i, 0,
+ 0xffffffff & ~(1 << smp_processor_id()));
+ break;
+ default:
+ openpic_cause_IPI(target, 0, 1U << target);
+ break;
+ }
+ }
+
+ spin_unlock(&mesg_pass_lock);
}
void __init smp_boot_cpus(void)
{
extern struct task_struct *current_set[NR_CPUS];
- extern void __secondary_start(void);
+ extern void __secondary_start_psurge(void);
int i;
struct task_struct *p;
unsigned long a;
printk("Entering SMP Mode...\n");
-
+ /* let other processors know to not do certain initialization */
first_cpu_booted = 1;
- /*dcbf(&first_cpu_booted);*/
+
+ /*
+ * assume for now that the first cpu booted is
+ * cpu 0, the master -- Cort
+ */
+ cpu_callin_map[0] = 1;
+ cpu_callin_map[1] = 0;
+ smp_store_cpu_info(0);
+ active_kernel_processor = 0;
+ current->processor = 0;
for (i = 0; i < NR_CPUS; i++) {
prof_counter[i] = 1;
prof_multiplier[i] = 1;
}
- cpu_callin_map[0] = 1;
- smp_store_cpu_info(0);
- active_kernel_processor = 0;
- current->processor = 0;
-
/*
* XXX very rough, assumes 20 bus cycles to read a cache line,
* timebase increments every 4 bus cycles, 32kB L1 data cache.
*/
cacheflush_time = 5 * 1024;
- if ( _machine != _MACH_Pmac )
+ if ( !(_machine & (_MACH_Pmac|_MACH_chrp)) )
{
printk("SMP not supported on this machine.\n");
return;
}
- /* create a process for second processor */
- kernel_thread(start_secondary, NULL, CLONE_PID);
- p = task[1];
- if ( !p )
- panic("No idle task for secondary processor\n");
- p->processor = 1;
- p->has_cpu = 1;
- current_set[1] = p;
-
- /* need to flush here since secondary bat's aren't setup */
- /* XXX ??? */
- for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32)
- asm volatile("dcbf 0,%0" : : "r" (a) : "memory");
- asm volatile("sync");
-
- /*dcbf((void *)&current_set[1]);*/
- /* setup entry point of secondary processor */
- *(volatile unsigned long *)(0xf2800000) =
- (unsigned long)__secondary_start-KERNELBASE;
- eieio();
- /* interrupt secondary to begin executing code */
- *(volatile unsigned long *)(0xf80000c0) = ~0L;
- eieio();
- *(volatile unsigned long *)(0xf80000c0) = 0L;
- eieio();
+ switch ( _machine )
+ {
+ case _MACH_Pmac:
+ /* assume powersurge board - 2 processors -- Cort */
+ smp_num_cpus = 2;
+ break;
+ case _MACH_chrp:
+ smp_num_cpus = ((openpic_read(&OpenPIC->Global.Feature_Reporting0)
+ & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
+ OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT)+1;
+ /* get our processor # - we may not be cpu 0 */
+ printk("SMP %d processors, boot CPU is %d (should be 0)\n",
+ smp_num_cpus,
+ 10/*openpic_read(&OpenPIC->Processor[0]._Who_Am_I)*/);
+ break;
+ }
+
/*
- * wait to see if the secondary made a callin (is actually up).
- * udelay() isn't accurate here since we haven't yet called
- * calibrate_delay() so use this value that I found through
- * experimentation. -- Cort
+ * only check for cpus we know exist. We keep the callin map
+ * with cpus at the bottom -- Cort
*/
- for ( i = 1000; i && !cpu_callin_map[1] ; i-- )
- udelay(100);
+ for ( i = 1 ; i < smp_num_cpus; i++ )
+ {
+ int c;
+
+ /* create a process for the processor */
+ kernel_thread(start_secondary, NULL, CLONE_PID);
+ p = task[i];
+ if ( !p )
+ panic("No idle task for secondary processor\n");
+ p->processor = i;
+ p->has_cpu = 1;
+ current_set[i] = p;
+
+ /* need to flush here since secondary bats aren't setup */
+ for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32)
+ asm volatile("dcbf 0,%0" : : "r" (a) : "memory");
+ asm volatile("sync");
+
+ /* wake up cpus */
+ switch ( _machine )
+ {
+ case _MACH_Pmac:
+ /* setup entry point of secondary processor */
+ *(volatile unsigned long *)(0xf2800000) =
+ (unsigned long)__secondary_start_psurge-KERNELBASE;
+ eieio();
+ /* interrupt secondary to begin executing code */
+ out_be32(PSURGE_INTR, ~0);
+ out_be32(PSURGE_INTR, 0);
+ break;
+ case _MACH_chrp:
+ *(unsigned long *)KERNELBASE = i;
+ asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
+ break;
+ }
+
+ /*
+ * wait to see if the cpu made a callin (is actually up).
+ * use this value that I found through experimentation.
+ * -- Cort
+ */
+ for ( c = 1000; c && !cpu_callin_map[i] ; c-- )
+ udelay(100);
+
+ if ( cpu_callin_map[i] )
+ {
+ printk("Processor %d found.\n", i);
+ /* this sync's the decr's -- Cort */
+ if ( _machine == _MACH_Pmac )
+ set_dec(decrementer_count);
+ } else {
+ printk("Processor %d is stuck.\n", i);
+ }
+ }
- if(cpu_callin_map[1]) {
- printk("Processor %d found.\n", smp_num_cpus);
- smp_num_cpus++;
-#if 1 /* this sync's the decr's, but we don't want this now -- Cort */
- set_dec(decrementer_count);
-#endif
- } else {
- printk("Processor %d is stuck. \n", smp_num_cpus);
+ if ( _machine == _MACH_Pmac )
+ {
+ /* reset the entry point so if we get another intr we won't
+ * try to startup again */
+ *(volatile unsigned long *)(0xf2800000) = 0x100;
+ /* send interrupt to other processors to start decr's on all cpus */
+ smp_message_pass(1,0xf0f0, 0, 0);
}
- /* reset the entry point so if we get another intr we won't
- * try to startup again */
- *(volatile unsigned long *)(0xf2800000) = 0x100;
- /* send interrupt to other processors to start decr's on all cpus */
- smp_message_pass(1,0xf0f0, 0, 0);
}
void __init smp_commence(void)
@@ -308,7 +400,6 @@ void __init smp_callin(void)
while(!smp_commenced)
barrier();
__sti();
- printk("SMP %d: smp_callin done\n", current->processor);
}
void __init smp_setup(char *str, int *ints)
diff --git a/arch/ppc/kernel/softemu8xx.c b/arch/ppc/kernel/softemu8xx.c
index ae44266f7..b90760d7e 100644
--- a/arch/ppc/kernel/softemu8xx.c
+++ b/arch/ppc/kernel/softemu8xx.c
@@ -38,6 +38,7 @@
#define LFDU 51
#define STFD 54
#define STFDU 55
+#define FMR 63
/*
* We return 0 on success, 1 on unimplemented instruction, and EFAULT
@@ -49,6 +50,7 @@ Soft_emulate_8xx(struct pt_regs *regs)
uint inst, instword;
uint flreg, idxreg, disp;
uint retval;
+ signed short sdisp;
uint *ea, *ip;
retval = 0;
@@ -66,6 +68,11 @@ Soft_emulate_8xx(struct pt_regs *regs)
switch ( inst )
{
case LFD:
+ /* this is a 16 bit quantity that is sign extended
+ * so use a signed short here -- Cort
+ */
+ sdisp = (instword & 0xffff);
+ ea = (uint *)(regs->gpr[idxreg] + sdisp);
if (copy_from_user(ip, ea, sizeof(double)))
retval = EFAULT;
break;
@@ -77,6 +84,11 @@ Soft_emulate_8xx(struct pt_regs *regs)
regs->gpr[idxreg] = (uint)ea;
break;
case STFD:
+ /* this is a 16 bit quantity that is sign extended
+ * so use a signed short here -- Cort
+ */
+ sdisp = (instword & 0xffff);
+ ea = (uint *)(regs->gpr[idxreg] + sdisp);
if (copy_to_user(ea, ip, sizeof(double)))
retval = EFAULT;
break;
@@ -87,6 +99,11 @@ Soft_emulate_8xx(struct pt_regs *regs)
else
regs->gpr[idxreg] = (uint)ea;
break;
+ case FMR:
+ /* assume this is a fp move -- Cort */
+ memcpy( ip, &current->tss.fpr[(instword>>11)&0x1f],
+ sizeof(double) );
+ break;
default:
retval = 1;
printk("Bad emulation %s/%d\n"
@@ -98,7 +115,7 @@ Soft_emulate_8xx(struct pt_regs *regs)
(instword>>16)&0x1f,
(instword>>11)&0x1f,
(instword>>6)&0x1f,
- (instword>>1)&0x1f,
+ (instword>>1)&0x3ff,
instword&1);
{
int pa;
diff --git a/arch/ppc/kernel/syscalls.c b/arch/ppc/kernel/syscalls.c
index b97456226..4d96a6f0a 100644
--- a/arch/ppc/kernel/syscalls.c
+++ b/arch/ppc/kernel/syscalls.c
@@ -205,12 +205,15 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
lock_kernel();
if (!(flags & MAP_ANONYMOUS)) {
- if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+ file = fget(fd);
+ if (!file)
goto out;
}
flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
ret = do_mmap(file, addr, len, prot, flags, offset);
+ if (file)
+ fput(file);
out:
unlock_kernel();
return ret;
diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c
index 32f60a236..6f0eb798b 100644
--- a/arch/ppc/kernel/time.c
+++ b/arch/ppc/kernel/time.c
@@ -1,5 +1,5 @@
/*
- * $Id: time.c,v 1.39 1998/12/28 10:28:51 paulus Exp $
+ * $Id: time.c,v 1.47 1999/03/18 05:11:11 cort Exp $
* Common time routines among all ppc machines.
*
* Written by Cort Dougan (cort@cs.nmt.edu) to merge
@@ -18,8 +18,8 @@
* Since it is not possible to get a nice 100 Hz clock out of this, without
* creating a software PLL, I have set HZ to 128. -- Dan
*
- * 1997-09-10 Updated NTP code according to technical memorandum Jan '96
- * "A Kernel Model for Precision Timekeeping" by Dave Mills
+ * 1997-09-10 Updated NTP code according to technical memorandum Jan '96
+ * "A Kernel Model for Precision Timekeeping" by Dave Mills
*/
#include <linux/config.h>
@@ -41,18 +41,14 @@
#include <asm/processor.h>
#include <asm/nvram.h>
#include <asm/cache.h>
-#ifdef CONFIG_MBX
-#include <asm/mbx.h>
-#endif
+/* Fixme - Why is this here? - Corey */
#ifdef CONFIG_8xx
#include <asm/8xx_immap.h>
#endif
+#include <asm/machdep.h>
#include "time.h"
-/* this is set to the appropriate pmac/prep/chrp func in init_IRQ() */
-int (*set_rtc_time)(unsigned long);
-
void smp_local_timer_interrupt(struct pt_regs *);
/* keep track of when we need to update the rtc */
@@ -76,9 +72,6 @@ void timer_interrupt(struct pt_regs * regs)
{
int dval, d;
unsigned long cpu = smp_processor_id();
- /* save the HID0 in case dcache was off - see idle.c
- * this hack should leave for a better solution -- Cort */
- unsigned dcache_locked = unlock_dcache();
hardirq_enter(cpu);
#ifdef __SMP__
@@ -119,16 +112,21 @@ void timer_interrupt(struct pt_regs * regs)
*/
if ( xtime.tv_sec > last_rtc_update + 660 )
{
- if (set_rtc_time(xtime.tv_sec) == 0)
+ if (ppc_md.set_rtc_time(xtime.tv_sec) == 0) {
last_rtc_update = xtime.tv_sec;
- else
- last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+ }
+ else {
+ /* do it again in 60 s */
+ last_rtc_update = xtime.tv_sec - 60;
+ }
}
}
}
#ifdef __SMP__
smp_local_timer_interrupt(regs);
#endif
+
+ /* Fixme - make this more generic - Corey */
#ifdef CONFIG_APUS
{
extern void apus_heartbeat (void);
@@ -136,33 +134,8 @@ void timer_interrupt(struct pt_regs * regs)
}
#endif
hardirq_exit(cpu);
- /* restore the HID0 in case dcache was off - see idle.c
- * this hack should leave for a better solution -- Cort */
- lock_dcache(dcache_locked);
}
-#ifdef CONFIG_MBX
-/* A place holder for time base interrupts, if they are ever enabled.
-*/
-void timebase_interrupt(int irq, void * dev, struct pt_regs * regs)
-{
- printk("timebase_interrupt()\n");
-}
-
-/* The RTC on the MPC8xx is an internal register.
- * We want to protect this during power down, so we need to unlock,
- * modify, and re-lock.
- */
-static int
-mbx_set_rtc_time(unsigned long time)
-{
- ((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY;
- ((immap_t *)IMAP_ADDR)->im_sit.sit_rtc = time;
- ((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY;
- return(0);
-}
-#endif /* CONFIG_MBX */
-
/*
* This version of gettimeofday has microsecond resolution.
*/
@@ -198,9 +171,9 @@ void do_settimeofday(struct timeval *tv)
xtime.tv_sec = tv->tv_sec;
xtime.tv_usec = tv->tv_usec - frac_tick;
set_dec(frac_tick * count_period_den / count_period_num);
- time_adjust = 0; /* stop active adjtime() */
+ time_adjust = 0; /* stop active adjtime() */
time_status |= STA_UNSYNC;
- time_state = TIME_ERROR; /* p. 24, (a) */
+ time_state = TIME_ERROR; /* p. 24, (a) */
time_maxerror = NTP_PHASE_LIMIT;
time_esterror = NTP_PHASE_LIMIT;
restore_flags(flags);
@@ -209,81 +182,23 @@ void do_settimeofday(struct timeval *tv)
__initfunc(void time_init(void))
{
-#ifndef CONFIG_MBX
+ if (ppc_md.time_init != NULL)
+ {
+ ppc_md.time_init();
+ }
+
if ((_get_PVR() >> 16) == 1) {
/* 601 processor: dec counts down by 128 every 128ns */
decrementer_count = DECREMENTER_COUNT_601;
count_period_num = COUNT_PERIOD_NUM_601;
count_period_den = COUNT_PERIOD_DEN_601;
+ } else if (!smp_processor_id()) {
+ ppc_md.calibrate_decr();
}
- switch (_machine) {
- case _MACH_Pmac:
- xtime.tv_sec = pmac_get_rtc_time();
- if ( (_get_PVR() >> 16) != 1 && (!smp_processor_id()) )
- pmac_calibrate_decr();
- if ( !smp_processor_id() )
- set_rtc_time = pmac_set_rtc_time;
- break;
- case _MACH_chrp:
- chrp_time_init();
- xtime.tv_sec = chrp_get_rtc_time();
- if ((_get_PVR() >> 16) != 1)
- chrp_calibrate_decr();
- set_rtc_time = chrp_set_rtc_time;
- break;
- case _MACH_prep:
- xtime.tv_sec = prep_get_rtc_time();
- prep_calibrate_decr();
- set_rtc_time = prep_set_rtc_time;
- break;
-#ifdef CONFIG_APUS
- case _MACH_apus:
- {
- xtime.tv_sec = apus_get_rtc_time();
- apus_calibrate_decr();
- set_rtc_time = apus_set_rtc_time;
- break;
- }
-#endif
- }
- xtime.tv_usec = 0;
-#else /* CONFIG_MBX */
- mbx_calibrate_decr();
- set_rtc_time = mbx_set_rtc_time;
-
- /* First, unlock all of the registers we are going to modify.
- * To protect them from corruption during power down, registers
- * that are maintained by keep alive power are "locked". To
- * modify these registers we have to write the key value to
- * the key location associated with the register.
- */
- ((immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk = KAPWR_KEY;
- ((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck = KAPWR_KEY;
-
+ xtime.tv_sec = ppc_md.get_rtc_time();
+ xtime.tv_usec = 0;
- /* Disable the RTC one second and alarm interrupts.
- */
- ((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc &=
- ~(RTCSC_SIE | RTCSC_ALE);
-
- /* Enabling the decrementer also enables the timebase interrupts
- * (or from the other point of view, to get decrementer interrupts
- * we have to enable the timebase). The decrementer interrupt
- * is wired into the vector table, nothing to do here for that.
- */
- ((immap_t *)IMAP_ADDR)->im_sit.sit_tbscr =
- ((mk_int_int_mask(DEC_INTERRUPT) << 8) |
- (TBSCR_TBF | TBSCR_TBE));
- if (request_irq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint", NULL) != 0)
- panic("Could not allocate timer IRQ!");
-
- /* Get time from the RTC.
- */
- xtime.tv_sec = ((immap_t *)IMAP_ADDR)->im_sit.sit_rtc;
- xtime.tv_usec = 0;
-
-#endif /* CONFIG_MBX */
set_dec(decrementer_count);
/* mark the rtc/on-chip timer as in sync
* so we don't update right away
@@ -291,109 +206,6 @@ __initfunc(void time_init(void))
last_rtc_update = xtime.tv_sec;
}
-#ifndef CONFIG_MBX
-/*
- * 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
- */
-int calibrate_done = 0;
-volatile int *done_ptr = &calibrate_done;
-__initfunc(void prep_calibrate_decr(void))
-{
- unsigned long flags;
-
- /* the Powerstack II's have trouble with the timer so
- * we use a default value -- Cort
- */
- if ( (_prep_type == _PREP_Motorola) &&
- ((inb(0x800) & 0xF0) & 0x40) )
- {
- unsigned long freq, divisor;
- static unsigned long t2 = 0;
-
- t2 = 998700000/60;
- freq = t2 * 60; /* try to make freq/1e6 an integer */
- divisor = 60;
- printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n",
- freq, divisor,t2>>20);
- decrementer_count = freq / HZ / divisor;
- count_period_num = divisor;
- count_period_den = freq / 1000000;
- return;
- }
-
-
- 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();
- while ( ! *done_ptr ) /* nothing */; /* wait for calibrate */
- restore_flags(flags);
- free_irq( 0, NULL);
-}
-
-__initfunc(void prep_calibrate_decr_handler(int irq, void *dev, struct pt_regs * regs))
-{
- unsigned long freq, divisor;
- static unsigned long t1 = 0, t2 = 0;
-
- if ( !t1 )
- t1 = get_dec();
- else if (!t2)
- {
- t2 = get_dec();
- t2 = t1-t2; /* decr's in 1/HZ */
- t2 = t2*HZ; /* # decrs in 1s - thus in Hz */
- freq = t2 * 60; /* try to make freq/1e6 an integer */
- divisor = 60;
- printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n",
- freq, divisor,t2>>20);
- decrementer_count = freq / HZ / divisor;
- count_period_num = divisor;
- count_period_den = freq / 1000000;
- *done_ptr = 1;
- }
-}
-
-#else /* CONFIG_MBX */
-
-/* The decrementer counts at the system (internal) clock frequency divided by
- * sixteen, or external oscillator divided by four. Currently, we only
- * support the MBX, which is system clock divided by sixteen.
- */
-__initfunc(void mbx_calibrate_decr(void))
-{
- bd_t *binfo = (bd_t *)res;
- int freq, fp, divisor;
-
- if ((((immap_t *)IMAP_ADDR)->im_clkrst.car_sccr & 0x02000000) == 0)
- printk("WARNING: Wrong decrementer source clock.\n");
-
- /* The manual says the frequency is in Hz, but it is really
- * as MHz. The value 'fp' is the number of decrementer ticks
- * per second.
- */
- fp = (binfo->bi_intfreq * 1000000) / 16;
- freq = fp*60; /* try to make freq/1e6 an integer */
- divisor = 60;
- printk("time_init: decrementer frequency = %d/%d\n", freq, divisor);
- decrementer_count = freq / HZ / divisor;
- count_period_num = divisor;
- count_period_den = freq / 1000000;
-}
-#endif /* CONFIG_MBX */
-
/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
* Assumes input in normal date format, i.e. 1980-12-31 23:59:59
* => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
@@ -439,6 +251,49 @@ 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;
@@ -467,6 +322,11 @@ void to_tm(int tim, struct rtc_time * tm)
/* Days are what is left over (+1) from all that. */
tm->tm_mday = day + 1;
+
+ /*
+ * Determine the day of week
+ */
+ GregorianDay(tm);
}
diff --git a/arch/ppc/kernel/time.h b/arch/ppc/kernel/time.h
index 64a07250c..a1c912308 100644
--- a/arch/ppc/kernel/time.h
+++ b/arch/ppc/kernel/time.h
@@ -1,5 +1,5 @@
/*
- * $Id: time.h,v 1.10 1998/04/01 07:46:03 geert Exp $
+ * $Id: time.h,v 1.11 1999/03/18 04:16:34 cort Exp $
* Common time prototypes and such for all ppc machines.
*
* Written by Cort Dougan (cort@cs.nmt.edu) to merge
@@ -9,32 +9,15 @@
#include <linux/mc146818rtc.h>
/* time.c */
-void prep_calibrate_decr_handler(int, void *,struct pt_regs *);
-void prep_calibrate_decr(void);
-void pmac_calibrate_decr(void);
-extern void apus_calibrate_decr(void);
extern unsigned decrementer_count;
extern unsigned count_period_num;
extern unsigned count_period_den;
-extern unsigned long mktime(unsigned int, unsigned int,unsigned int,
+extern unsigned long mktime(unsigned int, unsigned int, unsigned int,
unsigned int, unsigned int, unsigned int);
extern void to_tm(int tim, struct rtc_time * tm);
extern unsigned long last_rtc_update;
-/* pmac/prep/chrp_time.c */
-unsigned long prep_get_rtc_time(void);
-unsigned long pmac_get_rtc_time(void);
-unsigned long chrp_get_rtc_time(void);
-unsigned long apus_get_rtc_time(void);
-int prep_set_rtc_time(unsigned long nowtime);
-int pmac_set_rtc_time(unsigned long nowtime);
-int chrp_set_rtc_time(unsigned long nowtime);
-int apus_set_rtc_time(unsigned long nowtime);
-void pmac_read_rtc_time(void);
-void chrp_calibrate_decr(void);
-void chrp_time_init(void);
int via_calibrate_decr(void);
-void mbx_calibrate_decr(void);
/* Accessor functions for the decrementer register. */
static __inline__ unsigned int get_dec(void)
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
index fa5184af2..87cc2bd68 100644
--- a/arch/ppc/kernel/traps.c
+++ b/arch/ppc/kernel/traps.c
@@ -191,13 +191,8 @@ AlignmentException(struct pt_regs *regs)
{
int fixed;
-#ifdef __SMP__
- if (regs->msr & MSR_FP )
- smp_giveup_fpu(current);
-#else
- if (last_task_used_math == current)
- giveup_fpu();
-#endif
+ if (regs->msr & MSR_FP)
+ giveup_fpu(current);
fixed = fix_alignment(regs);
if (fixed == 1) {
regs->nip += 4; /* skip over emulated instruction */