diff options
Diffstat (limited to 'arch/alpha/kernel')
-rw-r--r-- | arch/alpha/kernel/Makefile | 26 | ||||
-rw-r--r-- | arch/alpha/kernel/alpha_ksyms.c | 36 | ||||
-rw-r--r-- | arch/alpha/kernel/apecs.c | 83 | ||||
-rw-r--r-- | arch/alpha/kernel/bios32.c | 1277 | ||||
-rw-r--r-- | arch/alpha/kernel/cia.c | 302 | ||||
-rw-r--r-- | arch/alpha/kernel/entry.S | 61 | ||||
-rw-r--r-- | arch/alpha/kernel/fpreg.c | 104 | ||||
-rw-r--r-- | arch/alpha/kernel/head.S | 60 | ||||
-rw-r--r-- | arch/alpha/kernel/irq.c | 969 | ||||
-rw-r--r-- | arch/alpha/kernel/lca.c | 207 | ||||
-rw-r--r-- | arch/alpha/kernel/osf_sys.c | 68 | ||||
-rw-r--r-- | arch/alpha/kernel/process.c | 42 | ||||
-rw-r--r-- | arch/alpha/kernel/pyxis.c | 557 | ||||
-rw-r--r-- | arch/alpha/kernel/setup.c | 148 | ||||
-rw-r--r-- | arch/alpha/kernel/signal.c | 2 | ||||
-rw-r--r-- | arch/alpha/kernel/smc37c669.c | 2583 | ||||
-rw-r--r-- | arch/alpha/kernel/smc37c93x.c | 264 | ||||
-rw-r--r-- | arch/alpha/kernel/t2.c | 599 | ||||
-rw-r--r-- | arch/alpha/kernel/traps.c | 20 |
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, ®s); - return; - case 2: - machine_check(vector, la_ptr, ®s); - return; - case 3: + case 0: + printk("Interprocessor interrupt? You must be kidding\n"); + break; + case 1: + handle_irq(RTC_IRQ, ®s); + return; + case 2: + machine_check(vector, la_ptr, ®s); + return; + case 3: #if defined(CONFIG_ALPHA_JENSEN) || defined(CONFIG_ALPHA_NONAME) || \ defined(CONFIG_ALPHA_P2K) || defined(CONFIG_ALPHA_SRM) - srm_device_interrupt(vector, ®s); -#elif NR_IRQS == 48 - alcor_and_xlt_device_interrupt(vector, ®s); -#elif NR_IRQS == 33 - cabriolet_and_eb66p_device_interrupt(vector, ®s); + srm_device_interrupt(vector, ®s); +#elif defined(CONFIG_ALPHA_MIATA) || defined(CONFIG_ALPHA_SX164) + miata_device_interrupt(vector, ®s); +#elif defined(CONFIG_ALPHA_NORITAKE) + noritake_device_interrupt(vector, ®s); +#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) + alcor_and_xlt_device_interrupt(vector, ®s); +#elif defined(CONFIG_ALPHA_RUFFIAN) + ruffian_device_interrupt(vector, ®s); #elif defined(CONFIG_ALPHA_MIKASA) - mikasa_device_interrupt(vector, ®s); + mikasa_device_interrupt(vector, ®s); +#elif NR_IRQS == 33 + cabriolet_and_eb66p_device_interrupt(vector, ®s); #elif NR_IRQS == 32 - eb66_and_eb64p_device_interrupt(vector, ®s); + eb66_and_eb64p_device_interrupt(vector, ®s); #elif NR_IRQS == 16 - isa_device_interrupt(vector, ®s); + isa_device_interrupt(vector, ®s); #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; } |