From e3cae900c37a51b6fa422a88b90ae4c0e46e2b5a Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 23 Nov 2007 15:11:45 -0500 Subject: [PATCH] Import 2.0.34pre15 --- Documentation/Configure.help | 37 +- Documentation/rtc.txt | 29 + arch/alpha/Makefile | 18 + arch/alpha/boot/Makefile | 18 +- arch/alpha/boot/bootp.c | 239 +++ arch/alpha/config.in | 95 +- arch/alpha/defconfig | 4 + arch/alpha/kernel/Makefile | 7 +- arch/alpha/kernel/apecs.c | 112 +- arch/alpha/kernel/bios32.c | 1380 ++++++++++++---- arch/alpha/kernel/cia.c | 389 +++-- arch/alpha/kernel/entry.S | 170 +- arch/alpha/kernel/head.S | 44 + arch/alpha/kernel/irq.c | 620 ++++++- arch/alpha/kernel/lca.c | 112 +- arch/alpha/kernel/process.c | 39 +- arch/alpha/kernel/pyxis.c | 670 ++++++++ arch/alpha/kernel/setup.c | 197 ++- arch/alpha/kernel/signal.c | 3 + arch/alpha/kernel/smc.c | 2842 +++++++++++++++++++++++++++++++++ arch/alpha/kernel/t2.c | 654 ++++++++ arch/alpha/kernel/traps.c | 6 +- arch/alpha/math-emu/fp-emul.c | 6 +- arch/alpha/mm/init.c | 25 +- arch/i386/kernel/entry.S | 2 +- arch/i386/kernel/ptrace.c | 6 + arch/i386/kernel/smp.c | 2 +- drivers/block/genhd.c | 1 + drivers/block/ide.c | 25 +- drivers/block/rd.c | 39 +- drivers/char/Config.in | 3 + drivers/char/Makefile | 8 + drivers/char/h8.c | 1272 +++++++++++++++ drivers/char/h8.h | 250 +++ drivers/char/mem.c | 2 +- drivers/char/misc.c | 3 + drivers/char/rtc.c | 132 +- drivers/char/selection.h | 52 +- drivers/char/tga.c | 49 +- drivers/char/tty_io.c | 7 +- drivers/net/3c509.c | 4 +- drivers/net/3c59x.c | 146 +- drivers/net/auto_irq.c | 10 +- drivers/net/lance.c | 36 +- drivers/net/ne.c | 2 +- drivers/net/ppp.c | 12 +- drivers/pci/pci.c | 36 +- drivers/scsi/BusLogic.c | 15 +- drivers/scsi/Config.in | 3 + drivers/scsi/NCR5380.c | 12 +- drivers/scsi/NCR5380.h | 29 +- drivers/scsi/README.BusLogic | 6 +- drivers/scsi/README.ppa | 110 +- drivers/scsi/aic7xxx.c | 352 ++-- drivers/scsi/dtc.c | 16 +- drivers/scsi/ncr53c8xx.c | 41 +- drivers/scsi/ncr53c8xx.h | 2 +- drivers/scsi/ppa.c | 1932 +++++++++++++++++----- drivers/scsi/ppa.h | 201 ++- drivers/scsi/qlogicisp.c | 12 +- drivers/scsi/scsi.c | 1 + drivers/scsi/scsi_ioctl.c | 4 +- drivers/scsi/scsi_syms.c | 2 + drivers/scsi/sg.c | 9 +- fs/Makefile | 8 + fs/binfmt_elf.c | 830 +++++----- fs/binfmt_em86.c | 131 ++ fs/buffer.c | 2 + fs/dquot.c | 3 + fs/ext2/namei.c | 1 + fs/fat/dir.c | 15 - fs/isofs/inode.c | 36 +- fs/select.c | 81 +- fs/super.c | 13 +- include/asm-alpha/a.out.h | 3 +- include/asm-alpha/apecs.h | 28 +- include/asm-alpha/cia.h | 271 +++- include/asm-alpha/dma.h | 14 +- include/asm-alpha/floppy.h | 6 +- include/asm-alpha/hwrpb.h | 32 +- include/asm-alpha/io.h | 39 +- include/asm-alpha/irq.h | 37 +- include/asm-alpha/lca.h | 44 +- include/asm-alpha/pal.h | 3 +- include/asm-alpha/processor.h | 10 +- include/asm-alpha/ptrace.h | 4 + include/asm-alpha/pyxis.h | 742 +++++++++ include/asm-alpha/shmparam.h | 10 +- include/asm-alpha/system.h | 2 + include/asm-alpha/t2.h | 654 ++++++++ include/asm-i386/processor.h | 2 + include/asm-m68k/processor.h | 2 + include/asm-mips/processor.h | 2 + include/asm-ppc/processor.h | 2 + include/asm-sparc/processor.h | 2 + include/linux/fs.h | 2 +- include/linux/genhd.h | 3 +- include/linux/ioport.h | 2 +- include/linux/lists.h | 24 +- include/linux/mc146818rtc.h | 2 + include/linux/personality.h | 4 + include/linux/swap.h | 5 +- include/scsi/scsi_ioctl.h | 1 + init/main.c | 2 +- ipc/shm.c | 4 +- kernel/exit.c | 11 +- mm/mmap.c | 15 +- mm/mremap.c | 11 +- mm/swap_state.c | 20 +- mm/swapfile.c | 15 +- net/ax25/af_ax25.c | 2 +- net/core/sock.c | 5 +- net/ethernet/eth.c | 4 + net/ipv4/af_inet.c | 2 - net/ipv4/rarp.c | 4 +- net/ipv4/tcp.c | 5 +- net/ipv4/tcp_output.c | 26 +- net/netrom/af_netrom.c | 2 +- net/netsyms.c | 1 + net/unix/af_unix.c | 4 + 120 files changed, 13723 insertions(+), 2044 deletions(-) create mode 100644 arch/alpha/boot/bootp.c create mode 100644 arch/alpha/kernel/pyxis.c create mode 100644 arch/alpha/kernel/smc.c create mode 100644 arch/alpha/kernel/t2.c create mode 100644 drivers/char/h8.c create mode 100644 drivers/char/h8.h create mode 100644 fs/binfmt_em86.c create mode 100644 include/asm-alpha/pyxis.h create mode 100644 include/asm-alpha/t2.h diff --git a/Documentation/Configure.help b/Documentation/Configure.help index 10cda3dbe579..7b274e3dd7f1 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -465,31 +465,9 @@ CONFIG_SYN_COOKIES this option turned on the TCP/IP stack will use a cryptographic challenge protocol known as SYN cookies to enable legitimate users to continue to connect, even when your machine is under attack. - The RST_COOKIES option provides an alternative method to accomplish - the same end. SYN cookies use less space than RST cookies, - but have a small probability of introducing an non timed-out - failure to connect in the remote TCP. You can use both options - simultatenously. If you are SYN flooded, the source address - reported by the kernel is likely to have been forged by the - attacker. The source address is reported as an aid in tracing the - packets to their actual source. - -SYN flood protection -CONFIG_RST_COOKIES - Normal TCP/IP networking is open to an attack known as SYN flooding. - This attack prevents legitimate users from being able to connect to - your computer and requires very little work for the attacker. - SYN cookies provide protection against this type of attack. With - this option turned on the TCP/IP stack will use a cryptographic - challenge protocol known as RST cookies to enable legitimate users - to continue to connect, even when your machine is under attack. - The SYN_COOKIES option provides an alternative method to accomplish - the same end. RST cookies use more space than SYN cookies on your - machine, but never increase the probability of a frozen connection - in a remote TCP. You can use both options simultatenously. If you - are SYN flooded, the source address reported by the kernel is likely - to have been forged by the attacker. The source address is reported - as an aid in tracing the packets to their actual source. + If you are SYN flooded, the source address reported by the kernel is + likely to have been forged by the attacker. The source address is + reported as an aid in tracing the packets to their actual source. Sun floppy controller support CONFIG_BLK_DEV_SUNFD @@ -1868,6 +1846,15 @@ CONFIG_SCSI_PPA the SCSI version of the ZIP drive: it will be supported automatically if you enabled the generic "SCSI disk support", above. +IOMEGA ZIP drive - Buggy EPP chipset support +CONFIG_SCSI_PPA_HAVE_PEDANTIC + Contacts with the Iomega driver development team indicate there are + a few reputably bad EPP implementations in existance. The following + mainboard chipsets will probably require the PEDANTIC option to + reliably transfer data: + Winbond xxx837 + National Semiconductor PC87306 (early revisions) + Network device support? CONFIG_NETDEVICES You can say N here in case you don't intend to connect to any other diff --git a/Documentation/rtc.txt b/Documentation/rtc.txt index e290b4177750..927ad6dca650 100644 --- a/Documentation/rtc.txt +++ b/Documentation/rtc.txt @@ -65,6 +65,35 @@ that will be using this driver. Paul Gortmaker +Update in version 1.09 +====================== + +Epoch handling is added. Epoch is the number which should be added to the +value of the clock's year register to get the actual year. The default +Linux epoch is therefore 1900. + +Epochs are especially useful on Alphas where different operating systems +use different epochs, and Linux wants to be compatible with all of them. +They may eventually be helpful on Intel architecture as well, where a +value of an RTC register cannot exceed 99 due to BCD tradition originated +from DOS. + +When the epoch is set to 1900, the new code behaves exactly like the old +one with respect to the BCD wrapping: values 00 - 69 are treated as if +they were 100 - 169. That means that after the 2000th year epoch 1900 +will be the same as epoch 2000. + +Two new ioctls are introduced to read and set the epoch, RTC_EPOCH_READ +and RTC_EPOCH_SET. They can be used in exactly the same manner as +RTC_IRQP_READ and RTC_IRQP_SET, so they are not included in the example +program below. + +On Alphas an epoch autodetection is performed. Currently 3 epochs +are recognised: Linux (1900), Digital UNIX (1952) and Windows NT (1980). + +Nikita Schmidt + + -------------------- 8< ---------------- 8< ----------------------------- /* diff --git a/arch/alpha/Makefile b/arch/alpha/Makefile index a234e9453662..2467ba8ebb90 100644 --- a/arch/alpha/Makefile +++ b/arch/alpha/Makefile @@ -26,6 +26,21 @@ endif CFLAGS := $(CFLAGS) -mno-fp-regs +# determine if we can use the BWX instructions with GAS +$(shell rm -f /tmp/GAS_VER) +#$(shell $(AS) --version >& /tmp/GAS_VER) +$(shell $(AS) --version > /tmp/GAS_VER 2>&1) +OLD_GAS := $(shell if cat /tmp/GAS_VER | grep 'version 2.7' > /dev/null; then echo yes; else echo no; fi) + +ifneq ($(OLD_GAS),yes) + CFLAGS := $(CFLAGS) -Wa,-m21164a -DBWX_USABLE + +# if PYXIS, then enable use of BWIO space + ifeq ($(CONFIG_ALPHA_PYXIS),y) + CFLAGS := $(CFLAGS) -DBWIO_ENABLED + endif +endif + HEAD := arch/alpha/kernel/head.o SUBDIRS := $(SUBDIRS) arch/alpha/kernel arch/alpha/mm arch/alpha/lib \ @@ -57,3 +72,6 @@ archclean: archdep: @$(MAKEBOOT) dep + +bootpfile: + @$(MAKEBOOT) bootpfile diff --git a/arch/alpha/boot/Makefile b/arch/alpha/boot/Makefile index b3d888a9231f..ee2ecd37952b 100644 --- a/arch/alpha/boot/Makefile +++ b/arch/alpha/boot/Makefile @@ -26,6 +26,7 @@ endif $(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $< OBJECTS = head.o main.o +BPOBJECTS = head.o bootp.o TARGETS = vmlinux.gz tools/objstrip # also needed by aboot & milo VMLINUX = $(TOPDIR)/vmlinux OBJSTRIP = tools/objstrip @@ -44,6 +45,9 @@ bootimage: tools/mkbb tools/lxboot tools/bootlx vmlinux.nh ( cat tools/lxboot tools/bootlx vmlinux.nh ) > bootimage tools/mkbb bootimage tools/lxboot +bootpfile: tools/bootph vmlinux.nh + ( cat tools/bootph vmlinux.nh ) > bootpfile + srmboot: bootdevice bootimage dd if=bootimage of=$(BOOTDEV) bs=512 seek=1 skip=1 tools/mkbb $(BOOTDEV) tools/lxboot @@ -59,6 +63,8 @@ vmlinux.gz: vmlinux # main.o: ksize.h +bootp.o: ksize.h + ksize.h: $(OBJSTRIP) vmlinux.nh echo "#define KERNEL_SIZE `$(OBJSTRIP) -p vmlinux.nh /dev/null`" > $@ @@ -82,6 +88,9 @@ tools/lxboot: $(OBJSTRIP) bootloader tools/bootlx: bootloader $(OBJSTRIP) $(OBJSTRIP) -vb bootloader tools/bootlx +tools/bootph: bootpheader $(OBJSTRIP) + $(OBJSTRIP) -vb bootpheader tools/bootph + $(OBJSTRIP): $(OBJSTRIP).c $(HOSTCC) $(OBJSTRIP).c -o $(OBJSTRIP) @@ -95,8 +104,15 @@ bootloader: $(OBJECTS) -o bootloader && strip bootloader || \ (rm -f bootloader && exit 1) +bootpheader: $(BPOBJECTS) + $(LD) $(LINKFLAGS) \ + $(BPOBJECTS) \ + $(LIBS) \ + -o bootpheader && strip bootpheader || \ + (rm -f bootpheader && exit 1) + clean: rm -f $(TARGETS) bootloader bootimage vmlinux.nh \ - tools/mkbb tools/bootlx tools/lxboot + tools/mkbb tools/bootlx tools/lxboot ksize.h dep: diff --git a/arch/alpha/boot/bootp.c b/arch/alpha/boot/bootp.c new file mode 100644 index 000000000000..53425035713a --- /dev/null +++ b/arch/alpha/boot/bootp.c @@ -0,0 +1,239 @@ +/* + * arch/alpha/boot/bootp.c + * + * Copyright (C) 1997 Jay Estabrook + * + * This file is used for creating a bootp file for the Linux/AXP kernel + * + * based significantly on the arch/alpha/boot/main.c of Linus Torvalds + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "ksize.h" + +extern int vsprintf(char *, const char *, va_list); +extern unsigned long switch_to_osf_pal(unsigned long nr, + struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa, + unsigned long vptb, unsigned long *kstk); + +int printk(const char * fmt, ...) +{ + va_list args; + int i, j, written, remaining, num_nl; + static char buf[1024]; + char * str; + + va_start(args, fmt); + i = vsprintf(buf, fmt, args); + va_end(args); + + /* expand \n into \r\n: */ + + num_nl = 0; + for (j = 0; j < i; ++j) { + if (buf[j] == '\n') + ++num_nl; + } + remaining = i + num_nl; + for (j = i - 1; j >= 0; --j) { + buf[j + num_nl] = buf[j]; + if (buf[j] == '\n') { + --num_nl; + buf[j + num_nl] = '\r'; + } + } + + str = buf; + do { + written = puts(str, remaining); + remaining -= written; + str += written; + } while (remaining > 0); + return i; +} + +#define hwrpb (*INIT_HWRPB) + +/* + * Find a physical address of a virtual object.. + * + * This is easy using the virtual page table address. + */ +struct pcb_struct * find_pa(unsigned long *vptb, struct pcb_struct * pcb) +{ + unsigned long address = (unsigned long) pcb; + unsigned long result; + + result = vptb[address >> 13]; + result >>= 32; + result <<= 13; + result |= address & 0x1fff; + return (struct pcb_struct *) result; +} + +/* + * This function moves into OSF/1 pal-code, and has a temporary + * PCB for that. The kernel proper should replace this PCB with + * the real one as soon as possible. + * + * The page table muckery in here depends on the fact that the boot + * code has the L1 page table identity-map itself in the second PTE + * in the L1 page table. Thus the L1-page is virtually addressable + * itself (through three levels) at virtual address 0x200802000. + * + * As we don't want it there anyway, we also move the L1 self-map + * up as high as we can, so that the last entry in the L1 page table + * maps the page tables. + * + * As a result, the OSF/1 pal-code will instead use a virtual page table + * map located at 0xffffffe00000000. + */ +#define pcb_va ((struct pcb_struct *) 0x20000000) +#define old_vptb (0x0000000200000000UL) +#define new_vptb (0xfffffffe00000000UL) +void pal_init(void) +{ + unsigned long i, rev, sum; + unsigned long *L1, *l; + struct percpu_struct * percpu; + struct pcb_struct * pcb_pa; + + /* Find the level 1 page table and duplicate it in high memory */ + L1 = (unsigned long *) 0x200802000UL; /* (1<<33 | 1<<23 | 1<<13) */ + L1[1023] = L1[1]; + + percpu = (struct percpu_struct *) + (hwrpb.processor_offset + (unsigned long) &hwrpb), + + pcb_va->ksp = 0; + pcb_va->usp = 0; + pcb_va->ptbr = L1[1] >> 32; + pcb_va->asn = 0; + pcb_va->pcc = 0; + pcb_va->unique = 0; + pcb_va->flags = 1; + pcb_pa = find_pa((unsigned long *) old_vptb, pcb_va); + printk("Switching to OSF PAL-code .. "); + /* + * a0 = 2 (OSF) + * a1 = return address, but we give the asm the vaddr of the PCB + * a2 = physical addr of PCB + * a3 = new virtual page table pointer + * a4 = KSP (but we give it 0, asm sets it) + */ + i = switch_to_osf_pal( + 2, + pcb_va, + pcb_pa, + new_vptb, + 0); + if (i) { + printk("failed, code %ld\n", i); + halt(); + } + rev = percpu->pal_revision = percpu->palcode_avail[2]; + + hwrpb.vptb = new_vptb; + + /* update checksum: */ + sum = 0; + for (l = (unsigned long *) &hwrpb; + l < (unsigned long *) &hwrpb.chksum; + ++l) + sum += *l; + hwrpb.chksum = sum; + + printk("Ok (rev %lx)\n", rev); + /* remove the old virtual page-table mapping */ + L1[1] = 0; + flush_tlb_all(); +} + +static inline long load(unsigned long dst, + unsigned long src, + unsigned long count) +{ + extern void * memcpy(void *, const void *, size_t); + + memcpy((void *)dst, (void *)src, count); + return count; +} + +/* + * Start the kernel. + */ +static void runkernel(void) +{ + __asm__ __volatile__( + "bis %1,%1,$30\n\t" + "bis %0,%0,$26\n\t" + "ret ($26)" + : /* no outputs: it doesn't even return */ + : "r" (START_ADDR), + "r" (PAGE_SIZE + INIT_STACK)); +} + +extern char _end; +#define KERNEL_ORIGIN \ + ((((unsigned long)&_end) + 511) & ~511) + +void start_kernel(void) +{ + static long i; + static int nbytes; + static char envval[256]; + char envbuf[256]; + + printk("Linux/AXP bootp loader for Linux " UTS_RELEASE "\n"); + + if (hwrpb.pagesize != 8192) { + printk("Expected 8kB pages, got %ldkB\n", + hwrpb.pagesize >> 10); + return; + } + pal_init(); + + nbytes = dispatch(CCB_GET_ENV, ENV_BOOTED_OSFLAGS, + envbuf, sizeof(envbuf)); + if (nbytes < 0 || nbytes >= sizeof(envbuf)) { + nbytes = 0; + } + + envbuf[nbytes] = '\0'; + memcpy(envval, envbuf, nbytes+1); + printk("Loading the kernel...'%s'\n", envval); + + /* NOTE: *no* callbacks or printouts from here on out!!! */ + + /* + * HACK alert: + * + * assume direct copy will fail due to overlap of virtual source + * and physical destination, so move it way high physical first, + * then move it back to its final resting place... + * + * this way could fail, too, but it works on the platforms *I* have + */ + i = load(START_ADDR+(4*KERNEL_SIZE), KERNEL_ORIGIN, KERNEL_SIZE); + i = load(START_ADDR, START_ADDR+(4*KERNEL_SIZE), KERNEL_SIZE); + + strcpy((char*)ZERO_PAGE, envval); + + runkernel(); + + for (i = 0 ; i < 0x100000000 ; i++) + /* nothing */; + halt(); +} diff --git a/arch/alpha/config.in b/arch/alpha/config.in index 3d6af2841855..05cd3bdbd861 100644 --- a/arch/alpha/config.in +++ b/arch/alpha/config.in @@ -6,8 +6,12 @@ mainmenu_name "Kernel configuration of Linux for Alpha machines" # clear all implied options (don't want default values for those): unset CONFIG_CROSSCOMPILE CONFIG_NATIVE -unset CONFIG_PCI CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS +unset CONFIG_PCI CONFIG_ALPHA_EISA +unset CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS CONFIG_ALPHA_CIA CONFIG_ALPHA_T2 +unset CONFIG_ALPHA_PYXIS +unset CONFIG_ALPHA_EV4 CONFIG_ALPHA_EV5 unset CONFIG_ALPHA_NEED_ROUNDING_EMULATION +unset CONFIG_ALPHA_SRM CONFIG_ALPHA_SRM_SETUP mainmenu_option next_comment comment 'Code maturity level options' @@ -43,49 +47,123 @@ choice 'Alpha system type' \ EB64+ CONFIG_ALPHA_EB64P \ EB164 CONFIG_ALPHA_EB164 \ PC164 CONFIG_ALPHA_PC164 \ + LX164 CONFIG_ALPHA_LX164 \ + SX164 CONFIG_ALPHA_SX164 \ Jensen CONFIG_ALPHA_JENSEN \ Noname CONFIG_ALPHA_NONAME \ + Takara CONFIG_ALPHA_TAKARA \ Mikasa CONFIG_ALPHA_MIKASA \ + Noritake CONFIG_ALPHA_NORITAKE \ Alcor CONFIG_ALPHA_ALCOR \ + Miata CONFIG_ALPHA_MIATA \ + Sable CONFIG_ALPHA_SABLE \ + AlphaBook1 CONFIG_ALPHA_BOOK1 \ + Ruffian CONFIG_ALPHA_RUFFIAN \ Platform2000 CONFIG_ALPHA_P2K" Cabriolet + +if [ "$CONFIG_ALPHA_BOOK1" = "y" ] +then + define_bool CONFIG_ALPHA_NONAME y +fi if [ "$CONFIG_ALPHA_NONAME" = "y" -o "$CONFIG_ALPHA_EB66" = "y" \ -o "$CONFIG_ALPHA_EB66P" = "y" -o "$CONFIG_ALPHA_P2K" = "y" ] then define_bool CONFIG_PCI y + define_bool CONFIG_ALPHA_EV4 y define_bool CONFIG_ALPHA_LCA y fi if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \ - -o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_MIKASA" = "y" \ - -o "$CONFIG_ALPHA_XL" = "y" ] + -o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_XL" = "y" ] then define_bool CONFIG_PCI y + define_bool CONFIG_ALPHA_EV4 y define_bool CONFIG_ALPHA_APECS y fi if [ "$CONFIG_ALPHA_EB164" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \ - -o "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_XLT" = "y" ] + -o "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_XLT" = "y" \ + -o "$CONFIG_ALPHA_TAKARA" = "y" ] then define_bool CONFIG_PCI y define_bool CONFIG_ALPHA_EV5 y define_bool CONFIG_ALPHA_CIA y +fi +if [ "$CONFIG_ALPHA_MIKASA" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" ] +then + bool 'Pinnacle or Primo CPU daughtercard?' CONFIG_ALPHA_PRIMO + if [ "$CONFIG_ALPHA_PRIMO" = "y" ] + then + define_bool CONFIG_ALPHA_EV5 y + define_bool CONFIG_ALPHA_CIA y +else + define_bool CONFIG_ALPHA_EV4 y + define_bool CONFIG_ALPHA_APECS y + fi + define_bool CONFIG_PCI y +fi +if [ "$CONFIG_ALPHA_SABLE" = "y" ] +then + bool 'EV5 or EV56 CPU daughtercard?' CONFIG_ALPHA_GAMMA + if [ "$CONFIG_ALPHA_GAMMA" = "y" ] + then + define_bool CONFIG_ALPHA_EV5 y else + define_bool CONFIG_ALPHA_EV4 y + fi + define_bool CONFIG_PCI y + define_bool CONFIG_ALPHA_T2 y +fi +if [ "$CONFIG_ALPHA_MIATA" = "y" -o "$CONFIG_ALPHA_LX164" = "y" \ + -o "$CONFIG_ALPHA_SX164" = "y" -o "$CONFIG_ALPHA_RUFFIAN" = "y" ] +then + define_bool CONFIG_PCI y + define_bool CONFIG_ALPHA_EV5 y + define_bool CONFIG_ALPHA_PYXIS y +fi +if [ "$CONFIG_ALPHA_JENSEN" = "y" ] +then + define_bool CONFIG_ALPHA_EV4 y +fi +if [ "$CONFIG_ALPHA_EV4" = "y" ] +then # EV45 and older do not support all rounding modes in hw: define_bool CONFIG_ALPHA_NEED_ROUNDING_EMULATION y fi if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \ -o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_JENSEN" = "y" \ - -o "$CONFIG_ALPHA_MIKASA" = "y" -o "$CONFIG_ALPHA_ALCOR" = "y" ] + -o "$CONFIG_ALPHA_MIKASA" = "y" -o "$CONFIG_ALPHA_ALCOR" = "y" \ + -o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_MIATA" = "y" \ + -o "$CONFIG_ALPHA_NORITAKE" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \ + -o "$CONFIG_ALPHA_LX164" = "y" -o "$CONFIG_ALPHA_SX164" = "y" ] then - bool 'Using SRM as bootloader' CONFIG_ALPHA_SRM + bool 'Use SRM as bootloader' CONFIG_ALPHA_SRM + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + if [ "$CONFIG_ALPHA_SRM" = "y" ]; then + bool ' Use SRM PCI setup' CONFIG_ALPHA_SRM_SETUP + fi + fi +fi +if [ "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_MIKASA" = "y" \ + -o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" ] +then + define_bool CONFIG_ALPHA_EISA y fi if [ "$CONFIG_ALPHA_XL" = "y" ] then define_bool CONFIG_ALPHA_AVANTI y fi +bool 'Kernel GDB support' CONFIG_KGDB +if [ "$CONFIG_KGDB" = "y" ]; then + bool 'Kernel tracing support?' CONFIG_KGDB_TRACING +fi + bool 'Echo console messages on /dev/ttyS0 (COM1)' CONFIG_SERIAL_ECHO if [ "$CONFIG_PCI" = "y" ]; then bool 'TGA Console Support' CONFIG_TGA_CONSOLE + if [ "$CONFIG_TGA_CONSOLE" = "y" ]; then + bool 'VGA Console Support' CONFIG_VGA_CONSOLE + fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool 'PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE fi @@ -94,6 +172,7 @@ bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC tristate 'Kernel support for a.out (ECOFF) binaries' CONFIG_BINFMT_AOUT tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +tristate 'Kernel support for Linux/Intel ELF binaries' CONFIG_BINFMT_EM86 endmenu source drivers/block/Config.in @@ -163,3 +242,7 @@ if [ "$CONFIG_PROFILE" = "y" ]; then int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 fi endmenu + +if [ "$CONFIG_TGA_CONSOLE" = "n" ]; then + define_bool CONFIG_VGA_CONSOLE y +fi diff --git a/arch/alpha/defconfig b/arch/alpha/defconfig index 9f33eeaa45af..4f758e5b64fd 100644 --- a/arch/alpha/defconfig +++ b/arch/alpha/defconfig @@ -36,12 +36,16 @@ CONFIG_PCI=y CONFIG_ALPHA_EV5=y CONFIG_ALPHA_CIA=y CONFIG_ALPHA_SRM=y +CONFIG_KGDB=y +CONFIG_KGDB_TRACING=n # CONFIG_SERIAL_ECHO is not set CONFIG_TGA_CONSOLE=y +CONFIG_VGA_CONSOLE=y CONFIG_NET=y CONFIG_SYSVIPC=y CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_EM86=y # # Floppy, IDE, and other block devices diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile index 4aa11ce78862..cac0ffe5a04b 100644 --- a/arch/alpha/kernel/Makefile +++ b/arch/alpha/kernel/Makefile @@ -16,7 +16,12 @@ 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 ksyms.o + bios32.o ptrace.o time.o apecs.o lca.o cia.o t2.o pyxis.o \ + ksyms.o smc.o + +ifdef CONFIG_KGDB +O_OBJS += kgdb.o +endif all: kernel.o head.o diff --git a/arch/alpha/kernel/apecs.c b/arch/alpha/kernel/apecs.c index f4554bcc13a7..c907454102b3 100644 --- a/arch/alpha/kernel/apecs.c +++ b/arch/alpha/kernel/apecs.c @@ -20,7 +20,7 @@ extern struct hwrpb_struct *hwrpb; extern asmlinkage void wrmces(unsigned long mces); -extern int alpha_sys_type; + /* * BIOS32-style PCI interface: */ @@ -33,13 +33,16 @@ extern int alpha_sys_type; # define DBG(args) #endif -#define vulp volatile unsigned long * #define vuip volatile unsigned int * static volatile unsigned int apecs_mcheck_expected = 0; static volatile unsigned int apecs_mcheck_taken = 0; -static unsigned long apecs_jd, apecs_jd1, apecs_jd2; +static unsigned int apecs_jd, apecs_jd1, apecs_jd2; +#ifdef CONFIG_ALPHA_SRM_SETUP +unsigned int APECS_DMA_WIN_BASE = APECS_DMA_WIN_BASE_DEFAULT; +unsigned int APECS_DMA_WIN_SIZE = APECS_DMA_WIN_SIZE_DEFAULT; +#endif /* SRM_SETUP */ /* * Given a bus, device, and function number, compute resulting @@ -142,15 +145,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,7 +162,7 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1) apecs_mcheck_taken = 0; mb(); /* access configuration space: */ - value = *((volatile unsigned int *)addr); + value = *((vuip)addr); mb(); mb(); if (apecs_mcheck_taken) { @@ -179,7 +182,7 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1) 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 +191,7 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1) } /* reset error status: */ - *((volatile unsigned long *)APECS_IOC_DCSR) = stat0; + *((vuip)APECS_IOC_DCSR) = stat0; mb(); wrmces(0x7); /* reset machine check */ value = 0xffffffff; @@ -197,7 +200,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,22 +227,22 @@ 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; + *((vuip)addr) = value; mb(); mb(); apecs_mcheck_expected = 0; @@ -254,7 +257,7 @@ static void conf_write(unsigned long addr, unsigned int value, unsigned char typ 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 +265,7 @@ static void conf_write(unsigned long addr, unsigned int value, unsigned char typ } /* reset error status: */ - *((volatile unsigned long *)APECS_IOC_DCSR) = stat0; + *((vuip)APECS_IOC_DCSR) = stat0; mb(); wrmces(0x7); /* reset machine check */ } @@ -270,7 +273,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); @@ -417,6 +420,38 @@ unsigned long apecs_init(unsigned long mem_start, unsigned long mem_end) *(vuip)APECS_IOC_TB2R = 0; #else /* CONFIG_ALPHA_XL */ +#ifdef CONFIG_ALPHA_SRM_SETUP + /* check window 1 for enabled and mapped to 0 */ + if ((*(vuip)APECS_IOC_PB1R & (1U<<19)) && (*(vuip)APECS_IOC_TB1R == 0)) + { + APECS_DMA_WIN_BASE = *(vuip)APECS_IOC_PB1R & 0xfff00000U; + APECS_DMA_WIN_SIZE = *(vuip)APECS_IOC_PM1R & 0xfff00000U; + APECS_DMA_WIN_SIZE += 0x00100000U; +#if 0 + printk("apecs_init: using Window 1 settings\n"); + printk("apecs_init: PB1R 0x%x PM1R 0x%x TB1R 0x%x\n", + *(vuip)APECS_IOC_PB1R, + *(vuip)APECS_IOC_PM1R, + *(vuip)APECS_IOC_TB1R); +#endif + } + else /* check window 2 for enabled and mapped to 0 */ + if ((*(vuip)APECS_IOC_PB2R & (1U<<19)) && (*(vuip)APECS_IOC_TB2R == 0)) + { + APECS_DMA_WIN_BASE = *(vuip)APECS_IOC_PB2R & 0xfff00000U; + APECS_DMA_WIN_SIZE = *(vuip)APECS_IOC_PM2R & 0xfff00000U; + APECS_DMA_WIN_SIZE += 0x00100000U; +#if 0 + printk("apecs_init: using Window 2 settings\n"); + printk("apecs_init: PB2R 0x%x PM2R 0x%x TB2R 0x%x\n", + *(vuip)APECS_IOC_PB2R, + *(vuip)APECS_IOC_PM2R, + *(vuip)APECS_IOC_TB2R); +#endif + } + else /* we must use our defaults... */ +#endif /* SRM_SETUP */ + { /* * Set up the PCI->physical memory translation windows. * For now, window 2 is disabled. In the future, we may @@ -428,9 +463,11 @@ unsigned long apecs_init(unsigned long mem_start, unsigned long mem_end) *(vuip)APECS_IOC_PB1R = 1U<<19 | (APECS_DMA_WIN_BASE & 0xfff00000U); *(vuip)APECS_IOC_PM1R = (APECS_DMA_WIN_SIZE - 1) & 0xfff00000U; *(vuip)APECS_IOC_TB1R = 0; + } #endif /* CONFIG_ALPHA_XL */ #ifdef CONFIG_ALPHA_CABRIOLET +#if 0 /* * JAE: HACK!!! for now, hardwire if configured... * davidm: Older miniloader versions don't set the clockfrequency @@ -448,10 +485,13 @@ 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; } +#endif #endif /* CONFIG_ALPHA_CABRIOLET */ /* @@ -462,10 +502,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 +514,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 = *((vuip)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 = *((vuip)APECS_IOC_SEAR); + *((vuip)APECS_IOC_DCSR) = apecs_jd | 0xffe1L; + apecs_jd = *((vuip)APECS_IOC_DCSR); mb(); } - *((unsigned long *)APECS_IOC_TBIA) = APECS_IOC_TBIA; - apecs_jd2 = *((unsigned long *)APECS_IOC_TBIA); + *((vuip)APECS_IOC_TBIA) = APECS_IOC_TBIA; + apecs_jd2 = *((vuip)APECS_IOC_TBIA); mb(); return 0; } @@ -526,8 +566,8 @@ void apecs_machine_check(unsigned long vector, unsigned long la_ptr, #define MCHK_NO_DEVSEL 0x205L #define MCHK_NO_TABT 0x204L if (apecs_mcheck_expected && - (((unsigned int)mchk_procdata->paltemp[0] == MCHK_NO_DEVSEL) || - ((unsigned int)mchk_procdata->paltemp[0] == MCHK_NO_TABT)) + (((unsigned int)mchk_header->code == MCHK_NO_DEVSEL) || + ((unsigned int)mchk_header->code == MCHK_NO_TABT)) ) { #else @@ -550,19 +590,21 @@ void apecs_machine_check(unsigned long vector, unsigned long la_ptr, printk("apecs_machine_check: HW correctable (0x%lx)\n", vector); } else { - printk("APECS machine check:\n"); - printk(" vector=0x%lx la_ptr=0x%lx\n", + printk(KERN_CRIT "APECS machine check:\n"); + printk(KERN_CRIT " vector=0x%lx la_ptr=0x%lx\n", vector, la_ptr); - printk(" pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n", + printk(KERN_CRIT + " 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); - printk(" expected %d DCSR 0x%lx PEAR 0x%lx\n", + printk(KERN_CRIT " expected %d DCSR 0x%lx PEAR 0x%lx\n", apecs_mcheck_expected, mchk_sysdata->epic_dcsr, mchk_sysdata->epic_pear); 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]); + printk(KERN_CRIT " +%lx %lx %lx\n", + i*sizeof(long), ptr[i], ptr[i+1]); } #if 0 /* doesn't work with MILO */ diff --git a/arch/alpha/kernel/bios32.c b/arch/alpha/kernel/bios32.c index 2220552e0c7d..d05128960200 100644 --- a/arch/alpha/kernel/bios32.c +++ b/arch/alpha/kernel/bios32.c @@ -57,7 +57,7 @@ asmlinkage int sys_pciconfig_write() #include #include #include - +#include #define KB 1024 #define MB (1024*KB) @@ -73,6 +73,8 @@ asmlinkage int sys_pciconfig_write() /* + * PCI_MODIFY + * * Temporary internal macro. If this 0, then do not write to any of * the PCI registers, merely read them (i.e., use configuration as * determined by SRM). The SRM seem do be doing a less than perfect @@ -89,34 +91,72 @@ asmlinkage int sys_pciconfig_write() * the graphics card---there have been some rumor that the #9 BIOS * incorrectly resets that address to 0...). */ +#ifdef CONFIG_ALPHA_SRM_SETUP +#define PCI_MODIFY 0 +static struct pci_dev *irq_dev_to_reset[16]; +static unsigned char irq_to_reset[16]; +static int irq_reset_count = 0; +static struct pci_dev *io_dev_to_reset[16]; +static unsigned char io_reg_to_reset[16]; +static unsigned int io_to_reset[16]; +static int io_reset_count = 0; +#else /* SRM_SETUP */ #define PCI_MODIFY 1 +#endif /* SRM_SETUP */ extern struct hwrpb_struct *hwrpb; - #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 also that we may need this stuff for SRM_SETUP also, since certain + SRM consoles screw up and allocate I/O space addresses > 64K behind + PCI-to_PCI bridges, which can't pass addresses larger than 64K... */ +#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. + 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 = 1024*MB; -#else /* CONFIG_ALPHA_XL */ -static unsigned int mem_base = 16*MB; /* <16MB is ISA memory */ +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 /* CONFIG_ALPHA_XL */ /* @@ -128,7 +168,7 @@ static void disable_dev(struct pci_dev *dev) struct pci_bus *bus; unsigned short cmd; -#if defined(CONFIG_ALPHA_MIKASA) || defined(CONFIG_ALPHA_ALCOR) +#if defined(CONFIG_ALPHA_EISA) /* * HACK: the PCI-to-EISA bridge does not seem to identify * itself as a bridge... :-( @@ -139,6 +179,18 @@ static void disable_dev(struct pci_dev *dev) } #endif + /* + * we don't have code that will init the CYPRESS bridge correctly + * so we do the next best thing, and depend on the previous + * console code to do the right thing, and ignore it here... :-\ + */ + if ((dev->vendor == 0x1080) && (dev->device == 0xC693)) { +#if 0 + printk("disable_dev: ignoring CYPRESS bridge...\n"); +#endif + return; + } + bus = dev->bus; pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd); @@ -160,7 +212,7 @@ 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) +#if defined(CONFIG_ALPHA_EISA) /* * HACK: the PCI-to-EISA bridge does not seem to identify * itself as a bridge... :-( @@ -171,10 +223,36 @@ static void layout_dev(struct pci_dev *dev) } #endif + /* + * we don't have code that will init the CYPRESS bridge correctly + * so we do the next best thing, and depend on the previous + * console code to do the right thing, and ignore it here... :-\ + */ + if ((dev->vendor == 0x1080) && (dev->device == 0xC693)) { +#if 0 + printk("layout_dev: ignoring CYPRESS bridge...\n"); +#endif + return; + } + bus = dev->bus; pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd); for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) { + +#ifdef NOT_NOW + if ((dev->vendor == 0x1080) && (dev->device == 0xC693) && + ((PCI_FUNC(dev->devfn) == 1) || (PCI_FUNC(dev->devfn) == 2))) + { /* if primary or secondary IDE on the CYPRESS bridge */ + if ((reg == PCI_BASE_ADDRESS_0) || (reg == PCI_BASE_ADDRESS_1)) { +#if 0 + printk("layout_dev: ignoring CYPRESS IDE base reg 0/1\n"); +#endif + continue; /* ignore first two registers */ + } + } +#endif /* NOT_NOW */ + /* * Figure out how much space and of what type this * device wants. @@ -182,6 +260,10 @@ static void layout_dev(struct pci_dev *dev) pcibios_write_config_dword(bus->number, dev->devfn, reg, 0xffffffff); pcibios_read_config_dword(bus->number, dev->devfn, reg, &base); +#if 0 +printk("layout_dev: slot %d fn %d off 0x%x base 0x%x\n", + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), reg, base); +#endif if (!base) { /* this base-address register is unused */ continue; @@ -201,11 +283,23 @@ static void layout_dev(struct pci_dev *dev) mask = (~base << 1) | 0x1; size = (mask & base) & 0xffffffff; /* align to multiple of size of minimum base */ +#if 0 alignto = MAX(0x400, size) ; +#else + /* + If we align to 0x800 bounds, we probably avoid + having devices in any 0xzCzz range, which is + where the DE4X5 driver probes for EISA cards. + Adaptecs, especially, resent such intrusions. :-( + */ + alignto = MAX(0x800, size) ; +#endif base = ALIGN(io_base, alignto ); io_base = base + size; pcibios_write_config_dword(bus->number, dev->devfn, reg, base | 0x1); + DBG_DEVS(("layout_dev: dev 0x%x IO @ 0x%x (0x%x)\n", + dev->device, base, size)); } else { unsigned int type; /* @@ -266,7 +360,7 @@ static void layout_dev(struct pci_dev *dev) base = ALIGN(mem_base, alignto); if (size > 7 * 16*MB) { printk("bios32 WARNING: slot %d, function %d " - "requests %dB of contiguous address " + "requests 0x%x bytes of contig address " " space---don't use sparse memory " " accesses on this device!!\n", PCI_SLOT(dev->devfn), @@ -277,7 +371,8 @@ 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); @@ -286,13 +381,15 @@ static void layout_dev(struct pci_dev *dev) mem_base = base + size; pcibios_write_config_dword(bus->number, dev->devfn, reg, base); + DBG_DEVS(("layout_dev: dev 0x%x MEM @ 0x%x (0x%x)\n", + dev->device, base, size)); } - } + } /* end for-loop */ /* 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 @@ -305,21 +402,24 @@ 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 0x%x\n", + bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device, + dev->class, cmd|PCI_COMMAND_MASTER)); } -static void layout_bus(struct pci_bus *bus) +static int layout_bus(struct pci_bus *bus) { unsigned int l, tio, bio, tmem, bmem; struct pci_bus *child; struct pci_dev *dev; + int found_vga = 0; DBG_DEVS(("layout_bus: starting bus %d\n", bus->number)); if (!bus->devices && !bus->children) - return; + return 0; /* * Align the current bases on appropriate boundaries (4K for @@ -338,7 +438,11 @@ 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) { + if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) +#ifdef CONFIG_ALPHA_BOOK1 + || (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA) +#endif /* CONFIG_ALPHA_BOOK1 */ + ) { disable_dev(dev) ; } } @@ -349,9 +453,15 @@ 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) +#ifdef CONFIG_ALPHA_BOOK1 + || (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA) +#endif /* CONFIG_ALPHA_BOOK1 */ + ) { layout_dev(dev); } + if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) + found_vga = 1; } /* * Recursively allocate space for all of the sub-buses: @@ -359,7 +469,7 @@ static void layout_bus(struct pci_bus *bus) DBG_DEVS(("layout_bus: starting bus %d children\n", bus->number)); for (child = bus->children; child; child = child->next) { - layout_bus(child); + found_vga += layout_bus(child); } /* * Align the current bases on 4K and 1MB boundaries: @@ -375,7 +485,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 = (l & 0xffff0000) | ((bio >> 8) & 0x00f0) | + ((tio - 1) & 0xf000); pcibios_write_config_dword(bridge->bus->number, bridge->devfn, 0x1c, l); /* @@ -391,10 +502,13 @@ static void layout_bus(struct pci_bus *bus) pcibios_write_config_dword(bridge->bus->number, bridge->devfn, 0x24, 0x0000ffff); /* - * Tell bridge that there is an ISA bus in the system: + * Tell bridge that there is an ISA bus in the system, + * and (possibly) a VGA as well. */ + l = 0x00040000; /* ISA present */ + if (found_vga) l |= 0x00080000; /* VGA present */ pcibios_write_config_dword(bridge->bus->number, bridge->devfn, - 0x3c, 0x00040000); + 0x3c, l); /* * Clear status bits, enable I/O (for downstream I/O), * turn on master enable (for upstream I/O), turn on @@ -404,6 +518,7 @@ static void layout_bus(struct pci_bus *bus) pcibios_write_config_dword(bridge->bus->number, bridge->devfn, 0x4, 0xffff0007); } + return found_vga; } #endif /* !PCI_MODIFY */ @@ -501,9 +616,9 @@ 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 DC 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: * * Dev Interrupt Interrupt * Pin on Pin on @@ -541,13 +656,86 @@ static inline unsigned char bridge_swizzle(unsigned char pin, unsigned int slot) return (((pin-1) + slot) % 4) + 1 ; } +#ifdef CONFIG_ALPHA_SRM_SETUP +/* look for mis-configured devices' IO space addresses behind bridges */ +static void check_behind_io(struct pci_dev *dev) +{ + struct pci_bus *bus = dev->bus; + unsigned int reg, orig_base, new_base, found_one = 0; + + for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) { + /* read the current setting, check for I/O space and >= 64K */ + pcibios_read_config_dword(bus->number, dev->devfn, reg, &orig_base); + if (!orig_base || !(orig_base & PCI_BASE_ADDRESS_SPACE_IO)) + continue; /* unused or non-IO */ + if (orig_base < 64*1024) { +#if 1 +printk("check_behind_io: ALREADY OK! bus %d slot %d base 0x%x\n", + bus->number, PCI_SLOT(dev->devfn), orig_base); +#endif + if (orig_base & ~1) + continue; /* OK! */ + orig_base = 0x12001; /* HACK! FIXME!! */ + } + + /* HACK ALERT! for now, just subtract 32K from the + original address, which should give us addresses + in the range 0x8000 and up */ + new_base = orig_base - 0x8000; +#if 1 +printk("check_behind_io: ALERT! bus %d slot %d old 0x%x new 0x%x\n", + bus->number, PCI_SLOT(dev->devfn), orig_base, new_base); +#endif + pcibios_write_config_dword(bus->number, dev->devfn, + reg, new_base); + + io_dev_to_reset[io_reset_count] = dev; + io_reg_to_reset[io_reset_count] = reg; + io_to_reset[io_reset_count] = orig_base; + io_reset_count++; + found_one++; + } /* end for-loop */ + + /* if any were modified, gotta hack the bridge IO limits too... */ + if (found_one) { + if (bus->self) { + struct pci_dev *bridge = bus->self; + unsigned int l; + /* + * Set up the top and bottom of the PCI I/O segment + * for this bus. + */ + pcibios_read_config_dword(bridge->bus->number, + bridge->devfn, 0x1c, &l); +#if 1 +printk("check_behind_io: ALERT! bus %d slot %d oldLIM 0x%x\n", + bus->number, PCI_SLOT(bridge->devfn), l); +#endif + l = (l & 0xffff0000U) | 0xf080U; /* give it ALL */ + pcibios_write_config_dword(bridge->bus->number, + bridge->devfn, 0x1c, l); + pcibios_write_config_dword(bridge->bus->number, + bridge->devfn, + 0x3c, 0x00040000); + pcibios_write_config_dword(bridge->bus->number, + bridge->devfn, + 0x4, 0xffff0007); + } else + printk("check_behind_io: WARNING! bus->self NULL\n"); + } +} +#endif /* CONFIG_ALPHA_SRM_SETUP */ + /* * 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, +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) { @@ -559,37 +747,122 @@ static inline void common_fixup(long min_idsel, long max_idsel, long irqs_per_sl * 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) + if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) +#if defined(CONFIG_ALPHA_EISA) /* PCEB (PCI to EISA bridge) does not identify itself as a bridge... :-( */ && !((dev->vendor==0x8086) && (dev->device==0x482)) #endif +#ifdef CONFIG_ALPHA_BOOK1 + || (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA) +#endif /* CONFIG_ALPHA_BOOK1 */ ) { dev->irq = 0; /* - * 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 + * 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 'cuz 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). */ 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); + /* 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 */ + /* follow the chain of bridges, + swizzling as we go */ +#if defined(CONFIG_ALPHA_MIATA) + /* check first for the built-in bridge */ + if ((PCI_SLOT(dev->bus->self->devfn) == 8) || + (PCI_SLOT(dev->bus->self->devfn) == 20)) { + slot = PCI_SLOT(dev->devfn) + 9; +#if 0 + printk("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); +#endif + } + else /* must be a card-based bridge */ + { + struct pci_dev *curr = dev ; do { + if ((PCI_SLOT(curr->bus->self->devfn) == 8) || + (PCI_SLOT(curr->bus->self->devfn) == 20)) + { + slot = PCI_SLOT(curr->devfn) + 5; + break; + } /* 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 ; + /* slot of the next bridge. */ + slot = PCI_SLOT(curr->devfn); + } while (curr->bus->self) ; + } +#elif defined(CONFIG_ALPHA_NORITAKE) + /* check first for the built-in bridge */ + if (PCI_SLOT(dev->bus->self->devfn) == 8) { + slot = PCI_SLOT(dev->devfn) + 15; /* WAG! */ +#if 0 + printk("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); +#endif + } + else /* must be a card-based bridge */ + { + struct pci_dev *curr = dev ; + do { + if (PCI_SLOT(curr->bus->self->devfn) == 8) { + slot = PCI_SLOT(curr->devfn) + 15; + break; + } + /* swizzle */ + pin = bridge_swizzle( + pin, PCI_SLOT(curr->devfn)) ; + /* move up the chain of bridges */ + curr = curr->bus->self ; + /* slot of the next bridge. */ + slot = PCI_SLOT(curr->devfn); + } while (curr->bus->self) ; + } +#else /* not MIATA or NORITAKE */ + { + struct pci_dev *curr = dev ; + do { + /* swizzle */ + pin = bridge_swizzle( + pin, PCI_SLOT(curr->devfn)) ; /* move up the chain of bridges */ curr = curr->bus->self ; } while (curr->bus->self) ; /* The slot is the slot of the last bridge. */ slot = PCI_SLOT(curr->devfn) ; + } +#endif /* not MIATA or NORITAKE */ +#ifdef CONFIG_ALPHA_SRM_SETUP + /* + must make sure that SRM didn't screw up + and allocate an address > 64K for I/O + space behind a PCI-PCI bridge + */ + check_behind_io(dev); +#endif /* CONFIG_ALPHA_SRM_SETUP */ } else { /* work out the slot */ slot = PCI_SLOT(dev->devfn) ; @@ -601,28 +874,193 @@ static inline void common_fixup(long min_idsel, long max_idsel, long irqs_per_sl } if (irq_tab[slot - min_idsel][pin] != -1) dev->irq = irq_tab[slot - min_idsel][pin]; -#if PCI_MODIFY - /* tell the device: */ + +#ifdef CONFIG_ALPHA_SRM + { + unsigned char irq_orig; + /* read the original SRM-set IRQ and tell */ + pcibios_read_config_byte(dev->bus->number, + dev->devfn, + PCI_INTERRUPT_LINE, + &irq_orig); + if (irq_orig != dev->irq) { + printk("common_fixup: bus %d slot 0x%x " + "SRM IRQ 0x%x changed to 0x%x\n", + dev->bus->number,PCI_SLOT(dev->devfn), + irq_orig, dev->irq); +#ifdef CONFIG_ALPHA_SRM_SETUP + irq_dev_to_reset[irq_reset_count] = dev; + irq_to_reset[irq_reset_count] = irq_orig; + irq_reset_count++; +#endif /* CONFIG_ALPHA_SRM_SETUP */ + } + } +#endif /* SRM */ + + /* always tell the device, so the driver knows */ 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 irq 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, + /* but if its a Cirrus 543x/544x DISABLE it, */ + /* since enabling ROM disables the memory... */ + if ((dev->vendor == PCI_VENDOR_ID_CIRRUS) && + (dev->device >= 0x00a0) && + (dev->device <= 0x00ac)) { + pcibios_write_config_dword( + dev->bus->number, + dev->devfn, + PCI_ROM_ADDRESS, + 0x00000000); + } else { + 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 NOT_NOW + if ((dev->vendor == 0x1080) && (dev->device == 0xC693) + && (PCI_FUNC(dev->devfn) == 1)) + { +#if 0 +{ +int i; unsigned char b; unsigned short w; unsigned int d; + pcibios_read_config_word(dev->bus->number, dev->devfn, 4, &w); + printk("common_fixup: CYPRESS fn 1: PCI CMD reg = 0x%x\n", w); + pcibios_read_config_word(dev->bus->number, dev->devfn, 6, &w); + printk("common_fixup: CYPRESS fn 1: PCI STS reg = 0x%x\n", w); + for (i = 0x10; i <= 0x14; i+=4) { + pcibios_read_config_dword(dev->bus->number, dev->devfn, i, &d); + printk("common_fixup: CYPRESS fn 1: PCI register offset 0x%x = 0x%x\n",i,d); + } + pcibios_read_config_dword(dev->bus->number, dev->devfn, 0x20, &d); + printk("common_fixup: CYPRESS fn 1: PCI register offset 0x20 = 0x%x\n", d); + for (i = 0x3c; i <= 0x3d; i++) { + pcibios_read_config_byte(dev->bus->number, dev->devfn, i, &b); + printk("common_fixup: CYPRESS fn 1: PCI register offset 0x%x = 0x%x\n",i,b); + } + pcibios_read_config_dword(dev->bus->number, dev->devfn, 0x40, &d); + printk("common_fixup: CYPRESS fn 1: PCI register offset 0x40 = 0x%x\n",d); +} +#endif + } + if ((dev->vendor == 0x1080) && (dev->device == 0xC693) + && (PCI_FUNC(dev->devfn) == 2)) + { +#if 0 +{ +int i; unsigned char b; unsigned short w; unsigned int d; + pcibios_read_config_word(dev->bus->number, dev->devfn, 4, &w); + printk("common_fixup: CYPRESS fn 2: PCI CMD reg = 0x%x\n", w); + pcibios_read_config_word(dev->bus->number, dev->devfn, 6, &w); + printk("common_fixup: CYPRESS fn 2: PCI STS reg = 0x%x\n", w); + for (i = 0x10; i <= 0x14; i+=4) { + pcibios_read_config_dword(dev->bus->number, dev->devfn, i, &d); + printk("common_fixup: CYPRESS fn 2: PCI register offset 0x%x = 0x%x\n",i,d); + } + pcibios_read_config_dword(dev->bus->number, dev->devfn, 0x20, &d); + printk("common_fixup: CYPRESS fn 2: PCI register offset 0x20 = 0x%x\n", d); + for (i = 0x3c; i <= 0x3d; i++) { + pcibios_read_config_byte(dev->bus->number, dev->devfn, i, &b); + printk("common_fixup: CYPRESS fn 2: PCI register offset 0x%x = 0x%x\n",i,b); + } + pcibios_read_config_dword(dev->bus->number, dev->devfn, 0x40, &d); + printk("common_fixup: CYPRESS fn 2: PCI register offset 0x40 = 0x%x\n",d); +} +#endif + } +#endif /* NOT_NOW */ + } else { /* it *is* a bridge... */ +#ifdef NOT_NOW + /* + * if it's CYPRESS PCI-ISA bridge, disable IDE + * interrupt routing through PCI (ie do through PIC) + */ + if ((dev->vendor == 0x1080) && (dev->device == 0xC693) + && (PCI_FUNC(dev->devfn) == 0)) + { +#if 0 +{ +int i; unsigned char d; unsigned short w; + pcibios_read_config_word(dev->bus->number, dev->devfn, 4, &w); + printk("common_fixup: CYPRESS fn 0: PCI CMD reg = 0x%x\n", w); + for (i = 0x40; i < 0x50; i++) { + pcibios_read_config_byte(dev->bus->number, dev->devfn, i, &d); + printk("common_fixup: CYPRESS fn 0: PCI register offset 0x%x = 0x%x\n", + i, d); + } + for (i=1; i <= 5; i++) { + outb(i, 0x22); + printk("CY control reg %d: 0x%02x\n", i, inb(0x23)); + } +} +#endif +#if 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); +#endif + outb(0, DMA1_RESET_REG); + outb(0, DMA2_RESET_REG); + outb(DMA_MODE_CASCADE, DMA2_MODE_REG); + outb(0, DMA2_MASK_REG); +#if 0 + outb(0, DMA1_CLR_MASK_REG); + outb(0, DMA2_CLR_MASK_REG); +#endif + } +#endif /* NOT_NOW */ + } } if (ide_base) { enable_ide(ide_base); } } + /* * The EB66+ is very similar to the EB66 except that it does not have * the on-board NCR and Tulip chips. In the code below, I have used @@ -639,6 +1077,7 @@ 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] = { + /*INT INTA INTB INTC INTD */ {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 */ @@ -650,7 +1089,7 @@ static inline void eb66p_fixup(void) /* - * The PC164 has 19 PCI interrupts, four from each of the four PCI + * The PC164/LX164 have 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 @@ -693,12 +1132,9 @@ static inline void eb66p_fixup(void) static inline void alphapc164_fixup(void) { - extern int SMCInit(void); + extern void SMC93X_Init(void); char irq_tab[7][5] = { - /* - * int intA intB intC intD - * ---- ---- ---- ---- ---- - */ + /*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 */ @@ -710,7 +1146,7 @@ static inline void alphapc164_fixup(void) common_fixup(5, 11, 5, irq_tab, 0); - SMCInit(); + SMC93X_Init(); } /* @@ -729,6 +1165,7 @@ static inline void alphapc164_fixup(void) static inline void cabriolet_fixup(void) { char irq_tab[5][5] = { + /*INT INTA INTB INTC INTD */ { 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 */ @@ -785,6 +1222,7 @@ static inline void cabriolet_fixup(void) static inline void eb66_and_eb64p_fixup(void) { char irq_tab[5][5] = { + /*INT INTA INTB INTC INTD */ {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 ?, ?? */ @@ -796,7 +1234,7 @@ static inline void eb66_and_eb64p_fixup(void) /* - * Fixup configuration for MIKASA (NORITAKE is different) + * Fixup configuration for MIKASA * * Summary @ 0x536: * Bit Meaning @@ -847,6 +1285,86 @@ static inline void mikasa_fixup(void) common_fixup(6, 13, 5, irq_tab, 0); } +/* + * Fixup configuration for NORITAKE + * + * 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) +{ + char irq_tab[15][5] = { + /*INT INTA INTB INTC INTD */ + /* note: IDSELs 16, 17, and 25 are CORELLE only */ + { 16+1, 16+1, 16+1, 16+1, 16+1}, /* IdSel 16, QLOGIC */ + { -1, -1, -1, -1, -1}, /* IdSel 17, S3 Trio64 */ + { -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 */ + { 16+8, 16+8, 16+9, 32+8, 32+9}, /* IdSel 25, slot 3 */ + /* the following 5 are actually on PCI 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(5, 19, 5, irq_tab, 0); +} + /* * Fixup configuration for ALCOR * @@ -892,8 +1410,10 @@ static inline void mikasa_fixup(void) */ static inline void alcor_fixup(void) { - char irq_tab[6][5] = { + char irq_tab[7][5] = { /*INT INTA INTB INTC INTD */ + /* note: IDSEL 17 is XLT only */ + {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 */ {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 */ @@ -901,9 +1421,10 @@ static inline void alcor_fixup(void) { 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); + common_fixup(6, 12, 5, irq_tab, 0); } +#if 0 /* * Fixup configuration for ALPHA XLT (EV5/EV56) * @@ -959,7 +1480,303 @@ static inline void xlt_fixup(void) }; common_fixup(6, 12, 5, irq_tab, 0); } +#endif /* 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 + */ +static inline void sable_fixup(void) +{ + char irq_tab[9][5] = { + /*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); +} + +/* + * 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. + */ +static inline void miata_fixup(void) +{ + extern int es1888_init(void); + extern void SMC669_Init(void); /* might be a MiataGL */ + char irq_tab[18][5] = { + /*INT INTA INTB INTC INTD */ + {16+ 8, 16+ 8, 16+ 8, 16+ 8, 16+ 8}, /* IdSel 14, DC21142/3 */ + { -1, -1, -1, -1, -1}, /* IdSel 15, EIDE */ + { -1, -1, -1, -1, -1}, /* IdSel 16, none */ + { -1, -1, -1, -1, -1}, /* IdSel 17, none */ + { -1, -1, -1, -1, -1}, /* IdSel 18, PCI-ISA */ + { -1, -1, -1, -1, -1}, /* IdSel 19, PCI-PCI old */ + { -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 7 are actually on PCI bus 1, across the bridge */ + {16+11, 16+11, 16+11, 16+11, 16+11}, /* IdSel 24, QLISP on GL */ + { -1, -1, -1, -1, -1}, /* IdSel 25, none */ + { -1, -1, -1, -1, -1}, /* IdSel 26, none */ + { -1, -1, -1, -1, -1}, /* IdSel 27, none */ + {16+20, 16+20, 16+21, 16+22, 16+23}, /* IdSel 28, slot 1 */ + {16+24, 16+24, 16+25, 16+26, 16+27}, /* IdSel 29, slot 2 */ + {16+28, 16+28, 16+29, 16+30, 16+31}, /* IdSel 30, slot 3 */ + /* this bridge is on the main bus of the later original MIATA */ + { -1, -1, -1, -1, -1}, /* IdSel 31, PCI-PCI new */ + }; + common_fixup(3, 20, 5, irq_tab, 0); + SMC669_Init(); /* might be a MiataGL, so try to find one of these */ + es1888_init(); +} + +/* + * 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 + * + */ + +static inline void sx164_fixup(void) +{ + extern void SMC669_Init(void); + char irq_tab[5][5] = { + /*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(); +} + +static inline void ruffian_fixup(void) +{ + struct pci_dev *dev; + + /* + * Go through all devices + */ + for (dev = pci_devices; dev; dev = dev->next) { + if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) { + /* + * if it's a VGA, enable its BIOS ROM at C0000 + */ + if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) { + /* but if its a Cirrus 543x/544x DISABLE it, */ + /* since enabling ROM disables the memory... */ + if ((dev->vendor == PCI_VENDOR_ID_CIRRUS) && + (dev->device >= 0x00a0) && + (dev->device <= 0x00ac)) { + pcibios_write_config_dword( + dev->bus->number, + dev->devfn, + PCI_ROM_ADDRESS, + 0x00000000); + } else { + 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); + } + } + } +} + +/* + * The Takara has PCI devices 1, 2, and 3 configured to slots 20, + * 19, and 18 respectively, in the default configuration. They can + * also be jumpered to slots 8, 7, and 6 respectively, which is fun + * because the SIO ISA bridge can also be slot 7. However, the SIO + * doesn't explicitly generate PCI-type interrupts, so we can + * assign it whatever the hell IRQ we like and it doesn't matter. + */ +static inline void takara_fixup(void) +{ + char irq_tab[15][5] = { + { 16+3, 16+3, 16+3, 16+3, 16+3}, /* slot 6 == device 3 */ + { 16+2, 16+2, 16+2, 16+2, 16+2}, /* slot 7 == device 2 */ + { 16+1, 16+1, 16+1, 16+1, 16+1}, /* slot 8 == device 1 */ + { -1, -1, -1, -1, -1}, /* slot 9 == nothing */ + { -1, -1, -1, -1, -1}, /* slot 10 == nothing */ + { -1, -1, -1, -1, -1}, /* slot 11 == nothing */ + { -1, -1, -1, -1, -1}, /* slot 12 == nothing */ + { -1, -1, -1, -1, -1}, /* slot 13 == nothing */ + { -1, -1, -1, -1, -1}, /* slot 14 == nothing */ + { -1, -1, -1, -1, -1}, /* slot 15 == nothing */ + { -1, -1, -1, -1, -1}, /* slot 16 == nothing */ + { -1, -1, -1, -1, -1}, /* slot 17 == nothing */ + { 16+3, 16+3, 16+3, 16+3, 16+3}, /* slot 18 == device 3 */ + { 16+2, 16+2, 16+2, 16+2, 16+2}, /* slot 19 == device 2 */ + { 16+1, 16+1, 16+1, 16+1, 16+1}, /* slot 20 == device 1 */ + }; + + common_fixup(6, 20, 5, irq_tab, 0x26e); +} /* * Fixup configuration for all boards that route the PCI interrupts @@ -1029,7 +1846,12 @@ static inline void sio_fixup(void) * they are co-indicated when the platform type "Noname" is * selected... :-( */ +#ifdef CONFIG_ALPHA_BOOK1 + /* for the AlphaBook1, NCR810 SCSI is 14, PCMCIA controller is 15 */ + const unsigned int route_tab = 0x0e0f0a0a; +#else /* CONFIG_ALPHA_BOOK1 */ const unsigned int route_tab = 0x0b0a0f09; +#endif /* CONFIG_ALPHA_BOOK1 */ #else /* CONFIG_ALPHA_NONAME */ const unsigned int route_tab = 0x0b0a090f; #endif /* CONFIG_ALPHA_NONAME */ @@ -1044,7 +1866,11 @@ 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) +#ifdef CONFIG_ALPHA_BOOK1 + && (dev->class >> 8 != PCI_CLASS_BRIDGE_PCMCIA) +#endif /* CONFIG_ALPHA_BOOK1 */ + ) continue; dev->irq = 0; if (dev->bus->number != 0) { @@ -1076,16 +1902,17 @@ static inline void sio_fixup(void) if (slot < 6 || slot >= 6 + sizeof(pirq_tab)/sizeof(pirq_tab[0])) { 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 */ @@ -1107,15 +1934,51 @@ static inline void sio_fixup(void) dev->irq = (route_tab >> (8 * pirq)) & 0xff; +#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() @@ -1125,21 +1988,43 @@ 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); + +#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 /* !CONFIG_ALPHA_BOOK1 */ } #ifdef CONFIG_TGA_CONSOLE -extern void tga_console_init(void); +extern void tga_console_find(void); #endif /* CONFIG_TGA_CONSOLE */ unsigned long 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. */ @@ -1153,7 +2038,7 @@ unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end) 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(); @@ -1163,16 +2048,26 @@ unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end) eb66_and_eb64p_fixup(); #elif defined(CONFIG_ALPHA_MIKASA) mikasa_fixup(); -#elif defined(CONFIG_ALPHA_ALCOR) +#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) 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_TAKARA) + takara_fixup(); +#elif defined(CONFIG_ALPHA_RUFFIAN) + ruffian_fixup(); #else # error You must tell me what kind of platform you want. #endif #ifdef CONFIG_TGA_CONSOLE - tga_console_init(); + tga_console_find(); #endif /* CONFIG_TGA_CONSOLE */ return mem_start; @@ -1282,262 +2177,117 @@ 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 ); -} +#if (defined(CONFIG_ALPHA_PC164) || \ + defined(CONFIG_ALPHA_LX164) || \ + defined(CONFIG_ALPHA_SX164) || \ + defined(CONFIG_ALPHA_EB164) || \ + defined(CONFIG_ALPHA_EB66P) || \ + defined(CONFIG_ALPHA_CABRIOLET)) && defined(CONFIG_ALPHA_SRM) -void SMCEnableDevice( unsigned long baseAddr, - unsigned long device, - unsigned long portaddr, - unsigned long interrupt) +/* + on the above machines, under SRM console, we must use the CSERVE PALcode + routine to manage the interrupt mask for us, otherwise, the kernel/HW get + out of sync with what the PALcode thinks it needs to deliver/ignore + */ +void +cserve_update_hw(unsigned long irq, unsigned long mask) { - 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); + extern void cserve_ena(unsigned long); + extern void cserve_dis(unsigned long); - outb(INTERRUPT_SEL, indexPort); - outb(interrupt, dataPort); - - outb(ACTIVATE, indexPort); - outb(DEVICE_ON, dataPort); + if (mask & (1UL << irq)) + /* disable */ + cserve_dis(irq - 16); + else + /* enable */ + cserve_ena(irq - 16); + return; } +#endif /* (PC164 || LX164 || SX164 || EB164 || CABRIO) && SRM */ -void SMCEnableKYBD( unsigned long baseAddr ) -{ - unsigned long indexPort; - unsigned long dataPort; - - indexPort = baseAddr; - dataPort = ( unsigned long )( ( char * )baseAddr + 1 ); +#ifdef CONFIG_ALPHA_MIATA - 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 ) +/* init the built-in ES1888 sound chip (SB16 compatible) */ +int es1888_init(void) { - 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); + /* 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; } -#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 ); +#endif /* CONFIG_ALPHA_MIATA */ - 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_SRM_SETUP +void reset_for_srm(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 ); + extern void scrreset(void); + struct pci_dev *dev; + int i; + + /* reset any IRQs that we changed */ + for (i = 0; i < irq_reset_count; i++) { + dev = irq_dev_to_reset[i]; + + pcibios_write_config_byte(dev->bus->number, dev->devfn, + PCI_INTERRUPT_LINE, irq_to_reset[i]); +#if 1 + printk("reset_for_srm: bus %d slot 0x%x " + "SRM IRQ 0x%x changed back from 0x%x\n", + dev->bus->number, PCI_SLOT(dev->devfn), + irq_to_reset[i], dev->irq); #endif - SMCRunState( SMCUltraBase ); - return( 1 ); - } - else { -#if SMC_DEBUG - printk( "No SMC FDC37C93X Ultra I/O Controller found\n" ); + } + + /* reset any IO addresses that we changed */ + for (i = 0; i < io_reset_count; i++) { + dev = io_dev_to_reset[i]; + + pcibios_write_config_byte(dev->bus->number, dev->devfn, + io_reg_to_reset[i], io_to_reset[i]); +#if 1 + printk("reset_for_srm: bus %d slot 0x%x " + "SRM IO restored to 0x%x\n", + dev->bus->number, PCI_SLOT(dev->devfn), + io_to_reset[i]); #endif - return( 0 ); - } } -#endif /* CONFIG_ALPHA_PC164 */ + /* reset the visible screen to the top of display memory */ + scrreset(); +} +#endif /* CONFIG_ALPHA_SRM_SETUP */ #endif /* CONFIG_PCI */ diff --git a/arch/alpha/kernel/cia.c b/arch/alpha/kernel/cia.c index ea59808e4329..6b4648bfd3af 100644 --- a/arch/alpha/kernel/cia.c +++ b/arch/alpha/kernel/cia.c @@ -20,26 +20,51 @@ extern struct hwrpb_struct *hwrpb; extern asmlinkage void wrmces(unsigned long mces); -extern int alpha_sys_type; + +/* + * 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 CONFIG_ALPHA_CIA -#ifdef DEBUG -# define DBG(args) printk args +/* #define DEBUG_MCHECK */ +/* #define DEBUG_CONFIG */ +/* #define DEBUG_DUMP_REGS */ + +#ifdef DEBUG_MCHECK +# define DBGM(args) printk args #else -# define DBG(args) +# define DBGM(args) +#endif +#ifdef DEBUG_CONFIG +# define DBGC(args) printk args +#else +# define DBGC(args) #endif -#define vulp volatile unsigned long * #define vuip volatile unsigned int * static volatile unsigned int CIA_mcheck_expected = 0; static volatile unsigned int CIA_mcheck_taken = 0; -static unsigned long CIA_jd, CIA_jd1, CIA_jd2; +static unsigned int CIA_jd; +#ifdef CONFIG_ALPHA_SRM_SETUP +unsigned int CIA_DMA_WIN_BASE = CIA_DMA_WIN_BASE_DEFAULT; +unsigned int CIA_DMA_WIN_SIZE = CIA_DMA_WIN_SIZE_DEFAULT; +unsigned long cia_sm_base_r1, cia_sm_base_r2, cia_sm_base_r3; +#endif /* SRM_SETUP */ /* * Given a bus, device, and function number, compute resulting @@ -88,7 +113,7 @@ 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", + 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) { @@ -97,7 +122,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; } @@ -109,7 +135,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; } @@ -120,22 +146,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(); @@ -144,7 +173,7 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1) CIA_mcheck_taken = 0; mb(); /* access configuration space: */ - value = *((volatile unsigned int *)addr); + value = *((vuip)addr); mb(); mb(); if (CIA_mcheck_taken) { @@ -154,39 +183,14 @@ 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 - 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 */ - if (!(stat0 & 0x0080)) { - printk("CIA.c:conf_read: got stat0=%x\n", stat0); - } - - /* reset error status: */ - *((volatile unsigned long *)CIA_IOC_CIA_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) { - *((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; @@ -203,60 +207,36 @@ 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(); - 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 - 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 */ - if (!(stat0 & 0x0080)) { - printk("CIA.c:conf_read: got stat0=%x\n", stat0); - } - /* reset error status: */ - *((volatile unsigned long *)CIA_IOC_CIA_ERR) = stat0; + CIA_mcheck_expected = 0; mb(); - wrmces(0x7); /* reset machine check */ - value = 0xffffffff; - } -#endif /* 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); } @@ -377,16 +357,135 @@ 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; +#if 1 + 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); + temp = *((vuip)CIA_IOC_ERR_MASK); mb(); + printk("CIA_init: CIA_ERR_MASK was 0x%x\n", temp); +#endif + temp = *((vuip)CIA_IOC_PCI_W0_BASE); mb(); + printk("CIA_init: W0_BASE was 0x%x\n", temp); + temp = *((vuip)CIA_IOC_PCI_W1_BASE); mb(); + printk("CIA_init: W1_BASE was 0x%x\n", temp); + temp = *((vuip)CIA_IOC_PCI_W2_BASE); mb(); + printk("CIA_init: W2_BASE was 0x%x\n", temp); + temp = *((vuip)CIA_IOC_PCI_W3_BASE); mb(); + printk("CIA_init: W3_BASE 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 ; + 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() ; + +#ifdef CONFIG_ALPHA_SRM_SETUP + /* check window 0 for enabled and mapped to 0 */ + if (((*(vuip)CIA_IOC_PCI_W0_BASE & 3) == 1) && + (*(vuip)CIA_IOC_PCI_T0_BASE == 0)) + { + CIA_DMA_WIN_BASE = *(vuip)CIA_IOC_PCI_W0_BASE & 0xfff00000U; + CIA_DMA_WIN_SIZE = *(vuip)CIA_IOC_PCI_W0_MASK & 0xfff00000U; + CIA_DMA_WIN_SIZE += 0x00100000U; +#if 1 + printk("cia_init: using Window 0 settings\n"); + printk("cia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", + *(vuip)CIA_IOC_PCI_W0_BASE, + *(vuip)CIA_IOC_PCI_W0_MASK, + *(vuip)CIA_IOC_PCI_T0_BASE); +#endif + } + else /* check window 1 for enabled and mapped to 0 */ + if (((*(vuip)CIA_IOC_PCI_W1_BASE & 3) == 1) && + (*(vuip)CIA_IOC_PCI_T1_BASE == 0)) + { + CIA_DMA_WIN_BASE = *(vuip)CIA_IOC_PCI_W1_BASE & 0xfff00000U; + CIA_DMA_WIN_SIZE = *(vuip)CIA_IOC_PCI_W1_MASK & 0xfff00000U; + CIA_DMA_WIN_SIZE += 0x00100000U; +#if 1 + printk("cia_init: using Window 1 settings\n"); + printk("cia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", + *(vuip)CIA_IOC_PCI_W1_BASE, + *(vuip)CIA_IOC_PCI_W1_MASK, + *(vuip)CIA_IOC_PCI_T1_BASE); +#endif + } + else /* check window 2 for enabled and mapped to 0 */ + if (((*(vuip)CIA_IOC_PCI_W2_BASE & 3) == 1) && + (*(vuip)CIA_IOC_PCI_T2_BASE == 0)) + { + CIA_DMA_WIN_BASE = *(vuip)CIA_IOC_PCI_W2_BASE & 0xfff00000U; + CIA_DMA_WIN_SIZE = *(vuip)CIA_IOC_PCI_W2_MASK & 0xfff00000U; + CIA_DMA_WIN_SIZE += 0x00100000U; +#if 1 + printk("cia_init: using Window 2 settings\n"); + printk("cia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", + *(vuip)CIA_IOC_PCI_W2_BASE, + *(vuip)CIA_IOC_PCI_W2_MASK, + *(vuip)CIA_IOC_PCI_T2_BASE); +#endif + } + else /* check window 3 for enabled and mapped to 0 */ + if (((*(vuip)CIA_IOC_PCI_W3_BASE & 3) == 1) && + (*(vuip)CIA_IOC_PCI_T3_BASE == 0)) + { + CIA_DMA_WIN_BASE = *(vuip)CIA_IOC_PCI_W3_BASE & 0xfff00000U; + CIA_DMA_WIN_SIZE = *(vuip)CIA_IOC_PCI_W3_MASK & 0xfff00000U; + CIA_DMA_WIN_SIZE += 0x00100000U; +#if 1 + printk("cia_init: using Window 3 settings\n"); + printk("cia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", + *(vuip)CIA_IOC_PCI_W3_BASE, + *(vuip)CIA_IOC_PCI_W3_MASK, + *(vuip)CIA_IOC_PCI_T3_BASE); +#endif + } + else /* we must use our defaults which were pre-initialized... */ +#endif /* SRM_SETUP */ + { /* * Set up the PCI->physical memory translation windows. * For now, windows 1,2 and 3 are disabled. In the future, we may @@ -401,6 +500,7 @@ unsigned long cia_init(unsigned long mem_start, unsigned long mem_end) *(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 @@ -412,17 +512,44 @@ unsigned long cia_init(unsigned long mem_start, unsigned long mem_end) } /* - * Finally, clear the CIA_CFG register, which gets used + * Next, clear the CIA_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 cia_cfg = *((vuip)CIA_IOC_CFG); mb(); + if (cia_cfg) { + printk("CIA_init: CFG was 0x%x\n", cia_cfg); + *((vuip)CIA_IOC_CFG) = 0; mb(); + } + } + + { + unsigned int cia_hae_mem = *((vuip)CIA_IOC_HAE_MEM); + unsigned int cia_hae_io = *((vuip)CIA_IOC_HAE_IO); #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); + printk("CIA_init: HAE_MEM was 0x%x\n", cia_hae_mem); + printk("CIA_init: HAE_IO was 0x%x\n", cia_hae_io); #endif - *((unsigned int *)CIA_IOC_CFG) = 0; mb(); +#ifdef CONFIG_ALPHA_SRM_SETUP + /* + sigh... For the SRM setup, unless we know apriori what the HAE + contents will be, we need to setup the arbitrary region bases + so we can test against the range of addresses and tailor the + region chosen for the SPARSE memory access. + + see include/asm-alpha/cia.h for the SPARSE mem read/write + */ + cia_sm_base_r1 = (cia_hae_mem ) & 0xe0000000UL; /* region 1 */ + cia_sm_base_r2 = (cia_hae_mem << 16) & 0xf8000000UL; /* region 2 */ + cia_sm_base_r3 = (cia_hae_mem << 24) & 0xfc000000UL; /* region 3 */ +#else /* SRM_SETUP */ + *((vuip)CIA_IOC_HAE_MEM) = 0; mb(); + cia_hae_mem = *((vuip)CIA_IOC_HAE_MEM); + *((vuip)CIA_IOC_HAE_IO) = 0; mb(); + cia_hae_io = *((vuip)CIA_IOC_HAE_IO); +#endif /* SRM_SETUP */ } return mem_start; @@ -430,9 +557,9 @@ unsigned long cia_init(unsigned long mem_start, unsigned long mem_end) 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)); + *((vuip)CIA_IOC_CIA_ERR) = 0x0180; mb(); return 0; } @@ -440,41 +567,45 @@ int cia_pci_clr_err(void) void cia_machine_check(unsigned long vector, unsigned long la_ptr, struct pt_regs * regs) { -#if 0 - printk("CIA machine check ignored\n") ; -#else struct el_common *mchk_header; + struct el_procdata *mchk_procdata; struct el_CIA_sysdata_mcheck *mchk_sysdata; + unsigned long * ptr; + const char * reason; + char buf[128]; + 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", + 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)); - DBG(("cia_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n", + 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 +#ifdef DEBUG_MCHECK { 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]); + printk(" +%lx %lx %lx\n", i*sizeof(long), + ptr[i], ptr[i+1]); } } -#endif /* DEBUG */ +#endif /* DEBUG_MCHECK */ /* * 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")); + if (CIA_mcheck_expected) { + DBGM(("CIA machine check expected\n")); CIA_mcheck_expected = 0; CIA_mcheck_taken = 1; mb(); @@ -483,12 +614,58 @@ void cia_machine_check(unsigned long vector, unsigned long la_ptr, cia_pci_clr_err(); wrmces(0x7); mb(); + return; + } + + 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; + + /* 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: + sprintf(buf, "reason for machine-check unknown (0x%x)", + (unsigned int) mchk_header->code); + reason = buf; + break; + } + wrmces(rdmces()); /* reset machine check pending flag */ + mb(); + + 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]); } -#if 1 - else - printk("CIA machine check NOT expected\n") ; -#endif -#endif } #endif /* CONFIG_ALPHA_CIA */ diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index b7a64848655a..a5b738a4c18b 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S @@ -4,6 +4,7 @@ * kernel entry-points */ +#include #include #define halt .long PAL_halt @@ -22,7 +23,7 @@ /* * stack offsets */ -#define SP_OFF 160 +#define SP_OFF 184 #define SWITCH_STACK_SIZE 320 @@ -47,9 +48,11 @@ * regs 9-15 preserved by C code * regs 16-18 saved by PAL-code * regs 29-30 saved and set up by PAL-code + * JRP - Save regs 16-18 in a special area of the stack, so that + * the palcode-provided values are available to the signal handler. */ #define SAVE_ALL \ - subq $30,160,$30; \ + subq $30,184,$30; \ stq $0,0($30); \ stq $1,8($30); \ stq $2,16($30); \ @@ -71,7 +74,10 @@ stq $28,144($30); \ lda $2,hae; \ ldq $2,HAE_CACHE($2); \ - stq $2,152($30) + stq $2,152($30); \ + stq $16,160($30); \ + stq $17,168($30); \ + stq $18,176($30) #define RESTORE_ALL \ lda $8,hae; \ @@ -107,11 +113,11 @@ ldq $26,128($30); \ ldq $27,136($30); \ ldq $28,144($30); \ - addq $30,160,$30 + addq $30,184,$30 .text .set noat -#ifdef __linux__ +#if defined(__linux__) && !defined(__ELF__) .set singlegp #endif @@ -160,6 +166,36 @@ entArith: .globl entIF .ent entIF entIF: +#ifdef CONFIG_KGDB + bne $16,1f /* not a bpt trap -> */ + /* + * Call kgdb if it's enabled and if "current" is not being + * traced or if we get a bpt in kernel mode (the architecture + * manual defines the values of $17 and $18 as "unpredictable", + * so they are fair game). + */ + lda $17,kgdb_enabled + ldl $17,0($17) + beq $17,1f /* kgdb not enabled -> */ + +#ifndef CONFIG_ALPHA_CABRIOLET + /* + * MILO on Cabriolet doesn't seem to setup the PS in the + * PALframe correctly. (davidm@azstarnet.com) + */ + ldq $18,0($30) /* get ps */ + and $18,8,$18 + beq $18,entKGDB +#endif + + lda $17,current_set + ldq $17,0($17) + bis $31,PF_PTRACED,$18 + ldq $17,TASK_FLAGS($17) + and $17,$18,$17 + beq $17,entKGDB +1: +#endif SAVE_ALL lda $27,do_entIF lda $26,ret_from_sys_call @@ -759,3 +795,127 @@ sys_call_table: .quad sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, do_entSys /* sys_afs_syscall */, sys_newuname .quad sys_nanosleep, sys_mremap, do_entSys, do_entSys, do_entSys .quad sys_pciconfig_read, sys_pciconfig_write, do_entSys, do_entSys, do_entSys + + +#ifdef CONFIG_KGDB + +#define KGDB_STACK_SIZE (8*1024) + + .lcomm kgdb_stack_bottom, KGDB_STACK_SIZE + +/* + * The following is the nasty part of entering KGDB. GDB assumes that + * it can access the memory below the interrupted thread's stack + * pointer (SP). This means that the stub cannot run on this stack + * (interrupts could overwrite changes made by GDB). Similarly, we do + * not want to bother the GDB user with the call chain leading from + * the interrupt handler to this function. That is, the SP reported + * to GDB should be the thread's SP at the point it was interrupted. We + * achieve all this by switching to KGDB's own stack before saving any + * registers (of course, the PAL-generated frame is already on the stack and + * we copy that part explicitly). GDB does whatever it wants to the + * thread's stack; and when it continues execution, we restore the + * registers from the private stack and return from the interrupt. + * + * This is not re-entrant---gdb on the host probably would get confused + * anyway, but we probably ought to detect that case at the least... + */ +.align 3 +.globl entKGDB +.ent entKGDB +entKGDB: + lda $16,kgdb_stack_bottom + lda $16,(KGDB_STACK_SIZE-48)($16) + bis $31,$30,$17 /* save real sp in a1 */ + bis $31,$16,$30 /* update sp atomically! */ + SAVE_ALL /* save regular stuff */ + /* + * Only now can we disable interrupts (swpipl may step on + * t0,t8..t11, and a0): + */ + bis $31,7,$16 + call_pal PAL_swpipl + + /* copy PAL frame to kgdb stack: */ + + ldq $1,0($17) + ldq $2,8($17) + ldq $3,16($17) + ldq $4,24($17) + ldq $5,32($17) + ldq $6,40($17) + + stq $1,0+184($30) + stq $2,8+184($30) + stq $3,16+184($30) + stq $4,24+184($30) + stq $5,32+184($30) + stq $6,40+184($30) + + /* allocate space for and save caller saved regs as well as orig sp: */ + + lda $30,-320($30) + addq $17,48,$17 /* pop PAL frame */ + stq $17,0($30) /* save original sp */ + + stq $9,0x08($30); stq $10,0x10($30); stq $11,0x18($30) + stq $12,0x20($30); stq $13,0x28($30); stq $14,0x30($30) + stq $15,0x38($30) + + stt $f0,0x40($30); stt $f1,0x48($30); stt $f2,0x50($30); stt $f3,0x58($30) + stt $f4,0x60($30); stt $f5,0x68($30); stt $f6,0x70($30); stt $f7,0x78($30) + stt $f8,0x80($30); stt $f9,0x88($30); stt $f10,0x90($30); stt $f11,0x98($30) + stt $f12,0xa0($30); stt $f13,0xa8($30); stt $f14,0xb0($30); stt $f15,0xb8($30) + stt $f16,0xc0($30); stt $f17,0xc8($30); stt $f18,0xd0($30); stt $f19,0xd8($30) + stt $f20,0xe0($30); stt $f21,0xe8($30); stt $f22,0xf0($30); stt $f23,0xf8($30) + stt $f24,0x100($30); stt $f25,0x108($30); stt $f26,0x110($30); stt $f27,0x118($30) + stt $f28,0x120($30); stt $f29,0x128($30); stt $f30,0x130($30); stt $f31,0x138($30) + + bis $31,$30,$16 + + lda $27,kgdb_handle_exception + jsr $26,($27),kgdb_handle_exception + + ldq $17,0($30) /* load new sp and caller-saved registers */ + + ldq $9,0x08($30); ldq $10,0x10($30); ldq $11,0x18($30) + ldq $12,0x20($30); ldq $13,0x28($30); ldq $14,0x30($30) + ldq $15,0x38($30) + + ldt $f0,0x40($30); ldt $f1,0x48($30); ldt $f2,0x50($30); ldt $f3,0x58($30) + ldt $f4,0x60($30); ldt $f5,0x68($30); ldt $f6,0x70($30); ldt $f7,0x78($30) + ldt $f8,0x80($30); ldt $f9,0x88($30); ldt $f10,0x90($30); ldt $f11,0x98($30) + ldt $f12,0xa0($30); ldt $f13,0xa8($30); ldt $f14,0xb0($30); ldt $f15,0xb8($30) + ldt $f16,0xc0($30); ldt $f17,0xc8($30); ldt $f18,0xd0($30); ldt $f19,0xd8($30) + ldt $f20,0xe0($30); ldt $f21,0xe8($30); ldt $f22,0xf0($30); ldt $f23,0xf8($30) + ldt $f24,0x100($30); ldt $f25,0x108($30); ldt $f26,0x110($30); ldt $f27,0x118($30) + ldt $f28,0x120($30); ldt $f29,0x128($30); ldt $f30,0x130($30); ldt $f31,0x138($30) + lda $30,320($30) /* pop extra register frame */ + + /* + * Copy PAL frame from kgdb stack to new stack so we can rti + * to it: + */ + ldq $1,0+184($30) + ldq $2,8+184($30) + ldq $3,16+184($30) + ldq $4,24+184($30) + ldq $5,32+184($30) + ldq $6,40+184($30) + + subq $17,48,$17 /* alloc space for PAL frame on new stack */ + + stq $1,0($17) + stq $2,8($17) + stq $3,16($17) + stq $4,24($17) + stq $5,32($17) + stq $6,40($17) + + RESTORE_ALL + bis $31,$17,$30 /* establish new sp */ + rti + +.end entKGDB + +#endif /* CONFIG_KGDB */ diff --git a/arch/alpha/kernel/head.S b/arch/alpha/kernel/head.S index 0c1fc8681ecc..bea8c4e64f75 100644 --- a/arch/alpha/kernel/head.S +++ b/arch/alpha/kernel/head.S @@ -92,6 +92,50 @@ 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 + + .align 3 + .globl cserve_ena + .ent cserve_ena +cserve_ena: + lda $30,-0x08($30) + stq $17,0($30) + bis $16,$16,$17 + lda $16,52($31) + call_pal PAL_cserve + ldq $17,0($30) + lda $30,0x08($30) + ret ($26) + .end cserve_ena + + .align 3 + .globl cserve_dis + .ent cserve_dis +cserve_dis: + lda $30,-0x08($30) + stq $17,0($30) + bis $16,$16,$17 + lda $16,53($31) + call_pal PAL_cserve + ldq $17,0($30) + lda $30,0x08($30) + ret ($26) + .end cserve_dis + # # The following two functions don't need trapb/excb instructions # around the mf_fpcr/mt_fpcr instructions because (a) the kernel diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c index a8d293a2eabc..3defc0878c66 100644 --- a/arch/alpha/kernel/irq.c +++ b/arch/alpha/kernel/irq.c @@ -27,6 +27,7 @@ #include extern void timer_interrupt(struct pt_regs * regs); +extern void cserve_update_hw(unsigned long, unsigned long); #if NR_IRQS > 64 # error Unable to handle more than 64 irq levels. @@ -42,7 +43,8 @@ extern void timer_interrupt(struct pt_regs * regs); * 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) + * or PYXIS (e.g. Miata, PC164-LX) + * 16..47 PCI interrupts 0..31 (xxx_INT_MASK reg) * Mikasa: * 16..31 PCI interrupts 0..15 (short at I/O port 536) * Other systems (not Mikasa) with 16 PCI interrupt lines: @@ -50,13 +52,43 @@ extern void timer_interrupt(struct pt_regs * regs); * 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) + * Takara: + * 16..19 PCI interrupts A thru D + * 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 */ +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. + * + * There deliberately isn't a case in here for the Takara since it + * wouldn't work anyway because the interrupt controller is bizarre. */ static void update_hw(unsigned long irq, unsigned long mask) { @@ -65,32 +97,111 @@ static void update_hw(unsigned long irq, unsigned long mask) mask |= 0x7ff00000UL << 16; #endif switch (irq) { -#if NR_IRQS == 48 - default: + +#ifdef CONFIG_ALPHA_SABLE + /* SABLE does everything different, so we manage it that way... :-( */ + /* the "irq" argument is really the mask bit number */ + case 0 ... 7: + outb(mask, 0x537); + break; + case 8 ... 15: + outb(mask >> 8, 0x53b); + break; + case 16 ... 23: + outb(mask >> 16, 0x53d); + break; +#else /* SABLE */ + +#if defined(CONFIG_ALPHA_NORITAKE) + /* note inverted sense of mask bits: */ + case 16 ... 31: + outw(~(mask >> 16), 0x54a); + break; + case 32 ... 47: + outw(~(mask >> 32), 0x54c); + break; +#endif /* NORITAKE */ + +#if defined(CONFIG_ALPHA_MIATA) + case 16 ... 47: + { unsigned long temp; + /* note inverted sense of mask bits: */ + /* make CERTAIN none of the bogus ints get enabled */ + *(unsigned long *)PYXIS_INT_MASK = + ~((long)mask >> 16) & ~0x400000000000063bUL; mb(); + temp = *(unsigned long *)PYXIS_INT_MASK; + break; + } +#endif /* MIATA */ + +#if defined(CONFIG_ALPHA_RUFFIAN) + case 16 ... 47: + { unsigned long temp; + /* note inverted sense of mask bits: */ + /* make CERTAIN none of the bogus ints get enabled */ + *(unsigned long *)PYXIS_INT_MASK = + ~((long)mask >> 16) & 0x00000000ffffffbfUL; mb(); + temp = *(unsigned long *)PYXIS_INT_MASK; + break; + } +#endif /* RUFFIAN */ + +#if defined(CONFIG_ALPHA_SX164) + case 16 ... 39: +#if defined(CONFIG_ALPHA_SRM) + cserve_update_hw(irq, mask); + break; +#else + { unsigned long temp; + /* make CERTAIN none of the bogus ints get enabled */ + *(unsigned long *)PYXIS_INT_MASK = + ~((long)mask >> 16) & ~0x000000000000003bUL; mb(); + temp = *(unsigned long *)PYXIS_INT_MASK; + break; + } +#endif /* SRM */ +#endif /* SX164 */ + +#if defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) + case 16 ... 47: /* note inverted sense of mask bits: */ *(unsigned int *)GRU_INT_MASK = ~(mask >> 16); mb(); break; +#endif /* ALCOR || XLT */ -#elif NR_IRQS == 33 - default: - outl(mask >> 16, 0x804); +#if defined(CONFIG_ALPHA_CABRIOLET) || \ + defined(CONFIG_ALPHA_EB66P) || \ + defined(CONFIG_ALPHA_EB164) || \ + defined(CONFIG_ALPHA_PC164) || \ + defined(CONFIG_ALPHA_LX164) +#if defined(CONFIG_ALPHA_SRM) + case 16 ... 34: + cserve_update_hw(irq, mask); + break; +#else /* SRM */ + case 16 ... 34: + outl(irq_mask >> 16, 0x804); break; +#endif /* SRM */ +#endif /* CABRIO || EB66P || EB164 || PC164 || LX164 */ -#elif defined(CONFIG_ALPHA_MIKASA) - default: +#if defined(CONFIG_ALPHA_MIKASA) + case 16 ... 31: outw(~(mask >> 16), 0x536); /* note invert */ break; +#endif /* MIKASA */ -#elif NR_IRQS == 32 +#if defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P) case 16 ... 23: outb(mask >> 16, 0x26); break; - - default: + case 24 ... 31: outb(mask >> 24, 0x27); break; -#endif +#endif /* EB66 || EB64P */ + /* handle ISA irqs last---fast devices belong on PCI... */ + /* this is common for all except SABLE! */ case 0 ... 7: /* ISA PIC1 */ outb(mask, 0x21); @@ -99,7 +210,10 @@ static void update_hw(unsigned long irq, unsigned long mask) case 8 ...15: /* ISA PIC2 */ outb(mask >> 8, 0xA1); break; - } + +#endif /* SABLE */ + + } /* end switch (irq) */ } static inline void mask_irq(unsigned long irq) @@ -120,7 +234,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); } @@ -130,7 +244,7 @@ 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); } @@ -164,7 +278,32 @@ 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; + } +#else /* CONFIG_ALPHA_SABLE */ if (irq < 16) { +#if defined(CONFIG_ALPHA_RUFFIAN) + /* ack pyxis ISA interrupt */ + *(unsigned long *)PYXIS_INT_REQ = (0x01UL << 7); + if (irq > 7) { + outb(0x20,0xa0); + } + outb(0x20,0x20); +#else /* RUFFIAN */ /* ACK the interrupt making it the lowest priority */ /* First the slave .. */ if (irq > 7) { @@ -178,7 +317,16 @@ static inline void ack_irq(int irq) *(int *)GRU_INT_CLEAR = 0x80000000; mb(); *(int *)GRU_INT_CLEAR = 0x00000000; mb(); #endif /* ALCOR || XLT */ +#endif /* RUFFIAN */ } +#if defined(CONFIG_ALPHA_RUFFIAN) + else { + /* ack pyxis int */ + *(unsigned long *)PYXIS_INT_REQ = (1UL << (irq-16)); + } +#endif /* RUFFIAN */ + +#endif /* CONFIG_ALPHA_SABLE */ } int request_irq(unsigned int irq, @@ -236,7 +384,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; @@ -264,7 +412,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; @@ -323,25 +471,39 @@ static inline void device_interrupt(int irq, int ack, struct pt_regs * regs) struct irqaction * action; if ((unsigned) irq > NR_IRQS) { - printk("device_interrupt: unexpected interrupt %d\n", irq); + printk("device_interrupt: illegal interrupt %d\n", irq); + return; + } + +#if defined(CONFIG_ALPHA_RUFFIAN) + /* RUFFIAN uses ISA IRQ #0 to deliver clock ticks */ + if (irq == 0) { + timer_interrupt(regs); + ack_irq(0); return; } +#endif /* RUFFIAN */ kstat.interrupts[irq]++; 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). */ mask_irq(ack); ack_irq(ack); - if (!action) + if (!action) { +#if 1 + printk("device_interrupt: unexpected interrupt %d\n", irq); +#endif return; + } if (action->flags & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); do { @@ -365,6 +527,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 @@ -554,8 +718,185 @@ 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 = (*(volatile unsigned long *)PYXIS_INT_REQ); + +#if 0 + printk("[0x%08lx/0x%08lx/0x%04x]", pld, + *(volatile unsigned long *)PYXIS_INT_MASK, + inb(0x20) | (inb(0xA0) << 8)); +#endif + +#ifdef CONFIG_ALPHA_MIATA + /* 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) */ +/* maybe HALT should only be used for SRM console boots? */ + pld &= 0x00000000fffff9c4UL; +#endif /* MIATA */ +#ifdef CONFIG_ALPHA_SX164 + /* for now, AND off any bits we are not interested in: */ + /* 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 /* SX164 */ + + /* + * 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); + } + *(unsigned long *)PYXIS_INT_REQ = 1UL << i; mb(); + tmp = *(volatile unsigned long *)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 */ + /* read the interrupt summary registers of NORITAKE */ + pld = ((unsigned long) inw(0x544) << 32) | + ((unsigned long) inw(0x542) << 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); +} + #endif /* CONFIG_PCI */ +#if defined(CONFIG_ALPHA_RUFFIAN) +static inline void ruffian_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 = (*(volatile unsigned long *)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;/* was ffff7f */ + + /* + * 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 not timer int */ + device_interrupt(16 + i,16 + i,regs); + } + *(unsigned long *)PYXIS_INT_REQ = 1UL << i; mb(); + tmp = *(volatile unsigned long *)PYXIS_INT_REQ; + } + restore_flags(flags); +} +#endif /* RUFFIAN */ + +static inline void takara_device_interrupt(unsigned long vector, + struct pt_regs * regs) +{ + unsigned long flags; + unsigned intstatus; + + save_flags(flags); + cli(); + + /* + * The PALcode will have passed us vectors 0x800 or 0x810, + * which are fairly arbitrary values and serve only to tell + * us whether an interrupt has come in on IRQ0 or IRQ1. If + * it's IRQ1 it's a PCI interrupt; if it's IRQ0, it's + * probably ISA, but PCI interrupts can come through IRQ0 + * as well if the interrupt controller isn't in accelerated + * mode. + * + * OTOH, the accelerator thing doesn't seem to be working + * overly well, so what we'll do instead is try directly + * examining the Master Interrupt Register to see if it's a + * PCI interrupt, and if _not_ then we'll pass it on to the + * ISA handler. + */ + + intstatus = inw(0x500) & 15; + if (intstatus) { + /* + * This is a PCI interrupt. Check each bit and + * despatch an interrupt if it's set. + */ + if (intstatus & 8) device_interrupt(16+3, 16+3, regs); + if (intstatus & 4) device_interrupt(16+2, 16+2, regs); + if (intstatus & 2) device_interrupt(16+1, 16+1, regs); + if (intstatus & 1) device_interrupt(16+0, 16+0, regs); + } else + isa_device_interrupt (vector, regs); + + restore_flags(flags); +} + /* * Jensen is special: the vector is 0x8X0 for EISA interrupt X, and * 0x9X0 for the local motherboard interrupts.. @@ -587,6 +928,9 @@ static inline void srm_device_interrupt(unsigned long vector, struct pt_regs * r save_flags(flags); cli(); +#if 0 +printk("srm_device_interrupt: vector 0x%lx\n", vector); +#endif ack = irq = (vector - 0x800) >> 4; @@ -608,11 +952,69 @@ static inline void srm_device_interrupt(unsigned long vector, struct pt_regs * r 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 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) ; } +/* PROBE_MASK is the bitset of irqs that we consider for autoprobing: */ +#if defined(CONFIG_ALPHA_P2K) + /* always mask out unused timer irq 0 and RTC irq 8 */ +# define PROBE_MASK (((1UL << NR_IRQS) - 1) & ~0x101UL) +#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) + /* 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) +#endif + /* * Start listening for interrupts.. */ @@ -624,10 +1026,13 @@ unsigned long probe_irq_on(void) unsigned int i; for (i = NR_IRQS - 1; i > 0; i--) { + if (!(PROBE_MASK & (1UL << i))) { + continue; + } action = irq_action[i]; if (!action) { enable_irq(i); - irqs |= (1 << i); + irqs |= (1UL << i); } } /* @@ -650,10 +1055,7 @@ int probe_irq_off(unsigned long irqs) { int i; - irqs &= irq_mask & ~1; /* always mask out irq 0---it's the unused timer */ -#ifdef CONFIG_ALPHA_P2K - irqs &= ~(1 << 8); /* mask out irq 8 since that's the unused RTC input to PIC */ -#endif + irqs &= irq_mask; if (!irqs) return 0; i = ffz(~irqs); @@ -676,6 +1078,14 @@ static void machine_check(unsigned long vector, unsigned long la, struct pt_regs 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) + extern void pyxis_machine_check(unsigned long vector, unsigned long la, + struct pt_regs * regs); + pyxis_machine_check(vector, la, regs); +#elif defined(CONFIG_ALPHA_T2) + extern void t2_machine_check(unsigned long vector, unsigned long la, + struct pt_regs * regs); + t2_machine_check(vector, la, regs); #else printk("Machine check\n"); #endif @@ -685,6 +1095,9 @@ asmlinkage void do_entInt(unsigned long type, unsigned long vector, unsigned lon unsigned long a3, unsigned long a4, unsigned long a5, struct pt_regs regs) { +#if 0 +printk("do_entInt: type 0x%lx\n", type); +#endif switch (type) { case 0: printk("Interprocessor interrupt? You must be kidding\n"); @@ -699,17 +1112,30 @@ asmlinkage void do_entInt(unsigned long type, unsigned long vector, unsigned lon #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 +#else /* everyone else */ + +#if 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 NR_IRQS == 33 +#elif defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P) || \ + defined(CONFIG_ALPHA_EB164) || defined(CONFIG_ALPHA_PC164) || \ + defined(CONFIG_ALPHA_LX164) cabriolet_and_eb66p_device_interrupt(vector, ®s); #elif defined(CONFIG_ALPHA_MIKASA) mikasa_device_interrupt(vector, ®s); -#elif NR_IRQS == 32 +#elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P) eb66_and_eb64p_device_interrupt(vector, ®s); +#elif defined(CONFIG_ALPHA_RUFFIAN) + ruffian_device_interrupt(vector, ®s); +#elif defined(CONFIG_ALPHA_TAKARA) + takara_device_interrupt(vector, ®s); #elif NR_IRQS == 16 isa_device_interrupt(vector, ®s); #endif +#endif /* everyone else */ return; case 4: printk("Performance counter interrupt\n"); @@ -724,23 +1150,141 @@ extern asmlinkage void entInt(void); void init_IRQ(void) { + unsigned int temp; + wrent(entInt, 0); - dma_outb(0, DMA1_RESET_REG); - dma_outb(0, DMA2_RESET_REG); - dma_outb(0, DMA1_CLR_MASK_REG); - dma_outb(0, DMA2_CLR_MASK_REG); -#if NR_IRQS == 48 + + outb(0, DMA1_RESET_REG); + outb(0, DMA2_RESET_REG); + +/* FIXME FIXME FIXME FIXME FIXME */ +#if !defined(CONFIG_ALPHA_SX164) + outb(0, DMA1_CLR_MASK_REG); + /* we need to figure out why this fails on the SX164 */ + outb(0, DMA2_CLR_MASK_REG); +#endif /* !SX164 */ +/* end FIXMEs */ + +#if defined(CONFIG_ALPHA_SABLE) + 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 */ +#else /* everybody but SABLE */ + +#if defined(CONFIG_ALPHA_MIATA) + /* note invert on MASK bits */ + *(unsigned long *)PYXIS_INT_MASK = + ~((long)irq_mask >> 16) & ~0x400000000000063bUL; mb(); +#if 0 + /* these break on MiataGL so we'll try not to do it at all */ + *(unsigned long *)PYXIS_INT_HILO = 0x000000B2UL; mb();/* ISA/NMI HI */ + *(unsigned long *)PYXIS_RT_COUNT = 0UL; mb();/* clear count */ +#endif + /* clear upper timer */ + *(unsigned long *)PYXIS_INT_REQ = 0x4000000000000180UL; mb(); + + /* Send -INTA pulses to clear any pending interrupts ...*/ + temp = *(volatile unsigned int *) IACK_SC; + + enable_irq(16 + 2); /* enable HALT switch - SRM only? */ + enable_irq(16 + 6); /* enable timer */ + enable_irq(16 + 7); /* enable ISA PIC cascade */ +#endif /* MIATA */ + +#if defined(CONFIG_ALPHA_SX164) +#if !defined(CONFIG_ALPHA_SRM) + /* note invert on MASK bits */ + *(unsigned long *)PYXIS_INT_MASK = ~((long)irq_mask >> 16); mb(); +#if 0 + *(unsigned long *)PYXIS_INT_HILO = 0x000000B2UL; mb();/* ISA/NMI HI */ + *(unsigned long *)PYXIS_RT_COUNT = 0UL; mb();/* clear count */ +#endif +#endif /* !SRM */ + enable_irq(16 + 6); /* enable timer */ + enable_irq(16 + 7); /* enable ISA PIC cascade */ +#endif /* SX164 */ + +#if defined(CONFIG_ALPHA_NORITAKE) + outw(~(irq_mask >> 16), 0x54a); /* note invert */ + outw(~(irq_mask >> 32), 0x54c); /* note invert */ +#endif /* NORITAKE */ + +#if defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) *(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 +#endif /* ALCOR || XLT */ + +#if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P) || \ + defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164) || \ + defined(CONFIG_ALPHA_EB164) +#if !defined(CONFIG_ALPHA_SRM) outl(irq_mask >> 16, 0x804); +#endif /* !SRM */ + /* Send -INTA pulses to clear any pending interrupts ...*/ + temp = *(volatile unsigned int *) IACK_SC; enable_irq(16 + 4); /* enable SIO cascade */ -#elif defined(CONFIG_ALPHA_MIKASA) +#endif /* CABRIO || EB66P || PC164 || LX164 || EB164 */ + +#if defined(CONFIG_ALPHA_MIKASA) outw(~(irq_mask >> 16), 0x536); /* note invert */ -#elif NR_IRQS == 32 +#endif /* MIKASA */ + +#if defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P) outb(irq_mask >> 16, 0x26); outb(irq_mask >> 24, 0x27); enable_irq(16 + 5); /* enable SIO cascade */ -#endif - enable_irq(2); /* enable cascade */ +#endif /* EB66 || EB64P */ + +#if defined(CONFIG_ALPHA_RUFFIAN) + /* invert 6&7 for i82371 */ + *(unsigned long *)PYXIS_INT_HILO = 0x000000c0UL;mb(); + *(unsigned long *)PYXIS_INT_CNFG = 0x00002064UL;mb(); /* all clear */ + *(unsigned long *)PYXIS_INT_MASK = ((long)0x00000000UL);mb(); + *(unsigned long *)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 ...*/ + temp = *(volatile unsigned int *) 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 */ +#endif /* RUFFIAN */ + +#ifdef CONFIG_ALPHA_TAKARA + { + unsigned int ctlreg = inl(0x500); + ctlreg &= ~0x8000; /* return to non-accelerated mode */ + outw(ctlreg >> 16, 0x502); + outw(ctlreg & 0xFFFF, 0x500); + ctlreg = 0x05107c00; /* enable the PCI interrupt register */ + printk("Setting to 0x%08x\n", ctlreg); + outw(ctlreg >> 16, 0x502); + outw(ctlreg & 0xFFFF, 0x500); + } +#endif /* TAKARA */ + + /* and finally, everyone but SABLE does this */ + enable_irq(2); /* enable 2nd PIC cascade */ + +#endif /* SABLE */ } diff --git a/arch/alpha/kernel/lca.c b/arch/alpha/kernel/lca.c index f153f5be1a05..65a8aef532ff 100644 --- a/arch/alpha/kernel/lca.c +++ b/arch/alpha/kernel/lca.c @@ -22,6 +22,7 @@ #ifdef CONFIG_ALPHA_LCA #define vulp volatile unsigned long * +#define vuip volatile unsigned int * /* * Machine check reasons. Defined according to PALcode sources @@ -46,6 +47,11 @@ #define MCHK_K_SIO_IOCHK 0x206 /* all platforms so far */ #define MCHK_K_DCSR 0x208 /* all but Noname */ +#ifdef CONFIG_ALPHA_SRM_SETUP +unsigned int LCA_DMA_WIN_BASE = LCA_DMA_WIN_BASE_DEFAULT; +unsigned int LCA_DMA_WIN_SIZE = LCA_DMA_WIN_SIZE_DEFAULT; +#endif /* SRM_SETUP */ + /* * Given a bus, device, and function number, compute resulting * configuration space address and setup the LCA_IOC_CONF register @@ -289,6 +295,40 @@ int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn, unsigned long lca_init(unsigned long mem_start, unsigned long mem_end) { +#ifdef CONFIG_ALPHA_SRM_SETUP + /* check window 0 for enabled and mapped to 0 */ + if ((*(vulp)LCA_IOC_W_BASE0 & (1UL<<33)) && + (*(vulp)LCA_IOC_T_BASE0 == 0)) + { + LCA_DMA_WIN_BASE = *(vulp)LCA_IOC_W_BASE0 & 0xffffffffUL; + LCA_DMA_WIN_SIZE = *(vulp)LCA_IOC_W_MASK0 & 0xffffffffUL; + LCA_DMA_WIN_SIZE += 1; +#if 1 + printk("lca_init: using Window 0 settings\n"); + printk("lca_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n", + *(vulp)LCA_IOC_W_BASE0, + *(vulp)LCA_IOC_W_MASK0, + *(vulp)LCA_IOC_T_BASE0); +#endif + } + else /* check window 2 for enabled and mapped to 0 */ + if ((*(vulp)LCA_IOC_W_BASE1 & (1UL<<33)) && + (*(vulp)LCA_IOC_T_BASE1 == 0)) + { + LCA_DMA_WIN_BASE = *(vulp)LCA_IOC_W_BASE1 & 0xffffffffUL; + LCA_DMA_WIN_SIZE = *(vulp)LCA_IOC_W_MASK1 & 0xffffffffUL; + LCA_DMA_WIN_SIZE += 1; +#if 1 + printk("lca_init: using Window 1 settings\n"); + printk("lca_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n", + *(vulp)LCA_IOC_W_BASE1, + *(vulp)LCA_IOC_W_MASK1, + *(vulp)LCA_IOC_T_BASE1); +#endif + } + else /* we must use our defaults... */ +#endif /* SRM_SETUP */ + { /* * Set up the PCI->physical memory translation windows. * For now, window 1 is disabled. In the future, we may @@ -296,9 +336,11 @@ unsigned long lca_init(unsigned long mem_start, unsigned long mem_end) * goes at 1 GB and is 1 GB large. */ *(vulp)LCA_IOC_W_BASE1 = 0UL<<33; + *(vulp)LCA_IOC_W_BASE0 = 1UL<<33 | LCA_DMA_WIN_BASE; *(vulp)LCA_IOC_W_MASK0 = LCA_DMA_WIN_SIZE - 1; *(vulp)LCA_IOC_T_BASE0 = 0; + } /* * Disable PCI parity for now. The NCR53c810 chip has @@ -386,11 +428,14 @@ void ioc_error (__u32 stat0, __u32 stat1) void lca_machine_check (unsigned long vector, unsigned long la, struct pt_regs *regs) { + unsigned long * ptr; const char * reason; union el_lca el; char buf[128]; + long i; - printk("lca: machine check (la=0x%lx,pc=0x%lx)\n", la, regs->pc); + printk(KERN_CRIT "lca: machine check (la=0x%lx,pc=0x%lx)\n", + la, regs->pc); el.c = (struct el_common *) la; /* * The first quadword after the common header always seems to @@ -399,9 +444,9 @@ void lca_machine_check (unsigned long vector, unsigned long la, struct pt_regs * * logout frame, the upper 32 bits is the machine check * revision level, which we ignore for now. */ - switch (el.s->reason & 0xffffffff) { + switch (el.c->code & 0xffffffff) { case MCHK_K_TPERR: reason = "tag parity error"; break; - case MCHK_K_TCPERR: reason = "tag something 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; @@ -416,7 +461,7 @@ void lca_machine_check (unsigned long vector, unsigned long la, struct pt_regs * case MCHK_K_UNKNOWN: default: sprintf(buf, "reason for machine-check unknown (0x%lx)", - el.s->reason & 0xffffffff); + el.c->code & 0xffffffff); reason = buf; break; } @@ -425,7 +470,8 @@ void lca_machine_check (unsigned long vector, unsigned long la, struct pt_regs * switch (el.c->size) { case sizeof(struct el_lca_mcheck_short): - printk(" Reason: %s (short frame%s, dc_stat=%lx):\n", + printk(KERN_CRIT + " Reason: %s (short frame%s, dc_stat=%lx):\pn", reason, el.c->retry ? ", retryable" : "", el.s->dc_stat); if (el.s->esr & ESR_EAV) { mem_error(el.s->esr, el.s->ear); @@ -436,11 +482,12 @@ void lca_machine_check (unsigned long vector, unsigned long la, struct pt_regs * break; case sizeof(struct el_lca_mcheck_long): - printk(" Reason: %s (long frame%s):\n", + printk(KERN_CRIT " Reason: %s (long frame%s):\n", reason, el.c->retry ? ", retryable" : ""); - printk(" reason: %lx exc_addr: %lx dc_stat: %lx\n", + printk(KERN_CRIT + " reason: %lx exc_addr: %lx dc_stat: %lx\n", el.l->pt[0], el.l->exc_addr, el.l->dc_stat); - printk(" car: %lx\n", el.l->car); + printk(KERN_CRIT " car: %lx\n", el.l->car); if (el.l->esr & ESR_EAV) { mem_error(el.l->esr, el.l->ear); } @@ -450,8 +497,55 @@ void lca_machine_check (unsigned long vector, unsigned long la, struct pt_regs * break; default: - printk(" Unknown errorlog size %d\n", el.c->size); + printk(KERN_CRIT " Unknown errorlog size %d\n", el.c->size); + } + + /* dump the the logout area to give all info: */ + + 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]); } } +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(); +} + #endif /* CONFIG_ALPHA_LCA */ diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 47fdf8e8b93b..705679019d51 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -32,8 +32,9 @@ #include #include -asmlinkage int sys_sethae(unsigned long hae, unsigned long a1, unsigned long a2, - unsigned long a3, unsigned long a4, unsigned long a5, +asmlinkage int sys_sethae(unsigned long hae, unsigned long a1, + unsigned long a2, unsigned long a3, + unsigned long a4, unsigned long a5, struct pt_regs regs) { (®s)->hae = hae; @@ -52,8 +53,42 @@ asmlinkage int sys_idle(void) } } +#include + +static void swap_context(struct thread_struct * pcb) +{ + __asm__ __volatile__( + "bis %0,%0,$16\n\t" + "call_pal %1\n\t" + : /* no outputs */ + : "r" (pcb), "i" (PAL_swpctx) + : "$0", "$1", "$16", "$22", "$23", "$24", "$25"); +} + void hard_reset_now(void) { +#if defined(CONFIG_ALPHA_SRM_SETUP) + extern void reset_for_srm(void); + extern struct hwrpb_struct *hwrpb; + extern struct thread_struct *original_pcb_ptr; + struct percpu_struct *cpup; + unsigned long flags; + + cpup = (struct percpu_struct *) + ((unsigned long)hwrpb + hwrpb->processor_offset); + flags = cpup->flags; +#if 1 + printk("hard_reset_now: flags 0x%lx\n", flags); +#endif + flags &= ~0x0000000000ff0001UL; /* clear reason to "default" */ + flags |= 0x0000000000020000UL; /* this is "cold bootstrap" */ +/* flags |= 0x0000000000030000UL; *//* this is "warm bootstrap" */ +/* flags |= 0x0000000000040000UL; *//* this is "remain halted" */ + cpup->flags = flags; + mb(); + reset_for_srm(); + swap_context(original_pcb_ptr); +#endif #if defined(CONFIG_ALPHA_SRM) && defined(CONFIG_ALPHA_ALCOR) /* who said DEC engineer's have no sense of humor? ;-)) */ *(int *) GRU_RESET = 0x0000dead; diff --git a/arch/alpha/kernel/pyxis.c b/arch/alpha/kernel/pyxis.c new file mode 100644 index 000000000000..d74190d28eb6 --- /dev/null +++ b/arch/alpha/kernel/pyxis.c @@ -0,0 +1,670 @@ +/* + * Code common to all PYXIS chips. + * + * Based on code written by David A Rusling (david.rusling@reo.mts.dec.com). + * + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +extern struct hwrpb_struct *hwrpb; +extern asmlinkage void wrmces(unsigned long mces); + +/* + * BIOS32-style PCI interface: + */ + +#ifdef CONFIG_ALPHA_PYXIS + +#ifdef DEBUG +# define DBG(args) printk args +#else +# define DBG(args) +#endif + +#define DEBUG_MCHECK +#ifdef DEBUG_MCHECK +# define DBG_MCK(args) printk args +/* #define DEBUG_MCHECK_DUMP */ +#else +# define DBG_MCK(args) +#endif + +#define vuip volatile unsigned int * +#define vulp volatile unsigned long * + +static volatile unsigned int PYXIS_mcheck_expected = 0; +static volatile unsigned int PYXIS_mcheck_taken = 0; +static unsigned int PYXIS_jd; + +#ifdef CONFIG_ALPHA_SRM_SETUP +unsigned int PYXIS_DMA_WIN_BASE = PYXIS_DMA_WIN_BASE_DEFAULT; +unsigned int PYXIS_DMA_WIN_SIZE = PYXIS_DMA_WIN_SIZE_DEFAULT; +unsigned long pyxis_sm_base_r1, pyxis_sm_base_r2, pyxis_sm_base_r3; +#endif /* SRM_SETUP */ + +/* + * 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, temp; + 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(); + temp = *((vuip)PYXIS_ERR); + 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(); + temp = *((vuip)PYXIS_CFG); + 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(); + if (PYXIS_mcheck_taken) { + PYXIS_mcheck_taken = 0; + value = 0xffffffffU; + mb(); + } + 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(); + temp = *((vuip)PYXIS_CFG); + } + + 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, temp; + 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(); + temp = *((vuip)PYXIS_ERR); + 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(); + temp = *((vuip)PYXIS_CFG); + DBG(("conf_read: TYPE1 access\n")); + } + + draina(); + PYXIS_mcheck_expected = 1; + mb(); + /* access configuration space: */ + *((vuip)addr) = value; + mb(); + mb(); + temp = *((vuip)PYXIS_ERR); /* do a PYXIS read to force the write */ + 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(); + temp = *((vuip)PYXIS_CFG); + } + + 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; + +#if 0 +printk("pyxis_init: PYXIS_ERR_MASK 0x%x\n", *(vuip)PYXIS_ERR_MASK); +printk("pyxis_init: PYXIS_ERR 0x%x\n", *(vuip)PYXIS_ERR); + +printk("pyxis_init: PYXIS_INT_REQ 0x%lx\n", *(vulp)PYXIS_INT_REQ); +printk("pyxis_init: PYXIS_INT_MASK 0x%lx\n", *(vulp)PYXIS_INT_MASK); +printk("pyxis_init: PYXIS_INT_ROUTE 0x%lx\n", *(vulp)PYXIS_INT_ROUTE); +printk("pyxis_init: PYXIS_INT_HILO 0x%lx\n", *(vulp)PYXIS_INT_HILO); +printk("pyxis_init: PYXIS_INT_CNFG 0x%x\n", *(vuip)PYXIS_INT_CNFG); +printk("pyxis_init: PYXIS_RT_COUNT 0x%lx\n", *(vulp)PYXIS_RT_COUNT); +#endif + +#if 0 +printk("pyxis_init: W0 BASE 0x%x MASK 0x%x TRANS 0x%x\n", + *(vuip)PYXIS_W0_BASE, *(vuip)PYXIS_W0_MASK, *(vuip)PYXIS_T0_BASE); +printk("pyxis_init: W1 BASE 0x%x MASK 0x%x TRANS 0x%x\n", + *(vuip)PYXIS_W1_BASE, *(vuip)PYXIS_W1_MASK, *(vuip)PYXIS_T1_BASE); +printk("pyxis_init: W2 BASE 0x%x MASK 0x%x TRANS 0x%x\n", + *(vuip)PYXIS_W2_BASE, *(vuip)PYXIS_W2_MASK, *(vuip)PYXIS_T2_BASE); +printk("pyxis_init: W3 BASE 0x%x MASK 0x%x TRANS 0x%x\n", + *(vuip)PYXIS_W3_BASE, *(vuip)PYXIS_W3_MASK, *(vuip)PYXIS_T3_BASE); +#endif + + /* + * Set up error reporting. Make sure CPU_PE is OFF in the mask. + */ + pyxis_err = *(vuip)PYXIS_ERR_MASK; + pyxis_err &= ~4; + *(vuip)PYXIS_ERR_MASK = pyxis_err; + mb(); + pyxis_err = *(vuip)PYXIS_ERR_MASK; + + 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_SRM_SETUP + /* check window 0 for enabled and mapped to 0 */ + if (((*(vuip)PYXIS_W0_BASE & 3) == 1) && + (*(vuip)PYXIS_T0_BASE == 0) && + ((*(vuip)PYXIS_W0_MASK & 0xfff00000U) > 0x0ff00000U)) + { + PYXIS_DMA_WIN_BASE = *(vuip)PYXIS_W0_BASE & 0xfff00000U; + PYXIS_DMA_WIN_SIZE = *(vuip)PYXIS_W0_MASK & 0xfff00000U; + PYXIS_DMA_WIN_SIZE += 0x00100000U; +#if 1 + printk("pyxis_init: using Window 0 settings\n"); + printk("pyxis_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", + *(vuip)PYXIS_W0_BASE, + *(vuip)PYXIS_W0_MASK, + *(vuip)PYXIS_T0_BASE); +#endif + } + else /* check window 1 for enabled and mapped to 0 */ + if (((*(vuip)PYXIS_W1_BASE & 3) == 1) && + (*(vuip)PYXIS_T1_BASE == 0) && + ((*(vuip)PYXIS_W1_MASK & 0xfff00000U) > 0x0ff00000U)) +{ + PYXIS_DMA_WIN_BASE = *(vuip)PYXIS_W1_BASE & 0xfff00000U; + PYXIS_DMA_WIN_SIZE = *(vuip)PYXIS_W1_MASK & 0xfff00000U; + PYXIS_DMA_WIN_SIZE += 0x00100000U; +#if 1 + printk("pyxis_init: using Window 1 settings\n"); + printk("pyxis_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", + *(vuip)PYXIS_W1_BASE, + *(vuip)PYXIS_W1_MASK, + *(vuip)PYXIS_T1_BASE); +#endif + } + else /* check window 2 for enabled and mapped to 0 */ + if (((*(vuip)PYXIS_W2_BASE & 3) == 1) && + (*(vuip)PYXIS_T2_BASE == 0) && + ((*(vuip)PYXIS_W2_MASK & 0xfff00000U) > 0x0ff00000U)) + { + PYXIS_DMA_WIN_BASE = *(vuip)PYXIS_W2_BASE & 0xfff00000U; + PYXIS_DMA_WIN_SIZE = *(vuip)PYXIS_W2_MASK & 0xfff00000U; + PYXIS_DMA_WIN_SIZE += 0x00100000U; +#if 1 + printk("pyxis_init: using Window 2 settings\n"); + printk("pyxis_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", + *(vuip)PYXIS_W2_BASE, + *(vuip)PYXIS_W2_MASK, + *(vuip)PYXIS_T2_BASE); +#endif + } + else /* check window 3 for enabled and mapped to 0 */ + if (((*(vuip)PYXIS_W3_BASE & 3) == 1) && + (*(vuip)PYXIS_T3_BASE == 0) && + ((*(vuip)PYXIS_W3_MASK & 0xfff00000U) > 0x0ff00000U)) + { + PYXIS_DMA_WIN_BASE = *(vuip)PYXIS_W3_BASE & 0xfff00000U; + PYXIS_DMA_WIN_SIZE = *(vuip)PYXIS_W3_MASK & 0xfff00000U; + PYXIS_DMA_WIN_SIZE += 0x00100000U; +#if 1 + printk("pyxis_init: using Window 3 settings\n"); + printk("pyxis_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", + *(vuip)PYXIS_W3_BASE, + *(vuip)PYXIS_W3_MASK, + *(vuip)PYXIS_T3_BASE); +#endif + } + else /* we must use our defaults which were pre-initialized... */ +#endif /* SRM_SETUP */ + { +#if defined(CONFIG_ALPHA_RUFFIAN) +#if 1 + printk("pyxis_init: skipping window register rewrites... " + "trust DeskStation firmware!\n"); +#endif +#else /* RUFFIAN */ + /* + * 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 /* RUFFIAN */ + } + + /* + * 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; + } + + /* + * Next, 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, temp; + pyxis_cfg = *((vuip)PYXIS_CFG); mb(); + if (pyxis_cfg != 0) { +#if 1 + printk("PYXIS_init: CFG was 0x%x\n", pyxis_cfg); +#endif + *((vuip)PYXIS_CFG) = 0; mb(); + temp = *((vuip)PYXIS_CFG); + } + } + + { + 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 +#ifdef CONFIG_ALPHA_SRM_SETUP + /* + sigh... For the SRM setup, unless we know apriori what the HAE + contents will be, we need to setup the arbitrary region bases + so we can test against the range of addresses and tailor the + region chosen for the SPARSE memory access. + + see include/asm-alpha/pyxis.h for the SPARSE mem read/write + */ + pyxis_sm_base_r1 = (pyxis_hae_mem ) & 0xe0000000UL;/* region 1 */ + pyxis_sm_base_r2 = (pyxis_hae_mem << 16) & 0xf8000000UL;/* region 2 */ + pyxis_sm_base_r3 = (pyxis_hae_mem << 24) & 0xfc000000UL;/* region 3 */ +#else /* SRM_SETUP */ + *((vuip)PYXIS_HAE_MEM) = 0U; mb(); + pyxis_hae_mem = *((vuip)PYXIS_HAE_MEM); + *((vuip)PYXIS_HAE_IO) = 0; mb(); + pyxis_hae_io = *((vuip)PYXIS_HAE_IO); +#endif /* SRM_SETUP */ + } + + /* + * Finally, check that the PYXIS_CTRL1 has IOA_BEN set for + * enabling byte/word PCI bus space(s) access. + */ + { + unsigned int ctrl1; + ctrl1 = *((vuip) PYXIS_CTRL1); + if (!(ctrl1 & 1)) { +#if 0 + printk("PYXIS_init: enabling byte/word PCI space\n"); +#endif + *((vuip) PYXIS_CTRL1) = ctrl1 | 1; mb(); + ctrl1 = *((vuip)PYXIS_CTRL1); + } + } + + 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) +{ +#if 0 + printk("PYXIS machine check ignored\n") ; +#else + 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(); + 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(); + 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(); + draina(); + pyxis_pci_clr_err(); + wrmces(0x7); + mb(); + } +#endif +#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, it uses + * the Bank Configuration Registers in PYXIS to obtain the size. + */ +unsigned long pyxis_get_bank_size(unsigned long offset) +{ + unsigned long bank_addr; + + /* valid offsets are: 0x800, 0x840 and 0x880 + * since Ruffian only uses three banks + */ + bank_addr = (unsigned long)PYXIS_MCR + offset; + + /* check BANK_ENABLE */ + if (*((unsigned long *)bank_addr) && 0x01) + { + /* do case on BANK_SIZE bits */ + switch (*((unsigned long *)bank_addr) & 0x01e) + { + case 0x00: return 0x40000000UL; break; /* 1G */ + case 0x02: return 0x20000000UL; break; /* 512M */ + case 0x04: return 0x10000000UL; break; /* 256M */ + case 0x06: return 0x08000000UL; break; /* 128M */ + case 0x08: return 0x04000000UL; break; /* 64M */ + case 0x0a: return 0x02000000UL; break; /* 32M */ + case 0x0c: return 0x01000000UL; break; /* 16M */ + case 0x0e: return 0x00800000UL; break; /* 8M */ + case 0x10: return 0x80000000UL; break; /* 2G */ + default : return 0x00000000UL; break; /* ERROR*/ + } + } else + return 0x00UL; +} +#endif /* CONFIG_ALPHA_RUFFIAN */ + +#endif /* CONFIG_ALPHA_PYXIS */ diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index 7ad7c41ab081..5281161552c0 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c @@ -22,6 +22,7 @@ #include #include #include /* CONFIG_ALPHA_LCA etc */ +#include #include #include @@ -58,13 +59,26 @@ 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 */ +#else 0, 25, /* orig-x, orig-y */ +#endif { 0, 0 }, /* unused */ 0, /* orig-video-page */ 0, /* orig-video-mode */ +#if defined(CONFIG_ALPHA_BOOK1) + 100, /* orig-video-cols */ +#else 80, /* orig-video-cols */ +#endif 0,0,0, /* ega_ax, ega_bx, ega_cx */ +#if defined(CONFIG_ALPHA_BOOK1) + 37, /* orig-video-lines */ +#else 25, /* orig-video-lines */ +#endif 1, /* orig-video-isVGA */ 16 /* orig-video-points */ }; @@ -84,9 +98,12 @@ static void init_pit (void) outb(0x18, 0x41); #endif +#if !defined(CONFIG_ALPHA_RUFFIAN) + /* Ruffian depends on the system timer established in MILO!! */ outb(0x36, 0x43); /* counter 0: system timer */ outb(0x00, 0x40); outb(0x00, 0x40); +#endif /* RUFFIAN */ outb(0xb6, 0x43); /* counter 2: speaker */ outb(0x31, 0x42); @@ -121,9 +138,19 @@ void setup_arch(char **cmdline_p, init_pit(); + if ((CMOS_READ(RTC_FREQ_SELECT) & 0x3f) != 0x26) { +#if 1 + printk("init_timers: setting RTC_FREQ to 1024/sec\n"); +#endif + CMOS_WRITE(0x26, RTC_FREQ_SELECT); + } + hwrpb = (struct hwrpb_struct*)(IDENT_ADDR + INIT_HWRPB->phys_addr); +#ifndef CONFIG_ALPHA_SRM_SETUP set_hae(hae.cache); /* sync HAE register w/hae_cache */ +#endif /* !SRM_SETUP */ + wrmces(0x7); /* reset enable correctable error reports */ ROOT_DEV = to_kdev_t(0x0802); /* sda2 */ @@ -154,39 +181,161 @@ 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 } -/* - * BUFFER is PAGE_SIZE bytes long. +# define N(a) (sizeof(a)/sizeof(a[0])) + +/* A change was made to the HWRPB via an ECO and the following code tracks + * a part of the ECO. The HWRPB version must be 5 or higher or the ECO + * was not implemented in the console firmware. If its at rev 5 or greater + * we can get the platform ascii string name from the HWRPB. Thats what this + * function does. It checks the rev level and if the string is in the HWRPB + * it returns the addtess of the string ... a pointer to the platform name. + * + * Returns: + * - Pointer to a ascii string if its in the HWRPB + * - Pointer to a blank string if the data is not in the HWRPB. */ +static char * +platform_string(void) +{ + struct dsr_struct *dsr; + static char unk_system_string[] = "N/A"; + + /* Go to the console for the string pointer. + * If the rpb_vers is not 5 or greater the rpb + * is old and does not have this data in it. + */ + if (hwrpb->revision < 5) + return (unk_system_string); + else { + /* The Dynamic System Recognition struct + * has the system platform name starting + * after the character count of the string. + */ + dsr = ((struct dsr_struct *) + ((char *)hwrpb + hwrpb->dsr_offset)); + return ((char *)dsr + (dsr->sysname_off + + sizeof(long))); + } +} + +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", "14", "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}; + + static char * rawhide_names[] = {"Dodge", "Wrangler", "Durango", + "Tincup", "DaVinci"}; + static int rawhide_indices[] = {0,0,0,1,1,2,2,3,3,4,4}; + + 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) { /* select by family */ + default: /* default to variation "0" ????FIXME???? */ + break; + 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; + case ST_DEC_RAWHIDE: + if (member < N(rawhide_indices)) + *variation_name = rawhide_names[rawhide_indices[member]]; + break; + } /* end family switch */ + return; +} + int get_cpuinfo(char *buffer) +/* BUFFER is PAGE_SIZE bytes long. */ { 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" + "EV3", "EV4", "Unknown 1", "LCA4", "EV5", "EV45", "EV56", + "EV6", "PCA56" }; struct percpu_struct *cpu; unsigned int cpu_index; - long sysname_index; + char *systype_name; + char *sysvariation_name; extern struct unaligned_stat { unsigned long count, va, pc; } unaligned[2]; -# define N(a) (sizeof(a)/sizeof(a[0])) cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset); cpu_index = (unsigned) (cpu->type - 1); - sysname_index = hwrpb->sys_type + SYSTYPE_NAME_BIAS; + get_sysnames(hwrpb->sys_type, hwrpb->sys_variation, + &systype_name, &sysvariation_name); return sprintf(buffer, "cpu\t\t\t: Alpha\n" @@ -195,7 +344,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" @@ -205,14 +354,13 @@ int get_cpuinfo(char *buffer) "max. addr. space #\t: %ld\n" "BogoMIPS\t\t: %lu.%02lu\n" "kernel unaligned acc\t: %ld (pc=%lx,va=%lx)\n" - "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n", + "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n" + "platform string\t\t: %s\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, + systype_name, sysvariation_name, hwrpb->sys_revision, (char*)hwrpb->ssn, hwrpb->cycle_freq, hwrpb->intr_freq / 4096, @@ -222,6 +370,7 @@ int get_cpuinfo(char *buffer) hwrpb->max_asn, 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 + unaligned[1].count, unaligned[1].pc, unaligned[1].va, + platform_string()); } +# undef N diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index 91abaf4f0390..91fd485a164b 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c @@ -203,6 +203,9 @@ static void setup_frame(struct sigaction * sa, put_fs_quad(regs->gp , sc->sc_regs+29); for (i = 0; i < 31; i++) put_fs_quad(sw->fp[i], sc->sc_fpregs+i); + put_fs_quad(regs->trap_a0, &sc->sc_traparg_a0); + put_fs_quad(regs->trap_a1, &sc->sc_traparg_a1); + put_fs_quad(regs->trap_a2, &sc->sc_traparg_a2); /* * The following is: diff --git a/arch/alpha/kernel/smc.c b/arch/alpha/kernel/smc.c new file mode 100644 index 000000000000..ae9f5d8065d7 --- /dev/null +++ b/arch/alpha/kernel/smc.c @@ -0,0 +1,2842 @@ +/* + * SMC 37C93X and 37C669 initialization code + */ +#include +#include + +#if 0 +# define DBG_DEVS(args) printk args +#else +# define DBG_DEVS(args) +#endif + +#include +#include +#include +#include + +#include +#include +#include + +#define KB 1024 +#define MB (1024*KB) +#define GB (1024*MB) + +#if defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164) + +/* 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 + +void SMC93X_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 ); + /* IDE on the SMC is not enabled; CMD646 (PCI) on MB */ + SMCEnableKYBD( SMCUltraBase ); + SMCEnableFDC( SMCUltraBase ); +#if SMC_DEBUG + SMCReportDeviceStatus( SMCUltraBase ); +#endif + SMCRunState( SMCUltraBase ); + } + else { +#if SMC_DEBUG + printk( "No SMC FDC37C93X Ultra I/O Controller found\n" ); +#endif + } +} + +#endif /* PC164 || LX164 */ + +/* we include MIATA because the GL has the SMC669 on board */ +#if defined(CONFIG_ALPHA_SX164) || defined(CONFIG_ALPHA_MIATA) + +#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 = 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 = 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[] = + { + 0x3F0UL, /* Primary address */ + 0x370UL, /* Secondary address */ + 0UL /* End of list */ + }; + +/* +** Global Pointer to the Super I/O device +*/ +static SMC37c669_CONFIG_REGS *SMC37c669 = 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; + +/* +** The following definition is for the default IRQ +** translation table. +*/ +static SMC37c669_IRQ_TRANSLATION_ENTRY SMC37c669_default_irq_table[ ] = + { + { 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; + +/* +** The following definition is the default DRQ +** translation table. +*/ +static SMC37c669_DRQ_TRANSLATION_ENTRY SMC37c669_default_drq_table[ ] = + { + { 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 *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 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 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 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 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 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 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 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 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 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 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 *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 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 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 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 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 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 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 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 +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 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 + } +} + +#endif /* SX164 */ diff --git a/arch/alpha/kernel/t2.c b/arch/alpha/kernel/t2.c new file mode 100644 index 000000000000..dbcc5b645421 --- /dev/null +++ b/arch/alpha/kernel/t2.c @@ -0,0 +1,654 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +extern struct hwrpb_struct *hwrpb; +extern asmlinkage void wrmces(unsigned long mces); +extern asmlinkage unsigned long whami(void); + +#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 CONFIG_ALPHA_T2 + +#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; + +#ifdef CONFIG_ALPHA_SRM_SETUP +unsigned int T2_DMA_WIN_BASE = T2_DMA_WIN_BASE_DEFAULT; +unsigned int T2_DMA_WIN_SIZE = T2_DMA_WIN_SIZE_DEFAULT; +unsigned long t2_sm_base; +#endif /* SRM_SETUP */ + +/* + * 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; +#if 0 + addr = (device_fn << 8) | (where); +#else + addr = (0x0800L << device) | ((device_fn & 7) << 8) | (where); +#endif + } 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 = *((volatile unsigned int *)T2_IOCSR); + *((volatile unsigned int *)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 = *((unsigned int *)T2_IOC_CFG); + mb(); + *((unsigned int *)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 = *((volatile unsigned int *)addr); + mb(); + mb(); + 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) { + *((unsigned int *)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 = *((volatile unsigned int *)T2_IOCSR); + *((volatile unsigned int *)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 = *((unsigned int *)T2_IOC_CFG); + mb(); + *((unsigned int *)T2_IOC_CFG) = t2_cfg | 1; + DBG(("conf_write: TYPE1 access\n")); + } + draina(); +#endif + T2_mcheck_expected = 1; + mb(); + /* access configuration space: */ + *((volatile unsigned int *)addr) = value; + mb(); + mb(); + T2_mcheck_expected = 0; + mb(); + +#if 0 + /* if Type1 access, must reset IOC CFG so normal IO space ops work */ + if (type1) { + *((unsigned int *)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", *((unsigned long *)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 + +#ifdef CONFIG_ALPHA_SRM_SETUP + /* check window 1 for enabled and mapped to 0 */ + if (((*(vulp)T2_WBASE1 & (3UL<<18)) == (2UL<<18)) && + (*(vuip)T2_TBASE1 == 0)) + { + T2_DMA_WIN_BASE = *(vulp)T2_WBASE1 & 0xfff00000UL; + T2_DMA_WIN_SIZE = *(vulp)T2_WMASK1 & 0xfff00000UL; + T2_DMA_WIN_SIZE += 0x00100000UL; +/* DISABLE window 2!! ?? */ +#if 1 + printk("t2_init: using Window 1 settings\n"); + printk("t2_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n", + *(vulp)T2_WBASE1, + *(vulp)T2_WMASK1, + *(vulp)T2_TBASE1); +#endif + } + else /* check window 2 for enabled and mapped to 0 */ + if (((*(vulp)T2_WBASE2 & (3UL<<18)) == (2UL<<18)) && + (*(vuip)T2_TBASE2 == 0)) + { + T2_DMA_WIN_BASE = *(vulp)T2_WBASE2 & 0xfff00000UL; + T2_DMA_WIN_SIZE = *(vulp)T2_WMASK2 & 0xfff00000UL; + T2_DMA_WIN_SIZE += 0x00100000UL; +/* DISABLE window 1!! ?? */ +#if 1 + printk("t2_init: using Window 2 settings\n"); + printk("t2_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n", + *(vulp)T2_WBASE2, + *(vulp)T2_WMASK2, + *(vulp)T2_TBASE2); +#endif + } + else /* we must use our defaults... */ +#endif /* SRM_SETUP */ + { + /* + * 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... + */ + { + unsigned long t2_hae_1 = *((unsigned long *)T2_HAE_1); + unsigned long t2_hae_2 = *((unsigned long *)T2_HAE_2); + unsigned long t2_hae_3 = *((unsigned long *)T2_HAE_3); + unsigned long t2_hae_4 = *((unsigned long *)T2_HAE_4); +#if 1 + printk("T2_init: HAE1 was 0x%lx\n", t2_hae_1); + printk("T2_init: HAE2 was 0x%lx\n", t2_hae_2); + printk("T2_init: HAE3 was 0x%lx\n", t2_hae_3); + printk("T2_init: HAE4 was 0x%lx\n", t2_hae_4); +#endif +#ifdef CONFIG_ALPHA_SRM_SETUP + /* + sigh... For the SRM setup, unless we know apriori what the HAE + contents will be, we need to setup the arbitrary region bases + so we can test against the range of addresses and tailor the + region chosen for the SPARSE memory access. + + see include/asm-alpha/t2.h for the SPARSE mem read/write + */ + t2_sm_base = (t2_hae_1 << 27) & 0xf8000000UL; +#else /* SRM_SETUP */ + *((unsigned int *)T2_HAE_1) = 0; mb(); + *((unsigned int *)T2_HAE_2) = 0; mb(); + *((unsigned int *)T2_HAE_3) = 0; mb(); +#if 0 + *((unsigned int *)T2_HAE_4) = 0; mb(); +#endif +#endif /* SRM_SETUP */ + } + +#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 */ + +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; + + *(unsigned long *)T2_CERR1 |= *(unsigned long *)T2_CERR1; + *(unsigned long *)T2_PERR1 |= *(unsigned long *)T2_PERR1; + + mb(); + mb(); + 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(); + 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(); + 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]); + } +} + +#endif /* CONFIG_ALPHA_T2 */ diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c index 694820c96ede..6dd3c129b1f0 100644 --- a/arch/alpha/kernel/traps.c +++ b/arch/alpha/kernel/traps.c @@ -286,7 +286,7 @@ asmlinkage void do_entUnaUser(void * va, unsigned long opcode, unsigned long reg extern void alpha_write_fp_reg (unsigned long reg, unsigned long val); extern unsigned long alpha_read_fp_reg (unsigned long reg); - pc_addr = frame + 7 + 20 + 1; /* pc in PAL frame */ + pc_addr = frame + 7 + 20 + 3 /* em86 */ + 1; /* pc in PAL frame */ if (cnt >= 5 && jiffies - last_time > 5*HZ) { cnt = 0; @@ -336,7 +336,7 @@ asmlinkage void do_entUnaUser(void * va, unsigned long opcode, unsigned long reg case 16: case 17: case 18: /* a0-a2 in PAL frame */ - reg_addr += 7 + 20 + 3 + (reg - 16); + reg_addr += 7 + 20 + 3 /* em86 */ + 3 + (reg - 16); break; case 19: case 20: case 21: case 22: case 23: @@ -347,7 +347,7 @@ asmlinkage void do_entUnaUser(void * va, unsigned long opcode, unsigned long reg case 29: /* gp in PAL frame */ - reg_addr += 7 + 20 + 2; + reg_addr += 7 + 20 + 3 /* em86 */ + 2; break; case 30: diff --git a/arch/alpha/math-emu/fp-emul.c b/arch/alpha/math-emu/fp-emul.c index f45b7069b60d..43a5b1fa0c65 100644 --- a/arch/alpha/math-emu/fp-emul.c +++ b/arch/alpha/math-emu/fp-emul.c @@ -13,9 +13,9 @@ #define OPC_INTL 0x11 #define OPC_INTS 0x12 #define OPC_INTM 0x13 -#define OPC_FLTV 0x14 -#define OPC_FLTI 0x15 -#define OPC_FLTL 0x16 +#define OPC_FLTV 0x15 +#define OPC_FLTI 0x16 +#define OPC_FLTL 0x17 #define OPC_MISC 0x18 diff --git a/arch/alpha/mm/init.c b/arch/alpha/mm/init.c index 12676f1aa55f..e550774d94bf 100644 --- a/arch/alpha/mm/init.c +++ b/arch/alpha/mm/init.c @@ -26,6 +26,8 @@ extern void die_if_kernel(char *,struct pt_regs *,long); extern void show_net_buffers(void); +struct thread_struct * original_pcb_ptr; + /* * BAD_PAGE is the page that is used for page faults when linux * is out-of-memory. Older versions of linux just did a @@ -81,15 +83,19 @@ void show_mem(void) extern unsigned long free_area_init(unsigned long, unsigned long); -static void load_PCB(struct thread_struct * pcb) +static struct thread_struct * load_PCB(struct thread_struct * pcb) { + struct thread_struct *old_pcb; + __asm__ __volatile__( - "stq $30,0(%0)\n\t" - "bis %0,%0,$16\n\t" - "call_pal %1" - : /* no outputs */ + "stq $30,0(%1)\n\t" + "bis %1,%1,$16\n\t" + "call_pal %2\n\t" + "bis $0,$0,%0" + : "=r" (old_pcb) : "r" (pcb), "i" (PAL_swpctx) : "$0", "$1", "$16", "$22", "$23", "$24", "$25"); + return old_pcb; } /* @@ -107,10 +113,15 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem) start_mem = free_area_init(start_mem, end_mem); /* find free clusters, update mem_map[] accordingly */ - memdesc = (struct memdesc_struct *) (INIT_HWRPB->mddt_offset + (unsigned long) INIT_HWRPB); + memdesc = (struct memdesc_struct *) + (INIT_HWRPB->mddt_offset + (unsigned long) INIT_HWRPB); cluster = memdesc->cluster; for (i = memdesc->numclusters ; i > 0; i--, cluster++) { unsigned long pfn, nr; +#if 0 +printk("paging_init: cluster %d usage %ld start %ld size %ld\n", + i, cluster->usage, cluster->start_pfn, cluster->numpages); +#endif if (cluster->usage & 1) continue; pfn = cluster->start_pfn; @@ -134,7 +145,7 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem) init_task.tss.pal_flags = 1; /* set FEN, clear everything else */ init_task.tss.flags = 0; init_task.kernel_stack_page = INIT_STACK; - load_PCB(&init_task.tss); + original_pcb_ptr = load_PCB(&init_task.tss); flush_tlb_all(); return start_mem; diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index ee34abdda3c2..12ae5a5b38f0 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -326,7 +326,7 @@ ENTRY(system_call) ALIGN 1: call SYMBOL_NAME(syscall_trace) movl ORIG_EAX(%esp),%eax - call SYMBOL_NAME(sys_call_table)(,%eax,4) + call *SYMBOL_NAME(sys_call_table)(,%eax,4) movl %eax,EAX(%esp) # save the return value #ifdef __SMP__ GET_PROCESSOR_OFFSET(%eax) diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c index c1d7390564d0..be1f46467de2 100644 --- a/arch/i386/kernel/ptrace.c +++ b/arch/i386/kernel/ptrace.c @@ -689,3 +689,9 @@ asmlinkage void syscall_trace(void) current->signal |= (1 << (current->exit_code - 1)); current->exit_code = 0; } + +void get_pt_regs_for_task(struct pt_regs *regs, struct task_struct *task) +{ + *regs = *(struct pt_regs *) (((unsigned char *) task->tss.esp0) - MAGICNUMBER); +} + diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c index 5fa9d4ba3367..4682a178c61d 100644 --- a/arch/i386/kernel/smp.c +++ b/arch/i386/kernel/smp.c @@ -1025,7 +1025,7 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait) */ if(ct==1000) - printk("CPU #%d: previous IPI still not cleared after 10mS", smp_processor_id()); + printk("CPU #%d: previous IPI still not cleared after 10ms\n", smp_processor_id()); /* * Program the APIC to deliver the IPI diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c index 9215efbb0cb2..ebee7ff589cb 100644 --- a/drivers/block/genhd.c +++ b/drivers/block/genhd.c @@ -102,6 +102,7 @@ static void add_partition (struct gendisk *hd, int minor, int start, int size) static inline int is_extended_partition(struct partition *p) { return (SYS_IND(p) == DOS_EXTENDED_PARTITION || + SYS_IND(p) == WIN98_EXTENDED_PARTITION || SYS_IND(p) == LINUX_EXTENDED_PARTITION); } diff --git a/drivers/block/ide.c b/drivers/block/ide.c index 9d9432d0a515..2cd4efd27afd 100644 --- a/drivers/block/ide.c +++ b/drivers/block/ide.c @@ -2634,11 +2634,12 @@ static int try_to_identify (ide_drive_t *drive, byte cmd) { int hd_status, rc; unsigned long timeout; - int irqs = 0; + unsigned long irqs_on = 0; + int irq_off; if (!HWIF(drive)->irq) { /* already got an IRQ? */ probe_irq_off(probe_irq_on()); /* clear dangling irqs */ - irqs = probe_irq_on(); /* start monitoring irqs */ + irqs_on = probe_irq_on(); /* start monitoring irqs */ OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* enable device irq */ } @@ -2652,8 +2653,8 @@ static int try_to_identify (ide_drive_t *drive, byte cmd) #if CONFIG_BLK_DEV_PROMISE if (IS_PROMISE_DRIVE) { if (promise_cmd(drive,PROMISE_IDENTIFY)) { - if (irqs) - (void) probe_irq_off(irqs); + if (irqs_on) + (void) probe_irq_off(irqs_on); return 1; } } else @@ -2663,8 +2664,8 @@ static int try_to_identify (ide_drive_t *drive, byte cmd) timeout += jiffies; do { if (jiffies > timeout) { - if (irqs) - (void) probe_irq_off(irqs); + if (irqs_on) + (void) probe_irq_off(irqs_on); return 1; /* drive timed-out */ } delay_50ms(); /* give drive a breather */ @@ -2682,18 +2683,18 @@ static int try_to_identify (ide_drive_t *drive, byte cmd) } else rc = 2; /* drive refused ID */ if (!HWIF(drive)->irq) { - irqs = probe_irq_off(irqs); /* get our irq number */ - if (irqs > 0) { - HWIF(drive)->irq = irqs; /* save it for later */ - irqs = probe_irq_on(); + irq_off = probe_irq_off(irqs_on); /* get our irq number */ + if (irq_off > 0) { + HWIF(drive)->irq = irq_off; /* save it for later */ + irqs_on = probe_irq_on(); OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* mask device irq */ udelay(5); - (void) probe_irq_off(irqs); + (void) probe_irq_off(irqs_on); (void) probe_irq_off(probe_irq_on()); /* clear self-inflicted irq */ (void) GET_STAT(); /* clear drive IRQ */ } else { /* Mmmm.. multiple IRQs.. don't know which was ours */ - printk("%s: IRQ probe failed (%d)\n", drive->name, irqs); + printk("%s: IRQ probe failed (%d)\n", drive->name, irq_off); #ifdef CONFIG_BLK_DEV_CMD640 #ifdef CMD640_DUMP_REGS if (HWIF(drive)->chipset == ide_cmd640) { diff --git a/drivers/block/rd.c b/drivers/block/rd.c index d064929601eb..0376f64243d4 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -422,7 +422,7 @@ done: /* * This routine loads in the ramdisk image. */ -static void rd_load_image(kdev_t device,int offset) +static void rd_load_image(kdev_t device,int offset, int unit) { struct inode inode, out_inode; struct file infile, outfile; @@ -433,7 +433,7 @@ static void rd_load_image(kdev_t device,int offset) unsigned short rotate = 0; char rotator[4] = { '|' , '/' , '-' , '\\' }; - ram_device = MKDEV(MAJOR_NR, 0); + ram_device = MKDEV(MAJOR_NR, unit); memset(&infile, 0, sizeof(infile)); memset(&inode, 0, sizeof(inode)); @@ -500,7 +500,7 @@ static void rd_load_image(kdev_t device,int offset) successful_load: invalidate_buffers(device); - ROOT_DEV = MKDEV(MAJOR_NR,0); + ROOT_DEV = MKDEV(MAJOR_NR,unit); done: if (infile.f_op->release) @@ -509,12 +509,21 @@ done: } -void rd_load() +static void rd_load_disk(int n) { +#ifdef CONFIG_BLK_DEV_INITRD + extern kdev_t real_root_dev; +#endif + if (rd_doload == 0) return; - if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR) return; + if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR +#ifdef CONFIG_BLK_DEV_INITRD + && MAJOR(real_root_dev) != FLOPPY_MAJOR +#endif + ) + return; if (rd_prompt) { #ifdef CONFIG_BLK_DEV_FD @@ -525,15 +534,24 @@ void rd_load() wait_for_keypress(); } - rd_load_image(ROOT_DEV,rd_image_start); + rd_load_image(ROOT_DEV,rd_image_start,n); + +} +void rd_load(void) +{ + rd_load_disk(0); } +void rd_load_secondary(void) +{ + rd_load_disk(1); +} #ifdef CONFIG_BLK_DEV_INITRD void initrd_load(void) { - rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),0); + rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),0,0); } #endif @@ -658,6 +676,13 @@ static int crd_load(struct file * fp, struct file *outfp) { int result; + + insize = 0; /* valid bytes in inbuf */ + inptr = 0; /* index of next byte to be processed in inbuf */ + outcnt = 0; /* bytes in output buffer */ + exit_code = 0; + bytes_out = 0; + crc = 0xFFFFFFFF; crd_infp = fp; crd_outfp = outfp; diff --git a/drivers/char/Config.in b/drivers/char/Config.in index a6e3464c4f44..256bec079049 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -59,6 +59,9 @@ if [ "$CONFIG_APM" = "y" ]; then bool ' Power off on shutdown' CONFIG_APM_POWER_OFF bool ' Ignore multiple suspend' CONFIG_APM_IGNORE_MULTIPLE_SUSPEND fi +if [ "$CONFIG_ALPHA_BOOK1" = "y" ]; then + bool 'Tadpole ANA H8 Support' CONFIG_H8 +fi bool 'Watchdog Timer Support' CONFIG_WATCHDOG if [ "$CONFIG_WATCHDOG" != "n" ]; then bool ' Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 205a78428bdb..49f68af0511f 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -196,6 +196,11 @@ LX_OBJS += apm_bios.o M = y endif +ifdef CONFIG_H8 +LX_OBJS += h8.o +M = y +endif + ifdef M LX_OBJS += misc.o else @@ -222,6 +227,9 @@ endif ifdef CONFIG_TGA_CONSOLE L_OBJS += tga.o + ifdef CONFIG_VGA_CONSOLE + L_OBJS += vga.o vesa_blank.o + endif else ifndef CONFIG_SUN_CONSOLE L_OBJS += vga.o vesa_blank.o diff --git a/drivers/char/h8.c b/drivers/char/h8.c new file mode 100644 index 000000000000..73941a0591e8 --- /dev/null +++ b/drivers/char/h8.c @@ -0,0 +1,1272 @@ +/* + */ +/* + * Hitachi H8/337 Microcontroller driver + * + * The H8 is used to deal with the power and thermal environment + * of a system. + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_PROC_FS +#include +#include +#endif +#include +#include +#include + +#define __KERNEL_SYSCALLS__ +#include + +#include "h8.h" + +#define DEBUG_H8 + +#ifdef DEBUG_H8 +#define Dprintk printk +#else +#define Dprintk +#endif + +#define XDprintk if(h8_debug==-1)printk + +/* + * The h8 device is one of the misc char devices. + */ +#define H8_MINOR_DEV 140 + +/* + * Forward declarations. + */ +int h8_init(void); +int h8_display_blank(void); +int h8_display_unblank(void); + +static int h8_open(struct inode *, struct file *); +static void h8_release(struct inode *, struct file *); +static long h8_read(struct inode *, struct file *, char *, u_long); +static int h8_select(struct inode *, struct file *, int, select_table *); +static int h8_ioctl(struct inode *, struct file *, u_int, u_long); + +static void h8_intr(int irq, void *dev_id, struct pt_regs *regs); + +#ifdef CONFIG_PROC_FS +static int h8_get_info(char *, char **, off_t, int, int); +#endif + +/* + * Support Routines. + */ +static void h8_hw_init(void); +static void h8_start_new_cmd(void); +static void h8_send_next_cmd_byte(void); +static void h8_read_event_status(void); +static void h8_sync(void); +static void h8_q_cmd(u_char *, int, int); +static void h8_cmd_done(h8_cmd_q_t *qp); +static int h8_alloc_queues(void); + +static u_long h8_get_cpu_speed(void); +static int h8_get_curr_temp(u_char curr_temp[]); +static void h8_get_max_temp(void); +static void h8_get_upper_therm_thold(void); +static void h8_set_upper_therm_thold(int); +static int h8_get_ext_status(u_char stat_word[]); + +static int h8_monitor_thread(void *); + +static int h8_manage_therm(void); +static void h8_set_cpu_speed(int speed_divisor); + +static void h8_start_monitor_timer(unsigned long secs); +static void h8_activate_monitor(unsigned long unused); + +/* in arch/alpha/kernel/lca.c */ +extern void lca_clock_print(void); +extern int lca_get_clock(void); +extern void lca_clock_fiddle(int); + +static void h8_set_event_mask(int); +static void h8_clear_event_mask(int); + +/* + * Driver structures + */ + +static struct timer_list h8_monitor_timer; +static int h8_monitor_timer_active = 0; + +static char driver_version[] = "X0.0";/* no spaces */ + +static struct file_operations h8_fops = { + NULL, /* lseek */ + h8_read, + NULL, /* write */ + NULL, /* readdir */ + h8_select, + h8_ioctl, + NULL, /* mmap */ + h8_open, + h8_release, + NULL, /* fsync */ + NULL /* fasync */ +}; + +static struct miscdevice h8_device = { + H8_MINOR_DEV, + "h8", + &h8_fops +}; + +#ifdef CONFIG_PROC_FS +static struct proc_dir_entry h8_proc_entry = { + 0, 3, "h8", S_IFREG | S_IRUGO, 1, 0, 0, 0, 0, h8_get_info +}; +#endif + +union intr_buf intrbuf; +int intr_buf_ptr; +union intr_buf xx; +u_char last_temp; + +/* + * I/O Macros for register reads and writes. + */ +#define H8_READ(a) inb((a)) +#define H8_WRITE(d,a) outb((d),(a)) + +#define H8_GET_STATUS H8_READ((h8_base) + H8_STATUS_REG_OFF) +#define H8_READ_DATA H8_READ((h8_base) + H8_DATA_REG_OFF) +#define WRITE_DATA(d) H8_WRITE((d), h8_base + H8_DATA_REG_OFF) +#define WRITE_CMD(d) H8_WRITE((d), h8_base + H8_CMD_REG_OFF) + +unsigned int h8_base = H8_BASE_ADDR; +unsigned int h8_irq = H8_IRQ; +unsigned int h8_state = H8_IDLE; +unsigned int h8_index = -1; +unsigned int h8_enabled = 0; + +queue_head_t h8_actq, h8_cmdq, h8_freeq; + +/* + * Globals used in thermal control of Alphabook1. + */ +int cpu_speed_divisor = -1; +int h8_event_mask = 0; +struct wait_queue *h8_monitor_wait = NULL; +unsigned int h8_command_mask = 0; +int h8_uthermal_threshold = DEFAULT_UTHERMAL_THRESHOLD; +int h8_uthermal_window = UTH_HYSTERESIS; +int h8_debug = 0xfffffdfc; +int h8_ldamp = MHZ_115; +int h8_udamp = MHZ_57; +u_char h8_current_temp = 0; +u_char h8_system_temp = 0; +int h8_sync_channel = 0; +struct wait_queue *h8_sync_wait = NULL; +int h8_init_performed; + +/* CPU speeds and clock divisor values */ +int speed_tab[6] = {230, 153, 115, 57, 28, 14}; + +/* + * H8 interrupt handler + */ +static void h8_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + u_char stat_reg, data_reg; + h8_cmd_q_t *qp = (h8_cmd_q_t *)QUEUE_FIRST(&h8_actq, link); + + stat_reg = H8_GET_STATUS; + data_reg = H8_READ_DATA; + + XDprintk("h8_intr: state %d status 0x%x data 0x%x\n", h8_state, stat_reg, data_reg); + + switch (h8_state) { + /* Response to an asynchronous event. */ + case H8_IDLE: { /* H8_IDLE */ + if (stat_reg & H8_OFULL) { + if (data_reg == H8_INTR) { + h8_state = H8_INTR_MODE; + /* Executing a command to determine what happened. */ + WRITE_CMD(H8_RD_EVENT_STATUS); + intr_buf_ptr = 1; + WRITE_CMD(H8_RD_EVENT_STATUS); + } else { + Dprintk("h8_intr: idle stat 0x%x data 0x%x\n", + stat_reg, data_reg); + } + } else { + Dprintk("h8_intr: bogus interrupt\n"); + } + break; + } + case H8_INTR_MODE: { /* H8_INTR_MODE */ + XDprintk("H8 intr/intr_mode\n"); + if (data_reg == H8_BYTE_LEVEL_ACK) { + return; + } else if (data_reg == H8_CMD_ACK) { + return; + } else { + intrbuf.byte[intr_buf_ptr] = data_reg; + if(!intr_buf_ptr) { + h8_state = H8_IDLE; + h8_read_event_status(); + } + intr_buf_ptr--; + } + break; + } + /* Placed in this state by h8_start_new_cmd(). */ + case H8_XMIT: { /* H8_XMIT */ + XDprintk("H8 intr/xmit\n"); + /* If a byte level acknowledgement has been received */ + if (data_reg == H8_BYTE_LEVEL_ACK) { + XDprintk("H8 intr/xmit BYTE ACK\n"); + qp->nacks++; + if (qp->nacks > qp->ncmd) + if(h8_debug & 0x1) + Dprintk("h8intr: bogus # of acks!\n"); + /* + * If the number of bytes sent is less than the total + * number of bytes in the command. + */ + if (qp->cnt < qp->ncmd) { + h8_send_next_cmd_byte(); + } + return; + /* If the complete command has produced an acknowledgement. */ + } else if (data_reg == H8_CMD_ACK) { + XDprintk("H8 intr/xmit CMD ACK\n"); + /* If there are response bytes */ + if (qp->nrsp) + h8_state = H8_RCV; + else + h8_state = H8_IDLE; + qp->cnt = 0; + return; + /* Error, need to start over with a clean slate. */ + } else if (data_reg == H8_NACK) { + XDprintk("h8_intr: NACK received restarting command\n"); + qp->nacks = 0; + qp->cnt = 0; + h8_state = H8_IDLE; + WRITE_CMD(H8_SYNC); + return; + } else { + Dprintk ("h8intr: xmit unknown data 0x%x \n", data_reg); + return; + } + break; + } + case H8_RESYNC: { /* H8_RESYNC */ + XDprintk("H8 intr/resync\n"); + if (data_reg == H8_BYTE_LEVEL_ACK) { + return; + } else if (data_reg == H8_SYNC_BYTE) { + h8_state = H8_IDLE; + if (!QUEUE_EMPTY(&h8_actq, link)) + h8_send_next_cmd_byte(); + } else { + Dprintk ("h8_intr: resync unknown data 0x%x \n", data_reg); + return; + } + break; + } + case H8_RCV: { /* H8_RCV */ + XDprintk("H8 intr/rcv\n"); + if (qp->cnt < qp->nrsp) { + qp->rcvbuf[qp->cnt] = data_reg; + qp->cnt++; + /* If command reception finished. */ + if (qp->cnt == qp->nrsp) { + h8_state = H8_IDLE; + QUEUE_REMOVE(&h8_actq, qp, link); + h8_cmd_done (qp); + /* More commands to send over? */ + if (!QUEUE_EMPTY(&h8_cmdq, link)) + h8_start_new_cmd(); + } + return; + } else { + Dprintk ("h8intr: rcv overflow cmd 0x%x\n", qp->cmdbuf[0]); + } + break; + } + default: /* default */ + Dprintk("H8 intr/unknown\n"); + break; + } + return; +} + +#ifdef MODULE + +int init_module(void) +{ + printk("H8 module at %X(Interrupt %d)\n", h8_base, h8_irq); + if(request_irq(h8_irq, h8_intr, SA_INTERRUPT, "h8", NULL)) + { + printk("H8: error: IRQ %d is not free.\n", h8_irq); + return -EIO; + } + + misc_register(&h8_device); + request_region(h8_base, 8, "h8"); + +#ifdef CONFIG_PROC_FS + proc_register_dynamic(&proc_root, &h8_proc_entry); +#endif + + QUEUE_INIT(&h8_actq, link, h8_cmd_q_t *); + QUEUE_INIT(&h8_cmdq, link, h8_cmd_q_t *); + QUEUE_INIT(&h8_freeq, link, h8_cmd_q_t *); + h8_alloc_queues(); + + h8_hw_init(); + + kernel_thread(h8_monitor_thread, NULL, 0); + + return 0; +} + +void cleanup_module(void) +{ + misc_deregister(&h8_device); + release_region(h8_base, 8); + free_irq(h8_irq, NULL); +} + +#else /* MODULE */ + +int h8_init(void) +{ + if(request_irq(h8_irq, h8_intr, SA_INTERRUPT, "h8", NULL)) + { + printk("H8: error: IRQ %d is not free\n", h8_irq); + return -EIO; + } + printk("H8 at 0x%x IRQ %d\n", h8_base, h8_irq); + +#ifdef CONFIG_PROC_FS + proc_register_dynamic(&proc_root, &h8_proc_entry); +#endif + + misc_register(&h8_device); + request_region(h8_base, 8, "h8"); + + QUEUE_INIT(&h8_actq, link, h8_cmd_q_t *); + QUEUE_INIT(&h8_cmdq, link, h8_cmd_q_t *); + QUEUE_INIT(&h8_freeq, link, h8_cmd_q_t *); + h8_alloc_queues(); + + h8_hw_init(); + + kernel_thread(h8_monitor_thread, NULL, 0); + + return 0; +} +#endif /* MODULE */ + +void h8_hw_init(void) +{ + u_char buf[H8_MAX_CMD_SIZE]; + + /* set CPU speed to max for booting */ + h8_set_cpu_speed(MHZ_230); + + /* + * Initialize the H8 + */ + h8_sync(); /* activate interrupts */ + + /* To clear conditions left by console */ + h8_read_event_status(); + + /* Perform a conditioning read */ + buf[0] = H8_DEVICE_CONTROL; + buf[1] = 0xff; + buf[2] = 0x0; + h8_q_cmd(buf, 3, 1); + + /* Turn on built-in and external mice, capture power switch */ + buf[0] = H8_DEVICE_CONTROL; + buf[1] = 0x0; + buf[2] = H8_ENAB_INT_PTR | H8_ENAB_EXT_PTR | + /*H8_DISAB_PWR_OFF_SW |*/ H8_ENAB_LOW_SPD_IND; + h8_q_cmd(buf, 3, 1); + + h8_enabled = 1; + return; +} + +#ifdef CONFIG_PROC_FS +int h8_get_info(char *buf, char **start, off_t fpos, int length, int dummy) +{ + char *p; + + if (!h8_enabled) + return 0; + p = buf; + + + /* + 0) Linux driver version (this will change if format changes) + 1) + 2) + 3) + 4) + */ + + p += sprintf(p, "%s \n", + driver_version + ); + + return p - buf; +} +#endif + +static long h8_read(struct inode *inode, struct file *fp, char *buf, + u_long count) +{ + printk("h8_read: IMPDEL\n"); + return 0; +} + +static int h8_select(struct inode *inode, struct file *fp, int sel_type, + select_table * wait) +{ + printk("h8_select: IMPDEL\n"); + return 0; +} + +static int h8_ioctl(struct inode * inode, struct file *filp, + u_int cmd, u_long arg) +{ + printk("h8_ioctl: IMPDEL\n"); + return 0; +} + +static void h8_release(struct inode * inode, struct file * filp) +{ + printk("h8_release: IMPDEL\n"); +} + +static int h8_open(struct inode * inode, struct file * filp) +{ + printk("h8_open: IMPDEL\n"); + return 0; +} + +/* Called from console driver -- must make sure h8_enabled. */ +int h8_display_blank(void) +{ +#ifdef CONFIG_H8_DISPLAY_BLANK + int error; + + if (!h8_enabled) + return 0; + error = h8_set_display_power_state(H8_STATE_STANDBY); + if (error == H8_SUCCESS) + return 1; + h8_error("set display standby", error); +#endif + return 0; +} + +/* Called from console driver -- must make sure h8_enabled. */ +int h8_display_unblank(void) +{ +#ifdef CONFIG_H8_DISPLAY_BLANK + int error; + + if (!h8_enabled) + return 0; + error = h8_set_display_power_state(H8_STATE_READY); + if (error == H8_SUCCESS) + return 1; + h8_error("set display ready", error); +#endif + return 0; +} + +int +h8_alloc_queues(void) +{ + h8_cmd_q_t *qp; + unsigned long flags; + int i; + + qp = (h8_cmd_q_t *)kmalloc((sizeof (h8_cmd_q_t) * H8_Q_ALLOC_AMOUNT), + GFP_KERNEL); + + if (!qp) { + printk("H8: could not allocate memory for command queue\n"); + return(0); + } + /* add to the free queue */ + save_flags(flags); cli(); + for (i = 0; i < H8_Q_ALLOC_AMOUNT; i++) { + /* place each at front of freeq */ + QUEUE_ENTER(&h8_freeq, &qp[i], link, h8_cmd_q_t *); + } + restore_flags(flags); + return (1); +} + +/* + * Basic means by which commands are sent to the H8. + */ +void +h8_q_cmd(u_char *cmd, int cmd_size, int resp_size) +{ + h8_cmd_q_t *qp; + unsigned long flags; + int i; + + /* get cmd buf */ + save_flags(flags); cli(); + while (QUEUE_EMPTY(&h8_freeq, link)) { + Dprintk("H8: need to allocate more cmd buffers\n"); + restore_flags(flags); + h8_alloc_queues(); + save_flags(flags); cli(); + } + /* get first element from queue */ + qp = (h8_cmd_q_t *)QUEUE_FIRST(&h8_freeq, link); + QUEUE_REMOVE(&h8_freeq, qp, link); + + restore_flags(flags); + + /* fill it in */ + for (i = 0; i < cmd_size; i++) + qp->cmdbuf[i] = cmd[i]; + qp->ncmd = cmd_size; + qp->nrsp = resp_size; + + /* queue it at the end of the cmd queue */ + save_flags(flags); cli(); + + QUEUE_ENTER(&h8_cmdq, qp, link, h8_cmd_q_t *); + + restore_flags(flags); + + h8_start_new_cmd(); +} + +void +h8_start_new_cmd(void) +{ + unsigned long flags; + h8_cmd_q_t *qp; + + save_flags(flags); cli(); + if (h8_state != H8_IDLE) { + if (h8_debug & 0x1) + Dprintk("h8_start_new_cmd: not idle\n"); + restore_flags(flags); + return; + } + + if (!QUEUE_EMPTY(&h8_actq, link)) { + Dprintk("h8_start_new_cmd: inconsistency: IDLE with non-empty active queue!\n"); + restore_flags(flags); + return; + } + + if (QUEUE_EMPTY(&h8_cmdq, link)) { + Dprintk("h8_start_new_cmd: no command to dequeue\n"); + restore_flags(flags); + return; + } + /* + * Take first command off of the command queue and put + * it on the active queue. + */ + qp = (h8_cmd_q_t *) QUEUE_FIRST(&h8_cmdq, link); + QUEUE_REMOVE(&h8_cmdq, qp, link); + QUEUE_ENTER(&h8_actq, qp, link, h8_cmd_q_t *); + h8_state = H8_XMIT; + if (h8_debug & 0x1) + Dprintk("h8_start_new_cmd: Starting a command\n"); + + qp->cnt = 1; + WRITE_CMD(qp->cmdbuf[0]); /* Kick it off */ + + restore_flags(flags); + return; +} + +void +h8_send_next_cmd_byte(void) +{ + h8_cmd_q_t *qp = (h8_cmd_q_t *)QUEUE_FIRST(&h8_actq, link); + int cnt; + + cnt = qp->cnt; + qp->cnt++; + + if (h8_debug & 0x1) + Dprintk("h8 sending next cmd byte 0x%x (0x%x)\n", + cnt, qp->cmdbuf[cnt]); + + if (cnt) { + WRITE_DATA(qp->cmdbuf[cnt]); + } else { + WRITE_CMD(qp->cmdbuf[cnt]); + } + return; +} + +/* + * Synchronize H8 communications channel for command transmission. + */ +void +h8_sync(void) +{ + u_char buf[H8_MAX_CMD_SIZE]; + + buf[0] = H8_SYNC; + buf[1] = H8_SYNC_BYTE; + h8_q_cmd(buf, 2, 1); +} + +/* + * Responds to external interrupt. Reads event status word and + * decodes type of interrupt. + */ +void +h8_read_event_status(void) +{ + + if(h8_debug & 0x200) + printk("h8_read_event_status: value 0x%x\n", intrbuf.word); + + /* + * Power related items + */ + if (intrbuf.word & H8_DC_CHANGE) { + if(h8_debug & 0x4) + printk("h8_read_event_status: DC_CHANGE\n"); + /* see if dc added or removed, set batt/dc flag, send event */ + + h8_set_event_mask(H8_MANAGE_BATTERY); + wake_up(&h8_monitor_wait); + } + + if (intrbuf.word & H8_POWER_BUTTON) { + printk("Power switch pressed - please wait - preparing to power +off\n"); + h8_set_event_mask(H8_POWER_BUTTON); + wake_up(&h8_monitor_wait); + } + + /* + * Thermal related items + */ + if (intrbuf.word & H8_THERMAL_THRESHOLD) { + if(h8_debug & 0x4) + printk("h8_read_event_status: THERMAL_THRESHOLD\n"); + h8_set_event_mask(H8_MANAGE_UTHERM); + wake_up(&h8_monitor_wait); + } + + /* + * nops -for now + */ + if (intrbuf.word & H8_DOCKING_STATION_STATUS) { + if(h8_debug & 0x4) + printk("h8_read_event_status: DOCKING_STATION_STATUS\n"); + /* read_ext_status */ + } + if (intrbuf.word & H8_EXT_BATT_STATUS) { + if(h8_debug & 0x4) + printk("h8_read_event_status: EXT_BATT_STATUS\n"); + + } + if (intrbuf.word & H8_EXT_BATT_CHARGE_STATE) { + if(h8_debug & 0x4) + printk("h8_read_event_status: EXT_BATT_CHARGE_STATE\n"); + + } + if (intrbuf.word & H8_BATT_CHANGE_OVER) { + if(h8_debug & 0x4) + printk("h8_read_event_status: BATT_CHANGE_OVER\n"); + + } + if (intrbuf.word & H8_WATCHDOG) { + if(h8_debug & 0x4) + printk("h8_read_event_status: WATCHDOG\n"); + /* nop */ + } + if (intrbuf.word & H8_SHUTDOWN) { + if(h8_debug & 0x4) + printk("h8_read_event_status: SHUTDOWN\n"); + /* nop */ + } + if (intrbuf.word & H8_KEYBOARD) { + if(h8_debug & 0x4) + printk("h8_read_event_status: KEYBOARD\n"); + /* nop */ + } + if (intrbuf.word & H8_EXT_MOUSE_OR_CASE_SWITCH) { + if(h8_debug & 0x4) + printk("h8_read_event_status: EXT_MOUSE_OR_CASE_SWITCH\n"); + /* read_ext_status*/ + } + if (intrbuf.word & H8_INT_BATT_LOW) { + if(h8_debug & 0x4) + printk("h8_read_event_status: INT_BATT_LOW\n"); + /* post event, warn user */ + } + if (intrbuf.word & H8_INT_BATT_CHARGE_STATE) { + if(h8_debug & 0x4) + printk("h8_read_event_status: INT_BATT_CHARGE_STATE\n"); + /* nop - happens often */ + } + if (intrbuf.word & H8_INT_BATT_STATUS) { + if(h8_debug & 0x4) + printk("h8_read_event_status: INT_BATT_STATUS\n"); + + } + if (intrbuf.word & H8_INT_BATT_CHARGE_THRESHOLD) { + if(h8_debug & 0x4) + printk("h8_read_event_status: INT_BATT_CHARGE_THRESHOLD\n"); + /* nop - happens often */ + } + if (intrbuf.word & H8_EXT_BATT_LOW) { + if(h8_debug & 0x4) + printk("h8_read_event_status: EXT_BATT_LOW\n"); + /*if no internal, post event, warn user */ + /* else nop */ + } + + return; +} + +/* + * Function called when H8 has performed requested command. + */ +void +h8_cmd_done(h8_cmd_q_t *qp) +{ + + /* what to do */ + switch (qp->cmdbuf[0]) { + case H8_SYNC: + if (h8_debug & 0x40000) + printk("H8: Sync command done - byte returned was 0x%x\n", + qp->rcvbuf[0]); + QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + break; + + case H8_RD_SN: + case H8_RD_ENET_ADDR: + printk("H8: Read ethernet addr - command done - address: %x - %x - %x - %x - %x - %x \n", + qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2], + qp->rcvbuf[3], qp->rcvbuf[4], qp->rcvbuf[5]); + QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + break; + + case H8_RD_HW_VER: + case H8_RD_MIC_VER: + case H8_RD_MAX_TEMP: + printk("H8: Max recorded CPU temp %d, Sys temp %d\n", + qp->rcvbuf[0], qp->rcvbuf[1]); + QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + break; + + case H8_RD_MIN_TEMP: + printk("H8: Min recorded CPU temp %d, Sys temp %d\n", + qp->rcvbuf[0], qp->rcvbuf[1]); + QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + break; + + case H8_RD_CURR_TEMP: + h8_sync_channel |= H8_RD_CURR_TEMP; + xx.byte[0] = qp->rcvbuf[0]; + xx.byte[1] = qp->rcvbuf[1]; + wake_up(&h8_sync_wait); + QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + break; + + case H8_RD_SYS_VARIENT: + case H8_RD_PWR_ON_CYCLES: + printk(" H8: RD_PWR_ON_CYCLES command done\n"); + break; + + case H8_RD_PWR_ON_SECS: + printk("H8: RD_PWR_ON_SECS command done\n"); + break; + + case H8_RD_RESET_STATUS: + case H8_RD_PWR_DN_STATUS: + case H8_RD_EVENT_STATUS: + case H8_RD_ROM_CKSM: + case H8_RD_EXT_STATUS: + xx.byte[1] = qp->rcvbuf[0]; + xx.byte[0] = qp->rcvbuf[1]; + h8_sync_channel |= H8_GET_EXT_STATUS; + wake_up(&h8_sync_wait); + QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + break; + + case H8_RD_USER_CFG: + case H8_RD_INT_BATT_VOLT: + case H8_RD_DC_INPUT_VOLT: + case H8_RD_HORIZ_PTR_VOLT: + case H8_RD_VERT_PTR_VOLT: + case H8_RD_EEPROM_STATUS: + case H8_RD_ERR_STATUS: + case H8_RD_NEW_BUSY_SPEED: + case H8_RD_CONFIG_INTERFACE: + case H8_RD_INT_BATT_STATUS: + printk("H8: Read int batt status cmd done - returned was %x %x %x\n", + qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2]); + QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + break; + + case H8_RD_EXT_BATT_STATUS: + case H8_RD_PWR_UP_STATUS: + case H8_RD_EVENT_STATUS_MASK: + case H8_CTL_EMU_BITPORT: + case H8_DEVICE_CONTROL: + if(h8_debug & 0x20000) { + printk("H8: Device control cmd done - byte returned was 0x%x\n", + qp->rcvbuf[0]); + } + QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + break; + + case H8_CTL_TFT_BRT_DC: + case H8_CTL_WATCHDOG: + case H8_CTL_MIC_PROT: + case H8_CTL_INT_BATT_CHG: + case H8_CTL_EXT_BATT_CHG: + case H8_CTL_MARK_SPACE: + case H8_CTL_MOUSE_SENSITIVITY: + case H8_CTL_DIAG_MODE: + case H8_CTL_IDLE_AND_BUSY_SPDS: + printk("H8: Idle and busy speed command done\n"); + break; + + case H8_CTL_TFT_BRT_BATT: + case H8_CTL_UPPER_TEMP: + if(h8_debug & 0x10) { + XDprintk("H8: ctl upper thermal thresh cmd done - returned was %d\n", + qp->rcvbuf[0]); + } + QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + break; + + case H8_CTL_LOWER_TEMP: + case H8_CTL_TEMP_CUTOUT: + case H8_CTL_WAKEUP: + case H8_CTL_CHG_THRESHOLD: + case H8_CTL_TURBO_MODE: + case H8_SET_DIAG_STATUS: + case H8_SOFTWARE_RESET: + case H8_RECAL_PTR: + case H8_SET_INT_BATT_PERCENT: + case H8_WRT_CFG_INTERFACE_REG: + case H8_WRT_EVENT_STATUS_MASK: + case H8_ENTER_POST_MODE: + case H8_EXIT_POST_MODE: + case H8_RD_EEPROM: + case H8_WRT_EEPROM: + case H8_WRT_TO_STATUS_DISP: + printk("H8: Write IO status display command done\n"); + break; + + case H8_DEFINE_SPC_CHAR: + case H8_DEFINE_TABLE_STRING_ENTRY: + case H8_PERFORM_EMU_CMD: + case H8_EMU_RD_REG: + case H8_EMU_WRT_REG: + case H8_EMU_RD_RAM: + case H8_EMU_WRT_RAM: + case H8_BQ_RD_REG: + case H8_BQ_WRT_REG: + case H8_PWR_OFF: + printk ("H8: misc command completed\n"); + break; + } + return; +} + +/* + * Retrieve the current cpu temperature and case temperature. Provides + * the feedback for the thermal control algorithm. Synchcronized via + * sleep() for priority so that no other actions in the process will take + * place before the data becomes available. + */ +int +h8_get_curr_temp(u_char curr_temp[]) +{ + u_char buf[H8_MAX_CMD_SIZE]; + unsigned long flags; + + memset(buf, 0, H8_MAX_CMD_SIZE); + buf[0] = H8_RD_CURR_TEMP; + + h8_q_cmd(buf, 1, 2); + + save_flags(flags); cli(); + + while((h8_sync_channel & H8_RD_CURR_TEMP) == 0) + sleep_on(&h8_sync_wait); + + restore_flags(flags); + + h8_sync_channel &= ~H8_RD_CURR_TEMP; + curr_temp[0] = xx.byte[0]; + curr_temp[1] = xx.byte[1]; + xx.word = 0; + + if(h8_debug & 0x8) + printk("H8: curr CPU temp %d, Sys temp %d\n", + curr_temp[0], curr_temp[1]); + return 0; +} + +static void +h8_get_max_temp(void) +{ + u_char buf[H8_MAX_CMD_SIZE]; + + buf[0] = H8_RD_MAX_TEMP; + h8_q_cmd(buf, 1, 2); +} + +/* + * Assigns an upper limit to the value of the H8 thermal interrupt. + * As an example setting a value of 115 F here will cause the + * interrupt to trigger when the cpu temperature reaches 115 F. + */ +static void +h8_set_upper_therm_thold(int thold) +{ + u_char buf[H8_MAX_CMD_SIZE]; + + /* write 0 to reinitialize interrupt */ + buf[0] = H8_CTL_UPPER_TEMP; + buf[1] = 0x0; + buf[2] = 0x0; + h8_q_cmd(buf, 3, 1); + + /* Do it for real */ + buf[0] = H8_CTL_UPPER_TEMP; + buf[1] = 0x0; + buf[2] = thold; + h8_q_cmd(buf, 3, 1); +} + +static void +h8_get_upper_therm_thold(void) +{ + u_char buf[H8_MAX_CMD_SIZE]; + + buf[0] = H8_CTL_UPPER_TEMP; + buf[1] = 0xff; + buf[2] = 0; + h8_q_cmd(buf, 3, 1); +} + +/* + * The external status word contains information on keyboard controller, + * power button, changes in external batt status, change in DC state, + * docking station, etc. General purpose querying use. + */ +int +h8_get_ext_status(u_char stat_word[]) +{ + u_char buf[H8_MAX_CMD_SIZE]; + unsigned long flags; + + memset(buf, 0, H8_MAX_CMD_SIZE); + buf[0] = H8_RD_EXT_STATUS; + + h8_q_cmd(buf, 1, 2); + + save_flags(flags); cli(); + + while((h8_sync_channel & H8_GET_EXT_STATUS) == 0) + sleep_on(&h8_sync_wait); + + restore_flags(flags); + + h8_sync_channel &= ~H8_GET_EXT_STATUS; + stat_word[0] = xx.byte[0]; + stat_word[1] = xx.byte[1]; + xx.word = 0; + + if(h8_debug & 0x8) + printk("H8: curr ext status %x, %x\n", + stat_word[0], stat_word[1]); + + return 0; +} + +/* + * Thread attached to task 0 manages thermal/physcial state of Alphabook. + * When a condition is detected by the interrupt service routine, the + * isr does a wakeup() on h8_monitor_wait. The mask value is then + * screened for the appropriate action. + */ + +int +h8_monitor_thread(void * unused) +{ + u_char curr_temp[2]; + + /* + * Need a logic based safety valve here. During boot when this thread is + * started and the thermal interrupt is not yet initialized this logic + * checks the temperature and acts accordingly. When this path is acted + * upon system boot is painfully slow, however, the priority associated + * with overheating is high enough to warrant this action. + */ + h8_get_curr_temp(curr_temp); + + printk("H8: Initial CPU temp: %d\n", curr_temp[0]); + + if(curr_temp[0] >= h8_uthermal_threshold) { + h8_set_event_mask(H8_MANAGE_UTHERM); + h8_manage_therm(); + } else { + /* + * Arm the upper thermal limit of the H8 so that any temp in + * excess will trigger the thermal control mechanism. + */ + h8_set_upper_therm_thold(h8_uthermal_threshold); + } + + for(;;) { + sleep_on(&h8_monitor_wait); + + if(h8_debug & 0x2) + printk("h8_monitor_thread awakened, mask:%x\n", + h8_event_mask); + + if (h8_event_mask & (H8_MANAGE_UTHERM|H8_MANAGE_LTHERM)) { + h8_manage_therm(); + } + +#if 0 + if (h8_event_mask & H8_POWER_BUTTON) { + h8_system_down(); + } + + /* + * If an external DC supply is removed or added make + * appropriate cpu speed adjustments. + */ + if (h8_event_mask & H8_MANAGE_BATTERY) { + h8_run_level_3_manage(H8_RUN); + h8_clear_event_mask(H8_MANAGE_BATTERY); + } +#endif + } +} + +/* + * Function implements the following policy. When the machine is booted + * the system is set to run at full clock speed. When the upper thermal + * threshold is reached as a result of full clock a damping factor is + * applied to cool off the cpu. The default value is one quarter clock + * (57 Mhz). When as a result of this cooling a temperature lower by + * hmc_uthermal_window is reached, the machine is reset to a higher + * speed, one half clock (115 Mhz). One half clock is maintained until + * the upper thermal threshold is again reached restarting the cycle. + */ + +int +h8_manage_therm(void) +{ + u_char curr_temp[2]; + + if(h8_event_mask & H8_MANAGE_UTHERM) { + /* Upper thermal interrupt received, need to cool down. */ + if(h8_debug & 0x10) + printk("H8: Thermal threshold %d F reached\n", + h8_uthermal_threshold); + h8_set_cpu_speed(h8_udamp); + h8_clear_event_mask(H8_MANAGE_UTHERM); + h8_set_event_mask(H8_MANAGE_LTHERM); + /* Check again in 30 seconds for cpu temperature */ + h8_start_monitor_timer(H8_TIMEOUT_INTERVAL); + } else if (h8_event_mask & H8_MANAGE_LTHERM) { + /* See how cool the system has become as a result + of the reduction in speed. */ + h8_get_curr_temp(curr_temp); + last_temp = curr_temp[0]; + if (curr_temp[0] < (h8_uthermal_threshold - h8_uthermal_window)) + { + /* System cooling has progressed to a point + that the cpu may be speeded up. */ + h8_set_upper_therm_thold(h8_uthermal_threshold); + h8_set_cpu_speed(h8_ldamp); /* adjustable */ + if(h8_debug & 0x10) + printk("H8: CPU cool, applying cpu_divisor: %d \n", + h8_ldamp); + h8_clear_event_mask(H8_MANAGE_LTHERM); + } + else /* Not cool enough yet, check again in 30 seconds. */ + h8_start_monitor_timer(H8_TIMEOUT_INTERVAL); + } else { + + } + return 0; +} + +/* + * Function conditions the value of global_rpb_counter before + * calling the primitive which causes the actual speed change. + */ +void +h8_set_cpu_speed(int speed_divisor) +{ + +#ifdef NOT_YET +/* + * global_rpb_counter is consumed by alpha_delay() in determining just + * how much time to delay. It is necessary that the number of microseconds + * in DELAY(n) be kept consistent over a variety of cpu clock speeds. + * To that end global_rpb_counter is here adjusted. + */ + + switch (speed_divisor) { + case 0: + global_rpb_counter = rpb->rpb_counter * 2L; + break; + case 1: + global_rpb_counter = rpb->rpb_counter * 4L / 3L ; + break; + case 3: + global_rpb_counter = rpb->rpb_counter / 2L; + break; + case 4: + global_rpb_counter = rpb->rpb_counter / 4L; + break; + case 5: + global_rpb_counter = rpb->rpb_counter / 8L; + break; + /* + * This case most commonly needed for cpu_speed_divisor + * of 2 which is the value assigned by the firmware. + */ + default: + global_rpb_counter = rpb->rpb_counter; + break; + } +#endif /* NOT_YET */ + + if(h8_debug & 0x8) + printk("H8: Setting CPU speed to %d MHz\n", + speed_tab[speed_divisor]); + + /* Make the actual speed change */ + lca_clock_fiddle(speed_divisor); +} + +/* + * Gets value stored in rpb representing cpu clock speed and adjusts this + * value based on the current clock speed divisor. + */ +u_long +h8_get_cpu_speed(void) +{ + u_long speed = 0; + u_long counter; + +#ifdef NOT_YET + counter = rpb->rpb_counter / 1000000L; + + switch (alphabook_get_clock()) { + case 0: + speed = counter * 2L; + break; + case 1: + speed = counter * 4L / 3L ; + break; + case 2: + speed = counter; + break; + case 3: + speed = counter / 2L; + break; + case 4: + speed = counter / 4L; + break; + case 5: + speed = counter / 8L; + break; + default: + break; + } + if(h8_debug & 0x8) + printk("H8: CPU speed current setting: %d MHz\n", speed); +#endif /* NOT_YET */ + return speed; +} + +static void +h8_activate_monitor(unsigned long unused) +{ + unsigned long flags; + + save_flags(flags); cli(); + h8_monitor_timer_active = 0; + restore_flags(flags); + + wake_up(&h8_monitor_wait); +} + +static void +h8_start_monitor_timer(unsigned long secs) +{ + unsigned long flags; + + if (h8_monitor_timer_active) + return; + + save_flags(flags); cli(); + h8_monitor_timer_active = 1; + restore_flags(flags); + + init_timer(&h8_monitor_timer); + h8_monitor_timer.function = h8_activate_monitor; + h8_monitor_timer.expires = secs * HZ + jiffies; + add_timer(&h8_monitor_timer); +} + +static void h8_set_event_mask(int mask) +{ + unsigned long flags; + + save_flags(flags); cli(); + h8_event_mask |= mask; + restore_flags(flags); +} + +static void h8_clear_event_mask(int mask) +{ + unsigned long flags; + + save_flags(flags); cli(); + h8_event_mask &= (~mask); + restore_flags(flags); +} diff --git a/drivers/char/h8.h b/drivers/char/h8.h new file mode 100644 index 000000000000..533c4ece1179 --- /dev/null +++ b/drivers/char/h8.h @@ -0,0 +1,250 @@ +/* + */ + +#ifndef __H8_H__ +#define __H8_H__ + +/* + * Register address and offsets + */ +#define H8_BASE_ADDR 0x170 /* default */ +#define H8_IRQ 9 /* default */ +#define H8_STATUS_REG_OFF 0x4 +#define H8_CMD_REG_OFF 0x4 +#define H8_DATA_REG_OFF 0x0 + + +/* H8 register bit definitions */ +/* status register */ +#define H8_OFULL 0x1 /* output data register full */ +#define H8_IFULL 0x2 /* input data register full */ +#define H8_CMD 0x8 /* command / not data */ + +#define H8_INTR 0xfa +#define H8_NACK 0xfc +#define H8_BYTE_LEVEL_ACK 0xfd +#define H8_CMD_ACK 0xfe +#define H8_SYNC_BYTE 0x99 + +/* + * H8 command definitions + */ +/* System info commands */ +#define H8_SYNC 0x0 +#define H8_RD_SN 0x1 +#define H8_RD_ENET_ADDR 0x2 +#define H8_RD_HW_VER 0x3 +#define H8_RD_MIC_VER 0x4 +#define H8_RD_MAX_TEMP 0x5 +#define H8_RD_MIN_TEMP 0x6 +#define H8_RD_CURR_TEMP 0x7 +#define H8_RD_SYS_VARIENT 0x8 +#define H8_RD_PWR_ON_CYCLES 0x9 +#define H8_RD_PWR_ON_SECS 0xa +#define H8_RD_RESET_STATUS 0xb +#define H8_RD_PWR_DN_STATUS 0xc +#define H8_RD_EVENT_STATUS 0xd +#define H8_RD_ROM_CKSM 0xe +#define H8_RD_EXT_STATUS 0xf +#define H8_RD_USER_CFG 0x10 +#define H8_RD_INT_BATT_VOLT 0x11 +#define H8_RD_DC_INPUT_VOLT 0x12 +#define H8_RD_HORIZ_PTR_VOLT 0x13 +#define H8_RD_VERT_PTR_VOLT 0x14 +#define H8_RD_EEPROM_STATUS 0x15 +#define H8_RD_ERR_STATUS 0x16 +#define H8_RD_NEW_BUSY_SPEED 0x17 +#define H8_RD_CONFIG_INTERFACE 0x18 +#define H8_RD_INT_BATT_STATUS 0x19 +#define H8_RD_EXT_BATT_STATUS 0x1a +#define H8_RD_PWR_UP_STATUS 0x1b +#define H8_RD_EVENT_STATUS_MASK 0x56 + +/* Read/write/modify commands */ +#define H8_CTL_EMU_BITPORT 0x32 +#define H8_DEVICE_CONTROL 0x21 +#define H8_CTL_TFT_BRT_DC 0x22 +#define H8_CTL_WATCHDOG 0x23 +#define H8_CTL_MIC_PROT 0x24 +#define H8_CTL_INT_BATT_CHG 0x25 +#define H8_CTL_EXT_BATT_CHG 0x26 +#define H8_CTL_MARK_SPACE 0x27 +#define H8_CTL_MOUSE_SENSITIVITY 0x28 +#define H8_CTL_DIAG_MODE 0x29 +#define H8_CTL_IDLE_AND_BUSY_SPDS 0x2a +#define H8_CTL_TFT_BRT_BATT 0x2b +#define H8_CTL_UPPER_TEMP 0x2c +#define H8_CTL_LOWER_TEMP 0x2d +#define H8_CTL_TEMP_CUTOUT 0x2e +#define H8_CTL_WAKEUP 0x2f +#define H8_CTL_CHG_THRESHOLD 0x30 +#define H8_CTL_TURBO_MODE 0x31 +#define H8_SET_DIAG_STATUS 0x40 +#define H8_SOFTWARE_RESET 0x41 +#define H8_RECAL_PTR 0x42 +#define H8_SET_INT_BATT_PERCENT 0x43 +#define H8_WRT_CFG_INTERFACE_REG 0x45 +#define H8_WRT_EVENT_STATUS_MASK 0x57 +#define H8_ENTER_POST_MODE 0x46 +#define H8_EXIT_POST_MODE 0x47 + +/* Block transfer commands */ +#define H8_RD_EEPROM 0x50 +#define H8_WRT_EEPROM 0x51 +#define H8_WRT_TO_STATUS_DISP 0x52 +#define H8_DEFINE_SPC_CHAR 0x53 + +/* Generic commands */ +#define H8_DEFINE_TABLE_STRING_ENTRY 0x60 + +/* Battery control commands */ +#define H8_PERFORM_EMU_CMD 0x70 +#define H8_EMU_RD_REG 0x71 +#define H8_EMU_WRT_REG 0x72 +#define H8_EMU_RD_RAM 0x73 +#define H8_EMU_WRT_RAM 0x74 +#define H8_BQ_RD_REG 0x75 +#define H8_BQ_WRT_REG 0x76 + +/* System admin commands */ +#define H8_PWR_OFF 0x80 + +/* + * H8 command related definitions + */ + +/* device control argument bits */ +#define H8_ENAB_EXTSMI 0x1 +#define H8_DISAB_IRQ 0x2 +#define H8_ENAB_FLASH_WRT 0x4 +#define H8_ENAB_THERM 0x8 +#define H8_ENAB_INT_PTR 0x10 +#define H8_ENAB_LOW_SPD_IND 0x20 +#define H8_ENAB_EXT_PTR 0x40 +#define H8_DISAB_PWR_OFF_SW 0x80 +#define H8_POWER_OFF 0x80 + +/* H8 read event status bits */ +#define H8_DC_CHANGE 0x1 +#define H8_INT_BATT_LOW 0x2 +#define H8_INT_BATT_CHARGE_THRESHOLD 0x4 +#define H8_INT_BATT_CHARGE_STATE 0x8 +#define H8_INT_BATT_STATUS 0x10 +#define H8_EXT_BATT_CHARGE_STATE 0x20 +#define H8_EXT_BATT_LOW 0x40 +#define H8_EXT_BATT_STATUS 0x80 +#define H8_THERMAL_THRESHOLD 0x100 +#define H8_WATCHDOG 0x200 +#define H8_DOCKING_STATION_STATUS 0x400 +#define H8_EXT_MOUSE_OR_CASE_SWITCH 0x800 +#define H8_KEYBOARD 0x1000 +#define H8_BATT_CHANGE_OVER 0x2000 +#define H8_POWER_BUTTON 0x4000 +#define H8_SHUTDOWN 0x8000 + +/* H8 control idle and busy speeds */ +#define H8_SPEED_LOW 0x1 +#define H8_SPEED_MED 0x2 +#define H8_SPEED_HI 0x3 +#define H8_SPEED_LOCKED 0x80 + +#define H8_MAX_CMD_SIZE 18 +#define H8_Q_ALLOC_AMOUNT 10 + +/* H8 state field values */ +#define H8_IDLE 1 +#define H8_XMIT 2 +#define H8_RCV 3 +#define H8_RESYNC 4 +#define H8_INTR_MODE 5 + +/* Mask values for control functions */ +#define UTH_HYSTERESIS 5 +#define DEFAULT_UTHERMAL_THRESHOLD 115 +#define H8_TIMEOUT_INTERVAL 30 +#define H8_RUN 4 + +#define H8_GET_MAX_TEMP 0x1 +#define H8_GET_CURR_TEMP 0x2 +#define H8_GET_UPPR_THRMAL_THOLD 0x4 +#define H8_GET_ETHERNET_ADDR 0x8 +#define H8_SYNC_OP 0x10 +#define H8_SET_UPPR_THRMAL_THOLD 0x20 +#define H8_GET_INT_BATT_STAT 0x40 +#define H8_GET_CPU_SPD 0x80 +#define H8_MANAGE_UTHERM 0x100 +#define H8_MANAGE_LTHERM 0x200 +#define H8_HALT 0x400 +#define H8_CRASH 0x800 +#define H8_GET_EXT_STATUS 0x10000 +#define H8_MANAGE_QUIET 0x20000 +#define H8_MANAGE_SPEEDUP 0x40000 +#define H8_MANAGE_BATTERY 0x80000 +#define H8_SYSTEM_DELAY_TEST 0x100000 +#define H8_POWER_SWITCH_TEST 0x200000 + +/* cpu speeds and clock divisor values */ +#define MHZ_14 5 +#define MHZ_28 4 +#define MHZ_57 3 +#define MHZ_115 2 +#define MHZ_230 0 + +/* + * H8 data + */ +struct h8_data { + u_int ser_num; + u_char ether_add[6]; + u_short hw_ver; + u_short mic_ver; + u_short max_tmp; + u_short min_tmp; + u_short cur_tmp; + u_int sys_var; + u_int pow_on; + u_int pow_on_secs; + u_char reset_status; + u_char pwr_dn_status; + u_short event_status; + u_short rom_cksm; + u_short ext_status; + u_short u_cfg; + u_char ibatt_volt; + u_char dc_volt; + u_char ptr_horiz; + u_char ptr_vert; + u_char eeprom_status; + u_char error_status; + u_char new_busy_speed; + u_char cfg_interface; + u_short int_batt_status; + u_short ext_batt_status; + u_char pow_up_status; + u_char event_status_mask; +}; + + +/* + * H8 command buffers + */ +typedef struct h8_cmd_q { + DLNODE(struct h8_cmd_q) link; /* double linked list */ + int ncmd; /* number of bytes in command */ + int nrsp; /* number of bytes in response */ + int cnt; /* number of bytes sent/received */ + int nacks; /* number of byte level acks */ + u_char cmdbuf[H8_MAX_CMD_SIZE]; /* buffer to store command */ + u_char rcvbuf[H8_MAX_CMD_SIZE]; /* buffer to store response */ +} h8_cmd_q_t; + +typedef struct __queue_head { + DLNODE(struct h8_cmd_q) link; +} queue_head_t; + +union intr_buf { + u_char byte[2]; + u_int word; +}; + +#endif /* __H8_H_ */ diff --git a/drivers/char/mem.c b/drivers/char/mem.c index f69b8ea28e4e..79387fbd1bad 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -400,7 +400,7 @@ int chr_dev_init(void) #if defined (CONFIG_BUSMOUSE) || defined(CONFIG_UMISC) || \ defined (CONFIG_PSMOUSE) || defined (CONFIG_MS_BUSMOUSE) || \ defined (CONFIG_ATIXL_BUSMOUSE) || defined(CONFIG_SOFT_WATCHDOG) || \ - defined (CONFIG_PCWATCHDOG) || \ + defined (CONFIG_PCWATCHDOG) || defined (CONFIG_H8) || \ defined (CONFIG_APM) || defined (CONFIG_RTC) || defined (CONFIG_SUN_MOUSE) misc_init(); #endif diff --git a/drivers/char/misc.c b/drivers/char/misc.c index dc91564f164b..7d94147f9ac8 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -232,6 +232,9 @@ int misc_init(void) #ifdef CONFIG_APM apm_bios_init(); #endif +#ifdef CONFIG_H8 + h8_init(); +#endif #ifdef CONFIG_RTC rtc_init(); #endif diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 4a6ab6f9b8f2..7964348432a0 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -28,9 +28,14 @@ * Based on other minimal char device drivers, like Alan's * watchdog, Ted's random, etc. etc. * + * 1.07 Paul Gortmaker. + * 1.08 Miquel van Smoorenburg: disallow certain things on the + * DEC Alpha as the CMOS clock is also used for other things. + * 1.09 Nikita Schmidt: epoch support and some Alpha cleanup. + * */ -#define RTC_VERSION "1.07" +#define RTC_VERSION "1.09" #define RTC_IRQ 8 /* Can't see this changing soon. */ #define RTC_IO_EXTENT 0x10 /* Only really two ports, but... */ @@ -98,6 +103,13 @@ unsigned char rtc_status = 0; /* bitmapped status byte. */ unsigned long rtc_freq = 0; /* Current periodic IRQ rate */ unsigned long rtc_irq_data = 0; /* our output to the world */ +/* + * If this driver ever becomes modularised, it will be really nice + * to make the epoch retain its value across module reload... + */ + +static unsigned long epoch = 1900; /* year corresponding to 0x00 */ + unsigned char days_in_mo[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; @@ -106,8 +118,12 @@ unsigned char days_in_mo[] = * so that there is no possibility of conflicting with the * set_rtc_mmss() call that happens during some timer interrupts. * (See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.) + * + * On Alpha we won't get any interrupts anyway, as they all end up + * in the system timer code. */ +#ifndef __alpha__ static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) { /* @@ -128,9 +144,11 @@ static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) add_timer(&rtc_irq_timer); } } +#endif /* * Now all the various file operations that we export. + * They are all useless on Alpha... *sigh*. */ static int rtc_lseek(struct inode *inode, struct file *file, off_t offset, @@ -141,6 +159,9 @@ static int rtc_lseek(struct inode *inode, struct file *file, off_t offset, static int rtc_read(struct inode *inode, struct file *file, char *buf, int count) { +#ifdef __alpha__ + return -EIO; +#else struct wait_queue wait = { current, NULL }; int retval; @@ -182,6 +203,7 @@ static int rtc_read(struct inode *inode, struct file *file, char *buf, int count remove_wait_queue(&rtc_wait, &wait); return retval; +#endif } static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, @@ -191,6 +213,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long flags; switch (cmd) { +#ifndef __alpha__ case RTC_AIE_OFF: /* Mask alarm int. enab. bit */ { mask_rtc_irq_bit(RTC_AIE); @@ -238,6 +261,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, set_rtc_irq_bit(RTC_UIE); return 0; } +#endif case RTC_ALM_READ: /* Read the present alarm time */ { /* @@ -342,7 +366,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, min = rtc_tm.tm_min; sec = rtc_tm.tm_sec; - if ((yrs < 1970) || (yrs > 2069)) + if (yrs < 1970) return -EINVAL; leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); @@ -356,16 +380,19 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, if ((hrs >= 24) || (min >= 60) || (sec >= 60)) return -EINVAL; - if (yrs >= 2000) - yrs -= 2000; /* RTC (0, 1, ... 69) */ - else - yrs -= 1900; /* RTC (70, 71, ... 99) */ + if ((yrs -= epoch) > 255) /* They are unsigned */ + return -EINVAL; save_flags(flags); cli(); - if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || - RTC_ALWAYS_BCD) - { + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + if (yrs > 169) { + restore_flags(flags); + return -EINVAL; + } + if (yrs >= 100) + yrs -= 100; + BIN_TO_BCD(sec); BIN_TO_BCD(min); BIN_TO_BCD(hrs); @@ -403,6 +430,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, memcpy_tofs((unsigned long*)arg, &rtc_freq, sizeof(unsigned long)); return 0; } +#ifndef __alpha__ case RTC_IRQP_SET: /* Set periodic IRQ rate. */ { int tmp = 0; @@ -439,6 +467,34 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, restore_flags(flags); return 0; } +#endif +#ifdef __alpha__ + case RTC_EPOCH_READ: /* Read the epoch. */ + { + int retval; + + retval = verify_area(VERIFY_WRITE, (unsigned long*)arg, sizeof(unsigned long)); + if (retval != 0) + return retval; + + memcpy_tofs((unsigned long*)arg, &epoch, sizeof(unsigned long)); + return 0; + } + case RTC_EPOCH_SET: /* Set the epoch. */ + { + /* + * There were no RTC clocks before 1900. + */ + if (arg < 1900) + return -EINVAL; + + if (!suser()) + return -EACCES; + + epoch = arg; + return 0; + } +#endif default: return -EINVAL; } @@ -448,16 +504,18 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, * We enforce only one user at a time here with the open/close. * Also clear the previous interrupt data on an open, and clean * up things on a close. + * On Alpha we just open, for we don't mess with interrups anyway. */ static int rtc_open(struct inode *inode, struct file *file) { - +#ifndef __alpha__ if(rtc_status & RTC_IS_OPEN) return -EBUSY; rtc_status |= RTC_IS_OPEN; rtc_irq_data = 0; +#endif return 0; } @@ -469,6 +527,7 @@ static void rtc_release(struct inode *inode, struct file *file) * in use, and clear the data. */ +#ifndef __alpha__ unsigned char tmp; unsigned long flags; @@ -489,8 +548,10 @@ static void rtc_release(struct inode *inode, struct file *file) rtc_irq_data = 0; rtc_status &= ~RTC_IS_OPEN; +#endif } +#ifndef __alpha__ static int rtc_select(struct inode *inode, struct file *file, int sel_type, select_table *wait) { @@ -501,6 +562,7 @@ static int rtc_select(struct inode *inode, struct file *file, } return 0; } +#endif /* * The various file operations we support. @@ -511,7 +573,11 @@ static struct file_operations rtc_fops = { rtc_read, NULL, /* No write */ NULL, /* No readdir */ +#ifdef __alpha__ + NULL, /* No select on Alpha */ +#else rtc_select, +#endif rtc_ioctl, NULL, /* No mmap */ rtc_open, @@ -528,17 +594,54 @@ static struct miscdevice rtc_dev= int rtc_init(void) { unsigned long flags; +#ifdef __alpha__ + unsigned int year, ctrl; + unsigned long uip_watchdog; + char *guess = NULL; +#endif printk("Real Time Clock Driver v%s\n", RTC_VERSION); +#ifndef __alpha__ if(request_irq(RTC_IRQ, rtc_interrupt, SA_INTERRUPT, "rtc", NULL)) { /* Yeah right, seeing as irq 8 doesn't even hit the bus. */ printk("rtc: IRQ %d is not free.\n", RTC_IRQ); return -EIO; } +#endif misc_register(&rtc_dev); /* Check region? Naaah! Just snarf it up. */ request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc"); +#ifdef __alpha__ + rtc_freq = HZ; + + /* Each operating system on an Alpha uses its own epoch. + Let's try to guess which one we are using now. */ + + uip_watchdog = jiffies; + if (rtc_is_updating() != 0) + while (jiffies - uip_watchdog < 2*HZ/100) + barrier(); + + save_flags(flags); + cli(); + year = CMOS_READ(RTC_YEAR); + ctrl = CMOS_READ(RTC_CONTROL); + restore_flags(flags); + + if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) + BCD_TO_BIN(year); /* This should never happen... */ + + if (year > 10 && year < 44) { + epoch = 1980; + guess = "ARC console"; + } else if (year < 96) { + epoch = 1952; + guess = "Digital UNIX"; + } + if (guess) + printk("rtc: %s epoch (%ld) detected\n", guess, epoch); +#else init_timer(&rtc_irq_timer); rtc_irq_timer.function = rtc_dropped_irq; rtc_wait = NULL; @@ -548,6 +651,7 @@ int rtc_init(void) CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT); restore_flags(flags); rtc_freq = 1024; +#endif return 0; } @@ -563,6 +667,7 @@ int rtc_init(void) * for something that requires a steady > 1KHz signal anyways.) */ +#ifndef __alpha__ void rtc_dropped_irq(unsigned long data) { unsigned long flags; @@ -579,6 +684,7 @@ void rtc_dropped_irq(unsigned long data) rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */ restore_flags(flags); } +#endif /* * Info exported via "/proc/rtc". @@ -723,7 +829,7 @@ void get_rtc_time(struct rtc_time *rtc_tm) * Account for differences between how the RTC uses the values * and how they are defined in a struct rtc_time; */ - if (rtc_tm->tm_year <= 69) + if ((rtc_tm->tm_year += epoch - 1900) <= 69) rtc_tm->tm_year += 100; rtc_tm->tm_mon--; @@ -763,6 +869,8 @@ void get_rtc_alm_time(struct rtc_time *alm_tm) * We also clear out any old irq data after an ioctl() that * meddles with the interrupt enable/disable bits. */ + +#ifndef __alpha__ void mask_rtc_irq_bit(unsigned char bit) { unsigned char val; @@ -792,4 +900,4 @@ void set_rtc_irq_bit(unsigned char bit) rtc_irq_data = 0; restore_flags(flags); } - +#endif diff --git a/drivers/char/selection.h b/drivers/char/selection.h index 7310f63083bd..41e4c11d0bff 100644 --- a/drivers/char/selection.h +++ b/drivers/char/selection.h @@ -61,10 +61,15 @@ extern void putconsxy(int currcons, char *p); /* how to access screen memory */ #include +#include #ifdef CONFIG_TGA_CONSOLE -extern int tga_blitc(unsigned int, unsigned long); +# ifdef CONFIG_VGA_CONSOLE +extern int curr_cons; +extern const struct console_desc cons_devices[]; +# endif + extern unsigned long video_mem_term; /* @@ -83,24 +88,57 @@ extern unsigned long video_mem_term; * * NOTE also: there's only *TWO* operations: to put/get a character/attribute. * All the others needed by VGA support go away, as Not Applicable for TGA. + * + * NOTE: "(long) addr < 0" tests for an Alpha kernel virtual address; this + * indicates a VC's backing store; otherwise, it's a bus memory address, for + * the VGA's screen memory, so we do the Alpha "swizzle"... :-) */ +#define IS_VIDEO_MEMORY(a) \ + ((unsigned long)(a) - video_mem_base < video_mem_term - video_mem_base) + static inline void scr_writew(unsigned short val, unsigned short * addr) { + if ((long) addr < 0) { /* - * always deposit the char/attr, then see if it was to "screen" mem. + * always deposit the char/attr, then see if it was to + * "screen" mem. * if so, then render the char/attr onto the real screen. */ *addr = val; - if ((unsigned long)addr < video_mem_term && - (unsigned long)addr >= video_mem_base) { - tga_blitc(val, (unsigned long) addr); - } + + /* + * TGA might need the char blitted to the screen, + * but check first, we could be running on a VGA. + */ + if (con_blitc && IS_VIDEO_MEMORY(addr)) + con_blitc(val, (unsigned long) addr); + } else + writew(val, (unsigned long) addr); } static inline unsigned short scr_readw(unsigned short * addr) { + if ((long) addr < 0) return *addr; + return readw((unsigned long) addr); +} + +/* scr_writeb and scr_readb are not expected to be called with a TGA */ +static inline void scr_writeb(unsigned char val, unsigned char * addr) +{ + if ((long) addr < 0) + *addr = val; + else + writeb(val, (unsigned long) addr); +} + +static inline unsigned char scr_readb(unsigned char * addr) +{ + if ((long) addr < 0) + return *addr; + return readb((unsigned long) addr); } + #else /* CONFIG_TGA_CONSOLE */ /* @@ -110,8 +148,6 @@ static inline unsigned short scr_readw(unsigned short * addr) #ifdef __alpha__ -#include - /* * NOTE: "(long) addr < 0" tests for an Alpha kernel virtual address; this * indicates a VC's backing store; otherwise, it's a bus memory address, for diff --git a/drivers/char/tga.c b/drivers/char/tga.c index a992029641a4..dc6ebb67c7d4 100644 --- a/drivers/char/tga.c +++ b/drivers/char/tga.c @@ -201,7 +201,7 @@ void tga_init_video(void); void tga_clear_screen(void); void -set_palette (void) +tga_set_palette (void) { int i, j; @@ -233,7 +233,7 @@ set_palette (void) } void -__set_origin(unsigned short offset) +tga_set_origin(unsigned short offset) { /* * should not be called, but if so, do nothing... @@ -244,7 +244,7 @@ __set_origin(unsigned short offset) * Hide the cursor from view, during blanking, usually... */ void -hide_cursor(void) +tga_hide_cursor(void) { unsigned long flags; save_flags(flags); cli(); @@ -259,7 +259,7 @@ hide_cursor(void) } void -set_cursor(int currcons) +tga_set_cursor(int currcons) { unsigned int idx, xt, yt, row, col; unsigned long flags; @@ -267,8 +267,10 @@ set_cursor(int currcons) if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS) return; +#if 0 if (__real_origin != __origin) - __set_origin(__real_origin); + tga_set_origin(__real_origin); +#endif save_flags(flags); cli(); @@ -300,12 +302,12 @@ set_cursor(int currcons) } } else - hide_cursor(); + tga_hide_cursor(); restore_flags(flags); } unsigned long -con_type_init(unsigned long kmem_start, const char **display_desc) +tga_init(unsigned long kmem_start, const char **display_desc) { can_do_color = 1; @@ -328,7 +330,7 @@ con_type_init(unsigned long kmem_start, const char **display_desc) * the VGA version of set_scrmem() has some direct VGA references. */ void -get_scrmem(int currcons) +tga_get_scrmem(int currcons) { memcpyw((unsigned short *)vc_scrbuf[currcons], (unsigned short *)origin, video_screen_size); @@ -338,7 +340,7 @@ get_scrmem(int currcons) } void -set_scrmem(int currcons, long offset) +tga_set_scrmem(int currcons, long offset) { if (video_mem_term - video_mem_base < offset + video_screen_size) offset = 0; /* strange ... */ @@ -357,7 +359,7 @@ set_scrmem(int currcons, long offset) * for now, we will use/allow *only* our built-in font... */ int -set_get_font(char * arg, int set, int ch512) +tga_set_get_font(char * arg, int set, int ch512) { return -EINVAL; } @@ -371,7 +373,7 @@ set_get_font(char * arg, int set, int ch512) * for now, we only support the built-in font... */ int -con_adjust_height(unsigned long fontheight) +tga_adjust_height(unsigned long fontheight) { return -EINVAL; } @@ -386,7 +388,7 @@ con_adjust_height(unsigned long fontheight) */ int -set_get_cmap(unsigned char * arg, int set) { +tga_set_get_cmap(unsigned char * arg, int set) { int i; i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, 16*3); @@ -424,16 +426,16 @@ set_get_cmap(unsigned char * arg, int set) { * dummy routines for the VESA blanking code, which is VGA only, * so we don't have to carry that stuff around for the TGA... */ -void vesa_powerdown(void) +void tga_vesa_powerdown(void) { } -void vesa_blank(void) +void tga_vesa_blank(void) { } -void vesa_unblank(void) +void tga_vesa_unblank(void) { } -void set_vesa_blanking(const unsigned long arg) +void tga_set_vesa_blanking(const unsigned long arg) { } @@ -441,9 +443,13 @@ void set_vesa_blanking(const unsigned long arg) * video init code, called from within the PCI bus probing code; * when TGA console is configured, at the end of the probing code, * we call here to look for a TGA device, and proceed... + * + * note that this code MUST be called BEFORE console_init/con_init, + * so that either VGA or TGA are set up but not both. we had to move + * console_init to after pci_init in start_kernel to assure this. */ void -tga_console_init(void) +tga_console_find(void) { unsigned char pci_bus, pci_devfn; int status; @@ -477,10 +483,11 @@ tga_console_init(void) tga_init_video(); tga_clear_screen(); - /* - * FINALLY, we can register TGA as console (whew!) - */ - register_console(console_print); +#ifdef CONFIG_VGA_CONSOLE + /* if both are configured, we are using a dispatch table, + so we must set the index */ + curr_cons = 1; +#endif } unsigned char PLLbits[7] = { 0x80, 0x04, 0x00, 0x24, 0x44, 0x80, 0xb8 }; diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 81b3122609f6..90051a4396da 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -1163,6 +1163,10 @@ static void release_dev(struct file * filp) } } #endif + + if (tty->driver.close) + tty->driver.close(tty, filp); + /* * Sanity check: if tty->count is going to zero, there shouldn't be * any waiters on tty->read_wait or tty->write_wait. We test the @@ -1220,9 +1224,6 @@ static void release_dev(struct file * filp) * block, so it's safe to proceed with closing. */ - if (tty->driver.close) - tty->driver.close(tty, filp); - if (pty_master) { if (--o_tty->count < 0) { printk("release_dev: bad pty slave count (%d) for %s\n", diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 7c9013390939..52f0fae18144 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -689,13 +689,13 @@ el3_rx(struct device *dev) lp->stats.rx_packets++; continue; } else if (el3_debug) - printk("%s: Couldn't allocate a sk_buff of size %d.\n", + printk(KERN_WARNING "%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len); } lp->stats.rx_dropped++; outw(RxDiscard, ioaddr + EL3_CMD); while (inw(ioaddr + EL3_STATUS) & 0x1000) - printk(" Waiting for 3c509 to discard packet, status %x.\n", + printk(KERN_DEBUG " Waiting for 3c509 to discard packet, status %x.\n", inw(ioaddr + EL3_STATUS) ); } diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index d8fa645abda7..8f98bf9184dc 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -15,7 +15,7 @@ */ static char *version = -"3c59x.c:v0.99 4/7/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n"; +"3c59x.c:v0.99E 5/12/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n"; /* "Knobs" that adjust features and parameters. */ /* Set the copy breakpoint for the copy-only-tiny-frames scheme. @@ -35,7 +35,7 @@ static int vortex_debug = 1; /* Some values here only for performance evaluation and path-coverage debugging. */ -static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0; +static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits; /* Enable the automatic media selection code -- usually set. */ #define AUTOMEDIA 1 @@ -44,7 +44,9 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0; programmed-I/O for Vortex cards. Full-bus-master transfers are always enabled by default on Boomerang cards. If VORTEX_BUS_MASTER is defined, the feature may be turned on using 'options'. */ +#if YOU_ARE_BRAVER_THAN_ME #define VORTEX_BUS_MASTER +#endif /* A few values that may be tweaked. */ /* Time in jiffies before concluding the transmitter is hung. */ @@ -105,6 +107,11 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0; #define RUN_AT(x) (jiffies + (x)) #define DEV_ALLOC_SKB(len) dev_alloc_skb(len) #endif +#if LINUX_VERSION_CODE < 0x20159 +#define DEV_FREE_SKB(skb) dev_kfree_skb (skb, FREE_WRITE); +#else /* Grrr, unneeded incompatible change. */ +#define DEV_FREE_SKB(skb) dev_kfree_skb(skb); +#endif #ifdef SA_SHIRQ #define FREE_IRQ(irqnum, dev) free_irq(irqnum, dev) @@ -329,7 +336,7 @@ union wn3_config { struct w3_config_fields { unsigned int ram_size:3, ram_width:1, ram_speed:2, rom_size:2; int pad8:8; - unsigned int ram_split:2, pad18:2, xcvr:3, pad21:1, autoselect:1; + unsigned int ram_split:2, pad18:2, xcvr:4, autoselect:1; int pad24:7; } u; }; @@ -366,6 +373,8 @@ struct boom_rx_desc { enum rx_desc_status { RxDComplete=0x00008000, RxDError=0x4000, /* See boomerang_rx() for actual error bits */ + IPChksumErr=1<<25, TCPChksumErr=1<<26, UDPChksumErr=1<<27, + IPChksumValid=1<<29, TCPChksumValid=1<<30, UDPChksumValid=1<<31, }; struct boom_tx_desc { @@ -378,6 +387,7 @@ struct boom_tx_desc { /* Values for the Tx status entry. */ enum tx_desc_status { CRCDisable=0x2000, TxDComplete=0x8000, + AddIPChksum=0x02000000, AddTCPChksum=0x04000000, AddUDPChksum=0x08000000, TxIntrUploaded=0x80000000, /* IRQ when in FIFO, but maybe not sent. */ }; @@ -413,6 +423,7 @@ struct vortex_private { full_duplex:1, autoselect:1, bus_master:1, /* Vortex can only do a fragment bus-m. */ full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang */ + hw_csums:1, /* Has hardware checksums. */ tx_full:1; u16 status_enable; u16 available_media; /* From Wn3_Options. */ @@ -426,7 +437,7 @@ struct vortex_private { */ enum xcvr_types { XCVR_10baseT=0, XCVR_AUI, XCVR_10baseTOnly, XCVR_10base2, XCVR_100baseTx, - XCVR_100baseFx, XCVR_MII=6, XCVR_Default=8, + XCVR_100baseFx, XCVR_MII=6, XCVR_NWAY=8, XCVR_ExtMII=9, XCVR_Default=10, }; static struct media_table { @@ -444,6 +455,8 @@ static struct media_table { { "100baseFX", Media_Lnk, 0x04, XCVR_MII, (14*HZ)/10}, { "MII", 0, 0x41, XCVR_10baseT, 3*HZ }, { "undefined", 0, 0x01, XCVR_10baseT, 10000}, + { "Autonegotiate", 0, 0x41, XCVR_10baseT, 3*HZ}, + { "MII-External", 0, 0x41, XCVR_10baseT, 3*HZ }, { "Default", 0, 0xFF, XCVR_10baseT, 10000}, }; @@ -612,9 +625,10 @@ static int vortex_scan(struct device *dev) unsigned char pci_bus, pci_device_fn; for (;pci_index < 0xff; pci_index++) { - u8 pci_irq_line, pci_latency; + u8 pci_latency; u16 pci_command, new_command, vendor, device; - u32 pci_ioaddr; + int irq; + long ioaddr; if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index, &pci_bus, &pci_device_fn) @@ -624,19 +638,39 @@ static int vortex_scan(struct device *dev) PCI_VENDOR_ID, &vendor); pcibios_read_config_word(pci_bus, pci_device_fn, PCI_DEVICE_ID, &device); - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_INTERRUPT_LINE, &pci_irq_line); - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_0, &pci_ioaddr); pcibios_read_config_word(pci_bus, pci_device_fn, PCI_COMMAND, &pci_command); + { +#if LINUX_VERSION_CODE >= 0x20155 + struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn); + ioaddr = pdev->base_address[0]; + irq = pdev->irq; +#else + u32 pci_ioaddr; + u8 pci_irq_line; + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_INTERRUPT_LINE, &pci_irq_line); + pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_0, &pci_ioaddr); + ioaddr = pci_ioaddr; + irq = pci_irq_line; +#endif + } /* Remove I/O space marker in bit 0. */ - pci_ioaddr &= ~3; + ioaddr &= ~3; if (vendor != TCOM_VENDOR_ID) continue; - if (check_region(pci_ioaddr, VORTEX_TOTAL_SIZE)) + if (ioaddr == 0) { + printk(KERN_WARNING " A 3Com network adapter has been found, " + "however it has not been assigned an I/O address.\n" + " You may need to power-cycle the machine for this " + "device to work!\n"); + continue; + } + + if (check_region(ioaddr, VORTEX_TOTAL_SIZE)) continue; /* Activate the card. */ @@ -649,7 +683,7 @@ static int vortex_scan(struct device *dev) PCI_COMMAND, new_command); } - dev = vortex_found_device(dev, pci_ioaddr, pci_irq_line, + dev = vortex_found_device(dev, ioaddr, irq, device, dev && dev->mem_start ? dev->mem_start : options[cards_found], cards_found); @@ -886,6 +920,7 @@ static int vortex_probe1(struct device *dev) config.u.ram_width ? "word" : "byte", ram_split[config.u.ram_split], config.u.autoselect ? "autoselect/" : "", + config.u.xcvr ? "NWay Autonegotiation" : media_tbl[config.u.xcvr].name); vp->default_media = config.u.xcvr; vp->autoselect = config.u.autoselect; @@ -905,7 +940,7 @@ static int vortex_probe1(struct device *dev) int mii_status; mdio_sync(ioaddr, 32); mii_status = mdio_read(ioaddr, phy, 1); - if (mii_status != 0xffff) { + if (mii_status && mii_status != 0xffff) { vp->phys[phy_idx++] = phy; printk(KERN_INFO " MII transceiver found at address %d, status %4x.\n", phy, mii_status); @@ -996,8 +1031,6 @@ vortex_open(struct device *dev) if (dev->if_port == XCVR_MII) { int mii_reg1, mii_reg5; - /* We cheat here: we know that we are using the 83840 transceiver - which summarizes the FD status in an extended register. */ EL3WINDOW(4); /* Read BMSR (reg1) only to clear old status. */ mii_reg1 = mdio_read(ioaddr, vp->phys[0], 1); @@ -1024,13 +1057,13 @@ vortex_open(struct device *dev) } outw(TxReset, ioaddr + EL3_CMD); - for (i = 20; i >= 0 ; i--) + for (i = 2000; i >= 0 ; i--) if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) break; outw(RxReset, ioaddr + EL3_CMD); /* Wait a few ticks for the RxReset command to complete. */ - for (i = 20; i >= 0 ; i--) + for (i = 2000; i >= 0 ; i--) if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) break; @@ -1038,8 +1071,7 @@ vortex_open(struct device *dev) #ifdef SA_SHIRQ /* Use the now-standard shared IRQ implementation. */ - if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ, - vp->product_name, dev)) { + if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ, dev->name, dev)) { return -EAGAIN; } #else @@ -1263,7 +1295,7 @@ static void vortex_tx_timeout(struct device *dev) vortex_interrupt IRQ(dev->irq, dev, 0); } outw(TxReset, ioaddr + EL3_CMD); - for (j = 20; j >= 0 ; j--) + for (j = 200; j >= 0 ; j--) if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) break; @@ -1292,6 +1324,10 @@ static void vortex_tx_timeout(struct device *dev) if (vp->cur_tx - vp->dirty_tx > 0 && inl(ioaddr + DownListPtr) == 0) outl(virt_to_bus(&vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]), ioaddr + DownListPtr); + if (vp->tx_full && (vp->cur_tx - vp->dirty_tx <= TX_RING_SIZE - 1)) { + vp->tx_full = 0; + clear_bit(0, (void*)&dev->tbusy); + } outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); outw(DownUnstall, ioaddr + EL3_CMD); } else @@ -1315,6 +1351,7 @@ vortex_error(struct device *dev, int status) struct vortex_private *vp = (struct vortex_private *)dev->priv; int ioaddr = dev->base_addr; int do_tx_reset = 0; + int i; if (status & TxComplete) { /* Really "TxError" for us. */ unsigned char tx_status = inb(ioaddr + TxStatus); @@ -1363,9 +1400,8 @@ vortex_error(struct device *dev, int status) dev->name, fifo_diag); /* Adapter failure requires Tx/Rx reset and reinit. */ if (vp->full_bus_master_tx) { - int j; outw(TotalReset | 0xff, ioaddr + EL3_CMD); - for (j = 200; j >= 0 ; j--) + for (i = 2000; i >= 0 ; i--) if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) break; /* Re-enable the receiver. */ @@ -1373,8 +1409,11 @@ vortex_error(struct device *dev, int status) outw(TxEnable, ioaddr + EL3_CMD); } else if (fifo_diag & 0x0400) do_tx_reset = 1; - if (fifo_diag & 0x2000) { + if (fifo_diag & 0x3000) { outw(RxReset, ioaddr + EL3_CMD); + for (i = 2000; i >= 0 ; i--) + if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) + break; /* Set the Rx filter to the current state. */ set_rx_mode(dev); outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */ @@ -1384,7 +1423,7 @@ vortex_error(struct device *dev, int status) if (do_tx_reset) { int j; outw(TxReset, ioaddr + EL3_CMD); - for (j = 20; j >= 0 ; j--) + for (j = 200; j >= 0 ; j--) if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) break; outw(TxEnable, ioaddr + EL3_CMD); @@ -1418,7 +1457,7 @@ vortex_start_xmit(struct sk_buff *skb, struct device *dev) } else { /* ... and the packet rounded to a doubleword. */ outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); - dev_kfree_skb (skb, FREE_WRITE); + DEV_FREE_SKB(skb); if (inw(ioaddr + TxFree) > 1536) { clear_bit(0, (void*)&dev->tbusy); } else @@ -1428,7 +1467,7 @@ vortex_start_xmit(struct sk_buff *skb, struct device *dev) #else /* ... and the packet rounded to a doubleword. */ outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); - dev_kfree_skb (skb, FREE_WRITE); + DEV_FREE_SKB(skb); if (inw(ioaddr + TxFree) > 1536) { clear_bit(0, (void*)&dev->tbusy); } else @@ -1453,7 +1492,7 @@ vortex_start_xmit(struct sk_buff *skb, struct device *dev) if (tx_status & 0x30) { int j; outw(TxReset, ioaddr + EL3_CMD); - for (j = 20; j >= 0 ; j--) + for (j = 200; j >= 0 ; j--) if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) break; } @@ -1503,7 +1542,7 @@ boomerang_start_xmit(struct sk_buff *skb, struct device *dev) cli(); outw(DownStall, ioaddr + EL3_CMD); /* Wait for the stall to complete. */ - for (i = 60; i >= 0 ; i--) + for (i = 600; i >= 0 ; i--) if ( (inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0) break; prev_entry->next = virt_to_bus(&vp->tx_ring[entry]); @@ -1535,13 +1574,13 @@ static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs) #else struct device *dev = (struct device *)(irq2dev_map[irq]); #endif - struct vortex_private *lp; + struct vortex_private *vp; int ioaddr, status; int latency; int work_done = max_interrupt_work; - lp = (struct vortex_private *)dev->priv; - if (test_and_set_bit(0, (void*)&lp->in_interrupt)) { + vp = (struct vortex_private *)dev->priv; + if (test_and_set_bit(0, (void*)&vp->in_interrupt)) { printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name); return; } @@ -1576,24 +1615,24 @@ static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs) } if (status & DownComplete) { - unsigned int dirty_tx = lp->dirty_tx; + unsigned int dirty_tx = vp->dirty_tx; - while (lp->cur_tx - dirty_tx > 0) { + while (vp->cur_tx - dirty_tx > 0) { int entry = dirty_tx % TX_RING_SIZE; if (inl(ioaddr + DownListPtr) == - virt_to_bus(&lp->tx_ring[entry])) + virt_to_bus(&vp->tx_ring[entry])) break; /* It still hasn't been processed. */ - if (lp->tx_skbuff[entry]) { - dev_kfree_skb(lp->tx_skbuff[entry], FREE_WRITE); - lp->tx_skbuff[entry] = 0; + if (vp->tx_skbuff[entry]) { + DEV_FREE_SKB(vp->tx_skbuff[entry]); + vp->tx_skbuff[entry] = 0; } - /* lp->stats.tx_packets++; Counted below. */ + /* vp->stats.tx_packets++; Counted below. */ dirty_tx++; } - lp->dirty_tx = dirty_tx; + vp->dirty_tx = dirty_tx; outw(AckIntr | DownComplete, ioaddr + EL3_CMD); - if (lp->tx_full && (lp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) { - lp->tx_full= 0; + if (vp->tx_full && (vp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) { + vp->tx_full= 0; clear_bit(0, (void*)&dev->tbusy); mark_bh(NET_BH); } @@ -1602,7 +1641,7 @@ static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs) if (status & DMADone) { outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */ clear_bit(0, (void*)&dev->tbusy); - dev_kfree_skb (lp->tx_skb, FREE_WRITE); /* Release the transfered buffer */ + DEV_FREE_SKB(vp->tx_skb); /* Release the transfered buffer */ mark_bh(NET_BH); } #endif @@ -1636,7 +1675,7 @@ static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs) dev->name, status); dev->interrupt = 0; - clear_bit(0, (void*)&lp->in_interrupt); + clear_bit(0, (void*)&vp->in_interrupt); return; } @@ -1777,6 +1816,15 @@ boomerang_rx(struct device *dev) } #if LINUX_VERSION_CODE > 0x10300 skb->protocol = eth_type_trans(skb, dev); + { /* Use hardware checksum info. */ + int csum_bits = rx_status & 0xee000000; + if (csum_bits && + (csum_bits == (IPChksumValid | TCPChksumValid) || + csum_bits == (IPChksumValid | UDPChksumValid))) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + rx_csumhits++; + } + } #else skb->len = pkt_len; #endif @@ -1825,13 +1873,13 @@ vortex_close(struct device *dev) printk(KERN_DEBUG"%s: vortex_close() status %4.4x, Tx status %2.2x.\n", dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus)); printk(KERN_DEBUG "%s: vortex close stats: rx_nocopy %d rx_copy %d" - " tx_queued %d.\n", - dev->name, rx_nocopy, rx_copy, queued_packet); + " tx_queued %d Rx pre-checksummed %d.\n", + dev->name, rx_nocopy, rx_copy, queued_packet, rx_csumhits); } del_timer(&vp->timer); - /* Turn off statistics ASAP. We update lp->stats below. */ + /* Turn off statistics ASAP. We update vp->stats below. */ outw(StatsDisable, ioaddr + EL3_CMD); /* Disable the receiver and transmitter. */ @@ -1859,7 +1907,7 @@ vortex_close(struct device *dev) #if LINUX_VERSION_CODE < 0x20100 vp->rx_skbuff[i]->free = 1; #endif - dev_kfree_skb (vp->rx_skbuff[i], FREE_WRITE); + DEV_FREE_SKB(vp->rx_skbuff[i]); vp->rx_skbuff[i] = 0; } } @@ -1867,7 +1915,7 @@ vortex_close(struct device *dev) outl(0, ioaddr + DownListPtr); for (i = 0; i < TX_RING_SIZE; i++) if (vp->tx_skbuff[i]) { - dev_kfree_skb(vp->tx_skbuff[i], FREE_WRITE); + DEV_FREE_SKB(vp->tx_skbuff[i]); vp->tx_skbuff[i] = 0; } } diff --git a/drivers/net/auto_irq.c b/drivers/net/auto_irq.c index 6ac1531ea7a1..82bc7b1ca349 100644 --- a/drivers/net/auto_irq.c +++ b/drivers/net/auto_irq.c @@ -39,7 +39,7 @@ static const char *version= #include #include -struct device *irq2dev_map[16] = {0, 0, /* ... zeroed */}; +struct device *irq2dev_map[NR_IRQS] = {0, 0, /* ... zeroed */}; unsigned long irqs_busy = 0x2147; /* The set of fixed IRQs (keyboard, timer, etc) */ unsigned long irqs_used = 0x0001; /* The set of fixed IRQs sometimes enabled. */ @@ -65,8 +65,8 @@ static void autoirq_probe(int irq, void *dev_id, struct pt_regs * regs) int autoirq_setup(int waittime) { int i; - int timeout = jiffies + waittime; - int boguscount = (waittime*loops_per_sec) / 100; + unsigned long timeout = jiffies + waittime; + unsigned long boguscount = (waittime*loops_per_sec) / 100; irq_handled = 0; irq_bitmap = 0; @@ -93,8 +93,8 @@ int autoirq_setup(int waittime) int autoirq_report(int waittime) { int i; - int timeout = jiffies+waittime; - int boguscount = (waittime*loops_per_sec) / 100; + unsigned long timeout = jiffies+waittime; + unsigned long boguscount = (waittime*loops_per_sec) / 100; /* Hang out at least jiffies waiting for the IRQ. */ diff --git a/drivers/net/lance.c b/drivers/net/lance.c index 83b889d05882..d33808c1dc2a 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -76,7 +76,7 @@ static const char *version = "lance.c:v1.14 2/3/1998 dplatt@3do.com, becker@cesd static unsigned int lance_portlist[] = { 0x300, 0x320, 0x340, 0x360, 0}; int lance_probe(struct device *dev); -void lance_probe1(struct device *dev, int ioaddr, int irq, int options); +int lance_probe1(struct device *dev, int ioaddr, int irq, int options); #ifdef HAVE_DEVLIST struct netdev_entry lance_drv = @@ -374,7 +374,7 @@ cleanup_module(void) */ int lance_probe(struct device *dev) { - int *port; + int *port, result; if (high_memory <= 16*1024*1024) lance_need_isa_bounce_buffers = 0; @@ -413,8 +413,9 @@ int lance_probe(struct device *dev) } printk("Found PCnet/PCI at %#x, irq %d.\n", pci_ioaddr, pci_irq_line); - lance_probe1(dev, pci_ioaddr, pci_irq_line, 0); + result = lance_probe1(dev, pci_ioaddr, pci_irq_line, 0); pci_irq_line = 0; + if (!result) return 0; } } #endif /* defined(CONFIG_PCI) */ @@ -428,14 +429,16 @@ int lance_probe(struct device *dev) char offset15, offset14 = inb(ioaddr + 14); if ((offset14 == 0x52 || offset14 == 0x57) && - ((offset15 = inb(ioaddr + 15)) == 0x57 || offset15 == 0x44)) - lance_probe1(dev, ioaddr, 0, 0); + ((offset15 = inb(ioaddr + 15)) == 0x57 || offset15 == 0x44)) { + result = lance_probe1(dev, ioaddr, 0, 0); + if ( !result ) return 0; + } } } - return 0; + return -ENODEV; } -void lance_probe1(struct device *dev, int ioaddr, int irq, int options) +int lance_probe1(struct device *dev, int ioaddr, int irq, int options) { struct lance_private *lp; short dma_channels; /* Mark spuriously-busy DMA channels */ @@ -473,7 +476,7 @@ void lance_probe1(struct device *dev, int ioaddr, int irq, int options) outw(0x0000, ioaddr+LANCE_ADDR); /* Switch to window 0 */ if (inw(ioaddr+LANCE_DATA) != 0x0004) - return; + return -ENODEV; /* Get the version of the chip. */ outw(88, ioaddr+LANCE_ADDR); @@ -486,7 +489,7 @@ void lance_probe1(struct device *dev, int ioaddr, int irq, int options) if (lance_debug > 2) printk(" LANCE chip version is %#x.\n", chip_version); if ((chip_version & 0xfff) != 0x003) - return; + return -ENODEV; chip_version = (chip_version >> 12) & 0xffff; for (lance_version = 1; chip_table[lance_version].id_number; lance_version++) { if (chip_table[lance_version].id_number == chip_version) @@ -512,10 +515,9 @@ void lance_probe1(struct device *dev, int ioaddr, int irq, int options) #ifdef CONFIG_LANCE32 /* look if it's a PCI or VLB chip */ if (lance_version == PCNET_PCI || lance_version == PCNET_VLB || lance_version == PCNET_PCI_II) { - extern void lance32_probe1 (struct device *dev, const char *chipname, int pci_irq_line); + extern int lance32_probe1 (struct device *dev, const char *chipname, int pci_irq_line); - lance32_probe1 (dev, chipname, pci_irq_line); - return; + return lance32_probe1 (dev, chipname, pci_irq_line); } #endif /* Make certain the data structures used by the LANCE are aligned and DMAble. */ @@ -604,7 +606,7 @@ void lance_probe1(struct device *dev, int ioaddr, int irq, int options) printk(", probed IRQ %d", dev->irq); else { printk(", failed to detect IRQ line.\n"); - return; + return -ENODEV; } /* Check for the initialization done bit, 0x0100, which means @@ -618,7 +620,7 @@ void lance_probe1(struct device *dev, int ioaddr, int irq, int options) } else if (dev->dma) { if (request_dma(dev->dma, chipname)) { printk("DMA %d allocation failed.\n", dev->dma); - return; + return -ENODEV; } else printk(", assigned DMA %d.\n", dev->dma); } else { /* OK, we have to auto-DMA. */ @@ -653,7 +655,7 @@ void lance_probe1(struct device *dev, int ioaddr, int irq, int options) } if (i == 4) { /* Failure: bail. */ printk("DMA detection failed.\n"); - return; + return -ENODEV; } } @@ -666,7 +668,7 @@ void lance_probe1(struct device *dev, int ioaddr, int irq, int options) dev->irq = autoirq_report(4); if (dev->irq == 0) { printk(" Failed to detect the 7990 IRQ line.\n"); - return; + return -ENODEV; } printk(" Auto-IRQ detected IRQ%d.\n", dev->irq); } @@ -689,7 +691,7 @@ void lance_probe1(struct device *dev, int ioaddr, int irq, int options) dev->get_stats = lance_get_stats; dev->set_multicast_list = set_multicast_list; - return; + return 0; } static int diff --git a/drivers/net/ne.c b/drivers/net/ne.c index 791c44a9cc63..ed2efbb0bdd5 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -793,7 +793,7 @@ cleanup_module(void) if (dev->priv != NULL) { kfree(dev->priv); dev->priv = NULL; - free_irq(dev->irq, NULL); + free_irq(dev->irq, dev); irq2dev_map[dev->irq] = NULL; release_region(dev->base_addr, NE_IO_EXTENT); unregister_netdev(dev); diff --git a/drivers/net/ppp.c b/drivers/net/ppp.c index 632afa094ca8..d78146d5faf3 100644 --- a/drivers/net/ppp.c +++ b/drivers/net/ppp.c @@ -5,8 +5,9 @@ * * Dynamic PPP devices by Jim Freeman . * ppp_tty_receive ``noisy-raise-bug'' fixed by Ove Ewerlid + * Fixed (I hope) the wait_queue trashing bug. Alan Cox * - * ==FILEVERSION 970703== + * ==FILEVERSION 980512== * * NOTE TO MAINTAINERS: * If you modify this file at all, please set the number above to the @@ -448,8 +449,13 @@ ppp_init_ctrl_blk (register struct ppp *ppp) ppp->ubuf = NULL; ppp->cbuf = NULL; ppp->slcomp = NULL; +#if 0 + /* AC - We don't want to initialise this as the wait queue may still + be live. Having someone waiting on the old and the new queue is fine + the old people will unhook themselves so just set this up in ppp_alloc */ ppp->read_wait = NULL; ppp->write_wait = NULL; +#endif ppp->last_xmit = jiffies - flag_time; /* clear statistics */ @@ -798,9 +804,7 @@ ppp_tty_open (struct tty_struct *tty) } if (ppp == NULL) { - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR - "ppp_tty_open: couldn't allocate ppp channel\n"); + printk (KERN_WARNING "ppp_tty_open: couldn't allocate ppp channel\n"); return -ENFILE; } /* diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 0574de0ced9c..d35569dafa55 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -740,6 +740,7 @@ const char *pci_strvendor(unsigned int vendor) case PCI_VENDOR_ID_MATROX: return "Matrox"; case PCI_VENDOR_ID_CT: return "Chips & Technologies"; case PCI_VENDOR_ID_MIRO: return "Miro"; + case PCI_VENDOR_ID_NEC: return "NEC"; case PCI_VENDOR_ID_FD: return "Future Domain"; case PCI_VENDOR_ID_SI: return "Silicon Integrated Systems"; case PCI_VENDOR_ID_HP: return "Hewlett Packard"; @@ -892,15 +893,16 @@ static void burst_bridge(unsigned char bus, unsigned char devfn, static int sprint_dev_config(struct pci_dev *dev, char *buf, int size) { unsigned long base; - unsigned int l, class_rev, bus, devfn; + unsigned int l, class_rev, bus, devfn, last_reg; unsigned short vendor, device, status; - unsigned char bist, latency, min_gnt, max_lat; + unsigned char bist, latency, min_gnt, max_lat, hdr_type; int reg, len = 0; const char *str; bus = dev->bus->number; devfn = dev->devfn; + pcibios_read_config_byte (bus, devfn, PCI_HEADER_TYPE, &hdr_type); pcibios_read_config_dword(bus, devfn, PCI_CLASS_REVISION, &class_rev); pcibios_read_config_word (bus, devfn, PCI_VENDOR_ID, &vendor); pcibios_read_config_word (bus, devfn, PCI_DEVICE_ID, &device); @@ -979,7 +981,17 @@ static int sprint_dev_config(struct pci_dev *dev, char *buf, int size) len += sprintf(buf + len, "Max Lat=%d.", max_lat); } - for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) { + switch (hdr_type & 0x7f) { + case 0: + last_reg = PCI_BASE_ADDRESS_5; + break; + case 1: + last_reg = PCI_BASE_ADDRESS_1; + break; + default: + last_reg = 0; + } + for (reg = PCI_BASE_ADDRESS_0; reg <= last_reg; reg += 4) { if (len + 40 > size) { return -1; } @@ -1072,7 +1084,7 @@ static void *pci_malloc(long size, unsigned long *mem_startp) static unsigned int scan_bus(struct pci_bus *bus, unsigned long *mem_startp) { unsigned int devfn, l, max; - unsigned char cmd, tmp, hdr_type, is_multi = 0; + unsigned char cmd, tmp, hdr_type, ht, is_multi = 0; struct pci_dev_info *info; struct pci_dev *dev; struct pci_bus *child; @@ -1146,10 +1158,20 @@ static unsigned int scan_bus(struct pci_bus *bus, unsigned long *mem_startp) /* * Check if the header type is known and consistent with - * device type. Bridges should have hdr_type 1, all other - * devices 0. + * device type. PCI-to-PCI Bridges should have hdr_type 1, + * CardBus Bridges 2, all other devices 0. */ - if ((dev->class >> 8 == PCI_CLASS_BRIDGE_PCI) != (hdr_type & 0x7f)) { + switch (dev->class >> 8) { + case PCI_CLASS_BRIDGE_PCI: + ht = 1; + break; + case PCI_CLASS_BRIDGE_CARDBUS: + ht = 2; + break; + default: + ht = 0; + } + if (ht != (hdr_type & 0x7f)) { printk(KERN_WARNING "PCI: %02x:%02x [%04x/%04x/%06x] has unknown header type %02x, ignoring.\n", bus->number, dev->devfn, dev->vendor, dev->device, dev->class, hdr_type); continue; diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index 89b129f9d6cc..a8418e7b33dc 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -26,8 +26,8 @@ */ -#define BusLogic_DriverVersion "2.0.13" -#define BusLogic_DriverDate "17 April 1998" +#define BusLogic_DriverVersion "2.0.14" +#define BusLogic_DriverDate "29 April 1998" #include @@ -1217,10 +1217,13 @@ static boolean BusLogic_Failure(BusLogic_HostAdapter_T *HostAdapter, { BusLogic_AnnounceDriver(HostAdapter); if (HostAdapter->HostAdapterBusType == BusLogic_PCI_Bus) - BusLogic_Error("While configuring BusLogic PCI Host Adapter at\n" - "Bus %d Device %d I/O Address 0x%X PCI Address 0x%X:\n", - HostAdapter, HostAdapter->Bus, HostAdapter->Device, - HostAdapter->IO_Address, HostAdapter->PCI_Address); + { + BusLogic_Error("While configuring BusLogic PCI Host Adapter at\n", + HostAdapter); + BusLogic_Error("Bus %d Device %d I/O Address 0x%X PCI Address 0x%X:\n", + HostAdapter, HostAdapter->Bus, HostAdapter->Device, + HostAdapter->IO_Address, HostAdapter->PCI_Address); + } else BusLogic_Error("While configuring BusLogic Host Adapter at " "I/O Address 0x%X:\n", HostAdapter, HostAdapter->IO_Address); diff --git a/drivers/scsi/Config.in b/drivers/scsi/Config.in index c6bac228efee..d9f93971975d 100644 --- a/drivers/scsi/Config.in +++ b/drivers/scsi/Config.in @@ -77,6 +77,9 @@ if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_NCR53C7xx" != "y" ]; then fi fi dep_tristate 'IOMEGA Parallel Port ZIP drive SCSI support' CONFIG_SCSI_PPA $CONFIG_SCSI +if [ "$CONFIG_SCSI_PPA" != "n" ]; then + bool ' Buggy EPP chipset support' CONFIG_SCSI_PPA_HAVE_PEDANTIC +fi dep_tristate 'PAS16 SCSI support' CONFIG_SCSI_PAS16 $CONFIG_SCSI dep_tristate 'Qlogic FAS SCSI support' CONFIG_SCSI_QLOGIC_FAS $CONFIG_SCSI if [ "$CONFIG_PCI" = "y" ]; then diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index 46c5e42f2706..e6fc75c9952f 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -491,11 +491,11 @@ static __inline__ void run_main(void) { */ #ifndef USLEEP_SLEEP /* 20 ms (reasonable hard disk speed) */ -#define USLEEP_SLEEP 2 +#define USLEEP_SLEEP (20*HZ/1000) #endif /* 300 RPM (floppy speed) */ #ifndef USLEEP_POLL -#define USLEEP_POLL 20 +#define USLEEP_POLL (200*HZ/1000) #endif static struct Scsi_Host * expires_first = NULL; @@ -643,7 +643,7 @@ static int NCR5380_probe_irq (struct Scsi_Host *instance, int possible) { == 0)) trying_irqs |= mask; - timeout = jiffies + 25; + timeout = jiffies + 250*HZ/1000; probe_irq = IRQ_NONE; /* @@ -819,7 +819,7 @@ int NCR5380_proc_info ( SPRINTF("PAS16 release=%d", PAS16_PUBLIC_RELEASE); #endif - SPRINTF("\nBase Addr: 0x%05X ", (int)instance->base); + SPRINTF("\nBase Addr: 0x%05lX ", (long)instance->base); SPRINTF("io_port: %04x ", (int)instance->io_port); if (instance->irq == IRQ_NONE) SPRINTF("IRQ: None.\n"); @@ -1002,7 +1002,7 @@ static void NCR5380_init (struct Scsi_Host *instance, int flags) { case 5: printk("scsi%d: SCSI bus busy, waiting up to five seconds\n", instance->host_no); - timeout = jiffies + 500; + timeout = jiffies + 5*HZ; while (jiffies < timeout && (NCR5380_read(STATUS_REG) & SR_BSY)); break; case 2: @@ -1618,7 +1618,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, * selection. */ - timeout = jiffies + 25; + timeout = jiffies + 250*HZ/1000; /* * XXX very interesting - we're seeing a bounce where the BSY we diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h index 50708cfca8a2..08e2897a6f1a 100644 --- a/drivers/scsi/NCR5380.h +++ b/drivers/scsi/NCR5380.h @@ -314,29 +314,33 @@ static int NCR5380_transfer_dma (struct Scsi_Host *instance, static int NCR5380_transfer_pio (struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data); -#if (defined(REAL_DMA) || defined(REAL_DMA_POLL)) && defined(i386) -static __inline__ int NCR5380_i386_dma_setup (struct Scsi_Host *instance, +#if (defined(REAL_DMA) || defined(REAL_DMA_POLL)) + +#if defined(i386) || defined(__alpha__) + +static __inline__ int NCR5380_pc_dma_setup (struct Scsi_Host *instance, unsigned char *ptr, unsigned int count, unsigned char mode) { unsigned limit; + unsigned long bus_addr = virt_to_bus(ptr); if (instance->dma_channel <=3) { if (count > 65536) count = 65536; - limit = 65536 - (((unsigned) ptr) & 0xFFFF); + limit = 65536 - (bus_addr & 0xFFFF); } else { if (count > 65536 * 2) count = 65536 * 2; - limit = 65536* 2 - (((unsigned) ptr) & 0x1FFFF); + limit = 65536* 2 - (bus_addr & 0x1FFFF); } if (count > limit) count = limit; - if ((count & 1) || (((unsigned) ptr) & 1)) + if ((count & 1) || (bus_addr & 1)) panic ("scsi%d : attempted unaligned DMA transfer\n", instance->host_no); cli(); disable_dma(instance->dma_channel); clear_dma_ff(instance->dma_channel); - set_dma_addr(instance->dma_channel, (unsigned int) ptr); + set_dma_addr(instance->dma_channel, bus_addr); set_dma_count(instance->dma_channel, count); set_dma_mode(instance->dma_channel, mode); enable_dma(instance->dma_channel); @@ -344,17 +348,17 @@ static __inline__ int NCR5380_i386_dma_setup (struct Scsi_Host *instance, return count; } -static __inline__ int NCR5380_i386_dma_write_setup (struct Scsi_Host *instance, +static __inline__ int NCR5380_pc_dma_write_setup (struct Scsi_Host *instance, unsigned char *src, unsigned int count) { - return NCR5380_i386_dma_setup (instance, src, count, DMA_MODE_WRITE); + return NCR5380_pc_dma_setup (instance, src, count, DMA_MODE_WRITE); } -static __inline__ int NCR5380_i386_dma_read_setup (struct Scsi_Host *instance, +static __inline__ int NCR5380_pc_dma_read_setup (struct Scsi_Host *instance, unsigned char *src, unsigned int count) { - return NCR5380_i386_dma_setup (instance, src, count, DMA_MODE_READ); + return NCR5380_pc_dma_setup (instance, src, count, DMA_MODE_READ); } -static __inline__ int NCR5380_i386_dma_residual (struct Scsi_Host *instance) { +static __inline__ int NCR5380_pc_dma_residual (struct Scsi_Host *instance) { register int tmp; cli(); clear_dma_ff(instance->dma_channel); @@ -362,7 +366,8 @@ static __inline__ int NCR5380_i386_dma_residual (struct Scsi_Host *instance) { sti(); return tmp; } -#endif /* defined(REAL_DMA) && defined(i386) */ +#endif /* defined(i386) || defined(__alpha__) */ +#endif /* defined(REAL_DMA) */ #endif __KERNEL_ #endif /* ndef ASM */ #endif /* NCR5380_H */ diff --git a/drivers/scsi/README.BusLogic b/drivers/scsi/README.BusLogic index d7126695be8b..36a7d703be16 100644 --- a/drivers/scsi/README.BusLogic +++ b/drivers/scsi/README.BusLogic @@ -1,10 +1,10 @@ BusLogic MultiMaster and FlashPoint SCSI Driver for Linux - Version 2.0.13 for Linux 2.0 + Version 2.0.14 for Linux 2.0 PRODUCTION RELEASE - 17 April 1998 + 29 April 1998 Leonard N. Zubkoff Dandelion Digital @@ -591,7 +591,7 @@ To install the new BusLogic SCSI driver, you may use the following commands, replacing "/usr/src" with wherever you keep your Linux kernel source tree: cd /usr/src - tar -xvzf BusLogic-2.0.13.tar.gz + tar -xvzf BusLogic-2.0.14.tar.gz mv README.* LICENSE.* BusLogic.[ch] FlashPoint.c linux/drivers/scsi patch -p < BusLogic.patch cd linux diff --git a/drivers/scsi/README.ppa b/drivers/scsi/README.ppa index 509541d7a8fb..370d1b03d1a1 100644 --- a/drivers/scsi/README.ppa +++ b/drivers/scsi/README.ppa @@ -1,4 +1,5 @@ README.ppa (c) 1996 Grant R. Guenther, grant@torque.net +README.ppa (c) 1998 David J. Campbell, campbell@torque.net The IOMEGA PPA3 parallel port SCSI Host Bus Adapter @@ -37,83 +38,72 @@ I'd like to thank Byron Jeff (byron@cc.gatech.edu) for publishing his observation that the 'guest' driver loads under DOSemu. His remark was the stimulus that began this project. -The ppa driver can detect and adapt to 4- and 8-bit parallel ports, but -there is currently no support for EPP or ECP ports, as I have been unable -to make the DOS drivers work in these modes on my test rig. +For information about using the ZIP drive, please read the generic +instructions in the SCSI-HOWTO and the man pages for the normal disk +management tools, fdisk, mkfs, mount, umount, etc. There is a mini-HOWTO +circulating concerning the use of the normal SCSI version of the ZIP +drive, most of its comments will apply to disks connected through the +ppa driver as well. -The driver may be built in to the kernel, or loaded as a module. It -may be configured on the command line in both cases, although the syntax -is different. It may also be configured by editing the source file. +>------------------------------------------------------------------------< +David Campbell writes: -Built-in drivers accept parameters using this LILO/LOADLIN command line -syntax (omitted parameters retain their default values): +Since the original was released by Grant several people have made many minor +modifications: - ppa=base[,speed_high[,speed_low[,nybble]]] + a) Support for EPP + b) Autoprobing known parallel ports + c) Parallel port sharing with other devices (see notes) -For example: ppa=0x378,0,3 +It has been found that the JAZ Traveller also uses the VPI0 interface chipset +(a reworked ppa3). This driver will also support this device without +modifications. -If a driver is loaded as a module the parameters may be set on the -insmod command line, but each one must be specified by name: +Please note that the ZIP Plus drive uses a VPI2 interface chipset (VPI1 never +made it out of the Iomega development lab). A driver for this device exists, +check my web page at http://www.torque.net/~campbell for further details. -For example: insmod ppa.o ppa_base=0x378 ppa_nybble=1 + -<-->- -(Notice the ppa_ prefix on each of the parameters in the insmod form.) +Built-in drivers accept parameters using this LILO/LOADLIN command line +syntax (omitted parameters retain their default values): -Here are the parameters and their functions: + ppa=base,mode[,sg_buffer_size] -Variable Default Description +For example: ppa=0x378,1 -ppa_base 0x378 The base address of PPA's parallel port. -ppa_speed_high 1 Microsecond i/o delay used in data transfers -ppa_speed_low 6 Microsecond delay used in other operations -ppa_nybble 0 1 to force the driver to use 4-bit mode. +The modes are as follows: + 0 Autodetect mode + 1 work in standard 4 bit mode + 2 PS/2 byte mode + 3 EPP mode, 8 bit + 4 EPP mode, 16 bit + 5 EPP mode, 32 bit -A word about the timing parameters: the ppa_speed_low parameter controls -the widths of a large number of pulses that are sent over the parallel bus, -the narrower the pulses, the faster things go, but the greater the risk of -distortion by noise damping circuits in the parallel ports. The -ppa_speed_high parameter controls the same delays, but during the data -transfer phase only. In this phase, there is a lot of handshaking going -on and the pulse shaping should not be so much of an issue, but if you -see data corruption, you can increase this parameter as well. +If ppa is built as a module there is currently no method of changing the +operation of the driver. Basically there is no need (unless you have a very +strange parallel port address). -You might also want to reduce the timing values to attempt to increase -the transfer rates on your system. Please be careful to watch for -SCSI timeout errors in your log files. If you are getting timeouts, you -have set these parameters too low. The default values appear to be -safe on most machines. + -<-->- -If you have both the lp and ppa drivers in your kernel, you must ensure -that they access different parallel ports. By default, the lp driver is -initialised early in the booting process, and it claims all parallel -ports that it can find. You may control this behaviour with a LILO or -LOADLIN command line argument of the form: +Using the ZIP drive and a printer either requires two parallel ports (one +for each device) or use of the parport driver (which can be found in the +2.1.x kernels). +In the first case compile the lp driver as a module and load it after ppa. +Alternatively specify which ports the lp driver should use by the LILO/LOADLIN +options: lp=base0[,irq0[,base1[,irq1[,base2[,irq2]]]]] -For example: lp=0x278,7 + -<-->- -If you use this method, only the ports named will be adopted by the lp -driver. You can disable them all with lp=0 . +Mainboard buggy chipset hall of shame: [information courtesy of Iomega] -So, if you have a printer on 0x3bc and a ZIP drive on 0x278 you would -give the following options on your boot command: + National Semiconductor PC87306 rev ID 0x70, 0x71 + Winbond xx837 - lp=0x3bc ppa=0x278 - -In this case lp would use the polling driver, since an interrupt was not -specified. - -If you want to share the same parallel port between a ZIP drive and a -printer, you should build both the lp and ppa drivers as modules and -load and unload one or the other as required. This is clumsy but we -currently have no protocol for synchronising access to shared parallel -ports. - -For information about using the ZIP drive, please read the generic -instructions in the SCSI-HOWTO and the man pages for the normal disk -management tools, fdisk, mkfs, mount, umount, etc. There is a mini-HOWTO -circulating concerning the use of the normal SCSI version of the ZIP -drive, most of its comments will apply to disks connected through the -ppa driver as well. +The above chipsets are known to have problems using EPP. Note that the +National Semicondutor problems only affect early batches of PC87306 which +should really never made it to market (a run for mainboard developers). +>------------------------------------------------------------------------< diff --git a/drivers/scsi/aic7xxx.c b/drivers/scsi/aic7xxx.c index 17b17fe0c501..b2622bc8dc87 100644 --- a/drivers/scsi/aic7xxx.c +++ b/drivers/scsi/aic7xxx.c @@ -209,7 +209,7 @@ struct proc_dir_entry proc_scsi_aic7xxx = { 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; -#define AIC7XXX_C_VERSION "5.0.13" +#define AIC7XXX_C_VERSION "5.0.14" #define NUMBER(arr) (sizeof(arr) / sizeof(arr[0])) #define MIN(a,b) (((a) < (b)) ? (a) : (b)) @@ -242,7 +242,7 @@ struct proc_dir_entry proc_scsi_aic7xxx = { # include #endif -#if !defined(__alpha__) +#if !defined(__alpha__) && !defined(__sparc__) # define MMAPIO #endif @@ -936,6 +936,7 @@ struct aic7xxx_host { volatile unsigned char untagged_scbs[256]; volatile unsigned char qoutfifo[256]; volatile unsigned char qinfifo[256]; + unsigned int irq; /* IRQ for this adapter */ unsigned short needsdtr; unsigned short sdtr_pending; unsigned short needwdtr; @@ -953,7 +954,6 @@ struct aic7xxx_host { unsigned short adapter_control; /* adapter control - SEEPROM */ unsigned char pci_bus; unsigned char pci_device_fn; - unsigned char irq; /* IRQ for this adapter */ #ifdef AIC7XXX_PROC_STATS /* @@ -1799,10 +1799,16 @@ scbq_init(volatile scb_queue_type *queue) static inline void scbq_insert_head(volatile scb_queue_type *queue, struct aic7xxx_scb *scb) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags; +#endif + + DRIVER_LOCK scb->q_next = queue->head; queue->head = scb; if (queue->tail == NULL) /* If list was empty, update tail. */ queue->tail = queue->head; + DRIVER_UNLOCK } /*+F************************************************************************* @@ -1817,11 +1823,17 @@ static __inline struct aic7xxx_scb * scbq_remove_head(volatile scb_queue_type *queue) { struct aic7xxx_scb * scbp; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags; +#endif + + DRIVER_LOCK scbp = queue->head; if (queue->head != NULL) queue->head = queue->head->q_next; if (queue->head == NULL) /* If list is now empty, update tail. */ queue->tail = NULL; + DRIVER_UNLOCK return(scbp); } @@ -1836,6 +1848,11 @@ scbq_remove_head(volatile scb_queue_type *queue) static inline void scbq_remove(volatile scb_queue_type *queue, struct aic7xxx_scb *scb) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags; +#endif + + DRIVER_LOCK if (queue->head == scb) { /* At beginning of queue, remove from head. */ @@ -1864,6 +1881,7 @@ scbq_remove(volatile scb_queue_type *queue, struct aic7xxx_scb *scb) } } } + DRIVER_UNLOCK } /*+F************************************************************************* @@ -1877,12 +1895,18 @@ scbq_remove(volatile scb_queue_type *queue, struct aic7xxx_scb *scb) static inline void scbq_insert_tail(volatile scb_queue_type *queue, struct aic7xxx_scb *scb) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags; +#endif + + DRIVER_LOCK scb->q_next = NULL; if (queue->tail != NULL) /* Add the scb at the end of the list. */ queue->tail->q_next = scb; queue->tail = scb; /* Update the tail. */ if (queue->head == NULL) /* If list was empty, update head. */ queue->head = queue->tail; + DRIVER_UNLOCK } /*+F************************************************************************* @@ -2167,7 +2191,6 @@ aic7xxx_done_cmds_complete(struct aic7xxx_host *p) Scsi_Cmnd *cmd; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) unsigned int cpu_flags = 0; -#endif DRIVER_LOCK while (p->completeq.head != NULL) @@ -2175,11 +2198,20 @@ aic7xxx_done_cmds_complete(struct aic7xxx_host *p) cmd = p->completeq.head; p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble; cmd->host_scribble = NULL; - DRIVER_UNLOCK + sti(); cmd->scsi_done(cmd); - DRIVER_LOCK + cli(); } DRIVER_UNLOCK +#else + while (p->completeq.head != NULL) + { + cmd = p->completeq.head; + p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble; + cmd->host_scribble = NULL; + cmd->scsi_done(cmd); + } +#endif } /*+F************************************************************************* @@ -2321,16 +2353,6 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb) scbq_insert_tail(&p->waiting_scbs, scbp); } } - if ( (p->dev_timer[tindex].expires) && - ((p->dev_active_cmds[tindex] == 1) || - (p->dev_max_queue_depth[tindex] == - p->dev_temp_queue_depth[tindex])) ) - { - del_timer(&p->dev_timer[tindex]); - p->dev_timer[tindex].expires = 0; - p->dev_temp_queue_depth[tindex] = - p->dev_max_queue_depth[tindex]; - } p->dev_active_cmds[tindex]--; p->activescbs--; @@ -2528,13 +2550,18 @@ aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, int channel, */ if (requeue && (queue != NULL)) { - if ( !(scbp->flags & SCB_WAITINGQ) ) + if (scbp->flags & SCB_WAITINGQ) { - scbq_insert_tail(queue, scbp); - p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]--; - p->activescbs--; - scbp->flags |= SCB_WAITINGQ; + scbq_remove(queue, scbp); + scbq_remove(&p->waiting_scbs, scbp); + scbq_remove(&p->delayed_scbs[TARGET_INDEX(scbp->cmd)], scbp); + p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++; + p->activescbs++; } + scbq_insert_tail(queue, scbp); + p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]--; + p->activescbs--; + scbp->flags |= SCB_WAITINGQ; if ( !(scbp->tag_action & TAG_ENB) ) { aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun, @@ -2704,12 +2731,11 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel, * here so that we can delay all re-sent commands for this device for the * 4 seconds and then have our timer routine pick them back up. */ - if( (p->dev_timer[i].prev != NULL) || - (p->dev_timer[i].next != NULL) ) + if(p->dev_timer[i].expires) { del_timer(&p->dev_timer[i]); } - p->dev_timer[i].expires = jiffies + (3 * HZ); + p->dev_timer[i].expires = jiffies + (4 * HZ); add_timer(&p->dev_timer[i]); } for(j=0; jdelayed_scbs[i], prev_scbp); - if ( !(prev_scbp->flags & SCB_WAITINGQ) ) + if (prev_scbp->flags & SCB_WAITINGQ) { p->dev_active_cmds[i]++; p->activescbs++; @@ -2800,7 +2826,7 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel, if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag)) { scbq_remove(&p->waiting_scbs, prev_scbp); - if ( !(prev_scbp->flags & SCB_WAITINGQ) ) + if (prev_scbp->flags & SCB_WAITINGQ) { p->dev_active_cmds[TARGET_INDEX(prev_scbp->cmd)]++; p->activescbs++; @@ -2853,7 +2879,7 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel, if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag)) { next = aic7xxx_abort_waiting_scb(p, scbp, next, prev); - if ( !(scbp->flags & SCB_WAITINGQ) ) + if (scbp->flags & SCB_WAITINGQ) { p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++; p->activescbs++; @@ -2869,6 +2895,7 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel, * it isn't already off. */ aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ); + aic_outb(p, CLRSELTIMEO, CLRSINT1); } } else @@ -2890,6 +2917,9 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel, * Go through disconnected list and remove any entries we have queued * for completion, zeroing their control byte too. */ + if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) + printk(INFO_LEAD "Cleaning disconnected scbs " + "list.\n", p->host_no, channel, target, lun); { unsigned char next, prev, scb_index; @@ -2902,7 +2932,7 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel, scb_index = aic_inb(p, SCB_TAG); if (scb_index > p->scb_data->numscbs) { - printk(WARN_LEAD "Waiting List inconsistency; SCB index=%d, " + printk(WARN_LEAD "Disconnected List inconsistency; SCB index=%d, " "numscbs=%d\n", p->host_no, channel, target, lun, scb_index, p->scb_data->numscbs); next = aic7xxx_rem_scb_from_disc_list(p, next); @@ -2913,7 +2943,7 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel, if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag)) { next = aic7xxx_rem_scb_from_disc_list(p, next); - if ( !(scbp->flags & SCB_WAITINGQ) ) + if (scbp->flags & SCB_WAITINGQ) { p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++; p->activescbs++; @@ -3027,6 +3057,13 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel, aic7xxx_match_scb(p, scbp, target, channel, lun, tag) && !aic7xxx_scb_on_qoutfifo(p, scbp)) { + if (scbp->flags & SCB_WAITINGQ) + { + scbq_remove(&p->waiting_scbs, scbp); + scbq_remove(&p->delayed_scbs[TARGET_INDEX(scbp->cmd)], scbp); + p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++; + p->activescbs++; + } scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE; scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ); } @@ -3203,12 +3240,6 @@ aic7xxx_reset_channel(struct aic7xxx_host *p, int channel, int initiate_reset) restart_sequencer(p); } - /* - * Now loop through all the SCBs that have been marked for abortion, - * and call the scsi_done routines. - */ - if(!(p->flags & AHC_IN_ISR)) - aic7xxx_run_done_queue(p, /*complete*/ TRUE); return; } @@ -3245,18 +3276,21 @@ aic7xxx_run_waiting_queues(struct aic7xxx_host *p) tindex = TARGET_INDEX(scb->cmd); if ( (p->dev_active_cmds[tindex] >= p->dev_temp_queue_depth[tindex]) || - (p->dev_last_reset[tindex] >= (jiffies + (3 * HZ))) ) + (p->dev_last_reset[tindex] >= (jiffies - (4 * HZ))) ) { scbq_insert_tail(&p->delayed_scbs[tindex], scb); + if ( !(p->dev_timer[tindex].expires) && + !(p->dev_active_cmds[tindex]) ) + { + p->dev_timer[tindex].expires = p->dev_last_reset[tindex] + (4 * HZ); + add_timer(&p->dev_timer[tindex]); + } } else { scb->flags &= ~SCB_WAITINGQ; - if ( !(scb->flags & SCB_QUEUED_ABORT) ) - { - p->dev_active_cmds[tindex]++; - p->activescbs++; - } + p->dev_active_cmds[tindex]++; + p->activescbs++; if ( !(scb->tag_action) ) { aic7xxx_busy_target(p, scb); @@ -3293,7 +3327,7 @@ aic7xxx_run_waiting_queues(struct aic7xxx_host *p) static void aic7xxx_timer(struct aic7xxx_host *p) { - int i; + int i, j; unsigned long cpu_flags = 0; struct aic7xxx_scb *scb; @@ -3314,10 +3348,23 @@ aic7xxx_timer(struct aic7xxx_host *p) del_timer(&p->dev_timer[i]); } p->dev_temp_queue_depth[i] = p->dev_max_queue_depth[i]; - while ( (scb = scbq_remove_head(&p->delayed_scbs[i])) != NULL ) + j = 0; + while ( ((scb = scbq_remove_head(&p->delayed_scbs[i])) != NULL) && + (j++ < p->scb_data->numscbs) ) { scbq_insert_tail(&p->waiting_scbs, scb); } + if (j == p->scb_data->numscbs) + { + printk(INFO_LEAD "timer: Yikes, loop in delayed_scbs list.\n", + p->host_no, 0, i, -1); + scbq_init(&p->delayed_scbs[i]); + scbq_init(&p->waiting_scbs); + /* + * Well, things are screwed now, wait for a reset to clean the junk + * out. + */ + } } } aic7xxx_run_waiting_queues(p); @@ -3458,7 +3505,7 @@ aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, int channel) if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) printk(INFO_LEAD "Bus Device Reset delivered.\n", p->host_no, channel, target, -1); - aic7xxx_run_done_queue(p, /*complete*/ TRUE); + aic7xxx_run_done_queue(p, /*complete*/ FALSE); } /*+F************************************************************************* @@ -3520,6 +3567,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat) lun, aic_inb(p, LASTPHASE), aic_inb(p, SAVED_TCL)); aic7xxx_reset_channel(p, channel, /*initiate reset*/ TRUE); + aic7xxx_run_done_queue(p, FALSE); } break; @@ -3585,7 +3633,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat) if ( (last_msg == MSG_IDENTIFYFLAG) && (scb->tag_action != 0 ) && - !(p->flags & AHC_HANDLING_REQINITS) ) + !(scb->flags & SCB_MSGOUT_BITS) ) { if ((scb->tag_action == MSG_ORDERED_Q_TAG) && (p->dev_flags[scratch_offset] & DEVICE_TAGGED_SUCCESS)) @@ -3606,8 +3654,11 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat) * ATNO and hope this will take us into the identify phase again * so we can resend the tag type and info to the device. */ + aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT); + aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO); } - else + else if ( (scb->tag_action == MSG_SIMPLE_Q_TAG) && + !(p->dev_flags[scratch_offset] & DEVICE_TAGGED_SUCCESS) ) { unsigned char i, reset = 0; struct aic7xxx_scb *scbp; @@ -3637,7 +3688,6 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat) */ scb->tag_action = 0; scb->hscb->control &= ~(TAG_ENB | SCB_TAG_TYPE); - scb->hscb->control |= MK_MESSAGE; aic_outb(p, scb->hscb->control, SCB_CONTROL); old_verbose = aic7xxx_verbose; @@ -3652,6 +3702,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat) aic7xxx_reset_device(p, target, channel, lun, i); reset++; } + aic7xxx_run_done_queue(p, FALSE); } } aic7xxx_verbose = old_verbose; @@ -3663,12 +3714,11 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat) aic7xxx_busy_target(p, scb); printk(INFO_LEAD "Device is refusing tagged commands, using " "untagged I/O.\n", p->host_no, channel, target, lun); + aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT); + aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO); } - aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT); - aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO); } - else if ( (last_msg == MSG_IDENTIFYFLAG) && - (scb->flags & SCB_MSGOUT_WDTR) ) + else if (scb->flags & SCB_MSGOUT_WDTR) { /* * note 8bit xfers and clear flag @@ -3686,13 +3736,14 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat) } scb->flags &= ~SCB_MSGOUT_WDTR_16BIT; p->syncinfo[scratch_offset].offset = MAX_OFFSET_8BIT; - if (p->needsdtr & target_mask) - { - p->sdtr_pending |= target_mask; - scb->flags |= SCB_MSGOUT_SDTR; - aic_outb(p, HOST_MSG, MSG_OUT); - aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO); - } + /* + * The sequencer should have already cleared the MK_MESSAGE bit in + * the SCB, so we simply restart the message out phase and resend + * the IDENTIFY and TAG values so that there is no confusion over + * what has been rejected. + */ + aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT); + aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO); } else if (scb->flags & SCB_MSGOUT_SDTR) { @@ -3712,6 +3763,14 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat) "asynchronous transfers.\n", p->host_no, CTL_OF_SCB(scb)); p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_SDTR; } + /* + * The sequencer should have already cleared the MK_MESSAGE bit in + * the SCB, so we simply restart the message out phase and resend + * the IDENTIFY and TAG values so that there is no confusion over + * what has been rejected. + */ + aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT); + aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO); } else if (aic7xxx_verbose & VERBOSE_SEQINT) { @@ -3831,25 +3890,24 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat) * so if needed, we'll re-negotiate while doing the sense cmd. * However, if this SCB already was attempting to negotiate, * then we assume this isn't the problem and skip this part. + * + * 1998/04/23 - We also don't want to set the flag if the + * original command was a TEST_UNIT_READY since that + * implies a SEND_SENSE anyway. Plus, we don't actually + * start the negotiation here, we just flag it because + * some devices appear to choke up their message buffer + * when we mix things together like this. */ - if ( !(scb->flags & SCB_MSGOUT_BITS) ) + if ( !(scb->flags & SCB_MSGOUT_BITS) && + (scb->cmd->cmnd[0] != TEST_UNIT_READY) ) { if ( p->needwdtr_copy & target_mask ) { p->needwdtr |= target_mask; - p->wdtr_pending |= target_mask; - hscb->control |= MK_MESSAGE; - scb->flags |= SCB_MSGOUT_WDTR_16BIT; } if ( p->needsdtr_copy & target_mask ) { p->needsdtr |= target_mask; - if ((hscb->control & MK_MESSAGE) == 0) - { - p->sdtr_pending |= target_mask; - hscb->control |= MK_MESSAGE; - scb->flags |= SCB_MSGOUT_SDTR; - } } } @@ -3904,41 +3962,60 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat) { aic_outb(p, next_hscb, SCBPTR); scb_index = aic_inb(p, SCB_TAG); - next_scbp = p->scb_data->scb_array[scb_index]; - if (aic7xxx_match_scb(p, next_scbp, target, channel, lun, - SCB_LIST_NULL) ) + if (scb_index < p->scb_data->numscbs) { - scbq_insert_head(&p->delayed_scbs[scratch_offset], - next_scbp); - next_scbp->flags |= SCB_WAITINGQ; - p->dev_active_cmds[scratch_offset]--; - p->activescbs--; - next_hscb = aic_inb(p, SCB_NEXT); - aic_outb(p, 0, SCB_CONTROL); - aic_outb(p, SCB_LIST_NULL, SCB_TAG); - aic7xxx_add_curscb_to_free_list(p); - if (prev_hscb == SCB_LIST_NULL) + next_scbp = p->scb_data->scb_array[scb_index]; + if (aic7xxx_match_scb(p, next_scbp, target, channel, lun, + SCB_LIST_NULL) ) { - aic_outb(p, 0, SCSISEQ); /* We were first on the list, - * so we kill the selection - * hardware. Let the sequencer - * re-init the hardware itself - */ - aic_outb(p, next_hscb, WAITING_SCBH); + if (next_scbp->flags & SCB_WAITINGQ) + { + p->dev_active_cmds[scratch_offset]++; + p->activescbs--; + scbq_remove(&p->delayed_scbs[scratch_offset], next_scbp); + scbq_remove(&p->waiting_scbs, next_scbp); + } + scbq_insert_head(&p->delayed_scbs[scratch_offset], + next_scbp); + next_scbp->flags |= SCB_WAITINGQ; + p->dev_active_cmds[scratch_offset]--; + p->activescbs--; + next_hscb = aic_inb(p, SCB_NEXT); + aic_outb(p, 0, SCB_CONTROL); + aic_outb(p, SCB_LIST_NULL, SCB_TAG); + aic7xxx_add_curscb_to_free_list(p); + if (prev_hscb == SCB_LIST_NULL) + { + /* We were first on the list, + * so we kill the selection + * hardware. Let the sequencer + * re-init the hardware itself + */ + aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ); + aic_outb(p, CLRSELTIMEO, CLRSINT1); + aic_outb(p, next_hscb, WAITING_SCBH); + } + else + { + aic_outb(p, prev_hscb, SCBPTR); + aic_outb(p, next_hscb, SCB_NEXT); + } } else { - aic_outb(p, prev_hscb, SCBPTR); - aic_outb(p, next_hscb, SCB_NEXT); + prev_hscb = next_hscb; + next_hscb = aic_inb(p, SCB_NEXT); } - } - else - { - prev_hscb = next_hscb; - next_hscb = aic_inb(p, SCB_NEXT); - } + } /* scb_index >= p->scb_data->numscbs */ } aic_outb(p, active_hscb, SCBPTR); + if (scb->flags & SCB_WAITINGQ) + { + scbq_remove(&p->delayed_scbs[scratch_offset], scb); + scbq_remove(&p->waiting_scbs, scb); + p->dev_active_cmds[scratch_offset]++; + p->activescbs++; + } scbq_insert_head(&p->delayed_scbs[scratch_offset], scb); p->dev_active_cmds[scratch_offset]--; p->activescbs--; @@ -4014,9 +4091,10 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat) case AWAITING_MSG: { - unsigned char scb_index; + unsigned char scb_index, msg_out; scb_index = aic_inb(p, SCB_TAG); + msg_out = aic_inb(p, MSG_OUT); scb = p->scb_data->scb_array[scb_index]; p->msg_index = p->msg_len = 0; /* @@ -4037,7 +4115,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat) { if (scb->hscb->control & TAG_ENB) { - if (aic_inb(p, MSG_OUT) == MSG_IDENTIFYFLAG) + if (msg_out == MSG_IDENTIFYFLAG) { p->msg_buf[p->msg_index++] = scb->tag_action; p->msg_buf[p->msg_index++] = scb->hscb->tag; @@ -4056,6 +4134,13 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat) } else if (scb->flags & SCB_MSGOUT_WDTR) { + if ( (scb->hscb->control & TAG_ENB) && + (msg_out == MSG_IDENTIFYFLAG) ) + { + p->msg_buf[p->msg_index++] = scb->tag_action; + p->msg_buf[p->msg_index++] = scb->hscb->tag; + p->msg_len += 2; + } aic7xxx_construct_wdtr(p, (scb->flags & SCB_WDTR_16BIT)); } else if (scb->flags & SCB_MSGOUT_SDTR) @@ -4072,10 +4157,18 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat) period = 0; offset = 0; } + if ( (scb->hscb->control & TAG_ENB) && + (msg_out == MSG_IDENTIFYFLAG) ) + { + p->msg_buf[p->msg_index++] = scb->tag_action; + p->msg_buf[p->msg_index++] = scb->hscb->tag; + p->msg_len += 2; + } aic7xxx_construct_sdtr(p, period, offset); } else { + sti(); panic("aic7xxx: AWAITING_MSG for an SCB that does " "not have a waiting message.\n"); } @@ -4398,21 +4491,6 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb) p->syncinfo[scratch_offset].offset = (bus_width == MSG_EXT_WDTR_BUS_8_BIT) ? MAX_OFFSET_8BIT : MAX_OFFSET_16BIT; - if ( !(p->wdtr_pending & target_mask) && !reject) - { - /* - * We've successfully completed the wide negotiation, so let's start - * up the sync negotiation now. - */ - scb->flags &= ~SCB_MSGOUT_WDTR_16BIT; - if ((p->needsdtr & target_mask) && !(p->sdtr_pending & target_mask)) - { - p->sdtr_pending |= target_mask; - scb->flags |= SCB_MSGOUT_SDTR; - aic_outb(p, HOST_MSG, MSG_OUT); - aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO); - } - } done = TRUE; break; } @@ -4594,6 +4672,7 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat) * reset the channel again. */ aic7xxx_reset_channel(p, channel, /* Initiate Reset */ FALSE); + aic7xxx_run_done_queue(p, FALSE); scb = NULL; } else if ( ((status & BUSFREE) != 0) && ((status & SELTO) == 0) ) @@ -4749,9 +4828,9 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat) } } /* - * Stop the selection. + * Restarting the sequencer will stop the selection and make sure devices + * are allowed to reselect in. */ - aic_outb(p, 0, SCSISEQ); aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1); p->flags &= ~AHC_HANDLING_REQINITS; aic_outb(p, CLRSELTIMEO | CLRBUSFREE | CLRREQINIT, CLRSINT1); @@ -5096,6 +5175,7 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs) aic7xxx_reset_channel(p, 1, TRUE); restart_sequencer(p); } + aic7xxx_run_done_queue(p, FALSE); aic_outb(p, CLRBRKADRINT, CLRINT); } @@ -5108,11 +5188,8 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs) { aic7xxx_handle_scsiint(p, intstat); } - if(!(p->flags & (AHC_IN_ABORT | AHC_IN_RESET))) - { - aic7xxx_done_cmds_complete(p); - aic7xxx_run_waiting_queues(p); - } + aic7xxx_done_cmds_complete(p); + aic7xxx_run_waiting_queues(p); p->flags &= ~AHC_IN_ISR; } @@ -5306,7 +5383,13 @@ aic7xxx_select_queue_depth(struct Scsi_Host *host, * * The fourth byte's lowest bit seems to be an enabled/disabled * flag (rest of the bits are reserved?). + * + * NOTE: This function is only needed on Intel and Alpha platforms, + * the other platforms we support don't have EISA/VLB busses. So, + * we #ifdef this entire function to avoid compiler warnings about + * an unused function. *-F*************************************************************************/ +#if defined(__i386__) || defined(__alpha__) static ahc_type aic7xxx_probe(int slot, int base, ahc_flag_type *flags) { @@ -5362,6 +5445,8 @@ aic7xxx_probe(int slot, int base, ahc_flag_type *flags) return (AHC_NONE); } +#endif /* (__i386__) || (__alpha__) */ + /*+F************************************************************************* * Function: @@ -7306,7 +7391,7 @@ aic7xxx_detect(Scsi_Host_Template *template) unsigned short command; unsigned int devconfig, i; #ifdef MMAPIO - unsigned long page_offset; + unsigned long page_offset, base; #endif struct aic7xxx_host *first_7895 = NULL; #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) @@ -7314,7 +7399,7 @@ aic7xxx_detect(Scsi_Host_Template *template) #else int index; unsigned int piobase, mmapbase; - unsigned char pci_bus, pci_devfn; + unsigned char pci_bus, pci_devfn, pci_irq; #endif for (i = 0; i < NUMBER(aic7xxx_pci_devices); i++) @@ -7365,7 +7450,8 @@ aic7xxx_detect(Scsi_Host_Template *template) temp_p->pci_bus = pci_bus; temp_p->pci_device_fn = pci_devfn; pcibios_read_config_byte(pci_bus, pci_devfn, PCI_INTERRUPT_LINE, - &temp_p->irq); + &pci_irq); + temp_p->irq = pci_irq; pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_0, &piobase); temp_p->base = piobase; @@ -7521,7 +7607,7 @@ aic7xxx_detect(Scsi_Host_Template *template) temp_p->flags |= AHC_USEDEFAULTS; if (sxfrctl1 & STPWEN) temp_p->flags |= AHC_TERM_ENB_A | AHC_TERM_ENB_B; - temp_p->scsi_id = temp_p->scsi_id_b = 7; + temp_p->scsi_id_b = temp_p->scsi_id; } /* @@ -7943,7 +8029,7 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd, } if ( (p->needwdtr & mask) && !(p->wdtr_pending & mask) && - !(scb->tag_action)) + (scb->cmd->lun == 0) ) { p->wdtr_pending |= mask; hscb->control |= MK_MESSAGE; @@ -7957,7 +8043,7 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd, if ( (p->needsdtr & mask) && !(p->sdtr_pending & mask) && !(p->wdtr_pending & mask) && - !(scb->tag_action) ) + (scb->cmd->lun == 0) ) { p->sdtr_pending |= mask; hscb->control |= MK_MESSAGE; @@ -8224,9 +8310,6 @@ aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd) { if ( (lastphase != P_MESGOUT) && (lastphase != P_MESGIN) ) { - /* Send the abort message to the active SCB. */ - aic_outb(p, HOST_MSG, MSG_OUT); - aic_outb(p, lastphase | ATNO, SCSISIGO); if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) printk(INFO_LEAD "Device reset message in " "message buffer\n", p->host_no, CTL_OF_SCB(scb)); @@ -8236,6 +8319,9 @@ aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd) ~DEVICE_SUCCESS; p->dev_flags[TARGET_INDEX(scb->cmd)] |= BUS_DEVICE_RESET_PENDING; + /* Send the abort message to the active SCB. */ + aic_outb(p, HOST_MSG, MSG_OUT); + aic_outb(p, lastphase | ATNO, SCSISIGO); return(SCSI_RESET_PENDING); } else @@ -8594,9 +8680,12 @@ aic7xxx_abort(Scsi_Cmnd *cmd) if ( prev_hscbptr == SCB_LIST_NULL ) { aic_outb(p, aic_inb(p, SCB_NEXT), WAITING_SCBH); - aic_outb(p, 0, SCSISEQ); /* stop the selection since we just - * grabbed the scb out from under the - * card */ + /* stop the selection since we just + * grabbed the scb out from under the + * card + */ + aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ); + aic_outb(p, CLRSELTIMEO, CLRSINT1); } else { @@ -8932,6 +9021,7 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags) p->msg_index = 0; p->msg_len = 0; } + aic7xxx_run_done_queue(p, TRUE); p->flags &= ~AHC_IN_RESET; /* We can't rely on run_waiting_queues to unpause the sequencer for * PCI based controllers since we use AAP */ diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c index 8e2ef88cd416..d951420643d7 100644 --- a/drivers/scsi/dtc.c +++ b/drivers/scsi/dtc.c @@ -94,23 +94,23 @@ struct proc_dir_entry proc_scsi_dtc = { static struct override { - unsigned char *address; + __u32 address; int irq; } overrides #ifdef OVERRIDE [] = OVERRIDE; #else -[4] = {{NULL, IRQ_AUTO}, {NULL, IRQ_AUTO}, {NULL, IRQ_AUTO}, - {NULL, IRQ_AUTO}}; +[4] = {{0, IRQ_AUTO}, {0, IRQ_AUTO}, {0, IRQ_AUTO}, + {0, IRQ_AUTO}}; #endif #define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override)) static struct base { - unsigned char *address; + __u32 address; int noauto; -} bases[] = {{(unsigned char *) 0xcc000, 0}, {(unsigned char *) 0xc8000, 0}, -{(unsigned char *) 0xdc000, 0}, {(unsigned char *) 0xd8000, 0}}; +} bases[] = {{0xcc000, 0}, {0xc8000, 0}, +{0xdc000, 0}, {0xd8000, 0}}; #define NO_BASES (sizeof (bases) / sizeof (struct base)) @@ -138,10 +138,10 @@ void dtc_setup(char *str, int *ints) { printk("dtc_setup: usage dtc=address,irq\n"); else if (commandline_current < NO_OVERRIDES) { - overrides[commandline_current].address = (unsigned char *) ints[1]; + overrides[commandline_current].address = ints[1]; overrides[commandline_current].irq = ints[2]; for (i = 0; i < NO_BASES; ++i) - if (bases[i].address == (unsigned char *) ints[1]) { + if (bases[i].address == ints[1]) { bases[i].noauto = 1; break; } diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index eafc5d3c41c3..ec0ed5554b51 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -67,7 +67,7 @@ */ /* -** 2 January 1998, version 2.5f +** 30 January 1998, version 2.5f.1 ** ** Supported SCSI-II features: ** Synchronous negotiation @@ -1959,7 +1959,7 @@ static void ncr_free_ccb (ncb_p np, ccb_p cp, u_long t, u_long l); static void ncr_getclock (ncb_p np, int mult); static void ncr_selectclock (ncb_p np, u_char scntl3); static ccb_p ncr_get_ccb (ncb_p np, u_long t,u_long l); -static void ncr_init (ncb_p np, char * msg, u_long code); +static void ncr_init (ncb_p np, int reset, char * msg, u_long code); static int ncr_int_sbmc (ncb_p np); static int ncr_int_par (ncb_p np); static void ncr_int_ma (ncb_p np); @@ -5243,6 +5243,12 @@ static int ncr_reset_scsi_bus(ncb_p np, int enab_int, int settle_delay) OUTB (nc_istat, 0); if (enab_int) OUTW (nc_sien, RST); + /* + ** Enable Tolerant, reset IRQD if present and + ** properly set IRQ mode, prior to resetting the bus. + */ + OUTB (nc_stest3, TE); + OUTB (nc_dcntl, (np->rv_dcntl & IRQM)); OUTB (nc_scntl1, CRST); DELAY (100); @@ -5958,16 +5964,21 @@ void ncr_wakeup (ncb_p np, u_long code) **========================================================== */ -void ncr_init (ncb_p np, char * msg, u_long code) +void ncr_init (ncb_p np, int reset, char * msg, u_long code) { int i; /* - ** Reset chip. + ** Reset chip if asked, otherwise just clear fifos. */ - - OUTB (nc_istat, SRST); - DELAY (10000); + if (reset) { + OUTB (nc_istat, SRST); + DELAY (10000); + } + else { + OUTB (nc_stest3, TE|CSF); + OUTONB (nc_ctest3, CLF); + } /* ** Message. @@ -7035,7 +7046,7 @@ void ncr_exception (ncb_p np) */ if (sist & RST) { - ncr_init (np, bootverbose ? "scsi reset" : NULL, HS_RESET); + ncr_init (np, 1, bootverbose ? "scsi reset" : NULL, HS_RESET); return; }; @@ -7156,7 +7167,7 @@ void ncr_int_sto (ncb_p np) OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start)); return; }; - ncr_init (np, "selection timeout", HS_FAIL); + ncr_init (np, 1, "selection timeout", HS_FAIL); np->disc = 1; } @@ -7181,11 +7192,17 @@ static int ncr_int_sbmc (ncb_p np) { u_char scsi_mode = INB (nc_stest4) & SMODE; - printf("%s: SCSI bus mode change from %x to %x, resetting ...\n", + printf("%s: SCSI bus mode change from %x to %x.\n", ncr_name(np), np->scsi_mode, scsi_mode); np->scsi_mode = scsi_mode; - ncr_start_reset(np, driver_setup.settle_delay); + + /* + ** Suspend command processing for 1 second and + ** reinitialize all except the chip. + */ + np->settle_time = jiffies + HZ; + ncr_init (np, 0, bootverbose ? "scsi mode change" : NULL, HS_RESET); return 1; } @@ -8785,7 +8802,7 @@ static void ncr_selectclock(ncb_p np, u_char scntl3) OUTB(nc_stest3, HSC); /* Halt the scsi clock */ OUTB(nc_scntl3, scntl3); OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier */ - OUTB(nc_stest3, 0x00); /* Restart scsi clock */ + OUTB(nc_stest3, 0x00|TE); /* Restart scsi clock */ } diff --git a/drivers/scsi/ncr53c8xx.h b/drivers/scsi/ncr53c8xx.h index 9b54fc3b231a..cc009ca64360 100644 --- a/drivers/scsi/ncr53c8xx.h +++ b/drivers/scsi/ncr53c8xx.h @@ -45,7 +45,7 @@ /* ** Name and revision of the driver */ -#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - revision 2.5f" +#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - revision 2.5f.1" /* ** Check supported Linux versions diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c index 25297a5cddc1..4e47775fe36b 100644 --- a/drivers/scsi/ppa.c +++ b/drivers/scsi/ppa.c @@ -1,504 +1,1550 @@ -/* ppa.c -- low level driver for the IOMEGA PPA3 - parallel port SCSI host adapter. - - (The PPA3 is the embedded controller in the ZIP drive.) - - (c) 1995,1996 Grant R. Guenther, grant@torque.net, - under the terms of the GNU Public License. - -*/ - -/* This driver was developed without the benefit of any technical - specifications for the interface. Instead, a modified version of - DOSemu was used to monitor the protocol used by the DOS driver - for this adapter. I have no idea how my programming model relates - to IOMEGA's design. - - IOMEGA's driver does not generate linked commands. I've never - observed a SCSI message byte in the protocol transactions, so - I am assuming that as long as linked commands are not used - we won't see any. - - So far, this driver has been tested with the embedded PPA3 in the - ZIP drive, only. It can detect and adapt to 4- and 8-bit parallel - ports, but there is currently no support for EPP or ECP ports, as - I have been unable to make the DOS drivers work in these modes on - my test rig. - - For more information, see the file drivers/scsi/README.ppa. - -*/ - -#define PPA_VERSION "0.26" - -/* Change these variables here or with insmod or with a LILO or LOADLIN - command line argument -*/ - -static int ppa_base = 0x378; /* parallel port address */ -static int ppa_speed_high = 1; /* port delay in data phase */ -static int ppa_speed_low = 6; /* port delay otherwise */ -static int ppa_nybble = 0; /* don't force nybble mode */ - - -#define PPA_CAN_QUEUE 1 /* use "queueing" interface */ -#define PPA_SELECT_TMO 5000 /* how long to wait for target ? */ -#define PPA_SPIN_TMO 5000000 /* ppa_wait loop limiter */ -#define PPA_SECTOR_SIZE 512 /* for a performance hack only */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sd.h" -#include "hosts.h" -#include "ppa.h" +/* ppa.c -- low level driver for the IOMEGA PPA3 + * parallel port SCSI host adapter. + * + * (The PPA3 is the embedded controller in the ZIP drive.) + * + * (c) 1995,1996 Grant R. Guenther, grant@torque.net, + * under the terms of the GNU Public License. + * + * Current Maintainer: David Campbell (Perth, Western Australia) + * campbell@gear.torque.net + * dcampbel@p01.as17.honeywell.com.au + * + * My unoffical company acronym list is 21 pages long: + * FLA: Four letter acronym with built in facility for + * future expansion to five letters. + */ + +#include + +/* The following #define is to avoid a clash with hosts.c */ +#define PPA_CODE 1 +#ifndef HAVE_PC87332 +#define HAVE_PC87332 0 +#endif +#define PPA_PROBE_SPP 0x0001 +#define PPA_PROBE_PS2 0x0002 +#define PPA_PROBE_ECR 0x0010 +#define PPA_PROBE_EPP17 0x0100 +#define PPA_PROBE_EPP19 0x0200 +int port_probe(unsigned short); + +#include +#include "sd.h" +#include "hosts.h" +typedef struct { + int base; /* Actual port address */ + int mode; /* Transfer mode */ + int host; /* Host number (for proc) */ + Scsi_Cmnd *cur_cmd; /* Current queued command */ + struct tq_struct ppa_tq; /* Polling interupt stuff */ + unsigned long jstart; /* Jiffies at start */ + unsigned failed:1; /* Failure flag */ +} ppa_struct; + +#define PPA_EMPTY \ +{-1, /* base */ \ +PPA_AUTODETECT, /* mode */ \ +-1, /* host */ \ +NULL, /* cur_cmd */ \ +{0, 0, ppa_interrupt, NULL}, \ +0, /* jstart */ \ +0 /* failed */ \ +} -struct proc_dir_entry proc_scsi_ppa = - { PROC_SCSI_PPA, 3, "ppa", S_IFDIR|S_IRUGO|S_IXUGO, 2 }; +#include "ppa.h" +#undef CONFIG_PARPORT +#define NO_HOSTS 4 +static ppa_struct ppa_hosts[NO_HOSTS] = +{PPA_EMPTY, PPA_EMPTY, PPA_EMPTY, PPA_EMPTY}; -static int ppa_abort_flag = 0; -static int ppa_error_code = DID_OK; -static char ppa_info_string[132]; -static Scsi_Cmnd *ppa_current = 0; -static void (*ppa_done) (Scsi_Cmnd *); -static int ppa_port_delay; +#define PPA_BASE(x) ppa_hosts[(x)].base -void out_p( short port, char byte) +int base[NO_HOSTS] = +{0x03bc, 0x0378, 0x0278, 0x0000}; +#define parbus_base base +#define parbus_no NO_HOSTS -{ outb(byte,ppa_base+port); - udelay(ppa_port_delay); +static inline int ppa_pb_claim(int host_no) +{ + if (ppa_hosts[host_no].cur_cmd) + ppa_hosts[host_no].cur_cmd->SCp.phase++; + return 0; } -char in_p( short port) - -{ return inb(ppa_base+port); - udelay(ppa_port_delay); +/*************************************************************************** + * Parallel port probing routines * + ***************************************************************************/ + +#ifndef MODULE +/* + * Command line parameters (for built-in driver): + * + * Syntax: ppa=base[,mode[,use_sg]] + * + * For example: ppa=0x378 or ppa=0x378,0,3 + * + */ + +void ppa_setup(char *str, int *ints) +{ + static int x = 0; + + if (x == 0) { /* Disable ALL known ports */ + int i; + + for (i = 0; i < NO_HOSTS; i++) + parbus_base[i] = 0x0000; + } + switch (ints[0]) { + case 3: + ppa_sg = ints[3]; + case 2: + ppa_hosts[x].mode = ints[2]; + parbus_base[x] = ints[1]; + break; + default: + printk("PPA: I only use between 2 to 3 parameters.\n"); + break; + } + x++; + } +#else +Scsi_Host_Template driver_template = PPA; +#include "scsi_module.c" +#endif + +/* + * Start of Chipset kludges + */ + +#if HAVE_PC87332 > 0 +#warning PC87332 Kludge code included +static inline int pc87332_port(int host_no) +{ + /* A routine to detect and kludge pc87332 chipsets into the + * "optimum" mode for parallel port data transfer. + * This assumes EPP is better than ECP... + * (Which it is for disk drives but not printers and scanners) + */ + int base = ppa_hosts[host_no].base; + + /* This is where an pc87332 can hide */ + unsigned short index_addr[4] = + { + 0x0398, 0x026e, 0x015c, 0x002e + }; + + /* Bits 0&1 of FAR (Function Address Register) which specify where + * the LPT port will show up at. + */ + unsigned short port_ref[4] = + { + 0x378, 0x3bc, 0x278, 0xffff + }; + + unsigned char a; + int loop; + + for (loop = 0; loop < 4; loop++) { + /* Clear the "wax" out of the pc87332, only needed after hard + * reset. + */ + inb(index_addr[loop]); + inb(index_addr[loop]); + inb(index_addr[loop]); + inb(index_addr[loop]); + + /* Anyone home ?? */ + outb(0xff, index_addr[loop]); + a = inb(index_addr[loop]); + switch (a) { + case (0x0f): /* PC87732 */ + break; + case (0x1f): /* PC87306 */ + break; + case (0x7f): /* PC87??? */ + break; + default: + continue; + } /* Is this pc87332 on the desired port */ + outb(0x01, index_addr[loop]); + a = inb(index_addr[loop] + 1); + if (port_ref[a & 0x03] != base) + continue; + + /* Found a pc87332 */ + printk("NatSemi PC87332 (or variant) at 0x%04x\n", base); + + /* Try to enable EPP modes + * with hardware data direction + */ + if (base != 0x3bc) { + /* EPP 1.9 */ + outb(0x04, index_addr[loop]); + a = inb(index_addr[loop] + 1); + printk("Old reg1 = %02x\n", a); + /* 0x01 for EPP 1.7, 0x03 for EPP 1.9, 0x0c for ECP */ + a = (a & 0xf0) | 0x03; + outb(a, index_addr[loop] + 1); + outb(a, index_addr[loop] + 1); + + /* Software data direction selection */ + outb(0x02, index_addr[loop]); + a = inb(index_addr[loop] + 1); + printk("Old reg2 = %02x\n", a); + /* 0x80 for software, 0x00 for hardware */ + a = (a & 0x7f) | 0x80; + outb(a, index_addr[loop] + 1); + outb(a, index_addr[loop] + 1); + ppa_hosts[host_no].mode = PPA_EPP_32; + } else { + /* There is not enough address space for the 0x3bc port + * to have EPP registers so we will kludge it into an + * ECP + * port to allow bi-directional byte mode... + */ + /* ECP */ + outb(0x04, index_addr[loop]); + a = inb(index_addr[loop] + 1); + a = (a & 0xfb) | 0x06; + outb(a, index_addr[loop] + 1); + outb(a, index_addr[loop] + 1); + ppa_hosts[host_no].mode = PPA_PS2; + } + + outb(0x04, index_addr[loop]); + a = inb(index_addr[loop] + 1); + return ppa_hosts[host_no].mode; + } + return 0; + } +#else +#define pc87332_port(x) +#endif /* HAVE_PC87332 */ + +static inline int generic_port(int host_no) +{ + /* Generic parallel port detection + * This will try to discover if the port is + * EPP, ECP, PS/2 or NIBBLE (In that order, approx....) + */ + unsigned int save_ctr, save_ecr, r; + int ppb = PPA_BASE(host_no); + + save_ctr = r_ctr(ppb); + save_ecr = r_ecr(ppb); + r = port_probe(ppb); + w_ecr(ppb, save_ecr); + w_ctr(ppb, save_ctr); + + if (r & PPA_PROBE_SPP) + ppa_hosts[host_no].mode = PPA_NIBBLE; + + if (r & PPA_PROBE_PS2) { + ppa_hosts[host_no].mode = PPA_PS2; + if (r & PPA_PROBE_ECR) + w_ecr(ppb, 0x20); + } + if ((r & PPA_PROBE_EPP17) || (r & PPA_PROBE_EPP19)) { + /* ppa_hosts[host_no].mode = PPA_EPP_32; */ + if (r & PPA_PROBE_ECR) + w_ecr(ppb, 0x80); + } + return ppa_hosts[host_no].mode; } -void ppa_d_pulse( char b ) - -{ out_p(0,b); - out_p(2,0xc); out_p(2,0xe); out_p(2,0xc); out_p(2,0x4); out_p(2,0xc); +int ppa_detect(Scsi_Host_Template * host) +{ + struct Scsi_Host *hreg; + int ports; + int i, nhosts; + unsigned short ppb; + + printk("ppa: Version %s\n", PPA_VERSION); + nhosts = 0; + + for (i = 0; i < parbus_no; i++) { + if (parbus_base[i] == 0x0000) + continue; + ppb = ppa_hosts[i].base = parbus_base[i]; + + /* sanity checks */ + if (check_region(parbus_base[i], + (parbus_base[i] == 0x03bc) ? 3 : 8)) + continue; + + pc87332_port(i); + if (!generic_port(i)) + continue; + + if (ppa_init(i)) + continue; + + /* now the glue ... */ + switch (ppa_hosts[i].mode) { + case PPA_NIBBLE: + case PPA_PS2: + ports = 3; + break; + case PPA_EPP_8: + case PPA_EPP_16: + case PPA_EPP_32: + ports = 8; + break; + default: /* Never gets here */ + continue; + } + request_region(ppa_hosts[i].base, ports, "ppa"); + host->can_queue = PPA_CAN_QUEUE; + host->sg_tablesize = ppa_sg; + hreg = scsi_register(host, 0); + hreg->io_port = ppa_hosts[i].base; + hreg->n_io_port = ports; + hreg->dma_channel = -1; + hreg->unique_id = i; + ppa_hosts[i].host = hreg->host_no; + nhosts++; + } + if (nhosts == 0) + return 0; + else + return 1; /* return number of hosts detected */ } -void ppa_disconnect( void ) - -{ ppa_d_pulse(0); - ppa_d_pulse(0x3c); - ppa_d_pulse(0x20); - ppa_d_pulse(0xf); +/* This is to give the ppa driver a way to modify the timings (and other + * parameters) by writing to the /proc/scsi/ppa/0 file. + * Very simple method really... (To simple, no error checking :( ) + * Reason: Kernel hackers HATE having to unload and reload modules for + * testing... + * Also gives a method to use a script to obtain optimum timings (TODO) + */ + +static inline int ppa_strncmp(const char *a, const char *b, int len) +{ + int loop; + for (loop = 0; loop < len; loop++) + if (a[loop] != b[loop]) + return 1; + + return 0; } - -void ppa_c_pulse( char b ) - -{ out_p(0,b); - out_p(2,0x4); out_p(2,0x6); out_p(2,0x4); out_p(2,0xc); +static inline int ppa_proc_write(int hostno, char *buffer, int length) +{ + unsigned long x; + + if ((length > 5) && (ppa_strncmp(buffer, "mode=", 5) == 0)) { + x = simple_strtoul(buffer + 5, NULL, 0); + ppa_hosts[hostno].mode = x; + return length; + } + printk("ppa /proc: invalid variable\n"); + return (-EINVAL); } -void ppa_connect( void ) - -{ ppa_c_pulse(0); - ppa_c_pulse(0x3c); - ppa_c_pulse(0x20); - ppa_c_pulse(0x8f); +int ppa_proc_info(char *buffer, char **start, off_t offset, + int length, int hostno, int inout) +{ + int i; + int len = 0; + + for (i = 0; i < 4; i++) + if (ppa_hosts[i].host == hostno) + break; + + if (inout) + return ppa_proc_write(i, buffer, length); + + len += sprintf(buffer + len, "Version : %s\n", PPA_VERSION); + len += sprintf(buffer + len, "Port : 0x%04x\n", ppa_hosts[i].base); + len += sprintf(buffer + len, "Mode : %s\n", PPA_MODE_STRING[ppa_hosts[i].mode]); + + /* Request for beyond end of buffer */ + if (offset > len) + return 0; + + *start = buffer + offset; + len -= offset; + if (len > length) + len = length; + return len; +} /* end of ppa.c */ +static int device_check(int host_no); + +#if PPA_DEBUG > 0 +#define ppa_fail(x,y) printk("ppa: ppa_fail(%i) from %s at line %d\n",\ + y, __FUNCTION__, __LINE__); ppa_fail_func(x,y); +static inline void ppa_fail_func(int host_no, int error_code) +#else +static inline void ppa_fail(int host_no, int error_code) + #endif +{ + /* If we fail a device then we trash status / message bytes */ + if (ppa_hosts[host_no].cur_cmd) { + ppa_hosts[host_no].cur_cmd->result = error_code << 16; + ppa_hosts[host_no].failed = 1; + } } -void ppa_do_reset( void ) - -{ out_p(2,0); /* This is really just a guess */ - udelay(100); +/* + * Wait for the high bit to be set. + * + * In principle, this could be tied to an interrupt, but the adapter + * doesn't appear to be designed to support interrupts. We spin on + * the 0x80 ready bit. + */ +static unsigned char ppa_wait(int host_no) +{ + int k; + unsigned short ppb = PPA_BASE(host_no); + unsigned char r; + + k = PPA_SPIN_TMO; + do { + r = r_str(ppb); + k--; + udelay(1); + } + while (!(r & 0x80) && (k)); + + /* + * return some status information. + * Semantics: 0xc0 = ZIP wants more data + * 0xd0 = ZIP wants to send more data + * 0xe0 = ZIP is expecting SCSI command data + * 0xf0 = end of transfer, ZIP is sending status + */ + if (k) + return (r & 0xf0); + + /* Counter expired - Time out occured */ + ppa_fail(host_no, DID_TIME_OUT); + printk("ppa timeout in ppa_wait\n"); + return 0; /* command timed out */ } -char ppa_select( int initiator, int target ) - -{ char r; - int k; - - r = in_p(1); - out_p(0,(1<= PPA_SPIN_TMO) { - ppa_error_code = DID_TIME_OUT; - ppa_disconnect(); - return 0; /* command timed out */ - } - return (r & 0xf0); + for (i = 0; i < 100; i++) { + if (r_ecr(ppb) & 0x01) + return; + udelay(5); + } + printk("ppa: ECP sync failed as data still present in FIFO.\n"); } -int ppa_init( void ) - -/* This is based on a trace of what the Iomega DOS 'guest' driver does. - I've tried several different kinds of parallel ports with guest and - coded this to react in the same ways that it does. +/* + * Here is the asm code for the SPP/PS2 protocols for the i386. + * This has been optimised for speed on 386/486 machines. There will + * be very little improvement on the current 586+ machines as it is the + * IO statements which will limit throughput. + */ +#ifdef __i386__ +#define BYTE_OUT(reg) \ + " movb " #reg ",%%al\n" \ + " outb %%al,(%%dx)\n" \ + " addl $2,%%edx\n" \ + " movb $0x0e,%%al\n" \ + " outb %%al,(%%dx)\n" \ + " movb $0x0c,%%al\n" \ + " outb %%al,(%%dx)\n" \ + " subl $2,%%edx\n" + +static inline int ppa_byte_out(unsigned short base, char *buffer, unsigned int len) +{ + /* + * %eax scratch + * %ebx Data to transfer + * %ecx Counter (Don't touch!!) + * %edx Port + * %esi Source buffer (mem pointer) + * + * In case you are wondering what the last line of the asm does... + * : : + */ + asm("shr $2,%%ecx\n" \ + " jz .no_more_bulk_bo\n" \ + " .align 4\n" \ + ".loop_bulk_bo:\n" \ + " movl (%%esi),%%ebx\n" \ + BYTE_OUT(%%bl) \ + BYTE_OUT(%%bh) \ + " rorl $16,%%ebx\n" \ + BYTE_OUT(%%bl) \ + BYTE_OUT(%%bh) \ + " addl $4,%%esi\n" \ + " loop .loop_bulk_bo\n" \ + " .align 4\n" \ + ".no_more_bulk_bo:" \ + : "=S"(buffer): "c"(len), "d"(base), "S"(buffer):"eax", "ebx", "ecx"); + + asm("andl $3,%%ecx\n" \ + " jz .no_more_loose_bo\n" \ + " .align 4\n" \ + ".loop_loose_bo:\n" \ + BYTE_OUT((%%esi)) \ + " incl %%esi\n" \ + " loop .loop_loose_bo\n" \ + ".no_more_loose_bo:\n" \ + : /* no output */ : "c"(len), "d"(base), "S"(buffer):"eax", "ebx", "ecx"); + return 1; /* All went well - we hope! */ +} - The return value from this function is just a hint about where the - handshaking failed. +#define BYTE_IN(reg) \ + " inb (%%dx),%%al\n" \ + " movb %%al," #reg "\n" \ + " addl $2,%%edx\n" \ + " movb $0x27,%%al\n" \ + " outb %%al,(%%dx)\n" \ + " movb $0x25,%%al\n" \ + " outb %%al,(%%dx)\n" \ + " subl $2,%%edx\n" + +static inline int ppa_byte_in(unsigned short base, char *buffer, int len) +{ + /* + * %eax scratch + * %ebx Data to transfer + * %ecx Counter (Don't touch!!) + * %edx Port + * %esi Source buffer (mem pointer) + * + * In case you are wondering what the last line of the asm does... + * : : + */ + asm("shr $2,%%ecx\n" \ + " jz .no_more_bulk_bi\n" \ + " .align 4\n" \ + ".loop_bulk_bi:\n" \ + BYTE_IN(%%bl) \ + BYTE_IN(%%bh) \ + " rorl $16,%%ebx\n" \ + BYTE_IN(%%bl) \ + BYTE_IN(%%bh) \ + " rorl $16,%%ebx\n" \ + " movl %%ebx,(%%esi)\n" \ + " addl $4,%%esi\n" \ + " loop .loop_bulk_bi\n" \ + " .align 4\n" \ + ".no_more_bulk_bi:" \ + : "=S"(buffer): "c"(len), "d"(base), "S"(buffer):"eax", "ebx", "ecx"); + + asm("andl $3,%%ecx\n" \ + " jz .no_more_loose_bi\n" \ + " .align 4\n" \ + ".loop_loose_bi:\n" \ + BYTE_IN((%%esi)) \ + " incl %%esi\n" \ + " loop .loop_loose_bi\n" \ + ".no_more_loose_bi:\n" \ + : /* no output */ : "c"(len), "d"(base), "S"(buffer):"eax", "ebx", "ecx"); + return 1; /* All went well - we hope! */ +} -*/ +#define NIBBLE_IN(reg) \ + " incl %%edx\n" \ + " movb $0x04,%%al\n" \ + " outb %%al,(%%dx)\n" \ + " decl %%edx\n" \ + " inb (%%dx),%%al\n" \ + " andb $0xf0,%%al\n" \ + " movb %%al," #reg "\n" \ + " incl %%edx\n" \ + " movb $0x06,%%al\n" \ + " outb %%al,(%%dx)\n" \ + " decl %%edx\n" \ + " inb (%%dx),%%al\n" \ + " shrb $4,%%al\n" \ + " orb %%al," #reg "\n" + +static inline int ppa_nibble_in(unsigned short str_p, char *buffer, int len) +{ + /* + * %eax scratch + * %ebx Data to transfer + * %ecx Counter (Don't touch!!) + * %edx Port + * %esi Source buffer (mem pointer) + * + * In case you are wondering what the last line of the asm does... + * : : + */ + asm("shr $2,%%ecx\n" \ + " jz .no_more_bulk_ni\n" \ + " .align 4\n" \ + ".loop_bulk_ni:\n" \ + NIBBLE_IN(%%bl) \ + NIBBLE_IN(%%bh) \ + " rorl $16,%%ebx\n" \ + NIBBLE_IN(%%bl) \ + NIBBLE_IN(%%bh) \ + " rorl $16,%%ebx\n" \ + " movl %%ebx,(%%esi)\n" \ + " addl $4,%%esi\n" \ + " loop .loop_bulk_ni\n" \ + " .align 4\n" \ + ".no_more_bulk_ni:" \ + : "=S"(buffer): "c"(len), "d"(str_p), "S"(buffer):"eax", "ebx", "ecx"); + + asm("andl $3,%%ecx\n" \ + " jz .no_more_loose_ni\n" \ + " .align 4\n" \ + ".loop_loose_ni:\n" \ + NIBBLE_IN((%%esi)) \ + " incl %%esi\n" \ + " loop .loop_loose_ni\n" \ + ".no_more_loose_ni:\n" \ + : /* no output */ : "c"(len), "d"(str_p), "S"(buffer):"eax", "ebx", "ecx"); + return 1; /* All went well - we hope! */ +} +#else /* Old style C routines */ + +static inline int ppa_byte_out(unsigned short base, const char *buffer, int len) +{ + unsigned short ctr_p = base + 2; + int i; + + for (i = len; i; i--) { + outb(*buffer++, base); + outb(0xe, ctr_p); + outb(0xc, ctr_p); + } + return 1; /* All went well - we hope! */ +} -{ char r, s; +static inline int ppa_byte_in(unsigned short base, char *buffer, int len) +{ + unsigned short ctr_p = base + 2; + int i; + + for (i = len; i; i--) { + *buffer++ = inb(base); + outb(0x27, ctr_p); + outb(0x25, ctr_p); + } + return 1; /* All went well - we hope! */ +} - out_p(0,0xaa); - if (in_p(0) != (char) 0xaa) return 1; - ppa_disconnect(); - ppa_connect(); - out_p(2,0x6); - if ((in_p(1) & 0xf0) != 0xf0) return 2; - out_p(2,0x4); - if ((in_p(1) & 0xf0) != 0x80) return 3; - ppa_disconnect(); - s = in_p(2); - out_p(2,0xec); - out_p(0,0x55); - r = in_p(0); - if (r != (char) 0xff) { - ppa_nybble = 1; - if (r != (char) 0x55) return 4; - out_p(0,0xaa); if (in_p(0) != (char) 0xaa) return 5; - } - out_p(2,s); - ppa_connect(); - out_p(0,0x40); out_p(2,0x8); out_p(2,0xc); - ppa_disconnect(); - - return 0; -} - -int ppa_start( Scsi_Cmnd * cmd ) - -{ int k; - - ppa_error_code = DID_OK; - ppa_abort_flag = 0; - - if (cmd->target == PPA_INITIATOR) { - ppa_error_code = DID_BAD_TARGET; - return 0; - } - ppa_connect(); - if (!ppa_select(PPA_INITIATOR,cmd->target)) { - ppa_disconnect(); - ppa_error_code = DID_NO_CONNECT; - return 0; - } - out_p(2,0xc); - - for (k=0; k < cmd->cmd_len; k++) { /* send the command */ - if (!ppa_wait()) return 0; - out_p(0,cmd->cmnd[k]); - out_p(2,0xe); - out_p(2,0xc); - } - -#ifdef PPA_DEBUG - printk("PPA: command out: "); - for (k=0; k < cmd->cmd_len; k++) - printk("%3x",(cmd->cmnd[k]) & 0xff ); - printk("\n"); +static inline int ppa_nibble_in(unsigned short str_p, char *buffer, int len) +{ + unsigned short ctr_p = str_p + 1; + unsigned char h, l; + int i; + + for (i = len; i; i--) { + outb(0x4, ctr_p); + h = inb(str_p); + outb(0x6, ctr_p); + l = inb(str_p); + *buffer++ = (h & 0xf0) | ((l & 0xf0) >> 4); + } + return 1; /* All went well - we hope! */ + } + #endif + +static inline int ppa_epp_out(unsigned short epp_p, unsigned short str_p, const char *buffer, int len) +{ + int i; + for (i = len; i; i--) { + outb(*buffer++, epp_p); +#ifdef CONFIG_SCSI_PPA_HAVE_PEDANTIC + if (inb(str_p) & 0x01) + return 0; + #endif + } + return 1; + } + +static int ppa_out(int host_no, char *buffer, int len) +{ + int r; + unsigned short ppb = PPA_BASE(host_no); + + r = ppa_wait(host_no); + + if ((r & 0x50) != 0x40) { + ppa_fail(host_no, DID_ERROR); + return 0; + } + switch (ppa_hosts[host_no].mode) { + case PPA_NIBBLE: + case PPA_PS2: + /* 8 bit output, with a loop */ + r = ppa_byte_out(ppb, buffer, len); + break; + + case PPA_EPP_32: + case PPA_EPP_16: + case PPA_EPP_8: + epp_reset(ppb); + w_ctr(ppb, 0x4); +#ifdef CONFIG_SCSI_PPA_HAVE_PEDANTIC + r = ppa_epp_out(ppb + 4, ppb + 1, buffer, len); +#else + if (!(((long) buffer | len) & 0x03)) + outsl(ppb + 4, buffer, len >> 2); + else + outsb(ppb + 4, buffer, len); + w_ctr(ppb, 0xc); + r = !(r_str(ppb) & 0x01); #endif - - return 1; + w_ctr(ppb, 0xc); + ecp_sync(ppb); + break; + + default: + printk("PPA: bug in ppa_out()\n"); + r = 0; + } + return r; } -int ppa_completion( Scsi_Cmnd * cmd ) - -/* The bulk flag enables some optimisations in the data transfer loops, - it should be true for any command that transfers data in integral - numbers of sectors. - - The driver appears to remain stable if we speed up the parallel port - i/o in this function, but not elsewhere. -*/ - -{ char r, l, h, v; - int dir, cnt, blen, fast, bulk; - char *buffer; - -#ifdef PPA_DEBUG - int k; +static inline int ppa_epp_in(int epp_p, int str_p, char *buffer, int len) +{ + int i; + for (i = len; i; i--) { + *buffer++ = inb(epp_p); +#ifdef CONFIG_SCSI_PPA_HAVE_PEDANTIC + if (inb(str_p) & 0x01) + return 0; #endif - - if (!(r = ppa_wait())) return 0; - v = cmd->cmnd[0]; - bulk = ((v==READ_6)||(v==READ_10)||(v==WRITE_6)||(v==WRITE_10)); - buffer = cmd->request_buffer; - blen = cmd->request_bufflen; - cnt = 0; dir = 0; - if (r == (char) 0xc0) dir = 1; /* d0 = read c0 = write f0 = status */ - - ppa_port_delay = ppa_speed_high; - - while (r != (char) 0xf0) { - if (((r & 0xc0) != 0xc0 ) || (cnt >= blen)) { - ppa_disconnect(); - ppa_error_code = DID_ERROR; - return 0; - } - fast = bulk && ((blen - cnt) >= PPA_SECTOR_SIZE); - if (dir) do { - out_p(0,buffer[cnt++]); - out_p(2,0xe); out_p(2,0xc); - if (!fast) break; - } while (cnt % PPA_SECTOR_SIZE); - else { - if (ppa_nybble) do { - out_p(2,0x4); h = in_p(1); - out_p(2,0x6); l = in_p(1); - v = ((l >> 4) & 0x0f) + (h & 0xf0); - buffer[cnt++] = v; - if (!fast) break; - } while (cnt % PPA_SECTOR_SIZE); - else do { - out_p(2,0x25); v = in_p(0); out_p(2,0x27); - buffer[cnt++] = v; - if (!fast) break; - } while (cnt % PPA_SECTOR_SIZE); - if (!ppa_nybble) { - out_p(2,0x5); out_p(2,0x4); - } - out_p(2,0xc); - } - if (!(r = ppa_wait())) return 0; - } - - ppa_port_delay = ppa_speed_low; - - out_p(2,0x4); /* now read status byte */ - h = in_p(1); - out_p(2,0x6); - l = in_p(1); - out_p(2,0xc); - r = ((l >> 4) & 0x0f) + (h & 0xf0); - - out_p(2,0xe); out_p(2,0xc); - ppa_disconnect(); - -#ifdef PPA_DEBUG - printk("PPA: status: %x, data[%d]: ",r & STATUS_MASK,cnt); - if (cnt > 12) cnt = 12; - for (k=0; k < cnt; k++) - printk("%3x",buffer[k] & 0xff ); - printk("\n"); + } + return 1; + } + +static int ppa_in(int host_no, char *buffer, int len) +{ + int r; + unsigned short ppb = PPA_BASE(host_no); + + r = ppa_wait(host_no); + + if ((r & 0x50) != 0x50) { + ppa_fail(host_no, DID_ERROR); + return 0; + } + switch (ppa_hosts[host_no].mode) { + case PPA_NIBBLE: + /* 4 bit input, with a loop */ + r = ppa_nibble_in(ppb + 1, buffer, len); + w_ctr(ppb, 0xc); + break; + + case PPA_PS2: + /* 8 bit input, with a loop */ + w_ctr(ppb, 0x25); + r = ppa_byte_in(ppb, buffer, len); + w_ctr(ppb, 0x4); + w_ctr(ppb, 0xc); + break; + + case PPA_EPP_32: + case PPA_EPP_16: + case PPA_EPP_8: + epp_reset(ppb); + w_ctr(ppb, 0x24); +#ifdef CONFIG_SCSI_PPA_HAVE_PEDANTIC + r = ppa_epp_in(ppb + 4, ppb + 1, buffer, len); + #else + if (!(((long) buffer | len) & 0x03)) + insl(ppb + 4, buffer, len >> 2); + else + insb(ppb + 4, buffer, len); + w_ctr(ppb, 0x2c); + r = !(r_str(ppb) & 0x01); #endif - - return (r & STATUS_MASK); + w_ctr(ppb, 0x2c); + ecp_sync(ppb); + break; + + default: + printk("PPA: bug in ppa_ins()\n"); + r = 0; + break; + } + return r; } -/* deprecated synchronous interface */ - -int ppa_command( Scsi_Cmnd * cmd ) - -{ int s; - - sti(); - s = 0; - if (ppa_start(cmd)) - if (ppa_wait()) - s = ppa_completion(cmd); - return s + (ppa_error_code << 16); +/* end of ppa_io.h */ +static inline void ppa_d_pulse(unsigned short ppb, unsigned char b) +{ + w_dtr(ppb, b); + w_ctr(ppb, 0xc); + w_ctr(ppb, 0xe); + w_ctr(ppb, 0xc); + w_ctr(ppb, 0x4); + w_ctr(ppb, 0xc); } -/* pseudo-interrupt queueing interface */ - -/* Since the PPA itself doesn't generate interrupts, we use - the scheduler's task queue to generate a stream of call-backs and - complete the request when the drive is ready. -*/ - -static void ppa_interrupt( void *data); - -static struct tq_struct ppa_tq = {0,0,ppa_interrupt,NULL}; - -static void ppa_interrupt( void *data) +static void ppa_disconnect(int host_no) +{ + unsigned short ppb = PPA_BASE(host_no); -{ Scsi_Cmnd *cmd; - void (*done) (Scsi_Cmnd *); - - cmd = ppa_current; - done = ppa_done; - if (!cmd) return; - - if (ppa_abort_flag) { - ppa_disconnect(); - if(ppa_abort_flag == 1) cmd->result = DID_ABORT << 16; - else { ppa_do_reset(); - cmd->result = DID_RESET << 16; - } - ppa_current = 0; - done(cmd); - return; - } - if (!( in_p(1) & 0x80)) { - queue_task(&ppa_tq,&tq_scheduler); - return; - } - cmd->result = ppa_completion(cmd) + (ppa_error_code << 16); - ppa_current = 0; - done(cmd); - return; + ppa_d_pulse(ppb, 0); + ppa_d_pulse(ppb, 0x3c); + ppa_d_pulse(ppb, 0x20); + ppa_d_pulse(ppb, 0xf); } -int ppa_queuecommand( Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) - -{ if (ppa_current) return 0; - sti(); - ppa_current = cmd; - ppa_done = done; - if (!ppa_start(cmd)) { - cmd->result = ppa_error_code << 16; - ppa_current = 0; - done(cmd); - return 0; - } - queue_task(&ppa_tq,&tq_scheduler); - return 0; +static inline void ppa_c_pulse(unsigned short ppb, unsigned char b) +{ + w_dtr(ppb, b); + w_ctr(ppb, 0x4); + w_ctr(ppb, 0x6); + w_ctr(ppb, 0x4); + w_ctr(ppb, 0xc); } -int ppa_detect( Scsi_Host_Template * host ) - -{ struct Scsi_Host *hreg; - int rs; - - host->proc_dir = &proc_scsi_ppa; - - /* can we have the ports ? */ - - if (check_region(ppa_base,3)) { - printk("PPA: ports at 0x%3x are not available\n",ppa_base); - return 0; - } - - /* attempt to initialise the controller */ - - ppa_port_delay = ppa_speed_low; - - rs = ppa_init(); - if (rs) { - printk("PPA: unable to initialise controller at 0x%x, error %d\n", - ppa_base,rs); - return 0; - } - - /* now the glue ... */ - - request_region(ppa_base,3,"ppa"); - - host->can_queue = PPA_CAN_QUEUE; - - hreg = scsi_register(host,0); - hreg->io_port = ppa_base; - hreg->n_io_port = 3; - hreg->dma_channel = -1; +static inline void ppa_connect(int host_no, int flag) +{ + unsigned short ppb = PPA_BASE(host_no); + + ppa_c_pulse(ppb, 0); + ppa_c_pulse(ppb, 0x3c); + ppa_c_pulse(ppb, 0x20); + if ((flag == CONNECT_EPP_MAYBE) && + IN_EPP_MODE(ppa_hosts[host_no].mode)) + ppa_c_pulse(ppb, 0xcf); + else + ppa_c_pulse(ppb, 0x8f); +} - sprintf(ppa_info_string, - "PPA driver version %s using %d-bit mode on port 0x%x.", - PPA_VERSION,8-ppa_nybble*4,ppa_base); - host->name = ppa_info_string; +static int ppa_select(int host_no, int target) +{ + int k; + unsigned short ppb = PPA_BASE(host_no); + + /* + * Bit 6 (0x40) is the device selected bit. + * First we must wait till the current device goes off line... + */ + k = PPA_SELECT_TMO; + do { + k--; + } while ((r_str(ppb) & 0x40) && (k)); + if (!k) + return 0; + + w_dtr(ppb, (1 << target)); + w_ctr(ppb, 0xe); + w_ctr(ppb, 0xc); + w_dtr(ppb, 0x80); /* This is NOT the initator */ + w_ctr(ppb, 0x8); + + k = PPA_SELECT_TMO; + do { + k--; + } + while (!(r_str(ppb) & 0x40) && (k)); + if (!k) + return 0; + + return 1; +} - return 1; /* 1 host detected */ +/* + * This is based on a trace of what the Iomega DOS 'guest' driver does. + * I've tried several different kinds of parallel ports with guest and + * coded this to react in the same ways that it does. + * + * The return value from this function is just a hint about where the + * handshaking failed. + * + */ +static int ppa_init(int host_no) +{ + int retv; + unsigned short ppb = PPA_BASE(host_no); + + ppa_disconnect(host_no); + ppa_connect(host_no, CONNECT_NORMAL); + + retv = 2; /* Failed */ + + w_ctr(ppb, 0xe); + if ((r_str(ppb) & 0x08) == 0x08) + retv--; + + w_ctr(ppb, 0xc); + if ((r_str(ppb) & 0x08) == 0x00) + retv--; + + /* This is a SCSI BUS reset signal */ + if (!retv) { + w_dtr(ppb, 0x40); + w_ctr(ppb, 0x08); + udelay(30); + w_ctr(ppb, 0x0c); + udelay(1000); /* Allow devices to settle down */ + } + ppa_disconnect(host_no); + udelay(1000); /* Another delay to allow devices to settle */ + + if (!retv) + retv = device_check(host_no); + + return retv; } -int ppa_biosparam( Disk * disk, kdev_t dev, int ip[]) +static inline int ppa_send_command(Scsi_Cmnd * cmd) +{ + int host_no = cmd->host->unique_id; + int k; -/* Apparently the the disk->capacity attribute is off by 1 sector - for all disk drives. We add the one here, but it should really - be done in sd.c. Even if it gets fixed there, this will still - work. -*/ + w_ctr(PPA_BASE(host_no), 0x0c); -{ ip[0] = 0x40; - ip[1] = 0x20; - ip[2] = (disk->capacity +1) / (ip[0] * ip[1]); - if (ip[2] > 1024) { - ip[0] = 0xff; - ip[1] = 0x3f; - ip[2] = (disk->capacity +1) / (ip[0] * ip[1]); - if (ip[2] > 1023) - ip[2] = 1023; - } - return 0; + for (k = 0; k < cmd->cmd_len; k++) + if (!ppa_out(host_no, &cmd->cmnd[k], 1)) + return 0; + return 1; } -int ppa_abort( Scsi_Cmnd * cmd ) - -{ ppa_abort_flag = 1; - return SCSI_ABORT_SNOOZE; +/* + * The bulk flag enables some optimisations in the data transfer loops, + * it should be true for any command that transfers data in integral + * numbers of sectors. + * + * The driver appears to remain stable if we speed up the parallel port + * i/o in this function, but not elsewhere. + */ +static int ppa_completion(Scsi_Cmnd * cmd) +{ + /* Return codes: + * -1 Error + * 0 Told to schedule + * 1 Finished data transfer + */ + int host_no = cmd->host->unique_id; + unsigned short ppb = PPA_BASE(host_no); + unsigned long start_jiffies = jiffies; + + unsigned char r, v; + int fast, bulk, status; + + v = cmd->cmnd[0]; + bulk = ((v == READ_6) || + (v == READ_10) || + (v == WRITE_6) || + (v == WRITE_10)); + + /* + * We only get here if the drive is ready to comunicate, + * hence no need for a full ppa_wait. + */ + r = (r_str(ppb) & 0xf0); + + while (r != (unsigned char) 0xf0) { + /* + * If we have been running for more than a full timer tick + * then take a rest. + */ + if (jiffies > start_jiffies + 1) + return 0; + + if (((r & 0xc0) != 0xc0) || (cmd->SCp.this_residual <= 0)) { + ppa_fail(host_no, DID_ERROR); + return -1; /* ERROR_RETURN */ + } + /* determine if we should use burst I/O */ fast = (bulk && (cmd->SCp.this_residual >= PPA_BURST_SIZE)) + ? PPA_BURST_SIZE : 1; + + if (r == (unsigned char) 0xc0) + status = ppa_out(host_no, cmd->SCp.ptr, fast); + else + status = ppa_in(host_no, cmd->SCp.ptr, fast); + + cmd->SCp.ptr += fast; + cmd->SCp.this_residual -= fast; + + if (!status) { + ppa_fail(host_no, DID_BUS_BUSY); + return -1; /* ERROR_RETURN */ + } + if (cmd->SCp.buffer && !cmd->SCp.this_residual) { + /* if scatter/gather, advance to the next segment */ + if (cmd->SCp.buffers_residual--) { + cmd->SCp.buffer++; + cmd->SCp.this_residual = cmd->SCp.buffer->length; + cmd->SCp.ptr = cmd->SCp.buffer->address; + } + } + /* Now check to see if the drive is ready to comunicate */ + r = (r_str(ppb) & 0xf0); + /* If not, drop back down to the scheduler and wait a timer tick */ + if (!(r & 0x80)) + return 0; + } + return 1; /* FINISH_RETURN */ } -int ppa_reset( Scsi_Cmnd * cmd ) - -{ ppa_abort_flag = 2; - return SCSI_RESET_PUNT; +/* + * Since the PPA itself doesn't generate interrupts, we use + * the scheduler's task queue to generate a stream of call-backs and + * complete the request when the drive is ready. + */ +static void ppa_interrupt(void *data) +{ + ppa_struct *tmp = (ppa_struct *) data; + Scsi_Cmnd *cmd = tmp->cur_cmd; + + if (!cmd) { + printk("PPA: bug in ppa_interrupt\n"); + return; + } + if (ppa_engine(tmp, cmd)) { + tmp->ppa_tq.data = (void *) tmp; + tmp->ppa_tq.sync = 0; + queue_task(&tmp->ppa_tq, &tq_timer); + return; + } + /* Command must of completed hence it is safe to let go... */ +#if PPA_DEBUG > 0 + switch ((cmd->result >> 16) & 0xff) { + case DID_OK: + break; + case DID_NO_CONNECT: + printk("ppa: no device at SCSI ID %i\n", cmd->target); + break; + case DID_BUS_BUSY: + printk("ppa: BUS BUSY - EPP timeout detected\n"); + break; + case DID_TIME_OUT: + printk("ppa: unknown timeout\n"); + break; + case DID_ABORT: + printk("ppa: told to abort\n"); + break; + case DID_PARITY: + printk("ppa: parity error (???)\n"); + break; + case DID_ERROR: + printk("ppa: internal driver error\n"); + break; + case DID_RESET: + printk("ppa: told to reset device\n"); + break; + case DID_BAD_INTR: + printk("ppa: bad interrupt (???)\n"); + break; + default: + printk("ppa: bad return code (%02x)\n", (cmd->result >> 16) & 0xff); + } + #endif + + if (cmd->SCp.phase > 1) + ppa_disconnect(cmd->host->unique_id); + + tmp->cur_cmd = 0; + cmd->scsi_done(cmd); + return; } -const char *ppa_info( struct Scsi_Host * host ) - -{ return ppa_info_string; +static int ppa_engine(ppa_struct * tmp, Scsi_Cmnd * cmd) +{ + int host_no = cmd->host->unique_id; + unsigned short ppb = PPA_BASE(host_no); + unsigned char l = 0, h = 0; + int retv; + + /* First check for any errors that may of occured + * Here we check for internal errors + */ + if (tmp->failed) + return 0; + + switch (cmd->SCp.phase) { + case 0: /* Phase 0 - Waiting for parport */ + if ((jiffies - tmp->jstart) > HZ) { + /* + * We waited more than a second + * for parport to call us + */ + ppa_fail(host_no, DID_BUS_BUSY); + return 0; + } + return 1; /* wait until ppa_wakeup claims parport */ + case 1: /* Phase 1 - Connected */ + { /* Perform a sanity check for cable unplugged */ + int retv = 2; /* Failed */ + + ppa_connect(host_no, CONNECT_EPP_MAYBE); + + w_ctr(ppb, 0xe); + if ((r_str(ppb) & 0x08) == 0x08) + retv--; + + w_ctr(ppb, 0xc); + if ((r_str(ppb) & 0x08) == 0x00) + retv--; + + if (retv) + if ((jiffies - tmp->jstart) > (1 * HZ)) { + printk("ppa: Parallel port cable is unplugged!!\n"); + ppa_fail(host_no, DID_BUS_BUSY); + return 0; + } else { + ppa_disconnect(host_no); + return 1; /* Try again in a jiffy */ + } + cmd->SCp.phase++; + } + + case 2: /* Phase 2 - We are now talking to the scsi bus */ + if (!ppa_select(host_no, cmd->target)) { + ppa_fail(host_no, DID_NO_CONNECT); + return 0; + } + cmd->SCp.phase++; + + case 3: /* Phase 3 - Ready to accept a command */ + w_ctr(ppb, 0x0c); + if (!(r_str(ppb) & 0x80)) + return 1; + + if (!ppa_send_command(cmd)) + return 0; + cmd->SCp.phase++; + + case 4: /* Phase 4 - Setup scatter/gather buffers */ + if (cmd->use_sg) { + /* if many buffers are available, start filling the first */ + cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer; + cmd->SCp.this_residual = cmd->SCp.buffer->length; + cmd->SCp.ptr = cmd->SCp.buffer->address; + } else { + /* else fill the only available buffer */ + cmd->SCp.buffer = NULL; + cmd->SCp.this_residual = cmd->request_bufflen; + cmd->SCp.ptr = cmd->request_buffer; + } + cmd->SCp.buffers_residual = cmd->use_sg; + cmd->SCp.phase++; + + case 5: /* Phase 5 - Data transfer stage */ + w_ctr(ppb, 0x0c); + if (!(r_str(ppb) & 0x80)) + return 1; + + retv = ppa_completion(cmd); + if (retv == -1) + return 0; + if (retv == 0) + return 1; + cmd->SCp.phase++; + + case 6: /* Phase 6 - Read status/message */ + cmd->result = DID_OK << 16; + /* Check for data overrun */ + if (ppa_wait(host_no) != (unsigned char) 0xf0) { + ppa_fail(host_no, DID_ERROR); + return 0; + } + if (ppa_in(host_no, &l, 1)) { /* read status byte */ + /* Check for optional message byte */ + if (ppa_wait(host_no) == (unsigned char) 0xf0) + ppa_in(host_no, &h, 1); + cmd->result = (DID_OK << 16) + (h << 8) + (l & STATUS_MASK); + } + return 0; /* Finished */ + break; + + default: + printk("ppa: Invalid scsi phase\n"); + } + return 0; } -#ifndef MODULE - -/* Command line parameters (for built-in driver): - - Syntax: ppa=base[,speed_high[,speed_low[,nybble]]] - - For example: ppa=0x378 or ppa=0x378,0,3 - -*/ - -void ppa_setup(char *str, int *ints) - -{ if (ints[0] > 0) ppa_base = ints[1]; - if (ints[0] > 1) ppa_speed_high = ints[2]; - if (ints[0] > 2) ppa_speed_low = ints[3]; - if (ints[0] > 3) ppa_nybble = ints[4]; - if (ints[0] > 4) ppa_nybble = ints[5]; +int ppa_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) +{ + int host_no = cmd->host->unique_id; + + if (ppa_hosts[host_no].cur_cmd) { + printk("PPA: bug in ppa_queuecommand\n"); + return 0; + } + ppa_hosts[host_no].failed = 0; + ppa_hosts[host_no].jstart = jiffies; + ppa_hosts[host_no].cur_cmd = cmd; + cmd->scsi_done = done; + cmd->result = DID_ERROR << 16; /* default return code */ + cmd->SCp.phase = 0; /* bus free */ + + ppa_pb_claim(host_no); + + ppa_hosts[host_no].ppa_tq.data = ppa_hosts + host_no; + ppa_hosts[host_no].ppa_tq.sync = 0; + queue_task(&ppa_hosts[host_no].ppa_tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + + return 0; } -#else +/* + * Apparently the the disk->capacity attribute is off by 1 sector + * for all disk drives. We add the one here, but it should really + * be done in sd.c. Even if it gets fixed there, this will still + * work. + */ +int ppa_biosparam(Disk * disk, kdev_t dev, int ip[]) +{ + ip[0] = 0x40; + ip[1] = 0x20; + ip[2] = (disk->capacity + 1) / (ip[0] * ip[1]); + if (ip[2] > 1024) { + ip[0] = 0xff; + ip[1] = 0x3f; + ip[2] = (disk->capacity + 1) / (ip[0] * ip[1]); + if (ip[2] > 1023) + ip[2] = 1023; + } + return 0; +} -Scsi_Host_Template driver_template = PPA; +int ppa_abort(Scsi_Cmnd * cmd) +{ + /* + * There is no method for aborting commands since Iomega + * have tied the SCSI_MESSAGE line high in the interface + */ + + switch (cmd->SCp.phase) { + case 0: /* Do not have access to parport */ + case 1: /* Have not connected to interface */ + cmd->result = DID_ABORT; + cmd->done(cmd); + return SCSI_ABORT_SUCCESS; + break; + default: /* SCSI command sent, can not abort */ + return SCSI_ABORT_BUSY; + break; + } +} -#include "scsi_module.c" +int ppa_reset(Scsi_Cmnd * cmd, unsigned int x) +{ + int host_no = cmd->host->unique_id; + int ppb = PPA_BASE(host_no); + + /* + * PHASE1: + * Bring the interface crashing down on whatever is running + * hopefully this will kill the request. + * Bring back up the interface, reset the drive (and anything + * attached for that manner) + */ + if (cmd) + if (cmd->SCp.phase) + ppa_disconnect(cmd->host->unique_id); + + ppa_connect(host_no, CONNECT_NORMAL); + w_dtr(ppb, 0x40); + w_ctr(ppb, 0x8); + udelay(30); + w_ctr(ppb, 0xc); + udelay(1000); /* delay for devices to settle down */ + ppa_disconnect(host_no); + udelay(1000); /* Additional delay to allow devices to settle down */ + + /* + * PHASE2: + * Sanity check for the sake of mid-level driver + */ + if (!cmd) { + printk("ppa bus reset called for invalid command.\n"); + return SCSI_RESET_NOT_RUNNING; + } + /* + * PHASE3: + * Flag the current command as having died due to reset + */ + ppa_connect(host_no, CONNECT_NORMAL); + ppa_fail(host_no, DID_RESET); + + /* Since the command was already on the timer queue ppa_interrupt + * will be called shortly. + */ + return SCSI_RESET_PENDING; +} -#endif +static int device_check(int host_no) +{ + /* This routine looks for a device and then attempts to use EPP + to send a command. If all goes as planned then EPP is available. */ + + static char cmd[6] = + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + int loop, old_mode, status, k, ppb = PPA_BASE(host_no); + unsigned char l; + + old_mode = ppa_hosts[host_no].mode; + for (loop = 0; loop < 8; loop++) { + /* Attempt to use EPP for Test Unit Ready */ + if ((ppb & 0x0007) == 0x0000) + ppa_hosts[host_no].mode = PPA_EPP_32; + + second_pass: + ppa_connect(host_no, CONNECT_EPP_MAYBE); + /* Select SCSI device */ + if (!ppa_select(host_no, loop)) { + ppa_disconnect(host_no); + continue; + } + printk("ppa: Found device at ID %i, Attempting to use %s\n", loop, + PPA_MODE_STRING[ppa_hosts[host_no].mode]); + + /* Send SCSI command */ + status = 1; + w_ctr(ppb, 0x0c); + for (l = 0; (l < 6) && (status); l++) + status = ppa_out(host_no, cmd, 1); + + if (!status) { + ppa_disconnect(host_no); + ppa_connect(host_no, CONNECT_EPP_MAYBE); + w_dtr(ppb, 0x40); + w_ctr(ppb, 0x08); + udelay(30); + w_ctr(ppb, 0x0c); + udelay(1000); + ppa_disconnect(host_no); + udelay(1000); + if (ppa_hosts[host_no].mode == PPA_EPP_32) { + ppa_hosts[host_no].mode = old_mode; + goto second_pass; + } + printk("ppa: Unable to establish communication, aborting driver load.\n"); + return 1; + } + w_ctr(ppb, 0x0c); + k = 1000000; /* 1 Second */ + do { + l = r_str(ppb); + k--; + udelay(1); + } while (!(l & 0x80) && (k)); + + l &= 0xf0; + + if (l != 0xf0) { + ppa_disconnect(host_no); + ppa_connect(host_no, CONNECT_EPP_MAYBE); + w_dtr(ppb, 0x40); + w_ctr(ppb, 0x08); + udelay(30); + w_ctr(ppb, 0x0c); + udelay(1000); + ppa_disconnect(host_no); + udelay(1000); + if (ppa_hosts[host_no].mode == PPA_EPP_32) { + ppa_hosts[host_no].mode = old_mode; + goto second_pass; + } + printk("ppa: Unable to establish communication, aborting driver load.\n"); + return 1; + } + ppa_disconnect(host_no); + printk("ppa: Communication established with ID %i using %s\n", loop, + PPA_MODE_STRING[ppa_hosts[host_no].mode]); + return 0; + } + printk("ppa: No devices found, aborting driver load.\n"); + return 1; +} -/* end of ppa.c */ +#define PPA_ID "ppa: " + +int port_probe(unsigned short port) +{ + int retv = 0; + unsigned char a, b, c; + unsigned int i, j; + + + printk(PPA_ID "Probing port %04x\n", port); + +/* ##### ###### ###### + * # # # # # # + * # # # # # + * ##### ###### ###### + * # # # + * # # # # + * ##### # # + */ + + outb(0x0c, port + 0x402); + outb(0x0c, port + 0x002); + outb(0x55, port); + a = inb(port); + if (a != 0x55) + return retv; + printk(PPA_ID " SPP port present\n"); + + retv += PPA_PROBE_SPP; + +/* ####### ##### ###### + * # # # # # + * # # # # + * ##### # ###### + * # # # + * # # # # + * ####### ##### # + */ + + for (i = 1024; i > 0; i--) { /* clear at most 1k of data from FIFO */ + a = inb(port + 0x402); + if ((a & 0x03) == 0x03) + goto no_ecp; + if (a & 0x01) + break; + inb(port + 0x400); /* Remove byte from FIFO */ + } + + if (i <= 0) + goto no_ecp; + + b = a ^ 3; + outb(b, port + 0x402); + c = inb(port + 0x402); + + if (a == c) { + outb(0xc0, port + 0x402); /* FIFO test */ + j = 0; + while (!(inb(port + 0x402) & 0x01) && (j < 1024)) { + inb(port + 0x400); + j++; + } + if (j >= 1024) + goto no_ecp; + i = 0; + j = 0; + while (!(inb(port + 0x402) & 0x02) && (j < 1024)) { + outb(0x00, port + 0x400); + i++; + j++; + } + if (j >= 1024) + goto no_ecp; + j = 0; + while (!(inb(port + 0x402) & 0x01) && (j < 1024)) { + inb(port + 0x400); + j++; + } + if (j >= 1024) + goto no_ecp; + printk(PPA_ID " ECP with a %i byte FIFO present\n", i); + + retv += PPA_PROBE_ECR; + } +/* ###### ##### ##### + * # # # # # # + * # # # # + * ###### ##### ##### + * # # # + * # # # # + * # ##### ####### + */ + + no_ecp: + if (retv & PPA_PROBE_ECR) + outb(0x20, port + 0x402); + + outb(0x55, port); + outb(0x0c, port + 2); + a = inb(port); + outb(0x55, port); + outb(0x2c, port + 2); + b = inb(port); + if (a != b) { + printk(PPA_ID " PS/2 bidirectional port present\n"); + retv += PPA_PROBE_PS2; + } +/* ####### ###### ###### + * # # # # # + * # # # # # + * ##### ###### ###### + * # # # + * # # # + * ####### # # + */ + + if (port & 0x007) { + printk(PPA_ID " EPP not supported at this address\n"); + return retv; + } + if (retv & PPA_PROBE_ECR) { + for (i = 0x00; i < 0x80; i += 0x20) { + outb(i, port + 0x402); + + a = inb(port + 1); + outb(a, port + 1); + outb(a & 0xfe, port + 1); + a = inb(port + 1); + if (!(a & 0x01)) { + printk(PPA_ID " Failed Intel bug check. (Phony EPP in ECP)\n"); + return retv; + } + } + printk(PPA_ID " Passed Intel bug check.\n"); + outb(0x80, port + 0x402); + } + a = inb(port + 1); + outb(a, port + 1); + outb(a & 0xfe, port + 1); + a = inb(port + 1); + + if (a & 0x01) { + outb(0x0c, port + 0x402); + outb(0x0c, port + 0x002); + return retv; + } + + outb(0x04, port + 2); + inb(port + 4); + a = inb(port + 1); + outb(a, port + 1); + outb(a & 0xfe, port + 1); + + if (a & 0x01) { + printk(PPA_ID " EPP 1.9 with hardware direction protocol\n"); + retv += PPA_PROBE_EPP19; + } else { + /* The EPP timeout bit was not set, this could either be: + * EPP 1.7 + * EPP 1.9 with software direction + */ + outb(0x24, port + 2); + inb(port + 4); + a = inb(port + 1); + outb(a, port + 1); + outb(a & 0xfe, port + 1); + if (a & 0x01) { + printk(PPA_ID " EPP 1.9 with software direction protocol\n"); + retv += PPA_PROBE_EPP19; + } else { + printk(PPA_ID " EPP 1.7\n"); + retv += PPA_PROBE_EPP17; + } + } + + outb(0x0c, port + 0x402); + outb(0x0c, port + 0x002); + return retv; +} diff --git a/drivers/scsi/ppa.h b/drivers/scsi/ppa.h index 9dbfe7e63c20..2106222293a1 100644 --- a/drivers/scsi/ppa.h +++ b/drivers/scsi/ppa.h @@ -1,44 +1,173 @@ +/* Driver for the PPA3 parallel port SCSI HBA embedded in + * the Iomega ZIP drive + * + * (c) 1996 Grant R. Guenther grant@torque.net + * David Campbell campbell@torque.net + * + * All comments to David. + */ + #ifndef _PPA_H #define _PPA_H -/* Driver for the PPA3 parallel port SCSI HBA embedded in - the Iomega ZIP drive +#define PPA_VERSION "1.42" + +/* Use the following to enable certain chipset support + * Default is PEDANTIC = 3 + */ +#ifndef CONFIG_SCSI_PPA_HAVE_PEDANTIC +#define CONFIG_SCSI_PPA_HAVE_PEDANTIC 3 +#endif + +/* + * this driver has been hacked by Matteo Frigo (athena@theory.lcs.mit.edu) + * to support EPP and scatter-gather. [0.26-athena] + * + * additional hacks by David Campbell + * in response to this driver "mis-behaving" on his machine. + * Fixed EPP to handle "software" changing of EPP port data direction. + * Chased down EPP timeouts + * Made this driver "kernel version friendly" [0.28-athena] + * + * [ Stuff removed ] + * + * Compiled against 2.1.53. + * Rebuilt ppa_abort() function, should handle unplugged cable. + * [1.35s] + * + * PPA now auto probes for EPP on base address which are aligned on + * 8 byte boundaries (0x278 & 0x378) using the attached devices. + * This hopefully avoids the nasty problem of trying to detect EPP. + * Tested on 2.1.53 [1.36] + * + * The id_probe utility no longer performs read/write tests. + * Additional code included for checking the Intel ECP bug + * (Bit 0 of STR stuck low which fools the EPP detection routine) + * [1.37] + * + * Oops! Got the bit sign mixed up for the Intel bug check. + * Found that an additional delay is required during SCSI resets + * to allow devices to settle down. + * [1.38] + * + * Fixed all problems in the parport sharing scheme. Now ppa can be safe + * used with lp or other parport devices on the same parallel port. + * 1997 by Andrea Arcangeli + * [1.39] + * + * Little fix in ppa engine to ensure that ppa don' t release parport + * or disconnect in wrong cases. + * 1997 by Andrea Arcangeli + * [1.40] + * + * Corrected ppa.h for 2.1.x kernels (>=2.1.85) + * Modified "Nat Semi Kludge" for extended chipsets + * [1.41] + * + * Fixed id_probe for EPP 1.9 chipsets (misdetected as EPP 1.7) + * [1.42] + */ +/* ------ END OF USER CONFIGURABLE PARAMETERS ----- */ + +#ifdef PPA_CODE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "sd.h" +#include "hosts.h" +/* batteries not included :-) */ + +/* + * modes in which the driver can operate + */ +#define PPA_AUTODETECT 0 /* Autodetect mode */ +#define PPA_NIBBLE 1 /* work in standard 4 bit mode */ +#define PPA_PS2 2 /* PS/2 byte mode */ +#define PPA_EPP_8 3 /* EPP mode, 8 bit */ +#define PPA_EPP_16 4 /* EPP mode, 16 bit */ +#define PPA_EPP_32 5 /* EPP mode, 32 bit */ +#define PPA_UNKNOWN 6 /* Just in case... */ - (c) 1996 Grant R. Guenther grant@torque.net -*/ +static char *PPA_MODE_STRING[] = +{ + "Autodetect", + "SPP", + "PS/2", + "EPP 8 bit", + "EPP 16 bit", + "EPP 32 bit", + "Unknown"}; -#define PPA_INITIATOR 7 +/* This is a global option */ +int ppa_sg = SG_ALL; /* enable/disable scatter-gather. */ -int ppa_detect(Scsi_Host_Template * ); -const char * ppa_info(struct Scsi_Host *); -int ppa_command(Scsi_Cmnd *); -int ppa_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); +/* other options */ +#define PPA_CAN_QUEUE 1 /* use "queueing" interface */ +#define PPA_BURST_SIZE 512 /* data burst size */ +#define PPA_SELECT_TMO 5000 /* how long to wait for target ? */ +#define PPA_SPIN_TMO 50000 /* ppa_wait loop limiter */ +#define PPA_DEBUG 0 /* debuging option */ +#define IN_EPP_MODE(x) (x == PPA_EPP_8 || x == PPA_EPP_16 || x == PPA_EPP_32) + +/* args to ppa_connect */ +#define CONNECT_EPP_MAYBE 1 +#define CONNECT_NORMAL 0 + +#define r_dtr(x) (unsigned char)inb((x)) +#define r_str(x) (unsigned char)inb((x)+1) +#define r_ctr(x) (unsigned char)inb((x)+2) +#define r_epp(x) (unsigned char)inb((x)+4) +#define r_fifo(x) (unsigned char)inb((x)+0x400) +#define r_ecr(x) (unsigned char)inb((x)+0x402) + +#define w_dtr(x,y) outb(y, (x)) +#define w_str(x,y) outb(y, (x)+1) +#define w_ctr(x,y) outb(y, (x)+2) +#define w_epp(x,y) outb(y, (x)+4) +#define w_fifo(x,y) outb(y, (x)+0x400) +#define w_ecr(x,y) outb(y, (x)+0x402) + +static int ppa_engine(ppa_struct *, Scsi_Cmnd *); +static int ppa_in(int, char *, int); +static int ppa_init(int); +static void ppa_interrupt(void *); +static int ppa_out(int, char *, int); + +struct proc_dir_entry proc_scsi_ppa = +{PROC_SCSI_PPA, 3, "ppa", S_IFDIR | S_IRUGO | S_IXUGO, 2}; +#else +extern struct proc_dir_entry proc_scsi_ppa; +#endif + +int ppa_detect(Scsi_Host_Template *); +const char *ppa_info(struct Scsi_Host *); +int ppa_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); int ppa_abort(Scsi_Cmnd *); -int ppa_reset(Scsi_Cmnd *); -int ppa_biosparam(Disk *, kdev_t, int[]); - -#define PPA { \ - 0, \ - 0, \ - 0, \ - 0, \ - 0, \ - ppa_detect, \ - 0, \ - ppa_info, \ - ppa_command, \ - ppa_queuecommand, \ - ppa_abort, \ - ppa_reset, \ - 0, \ - ppa_biosparam, \ - 0, \ - PPA_INITIATOR, \ - SG_NONE, \ - 1, \ - 0, \ - 0, \ - DISABLE_CLUSTERING \ -} +int ppa_reset(Scsi_Cmnd *, unsigned int); +int ppa_proc_info(char *, char **, off_t, int, int, int); +int ppa_biosparam(Disk *, kdev_t, int *); -#endif /* _PPA_H */ +#define PPA { proc_dir: &proc_scsi_ppa, \ + proc_info: ppa_proc_info, \ + name: "Iomega parport ZIP drive", \ + detect: ppa_detect, \ + queuecommand: ppa_queuecommand, \ + abort: ppa_abort, \ + reset: ppa_reset, \ + bios_param: ppa_biosparam, \ + this_id: -1, \ + sg_tablesize: SG_ALL, \ + cmd_per_lun: 1, \ + use_clustering: ENABLE_CLUSTERING \ +} +#endif /* _PPA_H */ diff --git a/drivers/scsi/qlogicisp.c b/drivers/scsi/qlogicisp.c index 324969f7dddc..368388568138 100644 --- a/drivers/scsi/qlogicisp.c +++ b/drivers/scsi/qlogicisp.c @@ -296,7 +296,12 @@ struct Status_Entry { #define CS_DEVICE_RESET_MSG_FAILED 0x0012 #define CS_ID_MSG_FAILED 0x0013 #define CS_UNEXP_BUS_FREE 0x0014 +/* as per app note #83120-514-06a: */ #define CS_DATA_UNDERRUN 0x0015 +#define CS_INVALID_ENTRY_TYPE 0x001b +#define CS_DEVICE_QUEUE_FULL 0x001c +#define CS_SCSI_PHASE_SKIPPED 0x001d +#define CS_ARS_FAILED 0x001e /* auto Req. Sense failed */ /* status entry state flag definitions */ #define SF_GOT_BUS 0x0100 @@ -992,6 +997,10 @@ static int isp1020_return_status(struct Status_Entry *sts) case CS_DEVICE_RESET_MSG_FAILED: case CS_ID_MSG_FAILED: case CS_UNEXP_BUS_FREE: + case CS_INVALID_ENTRY_TYPE: + case CS_DEVICE_QUEUE_FULL: + case CS_SCSI_PHASE_SKIPPED: + case CS_ARS_FAILED: host_status = DID_ERROR; break; case CS_DATA_UNDERRUN: @@ -1248,7 +1257,8 @@ static int isp1020_init(struct Scsi_Host *sh) if (inw(io_base + PCI_ID_LOW) != PCI_VENDOR_ID_QLOGIC || inw(io_base + PCI_ID_HIGH) != PCI_DEVICE_ID_QLOGIC_ISP1020) { - printk("qlogicisp : can't decode i/o address space\n"); + printk("qlogicisp : can't decode i/o address space at 0x%x\n", + io_base); return 1; } diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index e6874f8cb7ce..c0a8ae894170 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -229,6 +229,7 @@ struct dev_info{ */ static struct dev_info device_list[] = { +{"TEAC","CD-R55S","1.0H", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ {"CHINON","CD-ROM CDS-431","H42", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ {"CHINON","CD-ROM CDS-535","Q14", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ {"DENON","DRD-25X","V", BLIST_NOLUN}, /* Locks up if probed for lun != 0 */ diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index 03bd0d7a0414..7691859575f0 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -164,7 +164,7 @@ static int ioctl_internal_command(Scsi_Device *dev, char * cmd, * interface instead, as this is a more flexible approach to performing * generic SCSI commands on a device. */ -static int ioctl_command(Scsi_Device *dev, void *buffer) +int scsi_ioctl_send_command(Scsi_Device *dev, void *buffer) { char * buf; unsigned char cmd[12]; @@ -369,7 +369,7 @@ int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg) return ioctl_probe(dev->host, arg); case SCSI_IOCTL_SEND_COMMAND: if(!suser() || securelevel > 0) return -EACCES; - return ioctl_command((Scsi_Device *) dev, arg); + return scsi_ioctl_send_command((Scsi_Device *) dev, arg); case SCSI_IOCTL_DOORLOCK: if (!dev->removable || !dev->lockable) return 0; scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL; diff --git a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c index 932610f98fa3..985b3eaaa39c 100644 --- a/drivers/scsi/scsi_syms.c +++ b/drivers/scsi/scsi_syms.c @@ -36,6 +36,7 @@ extern int scsicam_bios_param (Disk * disk, extern void print_command (unsigned char *command); extern void print_sense(const char * devclass, Scsi_Cmnd * SCpnt); +extern int scsi_ioctl_send_command(Scsi_Device *dev, void *buffer); struct symbol_table scsi_symbol_table = { #include @@ -64,6 +65,7 @@ struct symbol_table scsi_symbol_table = { X(scsi_mark_host_reset), X(scsi_mark_bus_reset), X(scsi_device_types), + X(scsi_ioctl_send_command), #if defined(CONFIG_PROC_FS) X(proc_print_scsidevice), #endif diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 6cb8801864e6..706639dab376 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -73,13 +73,20 @@ static int sg_ioctl(struct inode * inode,struct file * file, switch(cmd_in) { case SG_SET_TIMEOUT: - result = verify_area(VERIFY_READ, (const void *)arg, sizeof(long)); + result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int)); if (result) return result; scsi_generics[dev].timeout=get_user((int *) arg); return 0; case SG_GET_TIMEOUT: return scsi_generics[dev].timeout; + case SCSI_IOCTL_SEND_COMMAND: + /* + Allow SCSI_IOCTL_SEND_COMMAND without checking suser() since the + user already has read/write access to the generic device and so + can execute arbitrary SCSI commands. + */ + return scsi_ioctl_send_command(scsi_generics[dev].device, (void *) arg); default: return scsi_ioctl(scsi_generics[dev].device, cmd_in, (void *) arg); } diff --git a/fs/Makefile b/fs/Makefile index 5ac1952a9daa..13897ec1eef6 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -190,6 +190,14 @@ else endif endif +ifeq ($(CONFIG_BINFMT_EM86),y) +BINFMTS += binfmt_em86.o +else + ifeq ($(CONFIG_BINFMT_EM86),m) + M_OBJS += binfmt_em86.o + endif +endif + # binfmt_script is always there BINFMTS += binfmt_script.o diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index e4ebe3651f4c..11c1a91496dd 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -37,9 +37,9 @@ #include -static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs); +static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs); static int load_elf_library(int fd); -extern int dump_fpu (struct pt_regs *, elf_fpregset_t *); +extern int dump_fpu(struct pt_regs *, elf_fpregset_t *); extern void dump_thread(struct pt_regs *, struct user *); /* @@ -47,7 +47,7 @@ extern void dump_thread(struct pt_regs *, struct user *); * don't even try. */ #ifdef USE_ELF_CORE_DUMP -static int elf_core_dump(long signr, struct pt_regs * regs); +static int elf_core_dump(long signr, struct pt_regs *regs); #else #define elf_core_dump NULL #endif @@ -55,11 +55,12 @@ static int elf_core_dump(long signr, struct pt_regs * regs); #define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_EXEC_PAGESIZE-1)) #define ELF_PAGEOFFSET(_v) ((_v) & (ELF_EXEC_PAGESIZE-1)) -static struct linux_binfmt elf_format = { +static struct linux_binfmt elf_format = +{ #ifndef MODULE NULL, NULL, load_elf_binary, load_elf_library, elf_core_dump #else - NULL, &mod_use_count_, load_elf_binary, load_elf_library, elf_core_dump + NULL, &mod_use_count_, load_elf_binary, load_elf_library, elf_core_dump #endif }; @@ -67,7 +68,7 @@ static void set_brk(unsigned long start, unsigned long end) { start = PAGE_ALIGN(start); end = PAGE_ALIGN(end); - if (end <= start) + if (end <= start) return; do_mmap(NULL, start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC, @@ -84,9 +85,9 @@ static void set_brk(unsigned long start, unsigned long end) static void padzero(unsigned long elf_bss) { unsigned long nbyte; - char * fpnt; - - nbyte = elf_bss & (PAGE_SIZE-1); + char *fpnt; + + nbyte = elf_bss & (PAGE_SIZE - 1); if (nbyte) { nbyte = PAGE_SIZE - nbyte; /* FIXME: someone should investigate, why a bad binary @@ -103,10 +104,10 @@ static void padzero(unsigned long elf_bss) } } -unsigned long * create_elf_tables(char *p, int argc, int envc, - struct elfhdr * exec, - unsigned long load_addr, - unsigned long interp_load_addr, int ibcs) +unsigned long *create_elf_tables(char *p, int argc, int envc, + struct elfhdr *exec, + unsigned long load_addr, + unsigned long interp_load_addr, int ibcs) { unsigned long *argv, *envp, *dlinfo; unsigned long *sp; @@ -115,52 +116,53 @@ unsigned long * create_elf_tables(char *p, int argc, int envc, * Force 16 byte alignment here for generality. */ sp = (unsigned long *) (~15UL & (unsigned long) p); - sp -= exec ? DLINFO_ITEMS*2 : 2; + sp -= exec ? DLINFO_ITEMS * 2 : 2; dlinfo = sp; - sp -= envc+1; + sp -= envc + 1; envp = sp; - sp -= argc+1; + sp -= argc + 1; argv = sp; if (!ibcs) { - put_user(envp,--sp); - put_user(argv,--sp); + put_user(envp, --sp); + put_user(argv, --sp); } - #define NEW_AUX_ENT(id, val) \ put_user ((id), dlinfo++); \ put_user ((val), dlinfo++) - if (exec) { /* Put this here for an ELF program interpreter */ - struct elf_phdr * eppnt; - eppnt = (struct elf_phdr *) exec->e_phoff; - - NEW_AUX_ENT (AT_PHDR, load_addr + exec->e_phoff); - NEW_AUX_ENT (AT_PHENT, sizeof (struct elf_phdr)); - NEW_AUX_ENT (AT_PHNUM, exec->e_phnum); - NEW_AUX_ENT (AT_PAGESZ, PAGE_SIZE); - NEW_AUX_ENT (AT_BASE, interp_load_addr); - NEW_AUX_ENT (AT_FLAGS, 0); - NEW_AUX_ENT (AT_ENTRY, (unsigned long) exec->e_entry); - NEW_AUX_ENT (AT_UID, (unsigned long) current->uid); - NEW_AUX_ENT (AT_EUID, (unsigned long) current->euid); - NEW_AUX_ENT (AT_GID, (unsigned long) current->gid); - NEW_AUX_ENT (AT_EGID, (unsigned long) current->egid); + if (exec) { /* Put this here for an ELF program interpreter */ + struct elf_phdr *eppnt; + eppnt = (struct elf_phdr *) exec->e_phoff; + + NEW_AUX_ENT(AT_PHDR, load_addr + exec->e_phoff); + NEW_AUX_ENT(AT_PHENT, sizeof(struct elf_phdr)); + NEW_AUX_ENT(AT_PHNUM, exec->e_phnum); + NEW_AUX_ENT(AT_PAGESZ, PAGE_SIZE); + NEW_AUX_ENT(AT_BASE, interp_load_addr); + NEW_AUX_ENT(AT_FLAGS, 0); + NEW_AUX_ENT(AT_ENTRY, (unsigned long) exec->e_entry); + NEW_AUX_ENT(AT_UID, (unsigned long) current->uid); + NEW_AUX_ENT(AT_EUID, (unsigned long) current->euid); + NEW_AUX_ENT(AT_GID, (unsigned long) current->gid); + NEW_AUX_ENT(AT_EGID, (unsigned long) current->egid); } - NEW_AUX_ENT (AT_NULL, 0); + NEW_AUX_ENT(AT_NULL, 0); #undef NEW_AUX_ENT - put_user((unsigned long)argc,--sp); + put_user((unsigned long) argc, --sp); current->mm->arg_start = (unsigned long) p; - while (argc-->0) { - put_user(p,argv++); - while (get_user(p++)) /* nothing */ ; + while (argc-- > 0) { + put_user(p, argv++); + while (get_user(p++)) /* nothing */ + ; } - put_user(0,argv); + put_user(0, argv); current->mm->arg_end = current->mm->env_start = (unsigned long) p; - while (envc-->0) { - put_user(p,envp++); - while (get_user(p++)) /* nothing */ ; + while (envc-- > 0) { + put_user(p, envp++); + while (get_user(p++)) /* nothing */ + ; } - put_user(0,envp); + put_user(0, envp); current->mm->env_end = (unsigned long) p; return sp; } @@ -171,12 +173,12 @@ unsigned long * create_elf_tables(char *p, int argc, int envc, is only provided so that we can read a.out libraries that have an ELF header */ -static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, - struct inode * interpreter_inode, +static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, + struct inode *interpreter_inode, unsigned long *interp_load_addr) { - struct file * file; - struct elf_phdr *elf_phdata = NULL; + struct file *file; + struct elf_phdr *elf_phdata = NULL; struct elf_phdr *eppnt; unsigned long load_addr; int load_addr_set = 0; @@ -185,108 +187,104 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, unsigned long last_bss, elf_bss; unsigned long error; int i; - + elf_bss = 0; last_bss = 0; error = load_addr = 0; - + /* First of all, some simple consistency checks */ - if ((interp_elf_ex->e_type != ET_EXEC && - interp_elf_ex->e_type != ET_DYN) || - !elf_check_arch(interp_elf_ex->e_machine) || - (!interpreter_inode->i_op || - !interpreter_inode->i_op->default_file_ops->mmap)){ + if ((interp_elf_ex->e_type != ET_EXEC && + interp_elf_ex->e_type != ET_DYN) || + !elf_check_arch(interp_elf_ex->e_machine) || + (!interpreter_inode->i_op || + !interpreter_inode->i_op->default_file_ops->mmap)) { return ~0UL; } - /* Now read in all of the header information */ - + if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE) - return ~0UL; - - elf_phdata = (struct elf_phdr *) - kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, - GFP_KERNEL); + return ~0UL; + + elf_phdata = (struct elf_phdr *) + kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, + GFP_KERNEL); if (!elf_phdata) - return ~0UL; - + return ~0UL; + /* * If the size of this structure has changed, then punt, since * we will be doing the wrong thing. */ - if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) - { - kfree(elf_phdata); - return ~0UL; - } - - retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff, + if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) { + kfree(elf_phdata); + return ~0UL; + } + retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff, (char *) elf_phdata, - sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 1); - + sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 1); + if (retval < 0) { - kfree (elf_phdata); + kfree(elf_phdata); return retval; - } - + } elf_exec_fileno = open_inode(interpreter_inode, O_RDONLY); if (elf_exec_fileno < 0) { - kfree(elf_phdata); - return ~0UL; + kfree(elf_phdata); + return ~0UL; } - file = current->files->fd[elf_exec_fileno]; eppnt = elf_phdata; - for(i=0; ie_phnum; i++, eppnt++) - if (eppnt->p_type == PT_LOAD) { - int elf_type = MAP_PRIVATE | MAP_DENYWRITE; - int elf_prot = 0; - unsigned long vaddr = 0; - unsigned long k; - - if (eppnt->p_flags & PF_R) elf_prot = PROT_READ; - if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; - if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; - if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) { - elf_type |= MAP_FIXED; - vaddr = eppnt->p_vaddr; - } - - error = do_mmap(file, - load_addr + ELF_PAGESTART(vaddr), - eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), - elf_prot, - elf_type, - eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr)); - - if (error > -1024UL) { - /* Real error */ - sys_close(elf_exec_fileno); - kfree(elf_phdata); - return ~0UL; - } - - if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { - load_addr = error; - load_addr_set = 1; - } - - /* - * Find the end of the file mapping for this phdr, and keep - * track of the largest address we see for this. - */ - k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; - if (k > elf_bss) elf_bss = k; - - /* - * Do the same thing for the memory mapping - between - * elf_bss and last_bss is the bss section. - */ - k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; - if (k > last_bss) last_bss = k; - } - + for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) + if (eppnt->p_type == PT_LOAD) { + int elf_type = MAP_PRIVATE | MAP_DENYWRITE; + int elf_prot = 0; + unsigned long vaddr = 0; + unsigned long k; + + if (eppnt->p_flags & PF_R) + elf_prot = PROT_READ; + if (eppnt->p_flags & PF_W) + elf_prot |= PROT_WRITE; + if (eppnt->p_flags & PF_X) + elf_prot |= PROT_EXEC; + if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) { + elf_type |= MAP_FIXED; + vaddr = eppnt->p_vaddr; + } + error = do_mmap(file, + load_addr + ELF_PAGESTART(vaddr), + eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), + elf_prot, + elf_type, + eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr)); + + if (error > -1024UL) { + /* Real error */ + sys_close(elf_exec_fileno); + kfree(elf_phdata); + return ~0UL; + } + if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { + load_addr = error; + load_addr_set = 1; + } + /* + * Find the end of the file mapping for this phdr, and keep + * track of the largest address we see for this. + */ + k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; + if (k > elf_bss) + elf_bss = k; + + /* + * Do the same thing for the memory mapping - between + * elf_bss and last_bss is the bss section. + */ + k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; + if (k > last_bss) + last_bss = k; + } /* Now use mmap to map the library into memory. */ sys_close(elf_exec_fileno); @@ -298,55 +296,56 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, * bss page. */ padzero(elf_bss); - elf_bss = ELF_PAGESTART(elf_bss + ELF_EXEC_PAGESIZE - 1); /* What we have mapped so far */ + elf_bss = ELF_PAGESTART(elf_bss + ELF_EXEC_PAGESIZE - 1); /* What we have mapped so far */ /* Map the last of the bss segment */ if (last_bss > elf_bss) - do_mmap(NULL, elf_bss, last_bss-elf_bss, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_FIXED|MAP_PRIVATE, 0); + do_mmap(NULL, elf_bss, last_bss - elf_bss, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, 0); kfree(elf_phdata); *interp_load_addr = load_addr; return ((unsigned long) interp_elf_ex->e_entry) + load_addr; } -static unsigned long load_aout_interp(struct exec * interp_ex, - struct inode * interpreter_inode) +static unsigned long load_aout_interp(struct exec *interp_ex, + struct inode *interpreter_inode) { - int retval; - unsigned long elf_entry; - - current->mm->brk = interp_ex->a_bss + - (current->mm->end_data = interp_ex->a_data + - (current->mm->end_code = interp_ex->a_text)); - elf_entry = interp_ex->a_entry; - - - if (N_MAGIC(*interp_ex) == OMAGIC) { - do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_FIXED|MAP_PRIVATE, 0); - retval = read_exec(interpreter_inode, 32, (char *) 0, - interp_ex->a_text+interp_ex->a_data, 0); - } else if (N_MAGIC(*interp_ex) == ZMAGIC || N_MAGIC(*interp_ex) == QMAGIC) { - do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_FIXED|MAP_PRIVATE, 0); - retval = read_exec(interpreter_inode, - N_TXTOFF(*interp_ex) , - (char *) N_TXTADDR(*interp_ex), - interp_ex->a_text+interp_ex->a_data, 0); - } else - retval = -1; - - if (retval >= 0) - do_mmap(NULL, ELF_PAGESTART(interp_ex->a_text + interp_ex->a_data + ELF_EXEC_PAGESIZE - 1), - interp_ex->a_bss, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_FIXED|MAP_PRIVATE, 0); - if (retval < 0) return ~0UL; - return elf_entry; + int retval; + unsigned long elf_entry; + + current->mm->brk = interp_ex->a_bss + + (current->mm->end_data = interp_ex->a_data + + (current->mm->end_code = interp_ex->a_text)); + elf_entry = interp_ex->a_entry; + + + if (N_MAGIC(*interp_ex) == OMAGIC) { + do_mmap(NULL, 0, interp_ex->a_text + interp_ex->a_data, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, 0); + retval = read_exec(interpreter_inode, 32, (char *) 0, + interp_ex->a_text + interp_ex->a_data, 0); + } else if (N_MAGIC(*interp_ex) == ZMAGIC || N_MAGIC(*interp_ex) == QMAGIC) { + do_mmap(NULL, 0, interp_ex->a_text + interp_ex->a_data, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, 0); + retval = read_exec(interpreter_inode, + N_TXTOFF(*interp_ex), + (char *) N_TXTADDR(*interp_ex), + interp_ex->a_text + interp_ex->a_data, 0); + } else + retval = -1; + + if (retval >= 0) + do_mmap(NULL, ELF_PAGESTART(interp_ex->a_text + interp_ex->a_data + ELF_EXEC_PAGESIZE - 1), + interp_ex->a_bss, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, 0); + if (retval < 0) + return ~0UL; + return elf_entry; } /* @@ -359,13 +358,12 @@ static unsigned long load_aout_interp(struct exec * interp_ex, #define INTERPRETER_ELF 2 -static inline int -do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) +static inline int do_load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) { struct elfhdr elf_ex; struct elfhdr interp_elf_ex; - struct file * file; - struct exec interp_ex; + struct file *file; + struct exec interp_ex; struct inode *interpreter_inode; unsigned long load_addr; int load_addr_set = 0; @@ -374,125 +372,123 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) int i; int old_fs; int error; - struct elf_phdr * elf_ppnt, *elf_phdata; + struct elf_phdr *elf_ppnt, *elf_phdata; int elf_exec_fileno; unsigned long elf_bss, k, elf_brk; - int retval; - char * elf_interpreter; + int retval, ret_namei = -1; + char *elf_interpreter; unsigned long elf_entry, interp_load_addr = 0; int status; unsigned long start_code, end_code, end_data; unsigned long elf_stack; char passed_fileno[6]; - + ibcs2_interpreter = 0; status = 0; load_addr = 0; - elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ - + elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ + if (elf_ex.e_ident[0] != 0x7f || - strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) { - return -ENOEXEC; + strncmp(&elf_ex.e_ident[1], "ELF", 3) != 0) { + return -ENOEXEC; } - - /* First of all, some simple consistency checks */ if ((elf_ex.e_type != ET_EXEC && - elf_ex.e_type != ET_DYN) || - (! elf_check_arch(elf_ex.e_machine)) || - (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops || - !bprm->inode->i_op->default_file_ops->mmap)){ + elf_ex.e_type != ET_DYN) || + (!elf_check_arch(elf_ex.e_machine)) || + (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops || + !bprm->inode->i_op->default_file_ops->mmap)) { return -ENOEXEC; } - /* Now read in all of the header information */ - - elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize * - elf_ex.e_phnum, GFP_KERNEL); + + elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize * + elf_ex.e_phnum, GFP_KERNEL); if (elf_phdata == NULL) { return -ENOMEM; } - retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata, elf_ex.e_phentsize * elf_ex.e_phnum, 1); if (retval < 0) { - kfree (elf_phdata); + kfree(elf_phdata); return retval; } - elf_ppnt = elf_phdata; - + elf_bss = 0; elf_brk = 0; - + elf_exec_fileno = open_inode(bprm->inode, O_RDONLY); if (elf_exec_fileno < 0) { - kfree (elf_phdata); + kfree(elf_phdata); return elf_exec_fileno; } - file = current->files->fd[elf_exec_fileno]; - + elf_stack = ~0UL; elf_interpreter = NULL; start_code = ~0UL; end_code = 0; end_data = 0; - - for(i=0;i < elf_ex.e_phnum; i++){ + + for (i = 0; i < elf_ex.e_phnum; i++) { if (elf_ppnt->p_type == PT_INTERP) { - if ( elf_interpreter != NULL ) - { - kfree (elf_phdata); + if (elf_interpreter != NULL) { + iput(interpreter_inode); + kfree(elf_phdata); kfree(elf_interpreter); sys_close(elf_exec_fileno); return -EINVAL; } - /* This is the program interpreter used for * shared libraries - for now assume that this * is an a.out format binary */ - - elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz, + + elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz, GFP_KERNEL); if (elf_interpreter == NULL) { - kfree (elf_phdata); + kfree(elf_phdata); sys_close(elf_exec_fileno); return -ENOMEM; } - - retval = read_exec(bprm->inode,elf_ppnt->p_offset, + retval = read_exec(bprm->inode, elf_ppnt->p_offset, elf_interpreter, elf_ppnt->p_filesz, 1); /* If the program interpreter is one of these two, then assume an iBCS2 image. Otherwise assume a native linux image. */ - if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 || - strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) - ibcs2_interpreter = 1; + if (strcmp(elf_interpreter, "/usr/lib/libc.so.1") == 0 || + strcmp(elf_interpreter, "/usr/lib/ld.so.1") == 0) + ibcs2_interpreter = 1; #if 0 printk("Using ELF interpreter %s\n", elf_interpreter); #endif if (retval >= 0) { - old_fs = get_fs(); /* This could probably be optimized */ + old_fs = get_fs(); /* This could probably be optimized */ set_fs(get_ds()); - retval = open_namei(elf_interpreter, 0, 0, - &interpreter_inode, NULL); + retval = ret_namei = open_namei(elf_interpreter, 0, 0, + &interpreter_inode, NULL); set_fs(old_fs); } + if (retval >= 0) + retval = permission(interpreter_inode, MAY_EXEC); + if (retval >= 0) + retval = S_ISREG(interpreter_inode->i_mode) ? 0 : -EACCES; if (retval >= 0) - retval = read_exec(interpreter_inode,0,bprm->buf,128, 1); - + retval = read_exec(interpreter_inode, 0, bprm->buf, 128, 1); + if (retval >= 0) { - interp_ex = *((struct exec *) bprm->buf); /* exec-header */ - interp_elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ - + interp_ex = *((struct exec *) bprm->buf); /* exec-header */ + interp_elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ + } if (retval < 0) { - kfree (elf_phdata); + if (ret_namei >= 0) + iput(interpreter_inode); + kfree(elf_phdata); kfree(elf_interpreter); sys_close(elf_exec_fileno); return retval; @@ -502,56 +498,56 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) } /* Some simple consistency checks for the interpreter */ - if (elf_interpreter){ + if (elf_interpreter) { interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; /* Now figure out which format our binary is */ - if ((N_MAGIC(interp_ex) != OMAGIC) && + if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) && - (N_MAGIC(interp_ex) != QMAGIC)) - interpreter_type = INTERPRETER_ELF; + (N_MAGIC(interp_ex) != QMAGIC)) + interpreter_type = INTERPRETER_ELF; if (interp_elf_ex.e_ident[0] != 0x7f || - strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0) - interpreter_type &= ~INTERPRETER_ELF; - - if (!interpreter_type) - { - kfree(elf_interpreter); - kfree(elf_phdata); - sys_close(elf_exec_fileno); - return -ELIBBAD; - } + strncmp(&interp_elf_ex.e_ident[1], "ELF", 3) != 0) + interpreter_type &= ~INTERPRETER_ELF; + + if (!interpreter_type) { + iput(interpreter_inode); + kfree(elf_interpreter); + kfree(elf_phdata); + sys_close(elf_exec_fileno); + return -ELIBBAD; + } } - /* OK, we are done with that, now set up the arg stuff, and then start this sucker up */ - + if (!bprm->sh_bang) { - char * passed_p; - + char *passed_p; + if (interpreter_type == INTERPRETER_AOUT) { - sprintf(passed_fileno, "%d", elf_exec_fileno); - passed_p = passed_fileno; - - if (elf_interpreter) { - bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2); - bprm->argc++; - } + sprintf(passed_fileno, "%d", elf_exec_fileno); + passed_p = passed_fileno; + + if (elf_interpreter) { + bprm->p = copy_strings(1, &passed_p, bprm->page, bprm->p, 2); + bprm->argc++; + } } if (!bprm->p) { if (elf_interpreter) { - kfree(elf_interpreter); + kfree(elf_interpreter); } - kfree (elf_phdata); + iput(interpreter_inode); + kfree(elf_phdata); sys_close(elf_exec_fileno); return -E2BIG; } } - - if (flush_old_exec(bprm)) + if (flush_old_exec(bprm)) { + iput(interpreter_inode); return -ENOMEM; - + } /* OK, This is the point of no return */ current->mm->end_data = 0; @@ -559,86 +555,93 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) current->mm->start_mmap = ELF_START_MMAP; current->mm->mmap = NULL; elf_entry = (unsigned long) elf_ex.e_entry; - + /* Do this so that we can load the interpreter, if need be. We will change some of these later */ current->mm->rss = 0; bprm->p = setup_arg_pages(bprm->p, bprm); current->mm->start_stack = bprm->p; - + /* Now we do a little grungy work by mmaping the ELF image into the correct location in memory. At this point, we assume that the image should be loaded at fixed address, not at a variable address. */ - + old_fs = get_fs(); set_fs(get_ds()); - for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { + for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { if (elf_ppnt->p_type == PT_LOAD) { int elf_prot = 0; - if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; - if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; - if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; + if (elf_ppnt->p_flags & PF_R) + elf_prot |= PROT_READ; + if (elf_ppnt->p_flags & PF_W) + elf_prot |= PROT_WRITE; + if (elf_ppnt->p_flags & PF_X) + elf_prot |= PROT_EXEC; error = do_mmap(file, ELF_PAGESTART(elf_ppnt->p_vaddr), (elf_ppnt->p_filesz + - ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), + ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), elf_prot, (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE), (elf_ppnt->p_offset - - ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); - + ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); + #ifdef LOW_ELF_STACK - if (ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) + if (ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) elf_stack = ELF_PAGESTART(elf_ppnt->p_vaddr); #endif - - if (!load_addr_set) { - load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; - load_addr_set = 1; + + if (!load_addr_set) { + load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; + load_addr_set = 1; } k = elf_ppnt->p_vaddr; - if (k < start_code) start_code = k; + if (k < start_code) + start_code = k; k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; - if (k > elf_bss) elf_bss = k; + if (k > elf_bss) + elf_bss = k; #if 1 - if ((elf_ppnt->p_flags & PF_X) && end_code < k) + if ((elf_ppnt->p_flags & PF_X) && end_code < k) #else - if ( !(elf_ppnt->p_flags & PF_W) && end_code < k) + if (!(elf_ppnt->p_flags & PF_W) && end_code < k) #endif - end_code = k; - if (end_data < k) end_data = k; + end_code = k; + if (end_data < k) + end_data = k; k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; - if (k > elf_brk) elf_brk = k; + if (k > elf_brk) + elf_brk = k; } } set_fs(old_fs); if (elf_interpreter) { - if (interpreter_type & 1) + if (interpreter_type & 1) elf_entry = load_aout_interp(&interp_ex, interpreter_inode); - else if (interpreter_type & 2) - elf_entry = load_elf_interp(&interp_elf_ex, - interpreter_inode, + else if (interpreter_type & 2) + elf_entry = load_elf_interp(&interp_elf_ex, + interpreter_inode, &interp_load_addr); iput(interpreter_inode); kfree(elf_interpreter); - - if (elf_entry == ~0UL) { + + if (elf_entry == ~0UL) { printk("Unable to load interpreter\n"); kfree(elf_phdata); send_sig(SIGSEGV, current, 0); return 0; } } - kfree(elf_phdata); - - if (interpreter_type != INTERPRETER_AOUT) sys_close(elf_exec_fileno); + + if (interpreter_type != INTERPRETER_AOUT) + sys_close(elf_exec_fileno); current->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX); if (current->exec_domain && current->exec_domain->use_count) @@ -662,16 +665,16 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) current->suid = current->euid = current->fsuid = bprm->e_uid; current->sgid = current->egid = current->fsgid = bprm->e_gid; current->flags &= ~PF_FORKNOEXEC; - bprm->p = (unsigned long) - create_elf_tables((char *)bprm->p, - bprm->argc, - bprm->envc, - (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL), - load_addr, - interp_load_addr, - (interpreter_type == INTERPRETER_AOUT ? 0 : 1)); + bprm->p = (unsigned long) + create_elf_tables((char *) bprm->p, + bprm->argc, + bprm->envc, + (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL), + load_addr, + interp_load_addr, + (interpreter_type == INTERPRETER_AOUT ? 0 : 1)); if (interpreter_type == INTERPRETER_AOUT) - current->mm->arg_start += strlen(passed_fileno) + 1; + current->mm->arg_start += strlen(passed_fileno) + 1; current->mm->start_brk = current->mm->brk = elf_brk; current->mm->end_code = end_code; current->mm->start_code = start_code; @@ -685,16 +688,15 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) padzero(elf_bss); #if 0 - printk("(start_brk) %x\n" , current->mm->start_brk); - printk("(end_code) %x\n" , current->mm->end_code); - printk("(start_code) %x\n" , current->mm->start_code); - printk("(end_data) %x\n" , current->mm->end_data); - printk("(start_stack) %x\n" , current->mm->start_stack); - printk("(brk) %x\n" , current->mm->brk); + printk("(start_brk) %x\n", current->mm->start_brk); + printk("(end_code) %x\n", current->mm->end_code); + printk("(start_code) %x\n", current->mm->start_code); + printk("(end_data) %x\n", current->mm->end_data); + printk("(start_stack) %x\n", current->mm->start_stack); + printk("(brk) %x\n", current->mm->brk); #endif - if ( current->personality == PER_SVR4 ) - { + if (current->personality == PER_SVR4) { /* Why this, you ask??? Well SVr4 maps page 0 as read-only, and some applications "depend" upon this behavior. Since we do not have the power to recompile these, we @@ -702,7 +704,6 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, 0); } - #ifdef ELF_PLAT_INIT /* * The ABI may specify that certain registers be set up in special @@ -720,8 +721,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) return 0; } -static int -load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) +static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) { int retval; @@ -734,24 +734,24 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) /* This is really simpleminded and specialized - we are loading an a.out library that is given an ELF header. */ -static inline int -do_load_elf_library(int fd){ - struct file * file; +static inline int do_load_elf_library(int fd) +{ + struct file *file; struct elfhdr elf_ex; - struct elf_phdr *elf_phdata = NULL; - struct inode * inode; + struct elf_phdr *elf_phdata = NULL; + struct inode *inode; unsigned long len; int elf_bss; int retval; unsigned long bss; int error; - int i,j, k; + int i, j, k; len = 0; file = current->files->fd[fd]; inode = file->f_inode; elf_bss = 0; - + if (!file || !file->f_op) return -EACCES; @@ -769,39 +769,40 @@ do_load_elf_library(int fd){ return -ENOEXEC; if (elf_ex.e_ident[0] != 0x7f || - strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) + strncmp(&elf_ex.e_ident[1], "ELF", 3) != 0) return -ENOEXEC; /* First of all, some simple consistency checks */ if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 || - !elf_check_arch(elf_ex.e_machine) || - (!inode->i_op || !inode->i_op->default_file_ops->mmap)) + !elf_check_arch(elf_ex.e_machine) || + (!inode->i_op || !inode->i_op->default_file_ops->mmap)) return -ENOEXEC; - + /* Now read in all of the header information */ - + if (sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE) - return -ENOEXEC; - - elf_phdata = (struct elf_phdr *) - kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL); + return -ENOEXEC; + + elf_phdata = (struct elf_phdr *) + kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL); if (elf_phdata == NULL) return -ENOMEM; - + retval = read_exec(inode, elf_ex.e_phoff, (char *) elf_phdata, sizeof(struct elf_phdr) * elf_ex.e_phnum, 1); - + j = 0; - for(i=0; ip_type == PT_LOAD) j++; - - if (j != 1) { + for (i = 0; i < elf_ex.e_phnum; i++) + if ((elf_phdata + i)->p_type == PT_LOAD) + j++; + + if (j != 1) { kfree(elf_phdata); return -ENOEXEC; } - - while(elf_phdata->p_type != PT_LOAD) elf_phdata++; - + while (elf_phdata->p_type != PT_LOAD) + elf_phdata++; + /* Now use mmap to map the library into memory. */ error = do_mmap(file, ELF_PAGESTART(elf_phdata->p_vaddr), @@ -813,21 +814,21 @@ do_load_elf_library(int fd){ ELF_PAGEOFFSET(elf_phdata->p_vaddr))); k = elf_phdata->p_vaddr + elf_phdata->p_filesz; - if (k > elf_bss) elf_bss = k; - + if (k > elf_bss) + elf_bss = k; + if (error != ELF_PAGESTART(elf_phdata->p_vaddr)) { kfree(elf_phdata); return error; } - padzero(elf_bss); - len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr+ ELF_EXEC_PAGESIZE - 1); + len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr + ELF_EXEC_PAGESIZE - 1); bss = elf_phdata->p_memsz + elf_phdata->p_vaddr; if (bss > len) - do_mmap(NULL, len, bss-len, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_FIXED|MAP_PRIVATE, 0); + do_mmap(NULL, len, bss - len, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, 0); kfree(elf_phdata); return 0; } @@ -882,12 +883,12 @@ static int dump_seek(struct file *file, off_t off) */ static inline int maydump(struct vm_area_struct *vma) { - if (!(vma->vm_flags & (VM_READ|VM_EXEC))) + if (!(vma->vm_flags & (VM_READ | VM_EXEC))) return 0; #if 1 - if (vma->vm_flags & (VM_WRITE|VM_GROWSUP|VM_GROWSDOWN)) + if (vma->vm_flags & (VM_WRITE | VM_GROWSUP | VM_GROWSDOWN)) return 1; - if (vma->vm_flags & (VM_READ|VM_EXEC|VM_EXECUTABLE|VM_SHARED)) + if (vma->vm_flags & (VM_READ | VM_EXEC | VM_EXECUTABLE | VM_SHARED)) return 0; #endif return 1; @@ -896,8 +897,7 @@ static inline int maydump(struct vm_area_struct *vma) #define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) /* An ELF note in memory */ -struct memelfnote -{ +struct memelfnote { const char *name; int type; unsigned int datasz; @@ -907,32 +907,33 @@ struct memelfnote static int notesize(struct memelfnote *en) { int sz; - + sz = sizeof(struct elf_note); sz += roundup(strlen(en->name), 4); sz += roundup(en->datasz, 4); - + return sz; } /* #define DEBUG */ #ifdef DEBUG -static void dump_regs(const char *str, elf_greg_t *r) +static void dump_regs(const char *str, elf_greg_t * r) { int i; - static const char *regs[] = { "ebx", "ecx", "edx", "esi", "edi", "ebp", - "eax", "ds", "es", "fs", "gs", - "orig_eax", "eip", "cs", - "efl", "uesp", "ss"}; + static const char *regs[] = + {"ebx", "ecx", "edx", "esi", "edi", "ebp", + "eax", "ds", "es", "fs", "gs", + "orig_eax", "eip", "cs", + "efl", "uesp", "ss"}; printk("Registers: %s\n", str); - for(i = 0; i < ELF_NGREG; i++) - { + for (i = 0; i < ELF_NGREG; i++) { unsigned long val = r[i]; printk(" %-2d %-5s=%08lx %lu\n", i, regs[i], val, val); } } + #endif #define DUMP_WRITE(addr, nr) \ @@ -951,10 +952,10 @@ static int writenote(struct memelfnote *men, struct file *file) DUMP_WRITE(&en, sizeof(en)); DUMP_WRITE(men->name, en.n_namesz); /* XXX - cast from long long to long to avoid need for libgcc.a */ - DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */ + DUMP_SEEK(roundup((unsigned long) file->f_pos, 4)); /* XXX */ DUMP_WRITE(men->data, men->datasz); - DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */ - + DUMP_SEEK(roundup((unsigned long) file->f_pos, 4)); /* XXX */ + return 1; } #undef DUMP_WRITE @@ -973,13 +974,13 @@ static int writenote(struct memelfnote *men, struct file *file) * and then they are actually written out. If we run out of core limit * we just truncate. */ -static int elf_core_dump(long signr, struct pt_regs * regs) +static int elf_core_dump(long signr, struct pt_regs *regs) { int has_dumped = 0; struct file file; struct inode *inode; unsigned short fs; - char corefile[6+sizeof(current->comm)]; + char corefile[6 + sizeof(current->comm)]; int segs; int i; size_t size; @@ -990,9 +991,9 @@ static int elf_core_dump(long signr, struct pt_regs * regs) int numnote = 4; struct memelfnote notes[4]; struct elf_prstatus prstatus; /* NT_PRSTATUS */ - elf_fpregset_t fpu; /* NT_PRFPREG */ + elf_fpregset_t fpu; /* NT_PRFPREG */ struct elf_prpsinfo psinfo; /* NT_PRPSINFO */ - + if (!current->dumpable || limit < PAGE_SIZE || current->mm->count != 1) return 0; current->dumpable = 0; @@ -1004,17 +1005,15 @@ static int elf_core_dump(long signr, struct pt_regs * regs) /* Count what's needed to dump, up to the limit of coredump size */ segs = 0; size = 0; - for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { - if (maydump(vma)) - { - int sz = vma->vm_end-vma->vm_start; - - if (size+sz >= limit) + for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { + if (maydump(vma)) { + int sz = vma->vm_end - vma->vm_start; + + if (size + sz >= limit) break; else size += sz; } - segs++; } #ifdef DEBUG @@ -1026,8 +1025,8 @@ static int elf_core_dump(long signr, struct pt_regs * regs) elf.e_ident[EI_CLASS] = ELF_CLASS; elf.e_ident[EI_DATA] = ELF_DATA; elf.e_ident[EI_VERSION] = EV_CURRENT; - memset(elf.e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); - + memset(elf.e_ident + EI_PAD, 0, EI_NIDENT - EI_PAD); + elf.e_type = ET_CORE; elf.e_machine = ELF_ARCH; elf.e_version = EV_CURRENT; @@ -1037,20 +1036,20 @@ static int elf_core_dump(long signr, struct pt_regs * regs) elf.e_flags = 0; elf.e_ehsize = sizeof(elf); elf.e_phentsize = sizeof(struct elf_phdr); - elf.e_phnum = segs+1; /* Include notes */ + elf.e_phnum = segs + 1; /* Include notes */ elf.e_shentsize = 0; elf.e_shnum = 0; elf.e_shstrndx = 0; - + fs = get_fs(); set_fs(KERNEL_DS); - memcpy(corefile,"core.",5); + memcpy(corefile, "core.", 5); #if 0 - memcpy(corefile+5,current->comm,sizeof(current->comm)); + memcpy(corefile + 5, current->comm, sizeof(current->comm)); #else corefile[4] = '\0'; #endif - if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) { + if (open_namei(corefile, O_CREAT | 2 | O_TRUNC, 0600, &inode, NULL)) { inode = NULL; goto end_coredump; } @@ -1066,7 +1065,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs) file.f_reada = 0; file.f_op = inode->i_op->default_file_ops; if (file.f_op->open) - if (file.f_op->open(inode,&file)) + if (file.f_op->open(inode, &file)) goto end_coredump; if (!file.f_op->write) goto close_coredump; @@ -1074,8 +1073,8 @@ static int elf_core_dump(long signr, struct pt_regs * regs) current->flags |= PF_DUMPCORE; DUMP_WRITE(&elf, sizeof(elf)); - offset += sizeof(elf); /* Elf header */ - offset += (segs+1) * sizeof(struct elf_phdr); /* Program headers */ + offset += sizeof(elf); /* Elf header */ + offset += (segs + 1) * sizeof(struct elf_phdr); /* Program headers */ /* * Set up the notes in similar form to SVR4 core dumps made @@ -1111,18 +1110,16 @@ static int elf_core_dump(long signr, struct pt_regs * regs) #ifdef ELF_CORE_COPY_REGS ELF_CORE_COPY_REGS(prstatus.pr_reg, regs) #else - if (sizeof(elf_gregset_t) != sizeof(struct pt_regs)) - { + if (sizeof(elf_gregset_t) != sizeof(struct pt_regs)) { printk("sizeof(elf_gregset_t) (%d) != sizeof(struct pt_regs) (%d)\n", - sizeof(elf_gregset_t), sizeof(struct pt_regs)); - } - else - *(struct pt_regs *)&prstatus.pr_reg = *regs; + sizeof(elf_gregset_t), sizeof(struct pt_regs)); + } else + *(struct pt_regs *) &prstatus.pr_reg = *regs; #endif - + #ifdef DEBUG - dump_regs("Passed in regs", (elf_greg_t *)regs); - dump_regs("prstatus regs", (elf_greg_t *)&prstatus.pr_reg); + dump_regs("Passed in regs", (elf_greg_t *) regs); + dump_regs("prstatus regs", (elf_greg_t *) & prstatus.pr_reg); #endif notes[1].name = "CORE"; @@ -1132,7 +1129,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs) psinfo.pr_state = current->state; psinfo.pr_sname = (current->state < 0 || current->state > 5) ? '.' : "RSDZTD"[current->state]; psinfo.pr_zomb = psinfo.pr_sname == 'Z'; - psinfo.pr_nice = current->priority-15; + psinfo.pr_nice = current->priority - 15; psinfo.pr_flag = current->flags; psinfo.pr_uid = current->uid; psinfo.pr_gid = current->gid; @@ -1140,12 +1137,12 @@ static int elf_core_dump(long signr, struct pt_regs * regs) int i, len; set_fs(fs); - + len = current->mm->arg_end - current->mm->arg_start; - len = (len >= ELF_PRARGSZ-1) ? ELF_PRARGSZ-1 : len; + len = (len >= ELF_PRARGSZ - 1) ? ELF_PRARGSZ - 1 : len; memcpy_fromfs(&psinfo.pr_psargs, - (const char *)current->mm->arg_start, len); - for(i = 0; i < len; i++) + (const char *) current->mm->arg_start, len); + for (i = 0; i < len; i++) if (psinfo.pr_psargs[i] == 0) psinfo.pr_psargs[i] = ' '; psinfo.pr_psargs[len] = 0; @@ -1158,29 +1155,26 @@ static int elf_core_dump(long signr, struct pt_regs * regs) notes[2].type = NT_TASKSTRUCT; notes[2].datasz = sizeof(*current); notes[2].data = current; - + /* Try to dump the fpu. */ - prstatus.pr_fpvalid = dump_fpu (regs, &fpu); - if (!prstatus.pr_fpvalid) - { + prstatus.pr_fpvalid = dump_fpu(regs, &fpu); + if (!prstatus.pr_fpvalid) { numnote--; - } - else - { + } else { notes[3].name = "CORE"; notes[3].type = NT_PRFPREG; notes[3].datasz = sizeof(fpu); notes[3].data = &fpu; } - + /* Write notes phdr entry */ { struct elf_phdr phdr; int sz = 0; - for(i = 0; i < numnote; i++) + for (i = 0; i < numnote; i++) sz += notesize(¬es[i]); - + phdr.p_type = PT_NOTE; phdr.p_offset = offset; phdr.p_vaddr = 0; @@ -1196,17 +1190,17 @@ static int elf_core_dump(long signr, struct pt_regs * regs) /* Page-align dumped data */ dataoff = offset = roundup(offset, PAGE_SIZE); - + /* Write program headers for segments dump */ - for(vma = current->mm->mmap, i = 0; - i < segs && vma != NULL; vma = vma->vm_next) { + for (vma = current->mm->mmap, i = 0; + i < segs && vma != NULL; vma = vma->vm_next) { struct elf_phdr phdr; size_t sz; i++; sz = vma->vm_end - vma->vm_start; - + phdr.p_type = PT_LOAD; phdr.p_offset = offset; phdr.p_vaddr = vma->vm_start; @@ -1215,34 +1209,36 @@ static int elf_core_dump(long signr, struct pt_regs * regs) phdr.p_memsz = sz; offset += phdr.p_filesz; phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; - if (vma->vm_flags & VM_WRITE) phdr.p_flags |= PF_W; - if (vma->vm_flags & VM_EXEC) phdr.p_flags |= PF_X; + if (vma->vm_flags & VM_WRITE) + phdr.p_flags |= PF_W; + if (vma->vm_flags & VM_EXEC) + phdr.p_flags |= PF_X; phdr.p_align = PAGE_SIZE; DUMP_WRITE(&phdr, sizeof(phdr)); } - for(i = 0; i < numnote; i++) + for (i = 0; i < numnote; i++) if (!writenote(¬es[i], &file)) goto close_coredump; - + set_fs(fs); DUMP_SEEK(dataoff); - - for(i = 0, vma = current->mm->mmap; - i < segs && vma != NULL; - vma = vma->vm_next) { + + for (i = 0, vma = current->mm->mmap; + i < segs && vma != NULL; + vma = vma->vm_next) { unsigned long addr = vma->vm_start; unsigned long len = vma->vm_end - vma->vm_start; - + i++; if (!maydump(vma)) continue; #ifdef DEBUG printk("elf_core_dump: writing %08lx %lx\n", addr, len); #endif - DUMP_WRITE((void *)addr, len); + DUMP_WRITE((void *) addr, len); } if ((off_t) file.f_pos != offset) { @@ -1250,12 +1246,11 @@ static int elf_core_dump(long signr, struct pt_regs * regs) printk("elf_core_dump: file.f_pos (%ld) != offset (%ld)\n", (off_t) file.f_pos, offset); } - - close_coredump: + close_coredump: if (file.f_op->release) - file.f_op->release(inode,&file); + file.f_op->release(inode, &file); - end_coredump: + end_coredump: set_fs(fs); iput(inode); #ifndef CONFIG_BINFMT_ELF @@ -1263,16 +1258,16 @@ static int elf_core_dump(long signr, struct pt_regs * regs) #endif return has_dumped; } -#endif /* USE_ELF_CORE_DUMP */ +#endif /* USE_ELF_CORE_DUMP */ -int init_elf_binfmt(void) +int init_elf_binfmt(void) { return register_binfmt(&elf_format); } #ifdef MODULE -int init_module(void) +int init_module(void) { /* Install the COFF, ELF and XOUT loaders. * N.B. We *rely* on the table being the right size with the @@ -1282,9 +1277,10 @@ int init_module(void) } -void cleanup_module( void) +void cleanup_module(void) { /* Remove the COFF and ELF loaders. */ unregister_binfmt(&elf_format); } + #endif diff --git a/fs/binfmt_em86.c b/fs/binfmt_em86.c new file mode 100644 index 000000000000..ca992261096f --- /dev/null +++ b/fs/binfmt_em86.c @@ -0,0 +1,131 @@ +/* + * linux/fs/binfmt_em86.c + * + * Based on linux/fs/binfmt_script.c + * Copyright (C) 1996 Martin von Löwis + * original #!-checking implemented by tytso. + * + * em86 changes Copyright (C) 1997 Jim Paradis + */ + +#include +#include +#include +#include +#include +#include + +#define EM86_INTERP "/usr/bin/em86" +#define EM86_I_NAME "em86" + +static int do_load_em86(struct linux_binprm *bprm,struct pt_regs *regs) +{ + char *cp, *interp, *i_name, *i_arg; + int retval; + struct elfhdr elf_ex; + uid_t x86_uid; + gid_t x86_gid; + + /* Make sure this is a Linux/Intel ELF executable... */ + elf_ex = *((struct elfhdr *)bprm->buf); + + if (elf_ex.e_ident[0] != 0x7f || + strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) { + return -ENOEXEC; + } + + + /* First of all, some simple consistency checks */ + if ((elf_ex.e_type != ET_EXEC && + elf_ex.e_type != ET_DYN) || + (!((elf_ex.e_machine == EM_386) || (elf_ex.e_machine == EM_486))) || + (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops || + !bprm->inode->i_op->default_file_ops->mmap)){ + return -ENOEXEC; + } + + bprm->sh_bang++; /* Well, the bang-shell is implicit... */ + iput(bprm->inode); + bprm->dont_iput = 1; + + /* Unlike in the script case, we don't have to do any hairy + * parsing to find our interpreter... it's hardcoded! + */ + interp = EM86_INTERP; + i_name = EM86_I_NAME; + i_arg = NULL; /* We reserve the right to add an arg later */ + + /* + * Splice in (1) the interpreter's name for argv[0] + * (2) (optional) argument to interpreter + * (3) filename of emulated file (replace argv[0]) + * + * This is done in reverse order, because of how the + * user environment and arguments are stored. + */ + remove_arg_zero(bprm); + bprm->p = copy_strings(1, &bprm->filename, bprm->page, bprm->p, 2); + bprm->argc++; + if (i_arg) { + bprm->p = copy_strings(1, &i_arg, bprm->page, bprm->p, 2); + bprm->argc++; + } + bprm->p = copy_strings(1, &i_name, bprm->page, bprm->p, 2); + bprm->argc++; + if (!bprm->p) + return -E2BIG; + /* + * OK, now restart the process with the interpreter's inode. + * Note that we use open_namei() as the name is now in kernel + * space, and we don't need to copy it. + */ + retval = open_namei(interp, 0, 0, &bprm->inode, NULL); + if (retval) + return retval; + bprm->dont_iput=0; + + /* Remember the uid/gid that was set by this executable */ + x86_uid = bprm->e_uid; + x86_gid = bprm->e_gid; + retval=prepare_binprm(bprm); + if(retval<0) + return retval; + + /* ...so that we may propagate them to em86 */ + bprm->e_uid = x86_uid; + bprm->e_gid = x86_gid; + current->personality = PER_LINUX_EM86; + return search_binary_handler(bprm,regs); +} + +static int load_em86(struct linux_binprm *bprm,struct pt_regs *regs) +{ + int retval; + MOD_INC_USE_COUNT; + retval = do_load_em86(bprm,regs); + MOD_DEC_USE_COUNT; + return retval; +} + +struct linux_binfmt em86_format = { +#ifndef MODULE + NULL, 0, load_em86, NULL, NULL +#else + NULL, &mod_use_count_, load_em86, NULL, NULL +#endif +}; + +int init_em86_binfmt(void) { + return register_binfmt(&em86_format); +} + +#ifdef MODULE +int init_module(void) +{ + return init_em86_binfmt(); +} + +void cleanup_module( void) { + unregister_binfmt(&em86_format); +} +#endif diff --git a/fs/buffer.c b/fs/buffer.c index ed101ec0241c..7d1aec49fde0 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -1249,6 +1249,8 @@ void unlock_buffer(struct buffer_head * bh) clear_bit(BH_Lock, &bh->b_state); wake_up(&bh->b_wait); + if (waitqueue_active(&buffer_wait)) + wake_up(&buffer_wait); if (!test_bit(BH_FreeOnIO, &bh->b_state)) return; diff --git a/fs/dquot.c b/fs/dquot.c index 0190764ba769..4ad2789037c1 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -1080,6 +1080,9 @@ asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr) return(-EINVAL); } + if (id & ~0xFFFF) + return(-EINVAL); + flags |= QUOTA_SYSCALL; if (has_quota_enabled(dev, type)) return(set_dqblk(dev, id, type, flags, (struct dqblk *) addr)); diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index a1b70b7564b7..6dd924d33b77 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -573,6 +573,7 @@ static int empty_dir (struct inode * inode) ext2_warning (inode->i_sb, "empty_dir", "bad directory (dir #%lu) - no `.' or `..'", inode->i_ino); + brelse (bh); return 1; } offset = de->rec_len + de1->rec_len; diff --git a/fs/fat/dir.c b/fs/fat/dir.c index ea135700cd2f..38ce8af2c146 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c @@ -112,18 +112,6 @@ uni16_to_x8(unsigned char *ascii, unsigned char *uni, int uni_xlate, } -static void dump_de(struct msdos_dir_entry *de) -{ - int i; - unsigned char *p = (unsigned char *) de; - printk("["); - - for (i = 0; i < 32; i++, p++) { - printk("%02x ", *p); - } - printk("]\n"); -} - int fat_readdirx( struct inode *inode, struct file *filp, @@ -172,9 +160,6 @@ int fat_readdirx( is_long = 0; ino = fat_get_entry(inode,&filp->f_pos,&bh,&de); while (ino > -1) { -#if 0 - dump_de(de); -#endif /* Check for long filename entry */ if (MSDOS_SB(sb)->options.isvfat && (de->name[0] == (__s8) DELETED_FLAG)) { is_long = 0; diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 1d62dcf53ac6..d7e2fc621c8b 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -629,26 +629,28 @@ int isofs_bmap(struct inode * inode,int block) inode->i_ino, nextino, firstext, size); #endif i = 0; - while(b_off >= offset + size) { - offset += size; - - if(nextino == 0) return 0; - ino = iget(inode->i_sb, nextino); - if(!ino) return 0; - firstext = ino->u.isofs_i.i_first_extent; - size = ino->u.isofs_i.i_section_size; + if (nextino) { + while(b_off >= offset + size) { + offset += size; + + if(nextino == 0) return 0; + ino = iget(inode->i_sb, nextino); + if(!ino) return 0; + firstext = ino->u.isofs_i.i_first_extent; + size = ino->u.isofs_i.i_section_size; #ifdef DEBUG - printk("read inode: inode=%lu ino=%lu nextino=%lu firstext=%u size=%lu\n", - inode->i_ino, nextino, ino->u.isofs_i.i_next_section_ino, firstext, size); + printk("read inode: inode=%lu ino=%lu nextino=%lu firstext=%u size=%lu\n", + inode->i_ino, nextino, ino->u.isofs_i.i_next_section_ino, firstext, size); #endif - nextino = ino->u.isofs_i.i_next_section_ino; - iput(ino); + nextino = ino->u.isofs_i.i_next_section_ino; + iput(ino); - if(++i > 100) { - printk("isofs_bmap: More than 100 file sections ?!?, aborting...\n"); - printk("isofs_bmap: ino=%lu block=%d firstext=%u size=%u nextino=%lu\n", - inode->i_ino, block, firstext, (unsigned)size, nextino); - return 0; + if(++i > 100) { + printk("isofs_bmap: More than 100 file sections ?!?, aborting...\n"); + printk("isofs_bmap: ino=%lu block=%d firstext=%u size=%u nextino=%lu\n", + inode->i_ino, block, firstext, (unsigned)size, nextino); + return 0; + } } } #ifdef DEBUG diff --git a/fs/select.c b/fs/select.c index 4a52f1b42572..479f08b0832c 100644 --- a/fs/select.c +++ b/fs/select.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -56,6 +57,34 @@ static void free_wait(select_table * p) } } +/* + * File handle locking + */ + +static void lock_fd_bits(int n, int x) +{ + int i; + for(i=0;i<__NFDBITS;i++) + { + if(x&(1<files->fd[n+i]; + fput(f, f->f_inode); + } + } +} + /* * The check function checks the ready status of a file using the vfs layer. * @@ -83,7 +112,7 @@ static int check(int flag, select_table * wait, struct file * file) } static int do_select(int n, fd_set *in, fd_set *out, fd_set *ex, - fd_set *res_in, fd_set *res_out, fd_set *res_ex) + fd_set *res_in, fd_set *res_out, fd_set *res_ex, fd_set *locked) { int count; select_table wait_table, *wait; @@ -91,7 +120,7 @@ static int do_select(int n, fd_set *in, fd_set *out, fd_set *ex, unsigned long set; int i,j; int max = -1; - + int threaded = 0; j = 0; for (;;) { i = j * __NFDBITS; @@ -113,8 +142,34 @@ static int do_select(int n, fd_set *in, fd_set *out, fd_set *ex, } end_check: n = max + 1; + + /* Now we _must_ lock the handles before we get the page otherwise + they may get closed on us during the kmalloc causing explosions.. */ + + if(current->files->count>1) + { + + /* + * Only for the threaded cases must we do work. + */ + j = 0; + for (;;) { + i = j * __NFDBITS; + if (i >= n) + break; + lock_fd_bits(i,in->fds_bits[j]); + lock_fd_bits(i,out->fds_bits[j]); + lock_fd_bits(i,ex->fds_bits[j]); + j++; + } + threaded=1; + } + if(!(entry = (struct select_table_entry*) __get_free_page(GFP_KERNEL))) - return -ENOMEM; + { + count = -ENOMEM; + goto bale; + } count = 0; wait_table.nr = 0; wait_table.entry = entry; @@ -149,6 +204,22 @@ repeat: free_wait(&wait_table); free_page((unsigned long) entry); current->state = TASK_RUNNING; +bale: + + if(threaded) + { + /* Unlock handles now */ + j = 0; + for (;;) { + i = j * __NFDBITS; + if (i >= n) + break; + unlock_fd_bits(i,in->fds_bits[j]); + unlock_fd_bits(i,out->fds_bits[j]); + unlock_fd_bits(i,ex->fds_bits[j]); + j++; + } + } return count; } @@ -243,6 +314,7 @@ asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct limited_fd_set res_in, in; limited_fd_set res_out, out; limited_fd_set res_ex, ex; + limited_fd_set locked; unsigned long timeout; error = -EINVAL; @@ -273,7 +345,8 @@ asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct (fd_set *) &ex, (fd_set *) &res_in, (fd_set *) &res_out, - (fd_set *) &res_ex); + (fd_set *) &res_ex, + (fd_set *) &locked); timeout = current->timeout - jiffies - 1; current->timeout = 0; if ((long) timeout < 0) diff --git a/fs/super.c b/fs/super.c index 689963337b9b..f9cdecb9e5ed 100644 --- a/fs/super.c +++ b/fs/super.c @@ -972,12 +972,21 @@ static void do_mount_root(void) #ifdef CONFIG_BLK_DEV_FD if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) { + extern int rd_doload; floppy_eject(); #ifndef CONFIG_BLK_DEV_RAM printk(KERN_NOTICE "(Warning, this kernel has no ramdisk support)\n"); #endif - printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n"); - wait_for_keypress(); +#ifdef CONFIG_BLK_DEV_INITRD + /* rd_doload is 2 for a dual initrd/ramload setup */ + if(rd_doload==2) + rd_load_secondary(); + else +#endif + { + printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n"); + wait_for_keypress(); + } } #endif diff --git a/include/asm-alpha/a.out.h b/include/asm-alpha/a.out.h index f1965d5cae42..bcda70a36539 100644 --- a/include/asm-alpha/a.out.h +++ b/include/asm-alpha/a.out.h @@ -90,7 +90,8 @@ struct exec #ifdef __KERNEL__ -#define STACK_TOP (0x00120000000UL) +#define STACK_TOP ((current->personality & ADDR_MAX_32BIT) ? 0x100000000UL : \ + ((current->personality&ADDR_MAX_31BIT) ? 0x80000000UL : 0x00120000000UL)) #endif diff --git a/include/asm-alpha/apecs.h b/include/asm-alpha/apecs.h index 0f38c8aac920..36ac35922d84 100644 --- a/include/asm-alpha/apecs.h +++ b/include/asm-alpha/apecs.h @@ -31,7 +31,7 @@ BIOS ROMs. So we must put the windows high enough to avoid these areas. We put window 1 at BUS 64Mb for 64Mb, mapping physical 0 to 64Mb-1, - and window 2 at BUS 512Mb for 512Mb, mapping physical 0 to 512Mb-1. + and window 2 at BUS 1Gb for 1Gb, mapping physical 0 to 1Gb-1. Yes, this does map 0 to 64Mb-1 twice, but only window 1 will actually be used for that range (via virt_to_bus()). @@ -53,12 +53,14 @@ DMAable memory; they count on being able to DMA to any memory they get from kmalloc()/get_free_pages(). They will also use window 1 for any physical memory accesses below 64Mb; the rest will be handled by - window 2, maxing out at 512Mb of memory. I trust this is enough... :-) + window 2, maxing out at 1Gb of memory. I trust this is enough... :-) - Finally, the reason we make window 2 start at 512Mb for 512Mb, is so that - we can allocate PCI bus devices' memory starting at 1Gb and up, to ensure - that no conflicts occur and bookkeeping is simplified (ie we don't - try to fill the gap between the two windows, we just go above the top). + We hope that the area before the first window is large enough so that + there will be no overlap at the top end (64Mb). We *must* locate the + PCI cards' memory just below window 1, so that there's still the + possibility of being able to access it via SPARSE space. This is + important for cards such as the Matrox Millennium, whose Xserver + wants to access memory-mapped registers in byte and short lengths. Note that the XL is treated differently from the AVANTI, even though for most other things they are identical. It didn't seem reasonable to @@ -69,14 +71,24 @@ #define APECS_XL_DMA_WIN1_BASE (64*1024*1024) #define APECS_XL_DMA_WIN1_SIZE (64*1024*1024) #define APECS_XL_DMA_WIN1_SIZE_PARANOID (48*1024*1024) -#define APECS_XL_DMA_WIN2_BASE (512*1024*1024) -#define APECS_XL_DMA_WIN2_SIZE (512*1024*1024) +#define APECS_XL_DMA_WIN2_BASE (1024*1024*1024) +#define APECS_XL_DMA_WIN2_SIZE (1024*1024*1024) #else /* CONFIG_ALPHA_XL */ /* these are for normal APECS family machines, AVANTI/MUSTANG/EB64/PC64 */ +#ifdef CONFIG_ALPHA_SRM_SETUP +/* if we are using the SRM PCI setup, we'll need to use variables instead */ +#define APECS_DMA_WIN_BASE_DEFAULT (1024*1024*1024) +#define APECS_DMA_WIN_SIZE_DEFAULT (1024*1024*1024) + +extern unsigned int APECS_DMA_WIN_BASE; +extern unsigned int APECS_DMA_WIN_SIZE; + +#else /* SRM_SETUP */ #define APECS_DMA_WIN_BASE (1024*1024*1024) #define APECS_DMA_WIN_SIZE (1024*1024*1024) +#endif /* SRM_SETUP */ #endif /* CONFIG_ALPHA_XL */ diff --git a/include/asm-alpha/cia.h b/include/asm-alpha/cia.h index 3bd5ea3cf9b3..2d9409ef84b5 100644 --- a/include/asm-alpha/cia.h +++ b/include/asm-alpha/cia.h @@ -74,11 +74,23 @@ #define BYTE_ENABLE_SHIFT 5 #define TRANSFER_LENGTH_SHIFT 3 -#define MEM_SP1_MASK 0x1fffffff /* Mem sparse space 1 mask is 29 bits */ +#define MEM_R1_MASK 0x1fffffff /* SPARSE Mem region 1 mask is 29 bits */ +#define MEM_R2_MASK 0x07ffffff /* SPARSE Mem region 2 mask is 27 bits */ +#define MEM_R3_MASK 0x03ffffff /* SPARSE Mem region 3 mask is 26 bits */ -#define CIA_DMA_WIN_BASE (1024UL*1024UL*1024UL) +#ifdef CONFIG_ALPHA_SRM_SETUP +/* if we are using the SRM PCI setup, we'll need to use variables instead */ +#define CIA_DMA_WIN_BASE_DEFAULT (1024*1024*1024) +#define CIA_DMA_WIN_SIZE_DEFAULT (1024*1024*1024) + +extern unsigned int CIA_DMA_WIN_BASE; +extern unsigned int CIA_DMA_WIN_SIZE; + +#else /* SRM_SETUP */ +#define CIA_DMA_WIN_BASE (1024*1024*1024) #define CIA_DMA_WIN_SIZE (1024*1024*1024) +#endif /* SRM_SETUP */ /* * 21171-CA Control and Status Registers (p4-1) @@ -86,6 +98,7 @@ #define CIA_IOC_CIA_REV (IDENT_ADDR + 0x8740000080UL) #define CIA_IOC_PCI_LAT (IDENT_ADDR + 0x87400000C0UL) #define CIA_IOC_CIA_CTRL (IDENT_ADDR + 0x8740000100UL) +#define CIA_IOC_CIA_CNFG (IDENT_ADDR + 0x8740000140UL) #define CIA_IOC_HAE_MEM (IDENT_ADDR + 0x8740000400UL) #define CIA_IOC_HAE_IO (IDENT_ADDR + 0x8740000440UL) #define CIA_IOC_CFG (IDENT_ADDR + 0x8740000480UL) @@ -119,18 +132,25 @@ #define CIA_IOC_PCI_ERR3 (IDENT_ADDR + 0x8740008880UL) /* - * 2117A-CA PCI Address Translation Registers. I've only defined - * the first window fully as that's the only one that we're currently using. - * The other window bases are needed to disable the windows. + * 2117A-CA PCI Address Translation Registers. */ #define CIA_IOC_PCI_TBIA (IDENT_ADDR + 0x8760000100UL) + #define CIA_IOC_PCI_W0_BASE (IDENT_ADDR + 0x8760000400UL) #define CIA_IOC_PCI_W0_MASK (IDENT_ADDR + 0x8760000440UL) #define CIA_IOC_PCI_T0_BASE (IDENT_ADDR + 0x8760000480UL) #define CIA_IOC_PCI_W1_BASE (IDENT_ADDR + 0x8760000500UL) +#define CIA_IOC_PCI_W1_MASK (IDENT_ADDR + 0x8760000540UL) +#define CIA_IOC_PCI_T1_BASE (IDENT_ADDR + 0x8760000580UL) + #define CIA_IOC_PCI_W2_BASE (IDENT_ADDR + 0x8760000600UL) +#define CIA_IOC_PCI_W2_MASK (IDENT_ADDR + 0x8760000640UL) +#define CIA_IOC_PCI_T2_BASE (IDENT_ADDR + 0x8760000680UL) + #define CIA_IOC_PCI_W3_BASE (IDENT_ADDR + 0x8760000700UL) +#define CIA_IOC_PCI_W3_MASK (IDENT_ADDR + 0x8760000740UL) +#define CIA_IOC_PCI_T3_BASE (IDENT_ADDR + 0x8760000780UL) /* * 21171-CA System configuration registers (p4-3) @@ -155,6 +175,8 @@ #define CIA_CONF (IDENT_ADDR + 0x8700000000UL) #define CIA_IO (IDENT_ADDR + 0x8580000000UL) #define CIA_SPARSE_MEM (IDENT_ADDR + 0x8000000000UL) +#define CIA_SPARSE_MEM_R2 (IDENT_ADDR + 0x8400000000UL) +#define CIA_SPARSE_MEM_R3 (IDENT_ADDR + 0x8500000000UL) #define CIA_DENSE_MEM (IDENT_ADDR + 0x8600000000UL) /* @@ -296,13 +318,125 @@ extern inline void __outl(unsigned int b, unsigned long addr) * */ +#ifdef CONFIG_ALPHA_SRM_SETUP + +extern unsigned long cia_sm_base_r1, cia_sm_base_r2, cia_sm_base_r3; + +extern inline unsigned long __readb(unsigned long addr) +{ + unsigned long result, shift, work; + + if ((addr >= cia_sm_base_r1) && + (addr <= (cia_sm_base_r1 + MEM_R1_MASK))) + work = (((addr & MEM_R1_MASK) << 5) + CIA_SPARSE_MEM + 0x00); + else + if ((addr >= cia_sm_base_r2) && + (addr <= (cia_sm_base_r2 + MEM_R2_MASK))) + work = (((addr & MEM_R2_MASK) << 5) + CIA_SPARSE_MEM_R2 + 0x00); + else + if ((addr >= cia_sm_base_r3) && + (addr <= (cia_sm_base_r3 + MEM_R3_MASK))) + work = (((addr & MEM_R3_MASK) << 5) + CIA_SPARSE_MEM_R3 + 0x00); + else + { +#if 0 + printk("__readb: address 0x%lx not covered by HAE\n", addr); +#endif + return 0x0ffUL; + } + shift = (addr & 0x3) << 3; + result = *(vuip) work; + result >>= shift; + return 0x0ffUL & result; +} + +extern inline unsigned long __readw(unsigned long addr) +{ + unsigned long result, shift, work; + + if ((addr >= cia_sm_base_r1) && + (addr <= (cia_sm_base_r1 + MEM_R1_MASK))) + work = (((addr & MEM_R1_MASK) << 5) + CIA_SPARSE_MEM + 0x08); + else + if ((addr >= cia_sm_base_r2) && + (addr <= (cia_sm_base_r2 + MEM_R2_MASK))) + work = (((addr & MEM_R2_MASK) << 5) + CIA_SPARSE_MEM_R2 + 0x08); + else + if ((addr >= cia_sm_base_r3) && + (addr <= (cia_sm_base_r3 + MEM_R3_MASK))) + work = (((addr & MEM_R3_MASK) << 5) + CIA_SPARSE_MEM_R3 + 0x08); + else + { +#if 0 + printk("__readw: address 0x%lx not covered by HAE\n", addr); +#endif + return 0x0ffUL; + } + shift = (addr & 0x3) << 3; + result = *(vuip) work; + result >>= shift; + return 0x0ffffUL & result; +} + +extern inline void __writeb(unsigned char b, unsigned long addr) +{ + unsigned long work; + + if ((addr >= cia_sm_base_r1) && + (addr <= (cia_sm_base_r1 + MEM_R1_MASK))) + work = (((addr & MEM_R1_MASK) << 5) + CIA_SPARSE_MEM + 0x00); + else + if ((addr >= cia_sm_base_r2) && + (addr <= (cia_sm_base_r2 + MEM_R2_MASK))) + work = (((addr & MEM_R2_MASK) << 5) + CIA_SPARSE_MEM_R2 + 0x00); + else + if ((addr >= cia_sm_base_r3) && + (addr <= (cia_sm_base_r3 + MEM_R3_MASK))) + work = (((addr & MEM_R3_MASK) << 5) + CIA_SPARSE_MEM_R3 + 0x00); + else + { +#if 0 + printk("__writeb: address 0x%lx not covered by HAE\n", addr); +#endif + return; + } + *(vuip) work = b * 0x01010101; +} + +extern inline void __writew(unsigned short b, unsigned long addr) +{ + unsigned long work; + + if ((addr >= cia_sm_base_r1) && + (addr <= (cia_sm_base_r1 + MEM_R1_MASK))) + work = (((addr & MEM_R1_MASK) << 5) + CIA_SPARSE_MEM + 0x00); + else + if ((addr >= cia_sm_base_r2) && + (addr <= (cia_sm_base_r2 + MEM_R2_MASK))) + work = (((addr & MEM_R2_MASK) << 5) + CIA_SPARSE_MEM_R2 + 0x00); + else + if ((addr >= cia_sm_base_r3) && + (addr <= (cia_sm_base_r3 + MEM_R3_MASK))) + work = (((addr & MEM_R3_MASK) << 5) + CIA_SPARSE_MEM_R3 + 0x00); + else + { +#if 0 + printk("__writew: address 0x%lx not covered by HAE\n", addr); +#endif + return; + } + *(vuip) work = b * 0x00010001; +} + +#else /* SRM_SETUP */ + extern inline unsigned long __readb(unsigned long addr) { unsigned long result, shift, msb; shift = (addr & 0x3) * 8 ; msb = addr & 0xE0000000 ; - addr &= MEM_SP1_MASK ; + addr &= MEM_R1_MASK ; if (msb != hae.cache) { set_hae(msb); } @@ -317,7 +451,7 @@ extern inline unsigned long __readw(unsigned long addr) shift = (addr & 0x3) * 8; msb = addr & 0xE0000000 ; - addr &= MEM_SP1_MASK ; + addr &= MEM_R1_MASK ; if (msb != hae.cache) { set_hae(msb); } @@ -326,17 +460,12 @@ extern inline unsigned long __readw(unsigned long addr) return 0xffffUL & result; } -extern inline unsigned long __readl(unsigned long addr) -{ - return *(vuip) (addr + CIA_DENSE_MEM); -} - extern inline void __writeb(unsigned char b, unsigned long addr) { unsigned long msb ; msb = addr & 0xE0000000 ; - addr &= MEM_SP1_MASK ; + addr &= MEM_R1_MASK ; if (msb != hae.cache) { set_hae(msb); } @@ -348,13 +477,20 @@ extern inline void __writew(unsigned short b, unsigned long addr) unsigned long msb ; msb = addr & 0xE0000000 ; - addr &= MEM_SP1_MASK ; + addr &= MEM_R1_MASK ; if (msb != hae.cache) { set_hae(msb); } *(vuip) ((addr << 5) + CIA_SPARSE_MEM + 0x08) = b * 0x00010001; } +#endif /* SRM_SETUP */ + +extern inline unsigned long __readl(unsigned long addr) +{ + return *(vuip) (addr + CIA_DENSE_MEM); +} + extern inline void __writel(unsigned int b, unsigned long addr) { *(vuip) (addr + CIA_DENSE_MEM) = b; @@ -379,48 +515,73 @@ extern unsigned long cia_init (unsigned long mem_start, /* * Data structure for handling CIA machine checks: */ +/* ev5-specific info: */ +struct el_procdata { + unsigned long shadow[8]; /* PALmode shadow registers */ + unsigned long paltemp[24]; /* PAL temporary registers */ + /* EV5-specific fields */ + unsigned long exc_addr; /* Address of excepting instruction. */ + unsigned long exc_sum; /* Summary of arithmetic traps. */ + unsigned long exc_mask; /* Exception mask (from exc_sum). */ + unsigned long exc_base; /* PALbase at time of exception. */ + unsigned long isr; /* Interrupt summary register. */ + unsigned long icsr; /* Ibox control register. */ + unsigned long ic_perr_stat; + unsigned long dc_perr_stat; + unsigned long va; /* Effective VA of fault or miss. */ + unsigned long mm_stat; + unsigned long sc_addr; + unsigned long sc_stat; + unsigned long bc_tag_addr; + unsigned long ei_addr; + unsigned long fill_syn; + unsigned long ei_stat; + unsigned long ld_lock; +}; + +/* system-specific info: */ struct el_CIA_sysdata_mcheck { - u_long coma_gcr; - u_long coma_edsr; - u_long coma_ter; - u_long coma_elar; - u_long coma_ehar; - u_long coma_ldlr; - u_long coma_ldhr; - u_long coma_base0; - u_long coma_base1; - u_long coma_base2; - u_long coma_cnfg0; - u_long coma_cnfg1; - u_long coma_cnfg2; - u_long epic_dcsr; - u_long epic_pear; - u_long epic_sear; - u_long epic_tbr1; - u_long epic_tbr2; - u_long epic_pbr1; - u_long epic_pbr2; - u_long epic_pmr1; - u_long epic_pmr2; - u_long epic_harx1; - u_long epic_harx2; - u_long epic_pmlt; - u_long epic_tag0; - u_long epic_tag1; - u_long epic_tag2; - u_long epic_tag3; - u_long epic_tag4; - u_long epic_tag5; - u_long epic_tag6; - u_long epic_tag7; - u_long epic_data0; - u_long epic_data1; - u_long epic_data2; - u_long epic_data3; - u_long epic_data4; - u_long epic_data5; - u_long epic_data6; - u_long epic_data7; + unsigned long coma_gcr; + unsigned long coma_edsr; + unsigned long coma_ter; + unsigned long coma_elar; + unsigned long coma_ehar; + unsigned long coma_ldlr; + unsigned long coma_ldhr; + unsigned long coma_base0; + unsigned long coma_base1; + unsigned long coma_base2; + unsigned long coma_cnfg0; + unsigned long coma_cnfg1; + unsigned long coma_cnfg2; + unsigned long epic_dcsr; + unsigned long epic_pear; + unsigned long epic_sear; + unsigned long epic_tbr1; + unsigned long epic_tbr2; + unsigned long epic_pbr1; + unsigned long epic_pbr2; + unsigned long epic_pmr1; + unsigned long epic_pmr2; + unsigned long epic_harx1; + unsigned long epic_harx2; + unsigned long epic_pmlt; + unsigned long epic_tag0; + unsigned long epic_tag1; + unsigned long epic_tag2; + unsigned long epic_tag3; + unsigned long epic_tag4; + unsigned long epic_tag5; + unsigned long epic_tag6; + unsigned long epic_tag7; + unsigned long epic_data0; + unsigned long epic_data1; + unsigned long epic_data2; + unsigned long epic_data3; + unsigned long epic_data4; + unsigned long epic_data5; + unsigned long epic_data6; + unsigned long epic_data7; }; #define RTC_PORT(x) (0x70 + (x)) diff --git a/include/asm-alpha/dma.h b/include/asm-alpha/dma.h index 05e70c96185a..7ae23bb41b3c 100644 --- a/include/asm-alpha/dma.h +++ b/include/asm-alpha/dma.h @@ -75,7 +75,9 @@ #define MAX_DMA_CHANNELS 8 -#ifdef CONFIG_ALPHA_XL +#if defined(CONFIG_ALPHA_RUFFIAN) +#define MAX_DMA_ADDRESS (0xfffffc0001000000UL) /* yup, 16Mb :-( */ +#elif defined(CONFIG_ALPHA_XL) /* The maximum address that we can perform a DMA transfer to on Alpha XL, due to a hardware SIO (PCI<->ISA bus bridge) chip limitation, is 64MB. See for more info. @@ -87,11 +89,13 @@ For now, this limit is set to 48Mb... */ #define MAX_DMA_ADDRESS (0xfffffc0003000000UL) -#else /* CONFIG_ALPHA_XL */ -/* The maximum address that we can perform a DMA transfer to on normal - Alpha platforms */ +#else +/* + * The maximum address that we can perform a DMA transfer to on + * normal Alpha platforms + */ #define MAX_DMA_ADDRESS (~0UL) -#endif /* CONFIG_ALPHA_XL */ +#endif /* 8237 DMA controllers */ #define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */ diff --git a/include/asm-alpha/floppy.h b/include/asm-alpha/floppy.h index 27013a9ecdcf..0a1b217f6ed3 100644 --- a/include/asm-alpha/floppy.h +++ b/include/asm-alpha/floppy.h @@ -51,11 +51,11 @@ static int FDC2 = -1; /* * Most Alphas have no problems with floppy DMA crossing 64k borders. Sigh... */ -#ifdef CONFIG_ALPHA_XL +#if defined(CONFIG_ALPHA_XL) || defined(CONFIG_ALPHA_RUFFIAN) #define CROSS_64KB(a,s) \ ((unsigned long)(a)/0x10000 != ((unsigned long)(a) + (s) - 1) / 0x10000) -#else /* CONFIG_ALPHA_XL */ +#else /* XL || RUFFIAN */ #define CROSS_64KB(a,s) (0) -#endif /* CONFIG_ALPHA_XL */ +#endif /* XL || RUFFIAN */ #endif /* __ASM_ALPHA_FLOPPY_H */ diff --git a/include/asm-alpha/hwrpb.h b/include/asm-alpha/hwrpb.h index 662aa35f6d72..fc2aa0517e31 100644 --- a/include/asm-alpha/hwrpb.h +++ b/include/asm-alpha/hwrpb.h @@ -15,6 +15,8 @@ #define EV45_CPU 6 /* EV4.5 (21064/xxx) */ #define EV56_CPU 7 /* EV5.6 (21164) */ #define EV6_CPU 8 /* EV6 (21164) */ +#define PCA56_CPU 9 /* PCA56 (21164PC) */ +#define PCA57_CPU 10 /* PCA57 (21164??) */ /* * DEC system types for Alpha systems. Found in HWRPB. @@ -32,14 +34,30 @@ #define ST_DEC_AXPPCI_33 11 /* NoName system type */ #define ST_DEC_TLASER 12 /* Turbolaser systype */ #define ST_DEC_2100_A50 13 /* Avanti systype */ -#define ST_DEC_MUSTANG 14 /* Mustang systype */ #define ST_DEC_ALCOR 15 /* Alcor (EV5) systype */ #define ST_DEC_1000 17 /* Mikasa systype */ +#define ST_DEC_EB64 18 /* EB64 systype */ #define ST_DEC_EB66 19 /* EB66 systype */ #define ST_DEC_EB64P 20 /* EB64+ systype */ -#define ST_DEC_EB66P -19 /* EB66 systype */ -#define ST_DEC_EBPC64 -20 /* Cabriolet (AlphaPC64) systype */ +#define ST_DEC_BURNS 21 /* laptop systype */ +#define ST_DEC_RAWHIDE 22 /* Rawhide systype */ +#define ST_DEC_K2 23 /* K2 systype */ +#define ST_DEC_LYNX 24 /* Lynx systype */ +#define ST_DEC_XL 25 /* Alpha XL systype */ #define ST_DEC_EB164 26 /* EB164 systype */ +#define ST_DEC_NORITAKE 27 /* Noritake systype */ +#define ST_DEC_CORTEX 28 /* Cortex systype */ +#define ST_DEC_MIATA 30 /* Miata systype */ +#define ST_DEC_XXM 31 /* XXM systype */ +#define ST_DEC_TAKARA 32 /* Takara systype */ +#define ST_DEC_YUKON 33 /* Yukon systype */ +#define ST_DEC_TSUNAMI 34 /* Tsunami systype */ +#define ST_DEC_WILDFIRE 35 /* Wildfire systype */ +#define ST_DEC_CUSCO 36 /* CUSCO systype */ + +/* UNOFFICIAL!!! */ +#define ST_UNOFFICIAL_BIAS 100 +#define ST_DTI_RUFFIAN 101 /* RUFFIAN systype */ struct pcb_struct { unsigned long ksp; @@ -118,6 +136,12 @@ struct memdesc_struct { struct memclust_struct cluster[0]; }; +struct dsr_struct { + long smm; /* SMM nubber used by LMF */ + unsigned long lurt_off; /* offset to LURT table */ + unsigned long sysname_off; /* offset to sysname char count */ +}; + struct hwrpb_struct { unsigned long phys_addr; /* check: physical address of the hwrpb */ unsigned long id; /* check: "HWRPB\0\0\0" */ @@ -157,7 +181,7 @@ struct hwrpb_struct { unsigned long chksum; unsigned long rxrdy; unsigned long txrdy; - unsigned long dsrdbt_offset; /* "Dynamic System Recognition Data Block Table" Whee */ + unsigned long dsr_offset; /* "Dynamic System Recognition Data Block Table" */ }; #endif diff --git a/include/asm-alpha/io.h b/include/asm-alpha/io.h index 44fea065e27a..24ab4cc02fbe 100644 --- a/include/asm-alpha/io.h +++ b/include/asm-alpha/io.h @@ -25,7 +25,11 @@ extern struct hae { /* * Virtual -> physical identity mapping starts at this offset */ +#ifdef USE_48_BIT_KSEG +#define IDENT_ADDR (0xffff800000000000UL) +#else #define IDENT_ADDR (0xfffffc0000000000UL) +#endif #ifdef __KERNEL__ @@ -42,6 +46,7 @@ extern inline void set_hae(unsigned long new_hae) hae.cache = new_hae; *hae.reg = new_hae; mb(); + new_hae = *hae.reg; /* read to make sure it was written */ setipl(ipl); } @@ -79,6 +84,10 @@ extern void _sethae (unsigned long addr); /* cached version */ # include /* get chip-specific definitions */ #elif defined(CONFIG_ALPHA_CIA) # include /* get chip-specific definitions */ +#elif defined(CONFIG_ALPHA_T2) +# include /* get chip-specific definitions */ +#elif defined(CONFIG_ALPHA_PYXIS) +# include /* get chip-specific definitions */ #else # include #endif @@ -150,9 +159,21 @@ extern void _writel(unsigned int b, unsigned long addr); #endif /* - * The "address" in IO memory space is not clearly either a integer or a + * The "address" in IO memory space is not clearly either an integer or a * pointer. We will accept both, thus the casts. + * + * On the alpha, we have the whole physical address space mapped at all + * times, so "ioremap()" and "iounmap()" do not need to do anything. */ +extern inline void * ioremap(unsigned long offset, unsigned long size) +{ + return (void *) offset; +} + +extern inline void iounmap(void *addr) +{ +} + #ifndef readb # define readb(a) _readb((unsigned long)(a)) #endif @@ -203,6 +224,22 @@ extern void outsl (unsigned long port, const void *src, unsigned long count); #define eth_io_copy_and_sum(skb,src,len,unused) memcpy_fromio((skb)->data,(src),(len)) +static inline int check_signature(unsigned long io_addr, + const unsigned char *signature, int length) +{ + int retval = 0; + do { + if (readb(io_addr) != *signature) + goto out; + io_addr++; + signature++; + length--; + } while (length); + retval = 1; +out: + return retval; +} + #endif /* __KERNEL__ */ #endif diff --git a/include/asm-alpha/irq.h b/include/asm-alpha/irq.h index bf2a380e9743..4be70268171f 100644 --- a/include/asm-alpha/irq.h +++ b/include/asm-alpha/irq.h @@ -10,14 +10,41 @@ #include #include -#if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P) || defined(CONFIG_ALPHA_EB164) || defined(CONFIG_ALPHA_PC164) -# define NR_IRQS 33 -#elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P) || defined(CONFIG_ALPHA_MIKASA) +#if defined(CONFIG_ALPHA_CABRIOLET) || \ + defined(CONFIG_ALPHA_EB66P) || \ + defined(CONFIG_ALPHA_EB164) || \ + defined(CONFIG_ALPHA_PC164) || \ + defined(CONFIG_ALPHA_LX164) + +# define NR_IRQS 35 + +#elif defined(CONFIG_ALPHA_EB66) || \ + defined(CONFIG_ALPHA_EB64P) || \ + defined(CONFIG_ALPHA_MIKASA) + # define NR_IRQS 32 -#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) + +#elif defined(CONFIG_ALPHA_ALCOR) || \ + defined(CONFIG_ALPHA_XLT) || \ + defined(CONFIG_ALPHA_MIATA) || \ + defined(CONFIG_ALPHA_RUFFIAN) || \ + defined(CONFIG_ALPHA_NORITAKE) + # define NR_IRQS 48 -#else + +#elif defined(CONFIG_ALPHA_SABLE) || \ + defined(CONFIG_ALPHA_SX164) + +# define NR_IRQS 40 + +#elif defined(CONFIG_ALPHA_TAKARA) + +# define NR_IRQS 20 + +#else /* everyone else */ + # define NR_IRQS 16 + #endif diff --git a/include/asm-alpha/lca.h b/include/asm-alpha/lca.h index 161e89a6fbc7..9ea03dd9b4ae 100644 --- a/include/asm-alpha/lca.h +++ b/include/asm-alpha/lca.h @@ -54,8 +54,18 @@ #include +#ifdef CONFIG_ALPHA_SRM_SETUP +/* if we are using the SRM PCI setup, we'll need to use variables instead */ +#define LCA_DMA_WIN_BASE_DEFAULT (1024*1024*1024) +#define LCA_DMA_WIN_SIZE_DEFAULT (1024*1024*1024) + +extern unsigned int LCA_DMA_WIN_BASE; +extern unsigned int LCA_DMA_WIN_SIZE; + +#else /* SRM_SETUP */ #define LCA_DMA_WIN_BASE (1024*1024*1024) #define LCA_DMA_WIN_SIZE (1024*1024*1024) +#endif /* SRM_SETUP */ /* * Memory Controller registers: @@ -130,6 +140,37 @@ #define HAE_ADDRESS LCA_IOC_HAE +/* LCA PMR Power Management register defines */ +#define LCA_PMR_ADDR (IDENT_ADDR + 0x120000098UL) +#define LCA_PMR_PDIV 0x7 /* Primary clock divisor */ +#define LCA_PMR_ODIV 0x38 /* Override clock divisor */ +#define LCA_PMR_INTO 0x40 /* Interrupt override */ +#define LCA_PMR_DMAO 0x80 /* DMA override */ +#define LCA_PMR_OCCEB 0xffff0000L /* Override cycle counter - even + bits */ +#define LCA_PMR_OCCOB 0xffff000000000000L /* Override cycle counter - even + bits */ +#define LCA_PMR_PRIMARY_MASK 0xfffffffffffffff8 +/* LCA PMR Macros */ + +#define READ_PMR (*(volatile unsigned long *)LCA_PMR_ADDR) +#define WRITE_PMR(d) (*((volatile unsigned long *)LCA_PMR_ADDR) = (d)) + +#define GET_PRIMARY(r) ((r) & LCA_PMR_PDIV) +#define GET_OVERRIDE(r) (((r) >> 3) & LCA_PMR_PDIV) +#define SET_PRIMARY_CLOCK(r, c) ((r) = (((r) & LCA_PMR_PRIMARY_MASK) | (c))) + +/* LCA PMR Divisor values */ +#define DIV_1 0x0 +#define DIV_1_5 0x1 +#define DIV_2 0x2 +#define DIV_4 0x3 +#define DIV_8 0x4 +#define DIV_16 0x5 +#define DIV_MIN DIV_1 +#define DIV_MAX DIV_16 + + #ifdef __KERNEL__ /* @@ -317,7 +358,6 @@ extern unsigned long lca_init (unsigned long mem_start, unsigned long mem_end); */ struct el_lca_mcheck_short { struct el_common h; /* common logout header */ - unsigned long reason; /* reason for machine check */ unsigned long esr; /* error-status register */ unsigned long ear; /* error-address register */ unsigned long dc_stat; /* dcache status register */ @@ -327,7 +367,7 @@ struct el_lca_mcheck_short { struct el_lca_mcheck_long { struct el_common h; /* common logout header */ - unsigned long pt[32]; /* PAL temps (pt[0] is reason) */ + unsigned long pt[31]; /* PAL temps */ unsigned long exc_addr; /* exception address */ unsigned long pad1[3]; unsigned long pal_base; /* PALcode base address */ diff --git a/include/asm-alpha/pal.h b/include/asm-alpha/pal.h index a4ef2e38a825..510d13326de4 100644 --- a/include/asm-alpha/pal.h +++ b/include/asm-alpha/pal.h @@ -7,7 +7,6 @@ #define PAL_halt 0 #define PAL_cflush 1 #define PAL_draina 2 -#define PAL_cobratt 9 #define PAL_bpt 128 #define PAL_bugchk 129 #define PAL_chmk 131 @@ -27,6 +26,8 @@ /* * OSF specific PAL-code */ +#define PAL_cserve 9 +#define PAL_wripir 13 #define PAL_rdmces 16 #define PAL_wrmces 17 #define PAL_wrfen 43 diff --git a/include/asm-alpha/processor.h b/include/asm-alpha/processor.h index e4b897f69889..1bf57f01abab 100644 --- a/include/asm-alpha/processor.h +++ b/include/asm-alpha/processor.h @@ -8,9 +8,17 @@ #define __ASM_ALPHA_PROCESSOR_H /* - * We have a 41-bit user address space: 2TB user VM... + * We have a 41-bit user address space: 2TB user VM. + * Under certain circumstances (e.g. when emulating 32-bit code) + * we may want to voluntarily limit this... */ #define TASK_SIZE (0x40000000000UL) +#define MAX_USER_ADDR ((current->personality&ADDR_MAX_32BIT) ? 0x100000000UL : \ + ((current->personality & ADDR_MAX_31BIT) ? 0x80000000UL : \ + 0x40000000000UL)) +#define MMAP_SEARCH_START ((current->personality & ADDR_MAX_31BIT) ? \ + (MAX_USER_ADDR/2) : (MAX_USER_ADDR/3)) + /* * Bus types diff --git a/include/asm-alpha/ptrace.h b/include/asm-alpha/ptrace.h index 8f7d643fc8c3..4079385ecb3b 100644 --- a/include/asm-alpha/ptrace.h +++ b/include/asm-alpha/ptrace.h @@ -37,6 +37,10 @@ struct pt_regs { unsigned long r27; unsigned long r28; unsigned long hae; +/* JRP - These are the values provided to a0-a2 by PALcode */ + unsigned long trap_a0; + unsigned long trap_a1; + unsigned long trap_a2; /* These are saved by PAL-code: */ unsigned long ps; unsigned long pc; diff --git a/include/asm-alpha/pyxis.h b/include/asm-alpha/pyxis.h new file mode 100644 index 000000000000..4cb98c4a5803 --- /dev/null +++ b/include/asm-alpha/pyxis.h @@ -0,0 +1,742 @@ +#ifndef __ALPHA_PYXIS__H__ +#define __ALPHA_PYXIS__H__ + +#include +#include + +/* + * PYXIS is the internal name for a core logic chipset which provides + * memory controller and PCI access for the 21164A chip based systems. + * + * This file is based on: + * + * Pyxis Chipset Spec + * 14-Jun-96 + * Rev. X2.0 + * + */ + +/*------------------------------------------------------------------------** +** ** +** I/O procedures ** +** ** +** inport[b|w|t|l], outport[b|w|t|l] 8:16:24:32 IO xfers ** +** inportbxt: 8 bits only ** +** inport: alias of inportw ** +** outport: alias of outportw ** +** ** +** inmem[b|w|t|l], outmem[b|w|t|l] 8:16:24:32 ISA memory xfers ** +** inmembxt: 8 bits only ** +** inmem: alias of inmemw ** +** outmem: alias of outmemw ** +** ** +**------------------------------------------------------------------------*/ + + +/* CIA ADDRESS BIT DEFINITIONS + * + * 3 3 3 3|3 3 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 + * 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 9 8|7 6 5 4|3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |1| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |0|0|0| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | \_/ \_/ + * | | | + * +-- IO space, not cached. Byte Enable --+ | + * Transfer Length --+ + * + * + * + * Byte Transfer + * Enable Length Transfer Byte Address + * adr<6:5> adr<4:3> Length Enable Adder + * --------------------------------------------- + * 00 00 Byte 1110 0x000 + * 01 00 Byte 1101 0x020 + * 10 00 Byte 1011 0x040 + * 11 00 Byte 0111 0x060 + * + * 00 01 Word 1100 0x008 + * 01 01 Word 1001 0x028 <= Not supported in this code. + * 10 01 Word 0011 0x048 + * + * 00 10 Tribyte 1000 0x010 + * 01 10 Tribyte 0001 0x030 + * + * 10 11 Longword 0000 0x058 + * + * Note that byte enables are asserted low. + * + */ + +#define BYTE_ENABLE_SHIFT 5 +#define TRANSFER_LENGTH_SHIFT 3 + +#define MEM_R1_MASK 0x1fffffff /* SPARSE Mem region 1 mask is 29 bits */ +#define MEM_R2_MASK 0x07ffffff /* SPARSE Mem region 2 mask is 27 bits */ +#define MEM_R3_MASK 0x03ffffff /* SPARSE Mem region 3 mask is 26 bits */ + +#ifdef CONFIG_ALPHA_SRM_SETUP +/* if we are using the SRM PCI setup, we'll need to use variables instead */ +#define PYXIS_DMA_WIN_BASE_DEFAULT (1024*1024*1024) +#define PYXIS_DMA_WIN_SIZE_DEFAULT (1024*1024*1024) + +extern unsigned int PYXIS_DMA_WIN_BASE; +extern unsigned int PYXIS_DMA_WIN_SIZE; + +#else /* SRM_SETUP */ +#define PYXIS_DMA_WIN_BASE (1024*1024*1024) +#define PYXIS_DMA_WIN_SIZE (1024*1024*1024) +#endif /* SRM_SETUP */ + +/* + * General Registers + */ +#define PYXIS_REV (IDENT_ADDR + 0x8740000080UL) +#define PYXIS_PCI_LAT (IDENT_ADDR + 0x87400000C0UL) +#define PYXIS_CTRL (IDENT_ADDR + 0x8740000100UL) +#define PYXIS_CTRL1 (IDENT_ADDR + 0x8740000140UL) +#define PYXIS_FLASH_CTRL (IDENT_ADDR + 0x8740000200UL) + +#define PYXIS_HAE_MEM (IDENT_ADDR + 0x8740000400UL) +#define PYXIS_HAE_IO (IDENT_ADDR + 0x8740000440UL) +#define PYXIS_CFG (IDENT_ADDR + 0x8740000480UL) + +/* + * Diagnostic Registers + */ +#define PYXIS_DIAG (IDENT_ADDR + 0x8740002000UL) +#define PYXIS_DIAG_CHECK (IDENT_ADDR + 0x8740003000UL) + +/* + * Performance Monitor registers + */ +#define PYXIS_PERF_MONITOR (IDENT_ADDR + 0x8740004000UL) +#define PYXIS_PERF_CONTROL (IDENT_ADDR + 0x8740004040UL) + +/* + * Error registers + */ +#define PYXIS_ERR (IDENT_ADDR + 0x8740008200UL) +#define PYXIS_STAT (IDENT_ADDR + 0x8740008240UL) +#define PYXIS_ERR_MASK (IDENT_ADDR + 0x8740008280UL) +#define PYXIS_SYN (IDENT_ADDR + 0x8740008300UL) +#define PYXIS_ERR_DATA (IDENT_ADDR + 0x8740008308UL) + +#define PYXIS_MEAR (IDENT_ADDR + 0x8740008400UL) +#define PYXIS_MESR (IDENT_ADDR + 0x8740008440UL) +#define PYXIS_PCI_ERR0 (IDENT_ADDR + 0x8740008800UL) +#define PYXIS_PCI_ERR1 (IDENT_ADDR + 0x8740008840UL) +#define PYXIS_PCI_ERR2 (IDENT_ADDR + 0x8740008880UL) + +/* + * PCI Address Translation Registers. + */ +#define PYXIS_TBIA (IDENT_ADDR + 0x8760000100UL) + +#define PYXIS_W0_BASE (IDENT_ADDR + 0x8760000400UL) +#define PYXIS_W0_MASK (IDENT_ADDR + 0x8760000440UL) +#define PYXIS_T0_BASE (IDENT_ADDR + 0x8760000480UL) + +#define PYXIS_W1_BASE (IDENT_ADDR + 0x8760000500UL) +#define PYXIS_W1_MASK (IDENT_ADDR + 0x8760000540UL) +#define PYXIS_T1_BASE (IDENT_ADDR + 0x8760000580UL) + +#define PYXIS_W2_BASE (IDENT_ADDR + 0x8760000600UL) +#define PYXIS_W2_MASK (IDENT_ADDR + 0x8760000640UL) +#define PYXIS_T2_BASE (IDENT_ADDR + 0x8760000680UL) + +#define PYXIS_W3_BASE (IDENT_ADDR + 0x8760000700UL) +#define PYXIS_W3_MASK (IDENT_ADDR + 0x8760000740UL) +#define PYXIS_T3_BASE (IDENT_ADDR + 0x8760000780UL) + +/* + * Memory Control registers + */ +#define PYXIS_MCR (IDENT_ADDR + 0x8750000000UL) + +/* + * Memory spaces: + */ +#define PYXIS_IACK_SC (IDENT_ADDR + 0x8720000000UL) +#define PYXIS_CONF (IDENT_ADDR + 0x8700000000UL) +#define PYXIS_IO (IDENT_ADDR + 0x8580000000UL) +#define PYXIS_SPARSE_MEM (IDENT_ADDR + 0x8000000000UL) +#define PYXIS_SPARSE_MEM_R2 (IDENT_ADDR + 0x8400000000UL) +#define PYXIS_SPARSE_MEM_R3 (IDENT_ADDR + 0x8500000000UL) +#define PYXIS_DENSE_MEM (IDENT_ADDR + 0x8600000000UL) + +/* + * Byte/Word PCI Memory Spaces: + */ +#define PYXIS_BW_MEM (IDENT_ADDR + 0x8800000000UL) +#define PYXIS_BW_IO (IDENT_ADDR + 0x8900000000UL) +#define PYXIS_BW_CFG_0 (IDENT_ADDR + 0x8a00000000UL) +#define PYXIS_BW_CFG_1 (IDENT_ADDR + 0x8b00000000UL) + +/* + * Interrupt Control registers + */ +#define PYXIS_INT_REQ (IDENT_ADDR + 0x87A0000000UL) +#define PYXIS_INT_MASK (IDENT_ADDR + 0x87A0000040UL) +#define PYXIS_INT_HILO (IDENT_ADDR + 0x87A00000C0UL) +#define PYXIS_INT_ROUTE (IDENT_ADDR + 0x87A0000140UL) +#define PYXIS_GPO (IDENT_ADDR + 0x87A0000180UL) +#define PYXIS_INT_CNFG (IDENT_ADDR + 0x87A00001C0UL) +#define PYXIS_RT_COUNT (IDENT_ADDR + 0x87A0000200UL) +#define PYXIS_INT_TIME (IDENT_ADDR + 0x87A0000240UL) +#define PYXIS_IIC_CTRL (IDENT_ADDR + 0x87A00002C0UL) + +/* + * Bit definitions for I/O Controller status register 0: + */ +#define PYXIS_STAT0_CMD 0xf +#define PYXIS_STAT0_ERR (1<<4) +#define PYXIS_STAT0_LOST (1<<5) +#define PYXIS_STAT0_THIT (1<<6) +#define PYXIS_STAT0_TREF (1<<7) +#define PYXIS_STAT0_CODE_SHIFT 8 +#define PYXIS_STAT0_CODE_MASK 0x7 +#define PYXIS_STAT0_P_NBR_SHIFT 13 +#define PYXIS_STAT0_P_NBR_MASK 0x7ffff + +#define HAE_ADDRESS PYXIS_HAE_MEM + +#ifdef __KERNEL__ + +/* + * Translate physical memory address as seen on (PCI) bus into + * a kernel virtual address and vv. + */ +#if defined(CONFIG_ALPHA_RUFFIAN) +#if 0 +/* Ruffian doesn't do 1G PCI window */ +extern inline unsigned long virt_to_bus(void * address) +{ + return virt_to_phys(address); +} + +extern inline void * bus_to_virt(unsigned long address) +{ + return phys_to_virt(address); +} +#else +/* Oh, yes, it does (at least with the latest FW) */ +extern inline unsigned long virt_to_bus(void * address) +{ + return virt_to_phys(address) + PYXIS_DMA_WIN_BASE; +} + +extern inline void * bus_to_virt(unsigned long address) +{ + return phys_to_virt(address - PYXIS_DMA_WIN_BASE); +} +#endif +#else /* RUFFIAN */ +extern inline unsigned long virt_to_bus(void * address) +{ + return virt_to_phys(address) + PYXIS_DMA_WIN_BASE; +} + +extern inline void * bus_to_virt(unsigned long address) +{ + return phys_to_virt(address - PYXIS_DMA_WIN_BASE); +} +#endif /* RUFFIAN */ + +/* + * I/O functions: + * + * PYXIS, the 21174 PCI/memory support chipset for the EV56 (21164) + * and PCA56 (21164PC) processors, can use either a sparse address + * mapping scheme, or the so-called byte-word PCI address space, to + * get at PCI memory and I/O. + */ + +#define vuip volatile unsigned int * + +#if defined(BWIO_ENABLED) +# if defined(CONFIG_ALPHA_LX164) || \ + defined(CONFIG_ALPHA_SX164) +/* only for the above platforms can we be sure this will work */ +# define BWIO_REALLY_ENABLED +# else +# undef BWIO_REALLY_ENABLED +# endif +#else +# undef BWIO_REALLY_ENABLED +#endif + +#ifdef BWIO_REALLY_ENABLED + +extern inline unsigned int __inb(unsigned long addr) +{ + register unsigned long result; + + __asm__ __volatile__ ( + "ldbu %0,%1" + : "=r" (result) + : "m" (*(unsigned char *)(addr+PYXIS_BW_IO))); + + return result; +} + +extern inline void __outb(unsigned char b, unsigned long addr) +{ + __asm__ __volatile__ ( + "stb %1,%0\n\t" + "mb" + : : "m" (*(unsigned char *)(addr+PYXIS_BW_IO)), "r" (b)); +} + +extern inline unsigned int __inw(unsigned long addr) +{ + register unsigned long result; + + __asm__ __volatile__ ( + "ldwu %0,%1" + : "=r" (result) + : "m" (*(unsigned short *)(addr+PYXIS_BW_IO))); + + return result; +} + +extern inline void __outw(unsigned short b, unsigned long addr) +{ + __asm__ __volatile__ ( + "stw %1,%0\n\t" + "mb" + : : "m" (*(unsigned short *)(addr+PYXIS_BW_IO)), "r" (b)); +} + +extern inline unsigned int __inl(unsigned long addr) +{ + register unsigned long result; + + __asm__ __volatile__ ( + "ldl %0,%1" + : "=r" (result) + : "m" (*(unsigned int *)(addr+PYXIS_BW_IO))); + + return result; +} + +extern inline void __outl(unsigned int b, unsigned long addr) +{ + __asm__ __volatile__ ( + "stl %1,%0\n\t" + "mb" + : : "m" (*(unsigned int *)(addr+PYXIS_BW_IO)), "r" (b)); +} + +#define inb(port) __inb((port)) +#define inw(port) __inw((port)) +#define inl(port) __inl((port)) + +#define outb(x, port) __outb((x),(port)) +#define outw(x, port) __outw((x),(port)) +#define outl(x, port) __outl((x),(port)) + +#else /* BWIO_REALLY_ENABLED */ + +extern inline unsigned int __inb(unsigned long addr) +{ + long result = *(vuip) ((addr << 5) + PYXIS_IO + 0x00); + result >>= (addr & 3) * 8; + return 0xffUL & result; +} + +extern inline void __outb(unsigned char b, unsigned long addr) +{ + unsigned int w; + + asm ("insbl %2,%1,%0" : "r="(w) : "ri"(addr & 0x3), "r"(b)); + *(vuip) ((addr << 5) + PYXIS_IO + 0x00) = w; + mb(); +} + +extern inline unsigned int __inw(unsigned long addr) +{ + long result = *(vuip) ((addr << 5) + PYXIS_IO + 0x08); + result >>= (addr & 3) * 8; + return 0xffffUL & result; +} + +extern inline void __outw(unsigned short b, unsigned long addr) +{ + unsigned int w; + + asm ("inswl %2,%1,%0" : "r="(w) : "ri"(addr & 0x3), "r"(b)); + *(vuip) ((addr << 5) + PYXIS_IO + 0x08) = w; + mb(); +} + +extern inline unsigned int __inl(unsigned long addr) +{ + return *(vuip) ((addr << 5) + PYXIS_IO + 0x18); +} + +extern inline void __outl(unsigned int b, unsigned long addr) +{ + *(vuip) ((addr << 5) + PYXIS_IO + 0x18) = b; + mb(); +} + +#define inb(port) \ +(__builtin_constant_p((port))?__inb(port):_inb(port)) + +#define outb(x, port) \ +(__builtin_constant_p((port))?__outb((x),(port)):_outb((x),(port))) + +#endif /* BWIO_REALLY_ENABLED */ + + +/* + * Memory functions. 64-bit and 32-bit accesses are done through + * dense memory space, everything else through sparse space. + * + * For reading and writing 8 and 16 bit quantities we need to + * go through one of the three sparse address mapping regions + * and use the HAE_MEM CSR to provide some bits of the address. + * The following few routines use only sparse address region 1 + * which gives 1Gbyte of accessible space which relates exactly + * to the amount of PCI memory mapping *into* system address space. + * See p 6-17 of the specification but it looks something like this: + * + * 21164 Address: + * + * 3 2 1 + * 9876543210987654321098765432109876543210 + * 1ZZZZ0.PCI.QW.Address............BBLL + * + * ZZ = SBZ + * BB = Byte offset + * LL = Transfer length + * + * PCI Address: + * + * 3 2 1 + * 10987654321098765432109876543210 + * HHH....PCI.QW.Address........ 00 + * + * HHH = 31:29 HAE_MEM CSR + * + */ + +#ifdef BWIO_REALLY_ENABLED + +extern inline unsigned long __readb(unsigned long addr) +{ + register unsigned long result; + + __asm__ __volatile__ ( + "ldbu %0,%1" + : "=r" (result) + : "m" (*(unsigned char *)(addr+PYXIS_BW_MEM))); + + return result; +} + +extern inline unsigned long __readw(unsigned long addr) +{ + register unsigned long result; + + __asm__ __volatile__ ( + "ldwu %0,%1" + : "=r" (result) + : "m" (*(unsigned short *)(addr+PYXIS_BW_MEM))); + + return result; +} + +extern inline unsigned long __readl(unsigned long addr) +{ + register unsigned long result; + + __asm__ __volatile__ ( + "ldl %0,%1" + : "=r" (result) + : "m" (*(unsigned int *)(addr+PYXIS_BW_MEM))); + + return result; +} + +extern inline void __writeb(unsigned char b, unsigned long addr) +{ + __asm__ __volatile__ ( + "stb %1,%0\n\t" + "mb" + : : "m" (*(unsigned char *)(addr+PYXIS_BW_MEM)), "r" (b)); +} + +extern inline void __writew(unsigned short b, unsigned long addr) +{ + __asm__ __volatile__ ( + "stw %1,%0\n\t" + "mb" + : : "m" (*(unsigned short *)(addr+PYXIS_BW_MEM)), "r" (b)); +} + +extern inline void __writel(unsigned int b, unsigned long addr) +{ + __asm__ __volatile__ ( + "stl %1,%0\n\t" + "mb" + : : "m" (*(unsigned int *)(addr+PYXIS_BW_MEM)), "r" (b)); +} + +#define readb(addr) __readb((addr)) +#define readw(addr) __readw((addr)) + +#define writeb(b, addr) __writeb((b),(addr)) +#define writew(b, addr) __writew((b),(addr)) + +#else /* BWIO_REALLY_ENABLED */ + +#ifdef CONFIG_ALPHA_SRM_SETUP + +extern unsigned long pyxis_sm_base_r1, pyxis_sm_base_r2, pyxis_sm_base_r3; + +extern inline unsigned long __readb(unsigned long addr) +{ + unsigned long result, shift, work; + + if ((addr >= pyxis_sm_base_r1) && + (addr <= (pyxis_sm_base_r1 + MEM_R1_MASK))) + work = (((addr & MEM_R1_MASK) << 5) + PYXIS_SPARSE_MEM + 0x00); + else + if ((addr >= pyxis_sm_base_r2) && + (addr <= (pyxis_sm_base_r2 + MEM_R2_MASK))) + work = (((addr & MEM_R2_MASK) << 5) + PYXIS_SPARSE_MEM_R2 + 0x00); + else + if ((addr >= pyxis_sm_base_r3) && + (addr <= (pyxis_sm_base_r3 + MEM_R3_MASK))) + work = (((addr & MEM_R3_MASK) << 5) + PYXIS_SPARSE_MEM_R3 + 0x00); + else + { +#if 0 + printk("__readb: address 0x%lx not covered by HAE\n", addr); +#endif + return 0x0ffUL; + } + shift = (addr & 0x3) << 3; + result = *(vuip) work; + result >>= shift; + return 0x0ffUL & result; +} + +extern inline unsigned long __readw(unsigned long addr) +{ + unsigned long result, shift, work; + + if ((addr >= pyxis_sm_base_r1) && + (addr <= (pyxis_sm_base_r1 + MEM_R1_MASK))) + work = (((addr & MEM_R1_MASK) << 5) + PYXIS_SPARSE_MEM + 0x08); + else + if ((addr >= pyxis_sm_base_r2) && + (addr <= (pyxis_sm_base_r2 + MEM_R2_MASK))) + work = (((addr & MEM_R2_MASK) << 5) + PYXIS_SPARSE_MEM_R2 + 0x08); + else + if ((addr >= pyxis_sm_base_r3) && + (addr <= (pyxis_sm_base_r3 + MEM_R3_MASK))) + work = (((addr & MEM_R3_MASK) << 5) + PYXIS_SPARSE_MEM_R3 + 0x08); + else + { +#if 0 + printk("__readw: address 0x%lx not covered by HAE\n", addr); +#endif + return 0x0ffUL; + } + shift = (addr & 0x3) << 3; + result = *(vuip) work; + result >>= shift; + return 0x0ffffUL & result; +} + +extern inline void __writeb(unsigned char b, unsigned long addr) +{ + unsigned long work; + + if ((addr >= pyxis_sm_base_r1) && + (addr <= (pyxis_sm_base_r1 + MEM_R1_MASK))) + work = (((addr & MEM_R1_MASK) << 5) + PYXIS_SPARSE_MEM + 0x00); + else + if ((addr >= pyxis_sm_base_r2) && + (addr <= (pyxis_sm_base_r2 + MEM_R2_MASK))) + work = (((addr & MEM_R2_MASK) << 5) + PYXIS_SPARSE_MEM_R2 + 0x00); + else + if ((addr >= pyxis_sm_base_r3) && + (addr <= (pyxis_sm_base_r3 + MEM_R3_MASK))) + work = (((addr & MEM_R3_MASK) << 5) + PYXIS_SPARSE_MEM_R3 + 0x00); + else + { +#if 0 + printk("__writeb: address 0x%lx not covered by HAE\n", addr); +#endif + return; + } + *(vuip) work = b * 0x01010101; +} + +extern inline void __writew(unsigned short b, unsigned long addr) +{ + unsigned long work; + + if ((addr >= pyxis_sm_base_r1) && + (addr <= (pyxis_sm_base_r1 + MEM_R1_MASK))) + work = (((addr & MEM_R1_MASK) << 5) + PYXIS_SPARSE_MEM + 0x00); + else + if ((addr >= pyxis_sm_base_r2) && + (addr <= (pyxis_sm_base_r2 + MEM_R2_MASK))) + work = (((addr & MEM_R2_MASK) << 5) + PYXIS_SPARSE_MEM_R2 + 0x00); + else + if ((addr >= pyxis_sm_base_r3) && + (addr <= (pyxis_sm_base_r3 + MEM_R3_MASK))) + work = (((addr & MEM_R3_MASK) << 5) + PYXIS_SPARSE_MEM_R3 + 0x00); + else + { +#if 0 + printk("__writew: address 0x%lx not covered by HAE\n", addr); +#endif + return; + } + *(vuip) work = b * 0x00010001; +} + +#else /* SRM_SETUP */ + +extern inline unsigned long __readb(unsigned long addr) +{ + unsigned long result, shift, msb, work, temp; + + shift = (addr & 0x3) << 3; + msb = addr & 0xE0000000UL; + temp = addr & MEM_R1_MASK ; + if (msb != hae.cache) { + set_hae(msb); + } + work = ((temp << 5) + PYXIS_SPARSE_MEM + 0x00); + result = *(vuip) work; + result >>= shift; + return 0x0ffUL & result; +} + +extern inline unsigned long __readw(unsigned long addr) +{ + unsigned long result, shift, msb, work, temp; + + shift = (addr & 0x3) << 3; + msb = addr & 0xE0000000UL; + temp = addr & MEM_R1_MASK ; + if (msb != hae.cache) { + set_hae(msb); + } + work = ((temp << 5) + PYXIS_SPARSE_MEM + 0x08); + result = *(vuip) work; + result >>= shift; + return 0x0ffffUL & result; +} + +extern inline void __writeb(unsigned char b, unsigned long addr) +{ + unsigned long msb ; + + msb = addr & 0xE0000000 ; + addr &= MEM_R1_MASK ; + if (msb != hae.cache) { + set_hae(msb); + } + *(vuip) ((addr << 5) + PYXIS_SPARSE_MEM + 0x00) = b * 0x01010101; +} + +extern inline void __writew(unsigned short b, unsigned long addr) +{ + unsigned long msb ; + + msb = addr & 0xE0000000 ; + addr &= MEM_R1_MASK ; + if (msb != hae.cache) { + set_hae(msb); + } + *(vuip) ((addr << 5) + PYXIS_SPARSE_MEM + 0x08) = b * 0x00010001; +} +#endif /* SRM_SETUP */ + +extern inline unsigned long __readl(unsigned long addr) +{ + return *(vuip) (addr + PYXIS_DENSE_MEM); +} + +extern inline void __writel(unsigned int b, unsigned long addr) +{ + *(vuip) (addr + PYXIS_DENSE_MEM) = b; +} + +#endif /* BWIO_REALLY_ENABLED */ + +#define readl(a) __readl((unsigned long)(a)) +#define writel(v,a) __writel((v),(unsigned long)(a)) + +#undef vuip + +extern unsigned long pyxis_init (unsigned long mem_start, + unsigned long mem_end); + +#endif /* __KERNEL__ */ + +/* + * Data structure for handling PYXIS machine checks: + */ +struct el_PYXIS_sysdata_mcheck { + u_long coma_gcr; + u_long coma_edsr; + u_long coma_ter; + u_long coma_elar; + u_long coma_ehar; + u_long coma_ldlr; + u_long coma_ldhr; + u_long coma_base0; + u_long coma_base1; + u_long coma_base2; + u_long coma_cnfg0; + u_long coma_cnfg1; + u_long coma_cnfg2; + u_long epic_dcsr; + u_long epic_pear; + u_long epic_sear; + u_long epic_tbr1; + u_long epic_tbr2; + u_long epic_pbr1; + u_long epic_pbr2; + u_long epic_pmr1; + u_long epic_pmr2; + u_long epic_harx1; + u_long epic_harx2; + u_long epic_pmlt; + u_long epic_tag0; + u_long epic_tag1; + u_long epic_tag2; + u_long epic_tag3; + u_long epic_tag4; + u_long epic_tag5; + u_long epic_tag6; + u_long epic_tag7; + u_long epic_data0; + u_long epic_data1; + u_long epic_data2; + u_long epic_data3; + u_long epic_data4; + u_long epic_data5; + u_long epic_data6; + u_long epic_data7; +}; + +#define RTC_PORT(x) (0x70 + (x)) +#define RTC_ADDR(x) (0x80 | (x)) +#ifdef CONFIG_ALPHA_RUFFIAN +#define RTC_ALWAYS_BCD 1 +#else /* RUFFIAN */ +#define RTC_ALWAYS_BCD 0 +#endif /* RUFFIAN */ + +#endif /* __ALPHA_PYXIS__H__ */ diff --git a/include/asm-alpha/shmparam.h b/include/asm-alpha/shmparam.h index 22f97fab11ef..beb579c28de2 100644 --- a/include/asm-alpha/shmparam.h +++ b/include/asm-alpha/shmparam.h @@ -2,14 +2,10 @@ #define _ASMAXP_SHMPARAM_H /* - * Address range for shared memory attaches if no address passed to - * shmat(). These ought to be changed to something >4GB so 32-bit - * errors are caught more easily. However, they don't seem to be used - * except for ELF stuff, so it's not really critical until we get ELF - * support for the Alpha. + * Address range for shared memory attaches if no address passed to shmat(). */ -#define SHM_RANGE_START 0x50000000 -#define SHM_RANGE_END 0x60000000 +#define SHM_RANGE_START 0x14000000000 +#define SHM_RANGE_END 0x15000000000 /* * Format of a swap-entry for shared memory pages currently out in diff --git a/include/asm-alpha/system.h b/include/asm-alpha/system.h index db9c62a7d214..d67108caa42a 100644 --- a/include/asm-alpha/system.h +++ b/include/asm-alpha/system.h @@ -52,6 +52,8 @@ extern void wrusp(unsigned long); extern unsigned long rdusp(void); extern unsigned long rdmces (void); extern void wrmces (unsigned long); +extern unsigned long whami(void); +extern void wripir(unsigned long); #define halt() __asm__ __volatile__ ("call_pal %0" : : "i" (PAL_halt) : "memory") diff --git a/include/asm-alpha/t2.h b/include/asm-alpha/t2.h new file mode 100644 index 000000000000..a86f02a4f0df --- /dev/null +++ b/include/asm-alpha/t2.h @@ -0,0 +1,654 @@ +#ifndef __ALPHA_T2__H__ +#define __ALPHA_T2__H__ + +#include +#include + +/* + * T2 is the internal name for the core logic chipset which provides + * memory controller and PCI access for the SABLE-based systems. + * + * This file is based on: + * + * SABLE I/O Specification + * Revision/Update Information: 1.3 + * + * jestabro@amt.tay1.dec.com Initial Version. + * + */ + +#define BYTE_ENABLE_SHIFT 5 +#define TRANSFER_LENGTH_SHIFT 3 +#define MEM_R1_MASK 0x03ffffff /* Mem sparse space region 1 mask is 26 bits */ + +#ifdef CONFIG_ALPHA_SRM_SETUP +/* if we are using the SRM PCI setup, we'll need to use variables instead */ +#define T2_DMA_WIN_BASE_DEFAULT (1024*1024*1024) +#define T2_DMA_WIN_SIZE_DEFAULT (1024*1024*1024) + +extern unsigned int T2_DMA_WIN_BASE; +extern unsigned int T2_DMA_WIN_SIZE; + +#else /* SRM_SETUP */ +#define T2_DMA_WIN_BASE (1024*1024*1024) +#define T2_DMA_WIN_SIZE (1024*1024*1024) +#endif /* SRM_SETUP */ + +/* GAMMA-SABLE is a SABLE with EV5-based CPUs */ +#ifdef CONFIG_ALPHA_GAMMA +# define GAMMA_BIAS 0x8000000000UL +#else /* GAMMA */ +# define GAMMA_BIAS 0x0000000000UL +#endif /* GAMMA */ + +/* + * Memory spaces: + */ +#define T2_CONF (IDENT_ADDR + GAMMA_BIAS + 0x390000000UL) +#define T2_IO (IDENT_ADDR + GAMMA_BIAS + 0x3a0000000UL) +#define T2_SPARSE_MEM (IDENT_ADDR + GAMMA_BIAS + 0x200000000UL) +#define T2_DENSE_MEM (IDENT_ADDR + GAMMA_BIAS + 0x3c0000000UL) + +#define T2_IOCSR (IDENT_ADDR + GAMMA_BIAS + 0x38e000000UL) +#define T2_CERR1 (IDENT_ADDR + GAMMA_BIAS + 0x38e000020UL) +#define T2_CERR2 (IDENT_ADDR + GAMMA_BIAS + 0x38e000040UL) +#define T2_CERR3 (IDENT_ADDR + GAMMA_BIAS + 0x38e000060UL) +#define T2_PERR1 (IDENT_ADDR + GAMMA_BIAS + 0x38e000080UL) +#define T2_PERR2 (IDENT_ADDR + GAMMA_BIAS + 0x38e0000a0UL) +#define T2_PSCR (IDENT_ADDR + GAMMA_BIAS + 0x38e0000c0UL) +#define T2_HAE_1 (IDENT_ADDR + GAMMA_BIAS + 0x38e0000e0UL) +#define T2_HAE_2 (IDENT_ADDR + GAMMA_BIAS + 0x38e000100UL) +#define T2_HBASE (IDENT_ADDR + GAMMA_BIAS + 0x38e000120UL) +#define T2_WBASE1 (IDENT_ADDR + GAMMA_BIAS + 0x38e000140UL) +#define T2_WMASK1 (IDENT_ADDR + GAMMA_BIAS + 0x38e000160UL) +#define T2_TBASE1 (IDENT_ADDR + GAMMA_BIAS + 0x38e000180UL) +#define T2_WBASE2 (IDENT_ADDR + GAMMA_BIAS + 0x38e0001a0UL) +#define T2_WMASK2 (IDENT_ADDR + GAMMA_BIAS + 0x38e0001c0UL) +#define T2_TBASE2 (IDENT_ADDR + GAMMA_BIAS + 0x38e0001e0UL) +#define T2_TLBBR (IDENT_ADDR + GAMMA_BIAS + 0x38e000200UL) + +#define T2_HAE_3 (IDENT_ADDR + GAMMA_BIAS + 0x38e000240UL) +#define T2_HAE_4 (IDENT_ADDR + GAMMA_BIAS + 0x38e000260UL) + +#define HAE_ADDRESS T2_HAE_1 + +/* T2 CSRs are in the non-cachable primary IO space from 3.8000.0000 to + 3.8fff.ffff + * + * +--------------+ 3 8000 0000 + * | CPU 0 CSRs | + * +--------------+ 3 8100 0000 + * | CPU 1 CSRs | + * +--------------+ 3 8200 0000 + * | CPU 2 CSRs | + * +--------------+ 3 8300 0000 + * | CPU 3 CSRs | + * +--------------+ 3 8400 0000 + * | CPU Reserved | + * +--------------+ 3 8700 0000 + * | Mem Reserved | + * +--------------+ 3 8800 0000 + * | Mem 0 CSRs | + * +--------------+ 3 8900 0000 + * | Mem 1 CSRs | + * +--------------+ 3 8a00 0000 + * | Mem 2 CSRs | + * +--------------+ 3 8b00 0000 + * | Mem 3 CSRs | + * +--------------+ 3 8c00 0000 + * | Mem Reserved | + * +--------------+ 3 8e00 0000 + * | PCI Bridge | + * +--------------+ 3 8f00 0000 + * | Expansion IO | + * +--------------+ 3 9000 0000 + * + * + */ +#define CPU0_BASE (IDENT_ADDR + GAMMA_BIAS + 0x380000000L) +#define CPU1_BASE (IDENT_ADDR + GAMMA_BIAS + 0x381000000L) +#define CPU2_BASE (IDENT_ADDR + GAMMA_BIAS + 0x382000000L) +#define CPU3_BASE (IDENT_ADDR + GAMMA_BIAS + 0x383000000L) +#define MEM0_BASE (IDENT_ADDR + GAMMA_BIAS + 0x388000000L) +#define MEM1_BASE (IDENT_ADDR + GAMMA_BIAS + 0x389000000L) +#define MEM2_BASE (IDENT_ADDR + GAMMA_BIAS + 0x38a000000L) +#define MEM3_BASE (IDENT_ADDR + GAMMA_BIAS + 0x38b000000L) + +#ifdef __KERNEL__ + +/* + * Translate physical memory address as seen on (PCI) bus into + * a kernel virtual address and vv. + */ +extern inline unsigned long virt_to_bus(void * address) +{ + return virt_to_phys(address) + T2_DMA_WIN_BASE; +} + +extern inline void * bus_to_virt(unsigned long address) +{ + return phys_to_virt(address - T2_DMA_WIN_BASE); +} + +/* + * I/O functions: + * + * T2 (the core logic PCI/memory support chipset for the SABLE + * series of processors uses a sparse address mapping scheme to + * get at PCI memory and I/O. + */ + +#define vuip volatile unsigned int * + +extern inline unsigned int __inb(unsigned long addr) +{ + long result = *(vuip) ((addr << 5) + T2_IO + 0x00); + result >>= (addr & 3) * 8; + return 0xffUL & result; +} + +extern inline void __outb(unsigned char b, unsigned long addr) +{ + unsigned int w; + + asm ("insbl %2,%1,%0" : "r="(w) : "ri"(addr & 0x3), "r"(b)); + *(vuip) ((addr << 5) + T2_IO + 0x00) = w; + mb(); +} + +extern inline unsigned int __inw(unsigned long addr) +{ + long result = *(vuip) ((addr << 5) + T2_IO + 0x08); + result >>= (addr & 3) * 8; + return 0xffffUL & result; +} + +extern inline void __outw(unsigned short b, unsigned long addr) +{ + unsigned int w; + + asm ("inswl %2,%1,%0" : "r="(w) : "ri"(addr & 0x3), "r"(b)); + *(vuip) ((addr << 5) + T2_IO + 0x08) = w; + mb(); +} + +extern inline unsigned int __inl(unsigned long addr) +{ + return *(vuip) ((addr << 5) + T2_IO + 0x18); +} + +extern inline void __outl(unsigned int b, unsigned long addr) +{ + *(vuip) ((addr << 5) + T2_IO + 0x18) = b; + mb(); +} + + +/* + * Memory functions. 64-bit and 32-bit accesses are done through + * dense memory space, everything else through sparse space. + * + * For reading and writing 8 and 16 bit quantities we need to + * go through one of the three sparse address mapping regions + * and use the HAE_MEM CSR to provide some bits of the address. + * The following few routines use only sparse address region 1 + * which gives 1Gbyte of accessible space which relates exactly + * to the amount of PCI memory mapping *into* system address space. + * See p 6-17 of the specification but it looks something like this: + * + * 21164 Address: + * + * 3 2 1 + * 9876543210987654321098765432109876543210 + * 1ZZZZ0.PCI.QW.Address............BBLL + * + * ZZ = SBZ + * BB = Byte offset + * LL = Transfer length + * + * PCI Address: + * + * 3 2 1 + * 10987654321098765432109876543210 + * HHH....PCI.QW.Address........ 00 + * + * HHH = 31:29 HAE_MEM CSR + * + */ +#ifdef CONFIG_ALPHA_SRM_SETUP + +extern unsigned long t2_sm_base; + +extern inline unsigned long __readb(unsigned long addr) +{ + unsigned long result, shift, work; + + if ((addr >= t2_sm_base) && (addr <= (t2_sm_base + MEM_R1_MASK))) + work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x00); + else + if ((addr >= 512*1024) && (addr < 1024*1024)) /* check HOLE */ + work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x00); + else + { +#if 0 + printk("__readb: address 0x%lx not covered by HAE\n", addr); +#endif + return 0x0ffUL; + } + shift = (addr & 0x3) << 3; + result = *(vuip) work; + result >>= shift; + return 0x0ffUL & result; +} + +extern inline unsigned long __readw(unsigned long addr) +{ + unsigned long result, shift, work; + + if ((addr >= t2_sm_base) && (addr <= (t2_sm_base + MEM_R1_MASK))) + work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x08); + else + if ((addr >= 512*1024) && (addr < 1024*1024)) /* check HOLE */ + work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x08); + else + { +#if 0 + printk("__readw: address 0x%lx not covered by HAE\n", addr); +#endif + return 0x0ffffUL; + } + shift = (addr & 0x3) << 3; + result = *(vuip) work; + result >>= shift; + return 0x0ffffUL & result; +} + +/* on SABLE with T2, we must use SPARSE memory even for 32-bit access */ +extern inline unsigned long __readl(unsigned long addr) +{ + unsigned long result, work; + + if ((addr >= t2_sm_base) && (addr <= (t2_sm_base + MEM_R1_MASK))) + work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x18); + else + if ((addr >= 512*1024) && (addr < 1024*1024)) /* check HOLE */ + work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x18); + else + { +#if 0 + printk("__readl: address 0x%lx not covered by HAE\n", addr); +#endif + return 0x0ffffffffUL; + } + result = *(vuip) work; + return 0xffffffffUL & result; +} + +extern inline void __writeb(unsigned char b, unsigned long addr) +{ + unsigned long work; + + if ((addr >= t2_sm_base) && (addr <= (t2_sm_base + MEM_R1_MASK))) + work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x00); + else + if ((addr >= 512*1024) && (addr < 1024*1024)) /* check HOLE */ + work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x00); + else + { +#if 0 + printk("__writeb: address 0x%lx not covered by HAE\n", addr); +#endif + return; + } + *(vuip) work = b * 0x01010101; +} + +extern inline void __writew(unsigned short b, unsigned long addr) +{ + unsigned long work; + + if ((addr >= t2_sm_base) && (addr <= (t2_sm_base + MEM_R1_MASK))) + work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x08); + else + if ((addr >= 512*1024) && (addr < 1024*1024)) /* check HOLE */ + work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x08); + else + { +#if 0 + printk("__writew: address 0x%lx not covered by HAE\n", addr); +#endif + return; + } + *(vuip) work = b * 0x00010001; +} + +/* on SABLE with T2, we must use SPARSE memory even for 32-bit access */ +extern inline void __writel(unsigned int b, unsigned long addr) +{ + unsigned long work; + + if ((addr >= t2_sm_base) && (addr <= (t2_sm_base + MEM_R1_MASK))) + work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x18); + else + if ((addr >= 512*1024) && (addr < 1024*1024)) /* check HOLE */ + work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x18); + { +#if 0 + printk("__writel: address 0x%lx not covered by HAE\n", addr); +#endif + return; + } + *(vuip) work = b; +} + +#else /* SRM_SETUP */ + +extern inline unsigned long __readb(unsigned long addr) +{ + unsigned long result, shift, msb; + + shift = (addr & 0x3) * 8 ; + msb = addr & 0xE0000000 ; + addr &= MEM_R1_MASK ; + if (msb != hae.cache) { + set_hae(msb); + } + result = *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x00) ; + result >>= shift; + return 0xffUL & result; +} + +extern inline unsigned long __readw(unsigned long addr) +{ + unsigned long result, shift, msb; + + shift = (addr & 0x3) * 8; + msb = addr & 0xE0000000 ; + addr &= MEM_R1_MASK ; + if (msb != hae.cache) { + set_hae(msb); + } + result = *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x08); + result >>= shift; + return 0xffffUL & result; +} + +/* on SABLE with T2, we must use SPARSE memory even for 32-bit access */ +extern inline unsigned long __readl(unsigned long addr) +{ + unsigned long result, msb; + + msb = addr & 0xE0000000 ; + addr &= MEM_R1_MASK ; + if (msb != hae.cache) { + set_hae(msb); + } + result = *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x18); + return 0xffffffffUL & result; +} + +extern inline void __writeb(unsigned char b, unsigned long addr) +{ + unsigned long msb ; + + msb = addr & 0xE0000000 ; + addr &= MEM_R1_MASK ; + if (msb != hae.cache) { + set_hae(msb); + } + *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x00) = b * 0x01010101; +} + +extern inline void __writew(unsigned short b, unsigned long addr) +{ + unsigned long msb ; + + msb = addr & 0xE0000000 ; + addr &= MEM_R1_MASK ; + if (msb != hae.cache) { + set_hae(msb); + } + *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x08) = b * 0x00010001; +} + +/* on SABLE with T2, we must use SPARSE memory even for 32-bit access */ +extern inline void __writel(unsigned int b, unsigned long addr) +{ + unsigned long msb ; + + msb = addr & 0xE0000000 ; + addr &= MEM_R1_MASK ; + if (msb != hae.cache) { + set_hae(msb); + } + *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x18) = b; +} + +#endif /* SRM_SETUP */ + +#define inb(port) \ +(__builtin_constant_p((port))?__inb(port):_inb(port)) + +#define outb(x, port) \ +(__builtin_constant_p((port))?__outb((x),(port)):_outb((x),(port))) + +#define readl(a) __readl((unsigned long)(a)) +#define writel(v,a) __writel((v),(unsigned long)(a)) + +#undef vuip + +extern unsigned long t2_init (unsigned long mem_start, + unsigned long mem_end); + +#endif /* __KERNEL__ */ + +/* + * Sable CPU Module CSRS + * + * These are CSRs for hardware other than the CPU chip on the CPU module. + * The CPU module has Backup Cache control logic, Cbus control logic, and + * interrupt control logic on it. There is a duplicate tag store to speed + * up maintaining cache coherency. + */ + +struct sable_cpu_csr { +unsigned long bcc; long fill_00[3]; /* Backup Cache Control */ +unsigned long bcce; long fill_01[3]; /* Backup Cache Correctable Error */ +unsigned long bccea; long fill_02[3]; /* B-Cache Corr Err Address Latch */ +unsigned long bcue; long fill_03[3]; /* B-Cache Uncorrectable Error */ +unsigned long bcuea; long fill_04[3]; /* B-Cache Uncorr Err Addr Latch */ +unsigned long dter; long fill_05[3]; /* Duplicate Tag Error */ +unsigned long cbctl; long fill_06[3]; /* CBus Control */ +unsigned long cbe; long fill_07[3]; /* CBus Error */ +unsigned long cbeal; long fill_08[3]; /* CBus Error Addr Latch low */ +unsigned long cbeah; long fill_09[3]; /* CBus Error Addr Latch high */ +unsigned long pmbx; long fill_10[3]; /* Processor Mailbox */ +unsigned long ipir; long fill_11[3]; /* Inter-Processor Int Request */ +unsigned long sic; long fill_12[3]; /* System Interrupt Clear */ +unsigned long adlk; long fill_13[3]; /* Address Lock (LDxL/STxC) */ +unsigned long madrl; long fill_14[3]; /* CBus Miss Address */ +unsigned long rev; long fill_15[3]; /* CMIC Revision */ +}; + +/* + * Data structure for handling T2 machine checks: + */ +struct el_t2_frame_header { + unsigned int elcf_fid; /* Frame ID (from above) */ + unsigned int elcf_size; /* Size of frame in bytes */ +}; + +struct el_t2_procdata_mcheck { + unsigned long elfmc_paltemp[32]; /* PAL TEMP REGS. */ + /* EV4-specific fields */ + unsigned long elfmc_exc_addr; /* Addr of excepting insn. */ + unsigned long elfmc_exc_sum; /* Summary of arith traps. */ + unsigned long elfmc_exc_mask; /* Exception mask (from exc_sum). */ + unsigned long elfmc_iccsr; /* IBox hardware enables. */ + unsigned long elfmc_pal_base; /* Base address for PALcode. */ + unsigned long elfmc_hier; /* Hardware Interrupt Enable. */ + unsigned long elfmc_hirr; /* Hardware Interrupt Request. */ + unsigned long elfmc_mm_csr; /* D-stream fault info. */ + unsigned long elfmc_dc_stat; /* D-cache status (ECC/Parity Err). */ + unsigned long elfmc_dc_addr; /* EV3 Phys Addr for ECC/DPERR. */ + unsigned long elfmc_abox_ctl; /* ABox Control Register. */ + unsigned long elfmc_biu_stat; /* BIU Status. */ + unsigned long elfmc_biu_addr; /* BUI Address. */ + unsigned long elfmc_biu_ctl; /* BIU Control. */ + unsigned long elfmc_fill_syndrome; /* For correcting ECC errors. */ + unsigned long elfmc_fill_addr;/* Cache block which was being read. */ + unsigned long elfmc_va; /* Effective VA of fault or miss. */ + unsigned long elfmc_bc_tag; /* Backup Cache Tag Probe Results. */ +}; + +/* + * Sable processor specific Machine Check Data segment. + */ + +struct el_t2_logout_header { + unsigned int elfl_size; /* size in bytes of logout area. */ + int elfl_sbz1:31; /* Should be zero. */ + char elfl_retry:1; /* Retry flag. */ + unsigned int elfl_procoffset; /* Processor-specific offset. */ + unsigned int elfl_sysoffset; /* Offset of system-specific. */ + unsigned int elfl_error_type; /* PAL error type code. */ + unsigned int elfl_frame_rev; /* PAL Frame revision. */ +}; +struct el_t2_sysdata_mcheck { + unsigned long elcmc_bcc; /* CSR 0 */ + unsigned long elcmc_bcce; /* CSR 1 */ + unsigned long elcmc_bccea; /* CSR 2 */ + unsigned long elcmc_bcue; /* CSR 3 */ + unsigned long elcmc_bcuea; /* CSR 4 */ + unsigned long elcmc_dter; /* CSR 5 */ + unsigned long elcmc_cbctl; /* CSR 6 */ + unsigned long elcmc_cbe; /* CSR 7 */ + unsigned long elcmc_cbeal; /* CSR 8 */ + unsigned long elcmc_cbeah; /* CSR 9 */ + unsigned long elcmc_pmbx; /* CSR 10 */ + unsigned long elcmc_ipir; /* CSR 11 */ + unsigned long elcmc_sic; /* CSR 12 */ + unsigned long elcmc_adlk; /* CSR 13 */ + unsigned long elcmc_madrl; /* CSR 14 */ + unsigned long elcmc_crrev4; /* CSR 15 */ +}; + +/* + * Sable memory error frame - sable pfms section 3.42 + */ +struct el_t2_data_memory { + struct el_t2_frame_header elcm_hdr; /* ID$MEM-FERR = 0x08 */ + unsigned int elcm_module; /* Module id. */ + unsigned int elcm_res04; /* Reserved. */ + unsigned long elcm_merr; /* CSR0: Error Reg 1. */ + unsigned long elcm_mcmd1; /* CSR1: Command Trap 1. */ + unsigned long elcm_mcmd2; /* CSR2: Command Trap 2. */ + unsigned long elcm_mconf; /* CSR3: Configuration. */ + unsigned long elcm_medc1; /* CSR4: EDC Status 1. */ + unsigned long elcm_medc2; /* CSR5: EDC Status 2. */ + unsigned long elcm_medcc; /* CSR6: EDC Control. */ + unsigned long elcm_msctl; /* CSR7: Stream Buffer Control. */ + unsigned long elcm_mref; /* CSR8: Refresh Control. */ + unsigned long elcm_filter; /* CSR9: CRD Filter Control. */ +}; + + +/* + * Sable other cpu error frame - sable pfms section 3.43 + */ +struct el_t2_data_other_cpu { + short elco_cpuid; /* CPU ID */ + short elco_res02[3]; + unsigned long elco_bcc; /* CSR 0 */ + unsigned long elco_bcce; /* CSR 1 */ + unsigned long elco_bccea; /* CSR 2 */ + unsigned long elco_bcue; /* CSR 3 */ + unsigned long elco_bcuea; /* CSR 4 */ + unsigned long elco_dter; /* CSR 5 */ + unsigned long elco_cbctl; /* CSR 6 */ + unsigned long elco_cbe; /* CSR 7 */ + unsigned long elco_cbeal; /* CSR 8 */ + unsigned long elco_cbeah; /* CSR 9 */ + unsigned long elco_pmbx; /* CSR 10 */ + unsigned long elco_ipir; /* CSR 11 */ + unsigned long elco_sic; /* CSR 12 */ + unsigned long elco_adlk; /* CSR 13 */ + unsigned long elco_madrl; /* CSR 14 */ + unsigned long elco_crrev4; /* CSR 15 */ +}; + +/* + * Sable other cpu error frame - sable pfms section 3.44 + */ +struct el_t2_data_t2{ + struct el_t2_frame_header elct_hdr; /* ID$T2-FRAME */ + unsigned long elct_iocsr; /* IO Control and Status Register */ + unsigned long elct_cerr1; /* Cbus Error Register 1 */ + unsigned long elct_cerr2; /* Cbus Error Register 2 */ + unsigned long elct_cerr3; /* Cbus Error Register 3 */ + unsigned long elct_perr1; /* PCI Error Register 1 */ + unsigned long elct_perr2; /* PCI Error Register 2 */ + unsigned long elct_hae0_1; /* High Address Extension Register 1 */ + unsigned long elct_hae0_2; /* High Address Extension Register 2 */ + unsigned long elct_hbase; /* High Base Register */ + unsigned long elct_wbase1; /* Window Base Register 1 */ + unsigned long elct_wmask1; /* Window Mask Register 1 */ + unsigned long elct_tbase1; /* Translated Base Register 1 */ + unsigned long elct_wbase2; /* Window Base Register 2 */ + unsigned long elct_wmask2; /* Window Mask Register 2 */ + unsigned long elct_tbase2; /* Translated Base Register 2 */ + unsigned long elct_tdr0; /* TLB Data Register 0 */ + unsigned long elct_tdr1; /* TLB Data Register 1 */ + unsigned long elct_tdr2; /* TLB Data Register 2 */ + unsigned long elct_tdr3; /* TLB Data Register 3 */ + unsigned long elct_tdr4; /* TLB Data Register 4 */ + unsigned long elct_tdr5; /* TLB Data Register 5 */ + unsigned long elct_tdr6; /* TLB Data Register 6 */ + unsigned long elct_tdr7; /* TLB Data Register 7 */ +}; + +/* + * Sable error log data structure - sable pfms section 3.40 + */ +struct el_t2_data_corrected { + unsigned long elcpb_biu_stat; + unsigned long elcpb_biu_addr; + unsigned long elcpb_biu_ctl; + unsigned long elcpb_fill_syndrome; + unsigned long elcpb_fill_addr; + unsigned long elcpb_bc_tag; +}; + +/* + * Sable error log data structure + * Note there are 4 memory slots on sable (see t2.h) + */ +struct el_t2_frame_mcheck { + struct el_t2_frame_header elfmc_header; /* ID$P-FRAME_MCHECK */ + struct el_t2_logout_header elfmc_hdr; + struct el_t2_procdata_mcheck elfmc_procdata; + struct el_t2_sysdata_mcheck elfmc_sysdata; + struct el_t2_data_t2 elfmc_t2data; + struct el_t2_data_memory elfmc_memdata[4]; + struct el_t2_frame_header elfmc_footer; /* empty */ +}; + + +/* + * Sable error log data structures on memory errors + */ +struct el_t2_frame_corrected { + struct el_t2_frame_header elfcc_header; /* ID$P-BC-COR */ + struct el_t2_logout_header elfcc_hdr; + struct el_t2_data_corrected elfcc_procdata; +/* struct el_t2_data_t2 elfcc_t2data; */ +/* struct el_t2_data_memory elfcc_memdata[4]; */ + struct el_t2_frame_header elfcc_footer; /* empty */ +}; + + +#define RTC_PORT(x) (0x70 + (x)) +#define RTC_ADDR(x) (0x80 | (x)) +#define RTC_ALWAYS_BCD 0 + +#endif /* __ALPHA_T2__H__ */ diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h index 7f6da89fb7e6..7b851a1bd3c7 100644 --- a/include/asm-i386/processor.h +++ b/include/asm-i386/processor.h @@ -40,6 +40,8 @@ extern int EISA_bus; * so don't change it unless you know what you are doing. */ #define TASK_SIZE (0xC0000000UL) +#define MAX_USER_ADDR TASK_SIZE +#define MMAP_SEARCH_START (TASK_SIZE/3) /* * Size of io_bitmap in longwords: 32 is ports 0-0x3ff. diff --git a/include/asm-m68k/processor.h b/include/asm-m68k/processor.h index a87ab5bf1f48..ccfa1ddfb83a 100644 --- a/include/asm-m68k/processor.h +++ b/include/asm-m68k/processor.h @@ -14,6 +14,8 @@ * so don't change it unless you know what you are doing. */ #define TASK_SIZE (0xF0000000UL) +#define MAX_USER_ADDR TASK_SIZE +#define MMAP_SEARCH_START (TASK_SIZE/3) /* * Bus types diff --git a/include/asm-mips/processor.h b/include/asm-mips/processor.h index b6ba4c03954c..26048cdc1935 100644 --- a/include/asm-mips/processor.h +++ b/include/asm-mips/processor.h @@ -44,6 +44,8 @@ extern int EISA_bus; * so don't change it unless you know what you are doing. */ #define TASK_SIZE (0x80000000UL) +#define MAX_USER_ADDR TASK_SIZE +#define MMAP_SEARCH_START (TASK_SIZE/3) /* * Size of io_bitmap in longwords: 32 is ports 0-0x3ff. diff --git a/include/asm-ppc/processor.h b/include/asm-ppc/processor.h index dc653912aa3b..9e94b50e513d 100644 --- a/include/asm-ppc/processor.h +++ b/include/asm-ppc/processor.h @@ -80,6 +80,8 @@ static inline void start_thread(struct pt_regs * regs, unsigned long eip, unsign * "this is gonna have to change to 1gig for the sparc" - David S. Miller */ #define TASK_SIZE (0x80000000UL) +#define MAX_USER_ADDR TASK_SIZE +#define MMAP_SEARCH_START (TASK_SIZE/3) struct thread_struct { diff --git a/include/asm-sparc/processor.h b/include/asm-sparc/processor.h index b06e267c9a45..8e8e1fa69ab8 100644 --- a/include/asm-sparc/processor.h +++ b/include/asm-sparc/processor.h @@ -31,6 +31,8 @@ /* Whee, this is STACK_TOP and the lowest kernel address too... */ #define TASK_SIZE (KERNBASE) +#define MAX_USER_ADDR TASK_SIZE +#define MMAP_SEARCH_START (TASK_SIZE/3) /* The Sparc processor specific thread struct. */ struct thread_struct { diff --git a/include/linux/fs.h b/include/linux/fs.h index c0f49f57d672..8492c3657a97 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -313,7 +313,7 @@ struct inode { unsigned char i_sock; unsigned char i_seek; unsigned char i_update; - unsigned char i_condemned; + unsigned char i_condemned; union { struct pipe_inode_info pipe_i; struct minix_inode_info minix_i; diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 535cdefdc531..8075af6a558a 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -21,10 +21,11 @@ #define CONFIG_SUN_PARTITION 1 #endif -/* These two have identical behaviour; use the second one if DOS fdisk gets +/* These three have identical behaviour; use the second one if DOS fdisk gets confused about extended/logical partitions starting past cylinder 1023. */ #define DOS_EXTENDED_PARTITION 5 #define LINUX_EXTENDED_PARTITION 0x85 +#define WIN98_EXTENDED_PARTITION 0x0f #define DM6_PARTITION 0x54 /* has DDO: use xlated geom & offset */ #define EZD_PARTITION 0x55 /* EZ-DRIVE: same as DM6 (we think) */ diff --git a/include/linux/ioport.h b/include/linux/ioport.h index 335e3b65f763..293b46870f37 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -24,7 +24,7 @@ extern int get_ioport_list(char *); #define HAVE_AUTOIRQ -extern void *irq2dev_map[16]; /* Use only if you own the IRQ. */ +extern void *irq2dev_map[]; /* Use only if you own the IRQ. */ extern int autoirq_setup(int waittime); extern int autoirq_report(int waittime); diff --git a/include/linux/lists.h b/include/linux/lists.h index 04f905aaf086..6a2240a2059e 100644 --- a/include/linux/lists.h +++ b/include/linux/lists.h @@ -13,7 +13,7 @@ #define DLIST_INIT(listnam) \ (listnam).dl_prev = &(listnam); \ - (listnam).dl_last = &(listnam); + (listnam).dl_next = &(listnam); #define DLIST_NEXT(listnam) listnam.dl_next #define DLIST_PREV(listnam) listnam.dl_prev @@ -38,3 +38,25 @@ node->listnam.dl_next->listnam.dl_prev = \ node->listnam.dl_prev; \ } while (0) + +/* + * queue-style operations, which have a head and tail + */ + +#define QUEUE_INIT(head, listnam, ptype) \ + (head)->listnam.dl_prev = (head)->listnam.dl_next = (ptype)(head); + +#define QUEUE_FIRST(head, listnam) (head)->DLIST_NEXT(listnam) +#define QUEUE_LAST(head, listnam) (head)->DLIST_PREV(listnam) +#define QUEUE_EMPTY(head, listnam) \ + ((QUEUE_FIRST(head, listnam) == QUEUE_LAST(head, listnam)) && \ + ((u_long)QUEUE_FIRST(head, listnam) == (u_long)head)) + +#define QUEUE_ENTER(head, new, listnam, ptype) do { \ + (new)->listnam.dl_prev = (ptype)(head); \ + (new)->listnam.dl_next = (head)->listnam.dl_next; \ + (head)->listnam.dl_next->listnam.dl_prev = (new); \ + (head)->listnam.dl_next = (new); \ + } while (0) + +#define QUEUE_REMOVE(head, node, listnam) DLIST_DELETE(node, listnam) diff --git a/include/linux/mc146818rtc.h b/include/linux/mc146818rtc.h index e870910c4958..0a2efb6e930d 100644 --- a/include/linux/mc146818rtc.h +++ b/include/linux/mc146818rtc.h @@ -142,6 +142,8 @@ struct rtc_time { #define RTC_SET_TIME _IOW('p', 0x0a, struct rtc_time) /* Set RTC time */ #define RTC_IRQP_READ _IOR('p', 0x0b, unsigned long) /* Read IRQ rate */ #define RTC_IRQP_SET _IOW('p', 0x0c, unsigned long) /* Set IRQ rate */ +#define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long) /* Read epoch */ +#define RTC_EPOCH_SET _IOW('p', 0x0e, unsigned long) /* Set epoch */ #endif /* _MC146818RTC_H */ diff --git a/include/linux/personality.h b/include/linux/personality.h index 91538d2bde3c..14df1888dca4 100644 --- a/include/linux/personality.h +++ b/include/linux/personality.h @@ -8,12 +8,16 @@ /* Flags for bug emulation. These occupy the top three bytes. */ #define STICKY_TIMEOUTS 0x4000000 #define WHOLE_SECONDS 0x2000000 +#define ADDR_MAX_32BIT 0x1000000 +#define ADDR_MAX_31BIT 0x0800000 /* Personality types. These go in the low byte. Avoid using the top bit, * it will conflict with error returns. */ #define PER_MASK (0x00ff) #define PER_LINUX (0x0000) +#define PER_LINUX_32BIT (PER_LINUX | ADDR_MAX_32BIT) +#define PER_LINUX_EM86 (PER_LINUX | ADDR_MAX_31BIT) #define PER_SVR4 (0x0001 | STICKY_TIMEOUTS) #define PER_SVR3 (0x0002 | STICKY_TIMEOUTS) #define PER_SCOSVR3 (0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS) diff --git a/include/linux/swap.h b/include/linux/swap.h index 6cfb7df0bb9d..47851e7a0d09 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -16,11 +16,14 @@ #define SWAP_CLUSTER_MAX 32 +#define SWAP_MAP_MAX 0xfffe /* max val of swapinfo->swap_map[n] */ +#define SWAP_MAP_RESERVED 0xffff /* max val of swapinfo->swap_map[n] */ + struct swap_info_struct { unsigned int flags; kdev_t swap_device; struct inode * swap_file; - unsigned char * swap_map; + unsigned short * swap_map; unsigned char * swap_lockmap; int lowest_bit; int highest_bit; diff --git a/include/scsi/scsi_ioctl.h b/include/scsi/scsi_ioctl.h index aa6577d741f9..a90abf633ec8 100644 --- a/include/scsi/scsi_ioctl.h +++ b/include/scsi/scsi_ioctl.h @@ -19,6 +19,7 @@ extern int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg); extern int kernel_scsi_ioctl (Scsi_Device *dev, int cmd, void *arg); +extern int scsi_ioctl_send_command(Scsi_Device *dev, void *buffer); #endif diff --git a/init/main.c b/init/main.c index a9750b55712d..f94032497688 100644 --- a/init/main.c +++ b/init/main.c @@ -454,7 +454,7 @@ static void ramdisk_start_setup(char *str, int *ints) static void load_ramdisk(char *str, int *ints) { if (ints[0] > 0 && ints[1] >= 0) - rd_doload = ints[1] & 1; + rd_doload = ints[1] & 3; } static void prompt_ramdisk(char *str, int *ints) diff --git a/ipc/shm.c b/ipc/shm.c index c92914a0cc1c..8436259468b1 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -494,10 +494,10 @@ asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr) return -EINVAL; } /* - * Check if addr exceeds TASK_SIZE (from do_mmap) + * Check if addr exceeds MAX_USER_ADDR (from do_mmap) */ len = PAGE_SIZE*shp->shm_npages; - if (addr >= TASK_SIZE || len > TASK_SIZE || addr > TASK_SIZE - len) + if (addr >= MAX_USER_ADDR || len > MAX_USER_ADDR || addr > MAX_USER_ADDR - len) return -EINVAL; /* * If shm segment goes below stack, make sure there is some diff --git a/kernel/exit.c b/kernel/exit.c index 99552fc17711..ae2bb3518857 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -660,9 +660,14 @@ repeat: if (p->pgrp != -pid) continue; } - /* wait for cloned processes iff the __WCLONE flag is set */ - if ((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0)) - continue; + /* If you are tracing a process, then you don't need to get the + * WCLONE bit right -- useful for strace and gdb + */ + if (!(p->flags & (PF_PTRACED|PF_TRACESYS))) { + /* wait for cloned processes iff the __WCLONE flag is set */ + if ((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0)) + continue; + } flag = 1; switch (p->state) { case TASK_STOPPED: diff --git a/mm/mmap.c b/mm/mmap.c index 868f6a9d41cd..962e13d731f8 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -45,7 +45,7 @@ pgprot_t protection_map[16] = { * Check that a process has enough memory to allocate a * new virtual mapping. */ -static inline int vm_enough_memory(long pages) +int vm_enough_memory(long pages) { /* * stupid algorithm to decide if we have enough memory: while @@ -147,7 +147,7 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len, if ((len = PAGE_ALIGN(len)) == 0) return addr; - if (len > TASK_SIZE || addr > TASK_SIZE-len) + if (len > MAX_USER_ADDR || addr > MAX_USER_ADDR-len) return -EINVAL; /* offset overflow? */ @@ -178,6 +178,9 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len, */ if (locks_verify_locked(file->f_inode)) return -EAGAIN; + /* cevans -- whoops another append-only file flaw */ + if (IS_APPEND(file->f_inode) && (prot & PROT_WRITE)) + return -EACCES; /* fall through */ case MAP_PRIVATE: if (!(file->f_mode & 1)) @@ -306,15 +309,15 @@ unsigned long get_unmapped_area(unsigned long addr, unsigned long len) { struct vm_area_struct * vmm; - if (len > TASK_SIZE) + if (len > MAX_USER_ADDR) return 0; if (!addr) - addr = TASK_SIZE / 3; + addr = MMAP_SEARCH_START; addr = PAGE_ALIGN(addr); for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { /* At this point: (!vmm || addr < vmm->vm_end). */ - if (TASK_SIZE - len < addr) + if (MAX_USER_ADDR - len < addr) return 0; if (!vmm || addr + len <= vmm->vm_start) return addr; @@ -794,7 +797,7 @@ int do_munmap(unsigned long addr, size_t len) { struct vm_area_struct *mpnt, *prev, *next, **npp, *free; - if ((addr & ~PAGE_MASK) || addr > TASK_SIZE || len > TASK_SIZE-addr) + if ((addr & ~PAGE_MASK) || addr > MAX_USER_ADDR || len > MAX_USER_ADDR-addr) return -EINVAL; if ((len = PAGE_ALIGN(len)) == 0) diff --git a/mm/mremap.c b/mm/mremap.c index 3284e04bbef2..b483806350e1 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -19,6 +19,8 @@ #include #include +extern int vm_enough_memory(long pages); + static inline pte_t *get_one_pte(struct mm_struct *mm, unsigned long addr) { pgd_t * pgd; @@ -173,7 +175,7 @@ asmlinkage unsigned long sys_mremap(unsigned long addr, * Always allow a shrinking remap: that just unmaps * the unnecessary pages.. */ - if (old_len > new_len) { + if (old_len >= new_len) { do_munmap(addr+new_len, old_len - new_len); return addr; } @@ -196,11 +198,16 @@ asmlinkage unsigned long sys_mremap(unsigned long addr, if ((current->mm->total_vm << PAGE_SHIFT) + (new_len - old_len) > current->rlim[RLIMIT_AS].rlim_cur) return -ENOMEM; + /* Private writable mapping? Check memory availability.. */ + if ((vma->vm_flags & (VM_SHARED | VM_WRITE)) == VM_WRITE) { + if (!vm_enough_memory((new_len - old_len) >> PAGE_SHIFT)) + return -ENOMEM; + } /* old_len exactly to the end of the area.. */ if (old_len == vma->vm_end - addr && (old_len != new_len || !(flags & MREMAP_MAYMOVE))) { - unsigned long max_addr = TASK_SIZE; + unsigned long max_addr = MAX_USER_ADDR; if (vma->vm_next) max_addr = vma->vm_next->vm_start; /* can we just expand the current mapping? */ diff --git a/mm/swap_state.c b/mm/swap_state.c index 9ca40ff9a7f5..4f2fb2a625ef 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -81,6 +81,12 @@ unsigned long init_swap_cache(unsigned long mem_start, return (unsigned long) (swap_cache + swap_cache_size); } +/* We shouldn't be able to have more processes sharing a swapped page than + we can count in the swap map */ +#if NR_TASKS > SWAP_MAP_MAX +#error SWAP_MAP_MAX is too small +#endif + void swap_duplicate(unsigned long entry) { struct swap_info_struct * p; @@ -98,14 +104,16 @@ void swap_duplicate(unsigned long entry) } p = type + swap_info; if (offset >= p->max) { - printk("swap_duplicate: weirdness\n"); - return; - } - if (!p->swap_map[offset]) { - printk("swap_duplicate: trying to duplicate unused page\n"); + printk("swap_duplicate: weirdness, entry %08lx\n", entry); return; } - p->swap_map[offset]++; + if (!p->swap_map[offset]) + printk("swap_duplicate: trying to duplicate unused page, " + "entry %08lx\n", entry); + else if (p->swap_map[offset] == SWAP_MAP_RESERVED) + printk("swap_duplicate: trying to duplicate reserved page, " + "entry %08lx\n", entry); + else p->swap_map[offset]++; return; } diff --git a/mm/swapfile.c b/mm/swapfile.c index 70d8703bf731..15384cc8bb70 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -145,9 +145,10 @@ void swap_free(unsigned long entry) if (offset > p->highest_bit) p->highest_bit = offset; if (!p->swap_map[offset]) - printk("swap_free: swap-space map bad (entry %08lx)\n",entry); - else - if (!--p->swap_map[offset]) + printk("swap_free: swap-space map null (entry %08lx)\n",entry); + else if (p->swap_map[offset] == SWAP_MAP_RESERVED) + printk("swap_free: swap-space reserved (entry %08lx)\n",entry); + else if (!--p->swap_map[offset]) nr_swap_pages++; if (p->prio > swap_info[swap_list.next].prio) { swap_list.next = swap_list.head; @@ -503,7 +504,7 @@ asmlinkage int sys_swapon(const char * specialfile, int swap_flags) error = -EINVAL; goto bad_swap; } - p->swap_map = (unsigned char *) vmalloc(p->max); + p->swap_map = (unsigned short *) vmalloc(p->max * sizeof(short)); if (!p->swap_map) { error = -ENOMEM; goto bad_swap; @@ -512,9 +513,9 @@ asmlinkage int sys_swapon(const char * specialfile, int swap_flags) if (test_bit(i,p->swap_lockmap)) p->swap_map[i] = 0; else - p->swap_map[i] = 0x80; + p->swap_map[i] = SWAP_MAP_RESERVED; } - p->swap_map[0] = 0x80; + p->swap_map[0] = SWAP_MAP_RESERVED; memset(p->swap_lockmap,0,PAGE_SIZE); p->flags = SWP_WRITEOK; p->pages = j; @@ -562,7 +563,7 @@ void si_swapinfo(struct sysinfo *val) continue; for (j = 0; j < swap_info[i].max; ++j) switch (swap_info[i].swap_map[j]) { - case 128: + case SWAP_MAP_RESERVED: continue; case 0: ++val->freeswap; diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 4f83db95a24a..6cc59a8139a9 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -1534,7 +1534,7 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags) newsk = skb->sk; newsk->pair = NULL; newsk->socket = newsock; - newsk->sleep = &newsock->wait; + newsk->sleep = newsock->wait; sti(); /* Now attach up the new socket */ diff --git a/net/core/sock.c b/net/core/sock.c index eeda476916d6..bb8760331375 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -72,6 +72,7 @@ * easier (suggested by Craig Metz). * Michael Pall : SO_ERROR returns positive errno again * Elliot Poger : Added support for SO_BINDTODEVICE. + * Russell King : Add #ifdef CONFIG_INET to SO_BINDTODEVICE * * To Fix: * @@ -247,13 +248,13 @@ int sock_setsockopt(struct sock *sk, int level, int optname, if(err) return err; memcpy_fromfs(&req,optval,sizeof(req)); - +#ifdef CONFIG_INET /* Remove any cached route for this socket. */ if (sk->ip_route_cache) { ip_rt_put(sk->ip_route_cache); sk->ip_route_cache=NULL; } - +#endif if (*(req.ifr_name) == '\0') { sk->bound_device = NULL; } else { diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 61eb8f02b145..d06dbb59a328 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -30,6 +30,8 @@ * Alan Cox : Protect against forwarding explosions with * older network drivers and IFF_ALLMULTI. * Christer Weinigel : Better rebuild header message. + * Russell King : eth_header_cache_bind and eth_header_cache_update + * only compiled if CONFIG_INET is selected * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -218,6 +220,7 @@ unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev) return htons(ETH_P_802_2); } +#ifdef CONFIG_INET /* * Upper level calls this function to bind hardware header cache entry. * If the call is successful, then corresponding Address Resolution Protocol @@ -258,6 +261,7 @@ void eth_header_cache_update(struct hh_cache *hh, struct device *dev, unsigned c memcpy(hh->hh_data, haddr, ETH_ALEN); hh->hh_uptodate = 1; } +#endif /* * Copy from an ethernet device memory space to an sk_buff while checksumming if IP diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 4fe8a32c9d74..76b52fc6dfb5 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -838,8 +838,6 @@ static int inet_getname(struct socket *sock, struct sockaddr *uaddr, __u32 addr = sk->rcv_saddr; if (!addr) { addr = sk->saddr; - if (!addr) - addr = ip_my_addr(); } sin->sin_port = sk->dummy_th.source; sin->sin_addr.s_addr = addr; diff --git a/net/ipv4/rarp.c b/net/ipv4/rarp.c index ac1f7ed35a10..dc8b276165a3 100644 --- a/net/ipv4/rarp.c +++ b/net/ipv4/rarp.c @@ -28,7 +28,9 @@ * Fixes * Alan Cox : Rarp delete on device down needed as * reported by Walter Wolfgang. - * Lawrence V. Stefani : Added FDDI support. + * Lawrence V. Stefani : Added FDDI support. + * San Mehat : Fixed bug where rarp would fail to build + * if procfs was not compiled into the kernel */ #include diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index f598c993d626..1e72c56c7ebc 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2067,9 +2067,11 @@ static struct sk_buff * wait_for_connect(struct sock * sk) add_wait_queue(sk->sleep, &wait); for (;;) { current->state = TASK_INTERRUPTIBLE; + end_bh_atomic(); release_sock(sk); schedule(); lock_sock(sk); + start_bh_atomic(); skb = tcp_find_established(sk); if (skb) break; @@ -2101,7 +2103,7 @@ static struct sock *tcp_accept(struct sock *sk, int flags) if (sk->state != TCP_LISTEN) goto no_listen; - lock_sock(sk); + lock_sock(sk);start_bh_atomic(); skb = tcp_find_established(sk); if (skb) { @@ -2112,6 +2114,7 @@ got_new_connect: sk->ack_backlog--; error = 0; out: + end_bh_atomic(); release_sock(sk); no_listen: sk->err = error; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 0b910d580821..2cd03603eaa5 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -370,7 +370,7 @@ void tcp_write_xmit(struct sock *sk) * a packet that contains both old and new data. (Feh!) * Soooo, we have this uglyness here. */ - if (after(sk->rcv_ack_seq,skb->seq+th->syn+th->fin)) + if (after(sk->rcv_ack_seq,skb->seq+th->syn)) tcp_shrink_skb(sk,skb,sk->rcv_ack_seq); size = skb->len - (((unsigned char *) th) - skb->data); @@ -487,6 +487,21 @@ void tcp_do_retransmit(struct sock *sk, int all) iph = (struct iphdr *)skb->data; th = (struct tcphdr *)(((char *)iph) + (iph->ihl << 2)); + + /* See if we need to shrink the leading packet on + * the retransmit queue. Strictly speaking, we + * should never need to do this, but some buggy TCP + * implementations get confused if you send them + * a packet that contains both old and new data. (Feh!) + * Soooo, we have this uglyness here. + * + * Is the && test needed here? If so, then it implies that + * we might be retransmitting an acked packet. This code is + * needed here to talk to Solaris 2.6 stack. + */ + if (after(sk->rcv_ack_seq,skb->seq+th->syn) && before(sk->rcv_ack_seq, skb->end_seq)) + tcp_shrink_skb(sk,skb,sk->rcv_ack_seq); + size = ntohs(iph->tot_len) - (iph->ihl<<2); /* @@ -1399,6 +1414,10 @@ void tcp_send_probe0(struct sock *sk) * Needed to deal with buggy TCP implementations that can't deal * with seeing a packet that contains some data that has already * been received. + * + * Note that the SYN sequence number is at the start of the packet + * while the FIN is at the end. This means that we always clear out + * the SYN bit, and never clear out the FIN bit. */ void tcp_shrink_skb(struct sock *sk, struct sk_buff *skb, u32 ack) { @@ -1416,9 +1435,9 @@ void tcp_shrink_skb(struct sock *sk, struct sk_buff *skb, u32 ack) th = (struct tcphdr *)(((char *)iph) +(iph->ihl << 2)); /* how much data are we droping from the tcp frame */ - diff = ack - skb->seq; + diff = ack - (skb->seq + th->syn); /* how much data are we keeping in the tcp frame */ - len = (skb->end_seq - (th->fin + th->syn)) - ack; + len = (skb->end_seq - th->fin) - ack; /* pointers to new start of remaining data, and old start */ new = (unsigned char *)th + th->doff*4; @@ -1427,6 +1446,7 @@ void tcp_shrink_skb(struct sock *sk, struct sk_buff *skb, u32 ack) /* Update our starting seq number */ skb->seq = ack; th->seq = htonl(ack); + th->syn = 0; /* Turn SYN off as it is logically at the start of the packet */ iph->tot_len = htons(ntohs(iph->tot_len)-diff); ip_send_check(iph); diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index 9bb558d90025..b183d634b26e 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -909,7 +909,7 @@ static int nr_accept(struct socket *sock, struct socket *newsock, int flags) newsk = skb->sk; newsk->pair = NULL; newsk->socket = newsock; - newsk->sleep = &newsock->wait; + newsk->sleep = newsock->wait; sti(); /* Now attach up the new socket */ diff --git a/net/netsyms.c b/net/netsyms.c index a25fe622dab9..ed2086f569be 100644 --- a/net/netsyms.c +++ b/net/netsyms.c @@ -13,6 +13,7 @@ #include #include #include +#include #ifdef CONFIG_AX25 #include diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 01f4ccd1f627..3bb14b3c0b9b 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -28,6 +28,7 @@ * Nick Nevin : recvmsg bugfix. * Alan Cox : Started proper garbage collector * Heiko EiBfeldt : Missing verify_area check + * Alan Cox : Shutdown() bug * * Known differences from reference BSD that was tested: * @@ -1155,6 +1156,9 @@ static int unix_shutdown(struct socket *sock, int mode) { unix_socket *sk=(unix_socket *)sock->data; unix_socket *other=sk->protinfo.af_unix.other; + + mode++; + if(mode&SEND_SHUTDOWN) { sk->shutdown|=SEND_SHUTDOWN; -- 2.39.5