summaryrefslogtreecommitdiffstats
path: root/arch/alpha/kernel
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-03-17 22:05:47 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-03-17 22:05:47 +0000
commit27cfca1ec98e91261b1a5355d10a8996464b63af (patch)
tree8e895a53e372fa682b4c0a585b9377d67ed70d0e /arch/alpha/kernel
parent6a76fb7214c477ccf6582bd79c5b4ccc4f9c41b1 (diff)
Look Ma' what I found on my harddisk ...
o New faster syscalls for 2.1.x, too o Upgrade to 2.1.89. Don't try to run this. It's flaky as hell. But feel free to debug ...
Diffstat (limited to 'arch/alpha/kernel')
-rw-r--r--arch/alpha/kernel/Makefile26
-rw-r--r--arch/alpha/kernel/alpha_ksyms.c36
-rw-r--r--arch/alpha/kernel/apecs.c83
-rw-r--r--arch/alpha/kernel/bios32.c1277
-rw-r--r--arch/alpha/kernel/cia.c302
-rw-r--r--arch/alpha/kernel/entry.S61
-rw-r--r--arch/alpha/kernel/fpreg.c104
-rw-r--r--arch/alpha/kernel/head.S60
-rw-r--r--arch/alpha/kernel/irq.c969
-rw-r--r--arch/alpha/kernel/lca.c207
-rw-r--r--arch/alpha/kernel/osf_sys.c68
-rw-r--r--arch/alpha/kernel/process.c42
-rw-r--r--arch/alpha/kernel/pyxis.c557
-rw-r--r--arch/alpha/kernel/setup.c148
-rw-r--r--arch/alpha/kernel/signal.c2
-rw-r--r--arch/alpha/kernel/smc37c669.c2583
-rw-r--r--arch/alpha/kernel/smc37c93x.c264
-rw-r--r--arch/alpha/kernel/t2.c599
-rw-r--r--arch/alpha/kernel/traps.c20
19 files changed, 6472 insertions, 936 deletions
diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile
index 260ac7bff..ba0aee556 100644
--- a/arch/alpha/kernel/Makefile
+++ b/arch/alpha/kernel/Makefile
@@ -16,9 +16,33 @@ all: kernel.o head.o
O_TARGET := kernel.o
O_OBJS := entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \
- bios32.o ptrace.o time.o apecs.o lca.o cia.o
+ bios32.o ptrace.o time.o fpreg.o
OX_OBJS := alpha_ksyms.o
+
+ifdef CONFIG_ALPHA_APECS
+O_OBJS += apecs.o
+endif
+ifdef CONFIG_ALPHA_CIA
+O_OBJS += cia.o
+endif
+ifdef CONFIG_ALPHA_LCA
+O_OBJS += lca.o
+endif
+ifdef CONFIG_ALPHA_PYXIS
+O_OBJS += pyxis.o
+endif
+ifdef CONFIG_ALPHA_T2
+O_OBJS += t2.o
+endif
+ifneq ($(CONFIG_ALPHA_PC164)$(CONFIG_ALPHA_LX164),nn)
+O_OBJS += smc37c93x.o
+endif
+ifdef CONFIG_ALPHA_SX164
+O_OBJS += smc37c669.o
+endif
+
+
all: kernel.o head.o
head.o: head.s
diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c
index 822513e4e..53741095c 100644
--- a/arch/alpha/kernel/alpha_ksyms.c
+++ b/arch/alpha/kernel/alpha_ksyms.c
@@ -21,10 +21,13 @@
#include <asm/checksum.h>
#include <linux/interrupt.h>
#include <asm/softirq.h>
+#include <asm/fpu.h>
+
+#define __KERNEL_SYSCALLS__
+#include <asm/unistd.h>
extern void bcopy (const char *src, char *dst, int len);
extern struct hwrpb_struct *hwrpb;
-extern long __kernel_thread(unsigned long, int (*)(void *), void *);
extern void dump_thread(struct pt_regs *, struct user *);
extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
@@ -38,7 +41,7 @@ extern void __remlu (void);
extern void __divqu (void);
extern void __remqu (void);
-EXPORT_SYMBOL(__alpha_bh_counter);
+EXPORT_SYMBOL(local_bh_count);
EXPORT_SYMBOL(local_irq_count);
/* platform dependent support */
@@ -54,6 +57,9 @@ EXPORT_SYMBOL(_readl);
EXPORT_SYMBOL(_writeb);
EXPORT_SYMBOL(_writew);
EXPORT_SYMBOL(_writel);
+EXPORT_SYMBOL(_memcpy_fromio);
+EXPORT_SYMBOL(_memcpy_toio);
+EXPORT_SYMBOL(_memset_io);
EXPORT_SYMBOL(insb);
EXPORT_SYMBOL(insw);
EXPORT_SYMBOL(insl);
@@ -71,6 +77,7 @@ EXPORT_SYMBOL(strncat);
EXPORT_SYMBOL(strstr);
EXPORT_SYMBOL(strtok);
EXPORT_SYMBOL(strchr);
+EXPORT_SYMBOL(strrchr);
EXPORT_SYMBOL(memcmp);
EXPORT_SYMBOL(memmove);
EXPORT_SYMBOL(__memcpy);
@@ -81,14 +88,35 @@ EXPORT_SYMBOL(dump_thread);
EXPORT_SYMBOL(dump_fpu);
EXPORT_SYMBOL(hwrpb);
EXPORT_SYMBOL(wrusp);
-EXPORT_SYMBOL(__kernel_thread);
EXPORT_SYMBOL(start_thread);
+EXPORT_SYMBOL(alpha_read_fp_reg);
+EXPORT_SYMBOL(alpha_write_fp_reg);
+
+/* In-kernel system calls. */
+EXPORT_SYMBOL(__kernel_thread);
+EXPORT_SYMBOL(sys_open);
+EXPORT_SYMBOL(sys_dup);
+EXPORT_SYMBOL(sys_exit);
+EXPORT_SYMBOL(sys_write);
+EXPORT_SYMBOL(sys_read);
+EXPORT_SYMBOL(sys_lseek);
+EXPORT_SYMBOL(__kernel_execve);
+EXPORT_SYMBOL(sys_setsid);
+EXPORT_SYMBOL(sys_sync);
+EXPORT_SYMBOL(sys_wait4);
/* Networking helper routines. */
EXPORT_SYMBOL(csum_tcpudp_magic);
-EXPORT_SYMBOL(ip_fast_csum);
EXPORT_SYMBOL(ip_compute_csum);
+EXPORT_SYMBOL(ip_fast_csum);
EXPORT_SYMBOL(csum_partial_copy);
+EXPORT_SYMBOL(csum_partial_copy_from_user);
+EXPORT_SYMBOL(csum_ipv6_magic);
+
+#ifdef CONFIG_MATHEMU_MODULE
+extern long (*alpha_fp_emul_imprecise)(struct pt_regs *, unsigned long);
+EXPORT_SYMBOL(alpha_fp_emul_imprecise);
+#endif
/*
* The following are specially called from the uaccess assembly stubs.
diff --git a/arch/alpha/kernel/apecs.c b/arch/alpha/kernel/apecs.c
index 124c5b58e..d5e7fa2a7 100644
--- a/arch/alpha/kernel/apecs.c
+++ b/arch/alpha/kernel/apecs.c
@@ -18,15 +18,18 @@
#include <asm/hwrpb.h>
#include <asm/ptrace.h>
+/* NOTE: Herein are back-to-back mb insns. They are magic.
+ A plausible explanation is that the i/o controler does not properly
+ handle the system transaction. Another involves timing. Ho hum. */
+
extern struct hwrpb_struct *hwrpb;
extern asmlinkage void wrmces(unsigned long mces);
extern int alpha_sys_type;
+
/*
* BIOS32-style PCI interface:
*/
-#ifdef CONFIG_ALPHA_APECS
-
#ifdef DEBUG
# define DBG(args) printk args
#else
@@ -88,7 +91,8 @@ static int mk_conf_addr(unsigned char bus, unsigned char device_fn,
{
unsigned long addr;
- DBG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, pci_addr=0x%p, type1=0x%p)\n",
+ DBG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x,"
+ " pci_addr=0x%p, type1=0x%p)\n",
bus, device_fn, where, pci_addr, type1));
if (bus == 0) {
@@ -97,7 +101,8 @@ static int mk_conf_addr(unsigned char bus, unsigned char device_fn,
/* type 0 configuration cycle: */
if (device > 20) {
- DBG(("mk_conf_addr: device (%d) > 20, returning -1\n", device));
+ DBG(("mk_conf_addr: device (%d) > 20, returning -1\n",
+ device));
return -1;
}
@@ -142,15 +147,15 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1)
DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1));
/* reset status register to avoid losing errors: */
- stat0 = *((volatile unsigned int *)APECS_IOC_DCSR);
- *((volatile unsigned int *)APECS_IOC_DCSR) = stat0;
+ stat0 = *(vuip)APECS_IOC_DCSR;
+ *(vuip)APECS_IOC_DCSR = stat0;
mb();
DBG(("conf_read: APECS DCSR was 0x%x\n", stat0));
/* if Type1 access, must set HAE #2 */
if (type1) {
- haxr2 = *((unsigned int *)APECS_IOC_HAXR2);
+ haxr2 = *(vuip)APECS_IOC_HAXR2;
mb();
- *((unsigned int *)APECS_IOC_HAXR2) = haxr2 | 1;
+ *(vuip)APECS_IOC_HAXR2 = haxr2 | 1;
DBG(("conf_read: TYPE1 access\n"));
}
@@ -159,9 +164,9 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1)
apecs_mcheck_taken = 0;
mb();
/* access configuration space: */
- value = *((volatile unsigned int *)addr);
- mb();
+ value = *(vuip)addr;
mb();
+ mb(); /* magic */
if (apecs_mcheck_taken) {
apecs_mcheck_taken = 0;
value = 0xffffffffU;
@@ -169,17 +174,18 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1)
}
apecs_mcheck_expected = 0;
mb();
+
+#if 1
/*
* david.rusling@reo.mts.dec.com. This code is needed for the
* EB64+ as it does not generate a machine check (why I don't
* know). When we build kernels for one particular platform
* then we can make this conditional on the type.
*/
-#if 1
draina();
/* now look for any errors */
- stat0 = *((unsigned int *)APECS_IOC_DCSR);
+ stat0 = *(vuip)APECS_IOC_DCSR;
DBG(("conf_read: APECS DCSR after read 0x%x\n", stat0));
if (stat0 & 0xffe0U) { /* is any error bit set? */
/* if not NDEV, print status */
@@ -188,7 +194,7 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1)
}
/* reset error status: */
- *((volatile unsigned long *)APECS_IOC_DCSR) = stat0;
+ *(vulp)APECS_IOC_DCSR = stat0;
mb();
wrmces(0x7); /* reset machine check */
value = 0xffffffff;
@@ -197,7 +203,7 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1)
/* if Type1 access, must reset HAE #2 so normal IO space ops work */
if (type1) {
- *((unsigned int *)APECS_IOC_HAXR2) = haxr2 & ~1;
+ *(vuip)APECS_IOC_HAXR2 = haxr2 & ~1;
mb();
}
restore_flags(flags);
@@ -224,37 +230,38 @@ static void conf_write(unsigned long addr, unsigned int value, unsigned char typ
cli();
/* reset status register to avoid losing errors: */
- stat0 = *((volatile unsigned int *)APECS_IOC_DCSR);
- *((volatile unsigned int *)APECS_IOC_DCSR) = stat0;
+ stat0 = *(vuip)APECS_IOC_DCSR;
+ *(vuip)APECS_IOC_DCSR = stat0;
mb();
/* if Type1 access, must set HAE #2 */
if (type1) {
- haxr2 = *((unsigned int *)APECS_IOC_HAXR2);
+ haxr2 = *(vuip)APECS_IOC_HAXR2;
mb();
- *((unsigned int *)APECS_IOC_HAXR2) = haxr2 | 1;
+ *(vuip)APECS_IOC_HAXR2 = haxr2 | 1;
}
draina();
apecs_mcheck_expected = 1;
mb();
/* access configuration space: */
- *((volatile unsigned int *)addr) = value;
- mb();
+ *(vuip)addr = value;
mb();
+ mb(); /* magic */
apecs_mcheck_expected = 0;
mb();
+
+#if 1
/*
* david.rusling@reo.mts.dec.com. This code is needed for the
* EB64+ as it does not generate a machine check (why I don't
* know). When we build kernels for one particular platform
* then we can make this conditional on the type.
*/
-#if 1
draina();
/* now look for any errors */
- stat0 = *((unsigned int *)APECS_IOC_DCSR);
+ stat0 = *(vuip)APECS_IOC_DCSR;
if (stat0 & 0xffe0U) { /* is any error bit set? */
/* if not NDEV, print status */
if (!(stat0 & 0x0800)) {
@@ -262,7 +269,7 @@ static void conf_write(unsigned long addr, unsigned int value, unsigned char typ
}
/* reset error status: */
- *((volatile unsigned long *)APECS_IOC_DCSR) = stat0;
+ *(vulp)APECS_IOC_DCSR = stat0;
mb();
wrmces(0x7); /* reset machine check */
}
@@ -270,7 +277,7 @@ static void conf_write(unsigned long addr, unsigned int value, unsigned char typ
/* if Type1 access, must reset HAE #2 so normal IO space ops work */
if (type1) {
- *((unsigned int *)APECS_IOC_HAXR2) = haxr2 & ~1;
+ *(vuip)APECS_IOC_HAXR2 = haxr2 & ~1;
mb();
}
restore_flags(flags);
@@ -433,7 +440,7 @@ unsigned long apecs_init(unsigned long mem_start, unsigned long mem_end)
#ifdef CONFIG_ALPHA_CABRIOLET
/*
* JAE: HACK!!! for now, hardwire if configured...
- * davidm: Older miniloader versions don't set the clockfrequency
+ * davidm: Older miniloader versions don't set the clock frequency
* right, so hardcode it for now.
*/
if (hwrpb->sys_type == ST_DEC_EB64P) {
@@ -448,7 +455,9 @@ unsigned long apecs_init(unsigned long mem_start, unsigned long mem_end)
unsigned long *l, sum;
sum = 0;
- for (l = (unsigned long *) hwrpb; l < (unsigned long *) &hwrpb->chksum; ++l)
+ for (l = (unsigned long *) hwrpb;
+ l < (unsigned long *) &hwrpb->chksum;
+ ++l)
sum += *l;
hwrpb->chksum = sum;
}
@@ -462,10 +471,10 @@ unsigned long apecs_init(unsigned long mem_start, unsigned long mem_end)
*/
{
#if 0
- unsigned int haxr2 = *((unsigned int *)APECS_IOC_HAXR2); mb();
+ unsigned int haxr2 = *(vuip)APECS_IOC_HAXR2; mb();
if (haxr2) printk("apecs_init: HAXR2 was 0x%x\n", haxr2);
#endif
- *((unsigned int *)APECS_IOC_HAXR2) = 0; mb();
+ *(vuip)APECS_IOC_HAXR2 = 0; mb();
}
@@ -474,15 +483,15 @@ unsigned long apecs_init(unsigned long mem_start, unsigned long mem_end)
int apecs_pci_clr_err(void)
{
- apecs_jd = *((unsigned long *)APECS_IOC_DCSR);
+ apecs_jd = *(vulp)APECS_IOC_DCSR;
if (apecs_jd & 0xffe0L) {
- apecs_jd1 = *((unsigned long *)APECS_IOC_SEAR);
- *((unsigned long *)APECS_IOC_DCSR) = apecs_jd | 0xffe1L;
- apecs_jd = *((unsigned long *)APECS_IOC_DCSR);
+ apecs_jd1 = *(vulp)APECS_IOC_SEAR;
+ *(vulp)APECS_IOC_DCSR = apecs_jd | 0xffe1L;
+ apecs_jd = *(vulp)APECS_IOC_DCSR;
mb();
}
- *((unsigned long *)APECS_IOC_TBIA) = APECS_IOC_TBIA;
- apecs_jd2 = *((unsigned long *)APECS_IOC_TBIA);
+ *(vulp)APECS_IOC_TBIA = APECS_IOC_TBIA;
+ apecs_jd2 = *(vulp)APECS_IOC_TBIA;
mb();
return 0;
}
@@ -536,7 +545,7 @@ void apecs_machine_check(unsigned long vector, unsigned long la_ptr,
apecs_mcheck_expected = 0;
apecs_mcheck_taken = 1;
mb();
- mb();
+ mb(); /* magic */
apecs_pci_clr_err();
wrmces(0x7);
mb();
@@ -547,7 +556,8 @@ void apecs_machine_check(unsigned long vector, unsigned long la_ptr,
wrmces(0x1f); /* disable correctable from now on */
mb();
draina();
- printk("apecs_machine_check: HW correctable (0x%lx)\n", vector);
+ printk("apecs_machine_check: HW correctable (0x%lx)\n",
+ vector);
}
else {
printk(KERN_CRIT "APECS machine check:\n");
@@ -572,4 +582,3 @@ void apecs_machine_check(unsigned long vector, unsigned long la_ptr,
#endif
}
}
-#endif /* CONFIG_ALPHA_APECS */
diff --git a/arch/alpha/kernel/bios32.c b/arch/alpha/kernel/bios32.c
index 851d33be7..9fbc46fd8 100644
--- a/arch/alpha/kernel/bios32.c
+++ b/arch/alpha/kernel/bios32.c
@@ -27,6 +27,8 @@
#include <linux/kernel.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <asm/dma.h>
#if 0
# define DBG_DEVS(args) printk args
@@ -40,13 +42,15 @@ int pcibios_present(void)
{
return 0;
}
+
asmlinkage int sys_pciconfig_read()
{
- return 0;
+ return -ENOSYS;
}
+
asmlinkage int sys_pciconfig_write()
{
- return 0;
+ return -ENOSYS;
}
#else /* CONFIG_PCI */
@@ -95,31 +99,76 @@ asmlinkage int sys_pciconfig_write()
extern struct hwrpb_struct *hwrpb;
+/* Forward declarations for some extra fixup routines for specific hardware. */
+#if defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164)
+extern int SMC93x_Init(void);
+#endif
+#ifdef CONFIG_ALPHA_SX164
+extern int SMC669_Init(void);
+#endif
+#ifdef CONFIG_ALPHA_MIATA
+static int es1888_init(void);
+#endif
#if PCI_MODIFY
-/* NOTE: we can't just blindly use 64K for machines with EISA busses; they
- may also have PCI-PCI bridges present, and then we'd configure the bridge
- incorrectly */
-#if 0
-static unsigned int io_base = 64*KB; /* <64KB are (E)ISA ports */
+/*
+ * NOTE: we can't just blindly use 64K for machines with EISA busses; they
+ * may also have PCI-PCI bridges present, and then we'd configure the bridge
+ * incorrectly
+ *
+ * Also, we start at 0x8000 or 0x9000, in hopes to get all devices'
+ * IO space areas allocated *before* 0xC000; this is because certain
+ * BIOSes (Millennium for one) use PCI Config space "mechanism #2"
+ * accesses to probe the bus. If a device's registers appear at 0xC000,
+ * it may see an INx/OUTx at that address during BIOS emulation of the
+ * VGA BIOS, and some cards, notably Adaptec 2940UW, take mortal offense.
+ */
+#if defined(CONFIG_ALPHA_EISA)
+static unsigned int io_base = 0x9000; /* start above 8th slot */
#else
-static unsigned int io_base = 0xb000;
+static unsigned int io_base = 0x8000;
#endif
#if defined(CONFIG_ALPHA_XL)
/*
- an AVANTI *might* be an XL, and an XL has only 27 bits of ISA address
- that get passed through the PCI<->ISA bridge chip. Because this causes
- us to set the PCI->Mem window bases lower than normal, we've gotta allocate
- PCI bus devices' memory addresses *above* the PCI<->memory mapping windows,
- so that CPU memory DMA addresses issued by a bus device don't conflict
- with bus memory addresses, like frame buffer memory for graphics cards.
-*/
-static unsigned int mem_base = 1024*MB;
-#else /* CONFIG_ALPHA_XL */
-static unsigned int mem_base = 16*MB; /* <16MB is ISA memory */
-#endif /* CONFIG_ALPHA_XL */
+ * An XL is AVANTI (APECS) family, *but* it has only 27 bits of ISA address
+ * that get passed through the PCI<->ISA bridge chip. Although this causes
+ * us to set the PCI->Mem window bases lower than normal, we still allocate
+ * PCI bus devices' memory addresses *below* the low DMA mapping window,
+ * and hope they fit below 64Mb (to avoid conflicts), and so that they can
+ * be accessed via SPARSE space.
+ *
+ * We accept the risk that a broken Myrinet card will be put into a true XL
+ * and thus can more easily run into the problem described below.
+ */
+static unsigned int mem_base = 16*MB + 2*MB; /* 16M to 64M-1 is avail */
+
+#elif defined(CONFIG_ALPHA_LCA) || defined(CONFIG_ALPHA_APECS)
+/*
+ * We try to make this address *always* have more than 1 bit set.
+ * this is so that devices like the broken Myrinet card will always have
+ * a PCI memory address that will never match a IDSEL address in
+ * PCI Config space, which can cause problems with early rev cards.
+ *
+ * However, APECS and LCA have only 34 bits for physical addresses, thus
+ * limiting PCI bus memory addresses for SPARSE access to be less than 128Mb.
+ */
+static unsigned int mem_base = 64*MB + 2*MB;
+
+#else
+/*
+ * We try to make this address *always* have more than 1 bit set.
+ * this is so that devices like the broken Myrinet card will always have
+ * a PCI memory address that will never match a IDSEL address in
+ * PCI Config space, which can cause problems with early rev cards.
+ *
+ * Because CIA and PYXIS and T2 have more bits for physical addresses,
+ * they support an expanded range of SPARSE memory addresses.
+ */
+static unsigned int mem_base = 128*MB + 16*MB;
+
+#endif
/*
* Disable PCI device DEV so that it does not respond to I/O or memory
@@ -130,14 +179,23 @@ static void disable_dev(struct pci_dev *dev)
struct pci_bus *bus;
unsigned short cmd;
-#if defined(CONFIG_ALPHA_MIKASA) || defined(CONFIG_ALPHA_ALCOR)
+#ifdef CONFIG_ALPHA_EISA
/*
* HACK: the PCI-to-EISA bridge does not seem to identify
* itself as a bridge... :-(
*/
- if (dev->vendor == 0x8086 && dev->device == 0x0482) {
- DBG_DEVS(("disable_dev: ignoring PCEB...\n"));
- return;
+ if (dev->vendor == PCI_VENDOR_ID_INTEL &&
+ dev->device == PCI_DEVICE_ID_INTEL_82375) {
+ DBG_DEVS(("disable_dev: ignoring PCEB...\n"));
+ return;
+ }
+#endif
+#ifdef CONFIG_ALPHA_SX164
+ if (dev->vendor == PCI_VENDOR_ID_CONTAQ &&
+ /* FIXME: We want a symbolic device name here. */
+ dev->device == 0xc693) {
+ DBG_DEVS(("disable_dev: ignoring CYPRESS bridge...\n"));
+ return;
}
#endif
@@ -153,7 +211,7 @@ static void disable_dev(struct pci_dev *dev)
/*
* Layout memory and I/O for a device:
*/
-#define MAX(val1, val2) ( ((val1) > (val2)) ? val1 : val2)
+#define MAX(val1, val2) ((val1) > (val2) ? val1 : val2)
static void layout_dev(struct pci_dev *dev)
{
@@ -162,14 +220,22 @@ static void layout_dev(struct pci_dev *dev)
unsigned int base, mask, size, reg;
unsigned int alignto;
-#if defined(CONFIG_ALPHA_MIKASA) || defined(CONFIG_ALPHA_ALCOR)
+#ifdef CONFIG_ALPHA_EISA
/*
* HACK: the PCI-to-EISA bridge does not seem to identify
* itself as a bridge... :-(
*/
- if (dev->vendor == 0x8086 && dev->device == 0x0482) {
- DBG_DEVS(("layout_dev: ignoring PCEB...\n"));
- return;
+ if (dev->vendor == PCI_VENDOR_ID_INTEL &&
+ dev->device == PCI_DEVICE_ID_INTEL_82375) {
+ DBG_DEVS(("layout_dev: ignoring PCEB...\n"));
+ return;
+ }
+#endif
+#ifdef CONFIG_ALPHA_SX164
+ if (dev->vendor == PCI_VENDOR_ID_CONTAQ &&
+ dev->device == 0xc693) {
+ DBG_DEVS(("layout_dev: ignoring CYPRESS bridge...\n"));
+ return;
}
#endif
@@ -203,12 +269,23 @@ static void layout_dev(struct pci_dev *dev)
base &= PCI_BASE_ADDRESS_IO_MASK;
mask = (~base << 1) | 0x1;
size = (mask & base) & 0xffffffff;
- /* align to multiple of size of minimum base */
- alignto = MAX(0x400, size) ;
- base = ALIGN(io_base, alignto );
+ /*
+ * Aligning to 0x800 rather than the minimum base of
+ * 0x400 is an attempt to avoid having devices in
+ * any 0x?C?? range, which is where the de4x5 driver
+ * probes for EISA cards.
+ *
+ * Adaptecs, especially, resent such intrusions.
+ */
+ alignto = MAX(0x800, size);
+ base = ALIGN(io_base, alignto);
io_base = base + size;
pcibios_write_config_dword(bus->number, dev->devfn,
reg, base | 0x1);
+ dev->base_address[(reg - PCI_BASE_ADDRESS_0)>>2]
+ = base | 0x1;
+ DBG_DEVS(("layout_dev: dev 0x%x IO @ 0x%x (0x%x)\n",
+ dev->device, base, size));
} else {
unsigned int type;
/*
@@ -220,10 +297,10 @@ static void layout_dev(struct pci_dev *dev)
mask = (~base << 1) | 0x1;
size = (mask & base) & 0xffffffff;
switch (type) {
- case PCI_BASE_ADDRESS_MEM_TYPE_32:
+ case PCI_BASE_ADDRESS_MEM_TYPE_32:
break;
- case PCI_BASE_ADDRESS_MEM_TYPE_64:
+ case PCI_BASE_ADDRESS_MEM_TYPE_64:
printk("bios32 WARNING: "
"ignoring 64-bit device in "
"slot %d, function %d: \n",
@@ -232,7 +309,7 @@ static void layout_dev(struct pci_dev *dev)
reg += 4; /* skip extra 4 bytes */
continue;
- case PCI_BASE_ADDRESS_MEM_TYPE_1M:
+ case PCI_BASE_ADDRESS_MEM_TYPE_1M:
/*
* Allocating memory below 1MB is *very*
* tricky, as there may be all kinds of
@@ -242,9 +319,9 @@ static void layout_dev(struct pci_dev *dev)
* Alpha (or that the console has set it
* up properly).
*/
- printk("bios32 WARNING: slot %d, function %d "
- "requests memory below 1MB---don't "
- "know how to do that.\n",
+ printk("bios32 WARNING: slot %d, function %d"
+ " requests memory below 1MB---don't"
+ " know how to do that.\n",
PCI_SLOT(dev->devfn),
PCI_FUNC(dev->devfn));
continue;
@@ -265,13 +342,13 @@ static void layout_dev(struct pci_dev *dev)
* dense memory space only!
*/
/* align to multiple of size of minimum base */
- alignto = MAX(0x1000, size) ;
+ alignto = MAX(0x1000, size);
base = ALIGN(mem_base, alignto);
if (size > 7 * 16*MB) {
- printk("bios32 WARNING: slot %d, function %d "
- "requests %dB of contiguous address "
- " space---don't use sparse memory "
- " accesses on this device!!\n",
+ printk("bios32 WARNING: slot %d, function %d"
+ " requests 0x%x bytes of contiguous"
+ " address space---don't use sparse"
+ " memory accesses on this device!!\n",
PCI_SLOT(dev->devfn),
PCI_FUNC(dev->devfn), size);
} else {
@@ -280,7 +357,7 @@ static void layout_dev(struct pci_dev *dev)
base += 16*MB;
base = ALIGN(base, alignto);
}
- if (base / (128*MB) != (base + size) / (128*MB)) {
+ if (base/(128*MB) != (base + size)/(128*MB)) {
base &= ~(128*MB - 1);
base += (128 + 16)*MB;
base = ALIGN(base, alignto);
@@ -289,13 +366,17 @@ static void layout_dev(struct pci_dev *dev)
mem_base = base + size;
pcibios_write_config_dword(bus->number, dev->devfn,
reg, base);
+ dev->base_address[(reg-PCI_BASE_ADDRESS_0)>>2] = base;
+ DBG_DEVS(("layout_dev: dev 0x%x MEM @ 0x%x (0x%x)\n",
+ dev->device, base, size));
}
}
- /* enable device: */
+
+ /* Enable device: */
if (dev->class >> 8 == PCI_CLASS_NOT_DEFINED ||
dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA ||
- dev->class >> 8 == PCI_CLASS_DISPLAY_VGA ||
- dev->class >> 8 == PCI_CLASS_DISPLAY_XGA)
+ dev->class >> 8 == PCI_CLASS_STORAGE_IDE ||
+ dev->class >> 16 == PCI_BASE_CLASS_DISPLAY)
{
/*
* All of these (may) have I/O scattered all around
@@ -308,8 +389,11 @@ static void layout_dev(struct pci_dev *dev)
pcibios_write_config_word(bus->number, dev->devfn, PCI_COMMAND,
cmd | PCI_COMMAND_MASTER);
- DBG_DEVS(("layout_dev: bus %d slot 0x%x VID 0x%x DID 0x%x class 0x%x\n",
- bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device, dev->class));
+
+ DBG_DEVS(("layout_dev: bus %d slot %d VID 0x%x DID 0x%x"
+ " class 0x%x cmd 0 x%x\n",
+ bus->number, PCI_SLOT(dev->devfn), dev->vendor,
+ dev->device, dev->class, cmd|PCI_COMMAND_MASTER));
}
@@ -322,7 +406,7 @@ static void layout_bus(struct pci_bus *bus)
DBG_DEVS(("layout_bus: starting bus %d\n", bus->number));
if (!bus->devices && !bus->children)
- return;
+ return;
/*
* Align the current bases on appropriate boundaries (4K for
@@ -341,8 +425,9 @@ static void layout_bus(struct pci_bus *bus)
* decoders are programmed consistently.
*/
for (dev = bus->devices; dev; dev = dev->sibling) {
- if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) {
- disable_dev(dev) ;
+ if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) ||
+ (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA)) {
+ disable_dev(dev);
}
}
@@ -352,7 +437,8 @@ static void layout_bus(struct pci_bus *bus)
DBG_DEVS(("layout_bus: starting bus %d devices\n", bus->number));
for (dev = bus->devices; dev; dev = dev->sibling) {
- if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) {
+ if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) ||
+ (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA)) {
layout_dev(dev);
}
}
@@ -378,7 +464,8 @@ static void layout_bus(struct pci_bus *bus)
*/
pcibios_read_config_dword(bridge->bus->number, bridge->devfn,
0x1c, &l);
- l = (l & 0xffff0000) | ((bio >> 8) & 0x00f0) | ((tio - 1) & 0xf000);
+ l &= 0xffff0000;
+ l |= ((bio >> 8) & 0x00f0) | ((tio - 1) & 0xf000);
pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
0x1c, l);
/*
@@ -504,9 +591,10 @@ static inline void enable_ide(long ide_base)
}
/*
- * A small note about bridges and interrupts. The DECchip 21050 (and later chips)
- * adheres to the PCI-PCI bridge specification. This says that the interrupts on
- * the other side of a bridge are swizzled in the following manner:
+ * A small note about bridges and interrupts. The DECchip 21050 (and later)
+ * adheres to the PCI-PCI bridge specification. This says that the
+ * interrupts on the other side of a bridge are swizzled in the following
+ * manner:
*
* Dev Interrupt Interrupt
* Pin on Pin on
@@ -538,64 +626,89 @@ static inline void enable_ide(long ide_base)
* The following code is somewhat simplistic as it assumes only one bridge.
* I will fix it later (david.rusling@reo.mts.dec.com).
*/
-static inline unsigned char bridge_swizzle(unsigned char pin, unsigned int slot)
+static inline unsigned char
+bridge_swizzle(unsigned char pin, unsigned int slot)
{
/* swizzle */
- return (((pin-1) + slot) % 4) + 1 ;
+ return (((pin-1) + slot) % 4) + 1;
}
/*
- * Most evaluation boards share most of the fixup code, which is isolated here.
- * This function is declared "inline" as only one platform will ever be selected
- * in any given kernel. If that platform doesn't need this code, we don't want
- * it around as dead code.
+ * Most evaluation boards share most of the fixup code, which is isolated
+ * here. This function is declared "inline" as only one platform will ever
+ * be selected in any given kernel. If that platform doesn't need this code,
+ * we don't want it around as dead code.
*/
-static inline void common_fixup(long min_idsel, long max_idsel, long irqs_per_slot,
- char irq_tab[max_idsel - min_idsel + 1][irqs_per_slot],
- long ide_base)
+static inline void
+common_fixup(long min_idsel, long max_idsel, long irqs_per_slot,
+ char irq_tab[max_idsel - min_idsel + 1][irqs_per_slot],
+ long ide_base)
{
struct pci_dev *dev;
unsigned char pin;
- unsigned char slot ;
+ unsigned char slot;
/*
* Go through all devices, fixing up irqs as we see fit:
*/
for (dev = pci_devices; dev; dev = dev->next) {
- if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE
-#if defined(CONFIG_ALPHA_MIKASA) || defined(CONFIG_ALPHA_ALCOR)
- /* PCEB (PCI to EISA bridge) does not identify
- itself as a bridge... :-( */
- && !((dev->vendor==0x8086) && (dev->device==0x482))
-#endif
- ) {
- dev->irq = 0;
+ if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE
+ /* PCEB (PCI to EISA bridge) does not identify
+ itself as a bridge... :-P */
+ && !(dev->vendor == PCI_VENDOR_ID_INTEL &&
+ dev->device == PCI_DEVICE_ID_INTEL_82375))
+ || dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA) {
/*
- * This device is not on the primary bus, we need to figure out which
- * interrupt pin it will come in on. We know which slot it will come
- * in on 'cos that slot is where the bridge is. Each time the interrupt
- * line passes through a PCI-PCI bridge we must apply the swizzle function
- * (see the inline static routine above).
+ * This device is not on the primary bus, we need
+ * to figure out which interrupt pin it will come
+ * in on. We know which slot it will come in on
+ * 'cos that slot is where the bridge is. Each
+ * time the interrupt line passes through a PCI-PCI
+ * bridge we must apply the swizzle function (see
+ * the inline static routine above).
*/
+ dev->irq = 0;
if (dev->bus->number != 0) {
- struct pci_dev *curr = dev ;
- /* read the pin and do the PCI-PCI bridge interrupt pin swizzle */
- pcibios_read_config_byte(dev->bus->number, dev->devfn,
- PCI_INTERRUPT_PIN, &pin);
+ struct pci_dev *curr = dev;
+ /* read the pin and do the PCI-PCI bridge
+ interrupt pin swizzle */
+ pcibios_read_config_byte(dev->bus->number,
+ dev->devfn,
+ PCI_INTERRUPT_PIN,
+ &pin);
/* cope with 0 */
- if (pin == 0) pin = 1 ;
- /* follow the chain of bridges, swizzling as we go */
+ if (pin == 0)
+ pin = 1;
+ /* follow the chain of bridges, swizzling
+ as we go */
+#if defined(CONFIG_ALPHA_MIATA)
+ slot = PCI_SLOT(dev->devfn) + 5;
+ DBG_DEVS(("MIATA: bus 1 slot %d pin %d"
+ " irq %d min_idsel %d\n",
+ PCI_SLOT(dev->devfn), pin,
+ irq_tab[slot - min_idsel][pin],
+ min_idsel));
+#elif defined(CONFIG_ALPHA_NORITAKE)
+ /* WAG Alert! */
+ slot = PCI_SLOT(dev->devfn) + 14;
+ DBG_DEVS(("NORITAKE: bus 1 slot %d pin %d"
+ " irq %d min_idsel %d\n",
+ PCI_SLOT(dev->devfn), pin,
+ irq_tab[slot - min_idsel][pin],
+ min_idsel));
+#else
do {
/* swizzle */
- pin = bridge_swizzle(pin, PCI_SLOT(curr->devfn)) ;
+ pin = bridge_swizzle(pin, PCI_SLOT(curr->devfn));
/* move up the chain of bridges */
- curr = curr->bus->self ;
- } while (curr->bus->self) ;
+ curr = curr->bus->self;
+ } while (curr->bus->self);
/* The slot is the slot of the last bridge. */
- slot = PCI_SLOT(curr->devfn) ;
+ slot = PCI_SLOT(curr->devfn);
+#endif /* MIATA */
} else {
/* work out the slot */
- slot = PCI_SLOT(dev->devfn) ;
+ slot = PCI_SLOT(dev->devfn);
/* read the pin */
pcibios_read_config_byte(dev->bus->number,
dev->devfn,
@@ -606,20 +719,79 @@ static inline void common_fixup(long min_idsel, long max_idsel, long irqs_per_sl
dev->irq = irq_tab[slot - min_idsel][pin];
#if PCI_MODIFY
/* tell the device: */
- pcibios_write_config_byte(dev->bus->number, dev->devfn,
- PCI_INTERRUPT_LINE, dev->irq);
+ pcibios_write_config_byte(dev->bus->number,
+ dev->devfn,
+ PCI_INTERRUPT_LINE,
+ dev->irq);
#endif
+
+ DBG_DEVS(("common_fixup: bus %d slot 0x%x"
+ " VID 0x%x DID 0x%x\n"
+ " int_slot 0x%x pin 0x%x"
+ " pirq 0x%x\n",
+ dev->bus->number, PCI_SLOT(dev->devfn),
+ dev->vendor, dev->device,
+ slot, pin, dev->irq));
+
/*
* if it's a VGA, enable its BIOS ROM at C0000
*/
if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) {
- pcibios_write_config_dword(dev->bus->number,
- dev->devfn,
- PCI_ROM_ADDRESS,
- 0x000c0000 | PCI_ROM_ADDRESS_ENABLE);
+ pcibios_write_config_dword(dev->bus->number,
+ dev->devfn,
+ PCI_ROM_ADDRESS,
+ 0x000c0000 | PCI_ROM_ADDRESS_ENABLE);
+ }
+ /*
+ * if it's a SCSI, disable its BIOS ROM
+ */
+ if ((dev->class >> 8) == PCI_CLASS_STORAGE_SCSI) {
+ pcibios_write_config_dword(dev->bus->number,
+ dev->devfn,
+ PCI_ROM_ADDRESS,
+ 0x0000000);
}
}
-
+#ifdef CONFIG_ALPHA_SX164
+ /* If it the CYPRESS PCI-ISA bridge, disable IDE
+ interrupt routing through PCI (ie do through PIC). */
+ else if (dev->vendor == PCI_VENDOR_ID_CONTAQ &&
+ dev->device == 0xc693 &&
+ PCI_FUNC(dev->devfn) == 0) {
+ pcibios_write_config_word(dev->bus->number,
+ dev->devfn, 0x04, 0x0007);
+
+ pcibios_write_config_byte(dev->bus->number,
+ dev->devfn, 0x40, 0x80);
+ pcibios_write_config_byte(dev->bus->number,
+ dev->devfn, 0x41, 0x80);
+ pcibios_write_config_byte(dev->bus->number,
+ dev->devfn, 0x42, 0x80);
+ pcibios_write_config_byte(dev->bus->number,
+ dev->devfn, 0x43, 0x80);
+ pcibios_write_config_byte(dev->bus->number,
+ dev->devfn, 0x44, 0x27);
+ pcibios_write_config_byte(dev->bus->number,
+ dev->devfn, 0x45, 0xe0);
+ pcibios_write_config_byte(dev->bus->number,
+ dev->devfn, 0x48, 0xf0);
+ pcibios_write_config_byte(dev->bus->number,
+ dev->devfn, 0x49, 0x40);
+ pcibios_write_config_byte(dev->bus->number,
+ dev->devfn, 0x4a, 0x00);
+ pcibios_write_config_byte(dev->bus->number,
+ dev->devfn, 0x4b, 0x80);
+ pcibios_write_config_byte(dev->bus->number,
+ dev->devfn, 0x4c, 0x80);
+ pcibios_write_config_byte(dev->bus->number,
+ dev->devfn, 0x4d, 0x70);
+
+ outb(0, DMA1_RESET_REG);
+ outb(0, DMA2_RESET_REG);
+ outb(DMA_MODE_CASCADE, DMA2_MODE_REG);
+ outb(0, DMA2_MASK_REG);
+ }
+#endif /* SX164 */
}
if (ide_base) {
enable_ide(ide_base);
@@ -641,19 +813,19 @@ static inline void common_fixup(long min_idsel, long max_idsel, long irqs_per_sl
*/
static inline void eb66p_fixup(void)
{
- char irq_tab[5][5] = {
- {16+0, 16+0, 16+5, 16+9, 16+13}, /* IdSel 6, slot 0, J25 */
- {16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7, slot 1, J26 */
- { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */
- {16+2, 16+2, 16+7, 16+11, 16+15}, /* IdSel 9, slot 2, J27 */
- {16+3, 16+3, 16+8, 16+12, 16+6} /* IdSel 10, slot 3, J28 */
+ static char irq_tab[5][5] __initdata = {
+ {16+0, 16+0, 16+5, 16+9, 16+13}, /* IdSel 6, slot 0, J25 */
+ {16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7, slot 1, J26 */
+ { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */
+ {16+2, 16+2, 16+7, 16+11, 16+15}, /* IdSel 9, slot 2, J27 */
+ {16+3, 16+3, 16+8, 16+12, 16+6} /* IdSel 10, slot 3, J28 */
};
common_fixup(6, 10, 5, irq_tab, 0x398);
}
/*
- * The PC164 has 19 PCI interrupts, four from each of the four PCI
+ * The PC164/LX164 has 19 PCI interrupts, four from each of the four PCI
* slots, the SIO, PCI/IDE, and USB.
*
* Each of the interrupts can be individually masked. This is
@@ -694,27 +866,24 @@ static inline void eb66p_fixup(void)
*
*/
+#if defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164)
static inline void alphapc164_fixup(void)
{
- extern int SMCInit(void);
- char irq_tab[7][5] = {
- /*
- * int intA intB intC intD
- * ---- ---- ---- ---- ----
- */
- { 16+2, 16+2, 16+9, 16+13, 16+17}, /* IdSel 5, slot 2, J20 */
- { 16+0, 16+0, 16+7, 16+11, 16+15}, /* IdSel 6, slot 0, J29 */
- { 16+1, 16+1, 16+8, 16+12, 16+16}, /* IdSel 7, slot 1, J26 */
- { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */
- { 16+3, 16+3, 16+10, 16+14, 16+18}, /* IdSel 9, slot 3, J19 */
- { 16+6, 16+6, 16+6, 16+6, 16+6}, /* IdSel 10, USB */
- { 16+5, 16+5, 16+5, 16+5, 16+5} /* IdSel 11, IDE */
+ static char irq_tab[7][5] __initdata = {
+ /*INT INTA INTB INTC INTD */
+ { 16+2, 16+2, 16+9, 16+13, 16+17}, /* IdSel 5, slot 2, J20 */
+ { 16+0, 16+0, 16+7, 16+11, 16+15}, /* IdSel 6, slot 0, J29 */
+ { 16+1, 16+1, 16+8, 16+12, 16+16}, /* IdSel 7, slot 1, J26 */
+ { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */
+ { 16+3, 16+3, 16+10, 16+14, 16+18}, /* IdSel 9, slot 3, J19 */
+ { 16+6, 16+6, 16+6, 16+6, 16+6}, /* IdSel 10, USB */
+ { 16+5, 16+5, 16+5, 16+5, 16+5} /* IdSel 11, IDE */
};
common_fixup(5, 11, 5, irq_tab, 0);
-
- SMCInit();
+ SMC93x_Init();
}
+#endif
/*
* The AlphaPC64 is very similar to the EB66+ except that its slots
@@ -731,12 +900,12 @@ static inline void alphapc164_fixup(void)
*/
static inline void cabriolet_fixup(void)
{
- char irq_tab[5][5] = {
- { 16+2, 16+2, 16+7, 16+11, 16+15}, /* IdSel 5, slot 2, J21 */
- { 16+0, 16+0, 16+5, 16+9, 16+13}, /* IdSel 6, slot 0, J19 */
- { 16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7, slot 1, J20 */
- { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */
- { 16+3, 16+3, 16+8, 16+12, 16+16} /* IdSel 9, slot 3, J22 */
+ static char irq_tab[5][5] __initdata = {
+ { 16+2, 16+2, 16+7, 16+11, 16+15}, /* IdSel 5, slot 2, J21 */
+ { 16+0, 16+0, 16+5, 16+9, 16+13}, /* IdSel 6, slot 0, J19 */
+ { 16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7, slot 1, J20 */
+ { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */
+ { 16+3, 16+3, 16+8, 16+12, 16+16} /* IdSel 9, slot 3, J22 */
};
common_fixup(5, 9, 5, irq_tab, 0x398);
@@ -787,12 +956,12 @@ static inline void cabriolet_fixup(void)
*/
static inline void eb66_and_eb64p_fixup(void)
{
- char irq_tab[5][5] = {
- {16+7, 16+7, 16+7, 16+7, 16+7}, /* IdSel 5, slot ?, ?? */
- {16+0, 16+0, 16+2, 16+4, 16+9}, /* IdSel 6, slot ?, ?? */
- {16+1, 16+1, 16+3, 16+8, 16+10}, /* IdSel 7, slot ?, ?? */
- { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */
- {16+6, 16+6, 16+6, 16+6, 16+6}, /* IdSel 9, TULIP */
+ static char irq_tab[5][5] __initdata = {
+ {16+7, 16+7, 16+7, 16+7, 16+7}, /* IdSel 5, slot ?, ?? */
+ {16+0, 16+0, 16+2, 16+4, 16+9}, /* IdSel 6, slot ?, ?? */
+ {16+1, 16+1, 16+3, 16+8, 16+10}, /* IdSel 7, slot ?, ?? */
+ { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */
+ {16+6, 16+6, 16+6, 16+6, 16+6}, /* IdSel 9, TULIP */
};
common_fixup(5, 9, 5, irq_tab, 0);
}
@@ -836,21 +1005,97 @@ static inline void eb66_and_eb64p_fixup(void)
*/
static inline void mikasa_fixup(void)
{
- char irq_tab[8][5] = {
- /*INT INTA INTB INTC INTD */
- {16+12, 16+12, 16+12, 16+12, 16+12}, /* IdSel 17, SCSI */
- { -1, -1, -1, -1, -1}, /* IdSel 18, PCEB */
- { -1, -1, -1, -1, -1}, /* IdSel 19, ???? */
- { -1, -1, -1, -1, -1}, /* IdSel 20, ???? */
- { -1, -1, -1, -1, -1}, /* IdSel 21, ???? */
- { 16+0, 16+0, 16+1, 16+2, 16+3}, /* IdSel 22, slot 0 */
- { 16+4, 16+4, 16+5, 16+6, 16+7}, /* IdSel 23, slot 1 */
- { 16+8, 16+8, 16+9, 16+10, 16+11}, /* IdSel 24, slot 2 */
+ static char irq_tab[8][5] __initdata = {
+ /*INT INTA INTB INTC INTD */
+ {16+12, 16+12, 16+12, 16+12, 16+12}, /* IdSel 17, SCSI */
+ { -1, -1, -1, -1, -1}, /* IdSel 18, PCEB */
+ { -1, -1, -1, -1, -1}, /* IdSel 19, ???? */
+ { -1, -1, -1, -1, -1}, /* IdSel 20, ???? */
+ { -1, -1, -1, -1, -1}, /* IdSel 21, ???? */
+ { 16+0, 16+0, 16+1, 16+2, 16+3}, /* IdSel 22, slot 0 */
+ { 16+4, 16+4, 16+5, 16+6, 16+7}, /* IdSel 23, slot 1 */
+ { 16+8, 16+8, 16+9, 16+10, 16+11}, /* IdSel 24, slot 2 */
};
common_fixup(6, 13, 5, irq_tab, 0);
}
/*
+ * Fixup configuration for NORITAKE (MIKASA is different)
+ *
+ * Summary @ 0x542, summary register #1:
+ * Bit Meaning
+ * 0 All valid ints from summary regs 2 & 3
+ * 1 QLOGIC ISP1020A SCSI
+ * 2 Interrupt Line A from slot 0
+ * 3 Interrupt Line B from slot 0
+ * 4 Interrupt Line A from slot 1
+ * 5 Interrupt line B from slot 1
+ * 6 Interrupt Line A from slot 2
+ * 7 Interrupt Line B from slot 2
+ * 8 Interrupt Line A from slot 3
+ * 9 Interrupt Line B from slot 3
+ *10 Interrupt Line A from slot 4
+ *11 Interrupt Line B from slot 4
+ *12 Interrupt Line A from slot 5
+ *13 Interrupt Line B from slot 5
+ *14 Interrupt Line A from slot 6
+ *15 Interrupt Line B from slot 6
+ *
+ * Summary @ 0x544, summary register #2:
+ * Bit Meaning
+ * 0 OR of all unmasked ints in SR #2
+ * 1 OR of secondary bus ints
+ * 2 Interrupt Line C from slot 0
+ * 3 Interrupt Line D from slot 0
+ * 4 Interrupt Line C from slot 1
+ * 5 Interrupt line D from slot 1
+ * 6 Interrupt Line C from slot 2
+ * 7 Interrupt Line D from slot 2
+ * 8 Interrupt Line C from slot 3
+ * 9 Interrupt Line D from slot 3
+ *10 Interrupt Line C from slot 4
+ *11 Interrupt Line D from slot 4
+ *12 Interrupt Line C from slot 5
+ *13 Interrupt Line D from slot 5
+ *14 Interrupt Line C from slot 6
+ *15 Interrupt Line D from slot 6
+ *
+ * The device to slot mapping looks like:
+ *
+ * Slot Device
+ * 7 Intel PCI-EISA bridge chip
+ * 8 DEC PCI-PCI bridge chip
+ * 11 PCI on board slot 0
+ * 12 PCI on board slot 1
+ * 13 PCI on board slot 2
+ *
+ *
+ * This two layered interrupt approach means that we allocate IRQ 16 and
+ * above for PCI interrupts. The IRQ relates to which bit the interrupt
+ * comes in on. This makes interrupt processing much easier.
+ */
+static inline void noritake_fixup(void)
+{
+ static char irq_tab[13][5] __initdata = {
+ /*INT INTA INTB INTC INTD */
+ { -1, -1, -1, -1, -1}, /* IdSel 18, PCEB */
+ { -1, -1, -1, -1, -1}, /* IdSel 19, PPB */
+ { -1, -1, -1, -1, -1}, /* IdSel 20, ???? */
+ { -1, -1, -1, -1, -1}, /* IdSel 21, ???? */
+ { 16+2, 16+2, 16+3, 32+2, 32+3}, /* IdSel 22, slot 0 */
+ { 16+4, 16+4, 16+5, 32+4, 32+5}, /* IdSel 23, slot 1 */
+ { 16+6, 16+6, 16+7, 32+6, 32+7}, /* IdSel 24, slot 2 */
+ /* The following are actually on bus 1, across the bridge */
+ { 16+1, 16+1, 16+1, 16+1, 16+1}, /* IdSel 16, QLOGIC */
+ { 16+8, 16+8, 16+9, 32+8, 32+9}, /* IdSel 17, slot 3 */
+ {16+10, 16+10, 16+11, 32+10, 32+11}, /* IdSel 18, slot 4 */
+ {16+12, 16+12, 16+13, 32+12, 32+13}, /* IdSel 19, slot 5 */
+ {16+14, 16+14, 16+15, 32+14, 32+15}, /* IdSel 20, slot 6 */
+ };
+ common_fixup(7, 18, 5, irq_tab, 0);
+}
+
+/*
* Fixup configuration for ALCOR
*
* Summary @ GRU_INT_REQ:
@@ -895,14 +1140,14 @@ static inline void mikasa_fixup(void)
*/
static inline void alcor_fixup(void)
{
- char irq_tab[6][5] = {
- /*INT INTA INTB INTC INTD */
- { 16+8, 16+8, 16+9, 16+10, 16+11}, /* IdSel 18, slot 0 */
- {16+16, 16+16, 16+17, 16+18, 16+19}, /* IdSel 19, slot 3 */
- {16+12, 16+12, 16+13, 16+14, 16+15}, /* IdSel 20, slot 4 */
- { -1, -1, -1, -1, -1}, /* IdSel 21, PCEB */
- { 16+0, 16+0, 16+1, 16+2, 16+3}, /* IdSel 22, slot 2 */
- { 16+4, 16+4, 16+5, 16+6, 16+7}, /* IdSel 23, slot 1 */
+ static char irq_tab[6][5] __initdata = {
+ /*INT INTA INTB INTC INTD */
+ { 16+8, 16+8, 16+9, 16+10, 16+11}, /* IdSel 18, slot 0 */
+ {16+16, 16+16, 16+17, 16+18, 16+19}, /* IdSel 19, slot 3 */
+ {16+12, 16+12, 16+13, 16+14, 16+15}, /* IdSel 20, slot 4 */
+ { -1, -1, -1, -1, -1}, /* IdSel 21, PCEB */
+ { 16+0, 16+0, 16+1, 16+2, 16+3}, /* IdSel 22, slot 2 */
+ { 16+4, 16+4, 16+5, 16+6, 16+7}, /* IdSel 23, slot 1 */
};
common_fixup(7, 12, 5, irq_tab, 0);
}
@@ -950,19 +1195,245 @@ static inline void alcor_fixup(void)
*/
static inline void xlt_fixup(void)
{
- char irq_tab[7][5] = {
- /*INT INTA INTB INTC INTD */
- {16+13, 16+13, 16+13, 16+13, 16+13}, /* IdSel 17, TULIP */
- { 16+8, 16+8, 16+9, 16+10, 16+11}, /* IdSel 18, slot 0 */
- { -1, -1, -1, -1, -1}, /* IdSel 19, none */
- {16+12, 16+12, 16+12, 16+12, 16+12}, /* IdSel 20, SCSI */
- { -1, -1, -1, -1, -1}, /* IdSel 21, SIO */
- { 16+0, 16+0, 16+1, 16+2, 16+3}, /* IdSel 22, slot 2 */
- { 16+4, 16+4, 16+5, 16+6, 16+7}, /* IdSel 23, slot 1 */
+ static char irq_tab[7][5] __initdata = {
+ /*INT INTA INTB INTC INTD */
+ {16+13, 16+13, 16+13, 16+13, 16+13}, /* IdSel 17, TULIP */
+ { 16+8, 16+8, 16+9, 16+10, 16+11}, /* IdSel 18, slot 0 */
+ { -1, -1, -1, -1, -1}, /* IdSel 19, none */
+ {16+12, 16+12, 16+12, 16+12, 16+12}, /* IdSel 20, SCSI */
+ { -1, -1, -1, -1, -1}, /* IdSel 21, SIO */
+ { 16+0, 16+0, 16+1, 16+2, 16+3}, /* IdSel 22, slot 2 */
+ { 16+4, 16+4, 16+5, 16+6, 16+7}, /* IdSel 23, slot 1 */
};
common_fixup(6, 12, 5, irq_tab, 0);
}
+/*
+ * Fixup configuration for ALPHA SABLE (2100) - 2100A is different ??
+ *
+ * Summary Registers (536/53a/53c):
+ * Bit Meaning
+ *-----------------
+ * 0 PCI slot 0
+ * 1 NCR810 (builtin)
+ * 2 TULIP (builtin)
+ * 3 mouse
+ * 4 PCI slot 1
+ * 5 PCI slot 2
+ * 6 keyboard
+ * 7 floppy
+ * 8 COM2
+ * 9 parallel port
+ *10 EISA irq 3
+ *11 EISA irq 4
+ *12 EISA irq 5
+ *13 EISA irq 6
+ *14 EISA irq 7
+ *15 COM1
+ *16 EISA irq 9
+ *17 EISA irq 10
+ *18 EISA irq 11
+ *19 EISA irq 12
+ *20 EISA irq 13
+ *21 EISA irq 14
+ *22 NC
+ *23 IIC
+ *
+ * The device to slot mapping looks like:
+ *
+ * Slot Device
+ * 0 TULIP
+ * 1 SCSI
+ * 2 PCI-EISA bridge
+ * 3 none
+ * 4 none
+ * 5 none
+ * 6 PCI on board slot 0
+ * 7 PCI on board slot 1
+ * 8 PCI on board slot 2
+ *
+ *
+ * This two layered interrupt approach means that we allocate IRQ 16 and
+ * above for PCI interrupts. The IRQ relates to which bit the interrupt
+ * comes in on. This makes interrupt processing much easier.
+ */
+/*
+ * NOTE: the IRQ assignments below are arbitrary, but need to be consistent
+ * with the values in the sable_irq_to_mask[] and sable_mask_to_irq[] tables
+ * in irq.c
+ */
+
+#ifdef CONFIG_ALPHA_SABLE
+static inline void sable_fixup(void)
+{
+ static char irq_tab[9][5] __initdata = {
+ /*INT INTA INTB INTC INTD */
+ { 32+0, 32+0, 32+0, 32+0, 32+0}, /* IdSel 0, TULIP */
+ { 32+1, 32+1, 32+1, 32+1, 32+1}, /* IdSel 1, SCSI */
+ { -1, -1, -1, -1, -1}, /* IdSel 2, SIO */
+ { -1, -1, -1, -1, -1}, /* IdSel 3, none */
+ { -1, -1, -1, -1, -1}, /* IdSel 4, none */
+ { -1, -1, -1, -1, -1}, /* IdSel 5, none */
+ { 32+2, 32+2, 32+2, 32+2, 32+2}, /* IdSel 6, slot 0 */
+ { 32+3, 32+3, 32+3, 32+3, 32+3}, /* IdSel 7, slot 1 */
+ { 32+4, 32+4, 32+4, 32+4, 32+4}, /* IdSel 8, slot 2 */
+ };
+ common_fixup(0, 8, 5, irq_tab, 0);
+}
+#endif
+
+/*
+ * Fixup configuration for MIATA (EV56+PYXIS)
+ *
+ * Summary @ PYXIS_INT_REQ:
+ * Bit Meaning
+ * 0 Fan Fault
+ * 1 NMI
+ * 2 Halt/Reset switch
+ * 3 none
+ * 4 CID0 (Riser ID)
+ * 5 CID1 (Riser ID)
+ * 6 Interval timer
+ * 7 PCI-ISA Bridge
+ * 8 Ethernet
+ * 9 EIDE (deprecated, ISA 14/15 used)
+ *10 none
+ *11 USB
+ *12 Interrupt Line A from slot 4
+ *13 Interrupt Line B from slot 4
+ *14 Interrupt Line C from slot 4
+ *15 Interrupt Line D from slot 4
+ *16 Interrupt Line A from slot 5
+ *17 Interrupt line B from slot 5
+ *18 Interrupt Line C from slot 5
+ *19 Interrupt Line D from slot 5
+ *20 Interrupt Line A from slot 1
+ *21 Interrupt Line B from slot 1
+ *22 Interrupt Line C from slot 1
+ *23 Interrupt Line D from slot 1
+ *24 Interrupt Line A from slot 2
+ *25 Interrupt Line B from slot 2
+ *26 Interrupt Line C from slot 2
+ *27 Interrupt Line D from slot 2
+ *27 Interrupt Line A from slot 3
+ *29 Interrupt Line B from slot 3
+ *30 Interrupt Line C from slot 3
+ *31 Interrupt Line D from slot 3
+ *
+ * The device to slot mapping looks like:
+ *
+ * Slot Device
+ * 3 DC21142 Ethernet
+ * 4 EIDE CMD646
+ * 5 none
+ * 6 USB
+ * 7 PCI-ISA bridge
+ * 8 PCI-PCI Bridge (SBU Riser)
+ * 9 none
+ * 10 none
+ * 11 PCI on board slot 4 (SBU Riser)
+ * 12 PCI on board slot 5 (SBU Riser)
+ *
+ * These are behind the bridge, so I'm not sure what to do...
+ *
+ * 13 PCI on board slot 1 (SBU Riser)
+ * 14 PCI on board slot 2 (SBU Riser)
+ * 15 PCI on board slot 3 (SBU Riser)
+ *
+ *
+ * This two layered interrupt approach means that we allocate IRQ 16 and
+ * above for PCI interrupts. The IRQ relates to which bit the interrupt
+ * comes in on. This makes interrupt processing much easier.
+ */
+
+#ifdef CONFIG_ALPHA_MIATA
+static inline void miata_fixup(void)
+{
+ static char irq_tab[18][5] __initdata = {
+ /*INT INTA INTB INTC INTD */
+ {16+ 8, 16+ 8, 16+ 8, 16+ 8, 16+ 8}, /* IdSel 14, DC21142 */
+ { -1, -1, -1, -1, -1}, /* IdSel 15, EIDE */
+ { -1, -1, -1, -1, -1}, /* IdSel 16, none */
+ { -1, -1, -1, -1, -1}, /* IdSel 17, none */
+/* {16+11, 16+11, 16+11, 16+11, 16+11},*//* IdSel 17, USB ?? */
+ { -1, -1, -1, -1, -1}, /* IdSel 18, PCI-ISA */
+ { -1, -1, -1, -1, -1}, /* IdSel 19, PCI-PCI */
+ { -1, -1, -1, -1, -1}, /* IdSel 20, none */
+ { -1, -1, -1, -1, -1}, /* IdSel 21, none */
+ {16+12, 16+12, 16+13, 16+14, 16+15}, /* IdSel 22, slot 4 */
+ {16+16, 16+16, 16+17, 16+18, 16+19}, /* IdSel 23, slot 5 */
+ /* The following are actually on bus 1, across the bridge */
+ {16+20, 16+20, 16+21, 16+22, 16+23}, /* IdSel 24, slot 1 */
+ {16+24, 16+24, 16+25, 16+26, 16+27}, /* IdSel 25, slot 2 */
+ {16+28, 16+28, 16+29, 16+30, 16+31}, /* IdSel 26, slot 3 */
+ { -1, -1, -1, -1, -1}, /* IdSel 27, none */
+ { -1, -1, -1, -1, -1}, /* IdSel 28, none */
+ { -1, -1, -1, -1, -1}, /* IdSel 29, none */
+ { -1, -1, -1, -1, -1}, /* IdSel 30, none */
+ { -1, -1, -1, -1, -1}, /* IdSel 31, PCI-PCI */
+ };
+ common_fixup(3, 20, 5, irq_tab, 0);
+ es1888_init();
+}
+#endif
+
+/*
+ * Fixup configuration for SX164 (PCA56+PYXIS)
+ *
+ * Summary @ PYXIS_INT_REQ:
+ * Bit Meaning
+ * 0 RSVD
+ * 1 NMI
+ * 2 Halt/Reset switch
+ * 3 MBZ
+ * 4 RAZ
+ * 5 RAZ
+ * 6 Interval timer (RTC)
+ * 7 PCI-ISA Bridge
+ * 8 Interrupt Line A from slot 3
+ * 9 Interrupt Line A from slot 2
+ *10 Interrupt Line A from slot 1
+ *11 Interrupt Line A from slot 0
+ *12 Interrupt Line B from slot 3
+ *13 Interrupt Line B from slot 2
+ *14 Interrupt Line B from slot 1
+ *15 Interrupt line B from slot 0
+ *16 Interrupt Line C from slot 3
+
+ *17 Interrupt Line C from slot 2
+ *18 Interrupt Line C from slot 1
+ *19 Interrupt Line C from slot 0
+ *20 Interrupt Line D from slot 3
+ *21 Interrupt Line D from slot 2
+ *22 Interrupt Line D from slot 1
+ *23 Interrupt Line D from slot 0
+ *
+ * IdSel
+ * 5 32 bit PCI option slot 2
+ * 6 64 bit PCI option slot 0
+ * 7 64 bit PCI option slot 1
+ * 8 Cypress I/O
+ * 9 32 bit PCI option slot 3
+ *
+ */
+
+#ifdef CONFIG_ALPHA_SX164
+static inline void sx164_fixup(void)
+{
+ static char irq_tab[5][5] __initdata = {
+ /*INT INTA INTB INTC INTD */
+ { 16+ 9, 16+ 9, 16+13, 16+17, 16+21}, /* IdSel 5 slot 2 J17 */
+ { 16+11, 16+11, 16+15, 16+19, 16+23}, /* IdSel 6 slot 0 J19 */
+ { 16+10, 16+10, 16+14, 16+18, 16+22}, /* IdSel 7 slot 1 J18 */
+ { -1, -1, -1, -1, -1}, /* IdSel 8 SIO */
+ { 16+ 8, 16+ 8, 16+12, 16+16, 16+20} /* IdSel 9 slot 3 J15 */
+ };
+
+ common_fixup(5, 9, 5, irq_tab, 0);
+
+ SMC669_Init();
+}
+#endif
/*
* Fixup configuration for all boards that route the PCI interrupts
@@ -990,7 +1461,7 @@ static inline void sio_fixup(void)
* that they use the default INTA line, if they are interrupt
* driven at all).
*/
- static const char pirq_tab[][5] = {
+ static const char pirq_tab[][5] __initdata = {
#ifdef CONFIG_ALPHA_P2K
{ 0, 0, -1, -1, -1}, /* idsel 6 (53c810) */
{-1, -1, -1, -1, -1}, /* idsel 7 (SIO: PCI/ISA bridge) */
@@ -1011,6 +1482,8 @@ static inline void sio_fixup(void)
{ 0, 0, 0, 0, 0}, /* idsel 14 AS255 TULIP */
#endif
};
+ const size_t pirq_tab_len = sizeof(pirq_tab)/sizeof(pirq_tab[0]);
+
/*
* route_tab selects irq routing in PCI/ISA bridge so that:
* PIRQ0 -> irq 15
@@ -1021,7 +1494,12 @@ static inline void sio_fixup(void)
* This probably ought to be configurable via MILO. For
* example, sound boards seem to like using IRQ 9.
*/
-#ifdef CONFIG_ALPHA_NONAME
+
+#if defined(CONFIG_ALPHA_BOOK1)
+ /* for the AlphaBook1, NCR810 SCSI is 14, PCMCIA controller is 15 */
+ const unsigned int route_tab = 0x0e0f0a0a;
+
+#elif defined(CONFIG_ALPHA_NONAME)
/*
* For UDB, the only available PCI slot must not map to IRQ 9,
* since that's the builtin MSS sound chip. That PCI slot
@@ -1033,9 +1511,10 @@ static inline void sio_fixup(void)
* selected... :-(
*/
const unsigned int route_tab = 0x0b0a0f09;
-#else /* CONFIG_ALPHA_NONAME */
+#else
const unsigned int route_tab = 0x0b0a090f;
-#endif /* CONFIG_ALPHA_NONAME */
+#endif
+
unsigned int level_bits;
unsigned char pin, slot;
int pirq;
@@ -1047,11 +1526,13 @@ static inline void sio_fixup(void)
*/
level_bits = 0;
for (dev = pci_devices; dev; dev = dev->next) {
- if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE)
+ if ((dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) &&
+ (dev->class >> 8 != PCI_CLASS_BRIDGE_PCMCIA))
continue;
+
dev->irq = 0;
if (dev->bus->number != 0) {
- struct pci_dev *curr = dev ;
+ struct pci_dev *curr = dev;
/*
* read the pin and do the PCI-PCI bridge
* interrupt pin swizzle
@@ -1059,41 +1540,44 @@ static inline void sio_fixup(void)
pcibios_read_config_byte(dev->bus->number, dev->devfn,
PCI_INTERRUPT_PIN, &pin);
/* cope with 0 */
- if (pin == 0) pin = 1 ;
+ if (pin == 0)
+ pin = 1;
/* follow the chain of bridges, swizzling as we go */
do {
/* swizzle */
- pin = bridge_swizzle(pin, PCI_SLOT(curr->devfn)) ;
+ pin = bridge_swizzle(pin, PCI_SLOT(curr->devfn));
/* move up the chain of bridges */
- curr = curr->bus->self ;
- } while (curr->bus->self) ;
+ curr = curr->bus->self;
+ } while (curr->bus->self);
/* The slot is the slot of the last bridge. */
- slot = PCI_SLOT(curr->devfn) ;
+ slot = PCI_SLOT(curr->devfn);
} else {
/* work out the slot */
- slot = PCI_SLOT(dev->devfn) ;
+ slot = PCI_SLOT(dev->devfn);
/* read the pin */
pcibios_read_config_byte(dev->bus->number, dev->devfn,
PCI_INTERRUPT_PIN, &pin);
}
- if (slot < 6 || slot >= 6 + sizeof(pirq_tab)/sizeof(pirq_tab[0])) {
+ if (slot < 6 || slot >= 6 + pirq_tab_len) {
printk("bios32.sio_fixup: "
- "weird, found device %04x:%04x in non-existent slot %d!!\n",
+ "weird, found device %04x:%04x in"
+ " non-existent slot %d!!\n",
dev->vendor, dev->device, slot);
continue;
}
pirq = pirq_tab[slot - 6][pin];
DBG_DEVS(("sio_fixup: bus %d slot 0x%x VID 0x%x DID 0x%x\n"
- " int_slot 0x%x int_pin 0x%x, pirq 0x%x\n",
- dev->bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device,
- slot, pin, pirq));
+ " int_slot 0x%x pin 0x%x pirq 0x%x\n",
+ dev->bus->number, PCI_SLOT(dev->devfn), dev->vendor,
+ dev->device, slot, pin, pirq));
/*
* if it's a VGA, enable its BIOS ROM at C0000
*/
if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) {
- pcibios_write_config_dword(dev->bus->number, dev->devfn,
+ pcibios_write_config_dword(dev->bus->number,
+ dev->devfn,
PCI_ROM_ADDRESS,
0x000c0000 | PCI_ROM_ADDRESS_ENABLE);
}
@@ -1103,22 +1587,60 @@ static inline void sio_fixup(void)
if (pirq < 0) {
printk("bios32.sio_fixup: "
- "weird, device %04x:%04x coming in on slot %d has no irq line!!\n",
+ "weird, device %04x:%04x coming in on"
+ " slot %d has no irq line!!\n",
dev->vendor, dev->device, slot);
continue;
}
dev->irq = (route_tab >> (8 * pirq)) & 0xff;
- /* must set the PCI IRQs to level triggered */
- level_bits |= (1 << dev->irq);
+#ifndef CONFIG_ALPHA_BOOK1
+ /* do not set *ANY* level triggers for AlphaBook1 */
+ /* must set the PCI IRQs to level triggered */
+ level_bits |= (1 << dev->irq);
+#endif /* !CONFIG_ALPHA_BOOK1 */
#if PCI_MODIFY
/* tell the device: */
pcibios_write_config_byte(dev->bus->number, dev->devfn,
PCI_INTERRUPT_LINE, dev->irq);
#endif
- }
+
+#ifdef CONFIG_ALPHA_BOOK1
+ /*
+ * On the AlphaBook1, the PCMCIA chip (Cirrus 6729)
+ * is sensitive to PCI bus bursts, so we must DISABLE
+ * burst mode for the NCR 8xx SCSI... :-(
+ *
+ * Note that the NCR810 SCSI driver must preserve the
+ * setting of the bit in order for this to work. At the
+ * moment (2.0.29), ncr53c8xx.c does NOT do this, but
+ * 53c7,8xx.c DOES.
+ */
+ if (dev->vendor == PCI_VENDOR_ID_NCR &&
+ (dev->device == PCI_DEVICE_ID_NCR_53C810 ||
+ dev->device == PCI_DEVICE_ID_NCR_53C815 ||
+ dev->device == PCI_DEVICE_ID_NCR_53C820 ||
+ dev->device == PCI_DEVICE_ID_NCR_53C825)) {
+ unsigned int io_port;
+ unsigned char ctest4;
+
+ pcibios_read_config_dword(dev->bus->number,
+ dev->devfn,
+ PCI_BASE_ADDRESS_0,
+ &io_port);
+ io_port &= PCI_BASE_ADDRESS_IO_MASK;
+ ctest4 = inb(io_port+0x21);
+ if (!(ctest4 & 0x80)) {
+ printk("AlphaBook1 NCR init: setting"
+ " burst disable\n");
+ outb(ctest4 | 0x80, io_port+0x21);
+ }
+ }
+#endif /* CONFIG_ALPHA_BOOK1 */
+ } /* end for-devs */
+
/*
* Now, make all PCI interrupts level sensitive. Notice:
* these registers must be accessed byte-wise. inw()/outw()
@@ -1128,11 +1650,34 @@ static inline void sio_fixup(void)
* so that the only bits getting set are for devices actually found.
* Note that we do preserve the remainder of the bits, which we hope
* will be set correctly by ARC/SRM.
+ *
+ * Note: we at least preserve any level-set bits on AlphaBook1
*/
level_bits |= ((inb(0x4d0) | (inb(0x4d1) << 8)) & 0x71ff);
outb((level_bits >> 0) & 0xff, 0x4d0);
outb((level_bits >> 8) & 0xff, 0x4d1);
- enable_ide(0x26e);
+
+#ifdef CONFIG_ALPHA_BOOK1
+ {
+ unsigned char orig, config;
+ /* On the AlphaBook1, make sure that register PR1
+ indicates 1Mb mem */
+ outb(0x0f, 0x3ce); orig = inb(0x3cf); /* read PR5 */
+ outb(0x0f, 0x3ce); outb(0x05, 0x3cf); /* unlock PR0-4 */
+ outb(0x0b, 0x3ce); config = inb(0x3cf); /* read PR1 */
+ if ((config & 0xc0) != 0xc0) {
+ printk("AlphaBook1 VGA init: setting 1Mb memory\n");
+ config |= 0xc0;
+ outb(0x0b, 0x3ce); outb(config, 0x3cf); /* write PR1 */
+ }
+ outb(0x0f, 0x3ce); outb(orig, 0x3cf); /* (re)lock PR0-4 */
+ }
+#endif /* CONFIG_ALPHA_BOOK1 */
+
+#ifndef CONFIG_ALPHA_BOOK1
+ /* Do not do IDE init for AlphaBook1 */
+ enable_ide(0x26e);
+#endif
}
@@ -1140,9 +1685,10 @@ static inline void sio_fixup(void)
extern void tga_console_init(void);
#endif /* CONFIG_TGA_CONSOLE */
-unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end)
+unsigned long __init
+pcibios_fixup(unsigned long mem_start, unsigned long mem_end)
{
-#if PCI_MODIFY
+#if PCI_MODIFY && !defined(CONFIG_ALPHA_RUFFIAN)
/*
* Scan the tree, allocating PCI memory and I/O space.
*/
@@ -1152,11 +1698,12 @@ unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end)
/*
* Now is the time to do all those dirty little deeds...
*/
-#if defined(CONFIG_ALPHA_NONAME) || defined(CONFIG_ALPHA_AVANTI) || defined(CONFIG_ALPHA_P2K)
+#if defined(CONFIG_ALPHA_NONAME) || defined(CONFIG_ALPHA_AVANTI) || \
+ defined(CONFIG_ALPHA_P2K)
sio_fixup();
#elif defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB164)
cabriolet_fixup();
-#elif defined(CONFIG_ALPHA_PC164)
+#elif defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164)
alphapc164_fixup();
#elif defined(CONFIG_ALPHA_EB66P)
eb66p_fixup();
@@ -1170,72 +1717,86 @@ unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end)
alcor_fixup();
#elif defined(CONFIG_ALPHA_XLT)
xlt_fixup();
+#elif defined(CONFIG_ALPHA_SABLE)
+ sable_fixup();
+#elif defined(CONFIG_ALPHA_MIATA)
+ miata_fixup();
+#elif defined(CONFIG_ALPHA_NORITAKE)
+ noritake_fixup();
+#elif defined(CONFIG_ALPHA_SX164)
+ sx164_fixup();
+#elif defined(CONFIG_ALPHA_RUFFIAN)
+ /* no fixup needed */
#else
-# error You must tell me what kind of platform you want.
+# error "You must tell me what kind of platform you want."
#endif
+#ifndef CONFIG_ABSTRACT_CONSOLE
#ifdef CONFIG_TGA_CONSOLE
tga_console_init();
-#endif /* CONFIG_TGA_CONSOLE */
+#endif
+#endif
return mem_start;
}
-asmlinkage int sys_pciconfig_read(
- unsigned long bus,
- unsigned long dfn,
- unsigned long off,
- unsigned long len,
- unsigned char *buf)
+asmlinkage int sys_pciconfig_read(unsigned long bus, unsigned long dfn,
+ unsigned long off, unsigned long len,
+ unsigned char *buf)
{
unsigned char ubyte;
unsigned short ushort;
unsigned int uint;
long err = 0;
+ if (!suser())
+ return -EPERM;
+
lock_kernel();
switch (len) {
- case 1:
+ case 1:
err = pcibios_read_config_byte(bus, dfn, off, &ubyte);
if (err != PCIBIOS_SUCCESSFUL)
- ubyte = 0xff;
+ ubyte = 0xff;
put_user(ubyte, buf);
break;
- case 2:
+ case 2:
err = pcibios_read_config_word(bus, dfn, off, &ushort);
if (err != PCIBIOS_SUCCESSFUL)
- ushort = 0xffff;
+ ushort = 0xffff;
put_user(ushort, (unsigned short *)buf);
break;
- case 4:
+ case 4:
err = pcibios_read_config_dword(bus, dfn, off, &uint);
if (err != PCIBIOS_SUCCESSFUL)
- uint = 0xffffffff;
+ uint = 0xffffffff;
put_user(uint, (unsigned int *)buf);
break;
- default:
+ default:
err = -EINVAL;
break;
}
unlock_kernel();
return err;
}
-asmlinkage int sys_pciconfig_write(
- unsigned long bus,
- unsigned long dfn,
- unsigned long off,
- unsigned long len,
- unsigned char *buf)
+
+
+asmlinkage int sys_pciconfig_write(unsigned long bus, unsigned long dfn,
+ unsigned long off, unsigned long len,
+ unsigned char *buf)
{
unsigned char ubyte;
unsigned short ushort;
unsigned int uint;
long err = 0;
+ if (!suser())
+ return -EPERM;
+
lock_kernel();
switch (len) {
- case 1:
+ case 1:
err = get_user(ubyte, buf);
if (err)
break;
@@ -1244,7 +1805,7 @@ asmlinkage int sys_pciconfig_write(
err = -EFAULT;
}
break;
- case 2:
+ case 2:
err = get_user(ushort, (unsigned short *)buf);
if (err)
break;
@@ -1253,7 +1814,7 @@ asmlinkage int sys_pciconfig_write(
err = -EFAULT;
}
break;
- case 4:
+ case 4:
err = get_user(uint, (unsigned int *)buf);
if (err)
break;
@@ -1262,7 +1823,7 @@ asmlinkage int sys_pciconfig_write(
err = -EFAULT;
}
break;
- default:
+ default:
err = -EINVAL;
break;
}
@@ -1270,262 +1831,50 @@ asmlinkage int sys_pciconfig_write(
return err;
}
-#ifdef CONFIG_ALPHA_PC164
-
-/* device "activate" register contents */
-#define DEVICE_ON 1
-#define DEVICE_OFF 0
-
-/* configuration on/off keys */
-#define CONFIG_ON_KEY 0x55
-#define CONFIG_OFF_KEY 0xaa
-
-/* configuration space device definitions */
-#define FDC 0
-#define IDE1 1
-#define IDE2 2
-#define PARP 3
-#define SER1 4
-#define SER2 5
-#define RTCL 6
-#define KYBD 7
-#define AUXIO 8
-
-/* Chip register offsets from base */
-#define CONFIG_CONTROL 0x02
-#define INDEX_ADDRESS 0x03
-#define LOGICAL_DEVICE_NUMBER 0x07
-#define DEVICE_ID 0x20
-#define DEVICE_REV 0x21
-#define POWER_CONTROL 0x22
-#define POWER_MGMT 0x23
-#define OSC 0x24
-
-#define ACTIVATE 0x30
-#define ADDR_HI 0x60
-#define ADDR_LO 0x61
-#define INTERRUPT_SEL 0x70
-#define INTERRUPT_SEL_2 0x72 /* KYBD/MOUS only */
-#define DMA_CHANNEL_SEL 0x74 /* FDC/PARP only */
-
-#define FDD_MODE_REGISTER 0x90
-#define FDD_OPTION_REGISTER 0x91
-
-/* values that we read back that are expected ... */
-#define VALID_DEVICE_ID 2
-
-/* default device addresses */
-#define KYBD_INTERRUPT 1
-#define MOUS_INTERRUPT 12
-#define COM2_BASE 0x2f8
-#define COM2_INTERRUPT 3
-#define COM1_BASE 0x3f8
-#define COM1_INTERRUPT 4
-#define PARP_BASE 0x3bc
-#define PARP_INTERRUPT 7
-
-#define SMC_DEBUG 0
-
-unsigned long SMCConfigState( unsigned long baseAddr )
-{
- unsigned char devId;
- unsigned char devRev;
-
- unsigned long configPort;
- unsigned long indexPort;
- unsigned long dataPort;
-
- configPort = indexPort = baseAddr;
- dataPort = ( unsigned long )( ( char * )configPort + 1 );
-
- outb(CONFIG_ON_KEY, configPort);
- outb(CONFIG_ON_KEY, configPort);
- outb(DEVICE_ID, indexPort);
- devId = inb(dataPort);
- if ( devId == VALID_DEVICE_ID ) {
- outb(DEVICE_REV, indexPort);
- devRev = inb(dataPort);
- }
- else {
- baseAddr = 0;
- }
- return( baseAddr );
-}
-
-void SMCRunState( unsigned long baseAddr )
-{
- outb(CONFIG_OFF_KEY, baseAddr);
-}
-
-unsigned long SMCDetectUltraIO(void)
-{
- unsigned long baseAddr;
-
- baseAddr = 0x3F0;
- if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x3F0 ) {
- return( baseAddr );
- }
- baseAddr = 0x370;
- if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x370 ) {
- return( baseAddr );
- }
- return( ( unsigned long )0 );
-}
-
-void SMCEnableDevice( unsigned long baseAddr,
- unsigned long device,
- unsigned long portaddr,
- unsigned long interrupt)
-{
- unsigned long indexPort;
- unsigned long dataPort;
-
- indexPort = baseAddr;
- dataPort = ( unsigned long )( ( char * )baseAddr + 1 );
-
- outb(LOGICAL_DEVICE_NUMBER, indexPort);
- outb(device, dataPort);
-
- outb(ADDR_LO, indexPort);
- outb(( portaddr & 0xFF ), dataPort);
-
- outb(ADDR_HI, indexPort);
- outb(( ( portaddr >> 8 ) & 0xFF ), dataPort);
-
- outb(INTERRUPT_SEL, indexPort);
- outb(interrupt, dataPort);
-
- outb(ACTIVATE, indexPort);
- outb(DEVICE_ON, dataPort);
-}
-
-void SMCEnableKYBD( unsigned long baseAddr )
-{
- unsigned long indexPort;
- unsigned long dataPort;
-
- indexPort = baseAddr;
- dataPort = ( unsigned long )( ( char * )baseAddr + 1 );
-
- outb(LOGICAL_DEVICE_NUMBER, indexPort);
- outb(KYBD, dataPort);
-
- outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */
- outb(KYBD_INTERRUPT, dataPort);
- outb(INTERRUPT_SEL_2, indexPort);/* Secondary interrupt select */
- outb(MOUS_INTERRUPT, dataPort);
-
- outb(ACTIVATE, indexPort);
- outb(DEVICE_ON, dataPort);
-}
-
-void SMCEnableFDC( unsigned long baseAddr )
-{
- unsigned long indexPort;
- unsigned long dataPort;
-
- unsigned char oldValue;
-
- indexPort = baseAddr;
- dataPort = ( unsigned long )( ( char * )baseAddr + 1 );
-
- outb(LOGICAL_DEVICE_NUMBER, indexPort);
- outb(FDC, dataPort);
-
- outb(FDD_MODE_REGISTER, indexPort);
- oldValue = inb(dataPort);
-
- oldValue |= 0x0E; /* Enable burst mode */
- outb(oldValue, dataPort);
-
- outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */
- outb(0x06, dataPort );
-
- outb(DMA_CHANNEL_SEL, indexPort); /* DMA channel select */
- outb(0x02, dataPort);
-
- outb(ACTIVATE, indexPort);
- outb(DEVICE_ON, dataPort);
-}
-
-#if SMC_DEBUG
-void SMCReportDeviceStatus( unsigned long baseAddr )
-{
- unsigned long indexPort;
- unsigned long dataPort;
- unsigned char currentControl;
-
- indexPort = baseAddr;
- dataPort = ( unsigned long )( ( char * )baseAddr + 1 );
-
- outb(POWER_CONTROL, indexPort);
- currentControl = inb(dataPort);
-
- if ( currentControl & ( 1 << FDC ) )
- printk( "\t+FDC Enabled\n" );
- else
- printk( "\t-FDC Disabled\n" );
-
- if ( currentControl & ( 1 << IDE1 ) )
- printk( "\t+IDE1 Enabled\n" );
- else
- printk( "\t-IDE1 Disabled\n" );
-
- if ( currentControl & ( 1 << IDE2 ) )
- printk( "\t+IDE2 Enabled\n" );
- else
- printk( "\t-IDE2 Disabled\n" );
-
- if ( currentControl & ( 1 << PARP ) )
- printk( "\t+PARP Enabled\n" );
- else
- printk( "\t-PARP Disabled\n" );
-
- if ( currentControl & ( 1 << SER1 ) )
- printk( "\t+SER1 Enabled\n" );
- else
- printk( "\t-SER1 Disabled\n" );
-
- if ( currentControl & ( 1 << SER2 ) )
- printk( "\t+SER2 Enabled\n" );
- else
- printk( "\t-SER2 Disabled\n" );
-
- printk( "\n" );
-}
-#endif
-
-int SMCInit(void)
+#ifdef CONFIG_ALPHA_MIATA
+/*
+ * Init the built-in ES1888 sound chip (SB16 compatible)
+ */
+static int __init
+es1888_init(void)
{
- unsigned long SMCUltraBase;
-
- if ( ( SMCUltraBase = SMCDetectUltraIO( ) ) != ( unsigned long )0 ) {
- printk( "SMC FDC37C93X Ultra I/O Controller found @ 0x%lx\n",
- SMCUltraBase );
-#if SMC_DEBUG
- SMCReportDeviceStatus( SMCUltraBase );
-#endif
- SMCEnableDevice( SMCUltraBase, SER1, COM1_BASE, COM1_INTERRUPT );
- SMCEnableDevice( SMCUltraBase, SER2, COM2_BASE, COM2_INTERRUPT );
- SMCEnableDevice( SMCUltraBase, PARP, PARP_BASE, PARP_INTERRUPT );
- /* on PC164, IDE on the SMC is not enabled; CMD646 (PCI) on MB */
- SMCEnableKYBD( SMCUltraBase );
- SMCEnableFDC( SMCUltraBase );
-#if SMC_DEBUG
- SMCReportDeviceStatus( SMCUltraBase );
-#endif
- SMCRunState( SMCUltraBase );
- return( 1 );
- }
- else {
-#if SMC_DEBUG
- printk( "No SMC FDC37C93X Ultra I/O Controller found\n" );
-#endif
- return( 0 );
- }
+ /* Sequence of IO reads to init the audio controller */
+ inb(0x0229);
+ inb(0x0229);
+ inb(0x0229);
+ inb(0x022b);
+ inb(0x0229);
+ inb(0x022b);
+ inb(0x0229);
+ inb(0x0229);
+ inb(0x022b);
+ inb(0x0229);
+ inb(0x0220); /* This sets the base address to 0x220 */
+
+ /* Sequence to set DMA channels */
+ outb(0x01, 0x0226); /* reset */
+ inb(0x0226); /* pause */
+ outb(0x00, 0x0226); /* release reset */
+ while (!(inb(0x022e) & 0x80)) /* wait for bit 7 to assert*/
+ continue;
+ inb(0x022a); /* pause */
+ outb(0xc6, 0x022c); /* enable extended mode */
+ while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */
+ continue;
+ outb(0xb1, 0x022c); /* setup for write to Interrupt CR */
+ while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */
+ continue;
+ outb(0x14, 0x022c); /* set IRQ 5 */
+ while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */
+ continue;
+ outb(0xb2, 0x022c); /* setup for write to DMA CR */
+ while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */
+ continue;
+ outb(0x18, 0x022c); /* set DMA channel 1 */
+
+ return 0;
}
-
-#endif /* CONFIG_ALPHA_PC164 */
+#endif /* CONFIG_ALPHA_MIATA */
#endif /* CONFIG_PCI */
diff --git a/arch/alpha/kernel/cia.c b/arch/alpha/kernel/cia.c
index 98bc94227..4bebe2732 100644
--- a/arch/alpha/kernel/cia.c
+++ b/arch/alpha/kernel/cia.c
@@ -6,7 +6,6 @@
*
*/
#include <linux/kernel.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/bios32.h>
#include <linux/pci.h>
@@ -18,6 +17,10 @@
#include <asm/ptrace.h>
#include <asm/mmu_context.h>
+/* NOTE: Herein are back-to-back mb insns. They are magic.
+ A plausible explanation is that the i/o controler does not properly
+ handle the system transaction. Another involves timing. Ho hum. */
+
extern struct hwrpb_struct *hwrpb;
extern asmlinkage void wrmces(unsigned long mces);
extern int alpha_sys_type;
@@ -38,12 +41,19 @@ extern int alpha_sys_type;
* BIOS32-style PCI interface:
*/
-#ifdef CONFIG_ALPHA_CIA
+/* #define DEBUG_MCHECK */
+/* #define DEBUG_CONFIG */
+/* #define DEBUG_DUMP_REGS */
-#ifdef DEBUG
-# define DBG(args) printk args
+#ifdef DEBUG_MCHECK
+# define DBGM(args) printk args
+#else
+# define DBGM(args)
+#endif
+#ifdef DEBUG_CONFIG
+# define DBGC(args) printk args
#else
-# define DBG(args)
+# define DBGC(args)
#endif
#define vulp volatile unsigned long *
@@ -51,7 +61,7 @@ extern int alpha_sys_type;
static volatile unsigned int CIA_mcheck_expected = 0;
static volatile unsigned int CIA_mcheck_taken = 0;
-static unsigned long CIA_jd;
+static unsigned int CIA_jd;
/*
@@ -101,8 +111,9 @@ static int mk_conf_addr(unsigned char bus, unsigned char device_fn,
{
unsigned long addr;
- DBG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, pci_addr=0x%p, type1=0x%p)\n",
- bus, device_fn, where, pci_addr, type1));
+ DBGC(("mk_conf_addr(bus=%d, device_fn=0x%x, where=0x%x, "
+ "pci_addr=0x%p, type1=0x%p)\n",
+ bus, device_fn, where, pci_addr, type1));
if (bus == 0) {
int device = device_fn >> 3;
@@ -110,7 +121,8 @@ static int mk_conf_addr(unsigned char bus, unsigned char device_fn,
/* type 0 configuration cycle: */
if (device > 20) {
- DBG(("mk_conf_addr: device (%d) > 20, returning -1\n", device));
+ DBGC(("mk_conf_addr: device (%d) > 20, returning -1\n",
+ device));
return -1;
}
@@ -122,7 +134,7 @@ static int mk_conf_addr(unsigned char bus, unsigned char device_fn,
addr = (bus << 16) | (device_fn << 8) | (where);
}
*pci_addr = addr;
- DBG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
+ DBGC(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
return 0;
}
@@ -133,22 +145,25 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1)
unsigned int stat0, value;
unsigned int cia_cfg = 0; /* to keep gcc quiet */
+ value = 0xffffffffU;
+ mb();
+
save_flags(flags); /* avoid getting hit by machine check */
cli();
- DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1));
+ DBGC(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1));
/* reset status register to avoid losing errors: */
- stat0 = *((volatile unsigned int *)CIA_IOC_CIA_ERR);
- *((volatile unsigned int *)CIA_IOC_CIA_ERR) = stat0;
+ stat0 = *(vuip)CIA_IOC_CIA_ERR;
+ *(vuip)CIA_IOC_CIA_ERR = stat0;
mb();
- DBG(("conf_read: CIA ERR was 0x%x\n", stat0));
+ DBGC(("conf_read: CIA ERR was 0x%x\n", stat0));
/* if Type1 access, must set CIA CFG */
if (type1) {
- cia_cfg = *((unsigned int *)CIA_IOC_CFG);
+ cia_cfg = *(vuip)CIA_IOC_CFG;
+ *(vuip)CIA_IOC_CFG = cia_cfg | 1;
mb();
- *((unsigned int *)CIA_IOC_CFG) = cia_cfg | 1;
- DBG(("conf_read: TYPE1 access\n"));
+ DBGC(("conf_read: TYPE1 access\n"));
}
mb();
@@ -157,9 +172,9 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1)
CIA_mcheck_taken = 0;
mb();
/* access configuration space: */
- value = *((volatile unsigned int *)addr);
- mb();
+ value = *(vuip)addr;
mb();
+ mb(); /* magic */
if (CIA_mcheck_taken) {
CIA_mcheck_taken = 0;
value = 0xffffffffU;
@@ -167,26 +182,25 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1)
}
CIA_mcheck_expected = 0;
mb();
- /*
- * david.rusling@reo.mts.dec.com. This code is needed for the
- * EB64+ as it does not generate a machine check (why I don't
- * know). When we build kernels for one particular platform
- * then we can make this conditional on the type.
- */
+
#if 0
+ /*
+ this code might be necessary if machine checks aren't taken,
+ but I can't get it to work on CIA-2, so its disabled.
+ */
draina();
/* now look for any errors */
- stat0 = *((unsigned int *)CIA_IOC_CIA_ERR);
- DBG(("conf_read: CIA ERR after read 0x%x\n", stat0));
- if (stat0 & 0x8280U) { /* is any error bit set? */
- /* if not NDEV, print status */
+ stat0 = *(vuip)CIA_IOC_CIA_ERR;
+ DBGC(("conf_read: CIA ERR after read 0x%x\n", stat0));
+ if (stat0 & 0x8FEF0FFFU) { /* is any error bit set? */
+ /* if not MAS_ABT, print status */
if (!(stat0 & 0x0080)) {
printk("CIA.c:conf_read: got stat0=%x\n", stat0);
}
/* reset error status: */
- *((volatile unsigned long *)CIA_IOC_CIA_ERR) = stat0;
+ *(vuip)CIA_IOC_CIA_ERR = stat0;
mb();
wrmces(0x7); /* reset machine check */
value = 0xffffffff;
@@ -195,18 +209,19 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1)
/* if Type1 access, must reset IOC CFG so normal IO space ops work */
if (type1) {
- *((unsigned int *)CIA_IOC_CFG) = cia_cfg & ~1;
+ *(vuip)CIA_IOC_CFG = cia_cfg & ~1;
mb();
}
- DBG(("conf_read(): finished\n"));
+ DBGC(("conf_read(): finished\n"));
restore_flags(flags);
return value;
}
-static void conf_write(unsigned long addr, unsigned int value, unsigned char type1)
+static void conf_write(unsigned long addr, unsigned int value,
+ unsigned char type1)
{
unsigned long flags;
unsigned int stat0;
@@ -216,47 +231,47 @@ static void conf_write(unsigned long addr, unsigned int value, unsigned char typ
cli();
/* reset status register to avoid losing errors: */
- stat0 = *((volatile unsigned int *)CIA_IOC_CIA_ERR);
- *((volatile unsigned int *)CIA_IOC_CIA_ERR) = stat0;
+ stat0 = *(vuip)CIA_IOC_CIA_ERR;
+ *(vuip)CIA_IOC_CIA_ERR = stat0;
mb();
- DBG(("conf_write: CIA ERR was 0x%x\n", stat0));
+ DBGC(("conf_write: CIA ERR was 0x%x\n", stat0));
/* if Type1 access, must set CIA CFG */
if (type1) {
- cia_cfg = *((unsigned int *)CIA_IOC_CFG);
+ cia_cfg = *(vuip)CIA_IOC_CFG;
+ *(vuip)CIA_IOC_CFG = cia_cfg | 1;
mb();
- *((unsigned int *)CIA_IOC_CFG) = cia_cfg | 1;
- DBG(("conf_read: TYPE1 access\n"));
+ DBGC(("conf_write: TYPE1 access\n"));
}
draina();
CIA_mcheck_expected = 1;
mb();
/* access configuration space: */
- *((volatile unsigned int *)addr) = value;
- mb();
+ *(vuip)addr = value;
mb();
+ mb(); /* magic */
+
CIA_mcheck_expected = 0;
mb();
+
+#if 0
/*
- * david.rusling@reo.mts.dec.com. This code is needed for the
- * EB64+ as it does not generate a machine check (why I don't
- * know). When we build kernels for one particular platform
- * then we can make this conditional on the type.
+ * This code might be necessary if machine checks aren't taken,
+ * but I can't get it to work on CIA-2, so its disabled.
*/
-#if 0
draina();
- /* now look for any errors */
- stat0 = *((unsigned int *)CIA_IOC_CIA_ERR);
- DBG(("conf_write: CIA ERR after write 0x%x\n", stat0));
- if (stat0 & 0x8280U) { /* is any error bit set? */
- /* if not NDEV, print status */
+ /* Now look for any errors */
+ stat0 = *(vuip)CIA_IOC_CIA_ERR;
+ DBGC(("conf_write: CIA ERR after write 0x%x\n", stat0));
+ if (stat0 & 0x8FEF0FFFU) { /* is any error bit set? */
+ /* If not MAS_ABT, print status */
if (!(stat0 & 0x0080)) {
printk("CIA.c:conf_read: got stat0=%x\n", stat0);
}
/* reset error status: */
- *((volatile unsigned long *)CIA_IOC_CIA_ERR) = stat0;
+ *(vulp)CIA_IOC_CIA_ERR = stat0;
mb();
wrmces(0x7); /* reset machine check */
value = 0xffffffff;
@@ -265,11 +280,11 @@ static void conf_write(unsigned long addr, unsigned int value, unsigned char typ
/* if Type1 access, must reset IOC CFG so normal IO space ops work */
if (type1) {
- *((unsigned int *)CIA_IOC_CFG) = cia_cfg & ~1;
+ *(vuip)CIA_IOC_CFG = cia_cfg & ~1;
mb();
}
- DBG(("conf_write(): finished\n"));
+ DBGC(("conf_write(): finished\n"));
restore_flags(flags);
}
@@ -390,15 +405,58 @@ int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn,
unsigned long cia_init(unsigned long mem_start, unsigned long mem_end)
{
- unsigned int cia_err ;
+ unsigned int cia_tmp;
+
+#ifdef DEBUG_DUMP_REGS
+ {
+ unsigned int temp;
+ temp = *(vuip)CIA_IOC_CIA_REV; mb();
+ printk("CIA_init: CIA_REV was 0x%x\n", temp);
+ temp = *(vuip)CIA_IOC_PCI_LAT; mb();
+ printk("CIA_init: CIA_PCI_LAT was 0x%x\n", temp);
+ temp = *(vuip)CIA_IOC_CIA_CTRL; mb();
+ printk("CIA_init: CIA_CTRL was 0x%x\n", temp);
+ temp = *(vuip)0xfffffc8740000140UL; mb();
+ printk("CIA_init: CIA_CTRL1 was 0x%x\n", temp);
+ temp = *(vuip)CIA_IOC_HAE_MEM; mb();
+ printk("CIA_init: CIA_HAE_MEM was 0x%x\n", temp);
+ temp = *(vuip)CIA_IOC_HAE_IO; mb();
+ printk("CIA_init: CIA_HAE_IO was 0x%x\n", temp);
+ temp = *(vuip)CIA_IOC_CFG; mb();
+ printk("CIA_init: CIA_CFG was 0x%x\n", temp);
+ temp = *(vuip)CIA_IOC_CACK_EN; mb();
+ printk("CIA_init: CIA_CACK_EN was 0x%x\n", temp);
+ temp = *(vuip)CIA_IOC_CFG; mb();
+ printk("CIA_init: CIA_CFG was 0x%x\n", temp);
+ temp = *(vuip)CIA_IOC_CIA_DIAG; mb();
+ printk("CIA_init: CIA_DIAG was 0x%x\n", temp);
+ temp = *(vuip)CIA_IOC_DIAG_CHECK; mb();
+ printk("CIA_init: CIA_DIAG_CHECK was 0x%x\n", temp);
+ temp = *(vuip)CIA_IOC_PERF_MONITOR; mb();
+ printk("CIA_init: CIA_PERF_MONITOR was 0x%x\n", temp);
+ temp = *(vuip)CIA_IOC_PERF_CONTROL; mb();
+ printk("CIA_init: CIA_PERF_CONTROL was 0x%x\n", temp);
+ temp = *(vuip)CIA_IOC_CIA_ERR; mb();
+ printk("CIA_init: CIA_ERR was 0x%x\n", temp);
+ temp = *(vuip)CIA_IOC_CIA_STAT; mb();
+ printk("CIA_init: CIA_STAT was 0x%x\n", temp);
+ temp = *(vuip)CIA_IOC_MCR; mb();
+ printk("CIA_init: CIA_MCR was 0x%x\n", temp);
+ }
+#endif /* DEBUG_DUMP_REGS */
/*
* Set up error reporting.
*/
- cia_err = *(vuip)CIA_IOC_CIA_ERR ;
- cia_err |= (0x1 << 7) ; /* master abort */
- *(vuip)CIA_IOC_CIA_ERR = cia_err ;
- mb() ;
+ cia_tmp = *(vuip)CIA_IOC_CIA_ERR;
+ cia_tmp |= 0x180; /* master, target abort */
+ *(vuip)CIA_IOC_CIA_ERR = cia_tmp;
+ mb();
+
+ cia_tmp = *(vuip)CIA_IOC_CIA_CTRL;
+ cia_tmp |= 0x400; /* turn on FILL_ERR to get mchecks */
+ *(vuip)CIA_IOC_CIA_CTRL = cia_tmp;
+ mb();
/*
* Set up the PCI->physical memory translation windows.
@@ -411,16 +469,16 @@ unsigned long cia_init(unsigned long mem_start, unsigned long mem_end)
*(vuip)CIA_IOC_PCI_W0_MASK = (CIA_DMA_WIN_SIZE - 1) & 0xfff00000U;
*(vuip)CIA_IOC_PCI_T0_BASE = 0;
- *(vuip)CIA_IOC_PCI_W1_BASE = 0x0 ;
- *(vuip)CIA_IOC_PCI_W2_BASE = 0x0 ;
- *(vuip)CIA_IOC_PCI_W3_BASE = 0x0 ;
+ *(vuip)CIA_IOC_PCI_W1_BASE = 0x0;
+ *(vuip)CIA_IOC_PCI_W2_BASE = 0x0;
+ *(vuip)CIA_IOC_PCI_W3_BASE = 0x0;
/*
* check ASN in HWRPB for validity, report if bad
*/
if (hwrpb->max_asn != MAX_ASN) {
printk("CIA_init: max ASN from HWRPB is bad (0x%lx)\n",
- hwrpb->max_asn);
+ hwrpb->max_asn);
hwrpb->max_asn = MAX_ASN;
}
@@ -432,20 +490,29 @@ unsigned long cia_init(unsigned long mem_start, unsigned long mem_end)
*/
{
#if 0
- unsigned int cia_cfg = *((unsigned int *)CIA_IOC_CFG); mb();
- if (cia_cfg) printk("CIA_init: CFG was 0x%x\n", cia_cfg);
+ unsigned int cia_cfg = *(vuip)CIA_IOC_CFG; mb();
+ if (cia_cfg) printk("CIA_init: CFG was 0x%x\n", cia_cfg);
#endif
- *((unsigned int *)CIA_IOC_CFG) = 0; mb();
+ *(vuip)CIA_IOC_CFG = 0; mb();
}
+#if 0
+ {
+ unsigned int temp;
+ temp = *(vuip)CIA_IOC_CIA_CTRL; mb();
+ printk("CIA_init: CIA_CTRL was 0x%x\n", temp);
+ temp = *(vuip)CIA_IOC_ERR_MASK; mb();
+ printk("CIA_init: CIA_ERR_MASK was 0x%x\n", temp);
+ }
+#endif
return mem_start;
}
int cia_pci_clr_err(void)
{
- CIA_jd = *((unsigned int *)CIA_IOC_CIA_ERR);
- DBG(("CIA_pci_clr_err: CIA ERR after read 0x%x\n", CIA_jd));
- *((unsigned long *)CIA_IOC_CIA_ERR) = 0x0080;
+ CIA_jd = *(vuip)CIA_IOC_CIA_ERR;
+ DBGM(("CIA_pci_clr_err: CIA ERR after read 0x%x\n", CIA_jd));
+ *(vulp)CIA_IOC_CIA_ERR = 0x0180;
mb();
return 0;
}
@@ -462,17 +529,21 @@ void cia_machine_check(unsigned long vector, unsigned long la_ptr,
long i;
mchk_header = (struct el_common *)la_ptr;
- mchk_procdata =
- (struct el_procdata *)(la_ptr + mchk_header->proc_offset);
- mchk_sysdata =
- (struct el_CIA_sysdata_mcheck *)(la_ptr + mchk_header->sys_offset);
-
- DBG(("cia_machine_check: vector=0x%lx la_ptr=0x%lx\n", vector, la_ptr));
- DBG((" pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
- regs->pc, mchk_header->size, mchk_header->proc_offset, mchk_header->sys_offset));
- DBG(("cia_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n",
- CIA_mcheck_expected, mchk_sysdata->epic_dcsr, mchk_sysdata->epic_pear));
-#ifdef DEBUG
+ mchk_procdata = (struct el_procdata *)
+ (la_ptr + mchk_header->proc_offset);
+ mchk_sysdata = (struct el_CIA_sysdata_mcheck *)
+ (la_ptr + mchk_header->sys_offset);
+
+ DBGM(("cia_machine_check: vector=0x%lx la_ptr=0x%lx\n",
+ vector, la_ptr));
+ DBGM((" pc=0x%lx size=0x%x procoffset=0x%x "
+ "sysoffset 0x%x\n", regs->pc, mchk_header->size,
+ mchk_header->proc_offset, mchk_header->sys_offset));
+ DBGM(("cia_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n",
+ CIA_mcheck_expected, mchk_sysdata->epic_dcsr,
+ mchk_sysdata->epic_pear));
+
+#ifdef DEBUG_MCHECK
{
unsigned long *ptr;
int i;
@@ -483,19 +554,20 @@ void cia_machine_check(unsigned long vector, unsigned long la_ptr,
ptr[i], ptr[i+1]);
}
}
-#endif /* DEBUG */
+#endif
+
/*
* Check if machine check is due to a badaddr() and if so,
* ignore the machine check.
*/
mb();
- mb();
- if (CIA_mcheck_expected/* && (mchk_sysdata->epic_dcsr && 0x0c00UL)*/) {
- DBG(("CIA machine check expected\n"));
+ mb(); /* magic */
+ if (CIA_mcheck_expected) {
+ DBGM(("CIA machine check expected\n"));
CIA_mcheck_expected = 0;
CIA_mcheck_taken = 1;
mb();
- mb();
+ mb(); /* magic */
draina();
cia_pci_clr_err();
wrmces(0x7);
@@ -504,34 +576,34 @@ void cia_machine_check(unsigned long vector, unsigned long la_ptr,
}
switch ((unsigned int) mchk_header->code) {
- case MCHK_K_TPERR: reason = "tag parity error"; break;
- case MCHK_K_TCPERR: reason = "tag control parity error"; break;
- case MCHK_K_HERR: reason = "generic hard error"; break;
- case MCHK_K_ECC_C: reason = "correctable ECC error"; break;
- case MCHK_K_ECC_NC: reason = "uncorrectable ECC error"; break;
- case MCHK_K_OS_BUGCHECK: reason = "OS-specific PAL bugcheck"; break;
- case MCHK_K_PAL_BUGCHECK: reason = "callsys in kernel mode"; break;
- case 0x96: reason = "i-cache read retryable error"; break;
- case 0x98: reason = "processor detected hard error"; break;
+ case MCHK_K_TPERR: reason = "tag parity error"; break;
+ case MCHK_K_TCPERR: reason = "tag control parity error"; break;
+ case MCHK_K_HERR: reason = "generic hard error"; break;
+ case MCHK_K_ECC_C: reason = "correctable ECC error"; break;
+ case MCHK_K_ECC_NC: reason = "uncorrectable ECC error"; break;
+ case MCHK_K_OS_BUGCHECK: reason = "OS-specific PAL bugcheck"; break;
+ case MCHK_K_PAL_BUGCHECK: reason = "callsys in kernel mode"; break;
+ case 0x96: reason = "i-cache read retryable error"; break;
+ case 0x98: reason = "processor detected hard error"; break;
/* system specific (these are for Alcor, at least): */
- case 0x203: reason = "system detected uncorrectable ECC error"; break;
- case 0x205: reason = "parity error detected by CIA"; break;
- case 0x207: reason = "non-existent memory error"; break;
- case 0x209: reason = "PCI SERR detected"; break;
- case 0x20b: reason = "PCI data parity error detected"; break;
- case 0x20d: reason = "PCI address parity error detected"; break;
- case 0x20f: reason = "PCI master abort error"; break;
- case 0x211: reason = "PCI target abort error"; break;
- case 0x213: reason = "scatter/gather PTE invalid error"; break;
- case 0x215: reason = "flash ROM write error"; break;
- case 0x217: reason = "IOA timeout detected"; break;
- case 0x219: reason = "IOCHK#, EISA add-in board parity or other catastrophic error"; break;
- case 0x21b: reason = "EISA fail-safe timer timeout"; break;
- case 0x21d: reason = "EISA bus time-out"; break;
- case 0x21f: reason = "EISA software generated NMI"; break;
- case 0x221: reason = "unexpected ev5 IRQ[3] interrupt"; break;
- default:
+ case 0x203: reason = "system detected uncorrectable ECC error"; break;
+ case 0x205: reason = "parity error detected by CIA"; break;
+ case 0x207: reason = "non-existent memory error"; break;
+ case 0x209: reason = "PCI SERR detected"; break;
+ case 0x20b: reason = "PCI data parity error detected"; break;
+ case 0x20d: reason = "PCI address parity error detected"; break;
+ case 0x20f: reason = "PCI master abort error"; break;
+ case 0x211: reason = "PCI target abort error"; break;
+ case 0x213: reason = "scatter/gather PTE invalid error"; break;
+ case 0x215: reason = "flash ROM write error"; break;
+ case 0x217: reason = "IOA timeout detected"; break;
+ case 0x219: reason = "IOCHK#, EISA add-in board parity or other catastrophic error"; break;
+ case 0x21b: reason = "EISA fail-safe timer timeout"; break;
+ case 0x21d: reason = "EISA bus time-out"; break;
+ case 0x21f: reason = "EISA software generated NMI"; break;
+ case 0x221: reason = "unexpected ev5 IRQ[3] interrupt"; break;
+ default:
sprintf(buf, "reason for machine-check unknown (0x%x)",
(unsigned int) mchk_header->code);
reason = buf;
@@ -542,14 +614,14 @@ void cia_machine_check(unsigned long vector, unsigned long la_ptr,
printk(KERN_CRIT " CIA machine check: %s%s\n",
reason, mchk_header->retry ? " (retryable)" : "");
+ printk(KERN_CRIT " vector=0x%lx la_ptr=0x%lx pc=0x%lx\n",
+ vector, la_ptr, regs->pc);
/* dump the the logout area to give all info: */
ptr = (unsigned long *)la_ptr;
for (i = 0; i < mchk_header->size / sizeof(long); i += 2) {
- printk(KERN_CRIT " +%8lx %016lx %016lx\n",
- i*sizeof(long), ptr[i], ptr[i+1]);
+ printk(KERN_CRIT " +%8lx %016lx %016lx\n",
+ i*sizeof(long), ptr[i], ptr[i+1]);
}
}
-
-#endif /* CONFIG_ALPHA_CIA */
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
index 0eef8b539..b139d5178 100644
--- a/arch/alpha/kernel/entry.S
+++ b/arch/alpha/kernel/entry.S
@@ -10,7 +10,7 @@
#define rti .long PAL_rti
#define SIGCHLD 20
-#define NR_SYSCALLS 360
+#define NR_SYSCALLS 370
#define osf_vfork sys_fork
/*
@@ -29,11 +29,10 @@
/*
* task structure offsets
*/
-#define TASK_STATE 0
-#define TASK_COUNTER 8
-#define TASK_PRIORITY 16
-#define TASK_FLAGS 24
-#define TASK_SIGPENDING 32
+#define TASK_STATE 0
+#define TASK_FLAGS 8
+#define TASK_SIGPENDING 16
+#define TASK_SIZE 24
/*
* task flags (must match include/linux/sched.h):
@@ -252,6 +251,28 @@ __kernel_thread:
call_pal PAL_halt
.end __kernel_thread
+/*
+ * __kernel_execve(path, argv, envp, regs)
+ */
+.align 3
+.globl __kernel_execve
+.ent __kernel_execve
+__kernel_execve:
+ ldgp $29,0($27) /* we can be called from modules. */
+ subq $30,16,$30
+ .frame $30,16,$26,0
+ stq $26,0($30)
+ stq $19,8($30)
+ .prologue 1
+ jsr $26,do_execve
+ bne $0,1f /* error! */
+ ldq $30,8($30)
+ br $31,ret_from_sys_call
+1: ldq $26,0($30)
+ addq $30,16,$30
+ ret
+.end __kernel_execve
+
.align 3
.ent do_switch_stack
do_switch_stack:
@@ -297,6 +318,7 @@ do_switch_stack:
stt $f29,296($30)
stt $f30,304($30)
stt $f0,312($30) # save fpcr in slot of $f31
+ ldt $f0,64($30) # don't let "do_switch_stack" change any fp state.
ret $31,($1),1
.end do_switch_stack
@@ -508,7 +530,7 @@ entSys:
lda $4,NR_SYSCALLS($31)
stq $16,SP_OFF+24($30)
lda $5,sys_call_table
- lda $27,alpha_ni_syscall
+ lda $27,sys_ni_syscall
cmpult $0,$4,$4
ldq $3,TASK_FLAGS($8)
stq $17,SP_OFF+32($30)
@@ -833,7 +855,7 @@ sys_call_table:
.quad alpha_ni_syscall
.quad alpha_ni_syscall /* 110 */
.quad sys_sigsuspend
- .quad alpha_ni_syscall
+ .quad sys_ni_syscall
.quad sys_recvmsg
.quad sys_sendmsg
.quad alpha_ni_syscall /* 115 */
@@ -929,7 +951,7 @@ sys_call_table:
.quad sys_semget /* 205 */
.quad sys_semop
.quad osf_utsname
- .quad alpha_ni_syscall
+ .quad sys_lchown
.quad osf_shmat
.quad sys_shmctl /* 210 */
.quad sys_shmdt
@@ -1025,7 +1047,7 @@ sys_call_table:
.quad sys_bdflush /* 300 */
.quad sys_sethae
.quad sys_mount
- .quad sys_adjtimex
+ .quad sys_old_adjtimex
.quad sys_swapoff
.quad sys_getdents /* 305 */
.quad alpha_create_module
@@ -1060,7 +1082,7 @@ sys_call_table:
.quad sys_sched_get_priority_max /* 335 */
.quad sys_sched_get_priority_min
.quad sys_sched_rr_get_interval
- .quad alpha_ni_syscall /* sys_afs_syscall */
+ .quad sys_ni_syscall /* sys_afs_syscall */
.quad sys_newuname
.quad sys_nanosleep /* 340 */
.quad sys_mremap
@@ -1080,8 +1102,15 @@ sys_call_table:
.quad sys_rt_sigtimedwait /* 355 */
.quad sys_rt_sigqueueinfo
.quad sys_rt_sigsuspend
- .quad alpha_ni_syscall
- .quad alpha_ni_syscall
- .quad alpha_ni_syscall
- .quad alpha_ni_syscall
- .quad alpha_ni_syscall /* 360 */
+ .quad sys_select
+ .quad sys_gettimeofday
+ .quad sys_settimeofday /* 360 */
+ .quad sys_getitimer
+ .quad sys_setitimer
+ .quad sys_utimes
+ .quad sys_getrusage
+ .quad sys_wait4 /* 365 */
+ .quad sys_adjtimex
+ .quad sys_ni_syscall
+ .quad sys_ni_syscall
+ .quad sys_ni_syscall /* 369 */
diff --git a/arch/alpha/kernel/fpreg.c b/arch/alpha/kernel/fpreg.c
new file mode 100644
index 000000000..502144058
--- /dev/null
+++ b/arch/alpha/kernel/fpreg.c
@@ -0,0 +1,104 @@
+/*
+ * kernel/fpreg.c
+ *
+ * (C) Copyright 1998 Linus Torvalds
+ */
+
+unsigned long
+alpha_read_fp_reg (unsigned long reg)
+{
+ unsigned long r;
+
+ switch (reg) {
+ case 0: asm ("stt $f0,%0" : "m="(r)); break;
+ case 1: asm ("stt $f1,%0" : "m="(r)); break;
+ case 2: asm ("stt $f2,%0" : "m="(r)); break;
+ case 3: asm ("stt $f3,%0" : "m="(r)); break;
+ case 4: asm ("stt $f4,%0" : "m="(r)); break;
+ case 5: asm ("stt $f5,%0" : "m="(r)); break;
+ case 6: asm ("stt $f6,%0" : "m="(r)); break;
+ case 7: asm ("stt $f7,%0" : "m="(r)); break;
+ case 8: asm ("stt $f8,%0" : "m="(r)); break;
+ case 9: asm ("stt $f9,%0" : "m="(r)); break;
+ case 10: asm ("stt $f10,%0" : "m="(r)); break;
+ case 11: asm ("stt $f11,%0" : "m="(r)); break;
+ case 12: asm ("stt $f12,%0" : "m="(r)); break;
+ case 13: asm ("stt $f13,%0" : "m="(r)); break;
+ case 14: asm ("stt $f14,%0" : "m="(r)); break;
+ case 15: asm ("stt $f15,%0" : "m="(r)); break;
+ case 16: asm ("stt $f16,%0" : "m="(r)); break;
+ case 17: asm ("stt $f17,%0" : "m="(r)); break;
+ case 18: asm ("stt $f18,%0" : "m="(r)); break;
+ case 19: asm ("stt $f19,%0" : "m="(r)); break;
+ case 20: asm ("stt $f20,%0" : "m="(r)); break;
+ case 21: asm ("stt $f21,%0" : "m="(r)); break;
+ case 22: asm ("stt $f22,%0" : "m="(r)); break;
+ case 23: asm ("stt $f23,%0" : "m="(r)); break;
+ case 24: asm ("stt $f24,%0" : "m="(r)); break;
+ case 25: asm ("stt $f25,%0" : "m="(r)); break;
+ case 26: asm ("stt $f26,%0" : "m="(r)); break;
+ case 27: asm ("stt $f27,%0" : "m="(r)); break;
+ case 28: asm ("stt $f28,%0" : "m="(r)); break;
+ case 29: asm ("stt $f29,%0" : "m="(r)); break;
+ case 30: asm ("stt $f30,%0" : "m="(r)); break;
+ case 31: asm ("stt $f31,%0" : "m="(r)); break;
+ default:
+ break;
+ }
+ return r;
+}
+
+#if 1
+/*
+ * This is IMHO the better way of implementing LDT(). But it
+ * has the disadvantage that gcc 2.7.0 refuses to compile it
+ * (invalid operand constraints), so instead, we use the uglier
+ * macro below.
+ */
+# define LDT(reg,val) \
+ asm volatile ("ldt $f"#reg",%0" : : "m"(val));
+#else
+# define LDT(reg,val) \
+ asm volatile ("ldt $f"#reg",0(%0)" : : "r"(&val));
+#endif
+
+void
+alpha_write_fp_reg (unsigned long reg, unsigned long val)
+{
+ switch (reg) {
+ case 0: LDT( 0, val); break;
+ case 1: LDT( 1, val); break;
+ case 2: LDT( 2, val); break;
+ case 3: LDT( 3, val); break;
+ case 4: LDT( 4, val); break;
+ case 5: LDT( 5, val); break;
+ case 6: LDT( 6, val); break;
+ case 7: LDT( 7, val); break;
+ case 8: LDT( 8, val); break;
+ case 9: LDT( 9, val); break;
+ case 10: LDT(10, val); break;
+ case 11: LDT(11, val); break;
+ case 12: LDT(12, val); break;
+ case 13: LDT(13, val); break;
+ case 14: LDT(14, val); break;
+ case 15: LDT(15, val); break;
+ case 16: LDT(16, val); break;
+ case 17: LDT(17, val); break;
+ case 18: LDT(18, val); break;
+ case 19: LDT(19, val); break;
+ case 20: LDT(20, val); break;
+ case 21: LDT(21, val); break;
+ case 22: LDT(22, val); break;
+ case 23: LDT(23, val); break;
+ case 24: LDT(24, val); break;
+ case 25: LDT(25, val); break;
+ case 26: LDT(26, val); break;
+ case 27: LDT(27, val); break;
+ case 28: LDT(28, val); break;
+ case 29: LDT(29, val); break;
+ case 30: LDT(30, val); break;
+ case 31: LDT(31, val); break;
+ default:
+ break;
+ }
+}
diff --git a/arch/alpha/kernel/head.S b/arch/alpha/kernel/head.S
index f76213624..4a3ec9e7c 100644
--- a/arch/alpha/kernel/head.S
+++ b/arch/alpha/kernel/head.S
@@ -80,36 +80,44 @@ wrmces:
ret ($26)
.end wrmces
+ .align 3
+ .globl whami
+ .ent whami
+whami:
+ call_pal PAL_whami
+ ret ($26)
+ .end whami
+
+ .align 3
+ .globl wripir
+ .ent wripir
+wripir:
+ call_pal PAL_wripir
+ ret ($26)
+ .end wripir
+
#
- # The following two functions don't need trapb/excb instructions
- # around the mf_fpcr/mt_fpcr instructions because (a) the kernel
- # never generates arithmetic faults and (b) call_pal instructions
- # are implied trap barriers.
+ # The following two functions are needed for supporting SRM PALcode
+ # on the PC164 (at least), since that PALcode manages the interrupt
+ # masking, and we cannot duplicate the effort without causing problems
#
+
.align 3
- .globl rdfpcr
- .ent rdfpcr
-rdfpcr:
- lda $30,-0x10($30)
- stt $f0,0($30)
- mf_fpcr $f0
- stt $f0,8($30)
- ldt $f0,0($30)
- ldq $0,8($30)
- lda $30,0x10($30)
+ .globl cserve_ena
+ .ent cserve_ena
+cserve_ena:
+ bis $16,$16,$17
+ lda $16,52($31)
+ call_pal PAL_cserve
ret ($26)
- .end rdfpcr
+ .end cserve_ena
.align 3
- .globl wrfpcr
- .ent wrfpcr
-wrfpcr:
- lda $30,-0x10($30)
- stt $f0,0($30)
- stq $16,8($30)
- ldt $f0,8($30)
- mt_fpcr $f0
- ldt $f0,0($30)
- lda $30,0x10($30)
+ .globl cserve_dis
+ .ent cserve_dis
+cserve_dis:
+ bis $16,$16,$17
+ lda $16,53($31)
+ call_pal PAL_cserve
ret ($26)
- .end wrfpcr
+ .end cserve_dis
diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c
index 3291f4603..41d5d5f01 100644
--- a/arch/alpha/kernel/irq.c
+++ b/arch/alpha/kernel/irq.c
@@ -19,6 +19,7 @@
#include <linux/interrupt.h>
#include <linux/malloc.h>
#include <linux/random.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -26,6 +27,9 @@
#include <asm/bitops.h>
#include <asm/dma.h>
+#define vulp volatile unsigned long *
+#define vuip volatile unsigned int *
+
#define RTC_IRQ 8
#ifdef CONFIG_RTC
#define TIMER_IRQ 0 /* timer is the pit */
@@ -44,6 +48,9 @@
#elif defined(CONFIG_ALPHA_ALCOR)
/* always mask out unused timer irq 0, "irqs" 20-30, and the EISA cascade: */
# define PROBE_MASK (((1UL << NR_IRQS) - 1) & ~0xfff000000001UL)
+#elif defined(CONFIG_ALPHA_RUFFIAN)
+ /* must leave timer irq 0 in the mask */
+# define PROBE_MASK ((1UL << NR_IRQS) - 1)
#else
/* always mask out unused timer irq 0: */
# define PROBE_MASK (((1UL << NR_IRQS) - 1) & ~1UL)
@@ -58,8 +65,9 @@
* The bits are used as follows:
* 0.. 7 first (E)ISA PIC (irq level 0..7)
* 8..15 second (E)ISA PIC (irq level 8..15)
- * Systems with PCI interrupt lines managed by GRU (e.g., Alcor, XLT):
- * 16..47 PCI interrupts 0..31 (int at GRU_INT_MASK)
+ * Systems with PCI interrupt lines managed by GRU (e.g., Alcor, XLT)
+ * or PYXIS (e.g. Miata, PC164-LX):
+ * 16..47 PCI interrupts 0..31 (int at xxx_INT_MASK)
* Mikasa:
* 16..31 PCI interrupts 0..15 (short at I/O port 536)
* Other systems (not Mikasa) with 16 PCI interrupt lines:
@@ -67,53 +75,311 @@
* 24..31 PCI interrupts 8..15 (char at I/O port 27)
* Systems with 17 PCI interrupt lines (e.g., Cabriolet and eb164):
* 16..32 PCI interrupts 0..31 (int at I/O port 804)
+ * For SABLE, which is really baroque, we manage 40 IRQ's, but the
+ * hardware really only supports 24, not via normal ISA PIC,
+ * but cascaded custom 8259's, etc.
+ * 0-7 (char at 536)
+ * 8-15 (char at 53a)
+ * 16-23 (char at 53c)
*/
static unsigned long irq_mask = ~0UL;
+#ifdef CONFIG_ALPHA_SABLE
+/*
+ * Note that the vector reported by the SRM PALcode corresponds to the
+ * interrupt mask bits, but we have to manage via more normal IRQs.
+ *
+ * We have to be able to go back and forth between MASK bits and IRQ:
+ * these tables help us do so.
+ */
+static char sable_irq_to_mask[NR_IRQS] = {
+ -1, 6, -1, 8, 15, 12, 7, 9, /* pseudo PIC 0-7 */
+ -1, 16, 17, 18, 3, -1, 21, 22, /* pseudo PIC 8-15 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* pseudo EISA 0-7 */
+ -1, -1, -1, -1, -1, -1, -1, -1, /* pseudo EISA 8-15 */
+ 2, 1, 0, 4, 5, -1, -1, -1, /* pseudo PCI */
+};
+#define IRQ_TO_MASK(irq) (sable_irq_to_mask[(irq)])
+static char sable_mask_to_irq[NR_IRQS] = {
+ 34, 33, 32, 12, 35, 36, 1, 6, /* mask 0-7 */
+ 3, 7, -1, -1, 5, -1, -1, 4, /* mask 8-15 */
+ 9, 10, 11, -1, -1, 14, 15, -1, /* mask 16-23 */
+};
+#else /* CONFIG_ALPHA_SABLE */
+#define IRQ_TO_MASK(irq) (irq)
+#endif /* CONFIG_ALPHA_SABLE */
+
/*
* Update the hardware with the irq mask passed in MASK. The function
* exploits the fact that it is known that only bit IRQ has changed.
*/
-static void update_hw(unsigned long irq, unsigned long mask)
+
+static inline void
+sable_update_hw(unsigned long irq, unsigned long mask)
{
+ /* The "irq" argument is really the mask bit number */
switch (irq) {
-#if NR_IRQS == 48
- default:
- /* note inverted sense of mask bits: */
- *(unsigned int *)GRU_INT_MASK = ~(mask >> 16); mb();
+ default: /* 16 ... 23 */
+ outb(mask >> 16, 0x53d);
+ break;
+ case 8 ... 15:
+ outb(mask >> 8, 0x53b);
+ break;
+ case 0 ... 7:
+ outb(mask, 0x537);
break;
+ }
+}
-#elif NR_IRQS == 33
- default:
- outl(mask >> 16, 0x804);
+static inline void
+noritake_update_hw(unsigned long irq, unsigned long mask)
+{
+ switch (irq) {
+ default: /* 32 ... 47 */
+ outw(~(mask >> 32), 0x54c);
+ break;
+ case 16 ... 31:
+ outw(~(mask >> 16), 0x54a);
+ break;
+ case 8 ... 15: /* ISA PIC2 */
+ outb(mask >> 8, 0xA1);
+ break;
+ case 0 ... 7: /* ISA PIC1 */
+ outb(mask, 0x21);
+ break;
+ }
+}
+
+#ifdef CONFIG_ALPHA_MIATA
+static inline void
+miata_update_hw(unsigned long irq, unsigned long mask)
+{
+ switch (irq) {
+ default: /* 16 ... 47 */
+ /* Make CERTAIN none of the bogus ints get enabled... */
+ *(vulp)PYXIS_INT_MASK =
+ ~((long)mask >> 16) & ~0x4000000000000e3bUL;
+ mb();
+ /* ... and read it back to make sure it got written. */
+ *(vulp)PYXIS_INT_MASK;
+ break;
+ case 8 ... 15: /* ISA PIC2 */
+ outb(mask >> 8, 0xA1);
break;
+ case 0 ... 7: /* ISA PIC1 */
+ outb(mask, 0x21);
+ break;
+ }
+}
+#endif
-#elif defined(CONFIG_ALPHA_MIKASA)
- default:
+#if defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
+static inline void
+alcor_and_xlt_update_hw(unsigned long irq, unsigned long mask)
+{
+ switch (irq) {
+ default: /* 16 ... 47 */
+ /* On Alcor, at least, lines 20..30 are not connected and can
+ generate spurrious interrupts if we turn them on while IRQ
+ probing. So explicitly mask them out. */
+ mask |= 0x7ff000000000UL;
+
+ /* Note inverted sense of mask bits: */
+ *(vuip)GRU_INT_MASK = ~(mask >> 16);
+ mb();
+ break;
+ case 8 ... 15: /* ISA PIC2 */
+ outb(mask >> 8, 0xA1);
+ break;
+ case 0 ... 7: /* ISA PIC1 */
+ outb(mask, 0x21);
+ break;
+ }
+}
+#endif
+
+static inline void
+mikasa_update_hw(unsigned long irq, unsigned long mask)
+{
+ switch (irq) {
+ default: /* 16 ... 31 */
outw(~(mask >> 16), 0x536); /* note invert */
break;
+ case 8 ... 15: /* ISA PIC2 */
+ outb(mask >> 8, 0xA1);
+ break;
+ case 0 ... 7: /* ISA PIC1 */
+ outb(mask, 0x21);
+ break;
+ }
+}
-#elif NR_IRQS == 32
- case 16 ... 23:
- outb(mask >> 16, 0x26);
+#ifdef CONFIG_ALPHA_RUFFIAN
+static inline void
+ruffian_update_hw(unsigned long irq, unsigned long mask)
+{
+ switch (irq) {
+ case 16 ... 47:
+ /* Note inverted sense of mask bits: */
+ /* Make CERTAIN none of the bogus ints get enabled... */
+ *(vulp)PYXIS_INT_MASK =
+ ~((long)mask >> 16) & 0x00000000ffffffbfUL;
+ mb();
+ /* ... and read it back to make sure it got written. */
+ *(vulp)PYXIS_INT_MASK;
break;
+ case 8 ... 15: /* ISA PIC2 */
+ outb(mask >> 8, 0xA1);
+ break;
+ case 0 ... 7: /* ISA PIC1 */
+ outb(mask, 0x21);
+ break;
+ }
+}
+#endif
- default:
- outb(mask >> 24, 0x27);
+#ifdef CONFIG_ALPHA_SX164
+static inline void
+sx164_update_hw(unsigned long irq, unsigned long mask)
+{
+ switch (irq) {
+ case 16 ... 39:
+ /* Make CERTAIN none of the bogus ints get enabled */
+ *(vulp)PYXIS_INT_MASK =
+ ~((long)mask >> 16) & ~0x000000000000003bUL;
+ mb();
+ /* ... and read it back to make sure it got written. */
+ *(vulp)PYXIS_INT_MASK;
+ break;
+ case 8 ... 15: /* ISA PIC2 */
+ outb(mask >> 8, 0xA1);
+ break;
+ case 0 ... 7: /* ISA PIC1 */
+ outb(mask, 0x21);
break;
+ }
+}
#endif
- /* handle ISA irqs last---fast devices belong on PCI... */
- case 0 ... 7: /* ISA PIC1 */
+/* Unlabeled mechanisms based on the number of irqs. Someone should
+ probably document and name these. */
+
+static inline void
+update_hw_33(unsigned long irq, unsigned long mask)
+{
+ switch (irq) {
+ default: /* 16 ... 32 */
+ outl(mask >> 16, 0x804);
+ break;
+
+ case 8 ... 15: /* ISA PIC2 */
+ outb(mask >> 8, 0xA1);
+ break;
+ case 0 ... 7: /* ISA PIC1 */
+ outb(mask, 0x21);
+ break;
+ }
+}
+
+static inline void
+update_hw_32(unsigned long irq, unsigned long mask)
+{
+ switch (irq) {
+ default: /* 24 ... 31 */
+ outb(mask >> 24, 0x27);
+ break;
+ case 16 ... 23:
+ outb(mask >> 16, 0x26);
+ break;
+ case 8 ... 15: /* ISA PIC2 */
+ outb(mask >> 8, 0xA1);
+ break;
+ case 0 ... 7: /* ISA PIC1 */
outb(mask, 0x21);
break;
+ }
+}
- case 8 ...15: /* ISA PIC2 */
+static inline void
+update_hw_16(unsigned long irq, unsigned long mask)
+{
+ switch (irq) {
+ default: /* 8 ... 15, ISA PIC2 */
outb(mask >> 8, 0xA1);
break;
+ case 0 ... 7: /* ISA PIC1 */
+ outb(mask, 0x21);
+ break;
}
}
+#if (defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164)) \
+ && defined(CONFIG_ALPHA_SRM)
+/*
+ * On the pc164, we cannot take over the IRQs from the SRM,
+ * so we call down to do our dirty work. Too bad the SRM
+ * isn't consistent across platforms otherwise we could do
+ * this always.
+ */
+
+extern void cserve_ena(unsigned long);
+extern void cserve_dis(unsigned long);
+
+static inline void mask_irq(unsigned long irq)
+{
+ irq_mask |= (1UL << irq);
+ cserve_dis(irq - 16);
+}
+
+static inline void unmask_irq(unsigned long irq)
+{
+ irq_mask &= ~(1UL << irq);
+ cserve_ena(irq - 16);
+}
+
+/* Since we are calling down to PALcode, no need to diddle IPL. */
+void disable_irq(unsigned int irq_nr)
+{
+ mask_irq(IRQ_TO_MASK(irq_nr));
+}
+
+void enable_irq(unsigned int irq_nr)
+{
+ unmask_irq(IRQ_TO_MASK(irq_nr));
+}
+
+#else
+/*
+ * We manipulate the hardware ourselves.
+ */
+
+static void update_hw(unsigned long irq, unsigned long mask)
+{
+#if defined(CONFIG_ALPHA_SABLE)
+ sable_update_hw(irq, mask);
+#elif defined(CONFIG_ALPHA_MIATA)
+ miata_update_hw(irq, mask);
+#elif defined(CONFIG_ALPHA_NORITAKE)
+ noritake_update_hw(irq, mask);
+#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
+ alcor_and_xlt_update_hw(irq, mask);
+#elif defined(CONFIG_ALPHA_MIKASA)
+ mikasa_update_hw(irq, mask);
+#elif defined(CONFIG_ALPHA_SX164)
+ sx164_update_hw(irq, mask);
+#elif defined(CONFIG_ALPHA_RUFFIAN)
+ ruffian_update_hw(irq, mask);
+#elif NR_IRQS == 33
+ update_hw_33(irq, mask);
+#elif NR_IRQS == 32
+ update_hw_32(irq, mask);
+#elif NR_IRQS == 16
+ update_hw_16(irq, mask);
+#else
+#error "How do I update the IRQ hardware?"
+#endif
+}
+
static inline void mask_irq(unsigned long irq)
{
irq_mask |= (1UL << irq);
@@ -132,7 +398,7 @@ void disable_irq(unsigned int irq_nr)
save_flags(flags);
cli();
- mask_irq(irq_nr);
+ mask_irq(IRQ_TO_MASK(irq_nr));
restore_flags(flags);
}
@@ -142,9 +408,10 @@ void enable_irq(unsigned int irq_nr)
save_flags(flags);
cli();
- unmask_irq(irq_nr);
+ unmask_irq(IRQ_TO_MASK(irq_nr));
restore_flags(flags);
}
+#endif /* (PC164 || LX164) && SRM */
/*
* Initial irq handlers.
@@ -157,18 +424,18 @@ int get_irq_list(char *buf)
int i, len = 0;
struct irqaction * action;
- for (i = 0 ; i < NR_IRQS ; i++) {
+ for (i = 0; i < NR_IRQS; i++) {
action = irq_action[i];
if (!action)
continue;
len += sprintf(buf+len, "%2d: %10u %c %s",
- i, kstat.interrupts[i],
- (action->flags & SA_INTERRUPT) ? '+' : ' ',
- action->name);
+ i, kstat.irqs[0][i],
+ (action->flags & SA_INTERRUPT) ? '+' : ' ',
+ action->name);
for (action=action->next; action; action = action->next) {
len += sprintf(buf+len, ",%s %s",
- (action->flags & SA_INTERRUPT) ? " +" : "",
- action->name);
+ (action->flags & SA_INTERRUPT) ? " +" : "",
+ action->name);
}
len += sprintf(buf+len, "\n");
}
@@ -177,8 +444,39 @@ int get_irq_list(char *buf)
static inline void ack_irq(int irq)
{
+#ifdef CONFIG_ALPHA_SABLE
+ /* Note that the "irq" here is really the mask bit number */
+ switch (irq) {
+ case 0 ... 7:
+ outb(0xE0 | (irq - 0), 0x536);
+ outb(0xE0 | 1, 0x534); /* slave 0 */
+ break;
+ case 8 ... 15:
+ outb(0xE0 | (irq - 8), 0x53a);
+ outb(0xE0 | 3, 0x534); /* slave 1 */
+ break;
+ case 16 ... 24:
+ outb(0xE0 | (irq - 16), 0x53c);
+ outb(0xE0 | 4, 0x534); /* slave 2 */
+ break;
+ }
+#elif defined(CONFIG_ALPHA_RUFFIAN)
+ if (irq < 16) {
+ /* Ack PYXIS ISA interrupt. */
+ *(vulp)PYXIS_INT_REQ = 1 << 7;
+ mb();
+ if (irq > 7) {
+ outb(0x20, 0xa0);
+ }
+ outb(0x20, 0x20);
+ } else {
+ /* Ack PYXIS interrupt. */
+ *(vulp)PYXIS_INT_REQ = (1UL << (irq - 16));
+ mb();
+ }
+#else
if (irq < 16) {
- /* ACK the interrupt making it the lowest priority */
+ /* Ack the interrupt making it the lowest priority */
/* First the slave .. */
if (irq > 7) {
outb(0xE0 | (irq - 8), 0xa0);
@@ -188,10 +486,21 @@ static inline void ack_irq(int irq)
outb(0xE0 | irq, 0x20);
#if defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
/* on ALCOR/XLT, need to dismiss interrupt via GRU */
- *(int *)GRU_INT_CLEAR = 0x80000000; mb();
- *(int *)GRU_INT_CLEAR = 0x00000000; mb();
-#endif /* ALCOR || XLT */
+ *(vuip)GRU_INT_CLEAR = 0x80000000; mb();
+ *(vuip)GRU_INT_CLEAR = 0x00000000; mb();
+#endif
}
+#endif
+}
+
+int check_irq(unsigned int irq)
+{
+ struct irqaction **p;
+
+ p = irq_action + irq;
+ if (*p == NULL)
+ return 0;
+ return -EBUSY;
}
int request_irq(unsigned int irq,
@@ -221,7 +530,7 @@ int request_irq(unsigned int irq,
if ((action->flags ^ irqflags) & SA_INTERRUPT)
return -EBUSY;
- /* add new interrupt at end of irq queue */
+ /* Add new interrupt at end of irq queue */
do {
p = &action->next;
action = *p;
@@ -229,11 +538,11 @@ int request_irq(unsigned int irq,
shared = 1;
}
- if (irq == TIMER_IRQ)
- action = &timer_irq;
- else
+ if (irq == TIMER_IRQ)
+ action = &timer_irq;
+ else
action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
- GFP_KERNEL);
+ GFP_KERNEL);
if (!action)
return -ENOMEM;
@@ -252,7 +561,7 @@ int request_irq(unsigned int irq,
*p = action;
if (!shared)
- unmask_irq(irq);
+ unmask_irq(IRQ_TO_MASK(irq));
restore_flags(flags);
return 0;
@@ -280,7 +589,7 @@ void free_irq(unsigned int irq, void *dev_id)
cli();
*p = action->next;
if (!irq[irq_action])
- mask_irq(irq);
+ mask_irq(IRQ_TO_MASK(irq));
restore_flags(flags);
kfree(action);
return;
@@ -295,10 +604,10 @@ static inline void handle_nmi(struct pt_regs * regs)
}
unsigned int local_irq_count[NR_CPUS];
-atomic_t __alpha_bh_counter;
+unsigned int local_bh_count[NR_CPUS];
#ifdef __SMP__
-#error Me no hablo Alpha SMP
+#error "Me no hablo Alpha SMP"
#else
#define irq_enter(cpu, irq) (++local_irq_count[cpu])
#define irq_exit(cpu, irq) (--local_irq_count[cpu])
@@ -319,9 +628,12 @@ static void unexpected_irq(int irq, struct pt_regs * regs)
action = action->next;
}
printk("\n");
+
#if defined(CONFIG_ALPHA_JENSEN)
+ /* ??? Is all this just debugging, or are the inb's and outb's
+ necessary to make things work? */
printk("64=%02x, 60=%02x, 3fa=%02x 2fa=%02x\n",
- inb(0x64), inb(0x60), inb(0x3fa), inb(0x2fa));
+ inb(0x64), inb(0x60), inb(0x3fa), inb(0x2fa));
outb(0x0c, 0x3fc);
outb(0x0c, 0x2fc);
outb(0,0x61);
@@ -335,7 +647,7 @@ static inline void handle_irq(int irq, struct pt_regs * regs)
int cpu = smp_processor_id();
irq_enter(cpu, irq);
- kstat.interrupts[irq]++;
+ kstat.irqs[0][irq] += 1;
if (!action) {
unexpected_irq(irq, regs);
} else {
@@ -353,19 +665,19 @@ static inline void device_interrupt(int irq, int ack, struct pt_regs * regs)
int cpu = smp_processor_id();
if ((unsigned) irq > NR_IRQS) {
- printk("device_interrupt: unexpected interrupt %d\n", irq);
+ printk("device_interrupt: illegal interrupt %d\n", irq);
return;
}
irq_enter(cpu, irq);
- kstat.interrupts[irq]++;
+ kstat.irqs[0][irq] += 1;
action = irq_action[irq];
/*
* For normal interrupts, we mask it out, and then ACK it.
* This way another (more timing-critical) interrupt can
* come through while we're doing this one.
*
- * Note! A irq without a handler gets masked and acked, but
+ * Note! An irq without a handler gets masked and acked, but
* never unmasked. The autoirq stuff depends on this (it looks
* at the masks before and after doing the probing).
*/
@@ -397,6 +709,8 @@ static inline void isa_device_interrupt(unsigned long vector,
# define IACK_SC LCA_IACK_SC
#elif defined(CONFIG_ALPHA_CIA)
# define IACK_SC CIA_IACK_SC
+#elif defined(CONFIG_ALPHA_PYXIS)
+# define IACK_SC PYXIS_IACK_SC
#else
/*
* This is bogus but necessary to get it to compile
@@ -413,14 +727,13 @@ static inline void isa_device_interrupt(unsigned long vector,
* Generate a PCI interrupt acknowledge cycle. The PIC will
* respond with the interrupt vector of the highest priority
* interrupt that is pending. The PALcode sets up the
- * interrupts vectors such that irq level L generates vector
- * L.
+ * interrupts vectors such that irq level L generates vector L.
*/
j = *(volatile int *) IACK_SC;
j &= 0xff;
if (j == 7) {
if (!(inb(0x20) & 0x80)) {
- /* it's only a passive release... */
+ /* It's only a passive release... */
return;
}
}
@@ -454,43 +767,44 @@ static inline void isa_device_interrupt(unsigned long vector,
}
#if defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
-/* we have to conditionally compile this because of GRU_xxx symbols */
-static inline void alcor_and_xlt_device_interrupt(unsigned long vector,
- struct pt_regs * regs)
+/* We have to conditionally compile this because of GRU_xxx symbols */
+static inline void
+alcor_and_xlt_device_interrupt(unsigned long vector, struct pt_regs *regs)
{
- unsigned long pld;
- unsigned int i;
- unsigned long flags;
+ unsigned long pld;
+ unsigned int i;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ save_flags(flags);
+ cli();
- /* read the interrupt summary register of the GRU */
- pld = (*(unsigned int *)GRU_INT_REQ) & GRU_INT_REQ_BITS;
+ /* read the interrupt summary register of the GRU */
+ pld = (*(vuip)GRU_INT_REQ) & GRU_INT_REQ_BITS;
#if 0
- printk("[0x%08lx/0x%04x]", pld, inb(0x20) | (inb(0xA0) << 8));
+ printk("[0x%08lx/0x%04x]", pld, inb(0x20) | (inb(0xA0) << 8));
#endif
- /*
- * Now for every possible bit set, work through them and call
- * the appropriate interrupt handler.
- */
- while (pld) {
- i = ffz(~pld);
- pld &= pld - 1; /* clear least bit set */
- if (i == 31) {
- isa_device_interrupt(vector, regs);
- } else {
- device_interrupt(16 + i, 16 + i, regs);
- }
- }
- restore_flags(flags);
+ /*
+ * Now for every possible bit set, work through them and call
+ * the appropriate interrupt handler.
+ */
+ while (pld) {
+ i = ffz(~pld);
+ pld &= pld - 1; /* clear least bit set */
+ if (i == 31) {
+ isa_device_interrupt(vector, regs);
+ } else {
+ device_interrupt(16 + i, 16 + i, regs);
+ }
+ }
+ restore_flags(flags);
}
#endif /* ALCOR || XLT */
-static inline void cabriolet_and_eb66p_device_interrupt(unsigned long vector,
- struct pt_regs * regs)
+static inline void
+cabriolet_and_eb66p_device_interrupt(unsigned long vector,
+ struct pt_regs *regs)
{
unsigned long pld;
unsigned int i;
@@ -522,8 +836,8 @@ static inline void cabriolet_and_eb66p_device_interrupt(unsigned long vector,
restore_flags(flags);
}
-static inline void mikasa_device_interrupt(unsigned long vector,
- struct pt_regs * regs)
+static inline void
+mikasa_device_interrupt(unsigned long vector, struct pt_regs *regs)
{
unsigned long pld;
unsigned int i;
@@ -532,20 +846,20 @@ static inline void mikasa_device_interrupt(unsigned long vector,
save_flags(flags);
cli();
- /* read the interrupt summary registers */
- pld = (((unsigned long) (~inw(0x534)) & 0x0000ffffUL) << 16) |
- (((unsigned long) inb(0xa0)) << 8) |
- ((unsigned long) inb(0x20));
+ /* read the interrupt summary registers */
+ pld = (((unsigned long) (~inw(0x534)) & 0x0000ffffUL) << 16) |
+ (((unsigned long) inb(0xa0)) << 8) |
+ ((unsigned long) inb(0x20));
#if 0
- printk("[0x%08lx]", pld);
+ printk("[0x%08lx]", pld);
#endif
- /*
- * Now for every possible bit set, work through them and call
- * the appropriate interrupt handler.
- */
- while (pld) {
+ /*
+ * Now for every possible bit set, work through them and call
+ * the appropriate interrupt handler.
+ */
+ while (pld) {
i = ffz(~pld);
pld &= pld - 1; /* clear least bit set */
if (i < 16) {
@@ -553,12 +867,12 @@ static inline void mikasa_device_interrupt(unsigned long vector,
} else {
device_interrupt(i, i, regs);
}
- }
+ }
restore_flags(flags);
}
-static inline void eb66_and_eb64p_device_interrupt(unsigned long vector,
- struct pt_regs * regs)
+static inline void
+eb66_and_eb64p_device_interrupt(unsigned long vector, struct pt_regs *regs)
{
unsigned long pld;
unsigned int i;
@@ -586,6 +900,160 @@ static inline void eb66_and_eb64p_device_interrupt(unsigned long vector,
restore_flags(flags);
}
+#if defined(CONFIG_ALPHA_MIATA) || defined(CONFIG_ALPHA_SX164)
+/* We have to conditionally compile this because of PYXIS_xxx symbols */
+static inline void
+miata_device_interrupt(unsigned long vector, struct pt_regs *regs)
+{
+ unsigned long pld, tmp;
+ unsigned int i;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ /* read the interrupt summary register of PYXIS */
+ pld = (*(vulp)PYXIS_INT_REQ);
+
+#if 0
+ printk("[0x%08lx/0x%08lx/0x%04x]", pld,
+ *(vulp)PYXIS_INT_MASK, inb(0x20) | (inb(0xA0) << 8));
+#endif
+
+ /* For now, AND off any bits we are not interested in. */
+#if defined(CONFIG_ALPHA_MIATA)
+ /* HALT (2), timer (6), ISA Bridge (7), 21142/3 (8),
+ then all the PCI slots/INTXs (12-31). */
+ /* Maybe HALT should only be used for SRM console boots? */
+ pld &= 0x00000000fffff1c4UL;
+#endif
+#if defined(CONFIG_ALPHA_SX164)
+ /* HALT (2), timer (6), ISA Bridge (7),
+ then all the PCI slots/INTXs (8-23). */
+ /* HALT should only be used for SRM console boots. */
+ pld &= 0x0000000000ffffc0UL;
+#endif
+
+ /*
+ * Now for every possible bit set, work through them and call
+ * the appropriate interrupt handler.
+ */
+ while (pld) {
+ i = ffz(~pld);
+ pld &= pld - 1; /* clear least bit set */
+ if (i == 7) {
+ isa_device_interrupt(vector, regs);
+ } else if (i == 6)
+ continue;
+ else { /* if not timer int */
+ device_interrupt(16 + i, 16 + i, regs);
+ }
+ *(vulp)PYXIS_INT_REQ = 1UL << i; mb();
+ tmp = *(vulp)PYXIS_INT_REQ;
+ }
+ restore_flags(flags);
+}
+#endif /* MIATA || SX164 */
+
+static inline void
+noritake_device_interrupt(unsigned long vector, struct pt_regs *regs)
+{
+ unsigned long pld;
+ unsigned int i;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ /* read the interrupt summary registers of NORITAKE */
+ pld = ((unsigned long) inw(0x54c) << 32) |
+ ((unsigned long) inw(0x54a) << 16) |
+ ((unsigned long) inb(0xa0) << 8) |
+ ((unsigned long) inb(0x20));
+
+#if 0
+ printk("[0x%08lx]", pld);
+#endif
+
+ /*
+ * Now for every possible bit set, work through them and call
+ * the appropriate interrupt handler.
+ */
+ while (pld) {
+ i = ffz(~pld);
+ pld &= pld - 1; /* clear least bit set */
+ if (i < 16) {
+ isa_device_interrupt(vector, regs);
+ } else {
+ device_interrupt(i, i, regs);
+ }
+ }
+ restore_flags(flags);
+}
+
+#if defined(CONFIG_ALPHA_RUFFIAN)
+static inline void
+ruffian_device_interrupt(unsigned long vector, struct pt_regs *regs)
+{
+ unsigned long pld;
+ unsigned int i;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ /* Read the interrupt summary register of PYXIS */
+ pld = *(vulp)PYXIS_INT_REQ;
+
+ /* For now, AND off any bits we are not interested in:
+ * HALT (2), timer (6), ISA Bridge (7), 21142 (8)
+ * then all the PCI slots/INTXs (12-31)
+ * flash(5) :DWH:
+ */
+ pld &= 0x00000000ffffff9fUL;
+
+ /*
+ * Now for every possible bit set, work through them and call
+ * the appropriate interrupt handler.
+ */
+ while (pld) {
+ i = ffz(~pld);
+ pld &= pld - 1; /* clear least bit set */
+
+ if (i == 7) {
+ /* Copy this bit from isa_device_interrupt cause
+ we need to hook into int 0 for the timer. I
+ refuse to soil device_interrupt with ifdefs. */
+
+ /* Generate a PCI interrupt acknowledge cycle.
+ The PIC will respond with the interrupt
+ vector of the highest priority interrupt
+ that is pending. The PALcode sets up the
+ interrupts vectors such that irq level L
+ generates vector L. */
+
+ unsigned int j = *(vuip)PYXIS_IACK_SC & 0xff;
+ if (j == 7 && !(inb(0x20) & 0x80)) {
+ /* It's only a passive release... */
+ } else if (j == 0) {
+ timer_interrupt(regs);
+ ack_irq(0);
+ } else {
+ device_interrupt(j, j, regs);
+ }
+ } else {
+ device_interrupt(16 + i, 16 + i, regs);
+ }
+
+ *(vulp)PYXIS_INT_REQ = 1UL << i;
+ mb();
+ *(vulp)PYXIS_INT_REQ;
+ }
+
+ restore_flags(flags);
+}
+#endif /* RUFFIAN */
+
#endif /* CONFIG_PCI */
/*
@@ -611,7 +1079,8 @@ static inline void eb66_and_eb64p_device_interrupt(unsigned long vector,
* "ack" to a different interrupt than we report to the rest of the
* world.
*/
-static inline void srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
+static inline void
+srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
{
int irq, ack;
unsigned long flags;
@@ -624,25 +1093,69 @@ static inline void srm_device_interrupt(unsigned long vector, struct pt_regs * r
#ifdef CONFIG_ALPHA_JENSEN
switch (vector) {
- case 0x660: handle_nmi(regs); return;
+ case 0x660: handle_nmi(regs); return;
/* local device interrupts: */
- case 0x900: handle_irq(4, regs); return; /* com1 -> irq 4 */
- case 0x920: handle_irq(3, regs); return; /* com2 -> irq 3 */
- case 0x980: handle_irq(1, regs); return; /* kbd -> irq 1 */
- case 0x990: handle_irq(9, regs); return; /* mouse -> irq 9 */
- default:
+ case 0x900: handle_irq(4, regs); return; /* com1 -> irq 4 */
+ case 0x920: handle_irq(3, regs); return; /* com2 -> irq 3 */
+ case 0x980: handle_irq(1, regs); return; /* kbd -> irq 1 */
+ case 0x990: handle_irq(9, regs); return; /* mouse -> irq 9 */
+ default:
if (vector > 0x900) {
printk("Unknown local interrupt %lx\n", vector);
}
}
- /* irq1 is supposed to be the keyboard, silly Jensen (is this really needed??) */
+ /* irq1 is supposed to be the keyboard, silly Jensen
+ (is this really needed??) */
if (irq == 1)
irq = 7;
#endif /* CONFIG_ALPHA_JENSEN */
+#ifdef CONFIG_ALPHA_MIATA
+ /*
+ * I really hate to do this, but the MIATA SRM console ignores the
+ * low 8 bits in the interrupt summary register, and reports the
+ * vector 0x80 *lower* than I expected from the bit numbering in
+ * the documentation.
+ * This was done because the low 8 summary bits really aren't used
+ * for reporting any interrupts (the PCI-ISA bridge, bit 7, isn't
+ * used for this purpose, as PIC interrupts are delivered as the
+ * vectors 0x800-0x8f0).
+ * But I really don't want to change the fixup code for allocation
+ * of IRQs, nor the irq_mask maintenance stuff, both of which look
+ * nice and clean now.
+ * So, here's this grotty hack... :-(
+ */
+ if (irq >= 16)
+ ack = irq = irq + 8;
+#endif /* CONFIG_ALPHA_MIATA */
+
+#ifdef CONFIG_ALPHA_NORITAKE
+ /*
+ * I really hate to do this, but the NORITAKE SRM console reports
+ * PCI vectors *lower* than I expected from the bit numbering in
+ * the documentation.
+ * But I really don't want to change the fixup code for allocation
+ * of IRQs, nor the irq_mask maintenance stuff, both of which look
+ * nice and clean now.
+ * So, here's this additional grotty hack... :-(
+ */
+ if (irq >= 16)
+ ack = irq = irq + 1;
+#endif /* CONFIG_ALPHA_NORITAKE */
+
+#ifdef CONFIG_ALPHA_SABLE
+ irq = sable_mask_to_irq[(ack)];
+#if 0
+ if (irq == 5 || irq == 9 || irq == 10 || irq == 11 ||
+ irq == 14 || irq == 15)
+ printk("srm_device_interrupt: vector=0x%lx ack=0x%x"
+ " irq=0x%x\n", vector, ack, irq);
+#endif
+#endif /* CONFIG_ALPHA_SABLE */
+
device_interrupt(irq, ack, regs);
- restore_flags(flags) ;
+ restore_flags(flags);
}
/*
@@ -665,6 +1178,7 @@ unsigned long probe_irq_on(void)
irqs |= (1UL << i);
}
}
+
/*
* Wait about 100ms for spurious interrupts to mask themselves
* out again...
@@ -683,7 +1197,6 @@ unsigned long probe_irq_on(void)
*/
int probe_irq_off(unsigned long irqs)
{
- unsigned long delay;
int i;
irqs &= irq_mask;
@@ -695,88 +1208,244 @@ int probe_irq_off(unsigned long irqs)
return i;
}
-static void machine_check(unsigned long vector, unsigned long la, struct pt_regs * regs)
+extern void lca_machine_check (unsigned long vector, unsigned long la,
+ struct pt_regs *regs);
+extern void apecs_machine_check(unsigned long vector, unsigned long la,
+ struct pt_regs * regs);
+extern void cia_machine_check(unsigned long vector, unsigned long la,
+ struct pt_regs * regs);
+extern void pyxis_machine_check(unsigned long vector, unsigned long la,
+ struct pt_regs * regs);
+extern void t2_machine_check(unsigned long vector, unsigned long la,
+ struct pt_regs * regs);
+
+static void
+machine_check(unsigned long vector, unsigned long la, struct pt_regs *regs)
{
#if defined(CONFIG_ALPHA_LCA)
- extern void lca_machine_check (unsigned long vector, unsigned long la,
- struct pt_regs *regs);
lca_machine_check(vector, la, regs);
#elif defined(CONFIG_ALPHA_APECS)
- extern void apecs_machine_check(unsigned long vector, unsigned long la,
- struct pt_regs * regs);
apecs_machine_check(vector, la, regs);
#elif defined(CONFIG_ALPHA_CIA)
- extern void cia_machine_check(unsigned long vector, unsigned long la,
- struct pt_regs * regs);
cia_machine_check(vector, la, regs);
+#elif defined(CONFIG_ALPHA_PYXIS)
+ pyxis_machine_check(vector, la, regs);
+#elif defined(CONFIG_ALPHA_T2)
+ t2_machine_check(vector, la, regs);
#else
printk("Machine check\n");
#endif
}
-asmlinkage void do_entInt(unsigned long type, unsigned long vector, unsigned long la_ptr,
- unsigned long a3, unsigned long a4, unsigned long a5,
- struct pt_regs regs)
+asmlinkage void
+do_entInt(unsigned long type, unsigned long vector, unsigned long la_ptr,
+ unsigned long a3, unsigned long a4, unsigned long a5,
+ struct pt_regs regs)
{
switch (type) {
- case 0:
- printk("Interprocessor interrupt? You must be kidding\n");
- break;
- case 1:
- handle_irq(RTC_IRQ, &regs);
- return;
- case 2:
- machine_check(vector, la_ptr, &regs);
- return;
- case 3:
+ case 0:
+ printk("Interprocessor interrupt? You must be kidding\n");
+ break;
+ case 1:
+ handle_irq(RTC_IRQ, &regs);
+ return;
+ case 2:
+ machine_check(vector, la_ptr, &regs);
+ return;
+ case 3:
#if defined(CONFIG_ALPHA_JENSEN) || defined(CONFIG_ALPHA_NONAME) || \
defined(CONFIG_ALPHA_P2K) || defined(CONFIG_ALPHA_SRM)
- srm_device_interrupt(vector, &regs);
-#elif NR_IRQS == 48
- alcor_and_xlt_device_interrupt(vector, &regs);
-#elif NR_IRQS == 33
- cabriolet_and_eb66p_device_interrupt(vector, &regs);
+ srm_device_interrupt(vector, &regs);
+#elif defined(CONFIG_ALPHA_MIATA) || defined(CONFIG_ALPHA_SX164)
+ miata_device_interrupt(vector, &regs);
+#elif defined(CONFIG_ALPHA_NORITAKE)
+ noritake_device_interrupt(vector, &regs);
+#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
+ alcor_and_xlt_device_interrupt(vector, &regs);
+#elif defined(CONFIG_ALPHA_RUFFIAN)
+ ruffian_device_interrupt(vector, &regs);
#elif defined(CONFIG_ALPHA_MIKASA)
- mikasa_device_interrupt(vector, &regs);
+ mikasa_device_interrupt(vector, &regs);
+#elif NR_IRQS == 33
+ cabriolet_and_eb66p_device_interrupt(vector, &regs);
#elif NR_IRQS == 32
- eb66_and_eb64p_device_interrupt(vector, &regs);
+ eb66_and_eb64p_device_interrupt(vector, &regs);
#elif NR_IRQS == 16
- isa_device_interrupt(vector, &regs);
+ isa_device_interrupt(vector, &regs);
#endif
- return;
- case 4:
- printk("Performance counter interrupt\n");
- break;;
- default:
- printk("Hardware intr %ld %lx? Huh?\n", type, vector);
+ return;
+ case 4:
+ printk("Performance counter interrupt\n");
+ break;
+ default:
+ printk("Hardware intr %ld %lx? Huh?\n", type, vector);
}
printk("PC = %016lx PS=%04lx\n", regs.pc, regs.ps);
}
extern asmlinkage void entInt(void);
-void init_IRQ(void)
+static inline void sable_init_IRQ(void)
+{
+ outb(irq_mask , 0x537); /* slave 0 */
+ outb(irq_mask >> 8, 0x53b); /* slave 1 */
+ outb(irq_mask >> 16, 0x53d); /* slave 2 */
+ outb(0x44, 0x535); /* enable cascades in master */
+}
+
+#ifdef CONFIG_ALPHA_SX164
+static inline void sx164_init_IRQ(void)
+{
+ /* note invert on MASK bits */
+ *(vulp)PYXIS_INT_MASK = ~((long)irq_mask >> 16); mb();
+#if 0
+ *(vulp)PYXIS_INT_HILO = 0x000000B2UL; mb(); /* ISA/NMI HI */
+ *(vulp)PYXIS_RT_COUNT = 0UL; mb(); /* clear count */
+#endif
+ enable_irq(16 + 6); /* enable timer */
+ enable_irq(16 + 7); /* enable ISA PIC cascade */
+ enable_irq(2); /* enable cascade */
+}
+#endif /* SX164 */
+
+#ifdef CONFIG_ALPHA_RUFFIAN
+static inline void ruffian_init_IRQ(void)
+{
+ /* invert 6&7 for i82371 */
+ *(vulp)PYXIS_INT_HILO = 0x000000c0UL; mb();
+ *(vulp)PYXIS_INT_CNFG = 0x00002064UL; mb(); /* all clear */
+ *(vulp)PYXIS_INT_MASK = 0x00000000UL; mb();
+ *(vulp)PYXIS_INT_REQ = 0xffffffffUL; mb();
+
+ outb(0x11,0xA0);
+ outb(0x08,0xA1);
+ outb(0x02,0xA1);
+ outb(0x01,0xA1);
+ outb(0xFF,0xA1);
+
+ outb(0x11,0x20);
+ outb(0x00,0x21);
+ outb(0x04,0x21);
+ outb(0x01,0x21);
+ outb(0xFF,0x21);
+
+ /* Send -INTA pulses to clear any pending interrupts ...*/
+ *(vuip) IACK_SC;
+
+ /* Finish writing the 82C59A PIC Operation Control Words */
+ outb(0x20,0xA0);
+ outb(0x20,0x20);
+
+ /* Turn on the interrupt controller, the timer interrupt */
+ enable_irq(16 + 7); /* enable ISA PIC cascade */
+ enable_irq(0); /* enable timer */
+ enable_irq(2); /* enable 2nd PIC cascade */
+}
+#endif /* RUFFIAN */
+
+
+#ifdef CONFIG_ALPHA_MIATA
+static inline void miata_init_IRQ(void)
+{
+ /* note invert on MASK bits */
+ *(vulp)PYXIS_INT_MASK = ~((long)irq_mask >> 16); mb(); /* invert */
+ *(vulp)PYXIS_INT_HILO = 0x000000B2UL; mb(); /* ISA/NMI HI */
+ *(vulp)PYXIS_RT_COUNT = 0UL; mb(); /* clear count */
+ *(vulp)PYXIS_INT_REQ = 0x4000000000000000UL; mb(); /* clear upper timer */
+#if 0
+ *(vulp)PYXIS_INT_ROUTE = 0UL; mb(); /* all are level */
+ *(vulp)PYXIS_INT_CNFG = 0UL; mb(); /* all clear */
+#endif
+ enable_irq(16 + 2); /* enable HALT switch - SRM only? */
+ enable_irq(16 + 6); /* enable timer */
+ enable_irq(16 + 7); /* enable ISA PIC cascade */
+ enable_irq(2); /* enable cascade */
+}
+#endif
+
+static inline void noritake_init_IRQ(void)
+{
+ outw(~(irq_mask >> 16), 0x54a); /* note invert */
+ outw(~(irq_mask >> 32), 0x54c); /* note invert */
+ enable_irq(2); /* enable cascade */
+}
+
+#if defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
+static inline void alcor_and_xlt_init_IRQ(void)
+{
+ *(vuip)GRU_INT_MASK = ~(irq_mask >> 16); mb(); /* note invert */
+ *(vuip)GRU_INT_EDGE = 0U; mb(); /* all are level */
+ *(vuip)GRU_INT_HILO = 0x80000000U; mb(); /* ISA only HI */
+ *(vuip)GRU_INT_CLEAR = 0UL; mb(); /* all clear */
+
+ enable_irq(16 + 31); /* enable (E)ISA PIC cascade */
+ enable_irq(2); /* enable cascade */
+}
+#endif
+
+static inline void mikasa_init_IRQ(void)
+{
+ outw(~(irq_mask >> 16), 0x536); /* note invert */
+ enable_irq(2); /* enable cascade */
+}
+
+static inline void init_IRQ_33(void)
+{
+ outl(irq_mask >> 16, 0x804);
+ enable_irq(16 + 4); /* enable SIO cascade */
+ enable_irq(2); /* enable cascade */
+}
+
+static inline void init_IRQ_32(void)
+{
+ outb(irq_mask >> 16, 0x26);
+ outb(irq_mask >> 24, 0x27);
+ enable_irq(16 + 5); /* enable SIO cascade */
+ enable_irq(2); /* enable cascade */
+}
+
+static inline void init_IRQ_16(void)
+{
+ enable_irq(2); /* enable cascade */
+}
+
+void __init
+init_IRQ(void)
{
wrent(entInt, 0);
dma_outb(0, DMA1_RESET_REG);
dma_outb(0, DMA2_RESET_REG);
+#ifndef CONFIG_ALPHA_SX164
dma_outb(0, DMA1_CLR_MASK_REG);
+ /* We need to figure out why this fails on the SX164. */
dma_outb(0, DMA2_CLR_MASK_REG);
-#if NR_IRQS == 48
- *(unsigned int *)GRU_INT_MASK = ~(irq_mask >> 16); mb();/* invert */
- *(unsigned int *)GRU_INT_EDGE = 0UL; mb();/* all are level */
- *(unsigned int *)GRU_INT_HILO = 0x80000000UL; mb();/* ISA only HI */
- *(unsigned int *)GRU_INT_CLEAR = 0UL; mb();/* all clear */
- enable_irq(16 + 31); /* enable (E)ISA PIC cascade */
-#elif NR_IRQS == 33
- outl(irq_mask >> 16, 0x804);
- enable_irq(16 + 4); /* enable SIO cascade */
+#endif
+
+#if defined(CONFIG_ALPHA_SABLE)
+ sable_init_IRQ();
+#elif defined(CONFIG_ALPHA_MIATA)
+ miata_init_IRQ();
+#elif defined(CONFIG_ALPHA_SX164)
+ sx164_init_IRQ();
+#elif defined(CONFIG_ALPHA_NORITAKE)
+ noritake_init_IRQ();
+#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
+ alcor_and_xlt_init_IRQ();
+#elif (defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164)) \
+ && defined(CONFIG_ALPHA_SRM)
+ /* Disable all the PCI interrupts? Otherwise, everthing was
+ done by SRM already. */
#elif defined(CONFIG_ALPHA_MIKASA)
- outw(~(irq_mask >> 16), 0x536); /* note invert */
+ mikasa_init_IRQ();
+#elif defined(CONFIG_ALPHA_RUFFIAN)
+ ruffian_init_IRQ();
+#elif NR_IRQS == 33
+ init_IRQ_33();
#elif NR_IRQS == 32
- outb(irq_mask >> 16, 0x26);
- outb(irq_mask >> 24, 0x27);
- enable_irq(16 + 5); /* enable SIO cascade */
+ init_IRQ_32();
+#elif NR_IRQS == 16
+ init_IRQ_16();
+#else
+#error "How do I initialize the interrupt hardware?"
#endif
- enable_irq(2); /* enable cascade */
}
diff --git a/arch/alpha/kernel/lca.c b/arch/alpha/kernel/lca.c
index 7dcc5506f..2a39a1cf9 100644
--- a/arch/alpha/kernel/lca.c
+++ b/arch/alpha/kernel/lca.c
@@ -6,7 +6,6 @@
* bios code.
*/
#include <linux/kernel.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/bios32.h>
#include <linux/pci.h>
@@ -19,9 +18,8 @@
* BIOS32-style PCI interface:
*/
-#ifdef CONFIG_ALPHA_LCA
-
#define vulp volatile unsigned long *
+#define vuip volatile unsigned int *
/*
* Machine check reasons. Defined according to PALcode sources
@@ -102,11 +100,11 @@ static int mk_conf_addr(unsigned char bus, unsigned char device_fn,
return -1;
}
- *((volatile unsigned long*) LCA_IOC_CONF) = 0;
+ *((vulp) LCA_IOC_CONF) = 0;
addr = (1 << (11 + device)) | (func << 8) | where;
} else {
/* type 1 configuration cycle: */
- *((volatile unsigned long*) LCA_IOC_CONF) = 1;
+ *((vulp) LCA_IOC_CONF) = 1;
addr = (bus << 16) | (device_fn << 8) | where;
}
*pci_addr = addr;
@@ -123,13 +121,13 @@ static unsigned int conf_read(unsigned long addr)
cli();
/* reset status register to avoid loosing errors: */
- stat0 = *((volatile unsigned long*)LCA_IOC_STAT0);
- *((volatile unsigned long*)LCA_IOC_STAT0) = stat0;
+ stat0 = *(vulp)LCA_IOC_STAT0;
+ *(vulp)LCA_IOC_STAT0 = stat0;
mb();
/* access configuration space: */
- value = *((volatile unsigned int*)addr);
+ value = *(vuip)addr;
draina();
stat0 = *((unsigned long*)LCA_IOC_STAT0);
@@ -141,7 +139,7 @@ static unsigned int conf_read(unsigned long addr)
}
/* reset error status: */
- *((volatile unsigned long*)LCA_IOC_STAT0) = stat0;
+ *(vulp)LCA_IOC_STAT0 = stat0;
mb();
wrmces(0x7); /* reset machine check */
@@ -160,13 +158,13 @@ static void conf_write(unsigned long addr, unsigned int value)
cli();
/* reset status register to avoid loosing errors: */
- stat0 = *((volatile unsigned long*)LCA_IOC_STAT0);
- *((volatile unsigned long*)LCA_IOC_STAT0) = stat0;
+ stat0 = *(vulp)LCA_IOC_STAT0;
+ *(vulp)LCA_IOC_STAT0 = stat0;
mb();
/* access configuration space: */
- *((volatile unsigned int*)addr) = value;
+ *(vuip)addr = value;
draina();
stat0 = *((unsigned long*)LCA_IOC_STAT0);
@@ -178,7 +176,7 @@ static void conf_write(unsigned long addr, unsigned int value)
}
/* reset error status: */
- *((volatile unsigned long*)LCA_IOC_STAT0) = stat0;
+ *(vulp)LCA_IOC_STAT0 = stat0;
mb();
wrmces(0x7); /* reset machine check */
}
@@ -310,13 +308,12 @@ unsigned long lca_init(unsigned long mem_start, unsigned long mem_end)
}
-
-
/*
* Constants used during machine-check handling. I suppose these
* could be moved into lca.h but I don't see much reason why anybody
* else would want to use them.
*/
+
#define ESR_EAV (1UL<< 0) /* error address valid */
#define ESR_CEE (1UL<< 1) /* correctable error */
#define ESR_UEE (1UL<< 2) /* uncorrectable error */
@@ -338,53 +335,60 @@ unsigned long lca_init(unsigned long mem_start, unsigned long mem_end)
void mem_error (unsigned long esr, unsigned long ear)
{
- printk(" %s %s error to %s occurred at address %x\n",
- (esr & ESR_CEE) ? "Correctable" : ((esr & ESR_UEE) ? "Uncorrectable" : "A"),
- (esr & ESR_WRE) ? "write" : "read",
- (esr & ESR_SOR) ? "memory" : "b-cache",
- (unsigned) (ear & 0x1ffffff8));
- if (esr & ESR_CTE) {
- printk(" A b-cache tag parity error was detected.\n");
- }
- if (esr & ESR_MSE) {
- printk(" Several other correctable errors occurred.\n");
- }
- if (esr & ESR_MHE) {
- printk(" Several other uncorrectable errors occurred.\n");
- }
- if (esr & ESR_NXM) {
- printk(" Attempted to access non-existent memory.\n");
- }
+ printk(" %s %s error to %s occurred at address %x\n",
+ *((esr & ESR_CEE) ? "Correctable" :
+ (esr & ESR_UEE) ? "Uncorrectable" : "A"),
+ (esr & ESR_WRE) ? "write" : "read",
+ (esr & ESR_SOR) ? "memory" : "b-cache",
+ (unsigned) (ear & 0x1ffffff8));
+ if (esr & ESR_CTE) {
+ printk(" A b-cache tag parity error was detected.\n");
+ }
+ if (esr & ESR_MSE) {
+ printk(" Several other correctable errors occurred.\n");
+ }
+ if (esr & ESR_MHE) {
+ printk(" Several other uncorrectable errors occurred.\n");
+ }
+ if (esr & ESR_NXM) {
+ printk(" Attempted to access non-existent memory.\n");
+ }
}
void ioc_error (__u32 stat0, __u32 stat1)
{
- const char *pci_cmd[] = {
- "Interrupt Acknowledge", "Special", "I/O Read", "I/O Write",
- "Rsvd 1", "Rsvd 2", "Memory Read", "Memory Write", "Rsvd3", "Rsvd4",
- "Configuration Read", "Configuration Write", "Memory Read Multiple",
- "Dual Address", "Memory Read Line", "Memory Write and Invalidate"
- };
- const char *err_name[] = {
- "exceeded retry limit", "no device", "bad data parity", "target abort",
- "bad address parity", "page table read error", "invalid page", "data error"
- };
- unsigned code = (stat0 & IOC_CODE) >> IOC_CODE_SHIFT;
- unsigned cmd = (stat0 & IOC_CMD) >> IOC_CMD_SHIFT;
-
- printk(" %s initiated PCI %s cycle to address %x failed due to %s.\n",
- code > 3 ? "PCI" : "CPU", pci_cmd[cmd], stat1, err_name[code]);
- if (code == 5 || code == 6) {
- printk(" (Error occurred at PCI memory address %x.)\n", (stat0 & ~IOC_P_NBR));
- }
- if (stat0 & IOC_LOST) {
- printk(" Other PCI errors occurred simultaneously.\n");
- }
+ static const char * const pci_cmd[] = {
+ "Interrupt Acknowledge", "Special", "I/O Read", "I/O Write",
+ "Rsvd 1", "Rsvd 2", "Memory Read", "Memory Write", "Rsvd3",
+ "Rsvd4", "Configuration Read", "Configuration Write",
+ "Memory Read Multiple", "Dual Address", "Memory Read Line",
+ "Memory Write and Invalidate"
+ };
+ static const char * const err_name[] = {
+ "exceeded retry limit", "no device", "bad data parity",
+ "target abort", "bad address parity", "page table read error",
+ "invalid page", "data error"
+ };
+ unsigned code = (stat0 & IOC_CODE) >> IOC_CODE_SHIFT;
+ unsigned cmd = (stat0 & IOC_CMD) >> IOC_CMD_SHIFT;
+
+ printk(" %s initiated PCI %s cycle to address %x"
+ " failed due to %s.\n",
+ code > 3 ? "PCI" : "CPU", pci_cmd[cmd], stat1, err_name[code]);
+
+ if (code == 5 || code == 6) {
+ printk(" (Error occurred at PCI memory address %x.)\n",
+ (stat0 & ~IOC_P_NBR));
+ }
+ if (stat0 & IOC_LOST) {
+ printk(" Other PCI errors occurred simultaneously.\n");
+ }
}
-void lca_machine_check (unsigned long vector, unsigned long la, struct pt_regs *regs)
+void lca_machine_check (unsigned long vector, unsigned long la,
+ struct pt_regs *regs)
{
unsigned long * ptr;
const char * reason;
@@ -403,21 +407,21 @@ void lca_machine_check (unsigned long vector, unsigned long la, struct pt_regs *
* revision level, which we ignore for now.
*/
switch (el.c->code & 0xffffffff) {
- case MCHK_K_TPERR: reason = "tag parity error"; break;
- case MCHK_K_TCPERR: reason = "tag control parity error"; break;
- case MCHK_K_HERR: reason = "access to non-existent memory"; break;
- case MCHK_K_ECC_C: reason = "correctable ECC error"; break;
- case MCHK_K_ECC_NC: reason = "non-correctable ECC error"; break;
- case MCHK_K_CACKSOFT: reason = "MCHK_K_CACKSOFT"; break; /* what's this? */
- case MCHK_K_BUGCHECK: reason = "illegal exception in PAL mode"; break;
- case MCHK_K_OS_BUGCHECK: reason = "callsys in kernel mode"; break;
- case MCHK_K_DCPERR: reason = "d-cache parity error"; break;
- case MCHK_K_ICPERR: reason = "i-cache parity error"; break;
- case MCHK_K_SIO_SERR: reason = "SIO SERR occurred on on PCI bus"; break;
- case MCHK_K_SIO_IOCHK: reason = "SIO IOCHK occurred on ISA bus"; break;
- case MCHK_K_DCSR: reason = "MCHK_K_DCSR"; break;
- case MCHK_K_UNKNOWN:
- default:
+ case MCHK_K_TPERR: reason = "tag parity error"; break;
+ case MCHK_K_TCPERR: reason = "tag control parity error"; break;
+ case MCHK_K_HERR: reason = "access to non-existent memory"; break;
+ case MCHK_K_ECC_C: reason = "correctable ECC error"; break;
+ case MCHK_K_ECC_NC: reason = "non-correctable ECC error"; break;
+ case MCHK_K_CACKSOFT: reason = "MCHK_K_CACKSOFT"; break; /* what's this? */
+ case MCHK_K_BUGCHECK: reason = "illegal exception in PAL mode"; break;
+ case MCHK_K_OS_BUGCHECK: reason = "callsys in kernel mode"; break;
+ case MCHK_K_DCPERR: reason = "d-cache parity error"; break;
+ case MCHK_K_ICPERR: reason = "i-cache parity error"; break;
+ case MCHK_K_SIO_SERR: reason = "SIO SERR occurred on on PCI bus"; break;
+ case MCHK_K_SIO_IOCHK: reason = "SIO IOCHK occurred on ISA bus"; break;
+ case MCHK_K_DCSR: reason = "MCHK_K_DCSR"; break;
+ case MCHK_K_UNKNOWN:
+ default:
sprintf(buf, "reason for machine-check unknown (0x%lx)",
el.c->code & 0xffffffff);
reason = buf;
@@ -427,19 +431,20 @@ void lca_machine_check (unsigned long vector, unsigned long la, struct pt_regs *
wrmces(rdmces()); /* reset machine check pending flag */
switch (el.c->size) {
- case sizeof(struct el_lca_mcheck_short):
+ case sizeof(struct el_lca_mcheck_short):
printk(KERN_CRIT
" Reason: %s (short frame%s, dc_stat=%lx):\n",
- reason, el.c->retry ? ", retryable" : "", el.s->dc_stat);
+ reason, el.c->retry ? ", retryable" : "",
+ el.s->dc_stat);
if (el.s->esr & ESR_EAV) {
- mem_error(el.s->esr, el.s->ear);
+ mem_error(el.s->esr, el.s->ear);
}
if (el.s->ioc_stat0 & IOC_ERR) {
- ioc_error(el.s->ioc_stat0, el.s->ioc_stat1);
+ ioc_error(el.s->ioc_stat0, el.s->ioc_stat1);
}
break;
- case sizeof(struct el_lca_mcheck_long):
+ case sizeof(struct el_lca_mcheck_long):
printk(KERN_CRIT " Reason: %s (long frame%s):\n",
reason, el.c->retry ? ", retryable" : "");
printk(KERN_CRIT
@@ -447,14 +452,14 @@ void lca_machine_check (unsigned long vector, unsigned long la, struct pt_regs *
el.l->pt[0], el.l->exc_addr, el.l->dc_stat);
printk(KERN_CRIT " car: %lx\n", el.l->car);
if (el.l->esr & ESR_EAV) {
- mem_error(el.l->esr, el.l->ear);
+ mem_error(el.l->esr, el.l->ear);
}
if (el.l->ioc_stat0 & IOC_ERR) {
- ioc_error(el.l->ioc_stat0, el.l->ioc_stat1);
+ ioc_error(el.l->ioc_stat0, el.l->ioc_stat1);
}
break;
- default:
+ default:
printk(KERN_CRIT " Unknown errorlog size %d\n", el.c->size);
}
@@ -462,9 +467,51 @@ void lca_machine_check (unsigned long vector, unsigned long la, struct pt_regs *
ptr = (unsigned long *) la;
for (i = 0; i < el.c->size / sizeof(long); i += 2) {
- printk(KERN_CRIT " +%8lx %016lx %016lx\n",
- i*sizeof(long), ptr[i], ptr[i+1]);
+ printk(KERN_CRIT " +%8lx %016lx %016lx\n",
+ i*sizeof(long), ptr[i], ptr[i+1]);
}
}
-#endif /* CONFIG_ALPHA_LCA */
+/*
+ * The following routines are needed to support the SPEED changing
+ * necessary to successfully manage the thermal problem on the AlphaBook1.
+ */
+
+void
+lca_clock_print(void)
+{
+ long pmr_reg;
+
+ pmr_reg = READ_PMR;
+
+ printk("Status of clock control:\n");
+ printk("\tPrimary clock divisor\t0x%x\n", GET_PRIMARY(pmr_reg));
+ printk("\tOverride clock divisor\t0x%x\n", GET_OVERRIDE(pmr_reg));
+ printk("\tInterrupt override is %s\n",
+ (pmr_reg & LCA_PMR_INTO) ? "on" : "off");
+ printk("\tDMA override is %s\n",
+ (pmr_reg & LCA_PMR_DMAO) ? "on" : "off");
+
+}
+
+int
+lca_get_clock(void)
+{
+ long pmr_reg;
+
+ pmr_reg = READ_PMR;
+ return(GET_PRIMARY(pmr_reg));
+
+}
+
+void
+lca_clock_fiddle(int divisor)
+{
+ long pmr_reg;
+
+ pmr_reg = READ_PMR;
+ SET_PRIMARY_CLOCK(pmr_reg, divisor);
+ /* lca_norm_clock = divisor; */
+ WRITE_PMR(pmr_reg);
+ mb();
+}
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index e64b6d5e1..a63fb2be6 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -24,6 +24,7 @@
#include <linux/a.out.h>
#include <linux/utsname.h>
#include <linux/time.h>
+#include <linux/timex.h>
#include <linux/major.h>
#include <linux/stat.h>
#include <linux/mman.h>
@@ -246,7 +247,7 @@ asmlinkage unsigned long osf_mmap(unsigned long addr, unsigned long len,
unsigned long ret = -EBADF;
lock_kernel();
- if (flags & (MAP_HASSEMAPHORE | MAP_INHERIT | MAP_UNALIGNED))
+ if (flags & (_MAP_HASSEMAPHORE | _MAP_INHERIT | _MAP_UNALIGNED))
printk("%s: unimplemented OSF mmap flags %04lx\n", current->comm, flags);
if (!(flags & MAP_ANONYMOUS)) {
if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
@@ -846,10 +847,6 @@ asmlinkage unsigned long osf_getsysinfo(unsigned long op, void *buffer,
return -EOPNOTSUPP;
}
-/* Dummy functions for now */
-#define wrfpcr(x) do { } while (0)
-#define rdfpcr() 0
-
asmlinkage unsigned long osf_setsysinfo(unsigned long op, void *buffer,
unsigned long nbytes,
int *start, void *arg)
@@ -875,7 +872,7 @@ asmlinkage unsigned long osf_setsysinfo(unsigned long op, void *buffer,
software but have not been seen, enable the exception in
hardware so that we can update our software status mask. */
fpcr = rdfpcr() & (~FPCR_MASK | FPCR_DYN_MASK);
- fpcr = ieee_swcr_to_fpcr(swcr | (~swcr & IEEE_STATUS_MASK)>>16);
+ fpcr |= ieee_swcr_to_fpcr(swcr | (~swcr & IEEE_STATUS_MASK)>>16);
wrfpcr(fpcr);
return 0;
@@ -929,6 +926,7 @@ extern int do_getitimer(int which, struct itimerval *value);
extern int do_setitimer(int which, struct itimerval *, struct itimerval *);
asmlinkage int sys_utimes(char *, struct timeval *);
extern int sys_wait4(pid_t, int *, int, struct rusage *);
+extern int do_adjtimex(struct timex *);
struct timeval32
{
@@ -966,7 +964,7 @@ static inline long get_it32(struct itimerval *o, struct itimerval32 *i)
static inline long put_it32(struct itimerval32 *o, struct itimerval *i)
{
- return (!access_ok(VERIFY_WRITE, i, sizeof(*i)) ||
+ return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
(__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) |
__put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) |
__put_user(i->it_value.tv_sec, &o->it_value.tv_sec) |
@@ -1241,7 +1239,7 @@ asmlinkage int osf_wait4(pid_t pid, int *ustatus, int options,
* seems to be a timeval pointer, and I suspect the second
* one is the time remaining.. Ho humm.. No documentation.
*/
-asmlinkage int osf_usleep_thread(struct timeval *sleep, struct timeval *remain)
+asmlinkage int osf_usleep_thread(struct timeval32 *sleep, struct timeval32 *remain)
{
struct timeval tmp;
unsigned long ticks;
@@ -1274,3 +1272,57 @@ asmlinkage int osf_usleep_thread(struct timeval *sleep, struct timeval *remain)
fault:
return -EFAULT;
}
+
+
+struct timex32 {
+ unsigned int modes; /* mode selector */
+ long offset; /* time offset (usec) */
+ long freq; /* frequency offset (scaled ppm) */
+ long maxerror; /* maximum error (usec) */
+ long esterror; /* estimated error (usec) */
+ int status; /* clock command/status */
+ long constant; /* pll time constant */
+ long precision; /* clock precision (usec) (read only) */
+ long tolerance; /* clock frequency tolerance (ppm)
+ * (read only)
+ */
+ struct timeval32 time; /* (read only) */
+ long tick; /* (modified) usecs between clock ticks */
+
+ long ppsfreq; /* pps frequency (scaled ppm) (ro) */
+ long jitter; /* pps jitter (us) (ro) */
+ int shift; /* interval duration (s) (shift) (ro) */
+ long stabil; /* pps stability (scaled ppm) (ro) */
+ long jitcnt; /* jitter limit exceeded (ro) */
+ long calcnt; /* calibration intervals (ro) */
+ long errcnt; /* calibration errors (ro) */
+ long stbcnt; /* stability limit exceeded (ro) */
+
+ int :32; int :32; int :32; int :32;
+ int :32; int :32; int :32; int :32;
+ int :32; int :32; int :32; int :32;
+};
+
+asmlinkage int sys_old_adjtimex(struct timex32 *txc_p)
+{
+ struct timex txc;
+ int ret;
+
+ /* copy relevant bits of struct timex. */
+ if (copy_from_user(&txc, txc_p, offsetof(struct timex32, time)) ||
+ copy_from_user(&txc.tick, &txc_p->tick, sizeof(struct timex32) -
+ offsetof(struct timex32, time)))
+ return -EFAULT;
+
+ if ((ret = do_adjtimex(&txc)))
+ return ret;
+
+ /* copy back to timex32 */
+ if (copy_to_user(txc_p, &txc, offsetof(struct timex32, time)) ||
+ (copy_to_user(&txc_p->tick, &txc.tick, sizeof(struct timex32) -
+ offsetof(struct timex32, tick))) ||
+ (put_tv32(&txc_p->time, &txc.time)))
+ return -EFAULT;
+
+ return 0;
+}
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index 81744663d..6a90ecb02 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -38,6 +38,7 @@
#include <asm/system.h>
#include <asm/io.h>
#include <asm/pgtable.h>
+#include <asm/hwrpb.h>
/*
* Initial task structure. Make this a per-architecture thing,
@@ -86,7 +87,7 @@ out:
return ret;
}
-void machine_restart(char * __unused)
+static void finish_shutdown(void)
{
#ifdef CONFIG_RTC /* reset rtc to defaults */
unsigned char control;
@@ -105,7 +106,6 @@ void machine_restart(char * __unused)
CMOS_READ(RTC_INTR_FLAGS);
restore_flags(flags);
#endif
-
#if defined(CONFIG_ALPHA_SRM) && defined(CONFIG_ALPHA_ALCOR)
/* who said DEC engineer's have no sense of humor? ;-)) */
*(int *) GRU_RESET = 0x0000dead;
@@ -114,12 +114,50 @@ void machine_restart(char * __unused)
halt();
}
+void machine_restart(char * __unused)
+{
+#if defined(CONFIG_ALPHA_SRM)
+ extern struct hwrpb_struct *hwrpb;
+ struct percpu_struct *cpup;
+ unsigned long flags;
+
+ cpup = (struct percpu_struct *)
+ ((unsigned long)hwrpb + hwrpb->processor_offset);
+ flags = cpup->flags;
+ flags &= ~0x0000000000ff0001UL; /* clear reason to "default" */
+ flags |= 0x0000000000020000UL; /* this is "cold bootstrap" */
+/* flags |= 0x0000000000030000UL; *//* this is "warm bootstrap" */
+ cpup->flags = flags;
+ mb();
+#endif /* SRM */
+
+ finish_shutdown();
+}
+
void machine_halt(void)
{
+#if defined(CONFIG_ALPHA_SRM)
+ extern struct hwrpb_struct *hwrpb;
+ struct percpu_struct *cpup;
+ unsigned long flags;
+
+ cpup = (struct percpu_struct *)
+ ((unsigned long)hwrpb + hwrpb->processor_offset);
+ flags = cpup->flags;
+ flags &= ~0x0000000000ff0001UL; /* clear reason to "default" */
+ flags |= 0x0000000000040000UL; /* this is "remain halted" */
+ cpup->flags = flags;
+ mb();
+
+ finish_shutdown();
+#endif /* SRM */
}
void machine_power_off(void)
{
+ /* None of the machines we support, at least, has switchable
+ power supplies. */
+ machine_halt();
}
void show_regs(struct pt_regs * regs)
diff --git a/arch/alpha/kernel/pyxis.c b/arch/alpha/kernel/pyxis.c
new file mode 100644
index 000000000..b4c5d188e
--- /dev/null
+++ b/arch/alpha/kernel/pyxis.c
@@ -0,0 +1,557 @@
+/*
+ * Code common to all PYXIS chips.
+ *
+ * Based on code written by David A Rusling (david.rusling@reo.mts.dec.com).
+ *
+ */
+#include <linux/config.h> /* CONFIG_ALPHA_RUFFIAN. */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/hwrpb.h>
+#include <asm/ptrace.h>
+#include <asm/mmu_context.h>
+
+/* NOTE: Herein are back-to-back mb insns. They are magic.
+ A plausible explanation is that the i/o controler does not properly
+ handle the system transaction. Another involves timing. Ho hum. */
+
+extern struct hwrpb_struct *hwrpb;
+extern asmlinkage void wrmces(unsigned long mces);
+extern int alpha_sys_type;
+
+/*
+ * BIOS32-style PCI interface:
+ */
+
+#ifdef DEBUG
+# define DBG(args) printk args
+#else
+# define DBG(args)
+#endif
+
+#define DEBUG_MCHECK
+#ifdef DEBUG_MCHECK
+# define DBG_MCK(args) printk args
+#else
+# define DBG_MCK(args)
+#endif
+
+#define vulp volatile unsigned long *
+#define vuip volatile unsigned int *
+
+static volatile unsigned int PYXIS_mcheck_expected = 0;
+static volatile unsigned int PYXIS_mcheck_taken = 0;
+static unsigned int PYXIS_jd;
+
+
+/*
+ * Given a bus, device, and function number, compute resulting
+ * configuration space address and setup the PYXIS_HAXR2 register
+ * accordingly. It is therefore not safe to have concurrent
+ * invocations to configuration space access routines, but there
+ * really shouldn't be any need for this.
+ *
+ * Type 0:
+ *
+ * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1
+ * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|0|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * 31:11 Device select bit.
+ * 10:8 Function number
+ * 7:2 Register number
+ *
+ * Type 1:
+ *
+ * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1
+ * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * 31:24 reserved
+ * 23:16 bus number (8 bits = 128 possible buses)
+ * 15:11 Device number (5 bits)
+ * 10:8 function number
+ * 7:2 register number
+ *
+ * Notes:
+ * The function number selects which function of a multi-function device
+ * (e.g., scsi and ethernet).
+ *
+ * The register selects a DWORD (32 bit) register offset. Hence it
+ * doesn't get shifted by 2 bits as we want to "drop" the bottom two
+ * bits.
+ */
+static int mk_conf_addr(unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned long *pci_addr,
+ unsigned char *type1)
+{
+ unsigned long addr;
+
+ DBG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x,"
+ " pci_addr=0x%p, type1=0x%p)\n",
+ bus, device_fn, where, pci_addr, type1));
+
+ if (bus == 0) {
+ int device;
+
+ device = device_fn >> 3;
+ /* type 0 configuration cycle: */
+#if NOT_NOW
+ if (device > 20) {
+ DBG(("mk_conf_addr: device (%d) > 20, returning -1\n",
+ device));
+ return -1;
+ }
+#endif
+ *type1 = 0;
+ addr = (device_fn << 8) | (where);
+ } else {
+ /* type 1 configuration cycle: */
+ *type1 = 1;
+ addr = (bus << 16) | (device_fn << 8) | (where);
+ }
+ *pci_addr = addr;
+ DBG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
+ return 0;
+}
+
+
+static unsigned int conf_read(unsigned long addr, unsigned char type1)
+{
+ unsigned long flags;
+ unsigned int stat0, value;
+ unsigned int pyxis_cfg = 0; /* to keep gcc quiet */
+
+ save_flags(flags); /* avoid getting hit by machine check */
+ cli();
+
+ DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1));
+
+ /* reset status register to avoid losing errors: */
+ stat0 = *(vuip)PYXIS_ERR;
+ *(vuip)PYXIS_ERR = stat0;
+ mb();
+ DBG(("conf_read: PYXIS ERR was 0x%x\n", stat0));
+ /* if Type1 access, must set PYXIS CFG */
+ if (type1) {
+ pyxis_cfg = *(vuip)PYXIS_CFG;
+ *(vuip)PYXIS_CFG = pyxis_cfg | 1;
+ mb();
+ DBG(("conf_read: TYPE1 access\n"));
+ }
+
+ mb();
+ draina();
+ PYXIS_mcheck_expected = 1;
+ PYXIS_mcheck_taken = 0;
+ mb();
+ /* access configuration space: */
+ value = *(vuip)addr;
+ mb();
+ mb(); /* magic */
+ if (PYXIS_mcheck_taken) {
+ PYXIS_mcheck_taken = 0;
+ value = 0xffffffffU;
+ mb();
+ }
+ PYXIS_mcheck_expected = 0;
+ mb();
+ /*
+ * david.rusling@reo.mts.dec.com. This code is needed for the
+ * EB64+ as it does not generate a machine check (why I don't
+ * know). When we build kernels for one particular platform
+ * then we can make this conditional on the type.
+ */
+#if 0
+ draina();
+
+ /* now look for any errors */
+ stat0 = *(vuip)PYXIS_IOC_PYXIS_ERR;
+ DBG(("conf_read: PYXIS ERR after read 0x%x\n", stat0));
+ if (stat0 & 0x8280U) { /* is any error bit set? */
+ /* if not NDEV, print status */
+ if (!(stat0 & 0x0080)) {
+ printk("PYXIS.c:conf_read: got stat0=%x\n", stat0);
+ }
+
+ /* reset error status: */
+ *(vulp)PYXIS_IOC_PYXIS_ERR = stat0;
+ mb();
+ wrmces(0x7); /* reset machine check */
+ value = 0xffffffff;
+ }
+#endif
+
+ /* if Type1 access, must reset IOC CFG so normal IO space ops work */
+ if (type1) {
+ *(vuip)PYXIS_CFG = pyxis_cfg & ~1;
+ mb();
+ }
+
+ DBG(("conf_read(): finished\n"));
+
+ restore_flags(flags);
+ return value;
+}
+
+
+static void conf_write(unsigned long addr, unsigned int value,
+ unsigned char type1)
+{
+ unsigned long flags;
+ unsigned int stat0;
+ unsigned int pyxis_cfg = 0; /* to keep gcc quiet */
+
+ save_flags(flags); /* avoid getting hit by machine check */
+ cli();
+
+ /* reset status register to avoid losing errors: */
+ stat0 = *(vuip)PYXIS_ERR;
+ *(vuip)PYXIS_ERR = stat0;
+ mb();
+ DBG(("conf_write: PYXIS ERR was 0x%x\n", stat0));
+ /* if Type1 access, must set PYXIS CFG */
+ if (type1) {
+ pyxis_cfg = *(vuip)PYXIS_CFG;
+ *(vuip)PYXIS_CFG = pyxis_cfg | 1;
+ mb();
+ DBG(("conf_read: TYPE1 access\n"));
+ }
+
+ draina();
+ PYXIS_mcheck_expected = 1;
+ mb();
+ /* access configuration space: */
+ *(vuip)addr = value;
+ mb();
+ mb(); /* magic */
+ PYXIS_mcheck_expected = 0;
+ mb();
+
+ /* if Type1 access, must reset IOC CFG so normal IO space ops work */
+ if (type1) {
+ *(vuip)PYXIS_CFG = pyxis_cfg & ~1;
+ mb();
+ }
+
+ DBG(("conf_write(): finished\n"));
+ restore_flags(flags);
+}
+
+
+int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned char *value)
+{
+ unsigned long addr = PYXIS_CONF;
+ unsigned long pci_addr;
+ unsigned char type1;
+
+ *value = 0xff;
+
+ if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ addr |= (pci_addr << 5) + 0x00;
+
+ *value = conf_read(addr, type1) >> ((where & 3) * 8);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_read_config_word (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned short *value)
+{
+ unsigned long addr = PYXIS_CONF;
+ unsigned long pci_addr;
+ unsigned char type1;
+
+ *value = 0xffff;
+
+ if (where & 0x1) {
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ }
+
+ if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) {
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ addr |= (pci_addr << 5) + 0x08;
+
+ *value = conf_read(addr, type1) >> ((where & 3) * 8);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned int *value)
+{
+ unsigned long addr = PYXIS_CONF;
+ unsigned long pci_addr;
+ unsigned char type1;
+
+ *value = 0xffffffff;
+ if (where & 0x3) {
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ }
+
+ if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) {
+ return PCIBIOS_SUCCESSFUL;
+ }
+ addr |= (pci_addr << 5) + 0x18;
+ *value = conf_read(addr, type1);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned char value)
+{
+ unsigned long addr = PYXIS_CONF;
+ unsigned long pci_addr;
+ unsigned char type1;
+
+ if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
+ return PCIBIOS_SUCCESSFUL;
+ }
+ addr |= (pci_addr << 5) + 0x00;
+ conf_write(addr, value << ((where & 3) * 8), type1);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_write_config_word (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned short value)
+{
+ unsigned long addr = PYXIS_CONF;
+ unsigned long pci_addr;
+ unsigned char type1;
+
+ if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
+ return PCIBIOS_SUCCESSFUL;
+ }
+ addr |= (pci_addr << 5) + 0x08;
+ conf_write(addr, value << ((where & 3) * 8), type1);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned int value)
+{
+ unsigned long addr = PYXIS_CONF;
+ unsigned long pci_addr;
+ unsigned char type1;
+
+ if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
+ return PCIBIOS_SUCCESSFUL;
+ }
+ addr |= (pci_addr << 5) + 0x18;
+ conf_write(addr, value << ((where & 3) * 8), type1);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+unsigned long pyxis_init(unsigned long mem_start, unsigned long mem_end)
+{
+ unsigned int pyxis_err ;
+
+ /*
+ * Set up error reporting.
+ */
+ pyxis_err = *(vuip)PYXIS_ERR ;
+ pyxis_err |= 0x180; /* master/target abort */
+ *(vuip)PYXIS_ERR = pyxis_err ;
+ mb() ;
+ pyxis_err = *(vuip)PYXIS_ERR ;
+
+#ifdef CONFIG_ALPHA_RUFFIAN
+ printk("pyxis_init: Skipping window register rewrites --"
+ " trust DeskStation firmware!\n");
+#else
+ /*
+ * Set up the PCI->physical memory translation windows.
+ * For now, windows 1,2 and 3 are disabled. In the future, we may
+ * want to use them to do scatter/gather DMA. Window 0
+ * goes at 1 GB and is 1 GB large.
+ */
+
+ *(vuip)PYXIS_W0_BASE = 1U | (PYXIS_DMA_WIN_BASE & 0xfff00000U);
+ *(vuip)PYXIS_W0_MASK = (PYXIS_DMA_WIN_SIZE - 1) & 0xfff00000U;
+ *(vuip)PYXIS_T0_BASE = 0;
+
+ *(vuip)PYXIS_W1_BASE = 0x0 ;
+ *(vuip)PYXIS_W2_BASE = 0x0 ;
+ *(vuip)PYXIS_W3_BASE = 0x0 ;
+ mb();
+#endif
+
+ /*
+ * check ASN in HWRPB for validity, report if bad
+ */
+ if (hwrpb->max_asn != MAX_ASN) {
+ printk("PYXIS_init: max ASN from HWRPB is bad (0x%lx)\n",
+ hwrpb->max_asn);
+ hwrpb->max_asn = MAX_ASN;
+ }
+
+ /*
+ * Finally, clear the PYXIS_CFG register, which gets used
+ * for PCI Config Space accesses. That is the way
+ * we want to use it, and we do not want to depend on
+ * what ARC or SRM might have left behind...
+ */
+ {
+ unsigned int pyxis_cfg;
+ pyxis_cfg = *(vuip)PYXIS_CFG; mb();
+#if 0
+ printk("PYXIS_init: CFG was 0x%x\n", pyxis_cfg);
+#endif
+ *(vuip)PYXIS_CFG = 0; mb();
+ }
+
+ {
+ unsigned int pyxis_hae_mem = *(vuip)PYXIS_HAE_MEM;
+ unsigned int pyxis_hae_io = *(vuip)PYXIS_HAE_IO;
+#if 0
+ printk("PYXIS_init: HAE_MEM was 0x%x\n", pyxis_hae_mem);
+ printk("PYXIS_init: HAE_IO was 0x%x\n", pyxis_hae_io);
+#endif
+ *(vuip)PYXIS_HAE_MEM = 0; mb();
+ pyxis_hae_mem = *(vuip)PYXIS_HAE_MEM;
+ *(vuip)PYXIS_HAE_IO = 0; mb();
+ pyxis_hae_io = *(vuip)PYXIS_HAE_IO;
+ }
+
+ return mem_start;
+}
+
+int pyxis_pci_clr_err(void)
+{
+ PYXIS_jd = *(vuip)PYXIS_ERR;
+ DBG(("PYXIS_pci_clr_err: PYXIS ERR after read 0x%x\n", PYXIS_jd));
+ *(vuip)PYXIS_ERR = 0x0180;
+ mb();
+ PYXIS_jd = *(vuip)PYXIS_ERR;
+ return 0;
+}
+
+void pyxis_machine_check(unsigned long vector, unsigned long la_ptr,
+ struct pt_regs * regs)
+{
+ struct el_common *mchk_header;
+ struct el_PYXIS_sysdata_mcheck *mchk_sysdata;
+
+ mchk_header = (struct el_common *)la_ptr;
+
+ mchk_sysdata = (struct el_PYXIS_sysdata_mcheck *)
+ (la_ptr + mchk_header->sys_offset);
+
+#if 0
+ DBG_MCK(("pyxis_machine_check: vector=0x%lx la_ptr=0x%lx\n",
+ vector, la_ptr));
+ DBG_MCK(("\t\t pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
+ regs->pc, mchk_header->size, mchk_header->proc_offset,
+ mchk_header->sys_offset));
+ DBG_MCK(("pyxis_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n",
+ PYXIS_mcheck_expected, mchk_sysdata->epic_dcsr,
+ mchk_sysdata->epic_pear));
+#endif
+#ifdef DEBUG_MCHECK_DUMP
+ {
+ unsigned long *ptr;
+ int i;
+
+ ptr = (unsigned long *)la_ptr;
+ for (i = 0; i < mchk_header->size / sizeof(long); i += 2) {
+ printk(" +%lx %lx %lx\n", i*sizeof(long), ptr[i], ptr[i+1]);
+ }
+ }
+#endif /* DEBUG_MCHECK_DUMP */
+
+ /*
+ * Check if machine check is due to a badaddr() and if so,
+ * ignore the machine check.
+ */
+ mb();
+ mb(); /* magic */
+ if (PYXIS_mcheck_expected/* && (mchk_sysdata->epic_dcsr && 0x0c00UL)*/) {
+ DBG(("PYXIS machine check expected\n"));
+ PYXIS_mcheck_expected = 0;
+ PYXIS_mcheck_taken = 1;
+ mb();
+ mb(); /* magic */
+ draina();
+ pyxis_pci_clr_err();
+ wrmces(0x7);
+ mb();
+ }
+#if 1
+ else {
+ printk("PYXIS machine check NOT expected\n") ;
+ DBG_MCK(("pyxis_machine_check: vector=0x%lx la_ptr=0x%lx\n",
+ vector, la_ptr));
+ DBG_MCK(("\t\t pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
+ regs->pc, mchk_header->size, mchk_header->proc_offset,
+ mchk_header->sys_offset));
+ PYXIS_mcheck_expected = 0;
+ PYXIS_mcheck_taken = 1;
+ mb();
+ mb(); /* magic */
+ draina();
+ pyxis_pci_clr_err();
+ wrmces(0x7);
+ mb();
+ }
+#endif
+}
+
+#if defined(CONFIG_ALPHA_RUFFIAN)
+/* Note: This is only used by MILO, AFAIK... */
+/*
+ * The DeskStation Ruffian motherboard firmware does not place
+ * the memory size in the PALimpure area. Therefore, we use
+ * the Bank Configuration Registers in PYXIS to obtain the size.
+ */
+unsigned long pyxis_get_bank_size(unsigned long offset)
+{
+ unsigned long bank_addr, bank, ret = 0;
+
+ /* Valid offsets are: 0x800, 0x840 and 0x880
+ since Ruffian only uses three banks. */
+ bank_addr = (unsigned long)PYXIS_MCR + offset;
+ bank = *(vulp)bank_addr;
+
+ /* Check BANK_ENABLE */
+ if (bank & 0x01) {
+ static unsigned long size[] = {
+ 0x40000000UL, /* 0x00, 1G */
+ 0x20000000UL, /* 0x02, 512M */
+ 0x10000000UL, /* 0x04, 256M */
+ 0x08000000UL, /* 0x06, 128M */
+ 0x04000000UL, /* 0x08, 64M */
+ 0x02000000UL, /* 0x0a, 32M */
+ 0x01000000UL, /* 0x0c, 16M */
+ 0x00800000UL, /* 0x0e, 8M */
+ 0x80000000UL, /* 0x10, 2G */
+ };
+
+ bank = (bank & 0x1e) >> 1;
+ if (bank < sizeof(size)/sizeof(*size))
+ ret = size[bank];
+ }
+
+ return ret;
+}
+#endif /* CONFIG_ALPHA_RUFFIAN */
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
index 31a1f21fc..9ce9c1f17 100644
--- a/arch/alpha/kernel/setup.c
+++ b/arch/alpha/kernel/setup.c
@@ -62,6 +62,18 @@ static char command_line[COMMAND_LINE_SIZE] = { 0, };
* code think we're on a VGA color display.
*/
struct screen_info screen_info = {
+#if defined(CONFIG_ALPHA_BOOK1)
+ /* the AlphaBook1 has LCD video fixed at 800x600, 37 rows and 100 cols */
+ 0, 37, /* orig-x, orig-y */
+ { 0, 0 }, /* unused */
+ 0, /* orig-video-page */
+ 0, /* orig-video-mode */
+ 100, /* orig-video-cols */
+ 0,0,0, /* ega_ax, ega_bx, ega_cx */
+ 37, /* orig-video-lines */
+ 1, /* orig-video-isVGA */
+ 16 /* orig-video-points */
+#else
0, 25, /* orig-x, orig-y */
{ 0, 0 }, /* unused */
0, /* orig-video-page */
@@ -71,6 +83,7 @@ struct screen_info screen_info = {
25, /* orig-video-lines */
1, /* orig-video-isVGA */
16 /* orig-video-points */
+#endif
};
/*
@@ -94,11 +107,13 @@ static void init_pit (void)
outb(LATCH >> 8, 0x40); /* MSB */
request_region(0x40, 0x20, "timer"); /* reserve pit */
#else
+#ifndef CONFIG_ALPHA_RUFFIAN
outb(0x36, 0x43); /* counter 0: system timer */
outb(0x00, 0x40);
outb(0x00, 0x40);
- request_region(0x70, 0x10, "timer"); /* reserve rtc */
#endif
+ request_region(0x70, 0x10, "timer"); /* reserve rtc */
+#endif /* RTC */
outb(0xb6, 0x43); /* counter 2: speaker */
outb(0x31, 0x42);
@@ -166,39 +181,122 @@ void setup_arch(char **cmdline_p,
*memory_start_p = apecs_init(*memory_start_p, *memory_end_p);
#elif defined(CONFIG_ALPHA_CIA)
*memory_start_p = cia_init(*memory_start_p, *memory_end_p);
+#elif defined(CONFIG_ALPHA_PYXIS)
+ *memory_start_p = pyxis_init(*memory_start_p, *memory_end_p);
+#elif defined(CONFIG_ALPHA_T2)
+ *memory_start_p = t2_init(*memory_start_p, *memory_end_p);
#endif
}
+
+#define N(a) (sizeof(a)/sizeof(a[0]))
+
+
+static void
+get_sysnames(long type, long variation,
+ char **type_name, char **variation_name)
+{
+ static char *sys_unknown = "Unknown";
+ static char *systype_names[] = {
+ "0",
+ "ADU", "Cobra", "Ruby", "Flamingo", "Mannequin", "Jensen",
+ "Pelican", "Morgan", "Sable", "Medulla", "Noname",
+ "Turbolaser", "Avanti", "Mustang", "Alcor", "Tradewind",
+ "Mikasa", "EB64", "EB66", "EB64+", "AlphaBook1",
+ "Rawhide", "K2", "Lynx", "XL", "EB164", "Noritake",
+ "Cortex", "29", "Miata", "XXM", "Takara", "Yukon",
+ "Tsunami", "Wildfire", "CUSCO"
+ };
+
+ static char *unofficial_names[] = {"100", "Ruffian"};
+
+ static char * eb164_names[] = {"EB164", "PC164", "LX164", "SX164"};
+ static int eb164_indices[] = {0,0,0,1,1,1,1,1,2,2,2,2,3,3,3,3};
+
+ static char * alcor_names[] = {"Alcor", "Maverick", "Bret"};
+ static int alcor_indices[] = {0,0,0,1,1,1,0,0,0,0,0,0,2,2,2,2,2,2};
+
+ static char * eb64p_names[] = {"EB64+", "Cabriolet", "AlphaPCI64"};
+ static int eb64p_indices[] = {0,0,1.2};
+
+ static char * eb66_names[] = {"EB66", "EB66+"};
+ static int eb66_indices[] = {0,0,1};
+
+ long member;
+
+ /* Restore real CABRIO and EB66+ family names, ie EB64+ and EB66 */
+ if (type < 0)
+ type = -type;
+
+ /* If not in the tables, make it UNKNOWN,
+ else set type name to family */
+ if (type < N(systype_names)) {
+ *type_name = systype_names[type];
+ } else if ((type > ST_UNOFFICIAL_BIAS) &&
+ (type - ST_UNOFFICIAL_BIAS) < N(unofficial_names)) {
+ *type_name = unofficial_names[type - ST_UNOFFICIAL_BIAS];
+ } else {
+ *type_name = sys_unknown;
+ *variation_name = sys_unknown;
+ return;
+ }
+
+ /* Set variation to "0"; if variation is zero, done */
+ *variation_name = systype_names[0];
+ if (variation == 0) {
+ return;
+ }
+
+ member = (variation >> 10) & 0x3f; /* member ID is a bit-field */
+
+ switch (type) {
+ case ST_DEC_EB164:
+ if (member < N(eb164_indices))
+ *variation_name = eb164_names[eb164_indices[member]];
+ break;
+ case ST_DEC_ALCOR:
+ if (member < N(alcor_indices))
+ *variation_name = alcor_names[alcor_indices[member]];
+ break;
+ case ST_DEC_EB64P:
+ if (member < N(eb64p_indices))
+ *variation_name = eb64p_names[eb64p_indices[member]];
+ break;
+ case ST_DEC_EB66:
+ if (member < N(eb66_indices))
+ *variation_name = eb66_names[eb66_indices[member]];
+ break;
+ }
+}
+
/*
* BUFFER is PAGE_SIZE bytes long.
*/
int get_cpuinfo(char *buffer)
{
- const char *cpu_name[] = {
- "EV3", "EV4", "Unknown 1", "LCA4", "EV5", "EV45"
- };
-# define SYSTYPE_NAME_BIAS 20
- const char *systype_name[] = {
- "Cabriolet", "EB66P", "-18", "-17", "-16", "-15",
- "-14", "-13", "-12", "-11", "-10", "-9", "-8",
- "-7", "-6", "-5", "-4", "-3", "-2", "-1", "0",
- "ADU", "Cobra", "Ruby", "Flamingo", "5", "Jensen",
- "Pelican", "8", "Sable", "AXPvme", "Noname",
- "Turbolaser", "Avanti", "Mustang", "Alcor", "16",
- "Mikasa", "18", "EB66", "EB64+", "21", "22", "23",
- "24", "25", "EB164"
+ static char *cpu_names[] = {
+ "EV3", "EV4", "Unknown", "LCA4", "EV5", "EV45", "EV56",
+ "EV6", "PCA56", "PCA57"
};
- struct percpu_struct *cpu;
- unsigned int cpu_index;
- long sysname_index;
+
extern struct unaligned_stat {
unsigned long count, va, pc;
} unaligned[2];
-# define N(a) (sizeof(a)/sizeof(a[0]))
+
+ struct percpu_struct *cpu;
+ unsigned int cpu_index;
+ char *cpu_name;
+ char *systype_name;
+ char *sysvariation_name;
cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset);
cpu_index = (unsigned) (cpu->type - 1);
- sysname_index = hwrpb->sys_type + SYSTYPE_NAME_BIAS;
+ cpu_name = "Unknown";
+ if (cpu_index < N(cpu_names))
+ cpu_name = cpu_names[cpu_index];
+
+ get_sysnames(hwrpb->sys_type, hwrpb->sys_variation,
+ &systype_name, &sysvariation_name);
return sprintf(buffer,
"cpu\t\t\t: Alpha\n"
@@ -207,7 +305,7 @@ int get_cpuinfo(char *buffer)
"cpu revision\t\t: %ld\n"
"cpu serial number\t: %s\n"
"system type\t\t: %s\n"
- "system variation\t: %ld\n"
+ "system variation\t: %s\n"
"system revision\t\t: %ld\n"
"system serial number\t: %s\n"
"cycle frequency [Hz]\t: %lu\n"
@@ -219,12 +317,9 @@ int get_cpuinfo(char *buffer)
"kernel unaligned acc\t: %ld (pc=%lx,va=%lx)\n"
"user unaligned acc\t: %ld (pc=%lx,va=%lx)\n",
- (cpu_index < N(cpu_name)
- ? cpu_name[cpu_index] : "Unknown"),
- cpu->variation, cpu->revision, (char*)cpu->serial_no,
- (sysname_index < N(systype_name)
- ? systype_name[sysname_index] : "Unknown"),
- hwrpb->sys_variation, hwrpb->sys_revision,
+ cpu_name, cpu->variation, cpu->revision,
+ (char*)cpu->serial_no,
+ systype_name, sysvariation_name, hwrpb->sys_revision,
(char*)hwrpb->ssn,
hwrpb->cycle_freq,
hwrpb->intr_freq / 4096,
@@ -235,5 +330,4 @@ int get_cpuinfo(char *buffer)
loops_per_sec / 500000, (loops_per_sec / 5000) % 100,
unaligned[0].count, unaligned[0].pc, unaligned[0].va,
unaligned[1].count, unaligned[1].pc, unaligned[1].va);
-# undef N
}
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
index 1d4e8931d..1943b26f7 100644
--- a/arch/alpha/kernel/signal.c
+++ b/arch/alpha/kernel/signal.c
@@ -116,7 +116,7 @@ osf_sigaction(int sig, const struct osf_sigaction *act,
asmlinkage int
sys_rt_sigaction(int sig, const struct sigaction *act, struct sigaction *oact,
- void *restorer, size_t sigsetsize)
+ size_t sigsetsize, void *restorer)
{
struct k_sigaction new_ka, old_ka;
int ret;
diff --git a/arch/alpha/kernel/smc37c669.c b/arch/alpha/kernel/smc37c669.c
new file mode 100644
index 000000000..6724372fe
--- /dev/null
+++ b/arch/alpha/kernel/smc37c669.c
@@ -0,0 +1,2583 @@
+/*
+ * SMC 37C669 initialization code
+ */
+#include <linux/kernel.h>
+
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+
+#include <asm/hwrpb.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+
+#if 0
+# define DBG_DEVS(args) printk args
+#else
+# define DBG_DEVS(args)
+#endif
+
+#define KB 1024
+#define MB (1024*KB)
+#define GB (1024*MB)
+
+#define SMC_DEBUG 0
+
+/* File: smcc669_def.h
+ *
+ * Copyright (C) 1997 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only in accordance of the terms of such license and with the
+ * inclusion of the above copyright notice. This software or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person. No title to and ownership of the software is hereby
+ * transferred.
+ *
+ * The information in this software is subject to change without notice
+ * and should not be construed as a commitment by Digital Equipment
+ * Corporation.
+ *
+ * Digital assumes no responsibility for the use or reliability of its
+ * software on equipment which is not supplied by Digital.
+ *
+ *
+ * Abstract:
+ *
+ * This file contains header definitions for the SMC37c669
+ * Super I/O controller.
+ *
+ * Author:
+ *
+ * Eric Rasmussen
+ *
+ * Modification History:
+ *
+ * er 28-Jan-1997 Initial Entry
+ */
+
+#ifndef __SMC37c669_H
+#define __SMC37c669_H
+
+/*
+** Macros for handling device IRQs
+**
+** The mask acts as a flag used in mapping actual ISA IRQs (0 - 15)
+** to device IRQs (A - H).
+*/
+#define SMC37c669_DEVICE_IRQ_MASK 0x80000000
+#define SMC37c669_DEVICE_IRQ( __i ) \
+ ((SMC37c669_DEVICE_IRQ_MASK) | (__i))
+#define SMC37c669_IS_DEVICE_IRQ(__i) \
+ (((__i) & (SMC37c669_DEVICE_IRQ_MASK)) == (SMC37c669_DEVICE_IRQ_MASK))
+#define SMC37c669_RAW_DEVICE_IRQ(__i) \
+ ((__i) & ~(SMC37c669_DEVICE_IRQ_MASK))
+
+/*
+** Macros for handling device DRQs
+**
+** The mask acts as a flag used in mapping actual ISA DMA
+** channels to device DMA channels (A - C).
+*/
+#define SMC37c669_DEVICE_DRQ_MASK 0x80000000
+#define SMC37c669_DEVICE_DRQ(__d) \
+ ((SMC37c669_DEVICE_DRQ_MASK) | (__d))
+#define SMC37c669_IS_DEVICE_DRQ(__d) \
+ (((__d) & (SMC37c669_DEVICE_DRQ_MASK)) == (SMC37c669_DEVICE_DRQ_MASK))
+#define SMC37c669_RAW_DEVICE_DRQ(__d) \
+ ((__d) & ~(SMC37c669_DEVICE_DRQ_MASK))
+
+#define SMC37c669_DEVICE_ID 0x3
+
+/*
+** SMC37c669 Device Function Definitions
+*/
+#define SERIAL_0 0
+#define SERIAL_1 1
+#define PARALLEL_0 2
+#define FLOPPY_0 3
+#define IDE_0 4
+#define NUM_FUNCS 5
+
+/*
+** Default Device Function Mappings
+*/
+#define COM1_BASE 0x3F8
+#define COM1_IRQ 4
+#define COM2_BASE 0x2F8
+#define COM2_IRQ 3
+#define PARP_BASE 0x3BC
+#define PARP_IRQ 7
+#define PARP_DRQ 3
+#define FDC_BASE 0x3F0
+#define FDC_IRQ 6
+#define FDC_DRQ 2
+
+/*
+** Configuration On/Off Key Definitions
+*/
+#define SMC37c669_CONFIG_ON_KEY 0x55
+#define SMC37c669_CONFIG_OFF_KEY 0xAA
+
+/*
+** SMC 37c669 Device IRQs
+*/
+#define SMC37c669_DEVICE_IRQ_A ( SMC37c669_DEVICE_IRQ( 0x01 ) )
+#define SMC37c669_DEVICE_IRQ_B ( SMC37c669_DEVICE_IRQ( 0x02 ) )
+#define SMC37c669_DEVICE_IRQ_C ( SMC37c669_DEVICE_IRQ( 0x03 ) )
+#define SMC37c669_DEVICE_IRQ_D ( SMC37c669_DEVICE_IRQ( 0x04 ) )
+#define SMC37c669_DEVICE_IRQ_E ( SMC37c669_DEVICE_IRQ( 0x05 ) )
+#define SMC37c669_DEVICE_IRQ_F ( SMC37c669_DEVICE_IRQ( 0x06 ) )
+/* SMC37c669_DEVICE_IRQ_G *** RESERVED ***/
+#define SMC37c669_DEVICE_IRQ_H ( SMC37c669_DEVICE_IRQ( 0x08 ) )
+
+/*
+** SMC 37c669 Device DMA Channel Definitions
+*/
+#define SMC37c669_DEVICE_DRQ_A ( SMC37c669_DEVICE_DRQ( 0x01 ) )
+#define SMC37c669_DEVICE_DRQ_B ( SMC37c669_DEVICE_DRQ( 0x02 ) )
+#define SMC37c669_DEVICE_DRQ_C ( SMC37c669_DEVICE_DRQ( 0x03 ) )
+
+/*
+** Configuration Register Index Definitions
+*/
+#define SMC37c669_CR00_INDEX 0x00
+#define SMC37c669_CR01_INDEX 0x01
+#define SMC37c669_CR02_INDEX 0x02
+#define SMC37c669_CR03_INDEX 0x03
+#define SMC37c669_CR04_INDEX 0x04
+#define SMC37c669_CR05_INDEX 0x05
+#define SMC37c669_CR06_INDEX 0x06
+#define SMC37c669_CR07_INDEX 0x07
+#define SMC37c669_CR08_INDEX 0x08
+#define SMC37c669_CR09_INDEX 0x09
+#define SMC37c669_CR0A_INDEX 0x0A
+#define SMC37c669_CR0B_INDEX 0x0B
+#define SMC37c669_CR0C_INDEX 0x0C
+#define SMC37c669_CR0D_INDEX 0x0D
+#define SMC37c669_CR0E_INDEX 0x0E
+#define SMC37c669_CR0F_INDEX 0x0F
+#define SMC37c669_CR10_INDEX 0x10
+#define SMC37c669_CR11_INDEX 0x11
+#define SMC37c669_CR12_INDEX 0x12
+#define SMC37c669_CR13_INDEX 0x13
+#define SMC37c669_CR14_INDEX 0x14
+#define SMC37c669_CR15_INDEX 0x15
+#define SMC37c669_CR16_INDEX 0x16
+#define SMC37c669_CR17_INDEX 0x17
+#define SMC37c669_CR18_INDEX 0x18
+#define SMC37c669_CR19_INDEX 0x19
+#define SMC37c669_CR1A_INDEX 0x1A
+#define SMC37c669_CR1B_INDEX 0x1B
+#define SMC37c669_CR1C_INDEX 0x1C
+#define SMC37c669_CR1D_INDEX 0x1D
+#define SMC37c669_CR1E_INDEX 0x1E
+#define SMC37c669_CR1F_INDEX 0x1F
+#define SMC37c669_CR20_INDEX 0x20
+#define SMC37c669_CR21_INDEX 0x21
+#define SMC37c669_CR22_INDEX 0x22
+#define SMC37c669_CR23_INDEX 0x23
+#define SMC37c669_CR24_INDEX 0x24
+#define SMC37c669_CR25_INDEX 0x25
+#define SMC37c669_CR26_INDEX 0x26
+#define SMC37c669_CR27_INDEX 0x27
+#define SMC37c669_CR28_INDEX 0x28
+#define SMC37c669_CR29_INDEX 0x29
+
+/*
+** Configuration Register Alias Definitions
+*/
+#define SMC37c669_DEVICE_ID_INDEX SMC37c669_CR0D_INDEX
+#define SMC37c669_DEVICE_REVISION_INDEX SMC37c669_CR0E_INDEX
+#define SMC37c669_FDC_BASE_ADDRESS_INDEX SMC37c669_CR20_INDEX
+#define SMC37c669_IDE_BASE_ADDRESS_INDEX SMC37c669_CR21_INDEX
+#define SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX SMC37c669_CR22_INDEX
+#define SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX SMC37c669_CR23_INDEX
+#define SMC37c669_SERIAL0_BASE_ADDRESS_INDEX SMC37c669_CR24_INDEX
+#define SMC37c669_SERIAL1_BASE_ADDRESS_INDEX SMC37c669_CR25_INDEX
+#define SMC37c669_PARALLEL_FDC_DRQ_INDEX SMC37c669_CR26_INDEX
+#define SMC37c669_PARALLEL_FDC_IRQ_INDEX SMC37c669_CR27_INDEX
+#define SMC37c669_SERIAL_IRQ_INDEX SMC37c669_CR28_INDEX
+
+/*
+** Configuration Register Definitions
+**
+** The INDEX (write only) and DATA (read/write) ports are effective
+** only when the chip is in the Configuration State.
+*/
+typedef struct _SMC37c669_CONFIG_REGS {
+ unsigned char index_port;
+ unsigned char data_port;
+} SMC37c669_CONFIG_REGS;
+
+/*
+** CR00 - default value 0x28
+**
+** IDE_EN (CR00<1:0>):
+** 0x - 30ua pull-ups on nIDEEN, nHDCS0, NHDCS1
+** 11 - IRQ_H available as IRQ output,
+** IRRX2, IRTX2 available as alternate IR pins
+** 10 - nIDEEN, nHDCS0, nHDCS1 used to control IDE
+**
+** VALID (CR00<7>):
+** A high level on this software controlled bit can
+** be used to indicate that a valid configuration
+** cycle has occurred. The control software must
+** take care to set this bit at the appropriate times.
+** Set to zero after power up. This bit has no
+** effect on any other hardware in the chip.
+**
+*/
+typedef union _SMC37c669_CR00 {
+ unsigned char as_uchar;
+ struct {
+ unsigned ide_en : 2; /* See note above */
+ unsigned reserved1 : 1; /* RAZ */
+ unsigned fdc_pwr : 1; /* 1 = supply power to FDC */
+ unsigned reserved2 : 3; /* Read as 010b */
+ unsigned valid : 1; /* See note above */
+ } by_field;
+} SMC37c669_CR00;
+
+/*
+** CR01 - default value 0x9C
+*/
+typedef union _SMC37c669_CR01 {
+ unsigned char as_uchar;
+ struct {
+ unsigned reserved1 : 2; /* RAZ */
+ unsigned ppt_pwr : 1; /* 1 = supply power to PPT */
+ unsigned ppt_mode : 1; /* 1 = Printer mode, 0 = EPP */
+ unsigned reserved2 : 1; /* Read as 1 */
+ unsigned reserved3 : 2; /* RAZ */
+ unsigned lock_crx: 1; /* Lock CR00 - CR18 */
+ } by_field;
+} SMC37c669_CR01;
+
+/*
+** CR02 - default value 0x88
+*/
+typedef union _SMC37c669_CR02 {
+ unsigned char as_uchar;
+ struct {
+ unsigned reserved1 : 3; /* RAZ */
+ unsigned uart1_pwr : 1; /* 1 = supply power to UART1 */
+ unsigned reserved2 : 3; /* RAZ */
+ unsigned uart2_pwr : 1; /* 1 = supply power to UART2 */
+ } by_field;
+} SMC37c669_CR02;
+
+/*
+** CR03 - default value 0x78
+**
+** CR03<7> CR03<2> Pin 94
+** ------- ------- ------
+** 0 X DRV2 (input)
+** 1 0 ADRX
+** 1 1 IRQ_B
+**
+** CR03<6> CR03<5> Op Mode
+** ------- ------- -------
+** 0 0 Model 30
+** 0 1 PS/2
+** 1 0 Reserved
+** 1 1 AT Mode
+*/
+typedef union _SMC37c669_CR03 {
+ unsigned char as_uchar;
+ struct {
+ unsigned pwrgd_gamecs : 1; /* 1 = PWRGD, 0 = GAMECS */
+ unsigned fdc_mode2 : 1; /* 1 = Enhanced Mode 2 */
+ unsigned pin94_0 : 1; /* See note above */
+ unsigned reserved1 : 1; /* RAZ */
+ unsigned drvden : 1; /* 1 = high, 0 - output */
+ unsigned op_mode : 2; /* See note above */
+ unsigned pin94_1 : 1; /* See note above */
+ } by_field;
+} SMC37c669_CR03;
+
+/*
+** CR04 - default value 0x00
+**
+** PP_EXT_MODE:
+** If CR01<PP_MODE> = 0 and PP_EXT_MODE =
+** 00 - Standard and Bidirectional
+** 01 - EPP mode and SPP
+** 10 - ECP mode
+** In this mode, 2 drives can be supported
+** directly, 3 or 4 drives must use external
+** 4 drive support. SPP can be selected
+** through the ECR register of ECP as mode 000.
+** 11 - ECP mode and EPP mode
+** In this mode, 2 drives can be supported
+** directly, 3 or 4 drives must use external
+** 4 drive support. SPP can be selected
+** through the ECR register of ECP as mode 000.
+** In this mode, EPP can be selected through
+** the ECR register of ECP as mode 100.
+**
+** PP_FDC:
+** 00 - Normal
+** 01 - PPFD1
+** 10 - PPFD2
+** 11 - Reserved
+**
+** MIDI1:
+** Serial Clock Select:
+** A low level on this bit disables MIDI support,
+** clock = divide by 13. A high level on this
+** bit enables MIDI support, clock = divide by 12.
+**
+** MIDI operates at 31.25 Kbps which can be derived
+** from 125 KHz (24 MHz / 12 = 2 MHz, 2 MHz / 16 = 125 KHz)
+**
+** ALT_IO:
+** 0 - Use pins IRRX, IRTX
+** 1 - Use pins IRRX2, IRTX2
+**
+** If this bit is set, the IR receive and transmit
+** functions will not be available on pins 25 and 26
+** unless CR00<IDE_EN> = 11.
+*/
+typedef union _SMC37c669_CR04 {
+ unsigned char as_uchar;
+ struct {
+ unsigned ppt_ext_mode : 2; /* See note above */
+ unsigned ppt_fdc : 2; /* See note above */
+ unsigned midi1 : 1; /* See note above */
+ unsigned midi2 : 1; /* See note above */
+ unsigned epp_type : 1; /* 0 = EPP 1.9, 1 = EPP 1.7 */
+ unsigned alt_io : 1; /* See note above */
+ } by_field;
+} SMC37c669_CR04;
+
+/*
+** CR05 - default value 0x00
+**
+** DEN_SEL:
+** 00 - Densel output normal
+** 01 - Reserved
+** 10 - Densel output 1
+** 11 - Densel output 0
+**
+*/
+typedef union _SMC37c669_CR05 {
+ unsigned char as_uchar;
+ struct {
+ unsigned reserved1 : 2; /* RAZ */
+ unsigned fdc_dma_mode : 1; /* 0 = burst, 1 = non-burst */
+ unsigned den_sel : 2; /* See note above */
+ unsigned swap_drv : 1; /* Swap the FDC motor selects */
+ unsigned extx4 : 1; /* 0 = 2 drive, 1 = external 4 drive decode */
+ unsigned reserved2 : 1; /* RAZ */
+ } by_field;
+} SMC37c669_CR05;
+
+/*
+** CR06 - default value 0xFF
+*/
+typedef union _SMC37c669_CR06 {
+ unsigned char as_uchar;
+ struct {
+ unsigned floppy_a : 2; /* Type of floppy drive A */
+ unsigned floppy_b : 2; /* Type of floppy drive B */
+ unsigned floppy_c : 2; /* Type of floppy drive C */
+ unsigned floppy_d : 2; /* Type of floppy drive D */
+ } by_field;
+} SMC37c669_CR06;
+
+/*
+** CR07 - default value 0x00
+**
+** Auto Power Management CR07<7:4>:
+** 0 - Auto Powerdown disabled (default)
+** 1 - Auto Powerdown enabled
+**
+** This bit is reset to the default state by POR or
+** a hardware reset.
+**
+*/
+typedef union _SMC37c669_CR07 {
+ unsigned char as_uchar;
+ struct {
+ unsigned floppy_boot : 2; /* 0 = A:, 1 = B: */
+ unsigned reserved1 : 2; /* RAZ */
+ unsigned ppt_en : 1; /* See note above */
+ unsigned uart1_en : 1; /* See note above */
+ unsigned uart2_en : 1; /* See note above */
+ unsigned fdc_en : 1; /* See note above */
+ } by_field;
+} SMC37c669_CR07;
+
+/*
+** CR08 - default value 0x00
+*/
+typedef union _SMC37c669_CR08 {
+ unsigned char as_uchar;
+ struct {
+ unsigned zero : 4; /* 0 */
+ unsigned addrx7_4 : 4; /* ADR<7:3> for ADRx decode */
+ } by_field;
+} SMC37c669_CR08;
+
+/*
+** CR09 - default value 0x00
+**
+** ADRx_CONFIG:
+** 00 - ADRx disabled
+** 01 - 1 byte decode A<3:0> = 0000b
+** 10 - 8 byte block decode A<3:0> = 0XXXb
+** 11 - 16 byte block decode A<3:0> = XXXXb
+**
+*/
+typedef union _SMC37c669_CR09 {
+ unsigned char as_uchar;
+ struct {
+ unsigned adra8 : 3; /* ADR<10:8> for ADRx decode */
+ unsigned reserved1 : 3;
+ unsigned adrx_config : 2; /* See note above */
+ } by_field;
+} SMC37c669_CR09;
+
+/*
+** CR0A - default value 0x00
+*/
+typedef union _SMC37c669_CR0A {
+ unsigned char as_uchar;
+ struct {
+ unsigned ecp_fifo_threshold : 4;
+ unsigned reserved1 : 4;
+ } by_field;
+} SMC37c669_CR0A;
+
+/*
+** CR0B - default value 0x00
+*/
+typedef union _SMC37c669_CR0B {
+ unsigned char as_uchar;
+ struct {
+ unsigned fdd0_drtx : 2; /* FDD0 Data Rate Table */
+ unsigned fdd1_drtx : 2; /* FDD1 Data Rate Table */
+ unsigned fdd2_drtx : 2; /* FDD2 Data Rate Table */
+ unsigned fdd3_drtx : 2; /* FDD3 Data Rate Table */
+ } by_field;
+} SMC37c669_CR0B;
+
+/*
+** CR0C - default value 0x00
+**
+** UART2_MODE:
+** 000 - Standard (default)
+** 001 - IrDA (HPSIR)
+** 010 - Amplitude Shift Keyed IR @500 KHz
+** 011 - Reserved
+** 1xx - Reserved
+**
+*/
+typedef union _SMC37c669_CR0C {
+ unsigned char as_uchar;
+ struct {
+ unsigned uart2_rcv_polarity : 1; /* 1 = invert RX */
+ unsigned uart2_xmit_polarity : 1; /* 1 = invert TX */
+ unsigned uart2_duplex : 1; /* 1 = full, 0 = half */
+ unsigned uart2_mode : 3; /* See note above */
+ unsigned uart1_speed : 1; /* 1 = high speed enabled */
+ unsigned uart2_speed : 1; /* 1 = high speed enabled */
+ } by_field;
+} SMC37c669_CR0C;
+
+/*
+** CR0D - default value 0x03
+**
+** Device ID Register - read only
+*/
+typedef union _SMC37c669_CR0D {
+ unsigned char as_uchar;
+ struct {
+ unsigned device_id : 8; /* Returns 0x3 in this field */
+ } by_field;
+} SMC37c669_CR0D;
+
+/*
+** CR0E - default value 0x02
+**
+** Device Revision Register - read only
+*/
+typedef union _SMC37c669_CR0E {
+ unsigned char as_uchar;
+ struct {
+ unsigned device_rev : 8; /* Returns 0x2 in this field */
+ } by_field;
+} SMC37c669_CR0E;
+
+/*
+** CR0F - default value 0x00
+*/
+typedef union _SMC37c669_CR0F {
+ unsigned char as_uchar;
+ struct {
+ unsigned test0 : 1; /* Reserved - set to 0 */
+ unsigned test1 : 1; /* Reserved - set to 0 */
+ unsigned test2 : 1; /* Reserved - set to 0 */
+ unsigned test3 : 1; /* Reserved - set t0 0 */
+ unsigned test4 : 1; /* Reserved - set to 0 */
+ unsigned test5 : 1; /* Reserved - set t0 0 */
+ unsigned test6 : 1; /* Reserved - set t0 0 */
+ unsigned test7 : 1; /* Reserved - set to 0 */
+ } by_field;
+} SMC37c669_CR0F;
+
+/*
+** CR10 - default value 0x00
+*/
+typedef union _SMC37c669_CR10 {
+ unsigned char as_uchar;
+ struct {
+ unsigned reserved1 : 3; /* RAZ */
+ unsigned pll_gain : 1; /* 1 = 3V, 2 = 5V operation */
+ unsigned pll_stop : 1; /* 1 = stop PLLs */
+ unsigned ace_stop : 1; /* 1 = stop UART clocks */
+ unsigned pll_clock_ctrl : 1; /* 0 = 14.318 MHz, 1 = 24 MHz */
+ unsigned ir_test : 1; /* Enable IR test mode */
+ } by_field;
+} SMC37c669_CR10;
+
+/*
+** CR11 - default value 0x00
+*/
+typedef union _SMC37c669_CR11 {
+ unsigned char as_uchar;
+ struct {
+ unsigned ir_loopback : 1; /* Internal IR loop back */
+ unsigned test_10ms : 1; /* Test 10ms autopowerdown FDC timeout */
+ unsigned reserved1 : 6; /* RAZ */
+ } by_field;
+} SMC37c669_CR11;
+
+/*
+** CR12 - CR1D are reserved registers
+*/
+
+/*
+** CR1E - default value 0x80
+**
+** GAMECS:
+** 00 - GAMECS disabled
+** 01 - 1 byte decode ADR<3:0> = 0001b
+** 10 - 8 byte block decode ADR<3:0> = 0XXXb
+** 11 - 16 byte block decode ADR<3:0> = XXXXb
+**
+*/
+typedef union _SMC37c66_CR1E {
+ unsigned char as_uchar;
+ struct {
+ unsigned gamecs_config: 2; /* See note above */
+ unsigned gamecs_addr9_4 : 6; /* GAMECS Addr<9:4> */
+ } by_field;
+} SMC37c669_CR1E;
+
+/*
+** CR1F - default value 0x00
+**
+** DT0 DT1 DRVDEN0 DRVDEN1 Drive Type
+** --- --- ------- ------- ----------
+** 0 0 DENSEL DRATE0 4/2/1 MB 3.5"
+** 2/1 MB 5.25"
+** 2/1.6/1 MB 3.5" (3-mode)
+** 0 1 DRATE1 DRATE0
+** 1 0 nDENSEL DRATE0 PS/2
+** 1 1 DRATE0 DRATE1
+**
+** Note: DENSEL, DRATE1, and DRATE0 map onto two output
+** pins - DRVDEN0 and DRVDEN1.
+**
+*/
+typedef union _SMC37c669_CR1F {
+ unsigned char as_uchar;
+ struct {
+ unsigned fdd0_drive_type : 2; /* FDD0 drive type */
+ unsigned fdd1_drive_type : 2; /* FDD1 drive type */
+ unsigned fdd2_drive_type : 2; /* FDD2 drive type */
+ unsigned fdd3_drive_type : 2; /* FDD3 drive type */
+ } by_field;
+} SMC37c669_CR1F;
+
+/*
+** CR20 - default value 0x3C
+**
+** FDC Base Address Register
+** - To disable this decode set Addr<9:8> = 0
+** - A<10> = 0, A<3:0> = 0XXXb to access.
+**
+*/
+typedef union _SMC37c669_CR20 {
+ unsigned char as_uchar;
+ struct {
+ unsigned zero : 2; /* 0 */
+ unsigned addr9_4 : 6; /* FDC Addr<9:4> */
+ } by_field;
+} SMC37c669_CR20;
+
+/*
+** CR21 - default value 0x3C
+**
+** IDE Base Address Register
+** - To disable this decode set Addr<9:8> = 0
+** - A<10> = 0, A<3:0> = 0XXXb to access.
+**
+*/
+typedef union _SMC37c669_CR21 {
+ unsigned char as_uchar;
+ struct {
+ unsigned zero : 2; /* 0 */
+ unsigned addr9_4 : 6; /* IDE Addr<9:4> */
+ } by_field;
+} SMC37c669_CR21;
+
+/*
+** CR22 - default value 0x3D
+**
+** IDE Alternate Status Base Address Register
+** - To disable this decode set Addr<9:8> = 0
+** - A<10> = 0, A<3:0> = 0110b to access.
+**
+*/
+typedef union _SMC37c669_CR22 {
+ unsigned char as_uchar;
+ struct {
+ unsigned zero : 2; /* 0 */
+ unsigned addr9_4 : 6; /* IDE Alt Status Addr<9:4> */
+ } by_field;
+} SMC37c669_CR22;
+
+/*
+** CR23 - default value 0x00
+**
+** Parallel Port Base Address Register
+** - To disable this decode set Addr<9:8> = 0
+** - A<10> = 0 to access.
+** - If EPP is enabled, A<2:0> = XXXb to access.
+** If EPP is NOT enabled, A<1:0> = XXb to access
+**
+*/
+typedef union _SMC37c669_CR23 {
+ unsigned char as_uchar;
+ struct {
+ unsigned addr9_2 : 8; /* Parallel Port Addr<9:2> */
+ } by_field;
+} SMC37c669_CR23;
+
+/*
+** CR24 - default value 0x00
+**
+** UART1 Base Address Register
+** - To disable this decode set Addr<9:8> = 0
+** - A<10> = 0, A<2:0> = XXXb to access.
+**
+*/
+typedef union _SMC37c669_CR24 {
+ unsigned char as_uchar;
+ struct {
+ unsigned zero : 1; /* 0 */
+ unsigned addr9_3 : 7; /* UART1 Addr<9:3> */
+ } by_field;
+} SMC37c669_CR24;
+
+/*
+** CR25 - default value 0x00
+**
+** UART2 Base Address Register
+** - To disable this decode set Addr<9:8> = 0
+** - A<10> = 0, A<2:0> = XXXb to access.
+**
+*/
+typedef union _SMC37c669_CR25 {
+ unsigned char as_uchar;
+ struct {
+ unsigned zero : 1; /* 0 */
+ unsigned addr9_3 : 7; /* UART2 Addr<9:3> */
+ } by_field;
+} SMC37c669_CR25;
+
+/*
+** CR26 - default value 0x00
+**
+** Parallel Port / FDC DMA Select Register
+**
+** D3 - D0 DMA
+** D7 - D4 Selected
+** ------- --------
+** 0000 None
+** 0001 DMA_A
+** 0010 DMA_B
+** 0011 DMA_C
+**
+*/
+typedef union _SMC37c669_CR26 {
+ unsigned char as_uchar;
+ struct {
+ unsigned ppt_drq : 4; /* See note above */
+ unsigned fdc_drq : 4; /* See note above */
+ } by_field;
+} SMC37c669_CR26;
+
+/*
+** CR27 - default value 0x00
+**
+** Parallel Port / FDC IRQ Select Register
+**
+** D3 - D0 IRQ
+** D7 - D4 Selected
+** ------- --------
+** 0000 None
+** 0001 IRQ_A
+** 0010 IRQ_B
+** 0011 IRQ_C
+** 0100 IRQ_D
+** 0101 IRQ_E
+** 0110 IRQ_F
+** 0111 Reserved
+** 1000 IRQ_H
+**
+** Any unselected IRQ REQ is in tristate
+**
+*/
+typedef union _SMC37c669_CR27 {
+ unsigned char as_uchar;
+ struct {
+ unsigned ppt_irq : 4; /* See note above */
+ unsigned fdc_irq : 4; /* See note above */
+ } by_field;
+} SMC37c669_CR27;
+
+/*
+** CR28 - default value 0x00
+**
+** UART IRQ Select Register
+**
+** D3 - D0 IRQ
+** D7 - D4 Selected
+** ------- --------
+** 0000 None
+** 0001 IRQ_A
+** 0010 IRQ_B
+** 0011 IRQ_C
+** 0100 IRQ_D
+** 0101 IRQ_E
+** 0110 IRQ_F
+** 0111 Reserved
+** 1000 IRQ_H
+** 1111 share with UART1 (only for UART2)
+**
+** Any unselected IRQ REQ is in tristate
+**
+** To share an IRQ between UART1 and UART2, set
+** UART1 to use the desired IRQ and set UART2 to
+** 0xF to enable sharing mechanism.
+**
+*/
+typedef union _SMC37c669_CR28 {
+ unsigned char as_uchar;
+ struct {
+ unsigned uart2_irq : 4; /* See note above */
+ unsigned uart1_irq : 4; /* See note above */
+ } by_field;
+} SMC37c669_CR28;
+
+/*
+** CR29 - default value 0x00
+**
+** IRQIN IRQ Select Register
+**
+** D3 - D0 IRQ
+** D7 - D4 Selected
+** ------- --------
+** 0000 None
+** 0001 IRQ_A
+** 0010 IRQ_B
+** 0011 IRQ_C
+** 0100 IRQ_D
+** 0101 IRQ_E
+** 0110 IRQ_F
+** 0111 Reserved
+** 1000 IRQ_H
+**
+** Any unselected IRQ REQ is in tristate
+**
+*/
+typedef union _SMC37c669_CR29 {
+ unsigned char as_uchar;
+ struct {
+ unsigned irqin_irq : 4; /* See note above */
+ unsigned reserved1 : 4; /* RAZ */
+ } by_field;
+} SMC37c669_CR29;
+
+/*
+** Aliases of Configuration Register formats (should match
+** the set of index aliases).
+**
+** Note that CR24 and CR25 have the same format and are the
+** base address registers for UART1 and UART2. Because of
+** this we only define 1 alias here - for CR24 - as the serial
+** base address register.
+**
+** Note that CR21 and CR22 have the same format and are the
+** base address and alternate status address registers for
+** the IDE controller. Because of this we only define 1 alias
+** here - for CR21 - as the IDE address register.
+**
+*/
+typedef SMC37c669_CR0D SMC37c669_DEVICE_ID_REGISTER;
+typedef SMC37c669_CR0E SMC37c669_DEVICE_REVISION_REGISTER;
+typedef SMC37c669_CR20 SMC37c669_FDC_BASE_ADDRESS_REGISTER;
+typedef SMC37c669_CR21 SMC37c669_IDE_ADDRESS_REGISTER;
+typedef SMC37c669_CR23 SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER;
+typedef SMC37c669_CR24 SMC37c669_SERIAL_BASE_ADDRESS_REGISTER;
+typedef SMC37c669_CR26 SMC37c669_PARALLEL_FDC_DRQ_REGISTER;
+typedef SMC37c669_CR27 SMC37c669_PARALLEL_FDC_IRQ_REGISTER;
+typedef SMC37c669_CR28 SMC37c669_SERIAL_IRQ_REGISTER;
+
+/*
+** ISA/Device IRQ Translation Table Entry Definition
+*/
+typedef struct _SMC37c669_IRQ_TRANSLATION_ENTRY {
+ int device_irq;
+ int isa_irq;
+} SMC37c669_IRQ_TRANSLATION_ENTRY;
+
+/*
+** ISA/Device DMA Translation Table Entry Definition
+*/
+typedef struct _SMC37c669_DRQ_TRANSLATION_ENTRY {
+ int device_drq;
+ int isa_drq;
+} SMC37c669_DRQ_TRANSLATION_ENTRY;
+
+/*
+** External Interface Function Prototype Declarations
+*/
+
+SMC37c669_CONFIG_REGS *SMC37c669_detect(
+ void
+);
+
+unsigned int SMC37c669_enable_device(
+ unsigned int func
+);
+
+unsigned int SMC37c669_disable_device(
+ unsigned int func
+);
+
+unsigned int SMC37c669_configure_device(
+ unsigned int func,
+ int port,
+ int irq,
+ int drq
+);
+
+void SMC37c669_display_device_info(
+ void
+);
+
+#endif /* __SMC37c669_H */
+
+/* file: smcc669.c
+ *
+ * Copyright (C) 1997 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only in accordance of the terms of such license and with the
+ * inclusion of the above copyright notice. This software or any other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person. No title to and ownership of the software is hereby
+ * transferred.
+ *
+ * The information in this software is subject to change without notice
+ * and should not be construed as a commitment by digital equipment
+ * corporation.
+ *
+ * Digital assumes no responsibility for the use or reliability of its
+ * software on equipment which is not supplied by digital.
+ */
+
+/*
+ *++
+ * FACILITY:
+ *
+ * Alpha SRM Console Firmware
+ *
+ * MODULE DESCRIPTION:
+ *
+ * SMC37c669 Super I/O controller configuration routines.
+ *
+ * AUTHORS:
+ *
+ * Eric Rasmussen
+ *
+ * CREATION DATE:
+ *
+ * 28-Jan-1997
+ *
+ * MODIFICATION HISTORY:
+ *
+ * er 01-May-1997 Fixed pointer conversion errors in
+ * SMC37c669_get_device_config().
+ * er 28-Jan-1997 Initial version.
+ *
+ *--
+ */
+#if 0
+/* $INCLUDE_OPTIONS$ */
+#include "cp$inc:platform_io.h"
+/* $INCLUDE_OPTIONS_END$ */
+#include "cp$src:common.h"
+#include "cp$inc:prototypes.h"
+#include "cp$src:kernel_def.h"
+#include "cp$src:msg_def.h"
+#include "cp$src:smcc669_def.h"
+/* Platform-specific includes */
+#include "cp$src:platform.h"
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define wb( _x_, _y_ ) outb( _y_, (unsigned int)((unsigned long)_x_) )
+#define rb( _x_ ) inb( (unsigned int)((unsigned long)_x_) )
+
+/*
+** Local storage for device configuration information.
+**
+** Since the SMC37c669 does not provide an explicit
+** mechanism for enabling/disabling individual device
+** functions, other than unmapping the device, local
+** storage for device configuration information is
+** allocated here for use in implementing our own
+** function enable/disable scheme.
+*/
+static struct DEVICE_CONFIG {
+ unsigned int port1;
+ unsigned int port2;
+ unsigned int irq;
+ unsigned int drq;
+} local_config [NUM_FUNCS];
+
+/*
+** List of all possible addresses for the Super I/O chip
+*/
+static unsigned long SMC37c669_Addresses[] __initdata =
+ {
+ 0x3F0UL, /* Primary address */
+ 0x370UL, /* Secondary address */
+ 0UL /* End of list */
+ };
+
+/*
+** Global Pointer to the Super I/O device
+*/
+static SMC37c669_CONFIG_REGS *SMC37c669 __initdata = NULL;
+
+/*
+** IRQ Translation Table
+**
+** The IRQ translation table is a list of SMC37c669 device
+** and standard ISA IRQs.
+**
+*/
+static SMC37c669_IRQ_TRANSLATION_ENTRY *SMC37c669_irq_table __initdata;
+
+/*
+** The following definition is for the default IRQ
+** translation table.
+*/
+static SMC37c669_IRQ_TRANSLATION_ENTRY SMC37c669_default_irq_table[]
+__initdata =
+ {
+ { SMC37c669_DEVICE_IRQ_A, -1 },
+ { SMC37c669_DEVICE_IRQ_B, -1 },
+ { SMC37c669_DEVICE_IRQ_C, 7 },
+ { SMC37c669_DEVICE_IRQ_D, 6 },
+ { SMC37c669_DEVICE_IRQ_E, 4 },
+ { SMC37c669_DEVICE_IRQ_F, 3 },
+ { SMC37c669_DEVICE_IRQ_H, -1 },
+ { -1, -1 } /* End of table */
+ };
+
+/*
+** DRQ Translation Table
+**
+** The DRQ translation table is a list of SMC37c669 device and
+** ISA DMA channels.
+**
+*/
+static SMC37c669_DRQ_TRANSLATION_ENTRY *SMC37c669_drq_table __initdata;
+
+/*
+** The following definition is the default DRQ
+** translation table.
+*/
+static SMC37c669_DRQ_TRANSLATION_ENTRY SMC37c669_default_drq_table[]
+__initdata =
+ {
+ { SMC37c669_DEVICE_DRQ_A, 2 },
+ { SMC37c669_DEVICE_DRQ_B, 3 },
+ { SMC37c669_DEVICE_DRQ_C, -1 },
+ { -1, -1 } /* End of table */
+ };
+
+/*
+** Local Function Prototype Declarations
+*/
+
+static unsigned int SMC37c669_is_device_enabled(
+ unsigned int func
+);
+
+#if 0
+static unsigned int SMC37c669_get_device_config(
+ unsigned int func,
+ int *port,
+ int *irq,
+ int *drq
+);
+#endif
+
+static void SMC37c669_config_mode(
+ unsigned int enable
+);
+
+static unsigned char SMC37c669_read_config(
+ unsigned char index
+);
+
+static void SMC37c669_write_config(
+ unsigned char index,
+ unsigned char data
+);
+
+static void SMC37c669_init_local_config( void );
+
+static struct DEVICE_CONFIG *SMC37c669_get_config(
+ unsigned int func
+);
+
+static int SMC37c669_xlate_irq(
+ unsigned int irq
+);
+
+static int SMC37c669_xlate_drq(
+ unsigned int drq
+);
+
+#if 0
+/*
+** External Data Declarations
+*/
+
+extern struct LOCK spl_atomic;
+
+/*
+** External Function Prototype Declarations
+*/
+
+/* From kernel_alpha.mar */
+extern spinlock(
+ struct LOCK *spl
+);
+
+extern spinunlock(
+ struct LOCK *spl
+);
+
+/* From filesys.c */
+int allocinode(
+ char *name,
+ int can_create,
+ struct INODE **ipp
+);
+
+extern int null_procedure( void );
+
+int smcc669_init( void );
+int smcc669_open( struct FILE *fp, char *info, char *next, char *mode );
+int smcc669_read( struct FILE *fp, int size, int number, unsigned char *buf );
+int smcc669_write( struct FILE *fp, int size, int number, unsigned char *buf );
+int smcc669_close( struct FILE *fp );
+
+struct DDB smc_ddb = {
+ "smc", /* how this routine wants to be called */
+ smcc669_read, /* read routine */
+ smcc669_write, /* write routine */
+ smcc669_open, /* open routine */
+ smcc669_close, /* close routine */
+ null_procedure, /* name expansion routine */
+ null_procedure, /* delete routine */
+ null_procedure, /* create routine */
+ null_procedure, /* setmode */
+ null_procedure, /* validation routine */
+ 0, /* class specific use */
+ 1, /* allows information */
+ 0, /* must be stacked */
+ 0, /* is a flash update driver */
+ 0, /* is a block device */
+ 0, /* not seekable */
+ 0, /* is an ethernet device */
+ 0, /* is a filesystem driver */
+};
+#endif
+
+#define spinlock(x)
+#define spinunlock(x)
+
+
+/*
+**++
+** FUNCTIONAL DESCRIPTION:
+**
+** This function detects the presence of an SMC37c669 Super I/O
+** controller.
+**
+** FORMAL PARAMETERS:
+**
+** None
+**
+** RETURN VALUE:
+**
+** Returns a pointer to the device if found, otherwise,
+** the NULL pointer is returned.
+**
+** SIDE EFFECTS:
+**
+** None
+**
+**--
+*/
+SMC37c669_CONFIG_REGS * __init SMC37c669_detect( void )
+{
+ int i;
+ SMC37c669_DEVICE_ID_REGISTER id;
+
+ for ( i = 0; SMC37c669_Addresses[i] != 0; i++ ) {
+/*
+** Initialize the device pointer even though we don't yet know if
+** the controller is at this address. The support functions access
+** the controller through this device pointer so we need to set it
+** even when we are looking ...
+*/
+ SMC37c669 = ( SMC37c669_CONFIG_REGS * )SMC37c669_Addresses[i];
+/*
+** Enter configuration mode
+*/
+ SMC37c669_config_mode( TRUE );
+/*
+** Read the device id
+*/
+ id.as_uchar = SMC37c669_read_config( SMC37c669_DEVICE_ID_INDEX );
+/*
+** Exit configuration mode
+*/
+ SMC37c669_config_mode( FALSE );
+/*
+** Does the device id match? If so, assume we have found an
+** SMC37c669 controller at this address.
+*/
+ if ( id.by_field.device_id == SMC37c669_DEVICE_ID ) {
+/*
+** Initialize the IRQ and DRQ translation tables.
+*/
+ SMC37c669_irq_table = SMC37c669_default_irq_table;
+ SMC37c669_drq_table = SMC37c669_default_drq_table;
+/*
+** erfix
+**
+** If the platform can't use the IRQ and DRQ defaults set up in this
+** file, it should call a platform-specific external routine at this
+** point to reset the IRQ and DRQ translation table pointers to point
+** at the appropriate tables for the platform. If the defaults are
+** acceptable, then the external routine should do nothing.
+*/
+
+/*
+** Put the chip back into configuration mode
+*/
+ SMC37c669_config_mode( TRUE );
+/*
+** Initialize local storage for configuration information
+*/
+ SMC37c669_init_local_config( );
+/*
+** Exit configuration mode
+*/
+ SMC37c669_config_mode( FALSE );
+/*
+** SMC37c669 controller found, break out of search loop
+*/
+ break;
+ }
+ else {
+/*
+** Otherwise, we did not find an SMC37c669 controller at this
+** address so set the device pointer to NULL.
+*/
+ SMC37c669 = NULL;
+ }
+ }
+ return SMC37c669;
+}
+
+
+/*
+**++
+** FUNCTIONAL DESCRIPTION:
+**
+** This function enables an SMC37c669 device function.
+**
+** FORMAL PARAMETERS:
+**
+** func:
+** Which device function to enable
+**
+** RETURN VALUE:
+**
+** Returns TRUE is the device function was enabled, otherwise, FALSE
+**
+** SIDE EFFECTS:
+**
+** {@description or none@}
+**
+** DESIGN:
+**
+** Enabling a device function in the SMC37c669 controller involves
+** setting all of its mappings (port, irq, drq ...). A local
+** "shadow" copy of the device configuration is kept so we can
+** just set each mapping to what the local copy says.
+**
+** This function ALWAYS updates the local shadow configuration of
+** the device function being enabled, even if the device is always
+** enabled. To avoid replication of code, functions such as
+** configure_device set up the local copy and then call this
+** function to the update the real device.
+**
+**--
+*/
+unsigned int __init SMC37c669_enable_device ( unsigned int func )
+{
+ unsigned int ret_val = FALSE;
+/*
+** Put the device into configuration mode
+*/
+ SMC37c669_config_mode( TRUE );
+ switch ( func ) {
+ case SERIAL_0:
+ {
+ SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr;
+ SMC37c669_SERIAL_IRQ_REGISTER irq;
+/*
+** Enable the serial 1 IRQ mapping
+*/
+ irq.as_uchar =
+ SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
+
+ irq.by_field.uart1_irq =
+ SMC37c669_RAW_DEVICE_IRQ(
+ SMC37c669_xlate_irq( local_config[ func ].irq )
+ );
+
+ SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar );
+/*
+** Enable the serial 1 port base address mapping
+*/
+ base_addr.as_uchar = 0;
+ base_addr.by_field.addr9_3 = local_config[ func ].port1 >> 3;
+
+ SMC37c669_write_config(
+ SMC37c669_SERIAL0_BASE_ADDRESS_INDEX,
+ base_addr.as_uchar
+ );
+ ret_val = TRUE;
+ break;
+ }
+ case SERIAL_1:
+ {
+ SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr;
+ SMC37c669_SERIAL_IRQ_REGISTER irq;
+/*
+** Enable the serial 2 IRQ mapping
+*/
+ irq.as_uchar =
+ SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
+
+ irq.by_field.uart2_irq =
+ SMC37c669_RAW_DEVICE_IRQ(
+ SMC37c669_xlate_irq( local_config[ func ].irq )
+ );
+
+ SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar );
+/*
+** Enable the serial 2 port base address mapping
+*/
+ base_addr.as_uchar = 0;
+ base_addr.by_field.addr9_3 = local_config[ func ].port1 >> 3;
+
+ SMC37c669_write_config(
+ SMC37c669_SERIAL1_BASE_ADDRESS_INDEX,
+ base_addr.as_uchar
+ );
+ ret_val = TRUE;
+ break;
+ }
+ case PARALLEL_0:
+ {
+ SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER base_addr;
+ SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq;
+ SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq;
+/*
+** Enable the parallel port DMA channel mapping
+*/
+ drq.as_uchar =
+ SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
+
+ drq.by_field.ppt_drq =
+ SMC37c669_RAW_DEVICE_DRQ(
+ SMC37c669_xlate_drq( local_config[ func ].drq )
+ );
+
+ SMC37c669_write_config(
+ SMC37c669_PARALLEL_FDC_DRQ_INDEX,
+ drq.as_uchar
+ );
+/*
+** Enable the parallel port IRQ mapping
+*/
+ irq.as_uchar =
+ SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
+
+ irq.by_field.ppt_irq =
+ SMC37c669_RAW_DEVICE_IRQ(
+ SMC37c669_xlate_irq( local_config[ func ].irq )
+ );
+
+ SMC37c669_write_config(
+ SMC37c669_PARALLEL_FDC_IRQ_INDEX,
+ irq.as_uchar
+ );
+/*
+** Enable the parallel port base address mapping
+*/
+ base_addr.as_uchar = 0;
+ base_addr.by_field.addr9_2 = local_config[ func ].port1 >> 2;
+
+ SMC37c669_write_config(
+ SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX,
+ base_addr.as_uchar
+ );
+ ret_val = TRUE;
+ break;
+ }
+ case FLOPPY_0:
+ {
+ SMC37c669_FDC_BASE_ADDRESS_REGISTER base_addr;
+ SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq;
+ SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq;
+/*
+** Enable the floppy controller DMA channel mapping
+*/
+ drq.as_uchar =
+ SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
+
+ drq.by_field.fdc_drq =
+ SMC37c669_RAW_DEVICE_DRQ(
+ SMC37c669_xlate_drq( local_config[ func ].drq )
+ );
+
+ SMC37c669_write_config(
+ SMC37c669_PARALLEL_FDC_DRQ_INDEX,
+ drq.as_uchar
+ );
+/*
+** Enable the floppy controller IRQ mapping
+*/
+ irq.as_uchar =
+ SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
+
+ irq.by_field.fdc_irq =
+ SMC37c669_RAW_DEVICE_IRQ(
+ SMC37c669_xlate_irq( local_config[ func ].irq )
+ );
+
+ SMC37c669_write_config(
+ SMC37c669_PARALLEL_FDC_IRQ_INDEX,
+ irq.as_uchar
+ );
+/*
+** Enable the floppy controller base address mapping
+*/
+ base_addr.as_uchar = 0;
+ base_addr.by_field.addr9_4 = local_config[ func ].port1 >> 4;
+
+ SMC37c669_write_config(
+ SMC37c669_FDC_BASE_ADDRESS_INDEX,
+ base_addr.as_uchar
+ );
+ ret_val = TRUE;
+ break;
+ }
+ case IDE_0:
+ {
+ SMC37c669_IDE_ADDRESS_REGISTER ide_addr;
+/*
+** Enable the IDE alternate status base address mapping
+*/
+ ide_addr.as_uchar = 0;
+ ide_addr.by_field.addr9_4 = local_config[ func ].port2 >> 4;
+
+ SMC37c669_write_config(
+ SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX,
+ ide_addr.as_uchar
+ );
+/*
+** Enable the IDE controller base address mapping
+*/
+ ide_addr.as_uchar = 0;
+ ide_addr.by_field.addr9_4 = local_config[ func ].port1 >> 4;
+
+ SMC37c669_write_config(
+ SMC37c669_IDE_BASE_ADDRESS_INDEX,
+ ide_addr.as_uchar
+ );
+ ret_val = TRUE;
+ break;
+ }
+ }
+/*
+** Exit configuration mode and return
+*/
+ SMC37c669_config_mode( FALSE );
+
+ return ret_val;
+}
+
+
+/*
+**++
+** FUNCTIONAL DESCRIPTION:
+**
+** This function disables a device function within the
+** SMC37c669 Super I/O controller.
+**
+** FORMAL PARAMETERS:
+**
+** func:
+** Which function to disable
+**
+** RETURN VALUE:
+**
+** Return TRUE if the device function was disabled, otherwise, FALSE
+**
+** SIDE EFFECTS:
+**
+** {@description or none@}
+**
+** DESIGN:
+**
+** Disabling a function in the SMC37c669 device involves
+** disabling all the function's mappings (port, irq, drq ...).
+** A shadow copy of the device configuration is maintained
+** in local storage so we won't worry aboving saving the
+** current configuration information.
+**
+**--
+*/
+unsigned int __init SMC37c669_disable_device ( unsigned int func )
+{
+ unsigned int ret_val = FALSE;
+
+/*
+** Put the device into configuration mode
+*/
+ SMC37c669_config_mode( TRUE );
+ switch ( func ) {
+ case SERIAL_0:
+ {
+ SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr;
+ SMC37c669_SERIAL_IRQ_REGISTER irq;
+/*
+** Disable the serial 1 IRQ mapping
+*/
+ irq.as_uchar =
+ SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
+
+ irq.by_field.uart1_irq = 0;
+
+ SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar );
+/*
+** Disable the serial 1 port base address mapping
+*/
+ base_addr.as_uchar = 0;
+ SMC37c669_write_config(
+ SMC37c669_SERIAL0_BASE_ADDRESS_INDEX,
+ base_addr.as_uchar
+ );
+ ret_val = TRUE;
+ break;
+ }
+ case SERIAL_1:
+ {
+ SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr;
+ SMC37c669_SERIAL_IRQ_REGISTER irq;
+/*
+** Disable the serial 2 IRQ mapping
+*/
+ irq.as_uchar =
+ SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
+
+ irq.by_field.uart2_irq = 0;
+
+ SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar );
+/*
+** Disable the serial 2 port base address mapping
+*/
+ base_addr.as_uchar = 0;
+
+ SMC37c669_write_config(
+ SMC37c669_SERIAL1_BASE_ADDRESS_INDEX,
+ base_addr.as_uchar
+ );
+ ret_val = TRUE;
+ break;
+ }
+ case PARALLEL_0:
+ {
+ SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER base_addr;
+ SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq;
+ SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq;
+/*
+** Disable the parallel port DMA channel mapping
+*/
+ drq.as_uchar =
+ SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
+
+ drq.by_field.ppt_drq = 0;
+
+ SMC37c669_write_config(
+ SMC37c669_PARALLEL_FDC_DRQ_INDEX,
+ drq.as_uchar
+ );
+/*
+** Disable the parallel port IRQ mapping
+*/
+ irq.as_uchar =
+ SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
+
+ irq.by_field.ppt_irq = 0;
+
+ SMC37c669_write_config(
+ SMC37c669_PARALLEL_FDC_IRQ_INDEX,
+ irq.as_uchar
+ );
+/*
+** Disable the parallel port base address mapping
+*/
+ base_addr.as_uchar = 0;
+
+ SMC37c669_write_config(
+ SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX,
+ base_addr.as_uchar
+ );
+ ret_val = TRUE;
+ break;
+ }
+ case FLOPPY_0:
+ {
+ SMC37c669_FDC_BASE_ADDRESS_REGISTER base_addr;
+ SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq;
+ SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq;
+/*
+** Disable the floppy controller DMA channel mapping
+*/
+ drq.as_uchar =
+ SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
+
+ drq.by_field.fdc_drq = 0;
+
+ SMC37c669_write_config(
+ SMC37c669_PARALLEL_FDC_DRQ_INDEX,
+ drq.as_uchar
+ );
+/*
+** Disable the floppy controller IRQ mapping
+*/
+ irq.as_uchar =
+ SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
+
+ irq.by_field.fdc_irq = 0;
+
+ SMC37c669_write_config(
+ SMC37c669_PARALLEL_FDC_IRQ_INDEX,
+ irq.as_uchar
+ );
+/*
+** Disable the floppy controller base address mapping
+*/
+ base_addr.as_uchar = 0;
+
+ SMC37c669_write_config(
+ SMC37c669_FDC_BASE_ADDRESS_INDEX,
+ base_addr.as_uchar
+ );
+ ret_val = TRUE;
+ break;
+ }
+ case IDE_0:
+ {
+ SMC37c669_IDE_ADDRESS_REGISTER ide_addr;
+/*
+** Disable the IDE alternate status base address mapping
+*/
+ ide_addr.as_uchar = 0;
+
+ SMC37c669_write_config(
+ SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX,
+ ide_addr.as_uchar
+ );
+/*
+** Disable the IDE controller base address mapping
+*/
+ ide_addr.as_uchar = 0;
+
+ SMC37c669_write_config(
+ SMC37c669_IDE_BASE_ADDRESS_INDEX,
+ ide_addr.as_uchar
+ );
+ ret_val = TRUE;
+ break;
+ }
+ }
+/*
+** Exit configuration mode and return
+*/
+ SMC37c669_config_mode( FALSE );
+
+ return ret_val;
+}
+
+
+/*
+**++
+** FUNCTIONAL DESCRIPTION:
+**
+** This function configures a device function within the
+** SMC37c669 Super I/O controller.
+**
+** FORMAL PARAMETERS:
+**
+** func:
+** Which device function
+**
+** port:
+** I/O port for the function to use
+**
+** irq:
+** IRQ for the device function to use
+**
+** drq:
+** DMA channel for the device function to use
+**
+** RETURN VALUE:
+**
+** Returns TRUE if the device function was configured,
+** otherwise, FALSE.
+**
+** SIDE EFFECTS:
+**
+** {@description or none@}
+**
+** DESIGN:
+**
+** If this function returns TRUE, the local shadow copy of
+** the configuration is also updated. If the device function
+** is currently disabled, only the local shadow copy is
+** updated and the actual device function will be updated
+** if/when is is enabled.
+**
+**--
+*/
+unsigned int __init SMC37c669_configure_device (
+ unsigned int func,
+ int port,
+ int irq,
+ int drq )
+{
+ struct DEVICE_CONFIG *cp;
+
+/*
+** Check for a valid configuration
+*/
+ if ( ( cp = SMC37c669_get_config ( func ) ) != NULL ) {
+/*
+** Configuration is valid, update the local shadow copy
+*/
+ if ( ( drq & ~0xFF ) == 0 ) {
+ cp->drq = drq;
+ }
+ if ( ( irq & ~0xFF ) == 0 ) {
+ cp->irq = irq;
+ }
+ if ( ( port & ~0xFFFF ) == 0 ) {
+ cp->port1 = port;
+ }
+/*
+** If the device function is enabled, update the actual
+** device configuration.
+*/
+ if ( SMC37c669_is_device_enabled( func ) ) {
+ SMC37c669_enable_device( func );
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/*
+**++
+** FUNCTIONAL DESCRIPTION:
+**
+** This function determines whether a device function
+** within the SMC37c669 controller is enabled.
+**
+** FORMAL PARAMETERS:
+**
+** func:
+** Which device function
+**
+** RETURN VALUE:
+**
+** Returns TRUE if the device function is enabled, otherwise, FALSE
+**
+** SIDE EFFECTS:
+**
+** {@description or none@}
+**
+** DESIGN:
+**
+** To check whether a device is enabled we will only look at
+** the port base address mapping. According to the SMC37c669
+** specification, all of the port base address mappings are
+** disabled if the addr<9:8> (bits <7:6> of the register) are
+** zero.
+**
+**--
+*/
+static unsigned int __init SMC37c669_is_device_enabled ( unsigned int func )
+{
+ unsigned char base_addr = 0;
+ unsigned int dev_ok = FALSE;
+ unsigned int ret_val = FALSE;
+/*
+** Enter configuration mode
+*/
+ SMC37c669_config_mode( TRUE );
+
+ switch ( func ) {
+ case SERIAL_0:
+ base_addr =
+ SMC37c669_read_config( SMC37c669_SERIAL0_BASE_ADDRESS_INDEX );
+ dev_ok = TRUE;
+ break;
+ case SERIAL_1:
+ base_addr =
+ SMC37c669_read_config( SMC37c669_SERIAL1_BASE_ADDRESS_INDEX );
+ dev_ok = TRUE;
+ break;
+ case PARALLEL_0:
+ base_addr =
+ SMC37c669_read_config( SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX );
+ dev_ok = TRUE;
+ break;
+ case FLOPPY_0:
+ base_addr =
+ SMC37c669_read_config( SMC37c669_FDC_BASE_ADDRESS_INDEX );
+ dev_ok = TRUE;
+ break;
+ case IDE_0:
+ base_addr =
+ SMC37c669_read_config( SMC37c669_IDE_BASE_ADDRESS_INDEX );
+ dev_ok = TRUE;
+ break;
+ }
+/*
+** If we have a valid device, check base_addr<7:6> to see if the
+** device is enabled (mapped).
+*/
+ if ( ( dev_ok ) && ( ( base_addr & 0xC0 ) != 0 ) ) {
+/*
+** The mapping is not disabled, so assume that the function is
+** enabled.
+*/
+ ret_val = TRUE;
+ }
+/*
+** Exit configuration mode
+*/
+ SMC37c669_config_mode( FALSE );
+
+ return ret_val;
+}
+
+
+#if 0
+/*
+**++
+** FUNCTIONAL DESCRIPTION:
+**
+** This function retrieves the configuration information of a
+** device function within the SMC37c699 Super I/O controller.
+**
+** FORMAL PARAMETERS:
+**
+** func:
+** Which device function
+**
+** port:
+** I/O port returned
+**
+** irq:
+** IRQ returned
+**
+** drq:
+** DMA channel returned
+**
+** RETURN VALUE:
+**
+** Returns TRUE if the device configuration was successfully
+** retrieved, otherwise, FALSE.
+**
+** SIDE EFFECTS:
+**
+** The data pointed to by the port, irq, and drq parameters
+** my be modified even if the configuration is not successfully
+** retrieved.
+**
+** DESIGN:
+**
+** The device configuration is fetched from the local shadow
+** copy. Any unused parameters will be set to -1. Any
+** parameter which is not desired can specify the NULL
+** pointer.
+**
+**--
+*/
+static unsigned int __init SMC37c669_get_device_config (
+ unsigned int func,
+ int *port,
+ int *irq,
+ int *drq )
+{
+ struct DEVICE_CONFIG *cp;
+ unsigned int ret_val = FALSE;
+/*
+** Check for a valid device configuration
+*/
+ if ( ( cp = SMC37c669_get_config( func ) ) != NULL ) {
+ if ( drq != NULL ) {
+ *drq = cp->drq;
+ ret_val = TRUE;
+ }
+ if ( irq != NULL ) {
+ *irq = cp->irq;
+ ret_val = TRUE;
+ }
+ if ( port != NULL ) {
+ *port = cp->port1;
+ ret_val = TRUE;
+ }
+ }
+ return ret_val;
+}
+#endif
+
+
+/*
+**++
+** FUNCTIONAL DESCRIPTION:
+**
+** This function displays the current state of the SMC37c699
+** Super I/O controller's device functions.
+**
+** FORMAL PARAMETERS:
+**
+** None
+**
+** RETURN VALUE:
+**
+** None
+**
+** SIDE EFFECTS:
+**
+** None
+**
+**--
+*/
+void __init SMC37c669_display_device_info ( void )
+{
+ if ( SMC37c669_is_device_enabled( SERIAL_0 ) ) {
+ printk( " Serial 0: Enabled [ Port 0x%x, IRQ %d ]\n",
+ local_config[ SERIAL_0 ].port1,
+ local_config[ SERIAL_0 ].irq
+ );
+ }
+ else {
+ printk( " Serial 0: Disabled\n" );
+ }
+
+ if ( SMC37c669_is_device_enabled( SERIAL_1 ) ) {
+ printk( " Serial 1: Enabled [ Port 0x%x, IRQ %d ]\n",
+ local_config[ SERIAL_1 ].port1,
+ local_config[ SERIAL_1 ].irq
+ );
+ }
+ else {
+ printk( " Serial 1: Disabled\n" );
+ }
+
+ if ( SMC37c669_is_device_enabled( PARALLEL_0 ) ) {
+ printk( " Parallel: Enabled [ Port 0x%x, IRQ %d/%d ]\n",
+ local_config[ PARALLEL_0 ].port1,
+ local_config[ PARALLEL_0 ].irq,
+ local_config[ PARALLEL_0 ].drq
+ );
+ }
+ else {
+ printk( " Parallel: Disabled\n" );
+ }
+
+ if ( SMC37c669_is_device_enabled( FLOPPY_0 ) ) {
+ printk( " Floppy Ctrl: Enabled [ Port 0x%x, IRQ %d/%d ]\n",
+ local_config[ FLOPPY_0 ].port1,
+ local_config[ FLOPPY_0 ].irq,
+ local_config[ FLOPPY_0 ].drq
+ );
+ }
+ else {
+ printk( " Floppy Ctrl: Disabled\n" );
+ }
+
+ if ( SMC37c669_is_device_enabled( IDE_0 ) ) {
+ printk( " IDE 0: Enabled [ Port 0x%x, IRQ %d ]\n",
+ local_config[ IDE_0 ].port1,
+ local_config[ IDE_0 ].irq
+ );
+ }
+ else {
+ printk( " IDE 0: Disabled\n" );
+ }
+}
+
+
+/*
+**++
+** FUNCTIONAL DESCRIPTION:
+**
+** This function puts the SMC37c669 Super I/O controller into,
+** and takes it out of, configuration mode.
+**
+** FORMAL PARAMETERS:
+**
+** enable:
+** TRUE to enter configuration mode, FALSE to exit.
+**
+** RETURN VALUE:
+**
+** None
+**
+** SIDE EFFECTS:
+**
+** The SMC37c669 controller may be left in configuration mode.
+**
+**--
+*/
+static void __init SMC37c669_config_mode(
+ unsigned int enable )
+{
+ if ( enable ) {
+/*
+** To enter configuration mode, two writes in succession to the index
+** port are required. If a write to another address or port occurs
+** between these two writes, the chip does not enter configuration
+** mode. Therefore, a spinlock is placed around the two writes to
+** guarantee that they complete uninterrupted.
+*/
+ spinlock( &spl_atomic );
+ wb( &SMC37c669->index_port, SMC37c669_CONFIG_ON_KEY );
+ wb( &SMC37c669->index_port, SMC37c669_CONFIG_ON_KEY );
+ spinunlock( &spl_atomic );
+ }
+ else {
+ wb( &SMC37c669->index_port, SMC37c669_CONFIG_OFF_KEY );
+ }
+}
+
+/*
+**++
+** FUNCTIONAL DESCRIPTION:
+**
+** This function reads an SMC37c669 Super I/O controller
+** configuration register. This function assumes that the
+** device is already in configuration mode.
+**
+** FORMAL PARAMETERS:
+**
+** index:
+** Index value of configuration register to read
+**
+** RETURN VALUE:
+**
+** Data read from configuration register
+**
+** SIDE EFFECTS:
+**
+** None
+**
+**--
+*/
+static unsigned char __init SMC37c669_read_config(
+ unsigned char index )
+{
+ unsigned char data;
+
+ wb( &SMC37c669->index_port, index );
+ data = rb( &SMC37c669->data_port );
+ return data;
+}
+
+/*
+**++
+** FUNCTIONAL DESCRIPTION:
+**
+** This function writes an SMC37c669 Super I/O controller
+** configuration register. This function assumes that the
+** device is already in configuration mode.
+**
+** FORMAL PARAMETERS:
+**
+** index:
+** Index of configuration register to write
+**
+** data:
+** Data to be written
+**
+** RETURN VALUE:
+**
+** None
+**
+** SIDE EFFECTS:
+**
+** None
+**
+**--
+*/
+static void __init SMC37c669_write_config(
+ unsigned char index,
+ unsigned char data )
+{
+ wb( &SMC37c669->index_port, index );
+ wb( &SMC37c669->data_port, data );
+}
+
+
+/*
+**++
+** FUNCTIONAL DESCRIPTION:
+**
+** This function initializes the local device
+** configuration storage. This function assumes
+** that the device is already in configuration
+** mode.
+**
+** FORMAL PARAMETERS:
+**
+** None
+**
+** RETURN VALUE:
+**
+** None
+**
+** SIDE EFFECTS:
+**
+** Local storage for device configuration information
+** is initialized.
+**
+**--
+*/
+static void __init SMC37c669_init_local_config ( void )
+{
+ SMC37c669_SERIAL_BASE_ADDRESS_REGISTER uart_base;
+ SMC37c669_SERIAL_IRQ_REGISTER uart_irqs;
+ SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER ppt_base;
+ SMC37c669_PARALLEL_FDC_IRQ_REGISTER ppt_fdc_irqs;
+ SMC37c669_PARALLEL_FDC_DRQ_REGISTER ppt_fdc_drqs;
+ SMC37c669_FDC_BASE_ADDRESS_REGISTER fdc_base;
+ SMC37c669_IDE_ADDRESS_REGISTER ide_base;
+ SMC37c669_IDE_ADDRESS_REGISTER ide_alt;
+
+/*
+** Get serial port 1 base address
+*/
+ uart_base.as_uchar =
+ SMC37c669_read_config( SMC37c669_SERIAL0_BASE_ADDRESS_INDEX );
+/*
+** Get IRQs for serial ports 1 & 2
+*/
+ uart_irqs.as_uchar =
+ SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
+/*
+** Store local configuration information for serial port 1
+*/
+ local_config[SERIAL_0].port1 = uart_base.by_field.addr9_3 << 3;
+ local_config[SERIAL_0].irq =
+ SMC37c669_xlate_irq(
+ SMC37c669_DEVICE_IRQ( uart_irqs.by_field.uart1_irq )
+ );
+/*
+** Get serial port 2 base address
+*/
+ uart_base.as_uchar =
+ SMC37c669_read_config( SMC37c669_SERIAL1_BASE_ADDRESS_INDEX );
+/*
+** Store local configuration information for serial port 2
+*/
+ local_config[SERIAL_1].port1 = uart_base.by_field.addr9_3 << 3;
+ local_config[SERIAL_1].irq =
+ SMC37c669_xlate_irq(
+ SMC37c669_DEVICE_IRQ( uart_irqs.by_field.uart2_irq )
+ );
+/*
+** Get parallel port base address
+*/
+ ppt_base.as_uchar =
+ SMC37c669_read_config( SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX );
+/*
+** Get IRQs for parallel port and floppy controller
+*/
+ ppt_fdc_irqs.as_uchar =
+ SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
+/*
+** Get DRQs for parallel port and floppy controller
+*/
+ ppt_fdc_drqs.as_uchar =
+ SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
+/*
+** Store local configuration information for parallel port
+*/
+ local_config[PARALLEL_0].port1 = ppt_base.by_field.addr9_2 << 2;
+ local_config[PARALLEL_0].irq =
+ SMC37c669_xlate_irq(
+ SMC37c669_DEVICE_IRQ( ppt_fdc_irqs.by_field.ppt_irq )
+ );
+ local_config[PARALLEL_0].drq =
+ SMC37c669_xlate_drq(
+ SMC37c669_DEVICE_DRQ( ppt_fdc_drqs.by_field.ppt_drq )
+ );
+/*
+** Get floppy controller base address
+*/
+ fdc_base.as_uchar =
+ SMC37c669_read_config( SMC37c669_FDC_BASE_ADDRESS_INDEX );
+/*
+** Store local configuration information for floppy controller
+*/
+ local_config[FLOPPY_0].port1 = fdc_base.by_field.addr9_4 << 4;
+ local_config[FLOPPY_0].irq =
+ SMC37c669_xlate_irq(
+ SMC37c669_DEVICE_IRQ( ppt_fdc_irqs.by_field.fdc_irq )
+ );
+ local_config[FLOPPY_0].drq =
+ SMC37c669_xlate_drq(
+ SMC37c669_DEVICE_DRQ( ppt_fdc_drqs.by_field.fdc_drq )
+ );
+/*
+** Get IDE controller base address
+*/
+ ide_base.as_uchar =
+ SMC37c669_read_config( SMC37c669_IDE_BASE_ADDRESS_INDEX );
+/*
+** Get IDE alternate status base address
+*/
+ ide_alt.as_uchar =
+ SMC37c669_read_config( SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX );
+/*
+** Store local configuration information for IDE controller
+*/
+ local_config[IDE_0].port1 = ide_base.by_field.addr9_4 << 4;
+ local_config[IDE_0].port2 = ide_alt.by_field.addr9_4 << 4;
+ local_config[IDE_0].irq = 14;
+}
+
+
+/*
+**++
+** FUNCTIONAL DESCRIPTION:
+**
+** This function returns a pointer to the local shadow
+** configuration of the requested device function.
+**
+** FORMAL PARAMETERS:
+**
+** func:
+** Which device function
+**
+** RETURN VALUE:
+**
+** Returns a pointer to the DEVICE_CONFIG structure for the
+** requested function, otherwise, NULL.
+**
+** SIDE EFFECTS:
+**
+** {@description or none@}
+**
+**--
+*/
+static struct DEVICE_CONFIG * __init SMC37c669_get_config( unsigned int func )
+{
+ struct DEVICE_CONFIG *cp = NULL;
+
+ switch ( func ) {
+ case SERIAL_0:
+ cp = &local_config[ SERIAL_0 ];
+ break;
+ case SERIAL_1:
+ cp = &local_config[ SERIAL_1 ];
+ break;
+ case PARALLEL_0:
+ cp = &local_config[ PARALLEL_0 ];
+ break;
+ case FLOPPY_0:
+ cp = &local_config[ FLOPPY_0 ];
+ break;
+ case IDE_0:
+ cp = &local_config[ IDE_0 ];
+ break;
+ }
+ return cp;
+}
+
+/*
+**++
+** FUNCTIONAL DESCRIPTION:
+**
+** This function translates IRQs back and forth between ISA
+** IRQs and SMC37c669 device IRQs.
+**
+** FORMAL PARAMETERS:
+**
+** irq:
+** The IRQ to translate
+**
+** RETURN VALUE:
+**
+** Returns the translated IRQ, otherwise, returns -1.
+**
+** SIDE EFFECTS:
+**
+** {@description or none@}
+**
+**--
+*/
+static int __init SMC37c669_xlate_irq ( unsigned int irq )
+{
+ int i, translated_irq = -1;
+
+ if ( SMC37c669_IS_DEVICE_IRQ( irq ) ) {
+/*
+** We are translating a device IRQ to an ISA IRQ
+*/
+ for ( i = 0; ( SMC37c669_irq_table[i].device_irq != -1 ) || ( SMC37c669_irq_table[i].isa_irq != -1 ); i++ ) {
+ if ( irq == SMC37c669_irq_table[i].device_irq ) {
+ translated_irq = SMC37c669_irq_table[i].isa_irq;
+ break;
+ }
+ }
+ }
+ else {
+/*
+** We are translating an ISA IRQ to a device IRQ
+*/
+ for ( i = 0; ( SMC37c669_irq_table[i].isa_irq != -1 ) || ( SMC37c669_irq_table[i].device_irq != -1 ); i++ ) {
+ if ( irq == SMC37c669_irq_table[i].isa_irq ) {
+ translated_irq = SMC37c669_irq_table[i].device_irq;
+ break;
+ }
+ }
+ }
+ return translated_irq;
+}
+
+
+/*
+**++
+** FUNCTIONAL DESCRIPTION:
+**
+** This function translates DMA channels back and forth between
+** ISA DMA channels and SMC37c669 device DMA channels.
+**
+** FORMAL PARAMETERS:
+**
+** drq:
+** The DMA channel to translate
+**
+** RETURN VALUE:
+**
+** Returns the translated DMA channel, otherwise, returns -1
+**
+** SIDE EFFECTS:
+**
+** {@description or none@}
+**
+**--
+*/
+static int __init SMC37c669_xlate_drq ( unsigned int drq )
+{
+ int i, translated_drq = -1;
+
+ if ( SMC37c669_IS_DEVICE_DRQ( drq ) ) {
+/*
+** We are translating a device DMA channel to an ISA DMA channel
+*/
+ for ( i = 0; ( SMC37c669_drq_table[i].device_drq != -1 ) || ( SMC37c669_drq_table[i].isa_drq != -1 ); i++ ) {
+ if ( drq == SMC37c669_drq_table[i].device_drq ) {
+ translated_drq = SMC37c669_drq_table[i].isa_drq;
+ break;
+ }
+ }
+ }
+ else {
+/*
+** We are translating an ISA DMA channel to a device DMA channel
+*/
+ for ( i = 0; ( SMC37c669_drq_table[i].isa_drq != -1 ) || ( SMC37c669_drq_table[i].device_drq != -1 ); i++ ) {
+ if ( drq == SMC37c669_drq_table[i].isa_drq ) {
+ translated_drq = SMC37c669_drq_table[i].device_drq;
+ break;
+ }
+ }
+ }
+ return translated_drq;
+}
+
+#if 0
+int __init smcc669_init ( void )
+{
+ struct INODE *ip;
+
+ allocinode( smc_ddb.name, 1, &ip );
+ ip->dva = &smc_ddb;
+ ip->attr = ATTR$M_WRITE | ATTR$M_READ;
+ ip->len[0] = 0x30;
+ ip->misc = 0;
+ INODE_UNLOCK( ip );
+
+ return msg_success;
+}
+
+int __init smcc669_open( struct FILE *fp, char *info, char *next, char *mode )
+{
+ struct INODE *ip;
+/*
+** Allow multiple readers but only one writer. ip->misc keeps track
+** of the number of writers
+*/
+ ip = fp->ip;
+ INODE_LOCK( ip );
+ if ( fp->mode & ATTR$M_WRITE ) {
+ if ( ip->misc ) {
+ INODE_UNLOCK( ip );
+ return msg_failure; /* too many writers */
+ }
+ ip->misc++;
+ }
+/*
+** Treat the information field as a byte offset
+*/
+ *fp->offset = xtoi( info );
+ INODE_UNLOCK( ip );
+
+ return msg_success;
+}
+
+int __init smcc669_close( struct FILE *fp )
+{
+ struct INODE *ip;
+
+ ip = fp->ip;
+ if ( fp->mode & ATTR$M_WRITE ) {
+ INODE_LOCK( ip );
+ ip->misc--;
+ INODE_UNLOCK( ip );
+ }
+ return msg_success;
+}
+
+int __init smcc669_read( struct FILE *fp, int size, int number, unsigned char *buf )
+{
+ int i;
+ int length;
+ int nbytes;
+ struct INODE *ip;
+
+/*
+** Always access a byte at a time
+*/
+ ip = fp->ip;
+ length = size * number;
+ nbytes = 0;
+
+ SMC37c669_config_mode( TRUE );
+ for ( i = 0; i < length; i++ ) {
+ if ( !inrange( *fp->offset, 0, ip->len[0] ) )
+ break;
+ *buf++ = SMC37c669_read_config( *fp->offset );
+ *fp->offset += 1;
+ nbytes++;
+ }
+ SMC37c669_config_mode( FALSE );
+ return nbytes;
+}
+
+int __init smcc669_write( struct FILE *fp, int size, int number, unsigned char *buf )
+{
+ int i;
+ int length;
+ int nbytes;
+ struct INODE *ip;
+/*
+** Always access a byte at a time
+*/
+ ip = fp->ip;
+ length = size * number;
+ nbytes = 0;
+
+ SMC37c669_config_mode( TRUE );
+ for ( i = 0; i < length; i++ ) {
+ if ( !inrange( *fp->offset, 0, ip->len[0] ) )
+ break;
+ SMC37c669_write_config( *fp->offset, *buf );
+ *fp->offset += 1;
+ buf++;
+ nbytes++;
+ }
+ SMC37c669_config_mode( FALSE );
+ return nbytes;
+}
+#endif
+
+void __init
+SMC37c669_dump_registers(void)
+{
+ int i;
+ for (i = 0; i <= 0x29; i++)
+ printk("-- CR%02x : %02x\n", i, SMC37c669_read_config(i));
+}
+/*+
+ * ============================================================================
+ * = SMC_init - SMC37c669 Super I/O controller initialization =
+ * ============================================================================
+ *
+ * OVERVIEW:
+ *
+ * This routine configures and enables device functions on the
+ * SMC37c669 Super I/O controller.
+ *
+ * FORM OF CALL:
+ *
+ * SMC_init( );
+ *
+ * RETURNS:
+ *
+ * Nothing
+ *
+ * ARGUMENTS:
+ *
+ * None
+ *
+ * SIDE EFFECTS:
+ *
+ * None
+ *
+ */
+void __init SMC669_Init ( void )
+{
+ SMC37c669_CONFIG_REGS *SMC_base;
+
+ if ( ( SMC_base = SMC37c669_detect( ) ) != NULL ) {
+ printk( "SMC37c669 Super I/O Controller found @ 0x%lx\n",
+ (unsigned long) SMC_base );
+#if SMC_DEBUG
+ SMC37c669_config_mode( TRUE );
+ SMC37c669_dump_registers( );
+ SMC37c669_config_mode( FALSE );
+ SMC37c669_display_device_info( );
+#endif
+ SMC37c669_disable_device( SERIAL_0 );
+ SMC37c669_configure_device(
+ SERIAL_0,
+ COM1_BASE,
+ COM1_IRQ,
+ -1
+ );
+ SMC37c669_enable_device( SERIAL_0 );
+
+ SMC37c669_disable_device( SERIAL_1 );
+ SMC37c669_configure_device(
+ SERIAL_1,
+ COM2_BASE,
+ COM2_IRQ,
+ -1
+ );
+ SMC37c669_enable_device( SERIAL_1 );
+
+ SMC37c669_disable_device( PARALLEL_0 );
+ SMC37c669_configure_device(
+ PARALLEL_0,
+ PARP_BASE,
+ PARP_IRQ,
+ PARP_DRQ
+ );
+ SMC37c669_enable_device( PARALLEL_0 );
+
+ SMC37c669_disable_device( FLOPPY_0 );
+ SMC37c669_configure_device(
+ FLOPPY_0,
+ FDC_BASE,
+ FDC_IRQ,
+ FDC_DRQ
+ );
+ SMC37c669_enable_device( FLOPPY_0 );
+
+ SMC37c669_disable_device( IDE_0 );
+
+#if SMC_DEBUG
+ SMC37c669_config_mode( TRUE );
+ SMC37c669_dump_registers( );
+ SMC37c669_config_mode( FALSE );
+ SMC37c669_display_device_info( );
+#endif
+ }
+ else {
+#if SMC_DEBUG
+ printk( "No SMC37c669 Super I/O Controller found\n" );
+#endif
+ }
+}
diff --git a/arch/alpha/kernel/smc37c93x.c b/arch/alpha/kernel/smc37c93x.c
new file mode 100644
index 000000000..a75998d7e
--- /dev/null
+++ b/arch/alpha/kernel/smc37c93x.c
@@ -0,0 +1,264 @@
+/*
+ * SMC 37C93X initialization code
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+
+#include <asm/hwrpb.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+
+#if 0
+# define DBG_DEVS(args) printk args
+#else
+# define DBG_DEVS(args)
+#endif
+
+#define KB 1024
+#define MB (1024*KB)
+#define GB (1024*MB)
+
+/* device "activate" register contents */
+#define DEVICE_ON 1
+#define DEVICE_OFF 0
+
+/* configuration on/off keys */
+#define CONFIG_ON_KEY 0x55
+#define CONFIG_OFF_KEY 0xaa
+
+/* configuration space device definitions */
+#define FDC 0
+#define IDE1 1
+#define IDE2 2
+#define PARP 3
+#define SER1 4
+#define SER2 5
+#define RTCL 6
+#define KYBD 7
+#define AUXIO 8
+
+/* Chip register offsets from base */
+#define CONFIG_CONTROL 0x02
+#define INDEX_ADDRESS 0x03
+#define LOGICAL_DEVICE_NUMBER 0x07
+#define DEVICE_ID 0x20
+#define DEVICE_REV 0x21
+#define POWER_CONTROL 0x22
+#define POWER_MGMT 0x23
+#define OSC 0x24
+
+#define ACTIVATE 0x30
+#define ADDR_HI 0x60
+#define ADDR_LO 0x61
+#define INTERRUPT_SEL 0x70
+#define INTERRUPT_SEL_2 0x72 /* KYBD/MOUS only */
+#define DMA_CHANNEL_SEL 0x74 /* FDC/PARP only */
+
+#define FDD_MODE_REGISTER 0x90
+#define FDD_OPTION_REGISTER 0x91
+
+/* values that we read back that are expected ... */
+#define VALID_DEVICE_ID 2
+
+/* default device addresses */
+#define KYBD_INTERRUPT 1
+#define MOUS_INTERRUPT 12
+#define COM2_BASE 0x2f8
+#define COM2_INTERRUPT 3
+#define COM1_BASE 0x3f8
+#define COM1_INTERRUPT 4
+#define PARP_BASE 0x3bc
+#define PARP_INTERRUPT 7
+
+#define SMC_DEBUG 0
+
+static unsigned long __init SMCConfigState(unsigned long baseAddr)
+{
+ unsigned char devId;
+ unsigned char devRev;
+
+ unsigned long configPort;
+ unsigned long indexPort;
+ unsigned long dataPort;
+
+ configPort = indexPort = baseAddr;
+ dataPort = configPort + 1;
+
+ outb(CONFIG_ON_KEY, configPort);
+ outb(CONFIG_ON_KEY, configPort);
+ outb(DEVICE_ID, indexPort);
+ devId = inb(dataPort);
+ if ( devId == VALID_DEVICE_ID ) {
+ outb(DEVICE_REV, indexPort);
+ devRev = inb(dataPort);
+ }
+ else {
+ baseAddr = 0;
+ }
+ return baseAddr;
+}
+
+static void __init SMCRunState(unsigned long baseAddr)
+{
+ outb(CONFIG_OFF_KEY, baseAddr);
+}
+
+static unsigned long __init SMCDetectUltraIO(void)
+{
+ unsigned long baseAddr;
+
+ baseAddr = 0x3F0;
+ if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x3F0 ) {
+ return( baseAddr );
+ }
+ baseAddr = 0x370;
+ if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x370 ) {
+ return( baseAddr );
+ }
+ return( ( unsigned long )0 );
+}
+
+static void __init SMCEnableDevice(unsigned long baseAddr,
+ unsigned long device,
+ unsigned long portaddr,
+ unsigned long interrupt)
+{
+ unsigned long indexPort;
+ unsigned long dataPort;
+
+ indexPort = baseAddr;
+ dataPort = baseAddr + 1;
+
+ outb(LOGICAL_DEVICE_NUMBER, indexPort);
+ outb(device, dataPort);
+
+ outb(ADDR_LO, indexPort);
+ outb(( portaddr & 0xFF ), dataPort);
+
+ outb(ADDR_HI, indexPort);
+ outb((portaddr >> 8) & 0xFF, dataPort);
+
+ outb(INTERRUPT_SEL, indexPort);
+ outb(interrupt, dataPort);
+
+ outb(ACTIVATE, indexPort);
+ outb(DEVICE_ON, dataPort);
+}
+
+static void __init SMCEnableKYBD(unsigned long baseAddr)
+{
+ unsigned long indexPort;
+ unsigned long dataPort;
+
+ indexPort = baseAddr;
+ dataPort = baseAddr + 1;
+
+ outb(LOGICAL_DEVICE_NUMBER, indexPort);
+ outb(KYBD, dataPort);
+
+ outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */
+ outb(KYBD_INTERRUPT, dataPort);
+
+ outb(INTERRUPT_SEL_2, indexPort); /* Secondary interrupt select */
+ outb(MOUS_INTERRUPT, dataPort);
+
+ outb(ACTIVATE, indexPort);
+ outb(DEVICE_ON, dataPort);
+}
+
+static void __init SMCEnableFDC(unsigned long baseAddr)
+{
+ unsigned long indexPort;
+ unsigned long dataPort;
+
+ unsigned char oldValue;
+
+ indexPort = baseAddr;
+ dataPort = baseAddr + 1;
+
+ outb(LOGICAL_DEVICE_NUMBER, indexPort);
+ outb(FDC, dataPort);
+
+ outb(FDD_MODE_REGISTER, indexPort);
+ oldValue = inb(dataPort);
+
+ oldValue |= 0x0E; /* Enable burst mode */
+ outb(oldValue, dataPort);
+
+ outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */
+ outb(0x06, dataPort );
+
+ outb(DMA_CHANNEL_SEL, indexPort); /* DMA channel select */
+ outb(0x02, dataPort);
+
+ outb(ACTIVATE, indexPort);
+ outb(DEVICE_ON, dataPort);
+}
+
+#if SMC_DEBUG
+static void __init SMCReportDeviceStatus(unsigned long baseAddr)
+{
+ unsigned long indexPort;
+ unsigned long dataPort;
+ unsigned char currentControl;
+
+ indexPort = baseAddr;
+ dataPort = baseAddr + 1;
+
+ outb(POWER_CONTROL, indexPort);
+ currentControl = inb(dataPort);
+
+ printk(currentControl & (1 << FDC)
+ ? "\t+FDC Enabled\n" : "\t-FDC Disabled\n");
+ printk(currentControl & (1 << IDE1)
+ ? "\t+IDE1 Enabled\n" : "\t-IDE1 Disabled\n");
+ printk(currentControl & (1 << IDE2)
+ ? "\t+IDE2 Enabled\n" : "\t-IDE2 Disabled\n");
+ printk(currentControl & (1 << PARP)
+ ? "\t+PARP Enabled\n" : "\t-PARP Disabled\n");
+ printk(currentControl & (1 << SER1)
+ ? "\t+SER1 Enabled\n" : "\t-SER1 Disabled\n");
+ printk(currentControl & (1 << SER2)
+ ? "\t+SER2 Enabled\n" : "\t-SER2 Disabled\n");
+
+ printk( "\n" );
+}
+#endif
+
+int __init SMC93x_Init(void)
+{
+ unsigned long SMCUltraBase;
+
+ if ((SMCUltraBase = SMCDetectUltraIO()) != 0UL) {
+ printk("SMC FDC37C93X Ultra I/O Controller found @ 0x%lx\n",
+ SMCUltraBase);
+#if SMC_DEBUG
+ SMCReportDeviceStatus(SMCUltraBase);
+#endif
+ SMCEnableDevice(SMCUltraBase, SER1, COM1_BASE, COM1_INTERRUPT);
+ SMCEnableDevice(SMCUltraBase, SER2, COM2_BASE, COM2_INTERRUPT);
+ SMCEnableDevice(SMCUltraBase, PARP, PARP_BASE, PARP_INTERRUPT);
+ /* On PC164, IDE on the SMC is not enabled;
+ CMD646 (PCI) on MB */
+ SMCEnableKYBD(SMCUltraBase);
+ SMCEnableFDC(SMCUltraBase);
+#if SMC_DEBUG
+ SMCReportDeviceStatus(SMCUltraBase);
+#endif
+ SMCRunState(SMCUltraBase);
+ return 1;
+ }
+ else {
+#if SMC_DEBUG
+ printk("No SMC FDC37C93X Ultra I/O Controller found\n");
+#endif
+ return 0;
+ }
+}
diff --git a/arch/alpha/kernel/t2.c b/arch/alpha/kernel/t2.c
new file mode 100644
index 000000000..398aaebb5
--- /dev/null
+++ b/arch/alpha/kernel/t2.c
@@ -0,0 +1,599 @@
+/*
+ * Code common to all T2 chips.
+ *
+ * Written by Jay A Estabrook (jestabro@amt.tay1.dec.com).
+ * December 1996.
+ *
+ * based on CIA code by David A Rusling (david.rusling@reo.mts.dec.com)
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/hwrpb.h>
+#include <asm/ptrace.h>
+#include <asm/mmu_context.h>
+
+/* NOTE: Herein are back-to-back mb insns. They are magic.
+ A plausable explanation is that the i/o controler does not properly
+ handle the system transaction. Another involves timing. Ho hum. */
+
+extern struct hwrpb_struct *hwrpb;
+extern asmlinkage void wrmces(unsigned long mces);
+extern asmlinkage unsigned long whami(void);
+extern int alpha_sys_type;
+
+#define CPUID whami()
+
+
+/*
+ * Machine check reasons. Defined according to PALcode sources
+ * (osf.h and platform.h).
+ */
+#define MCHK_K_TPERR 0x0080
+#define MCHK_K_TCPERR 0x0082
+#define MCHK_K_HERR 0x0084
+#define MCHK_K_ECC_C 0x0086
+#define MCHK_K_ECC_NC 0x0088
+#define MCHK_K_OS_BUGCHECK 0x008A
+#define MCHK_K_PAL_BUGCHECK 0x0090
+
+/*
+ * BIOS32-style PCI interface:
+ */
+
+#ifdef DEBUG_CONF
+# define DBG(args) printk args
+#else
+# define DBG(args)
+#endif
+
+#ifdef DEBUG_MCHECK
+# define DBGMC(args) printk args
+#else
+# define DBGMC(args)
+#endif
+
+#define vulp volatile unsigned long *
+#define vuip volatile unsigned int *
+
+static volatile unsigned int T2_mcheck_expected = 0;
+static volatile unsigned int T2_mcheck_taken = 0;
+static unsigned long T2_jd;
+
+
+/*
+ * Given a bus, device, and function number, compute resulting
+ * configuration space address and setup the T2_HAXR2 register
+ * accordingly. It is therefore not safe to have concurrent
+ * invocations to configuration space access routines, but there
+ * really shouldn't be any need for this.
+ *
+ * Type 0:
+ *
+ * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1
+ * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|0|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * 31:11 Device select bit.
+ * 10:8 Function number
+ * 7:2 Register number
+ *
+ * Type 1:
+ *
+ * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1
+ * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * 31:24 reserved
+ * 23:16 bus number (8 bits = 128 possible buses)
+ * 15:11 Device number (5 bits)
+ * 10:8 function number
+ * 7:2 register number
+ *
+ * Notes:
+ * The function number selects which function of a multi-function device
+ * (e.g., scsi and ethernet).
+ *
+ * The register selects a DWORD (32 bit) register offset. Hence it
+ * doesn't get shifted by 2 bits as we want to "drop" the bottom two
+ * bits.
+ */
+static int mk_conf_addr(unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned long *pci_addr,
+ unsigned char *type1)
+{
+ unsigned long addr;
+
+ DBG(("mk_conf_addr(bus=%d, dfn=0x%x, where=0x%x,"
+ " addr=0x%lx, type1=0x%x)\n",
+ bus, device_fn, where, pci_addr, type1));
+
+ if (bus == 0) {
+ int device = device_fn >> 3;
+
+ /* type 0 configuration cycle: */
+
+ if (device > 8) {
+ DBG(("mk_conf_addr: device (%d)>20, returning -1\n",
+ device));
+ return -1;
+ }
+
+ *type1 = 0;
+ addr = (0x0800L << device) | ((device_fn & 7) << 8) | (where);
+ } else {
+ /* type 1 configuration cycle: */
+ *type1 = 1;
+ addr = (bus << 16) | (device_fn << 8) | (where);
+ }
+ *pci_addr = addr;
+ DBG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
+ return 0;
+}
+
+
+static unsigned int conf_read(unsigned long addr, unsigned char type1)
+{
+ unsigned long flags;
+ unsigned int stat0, value;
+ unsigned int t2_cfg = 0; /* to keep gcc quiet */
+
+ save_flags(flags); /* avoid getting hit by machine check */
+ cli();
+
+ DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1));
+
+#if 0
+ /* reset status register to avoid losing errors: */
+ stat0 = *(vuip)T2_IOCSR;
+ *(vuip)T2_IOCSR = stat0;
+ mb();
+ DBG(("conf_read: T2 IOCSR was 0x%x\n", stat0));
+ /* if Type1 access, must set T2 CFG */
+ if (type1) {
+ t2_cfg = *(vuip)T2_IOC_CFG;
+ mb();
+ *(vuip)T2_IOC_CFG = t2_cfg | 1;
+ DBG(("conf_read: TYPE1 access\n"));
+ }
+ mb();
+ draina();
+#endif
+
+ T2_mcheck_expected = 1;
+ T2_mcheck_taken = 0;
+ mb();
+ /* access configuration space: */
+ value = *(vuip)addr;
+ mb();
+ mb(); /* magic */
+ if (T2_mcheck_taken) {
+ T2_mcheck_taken = 0;
+ value = 0xffffffffU;
+ mb();
+ }
+ T2_mcheck_expected = 0;
+ mb();
+
+#if 0
+ /* if Type1 access, must reset IOC CFG so normal IO space ops work */
+ if (type1) {
+ *(vuip)T2_IOC_CFG = t2_cfg & ~1;
+ mb();
+ }
+#endif
+ DBG(("conf_read(): finished\n"));
+
+ restore_flags(flags);
+ return value;
+}
+
+
+static void conf_write(unsigned long addr, unsigned int value,
+ unsigned char type1)
+{
+ unsigned long flags;
+ unsigned int stat0;
+ unsigned int t2_cfg = 0; /* to keep gcc quiet */
+
+ save_flags(flags); /* avoid getting hit by machine check */
+ cli();
+
+#if 0
+ /* reset status register to avoid losing errors: */
+ stat0 = *(vuip)T2_IOCSR;
+ *(vuip)T2_IOCSR = stat0;
+ mb();
+ DBG(("conf_write: T2 ERR was 0x%x\n", stat0));
+ /* if Type1 access, must set T2 CFG */
+ if (type1) {
+ t2_cfg = *(vuip)T2_IOC_CFG;
+ mb();
+ *(vuip)T2_IOC_CFG = t2_cfg | 1;
+ DBG(("conf_write: TYPE1 access\n"));
+ }
+ draina();
+#endif
+
+ T2_mcheck_expected = 1;
+ mb();
+ /* access configuration space: */
+ *(vuip)addr = value;
+ mb();
+ mb(); /* magic */
+ T2_mcheck_expected = 0;
+ mb();
+
+#if 0
+ /* if Type1 access, must reset IOC CFG so normal IO space ops work */
+ if (type1) {
+ *(vuip)T2_IOC_CFG = t2_cfg & ~1;
+ mb();
+ }
+#endif
+ DBG(("conf_write(): finished\n"));
+ restore_flags(flags);
+}
+
+
+int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned char *value)
+{
+ unsigned long addr = T2_CONF;
+ unsigned long pci_addr;
+ unsigned char type1;
+
+ *value = 0xff;
+
+ if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ addr |= (pci_addr << 5) + 0x00;
+
+ *value = conf_read(addr, type1) >> ((where & 3) * 8);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_read_config_word (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned short *value)
+{
+ unsigned long addr = T2_CONF;
+ unsigned long pci_addr;
+ unsigned char type1;
+
+ *value = 0xffff;
+
+ if (where & 0x1) {
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ }
+
+ if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) {
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ addr |= (pci_addr << 5) + 0x08;
+
+ *value = conf_read(addr, type1) >> ((where & 3) * 8);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned int *value)
+{
+ unsigned long addr = T2_CONF;
+ unsigned long pci_addr;
+ unsigned char type1;
+
+ *value = 0xffffffff;
+ if (where & 0x3) {
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ }
+
+ if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) {
+ return PCIBIOS_SUCCESSFUL;
+ }
+ addr |= (pci_addr << 5) + 0x18;
+ *value = conf_read(addr, type1);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned char value)
+{
+ unsigned long addr = T2_CONF;
+ unsigned long pci_addr;
+ unsigned char type1;
+
+ if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
+ return PCIBIOS_SUCCESSFUL;
+ }
+ addr |= (pci_addr << 5) + 0x00;
+ conf_write(addr, value << ((where & 3) * 8), type1);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_write_config_word (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned short value)
+{
+ unsigned long addr = T2_CONF;
+ unsigned long pci_addr;
+ unsigned char type1;
+
+ if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
+ return PCIBIOS_SUCCESSFUL;
+ }
+ addr |= (pci_addr << 5) + 0x08;
+ conf_write(addr, value << ((where & 3) * 8), type1);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned int value)
+{
+ unsigned long addr = T2_CONF;
+ unsigned long pci_addr;
+ unsigned char type1;
+
+ if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
+ return PCIBIOS_SUCCESSFUL;
+ }
+ addr |= (pci_addr << 5) + 0x18;
+ conf_write(addr, value << ((where & 3) * 8), type1);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+unsigned long t2_init(unsigned long mem_start, unsigned long mem_end)
+{
+ unsigned int t2_err;
+ struct percpu_struct *cpu;
+ int i;
+
+#if 0
+ /*
+ * Set up error reporting.
+ */
+ t2_err = *(vuip)T2_IOCSR ;
+ t2_err |= (0x1 << 7) ; /* master abort */
+ *(vuip)T2_IOC_T2_ERR = t2_err ;
+ mb() ;
+#endif
+
+ printk("t2_init: HBASE was 0x%lx\n", *(vulp)T2_HBASE);
+#if 0
+ printk("t2_init: WBASE1=0x%lx WMASK1=0x%lx TBASE1=0x%lx\n",
+ *(vulp)T2_WBASE1,
+ *(vulp)T2_WMASK1,
+ *(vulp)T2_TBASE1);
+ printk("t2_init: WBASE2=0x%lx WMASK2=0x%lx TBASE2=0x%lx\n",
+ *(vulp)T2_WBASE2,
+ *(vulp)T2_WMASK2,
+ *(vulp)T2_TBASE2);
+#endif
+
+ /*
+ * Set up the PCI->physical memory translation windows.
+ * For now, window 2 is disabled. In the future, we may
+ * want to use it to do scatter/gather DMA. Window 1
+ * goes at 1 GB and is 1 GB large.
+ */
+
+ /* WARNING!! must correspond to the DMA_WIN params!!! */
+ *(vuip)T2_WBASE1 = 0x400807ffU;
+ *(vuip)T2_WMASK1 = 0x3ff00000U;
+ *(vuip)T2_TBASE1 = 0;
+
+ *(vuip)T2_WBASE2 = 0x0;
+
+ *(vuip)T2_HBASE = 0x0;
+
+ /*
+ * check ASN in HWRPB for validity, report if bad
+ */
+ if (hwrpb->max_asn != MAX_ASN) {
+ printk("T2_init: max ASN from HWRPB is bad (0x%lx)\n",
+ hwrpb->max_asn);
+ hwrpb->max_asn = MAX_ASN;
+ }
+
+ /*
+ * Finally, clear the T2_HAE_3 register, which gets used
+ * for PCI Config Space accesses. That is the way
+ * we want to use it, and we do not want to depend on
+ * what ARC or SRM might have left behind...
+ */
+ {
+#if 0
+ printk("T2_init: HAE1 was 0x%lx\n", *(vulp)T2_HAE_1);
+ printk("T2_init: HAE2 was 0x%lx\n", *(vulp)T2_HAE_2);
+ printk("T2_init: HAE3 was 0x%lx\n", *(vulp)T2_HAE_3);
+ printk("T2_init: HAE4 was 0x%lx\n", *(vulp)T2_HAE_4);
+#endif
+#if 0
+ *(vuip)T2_HAE_1 = 0; mb();
+ *(vuip)T2_HAE_2 = 0; mb();
+ *(vuip)T2_HAE_3 = 0; mb();
+ *(vuip)T2_HAE_4 = 0; mb();
+#endif
+ }
+
+#if 1
+ if (hwrpb->nr_processors > 1) {
+ printk("T2_init: nr_processors 0x%lx\n",
+ hwrpb->nr_processors);
+ printk("T2_init: processor_size 0x%lx\n",
+ hwrpb->processor_size);
+ printk("T2_init: processor_offset 0x%lx\n",
+ hwrpb->processor_offset);
+
+ cpu = (struct percpu_struct *)
+ ((char*)hwrpb + hwrpb->processor_offset);
+
+ for (i = 0; i < hwrpb->nr_processors; i++ ) {
+ printk("T2_init: CPU 0x%x: flags 0x%lx type 0x%lx\n",
+ i, cpu->flags, cpu->type);
+ cpu = (struct percpu_struct *)
+ ((char *)cpu + hwrpb->processor_size);
+ }
+ }
+#endif
+
+ return mem_start;
+}
+
+#define SIC_SEIC (1UL << 33) /* System Event Clear */
+
+static struct sable_cpu_csr *sable_cpu_regs[4] = {
+ (struct sable_cpu_csr *)CPU0_BASE,
+ (struct sable_cpu_csr *)CPU1_BASE,
+ (struct sable_cpu_csr *)CPU2_BASE,
+ (struct sable_cpu_csr *)CPU3_BASE,
+};
+
+int t2_clear_errors(void)
+{
+ DBGMC(("???????? t2_clear_errors\n"));
+
+ sable_cpu_regs[CPUID]->sic &= ~SIC_SEIC;
+
+ /*
+ * clear cpu errors
+ */
+ sable_cpu_regs[CPUID]->bcce |= sable_cpu_regs[CPUID]->bcce;
+ sable_cpu_regs[CPUID]->cbe |= sable_cpu_regs[CPUID]->cbe;
+ sable_cpu_regs[CPUID]->bcue |= sable_cpu_regs[CPUID]->bcue;
+ sable_cpu_regs[CPUID]->dter |= sable_cpu_regs[CPUID]->dter;
+
+ *(vulp)T2_CERR1 |= *(vulp)T2_CERR1;
+ *(vulp)T2_PERR1 |= *(vulp)T2_PERR1;
+
+ mb();
+ mb(); /* magic */
+ return 0;
+}
+
+void t2_machine_check(unsigned long vector, unsigned long la_ptr,
+ struct pt_regs * regs)
+{
+ struct el_t2_logout_header *mchk_header;
+ struct el_t2_procdata_mcheck *mchk_procdata;
+ struct el_t2_sysdata_mcheck *mchk_sysdata;
+ unsigned long * ptr;
+ const char * reason;
+ char buf[128];
+ long i;
+
+ DBGMC(("t2_machine_check: vector=0x%lx la_ptr=0x%lx\n",
+ vector, la_ptr));
+
+ mchk_header = (struct el_t2_logout_header *)la_ptr;
+
+ DBGMC(("t2_machine_check: susoffset=0x%lx procoffset=0x%lx\n",
+ mchk_header->elfl_sysoffset, mchk_header->elfl_procoffset));
+
+ mchk_sysdata = (struct el_t2_sysdata_mcheck *)
+ (la_ptr + mchk_header->elfl_sysoffset);
+ mchk_procdata = (struct el_t2_procdata_mcheck *)
+ (la_ptr + mchk_header->elfl_procoffset - sizeof(unsigned long)*32);
+
+ DBGMC((" pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
+ regs->pc, mchk_header->elfl_size, mchk_header->elfl_procoffset,
+ mchk_header->elfl_sysoffset));
+ DBGMC(("t2_machine_check: expected %d\n", T2_mcheck_expected));
+
+#ifdef DEBUG_DUMP
+ {
+ unsigned long *ptr;
+ int i;
+
+ ptr = (unsigned long *)la_ptr;
+ for (i = 0; i < mchk_header->elfl_size/sizeof(long); i += 2) {
+ printk(" +%lx %lx %lx\n", i*sizeof(long),
+ ptr[i], ptr[i+1]);
+ }
+ }
+#endif /* DEBUG_DUMP */
+
+ /*
+ * Check if machine check is due to a badaddr() and if so,
+ * ignore the machine check.
+ */
+ mb();
+ mb(); /* magic */
+ if (T2_mcheck_expected/* && (mchk_sysdata->epic_dcsr && 0x0c00UL)*/) {
+ DBGMC(("T2 machine check expected\n"));
+ T2_mcheck_taken = 1;
+ t2_clear_errors();
+ T2_mcheck_expected = 0;
+ mb();
+ mb(); /* magic */
+ wrmces(rdmces()|1);/* ??? */
+ draina();
+ return;
+ }
+
+ switch ((unsigned int) mchk_header->elfl_error_type) {
+ case MCHK_K_TPERR: reason = "tag parity error"; break;
+ case MCHK_K_TCPERR: reason = "tag control parity error"; break;
+ case MCHK_K_HERR: reason = "generic hard error"; break;
+ case MCHK_K_ECC_C: reason = "correctable ECC error"; break;
+ case MCHK_K_ECC_NC: reason = "uncorrectable ECC error"; break;
+ case MCHK_K_OS_BUGCHECK: reason = "OS-specific PAL bugcheck"; break;
+ case MCHK_K_PAL_BUGCHECK: reason = "callsys in kernel mode"; break;
+ case 0x96: reason = "i-cache read retryable error"; break;
+ case 0x98: reason = "processor detected hard error"; break;
+
+ /* System specific (these are for Alcor, at least): */
+ case 0x203: reason = "system detected uncorrectable ECC error"; break;
+ case 0x205: reason = "parity error detected by T2"; break;
+ case 0x207: reason = "non-existent memory error"; break;
+ case 0x209: reason = "PCI SERR detected"; break;
+ case 0x20b: reason = "PCI data parity error detected"; break;
+ case 0x20d: reason = "PCI address parity error detected"; break;
+ case 0x20f: reason = "PCI master abort error"; break;
+ case 0x211: reason = "PCI target abort error"; break;
+ case 0x213: reason = "scatter/gather PTE invalid error"; break;
+ case 0x215: reason = "flash ROM write error"; break;
+ case 0x217: reason = "IOA timeout detected"; break;
+ case 0x219: reason = "IOCHK#, EISA add-in board parity or other catastrophic error"; break;
+ case 0x21b: reason = "EISA fail-safe timer timeout"; break;
+ case 0x21d: reason = "EISA bus time-out"; break;
+ case 0x21f: reason = "EISA software generated NMI"; break;
+ case 0x221: reason = "unexpected ev5 IRQ[3] interrupt"; break;
+ default:
+ sprintf(buf, "reason for machine-check unknown (0x%x)",
+ (unsigned int) mchk_header->elfl_error_type);
+ reason = buf;
+ break;
+ }
+ wrmces(rdmces()|1); /* reset machine check pending flag */
+ mb();
+
+ printk(KERN_CRIT " T2 machine check: %s%s\n",
+ reason, mchk_header->elfl_retry ? " (retryable)" : "");
+
+ /* dump the the logout area to give all info: */
+
+ ptr = (unsigned long *)la_ptr;
+ for (i = 0; i < mchk_header->elfl_size / sizeof(long); i += 2) {
+ printk(KERN_CRIT " +%8lx %016lx %016lx\n",
+ i*sizeof(long), ptr[i], ptr[i+1]);
+ }
+}
diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c
index 14a8e2010..42790d3aa 100644
--- a/arch/alpha/kernel/traps.c
+++ b/arch/alpha/kernel/traps.c
@@ -105,14 +105,24 @@ void die_if_kernel(char * str, struct pt_regs *regs, long err,
do_exit(SIGSEGV);
}
+#ifndef CONFIG_MATHEMU
+static long dummy_alpha_fp_emul_imprecise(struct pt_regs *r, unsigned long wm)
+{
+ return 0;
+}
+
+long (*alpha_fp_emul_imprecise)(struct pt_regs *regs, unsigned long writemask)
+ = dummy_alpha_fp_emul_imprecise;
+#else
+long alpha_fp_emul_imprecise(struct pt_regs *regs, unsigned long writemask);
+#endif
+
asmlinkage void do_entArith(unsigned long summary, unsigned long write_mask,
unsigned long a2, unsigned long a3,
unsigned long a4, unsigned long a5,
struct pt_regs regs)
{
if ((summary & 1)) {
- extern long alpha_fp_emul_imprecise (struct pt_regs * regs,
- unsigned long write_mask);
/*
* Software-completion summary bit is set, so try to
* emulate the instruction.
@@ -863,9 +873,9 @@ asmlinkage long alpha_ni_syscall(unsigned long a0, unsigned long a1,
unsigned long a4, unsigned long a5,
struct pt_regs regs)
{
- /* Only report OSF system calls. */
- if (regs.r0 != 112 && regs.r0 < 300)
- printk("<sc %ld(%lx,%lx,%lx)>", regs.r0, a0, a1, a2);
+ /* We only get here for OSF system calls, minus #112;
+ the rest go to sys_ni_syscall. */
+ printk("<sc %ld(%lx,%lx,%lx)>", regs.r0, a0, a1, a2);
return -ENOSYS;
}