]> git.neil.brown.name Git - history.git/commitdiff
Linux 2.2.17pre3 2.2.17pre3
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:21:34 +0000 (15:21 -0500)
committerAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:21:34 +0000 (15:21 -0500)
o Fix possible hang in TCP code under high net/ (Mark Hemment)
disk load
| Im very interested to know if this fixes some of the
| reported high load box totally hangs cases
o Fix a sparc64 problem with SABRE
o Bring the PPC port back into line (Cort Dougan, Paul Mackerras,
Benjamin Herrenschmidt, Henry Worth
| Lots of PPC fixes, DMA sound suspend fix, GMAC ethernet,
| PPC changes to de4x5 for new apple stuff, core99 fixes
| adb, rth, macserial and media bay work
o Require root for keymap reloading (Stephen Thorne)
o Fix a reported CD-ROM oops (Jens Axboe)
o Give BSD behaviour for iovec overruns (Ivan Kokshaysky)
| Also should fix OSF emulation
o Set file type on sockets in ext2 (Andreas Dilger)

90 files changed:
Makefile
arch/ppc/boot/Makefile
arch/ppc/coffboot/Makefile
arch/ppc/coffboot/chrpmain.c [new file with mode: 0644]
arch/ppc/coffboot/coffcrt0.S [new file with mode: 0644]
arch/ppc/coffboot/coffmain.c [new file with mode: 0644]
arch/ppc/coffboot/crt0.S
arch/ppc/coffboot/misc.S
arch/ppc/coffboot/mknote.c [new file with mode: 0644]
arch/ppc/coffboot/no_initrd.c [new file with mode: 0644]
arch/ppc/coffboot/piggyback.c [new file with mode: 0644]
arch/ppc/coffboot/start.c
arch/ppc/common_defconfig
arch/ppc/config.in
arch/ppc/defconfig
arch/ppc/kernel/Makefile
arch/ppc/kernel/checks.c
arch/ppc/kernel/chrp_setup.c
arch/ppc/kernel/feature.c
arch/ppc/kernel/head.S
arch/ppc/kernel/local_irq.h
arch/ppc/kernel/mbx_setup.c
arch/ppc/kernel/misc.S
arch/ppc/kernel/mk_defs.c
arch/ppc/kernel/openpic.c
arch/ppc/kernel/pci.c
arch/ppc/kernel/pmac_pci.c
arch/ppc/kernel/pmac_pic.c
arch/ppc/kernel/pmac_setup.c
arch/ppc/kernel/pmac_support.c
arch/ppc/kernel/ppc-stub.c
arch/ppc/kernel/ppc_asm.tmpl
arch/ppc/kernel/ppc_htab.c
arch/ppc/kernel/ppc_ksyms.c
arch/ppc/kernel/prep_pci.c
arch/ppc/kernel/prep_setup.c
arch/ppc/kernel/process.c
arch/ppc/kernel/prom.c
arch/ppc/kernel/setup.c
arch/ppc/kernel/signal.c
arch/ppc/kernel/smp.c
arch/ppc/kernel/syscalls.c
arch/ppc/kernel/traps.c
arch/ppc/lib/string.S
arch/ppc/mm/fault.c
arch/ppc/mm/init.c
arch/ppc/pmac_defconfig
arch/ppc/xmon/start.c
arch/sparc64/kernel/psycho.c
arch/sparc64/kernel/sparc64_ksyms.c
drivers/block/ide-cd.c
drivers/char/vt.c
drivers/macintosh/adb.c
drivers/macintosh/mac_keyb.c
drivers/macintosh/macio-adb.c
drivers/macintosh/macserial.c
drivers/macintosh/macserial.h
drivers/macintosh/mediabay.c
drivers/macintosh/via-cuda.c
drivers/macintosh/via-pmu.c
drivers/net/Config.in
drivers/net/Makefile
drivers/net/Space.c
drivers/net/de4x5.c
drivers/net/gmac.c [new file with mode: 0644]
drivers/net/gmac.h [new file with mode: 0644]
drivers/net/sunhme.c
drivers/sound/dmasound.c
fs/ext2/namei.c
fs/read_write.c
include/asm-ppc/bootx.h
include/asm-ppc/elf.h
include/asm-ppc/feature.h
include/asm-ppc/heathrow.h [new file with mode: 0644]
include/asm-ppc/ide.h
include/asm-ppc/io.h
include/asm-ppc/keyboard.h
include/asm-ppc/machdep.h
include/asm-ppc/mediabay.h
include/asm-ppc/nvram.h
include/asm-ppc/ohare.h
include/asm-ppc/page.h
include/asm-ppc/pmu.h
include/asm-ppc/processor.h
include/asm-ppc/prom.h
include/asm-ppc/system.h
include/asm-ppc/termbits.h
include/asm-ppc/types.h
include/asm-sparc64/pbm.h
net/ipv4/tcp.c

index 815dba3f9051e2f5c8cb5e8318db0f55fd7ededa..fb8ee7d08e9b3f23b5c98fc668831f0596400f29 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 17
-EXTRAVERSION = pre2
+EXTRAVERSION = pre3
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
index 96b6ba306ecce10c6d0c39e6706e411440730a0b..c595afaa77b3673e0b87192b5c66ce6cfe3c5287 100644 (file)
@@ -53,6 +53,9 @@ GZIP_FLAGS = -v9
 
 OBJECTS := head.o misc.o ../coffboot/zlib.o
 CFLAGS = -O2 -DSTDC_HEADERS -fno-builtin -I$(TOPDIR)/include
+ifeq ($(CONFIG_SMP),y)
+CFLAGS += -D__SMP__
+endif
 OBJCOPY = $(CROSS_COMPILE)objcopy
 OBJCOPY_ARGS = -O elf32-powerpc
 
index 9151717467801d0f5514f02d0c5e84568009ee62..7468bf7a79ed7a0d427cf7119c73e01850bd5402 100644 (file)
@@ -3,32 +3,32 @@
 #
 # Paul Mackerras       January 1997
 
-HOSTCC = gcc
 HOSTCFLAGS = -O -I$(TOPDIR)/include
 
 CC     = $(CROSS_COMPILE)gcc
 LD     = $(CROSS_COMPILE)ld
-CFLAGS = -O -fno-builtin -I$(TOPDIR)/include
+CFLAGS = $(CPPFLAGS) -O -fno-builtin
 OBJCOPY = $(CROSS_COMPILE)objcopy
-OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment \
-       --add-section=image=vmlinux.gz
-LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic
+OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment
+COFF_LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic
+CHRP_LD_ARGS = -Ttext 0x00400000
 GZ = gzip -9
 
-OBJS = crt0.o start.o main.o misc.o string.o zlib.o
+COFFOBJS = coffcrt0.o start.o coffmain.o misc.o string.o zlib.o image.o
+CHRPOBJS = crt0.o start.o chrpmain.o misc.o string.o zlib.o image.o
 LIBS = $(TOPDIR)/lib/lib.a
 
-ifeq ($(CONFIG_ALL_PPC),y)
-# yes, we want to build pmac stuff
-CONFIG_PMAC = y
-endif
-
 ifeq ($(CONFIG_PPC64),y)
 MSIZE=.64
 else
 MSIZE=
 endif
 
+ifeq ($(CONFIG_ALL_PPC),y)
+# yes, we want to build pmac stuff
+CONFIG_PMAC = y
+endif
+
 ifeq ($(CONFIG_SMP),y)
 TFTPIMAGE=/tftpboot/zImage.pmac.smp$(MSIZE)
 else
@@ -39,39 +39,81 @@ ifeq ($(CONFIG_PMAC),y)
 hack-coff: hack-coff.c
        $(HOSTCC) $(HOSTCFLAGS) -o hack-coff hack-coff.c
 
+znetboot: vmlinux.coff zImage vmlinux.elf
+       cp vmlinux.coff $(TFTPIMAGE)
+       cp vmlinux.elf $(TFTPIMAGE).elf
+
+znetboot.initrd: vmlinux.coff.initrd
+       cp vmlinux.coff.initrd $(TFTPIMAGE)
+       cp vmlinux.elf.initrd $(TFTPIMAGE).elf
+
 floppy: zImage
 #      mount -t hfs /dev/fd0 /mnt
 #      cp vmlinux.coff /mnt
 #      umount /mnt
 
-znetboot: vmlinux.coff
-       cp vmlinux.coff $(TFTPIMAGE)
+coffboot: $(COFFOBJS) no_initrd.o ld.script
+       $(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) no_initrd.o $(LIBS)
 
-znetboot.initrd: vmlinux.coff.initrd
-       cp vmlinux.coff.initrd $(TFTPIMAGE)
+coffboot.initrd: $(COFFOBJS) initrd.o ld.script
+       $(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) initrd.o $(LIBS)
 
-coffboot: $(OBJS) ld.script
-       $(LD) -o coffboot $(LD_ARGS) $(OBJS) $(LIBS)
+piggyback: piggyback.c
+       $(HOSTCC) $(HOSTCFLAGS) -DKERNELBASE=$(KERNELBASE) -o piggyback piggyback.c
 
-zImage: vmlinux.coff
+mknote: mknote.c
+       $(HOSTCC) $(HOSTCFLAGS) -o mknote mknote.c
 
-zImage.initrd: vmlinux.coff.initrd
+image.o: piggyback vmlinux.gz
+       ./piggyback image < vmlinux.gz | $(AS) -o image.o
 
-vmlinux.coff: coffboot hack-coff vmlinux.gz
+initrd.o: ramdisk.image.gz piggyback
+       ./piggyback initrd < ramdisk.image.gz | $(AS) -o initrd.o
+
+vmlinux.coff: coffboot hack-coff
        $(OBJCOPY) $(OBJCOPY_ARGS) coffboot $@
        ./hack-coff $@
        ln -sf vmlinux.coff zImage
 
-vmlinux.coff.initrd: coffboot hack-coff vmlinux.gz ramdisk.image.gz
-       $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=initrd=ramdisk.image.gz \
-               coffboot $@
+vmlinux.coff.initrd: coffboot.initrd hack-coff
+       $(OBJCOPY) $(OBJCOPY_ARGS) coffboot $@
        ./hack-coff $@
 
+vmlinux.elf: $(CHRPOBJS) no_initrd.o mknote
+       $(LD) $(CHRP_LD_ARGS) -o $@ $(CHRPOBJS) no_initrd.o $(LIBS)
+       ./mknote > note
+       $(OBJCOPY) $@ $@ --add-section=.note=note -R .comment
+
+vmlinux.elf.initrd: $(CHRPOBJS) initrd.o mknote
+       $(LD) $(CHRP_LD_ARGS) -o $@ $(CHRPOBJS) initrd.o $(LIBS)
+       ./mknote > note
+       $(OBJCOPY) $@ $@ --add-section=.note=note -R .comment
+
+micoffboot: dummy.o
+       $(LD) -o $@ $(COFF_LD_ARGS) dummy.o $(LIBS)
+
+miboot.image: micoffboot hack-coff
+       $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=vmlinux.gz micoffboot $@
+       ./hack-coff $@
+
+miboot.image.initrd: micoffboot hack-coff
+       $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=vmlinux.gz \
+       --add-section=initrd=ramdisk.image.gz micoffboot $@
+       ./hack-coff $@
+
+zImage: vmlinux.coff vmlinux.elf miboot.image
+
+zImage.initrd: vmlinux.coff.initrd vmlinux.elf.initrd miboot.image.initrd
+
 else
 znetboot: vmlinux.gz
 
 znetboot.initrd: vmlinux.gz
 
+miboot.image: vmlinux.gz
+
+miboot.image.initrd: vmlinux.gz
+
 coffboot: vmlinux.gz
 
 zImage: vmlinux.gz
@@ -92,5 +134,6 @@ vmlinux.gz: $(TOPDIR)/vmlinux
 
 clean:
        rm -f hack-coff coffboot zImage vmlinux.coff vmlinux.gz
+       rm -f mknote piggyback vmlinux.elf note
 
 fastdep:
diff --git a/arch/ppc/coffboot/chrpmain.c b/arch/ppc/coffboot/chrpmain.c
new file mode 100644 (file)
index 0000000..254ced6
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include "nonstdio.h"
+#include "zlib.h"
+
+extern void *finddevice(const char *);
+extern int getprop(void *, const char *, void *, int);
+void gunzip(void *, int, unsigned char *, int *);
+void stop_imac_ethernet(void);
+void stop_imac_usb(void);
+
+#define get_16be(x)    (*(unsigned short *)(x))
+#define get_32be(x)    (*(unsigned *)(x))
+
+#define RAM_START      0x00000000
+#define RAM_END                (8<<20)
+
+#define PROG_START     0x00010000
+
+char *avail_ram;
+char *end_avail;
+
+extern char _end[];
+extern char image_data[];
+extern int image_len;
+extern char initrd_data[];
+extern int initrd_len;
+
+
+boot(int a1, int a2, void *prom)
+{
+    int ns, oh, i;
+    unsigned sa, len;
+    void *dst;
+    unsigned char *im;
+    unsigned initrd_start, initrd_size;
+    extern char _start;
+    
+    printf("chrpboot starting: loaded at 0x%x\n", &_start);
+    if (initrd_len) {
+       initrd_size = initrd_len;
+       initrd_start = (RAM_END - initrd_size) & ~0xFFF;
+       a1 = initrd_start;
+       a2 = initrd_size;
+       claim(initrd_start, RAM_END - initrd_start, 0);
+       printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n",
+              initrd_start, initrd_data, initrd_size);
+       memcpy((char *)initrd_start, initrd_data, initrd_size);
+    }
+    im = image_data;
+    len = image_len;
+    /* claim 3MB starting at PROG_START */
+    claim(PROG_START, 3 << 20, 0);
+    dst = (void *) PROG_START;
+    if (im[0] == 0x1f && im[1] == 0x8b) {
+       /* claim 512kB for scratch space */
+       avail_ram = (char *) claim(0, 512 << 10, 0x10);
+       end_avail = avail_ram + (512 << 10);
+       printf("avail_ram = %x\n", avail_ram);
+       printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len);
+       gunzip(dst, 3 << 20, im, &len);
+       printf("done %u bytes\n", len);
+    } else {
+       memmove(dst, im, len);
+    }
+
+    flush_cache(dst, len);
+    stop_imac_ethernet();
+    stop_imac_usb();
+
+    sa = (unsigned long)PROG_START;
+    printf("start address = 0x%x\n", sa);
+
+    (*(void (*)())sa)(a1, a2, prom);
+
+    printf("returned?\n");
+
+    pause();
+}
+
+#define eieio()        asm volatile("eieio");
+
+void stop_imac_ethernet(void)
+{
+    void *macio, *enet;
+    unsigned int macio_addr[5], enet_reg[6];
+    int len;
+    volatile unsigned int *dbdma;
+
+    macio = finddevice("/pci/mac-io");
+    enet = finddevice("/pci/mac-io/ethernet");
+    if (macio == NULL || enet == NULL)
+       return;
+    len = getprop(macio, "assigned-addresses", macio_addr, sizeof(macio_addr));
+    if (len != sizeof(macio_addr))
+       return;
+    len = getprop(enet, "reg", enet_reg, sizeof(enet_reg));
+    if (len != sizeof(enet_reg))
+       return;
+    printf("macio base %x, dma at %x & %x\n",
+          macio_addr[2], enet_reg[2], enet_reg[4]);
+
+    /* hope this is mapped... */
+    dbdma = (volatile unsigned int *) (macio_addr[2] + enet_reg[2]);
+    *dbdma = 0x80;     /* clear the RUN bit */
+    eieio();
+    dbdma = (volatile unsigned int *) (macio_addr[2] + enet_reg[4]);
+    *dbdma = 0x80;     /* clear the RUN bit */
+    eieio();
+}
+
+void stop_imac_usb(void)
+{
+    void *usb;
+    unsigned int usb_addr[5];
+    int len;
+    volatile unsigned int *usb_ctrl;
+
+    usb = finddevice("/pci/usb");
+    if (usb == NULL)
+       return;
+    len = getprop(usb, "assigned-addresses", usb_addr, sizeof(usb_addr));
+    if (len != sizeof(usb_addr))
+       return;
+    printf("usb base %x\n", usb_addr[2]);
+
+    usb_ctrl = (volatile unsigned int *) (usb_addr[2] + 8);
+    *usb_ctrl = 0x01000000;    /* cpu_to_le32(1) */
+    eieio();
+}
+
+void *zalloc(void *x, unsigned items, unsigned size)
+{
+    void *p = avail_ram;
+
+    size *= items;
+    size = (size + 7) & -8;
+    avail_ram += size;
+    if (avail_ram > end_avail) {
+       printf("oops... out of memory\n");
+       pause();
+    }
+    return p;
+}
+
+void zfree(void *x, void *addr, unsigned nb)
+{
+}
+
+#define HEAD_CRC       2
+#define EXTRA_FIELD    4
+#define ORIG_NAME      8
+#define COMMENT                0x10
+#define RESERVED       0xe0
+
+#define DEFLATED       8
+
+void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
+{
+    z_stream s;
+    int r, i, flags;
+
+    /* skip header */
+    i = 10;
+    flags = src[3];
+    if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
+       printf("bad gzipped data\n");
+       exit();
+    }
+    if ((flags & EXTRA_FIELD) != 0)
+       i = 12 + src[10] + (src[11] << 8);
+    if ((flags & ORIG_NAME) != 0)
+       while (src[i++] != 0)
+           ;
+    if ((flags & COMMENT) != 0)
+       while (src[i++] != 0)
+           ;
+    if ((flags & HEAD_CRC) != 0)
+       i += 2;
+    if (i >= *lenp) {
+       printf("gunzip: ran out of data in header\n");
+       exit();
+    }
+
+    s.zalloc = zalloc;
+    s.zfree = zfree;
+    r = inflateInit2(&s, -MAX_WBITS);
+    if (r != Z_OK) {
+       printf("inflateInit2 returned %d\n", r);
+       exit();
+    }
+    s.next_in = src + i;
+    s.avail_in = *lenp - i;
+    s.next_out = dst;
+    s.avail_out = dstlen;
+    r = inflate(&s, Z_FINISH);
+    if (r != Z_OK && r != Z_STREAM_END) {
+       printf("inflate returned %d msg: %s\n", r, s.msg);
+       exit();
+    }
+    *lenp = s.next_out - (unsigned char *) dst;
+    inflateEnd(&s);
+}
diff --git a/arch/ppc/coffboot/coffcrt0.S b/arch/ppc/coffboot/coffcrt0.S
new file mode 100644 (file)
index 0000000..43ae4e0
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+       .text
+       .globl  _start
+_start:
+       .long   __start,0,0
+
+       .globl  __start
+__start:
+       lis     9,_start@h
+       lis     8,_etext@ha
+       addi    8,8,_etext@l
+1:     dcbf    0,9
+       icbi    0,9
+       addi    9,9,0x20
+       cmplwi  0,9,8
+       blt     1b
+       b       start
diff --git a/arch/ppc/coffboot/coffmain.c b/arch/ppc/coffboot/coffmain.c
new file mode 100644 (file)
index 0000000..cc63806
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include "nonstdio.h"
+#include "zlib.h"
+
+extern void *finddevice(const char *);
+extern int getprop(void *, const char *, void *, int);
+extern char *claim(unsigned, unsigned, unsigned);
+void gunzip(void *, int, unsigned char *, int *);
+
+#define get_16be(x)    (*(unsigned short *)(x))
+#define get_32be(x)    (*(unsigned *)(x))
+
+#define RAM_START      0xc0000000
+#define PROG_START     RAM_START
+#define RAM_END                (RAM_START + 0x800000)  /* only 8M mapped with BATs */
+
+char *avail_ram;
+char *end_avail;
+
+extern char _start[], _end[];
+extern char image_data[];
+extern int image_len;
+extern char initrd_data[];
+extern int initrd_len;
+
+
+boot(int a1, int a2, void *prom)
+{
+    int ns, oh, i;
+    unsigned sa, len;
+    void *dst;
+    unsigned char *im;
+    unsigned initrd_start, initrd_size;
+    
+    printf("coffboot starting: loaded at 0x%x\n", _start);
+    setup_bats(RAM_START);
+    if (initrd_len) {
+       initrd_size = initrd_len;
+       initrd_start = (RAM_END - initrd_size) & ~0xFFF;
+       a1 = initrd_start;
+       a2 = initrd_size;
+       claim(initrd_start - RAM_START, RAM_END - initrd_start, 0);
+       printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n",
+              initrd_start, initrd_data, initrd_size);
+       memcpy((char *)initrd_start, initrd_data, initrd_size);
+    }
+    im = image_data;
+    len = image_len;
+    /* claim 3MB starting at 0 */
+    claim(0, 3 << 20, 0);
+    dst = (void *) RAM_START;
+    if (im[0] == 0x1f && im[1] == 0x8b) {
+       /* claim 512kB for scratch space */
+       avail_ram = claim(0, 512 << 10, 0x10) + RAM_START;
+       end_avail = avail_ram + (512 << 10);
+       printf("avail_ram = %x\n", avail_ram);
+       printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len);
+       gunzip(dst, 3 << 20, im, &len);
+       printf("done %u bytes\n", len);
+    } else {
+       memmove(dst, im, len);
+    }
+
+    flush_cache(dst, len);
+    
+    sa = (unsigned long)PROG_START;
+    printf("start address = 0x%x\n", sa);
+
+#if 0
+    pause();
+#endif
+    (*(void (*)())sa)(a1, a2, prom);
+
+    printf("returned?\n");
+
+    pause();
+}
+
+void *zalloc(void *x, unsigned items, unsigned size)
+{
+    void *p = avail_ram;
+
+    size *= items;
+    size = (size + 7) & -8;
+    avail_ram += size;
+    if (avail_ram > end_avail) {
+       printf("oops... out of memory\n");
+       pause();
+    }
+    return p;
+}
+
+void zfree(void *x, void *addr, unsigned nb)
+{
+}
+
+#define HEAD_CRC       2
+#define EXTRA_FIELD    4
+#define ORIG_NAME      8
+#define COMMENT                0x10
+#define RESERVED       0xe0
+
+#define DEFLATED       8
+
+void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
+{
+    z_stream s;
+    int r, i, flags;
+
+    /* skip header */
+    i = 10;
+    flags = src[3];
+    if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
+       printf("bad gzipped data\n");
+       exit();
+    }
+    if ((flags & EXTRA_FIELD) != 0)
+       i = 12 + src[10] + (src[11] << 8);
+    if ((flags & ORIG_NAME) != 0)
+       while (src[i++] != 0)
+           ;
+    if ((flags & COMMENT) != 0)
+       while (src[i++] != 0)
+           ;
+    if ((flags & HEAD_CRC) != 0)
+       i += 2;
+    if (i >= *lenp) {
+       printf("gunzip: ran out of data in header\n");
+       exit();
+    }
+
+    s.zalloc = zalloc;
+    s.zfree = zfree;
+    r = inflateInit2(&s, -MAX_WBITS);
+    if (r != Z_OK) {
+       printf("inflateInit2 returned %d\n", r);
+       exit();
+    }
+    s.next_in = src + i;
+    s.avail_in = *lenp - i;
+    s.next_out = dst;
+    s.avail_out = dstlen;
+    r = inflate(&s, Z_FINISH);
+    if (r != Z_OK && r != Z_STREAM_END) {
+       printf("inflate returned %d msg: %s\n", r, s.msg);
+       exit();
+    }
+    *lenp = s.next_out - (unsigned char *) dst;
+    inflateEnd(&s);
+}
index 43ae4e0ec4a7e2509440f5832b987dadf04617ef..c43340594032f2cc5beb90636f9a7211163eb5c9 100644 (file)
@@ -9,10 +9,6 @@
        .text
        .globl  _start
 _start:
-       .long   __start,0,0
-
-       .globl  __start
-__start:
        lis     9,_start@h
        lis     8,_etext@ha
        addi    8,8,_etext@l
index df542a5223ec11e771f14cd8e0fd1a0370257187..7defc69e870d7c4ffee1c5484b22dbbf2d6de3f4 100644 (file)
  */
        .globl  setup_bats
 setup_bats:
-       mr      4,3
-       mfpvr   3
-       rlwinm  3,3,16,16,31            /* r3 = 1 for 601, 4 for 604 */
-       cmpi    0,3,1
+       mfpvr   5
+       rlwinm  5,5,16,16,31            /* r3 = 1 for 601, 4 for 604 */
+       cmpi    0,5,1
+       li      0,0
        bne     4f
-       ori     4,4,4                   /* set up BAT registers for 601 */
-       li      5,0x7f
-       mtibatu 3,4
-       mtibatl 3,5
-       isync
-       blr
-4:     ori     4,4,0xfe                /* set up BAT registers for 604 */
-       li      5,2
-       mtdbatl 3,5
-       mtdbatu 3,4
-       mtibatl 3,5
-       mtibatu 3,4
+       mtibatl 3,0                     /* invalidate BAT first */
+       ori     3,3,4                   /* set up BAT registers for 601 */
+       li      4,0x7f
+       mtibatu 3,3
+       mtibatl 3,4
+       b       5f
+4:     mtdbatu 3,0                     /* invalidate BATs first */
+       mtibatu 3,0
+       ori     3,3,0xff                /* set up BAT registers for 604 */
+       li      4,2
+       mtdbatl 3,4
+       mtdbatu 3,3
+       mtibatl 3,4
+       mtibatu 3,3
+5:     sync
        isync
        blr
 
diff --git a/arch/ppc/coffboot/mknote.c b/arch/ppc/coffboot/mknote.c
new file mode 100644 (file)
index 0000000..120cc1d
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) Cort Dougan 1999.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Generate a note section as per the CHRP specification.
+ *
+ */
+
+#include <stdio.h>
+
+#define PL(x) printf("%c%c%c%c", ((x)>>24)&0xff, ((x)>>16)&0xff, ((x)>>8)&0xff, (x)&0xff );
+
+int main(void)
+{
+/* header */
+       /* namesz */
+       PL(strlen("PowerPC")+1);
+       /* descrsz */
+       PL(6*4);
+       /* type */
+       PL(0x1275);
+       /* name */
+       printf("PowerPC"); printf("%c", 0);
+       
+/* descriptor */
+       /* real-mode */
+       PL(0xffffffff);
+       /* real-base */
+       PL(0x00c00000);
+       /* real-size */
+       PL(0xffffffff);
+       /* virt-base */
+       PL(0xffffffff);
+       /* virt-size */
+       PL(0xffffffff);
+       /* load-base */
+       PL(0x4000);
+       return 0;
+}
diff --git a/arch/ppc/coffboot/no_initrd.c b/arch/ppc/coffboot/no_initrd.c
new file mode 100644 (file)
index 0000000..ed5dcdb
--- /dev/null
@@ -0,0 +1,2 @@
+char initrd_data[1];
+int initrd_len = 0;
diff --git a/arch/ppc/coffboot/piggyback.c b/arch/ppc/coffboot/piggyback.c
new file mode 100644 (file)
index 0000000..1720258
--- /dev/null
@@ -0,0 +1,65 @@
+#include <stdio.h>
+
+extern long ce_exec_config[];
+
+main(int argc, char *argv[])
+{
+       int i, cnt, pos, len;
+       unsigned int cksum, val;
+       unsigned char *lp;
+       unsigned char buf[8192];
+       if (argc != 2)
+       {
+               fprintf(stderr, "usage: %s name <in-file >out-file\n",
+                       argv[0]);
+               exit(1);
+       }
+       fprintf(stdout, "#\n");
+       fprintf(stdout, "# Miscellaneous data structures:\n");
+       fprintf(stdout, "# WARNING - this file is automatically generated!\n");
+       fprintf(stdout, "#\n");
+       fprintf(stdout, "\n");
+       fprintf(stdout, "\t.data\n");
+       fprintf(stdout, "\t.globl %s_data\n", argv[1]);
+       fprintf(stdout, "%s_data:\n", argv[1]);
+       pos = 0;
+       cksum = 0;
+       while ((len = read(0, buf, sizeof(buf))) > 0)
+       {
+               cnt = 0;
+               lp = (unsigned char *)buf;
+               len = (len + 3) & ~3;  /* Round up to longwords */
+               for (i = 0;  i < len;  i += 4)
+               {
+                       if (cnt == 0)
+                       {
+                               fprintf(stdout, "\t.long\t");
+                       }
+                       fprintf(stdout, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]);
+                       val = *(unsigned long *)lp;
+                       cksum ^= val;
+                       lp += 4;
+                       if (++cnt == 4)
+                       {
+                               cnt = 0;
+                               fprintf(stdout, " # %x \n", pos+i-12);
+                               fflush(stdout);
+                       } else
+                       {
+                               fprintf(stdout, ",");
+                       }
+               }
+               if (cnt)
+               {
+                       fprintf(stdout, "0\n");
+               }
+               pos += len;
+       }
+       fprintf(stdout, "\t.globl %s_len\n", argv[1]);
+       fprintf(stdout, "%s_len:\t.long\t0x%x\n", argv[1], pos);
+       fflush(stdout);
+       fclose(stdout);
+       fprintf(stderr, "cksum = %x\n", cksum);
+       exit(0);
+}
+
index 1f11edbec83681e94aef541e3ca2b2e63707a673..6fc1fc1fbcdce56625be2056ac4df801fa8e08a0 100644 (file)
@@ -33,7 +33,7 @@ start(int a1, int a2, void *promptr)
     if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4)
        exit();
 
-    coffboot(a1, a2, promptr);
+    boot(a1, a2, promptr);
     for (;;)
        exit();
 }
@@ -62,6 +62,25 @@ write(void *handle, void *ptr, int nb)
     return args.actual;
 }
 
+int writestring(void *f, char *ptr, int nb)
+{
+       int w = 0, i;
+       char *ret = "\r";
+
+       for (i = 0; i < nb; ++i) {
+               if (ptr[i] == '\n') {
+                       if (i > w) {
+                               write(f, ptr + w, i - w);
+                               w = i;
+                       }
+                       write(f, ret, 1);
+               }
+       }
+       if (w < nb)
+               write(f, ptr + w, nb - w);
+       return nb;
+}
+
 int
 read(void *handle, void *ptr, int nb)
 {
@@ -130,6 +149,29 @@ finddevice(const char *name)
     return args.phandle;
 }
 
+void *
+claim(unsigned int virt, unsigned int size, unsigned int align)
+{
+    struct prom_args {
+       char *service;
+       int nargs;
+       int nret;
+       unsigned int virt;
+       unsigned int size;
+       unsigned int align;
+       void *ret;
+    } args;
+
+    args.service = "claim";
+    args.nargs = 3;
+    args.nret = 1;
+    args.virt = virt;
+    args.size = size;
+    args.align = align;
+    (*prom)(&args);
+    return args.ret;
+}
+
 int
 getprop(void *phandle, const char *name, void *buf, int buflen)
 {
@@ -161,9 +203,7 @@ putc(int c, void *f)
 {
     char ch = c;
 
-    if (c == '\n')
-       putc('\r', f);
-    return write(f, &ch, 1) == 1? c: -1;
+    return writestring(f, &ch, 1) == 1? c: -1;
 }
 
 int
@@ -177,7 +217,7 @@ fputs(char *str, void *f)
 {
     int n = strlen(str);
 
-    return write(f, str, n) == n? 0: -1;
+    return writestring(f, str, n) == n? 0: -1;
 }
 
 int
@@ -190,7 +230,7 @@ readchar()
        case 1:
            return ch;
        case -1:
-           printk("read(stdin) returned -1\r\n");
+           printk("read(stdin) returned -1\n");
            return -1;
        }
     }
@@ -264,7 +304,7 @@ printk(char *fmt, ...)
        va_start(args, fmt);
        n = vsprintf(sprint_buf, fmt, args);
        va_end(args);
-       write(stdout, sprint_buf, n);
+       writestring(stdout, sprint_buf, n);
 }
 
 int
@@ -276,6 +316,6 @@ printf(char *fmt, ...)
        va_start(args, fmt);
        n = vsprintf(sprint_buf, fmt, args);
        va_end(args);
-       write(stdout, sprint_buf, n);
+       writestring(stdout, sprint_buf, n);
        return n;
 }
index b42df37faea84b4154a8ffb8b3242529efe14cda..4e5fbb6a04aa29c12a161186bf9b96bd6232d187 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
 #
 
 #
@@ -7,15 +7,16 @@
 #
 CONFIG_PPC=y
 CONFIG_6xx=y
+# CONFIG_PPC64 is not set
 # CONFIG_8xx is not set
-# CONFIG_PMAC is not set
+CONFIG_PMAC=y
 # CONFIG_PREP is not set
 # CONFIG_CHRP is not set
-CONFIG_ALL_PPC=y
+# CONFIG_ALL_PPC is not set
 # CONFIG_APUS is not set
-# CONFIG_GEMINI is not set
 # CONFIG_MBX is not set
 # CONFIG_SMP is not set
+CONFIG_MACH_SPECIFIC=y
 CONFIG_6xx=y
 
 #
@@ -23,7 +24,7 @@ CONFIG_6xx=y
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_MODULES=y
-CONFIG_MODVERSIONS=y
+# CONFIG_MODVERSIONS is not set
 CONFIG_KMOD=y
 CONFIG_PCI=y
 # CONFIG_PCI_QUIRKS is not set
@@ -34,10 +35,11 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
+CONFIG_BINFMT_MISC=m
 # CONFIG_BINFMT_JAVA is not set
-# CONFIG_PARPORT is not set
-CONFIG_VGA_CONSOLE=y
+CONFIG_PARPORT=m
+# CONFIG_PARPORT_PC is not set
+# CONFIG_VGA_CONSOLE is not set
 CONFIG_FB=y
 CONFIG_FB_COMPAT_XPMAC=y
 CONFIG_PMAC_PBOOK=y
@@ -50,7 +52,6 @@ CONFIG_PROC_DEVICETREE=y
 # CONFIG_TOTALMP is not set
 CONFIG_BOOTX_TEXT=y
 # CONFIG_MOTOROLA_HOTSWAP is not set
-# CONFIG_CMDLINE_BOOL is not set
 
 #
 # Plug and Play support
@@ -60,8 +61,12 @@ CONFIG_BOOTX_TEXT=y
 #
 # Block devices
 #
-CONFIG_BLK_DEV_FD=y
+# CONFIG_BLK_DEV_FD is not set
 CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
 # CONFIG_BLK_DEV_HD_IDE is not set
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_BLK_DEV_IDECD=y
@@ -70,13 +75,25 @@ CONFIG_BLK_DEV_IDEFLOPPY=y
 # CONFIG_BLK_DEV_IDESCSI is not set
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-CONFIG_BLK_DEV_SL82C105=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_VIA82C586 is not set
+CONFIG_BLK_DEV_CMD646=y
+# CONFIG_BLK_DEV_SL82C105 is not set
 CONFIG_BLK_DEV_IDE_PMAC=y
 CONFIG_BLK_DEV_IDEDMA_PMAC=y
 CONFIG_BLK_DEV_IDEDMA=y
 CONFIG_PMAC_IDEDMA_AUTO=y
 # CONFIG_IDE_CHIPSETS is not set
+
+#
+# Additional Block Devices
+#
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_MD is not set
@@ -84,7 +101,7 @@ CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_PARIDE_PARPORT=y
+CONFIG_PARIDE_PARPORT=m
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_DEV_HD is not set
@@ -108,10 +125,18 @@ CONFIG_IP_MULTICAST=y
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_MROUTE is not set
 CONFIG_IP_ALIAS=y
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
+
+#
+# (it is safe to leave these untouched)
+#
 CONFIG_INET_RARP=y
 CONFIG_SKB_LARGE=y
 # CONFIG_IPV6 is not set
+
+#
+#  
+#
 # CONFIG_IPX is not set
 CONFIG_ATALK=m
 # CONFIG_X25 is not set
@@ -133,11 +158,19 @@ CONFIG_ATALK=m
 # SCSI support
 #
 CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SG is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
@@ -155,7 +188,6 @@ CONFIG_SCSI_AIC7XXX=y
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
 CONFIG_AIC7XXX_PROC_STATS=y
 CONFIG_AIC7XXX_RESET_DELAY=15
-# CONFIG_SCSI_IPS is not set
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_AM53C974 is not set
@@ -170,11 +202,12 @@ CONFIG_AIC7XXX_RESET_DELAY=15
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
 # CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_SIM710 is not set
 # CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_NCR53C8XX is not set
+CONFIG_SCSI_NCR53C8XX=y
 CONFIG_SCSI_SYM53C8XX=y
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
@@ -182,7 +215,7 @@ CONFIG_SCSI_NCR53C8XX_SYNC=20
 # CONFIG_SCSI_NCR53C8XX_PROFILE is not set
 # CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
 # CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
-# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
+CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT=y
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PCI2000 is not set
 # CONFIG_SCSI_PCI2220I is not set
@@ -220,21 +253,21 @@ CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
 CONFIG_MACE=y
 CONFIG_BMAC=y
-# CONFIG_NCR885E is not set
+CONFIG_GMAC=y
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_RTL8139 is not set
+# CONFIG_SIS900 is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_EISA=y
-CONFIG_PCNET32=y
+# CONFIG_PCNET32 is not set
 # CONFIG_ACENIC is not set
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
-# CONFIG_DM9102 is not set
 CONFIG_DE4X5=y
 # CONFIG_DEC_ELCP is not set
 # CONFIG_DGRS is not set
@@ -244,7 +277,6 @@ CONFIG_DE4X5=y
 # CONFIG_NE2K_PCI is not set
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
-# CONFIG_SIS900 is not set
 # CONFIG_ES3210 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_ZNET is not set
@@ -258,7 +290,12 @@ CONFIG_DE4X5=y
 # CONFIG_LTPC is not set
 # CONFIG_COPS is not set
 # CONFIG_IPDDP is not set
+# CONFIG_PLIP is not set
 CONFIG_PPP=y
+
+#
+# CCP compressors for PPP are only built as modules.
+#
 # CONFIG_SLIP is not set
 # CONFIG_NET_RADIO is not set
 
@@ -276,9 +313,7 @@ CONFIG_PPP=y
 # CONFIG_HOSTESS_SV11 is not set
 # CONFIG_COSA is not set
 # CONFIG_SEALEVEL_4021 is not set
-# CONFIG_COMX is not set
 # CONFIG_DLCI is not set
-# CONFIG_SBNI is not set
 
 #
 # Amateur Radio support
@@ -304,14 +339,12 @@ CONFIG_FB_OF=y
 CONFIG_FB_CONTROL=y
 CONFIG_FB_PLATINUM=y
 CONFIG_FB_VALKYRIE=y
+CONFIG_FB_ATY=y
+CONFIG_FB_ATY128=y
 CONFIG_FB_IMSTT=y
 CONFIG_FB_CT65550=y
 # CONFIG_FB_S3TRIO is not set
-CONFIG_FB_MATROX=y
-# CONFIG_FB_MATROX_MILLENIUM is not set
-CONFIG_FB_MATROX_MYSTIQUE=y
-CONFIG_FB_MATROX_G100=y
-# CONFIG_FB_MATROX_MULTIHEAD is not set
+# CONFIG_FB_MATROX is not set
 CONFIG_FB_ATY=y
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
@@ -334,22 +367,13 @@ CONFIG_FONT_SUN12x22=y
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=m
+# CONFIG_SERIAL is not set
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
-CONFIG_MOUSE=y
-
-#
-# Mice
-#
-# CONFIG_ATIXL_BUSMOUSE is not set
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MS_BUSMOUSE is not set
-CONFIG_PSMOUSE=y
-# CONFIG_82C710_MOUSE is not set
-# CONFIG_PC110_PAD is not set
+# CONFIG_PRINTER is not set
+# CONFIG_MOUSE is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_WATCHDOG is not set
 CONFIG_NVRAM=y
@@ -384,10 +408,10 @@ CONFIG_AUTOFS_FS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 CONFIG_HFS_FS=y
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
 # CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
+CONFIG_VFAT_FS=m
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_MINIX_FS is not set
@@ -453,7 +477,7 @@ CONFIG_NLS_CODEPAGE_437=y
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_ISO8859_9 is not set
 # CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
+CONFIG_NLS_ISO8859_15=y
 # CONFIG_NLS_KOI8_R is not set
 
 #
@@ -461,43 +485,13 @@ CONFIG_NLS_CODEPAGE_437=y
 #
 CONFIG_SOUND=y
 CONFIG_DMASOUND=y
-# CONFIG_SOUND_CMPCI is not set
 # CONFIG_SOUND_ES1370 is not set
 # CONFIG_SOUND_ES1371 is not set
-# CONFIG_SOUND_MAESTRO is not set
 # CONFIG_SOUND_ESSSOLO1 is not set
 # CONFIG_SOUND_SONICVIBES is not set
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
-CONFIG_SOUND_OSS=y
-# CONFIG_SOUND_DMAP is not set
-# CONFIG_SOUND_PAS is not set
-# CONFIG_SOUND_SB is not set
-# CONFIG_SOUND_GUS is not set
-# CONFIG_SOUND_MPU401 is not set
-# CONFIG_SOUND_PSS is not set
-# CONFIG_SOUND_MSS is not set
-# CONFIG_SOUND_SSCAPE is not set
-# CONFIG_SOUND_TRIX is not set
-# CONFIG_SOUND_VIA82CXXX is not set
-# CONFIG_SOUND_MAD16 is not set
-# CONFIG_SOUND_WAVEFRONT is not set
-CONFIG_SOUND_CS4232=m
-# CONFIG_SOUND_OPL3SA2 is not set
-# CONFIG_SOUND_MAUI is not set
-# CONFIG_SOUND_SGALAXY is not set
-# CONFIG_SOUND_AD1816 is not set
-# CONFIG_SOUND_OPL3SA1 is not set
-# CONFIG_SOUND_SOFTOSS is not set
-# CONFIG_SOUND_YM3812 is not set
-# CONFIG_SOUND_VMIDI is not set
-# CONFIG_SOUND_UART6850 is not set
-# CONFIG_SOUND_NM256 is not set
-
-#
-# Additional low level sound drivers
-#
-# CONFIG_LOWLEVEL_SOUND is not set
+# CONFIG_SOUND_OSS is not set
 
 #
 # Kernel hacking
index 8f24011b0abf6808475fcc516661de3ed01cc8ca..1f1bcd5320dbc074b7926b7ea599f877d580c4b9 100644 (file)
@@ -8,7 +8,7 @@ mainmenu_option next_comment
 comment 'Platform support'
 define_bool CONFIG_PPC y
 choice 'Processor type' \
-       "6xx/7xx                CONFIG_6xx \
+       "6xx/7xx/7400           CONFIG_6xx \
         860/821                CONFIG_8xx" 6xx/7xx
 
 choice 'Machine Type' \
@@ -21,6 +21,11 @@ choice 'Machine Type' \
         MBX            CONFIG_MBX" PowerMac
 
 bool 'Symmetric multi-processing support' CONFIG_SMP
+
+if [ "$CONFIG_6xx" = "y" ]; then
+  bool 'Altivec (G4) support' CONFIG_ALTIVEC
+fi
+
 if [ "$CONFIG_ALL_PPC" != "y" ];then
   define_bool CONFIG_MACH_SPECIFIC y
 fi
@@ -77,9 +82,6 @@ fi
 
 bool 'Support for VGA Console' CONFIG_VGA_CONSOLE
 bool 'Support for frame buffer devices' CONFIG_FB
-if [ "$CONFIG_FB" = "y" ]; then
-  bool 'Backward compatibility mode for Xpmac' CONFIG_FB_COMPAT_XPMAC
-fi
 
 bool 'Power management support for Apple PowerBooks' CONFIG_PMAC_PBOOK
 bool 'Support for PowerMac keyboard' CONFIG_MAC_KEYBOARD
@@ -152,6 +154,8 @@ fi
 
 source net/ax25/Config.in
 
+source net/irda/Config.in
+
 mainmenu_option next_comment
 comment 'ISDN subsystem'
 
index b42df37faea84b4154a8ffb8b3242529efe14cda..4e5fbb6a04aa29c12a161186bf9b96bd6232d187 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
 #
 
 #
@@ -7,15 +7,16 @@
 #
 CONFIG_PPC=y
 CONFIG_6xx=y
+# CONFIG_PPC64 is not set
 # CONFIG_8xx is not set
-# CONFIG_PMAC is not set
+CONFIG_PMAC=y
 # CONFIG_PREP is not set
 # CONFIG_CHRP is not set
-CONFIG_ALL_PPC=y
+# CONFIG_ALL_PPC is not set
 # CONFIG_APUS is not set
-# CONFIG_GEMINI is not set
 # CONFIG_MBX is not set
 # CONFIG_SMP is not set
+CONFIG_MACH_SPECIFIC=y
 CONFIG_6xx=y
 
 #
@@ -23,7 +24,7 @@ CONFIG_6xx=y
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_MODULES=y
-CONFIG_MODVERSIONS=y
+# CONFIG_MODVERSIONS is not set
 CONFIG_KMOD=y
 CONFIG_PCI=y
 # CONFIG_PCI_QUIRKS is not set
@@ -34,10 +35,11 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
+CONFIG_BINFMT_MISC=m
 # CONFIG_BINFMT_JAVA is not set
-# CONFIG_PARPORT is not set
-CONFIG_VGA_CONSOLE=y
+CONFIG_PARPORT=m
+# CONFIG_PARPORT_PC is not set
+# CONFIG_VGA_CONSOLE is not set
 CONFIG_FB=y
 CONFIG_FB_COMPAT_XPMAC=y
 CONFIG_PMAC_PBOOK=y
@@ -50,7 +52,6 @@ CONFIG_PROC_DEVICETREE=y
 # CONFIG_TOTALMP is not set
 CONFIG_BOOTX_TEXT=y
 # CONFIG_MOTOROLA_HOTSWAP is not set
-# CONFIG_CMDLINE_BOOL is not set
 
 #
 # Plug and Play support
@@ -60,8 +61,12 @@ CONFIG_BOOTX_TEXT=y
 #
 # Block devices
 #
-CONFIG_BLK_DEV_FD=y
+# CONFIG_BLK_DEV_FD is not set
 CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
 # CONFIG_BLK_DEV_HD_IDE is not set
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_BLK_DEV_IDECD=y
@@ -70,13 +75,25 @@ CONFIG_BLK_DEV_IDEFLOPPY=y
 # CONFIG_BLK_DEV_IDESCSI is not set
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-CONFIG_BLK_DEV_SL82C105=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_VIA82C586 is not set
+CONFIG_BLK_DEV_CMD646=y
+# CONFIG_BLK_DEV_SL82C105 is not set
 CONFIG_BLK_DEV_IDE_PMAC=y
 CONFIG_BLK_DEV_IDEDMA_PMAC=y
 CONFIG_BLK_DEV_IDEDMA=y
 CONFIG_PMAC_IDEDMA_AUTO=y
 # CONFIG_IDE_CHIPSETS is not set
+
+#
+# Additional Block Devices
+#
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_MD is not set
@@ -84,7 +101,7 @@ CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_PARIDE_PARPORT=y
+CONFIG_PARIDE_PARPORT=m
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_DEV_HD is not set
@@ -108,10 +125,18 @@ CONFIG_IP_MULTICAST=y
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_MROUTE is not set
 CONFIG_IP_ALIAS=y
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
+
+#
+# (it is safe to leave these untouched)
+#
 CONFIG_INET_RARP=y
 CONFIG_SKB_LARGE=y
 # CONFIG_IPV6 is not set
+
+#
+#  
+#
 # CONFIG_IPX is not set
 CONFIG_ATALK=m
 # CONFIG_X25 is not set
@@ -133,11 +158,19 @@ CONFIG_ATALK=m
 # SCSI support
 #
 CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SG is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
@@ -155,7 +188,6 @@ CONFIG_SCSI_AIC7XXX=y
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
 CONFIG_AIC7XXX_PROC_STATS=y
 CONFIG_AIC7XXX_RESET_DELAY=15
-# CONFIG_SCSI_IPS is not set
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_AM53C974 is not set
@@ -170,11 +202,12 @@ CONFIG_AIC7XXX_RESET_DELAY=15
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
 # CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_SIM710 is not set
 # CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_NCR53C8XX is not set
+CONFIG_SCSI_NCR53C8XX=y
 CONFIG_SCSI_SYM53C8XX=y
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
@@ -182,7 +215,7 @@ CONFIG_SCSI_NCR53C8XX_SYNC=20
 # CONFIG_SCSI_NCR53C8XX_PROFILE is not set
 # CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
 # CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
-# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
+CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT=y
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PCI2000 is not set
 # CONFIG_SCSI_PCI2220I is not set
@@ -220,21 +253,21 @@ CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
 CONFIG_MACE=y
 CONFIG_BMAC=y
-# CONFIG_NCR885E is not set
+CONFIG_GMAC=y
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_RTL8139 is not set
+# CONFIG_SIS900 is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_EISA=y
-CONFIG_PCNET32=y
+# CONFIG_PCNET32 is not set
 # CONFIG_ACENIC is not set
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
-# CONFIG_DM9102 is not set
 CONFIG_DE4X5=y
 # CONFIG_DEC_ELCP is not set
 # CONFIG_DGRS is not set
@@ -244,7 +277,6 @@ CONFIG_DE4X5=y
 # CONFIG_NE2K_PCI is not set
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
-# CONFIG_SIS900 is not set
 # CONFIG_ES3210 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_ZNET is not set
@@ -258,7 +290,12 @@ CONFIG_DE4X5=y
 # CONFIG_LTPC is not set
 # CONFIG_COPS is not set
 # CONFIG_IPDDP is not set
+# CONFIG_PLIP is not set
 CONFIG_PPP=y
+
+#
+# CCP compressors for PPP are only built as modules.
+#
 # CONFIG_SLIP is not set
 # CONFIG_NET_RADIO is not set
 
@@ -276,9 +313,7 @@ CONFIG_PPP=y
 # CONFIG_HOSTESS_SV11 is not set
 # CONFIG_COSA is not set
 # CONFIG_SEALEVEL_4021 is not set
-# CONFIG_COMX is not set
 # CONFIG_DLCI is not set
-# CONFIG_SBNI is not set
 
 #
 # Amateur Radio support
@@ -304,14 +339,12 @@ CONFIG_FB_OF=y
 CONFIG_FB_CONTROL=y
 CONFIG_FB_PLATINUM=y
 CONFIG_FB_VALKYRIE=y
+CONFIG_FB_ATY=y
+CONFIG_FB_ATY128=y
 CONFIG_FB_IMSTT=y
 CONFIG_FB_CT65550=y
 # CONFIG_FB_S3TRIO is not set
-CONFIG_FB_MATROX=y
-# CONFIG_FB_MATROX_MILLENIUM is not set
-CONFIG_FB_MATROX_MYSTIQUE=y
-CONFIG_FB_MATROX_G100=y
-# CONFIG_FB_MATROX_MULTIHEAD is not set
+# CONFIG_FB_MATROX is not set
 CONFIG_FB_ATY=y
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
@@ -334,22 +367,13 @@ CONFIG_FONT_SUN12x22=y
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=m
+# CONFIG_SERIAL is not set
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
-CONFIG_MOUSE=y
-
-#
-# Mice
-#
-# CONFIG_ATIXL_BUSMOUSE is not set
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MS_BUSMOUSE is not set
-CONFIG_PSMOUSE=y
-# CONFIG_82C710_MOUSE is not set
-# CONFIG_PC110_PAD is not set
+# CONFIG_PRINTER is not set
+# CONFIG_MOUSE is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_WATCHDOG is not set
 CONFIG_NVRAM=y
@@ -384,10 +408,10 @@ CONFIG_AUTOFS_FS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 CONFIG_HFS_FS=y
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
 # CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
+CONFIG_VFAT_FS=m
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_MINIX_FS is not set
@@ -453,7 +477,7 @@ CONFIG_NLS_CODEPAGE_437=y
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_ISO8859_9 is not set
 # CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
+CONFIG_NLS_ISO8859_15=y
 # CONFIG_NLS_KOI8_R is not set
 
 #
@@ -461,43 +485,13 @@ CONFIG_NLS_CODEPAGE_437=y
 #
 CONFIG_SOUND=y
 CONFIG_DMASOUND=y
-# CONFIG_SOUND_CMPCI is not set
 # CONFIG_SOUND_ES1370 is not set
 # CONFIG_SOUND_ES1371 is not set
-# CONFIG_SOUND_MAESTRO is not set
 # CONFIG_SOUND_ESSSOLO1 is not set
 # CONFIG_SOUND_SONICVIBES is not set
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
-CONFIG_SOUND_OSS=y
-# CONFIG_SOUND_DMAP is not set
-# CONFIG_SOUND_PAS is not set
-# CONFIG_SOUND_SB is not set
-# CONFIG_SOUND_GUS is not set
-# CONFIG_SOUND_MPU401 is not set
-# CONFIG_SOUND_PSS is not set
-# CONFIG_SOUND_MSS is not set
-# CONFIG_SOUND_SSCAPE is not set
-# CONFIG_SOUND_TRIX is not set
-# CONFIG_SOUND_VIA82CXXX is not set
-# CONFIG_SOUND_MAD16 is not set
-# CONFIG_SOUND_WAVEFRONT is not set
-CONFIG_SOUND_CS4232=m
-# CONFIG_SOUND_OPL3SA2 is not set
-# CONFIG_SOUND_MAUI is not set
-# CONFIG_SOUND_SGALAXY is not set
-# CONFIG_SOUND_AD1816 is not set
-# CONFIG_SOUND_OPL3SA1 is not set
-# CONFIG_SOUND_SOFTOSS is not set
-# CONFIG_SOUND_YM3812 is not set
-# CONFIG_SOUND_VMIDI is not set
-# CONFIG_SOUND_UART6850 is not set
-# CONFIG_SOUND_NM256 is not set
-
-#
-# Additional low level sound drivers
-#
-# CONFIG_LOWLEVEL_SOUND is not set
+# CONFIG_SOUND_OSS is not set
 
 #
 # Kernel hacking
index b45ac90cb571cd0cbc9c23a1b99ebfe1ec0872fd..fc0a5156eeb54f5901c26292400e5e1d4da909e2 100644 (file)
@@ -7,8 +7,13 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
+# Once a gas that groks -mvec is generally available, we'll use it...
 .S.o:
+#ifdef CONFIG_ALTIVEC
+#      $(CC) $(CFLAGS) -D__ASSEMBLY__ -Wa,-mvec -c $< -o $*.o
+#else
        $(CC) $(CFLAGS) -D__ASSEMBLY__ -c $< -o $*.o
+#endif
 
 O_TARGET := kernel.o
 OX_OBJS := ppc_ksyms.o setup.o
index 9bb8e690ee4ad2b98e12e0c71c653fa139339e54..841295d8227f597108ad07fd805ba588ebc64150 100644 (file)
@@ -1,3 +1,4 @@
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
index f80ad32365fe0ce5c00cbccceff749d3744cf540..2159e8133d3977295a29f447770126ea9bb93582 100644 (file)
@@ -488,6 +488,7 @@ __initfunc(void
                ppc_md.kbd_init_hw       = pckbd_init_hw;
 #ifdef CONFIG_MAGIC_SYSRQ
                ppc_md.kbd_sysrq_xlate   = pckbd_sysrq_xlate;
+               ppc_md.SYSRQ_KEY         = 0x54;
 #endif         
        }
        else
@@ -500,6 +501,7 @@ __initfunc(void
                ppc_md.kbd_init_hw       = mackbd_init_hw;
 #ifdef CONFIG_MAGIC_SYSRQ
                ppc_md.kbd_sysrq_xlate   = mackbd_sysrq_xlate;
+               ppc_md.SYSRQ_KEY         = 0x69;
 #endif         
        }
 #else
@@ -511,6 +513,7 @@ __initfunc(void
        ppc_md.kbd_init_hw       = pckbd_init_hw;
 #ifdef CONFIG_MAGIC_SYSRQ
        ppc_md.kbd_sysrq_xlate   = pckbd_sysrq_xlate;
+       ppc_md.SYSRQ_KEY         = 0x54;
 #endif
 #endif
 #endif
index a9a30396a0b2596d5b68cca98460934e22276ee6..1e561dd3bdcc0ac375366a171c3d99e94d0d432b 100644 (file)
  *  as published by the Free Software Foundation; either version
  *  2 of the License, or (at your option) any later version.
  *
+ *  BenH: Changed implementation to work on multiple registers
+ *       polarity is also taken into account. Removed delay (now
+ *       responsibility of the caller). Added spinlocks.
+ *
  */
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/spinlock.h>
 #include <asm/errno.h>
 #include <asm/ohare.h>
+#include <asm/heathrow.h>
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/feature.h>
 
-#define MAX_FEATURE_REGS               2
 #undef DEBUG_FEATURE
 
-static u32 feature_bits_pbook[] = {
-       0,                      /* FEATURE_null */
-       OH_SCC_RESET,           /* FEATURE_Serial_reset */
-       OH_SCC_ENABLE,          /* FEATURE_Serial_enable */
-       OH_SCCA_IO,             /* FEATURE_Serial_IO_A */
-       OH_SCCB_IO,             /* FEATURE_Serial_IO_B */
-       OH_FLOPPY_ENABLE,       /* FEATURE_SWIM3_enable */
-       OH_MESH_ENABLE,         /* FEATURE_MESH_enable */
-       OH_IDE_ENABLE,          /* FEATURE_IDE_enable */
-       OH_VIA_ENABLE,          /* FEATURE_VIA_enable */
-       OH_IDECD_POWER,         /* FEATURE_CD_power */
-       OH_BAY_RESET,           /* FEATURE_Mediabay_reset */
-       OH_BAY_ENABLE,          /* FEATURE_Mediabay_enable */
-       OH_BAY_PCI_ENABLE,      /* FEATURE_Mediabay_PCI_enable */
-       OH_BAY_IDE_ENABLE,      /* FEATURE_Mediabay_IDE_enable */
-       OH_BAY_FLOPPY_ENABLE,   /* FEATURE_Mediabay_floppy_enable */
-       0,                      /* FEATURE_BMac_reset */
-       0,                      /* FEATURE_BMac_IO_enable */
-       0,                      /* FEATURE_Modem_Reset -> guess... */
-       OH_IDE_POWER,           /* FEATURE_IDE_DiskPower -> guess... */
-       OH_IDE_RESET            /* FEATURE_IDE_Reset (0 based) -> guess... */
+#define MAX_FEATURE_CONTROLLERS                2
+#define MAX_FEATURE_OFFSET             0x50
+#define FREG(c,r)                      (&(((c)->reg)[(r)>>2]))
+
+typedef struct feature_bit {
+       int             reg;            /* reg. offset from mac-io base */
+       unsigned int    polarity;       /* 0 = normal, 1 = inverse */
+       unsigned int    mask;           /* bit mask */
+} fbit;
+
+/* I don't have an OHare machine to test with, so I left those as they
+ * were. Someone with such a machine chould check out what OF says and
+ * try too see if they match the heathrow ones and should be changed too
+ */
+static fbit feature_bits_ohare_pbook[] = {
+       {0x38,0,0},                     /* FEATURE_null */
+       {0x38,0,OH_SCC_RESET},          /* FEATURE_Serial_reset */
+       {0x38,0,OH_SCC_ENABLE},         /* FEATURE_Serial_enable */
+       {0x38,0,OH_SCCA_IO},            /* FEATURE_Serial_IO_A */
+       {0x38,0,OH_SCCB_IO},            /* FEATURE_Serial_IO_B */
+       {0x38,0,OH_FLOPPY_ENABLE},      /* FEATURE_SWIM3_enable */
+       {0x38,0,OH_MESH_ENABLE},        /* FEATURE_MESH_enable */
+       {0x38,0,OH_IDE0_ENABLE},        /* FEATURE_IDE0_enable */
+       {0x38,1,OH_IDE0_RESET_N},       /* FEATURE_IDE0_reset */
+       {0x38,0,OH_IOBUS_ENABLE},       /* FEATURE_IOBUS_enable */
+       {0x38,1,OH_BAY_RESET_N},        /* FEATURE_Mediabay_reset */
+       {0x38,1,OH_BAY_POWER_N},        /* FEATURE_Mediabay_power */
+       {0x38,0,OH_BAY_PCI_ENABLE},     /* FEATURE_Mediabay_PCI_enable */
+       {0x38,0,OH_BAY_IDE_ENABLE},     /* FEATURE_IDE1_enable */
+       {0x38,1,OH_IDE1_RESET_N},       /* FEATURE_IDE1_reset */
+       {0x38,0,OH_BAY_FLOPPY_ENABLE},  /* FEATURE_Mediabay_floppy_enable */
+       {0x38,0,0},                     /* FEATURE_BMac_reset */
+       {0x38,0,0},                     /* FEATURE_BMac_IO_enable */
+       {0x38,0,0},                     /* FEATURE_Modem_power */
+       {0x38,0,0},                     /* FEATURE_Slow_SCC_PCLK */
+       {0x38,0,0},                     /* FEATURE_Sound_Power */
+       {0x38,0,0},                     /* FEATURE_Sound_CLK_Enable */
+       {0x38,0,0},                     /* FEATURE_IDE2_enable */
+       {0x38,0,0},                     /* FEATURE_IDE2_reset */
+       {0x38,0,0},                     /* FEATURE_Mediabay_IDE_switch */
+       {0x38,0,0},                     /* FEATURE_Mediabay_content */
 };
 
-/* assume these are the same as the ohare until proven otherwise */
-static u32 feature_bits_heathrow[] = {
-       0,                      /* FEATURE_null */
-       OH_SCC_RESET,           /* FEATURE_Serial_reset */
-       OH_SCC_ENABLE,          /* FEATURE_Serial_enable */
-       OH_SCCA_IO,             /* FEATURE_Serial_IO_A */
-       OH_SCCB_IO,             /* FEATURE_Serial_IO_B */
-       OH_FLOPPY_ENABLE,       /* FEATURE_SWIM3_enable */
-       OH_MESH_ENABLE,         /* FEATURE_MESH_enable */
-       OH_IDE_ENABLE,          /* FEATURE_IDE_enable */
-       OH_VIA_ENABLE,          /* FEATURE_VIA_enable */
-       OH_IDECD_POWER,         /* FEATURE_CD_power */
-       OH_BAY_RESET,           /* FEATURE_Mediabay_reset */
-       OH_BAY_ENABLE,          /* FEATURE_Mediabay_enable */
-       OH_BAY_PCI_ENABLE,      /* FEATURE_Mediabay_PCI_enable */
-       OH_BAY_IDE_ENABLE,      /* FEATURE_Mediabay_IDE_enable */
-       OH_BAY_FLOPPY_ENABLE,   /* FEATURE_Mediabay_floppy_enable */
-       0x80000000,             /* FEATURE_BMac_reset */
-       0x60000000,             /* FEATURE_BMac_IO_enable */
-       0x02000000,             /* FEATURE_Modem_Reset -> guess...*/
-       OH_IDE_POWER,           /* FEATURE_IDE_DiskPower -> guess... */
-       OH_IDE_RESET            /* FEATURE_IDE_Reset (0 based) -> guess... */
+/* Those bits are from a PowerBook. It's possible that desktop machines
+ * based on heathrow need a different definition or some bits removed
+ */
+static fbit feature_bits_heathrow[] = {
+       {0x38,0,0},                     /* FEATURE_null */
+       {0x38,0,HRW_RESET_SCC},         /* FEATURE_Serial_reset */
+       {0x38,0,HRW_SCC_ENABLE},        /* FEATURE_Serial_enable */
+       {0x38,0,HRW_SCCA_IO},           /* FEATURE_Serial_IO_A */
+       {0x38,0,HRW_SCCB_IO},           /* FEATURE_Serial_IO_B */
+       {0x38,0,HRW_SWIM_ENABLE},       /* FEATURE_SWIM3_enable */
+       {0x38,0,HRW_MESH_ENABLE},       /* FEATURE_MESH_enable */
+       {0x38,0,HRW_IDE0_ENABLE},       /* FEATURE_IDE0_enable */
+       {0x38,1,HRW_IDE0_RESET_N},      /* FEATURE_IDE0_reset */
+       {0x38,0,HRW_IOBUS_ENABLE},      /* FEATURE_IOBUS_enable */
+       {0x38,1,HRW_BAY_RESET_N},       /* FEATURE_Mediabay_reset */
+       {0x38,1,HRW_BAY_POWER_N},       /* FEATURE_Mediabay_power */
+       {0x38,0,HRW_BAY_PCI_ENABLE},    /* FEATURE_Mediabay_PCI_enable */
+       {0x38,0,HRW_BAY_IDE_ENABLE},    /* FEATURE_IDE1_enable */
+       {0x38,1,HRW_IDE1_RESET_N},      /* FEATURE_IDE1_reset */
+       {0x38,0,HRW_BAY_FLOPPY_ENABLE}, /* FEATURE_Mediabay_floppy_enable */
+       {0x38,0,HRW_BMAC_RESET},        /* FEATURE_BMac_reset */
+       {0x38,0,HRW_BMAC_IO_ENABLE},    /* FEATURE_BMac_IO_enable */
+       {0x38,1,HRW_MODEM_POWER_N},     /* FEATURE_Modem_power */
+       {0x38,0,HRW_SLOW_SCC_PCLK},     /* FEATURE_Slow_SCC_PCLK */
+       {0x38,1,HRW_SOUND_POWER_N},     /* FEATURE_Sound_Power */
+       {0x38,0,HRW_SOUND_CLK_ENABLE},  /* FEATURE_Sound_CLK_Enable */
+       {0x38,0,0},                     /* FEATURE_IDE2_enable */
+       {0x38,0,0},                     /* FEATURE_IDE2_reset */
+       {0x38,0,0},                     /* FEATURE_Mediabay_IDE_switch */
+       {0x38,0,0},                     /* FEATURE_Mediabay_content */
+};
+
+/*
+ * Those bits are from a 1999 G3 PowerBook, with a paddington chip.
+ * Mostly the same as the heathrow.
+ */
+static fbit feature_bits_paddington[] = {
+       {0x38,0,0},                     /* FEATURE_null */
+       {0x38,0,0},                     /* FEATURE_Serial_reset */
+       {0x38,0,HRW_SCC_ENABLE},        /* FEATURE_Serial_enable */
+       {0x38,0,HRW_SCCA_IO},           /* FEATURE_Serial_IO_A */
+       {0x38,0,HRW_SCCB_IO},           /* FEATURE_Serial_IO_B */
+       {0x38,0,HRW_SWIM_ENABLE},       /* FEATURE_SWIM3_enable */
+       {0x38,0,HRW_MESH_ENABLE},       /* FEATURE_MESH_enable */
+       {0x38,0,HRW_IDE0_ENABLE},       /* FEATURE_IDE0_enable */
+       {0x38,1,HRW_IDE0_RESET_N},      /* FEATURE_IDE0_reset */
+       {0x38,0,HRW_IOBUS_ENABLE},      /* FEATURE_IOBUS_enable */
+       {0x38,1,HRW_BAY_RESET_N},       /* FEATURE_Mediabay_reset */
+       {0x38,1,HRW_BAY_POWER_N},       /* FEATURE_Mediabay_power */
+       {0x38,0,HRW_BAY_PCI_ENABLE},    /* FEATURE_Mediabay_PCI_enable */
+       {0x38,0,HRW_BAY_IDE_ENABLE},    /* FEATURE_IDE1_enable */
+       {0x38,1,HRW_IDE1_RESET_N},      /* FEATURE_IDE1_reset */
+       {0x38,0,HRW_BAY_FLOPPY_ENABLE}, /* FEATURE_Mediabay_floppy_enable */
+       {0x38,0,HRW_BMAC_RESET},        /* FEATURE_BMac_reset */
+       {0x38,0,HRW_BMAC_IO_ENABLE},    /* FEATURE_BMac_IO_enable */
+       {0x38,1,PADD_MODEM_POWER_N},    /* FEATURE_Modem_power */
+       {0x38,0,HRW_SLOW_SCC_PCLK},     /* FEATURE_Slow_SCC_PCLK */
+       {0x38,1,HRW_SOUND_POWER_N},     /* FEATURE_Sound_Power */
+       {0x38,0,HRW_SOUND_CLK_ENABLE},  /* FEATURE_Sound_CLK_Enable */
+       {0x38,0,0},                     /* FEATURE_IDE2_enable */
+       {0x38,0,0},                     /* FEATURE_IDE2_reset */
+       {0x38,0,0},                     /* FEATURE_Mediabay_IDE_switch */
+       {0x38,0,0},                     /* FEATURE_Mediabay_content */
+};
+
+/* Those bits are for Core99 machines (iBook,G4,iMacSL/DV,Pismo,...).
+ */
+static fbit feature_bits_keylargo[] = {
+       {0x38,0,0},                     /* FEATURE_null */
+       {0x38,0,0},                     /* FEATURE_Serial_reset */
+       {0x38,0,0x00000054},            /* FEATURE_Serial_enable */
+       {0x38,0,0},                     /* FEATURE_Serial_IO_A */
+       {0x38,0,0},                     /* FEATURE_Serial_IO_B */
+       {0x38,0,0},                     /* FEATURE_SWIM3_enable */
+       {0x38,0,0},                     /* FEATURE_MESH_enable */
+       {0x3c,0,0},                     /* FEATURE_IDE0_enable */
+       {0x3c,1,0x01000000},            /* FEATURE_IDE0_reset */
+       {0x38,0,0},                     /* FEATURE_IOBUS_enable */
+       {0x34,1,0x00000200},            /* FEATURE_Mediabay_reset */
+       {0x34,1,0x00000400},            /* FEATURE_Mediabay_power */
+       {0x38,0,0},                     /* FEATURE_Mediabay_PCI_enable */
+       {0x3c,0,0x0},                   /* FEATURE_IDE1_enable */
+       {0x3c,1,0x08000000},            /* FEATURE_IDE1_reset */
+       {0x38,0,0},                     /* FEATURE_Mediabay_floppy_enable */
+       {0x38,0,0},                     /* FEATURE_BMac_reset */
+       {0x38,0,0},                     /* FEATURE_BMac_IO_enable */
+       {0x40,1,0x02000000},            /* FEATURE_Modem_power */
+       {0x38,0,0},                     /* FEATURE_Slow_SCC_PCLK */
+       {0x38,0,0},                     /* FEATURE_Sound_Power */
+       {0x38,0,0},                     /* FEATURE_Sound_CLK_Enable */
+       {0x38,0,0},                     /* FEATURE_IDE2_enable */
+       {0x3c,1,0x40000000},            /* FEATURE_IDE2_reset */
+       {0x34,0,0x00001000},            /* FEATURE_Mediabay_IDE_switch */
+       {0x34,0,0x00000100},            /* FEATURE_Mediabay_content */
 };
 
 /* definition of a feature controller object */
-struct feature_controller
-{
-       u32*                    bits;
+struct feature_controller {
+       fbit*                   bits;
        volatile u32*           reg;
        struct device_node*     device;
+       spinlock_t              lock;
 };
 
 /* static functions */
 static void
-feature_add_controller(struct device_node *controller_device, u32* bits);
+feature_add_controller(struct device_node *controller_device, fbit* bits);
 
-static int
+static struct feature_controller*
 feature_lookup_controller(struct device_node *device);
 
 /* static varialbles */
-static struct feature_controller       controllers[MAX_FEATURE_REGS];
+static struct feature_controller       controllers[MAX_FEATURE_CONTROLLERS];
 static int                             controller_count = 0;
 
 
@@ -96,18 +193,25 @@ feature_init(void)
        struct device_node *np;
 
        np = find_devices("mac-io");
-       while (np != NULL)
-       {
-               feature_add_controller(np, feature_bits_heathrow);
+       while (np != NULL) {
+               /* KeyLargo contains several (5 ?) FCR registers in mac-io,
+                * plus some gpio's which could eventually be handled here.
+                */
+               if (device_is_compatible(np, "Keylargo")) {
+                       feature_add_controller(np, feature_bits_keylargo);
+               } else if (device_is_compatible(np, "paddington")) {
+                       feature_add_controller(np, feature_bits_paddington);
+               } else {
+                       feature_add_controller(np, feature_bits_heathrow);
+               }
                np = np->next;
        }
        if (controller_count == 0)
        {
                np = find_devices("ohare");
-               if (np)
-               {
+               if (np) {
                        if (find_devices("via-pmu") != NULL)
-                               feature_add_controller(np, feature_bits_pbook);
+                               feature_add_controller(np, feature_bits_ohare_pbook);
                        else
                                /* else not sure; maybe this is a Starmax? */
                                feature_add_controller(np, NULL);
@@ -116,17 +220,26 @@ feature_init(void)
 
        if (controller_count)
                printk(KERN_INFO "Registered %d feature controller(s)\n", controller_count);
+
+#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_DMASOUND_MODULE
+       /* On PowerBooks, we disable the sound chip when dmasound is a module */
+       if (controller_count && find_devices("via-pmu") != NULL) {
+               feature_clear(controllers[0].device, FEATURE_Sound_power);
+               feature_clear(controllers[0].device, FEATURE_Sound_CLK_enable);
+       }
+#endif 
+#endif
 }
 
 static void
-feature_add_controller(struct device_node *controller_device, u32* bits)
+feature_add_controller(struct device_node *controller_device, fbit* bits)
 {
        struct feature_controller*      controller;
        
-       if (controller_count >= MAX_FEATURE_REGS)
-       {
+       if (controller_count >= MAX_FEATURE_CONTROLLERS) {
                printk(KERN_INFO "Feature controller %s skipped(MAX:%d)\n",
-                       controller_device->full_name, MAX_FEATURE_REGS);
+                       controller_device->full_name, MAX_FEATURE_CONTROLLERS);
                return;
        }
        controller = &controllers[controller_count];
@@ -140,30 +253,32 @@ feature_add_controller(struct device_node *controller_device, u32* bits)
        }
 
        controller->reg         = (volatile u32 *)ioremap(
-               controller_device->addrs[0].address + OHARE_FEATURE_REG, 4);
+               controller_device->addrs[0].address, MAX_FEATURE_OFFSET);
 
        if (bits == NULL) {
                printk(KERN_INFO "Twiddling the magic ohare bits\n");
-               out_le32(controller->reg, STARMAX_FEATURES);
+               out_le32(FREG(controller,OHARE_FEATURE_REG), STARMAX_FEATURES);
                return;
        }
 
+       spin_lock_init(&controller->lock);
+       
        controller_count++;
 }
 
-static int
+static struct feature_controller*
 feature_lookup_controller(struct device_node *device)
 {
        int     i;
        
        if (device == NULL)
-               return -EINVAL;
+               return NULL;
                
        while(device)
        {
                for (i=0; i<controller_count; i++)
                        if (device == controllers[i].device)
-                               return i;
+                               return &controllers[i];
                device = device->parent;
        }
 
@@ -172,35 +287,38 @@ feature_lookup_controller(struct device_node *device)
                device->name);
 #endif
        
-       return -ENODEV;
+       return NULL;
 }
 
 int
 feature_set(struct device_node* device, enum system_feature f)
 {
-       int             controller;
-       unsigned long   flags;
+       struct feature_controller*      controller;
+       unsigned long                   flags;
+       unsigned long                   value;
+       fbit*                           bit;
 
        if (f >= FEATURE_last)
                return -EINVAL; 
 
        controller = feature_lookup_controller(device);
-       if (controller < 0)
-               return controller;
+       if (!controller)
+               return -ENODEV;
+       bit = &controller->bits[f];
+       if (!bit->mask)
+               return -EINVAL;
        
 #ifdef DEBUG_FEATURE
        printk("feature: <%s> setting feature %d in controller @0x%x\n",
-               device->name, (int)f, (unsigned int)controllers[controller].reg);
+               device->name, (int)f, (unsigned int)controller->reg);
 #endif
 
-       save_flags(flags);
-       cli();
-       out_le32( controllers[controller].reg,
-                in_le32(controllers[controller].reg) |
-                controllers[controller].bits[f]);
-       (void)in_le32(controllers[controller].reg);
-       restore_flags(flags);
-       udelay(10);
+       spin_lock_irqsave(&controller->lock, flags);
+       value = in_le32(FREG(controller, bit->reg));
+       value = bit->polarity ? (value & ~bit->mask) : (value | bit->mask);
+       out_le32(FREG(controller, bit->reg), value);
+       (void)in_le32(FREG(controller, bit->reg));
+       spin_unlock_irqrestore(&controller->lock, flags);
        
        return 0;
 }
@@ -208,29 +326,32 @@ feature_set(struct device_node* device, enum system_feature f)
 int
 feature_clear(struct device_node* device, enum system_feature f)
 {
-       int             controller;
-       unsigned long   flags;
+       struct feature_controller*      controller;
+       unsigned long                   flags;
+       unsigned long                   value;
+       fbit*                           bit;
 
        if (f >= FEATURE_last)
                return -EINVAL; 
 
        controller = feature_lookup_controller(device);
-       if (controller < 0)
-               return controller;
+       if (!controller)
+               return -ENODEV;
+       bit = &controller->bits[f];
+       if (!bit->mask)
+               return -EINVAL;
        
 #ifdef DEBUG_FEATURE
        printk("feature: <%s> clearing feature %d in controller @0x%x\n",
-               device->name, (int)f, (unsigned int)controllers[controller].reg);
+               device->name, (int)f, (unsigned int)controller->reg);
 #endif
 
-       save_flags(flags);
-       cli();
-       out_le32( controllers[controller].reg,
-                in_le32(controllers[controller].reg) &
-                ~(controllers[controller].bits[f]));
-       (void)in_le32(controllers[controller].reg);
-       restore_flags(flags);
-       udelay(10);
+       spin_lock_irqsave(&controller->lock, flags);
+       value = in_le32(FREG(controller, bit->reg));
+       value = bit->polarity ? (value | bit->mask) : (value & ~bit->mask);
+       out_le32(FREG(controller, bit->reg), value);
+       (void)in_le32(FREG(controller, bit->reg));
+       spin_unlock_irqrestore(&controller->lock, flags);
        
        return 0;
 }
@@ -238,16 +359,29 @@ feature_clear(struct device_node* device, enum system_feature f)
 int
 feature_test(struct device_node* device, enum system_feature f)
 {
-       int             controller;
+       struct feature_controller*      controller;
+       unsigned long                   value;
+       fbit*                           bit;
 
        if (f >= FEATURE_last)
                return -EINVAL; 
 
        controller = feature_lookup_controller(device);
-       if (controller < 0)
-               return controller;
+       if (!controller)
+               return -ENODEV;
+       bit = &controller->bits[f];
+       if (!bit->mask)
+               return -EINVAL;
        
-       return (in_le32(controllers[controller].reg) &
-               controllers[controller].bits[f]) != 0;
+#ifdef DEBUG_FEATURE
+       printk("feature: <%s> clearing feature %d in controller @0x%x\n",
+               device->name, (int)f, (unsigned int)controller->reg);
+#endif
+       /* If one feature contains several bits, all of them must be set
+        * for value to be true, or all of them must be 0 if polarity is
+        * inverse
+        */
+       value = (in_le32(FREG(controller, bit->reg)) & bit->mask);
+       return bit->polarity ? (value == 0) : (value == bit->mask);
 }
 
index adcbb82423d037fd8a412ff31669ff12a9eb3734..21ec8504443e29a820c7bfd94a3f2fdf5a12f9f5 100644 (file)
@@ -13,6 +13,7 @@
  *    Copyright (C) 1996 Paul Mackerras.
  *  MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net).
  *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
+ *  AltiVec additions by Kumar Gala (kumar.gala@motorola.com).
  *
  *  This file contains the low-level support and setup for the
  *  PowerPC platform, including trap and interrupt dispatch.
@@ -82,6 +83,28 @@ LG_CACHE_LINE_SIZE = 4
 #define REST_16FPRS(n, base)   REST_8FPRS(n, base); REST_8FPRS(n+8, base)
 #define REST_32FPRS(n, base)   REST_16FPRS(n, base); REST_16FPRS(n+16, base)
 
+/*
+ * Once a version of gas that understands the AltiVec instructions
+ * is freely available, we can do this the normal way...  - paulus
+ */
+#define LVX(r,a,b)     .long   (31<<26)+((r)<<21)+((a)<<16)+((b)<<11)+(103<<1)
+#define STVX(r,a,b)    .long   (31<<26)+((r)<<21)+((a)<<16)+((b)<<11)+(231<<1)
+#define MFVSCR(r)      .long   (4<<26)+((r)<<11)+(770<<1)
+#define MTVSCR(r)      .long   (4<<26)+((r)<<11)+(802<<1)
+
+#define SAVE_VR(n,b,base)      li b,TSS_VR0+(16*(n)); STVX(n,b,base)
+#define SAVE_2VR(n,b,base)     SAVE_VR(n,b,base); SAVE_VR(n+1,b,base) 
+#define SAVE_4VR(n,b,base)     SAVE_2VR(n,b,base); SAVE_2VR(n+2,b,base) 
+#define SAVE_8VR(n,b,base)     SAVE_4VR(n,b,base); SAVE_4VR(n+4,b,base) 
+#define SAVE_16VR(n,b,base)    SAVE_8VR(n,b,base); SAVE_8VR(n+8,b,base)
+#define SAVE_32VR(n,b,base)    SAVE_16VR(n,b,base); SAVE_16VR(n+16,b,base)
+#define REST_VR(n,b,base)      li b,TSS_VR0+(16*(n)); LVX(n,b,base)
+#define REST_2VR(n,b,base)     REST_VR(n,b,base); REST_VR(n+1,b,base) 
+#define REST_4VR(n,b,base)     REST_2VR(n,b,base); REST_2VR(n+2,b,base) 
+#define REST_8VR(n,b,base)     REST_4VR(n,b,base); REST_4VR(n+4,b,base) 
+#define REST_16VR(n,b,base)    REST_8VR(n,b,base); REST_8VR(n+8,b,base) 
+#define REST_32VR(n,b,base)    REST_16VR(n,b,base); REST_16VR(n+16,b,base)
+
 #define SYNC \
        sync; \
        isync
@@ -651,7 +674,26 @@ SystemCall:
        STD_EXCEPTION(0xd00, SingleStep, SingleStepException)
 
        STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+
+#ifndef CONFIG_ALTIVEC
        STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
+#else
+/*
+ * The Altivec unavailable trap is at 0x0f20.  Foo.
+ * We effectively remap it to 0x3000.
+ */
+       . = 0xf00
+       b       Trap_0f
+trap_0f_cont:
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       li      r20,MSR_KERNEL
+       bl      transfer_to_handler
+       .long   UnknownException
+       .long   int_return
+
+       . = 0xf20
+       b       AltiVecUnavailable
+#endif /* CONFIG_ALTIVEC */
 
 #ifndef CONFIG_8xx
 /*
@@ -1169,9 +1211,24 @@ DataTLBError:
        STD_EXCEPTION(0x2f00, Trap_2f, UnknownException)
 
        . = 0x3000
-#else
+#ifdef CONFIG_ALTIVEC
+AltiVecUnavailable:
+       EXCEPTION_PROLOG
+       bne     load_up_altivec         /* if from user, just load it up */
+       li      r20,MSR_KERNEL
+       bl      transfer_to_handler     /* if from kernel, take a trap */
+       .long   KernelAltiVec
+       .long   int_return
+
+/* here are the bits of trap 0xf00 which got displaced */
+Trap_0f:
+       EXCEPTION_PROLOG
+       b       trap_0f_cont
+#endif /* CONFIG_ALTIVEC */
+
+#else /* CONFIG_8xx */
        . = 0x2000
-#endif
+#endif /* CONFIG_8xx */
 
 /*
  * This code finishes saving the registers to the exception frame
@@ -1493,6 +1550,7 @@ found_slot:
        REST_GPR(20, r21)
        REST_2GPRS(22, r21)
        lwz     r21,GPR21(r21)
+       sync
        rfi
        
 #ifdef __SMP__
@@ -1632,6 +1690,135 @@ giveup_fpu:
 #endif /* __SMP__ */
        blr
 
+#ifdef CONFIG_ALTIVEC
+/* Note that the AltiVec support is closely modeled after the FP
+ * support.  Changes to one are likely to be applicable to the
+ * other!  */
+load_up_altivec:
+/*
+ * Disable AltiVec for the task which had AltiVec previously,
+ * and save its AltiVec registers in its thread_struct.
+ * Enables AltiVec for use in the kernel on return.
+ * On SMP we know the AltiVec units are free, since we give it up every
+ * switch.  -- Kumar
+ */
+       mfmsr   r5
+       oris    r5,r5,MSR_VEC@h
+       SYNC
+       mtmsr   r5                      /* enable use of AltiVec now */
+       SYNC
+/*
+ * For SMP, we don't do lazy AltiVec switching because it just gets too
+ * horrendously complex, especially when a task switches from one CPU
+ * to another.  Instead we call giveup_altivec in switch_to.
+ */
+#ifndef __SMP__
+#ifndef CONFIG_APUS
+       lis     r6,-KERNELBASE@h
+#else
+       lis     r6,CYBERBASEp@h
+       lwz     r6,0(r6)
+#endif
+       addis   r3,r6,last_task_used_altivec@ha
+       lwz     r4,last_task_used_altivec@l(r3)
+       cmpi    0,r4,0
+       beq     1f
+       add     r4,r4,r6
+       addi    r4,r4,TSS       /* want TSS of last_task_used_altivec */
+       SAVE_32VR(0,r20,r4)
+       MFVSCR(vr0)
+       li      r20,TSS_VSCR
+       STVX(vr0,r20,r4)
+       lwz     r5,PT_REGS(r4)
+       add     r5,r5,r6
+       lwz     r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+       lis     r20,MSR_VEC@h
+       andc    r4,r4,r20       /* disable altivec for previous task */
+       stw     r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
+#endif /* __SMP__ */
+       /* enable use of AltiVec after return */
+       oris    r23,r23,MSR_VEC@h
+       mfspr   r5,SPRG3                /* current task's TSS (phys) */
+       li      r20,TSS_VSCR
+       LVX(vr0,r20,r5)
+       MTVSCR(vr0)
+       REST_32VR(0,r20,r5)
+#ifndef __SMP__
+       subi    r4,r5,TSS
+       sub     r4,r4,r6
+       stw     r4,last_task_used_altivec@l(r3)
+#endif /* __SMP__ */
+       /* restore registers and return */
+       lwz     r3,_CCR(r21)
+       lwz     r4,_LINK(r21)
+       mtcrf   0xff,r3
+       mtlr    r4
+       REST_GPR(1, r21)
+       REST_4GPRS(3, r21)
+       /* we haven't used ctr or xer */
+       mtspr   SRR1,r23
+       mtspr   SRR0,r22
+       REST_GPR(20, r21)
+       REST_2GPRS(22, r21)
+       lwz     r21,GPR21(r21)
+       SYNC
+       rfi
+
+/*
+ * AltiVec unavailable trap from kernel - print a message, but let
+ * the task use AltiVec in the kernel until it returns to user mode.
+ */
+KernelAltiVec:
+       lwz     r3,_MSR(r1)
+       oris    r3,r3,MSR_VEC@h
+       stw     r3,_MSR(r1)     /* enable use of AltiVec after return */
+       lis     r3,87f@h
+       ori     r3,r3,87f@l
+       mr      r4,r2           /* current */
+       lwz     r5,_NIP(r1)
+       bl      printk
+       b       int_return
+87:    .string "AltiVec used in kernel  (task=%p, pc=%x)  \n"
+       .align  4
+
+/*
+ * giveup_altivec(tsk)
+ * Disable AltiVec for the task given as the argument,
+ * and save the AltiVec registers in its thread_struct.
+ * Enables AltiVec for use in the kernel on return.
+ */
+
+       .globl  giveup_altivec
+giveup_altivec:
+       mfmsr   r5
+       oris    r5,r5,MSR_VEC@h
+       SYNC
+       mtmsr   r5                      /* enable use of AltiVec now */
+       SYNC
+       cmpi    0,r3,0
+       beqlr-                          /* if no previous owner, done */
+       addi    r3,r3,TSS               /* want TSS of task */
+       lwz     r5,PT_REGS(r3)
+       cmpi    0,r5,0
+       SAVE_32VR(0, r4, r3)
+       MFVSCR(vr0)
+       li      r4,TSS_VSCR
+       STVX(vr0, r4, r3)
+       beq     1f
+       lwz     r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+       lis     r3,MSR_VEC@h
+       andc    r4,r4,r3                /* disable AltiVec for previous task */
+       stw     r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
+#ifndef __SMP__
+       li      r5,0
+       lis     r4,last_task_used_altivec@ha
+       stw     r5,last_task_used_altivec@l(r4)
+#endif /* __SMP__ */
+       blr
+#endif /* CONFIG_ALTIVEC */
+
 #else  /* CONFIG_8xx */
        .globl  giveup_fpu
 giveup_fpu:
@@ -1660,10 +1847,6 @@ relocate_kernel:
        addi    r9,r9,0x6f58            /* translate source addr */
        cmpw    r31,r9                  /* (we have to on chrp) */
        beq     7f
-#if 0 // still needed ? breaks on me if I don't disable this
-       rlwinm  r4,r4,0,8,31            /* translate source address */
-       add     r4,r4,r3                /* to region mapped with BATs */
-#endif 
 7:     addis   r9,r26,klimit@ha        /* fetch klimit */
        lwz     r25,klimit@l(r9)
        addis   r25,r25,-KERNELBASE@h
@@ -1790,14 +1973,23 @@ start_here:
        cmpi    0,r9,4                  /* check for 604 */
        cmpi    1,r9,9                  /* or 604e */
        cmpi    2,r9,10                 /* or mach5 */
+       cmpi    3,r9,8                  /* check for 750 (G3) */
+       cmpi    4,r9,12                 /* or 7400 (G4) */
        cror    2,2,6
        cror    2,2,10
        bne     4f
        ori     r11,r11,HID0_SIED|HID0_BHTE /* for 604[e], enable */
        bne     2,5f
        ori     r11,r11,HID0_BTCD
-5:     mtspr   HID0,r11                /* superscalar exec & br history tbl */
+       b       5f
 4:
+       cror    14,14,18
+       bne     3,6f
+       ori     r11,r11,HID0_SGE|HID0_BHTE|HID0_BTIC|HID0_ABE /* for g3/g4, enable */
+       li      r3,0
+       mtspr   ICTC,r3
+5:     mtspr   HID0,r11                /* superscalar exec & br history tbl */
+6:
 #endif /* CONFIG_8xx */
 #ifdef __SMP__
        /* if we're the second cpu stack and r2 are different
@@ -1878,10 +2070,10 @@ start_here:
        li      r3,MSR_KERNEL & ~(MSR_IR|MSR_DR)
        mtspr   SRR0,r4
        mtspr   SRR1,r3
+       SYNC
        rfi
 /* Load up the kernel context */
 2:
-       SYNC                    /* Force all PTE updates to finish */
        tlbia                   /* Clear all TLB entries */
        sync                    /* wait for tlbia/tlbie to finish */
 #ifdef __SMP__
@@ -1938,6 +2130,7 @@ start_here:
 #endif /* __SMP__ */
        mtspr   SRR0,r3
        mtspr   SRR1,r4
+       SYNC
        rfi                     /* enable MMU and jump to start_kernel */
 
 /*
@@ -2114,6 +2307,9 @@ _GLOBAL(_switch)
        mflr    r20             /* Return to switch caller */
        mfmsr   r22
        li      r0,MSR_FP       /* Disable floating-point */
+#ifdef CONFIG_ALTIVEC
+       oris    r0,r0,MSR_VEC@h
+#endif /* CONFIG_ALTIVEC */
        andc    r22,r22,r0
        stw     r20,_NIP(r1)
        stw     r22,_MSR(r1)
@@ -2426,6 +2622,38 @@ _GLOBAL(clear_page)
        bdnz    1b
        blr
 
+/*
+ * Copy a whole page.  We use the dcbz instruction on the destination
+ * to reduce memory traffic (it eliminates the unnecessary reads of
+ * the destination into cache).  This requires that the destination
+ * is cacheable.
+ */
+_GLOBAL(copy_page)
+       li      r0,4096/CACHE_LINE_SIZE
+       mtctr   r0
+       addi    r3,r3,-4
+       addi    r4,r4,-4
+       li      r5,4
+1:     dcbz    r5,r3
+       lwz     r6,4(r4)
+       lwz     r7,8(r4)
+       lwz     r8,12(r4)
+       lwzu    r9,16(r4)
+       stw     r6,4(r3)
+       stw     r7,8(r3)
+       stw     r8,12(r3)
+       stwu    r9,16(r3)
+       lwz     r6,4(r4)
+       lwz     r7,8(r4)
+       lwz     r8,12(r4)
+       lwzu    r9,16(r4)
+       stw     r6,4(r3)
+       stw     r7,8(r3)
+       stw     r8,12(r3)
+       stwu    r9,16(r3)
+       bdnz    1b
+       blr
+
 /*
  * Flush entries from the hash table with VSIDs in the range
  * given.
@@ -2624,6 +2852,7 @@ enter_rtas:
        mtspr   SPRG2,r7
        mtspr   SRR0,r8
        mtspr   SRR1,r9
+       SYNC
        rfi
 1:     addis   r9,r1,-KERNELBASE@h
        lwz     r8,20(r9)       /* get return address */
@@ -2632,6 +2861,7 @@ enter_rtas:
        mtspr   SPRG2,r0
        mtspr   SRR0,r8
        mtspr   SRR1,r9
+       SYNC
        rfi                     /* return to caller */
 #endif /* CONFIG_8xx */
 
index 5149c291ac75896663090f5de730fbf53a61480c..e9c23aef84f0d9ddc257913e4be80acf82b32432 100644 (file)
@@ -26,6 +26,7 @@ struct hw_interrupt_type {
 struct irqdesc {
        struct irqaction *action;
        struct hw_interrupt_type *ctl;
+       int level;
 };
 
 extern struct irqdesc irq_desc[NR_IRQS];
index 0f1eb3eb5f9cca6a64db981afb5a2f5679fd4a80..20a1356b982108f497b29c97493044a6e8a6a411 100644 (file)
@@ -454,6 +454,7 @@ mbx_init(unsigned long r3, unsigned long r4, unsigned long r5,
        ppc_md.kbd_init_hw       = pckbd_init_hw;
 #ifdef CONFIG_MAGIC_SYSRQ
        ppc_md.kbd_sysrq_xlate   = pckbd_sysrq_xlate;
+       ppc_md.SYSRQ_KEY         = 0x54;
 #endif
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
index 9425127147e5c6a0016fc5b78476938226c830b7..223f5c98456c68f8fe71f5b22a0e5764c3fe7e36 100644 (file)
@@ -480,6 +480,20 @@ _GLOBAL(_set_THRM3)
 _GLOBAL(_get_PVR)
        mfspr   r3,PVR
        blr
+       
+_GLOBAL(_get_HID0)
+       mfspr   r3,HID0
+       blr
+
+_GLOBAL(_get_ICTC)
+       mfspr   r3,ICTC
+       blr
+
+_GLOBAL(_set_ICTC)
+       mtspr   ICTC,r3
+       blr
+
+       
 /*
        L2CR functions
        Copyright Â© 1997-1998 by PowerLogix R & D, Inc.
@@ -546,6 +560,8 @@ _GLOBAL(_set_L2CR)
        rlwinm  r4,r4,16,16,31
        cmplwi  r4,0x0008
        beq     thisIs750
+       cmplwi  r4,0x000c
+       beq thisIs750
        li      r3,-1
        blr
        
@@ -640,9 +656,11 @@ _GLOBAL(_get_L2CR)
        mfspr   r3,PVR
        rlwinm  r3,r3,16,16,31
        cmplwi  r3,0x0008
+       beq     1f
+       cmplwi  r3,0x000c
        li      r3,0
        bnelr
-       
+1:     
        /* Return the L2CR contents */
        mfspr   r3,L2CR
        blr
index a3977193a3fe26ba525fb847f41b6abde914eddc..9cf0eb8349deeff254e3878c0ce79eb276a004fd 100644 (file)
@@ -8,7 +8,7 @@
  * #defines from the assembly-language output.
  */
 
-#include <stddef.h>
+#include <linux/config.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -48,6 +48,12 @@ main(void)
        DEFINE(NEED_RESCHED, offsetof(struct task_struct, need_resched));
        DEFINE(TSS_FPR0, offsetof(struct thread_struct, fpr[0]));
        DEFINE(TSS_FPSCR, offsetof(struct thread_struct, fpscr));
+#ifdef CONFIG_ALTIVEC
+       DEFINE(TSS_VR0, offsetof(struct thread_struct, vr[0]));
+       DEFINE(TSS_VRSAVE, offsetof(struct thread_struct, vrsave));
+       DEFINE(TSS_VSCR, offsetof(struct thread_struct, vscr));
+#endif /* CONFIG_ALTIVEC */
+
        /* Interrupt register frame */
        DEFINE(TASK_UNION_SIZE, sizeof(union task_union));
        DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
index 9fb8f274bda42eaeeee5e3ad16aaffdd83d248dc..f93945dd657f4d97e5c4cbfe12c947c24f59477f 100644 (file)
@@ -5,6 +5,12 @@
  *
  *  Fixed up IPI and restructured a bit
  *    Cort Dougan <cort@ppc.kernel.org>
+ *
+ *  Added initialisation code for Apple Core99 machines, tweaked a few things
+ *  to avoid bogus interrupts and to make sure the disable function exits with
+ *  the interrupt actually masked.
+ *    Benjamin Herrenschmidt <bh40@calva.net>
+ *  Todo: map interrupts to all available CPUs after the ack round
  * 
  *  This file is subject to the terms and conditions of the GNU General Public
  *  License.  See the file COPYING in the main directory of this archive
 #include <asm/io.h>
 #include <asm/irq.h>
 #include "open_pic.h"
+#ifdef __powerpc__
+#include <asm/prom.h>
+#endif
 
 #define REGISTER_DEBUG
 #undef REGISTER_DEBUG
 
+#ifdef __powerpc__
+extern int use_of_interrupt_tree;
+#endif
+
 volatile struct OpenPIC *OpenPIC = NULL;
 u_int OpenPIC_NumInitSenses __initdata = 0;
 u_char *OpenPIC_InitSenses __initdata = NULL;
@@ -80,7 +93,7 @@ static void no_action(int ir1, void *dev, struct pt_regs *regs)
  *  I/O functions
  */
 #ifdef __i386__
-static inline u_int ld_le32(volatile u_int *addr)
+static inline u_int in_le32(volatile u_int *addr)
 {
        return *addr;
 }
@@ -95,7 +108,7 @@ u_int openpic_read(volatile u_int *addr)
 {
        u_int val;
 
-       val = ld_le32(addr);
+       val = in_le32(addr);
 #ifdef REGISTER_DEBUG
        printk("openpic_read(0x%08x) = 0x%08x\n", (u_int)addr, val);
 #endif
@@ -142,6 +155,9 @@ static void openpic_safe_writefield(volatile u_int *addr, u_int mask,
 {
        openpic_setfield(addr, OPENPIC_MASK);
        /* wait until it's not in use */
+       /* BenH: Is this code really enough ? I would rather check the result
+        *       and eventually retry ...
+        */
        while (openpic_read(addr) & OPENPIC_ACTIVITY);
        openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
 }
@@ -149,6 +165,16 @@ static void openpic_safe_writefield(volatile u_int *addr, u_int mask,
 /*
  *  Initialize the OpenPIC
  */
+
+/* PoweMac note:
+ *
+ * With BootX, we consider the controller as beeing already initialized by MacOS
+ * and we only mask out interrupts.
+ * With OF booting, we initialize the interrupts that we find in the device tree,
+ * other ones are just masked out.
+ * Note: We might want to adjust priorities too.
+ */
+
 __initfunc(void openpic_init(int main_pic))
 {
        u_int t, i;
@@ -179,13 +205,16 @@ __initfunc(void openpic_init(int main_pic))
                      OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1;
        printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n", version,
               NumProcessors, NumSources, OpenPIC);
-       timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
-       printk("OpenPIC timer frequency is ");
-       if (timerfreq)
-               printk("%d Hz\n", timerfreq);
-       else
-               printk("not set\n");
-
+       /* Apple's OpenPIC is an IBM MPIC without the timer. */
+       if (_machine != _MACH_Pmac) {
+               timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
+               printk("OpenPIC timer frequency is ");
+               if (timerfreq)
+                       printk("%d Hz\n", timerfreq);
+               else
+                       printk("not set\n");
+       }
+       
        if ( main_pic )
        {
                /* Initialize timer interrupts */
@@ -198,24 +227,60 @@ __initfunc(void openpic_init(int main_pic))
            
                /* Initialize IPI interrupts */
                for (i = 0; i < OPENPIC_NUM_IPI; i++) {
-                       openpic_initipi(i, 10, OPENPIC_VEC_IPI+i);
+                       openpic_initipi(i, 0/*10*/, OPENPIC_VEC_IPI+i);
                }
            
-               /* Initialize external interrupts */
-               for (i = 0; i < NumSources; i++) {
-                       /* Enabled, Priority 8 */
-                       openpic_initirq(i, 8, open_pic.irq_offset+i, 0,
-                                       i < OpenPIC_NumInitSenses ? OpenPIC_InitSenses[i] : 1);
-                       /* Processor 0 */
-                       openpic_mapirq(i, 1<<0);
+               if (_machine != _MACH_Pmac) {
+                       /* Initialize external interrupts */
+                       for (i = 0; i < NumSources; i++) {
+                           /* Enabled, Priority 8 */
+                           openpic_initirq(i, 8, open_pic.irq_offset+i, 0,
+                               i < OpenPIC_NumInitSenses ? OpenPIC_InitSenses[i] : 1);
+                           /* Processor 0 */
+                           openpic_mapirq(i, 1<<0);
+                       }
+               } else {
+                       /* Prevent any interrupt from occuring during initialisation.
+                        * Hum... I beleive this is not necessary, Apple does that in
+                        * Darwin's PowerExpress code.
+                        */
+                       openpic_set_priority(0, 0xf);
+
+                       /* First disable all interrupts and map them to CPU 0 */
+                       for (i = 0; i < NumSources; i++) {
+                               openpic_disable_irq(i);
+                               openpic_mapirq(i, 1<<0);
+                       }
+                       
+                       /* If we use the device tree, then lookup all interrupts and
+                        * initialize them according to sense infos found in the tree
+                        */
+                       if (use_of_interrupt_tree) {
+                               struct device_node* np = find_all_nodes();
+                               while(np) {
+                                   int j, pri;
+                                   pri = strcmp(np->name, "programmer-switch") ? 2 : 7;
+                                   for (j=0;j<np->n_intrs;j++) {
+                                       openpic_initirq(        np->intrs[j].line,
+                                                               pri,
+                                                               np->intrs[j].line,
+                                                               np->intrs[j].sense,
+                                                               np->intrs[j].sense);
+                                       irq_desc[np->intrs[j].line].level = np->intrs[j].sense;
+                                   }
+                                   np = np->next;
+                               }
+                       } else {
+                               /* Fixme: read level value from controller */
+                               printk("openpic: WARNING, openpic running without interrupt tree\n");
+                       }
                }
-           
+
                /* Initialize the spurious interrupt */
                openpic_set_spurious(OPENPIC_VEC_SPURIOUS);
 
                /* Gemini has no i8259 */
-               if ( _machine != _MACH_gemini )
-               {
+               if (( _machine != _MACH_gemini ) && (_machine != _MACH_Pmac)) {
                        /* SIOint (8259 cascade) is special */
                        openpic_initirq(0, 8, open_pic.irq_offset, 1, 1);
                        openpic_mapirq(0, 1<<0);
@@ -225,6 +290,14 @@ __initfunc(void openpic_init(int main_pic))
                }
                openpic_set_priority(0, 0);
                openpic_disable_8259_pass_through();
+
+               /* We ack pending interrupts to avoid blocking them */
+               if (_machine == _MACH_Pmac) {
+                       for (i = 0; i < NumSources; i++) {
+                               (void)openpic_irq(0);
+                               openpic_eoi(0);
+                       }
+               }
        }
 }
 
@@ -281,6 +354,7 @@ void openpic_eoi(u_int cpu)
 {
        check_arg_cpu(cpu);
        openpic_write(&OpenPIC->THIS_CPU.EOI, 0);
+       (void)openpic_read(&OpenPIC->THIS_CPU.EOI);
 }
 
 
@@ -428,12 +502,22 @@ void openpic_enable_irq(u_int irq)
 {
        check_arg_irq(irq);
        openpic_clearfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK);
+       /* make sure mask gets to controller before we return to user */
+       do {
+               mb();
+       } while(openpic_readfield(&OpenPIC->Source[irq].Vector_Priority,
+                       OPENPIC_MASK));
 }
 
 void openpic_disable_irq(u_int irq)
 {
        check_arg_irq(irq);
        openpic_setfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK);
+       /* make sure mask gets to controller before we return to user */
+       do {
+               mb();
+       } while(!openpic_readfield(&OpenPIC->Source[irq].Vector_Priority,
+                       OPENPIC_MASK));
 }
 
 /*
@@ -452,10 +536,11 @@ void openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense)
        check_arg_vec(vec);
        openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority,
                                OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
-                               OPENPIC_SENSE_POLARITY | OPENPIC_SENSE_LEVEL,
+                               OPENPIC_POLARITY_MASK | OPENPIC_SENSE_MASK,
                                (pri << OPENPIC_PRIORITY_SHIFT) | vec |
-                               (pol ? OPENPIC_SENSE_POLARITY : 0) |
-                               (sense ? OPENPIC_SENSE_LEVEL : 0));
+                               (pol ? OPENPIC_POLARITY_POSITIVE :
+                                       OPENPIC_POLARITY_NEGATIVE) |
+                               (sense ? OPENPIC_SENSE_LEVEL : OPENPIC_SENSE_EDGE));
 }
 
 /*
index 39b2337fa533819e0ce12cedefea8e4ee56ec61e..058dc1f511e711366317d53f4289387690a79e2a 100644 (file)
@@ -93,7 +93,7 @@ void __init fix_intr(struct device_node *node, struct pci_dev *dev)
 
        for (; node != 0;node = node->sibling) {
                class_code = (unsigned int *) get_property(node, "class-code", 0);
-               if((*class_code >> 8) == PCI_CLASS_BRIDGE_PCI)
+               if(class_code && (*class_code >> 8) == PCI_CLASS_BRIDGE_PCI)
                        fix_intr(node->child, dev);
                reg = (unsigned int *) get_property(node, "reg", 0);
                if (reg == 0 || ((reg[0] >> 8) & 0xff) != dev->devfn)
index 089169e37a0ee1fc296846cdf1d4ca3c5ae1f43b..462b92bc70c7d6aad54f85e94c837812e536801d 100644 (file)
 struct bridge_data **bridges, *bridge_list;
 static int max_bus;
 
+struct uninorth_data {
+       struct device_node*     node;
+       volatile unsigned int*  cfg_addr;
+       volatile unsigned int*  cfg_data;
+};
+
+static struct uninorth_data uninorth_bridges[3];
+static int uninorth_count;
+static int uninorth_default = -1;
+
+
 static void add_bridges(struct device_node *dev, unsigned long *mem_ptr);
 
 /*
@@ -71,6 +83,161 @@ int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr,
        return 0;
 }
 
+/* This function only works for bus 0, uni-N uses a different mecanism for
+ * other busses (see below)
+ */
+#define UNI_N_CFA0(devfn, off) \
+       ((1 << (unsigned long)PCI_SLOT(dev_fn)) \
+       | (((unsigned long)PCI_FUNC(dev_fn)) << 8) \
+       | (((unsigned long)(off)) & 0xFCUL))
+
+/* This one is for type 1 config accesses */
+#define UNI_N_CFA1(bus, devfn, off)    \
+       ((((unsigned long)(bus)) << 16) \
+       |(((unsigned long)(devfn)) << 8) \
+       |(((unsigned long)(off)) & 0xFCUL) \
+       |1UL)
+       
+
+/* We should really use RTAS here, unfortunately, it's not available with BootX.
+ * (one more reason for writing a beautiful OF booter). I'll do the RTAS stuff
+ * later, once I have something that works enough with BootX.
+ */
+__pmac static
+unsigned int
+uni_north_access_data(unsigned char bus, unsigned char dev_fn,
+                               unsigned char offset)
+{
+       struct device_node *node, *bridge_node;
+       int bridge = uninorth_default;
+       unsigned int caddr;
+
+       if (bus == 0) {
+               if (PCI_SLOT(dev_fn) < 11) {
+                       return 0;
+               }
+               /* We look for the OF device corresponding to this bus/devfn pair. If we
+                * don't find it, we default to the external PCI */
+               bridge_node = NULL;
+               node = find_pci_device_OFnode(bus, dev_fn & 0xf8);
+               if (node) {
+                    /* note: we don't stop on the first occurence since we need to go
+                     * up to the root bridge */
+                   do {
+                       if (!strcmp(node->type, "pci"))
+                               bridge_node = node;
+                       node=node->parent;
+                   } while (node);
+               }
+               if (bridge_node) {
+                   int i;
+                   for (i=0;i<uninorth_count;i++)
+                       if (uninorth_bridges[i].node == bridge_node) {
+                           bridge = i;
+                           break;
+                       }
+               }
+               caddr = UNI_N_CFA0(dev_fn, offset);
+       } else
+               caddr = UNI_N_CFA1(bus, dev_fn, offset);
+
+       if (bridge == -1) {
+               printk(KERN_WARNING "pmac_pci: no default bridge !\n");
+               return 0;
+       }
+               
+       /* Uninorth will return garbage if we don't read back the value ! */
+       out_le32(uninorth_bridges[bridge].cfg_addr, caddr);
+       (void)in_le32(uninorth_bridges[bridge].cfg_addr);
+       /* Yes, offset is & 7, not & 3 ! */
+       return (unsigned int)(uninorth_bridges[bridge].cfg_data) + (offset & 0x07);
+}
+
+__pmac
+int uni_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+                                 unsigned char offset, unsigned char *val)
+{
+       unsigned int addr;
+       
+       *val = 0xff;
+       addr = uni_north_access_data(bus, dev_fn, offset);
+       if (!addr)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       *val = in_8((volatile unsigned char*)addr);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+__pmac
+int uni_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+                                 unsigned char offset, unsigned short *val)
+{
+       unsigned int addr;
+       
+       *val = 0xffff;
+       addr = uni_north_access_data(bus, dev_fn, offset);
+       if (!addr)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       *val = in_le16((volatile unsigned short*)addr);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+__pmac
+int uni_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+                                  unsigned char offset, unsigned int *val)
+{
+       unsigned int addr;
+       
+       *val = 0xffff;
+       addr = uni_north_access_data(bus, dev_fn, offset);
+       if (!addr)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       *val = in_le32((volatile unsigned int*)addr);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+__pmac
+int uni_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+                                  unsigned char offset, unsigned char val)
+{
+       unsigned int addr;
+       
+       addr = uni_north_access_data(bus, dev_fn, offset);
+       if (!addr)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       out_8((volatile unsigned char *)addr, val);
+       (void)in_8((volatile unsigned char *)addr);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+__pmac
+int uni_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+                                  unsigned char offset, unsigned short val)
+{
+       unsigned int addr;
+       
+       addr = uni_north_access_data(bus, dev_fn, offset);
+       if (!addr)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       out_le16((volatile unsigned short *)addr, val);
+       (void)in_le16((volatile unsigned short *)addr);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+__pmac
+int uni_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+                                   unsigned char offset, unsigned int val)
+{
+       unsigned int addr;
+       
+       addr = uni_north_access_data(bus, dev_fn, offset);
+       if (!addr)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       out_le32((volatile unsigned int *)addr, val);
+       (void)in_le32((volatile unsigned int *)addr);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+
 __pmac
 int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
                                  unsigned char offset, unsigned char *val)
@@ -360,6 +527,36 @@ __initfunc(static void init_bandit(struct bridge_data *bp))
               bp->io_base);
 }
 
+#define GRACKLE_PICR1_STG              0x00000040
+#define GRACKLE_PICR1_LOOPSNOOP                0x00000010
+
+/* N.B. this is called before bridges is initialized, so we can't
+   use grackle_pcibios_{read,write}_config_dword. */
+static inline void grackle_set_stg(struct bridge_data *bp, int enable)
+{
+       unsigned int val;
+
+       out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+       val = in_le32((volatile unsigned int *)bp->cfg_data);
+       val = enable? (val | GRACKLE_PICR1_STG) :
+               (val & ~GRACKLE_PICR1_STG);
+       out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+       out_le32((volatile unsigned int *)bp->cfg_data, val);
+}
+
+static inline void grackle_set_loop_snoop(struct bridge_data *bp, int enable)
+{
+       unsigned int val;
+
+       out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+       val = in_le32((volatile unsigned int *)bp->cfg_data);
+       val = enable? (val | GRACKLE_PICR1_LOOPSNOOP) :
+               (val & ~GRACKLE_PICR1_LOOPSNOOP);
+       out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+       out_le32((volatile unsigned int *)bp->cfg_data, val);
+}
+
+
 __initfunc(unsigned long pmac_find_bridges(unsigned long mem_start, unsigned long mem_end))
 {
        int bus;
@@ -411,21 +608,49 @@ __initfunc(static void add_bridges(struct device_node *dev, unsigned long *mem_p
                        printk(KERN_INFO "PCI buses %d..%d", bus_range[0],
                               bus_range[1]);
                printk(" controlled by %s at %x\n", dev->name, addr->address);
+               if (device_is_compatible(dev, "uni-north")) {
+                       int i = uninorth_count++;
+                       uninorth_bridges[i].cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
+                       uninorth_bridges[i].cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
+                       uninorth_bridges[i].node = dev;
+                       /* XXX This is the bridge with the PCI expansion bus. This is also the
+                        * address of the bus that will receive type 1 config accesses and io
+                        * accesses. Appears to be correct for iMac DV and G4 Sawtooth too.
+                        * That means that we cannot do io cycles on the AGP bus nor the internal
+                        * ethernet/fw bus. Fortunately, they appear not to be needed on iMac DV
+                        * and G4 neither.
+                        */
+                       if (addr->address == 0xf2000000)
+                               uninorth_default = i;
+                       else
+                               continue;
+               }
                bp = (struct bridge_data *) *mem_ptr;
                *mem_ptr += sizeof(struct bridge_data);
-               if (strcmp(dev->name, "pci") != 0) {
-                       bp->cfg_addr = (volatile unsigned int *)
-                               ioremap(addr->address + 0x800000, 0x1000);
-                       bp->cfg_data = (volatile unsigned char *)
-                               ioremap(addr->address + 0xc00000, 0x1000);
-                       bp->io_base = (void *) ioremap(addr->address, 0x10000);
-               } else {
-                       /* XXX */
+               if (device_is_compatible(dev, "uni-north")) {
+                       bp->cfg_addr = 0;
+                       bp->cfg_data = 0;
+                       /* is 0x10000 enough for io space ? */
+                       bp->io_base = (void *)ioremap(addr->address, 0x10000);
+               } else if (strcmp(dev->name, "pci") == 0) {
+                       /* XXX assume this is a mpc106 (grackle) */
                        bp->cfg_addr = (volatile unsigned int *)
                                ioremap(0xfec00000, 0x1000);
                        bp->cfg_data = (volatile unsigned char *)
                                ioremap(0xfee00000, 0x1000);
                         bp->io_base = (void *) ioremap(0xfe000000, 0x20000);
+                        if (machine_is_compatible("AAPL,PowerBook1998"))
+                               grackle_set_loop_snoop(bp, 1);
+#if 0                  /* Disabled for now, HW problems ??? */
+                       grackle_set_stg(bp, 1);
+#endif
+               } else {
+                       /* a `bandit' or `chaos' bridge */
+                       bp->cfg_addr = (volatile unsigned int *)
+                               ioremap(addr->address + 0x800000, 0x1000);
+                       bp->cfg_data = (volatile unsigned char *)
+                               ioremap(addr->address + 0xc00000, 0x1000);
+                       bp->io_base = (void *) ioremap(addr->address, 0x10000);
                }
                if (isa_io_base == 0)
                        isa_io_base = (unsigned long) bp->io_base;
@@ -468,7 +693,13 @@ pmac_pcibios_fixup(void))
                if (pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin) ||
                    !pin)
                        continue; /* No interrupt generated -> no fixup */
-                fix_intr(bp->node->child, dev);
+               /* We iterate all instances of uninorth for now */      
+               if (uninorth_count && dev->bus->number == 0) {
+                       int i;
+                       for (i=0;i<uninorth_count;i++)
+                               fix_intr(uninorth_bridges[i].node->child, dev);
+               } else
+                       fix_intr(bp->node->child, dev);
        }
 }
 
@@ -476,9 +707,17 @@ __initfunc(
 void
 pmac_setup_pci_ptrs(void))
 {
-       if (find_devices("pci") != 0) {
-               /* looks like a G3 powermac */
-               set_config_access_method(grackle);
+       struct device_node* np;
+
+       np = find_devices("pci");
+       if (np != 0) {
+               if (device_is_compatible(np, "uni-north")) {
+                       /* looks like an Core99 powermac */
+                       set_config_access_method(uni);
+               } else {
+                       /* looks like a G3 powermac */
+                       set_config_access_method(grackle);
+               }
        } else {
                set_config_access_method(pmac);
        }
index a1610c445bd0a77d9894057016995e7957a21557..083e043e8b98dc4748a0798f6fcef8da8924bd82 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/sched.h>
 #include <linux/signal.h>
 #include <linux/pci.h>
+#include <linux/openpic.h>
 #include <asm/pci-bridge.h>
 #include <asm/io.h>
 #include <asm/smp.h>
@@ -27,6 +28,7 @@ static volatile struct pmac_irq_hw *pmac_irq_hw[4] = {
 
 static int max_irqs;
 static int max_real_irqs;
+static int has_openpic = 0;
 
 #define MAXCOUNT 10000000
 
@@ -104,6 +106,18 @@ static void __pmac pmac_unmask_irq(unsigned int irq_nr)
         pmac_set_irq_mask(irq_nr);
 }
 
+static void pmac_openpic_mask_irq(unsigned int irq_nr)
+{
+       openpic_disable_irq(irq_nr);
+}
+
+static void pmac_openpic_unmask_irq(unsigned int irq_nr)
+{
+       openpic_enable_irq(irq_nr);
+}
+
+
+
 struct hw_interrupt_type pmac_pic = {
         " PMAC-PIC ",
         NULL,
@@ -126,6 +140,17 @@ struct hw_interrupt_type gatwick_pic = {
        0
 };
 
+struct hw_interrupt_type pmac_open_pic = {
+       " OpenPIC  ",
+       NULL,
+       NULL,
+       NULL,
+       pmac_openpic_unmask_irq,
+       pmac_openpic_mask_irq,
+       NULL,/*pmac_openpic_mask_irq,*/
+       0
+};
+
 static void gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
 {
        int irq, bits;
@@ -196,6 +221,29 @@ pmac_do_IRQ(struct pt_regs *regs,
         }
 #endif /* __SMP__ */
 
+       /* Yeah, I know, this could be a separate do_IRQ function */
+       if (has_openpic) {
+           irq = openpic_irq(0);
+           if (irq == OPENPIC_VEC_SPURIOUS) {
+                /* Spurious interrupts should never be ack'ed */
+                ppc_spurious_interrupts++;
+            } else {
+               /* Can this happen ? (comes from CHRP code) */
+               if (irq < 0) {
+                   printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
+                       irq, regs->nip);
+                   ppc_spurious_interrupts++;
+               } else {
+                   if (!irq_desc[irq].level)
+                       openpic_eoi(0);
+                   ppc_irq_dispatch_handler( regs, irq );
+                   if (irq_desc[irq].level)
+                       openpic_eoi(0);
+               }
+            }
+            return;
+       }
+
         for (irq = max_real_irqs - 1; irq > 0; irq -= 32) {
                 int i = irq >> 5;
                 bits = ld_le32(&pmac_irq_hw[i]->flag)
@@ -351,6 +399,36 @@ pmac_pic_init(void))
         volatile struct pmac_irq_hw *addr;
        int second_irq;
 
+       /* We first try to detect Apple's new Core99 chipset, since mac-io
+        * is quite different on those machines and contains an IBM MPIC2.
+        */
+       irqctrler = find_type_devices("open-pic");
+       if (irqctrler != NULL) {
+           printk("PowerMac using OpenPIC irq controller\n");
+           if (irqctrler->n_addrs > 0) {
+#ifdef CONFIG_XMON
+               struct device_node* pswitch;
+#endif /* CONFIG_XMON */       
+               OpenPIC = (volatile struct OpenPIC *)
+                       ioremap(irqctrler->addrs[0].address,
+                       irqctrler->addrs[0].size);
+               for ( i = 0 ; i < NR_IRQS ; i++ ) {
+                   irq_desc[i].ctl = &pmac_open_pic;
+                   irq_desc[i].level = 0;
+               }
+               openpic_init(1);
+               has_openpic = 1;
+#ifdef CONFIG_XMON
+               pswitch = find_devices("programmer-switch");
+               if (pswitch && pswitch->n_intrs)
+                       request_irq(pswitch->intrs[0].line, xmon_irq, 0,        
+                               "NMI - XMON", 0);
+#endif /* CONFIG_XMON */
+               return;
+           }
+           irqctrler = NULL;
+       }
+
        /*
         * G3 powermacs and 1999 G3 PowerBooks have 64 interrupts,
         * 1998 G3 Series PowerBooks have 128, 
index 31eb31e8c2d7a570ea83c430918165037ceb1991..e8fc30eb87f9a24aa0167e7ebfc92cb227fa7dbb 100644 (file)
@@ -87,6 +87,7 @@ extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
 extern char pckbd_unexpected_up(unsigned char keycode);
 extern void pckbd_leds(unsigned char leds);
 extern void pckbd_init_hw(void);
+extern void pmac_nvram_update(void);
 
 unsigned char drive_info;
 
@@ -95,11 +96,14 @@ int ppc_override_l2cr_value;
 
 extern char saved_command_line[];
 
+extern int pmac_newworld;
+
 #define DEFAULT_ROOT_DEVICE 0x0801     /* sda1 - slightly silly choice */
 
 extern void zs_kgdb_hook(int tty_num);
 static void ohare_init(void);
 static void init_p2pbridge(void);
+static void init_uninorth(void);
 
 __pmac
 int
@@ -187,6 +191,10 @@ pmac_get_cpuinfo(char *buffer)
                        len += sprintf(buffer+len, "l2cr override\t: 0x%x\n", *l2cr);
                }
        }
+
+       /* Indicate newworld/oldworld */
+       len += sprintf(buffer+len, "pmac-generation\t: %s\n",
+               pmac_newworld ? "NewWorld" : "OldWorld");               
        
        return len;
 }
@@ -246,8 +254,10 @@ pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p))
                if (fp != 0) {
                        switch (_get_PVR() >> 16) {
                        case 4:         /* 604 */
+                       case 8:         /* G3 */
                        case 9:         /* 604e */
                        case 10:        /* mach V (604ev5) */
+                       case 12:        /* G4 */
                        case 20:        /* 620 */
                                loops_per_sec = *fp;
                                break;
@@ -266,9 +276,10 @@ pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p))
 
        *memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p);
        init_p2pbridge();
-
+       init_uninorth();
+       
        /* Checks "l2cr-value" property in the registry */
-       if ( (_get_PVR() >> 16) == 8) {
+       if ( (_get_PVR() >> 16) == 8 || (_get_PVR() >> 16) == 12 ) {
                struct device_node *np = find_devices("cpus");          
                if (np == 0)
                        np = find_type_devices("cpu");          
@@ -288,7 +299,6 @@ pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p))
                printk(KERN_INFO "L2CR overriden (0x%x), backside cache is %s\n",
                        ppc_override_l2cr_value, (ppc_override_l2cr_value & 0x80000000)
                                ? "enabled" : "disabled");
-
        feature_init();
 
 #ifdef CONFIG_KGDB
@@ -355,6 +365,32 @@ __initfunc(static void ohare_init(void))
        }
 }
 
+__initfunc(static void init_uninorth(void))
+{
+       /* 
+        * Turns on the gmac clock so that it responds to PCI cycles
+        * later, the driver may want to turn it off again to save
+        * power when interface is down
+        */
+       struct device_node* uni_n = find_devices("uni-n");
+       struct device_node* gmac = find_devices("ethernet");
+       unsigned long* addr;
+       
+       if (!uni_n || uni_n->n_addrs < 1)
+               return;
+       addr = ioremap(uni_n->addrs[0].address, 0x300);
+
+       while(gmac) {
+               if (device_is_compatible(gmac, "gmac"))
+                       break;
+               gmac = gmac->next;
+       }
+       if (gmac) {
+               *(addr + 8) |= 2;
+               eieio();
+       }
+}
+
 extern char *bootpath;
 extern char *bootdevice;
 void *boot_host;
@@ -402,14 +438,13 @@ note_scsi_host(struct device_node *node, void *host))
 #endif
 
 #ifdef CONFIG_BLK_DEV_IDE_PMAC
-extern int pmac_ide_count;
-extern struct device_node *pmac_ide_node[];
-static int ide_majors[] = { 3, 22, 33, 34, 56, 57 };
+
+extern kdev_t pmac_find_ide_boot(char *bootdevice, int n);
 
 __initfunc(kdev_t find_ide_boot(void))
 {
        char *p;
-       int i, n;
+       int n;
 
        if (bootdevice == NULL)
                return 0;
@@ -418,18 +453,7 @@ __initfunc(kdev_t find_ide_boot(void))
                return 0;
        n = p - bootdevice;
 
-       /*
-        * Look through the list of IDE interfaces for this one.
-        */
-       for (i = 0; i < pmac_ide_count; ++i) {
-               char *name = pmac_ide_node[i]->full_name;
-               if (memcmp(name, bootdevice, n) == 0 && name[n] == 0) {
-                       /* XXX should cope with the 2nd drive as well... */
-                       return MKDEV(ide_majors[i], 0);
-               }
-       }
-
-       return 0;
+       return pmac_find_ide_boot(bootdevice, n);
 }
 #endif /* CONFIG_BLK_DEV_IDE_PMAC */
 
@@ -468,7 +492,7 @@ void note_bootable_part(kdev_t dev, int part)
        if (boot_dev == 0 || dev == boot_dev) {
                ROOT_DEV = MKDEV(MAJOR(dev), MINOR(dev) + part);
                boot_dev = NODEV;
-               printk(" (root)");
+               printk(" (root on %d)", part);
        }
 }
 
@@ -477,6 +501,8 @@ pmac_restart(char *cmd)
 {
        struct adb_request req;
 
+       pmac_nvram_update();
+       
        switch (adb_hardware) {
        case ADB_VIACUDA:
                cuda_request(&req, NULL, 2, CUDA_PACKET,
@@ -497,6 +523,8 @@ pmac_power_off(void)
 {
        struct adb_request req;
 
+       pmac_nvram_update();
+       
        switch (adb_hardware) {
        case ADB_VIACUDA:
                cuda_request(&req, NULL, 2, CUDA_PACKET,
@@ -515,7 +543,6 @@ pmac_power_off(void)
 void
 pmac_halt(void)
 {
-   pmac_power_off();
 }
 
 
@@ -541,11 +568,15 @@ pmac_ide_default_irq(ide_ioreg_t base)
         return 0;
 }
 
+#if defined(CONFIG_BLK_DEV_IDE_PMAC)
+extern ide_ioreg_t pmac_ide_get_base(int index);
+#endif
+
 ide_ioreg_t
 pmac_ide_default_io_base(int index)
 {
 #if defined(CONFIG_BLK_DEV_IDE_PMAC)
-        return pmac_ide_regbase[index];
+        return pmac_ide_get_base(index);
 #else
        return 0;
 #endif
@@ -625,6 +656,7 @@ pmac_init(unsigned long r3, unsigned long r4, unsigned long r5,
        ppc_md.kbd_init_hw       = mackbd_init_hw;
 #ifdef CONFIG_MAGIC_SYSRQ
        ppc_md.kbd_sysrq_xlate   = mackbd_sysrq_xlate;
+       ppc_md.SYSRQ_KEY         = 0x69;
 #endif
 #endif
 
index 0196c5eb64a6837c291811dd46fa71ad8b3a203b..698363261b884e64f397e29715501529ab31c52e 100644 (file)
@@ -1,10 +1,19 @@
 /*
  * Miscellaneous procedures for dealing with the PowerMac hardware.
+ * Contains support for the nvram.
+ * 
+ *   Copyright (C) 2000 Paul Mackerras
+ *   Copyright (C) 2000 Benjamin Herrenschmidt
+ *
+ * ToDo: Handle type 0 and type 1 "NameRegistry" NVRAM properties. Those
+ *       contain, among other things, the brightness, video mode, etc...
  */
 #include <linux/kernel.h>
 #include <linux/stddef.h>
 #include <linux/reboot.h>
 #include <linux/nvram.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
 #include <asm/init.h>
 #include <asm/ptrace.h>
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/adb.h>
 #include <asm/pmu.h>
+#include <asm/machdep.h>
+#include <asm/nvram.h>
+
+#undef DEBUG
 
 /*
  * Read and write the non-volatile RAM on PowerMacs and CHRP machines.
 static int nvram_naddrs;
 static volatile unsigned char *nvram_addr;
 static volatile unsigned char *nvram_data;
-static int nvram_mult;
+static int nvram_mult, is_core_99;
+static char* nvram_image;
+static int core99_bank = 0;
+
+extern int pmac_newworld;
+
+#define NVRAM_SIZE             0x2000  /* 8kB of non-volatile RAM */
+
+#define CORE99_SIGNATURE       0x5a
+#define CORE99_ADLER_START     0x14
+
+/* Core99 nvram is a flash */
+#define CORE99_FLASH_STATUS_DONE       0x80
+#define CORE99_FLASH_STATUS_ERR                0x38
+#define CORE99_FLASH_CMD_ERASE_CONFIRM 0xd0
+#define CORE99_FLASH_CMD_ERASE_SETUP   0x20
+#define CORE99_FLASH_CMD_RESET         0xff
+#define CORE99_FLASH_CMD_WRITE_SETUP   0x40
+
+
+/* CHRP NVRAM header */
+struct chrp_header {
+  u8           signature;
+  u8           cksum;
+  u16          len;
+  char          name[12];
+  u8           data[0];
+};
+
+struct core99_header {
+  struct chrp_header   hdr;
+  u32                  adler;
+  u32                  generation;
+  u32                  reserved[2];
+};
+
+static int nvram_partitions[3];
+
+static u8
+chrp_checksum(struct chrp_header* hdr)
+{
+       u8 *ptr;
+       u16 sum = hdr->signature;
+       for (ptr = (u8 *)&hdr->len; ptr < hdr->data; ptr++)
+               sum += *ptr;
+       while (sum > 0xFF)
+               sum = (sum & 0xFF) + (sum>>8);
+       return sum;
+}
+
+static u32
+core99_calc_adler(u8 *buffer)
+{
+       int cnt;
+       u32 low, high;
+
+       buffer += CORE99_ADLER_START;
+       low = 1;
+       high = 0;
+       for (cnt=0; cnt<(NVRAM_SIZE-CORE99_ADLER_START); cnt++) {
+               if ((cnt % 5000) == 0) {
+                       high  %= 65521UL;
+                       high %= 65521UL;
+               }
+               low += buffer[cnt];
+               high += low;
+       }
+       low  %= 65521UL;
+       high %= 65521UL;
+  
+       return (high << 16) | low;
+}
+
+static u32
+core99_check(u8* datas)
+{
+       struct core99_header* hdr99 = (struct core99_header*)datas;
+
+       if (hdr99->hdr.signature != CORE99_SIGNATURE) {
+#ifdef DEBUG
+               printk("Invalid signature\n");
+#endif         
+               return 0;
+       }
+       if (hdr99->hdr.cksum != chrp_checksum(&hdr99->hdr)) {
+#ifdef DEBUG
+               printk("Invalid checksum\n");
+#endif
+               return 0;
+       }
+       if (hdr99->adler != core99_calc_adler(datas)) {
+#ifdef DEBUG
+               printk("Invalid adler\n");
+#endif
+               return 0;
+       }
+       return hdr99->generation;
+}
+
+static int
+core99_erase_bank(int bank)
+{
+       int stat, i;
+       
+       u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+       
+       out_8(base, CORE99_FLASH_CMD_ERASE_SETUP);
+       out_8(base, CORE99_FLASH_CMD_ERASE_CONFIRM);
+       do { stat = in_8(base); }
+       while(!(stat & CORE99_FLASH_STATUS_DONE));
+       out_8(base, CORE99_FLASH_CMD_RESET);
+       if (stat & CORE99_FLASH_STATUS_ERR) {
+               printk("nvram: flash error 0x%02x on erase !\n", stat);
+               return -ENXIO;
+       }
+       for (i=0; i<NVRAM_SIZE; i++)
+               if (base[i] != 0xff) {
+                       printk("nvram: flash erase failed !\n");
+                       return -ENXIO;
+               }
+       return 0;
+}
 
-#define NVRAM_SIZE     0x2000  /* 8kB of non-volatile RAM */
+static int
+core99_write_bank(int bank, u8* datas)
+{
+       int i, stat = 0;
+       
+       u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+       
+       for (i=0; i<NVRAM_SIZE; i++) {
+               out_8(base+i, CORE99_FLASH_CMD_WRITE_SETUP);
+               out_8(base+i, datas[i]);
+               do { stat = in_8(base); }
+               while(!(stat & CORE99_FLASH_STATUS_DONE));
+               if (stat & CORE99_FLASH_STATUS_ERR)
+                       break;
+       }
+       out_8(base, CORE99_FLASH_CMD_RESET);
+       if (stat & CORE99_FLASH_STATUS_ERR) {
+               printk("nvram: flash error 0x%02x on write !\n", stat);
+               return -ENXIO;
+       }
+       for (i=0; i<NVRAM_SIZE; i++)
+               if (base[i] != datas[i]) {
+                       printk("nvram: flash write failed !\n");
+                       return -ENXIO;
+               }
+       return 0;       
+}
 
+static void
+lookup_partitions(void)
+{
+       u8 buffer[17];
+       int i, offset;
+       struct chrp_header* hdr;
+
+       if (pmac_newworld) {
+               nvram_partitions[pmac_nvram_OF] = -1;
+               nvram_partitions[pmac_nvram_XPRAM] = -1;
+               nvram_partitions[pmac_nvram_NR] = -1;
+               hdr = (struct chrp_header *)buffer;
+       
+               offset = 0;
+               do {
+                       for (i=0;i<16;i++)
+                               buffer[i] = nvram_read_byte(offset+i);
+                       if (!strcmp(hdr->name, "common"))
+                               nvram_partitions[pmac_nvram_OF] = offset + 0x10;
+                       if (!strcmp(hdr->name, "APL,MacOS75")) {
+                               nvram_partitions[pmac_nvram_XPRAM] = offset + 0x10;
+                               nvram_partitions[pmac_nvram_NR] = offset + 0x110;
+                       }
+                       offset += (hdr->len * 0x10);
+               } while(offset < NVRAM_SIZE);
+       } else {
+               nvram_partitions[pmac_nvram_OF] = 0x1800;
+               nvram_partitions[pmac_nvram_XPRAM] = 0x1300;
+               nvram_partitions[pmac_nvram_NR] = 0x1400;
+       }       
+#ifdef DEBUG
+       printk("nvram: OF partition at 0x%x\n", nvram_partitions[pmac_nvram_OF]);
+       printk("nvram: XP partition at 0x%x\n", nvram_partitions[pmac_nvram_XPRAM]);
+       printk("nvram: NR partition at 0x%x\n", nvram_partitions[pmac_nvram_NR]);
+#endif 
+}
 
 __init
 void pmac_nvram_init(void)
 {
        struct device_node *dp;
 
+       nvram_naddrs = 0;
+
        dp = find_devices("nvram");
        if (dp == NULL) {
                printk(KERN_ERR "Can't find NVRAM device\n");
-               nvram_naddrs = 0;
                return;
        }
        nvram_naddrs = dp->n_addrs;
-       if (_machine == _MACH_chrp && nvram_naddrs == 1) {
+       is_core_99 = device_is_compatible(dp, "nvram,flash");
+       printk("pmac nvram is core99: %d\n", is_core_99);
+       if (is_core_99) {
+               int i;
+               u32 gen_bank0, gen_bank1;
+               
+               if (nvram_naddrs < 1) {
+                       printk(KERN_ERR "nvram: no address\n");
+                       return;
+               }
+               nvram_image = kmalloc(NVRAM_SIZE, GFP_KERNEL);
+               if (!nvram_image) {
+                       printk(KERN_ERR "nvram: can't allocate image\n");
+                       return;
+               }
+               nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2);
+#ifdef DEBUG
+               printk("nvram: Checking bank 0...\n");
+#endif
+               gen_bank0 = core99_check((u8 *)nvram_data);
+               gen_bank1 = core99_check((u8 *)nvram_data + NVRAM_SIZE);
+               core99_bank = (gen_bank0 < gen_bank1) ? 1 : 0;
+#ifdef DEBUG
+               printk("nvram: gen0=%d, gen1=%d\n", gen_bank0, gen_bank1);
+               printk("nvram: Active bank is: %d\n", core99_bank);
+#endif
+               for (i=0; i<NVRAM_SIZE; i++)
+                       nvram_image[i] = nvram_data[i + core99_bank*NVRAM_SIZE];
+       } else if (_machine == _MACH_chrp && nvram_naddrs == 1) {
                nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
                nvram_mult = 1;
        } else if (nvram_naddrs == 1) {
@@ -52,9 +277,38 @@ void pmac_nvram_init(void)
                printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n",
                       nvram_naddrs);
        }
+       lookup_partitions();
 }
 
-unsigned char nvram_read_byte(int addr)
+void
+pmac_nvram_update(void)
+{
+       struct core99_header* hdr99;
+       
+       if (!is_core_99 || !nvram_data || !nvram_image)
+               return;
+       if (!memcmp(nvram_image, (u8*)nvram_data + core99_bank*NVRAM_SIZE,
+               NVRAM_SIZE))
+               return;
+#ifdef DEBUG
+       printk("Updating nvram...\n");
+#endif
+       hdr99 = (struct core99_header*)nvram_image;
+       hdr99->generation++;
+       hdr99->hdr.signature = CORE99_SIGNATURE;
+       hdr99->hdr.cksum = chrp_checksum(&hdr99->hdr);
+       hdr99->adler = core99_calc_adler(nvram_image);
+       core99_bank = core99_bank ? 0 : 1;
+       if (core99_erase_bank(core99_bank)) {
+               printk("nvram: Error erasing bank %d\n", core99_bank);
+               return;
+       }
+       if (core99_write_bank(core99_bank, nvram_image))
+               printk("nvram: Error writing bank %d\n", core99_bank);
+}
+
+unsigned char
+nvram_read_byte(int addr)
 {
        struct adb_request req;
 
@@ -67,6 +321,8 @@ unsigned char nvram_read_byte(int addr)
                        pmu_poll();
                return req.reply[1];
        case 1:
+               if (is_core_99)
+                       return nvram_image[addr];
                return nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult];
        case 2:
                *nvram_addr = addr >> 5;
@@ -76,7 +332,8 @@ unsigned char nvram_read_byte(int addr)
        return 0;
 }
 
-void nvram_write_byte(unsigned char val, int addr)
+void
+nvram_write_byte(unsigned char val, int addr)
 {
        struct adb_request req;
 
@@ -89,6 +346,10 @@ void nvram_write_byte(unsigned char val, int addr)
                        pmu_poll();
                break;
        case 1:
+               if (is_core_99) {
+                       nvram_image[addr] = val;
+                       break;
+               }
                nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult] = val;
                break;
        case 2:
@@ -99,3 +360,32 @@ void nvram_write_byte(unsigned char val, int addr)
        }
        eieio();
 }
+
+int
+pmac_get_partition(int partition)
+{
+       return nvram_partitions[partition];
+}
+
+u8
+pmac_xpram_read(int xpaddr)
+{
+       int offset = nvram_partitions[pmac_nvram_XPRAM];
+       
+       if (offset < 0)
+               return 0;
+               
+       return nvram_read_byte(xpaddr + offset);
+}
+
+void
+pmac_xpram_write(int xpaddr, u8 data)
+{
+       int offset = nvram_partitions[pmac_nvram_XPRAM];
+       
+       if (offset < 0)
+               return;
+               
+       nvram_write_byte(xpaddr + offset, data);
+}
+
index ac18a8c14e1a9e4c3e9b3d1692d03cad3b6b1cb5..49292adc0f63c823d39a8fb7f2e1e959f756beea 100644 (file)
@@ -351,7 +351,7 @@ static inline int get_msr()
 
 static inline void set_msr(int msr)
 {
-       asm volatile("mfmsr %0" : : "r" (msr));
+       asm volatile("mtmsr %0" : : "r" (msr));
 }
 
 /* Set up exception handlers for tracing and breakpoints
index e3004c8f64dea24cff798596ef5cbbef4c7558f2..0d8f00b121da71c973951b447b8f75ed1d88d687 100644 (file)
 #define        fr29    29
 #define        fr30    30
 #define        fr31    31
+
+#define        vr0     0
+#define        vr1     1
+#define        vr2     2
+#define        vr3     3
+#define        vr4     4
+#define        vr5     5
+#define        vr6     6
+#define        vr7     7
+#define        vr8     8
+#define        vr9     9
+#define        vr10    10
+#define        vr11    11
+#define        vr12    12
+#define        vr13    13
+#define        vr14    14
+#define        vr15    15
+#define        vr16    16
+#define        vr17    17
+#define        vr18    18
+#define        vr19    19
+#define        vr20    20
+#define        vr21    21
+#define        vr22    22
+#define        vr23    23
+#define        vr24    24
+#define        vr25    25
+#define        vr26    26
+#define        vr27    27
+#define        vr28    28
+#define        vr29    29
+#define        vr30    30
+#define        vr31    31
index b8dd53eccf15d1e4b0f268548464051a1b5d5f34..813179276e976f239f03063818f85f771d33839b 100644 (file)
@@ -547,7 +547,8 @@ int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
                "0.5", "1.0", "(reserved2)", "(reserved3)"
        };
 
-       if ( (_get_PVR() >> 16) != 8) return -EFAULT;
+       if ( ((_get_PVR() >> 16) != 8) && ((_get_PVR() >> 16) != 12))
+               return -EFAULT;
        
        if ( /*!table->maxlen ||*/ (filp->f_pos && !write)) {
                *lenp = 0;
index 3410c32f877a22a69a1227d172ca4d792a77fbeb..21302ad9bfb0280677c3ca1efdc15b3e4050c2ca 100644 (file)
@@ -46,9 +46,10 @@ extern atomic_t ppc_n_lost_interrupts;
 extern void do_lost_interrupts(unsigned long);
 extern int do_signal(sigset_t *, struct pt_regs *);
 
-asmlinkage long long __ashrdi3(long long, int);
-asmlinkage long long __lshrdi3(long long, int);
-asmlinkage int abs(int);
+long long __ashrdi3(long long, int);
+long long __ashldi3(long long, int);
+long long __lshrdi3(long long, int);
+int abs(int);
 
 EXPORT_SYMBOL(clear_page);
 EXPORT_SYMBOL(do_signal);
@@ -152,6 +153,7 @@ EXPORT_SYMBOL(ppc_ide_md);
 
 EXPORT_SYMBOL(start_thread);
 EXPORT_SYMBOL(kernel_thread);
+EXPORT_SYMBOL(init_mm);
 
 EXPORT_SYMBOL(__cli);
 EXPORT_SYMBOL(__sti);
@@ -164,6 +166,11 @@ EXPORT_SYMBOL(giveup_fpu);
 EXPORT_SYMBOL(enable_kernel_fp);
 EXPORT_SYMBOL(flush_icache_range);
 EXPORT_SYMBOL(xchg_u32);
+
+#ifdef CONFIG_ALTIVEC
+EXPORT_SYMBOL(giveup_altivec);
+#endif
+
 #ifdef __SMP__
 EXPORT_SYMBOL(__global_cli);
 EXPORT_SYMBOL(__global_sti);
@@ -200,6 +207,8 @@ EXPORT_SYMBOL(find_path_device);
 EXPORT_SYMBOL(find_phandle);
 EXPORT_SYMBOL(device_is_compatible);
 EXPORT_SYMBOL(machine_is_compatible);
+EXPORT_SYMBOL(find_pci_device_OFnode);
+EXPORT_SYMBOL(find_all_nodes);
 EXPORT_SYMBOL(get_property);
 EXPORT_SYMBOL(pci_io_base);
 EXPORT_SYMBOL(pci_device_loc);
@@ -210,14 +219,15 @@ EXPORT_SYMBOL(feature_test);
 EXPORT_SYMBOL(note_scsi_host);
 #endif
 EXPORT_SYMBOL(kd_mksound);
-#ifdef CONFIG_PMAC
+/*#ifdef CONFIG_PMAC */
 EXPORT_SYMBOL(nvram_read_byte);
 EXPORT_SYMBOL(nvram_write_byte);
-#endif /* CONFIG_PMAC */
+/*#endif*/ /* CONFIG_PMAC */
 
 EXPORT_SYMBOL(abs);
 
 EXPORT_SYMBOL_NOVERS(__ashrdi3);
+EXPORT_SYMBOL_NOVERS(__ashldi3);
 EXPORT_SYMBOL_NOVERS(__lshrdi3);
 EXPORT_SYMBOL_NOVERS(memcpy);
 EXPORT_SYMBOL_NOVERS(memset);
index 8627633381ed2b247a298aba2653628d9bab110b..2932aedd5a80e75304e9502af754f78089a4ee8f 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <linux/types.h>
+#include <linux/string.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -36,7 +37,7 @@ unsigned char *Motherboard_map_name;
 unsigned char *Motherboard_routes;
 void (*Motherboard_non0)(struct pci_dev *);
 
-void Mesquite_Map_Non0(struct pci_dev *);
+void Powerplus_Map_Non0(struct pci_dev *);
 
 /* Used for Motorola to store system config register */
 static unsigned long   *ProcInfo;
@@ -508,6 +509,51 @@ static char Nobis_pci_IRQ_routes[] __prepdata = {
         13      /* Line 4 */
 };
 
+/* Motorola PowerPlus architecture PCI IRQ tables */
+/* Interrupt line values for INTA-D on primary/secondary MPIC inputs */
+
+struct powerplus_irq_list
+{
+       unsigned char primary[4];       /* INT A-D */
+       unsigned char secondary[4];     /* INT A-D */
+};
+
+/*
+ * For standard PowerPlus boards, bus 0 PCI INTs A-D are routed to
+ * OpenPIC inputs 9-12.  PCI INTs A-D from the on board P2P bridge
+ * are routed to OpenPIC inputs 5-8.  These values are offset by 
+ * 16 in the table to reflect the Linux kernel interrupt value.
+ */
+struct powerplus_irq_list Powerplus_pci_IRQ_list =
+{
+       {25, 26, 27, 28},
+       {21, 22, 23, 24}
+};
+
+/* 
+ * For the MCP750 (system slot board), bus 0 PCI INTs A-D are routed
+ * to OpenPIC inputs 8-11.  PCI INTs A-D from the on board P2P bridge
+ * are routed to OpenPIC inputs 12-15.  These values are offset by 16
+ * in the table to reflect the Linux kernel interrupt value.
+ */
+struct powerplus_irq_list Mesquite_pci_IRQ_list =
+{
+       {24, 25, 26, 27},
+       {28, 29, 30, 31}
+};
+
+/*
+ * This table represents the standard PCI swizzle defined in the
+ * PCI bus specification.
+ */ 
+static unsigned char prep_pci_intpins[4][4] =
+{
+        { 1, 2, 3, 4},  /* Buses 0, 4, 8, ... */
+        { 2, 3, 4, 1},  /* Buses 1, 5, 9, ... */
+        { 3, 4, 1, 2},  /* Buses 2, 6, 10 ... */
+        { 4, 1, 2, 3},  /* Buses 3, 7, 11 ... */
+};
+
 /* We have to turn on LEVEL mode for changed IRQ's */
 /* All PCI IRQ's need to be level mode, so this should be something
  * other than hard-coded as well... IRQ's are individually mappable
@@ -685,8 +731,7 @@ static u_char mvme2600_openpic_initsenses[] __initdata = {
 #define MOT_RAVEN_PRESENT      0x1
 #define MOT_HAWK_PRESENT       0x2
 
-/* Keyboard present flag */
-int prep_kbd_present = 1;   /* Keyboard present by default */
+int mot_entry = -1;
 
 int MotMPIC = 0;
 int mot_multi = 0;
@@ -751,13 +796,17 @@ __initfunc(int raven_init(void))
                mot_multi = 1;
        }
 
-       /* This is a hack.  If this is a 2300 or 2400 mot board then there is
-        * no keyboard controller and we have to indicate that.
+       /*
+        * If a Motorola MVME2300, 2400, or MCPN750 board is detected
+        * disable keyboard controller initialization to avoid system
+        * hangs.
         */
        base_mod = inb(MOTOROLA_BASETYPE_REG);
        if ((MotMPIC == MOT_HAWK_PRESENT) || (base_mod == 0xF9) ||
-           (base_mod == 0xFA) || (base_mod == 0xE1))
-               prep_kbd_present = 0;
+           (base_mod == 0xFA) || (base_mod == 0xE1)) {
+               ppc_md.kbd_leds = NULL; 
+               ppc_md.kbd_init_hw = NULL; 
+       }
 
        return 1;
 }
@@ -771,33 +820,35 @@ struct mot_info {
        unsigned char   *map;
        unsigned char   *routes;
        void            (*map_non0_bus)(struct pci_dev *);      /* For boards with more than bus 0 devices. */
+       struct powerplus_irq_list *pci_irq_list; /* List of PCI MPIC inputs */
+       unsigned char   secondary_bridge_devfn; /* devfn of secondary bus transparent bridge */
 } mot_info[] = {
-       {0x300, 0x00, 0x00, "MVME 2400",                        Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes,   NULL},
-       {0x010, 0x00, 0x00, "Genesis",                          Genesis_pci_IRQ_map,    Genesis_pci_IRQ_routes, NULL},
-       {0x020, 0x00, 0x00, "Powerstack (Series E)",            Comet_pci_IRQ_map,      Comet_pci_IRQ_routes,   NULL},
-       {0x040, 0x00, 0x00, "Blackhawk (Powerstack)",           Blackhawk_pci_IRQ_map,  Blackhawk_pci_IRQ_routes, NULL},
-       {0x050, 0x00, 0x00, "Omaha (PowerStack II Pro3000)",    Omaha_pci_IRQ_map,      Omaha_pci_IRQ_routes,   NULL},
-       {0x060, 0x00, 0x00, "Utah (Powerstack II Pro4000)",     Utah_pci_IRQ_map,       Utah_pci_IRQ_routes,    NULL},
-       {0x0A0, 0x00, 0x00, "Powerstack (Series EX)",           Comet2_pci_IRQ_map,     Comet2_pci_IRQ_routes,  NULL},
-       {0x1E0, 0xE0, 0x00, "Mesquite cPCI (MCP750)",           Mesquite_pci_IRQ_map,   Raven_pci_IRQ_routes,   NULL},
-       {0x1E0, 0xE1, 0x00, "Sitka cPCI (MCPN750)",             Sitka_pci_IRQ_map,      Raven_pci_IRQ_routes,   NULL},
-       {0x1E0, 0xE2, 0x00, "Mesquite cPCI (MCP750) w/ HAC",    Mesquite_pci_IRQ_map,   Raven_pci_IRQ_routes,   Mesquite_Map_Non0},
-       {0x1E0, 0xF6, 0x80, "MTX Plus",                         MTXplus_pci_IRQ_map,    Raven_pci_IRQ_routes,   NULL},
-       {0x1E0, 0xF6, 0x81, "Dual MTX Plus",                    MTXplus_pci_IRQ_map,    Raven_pci_IRQ_routes,   NULL},
-       {0x1E0, 0xF7, 0x80, "MTX wo/ Parallel Port",            MTX_pci_IRQ_map,        Raven_pci_IRQ_routes,   NULL},
-       {0x1E0, 0xF7, 0x81, "Dual MTX wo/ Parallel Port",       MTX_pci_IRQ_map,        Raven_pci_IRQ_routes,   NULL},
-       {0x1E0, 0xF8, 0x80, "MTX w/ Parallel Port",             MTX_pci_IRQ_map,        Raven_pci_IRQ_routes,   NULL},
-       {0x1E0, 0xF8, 0x81, "Dual MTX w/ Parallel Port",        MTX_pci_IRQ_map,        Raven_pci_IRQ_routes,   NULL},
-       {0x1E0, 0xF9, 0x00, "MVME 2300",                        Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes,   NULL},
-       {0x1E0, 0xFA, 0x00, "MVME 2300SC/2600",                 Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes,   NULL},
-       {0x1E0, 0xFB, 0x00, "MVME 2600 with MVME712M",          Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes,   NULL},
-       {0x1E0, 0xFC, 0x00, "MVME 2600/2700 with MVME761",      Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes,   NULL},
-       {0x1E0, 0xFD, 0x80, "MVME 3600 with MVME712M",          Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes,   NULL},
-       {0x1E0, 0xFD, 0x81, "MVME 4600 with MVME712M",          Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes,   NULL},
-       {0x1E0, 0xFE, 0x80, "MVME 3600 with MVME761",           Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes,   NULL},
-       {0x1E0, 0xFE, 0x81, "MVME 4600 with MVME761",           Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes,   NULL},
-       {0x1E0, 0xFF, 0x00, "MVME 1600-001 or 1600-011",        Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes,   NULL},
-       {0x000, 0x00, 0x00, "",                                 NULL,                   NULL,   NULL}
+       {0x300, 0x00, 0x00, "MVME 2400",                        Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes,   Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+       {0x010, 0x00, 0x00, "Genesis",                          Genesis_pci_IRQ_map,    Genesis_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+       {0x020, 0x00, 0x00, "Powerstack (Series E)",            Comet_pci_IRQ_map,      Comet_pci_IRQ_routes,   NULL, NULL, 0x00},
+       {0x040, 0x00, 0x00, "Blackhawk (Powerstack)",           Blackhawk_pci_IRQ_map,  Blackhawk_pci_IRQ_routes, NULL, NULL, 0x00},
+       {0x050, 0x00, 0x00, "Omaha (PowerStack II Pro3000)",    Omaha_pci_IRQ_map,      Omaha_pci_IRQ_routes,   NULL, NULL, 0x00},
+       {0x060, 0x00, 0x00, "Utah (Powerstack II Pro4000)",     Utah_pci_IRQ_map,       Utah_pci_IRQ_routes,    NULL, NULL, 0x00},
+       {0x0A0, 0x00, 0x00, "Powerstack (Series EX)",           Comet2_pci_IRQ_map,     Comet2_pci_IRQ_routes,  NULL, NULL, 0x00},
+       {0x1E0, 0xE0, 0x00, "Mesquite cPCI (MCP750)",           Mesquite_pci_IRQ_map,   Raven_pci_IRQ_routes,   Powerplus_Map_Non0, &Mesquite_pci_IRQ_list, 0x00},
+       {0x1E0, 0xE1, 0x00, "Sitka cPCI (MCPN750)",             Sitka_pci_IRQ_map,      Raven_pci_IRQ_routes,   Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+       {0x1E0, 0xE2, 0x00, "Mesquite cPCI (MCP750) w/ HAC",    Mesquite_pci_IRQ_map,   Raven_pci_IRQ_routes,   Powerplus_Map_Non0, &Mesquite_pci_IRQ_list, 0xC0},
+       {0x1E0, 0xF6, 0x80, "MTX Plus",                         MTXplus_pci_IRQ_map,    Raven_pci_IRQ_routes,   Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xA0},
+       {0x1E0, 0xF6, 0x81, "Dual MTX Plus",                    MTXplus_pci_IRQ_map,    Raven_pci_IRQ_routes,   Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xA0},
+       {0x1E0, 0xF7, 0x80, "MTX wo/ Parallel Port",            MTX_pci_IRQ_map,        Raven_pci_IRQ_routes,   Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+       {0x1E0, 0xF7, 0x81, "Dual MTX wo/ Parallel Port",       MTX_pci_IRQ_map,        Raven_pci_IRQ_routes,   Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+       {0x1E0, 0xF8, 0x80, "MTX w/ Parallel Port",             MTX_pci_IRQ_map,        Raven_pci_IRQ_routes,   Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+       {0x1E0, 0xF8, 0x81, "Dual MTX w/ Parallel Port",        MTX_pci_IRQ_map,        Raven_pci_IRQ_routes,   Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+       {0x1E0, 0xF9, 0x00, "MVME 2300",                        Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes,   Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+       {0x1E0, 0xFA, 0x00, "MVME 2300SC/2600",                 Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes,   Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+       {0x1E0, 0xFB, 0x00, "MVME 2600 with MVME712M",          Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes,   Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+       {0x1E0, 0xFC, 0x00, "MVME 2600/2700 with MVME761",      Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes,   Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+       {0x1E0, 0xFD, 0x80, "MVME 3600 with MVME712M",          Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes,   Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+       {0x1E0, 0xFD, 0x81, "MVME 4600 with MVME712M",          Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes,   Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+       {0x1E0, 0xFE, 0x80, "MVME 3600 with MVME761",           Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes,   Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+       {0x1E0, 0xFE, 0x81, "MVME 4600 with MVME761",           Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes,   Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+       {0x1E0, 0xFF, 0x00, "MVME 1600-001 or 1600-011",        Genesis2_pci_IRQ_map,   Raven_pci_IRQ_routes,   NULL, NULL, 0x00},
+       {0x000, 0x00, 0x00, "",                                 NULL,                   NULL,   NULL, 0x00}
 };
 
 __initfunc(unsigned long prep_route_pci_interrupts(void))
@@ -812,7 +863,6 @@ __initfunc(unsigned long prep_route_pci_interrupts(void))
                unsigned char  cpu_type;
                unsigned char  base_mod;
                int            entry;
-               int            mot_entry = -1;
 
                cpu_type = inb(MOTOROLA_CPUTYPE_REG) & 0xF0;
                base_mod = inb(MOTOROLA_BASETYPE_REG);
@@ -989,91 +1039,91 @@ __initfunc(unsigned long prep_route_pci_interrupts(void))
        return 0;
 }
 
-static unsigned int pci_localpirqs[4] =
-{
-       24,
-       25,
-       26,
-       27
-};
-
-static unsigned int pci_remotepirqs[4] =
-{
-       28,
-       29,
-       30,
-       31
-};
-
-static unsigned int pci_remotedev = 0xc0;
-
+/*
+ * Remove a device from the kernel PCI device list based on its 
+ * devfn identifier.
+ */
+__initfunc(
 void
-Mesquite_Map_Non0(struct pci_dev *pdev)
+prep_exclude_pci_device(unsigned char devfn)
+)
 {
-       struct pci_bus  *pbus;          /* Parent Bus Structure Pointer */
-       unsigned int    devnum;         /* Accumulated Device Number */
-       unsigned int    irq;            /* IRQ Value */
+       struct pci_dev *dev, *pdev = NULL;
 
-       /*
-       **    Device Interrupt Line register initialization.
-       **    The IRQ line number will be generated after
-       **    taking into account all the PCI-2-PCI bridge
-       **    devices between the device and the Host Bridge.
-       */
-       devnum = PCI_SLOT(pdev->devfn);
-       pbus = pdev->bus;
-
-       while ((pbus->parent)->primary != (pbus->parent)->secondary)
-       {
-           devnum += PCI_SLOT((pbus->self)->devfn);
+       /* Walk the pci device list */
+       for(dev=pci_devices; dev; dev=dev->next) {
+               if (dev->devfn == devfn)
+               {
+                       /*
+                        * If we find a matching device, adjust
+                        * the list to remove the device.
+                        */
+                       if (pdev != NULL)
+                               pdev->next = dev->next;
+                       else
+                               pci_devices = dev->next;
 
-           pbus = pbus->parent;
+                       break;
+               }
+               pdev = dev;
        }
+}
 
-       devnum &= 0x03;
-
-       /*
-       **    By default, get the PCI local domain IRQ value.
-       */
-       irq = pci_localpirqs[devnum];
+void
+Powerplus_Map_Non0(struct pci_dev *dev)
+{
+       struct pci_bus  *pbus;          /* Parent bus structure pointer */
+       struct pci_dev  *tdev;          /* Temporary device structure */
+        unsigned int    devnum;         /* Accumulated device number */
+        unsigned char   intline;        /* Linux interrupt value */
+       unsigned char   intpin;         /* PCI interrupt pin */
+       /* Check for valid PCI dev pointer */
+       if (dev == NULL) return;
+
+       /* Fill our temporary device, and get the device number */
+       *tdev = *dev;
+       devnum = PCI_SLOT(tdev->devfn);
+
+       /* Read the interrupt pin of the device and adjust for indexing */
+       pcibios_read_config_byte(tdev->bus->number, tdev->devfn,
+                               PCI_INTERRUPT_PIN, &intpin);
+
+       /* If device doesn't request an interrupt, return */
+       if ( (intpin < 1) || (intpin > 4) )
+               return;
 
-       /*
-       **    Determine if the device is located in the
-       **    remote domain or not. We must find the
-       **    domain's bridge device located on bus 0.
-       */
-       pbus = pdev->bus;
+       intpin--;
 
-       while (pbus->primary != 0)
-           pbus = pbus->parent;
+       /* Walk up to bus 0, adjusting the interrupt pin for the standard
+          PCI bus swizzle. */
+       do {
+               intpin = (prep_pci_intpins[devnum % 4][intpin]) - 1;
+               pbus = tdev->bus;        /* up one level */
+               tdev = pbus->self;
+               devnum = PCI_SLOT(tdev->devfn);
+       } while(tdev->bus->number);
 
-       /*
-       **    Check the device/function of domain's bridge
-       **    device against the remote device/function.
-       **    If the same, then the device is located in
-       **    the remote domain. Thus, get the PCI remote
-       **    domain IRQ value.
-       */
-       if ((pbus->self)->devfn == pci_remotedev)
-        irq = pci_remotepirqs[devnum];
+       /* Use the primary interrupt inputs by default */
+       intline = mot_info[mot_entry].pci_irq_list->primary[intpin];
 
-       /*
-       **    Validate the IRQ number.
-       */
-       if (irq <= 255)
+       /* If the board has secondary interrupt inputs, walk the bus and
+          note the devfn of the bridge from bus 0.  If it is the same as
+          the devfn of the bus bridge with secondary inputs, use those. */
+       if (mot_info[mot_entry].secondary_bridge_devfn)
        {
-           /*
-           **    Set the device's Interrupt Line register
-           **    to the IRQ number and save it in the
-           **    device's structure.
-           */
-
-           pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, (u8)irq);
-
-           pdev->irq = irq;
-
+               pbus = dev->bus;
+               while (pbus->primary != 0)
+                       pbus = pbus->parent;
+               if ((pbus->self)->devfn == mot_info[mot_entry].secondary_bridge_devfn)
+                       intline = mot_info[mot_entry].pci_irq_list->secondary[intpin];
        }
-       return;
+       
+       /* Write calculated interrupt value to header and device list */
+       pci_write_config_byte(dev, PCI_INTERRUPT_LINE, (u8)intline);
+       dev->irq = intline;
 }
 
 int motopenpic_to_irq(int n)
@@ -1137,6 +1187,15 @@ struct pci_dev  *dev;
 
        prep_route_pci_interrupts();
 
+       /*
+        * If MTX+, exclude the SL82C105 IDE controller so the driver
+        * doesn't hang.
+        */
+       if ( _prep_type == _PREP_Motorola )
+               if ( strstr(mot_info[mot_entry].name, "MTX Plus") )
+                       /* On MTX+, SL82C105 is at IDSEL 0xb function 0x1 */
+                       prep_exclude_pci_device(PCI_DEVFN(0xb, 0x1));
+
        prep_pib_init();
 
        printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name);
@@ -1150,7 +1209,7 @@ struct pci_dev  *dev;
                       motopenpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]);
 
                    pcibios_write_config_byte(dev->bus->number, dev->devfn, 
-                                             PCI_INTERRUPT_PIN, dev->irq);
+                                             PCI_INTERRUPT_LINE, dev->irq);
                } else {
                        if (Motherboard_non0 != NULL)
                                Motherboard_non0(dev);
index 80408f73ca6717686088a709937763f65b48d956..10e1dc677bbb2a4961a97d61a9fbc45041c09627 100644 (file)
@@ -607,6 +607,7 @@ prep_init_IRQ(void))
        int i;
 
        if (OpenPIC != NULL) {
+               open_pic.irq_offset = 16;
                for ( i = 16 ; i < 36 ; i++ )
                        irq_desc[i].ctl = &open_pic;
                openpic_init(1);
@@ -857,6 +858,7 @@ prep_init(unsigned long r3, unsigned long r4, unsigned long r5,
        ppc_md.kbd_init_hw       = pckbd_init_hw;
 #ifdef CONFIG_MAGIC_SYSRQ
        ppc_md.kbd_sysrq_xlate   = pckbd_sysrq_xlate;
+       ppc_md.SYSRQ_KEY         = 0x54;
 #endif
 #endif
 }
index 9041fe3be2763c958b3377c1a236158103486a5e..0a6b08e66ec37100da31c5d9eea1196f2699c349 100644 (file)
 #include <asm/mmu_context.h>
 
 int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs);
+int dump_altivec(struct pt_regs *regs, elf_vrregset_t *vrregs);
 extern unsigned long _get_SP(void);
 
 struct task_struct *last_task_used_math = NULL;
+struct task_struct *last_task_used_altivec = NULL;
 static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
 static struct files_struct init_files = INIT_FILES;
@@ -79,6 +81,31 @@ dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
        return 1;
 }
 
+#ifdef CONFIG_ALTIVEC
+int
+dump_altivec(struct pt_regs *regs, elf_vrregset_t *vrregs)
+{
+       if (regs->msr & MSR_VEC)
+               giveup_altivec(current);
+       memcpy(vrregs, &current->tss.vr[0], sizeof(*vrregs));
+       return 1;
+}
+
+void 
+enable_kernel_altivec(void)
+{
+#ifdef __SMP__
+       if (current->tss.regs && (current->tss.regs->msr & MSR_VEC))
+               giveup_altivec(current);
+       else
+               giveup_altivec(NULL);   /* just enable AltiVec for kernel - force */
+#else
+       giveup_altivec(last_task_used_altivec);
+#endif /* __SMP __ */
+       printk("MSR_VEC in enable_altivec_kernel\n");
+}
+#endif /* CONFIG_ALTIVEC */
+
 void
 enable_kernel_fp(void)
 {
@@ -194,22 +221,53 @@ _switch_to(struct task_struct *prev, struct task_struct *new,
        _enable_interrupts(s);
 }
 
-void show_regs(struct pt_regs * regs)
+struct bits {
+       const char *name;
+       unsigned int bit;
+};
+
+void print_bits(unsigned int val, struct bits *bits)
+{
+       const char *sep = "";
+
+       printk("[");
+       for (; bits->bit != 0; ++bits) {
+               if (val & bits->bit) {
+                       printk("%s", bits->name);
+                       sep = ", ";
+               }
+       }
+       printk("]");
+}
+
+struct bits msr_bits[] = {
+       {"VEC", MSR_VEC},
+       {"EE", MSR_EE},
+       {"PR", MSR_PR},
+       {"FP", MSR_FP},
+       {"IR", MSR_IR},
+       {"DR", MSR_DR},
+       {"ME", MSR_ME},
+       {0, 0}
+};
+
+void show_regs(struct pt_regs *regs)
 {
        int i;
 
        printk("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx\n",
               regs->nip, regs->xer, regs->link, regs,regs->trap);
-       printk("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
-              regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
-              regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
-              regs->msr&MSR_IR ? 1 : 0,
-              regs->msr&MSR_DR ? 1 : 0);
+       printk("MSR: %08lx ", regs->msr);
+       print_bits(regs->msr, msr_bits);
+       printk("\n");
        printk("TASK = %p[%d] '%s' mm->pgd %p ",
               current, current->pid, current->comm, current->mm->pgd);
        printk("Last syscall: %ld ", current->tss.last_syscall);
-       printk("\nlast math %p", last_task_used_math);
-       
+       if (last_task_used_math)
+               printk("\nlast math %p", last_task_used_math);
+       if (last_task_used_altivec)
+               printk("\nlast altivec %p", last_task_used_altivec);
+
 #ifdef __SMP__ 
        printk(" CPU: %d last CPU: %d", current->processor,current->last_processor);
 #endif /* __SMP__ */
@@ -256,12 +314,16 @@ void exit_thread(void)
 {
        if (last_task_used_math == current)
                last_task_used_math = NULL;
+       if (last_task_used_altivec == current)
+               last_task_used_altivec = NULL;
 }
 
 void flush_thread(void)
 {
        if (last_task_used_math == current)
                last_task_used_math = NULL;
+       if (last_task_used_altivec == current)
+               last_task_used_altivec = NULL;
 }
 
 void
@@ -319,6 +381,19 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
        if (regs->msr & MSR_FP)
                giveup_fpu(current);
 
+#ifdef CONFIG_ALTIVEC
+       /*
+        * copy altiVec info - assume lazy altiVec switch
+        * - kumar
+        */
+       if (regs->msr & MSR_VEC)
+               giveup_altivec(current);
+
+       memcpy(&p->tss.vr, &current->tss.vr, sizeof(p->tss.vr));
+       p->tss.vscr = current->tss.vscr;
+       childregs->msr &= ~MSR_VEC;
+#endif /* CONFIG_ALTIVEC */
+
        memcpy(&p->tss.fpr, &current->tss.fpr, sizeof(p->tss.fpr));
        p->tss.fpscr = current->tss.fpscr;
        childregs->msr &= ~MSR_FP;
@@ -380,6 +455,8 @@ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp)
        shove_aux_table(sp);
        if (last_task_used_math == current)
                last_task_used_math = 0;
+       if (last_task_used_altivec == current)
+               last_task_used_altivec = 0;
        current->tss.fpscr = 0;
 }
 
@@ -439,6 +516,10 @@ asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
                goto out;
        if (regs->msr & MSR_FP)
                giveup_fpu(current);
+#ifdef CONFIG_ALTIVEC
+       if (regs->msr & MSR_VEC)
+               giveup_altivec(current);
+#endif /* CONFIG_ALTIVEC */ 
        error = do_execve(filename, (char **) a1, (char **) a2, regs);
        putname(filename);
 out:
index fa1d8cd410e65c20f178ec03794ebdead35cb8a1..f4676c8d99c2fe2c81b7a6d8b8e5e2d71ebe63ad 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/bootx.h>
 #include <asm/system.h>
 #include <asm/gemini.h>
+#include <asm/linux_logo.h>
 
 /*
  * Properties whose value is longer than this get excluded from our
@@ -88,7 +89,7 @@ unsigned int prom_num_displays = 0;
 char *of_stdout_device = 0;
 
 prom_entry prom = 0;
-ihandle prom_chosen = 0, prom_stdout = 0;
+ihandle prom_chosen = 0, prom_stdout = 0, prom_disp_node = 0;
 int prom_version = 0;
 
 extern char *klimit;
@@ -100,33 +101,38 @@ unsigned int rtas_entry = 0;  /* physical pointer */
 unsigned int rtas_size = 0;
 unsigned int old_rtas = 0;
 
+/* Set for a newworld machine */
+int use_of_interrupt_tree = 0;
+int pmac_newworld = 0;
+
 static struct device_node *allnodes = 0;
 
+#ifdef CONFIG_BOOTX_TEXT
+
 static void clearscreen(void);
 static void flushscreen(void);
 
-#ifdef CONFIG_BOOTX_TEXT
-
 void drawchar(char c);
 void drawstring(const char *c);
 static void drawhex(unsigned long v);
 static void scrollscreen(void);
 
 static void draw_byte(unsigned char c, long locX, long locY);
-static void draw_byte_32(unsigned char *bits, unsigned long *base);
-static void draw_byte_16(unsigned char *bits, unsigned long *base);
-static void draw_byte_8(unsigned char *bits, unsigned long *base);
+static void draw_byte_32(unsigned char *bits, unsigned long *base, int rb);
+static void draw_byte_16(unsigned char *bits, unsigned long *base, int rb);
+static void draw_byte_8(unsigned char *bits, unsigned long *base, int rb);
 
-static long                            g_loc_X;
-static long                            g_loc_Y;
-static long                            g_max_loc_X;
-static long                            g_max_loc_Y;
+/* We want those in the data section */
+static long                            g_loc_X = 0;
+static long                            g_loc_Y = 0;
+static long                            g_max_loc_X = 0;
+static long                            g_max_loc_Y = 0; 
 
 #define cmapsz (16*256)
 
 static unsigned char vga_font[cmapsz];
 
-#endif
+#endif /* CONFIG_BOOTX_TEXT */
 
 
 static void *call_prom(const char *service, int nargs, int nret, ...);
@@ -136,15 +142,25 @@ static unsigned long inspect_node(phandle, struct device_node *, unsigned long,
                                  unsigned long, struct device_node ***);
 static unsigned long finish_node(struct device_node *, unsigned long,
                                 interpret_func *);
+static unsigned long finish_node_interrupts(struct device_node *, unsigned long);
 static unsigned long check_display(unsigned long);
 static int prom_next_node(phandle *);
 static void *early_get_property(unsigned long, unsigned long, char *);
 
+#ifdef CONFIG_BOOTX_TEXT
+static void setup_disp_fake_bi(ihandle dp);
+static void prom_welcome(boot_infos_t* bi, unsigned long phys);
+#endif
+
 extern void enter_rtas(void *);
 extern unsigned long reloc_offset(void);
 
 extern char cmd_line[512];     /* XXX */
 boot_infos_t *boot_infos = 0;  /* init it so it's in data segment not bss */
+#ifdef CONFIG_BOOTX_TEXT
+boot_infos_t *disp_bi = 0;
+boot_infos_t fake_bi = {0,};
+#endif
 
 /*
  * prom_init() is called very early on, before the kernel text
@@ -237,7 +253,7 @@ prom_print(const char *msg)
        if (RELOC(prom_stdout) == 0)
        {
 #ifdef CONFIG_BOOTX_TEXT
-               if (RELOC(boot_infos) != 0)
+               if (RELOC(disp_bi) != 0)
                        drawstring(msg);
 #endif
                return;
@@ -273,6 +289,7 @@ prom_init(int r3, int r4, prom_entry pp)
        phandle node;
        char type[16], *path;
 #endif 
+       int chrp = 0;
        unsigned long mem;
        ihandle prom_rtas, prom_mmu, prom_op;
        unsigned long offset = reloc_offset();
@@ -299,22 +316,19 @@ prom_init(int r3, int r4, prom_entry pp)
                unsigned long space;
                unsigned long ptr, x;
                char *model;
-#ifdef CONFIG_BOOTX_TEXT
-               unsigned long flags;
-#endif         
 
                RELOC(boot_infos) = PTRUNRELOC(bi);
                if (!BOOT_INFO_IS_V2_COMPATIBLE(bi))
                        bi->logicalDisplayBase = 0;
-
-               clearscreen();
-
 #ifdef CONFIG_BOOTX_TEXT
                RELOC(g_loc_X) = 0;
                RELOC(g_loc_Y) = 0;
                RELOC(g_max_loc_X) = (bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) / 8;
                RELOC(g_max_loc_Y) = (bi->dispDeviceRect[3] - bi->dispDeviceRect[1]) / 16;
+               RELOC(disp_bi) = PTRUNRELOC(bi);
                
+               clearscreen();
+
                /* Test if boot-info is compatible. Done only in config CONFIG_BOOTX_TEXT since
                   there is nothing much we can do with an incompatible version, except display
                   a message and eventually hang the processor...
@@ -325,24 +339,10 @@ prom_init(int r3, int r4, prom_entry pp)
                if (!BOOT_INFO_IS_COMPATIBLE(bi))
                        prom_print(RELOC(" !!! WARNING - Incompatible version of BootX !!!\n\n\n"));
                
-               prom_print(RELOC("Welcome to Linux, kernel " UTS_RELEASE "\n"));
-               prom_print(RELOC("\nstarted at       : 0x"));
-               drawhex(reloc_offset() + KERNELBASE);
-               prom_print(RELOC("\nlinked at        : 0x"));
-               drawhex(KERNELBASE);
-               prom_print(RELOC("\nframe buffer at  : 0x"));
-               drawhex((unsigned long)bi->dispDeviceBase);
-               prom_print(RELOC(" (phys), 0x"));
-               drawhex((unsigned long)bi->logicalDisplayBase);
-               prom_print(RELOC(" (log)"));
-               prom_print(RELOC("\nMSR              : 0x"));
-               __asm__ __volatile__ ("mfmsr %0" : "=r" ((flags)) : : "memory");
-               drawhex(flags);
-               prom_print(RELOC("\n\n"));
-#endif
-               /* Out of the #if/#endif since it flushes the clearscreen too */
+               prom_welcome(bi, phys);
                flushscreen();
-               
+#endif /* CONFIG_BOOTX_TEXT */
+
                /* New BootX enters kernel with MMU off, i/os are not allowed
                   here. This hack will have been done by the boostrap anyway.
                 */
@@ -420,12 +420,15 @@ prom_init(int r3, int r4, prom_entry pp)
            int sz;
            sz = (int)call_prom(RELOC("getprop"), 4, 1, prom_op, RELOC("model"), model, 64);
            if (sz > 0) {
-               char *c;
-               for (c = model; *c; c++)
-                   if (*c >= '0' && *c <= '9') {
-                       RELOC(prom_version) = *c - '0';
-                       break;
-                   }
+               if ( strncmp(model,RELOC("IBM"),3) ) {
+                   char *c;
+                   for (c = model; *c; c++)
+                       if (*c >= '0' && *c <= '9') {
+                           RELOC(prom_version) = *c - '0';
+                           break;
+                       }
+               } else
+                   chrp = 1;
            }
        }
        if (RELOC(prom_version) >= 3)
@@ -533,6 +536,11 @@ prom_init(int r3, int r4, prom_entry pp)
            }
        }
            
+#ifdef CONFIG_BOOTX_TEXT
+       if (!chrp && RELOC(prom_disp_node) != 0)
+               setup_disp_fake_bi(RELOC(prom_disp_node));
+#endif
+
 #ifdef CONFIG_SMP
        /*
         * With CHRP SMP we need to use the OF to start the other
@@ -608,8 +616,8 @@ prom_init(int r3, int r4, prom_entry pp)
                else
                        prom_print(RELOC("...failed\n"));
        }
-#endif /* CONFIG_SMP */
        
+#endif 
        /* If OpenFirmware version >= 3, then use quiesce call */
        if (RELOC(prom_version) >= 3) {
            prom_print(RELOC("Calling quiesce ...\n"));
@@ -618,9 +626,80 @@ prom_init(int r3, int r4, prom_entry pp)
            phys = offset + KERNELBASE;
        }
 
+#ifdef CONFIG_BOOTX_TEXT
+       if (!chrp && RELOC(disp_bi)) {
+               RELOC(prom_stdout) = 0;
+               clearscreen();
+               prom_welcome(PTRRELOC(RELOC(disp_bi)), phys);
+               prom_print(RELOC("booting...\n"));
+       }
+#endif
+
        return phys;
 }
 
+#ifdef CONFIG_BOOTX_TEXT
+__init static void
+prom_welcome(boot_infos_t* bi, unsigned long phys)
+{
+       unsigned long offset = reloc_offset();
+       unsigned long flags;
+       unsigned long pvr;
+       
+       prom_print(RELOC("Welcome to Linux, kernel " UTS_RELEASE "\n"));
+       prom_print(RELOC("\nstarted at       : 0x"));
+       drawhex(phys);
+       prom_print(RELOC("\nlinked at        : 0x"));
+       drawhex(KERNELBASE);
+       prom_print(RELOC("\nframe buffer at  : 0x"));
+       drawhex((unsigned long)bi->dispDeviceBase);
+       prom_print(RELOC(" (phys), 0x"));
+       drawhex((unsigned long)bi->logicalDisplayBase);
+       prom_print(RELOC(" (log)"));
+       prom_print(RELOC("\nMSR              : 0x"));
+       __asm__ __volatile__ ("mfmsr %0" : "=r" (flags));
+       drawhex(flags);
+       __asm__ __volatile__ ("mfspr %0, 287" : "=r" (pvr));
+       pvr >>= 16;
+       if (pvr > 1) {
+           prom_print(RELOC("\nHID0             : 0x"));
+           __asm__ __volatile__ ("mfspr %0, 1008" : "=r" (flags));
+           drawhex(flags);
+       }
+       if (pvr == 8 || pvr == 12) {
+           prom_print(RELOC("\nICTC             : 0x"));
+           __asm__ __volatile__ ("mfspr %0, 1019" : "=r" (flags));
+           drawhex(flags);
+       }
+       prom_print(RELOC("\n\n"));
+}
+
+void showvalue(char *str, unsigned long val)
+{
+       drawstring(str);
+       drawhex(val);
+       drawstring("\n");
+}
+#endif
+
+static int prom_set_color(ihandle ih, int i, int r, int g, int b)
+{
+       struct prom_args prom_args;
+       unsigned long offset = reloc_offset();
+
+       prom_args.service = RELOC("call-method");
+       prom_args.nargs = 6;
+       prom_args.nret = 1;
+       prom_args.args[0] = RELOC("color!");
+       prom_args.args[1] = ih;
+       prom_args.args[2] = (void *) i;
+       prom_args.args[3] = (void *) b;
+       prom_args.args[4] = (void *) g;
+       prom_args.args[5] = (void *) r;
+       RELOC(prom)(&prom_args);
+       return (int) prom_args.args[6];
+}
+
 /*
  * If we have a display that we don't know how to drive,
  * we will want to try to execute OF's open method for it
@@ -633,11 +712,32 @@ __init
 static unsigned long
 check_display(unsigned long mem)
 {
+#ifdef CONFIG_FB
        phandle node;
        ihandle ih;
        int i;
        unsigned long offset = reloc_offset();
        char type[16], *path;
+       static unsigned char default_colors[] = {
+               0x00, 0x00, 0x00,
+               0x00, 0x00, 0xaa,
+               0x00, 0xaa, 0x00,
+               0x00, 0xaa, 0xaa,
+               0xaa, 0x00, 0x00,
+               0xaa, 0x00, 0xaa,
+               0xaa, 0xaa, 0x00,
+               0xaa, 0xaa, 0xaa,
+               0x55, 0x55, 0x55,
+               0x55, 0x55, 0xff,
+               0x55, 0xff, 0x55,
+               0x55, 0xff, 0xff,
+               0xff, 0x55, 0x55,
+               0xff, 0x55, 0xff,
+               0xff, 0xff, 0x55,
+               0xff, 0xff, 0xff
+       };
+
+       RELOC(prom_disp_node) = 0;
 
        for (node = 0; prom_next_node(&node); ) {
                type[0] = 0;
@@ -660,6 +760,24 @@ check_display(unsigned long mem)
                }
                prom_print(RELOC("... ok\n"));
 
+               if (RELOC(prom_disp_node) == 0)
+                       RELOC(prom_disp_node) = node;
+                       
+               /* Setup a useable color table when the appropriate
+                * method is available. Should update this to set-colors */
+               for (i = 0; i < 32; i++)
+                       if (prom_set_color(ih, i, RELOC(default_colors)[i*3],
+                                          RELOC(default_colors)[i*3+1],
+                                          RELOC(default_colors)[i*3+2]) != 0)
+                               break;
+
+               for (i = 0; i < LINUX_LOGO_COLORS; i++)
+                       if (prom_set_color(ih, i + 32,
+                                          RELOC(linux_logo_red)[i],
+                                          RELOC(linux_logo_green)[i],
+                                          RELOC(linux_logo_blue)[i]) != 0)
+                               break;
+
                /*
                 * If this display is the device that OF is using for stdout,
                 * move it to the front of the list.
@@ -676,9 +794,83 @@ check_display(unsigned long mem)
                if (RELOC(prom_num_displays) >= FB_MAX)
                        break;
        }
+#endif /* CONFIG_FB */
        return ALIGN(mem);
 }
 
+/* This function will enable the early boot text when doing OF booting. This
+ * way, xmon output should work too
+ */
+#ifdef CONFIG_BOOTX_TEXT
+__init
+static void
+setup_disp_fake_bi(ihandle dp)
+{
+       unsigned int len;
+       int width = 640, height = 480, depth = 8, pitch;
+       unsigned  address;
+       boot_infos_t* bi;
+       unsigned long offset = reloc_offset();
+       
+       prom_print(RELOC("Initing fake screen\n"));
+
+       len = 0;
+       call_prom(RELOC("getprop"), 4, 1, dp, RELOC("depth"), &len, sizeof(len));
+       if (len == 0)
+               prom_print(RELOC("Warning: assuming display depth = 8\n"));
+       else
+               depth = len;
+       width = len = 0;
+       call_prom(RELOC("getprop"), 4, 1, dp, RELOC("width"), &len, sizeof(len));
+       width = len;
+       if (width == 0) {
+               prom_print(RELOC("Failed to get width\n"));
+               return;
+       }
+       height = len = 0;
+       call_prom(RELOC("getprop"), 4, 1, dp, RELOC("height"), &len, sizeof(len));
+       height = len;
+       if (height == 0) {
+               prom_print(RELOC("Failed to get height\n"));
+               return;
+       }
+       pitch = len = 0;
+       call_prom(RELOC("getprop"), 4, 1, dp, RELOC("linebytes"), &len, sizeof(len));
+       pitch = len;
+       if (pitch == 0) {
+               prom_print(RELOC("Failed to get pitch\n"));
+               return;
+       }
+       address = len = 0;
+       call_prom(RELOC("getprop"), 4, 1, dp, RELOC("address"), &len, sizeof(len));
+       address = len;
+       if (address == 0) {
+               prom_print(RELOC("Failed to get address\n"));
+               return;
+       }
+#if 0
+       /* kludge for valkyrie */
+       if (strcmp(dp->name, "valkyrie") == 0) 
+           address += 0x1000;
+    }
+#endif
+    RELOC(disp_bi) = &fake_bi;
+    bi = PTRRELOC((&fake_bi));
+    RELOC(g_loc_X) = 0;
+    RELOC(g_loc_Y) = 0;
+    RELOC(g_max_loc_X) = width / 8;
+    RELOC(g_max_loc_Y) = height / 16;
+    bi->logicalDisplayBase = (unsigned char *)address;
+    bi->dispDeviceBase = (unsigned char *)address;
+    bi->dispDeviceRowBytes = pitch;
+    bi->dispDeviceDepth = depth;
+    bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0;
+    bi->dispDeviceRect[2] = width;
+    bi->dispDeviceRect[3] = height;
+}
+#endif
+
 __init
 static int
 prom_next_node(phandle *nodep)
@@ -813,6 +1005,32 @@ void
 finish_device_tree(void)
 {
        unsigned long mem = (unsigned long) klimit;
+#if 0
+       char* model;
+       
+       /* Here, we decide if we'll use the interrupt-tree (new Core99 code) or not.
+        * This code was only tested with Core99 machines so far, but should be easily
+        * adapted to older newworld machines (iMac, B&W G3, Lombard).
+        */
+       model = get_property(allnodes, "model", 0);
+       if ((boot_infos == 0) && model && (
+               strcmp(model, "PowerBook2,1") == 0 ||
+               strcmp(model, "PowerBook3,1") == 0 ||
+               strcmp(model, "PowerMac2,1") == 0 ||
+               strcmp(model, "PowerMac3,1") == 0))
+               use_of_interrupt_tree = 1;
+#endif         
+       /* All newworld machines now use the interrupt tree */
+       struct device_node *np = allnodes;
+       while(np) {
+               if (get_property(np, "interrupt-parent", 0)) {
+                       pmac_newworld = 1;
+                       break;
+               }
+               np = np->allnext;
+       }
+       if (boot_infos == 0 && pmac_newworld)
+               use_of_interrupt_tree = 1;
 
        mem = finish_node(allnodes, mem, NULL);
        printk(KERN_INFO "device tree used %lu bytes\n",
@@ -854,6 +1072,9 @@ finish_node(struct device_node *np, unsigned long mem_start,
        if (ifunc != NULL) {
                mem_start = ifunc(np, mem_start);
        }
+       if (use_of_interrupt_tree) {
+               mem_start = finish_node_interrupts(np, mem_start);
+       }
 
        /* the f50 sets the name to 'display' and 'compatible' to what we
         * expect for the name -- Cort
@@ -900,6 +1121,132 @@ finish_node(struct device_node *np, unsigned long mem_start,
        return mem_start;
 }
 
+/* This routine walks the interrupt tree for a given device node and gather 
+ * all necessary informations according to the draft interrupt mapping
+ * for CHRP. The current version was only tested on Apple "Core99" machines
+ * and may not handle cascaded controllers correctly.
+ */
+__init
+static unsigned long
+finish_node_interrupts(struct device_node *np, unsigned long mem_start)
+{
+       /* Finish this node */
+       unsigned int *isizep, *asizep, *interrupts, *map, *map_mask, *reg;
+       phandle *parent;
+       struct device_node *node, *parent_node;
+       int l, isize, ipsize, asize, map_size, regpsize;
+
+       /* Currently, we don't look at all nodes with no "interrupts" property */
+       interrupts = (unsigned int *)get_property(np, "interrupts", &l);
+       if (interrupts == NULL)
+               return mem_start;
+       ipsize = l>>2;
+
+       reg = (unsigned int *)get_property(np, "reg", &l);
+       regpsize = l>>2;
+
+       /* We assume default interrupt cell size is 1 (bugus ?) */
+       isize = 1;
+       node = np;
+       
+       do {
+           /* We adjust the cell size if the current parent contains an #interrupt-cells
+            * property */
+           isizep = (unsigned int *)get_property(node, "#interrupt-cells", &l);
+           if (isizep)
+               isize = *isizep;
+
+           /* We don't do interrupt cascade (ISA) for now, we stop on the first 
+            * controller found
+            */
+           if (get_property(node, "interrupt-controller", &l)) {
+               int i,j;
+               np->intrs = (struct interrupt_info *) mem_start;
+               np->n_intrs = ipsize / isize;
+               mem_start += np->n_intrs * sizeof(struct interrupt_info);
+               for (i = 0; i < np->n_intrs; ++i) {
+                   np->intrs[i].line = *interrupts++;
+                   np->intrs[i].sense = 0;
+                   if (isize > 1)
+                       np->intrs[i].sense = *interrupts++;
+                   for (j=2; j<isize; j++)
+                       interrupts++;
+               }
+               return mem_start;
+           }
+           /* We lookup for an interrupt-map. This code can only handle one interrupt
+            * per device in the map. We also don't handle #address-cells in the parent
+            * I skip the pci node itself here, may not be necessary but I don't like it's
+            * reg property.
+            */
+           if (np != node)
+               map = (unsigned int *)get_property(node, "interrupt-map", &l);
+            else
+               map = NULL;
+           if (map && l) {
+               int i, found, temp_isize;
+               map_size = l>>2;
+               map_mask = (unsigned int *)get_property(node, "interrupt-map-mask", &l);
+               asizep = (unsigned int *)get_property(node, "#address-cells", &l);
+               if (asizep && l == sizeof(unsigned int))
+                   asize = *asizep;
+               else
+                   asize = 0;
+               found = 0;
+               while(map_size>0 && !found) {
+                   found = 1;
+                   for (i=0; i<asize; i++) {
+                       unsigned int mask = map_mask ? map_mask[i] : 0xffffffff;
+                       if (!reg || (i>=regpsize) || ((mask & *map) != (mask & reg[i])))
+                           found = 0;
+                       map++;
+                       map_size--;
+                   }
+                   for (i=0; i<isize; i++) {
+                       unsigned int mask = map_mask ? map_mask[i+asize] : 0xffffffff;
+                       if ((mask & *map) != (mask & interrupts[i]))
+                           found = 0;
+                       map++;
+                       map_size--;
+                   }
+                   parent = *((phandle *)(map));
+                   map+=1; map_size-=1;
+                   parent_node = find_phandle(parent);
+                   temp_isize = isize;
+                   if (parent_node) {
+                       isizep = (unsigned int *)get_property(parent_node, "#interrupt-cells", &l);
+                       if (isizep)
+                           temp_isize = *isizep;
+                   }
+                   if (!found) {
+                       map += temp_isize;
+                       map_size-=temp_isize;
+                   }
+               }
+               if (found) {
+                   node = parent_node;
+                   reg = NULL;
+                   regpsize = 0;
+                   interrupts = (unsigned int *)map;
+                   ipsize = temp_isize*1;
+                   continue;
+               }
+           }
+           /* We look for an explicit interrupt-parent.
+            */
+           parent = (phandle *)get_property(node, "interrupt-parent", &l);
+           if (parent && (l == sizeof(phandle)) &&
+               (parent_node = find_phandle(*parent))) {
+               node = parent_node;
+               continue;
+           }
+           /* Default, get real parent */
+           node = node->parent;
+       } while(node);
+
+       return mem_start;
+}
+
 /*
  * When BootX makes a copy of the device tree from the MacOS
  * Name Registry, it is in the format we use but all of the pointers
@@ -958,6 +1305,9 @@ interpret_pci_props(struct device_node *np, unsigned long mem_start)
                mem_start += i * sizeof(struct address_range);
        }
 
+       if (use_of_interrupt_tree)
+               return mem_start;
+
        /*
         * If the pci host bridge has an interrupt-map property,
         * look for our node in it.
@@ -967,14 +1317,28 @@ interpret_pci_props(struct device_node *np, unsigned long mem_start)
                get_property(np->parent, "interrupt-map", &ml)) != 0
            && (ip = (int *) get_property(np, "interrupts", &l)) != 0) {
                unsigned int devfn = pci_addrs[0].addr.a_hi & 0xff00;
+               unsigned int cell_size;
+               struct device_node* np2;
+               /* This is hackish, but is only used for BootX booting */
+               cell_size = sizeof(struct pci_intr_map);
+               np2 = np->parent;
+               while(np2) {
+                       if (device_is_compatible(np2, "uni-north")) {
+                               cell_size += 4;
+                               break;
+                       }
+                       np2 = np2->parent;
+               }
                np->n_intrs = 0;
                np->intrs = (struct interrupt_info *) mem_start;
-               for (i = 0; (ml -= sizeof(struct pci_intr_map)) >= 0; ++i) {
-                       if (imp[i].addr.a_hi == devfn) {
-                               np->intrs[np->n_intrs].line = imp[i].intr;
-                               np->intrs[np->n_intrs].sense = 0;
+               for (i = 0; (ml -= cell_size) >= 0; ++i) {
+                       if (imp->addr.a_hi == devfn) {
+                               np->intrs[np->n_intrs].line = imp->intr;
+                               np->intrs[np->n_intrs].sense = 0; /* FIXME */
                                ++np->n_intrs;
                        }
+                       imp = (struct pci_intr_map *)(((unsigned int)imp)
+                               + cell_size);
                }
                if (np->n_intrs == 0)
                        np->intrs = 0;
@@ -1031,6 +1395,9 @@ interpret_dbdma_props(struct device_node *np, unsigned long mem_start)
                mem_start += i * sizeof(struct address_range);
        }
 
+       if (use_of_interrupt_tree)
+               return mem_start;
+
        ip = (int *) get_property(np, "AAPL,interrupts", &l);
        if (ip == 0)
                ip = (int *) get_property(np, "interrupts", &l);
@@ -1054,13 +1421,14 @@ interpret_macio_props(struct device_node *np, unsigned long mem_start)
        struct reg_property *rp;
        struct address_range *adr;
        unsigned long base_address;
-       int i, l, *ip;
+       int i, l, keylargo, *ip;
        struct device_node *db;
 
        base_address = 0;
        for (db = np->parent; db != NULL; db = db->parent) {
                if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) {
                        base_address = db->addrs[0].address;
+                       keylargo = device_is_compatible(db, "Keylargo");
                        break;
                }
        }
@@ -1080,6 +1448,9 @@ interpret_macio_props(struct device_node *np, unsigned long mem_start)
                mem_start += i * sizeof(struct address_range);
        }
 
+       if (use_of_interrupt_tree)
+               return mem_start;
+
        ip = (int *) get_property(np, "interrupts", &l);
        if (ip == 0)
                ip = (int *) get_property(np, "AAPL,interrupts", &l);
@@ -1088,9 +1459,15 @@ interpret_macio_props(struct device_node *np, unsigned long mem_start)
                if (_machine == _MACH_Pmac) {
                        /* for the iMac */
                        np->n_intrs = l / sizeof(int);
+                       /* Hack for BootX on Core99 */
+                       if (keylargo)
+                               np->n_intrs = np->n_intrs/2;
                        for (i = 0; i < np->n_intrs; ++i) {
                                np->intrs[i].line = *ip++;
-                               np->intrs[i].sense = 0;
+                               if (keylargo)
+                                       np->intrs[i].sense = *ip++;
+                               else
+                                       np->intrs[i].sense = 0;
                        }
                } else {
                        /* CHRP machines */
@@ -1130,6 +1507,9 @@ interpret_isa_props(struct device_node *np, unsigned long mem_start)
                mem_start += i * sizeof(struct address_range);
        }
 
+       if (use_of_interrupt_tree)
+               return mem_start;
        ip = (int *) get_property(np, "interrupts", &l);
        if (ip != 0) {
                np->intrs = (struct interrupt_info *) mem_start;
@@ -1167,6 +1547,9 @@ interpret_root_props(struct device_node *np, unsigned long mem_start)
                mem_start += i * sizeof(struct address_range);
        }
 
+       if (use_of_interrupt_tree)
+               return mem_start;
+
        ip = (int *) get_property(np, "AAPL,interrupts", &l);
        if (ip == 0)
                ip = (int *) get_property(np, "interrupts", &l);
@@ -1223,6 +1606,49 @@ find_type_devices(const char *type)
        return head;
 }
 
+/* Finds a device node given its PCI bus number, device number
+ * and function number
+ */
+__openfirmware
+struct device_node *
+find_pci_device_OFnode(unsigned char bus, unsigned char dev_fn)
+{
+       struct device_node* np;
+       unsigned int *reg;
+       int l;
+       
+       for (np = allnodes; np != 0; np = np->allnext) {
+               char *pname = np->parent ?
+                       (char *)get_property(np->parent, "name", &l) : 0;
+               if (pname && strcmp(pname, "mac-io") == 0)
+                       continue;
+               reg = (unsigned int *) get_property(np, "reg", &l);
+               if (reg == 0 || l < sizeof(struct reg_property))
+                       continue;
+               if (((reg[0] >> 8) & 0xff) == dev_fn && ((reg[0] >> 16) & 0xff) == bus)
+                       break;
+       }
+       return np;
+}
+
+/*
+ * Returns all nodes linked together
+ */
+__openfirmware
+struct device_node *
+find_all_nodes(void)
+{
+       struct device_node *head, **prevp, *np;
+
+       prevp = &head;
+       for (np = allnodes; np != 0; np = np->allnext) {
+               *prevp = np;
+               prevp = &np->next;
+       }
+       *prevp = 0;
+       return head;
+}
+
 /* Checks if the given "compat" string matches one of the strings in
  * the device's "compatible" property
  */
@@ -1424,18 +1850,44 @@ abort()
        prom_exit();
 }
 
-#ifdef CONFIG_XMON
+/* Indicates whether the root node has a given value in its
+ * compatible property.
+ */
+__openfirmware
+int
+machine_is_compatible(const char *compat)
+{
+       struct device_node *root;
+       
+       root = find_path_device("/");
+       if (root == 0)
+               return 0;
+       return device_is_compatible(root, compat);
+}
+
+
+#ifdef CONFIG_BOOTX_TEXT
+
+/* Here's a small text engine to use during early boot or for debugging purposes
+ * 
+ * todo:
+ * 
+ *  - build some kind of vgacon with it to enable early printk
+ *  - move to a separate file
+ *  - add a few video driver hooks to keep in sync with display
+ *    changes.
+ */
+
 __init
 void
 map_bootx_text(void)
 {
-       if (boot_infos == 0)
+       if (disp_bi == 0)
                return;
-       boot_infos->logicalDisplayBase =
-               ioremap((unsigned long) boot_infos->dispDeviceBase,
-                       boot_infos->dispDeviceRowBytes * boot_infos->dispDeviceRect[3]);
+       disp_bi->logicalDisplayBase =
+               ioremap((unsigned long) disp_bi->dispDeviceBase,
+                       disp_bi->dispDeviceRowBytes * disp_bi->dispDeviceRect[3]);
 }
-#endif /* CONFIG_XMON */
 
 /* Calc the base address of a given point (x,y) */
 __pmac
@@ -1457,7 +1909,7 @@ static void
 clearscreen(void)
 {
        unsigned long offset    = reloc_offset();
-       boot_infos_t* bi        = PTRRELOC(RELOC(boot_infos));
+       boot_infos_t* bi        = PTRRELOC(RELOC(disp_bi));
        unsigned long *base     = (unsigned long *)calc_base(bi, 0, 0);
        unsigned long width     = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
                                        (bi->dispDeviceDepth >> 3)) >> 2;
@@ -1482,7 +1934,7 @@ static void
 flushscreen(void)
 {
        unsigned long offset    = reloc_offset();
-       boot_infos_t* bi        = PTRRELOC(RELOC(boot_infos));
+       boot_infos_t* bi        = PTRRELOC(RELOC(disp_bi));
        unsigned long *base     = (unsigned long *)calc_base(bi, 0, 0);
        unsigned long width     = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
                                        (bi->dispDeviceDepth >> 3)) >> 2;
@@ -1499,29 +1951,12 @@ flushscreen(void)
        }
 }
 
-/* Indicates whether the root node has a given value in its
- * compatible property.
- */
-__openfirmware
-int
-machine_is_compatible(const char *compat)
-{
-       struct device_node *root;
-       
-       root = find_path_device("/");
-       if (root == 0)
-               return 0;
-       return device_is_compatible(root, compat);
-}
-
-#ifdef CONFIG_BOOTX_TEXT
-
 __pmac
 static void
 scrollscreen(void)
 {
        unsigned long offset            = reloc_offset();
-       boot_infos_t* bi                = PTRRELOC(RELOC(boot_infos));
+       boot_infos_t* bi                = PTRRELOC(RELOC(disp_bi));
        unsigned long *src              = (unsigned long *)calc_base(bi,0,16);
        unsigned long *dst              = (unsigned long *)calc_base(bi,0,0);
        unsigned long width             = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
@@ -1611,19 +2046,20 @@ static void
 draw_byte(unsigned char c, long locX, long locY)
 {
        unsigned long offset    = reloc_offset();
-       boot_infos_t* bi        = PTRRELOC(RELOC(boot_infos));
+       boot_infos_t* bi        = PTRRELOC(RELOC(disp_bi));
        unsigned char *base     = calc_base(bi, locX << 3, locY << 4);
        unsigned char *font     = &RELOC(vga_font)[((unsigned long)c) * 16];
+       int rb                  = bi->dispDeviceRowBytes;
        
        switch(bi->dispDeviceDepth) {
                case 32:
-                       draw_byte_32(font, (unsigned long *)base);
+                       draw_byte_32(font, (unsigned long *)base, rb);
                        break;
                case 16:
-                       draw_byte_16(font, (unsigned long *)base);
+                       draw_byte_16(font, (unsigned long *)base, rb);
                        break;
                case 8:
-                       draw_byte_8(font, (unsigned long *)base);
+                       draw_byte_8(font, (unsigned long *)base, rb);
                        break;
                default:
                        break;
@@ -1661,10 +2097,8 @@ static unsigned long expand_bits_16[4] = {
 
 __pmac
 static void
-draw_byte_32(unsigned char *font, unsigned long *base)
+draw_byte_32(unsigned char *font, unsigned long *base, int rb)
 {
-       unsigned long offset = reloc_offset();
-       boot_infos_t* bi                = PTRRELOC(RELOC(boot_infos));
        int l, bits;    
        int fg = 0xFFFFFFFFUL;
        int bg = 0x00000000UL;
@@ -1681,19 +2115,18 @@ draw_byte_32(unsigned char *font, unsigned long *base)
                base[5] = (-((bits >> 2) & 1) & fg) ^ bg;
                base[6] = (-((bits >> 1) & 1) & fg) ^ bg;
                base[7] = (-(bits & 1) & fg) ^ bg;
-               base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes);
+               base = (unsigned long *) ((char *)base + rb);
        }
 }
 
 __pmac
 static void
-draw_byte_16(unsigned char *font, unsigned long *base)
+draw_byte_16(unsigned char *font, unsigned long *base, int rb)
 {
-       unsigned long offset = reloc_offset();
-       boot_infos_t* bi                = PTRRELOC(RELOC(boot_infos));
        int l, bits;    
        int fg = 0xFFFFFFFFUL;
        int bg = 0x00000000UL;
+       unsigned long offset = reloc_offset();
        unsigned long *eb = RELOC(expand_bits_16);
 
        for (l = 0; l < 16; ++l)
@@ -1703,19 +2136,18 @@ draw_byte_16(unsigned char *font, unsigned long *base)
                base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg;
                base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg;
                base[3] = (eb[bits & 3] & fg) ^ bg;
-               base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes);
+               base = (unsigned long *) ((char *)base + rb);
        }
 }
 
 __pmac
 static void
-draw_byte_8(unsigned char *font, unsigned long *base)
+draw_byte_8(unsigned char *font, unsigned long *base, int rb)
 {
-       unsigned long offset = reloc_offset();
-       boot_infos_t* bi                = PTRRELOC(RELOC(boot_infos));
        int l, bits;    
        int fg = 0x0F0F0F0FUL;
        int bg = 0x00000000UL;
+       unsigned long offset = reloc_offset();
        unsigned long *eb = RELOC(expand_bits_8);
 
        for (l = 0; l < 16; ++l)
@@ -1723,7 +2155,7 @@ draw_byte_8(unsigned char *font, unsigned long *base)
                bits = *font++;
                base[0] = (eb[bits >> 4] & fg) ^ bg;
                base[1] = (eb[bits & 0xf] & fg) ^ bg;
-               base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes);
+               base = (unsigned long *) ((char *)base + rb);
        }
 }
 
index 6310c75146955b497aef212fe514cd921c3535bc..f66c5b6de6e973c0b1297fc59985dbf00db91b83 100644 (file)
@@ -68,6 +68,13 @@ extern void gemini_init(unsigned long r3,
                       unsigned long r6,
                       unsigned long r7);
 
+#ifdef CONFIG_BOOTX_TEXT
+extern void map_bootx_text(void);
+#endif
+#ifdef CONFIG_XMON
+extern void xmon_map_scc(void);
+#endif
+
 extern boot_infos_t *boot_infos;
 extern char cmd_line[512];
 char saved_command_line[256];
@@ -256,6 +263,9 @@ int get_cpuinfo(char *buffer)
                case 10:
                        len += sprintf(len+buffer, "604ev5 (MachV)\n");
                        break;
+               case 12:
+                       len += sprintf(len+buffer, "7400 (G4)\n");
+                       break;
                case 50:
                        len += sprintf(len+buffer, "821\n");
                case 80:
@@ -456,11 +466,15 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
                        char *p;
                        
 #ifdef CONFIG_BLK_DEV_INITRD
-                       if (r3 - KERNELBASE < 0x800000
-                           && r4 != 0 && r4 != 0xdeadbeef) {
+                       /* Removed check < 0x800000, yaboot loads the kernel at +16Mb
+                        * and the ramdisk _after_ the kernel */
+                       if (r3 && r4 && r4 != 0xdeadbeef) {
+                               if (r3 < KERNELBASE)
+                                       r3 += KERNELBASE;
                                initrd_start = r3;
                                initrd_end = r3 + r4;
                                ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+                               initrd_below_start_ok = 1;
                        }
 #endif
                        cmd_line[0] = 0;
@@ -538,7 +552,7 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
 /* Checks "l2cr=xxxx" command-line option */
 void ppc_setup_l2cr(char *str, int *ints)
 {
-       if ( (_get_PVR() >> 16) == 8)
+       if ( ((_get_PVR() >> 16) == 8) || ((_get_PVR() >> 16) == 12) )
        {
                unsigned long val = simple_strtoul(str, NULL, 0);
                printk(KERN_INFO "l2cr set to %lx\n", val);
@@ -564,14 +578,19 @@ __initfunc(void setup_arch(char **cmdline_p,
        extern unsigned long find_available_memory(void);
        extern unsigned long *end_of_DRAM;
 
+#ifdef CONFIG_BOOTX_TEXT
+       map_bootx_text();
+#endif
+
 #ifdef CONFIG_XMON
-       extern void xmon_map_scc(void);
-       char *p;
+       {
+               char *p;
 
-       xmon_map_scc();
-       p = strstr(cmd_line, "xmon");
-       if (p != NULL && (p == cmd_line || p[-1] == ' '))
-               xmon(0);
+               xmon_map_scc();
+               p = strstr(cmd_line, "xmon");
+               if (p != NULL && (p == cmd_line || p[-1] == ' '))
+                       xmon(0);
+       }
 #endif /* CONFIG_XMON */
  
        /* reboot on panic */   
index 05a48d1b44f8e05214e9c7c63c4aff11d0d81246..1684fd31559ec7db0db26623d88cb6f6edf77611 100644 (file)
@@ -220,6 +220,10 @@ int sys_sigreturn(struct pt_regs *regs)
                sr = (struct sigregs *) sigctx.regs;
                if (regs->msr & MSR_FP )
                        giveup_fpu(current);
+#ifdef CONFIG_ALTIVEC
+               if (regs->msr & MSR_VEC)
+                       giveup_altivec(current);
+#endif /* CONFIG_ALTIVEC */
                if (copy_from_user(saved_regs, &sr->gp_regs,
                                   sizeof(sr->gp_regs)))
                        goto badframe;
@@ -268,6 +272,10 @@ setup_frame(struct pt_regs *regs, struct sigregs *frame,
                goto badframe;
        if (regs->msr & MSR_FP)
                giveup_fpu(current);
+#ifdef CONFIG_ALTIVEC
+       if (regs->msr & MSR_VEC)
+               giveup_altivec(current);
+#endif /* CONFIG_ALTIVEC */
        if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE)
            || __copy_to_user(&frame->fp_regs, current->tss.fpr,
                              ELF_NFPREG * sizeof(double))
index 27033e8bfd8d1e509133de954381463d72738475..684805f6758b8824a012727c7910bf1b7116730f 100644 (file)
@@ -7,7 +7,7 @@
  * deal of code from the sparc and intel versions.
  *
  * Support for PReP (Motorola MTX/MVME) SMP by Troy Benjegerdes
- * (troy@microux.com, hozer@drgw.net)
+ * (troy@blacklablinux.com, hozer@drgw.net)
  */
 
 #include <linux/kernel.h>
index 3aa0becef6fba1891e4c6a4655fc8451c3ec0253..612b7667441abdc9b7cda42a328b210165260ee7 100644 (file)
@@ -246,9 +246,14 @@ asmlinkage int sys_pause(void)
 
 asmlinkage int sys_uname(struct old_utsname * name)
 {
-       if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
-               return 0;
-       return -EFAULT;
+       int err;
+       
+       if (!name)
+               return -EFAULT;
+       down(&uts_sem);
+       err = copy_to_user(name, &system_utsname, sizeof (*name));
+       up(&uts_sem);
+       return err ? -EFAULT : 0;
 }
 
 asmlinkage int sys_olduname(struct oldold_utsname * name)
@@ -260,6 +265,7 @@ asmlinkage int sys_olduname(struct oldold_utsname * name)
        if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
                return -EFAULT;
   
+       down(&uts_sem);
        error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
        error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
        error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
@@ -271,6 +277,7 @@ asmlinkage int sys_olduname(struct oldold_utsname * name)
        error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
        error = __put_user(0,name->machine+__OLD_UTS_LEN);
        error = error ? -EFAULT : 0;
+       up(&uts_sem);
 
        return error;
 }
index c33bff3e0b498f823242d97c4cef9a966487ba98..8b119e24000b4969f56b833ba3d66b14fb1531dc 100644 (file)
@@ -100,26 +100,27 @@ MachineCheckException(struct pt_regs *regs)
                        return;
                }
 #endif
-               printk("Machine check in kernel mode.\n");
-               printk("Caused by (from msr): ");
-               printk("regs %p ",regs);
-               switch( regs->msr & 0x0000F000)
-               {
-               case (1<<12) :
-                       printk("Machine check signal - probably due to mm fault\n"
-                               "with mmu off\n");
+               printk("Machine check in kernel mode.  (regs at %p)\n", regs);
+               printk("Caused by (from srr1): ");
+               switch( regs->msr & 0x001F0000) {
+               case 0x100000:
+                       printk("L2 data cache parity error\n");
                        break;
-               case (1<<13) :
+               case 0x80000:
+                       printk("Machine check signal\n");
+                       printk("(probably due to access of bad physical address\n");
+                       break;
+               case 0x40000:
                        printk("Transfer error ack signal\n");
                        break;
-               case (1<<14) :
+               case 0x20000:
                        printk("Data parity signal\n");
                        break;
-               case (1<<15) :
+               case 0x10000:
                        printk("Address parity signal\n");
                        break;
                default:
-                       printk("Unknown values in msr\n");
+                       printk("Unknown values in srr1\n");
                }
                show_regs(regs);
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
index 8d7bf06c4d00f7da73aa1d07974df3ca948314c8..9d605979d25e24d9b9d12e32325255966984a916 100644 (file)
 #include <asm/processor.h>
 #include <asm/errno.h>
 
+CACHELINE_BYTES = 32
+LG_CACHELINE_BYTES = 5
+CACHELINE_MASK = 0x1f
+CACHELINE_WORDS = 8
+
        .globl  strcpy
 strcpy:
        addi    r5,r3,-1
@@ -82,7 +87,35 @@ memset:
        andi.   r0,r6,3
        add     r5,r0,r5
        subf    r6,r0,r6
-       rlwinm  r0,r5,32-2,2,31
+#if 0  /* Clever, but breaks fb stuff -- paulus */
+/*
+ * Use dcbz on the complete cache lines in the destination if
+ * we are setting to zero.  This requires that the destination
+ * area is cacheable.  -- paulus
+ */
+       cmpwi   0,r4,0
+       bne     2f
+       clrlwi  r7,r6,32-LG_CACHELINE_BYTES
+       add     r8,r7,r5
+       srwi    r9,r8,LG_CACHELINE_BYTES
+       addic.  r9,r9,-1        /* total number of complete cachelines */
+       ble     2f
+       xori    r0,r7,CACHELINE_MASK & ~3
+       srwi.   r0,r0,2
+       beq     3f
+       mtctr   r0
+4:     stwu    r4,4(r6)
+       bdnz    4b
+3:     mtctr   r9
+       li      r7,4
+10:    dcbz    r7,r6
+       addi    r6,r6,CACHELINE_BYTES
+       bdnz    10b
+       clrlwi  r5,r8,32-LG_CACHELINE_BYTES
+       addi    r5,r5,4
+2:
+#endif
+       srwi    r0,r5,2
        mtctr   r0
        bdz     6f
 1:     stwu    r4,4(r6)
@@ -107,11 +140,94 @@ bcopy:
 memmove:
        cmplw   0,r3,r4
        bgt     backwards_memcpy
-       /* fall through */
+       b       forwards_memcpy
 
        .globl  memcpy
 memcpy:
-       rlwinm. r7,r5,32-3,3,31         /* r0 = r5 >> 3 */
+#if 0  /* Clever, but will probably break fb stuff -- paulus */
+/*
+ * This version uses dcbz on the complete cache lines in the
+ * destination area to reduce memory traffic.  This requires that
+ * the destination area is cacheable.
+ * We only use this version if the source and dest don't overlap.
+ * -- paulus.
+ */
+       add     r7,r3,r5                /* test if the src & dst overlap */
+       add     r8,r4,r5
+       cmplw   0,r4,r7
+       cmplw   1,r3,r8
+       crand   0,0,4                   /* cr0.lt &= cr1.lt */
+       blt     forwards_memcpy         /* if regions overlap */
+
+       addi    r4,r4,-4
+       addi    r6,r3,-4
+       neg     r0,r3
+       andi.   r0,r0,CACHELINE_MASK    /* # bytes to start of cache line */
+       beq     58f
+
+       cmplw   0,r5,r0                 /* is this more than total to do? */
+       blt     63f                     /* if not much to do */
+       andi.   r8,r0,3                 /* get it word-aligned first */
+       subf    r5,r0,r5
+       mtctr   r8
+       beq+    61f
+70:    lbz     r9,4(r4)                /* do some bytes */
+       stb     r9,4(r6)
+       addi    r4,r4,1
+       addi    r6,r6,1
+       bdnz    70b
+61:    srwi.   r0,r0,2
+       mtctr   r0
+       beq     58f
+72:    lwzu    r9,4(r4)                /* do some words */
+       stwu    r9,4(r6)
+       bdnz    72b
+
+58:    srwi.   r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */
+       clrlwi  r5,r5,32-LG_CACHELINE_BYTES
+       li      r11,4
+       mtctr   r0
+       beq     63f
+53:    dcbz    r11,r6
+       lwz     r7,4(r4)
+       lwz     r8,8(r4)
+       lwz     r9,12(r4)
+       lwzu    r10,16(r4)
+       stw     r7,4(r6)
+       stw     r8,8(r6)
+       stw     r9,12(r6)
+       stwu    r10,16(r6)
+       lwz     r7,4(r4)
+       lwz     r8,8(r4)
+       lwz     r9,12(r4)
+       lwzu    r10,16(r4)
+       stw     r7,4(r6)
+       stw     r8,8(r6)
+       stw     r9,12(r6)
+       stwu    r10,16(r6)
+       bdnz    53b
+
+63:    srwi.   r0,r5,2
+       mtctr   r0
+       beq     64f
+30:    lwzu    r0,4(r4)
+       stwu    r0,4(r6)
+       bdnz    30b
+
+64:    andi.   r0,r5,3
+       mtctr   r0
+       beq+    65f
+40:    lbz     r0,4(r4)
+       stb     r0,4(r6)
+       addi    r4,r4,1
+       addi    r6,r6,1
+       bdnz    40b
+65:    blr
+#endif
+
+       .global forwards_memcpy
+forwards_memcpy:
+       srwi.   r7,r5,3
        addi    r6,r3,-4
        addi    r4,r4,-4
        beq     2f                      /* if less than 8 bytes to do */
@@ -218,106 +334,167 @@ memchr:
 
        .globl  __copy_tofrom_user
 __copy_tofrom_user:
-       srwi.   r7,r5,3
-       addi    r6,r3,-4
        addi    r4,r4,-4
-       li      r3,0            /* success return value */
-       beq     2f              /* if less than 8 bytes to do */
-       andi.   r0,r6,3         /* get dest word aligned */
-       mtctr   r7
-       bne     5f
-1:     lwz     r7,4(r4)
-11:    lwzu    r8,8(r4)
-12:    stw     r7,4(r6)
-13:    stwu    r8,8(r6)
-       bdnz    1b
-       andi.   r5,r5,7
-2:     cmplwi  0,r5,4
-       blt     3f
-14:    lwzu    r0,4(r4)
-       addi    r5,r5,-4
-15:    stwu    r0,4(r6)
-3:     cmpwi   0,r5,0          /* do 1 byte at a time for the remainder */
-       beqlr
-       mtctr   r5
-       addi    r4,r4,3
-       addi    r6,r6,3
-4:     lbzu    r0,1(r4)
-16:    stbu    r0,1(r6)
-       bdnz    4b
-       blr
-5:     subfic  r0,r0,4         /* copy bytes until we have the */
-       mtctr   r0              /* destination 4-byte aligned */
-       subf    r5,r0,r5
-6:     lbz     r7,4(r4)
+       addi    r6,r3,-4
+       neg     r0,r3
+       andi.   r0,r0,CACHELINE_MASK    /* # bytes to start of cache line */
+       beq     58f
+
+       cmplw   0,r5,r0                 /* is this more than total to do? */
+       blt     63f                     /* if not much to do */
+       andi.   r8,r0,3                 /* get it word-aligned first */
+       mtctr   r8
+       beq+    61f
+70:    lbz     r9,4(r4)                /* do some bytes */
+71:    stb     r9,4(r6)
        addi    r4,r4,1
-17:    stb     r7,4(r6)
        addi    r6,r6,1
-       bdnz    6b
-       srwi.   r7,r5,3
-       beq     2b
-       mtctr   r7
-       b       1b
-/* we come here on a fault in the 8-byte-at-a-time loop */
-88:    subi    r4,r4,8         /* compensate for the lwzu */
-98:    mfctr   r0
-       rlwimi  r5,r0,3,0,28    /* use the byte-at-a-time loop to */
-       b       3b              /* copy up to the byte at fault */
-/* here on a write fault in the single-word copy */
-96:    subi    r4,r4,4
-       b       3b
-/* here on a read fault in the initial single-byte copy */
-90:    mfctr   r3
-       add     r3,r3,r5
-       b       70f
-/* here on a read fault in the final single-byte copy */
-99:    mfctr   r3
-       subi    r6,r6,3
-/* clear out the rest of the destination: r3 bytes starting at 4(r6) */
-70:    li      r0,0
-       mr.     r5,r3
-       beq     76f
-71:    andi.   r4,r6,3
-       beq     72f
-77:    stb     r0,4(r6)
+       bdnz    70b
+61:    subf    r5,r0,r5
+       srwi.   r0,r0,2
+       mtctr   r0
+       beq     58f
+72:    lwzu    r9,4(r4)                /* do some words */
+73:    stwu    r9,4(r6)
+       bdnz    72b
+
+58:    srwi.   r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */
+       clrlwi  r5,r5,32-LG_CACHELINE_BYTES
+       li      r11,4
+       mtctr   r0
+       beq     63f
+53:    dcbz    r11,r6
+10:    lwz     r7,4(r4)
+11:    lwz     r8,8(r4)
+12:    lwz     r9,12(r4)
+13:    lwzu    r10,16(r4)
+14:    stw     r7,4(r6)
+15:    stw     r8,8(r6)
+16:    stw     r9,12(r6)
+17:    stwu    r10,16(r6)
+20:    lwz     r7,4(r4)
+21:    lwz     r8,8(r4)
+22:    lwz     r9,12(r4)
+23:    lwzu    r10,16(r4)
+24:    stw     r7,4(r6)
+25:    stw     r8,8(r6)
+26:    stw     r9,12(r6)
+27:    stwu    r10,16(r6)
+       bdnz    53b
+
+63:    srwi.   r0,r5,2
+       mtctr   r0
+       beq     64f
+30:    lwzu    r0,4(r4)
+31:    stwu    r0,4(r6)
+       bdnz    30b
+
+64:    andi.   r0,r5,3
+       mtctr   r0
+       beq+    65f
+40:    lbz     r0,4(r4)
+41:    stb     r0,4(r6)
+       addi    r4,r4,1
        addi    r6,r6,1
-       addic.  r5,r5,-1
-       bne     71b
-72:    srwi.   r7,r5,2
-       beq     73f
-       mtctr   r7
-74:    stwu    r0,4(r6)
-       bdnz    74b
-73:    andi.   r5,r5,3
-       beq     76f
-       mtctr   r5
-       addi    r6,r6,3
-75:    stbu    r0,1(r6)
-       bdnz    75b
-76:    blr
-/* here on a write fault in the initial single-byte copy */
-80:    mfctr   r3
-       add     r3,r3,r5
-       blr
-/* here on a write fault in the final single-byte copy */
-81:    mfctr   r3
+       bdnz    40b
+65:    li      r3,0
        blr
 
+/* read fault, initial single-byte copy */
+100:   li      r4,0
+       b       90f
+/* write fault, initial single-byte copy */
+101:   li      r4,1
+90:    subf    r5,r8,r5
+       li      r3,0
+       b       99f
+/* read fault, initial word copy */
+102:   li      r4,0
+       b       91f
+/* write fault, initial word copy */
+103:   li      r4,1
+91:    li      r3,2
+       b       99f
+/* read fault in 2nd half of cacheline loop */
+106:   addi    r5,r5,-16
+/* read fault in 1st half of cacheline loop */
+104:   li      r4,0
+       b       92f
+/* write fault in 2nd half of cacheline loop */
+107:   addi    r5,r5,-16
+/* fault on dcbz (effectively a write fault) */
+/* or write fault in 1st half of cacheline loop */
+105:   li      r4,1
+92:    li      r3,LG_CACHELINE_BYTES
+       b       99f
+/* read fault in final word loop */
+108:   li      r4,0
+       b       93f
+/* write fault in final word loop */
+109:   li      r4,1
+93:    andi.   r5,r5,3
+       li      r3,2
+       b       99f
+/* read fault in final byte loop */
+110:   li      r4,0
+       b       94f
+/* write fault in final byte loop */
+111:   li      r4,1
+94:    li      r5,0
+       li      r3,0
+/*
+ * At this stage the number of bytes not copied is
+ * r5 + (ctr << r3), and r4 is 0 for read or 1 for write.
+ */
+99:    mfctr   r0
+       slw     r3,r0,r3
+       add     r3,r3,r5
+       cmpwi   0,r4,0
+       bne     120f
+/* for read fault, clear out the destination: r3 bytes starting at 4(r6) */
+       srwi.   r0,r3,2
+       li      r9,0
+       mtctr   r0
+       beq     113f
+112:   stwu    r9,4(r6)
+       bdnz    112b
+113:   andi.   r0,r3,3
+       mtctr   r0
+       beq     120f
+114:   stb     r9,4(r6)
+       addi    r6,r6,1
+       bdnz    114b
+120:   blr
+
 .section __ex_table,"a"
        .align  2
-       .long   1b,98b
-       .long   11b,98b
-       .long   12b,88b
-       .long   13b,88b
-       .long   14b,3b
-       .long   15b,96b
-       .long   4b,99b
-       .long   16b,81b
-       .long   6b,90b
-       .long   17b,80b
-       .long   77b,76b
-       .long   74b,76b
-       .long   75b,76b
+       .long   70b,100b
+       .long   71b,101b
+       .long   72b,102b
+       .long   73b,103b
+       .long   53b,105b
+       .long   10b,104b
+       .long   11b,104b
+       .long   12b,104b
+       .long   13b,104b
+       .long   14b,105b
+       .long   15b,105b
+       .long   16b,105b
+       .long   17b,105b
+       .long   20b,106b
+       .long   21b,106b
+       .long   22b,106b
+       .long   23b,106b
+       .long   24b,107b
+       .long   25b,107b
+       .long   26b,107b
+       .long   27b,107b
+       .long   30b,108b
+       .long   31b,109b
+       .long   40b,110b
+       .long   41b,111b
+       .long   112b,120b
+       .long   114b,120b
 .text
 
        .globl  __clear_user
@@ -334,7 +511,6 @@ __clear_user:
        andi.   r0,r6,3
        add     r4,r0,r4
        subf    r6,r0,r6
-       /*rlwinm        r0,r4,32-2,2,31*/
        srwi    r0,r4,2
        mtctr   r0
        bdz     6f
index 2e66dced65d5cfcfcf4fea807f66b05f61c16292..103f039cabc1b457d4a6298b34465367dd59f247 100644 (file)
@@ -71,7 +71,10 @@ void do_page_fault(struct pt_regs *regs, unsigned long address,
               (error_code&0x80000000)?"I/O ":"",
               (regs->trap == 0x400)?"instr":"data"
               );*/
-              
+
+       if (regs->trap == 0x400)
+               error_code &= 0x48200000;
+
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
        if (debugger_fault_handler && regs->trap == 0x300) {
                debugger_fault_handler(regs);
index c672c86151e1693aa6026233c0045fd9425e9309..9a257c82c7b83b34a8f96bf04e74c0865ff39891 100644 (file)
@@ -416,7 +416,12 @@ out:
 
 void iounmap(void *addr)
 {
-       /* XXX todo */
+       /* For support of dynamic hot swap on the cPCI bus this routine
+          is now necessary.  This has been well tested on a Motorola
+          MPC750 (Mesquite) processor board.  Johnnie Peters
+       */
+       if (addr > high_memory && addr < ioremap_bot)
+               return vfree((void *) (PAGE_MASK & (unsigned long) addr));
 }
 
 unsigned long iopa(unsigned long addr)
index c63ca94797f96dbb3d1e17d19ebb586cbc04f4c3..4e5fbb6a04aa29c12a161186bf9b96bd6232d187 100644 (file)
@@ -253,6 +253,7 @@ CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
 CONFIG_MACE=y
 CONFIG_BMAC=y
+CONFIG_GMAC=y
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
@@ -339,6 +340,7 @@ CONFIG_FB_CONTROL=y
 CONFIG_FB_PLATINUM=y
 CONFIG_FB_VALKYRIE=y
 CONFIG_FB_ATY=y
+CONFIG_FB_ATY128=y
 CONFIG_FB_IMSTT=y
 CONFIG_FB_CT65550=y
 # CONFIG_FB_S3TRIO is not set
index 0590b6eeaae125d01d14e4c9f538cd9a07a54899..18d17bd394a305b849ccef7f9d6528b1529cb084 100644 (file)
 #include <asm/prom.h>
 #include <asm/bootx.h>
 #include <asm/pmu.h>
+#include <asm/feature.h>
 
 static volatile unsigned char *sccc, *sccd;
 unsigned long TXRDY, RXRDY;
 extern void xmon_printf(const char *fmt, ...);
-extern void map_bootx_text(void);
 extern void drawchar(char);
 extern void drawstring(const char *str);
+static int xmon_expect(const char *str, unsigned int timeout);
 
 static int console = 0;
 static int use_screen = 0;
+static int via_modem = 0;
+static int xmon_use_sccb = 0;
+static struct device_node *macio_node;
+
+#define TB_SPEED       25000000
+
+static inline unsigned int readtb(void)
+{
+       unsigned int ret;
+
+       asm volatile("mftb %0" : "=r" (ret) :);
+       return ret;
+}
 
 void buf_access(void)
 {
@@ -36,17 +50,18 @@ xmon_map_scc(void)
        if ( _machine == _MACH_Pmac )
        {
                struct device_node *np;
-               extern boot_infos_t *boot_infos;
                unsigned long addr;
-
 #ifdef CONFIG_BOOTX_TEXT
-               if (boot_infos != 0 && find_via_pmu()) {
+               extern boot_infos_t *disp_bi;
+
+               /* needs to be hacked if xmon_printk is to be used
+                  from within find_via_pmu() */
+               if (!via_modem && disp_bi && find_via_pmu()) {
                        printk(KERN_INFO "xmon uses screen and keyboard\n");
                        use_screen = 1;
-                       map_bootx_text();
-                       return;
                }
 #endif
+
 #ifdef CHRP_ESCC
                addr = 0xc1013020;
 #else
@@ -57,18 +72,13 @@ xmon_map_scc(void)
                
                np = find_devices("mac-io");
                if (np && np->n_addrs) {
-                       addr = np->addrs[0].address + 0x13000;
-                       /* use the B channel on the iMac, A channel on others */
-                       if (addr >= 0xf0000000)
-                               addr += 0x20; /* use A channel */
+                       macio_node = np;
+                       addr = np->addrs[0].address + 0x13020;
                }
-               base = (volatile unsigned char *) ioremap(addr & PAGE_MASK, PAGE_SIZE);
+               base = (volatile unsigned char *)
+                       ioremap(addr & PAGE_MASK, PAGE_SIZE);
                sccc = base + (addr & ~PAGE_MASK);
-#ifdef CHRP_ESCC
-               sccd = sccc + (0xc1013030 - 0xc1013020);
-#else
-               sccd = sccc + (0xf3013030 - 0xf3013020);
-#endif
+               sccd = sccc + 0x10;
        }
        else
        {
@@ -89,7 +99,7 @@ int
 xmon_write(void *handle, void *ptr, int nb)
 {
     char *p = ptr;
-    int i, ct;
+    int i, c, ct;
 
 #ifdef CONFIG_BOOTX_TEXT
     if (use_screen) {
@@ -101,19 +111,23 @@ xmon_write(void *handle, void *ptr, int nb)
 #endif
     if (!scc_initialized)
        xmon_init_scc();
+    ct = 0;
     for (i = 0; i < nb; ++i) {
        while ((*sccc & TXRDY) == 0)
            if (adb_hardware == ADB_VIAPMU)
                pmu_poll();
+       c = p[i];
+       if (c == '\n' && !ct) {
+           c = '\r';
+           ct = 1;
+           --i;
+       } else {
+           if (console)
+               printk("%c", c);
+           ct = 0;
+       }
        buf_access();
-       if ( console && (*p != '\r'))
-               printk("%c", *p);
-       ct = 0;
-       if ( *p == '\n')
-               ct = 1;
-       *sccd = *p++;
-       if ( ct )
-               xmon_write(handle, "\r", 1);
+       *sccd = c;
     }
     return i;
 }
@@ -199,23 +213,30 @@ xmon_read(void *handle, void *ptr, int nb)
            if (adb_hardware == ADB_VIAPMU)
                pmu_poll();
        buf_access();
-#if 0  
-       if ( 0/*console*/ )
-               *p++ = ppc_md.kbd_getkeycode();
-       else
-#endif         
-               *p++ = *sccd;
+       *p++ = *sccd;
     }
     return i;
 }
 
+int
+xmon_read_poll(void)
+{
+       if ((*sccc & RXRDY) == 0) {
+               if (adb_hardware == ADB_VIAPMU)
+                       pmu_poll();
+               return -1;
+       }
+       buf_access();
+       return *sccd;
+}
+
 static unsigned char scc_inittab[] = {
     13, 0,             /* set baud rate divisor */
     12, 1,
     14, 1,             /* baud rate gen enable, src=rtxc */
     11, 0x50,          /* clocks = br gen */
-    5,  0x6a,          /* tx 8 bits, assert RTS */
-    4,  0x44,          /* x16 clock, 1 stop */
+    5,  0xea,          /* tx 8 bits, assert DTR & RTS */
+    4,  0x46,          /* x16 clock, 1 stop */
     3,  0xc1,          /* rx enable, 8 bits */
 };
 
@@ -235,6 +256,21 @@ xmon_init_scc()
        {
                int i, x;
 
+               if (macio_node != 0) {
+                       unsigned int t0;
+
+                       feature_set(macio_node, FEATURE_Serial_enable);
+                       if (via_modem) {
+                               feature_set(macio_node, FEATURE_Modem_power);
+                               t0 = readtb();
+                               while (readtb() - t0 < 3*TB_SPEED)
+                                       eieio();
+                       }
+               }
+               if (xmon_use_sccb) {
+                       sccc -= 0x20;
+                       sccd -= 0x20;
+               }
                for (i = 20000; i != 0; --i) {
                        x = *sccc; eieio();
                }
@@ -246,6 +282,18 @@ xmon_init_scc()
                }
        }
        scc_initialized = 1;
+       if (via_modem) {
+               for (;;) {
+                       xmon_write(0, "ATE1V1\r", 7);
+                       if (xmon_expect("OK", 5)) {
+                               xmon_write(0, "ATA\r", 4);
+                               if (xmon_expect("CONNECT", 40))
+                                       break;
+                       }
+                       xmon_write(0, "+++", 3);
+                       xmon_expect("OK", 3);
+               }
+       }
 }
 
 #if 0
@@ -318,6 +366,35 @@ static char line[256];
 static char *lineptr;
 static int lineleft;
 
+int xmon_expect(const char *str, unsigned int timeout)
+{
+       int c;
+       unsigned int t0;
+
+       timeout *= TB_SPEED;
+       t0 = readtb();
+       do {
+               lineptr = line;
+               for (;;) {
+                       c = xmon_read_poll();
+                       if (c == -1) {
+                               if (readtb() - t0 > timeout) {
+                                       printk("timeout\n");
+                                       return 0;
+                               }
+                               continue;
+                       }
+                       if (c == '\n')
+                               break;
+                       printk("%c", c);
+                       if (c != '\r' && lineptr < &line[sizeof(line) - 1])
+                               *lineptr++ = c;
+               }
+               *lineptr = 0;
+       } while (strstr(line, str) == NULL);
+       return 1;
+}
+
 int
 xmon_getchar(void)
 {
index 07bafd543c06bf948fed381e3fed24a33ddf8f0b..1f3ee859e9538ad360d111193d654023b7642b3f 100644 (file)
@@ -37,6 +37,12 @@ unsigned long pci_dvma_mask = 0xffffffffUL;
 unsigned long pci_dvma_v2p_hash[PCI_DVMA_HASHSZ];
 unsigned long pci_dvma_p2v_hash[PCI_DVMA_HASHSZ];
 
+/* If this is non-NULL it points to Sabre's DMA write-sync register
+ * which is used by drivers of devices behind bridges other than APB
+ * to synchronize DMA write streams with interrupt delivery.
+ */
+volatile u64 *pci_dma_wsync = NULL;
+
 #ifndef CONFIG_PCI
 
 int pcibios_present(void)
@@ -300,6 +306,8 @@ void __init sabre_init(int pnode)
                prom_halt();
        }
 
+       pci_dma_wsync = &sabre->psycho_regs->pci_dma_wsync;
+
        printk("PCI: Found SABRE, main regs at %p CTRL[%016lx]\n",
               sabre->psycho_regs, sabre->psycho_regs->control);
 #ifdef PROM_DEBUG
index 9a5e5cec0b9ca98c6d5b2e358faf6d98586311a5..3fd6b4c1e8ed0310d5ae4806a7a37b5ae19036f6 100644 (file)
@@ -43,6 +43,7 @@
 #endif
 #ifdef CONFIG_PCI
 #include <asm/ebus.h>
+#include <asm/pbm.h>
 #endif
 #include <asm/a.out.h>
 #include <asm/svr4.h>
@@ -193,6 +194,7 @@ EXPORT_SYMBOL(outsl);
 EXPORT_SYMBOL(insb);
 EXPORT_SYMBOL(insw);
 EXPORT_SYMBOL(insl);
+EXPORT_SYMBOL(pci_dma_wsync);
 #endif
 
 /* Solaris/SunOS binary compatibility */
index 28415078077c9dc1c53b0bd95d8c906da2960e8f..802d311b4248fc896c7fe1046e4c4c357718c937 100644 (file)
@@ -2066,11 +2066,11 @@ int ide_cdrom_get_last_session (struct cdrom_device_info *cdi,
        struct request_sense sense;
        int ret;
 
-       toc = info->toc;
-       if (!CDROM_STATE_FLAGS(drive)->toc_valid || toc == NULL)
+       if (!CDROM_STATE_FLAGS(drive)->toc_valid || info->toc == NULL)
                if ((ret = cdrom_read_toc(drive, &sense)))
                        return ret;
 
+       toc = info->toc;
        ms_info->addr.lba = toc->last_session_lba;
        ms_info->xa_flag = toc->xa_flag;
 
index 0c0b80e1157e6de30006a8e5a61525df9c9cf530..9f4c7cbb69d6b6429afdfdbbe549af5fd2496047 100644 (file)
@@ -590,6 +590,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
 
        case KDGETKEYCODE:
        case KDSETKEYCODE:
+               if(!suser())
+                       perm=0;
                return do_kbkeycode_ioctl(cmd, (struct kbkeycode *)arg, perm);
 
        case KDGKBENT:
index 0c98ace54b5dec4c76a422ed3f9a7ec9ea0027f0..7c2b45fd439c50e7300f71da51f6177c8d7056f6 100644 (file)
@@ -170,9 +170,9 @@ void adb_init(void)
        
        if (adb_controller == NULL)
                printk(KERN_WARNING "Warning: no ADB interface detected\n");
-       else
-       {
+       else {
                adb_hardware = adb_controller->kind;
+               
 #ifdef CONFIG_PMAC_PBOOK
                pmu_register_sleep_notifier(&adb_sleep_notifier);
 #endif /* CONFIG_PMAC_PBOOK */
@@ -194,6 +194,8 @@ adb_notify_sleep(struct pmu_sleep_notifier *self, int when)
        switch (when) {
        case PBOOK_SLEEP_REQUEST:
                adb_got_sleep = 1;
+               if (adb_controller->autopoll)
+                       adb_controller->autopoll(0);
                ret = notifier_call_chain(&adb_client_list, ADB_MSG_POWERDOWN, NULL);
                if (ret & NOTIFY_STOP_MASK)
                        return PBOOK_SLEEP_REFUSE;
@@ -209,6 +211,7 @@ adb_notify_sleep(struct pmu_sleep_notifier *self, int when)
                break;
        case PBOOK_WAKE:
                adb_reset_bus();
+               adb_got_sleep = 0;
                break;
        }
        return PBOOK_SLEEP_OK;
@@ -218,15 +221,21 @@ adb_notify_sleep(struct pmu_sleep_notifier *self, int when)
 int
 adb_reset_bus(void)
 {
-       int ret, devs;
+       int ret, nret, devs;
        unsigned long flags;
        
        if (adb_controller == NULL)
                return -ENXIO;
                
-       ret = notifier_call_chain(&adb_client_list, ADB_MSG_PRE_RESET, NULL);
-       if (ret & NOTIFY_STOP_MASK)
+       if (adb_controller->autopoll)
+               adb_controller->autopoll(0);
+
+       nret = notifier_call_chain(&adb_client_list, ADB_MSG_PRE_RESET, NULL);
+       if (nret & NOTIFY_STOP_MASK) {
+               if (adb_controller->autopoll)
+                       adb_controller->autopoll(devs);
                return -EBUSY;
+       }
 
        save_flags(flags);
        cli();
@@ -238,18 +247,17 @@ adb_reset_bus(void)
        else
                ret = 0;
 
-       if (!ret)
-       {
+       if (!ret) {
                devs = adb_scan_bus();
                if (adb_controller->autopoll)
                        adb_controller->autopoll(devs);
        }
 
-       ret = notifier_call_chain(&adb_client_list, ADB_MSG_POST_RESET, NULL);
-       if (ret & NOTIFY_STOP_MASK)
+       nret = notifier_call_chain(&adb_client_list, ADB_MSG_POST_RESET, NULL);
+       if (nret & NOTIFY_STOP_MASK)
                return -EBUSY;
        
-       return 1;
+       return ret;
 }
 
 void
@@ -327,6 +335,12 @@ adb_input(unsigned char *buf, int nb, struct pt_regs *regs, int autopoll)
        int i, id;
        static int dump_adb_input = 0;
 
+       /* We skip keystrokes and mouse moves when the sleep process
+        * has been started. We stop autopoll, but this is another security
+        */
+       if (adb_got_sleep)
+               return;
+               
        id = buf[0] >> 4;
        if (dump_adb_input) {
                printk(KERN_INFO "adb packet: ");
@@ -347,12 +361,8 @@ adb_try_handler_change(int address, int new_id)
 
        if (adb_handler[address].handler_id == new_id)
            return 1;
-       adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
-           ADB_READREG(address,3));
-       if (req.reply_len < 2)
-           return 0;
        adb_request(&req, NULL, ADBREQ_SYNC, 3,
-           ADB_WRITEREG(address, 3), req.reply[1] & 0xF0, new_id);     
+           ADB_WRITEREG(address, 3), address | 0x20, new_id);
        adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
            ADB_READREG(address, 3));
        if (req.reply_len < 2)
@@ -423,7 +433,7 @@ static int adb_open(struct inode *inode, struct file *file)
 {
        struct adbdev_state *state;
 
-       if (MINOR(inode->i_rdev) > 0 || (adb_controller == NULL)/*adb_hardware == ADB_NONE*/)
+       if (MINOR(inode->i_rdev) > 0 || (adb_controller == NULL))
                return -ENXIO;
        state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL);
        if (state == 0)
@@ -554,10 +564,11 @@ static ssize_t adb_write(struct file *file, const char *buf,
        /* Special case for ADB_BUSRESET request, all others are sent to
           the controller */
        if ((req->data[0] == ADB_PACKET)&&(count > 1)
-               &&(req->data[1] == ADB_BUSRESET))
+               &&(req->data[1] == ADB_BUSRESET)) {
                ret = adb_reset_bus();
-       else
-       {       
+               atomic_dec(&state->n_pending);
+               goto out;
+       } else {        
                req->reply_expected = ((req->data[1] & 0xc) == 0xc);
 
                if (adb_controller && adb_controller->send_request)
index cf58421c28120ed5c4c25dded4af2c0493b2c0f1..ab90dcef6492707e7a138f5241e65ec874795df3 100644 (file)
@@ -24,6 +24,7 @@
  * - Hunter digital (NoHandsMouse)
  * - Kensignton TurboMouse 5 (needs testing)
  * - Mouse Systems A3 mice and trackballs <aidan@kublai.com>
+ * - MacAlly 2-buttons mouse (needs testing) <pochini@denise.shiny.it>
  *
  * To do:
  *
@@ -272,6 +273,7 @@ static struct adb_ids buttons_ids;
 #define ADBMOUSE_MICROSPEED    6       /* Microspeed mouse (&trackball ?), MacPoint */
 #define ADBMOUSE_TRACKBALLPRO  7       /* Trackball Pro (special buttons) */
 #define ADBMOUSE_MS_A3         8       /* Mouse systems A3 trackball (handler 3) */
+#define ADBMOUSE_MACALLY2      9       /* MacAlly 2-button mouse */
 
 static int adb_mouse_kinds[16];
 
@@ -490,6 +492,19 @@ mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll)
     data[3] = byyy bxxx Third button and fourth button.  Y is additional
              high bits of y-axis motion.  XY is additional
              high bits of x-axis motion.
+
+    MacAlly 2-button mouse protocol.
+
+    For MacAlly 2-button mouse protocol the data array will contain the
+    following values:
+
+               BITS    COMMENTS
+    data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
+    data[1] = bxxx xxxx Left button and x-axis motion.
+    data[2] = byyy yyyy Right button and y-axis motion.
+    data[3] = ???? ???? unknown
+    data[4] = ???? ???? unknown
+
   */
        struct kbd_struct *kbd;
 
@@ -521,6 +536,11 @@ mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll)
                data[2] = (data[2] & 0x7f) | ((data[3] & 0x02) << 6);
                data[3] = ((data[3] & 0x04) << 5);
                break;
+            case ADBMOUSE_MACALLY2:
+               data[3] = (data[2] & 0x80) ? 0x80 : 0x00;
+               data[2] |= 0x80;  /* Right button is mapped as button 3 */
+               nb=4;
+                break;
        }
 
        if (adb_mouse_interrupt_hook)
@@ -581,7 +601,7 @@ buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll)
        /* Ignore data from register other than 0 */
        if ((adb_hardware != ADB_VIAPMU) || (data[0] & 0x3) || (nb < 2))
                return;
-               
+
        switch (data[1]&0xf )
        {
                /* mute */
@@ -645,7 +665,6 @@ static int pending_led_end=0;
 
 static void real_mackbd_leds(unsigned char leds, int device)
 {
-
     if (led_request.complete) {
        adb_request(&led_request, leds_done, 0, 3,
                    ADB_WRITEREG(device, KEYB_LEDREG), 0xff,
@@ -705,21 +724,29 @@ __initfunc(void mackbd_init_hw(void))
        led_request.complete = 1;
 
        mackeyb_probe();
-       
+
        notifier_chain_register(&adb_client_list, &mackeyb_adb_notifier);
 }
 
 static int
 adb_message_handler(struct notifier_block *this, unsigned long code, void *x)
 {
+       unsigned long flags;
+
        switch (code) {
        case ADB_MSG_PRE_RESET:
        case ADB_MSG_POWERDOWN:
-               /* Add unregister_keyboard when merging with Paul Mackerras */
+               /* Stop the repeat timer. Autopoll is already off at this point */
+               save_flags(flags);
+               cli();
+               del_timer(&repeat_timer);
+               restore_flags(flags);
+
+               /* Stop pending led requests */
                while(!led_request.complete)
                        adb_poll();
                break;
-                       
+
        case ADB_MSG_POST_RESET:
                mackeyb_probe();
                break;
@@ -802,7 +829,7 @@ mackeyb_probe(void)
                    || (adb_mouse_kinds[id] == ADBMOUSE_MICROSPEED)) {
                        init_microspeed(id);
                } else if (adb_mouse_kinds[id] == ADBMOUSE_MS_A3) {
-                       init_ms_a3(id); 
+                       init_ms_a3(id);
                }  else if (adb_mouse_kinds[id] ==  ADBMOUSE_EXTENDED) {
                        /*
                         * Register 1 is usually used for device
@@ -825,6 +852,14 @@ mackeyb_probe(void)
                            (req.reply[1] == 0x4b) && (req.reply[2] == 0x4d) &&
                            (req.reply[3] == 0x4c) && (req.reply[4] == 0x31))
                                init_turbomouse(id);
+                       else if ((req.reply_len == 9) &&
+                           (req.reply[1] == 0x4b) && (req.reply[2] == 0x4f) &&
+                           (req.reply[3] == 0x49) && (req.reply[4] == 0x54)){
+                               if (adb_try_handler_change(id, 0x42)) {
+                                       printk("\nADB MacAlly 2-button mouse at %d, handler set to 0x42", id);
+                                       adb_mouse_kinds[id] = ADBMOUSE_MACALLY2;
+                               }
+                       }
                }
                printk("\n");
         }
@@ -833,7 +868,7 @@ mackeyb_probe(void)
 static void 
 init_trackpad(int id)
 {
-       struct adb_request req; 
+       struct adb_request req;
        unsigned char r1_buffer[8];
 
        printk(" (trackpad)");
@@ -886,9 +921,9 @@ static void
 init_trackball(int id)
 {
        struct adb_request req;
-       
+
        printk(" (trackman/mouseman)");
-       
+
        adb_mouse_kinds[id] = ADBMOUSE_TRACKBALL;
 
        adb_request(&req, NULL, ADBREQ_SYNC, 3,
@@ -924,7 +959,7 @@ init_turbomouse(int id)
         printk(" (TurboMouse 5)");
 
        adb_mouse_kinds[id] = ADBMOUSE_TURBOMOUSE5;
-       
+
        adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
 
        adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(3));
index dcca410d94c95be23e9b922f910f32e1a69fddf8..a1cc769c0e4cb0b75b5cf261dc29e0309bfc7eb2 100644 (file)
@@ -115,11 +115,6 @@ void macio_adb_init(void)
        out_8(&adb->intr_enb.r, DFB | TAG);
 
        adb_controller = &macio_controller;
-//     adb_hardware = ADB_MACIO;
-
-//     adb_send_request = macio_adb_send_request;
-//     adb_autopoll = macio_adb_autopoll;
-//     adb_reset_bus = macio_reset_bus;
 }
 
 static int macio_adb_autopoll(int devs)
index ea8a6f74df0a9a8759e8a38113bc4ea744d922c8..238360be99d3d6477e3e9998237c9fdcbd0a0895 100644 (file)
@@ -129,6 +129,22 @@ static int serial_refcount;
 
 #define _INLINE_ inline
 
+#ifdef SERIAL_DEBUG_OPEN
+#define OPNDBG(fmt, arg...)    printk(KERN_INFO fmt , ## arg)
+#else
+#define OPNDBG(fmt, arg...)    do { } while (0)
+#endif
+#ifdef SERIAL_DEBUG_POWER
+#define PWRDBG(fmt, arg...)    printk(KERN_INFO fmt , ## arg)
+#else
+#define PWRDBG(fmt, arg...)    do { } while (0)
+#endif
+#ifdef SERIAL_DEBUG_BAUDS
+#define BAUDBG(fmt, arg...)    printk(KERN_INFO fmt , ## arg)
+#else
+#define BAUDBG(fmt, arg...)    do { } while (0)
+#endif
+
 static void probe_sccs(void);
 static void change_speed(struct mac_serial *info, struct termios *old);
 static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
@@ -318,7 +334,7 @@ static void dbdma_reset(volatile struct dbdma_regs *dma)
         * to it. - paulus)
         */
        for (i = 200; i > 0; --i)
-               if (ld_le32(&dma->control) & RUN)
+               if (ld_le32(&dma->status) & RUN)
                        udelay(1);
 }
 
@@ -398,7 +414,7 @@ static _INLINE_ void receive_chars(struct mac_serial *info,
                        continue;
                if (tty->flip.count >= TTY_FLIPBUF_SIZE)
                        tty_flip_buffer_push(tty);
-                       
+
                if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
                        static int flip_buf_ovf;
                        if (++flip_buf_ovf <= 1)
@@ -489,7 +505,7 @@ static _INLINE_ void status_handle(struct mac_serial *info)
                        if (info->tx_stopped) {
 #ifdef SERIAL_DEBUG_FLOW
                                printk("CTS up\n");
-#endif                 
+#endif
                                info->tx_stopped = 0;
                                if (!info->tx_active)
                                        transmit_chars(info);
@@ -497,7 +513,7 @@ static _INLINE_ void status_handle(struct mac_serial *info)
                } else {
 #ifdef SERIAL_DEBUG_FLOW
                        printk("CTS down\n");
-#endif                 
+#endif
                        info->tx_stopped = 1;
                }
        }
@@ -520,7 +536,7 @@ static _INLINE_ void receive_special_dma(struct mac_serial *info)
            == virt_to_bus(info->rx_cmds[info->rx_cbuf] + 1))
                where -= in_le16(&info->rx->res_count);
        where--;
-       
+
        stat = read_zsreg(info->zs_channel, R1);
 
        flag = stat_to_flag(stat);
@@ -566,7 +582,7 @@ static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 #ifdef SERIAL_DEBUG_INTR
                printk("rs_interrupt: irq %d, zs_intreg 0x%x\n",
                       irq, (int)zs_intreg);
-#endif 
+#endif
 
                if ((zs_intreg & CHAN_IRQMASK) == 0)
                        break;
@@ -643,7 +659,7 @@ static void rs_stop(struct tty_struct *tty)
 
        if (serial_paranoia_check(info, tty->device, "rs_stop"))
                return;
-       
+
 #if 0
        save_flags(flags); cli();
        if (info->curregs[5] & TxENAB) {
@@ -659,7 +675,7 @@ static void rs_start(struct tty_struct *tty)
 {
        struct mac_serial *info = (struct mac_serial *)tty->driver_data;
        unsigned long flags;
-       
+
 #ifdef SERIAL_DEBUG_STOP
        printk("rs_start %ld....\n", 
               tty->ldisc.chars_in_buffer(tty));
@@ -667,7 +683,7 @@ static void rs_start(struct tty_struct *tty)
 
        if (serial_paranoia_check(info, tty->device, "rs_start"))
                return;
-       
+
        save_flags(flags); cli();
 #if 0
        if (info->xmit_cnt && info->xmit_buf && !(info->curregs[5] & TxENAB)) {
@@ -701,7 +717,7 @@ static void do_softint(void *private_)
 {
        struct mac_serial       *info = (struct mac_serial *) private_;
        struct tty_struct       *tty;
-       
+
        tty = info->tty;
        if (!tty)
                return;
@@ -719,14 +735,10 @@ static int startup(struct mac_serial * info, int can_sleep)
 {
        int delay;
 
-#ifdef SERIAL_DEBUG_OPEN
-       printk("startup() (ttyS%d, irq %d)\n", info->line, info->irq);
-#endif
+       OPNDBG("startup() (ttyS%d, irq %d)\n", info->line, info->irq);
  
        if (info->flags & ZILOG_INITIALIZED) {
-#ifdef SERIAL_DEBUG_OPEN
-               printk(" -> already inited\n");
-#endif
+               OPNDBG(" -> already inited\n");
                return 0;
        }
 
@@ -736,22 +748,17 @@ static int startup(struct mac_serial * info, int can_sleep)
                        return -ENOMEM;
        }
 
-#ifdef SERIAL_DEBUG_OPEN
-       printk("starting up ttyS%d (irq %d)...\n", info->line, info->irq);
-#endif
+       OPNDBG("starting up ttyS%d (irq %d)...\n", info->line, info->irq);
 
        delay = set_scc_power(info, 1);
-       
+
        setup_scc(info);
 
-#ifdef SERIAL_DEBUG_OPEN
-       printk("enabling IRQ on ttyS%d (irq %d)...\n", info->line, info->irq);
-#endif
+       OPNDBG("enabling IRQ on ttyS%d (irq %d)...\n", info->line, info->irq);
 
        info->flags |= ZILOG_INITIALIZED;
        enable_irq(info->irq);
        if (info->dma_initted) {
-//             enable_irq(info->tx_dma_irq);
                enable_irq(info->rx_dma_irq);
        }
 
@@ -874,8 +881,6 @@ static void dma_init(struct mac_serial * info)
        volatile struct dbdma_cmd *cd;
        unsigned char *p;
 
-//printk(KERN_DEBUG "SCC: dma_init\n");
-
        info->rx_nbuf = 8;
 
        /* various mem set up */
@@ -951,12 +956,10 @@ static void dma_init(struct mac_serial * info)
 static int setup_scc(struct mac_serial * info)
 {
        unsigned long flags;
-       
-#ifdef SERIAL_DEBUG_OPEN
-       printk("setting up ttys%d SCC...\n", info->line);
-#endif
 
-       save_flags(flags); cli(); /* Disable interrupts */      
+       OPNDBG("setting up ttys%d SCC...\n", info->line);
+
+       save_flags(flags); cli(); /* Disable interrupts */
 
        /*
         * Reset the chip.
@@ -987,7 +990,8 @@ static int setup_scc(struct mac_serial * info)
        /*
         * Turn on RTS and DTR.
         */
-       zs_rtsdtr(info, 1);
+       if (!info->is_irda)
+               zs_rtsdtr(info, 1);
 
        /*
         * Finally, enable sequencing and interrupts
@@ -1051,16 +1055,11 @@ static int setup_scc(struct mac_serial * info)
  */
 static void shutdown(struct mac_serial * info)
 {
-#ifdef SERIAL_DEBUG_OPEN
-       printk("Shutting down serial port %d (irq %d)....\n", info->line,
+       OPNDBG("Shutting down serial port %d (irq %d)....\n", info->line,
               info->irq);
-#endif
-       
+
        if (!(info->flags & ZILOG_INITIALIZED)) {
-#ifdef SERIAL_DEBUG_OPEN
-               printk("(already shutdown)\n");
-#endif
-       
+               OPNDBG("(already shutdown)\n");
                return;
        }
 
@@ -1124,86 +1123,63 @@ static int set_scc_power(struct mac_serial * info, int state)
        /* The timings looks strange but that's the ones MacOS seems
           to use for the internal modem. I think we can use a lot faster
           ones, at least whe not using the modem, this should be tested.
-        */                             
+        */
        if (state) {
-#ifdef SERIAL_DEBUG_POWER
-               printk(KERN_INFO "ttyS%02d: powering up hardware\n", info->line);
-#endif
+               PWRDBG("ttyS%02d: powering up hardware\n", info->line);
                if (feature_test(info->dev_node, FEATURE_Serial_enable) == 0) {
-                       feature_clear(info->dev_node, FEATURE_Serial_reset);
-                       mdelay(5);
                        feature_set(info->dev_node, FEATURE_Serial_enable);
+                       mdelay(10);
+                       feature_set(info->dev_node, FEATURE_Serial_reset);
+                       mdelay(15);
+                       feature_clear(info->dev_node, FEATURE_Serial_reset);
+                       mdelay(10);
                }
                if (info->zs_chan_a == info->zs_channel)
                        feature_set(info->dev_node, FEATURE_Serial_IO_A);
                else
                        feature_set(info->dev_node, FEATURE_Serial_IO_B);
-               delay = 1;
-               
+               delay = 10;
                if (info->is_cobalt_modem){
-                       feature_set(info->dev_node, FEATURE_Modem_Reset);
+                       mdelay(300);
+                       feature_set(info->dev_node, FEATURE_Modem_power);
                        mdelay(5);
-                       feature_clear(info->dev_node, FEATURE_Modem_Reset);
+                       feature_clear(info->dev_node, FEATURE_Modem_power);
+                       mdelay(10);
+                       feature_set(info->dev_node, FEATURE_Modem_power);
                        delay = 2500;   /* wait for 2.5s before using */
                }
 #ifdef CONFIG_PMAC_PBOOK
-               if (info->is_pwbk_ir)
+               if (info->is_irda)
                        pmu_enable_irled(1);
 #endif /* CONFIG_PMAC_PBOOK */
        } else {
-#ifdef SERIAL_DEBUG_POWER
-               printk(KERN_INFO "ttyS%02d: shutting down hardware\n", info->line);
-#endif
-#ifdef CONFIG_KGDB
-               if (info->kgdb_channel) {
-#ifdef SERIAL_DEBUG_POWER
-                       printk(KERN_INFO "        (canceled by KGDB)\n");
-#endif
-                       return 0;
-               }
-#endif
-#ifdef CONFIG_XMON
-               if (!info->is_cobalt_modem) {
-#ifdef SERIAL_DEBUG_POWER
-                       printk(KERN_INFO "        (canceled by XMON)\n");
-#endif
-                       return 0;
-               }
-#endif
+               PWRDBG("ttyS%02d: shutting down hardware\n", info->line);
                if (info->is_cobalt_modem) {
-#ifdef SERIAL_DEBUG_POWER
-                       printk(KERN_INFO "ttyS%02d: shutting down modem\n", info->line);
-#endif
-                       feature_set(info->dev_node, FEATURE_Modem_Reset);
-                       mdelay(15);
-                       feature_clear(info->dev_node, FEATURE_Modem_Reset);
-                       mdelay(25);
+                       PWRDBG("ttyS%02d: shutting down modem\n", info->line);
+                       feature_clear(info->dev_node, FEATURE_Modem_power);
+                       mdelay(10);
                }
 #ifdef CONFIG_PMAC_PBOOK
-               if (info->is_pwbk_ir)
+               if (info->is_irda)
                        pmu_enable_irled(0);
 #endif /* CONFIG_PMAC_PBOOK */
-                       
-               if (info->zs_chan_a == info->zs_channel) {
-#ifdef SERIAL_DEBUG_POWER
-                       printk(KERN_INFO "ttyS%02d: shutting down SCC channel A\n", info->line);
-#endif
+
+               if (info->zs_chan_a == info->zs_channel && !info->is_irda) {
+                       PWRDBG("ttyS%02d: shutting down SCC channel A\n", info->line);
                        feature_clear(info->dev_node, FEATURE_Serial_IO_A);
-               } else {
-#ifdef SERIAL_DEBUG_POWER
-                       printk(KERN_INFO "ttyS%02d: shutting down SCC channel B\n", info->line);
-#endif
+               } else if (!info->is_irda) {
+                       PWRDBG("ttyS%02d: shutting down SCC channel B\n", info->line);
                        feature_clear(info->dev_node, FEATURE_Serial_IO_B);
                }
                /* XXX for now, shut down SCC core only on powerbooks */
                if (is_powerbook
                    && !(feature_test(info->dev_node, FEATURE_Serial_IO_A) ||
                         feature_test(info->dev_node, FEATURE_Serial_IO_B))) {
-#ifdef SERIAL_DEBUG_POWER
-                       printk(KERN_INFO "ttyS%02d: shutting down SCC core\n", info->line);
-#endif
+                       PWRDBG("ttyS%02d: shutting down SCC core\n", info->line);
                        feature_set(info->dev_node, FEATURE_Serial_reset);
-                       mdelay(10);
+                       mdelay(15);
+                       feature_clear(info->dev_node, FEATURE_Serial_reset);
+                       mdelay(25);
                        feature_clear(info->dev_node, FEATURE_Serial_enable);
                        mdelay(5);
                }
@@ -1211,6 +1187,113 @@ static int set_scc_power(struct mac_serial * info, int state)
        return delay;
 }
 
+static void irda_rts_pulses(struct mac_serial *info, int w)
+{
+       unsigned long flags;
+
+       udelay(w);
+       save_flags(flags); cli();
+       write_zsreg(info->zs_channel, 5, Tx8 | TxENAB);
+       udelay(2);
+       write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
+       udelay(8);
+       write_zsreg(info->zs_channel, 5, Tx8 | TxENAB);
+       udelay(4);
+       write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
+       restore_flags(flags);
+}
+
+/*
+ * Set the irda codec on the imac to the specified baud rate.
+ */
+static void irda_setup(struct mac_serial *info)
+{
+       int code, speed, t;
+       unsigned long flags;
+
+       speed = info->tty->termios->c_cflag & CBAUD;
+       if (speed < B2400 || speed > B115200)
+               return;
+       code = 0x4d + B115200 - speed;
+
+       /* disable serial interrupts and receive DMA */
+       write_zsreg(info->zs_channel, 1, info->curregs[1] & ~0x9f);
+
+       /* wait for transmitter to drain */
+       t = 10000;
+       while ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0
+              || (read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) {
+               if (--t <= 0) {
+                       printk(KERN_ERR "transmitter didn't drain\n");
+                       return;
+               }
+               udelay(10);
+       }
+       udelay(100);
+
+       /* set to 8 bits, no parity, 19200 baud, RTS on, DTR off */
+       write_zsreg(info->zs_channel, 4, X16CLK | SB1);
+       write_zsreg(info->zs_channel, 11, TCBR | RCBR);
+       t = BPS_TO_BRG(19200, ZS_CLOCK/16);
+       write_zsreg(info->zs_channel, 12, t);
+       write_zsreg(info->zs_channel, 13, t >> 8);
+       write_zsreg(info->zs_channel, 14, BRENABL);
+       write_zsreg(info->zs_channel, 3, Rx8 | RxENABLE);
+       write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
+
+       /* set TxD low for ~104us and pulse RTS */
+       udelay(1000);
+       save_flags(flags); cli();
+       write_zsdata(info->zs_channel, 0xfe);
+       irda_rts_pulses(info, 150);
+       restore_flags(flags);
+       irda_rts_pulses(info, 180);
+       irda_rts_pulses(info, 50);
+       udelay(100);
+
+       /* assert DTR, wait 30ms, talk to the chip */
+       write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS | DTR);
+       udelay(30000);
+       while (read_zsreg(info->zs_channel, 0) & Rx_CH_AV)
+               read_zsdata(info->zs_channel);
+
+       write_zsdata(info->zs_channel, 1);
+       t = 1000;
+       while ((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) == 0) {
+               if (--t <= 0) {
+                       printk(KERN_ERR "irda_setup timed out on 1st byte\n");
+                       goto out;
+               }
+               udelay(10);
+       }
+       t = read_zsdata(info->zs_channel);
+       if (t != 4)
+               printk(KERN_ERR "irda_setup 1st byte = %x\n", t);
+
+       write_zsdata(info->zs_channel, code);
+       t = 1000;
+       while ((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) == 0) {
+               if (--t <= 0) {
+                       printk(KERN_ERR "irda_setup timed out on 2nd byte\n");
+                       goto out;
+               }
+               udelay(10);
+       }
+       t = read_zsdata(info->zs_channel);
+       if (t != code)
+               printk(KERN_ERR "irda_setup 2nd byte = %x (%x)\n", t, code);
+
+       /* Drop DTR again and do some more RTS pulses */
+ out:
+       udelay(100);
+       write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
+       irda_rts_pulses(info, 80);
+
+       /* We should be right to go now.  We assume that load_zsregs
+          will get called soon to load up the correct baud rate etc. */
+       info->curregs[5] = (info->curregs[5] | RTS) & ~DTR;
+       info->pendregs[5] = info->curregs[5];
+}
 
 /*
  * This routine is called to set the UART divisor registers to match
@@ -1218,7 +1301,6 @@ static int set_scc_power(struct mac_serial * info, int state)
  */
 static void change_speed(struct mac_serial *info, struct termios *old_termios)
 {
-       unsigned short port;
        unsigned cflag;
        int     bits;
        int     brg, baud;
@@ -1226,8 +1308,6 @@ static void change_speed(struct mac_serial *info, struct termios *old_termios)
 
        if (!info->tty || !info->tty->termios)
                return;
-       if (!(port = info->port))
-               return;
 
        cflag = info->tty->termios->c_cflag;
        baud = tty_get_baud_rate(info->tty);
@@ -1250,9 +1330,7 @@ static void change_speed(struct mac_serial *info, struct termios *old_termios)
        info->zs_baud = baud;
        info->clk_divisor = 16;
 
-#ifdef SERIAL_DEBUG_BAUDS
-       printk("set speed to %d bds, ", baud);
-#endif
+       BAUDBG("set speed to %d bds, ", baud);
 
        switch (baud) {
        case ZS_CLOCK/16:       /* 230400 */
@@ -1279,34 +1357,26 @@ static void change_speed(struct mac_serial *info, struct termios *old_termios)
        case CS5:
                info->curregs[3] |= Rx5;
                info->curregs[5] |= Tx5;
-#ifdef SERIAL_DEBUG_BAUDS
-               printk("5 bits, ");
-#endif
+               BAUDBG("5 bits, ");
                bits = 7;
                break;
        case CS6:
                info->curregs[3] |= Rx6;
                info->curregs[5] |= Tx6;
-#ifdef SERIAL_DEBUG_BAUDS
-               printk("6 bits, ");
-#endif
+               BAUDBG("6 bits, ");
                bits = 8;
                break;
        case CS7:
                info->curregs[3] |= Rx7;
                info->curregs[5] |= Tx7;
-#ifdef SERIAL_DEBUG_BAUDS
-               printk("7 bits, ");
-#endif
+               BAUDBG("7 bits, ");
                bits = 9;
                break;
        case CS8:
        default: /* defaults to 8 bits */
                info->curregs[3] |= Rx8;
                info->curregs[5] |= Tx8;
-#ifdef SERIAL_DEBUG_BAUDS
-               printk("8 bits, ");
-#endif
+               BAUDBG("8 bits, ");
                bits = 10;
                break;
        }
@@ -1317,21 +1387,15 @@ static void change_speed(struct mac_serial *info, struct termios *old_termios)
        if (cflag & CSTOPB) {
                info->curregs[4] |= SB2;
                bits++;
-#ifdef SERIAL_DEBUG_BAUDS
-               printk("2 stop, ");
-#endif
+               BAUDBG("2 stop, ");
        } else {
                info->curregs[4] |= SB1;
-#ifdef SERIAL_DEBUG_BAUDS
-               printk("1 stop, ");
-#endif
+               BAUDBG("1 stop, ");
        }
        if (cflag & PARENB) {
                bits++;
                info->curregs[4] |= PAR_ENA;
-#ifdef SERIAL_DEBUG_BAUDS
-               printk("parity, ");
-#endif
+               BAUDBG("parity, ");
        }
        if (!(cflag & PARODD)) {
                info->curregs[4] |= PAR_EVEN;
@@ -1361,9 +1425,12 @@ static void change_speed(struct mac_serial *info, struct termios *old_termios)
        info->timeout = ((info->xmit_fifo_size*HZ*bits) / baud);
        info->timeout += HZ/50+1;       /* Add .02 seconds of slop */
 
-#ifdef SERIAL_DEBUG_BAUDS
-       printk("timeout=%d/%ds, base:%d\n", (int)info->timeout, (int)HZ, (int)info->baud_base);
-#endif
+       BAUDBG("timeout=%d/%ds, base:%d\n", (int)info->timeout, (int)HZ,
+              (int)info->baud_base);
+
+       /* set the irda codec to the right rate */
+       if (info->is_irda)
+               irda_setup(info);
 
        /* Load up the new values */
        load_zsregs(info->zs_channel, info->curregs);
@@ -1431,7 +1498,7 @@ static int rs_write(struct tty_struct * tty, int from_user,
        } else {
                while (1) {
                        save_flags(flags);
-                       cli();          
+                       cli();
                        c = MIN(count,
                                MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
                                    SERIAL_XMIT_SIZE - info->xmit_head));
@@ -1459,7 +1526,7 @@ static int rs_write_room(struct tty_struct *tty)
 {
        struct mac_serial *info = (struct mac_serial *)tty->driver_data;
        int     ret;
-                               
+
        if (serial_paranoia_check(info, tty->device, "rs_write_room"))
                return 0;
        ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
@@ -1471,7 +1538,7 @@ static int rs_write_room(struct tty_struct *tty)
 static int rs_chars_in_buffer(struct tty_struct *tty)
 {
        struct mac_serial *info = (struct mac_serial *)tty->driver_data;
-                               
+
        if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
                return 0;
        return info->xmit_cnt;
@@ -1481,7 +1548,7 @@ static void rs_flush_buffer(struct tty_struct *tty)
 {
        struct mac_serial *info = (struct mac_serial *)tty->driver_data;
        unsigned long flags;
-                               
+
        if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
                return;
        save_flags(flags); cli();
@@ -1507,13 +1574,13 @@ static void rs_throttle(struct tty_struct * tty)
        struct mac_serial *info = (struct mac_serial *)tty->driver_data;
        unsigned long flags;
 #ifdef SERIAL_DEBUG_THROTTLE
-       
+
        printk("throttle %ld....\n",tty->ldisc.chars_in_buffer(tty));
 #endif
 
        if (serial_paranoia_check(info, tty->device, "rs_throttle"))
                return;
-       
+
        if (I_IXOFF(tty)) {
                save_flags(flags); cli();
                info->x_char = STOP_CHAR(tty);
@@ -1543,13 +1610,13 @@ static void rs_unthrottle(struct tty_struct * tty)
        struct mac_serial *info = (struct mac_serial *)tty->driver_data;
        unsigned long flags;
 #ifdef SERIAL_DEBUG_THROTTLE
-       
+
        printk("unthrottle %s: %d....\n",tty->ldisc.chars_in_buffer(tty));
 #endif
 
        if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
                return;
-       
+
        if (I_IXOFF(tty)) {
                save_flags(flags); cli();
                if (info->x_char)
@@ -1726,8 +1793,6 @@ static void rs_break(struct tty_struct *tty, int break_state)
 
        if (serial_paranoia_check(info, tty->device, "rs_break"))
                return;
-       if (!info->port)
-               return;
 
        save_flags(flags); cli();
        if (break_state == -1)
@@ -1755,7 +1820,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
                if (tty->flags & (1 << TTY_IO_ERROR))
                    return -EIO;
        }
-       
+
        switch (cmd) {
                case TIOCMGET:
                        return get_modem_info(info, (unsigned int *) arg);
@@ -1777,7 +1842,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
                                         info, sizeof(struct mac_serial)))
                                return -EFAULT;
                        return 0;
-                       
+
                default:
                        return -ENOIOCTLCMD;
                }
@@ -1816,18 +1881,16 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
 
        if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
                return;
-       
+
        save_flags(flags); cli();
-       
+
        if (tty_hung_up_p(filp)) {
                MOD_DEC_USE_COUNT;
                restore_flags(flags);
                return;
        }
-       
-#ifdef SERIAL_DEBUG_OPEN
-       printk("rs_close ttys%d, count = %d\n", info->line, info->count);
-#endif
+
+       OPNDBG("rs_close ttys%d, count = %d\n", info->line, info->count);
        if ((tty->count == 1) && (info->count != 1)) {
                /*
                 * Uh, oh.  tty->count is 1, which means that the tty
@@ -1863,9 +1926,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
         * Now we wait for the transmit buffer to clear; and we notify 
         * the line discipline to only process XON/XOFF characters.
         */
-#ifdef SERIAL_DEBUG_OPEN
-       printk("waiting end of Tx... (timeout:%d)\n", info->closing_wait);
-#endif
+       OPNDBG("waiting end of Tx... (timeout:%d)\n", info->closing_wait);
        tty->closing = 1;
        if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE) {
                restore_flags(flags);
@@ -1889,9 +1950,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
                 * Before we drop DTR, make sure the SCC transmitter
                 * has completely drained.
                 */
-#ifdef SERIAL_DEBUG_OPEN
-               printk("waiting end of Rx...\n");
-#endif
+               OPNDBG("waiting end of Rx...\n");
                restore_flags(flags);
                rs_wait_until_sent(tty, info->timeout);
                save_flags(flags); cli();
@@ -2031,7 +2090,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
                info->flags |= ZILOG_CALLOUT_ACTIVE;
                return 0;
        }
-       
+
        /*
         * If non-blocking mode is set, or the port is not enabled,
         * then make the check up front and then exit.
@@ -2051,7 +2110,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
                if (tty->termios->c_cflag & CLOCAL)
                        do_clocal = 1;
        }
-       
+
        /*
         * Block waiting for the carrier detect and the line to become
         * free (i.e., not in use by the callout).  While we are in
@@ -2061,10 +2120,8 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
         */
        retval = 0;
        add_wait_queue(&info->open_wait, &wait);
-#ifdef SERIAL_DEBUG_OPEN
-       printk("block_til_ready before block: ttys%d, count = %d\n",
+       OPNDBG("block_til_ready before block: ttys%d, count = %d\n",
               info->line, info->count);
-#endif
        cli();
        if (!tty_hung_up_p(filp)) 
                info->count--;
@@ -2073,7 +2130,8 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
        while (1) {
                cli();
                if (!(info->flags & ZILOG_CALLOUT_ACTIVE) &&
-                   (tty->termios->c_cflag & CBAUD))
+                   (tty->termios->c_cflag & CBAUD) &&
+                   !info->is_irda)
                        zs_rtsdtr(info, 1);
                sti();
                current->state = TASK_INTERRUPTIBLE;
@@ -2083,7 +2141,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
                        if (info->flags & ZILOG_HUP_NOTIFY)
                                retval = -EAGAIN;
                        else
-                               retval = -ERESTARTSYS;  
+                               retval = -ERESTARTSYS;
 #else
                        retval = -EAGAIN;
 #endif
@@ -2097,10 +2155,8 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
                        retval = -ERESTARTSYS;
                        break;
                }
-#ifdef SERIAL_DEBUG_OPEN
-               printk("block_til_ready blocking: ttys%d, count = %d\n",
+               OPNDBG("block_til_ready blocking: ttys%d, count = %d\n",
                       info->line, info->count);
-#endif
                schedule();
        }
        current->state = TASK_RUNNING;
@@ -2108,15 +2164,13 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
        if (!tty_hung_up_p(filp))
                info->count++;
        info->blocked_open--;
-#ifdef SERIAL_DEBUG_OPEN
-       printk("block_til_ready after blocking: ttys%d, count = %d\n",
+       OPNDBG("block_til_ready after blocking: ttys%d, count = %d\n",
               info->line, info->count);
-#endif
        if (retval)
                return retval;
        info->flags |= ZILOG_NORMAL_ACTIVE;
        return 0;
-}      
+}
 
 /*
  * This routine is called whenever a serial port is opened.  It
@@ -2146,10 +2200,8 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
 #endif
        if (serial_paranoia_check(info, tty->device, "rs_open"))
                return -ENODEV;
-#ifdef SERIAL_DEBUG_OPEN
-       printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
+       OPNDBG("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
               info->count);
-#endif
 
        info->count++;
        tty->driver_data = info;
@@ -2190,10 +2242,8 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
 
        retval = block_til_ready(tty, filp, info);
        if (retval) {
-#ifdef SERIAL_DEBUG_OPEN
-               printk("rs_open returning after block_til_ready with %d\n",
+               OPNDBG("rs_open returning after block_til_ready with %d\n",
                        retval);
-#endif
                return retval;
        }
 
@@ -2215,9 +2265,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
        info->session = current->session;
        info->pgrp = current->pgrp;
 
-#ifdef SERIAL_DEBUG_OPEN
-       printk("rs_open ttys%d successful...\n", info->line);
-#endif
+       OPNDBG("rs_open ttys%d successful...\n", info->line);
        return 0;
 }
 
@@ -2239,6 +2287,10 @@ chan_init(struct mac_serial *zss, struct mac_zschannel *zs_chan,
        struct device_node *ch = zss->dev_node;
        char *conn;
        int len;
+       struct slot_names_prop {
+               int     count;
+               char    name[1];
+       } *slots;
 
        zss->irq = ch->intrs[0].line;
        zss->has_dma = 0;
@@ -2263,7 +2315,11 @@ chan_init(struct mac_serial *zss, struct mac_zschannel *zs_chan,
        /* XXX tested only with wallstreet PowerBook,
           should do no harm anyway */
        conn = get_property(ch, "AAPL,connector", &len);
-       zss->is_pwbk_ir = conn && (strcmp(conn, "infrared") == 0);
+       zss->is_irda = conn && (strcmp(conn, "infrared") == 0);
+       /* 1999 Powerbook G3 has slot-names property instead */
+       slots = (struct slot_names_prop *)get_property(ch, "slot-names", &len);
+       if (slots && slots->count > 0 && strcmp(slots->name, "IrDA") == 0)
+               zss->is_irda = 1;
 
        if (zss->has_dma) {
                zss->dma_priv = NULL;
@@ -2453,7 +2509,7 @@ int macserial_init(void)
                zs_soft[channel].clk_divisor = 16;
 /* -- we are not sure the SCC is powered ON at this point
                zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
-*/             
+*/
                zs_soft[channel].zs_baud = 38400;
 
                /* If console serial line, then enable interrupts. */
@@ -2504,20 +2560,17 @@ int macserial_init(void)
                        printk(", port = %s", connector);
                if (info->is_cobalt_modem)
                        printk(" (cobalt modem)");
-               if (info->is_pwbk_ir)
-                       printk(" (powerbook IR)");
+               if (info->is_irda)
+                       printk(" (IrDA)");
                printk("\n");
 
+#ifndef CONFIG_XMON
 #ifdef CONFIG_KGDB
-               if (info->kgdb_channel)
-                       continue;
-#endif                 
-#ifdef CONFIG_XMON
-               if (!info->is_cobalt_modem)
-                       continue;
-#endif                 
-               /* By default, disable the port */
-               set_scc_power(info, 0);
+               if (!info->kgdb_channel)
+#endif /* CONFIG_KGDB */
+                       /* By default, disable the port */
+                       set_scc_power(info, 0);
+#endif /* CONFIG_XMON */
        }
        tmp_buf = 0;
 
@@ -2613,7 +2666,7 @@ static void serial_console_write(struct console *co, const char *s,
                        while ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP)
                                 == 0)
                                eieio();
-                       
+
                        write_zsdata(info->zs_channel, 13);
                }
        }
@@ -2922,7 +2975,7 @@ __initfunc(void zs_kgdb_hook(int tty_num))
                probe_sccs();
 
        set_scc_power(&zs_soft[tty_num], 1);
-       
+
        zs_kgdbchan = zs_soft[tty_num].zs_channel;
        zs_soft[tty_num].change_needed = 0;
        zs_soft[tty_num].clk_divisor = 16;
@@ -2944,12 +2997,12 @@ int
 serial_notify_sleep(struct pmu_sleep_notifier *self, int when)
 {
        int i;
-       
+
        switch (when) {
        case PBOOK_SLEEP_REQUEST:
        case PBOOK_SLEEP_REJECT:
                break;
-               
+
        case PBOOK_SLEEP_NOW:
                for (i=0; i<zs_channels_found; i++) {
                        struct mac_serial *info = &zs_soft[i];
index 188589d1955d1a3f5cff5bc518e093eca299689e..26e28ead0aa58b1e2c0ae46b9d9d578a6b9fe1e9 100644 (file)
@@ -111,7 +111,7 @@ struct mac_serial {
        char kgdb_channel;  /* Kgdb is running on this channel */
        char is_cons;       /* Is this our console. */
        char is_cobalt_modem;   /* is a gatwick-based cobalt modem */
-       char is_pwbk_ir;        /* is connected to an IR led on powerbooks */
+       char is_irda;           /* is connected to an IrDA codec */
        unsigned char tx_active; /* character is being xmitted */
        unsigned char tx_stopped; /* output is suspended */
 
index 08094fcf6933366c0905031d98d076b667f75937..2f0a420c7d3341323ba62215b384a98092b01c1a 100644 (file)
@@ -3,6 +3,8 @@
  *
  * Copyright (C) 1998 Paul Mackerras.
  *
+ * Various evolutions by Benjamin Herrenschmidt & Henry Worth
+ *
  *  This program is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU General Public License
  *  as published by the Free Software Foundation; either version
@@ -38,6 +40,14 @@ static struct pmu_sleep_notifier mb_sleep_notifier = {
 #endif
 
 #undef MB_USE_INTERRUPTS
+#undef MB_DEBUG
+#define MB_IGNORE_SIGNALS
+
+#ifdef MB_DEBUG
+#define MBDBG(fmt, arg...)     printk(KERN_INFO fmt , ## arg)
+#else
+#define MBDBG(fmt, arg...)     do { } while (0)
+#endif
 
 struct media_bay_hw {
        unsigned char   b0;
@@ -48,18 +58,20 @@ struct media_bay_hw {
 
 struct media_bay_info {
        volatile struct media_bay_hw*   addr;
+       volatile u8*                    extint_gpio;
        int                             content_id;
-       int                             previous_id;
-       int                             ready;
+       int                             state;
        int                             last_value;
        int                             value_count;
-       int                             reset_timer;
+       int                             timer;
        struct device_node*             dev_node;
+       int                             pismo;  /* New PowerBook3,1 */
+       int                             gpio_cache;
 #ifdef CONFIG_BLK_DEV_IDE
        unsigned long                   cd_base;
        int                             cd_index;
        int                             cd_irq;
-       int                             cd_timer;
+       int                             cd_retry;
 #endif
 };
 
@@ -68,42 +80,102 @@ struct media_bay_info {
 static volatile struct media_bay_info media_bays[MAX_BAYS];
 int media_bay_count = 0;
 
-#define MB_CONTENTS(i) ((in_8(&media_bays[i].addr->contents) >> 4) & 7)
+inline int mb_content(volatile struct media_bay_info *bay)
+{
+        if (bay->pismo) {
+                unsigned char new_gpio = in_8(bay->extint_gpio + 0xe) & 2;
+                if (new_gpio) {
+                       bay->gpio_cache = new_gpio;
+                        return MB_NO;
+                } else if (bay->gpio_cache != new_gpio) {
+                        /* make sure content bits are set */
+                        feature_set(bay->dev_node, FEATURE_Mediabay_content);
+                        udelay(5);
+                        bay->gpio_cache = new_gpio;
+                }
+                return (in_le32((unsigned*)bay->addr) >> 4) & 0xf;
+        } else {
+                int cont = (in_8(&bay->addr->contents) >> 4) & 7;
+                return (cont == 7) ? MB_NO : cont;
+        }
+}
 
 #ifdef CONFIG_BLK_DEV_IDE
 /* check the busy bit in the media-bay ide interface
    (assumes the media-bay contains an ide device) */
+//#define MB_IDE_READY(i)      ((inb(media_bays[i].cd_base + 0x70) & 0xc0) == 0x40)
 #define MB_IDE_READY(i)        ((inb(media_bays[i].cd_base + 0x70) & 0x80) == 0)
 #endif
 
+/* Note: All delays are not in milliseconds and converted to HZ relative
+ * values by the macro below
+ */
+#define MS_TO_HZ(ms)   ((ms * HZ) / 1000)
+
 /*
  * Consider the media-bay ID value stable if it is the same for
- * this many consecutive samples (at intervals of 1/HZ seconds).
+ * this number of milliseconds
+ */
+#define MB_STABLE_DELAY        40
+
+/* Wait after powering up the media bay this delay in ms
+ * timeout bumped for some powerbooks
  */
-#define MB_STABLE_COUNT        4
+#define MB_POWER_DELAY 200
 
 /*
  * Hold the media-bay reset signal true for this many ticks
  * after a device is inserted before releasing it.
  */
-#define MB_RESET_COUNT 40
+#define MB_RESET_DELAY 40
+
+/*
+ * Wait this long after the reset signal is released and before doing
+ * further operations. After this delay, the IDE reset signal is released
+ * too for an IDE device
+ */
+#define MB_SETUP_DELAY 100
 
 /*
  * Wait this many ticks after an IDE device (e.g. CD-ROM) is inserted
- * (or until the device is ready) before registering the IDE interface.
+ * (or until the device is ready) before waiting for busy bit to disappear
+ */
+#define MB_IDE_WAIT    1000
+
+/*
+ * Timeout waiting for busy bit of an IDE device to go down
+ */
+#define MB_IDE_TIMEOUT 5000
+
+/*
+ * Max retries of the full power up/down sequence for an IDE device
  */
-#define MB_IDE_WAIT    1500
+#define MAX_CD_RETRIES 3
 
 /*
- * Wait at least this many ticks after resetting an IDE device before
- * believing its ready bit.
+ * States of a media bay
  */
-#define MB_IDE_MINWAIT 250
+enum {
+       mb_empty = 0,           /* Idle */
+       mb_powering_up,         /* power bit set, waiting MB_POWER_DELAY */
+       mb_enabling_bay,        /* enable bits set, waiting MB_RESET_DELAY */
+       mb_resetting,           /* reset bit unset, waiting MB_SETUP_DELAY */
+       mb_ide_resetting,       /* IDE reset bit unser, waiting MB_IDE_WAIT */
+       mb_ide_waiting,         /* Waiting for BUSY bit to go away until MB_IDE_TIMEOUT */
+       mb_up,                  /* Media bay full */
+       mb_powering_down        /* Powering down (avoid too fast down/up) */
+};
 
 static void poll_media_bay(int which);
 static void set_media_bay(int which, int id);
+static void set_mb_power(int which, int onoff);
+static void media_bay_step(int i);
 static int media_bay_task(void *);
 
+#ifdef MB_USE_INTERRUPTS
+static void media_bay_intr(int irq, void *devid, struct pt_regs *regs);
+#endif
+
 /*
  * It seems that the bit for the media-bay interrupt in the IRQ_LEVEL
  * register is always set when there is something in the media bay.
@@ -120,56 +192,69 @@ media_bay_init(void)
 {
        struct device_node *np;
        int             n,i;
-       
-       for (i=0; i<MAX_BAYS; i++)
-       {
+
+       for (i=0; i<MAX_BAYS; i++) {
                memset((char *)&media_bays[i], 0, sizeof(struct media_bay_info));
                media_bays[i].content_id        = -1;
 #ifdef CONFIG_BLK_DEV_IDE
                media_bays[i].cd_index          = -1;
 #endif
        }
-       
+
        np = find_devices("media-bay");
        n = 0;
-       while(np && (n<MAX_BAYS))
-       {
+       while(np && (n<MAX_BAYS)) {
                if (np->n_addrs == 0)
                        continue;
                media_bays[n].addr = (volatile struct media_bay_hw *)
                        ioremap(np->addrs[0].address, sizeof(struct media_bay_hw));
 
+               media_bays[n].pismo = device_is_compatible(np, "keylargo-media-bay");
+               if (media_bays[n].pismo) {
+                       if (!np->parent || strcmp(np->parent->name, "mac-io")) {
+                               printk(KERN_ERR "Pismo media-bay has no mac-io parent !\n");
+                               continue;
+                       }
+                       media_bays[n].extint_gpio = ioremap(np->parent->addrs[0].address
+                               + 0x58, 0x10);
+               }
+
 #ifdef MB_USE_INTERRUPTS
-               if (np->n_intrs == 0)
-               {
+               if (np->n_intrs == 0) {
                        printk(KERN_ERR "media bay %d has no irq\n",n);
                        continue;
                }
-               
-               if (request_irq(np_intrs[0].line, media_bay_intr, 0, "Media bay", NULL))
-               {
-                       printk(KERN_ERR "Couldn't get IRQ %d for media bay %d\n", irq, n);
+
+               if (request_irq(np->intrs[0].line, media_bay_intr, 0, "Media bay", (void *)n)) {
+                       printk(KERN_ERR "Couldn't get IRQ %d for media bay %d\n",
+                               np->intrs[0].line, n);
                        continue;
                }
-#endif 
+#endif
                media_bay_count++;
-       
-               set_media_bay(n, MB_CONTENTS(n));
-               if (media_bays[n].content_id != MB_NO) {
-                       feature_clear(media_bays[n].dev_node, FEATURE_Mediabay_reset);
-                       udelay(500);
-               }
-               media_bays[n].ready             = 1;
-               media_bays[n].previous_id       = media_bays[n].content_id;
-               media_bays[n].reset_timer       = 0;
+
                media_bays[n].dev_node          = np;
-#ifdef CONFIG_BLK_DEV_IDE
-               media_bays[n].cd_timer          = 0;
-#endif
+
+               /* Force an immediate detect */
+               set_mb_power(n,0);
+               mdelay(MB_POWER_DELAY);
+               if(!media_bays[n].pismo)
+                       out_8(&media_bays[n].addr->contents, 0x70);
+               mdelay(MB_STABLE_DELAY);
+               media_bays[n].content_id = MB_NO;
+               media_bays[n].last_value = mb_content(&media_bays[n]);
+               media_bays[n].value_count = MS_TO_HZ(MB_STABLE_DELAY);
+               media_bays[n].state = mb_empty;
+               do {
+                       mdelay(1000/HZ);
+                       media_bay_step(n);
+               } while((media_bays[n].state != mb_empty) &&
+                       (media_bays[n].state != mb_up));
+
                n++;
                np=np->next;
        }
-       
+
        if (media_bay_count)
        {
                printk(KERN_INFO "Registered %d media-bay(s)\n", media_bay_count);
@@ -178,21 +263,83 @@ media_bay_init(void)
                pmu_register_sleep_notifier(&mb_sleep_notifier);
 #endif /* CONFIG_PMAC_PBOOK */
 
-               kernel_thread(media_bay_task, NULL, 0);
+               kernel_thread(media_bay_task, NULL,
+                             CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
        }
 }
 
-#if 0
+#ifdef MB_USE_INTERRUPTS
 static void
 media_bay_intr(int irq, void *devid, struct pt_regs *regs)
 {
-       int id = MB_CONTENTS();
-
-       if (id == MB_NO)
-               set_media_bay(id);
 }
 #endif
 
+static void
+set_mb_power(int which, int onoff)
+{
+       volatile struct media_bay_info* mb = &media_bays[which];
+
+       if (onoff) {
+               feature_set(mb->dev_node, FEATURE_Mediabay_power);
+               udelay(10);
+               feature_set(mb->dev_node, FEATURE_Mediabay_reset);
+               udelay(10);
+               mb->state = mb_powering_up;
+               MBDBG("mediabay%d: powering up\n", which);
+       } else {
+               feature_clear(mb->dev_node, FEATURE_Mediabay_floppy_enable);
+               if (mb->pismo)
+                       feature_clear(mb->dev_node, FEATURE_IDE0_enable);
+               else
+                       feature_clear(mb->dev_node, FEATURE_IDE1_enable);
+               feature_clear(mb->dev_node, FEATURE_Mediabay_IDE_switch);
+               feature_clear(mb->dev_node, FEATURE_Mediabay_PCI_enable);
+               feature_clear(mb->dev_node, FEATURE_SWIM3_enable);
+               feature_clear(mb->dev_node, FEATURE_Mediabay_power);
+               mb->state = mb_powering_down;
+               MBDBG("mediabay%d: powering down\n", which);
+       }
+       mb->timer = MS_TO_HZ(MB_POWER_DELAY);
+}
+
+static void
+set_media_bay(int which, int id)
+{
+       volatile struct media_bay_info* bay;
+
+       bay = &media_bays[which];
+
+       switch (id) {
+       case MB_CD:
+               if (bay->pismo) {
+                       feature_set(bay->dev_node, FEATURE_Mediabay_IDE_switch);
+                       udelay(10);
+                       feature_set(bay->dev_node, FEATURE_IDE0_enable);
+                       udelay(10);
+                       feature_set(bay->dev_node, FEATURE_IDE0_reset);
+               } else {
+                       feature_set(bay->dev_node, FEATURE_IDE1_enable);
+                       udelay(10);
+                       feature_set(bay->dev_node, FEATURE_IDE1_reset);
+               }
+               printk(KERN_INFO "media bay %d contains a CD-ROM drive\n", which);
+               break;
+       case MB_FD:
+       case MB_FD1:
+               feature_set(bay->dev_node, FEATURE_Mediabay_floppy_enable);
+               feature_set(bay->dev_node, FEATURE_SWIM3_enable);
+               printk(KERN_INFO "media bay %d contains a floppy disk drive\n", which);
+               break;
+       case MB_NO:
+               break;
+       default:
+               printk(KERN_INFO "media bay %d contains an unknown device (%d)\n",
+                      which, id);
+               break;
+       }
+}
+
 int
 check_media_bay(struct device_node *which_bay, int what)
 {
@@ -202,7 +349,7 @@ check_media_bay(struct device_node *which_bay, int what)
        for (i=0; i<media_bay_count; i++)
                if (which_bay == media_bays[i].dev_node)
                {
-                       if ((what == media_bays[i].content_id) && media_bays[i].ready)
+                       if ((what == media_bays[i].content_id) && media_bays[i].state == mb_up)
                                return 0;
                        media_bays[i].cd_index = -1;
                        return -EINVAL;
@@ -220,13 +367,13 @@ check_media_bay_by_base(unsigned long base, int what)
        for (i=0; i<media_bay_count; i++)
                if (base == media_bays[i].cd_base)
                {
-                       if ((what == media_bays[i].content_id) && media_bays[i].ready)
+                       if ((what == media_bays[i].content_id) && media_bays[i].state == mb_up)
                                return 0;
                        media_bays[i].cd_index = -1;
                        return -EINVAL;
                } 
 #endif
-       
+
        return -ENODEV;
 }
 
@@ -240,17 +387,138 @@ media_bay_set_ide_infos(struct device_node* which_bay, unsigned long base,
        for (i=0; i<media_bay_count; i++)
                if (which_bay == media_bays[i].dev_node)
                {
+                       int timeout = 5000;
+
                        media_bays[i].cd_base   = base;
                        media_bays[i].cd_irq    = irq;
-                       media_bays[i].cd_index  = index;
-                       printk(KERN_DEBUG "Registered ide %d for media bay %d\n", index, i);                    
-                       return 0;
+
+                       if ((MB_CD != media_bays[i].content_id) || media_bays[i].state != mb_up)
+                               return 0;
+
+                       printk(KERN_DEBUG "Registered ide %d for media bay %d\n", index, i);
+                       do {
+                               if (MB_IDE_READY(i)) {
+                                       media_bays[i].cd_index  = index;
+                                       return 0;
+                               }
+                               mdelay(1);
+                       } while(--timeout);
+                       printk(KERN_DEBUG "Timeount waiting IDE in bay %d\n", i);
+                       return -ENODEV;
                } 
 #endif
-       
+
        return -ENODEV;
 }
 
+static void
+media_bay_step(int i)
+{
+       volatile struct media_bay_info* bay = &media_bays[i];
+
+       /* We don't poll when powering down */
+       if (bay->state != mb_powering_down)
+           poll_media_bay(i);
+
+       /* If timer expired or polling IDE busy, run state machine */
+       if ((bay->state != mb_ide_waiting) && (bay->timer != 0) && ((--bay->timer) != 0))
+           return;
+
+       switch(bay->state) {
+       case mb_powering_up:
+               set_media_bay(i, bay->last_value);
+               bay->timer = MS_TO_HZ(MB_RESET_DELAY);
+               bay->state = mb_enabling_bay;
+               MBDBG("mediabay%d: enabling (kind:%d)\n", i, bay->content_id);
+               break;
+       case mb_enabling_bay:
+               feature_clear(bay->dev_node, FEATURE_Mediabay_reset);
+               bay->timer = MS_TO_HZ(MB_SETUP_DELAY);
+               bay->state = mb_resetting;
+               MBDBG("mediabay%d: waiting reset (kind:%d)\n", i, bay->content_id);
+               break;
+           
+       case mb_resetting:
+               if (bay->content_id != MB_CD) {
+                       MBDBG("mediabay%d: bay is up (kind:%d)\n", i, bay->content_id);
+                       bay->state = mb_up;
+                       break;
+               }
+#ifdef CONFIG_BLK_DEV_IDE
+               MBDBG("mediabay%d: waiting IDE reset (kind:%d)\n", i, bay->content_id);
+               if (bay->pismo)
+                       feature_clear(bay->dev_node, FEATURE_IDE0_reset);
+               else
+                       feature_clear(bay->dev_node, FEATURE_IDE1_reset);
+               bay->timer = MS_TO_HZ(MB_IDE_WAIT);
+               bay->state = mb_ide_resetting;
+#else
+               printk(KERN_DEBUG "media-bay %d is ide (not compiled in kernel)\n", i);
+               set_mb_power(i, 0);
+#endif // #ifdef CONFIG_BLK_DEV_IDE
+               break;
+           
+#ifdef CONFIG_BLK_DEV_IDE
+       case mb_ide_resetting:
+               bay->timer = MS_TO_HZ(MB_IDE_TIMEOUT);
+               bay->state = mb_ide_waiting;
+               MBDBG("mediabay%d: waiting IDE ready (kind:%d)\n", i, bay->content_id);
+               break;
+           
+       case mb_ide_waiting:
+               if (bay->cd_base == 0) {
+                       bay->timer = 0;
+                       bay->state = mb_up;
+                       MBDBG("mediabay%d: up before IDE init\n", i);
+                       break;
+               } else if (MB_IDE_READY(i)) {
+                       bay->timer = 0;
+                       bay->state = mb_up;
+                       if (bay->cd_index < 0)
+                               bay->cd_index = ide_register(bay->cd_base, 0, bay->cd_irq);
+                       if (bay->cd_index == -1) {
+                               /* We eventually do a retry */
+                               bay->cd_retry++;
+                               printk("IDE register error\n");
+                               set_mb_power(i, 0);
+                       } else {
+                               printk(KERN_DEBUG "media-bay %d is ide %d\n", i, bay->cd_index);
+                               MBDBG("mediabay %d IDE ready\n", i);
+                       }
+                       break;
+               }
+               if (bay->timer == 0) {
+                       printk("\nIDE Timeout in bay %d !\n", i);
+                       MBDBG("mediabay%d: nIDE Timeout !\n", i);
+                       set_mb_power(i, 0);
+               }
+               break;
+#endif // #ifdef CONFIG_BLK_DEV_IDE
+
+       case mb_powering_down:
+               bay->state = mb_empty;
+#ifdef CONFIG_BLK_DEV_IDE
+               if (bay->cd_index >= 0) {
+                       printk(KERN_DEBUG "Unregistering mb %d ide, index:%d\n", i,
+                              bay->cd_index);
+                       ide_unregister(bay->cd_index);
+                       bay->cd_index = -1;
+               }
+               if (bay->cd_retry) {
+                       if (bay->cd_retry > MAX_CD_RETRIES) {
+                               /* Should add an error sound (sort of beep in dmasound) */
+                               printk("\nmedia-bay %d, IDE device badly inserted or unrecognised\n", i);
+                       } else {
+                               /* Force a new power down/up sequence */
+                               bay->content_id = MB_NO;
+                       }
+               }
+#endif     
+               MBDBG("mediabay%d: end of power down\n", i);
+               break;
+       }
+}
+
 /*
  * This procedure runs as a kernel thread to poll the media bay
  * once each tick and register and unregister the IDE interface
@@ -260,128 +528,57 @@ media_bay_set_ide_infos(struct device_node* which_bay, unsigned long base,
 int
 media_bay_task(void *x)
 {
-       volatile struct media_bay_info* bay;
        int     i = 0;
-       
+
        strcpy(current->comm, "media-bay");
-       for (;;)
-       {
-               bay = &media_bays[i];
-               poll_media_bay(i);
-               if (bay->content_id != bay->previous_id) {
-                       bay->reset_timer = (bay->content_id != MB_NO) ?
-                               MB_RESET_COUNT: 0;
-                       bay->ready = 0;
-#ifdef CONFIG_BLK_DEV_IDE
-                       bay->cd_timer = 0;
-                       if (bay->content_id != MB_CD && bay->cd_index >= 0) {
-                               printk(KERN_DEBUG "Unregistering mb %d ide, index:%d\n", i, bay->cd_index);
-                               ide_unregister(bay->cd_index);
-                               bay->cd_index = -1;
-                       }
+#ifdef MB_IGNORE_SIGNALS
+       sigfillset(&current->blocked);
 #endif
-               } else if (bay->reset_timer) {
-                       if (--bay->reset_timer == 0) {
-                               feature_clear(bay->dev_node, FEATURE_Mediabay_reset);
-                               bay->ready = 1;
-#ifdef CONFIG_BLK_DEV_IDE
-                               bay->cd_timer = 0;
-                               if (bay->content_id == MB_CD && bay->cd_base != 0)
-                                       bay->cd_timer = MB_IDE_WAIT;
-#endif
-                       }
-#ifdef CONFIG_BLK_DEV_IDE
-               } else if (bay->cd_timer
-                          && (--bay->cd_timer == 0
-                              || (bay->cd_timer < MB_IDE_WAIT - MB_IDE_MINWAIT
-                                  && MB_IDE_READY(i)))
-                          && bay->cd_index < 0) {
-                       bay->cd_timer = 0;
-                       printk(KERN_DEBUG "Registering IDE, base:0x%08lx, irq:%d\n", bay->cd_base, bay->cd_irq);
-                       printk("\n");
-                       bay->cd_index = ide_register(bay->cd_base, 0, bay->cd_irq);
-                       if (bay->cd_index == -1)
-                               printk("\nCD-ROM badly inserted. Remove it and try again !\n");
-                       else
-                               printk(KERN_DEBUG "media-bay %d is ide %d\n", i, bay->cd_index);
-#endif
-               }
 
-               bay->previous_id = bay->content_id;
-               if (++i >= media_bay_count) {
-                       i = 0;
-                       current->state = TASK_INTERRUPTIBLE;
-                       schedule_timeout(1);
-                       if (signal_pending(current))
-                               return 0;
-               }
+       for (;;) {
+           media_bay_step(i);
+
+           if (++i >= media_bay_count) {
+               i = 0;
+               current->state = TASK_INTERRUPTIBLE;
+               schedule_timeout(1);
+               if (signal_pending(current))
+                   return 0;
+           }
        }
 }
 
 void
 poll_media_bay(int which)
 {
-       int id = MB_CONTENTS(which);
+       volatile struct media_bay_info* bay = &media_bays[which];
+       int id = mb_content(bay);
 
-       if (id == media_bays[which].last_value) {
-           if (id != media_bays[which].content_id
-               && ++media_bays[which].value_count >= MB_STABLE_COUNT) {
+       if (id == bay->last_value) {
+           if (id != bay->content_id
+               && ++bay->value_count >= MS_TO_HZ(MB_STABLE_DELAY)) {
                /* If the device type changes without going thru "MB_NO", we force
                   a pass by "MB_NO" to make sure things are properly reset */
-               if ((id != MB_NO) && (media_bays[which].content_id != MB_NO)) {
-                   set_media_bay(which, MB_NO);
-                   udelay(500);
+               if ((id != MB_NO) && (bay->content_id != MB_NO)) {
+                   id = MB_NO;
+                   MBDBG("mediabay%d: forcing MB_NO\n", which);
+               }
+               MBDBG("mediabay%d: switching to %d\n", which, id);
+               set_mb_power(which, id != MB_NO);
+               bay->content_id = id;
+               if (id == MB_NO) {
+#ifdef CONFIG_BLK_DEV_IDE
+                   bay->cd_retry = 0;
+#endif
+                   printk(KERN_INFO "media bay %d is empty\n", which);
                }
-               set_media_bay(which, id);
            }
        } else {
-               media_bays[which].last_value = id;
-               media_bays[which].value_count = 0;
+               bay->last_value = id;
+               bay->value_count = 0;
        }
 }
 
-static void
-set_media_bay(int which, int id)
-{
-       volatile struct media_bay_info* bay;
-
-       bay = &media_bays[which];
-       
-       bay->content_id = id;
-       bay->last_value = id;
-       
-       switch (id) {
-       case MB_CD:
-               feature_set(bay->dev_node, FEATURE_Mediabay_enable);
-               feature_set(bay->dev_node, FEATURE_Mediabay_IDE_enable);
-               udelay(500);
-               feature_set(bay->dev_node, FEATURE_CD_power);
-               printk(KERN_INFO "media bay %d contains a CD-ROM drive\n", which);
-               break;
-       case MB_FD:
-               feature_set(bay->dev_node, FEATURE_Mediabay_enable);
-               feature_set(bay->dev_node, FEATURE_Mediabay_floppy_enable);
-               feature_set(bay->dev_node, FEATURE_SWIM3_enable);
-               printk(KERN_INFO "media bay %d contains a floppy disk drive\n", which);
-               break;
-       case MB_NO:
-               feature_clear(bay->dev_node, FEATURE_CD_power);
-               feature_clear(bay->dev_node, FEATURE_Mediabay_enable);
-               feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable);
-               feature_clear(bay->dev_node, FEATURE_Mediabay_IDE_enable);
-               feature_clear(bay->dev_node, FEATURE_SWIM3_enable);
-               feature_set(bay->dev_node, FEATURE_Mediabay_reset);
-               printk(KERN_INFO "media bay %d is empty\n", which);
-               break;
-       default:
-               feature_set(bay->dev_node, FEATURE_Mediabay_enable);
-               printk(KERN_INFO "media bay %d contains an unknown device (%d)\n",
-                      which, id);
-               break;
-       }
-       
-       udelay(500);
-}
 
 #ifdef CONFIG_PMAC_PBOOK
 /*
@@ -392,51 +589,44 @@ mb_notify_sleep(struct pmu_sleep_notifier *self, int when)
 {
        volatile struct media_bay_info* bay;
        int i;
-       
+
        switch (when) {
        case PBOOK_SLEEP_REQUEST:
        case PBOOK_SLEEP_REJECT:
                break;
-               
+
        case PBOOK_SLEEP_NOW:
                for (i=0; i<media_bay_count; i++) {
                        bay = &media_bays[i];
-                       feature_clear(bay->dev_node, FEATURE_Mediabay_enable);
-                       feature_clear(bay->dev_node, FEATURE_Mediabay_IDE_enable);
-                       feature_clear(bay->dev_node, FEATURE_SWIM3_enable);
-                       feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable);
-                       feature_set(bay->dev_node, FEATURE_Mediabay_reset);
-                       feature_clear(bay->dev_node, FEATURE_CD_power);
-                       out_8(&media_bays[i].addr->contents, 0x70);
+                       set_mb_power(i, 0);
+                       mdelay(10);
+                       feature_clear(bay->dev_node, FEATURE_IOBUS_enable);
                }
                break;
        case PBOOK_WAKE:
                for (i=0; i<media_bay_count; i++) {
                        bay = &media_bays[i];
-                       feature_set(bay->dev_node, FEATURE_Mediabay_enable);
-                       /* I suppose this is enough delay to stabilize MB_CONTENT ... */
-                       mdelay(10);
                        /* We re-enable the bay using it's previous content
-                          only if it did not change */
-                       if (MB_CONTENTS(i) != bay->content_id)
-                               continue;
-                       set_media_bay(i, bay->content_id);
-                       if (bay->content_id == MB_NO)
+                          only if it did not change. Note those bozo timings,
+                          they seem to help the 3400 get it right.
+                        */
+                       feature_set(bay->dev_node, FEATURE_IOBUS_enable);
+                       mdelay(MB_STABLE_DELAY);
+                       if (!bay->pismo)
+                               out_8(&bay->addr->contents, 0x70);
+                       mdelay(MB_STABLE_DELAY);
+                       if (mb_content(bay) != bay->content_id)
                                continue;
-                       mdelay(400);
-                       /* Clear the bay reset */
-                       feature_clear(bay->dev_node, FEATURE_Mediabay_reset);
-                       /* This small delay makes sure the device has time
-                          to assert the BUSY bit (used by IDE sleep) */
-                       udelay(100);
-                       /* We reset the state machine timers in case we were
-                          in the middle of a wait loop */
-                       if (bay->reset_timer)
-                               bay->reset_timer = MB_RESET_COUNT;
-#ifdef CONFIG_BLK_DEV_IDE
-                       if (bay->cd_timer)
-                               bay->cd_timer = MB_IDE_WAIT;
-#endif
+                       set_mb_power(i, 1);
+                       bay->last_value = bay->content_id;
+                       bay->value_count = MS_TO_HZ(MB_STABLE_DELAY);
+                       bay->timer = MS_TO_HZ(MB_POWER_DELAY);
+                       bay->cd_retry = 0;
+                       do {
+                               mdelay(1000/HZ);
+                               media_bay_step(i);
+                       } while((media_bays[i].state != mb_empty) &&
+                               (media_bays[i].state != mb_up));
                }
                break;
        }
index 0316b23400ea2485155b5ce754da4dde0a7eb4e7..25569d0b24d7cdf46e18965e7b2f5a5e9870b8da 100644 (file)
@@ -21,6 +21,7 @@
 #include <asm/pgtable.h>
 #include <asm/system.h>
 #include <asm/init.h>
+#include <asm/machdep.h>
 
 static volatile unsigned char *via;
 
@@ -496,4 +497,4 @@ int
 cuda_present(void)
 {
        return (adb_controller && (adb_controller->kind == ADB_VIACUDA) && via);
-}
\ No newline at end of file
+}
index ce8a2c3fd194cdbc514fe091b61ed539c2c7f178..9559c8b1800624ef28c4db93708557c16b3d73bd 100644 (file)
  * and the RTC (real time clock) chip.
  *
  * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi.
+ * 
+ * todo: - Check this driver for smp safety (new Core99 motherboards).
+ *       - Cleanup synchro between VIA interrupt and GPIO-based PMU
+ *         interrupt.
+ *
+ *
  */
 #include <stdarg.h>
 #include <linux/config.h>
@@ -39,7 +45,7 @@
 /* Misc minor number allocated for /dev/pmu */
 #define PMU_MINOR      154
 
-static volatile unsigned char *via;
+static volatile unsigned char *via = 0;
 
 /* VIA registers - spaced 0x200 bytes apart */
 #define RS             0x200           /* skip between registers */
@@ -91,16 +97,18 @@ static unsigned char interrupt_data[32];
 static unsigned char *reply_ptr;
 static int data_index;
 static int data_len;
-static int adb_int_pending;
+static volatile int adb_int_pending;
 static int pmu_adb_flags;
 static int adb_dev_map = 0;
 static struct adb_request bright_req_1, bright_req_2, bright_req_3;
 static struct device_node *vias;
 static int pmu_kind = PMU_UNKNOWN;
 static int pmu_fully_inited = 0;
+static int pmu_has_adb, pmu_has_backlight;
+static unsigned char *gpio_reg = NULL;
+static int gpio_irq;
 
 int asleep;
-struct notifier_block *sleep_notifier_list;
 
 static int init_pmu(void);
 static int pmu_queue_request(struct adb_request *req);
@@ -116,6 +124,7 @@ static void pmu_done(struct adb_request *req);
 static void pmu_handle_data(unsigned char *data, int len,
                            struct pt_regs *regs);
 static void set_volume(int level);
+static void gpio1_interrupt(int irq, void *arg, struct pt_regs *regs);
 #ifdef CONFIG_PMAC_PBOOK
 static void pmu_pass_intr(unsigned char *data, int len);
 #endif
@@ -186,6 +195,7 @@ static char *pbook_type[] = {
        "PowerBook 2400/3400/3500(G3)",
        "PowerBook G3 Series",
        "1999 PowerBook G3",
+       "Core99"
 };
 
 int __openfirmware
@@ -198,9 +208,6 @@ find_via_pmu()
                return 0;
        if (vias->next != 0)
                printk(KERN_WARNING "Warning: only using 1st via-pmu\n");
-       
-       feature_set(vias, FEATURE_VIA_enable);
-
 #if 0
        { int i;
 
@@ -213,13 +220,16 @@ find_via_pmu()
        printk("\n"); }
 #endif
 
-       if (vias->n_addrs != 1 || vias->n_intrs != 1) {
+       if (vias->n_addrs < 1 || vias->n_intrs < 1) {
                printk(KERN_ERR "via-pmu: %d addresses, %d interrupts!\n",
                       vias->n_addrs, vias->n_intrs);
                if (vias->n_addrs < 1 || vias->n_intrs < 1)
                        return 0;
        }
 
+       pmu_has_adb = 1;
+       pmu_has_backlight = 1;
+
        if (vias->parent->name && ((strcmp(vias->parent->name, "ohare") == 0)
            || device_is_compatible(vias->parent, "ohare")))
                pmu_kind = PMU_OHARE_BASED;
@@ -227,23 +237,29 @@ find_via_pmu()
                pmu_kind = PMU_PADDINGTON_BASED;
        else if (device_is_compatible(vias->parent, "heathrow"))
                pmu_kind = PMU_HEATHROW_BASED;
-       else
+       else if (device_is_compatible(vias->parent, "Keylargo")) {
+               pmu_kind = PMU_KEYLARGO_BASED;
+               pmu_has_adb = (find_type_devices("adb") != NULL);
+               pmu_has_backlight = (find_type_devices("backlight") != NULL);
+       } else
                pmu_kind = PMU_UNKNOWN;
 
        via = (volatile unsigned char *) ioremap(vias->addrs->address, 0x2000);
 
        out_8(&via[IER], IER_CLR | 0x7f);       /* disable all intrs */
+       out_8(&via[IFR], 0x7f);                 /* clear IFR */
 
        pmu_state = idle;
 
-       if (!init_pmu())
+       if (!init_pmu()) {
                via = NULL;
+               return 0;
+       }
 
        adb_controller = &pmu_controller;
 
-       if (via)
-               printk(KERN_INFO "PMU driver initialized for %s\n",
-                      pbook_type[pmu_kind]);
+       printk(KERN_INFO "PMU driver initialized for %s\n",
+              pbook_type[pmu_kind]);
 
        return via != 0;
 }
@@ -265,11 +281,28 @@ via_pmu_init(void)
                return;
        }
 
+       if (pmu_kind == PMU_KEYLARGO_BASED) {
+               struct device_node *gpio, *gpiop;
+
+               gpiop = find_devices("gpio");
+               if (gpiop && gpiop->n_addrs) {
+                       gpio_reg = ioremap(gpiop->addrs->address, 0x10);
+                       gpio = find_devices("extint-gpio1");
+                       if (gpio && gpio->parent == gpiop && gpio->n_intrs) {
+                               gpio_irq = gpio->intrs[0].line;
+                               if (request_irq(gpio_irq, gpio1_interrupt, 0,
+                                               "GPIO1/ADB", (void *)0))
+                                       printk(KERN_ERR "pmu: can't get irq %d (GPIO1)\n",
+                                              gpio->intrs[0].line);
+                       }
+               }
+       }
+
        /* Enable interrupts */
        out_8(&via[IER], IER_SET | SR_INT | CB1_INT);
 
        pmu_fully_inited = 1;
-       
+
        /* Enable backlight */
        pmu_enable_backlight(1);
 }
@@ -323,14 +356,13 @@ pmu_adb_send_request(struct adb_request *req, int sync)
 {
     int i, ret;
 
-    if ((vias == NULL) || (!pmu_fully_inited))
-    {
+    if ((vias == NULL) || (!pmu_fully_inited)) {
        req->complete = 1;
        return -ENXIO;
-   }
+    }
 
     ret = -EINVAL;
-       
+
     switch (req->data[0]) {
     case PMU_PACKET:
                for (i = 0; i < req->nbytes - 1; ++i)
@@ -372,6 +404,8 @@ pmu_adb_send_request(struct adb_request *req, int sync)
                }
                break;
     case ADB_PACKET:
+               if (!pmu_has_adb)
+                       return -ENXIO;
                for (i = req->nbytes - 1; i > 1; --i)
                        req->data[i+2] = req->data[i];
                req->data[3] = req->nbytes - 2;
@@ -389,7 +423,7 @@ pmu_adb_send_request(struct adb_request *req, int sync)
        req->complete = 1;
        return ret;
     }
-       
+    
     if (sync) {
        while (!req->complete)
                pmu_poll();
@@ -404,7 +438,7 @@ pmu_adb_autopoll(int devs)
 {
        struct adb_request req;
 
-       if ((vias == NULL) || (!pmu_fully_inited))
+       if ((vias == NULL) || (!pmu_fully_inited) || !pmu_has_adb)
                return -ENXIO;
 
        if (devs) {
@@ -426,10 +460,9 @@ static int __openfirmware
 pmu_adb_reset_bus(void)
 {
        struct adb_request req;
-       long timeout;
        int save_autopoll = adb_dev_map;
 
-       if ((vias == NULL) || (!pmu_fully_inited))
+       if ((vias == NULL) || (!pmu_fully_inited) || !pmu_has_adb)
                return -ENXIO;
 
        /* anyone got a better idea?? */
@@ -439,31 +472,21 @@ pmu_adb_reset_bus(void)
        req.done = NULL;
        req.data[0] = PMU_ADB_CMD;
        req.data[1] = 0;
-       req.data[2] = 3; /* ADB_BUSRESET ??? */
+       req.data[2] = ADB_BUSRESET; /* 3 ??? */
        req.data[3] = 0;
        req.data[4] = 0;
        req.reply_len = 0;
        req.reply_expected = 1;
-       if (pmu_queue_request(&req) != 0)
-       {
+       if (pmu_queue_request(&req) != 0) {
                printk(KERN_ERR "pmu_adb_reset_bus: pmu_queue_request failed\n");
                return -EIO;
        }
        while (!req.complete)
                pmu_poll();
-       timeout = 100000;
-       while (!req.complete) {
-               if (--timeout < 0) {
-                       printk(KERN_ERR "pmu_adb_reset_bus (reset): no response from PMU\n");
-                       return -EIO;
-               }
-               udelay(10);
-               pmu_poll();
-       }
 
        if (save_autopoll != 0)
                pmu_adb_autopoll(save_autopoll);
-               
+
        return 0;
 }
 
@@ -537,6 +560,8 @@ pmu_queue_request(struct adb_request *req)
        return 0;
 }
 
+/* New PMU seems to be very sensitive to those timings, so we make sure
+ * PCI is flushed immediately */
 static void __openfirmware
 send_byte(int x)
 {
@@ -545,6 +570,7 @@ send_byte(int x)
        out_8(&v[ACR], in_8(&v[ACR]) | SR_OUT | SR_EXT);
        out_8(&v[SR], x);
        out_8(&v[B], in_8(&v[B]) & ~TREQ);              /* assert TREQ */
+       (void)in_8(&v[B]);
 }
 
 static void __openfirmware
@@ -554,10 +580,11 @@ recv_byte()
 
        out_8(&v[ACR], (in_8(&v[ACR]) & ~SR_OUT) | SR_EXT);
        in_8(&v[SR]);           /* resets SR */
-       out_8(&v[B], in_8(&v[B]) & ~0x10);
+       out_8(&v[B], in_8(&v[B]) & ~TREQ);
+       (void)in_8(&v[B]);
 }
 
-static int disable_poll;
+static volatile int disable_poll;
 
 static void __openfirmware
 pmu_start()
@@ -594,7 +621,8 @@ pmu_poll()
        if (disable_poll)
                return;
        ie = _disable_interrupts();
-       if (via[IFR] & (SR_INT | CB1_INT))
+       if ((via[IFR] & (SR_INT | CB1_INT)) ||
+               (gpio_reg && (in_8(gpio_reg + 0x9) & 0x02) == 0))
                via_pmu_interrupt(0, 0, 0);
        _enable_interrupts(ie);
 }
@@ -604,7 +632,12 @@ via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
 {
        int intr;
        int nloop = 0;
+       unsigned long flags;
 
+       /* Currently, we use brute-force cli() for syncing with GPIO
+        * interrupt. I'll make this smarter later, along with some
+        * spinlocks for SMP */
+       save_flags(flags);cli();
        ++disable_poll;
        while ((intr = in_8(&via[IFR])) != 0) {
                if (++nloop > 1000) {
@@ -623,6 +656,9 @@ via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
                        out_8(&via[IFR], intr);
                }
        }
+       if (gpio_reg && (in_8(gpio_reg + 0x9) & 0x02) == 0)
+               adb_int_pending = 1;
+
        if (pmu_state == idle) {
                if (adb_int_pending) {
                        pmu_state = intack;
@@ -633,8 +669,15 @@ via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
                }
        }
        --disable_poll;
+       restore_flags(flags);
 }
 
+static void __openfirmware
+gpio1_interrupt(int irq, void *arg, struct pt_regs *regs)
+{
+       via_pmu_interrupt(0, 0, 0);
+ }
 static void __openfirmware
 pmu_sr_intr(struct pt_regs *regs)
 {
@@ -646,9 +689,17 @@ pmu_sr_intr(struct pt_regs *regs)
                out_8(&via[IFR], SR_INT);
                return;
        }
-       if (via[B] & TACK)
+       /* This one seems to appear with PMU99. According to OF methods,
+        * the protocol didn't change...
+        */
+       if (via[B] & TACK) {
+               while ((in_8(&via[B]) & TACK) != 0)
+                       ;
+#if 0
                printk(KERN_ERR "PMU: sr_intr but ack still high! (%x)\n",
                       via[B]);
+#endif
+       }
 
        /* reset TREQ and wait for TACK to go high */
        out_8(&via[B], in_8(&via[B]) | TREQ);
@@ -810,9 +861,9 @@ pmu_enable_backlight(int on)
 {
        struct adb_request req;
 
-       if (vias == NULL)
+       if ((vias == NULL) || !pmu_has_backlight)
                return;
-               
+
        /* first call: get current backlight value */
        if (on && backlight_level < 0) {
                switch (pmu_kind) {
@@ -831,6 +882,7 @@ pmu_enable_backlight(int on)
                        printk(KERN_DEBUG "pmu: nvram returned bright: %d\n", backlight_level);
                        break;
                case PMU_PADDINGTON_BASED:
+               case PMU_KEYLARGO_BASED:
                        /* the G3 PB 1999 has a backlight node
                           and chrp-structured nvram */
                        /* XXX should read macos's "blkt" property in nvram
@@ -861,7 +913,7 @@ pmu_set_brightness(int level)
 {
        int bright;
 
-       if (vias == NULL)
+       if ((vias == NULL) || !pmu_has_backlight)
                return ;
 
        backlight_level = level;
@@ -908,12 +960,12 @@ pmu_restart(void)
        struct adb_request req;
 
        _disable_interrupts();
-       
+
        pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB |
                                        PMU_INT_TICK );
        while(!req.complete)
                pmu_poll();
-       
+
        pmu_request(&req, NULL, 1, PMU_RESET);
        while(!req.complete || (pmu_state != idle))
                pmu_poll();
@@ -927,7 +979,7 @@ pmu_shutdown(void)
        struct adb_request req;
 
        _disable_interrupts();
-       
+
        pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB |
                                        PMU_INT_TICK );
        while(!req.complete)
@@ -944,7 +996,7 @@ pmu_shutdown(void)
 int
 pmu_present(void)
 {
-       return (adb_controller && (adb_controller->kind == ADB_VIAPMU) && vias);
+       return via != 0;
 }
 
 #ifdef CONFIG_PMAC_PBOOK
@@ -979,7 +1031,7 @@ pmu_unregister_sleep_notifier(struct pmu_sleep_notifier* n)
 
 /* Sleep is broadcast last-to-first */
 static int
-broadcast_sleep(int when, int can_cancel)
+broadcast_sleep(int when, int fallback)
 {
        int ret = PBOOK_SLEEP_OK;
        struct list_head *list;
@@ -989,8 +1041,15 @@ broadcast_sleep(int when, int can_cancel)
             list = list->prev) {
                current = list_entry(list, struct pmu_sleep_notifier, list);
                ret = current->notifier_call(current, when);
-               if (can_cancel && (ret != PBOOK_SLEEP_OK))
+               if (ret != PBOOK_SLEEP_OK) {
+                       printk(KERN_DEBUG "sleep %d rejected by %p (%p)\n",
+                              when, current, current->notifier_call);
+                       for (; list != &sleep_notifiers; list = list->next) {
+                               current = list_entry(list, struct pmu_sleep_notifier, list);
+                               current->notifier_call(current, fallback);
+                       }
                        return ret;
+               }
        }
        return ret;
 }
@@ -1127,9 +1186,8 @@ int __openfirmware powerbook_sleep_G3(void)
                        ioremap(macio->addrs[0].address, 0x40);
 
        /* Notify device drivers */
-       ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, 1);
+       ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT);
        if (ret != PBOOK_SLEEP_OK) {
-               broadcast_sleep(PBOOK_SLEEP_REJECT, 0);
                printk("pmu: sleep rejected\n");
                return -EBUSY;
        }
@@ -1142,7 +1200,12 @@ int __openfirmware powerbook_sleep_G3(void)
         * vmalloc's are done before actual sleep of block drivers */
        fsync_dev(0);
 
-       broadcast_sleep(PBOOK_SLEEP_NOW, 0);
+       /* Sleep can fail now. May not be very robust but useful for debugging */
+       ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE);
+       if (ret != PBOOK_SLEEP_OK) {
+               printk("pmu: sleep failed\n");
+               return -EBUSY;
+       }
 
        /* Give the disks a little time to actually finish writing */
        for (wait = jiffies + (HZ/4); time_before(jiffies, wait); )
@@ -1210,7 +1273,7 @@ int __openfirmware powerbook_sleep_G3(void)
        /* Restore L2 cache */
        if (save_l2cr)
                _set_L2CR(save_l2cr | 0x200000); /* set invalidate bit */
-       
+
        /* reenable interrupts */
        sleep_restore_intrs();
 
@@ -1231,9 +1294,8 @@ int __openfirmware powerbook_sleep_3400(void)
        struct adb_request sleep_req;
 
        /* Notify device drivers */
-       ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, 1);
+       ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT);
        if (ret != PBOOK_SLEEP_OK) {
-               broadcast_sleep(PBOOK_SLEEP_REJECT, 0);
                printk("pmu: sleep rejected\n");
                return -EBUSY;
        }
@@ -1246,7 +1308,12 @@ int __openfirmware powerbook_sleep_3400(void)
         * vmalloc's are done before actual sleep of block drivers */
        fsync_dev(0);
 
-       broadcast_sleep(PBOOK_SLEEP_NOW, 0);
+       /* Sleep can fail now. May not be very robust but useful for debugging */
+       ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE);
+       if (ret != PBOOK_SLEEP_OK) {
+               printk("pmu: sleep failed\n");
+               return -EBUSY;
+       }
 
        /* Give the disks a little time to actually finish writing */
        for (wait = jiffies + (HZ/4); time_before(jiffies, wait); )
@@ -1473,18 +1540,24 @@ static int pmu_ioctl(struct inode * inode, struct file *filp,
                        error = powerbook_sleep_G3();
                        break;
                default:
-                       error = ENOSYS;
+                       error = -ENOSYS;
                }
                return error;
        case PMU_IOC_GET_BACKLIGHT:
+               if (!pmu_has_backlight)
+                       return -ENOSYS;
                return put_user(backlight_level, (__u32 *)arg);
        case PMU_IOC_SET_BACKLIGHT:
+               if (!pmu_has_backlight)
+                       return -ENOSYS;
                error = get_user(value, (__u32 *)arg);
                if (!error)
                        pmu_set_brightness(value);
                return error;
        case PMU_IOC_GET_MODEL:
                return put_user(pmu_kind, (__u32 *)arg);
+       case PMU_IOC_HAS_ADB:
+               return put_user(pmu_has_adb, (__u32 *)arg);
        }
        return -EINVAL;
 }
@@ -1526,7 +1599,6 @@ static inline void polled_handshake(volatile unsigned char *via)
 
 static inline void polled_send_byte(volatile unsigned char *via, int x)
 {
-       xmon_printf("s%.2x", x);
        via[ACR] |= SR_OUT | SR_EXT; eieio();
        via[SR] = x; eieio();
        polled_handshake(via);
@@ -1540,7 +1612,6 @@ static inline int polled_recv_byte(volatile unsigned char *via)
        x = via[SR]; eieio();
        polled_handshake(via);
        x = via[SR]; eieio();
-       xmon_printf("r%.2x", x);
        return x;
 }
 
index dbb376dd232b80feaa4defd84858a7887b1c2546..8d66080f97d60a4530a998e45216d5fc2e095a41 100644 (file)
@@ -47,6 +47,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
   if [ "$CONFIG_PPC" = "y" ]; then
     tristate 'MACE (Power Mac ethernet) support' CONFIG_MACE
     tristate 'BMAC (G3 ethernet) support' CONFIG_BMAC
+    tristate 'GMAC (G4/iBook ethernet) support' CONFIG_GMAC
     tristate 'Symbios 53c885 (Synergy ethernet) support' CONFIG_NCR885E
   fi
   if [ "$CONFIG_ZORRO" = "y" ]; then
index 3983a614f74f27e19f2578faec7d5d7f39afb2b1..7b9856483ea24c2a2d4357aa4bcc43ae4f060374 100644 (file)
@@ -1253,6 +1253,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_GMAC),y)
+L_OBJS += gmac.o
+else
+  ifeq ($(CONFIG_GMAC),m)
+  M_OBJS += gmac.o
+  endif
+endif
+
 ifeq ($(CONFIG_NCR885E),y)
 L_OBJS += ncr885e.o
 else
index 740428ede00d4e61b90943e647e8db4cbf2cb804..2147b9b0649b8f66860378d4d32eaa1f79a33101 100644 (file)
@@ -103,6 +103,7 @@ extern int pamsnet_probe(struct device *);
 extern int tlan_probe(struct device *);
 extern int mace_probe(struct device *);
 extern int bmac_probe(struct device *);
+extern int gmac_probe(struct device *);
 extern int ncr885e_probe(struct device *);
 extern int cs89x0_probe(struct device *dev);
 extern int ethertap_probe(struct device *dev);
@@ -470,6 +471,9 @@ struct devprobe ppc_probes[] __initdata = {
 #ifdef CONFIG_BMAC
        {bmac_probe, 0},
 #endif
+#ifdef CONFIG_GMAC
+       {gmac_probe, 0},
+#endif
 #ifdef CONFIG_NCR885E
        {ncr885e_probe, 0},
 #endif
index 62a3f32e386dc130ebe082292b8c415b49ecacbd..0bd71464f6e5970917670ce136b6dd651f9cc912 100644 (file)
@@ -653,12 +653,20 @@ struct parameters {
 #define ALIGN64     ((u_long)64 - 1)    /* 16 longword align */
 #define ALIGN128    ((u_long)128 - 1)   /* 32 longword align */
 
+#ifndef __powerpc__
 #define ALIGN         ALIGN32           /* Keep the DC21040 happy... */
 #define CACHE_ALIGN   CAL_16LONG
 #define DESC_SKIP_LEN DSL_0             /* Must agree with DESC_ALIGN */
 /*#define DESC_ALIGN    u32 dummy[4];  / * Must agree with DESC_SKIP_LEN */
 #define DESC_ALIGN
 
+#else /* __powerpc__ */
+#define ALIGN         ALIGN32           /* Keep the DC21040 happy... */
+#define CACHE_ALIGN   CAL_8LONG
+#define DESC_SKIP_LEN DSL_4             /* Must agree with DESC_ALIGN */
+#define DESC_ALIGN    u32 dummy[4];    /* Must agree with DESC_SKIP_LEN */
+#endif /* __powerpc__ */
+
 #ifndef DEC_ONLY                        /* See README.de4x5 for using this */
 static int dec_only = 0;
 #else
@@ -763,6 +771,9 @@ struct de4x5_desc {
 struct de4x5_private {
     char adapter_name[80];                  /* Adapter name                 */
     u_long interrupt;                       /* Aligned ISR flag             */
+#ifdef __powerpc__
+    u_long dummy[3];                       /* Keep rx_ring 32-byte aligned */
+#endif
     struct de4x5_desc rx_ring[NUM_RX_DESC]; /* RX descriptor ring           */
     struct de4x5_desc tx_ring[NUM_TX_DESC]; /* TX descriptor ring           */
     struct sk_buff *tx_skb[NUM_TX_DESC];    /* TX skb for freeing when sent */
diff --git a/drivers/net/gmac.c b/drivers/net/gmac.c
new file mode 100644 (file)
index 0000000..ebf70df
--- /dev/null
@@ -0,0 +1,614 @@
+/*
+ * Network device driver for the GMAC ethernet controller on
+ * Apple G4 Powermacs.
+ *
+ * Copyright (C) 2000 Paul Mackerras.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include "gmac.h"
+
+#define DEBUG_PHY
+
+#define NTX            32              /* must be power of 2 */
+#define NRX            32              /* must be power of 2 */
+#define RX_BUFLEN      (ETH_FRAME_LEN + 8)
+
+struct gmac_dma_desc {
+       unsigned int    cmd;
+       unsigned int    status;
+       unsigned int    address;        /* phys addr, low 32 bits */
+       unsigned int    hi_addr;
+};
+
+/* Bits in cmd */
+#define RX_OWN 0x80000000              /* 1 = owned by chip */
+#define TX_SOP 0x80000000
+#define TX_EOP 0x40000000
+
+struct gmac {
+       volatile unsigned int *regs;    /* hardware registers, virtual addr */
+       volatile unsigned int *sysregs;
+       unsigned long   desc_page;      /* page for DMA descriptors */
+       volatile struct gmac_dma_desc *rxring;
+       struct sk_buff  *rx_buff[NRX];
+       int             next_rx;
+       volatile struct gmac_dma_desc *txring;
+       struct sk_buff  *tx_buff[NTX];
+       int             next_tx;
+       int             tx_gone;
+       unsigned char   tx_full;
+       int             phy_addr;
+       int             full_duplex;
+       struct net_device_stats stats;
+};
+
+#define GM_OUT(r, v)   out_le32(gm->regs + (r)/4, (v))
+#define GM_IN(r)       in_le32(gm->regs + (r)/4)
+#define GM_BIS(r, v)   GM_OUT((r), GM_IN(r) | (v))
+#define GM_BIC(r, v)   GM_OUT((r), GM_IN(r) & ~(v))
+
+#define PHY_B5400      0x6040
+#define PHY_B5201      0x6212
+
+static unsigned char dummy_buf[RX_BUFLEN+2];
+static struct device *gmacs = NULL;
+
+/* Prototypes */
+static int mii_read(struct gmac *gm, int phy, int r);
+static int mii_write(struct gmac *gm, int phy, int r, int v);
+static void powerup_transceiver(struct gmac *gm);
+static int gmac_reset(struct device *dev);
+static void gmac_mac_init(struct gmac *gm, unsigned char *mac_addr);
+static void gmac_init_rings(struct gmac *gm);
+static void gmac_start_dma(struct gmac *gm);
+static int gmac_open(struct device *dev);
+static int gmac_close(struct device *dev);
+static int gmac_xmit_start(struct sk_buff *skb, struct device *dev);
+static int gmac_tx_cleanup(struct gmac *gm);
+static void gmac_receive(struct device *dev);
+static void gmac_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static struct net_device_stats *gmac_stats(struct device *dev);
+int gmac_probe(struct device *dev);
+
+/* Stuff for talking to the physical-layer chip */
+static int
+mii_read(struct gmac *gm, int phy, int r)
+{
+       int timeout;
+
+       GM_OUT(MIFFRAME, 0x60020000 | (phy << 23) | (r << 18));
+       for (timeout = 1000; timeout > 0; --timeout) {
+               udelay(20);
+               if (GM_IN(MIFFRAME) & 0x10000)
+                       return GM_IN(MIFFRAME) & 0xffff;
+       }
+       return -1;
+}
+
+static int
+mii_write(struct gmac *gm, int phy, int r, int v)
+{
+       int timeout;
+
+       GM_OUT(MIFFRAME, 0x50020000 | (phy << 23) | (r << 18) | (v & 0xffff));
+       for (timeout = 1000; timeout > 0; --timeout) {
+               udelay(20);
+               if (GM_IN(MIFFRAME) & 0x10000)
+                       return 0;
+       }
+       return -1;
+}
+
+static void 
+mii_poll_start(struct gmac *gm)
+{
+       unsigned int tmp;
+       
+       /* Start the MIF polling on the external transceiver. */
+       tmp = GM_IN(MIFCONFIG);
+       tmp &= ~(GMAC_MIF_CFGPR_MASK | GMAC_MIF_CFGPD_MASK);
+       tmp |= ((gm->phy_addr & 0x1f) << GMAC_MIF_CFGPD_SHIFT);
+       tmp |= (0x19 << GMAC_MIF_CFGPR_SHIFT);
+       tmp |= GMAC_MIF_CFGPE;
+       GM_OUT(MIFCONFIG, tmp);
+
+       /* Let the bits set. */
+       udelay(GMAC_MIF_POLL_DELAY);
+
+       GM_OUT(MIFINTMASK, 0xffc0);
+}
+
+static void 
+mii_poll_stop(struct gmac *gm)
+{
+       GM_OUT(MIFINTMASK, 0xffff);
+       GM_BIC(MIFCONFIG, GMAC_MIF_CFGPE);
+       udelay(GMAC_MIF_POLL_DELAY);
+}
+
+static void
+mii_interrupt(struct gmac *gm)
+{
+       unsigned long   flags;
+       int             phy_status;
+       
+       save_flags(flags);
+       cli();
+
+       mii_poll_stop(gm);
+
+       /* May the status change before polling is re-enabled ? */
+       mii_poll_start(gm);
+       
+       /* We read the Auxilliary Status Summary register */
+       phy_status = mii_read(gm, gm->phy_addr, 0x19);
+#ifdef DEBUG_PHY
+       printk("mii_interrupt, phy_status: %x\n", phy_status);
+#endif
+       /* Auto-neg. complete ? */
+       if (phy_status & 0x8000) {
+               int full_duplex = 0;
+               switch((phy_status >> 8) & 0x7) {
+                       case 2:
+                       case 5:
+                               full_duplex = 1;
+                               break;
+               }
+               if (full_duplex != gm->full_duplex) {
+                       GM_BIC(TXMAC_CONFIG, 1);
+                       udelay(200);
+                       if (full_duplex) {
+                               printk("full duplex active\n");
+                               GM_OUT(TXMAC_CONFIG, 6);
+                               GM_OUT(XIF_CONFIG, 1);
+                       } else {
+                               printk("half duplex active\n");
+                               GM_OUT(TXMAC_CONFIG, 0);
+                               GM_OUT(XIF_CONFIG, 5);
+                       }
+                       GM_BIS(TXMAC_CONFIG, 1);
+                       gm->full_duplex = full_duplex;
+               }
+       }
+
+       restore_flags(flags);
+}
+
+static void
+powerup_transceiver(struct gmac *gm)
+{
+       int phytype = mii_read(gm, 0, 3);
+#ifdef DEBUG_PHY
+       int i;
+#endif 
+       switch (phytype) {
+       case PHY_B5400:
+               mii_write(gm, 0, 0, mii_read(gm, 0, 0) & ~0x800);
+               mii_write(gm, 31, 30, mii_read(gm, 31, 30) & ~8);
+               break;
+       case PHY_B5201:
+               mii_write(gm, 0, 30, mii_read(gm, 0, 30) & ~8);
+               break;
+       default:
+               printk(KERN_ERR "GMAC: unknown PHY type %x\n", phytype);
+       }
+       /* Check this */
+       gm->phy_addr = 0;
+       gm->full_duplex = 0;
+
+#ifdef DEBUG_PHY
+       printk("PHY regs:\n");
+       for (i=0; i<0x20; i++) {
+               printk("%04x ", mii_read(gm, 0, i)); 
+               if ((i % 4) == 3)
+                       printk("\n");
+       }
+#endif
+}
+
+static int
+gmac_reset(struct device *dev)
+{
+       struct gmac *gm = (struct gmac *) dev->priv;
+       int timeout;
+
+       /* turn on GB clock */
+       out_le32(gm->sysregs + 0x20/4, in_le32(gm->sysregs + 0x20/4) | 2);
+       udelay(10);
+       GM_OUT(SW_RESET, 3);
+       for (timeout = 100; timeout > 0; --timeout) {
+               mdelay(10);
+               if ((GM_IN(SW_RESET) & 3) == 0)
+                       return 0;
+       }
+       printk(KERN_ERR "GMAC: reset failed!\n");
+       return -1;
+}
+
+static void
+gmac_mac_init(struct gmac *gm, unsigned char *mac_addr)
+{
+       int i;
+
+       GM_OUT(RANSEED, 937);
+       GM_OUT(DATAPATHMODE, 4);
+       mii_write(gm, 0, 0, 0x1000);
+       GM_OUT(TXDMA_CONFIG, 0xffc00);
+       GM_OUT(RXDMA_CONFIG, 0);
+       GM_OUT(MACPAUSE, 0x1bf0);
+       GM_OUT(IPG0, 0);
+       GM_OUT(IPG1, 8);
+       GM_OUT(IPG2, 4);
+       GM_OUT(MINFRAMESIZE, 64);
+       GM_OUT(MAXFRAMESIZE, 2000);
+       GM_OUT(PASIZE, 7);
+       GM_OUT(JAMSIZE, 4);
+       GM_OUT(ATTEMPT_LIMIT, 16);
+       GM_OUT(SLOTTIME, 64);
+       GM_OUT(MACCNTL_TYPE, 0x8808);
+       GM_OUT(MAC_ADDR_0, (mac_addr[4] << 8) + mac_addr[5]);
+       GM_OUT(MAC_ADDR_1, (mac_addr[2] << 8) + mac_addr[3]);
+       GM_OUT(MAC_ADDR_2, (mac_addr[0] << 8) + mac_addr[1]);
+       GM_OUT(MAC_ADDR_3, 0);
+       GM_OUT(MAC_ADDR_4, 0);
+       GM_OUT(MAC_ADDR_5, 0);
+       GM_OUT(MAC_ADDR_6, 0x0180);
+       GM_OUT(MAC_ADDR_7, 0xc200);
+       GM_OUT(MAC_ADDR_8, 0x0001);
+       GM_OUT(MAC_ADDR_FILTER_0, 0);
+       GM_OUT(MAC_ADDR_FILTER_1, 0);
+       GM_OUT(MAC_ADDR_FILTER_2, 0);
+       GM_OUT(MAC_ADDR_FILTER_MASK21, 0);
+       GM_OUT(MAC_ADDR_FILTER_MASK0, 0);
+       for (i = 0; i < 27; ++i)
+               GM_OUT(MAC_HASHTABLE + i, 0);
+       GM_OUT(MACCNTL_CONFIG, 0);
+       /* default to half duplex */
+       GM_OUT(TXMAC_CONFIG, 0);
+       GM_OUT(XIF_CONFIG, 5);
+}
+
+static void
+gmac_init_rings(struct gmac *gm)
+{
+       int i;
+       struct sk_buff *skb;
+       unsigned char *data;
+       struct gmac_dma_desc *ring;
+
+       /* init rx ring */
+       ring = (struct gmac_dma_desc *) gm->rxring;
+       memset(ring, 0, NRX * sizeof(struct gmac_dma_desc));
+       for (i = 0; i < NRX; ++i, ++ring) {
+               data = dummy_buf;
+               gm->rx_buff[i] = skb = dev_alloc_skb(RX_BUFLEN + 2);
+               if (skb != 0) {
+                       /*skb_reserve(skb, 2);*/
+                       data = skb->data;
+               }
+               st_le32(&ring->address, virt_to_bus(data));
+               st_le32(&ring->cmd, RX_OWN);
+       }
+
+       /* init tx ring */
+       ring = (struct gmac_dma_desc *) gm->txring;
+       memset(ring, 0, NRX * sizeof(struct gmac_dma_desc));
+
+       /* set pointers in chip */
+       mb();
+       GM_OUT(RXDMA_BASE_HIGH, 0);
+       GM_OUT(RXDMA_BASE_LOW, virt_to_bus(gm->rxring));
+       GM_OUT(TXDMA_BASE_HIGH, 0);
+       GM_OUT(TXDMA_BASE_LOW, virt_to_bus(gm->txring));
+}
+
+static void
+gmac_start_dma(struct gmac *gm)
+{
+       GM_BIS(RXDMA_CONFIG, 1);
+       GM_BIS(RXMAC_CONFIG, 1);
+       GM_OUT(RXDMA_KICK, NRX);
+       GM_BIS(TXDMA_CONFIG, 1);
+       GM_BIS(TXMAC_CONFIG, 1);
+}
+
+static int gmac_open(struct device *dev)
+{
+       struct gmac *gm = (struct gmac *) dev->priv;
+
+       if (gmac_reset(dev))
+               return -EIO;
+
+       MOD_INC_USE_COUNT;
+
+       powerup_transceiver(gm);
+       gmac_mac_init(gm, dev->dev_addr);
+       gmac_init_rings(gm);
+       gmac_start_dma(gm);
+       mii_interrupt(gm);
+
+       GM_OUT(INTR_DISABLE, 0xfffdffe8);
+
+       return 0;
+}
+
+static int gmac_close(struct device *dev)
+{
+       struct gmac *gm = (struct gmac *) dev->priv;
+       int i;
+
+       mii_poll_stop(gm);
+       
+       GM_BIC(RXDMA_CONFIG, 1);
+       GM_BIC(RXMAC_CONFIG, 1);
+       GM_BIC(TXDMA_CONFIG, 1);
+       GM_BIC(TXMAC_CONFIG, 1);
+       GM_OUT(INTR_DISABLE, ~0U);
+       for (i = 0; i < NRX; ++i) {
+               if (gm->rx_buff[i] != 0) {
+                       dev_kfree_skb(gm->rx_buff[i]);
+                       gm->rx_buff[i] = 0;
+               }
+       }
+       for (i = 0; i < NTX; ++i) {
+               if (gm->tx_buff[i] != 0) {
+                       dev_kfree_skb(gm->tx_buff[i]);
+                       gm->tx_buff[i] = 0;
+               }
+       }
+
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+static int gmac_xmit_start(struct sk_buff *skb, struct device *dev)
+{
+       struct gmac *gm = (struct gmac *) dev->priv;
+       volatile struct gmac_dma_desc *dp;
+       unsigned long flags;
+       int i;
+
+       save_flags(flags); cli();
+       i = gm->next_tx;
+       if (gm->tx_buff[i] != 0) {
+               /* buffer is full, can't send this packet at the moment */
+               dev->tbusy = 1;
+               gm->tx_full = 1;
+               restore_flags(flags);
+               return 1;
+       }
+       gm->next_tx = (i + 1) & (NTX - 1);
+       gm->tx_buff[i] = skb;
+       restore_flags(flags);
+
+       dp = &gm->txring[i];
+       dp->status = 0;
+       dp->hi_addr = 0;
+       st_le32(&dp->address, virt_to_bus(skb->data));
+       mb();
+       st_le32(&dp->cmd, TX_SOP | TX_EOP | skb->len);
+       mb();
+
+       GM_OUT(TXDMA_KICK, gm->next_tx);
+
+       return 0;
+}
+
+static int gmac_tx_cleanup(struct gmac *gm)
+{
+       int i = gm->tx_gone;
+       volatile struct gmac_dma_desc *dp;
+       struct sk_buff *skb;
+       int ret = 0;
+       int gone = GM_IN(TXDMA_COMPLETE);
+
+       while (i != gone) {
+               skb = gm->tx_buff[i];
+               if (skb == NULL)
+                       break;
+               dp = &gm->txring[i];
+               gm->stats.tx_bytes += skb->len;
+               ++gm->stats.tx_packets;
+               gm->tx_buff[i] = NULL;
+               dev_kfree_skb(skb);
+               if (++i >= NTX)
+                       i = 0;
+       }
+       if (i != gm->tx_gone) {
+               ret = gm->tx_full;
+               gm->tx_gone = i;
+               gm->tx_full = 0;
+       }
+       return ret;
+}
+
+static void gmac_receive(struct device *dev)
+{
+       struct gmac *gm = (struct gmac *) dev->priv;
+       int i = gm->next_rx;
+       volatile struct gmac_dma_desc *dp;
+       struct sk_buff *skb;
+       int len;
+       unsigned char *data;
+
+       for (;;) {
+               dp = &gm->rxring[i];
+               if (ld_le32(&dp->cmd) & RX_OWN)
+                       break;
+               len = (ld_le32(&dp->cmd) >> 16) & 0x7fff;
+               skb = gm->rx_buff[i];
+               if (skb == 0) {
+                       ++gm->stats.rx_dropped;
+               } else if (ld_le32(&dp->status) & 0x40000000) {
+                       ++gm->stats.rx_errors;
+                       dev_kfree_skb(skb);
+               } else {
+                       skb_put(skb, len);
+                       skb->dev = dev;
+                       skb->protocol = eth_type_trans(skb, dev);
+                       netif_rx(skb);
+                       gm->stats.rx_bytes += skb->len;
+                       ++gm->stats.rx_packets;
+               }
+               data = dummy_buf;
+               gm->rx_buff[i] = skb = dev_alloc_skb(RX_BUFLEN + 2);
+               if (skb != 0) {
+                       /*skb_reserve(skb, 2);*/
+                       data = skb->data;
+               }
+               st_le32(&dp->address, virt_to_bus(data));
+               dp->hi_addr = 0;
+               mb();
+               st_le32(&dp->cmd, RX_OWN);
+               if (++i >= NRX)
+                       i = 0;
+       }
+       gm->next_rx = i;
+}
+
+static void gmac_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct device *dev = (struct device *) dev_id;
+       struct gmac *gm = (struct gmac *) dev->priv;
+       unsigned int status;
+
+       status = GM_IN(INTR_STATUS);
+       GM_OUT(INTR_ACK, status);
+       
+       if (status & GMAC_IRQ_MIF) {
+               mii_interrupt(gm);
+       }
+       gmac_receive(dev);
+       if (gmac_tx_cleanup(gm)){
+               dev->tbusy = 0;
+               mark_bh(NET_BH);
+       }
+}
+
+static struct net_device_stats *gmac_stats(struct device *dev)
+{
+       struct gmac *gm = (struct gmac *) dev->priv;
+
+       return &gm->stats;
+}
+
+int gmac_probe(struct device *dev)
+{
+       static int gmacs_found;
+       static struct device_node *next_gmac;
+       struct device_node *gmac;
+       struct gmac *gm;
+       unsigned long descpage;
+       unsigned char *addr;
+       int i;
+
+       /*
+        * We could (and maybe should) do this using PCI scanning
+        * for vendor/device ID 0x106b/0x21.
+        */
+       if (!gmacs_found) {
+               next_gmac = find_compatible_devices("network", "gmac");
+               gmacs_found = 1;
+       }
+       if ((gmac = next_gmac) == 0)
+               return -ENODEV;
+       next_gmac = gmac->next;
+
+       if (gmac->n_addrs < 1 || gmac->n_intrs < 1) {
+               printk(KERN_ERR "can't use GMAC %s: %d addrs and %d intrs\n",
+                      gmac->full_name, gmac->n_addrs, gmac->n_intrs);
+               return -ENODEV;
+       }
+
+       dev = init_etherdev(0, sizeof(struct gmac));
+       memset(dev->priv, 0, sizeof(struct gmac));
+
+       gm = (struct gmac *) dev->priv;
+       dev->base_addr = gmac->addrs[0].address;
+       gm->regs = (volatile unsigned int *)
+               ioremap(gmac->addrs[0].address, 0x10000);
+       gm->sysregs = (volatile unsigned int *) ioremap(0xf8000000, 0x1000);
+       dev->irq = gmac->intrs[0].line;
+
+       addr = get_property(gmac, "local-mac-address", NULL);
+       if (addr == NULL) {
+               printk(KERN_ERR "Can't get mac-address for GMAC %s\n",
+                      gmac->full_name);
+               return -EAGAIN;
+       }
+
+       printk(KERN_INFO "%s: GMAC at", dev->name);
+       for (i = 0; i < 6; ++i) {
+               dev->dev_addr[i] = addr[i];
+               printk("%c%.2x", (i? ':': ' '), addr[i]);
+       }
+       printk("\n");
+
+       descpage = get_free_page(GFP_KERNEL);
+       if (descpage == 0) {
+               printk(KERN_ERR "GMAC: can't get a page for descriptors\n");
+               return -EAGAIN;
+       }
+
+       gm->desc_page = descpage;
+       gm->rxring = (volatile struct gmac_dma_desc *) descpage;
+       gm->txring = (volatile struct gmac_dma_desc *) (descpage + 0x800);
+
+       gm->phy_addr = 0;
+       
+       dev->open = gmac_open;
+       dev->stop = gmac_close;
+       dev->hard_start_xmit = gmac_xmit_start;
+       dev->get_stats = gmac_stats;
+
+       ether_setup(dev);
+
+       if (request_irq(dev->irq, gmac_interrupt, 0, "GMAC", dev)) {
+               printk(KERN_ERR "GMAC: can't get irq %d\n", dev->irq);
+               return -EAGAIN;
+       }
+
+       gmacs = dev;
+
+       return 0;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Paul Mackerras");
+MODULE_DESCRIPTION("PowerMac GMAC driver.");
+
+int init_module(void)
+{
+       if (gmacs != NULL)
+               return -EBUSY;
+       return gmac_probe(NULL);
+}
+
+void cleanup_module(void)
+{
+       struct gmac *gm;
+
+       /* XXX should handle more than one */
+       if (gmacs == NULL)
+               return;
+
+       gm = (struct gmac *) gmacs->priv;
+       free_irq(gmacs->irq, gmac_interrupt);
+       free_page(gm->desc_page);
+       unregister_netdev(gmacs);
+       kfree(gmacs);
+       gmacs = NULL;
+}
+
+#endif
diff --git a/drivers/net/gmac.h b/drivers/net/gmac.h
new file mode 100644 (file)
index 0000000..2e50f60
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Definitions for the GMAC ethernet chip, used in the
+ * Apple G4 powermac.
+ */
+
+/* Register offsets */
+#define        INTR_STATUS             0x000c
+#define INTR_DISABLE           0x0010
+#define INTR_ACK               0x0014
+#define SW_RESET               0x1010
+#define TXDMA_KICK             0x2000
+#define TXDMA_CONFIG           0x2004
+#define TXDMA_BASE_LOW         0x2008
+#define TXDMA_BASE_HIGH                0x200c
+#define TXDMA_STATE_MACH       0x2028
+#define TXDMA_COMPLETE         0x2100
+#define RXDMA_CONFIG           0x4000
+#define RXDMA_BASE_LOW         0x4004
+#define RXDMA_BASE_HIGH                0x4008
+#define RXDMA_KICK             0x4100
+#define MACPAUSE               0x6008
+#define TXMAC_STATUS           0x6010
+#define TXMAC_CONFIG           0x6030
+#define RXMAC_CONFIG           0x6034
+#define MACCNTL_CONFIG         0x6038
+#define XIF_CONFIG             0x603c
+#define IPG0                   0x6040
+#define IPG1                   0x6044
+#define IPG2                   0x6048
+#define SLOTTIME               0x604c
+#define MINFRAMESIZE           0x6050
+#define MAXFRAMESIZE           0x6054
+#define PASIZE                 0x6058
+#define JAMSIZE                        0x605c
+#define ATTEMPT_LIMIT          0x6060
+#define MACCNTL_TYPE           0x6064
+#define MAC_ADDR_0             0x6080
+#define MAC_ADDR_1             0x6084
+#define MAC_ADDR_2             0x6088
+#define MAC_ADDR_3             0x608c
+#define MAC_ADDR_4             0x6090
+#define MAC_ADDR_5             0x6094
+#define MAC_ADDR_6             0x6098
+#define MAC_ADDR_7             0x609c
+#define MAC_ADDR_8             0x60a0
+#define MAC_ADDR_FILTER_0      0x60a4
+#define MAC_ADDR_FILTER_1      0x60a8
+#define MAC_ADDR_FILTER_2      0x60ac
+#define MAC_ADDR_FILTER_MASK21 0x60b0
+#define MAC_ADDR_FILTER_MASK0  0x60b4
+#define MAC_HASHTABLE          0x60c0
+#define RANSEED                        0x6130
+#define MIFFRAME               0x620c
+#define MIFCONFIG              0x6210
+#define MIFINTMASK             0x6214
+#define MIFSTATUS              0x6218
+#define DATAPATHMODE           0x9050
+
+/* -- 0x000C   R-C     Global Interrupt status. 
+ * d: 0x00000000       bits 0-6 cleared on read (C)
+ */
+#define GMAC_IRQ_TX_INT_ME     0x00000001      /* C Frame with INT_ME bit set in fifo */
+#define GMAC_IRQ_TX_ALL                0x00000002      /* C TX descriptor ring empty */
+#define GMAC_IRQ_TX_DONE       0x00000004      /* C moved from host to TX fifo */
+#define GMAC_IRQ_RX_DONE       0x00000010      /* C moved from RX fifo to host */
+#define GMAC_IRQ_RX_NO_BUF     0x00000020      /* C No RX buffer available */
+#define GMAC_IRQ_RX_TAG_ERR    0x00000040      /* C RX tag error */
+
+#define GMAC_IRQ_PCS           0x00002000      /* PCS interrupt ? */
+#define GMAC_IRQ_MAC_TX                0x00004000      /* MAC tx register set */
+#define GMAC_IRQ_MAC_RX                0x00008000      /* MAC rx register set  */
+#define GMAC_IRQ_MAC_CTRL      0x00010000      /* MAC control register set  */
+#define GMAC_IRQ_MIF           0x00020000      /* MIF status register set */
+#define GMAC_IRQ_BUS_ERROR     0x00040000      /* Bus error status register set */
+
+#define GMAC_IRQ_TX_COMP       0xfff80000      /* TX completion mask */
+
+/* -- 0x6210   RW      MIF config reg
+ */
+
+#define        GMAC_MIF_CFGPS                  0x00000001      /* PHY Select */
+#define        GMAC_MIF_CFGPE                  0x00000002      /* Poll Enable */
+#define        GMAC_MIF_CFGBB                  0x00000004      /* Bit Bang Enable */
+#define        GMAC_MIF_CFGPR_MASK             0x000000f8      /* Poll Register address */
+#define        GMAC_MIF_CFGPR_SHIFT            3
+#define        GMAC_MIF_CFGM0                  0x00000100      /* MDIO_0 Data / MDIO_0 attached */
+#define        GMAC_MIF_CFGM1                  0x00000200      /* MDIO_1 Data / MDIO_1 attached */
+#define        GMAC_MIF_CFGPD_MASK             0x00007c00      /* Poll Device PHY address */
+#define        GMAC_MIF_CFGPD_SHIFT            10
+
+#define        GMAC_MIF_POLL_DELAY             200
+
+#define        GMAC_INTERNAL_PHYAD             1               /* PHY address for int. transceiver */
+#define        GMAC_EXTERNAL_PHYAD             0               /* PHY address for ext. transceiver */
+
+
+/* -- 0x6214   RW      MIF interrupt mask reg
+ *                     same as basic/status Register
+ */
+
+/* -- 0x6214   RW      MIF basic/status reg
+ *                     The Basic portion of this register indicates the last
+ *                     value of the register read indicated in the POLL REG field
+ *                     of the Configuration Register.
+ *                     The Status portion indicates bit(s) that have changed.
+ *                     The MIF Mask register is corresponding to this register in
+ *                     terms of the bit(s) that need to be masked for generating
+ *                     interrupt on the MIF Interrupt Bit of the Global Status Rgister.
+ */
+
+#define        GMAC_MIF_STATUS                 0x0000ffff      /* 0-15 : Status */
+#define        GMAC_MIF_BASIC                  0xffff0000      /* 16-31 : Basic register */
+
index 3150b2b325373e509d2abafdb51dd4759dedca11..f719e33909fe9245f227e88e6047a8cb713db1d5 100644 (file)
@@ -2336,6 +2336,11 @@ static void pci_happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs
 
        dev->interrupt = 1;
 
+       if ((happy_status & (GREG_STAT_TXALL | GREG_STAT_RXTOHOST)) &&
+           (hp->happy_flags & HFLAG_QUATTRO) != 0 &&
+           pci_dma_wsync != NULL)
+               (void) *(pci_dma_wsync);
+
        if(happy_status & GREG_STAT_ERRORS) {
                HMD(("ERRORS "));
                if(happy_meal_is_not_so_happy(hp, gregs, /* un- */ happy_status)) {
index 1a782f20ae5192b907003632b571f73bd0788546..084de211e520c81d91af01638fb3fa74001ce350 100644 (file)
@@ -115,6 +115,7 @@ History:
 #include <asm/adb.h>
 #include <asm/cuda.h>
 #include <asm/pmu.h>
+#include <asm/feature.h>
 #include "awacs_defs.h"
 #include <linux/nvram.h>
 #include <linux/vt_kern.h>
@@ -175,6 +176,7 @@ static volatile struct dbdma_regs *awacs_txdma, *awacs_rxdma;
 static int awacs_rate_index;
 static int awacs_subframe;
 static int awacs_spkr_vol;
+static struct device_node* awacs_node;
 
 static int awacs_revision;
 #define AWACS_BURGUNDY 100             /* fake revision # for burgundy */
@@ -3018,6 +3020,12 @@ static void PMacIrqCleanup(void)
        out_le32(&awacs_txdma->control, RUN<<16);
        /* disable interrupts from awacs interface */
        out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff);
+#ifdef CONFIG_PMAC_PBOOK
+       if (is_pbook_G3) {
+               feature_clear(awacs_node, FEATURE_Sound_power);
+               feature_clear(awacs_node, FEATURE_Sound_CLK_enable);
+       }
+#endif
        free_irq(awacs_irq, (void *) awacs);
        free_irq(awacs_tx_irq, (void *) awacs);
        kfree(awacs_tx_cmd_space);
@@ -3370,8 +3378,21 @@ static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when)
                PMacSilence();
                disable_irq(awacs_irq);
                disable_irq(awacs_tx_irq);
+               feature_clear(awacs_node, FEATURE_Sound_CLK_enable);
+               feature_clear(awacs_node, FEATURE_Sound_power);
                break;
        case PBOOK_WAKE:
+               /* There is still a problem on wake. Sound seems to work fine
+                  if I launch mpg123 and resumes fine if mpg123 was playing,
+                  but the console beep is dead until I do something with the
+                  mixer. Probably yet another timing issue */
+               if (!feature_test(awacs_node, FEATURE_Sound_CLK_enable)
+                   || !feature_test(awacs_node, FEATURE_Sound_power)) {
+                       /* these aren't present on the 3400 AFAIK -- paulus */
+                       feature_set(awacs_node, FEATURE_Sound_CLK_enable);
+                       feature_set(awacs_node, FEATURE_Sound_power);
+                       mdelay(1000);
+               }
                out_le32(&awacs->control, MASK_IEPC
                         | (awacs_rate_index << 8) | 0x11
                         | (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0));
@@ -3388,6 +3409,16 @@ static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when)
                        mdelay(2);
                        awacs_write(awacs_reg[1] | MASK_ADDR1);
                }
+               /* enable CD sound input */
+               if (macio_base && is_pbook_G3) {
+                       out_8(macio_base + 0x37, 3);
+               } else if (is_pbook_3400) {
+                       feature_set(awacs_node, FEATURE_IOBUS_enable);
+                       udelay(10);
+                       in_8((unsigned char *)0xf301a190);
+               }
+               /* Resume pending sounds. Paul, Is this wrong ? */
+               PMacPlay();
        }
        return PBOOK_SLEEP_OK;
 }
@@ -4596,6 +4627,7 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
        u_long fmt;
        int data;
        int size, nbufs;
+       audio_buf_info info;
 
        switch (cmd) {
        case SNDCTL_DSP_RESET:
@@ -4671,6 +4703,14 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
                sq_setup(numBufs, size, sound_buffers);
                sq.max_active = nbufs;
                return 0;
+       case SNDCTL_DSP_GETOSPACE:
+               info.fragments = sq.max_active - sq.count;
+               info.fragstotal = sq.max_active;
+               info.fragsize = sq.block_size;
+               info.bytes = info.fragments * info.fragsize;
+               if (copy_to_user((void *)arg, &info, sizeof(info)))
+                       return -EFAULT;
+               return 0;
 
        default:
                return mixer_ioctl(inode, file, cmd, arg);
@@ -4777,7 +4817,9 @@ static int state_open(struct inode *inode, struct file *file)
 #endif /* CONFIG_AMIGA */
 #ifdef CONFIG_PPC
        case DMASND_AWACS:
-               sprintf(mach, "PowerMac (AWACS rev %d) ", awacs_revision);
+               /* BenH: This one used to sprintf in mach which doesn't point to
+                * a large enough buffer */
+               len += sprintf(buffer+len, "PowerMac (AWACS rev %d) ", awacs_revision);
                break;
 #endif /* CONFIG_PPC */
        }
@@ -5022,6 +5064,16 @@ void __init dmasound_init(void)
                        printk(KERN_ERR "DMA sound driver: Not enough buffer memory, driver disabled!\n");
                        return;
                }
+               awacs_node = np;
+#ifdef CONFIG_PMAC_PBOOK
+               if (machine_is_compatible("PowerBook1,1")
+                   || machine_is_compatible("AAPL,PowerBook1998")) {
+                       feature_set(np, FEATURE_Sound_CLK_enable);
+                       feature_set(np, FEATURE_Sound_power);
+                       /* Shorter delay will not work */
+                       mdelay(1000);
+               }
+#endif
                awacs_tx_cmds = (volatile struct dbdma_cmd *)
                        DBDMA_ALIGN(awacs_tx_cmd_space);
                awacs_reg[0] = MASK_MUX_CD;
@@ -5041,7 +5093,10 @@ void __init dmasound_init(void)
                        awacs_revision =
                                (in_le32(&awacs->codec_stat) >> 12) & 0xf;
                        if (awacs_revision == 3) {
+                               mdelay(100);
                                awacs_write(0x6000);
+                               mdelay(2);
+                               awacs_write(awacs_reg[1] + MASK_ADDR1);
                                awacs_enable_amp(100 * 0x101);
                        }
                }
@@ -5063,27 +5118,35 @@ void __init dmasound_init(void)
                /* Powerbooks have odd ways of enabling inputs such as
                   an expansion-bay CD or sound from an internal modem
                   or a PC-card modem. */
-               if (machine_is_compatible("AAPL,3400/2400")) {
+               if (machine_is_compatible("AAPL,3400/2400")
+                       || machine_is_compatible("AAPL,3500")) {
                        is_pbook_3400 = 1;
                        /*
                         * Enable CD and PC-card sound inputs.
                         * This is done by reading from address
                         * f301a000, + 0x10 to enable the expansion-bay
                         * CD sound input, + 0x80 to enable the PC-card
-                        * sound input.  The 0x100 seems to enable the
-                        * MESH and/or its SCSI bus drivers.
+                        * sound input.  The 0x100 enables the SCSI bus
+                        * terminator power.
                         */
                        in_8((unsigned char *)0xf301a190);
-               } else if (machine_is_compatible("PowerBook1,1")) {
-                       np = find_devices("mac-io");
-                       if (np && np->n_addrs > 0) {
-                               is_pbook_G3 = 1;
-                               macio_base = (unsigned char *)
-                                       ioremap(np->addrs[0].address, 0x40);
-                               /* enable CD sound input */
-                               out_8(macio_base + 0x37, 3);
+               } else if (machine_is_compatible("PowerBook1,1")
+                          || machine_is_compatible("AAPL,PowerBook1998")) {
+                       struct device_node* mio;
+                       macio_base = 0;
+                       is_pbook_G3 = 1;
+                       for (mio = np->parent; mio; mio = mio->parent) {
+                               if (strcmp(mio->name, "mac-io") == 0
+                                   && mio->n_addrs > 0) {
+                                       macio_base = (unsigned char *) ioremap
+                                               (mio->addrs[0].address, 0x40);
+                                       break;
+                               }
                        }
-               }
+                       /* enable CD sound input */
+                       if (macio_base)
+                               out_8(macio_base + 0x37, 3);
+               }
        }
 #endif /* CONFIG_PPC */
 
index 24cb4557258c7f0f7d2e46d72586692c4af2d7ee..14a7be2062ea0dbc0443f70542ccd55ed9c6f58f 100644 (file)
@@ -418,6 +418,10 @@ int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
                if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
                                              EXT2_FEATURE_INCOMPAT_FILETYPE))
                        de->file_type = EXT2_FT_REG_FILE;
+       } else if (S_ISSOCK(inode->i_mode)) {
+               if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
+                                             EXT2_FEATURE_INCOMPAT_FILETYPE))
+                       de->file_type = EXT2_FT_SOCK;
        } else if (S_ISCHR(inode->i_mode)) {
                inode->i_op = &chrdev_inode_operations;
                if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
@@ -793,6 +797,8 @@ int ext2_link (struct dentry * old_dentry,
                        de->file_type = EXT2_FT_DIR;
                else if (S_ISLNK(inode->i_mode))
                        de->file_type = EXT2_FT_SYMLINK;
+               else if (S_ISSOCK(inode->i_mode))  
+                       de->file_type = EXT2_FT_SOCK;
                else if (S_ISCHR(inode->i_mode))
                        de->file_type = EXT2_FT_CHRDEV;
                else if (S_ISBLK(inode->i_mode))
index b6315ad244273869cdedd5c676c12ae04cf3cfc5..e2b5b789977b5c3ee1269f908812253af3c26b75 100644 (file)
@@ -210,12 +210,19 @@ static ssize_t do_readv_writev(int type, struct file *file,
        if (copy_from_user(iov, vector, count*sizeof(*vector)))
                goto out;
 
+       /* BSD readv/writev returns EINVAL if one of the iov_len
+          values < 0 or tot_len overflowed a 32-bit integer. -ink */
        tot_len = 0;
-       for (i = 0 ; i < count ; i++)
-               tot_len += iov[i].iov_len;
-
-       if((long) tot_len <0)
-               return -EINVAL;
+       ret = -EINVAL;
+       for (i = 0 ; i < count ; i++) {
+               size_t tmp = tot_len;
+               int len = iov[i].iov_len;
+               if (len < 0)
+                       goto out;
+               (u32)tot_len += len;
+               if (tot_len < tmp || tot_len < (u32)len)
+                       goto out;
+       }
 
        inode = file->f_dentry->d_inode;
        /* VERIFY_WRITE actually means a read, as we write to user space */
index 5674bd0f9e511b3492cca62b9f642d8a7117ca20..90c79cdb795e875870038f462323d0b735cf9413 100644 (file)
@@ -133,4 +133,3 @@ typedef struct boot_infos
 #endif
 
 #endif
-    
\ No newline at end of file
index 002736abf1ce57af068daf3a25feffb7f457ab2d..0e5567c304174fad55f24fccb0923ace93b779b5 100644 (file)
@@ -5,9 +5,11 @@
  * ELF register definitions..
  */
 #include <asm/ptrace.h>
+#include <asm/types.h>
 
 #define ELF_NGREG      48      /* includes nip, msr, lr, etc. */
 #define ELF_NFPREG     33      /* includes fpscr */
+#define ELF_NVRREG     33      /* includes vscr */
 
 /*
  * This is used to ensure we don't load something for the wrong architecture.
@@ -37,6 +39,10 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG];
 typedef double elf_fpreg_t;
 typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
 
+/* Altivec registers */
+typedef vector128 elf_vrreg_t;
+typedef elf_vrreg_t elf_vrregset_t[ELF_NVRREG];
+
 #define ELF_CORE_COPY_REGS(gregs, regs) \
        memcpy(gregs, regs, \
               sizeof(struct pt_regs) < sizeof(elf_gregset_t)? \
index 07b10e8bc66ca215069169adc7f36debab7b6d53..78d73b5327bdccd56e4adb934465c32a85c03c98 100644 (file)
@@ -8,12 +8,13 @@
  * for more details.
  *
  * Copyright (C) 1998 Paul Mackerras.
+ * 
  */
 #ifndef __ASM_PPC_FEATURE_H
 #define __ASM_PPC_FEATURE_H
 
 /*
- * The FCR bits for particular features vary somewhat between
+ * The FCR selector for particular features vary somewhat between
  * different machines.  So we abstract a list of features here
  * and let the feature_* routines map them to the actual bits.
  */
@@ -25,19 +26,25 @@ enum system_feature {
        FEATURE_Serial_IO_B,
        FEATURE_SWIM3_enable,
        FEATURE_MESH_enable,
-       FEATURE_IDE_enable,
-       FEATURE_VIA_enable,
-       FEATURE_CD_power,
+       FEATURE_IDE0_enable,            /* Internal IDE */
+       FEATURE_IDE0_reset,             /* Internal IDE */
+       FEATURE_IOBUS_enable,           /* Internal IDE */
        FEATURE_Mediabay_reset,
-       FEATURE_Mediabay_enable,
+       FEATURE_Mediabay_power,
        FEATURE_Mediabay_PCI_enable,
-       FEATURE_Mediabay_IDE_enable,
+       FEATURE_IDE1_enable,            /* MediaBay IDE */
+       FEATURE_IDE1_reset,             /* MediaBay IDE */
        FEATURE_Mediabay_floppy_enable,
        FEATURE_BMac_reset,
        FEATURE_BMac_IO_enable,
-       FEATURE_Modem_Reset,
-       FEATURE_IDE_DiskPower,
-       FEATURE_IDE_Reset,
+       FEATURE_Modem_power,
+       FEATURE_Slow_SCC_PCLK,
+       FEATURE_Sound_power,
+       FEATURE_Sound_CLK_enable,
+       FEATURE_IDE2_enable,
+       FEATURE_IDE2_reset,
+       FEATURE_Mediabay_IDE_switch,    /* MB IDE bus switch */
+       FEATURE_Mediabay_content,       /* MB content indicator enable */
        FEATURE_last,
 };
 
diff --git a/include/asm-ppc/heathrow.h b/include/asm-ppc/heathrow.h
new file mode 100644 (file)
index 0000000..647c632
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * heathrow.h: definitions for using the "Heathrow" I/O controller chip.
+ *
+ * Grabbed from Open Firmware definitions on a PowerBook G3 Series
+ *
+ * Copyright (C) 1997 Paul Mackerras.
+ */
+
+/* offset from ohare base for feature control register */
+#define HEATHROW_FEATURE_REG   0x38
+
+/*
+ * Bits in feature control register.
+ * Bits postfixed with a _N are in inverse logic
+ */
+#define HRW_RESET_SCC          0x00000001      /* Named in_use_led in OF ??? */
+#define HRW_BAY_POWER_N                0x00000002
+#define HRW_BAY_PCI_ENABLE     0x00000004
+#define HRW_BAY_IDE_ENABLE     0x00000008
+#define HRW_BAY_FLOPPY_ENABLE  0x00000010
+#define HRW_IDE0_ENABLE                0x00000020
+#define HRW_IDE0_RESET_N       0x00000040
+#define HRW_BAY_RESET_N                0x00000080
+#define HRW_IOBUS_ENABLE       0x00000100      /* Internal IDE ? */
+#define HRW_SCC_ENABLE         0x00000200
+#define HRW_MESH_ENABLE                0x00000400
+#define HRW_SWIM_ENABLE                0x00000800
+#define HRW_SOUND_POWER_N      0x00001000
+#define HRW_SOUND_CLK_ENABLE   0x00002000
+#define HRW_SCCA_IO            0x00004000
+#define HRW_SCCB_IO            0x00008000
+#define HRW_PORT_OR_DESK_VIA_N 0x00010000      /* This one is 0 on PowerBook */
+#define HRW_PWM_MON_ID_N       0x00020000      /* ??? (0) */
+#define HRW_HOOK_MB_CNT_N      0x00040000      /* ??? (0) */
+#define HRW_SWIM_CLONE_FLOPPY  0x00080000      /* ??? (0) */
+#define HRW_AUD_RUN22          0x00100000      /* ??? (1) */
+#define HRW_SCSI_LINK_MODE     0x00200000      /* Read ??? (1) */
+#define HRW_ARB_BYPASS         0x00400000      /* ??? (0 on main, 1 on gatwick) */
+#define HRW_IDE1_RESET_N       0x00800000      /* Media bay */
+#define HRW_SLOW_SCC_PCLK      0x01000000      /* ??? (0) */
+#define HRW_MODEM_POWER_N      0x02000000      /* Used by internal modem on wallstreet */
+#define HRW_MFDC_CELL_ENABLE   0x04000000      /* ??? (0) */
+#define HRW_USE_MFDC           0x08000000      /* ??? (0) */
+#define HRW_BMAC_IO_ENABLE     0x60000000      /* two bits, not documented in OF */
+#define HRW_BMAC_RESET         0x80000000      /* not documented in OF */
+
+#define PADD_MODEM_POWER_N     0x00000001      /* modem power on paddington */
index 77c264c2366d079a006005d7823cdf0289a83fca..689cc93b24e985c03490c23a6e7c789f89e1900a 100644 (file)
@@ -63,16 +63,6 @@ void ide_insw(ide_ioreg_t port, void *buf, int ns);
 void ide_outsw(ide_ioreg_t port, void *buf, int ns);
 void ppc_generic_ide_fix_driveid(struct hd_driveid *id);
 
-#undef insw
-#define insw(port, buf, ns)    do {                            \
-       ppc_ide_md.insw((port), (buf), (ns));                   \
-} while (0)
-     
-#undef outsw
-#define outsw(port, buf, ns)   do {                            \
-       ppc_ide_md.outsw((port), (buf), (ns));                  \
-} while (0)
-
 #undef SUPPORT_SLOW_DATA_PORTS
 #define        SUPPORT_SLOW_DATA_PORTS 0
 #undef SUPPORT_VLB_SYNC
index 0d4610ec66ca26453b32c34e2a85fa502973e423..6e735170d4249fe781fa91433ec8a62bf4735ac3 100644 (file)
@@ -54,10 +54,10 @@ extern unsigned long pci_dram_offset;
 
 #define insb(port, buf, ns)    _insb((unsigned char *)((port)+_IO_BASE), (buf), (ns))
 #define outsb(port, buf, ns)   _outsb((unsigned char *)((port)+_IO_BASE), (buf), (ns))
-#define insw(port, buf, ns)    _insw((unsigned short *)((port)+_IO_BASE), (buf), (ns))
-#define outsw(port, buf, ns)   _outsw((unsigned short *)((port)+_IO_BASE), (buf), (ns))
-#define insl(port, buf, nl)    _insl((unsigned long *)((port)+_IO_BASE), (buf), (nl))
-#define outsl(port, buf, nl)   _outsl((unsigned long *)((port)+_IO_BASE), (buf), (nl))
+#define insw(port, buf, ns)    _insw_ns((unsigned short *)((port)+_IO_BASE), (buf), (ns))
+#define outsw(port, buf, ns)   _outsw_ns((unsigned short *)((port)+_IO_BASE), (buf), (ns))
+#define insl(port, buf, nl)    _insl_ns((unsigned long *)((port)+_IO_BASE), (buf), (nl))
+#define outsl(port, buf, nl)   _outsl_ns((unsigned long *)((port)+_IO_BASE), (buf), (nl))
 
 #define inb(port)              in_8((unsigned char *)((port)+_IO_BASE))
 #define outb(val, port)                out_8((unsigned char *)((port)+_IO_BASE), (val))
index 2f4c21e48010a8a991a16df09d4bb52d7f9ec918..f5c5bc97b9153a2064794d6d6e9269709e6816b4 100644 (file)
@@ -72,8 +72,7 @@ static inline void kbd_init_hw(void)
 }
 
 #define kbd_sysrq_xlate        (ppc_md.kbd_sysrq_xlate)
-
-#define SYSRQ_KEY 0x54
+#define SYSRQ_KEY (ppc_md.SYSRQ_KEY)
 
 /* resource allocation */
 #define kbd_request_region()
index 78f35e285817a33aeac098c83e82bc5a2f6294a6..42b8ceeec07933b282863acd0109ad7fd9da215d 100644 (file)
@@ -50,6 +50,7 @@ struct machdep_calls {
        void            (*kbd_init_hw)(void);
 #ifdef CONFIG_MAGIC_SYSRQ
        unsigned char   *kbd_sysrq_xlate;
+       unsigned long   SYSRQ_KEY;
 #endif
 
        /* PCI interfaces */
index 04792d15ed50854b9ffeb6011100583374a90085..d6b1d03bfde9cb90957e25276fc793a106ec7b1c 100644 (file)
@@ -7,11 +7,16 @@
 #ifndef _PPC_MEDIABAY_H
 #define _PPC_MEDIABAY_H
 
+#ifdef __KERNEL__
+
+/* We keep those constants local to the kernel to avoid
+ * compatibility problems with different HW. A /proc inteface
+ * could be defined to tell userland about the content of the bay
+ */
 #define MB_FD  0               /* media bay contains floppy drive */
+#define MB_FD1 1               /* media bay contains floppy drive */
 #define MB_CD  3               /* media bay contains ATA drive such as CD */
-#define MB_NO  7               /* media bay contains nothing */
-
-#ifdef __KERNEL__
+#define MB_NO  0xF             /* media bay contains nothing */
 
 void media_bay_init(void);
 int check_media_bay(struct device_node *which_bay, int what);
index ea7bf19146f681f54f3c5d55b39ba733e2d7d433..2e61bb8f44cd1de3a4bca3ec4ae7f67a4bc2f34b 100644 (file)
 
 #define MOTO_RTC_SECONDS               0x1FF9
 #define MOTO_RTC_MINUTES               0x1FFA
-#define MOTO_RTC_HOURS         0x1FFB
+#define MOTO_RTC_HOURS                 0x1FFB
 #define MOTO_RTC_DAY_OF_WEEK           0x1FFC
-#define MOTO_RTC_DAY_OF_MONTH  0x1FFD
-#define MOTO_RTC_MONTH         0x1FFE
-#define MOTO_RTC_YEAR          0x1FFF
-#define MOTO_RTC_CONTROLA            0x1FF8
-#define MOTO_RTC_CONTROLB            0x1FF9
+#define MOTO_RTC_DAY_OF_MONTH          0x1FFD
+#define MOTO_RTC_MONTH                 0x1FFE
+#define MOTO_RTC_YEAR                  0x1FFF
+#define MOTO_RTC_CONTROLA              0x1FF8
+#define MOTO_RTC_CONTROLB              0x1FF9
 
 #ifndef BCD_TO_BIN
 #define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
 #define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
 #endif
 
+/* PowerMac specific nvram stuffs */
+
+enum {
+       pmac_nvram_OF,          /* Open Firmware partition */
+       pmac_nvram_XPRAM,       /* MacOS XPRAM partition */
+       pmac_nvram_NR           /* MacOS Name Registry partition */
+};
+
+/* Return partition offset in nvram */
+extern int     pmac_get_partition(int partition);
+
+/* Direct access to XPRAM */
+extern u8      pmac_xpram_read(int xpaddr);
+extern void    pmac_xpram_write(int xpaddr, u8 data);
+
+/* Some offsets in XPRAM */
+#define PMAC_XPRAM_MACHINE_LOC 0xe4
+#define PMAC_XPRAM_SOUND_VOLUME        0x08
+
+/* Machine location structure in XPRAM */
+struct pmac_machine_location {
+       u32     latitude;       /* 2+30 bit Fractional number */
+       u32     longitude;      /* 2+30 bit Fractional number */
+       u32     delta;          /* mix of GMT delta and DLS */
+};
+
 #endif
index ffc4ef10bf50ed812f6b649cae3be7eead5c807c..1303e5869be1cca227daab4d0ec810054442ada5 100644 (file)
@@ -2,6 +2,9 @@
  * ohare.h: definitions for using the "O'Hare" I/O controller chip.
  *
  * Copyright (C) 1997 Paul Mackerras.
+ * 
+ * BenH: Changed to match those of heathrow (but not all of them). Please
+ *       check if I didn't break anything (especially the media bay).
  */
 
 /* offset from ohare base for feature control register */
  * and may differ for other machines.
  */
 #define OH_SCC_RESET           1
-#define OH_BAY_RESET           2       /* a guess */
+#define OH_BAY_POWER_N         2       /* a guess */
 #define OH_BAY_PCI_ENABLE      4       /* a guess */
 #define OH_BAY_IDE_ENABLE      8
 #define OH_BAY_FLOPPY_ENABLE   0x10
-#define OH_IDE_ENABLE          0x20
-#define OH_IDE_POWER           0x40    /* a guess */
-#define OH_BAY_ENABLE          0x80
-#define OH_IDE_RESET           0x100   /* 0-based, a guess */
+#define OH_IDE0_ENABLE         0x20
+#define OH_IDE0_RESET_N                0x40    /* a guess */
+#define OH_BAY_RESET_N         0x80
+#define OH_IOBUS_ENABLE                0x100   /* IOBUS seems to be IDE */
 #define OH_SCC_ENABLE          0x200
 #define OH_MESH_ENABLE         0x400
 #define OH_FLOPPY_ENABLE       0x800
 #define OH_SCCA_IO             0x4000
 #define OH_SCCB_IO             0x8000
-#define OH_VIA_ENABLE          0x10000
-#define OH_IDECD_POWER         0x800000
+#define OH_VIA_ENABLE          0x10000 /* Is apparently wrong, to be verified */
+#define OH_IDE1_RESET_N                0x800000
 
 /*
  * Bits to set in the feature control register on PowerBooks.
index 12e576e8555ae155ad1c4540d9526992e743ed8d..46ad64784afb196195e654e073a957a7e78be704 100644 (file)
@@ -64,7 +64,7 @@ typedef unsigned long pgprot_t;
 #define PAGE_ALIGN(addr)       (((addr)+PAGE_SIZE-1)&PAGE_MASK)
 
 extern void clear_page(unsigned long page);
-#define copy_page(to,from)     memcpy((void *)(to), (void *)(from), PAGE_SIZE)
+extern void copy_page(unsigned long to, unsigned long from);
 
 /* map phys->virtual and virtual->phys for RAM pages */
 #ifdef CONFIG_APUS
index 6991f2cd98a199f4e56bfc40868ced1faad4bf64..f6ee352e4088deea54bb69f765855c6ec70694b6 100644 (file)
@@ -51,6 +51,7 @@ enum {
        PMU_OHARE_BASED,        /* 2400, 3400, 3500 (old G3 powerbook) */
        PMU_HEATHROW_BASED,     /* PowerBook G3 series */
        PMU_PADDINGTON_BASED,   /* 1999 PowerBook G3 */
+       PMU_KEYLARGO_BASED,     /* Core99 motherboard (PMU99) */
 };
 
 /*
@@ -66,6 +67,8 @@ enum {
 #define PMU_IOC_SET_BACKLIGHT  _IOW('B', 2, sizeof(__u32))
 /* out param: u32*     backlight value: 0 to 31 */
 #define PMU_IOC_GET_MODEL      _IOR('B', 3, sizeof(__u32*))
+/* out param: u32*     has_adb: 0 or 1 */
+#define PMU_IOC_HAS_ADB                _IOR('B', 4, sizeof(__u32*)) 
 
 #ifdef __KERNEL__
 
index afac1bc8483ac8a57321f2a43aff0a8fc1989abd..86d6f0951748ec0f974e31e66e12de109275aaec 100644 (file)
@@ -7,6 +7,7 @@
 #include <asm/residual.h>
 
 /* Bit encodings for Machine State Register (MSR) */
+#define MSR_VEC                (1<<25)         /* Enable Altivec */
 #define MSR_POW                (1<<18)         /* Enable Power Management */
 #define MSR_TGPR       (1<<17)         /* TLB Update registers in use */
 #define MSR_ILE                (1<<16)         /* Interrupt Little-Endian enable */
@@ -53,6 +54,9 @@
 #define HID0_DCI       (1<<10)         /* Data Cache Invalidate */
 #define HID0_SPD       (1<<9)          /* Speculative disable */
 #define HID0_SIED      (1<<7)          /* Serial Instruction Execution [Disable] */
+#define HID0_SGE       (1<<7)          /* Store Gathering Enable */
+#define HID0_BTIC      (1<<5)          /* Branch Target Instruction Cache Enable */
+#define HID0_ABE       (1<<3)          /* Address Broadcast Enable */
 #define HID0_BHTE      (1<<2)          /* Branch History Table Enable */
 #define HID0_BTCD      (1<<1)          /* Branch target cache disable */
 
@@ -147,6 +151,7 @@ n:
 #define EAR    282     /* External Address Register */
 #define L2CR   1017    /* PPC 750 L2 control register */
 
+#define ICTC   1019
 #define THRM1  1020
 #define THRM2  1021
 #define THRM3  1022
@@ -177,6 +182,10 @@ n:
 #define SR15   15
 
 #ifndef __ASSEMBLY__
+#include <asm/types.h>
+
+#ifdef __KERNEL__
+
 extern int _machine;
 
 /* Temporary hacks until we can clean things up better - Corey */
@@ -242,10 +251,21 @@ struct thread_struct {
        double          fpr[32];        /* Complete floating point set */
        unsigned long   fpscr_pad;      /* fpr ... fpscr must be contiguous */
        unsigned long   fpscr;          /* Floating point status */
+#ifdef CONFIG_ALTIVEC
+       vector128       vr[32];         /* Complete AltiVec set */
+       vector128       vscr;           /* AltiVec status */
+       unsigned long   vrsave;
+#endif /* CONFIG_ALTIVEC */
 };
 
 #define INIT_SP                (sizeof(init_stack) + (unsigned long) &init_stack)
 
+#ifdef CONFIG_ALTIVEC
+#define INIT_TSS_AVEC  {{{0}}}, {{0}}, 0,
+#else
+#define INIT_TSS_AVEC
+#endif /* CONFIG_ALTIVEC */
+
 #define INIT_TSS  { \
        INIT_SP, /* ksp */ \
        (unsigned long *) swapper_pg_dir, /* pg_tables */ \
@@ -253,7 +273,8 @@ struct thread_struct {
        (struct pt_regs *)INIT_SP - 1, /* regs */ \
        KERNEL_DS, /*fs*/ \
        0, /* last_syscall */ \
-       {0}, 0, 0 \
+       {0}, 0, 0, \
+       INIT_TSS_AVEC \
 }
 
 /*
@@ -295,5 +316,6 @@ void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val);
 
 #endif /* ndef ASSEMBLY*/
 
-  
+#endif /* __KERNEL__ */
+
 #endif /* __ASM_PPC_PROCESSOR_H */
index 20a8519daaf5580bf1602a3618d8bb8f6011e18a..40deb121b0fe9b76aea21463553ad62bbc3d521d 100644 (file)
@@ -72,7 +72,10 @@ extern struct device_node *find_type_devices(const char *type);
 extern struct device_node *find_path_device(const char *path);
 extern struct device_node *find_compatible_devices(const char *type,
                                                   const char *compat);
+extern struct device_node *find_pci_device_OFnode(unsigned char bus,
+       unsigned char dev_fn);
 extern struct device_node *find_phandle(phandle);
+extern struct device_node *find_all_nodes(void);
 extern int device_is_compatible(struct device_node *device, const char *);
 extern int machine_is_compatible(const char *compat);
 extern unsigned char *get_property(struct device_node *node, const char *name,
index 09790d0cdb3317a9668af9bb7252d08d22b0a6e8..68c2a0e537c14c787ed0aa966d974110200a166d 100644 (file)
@@ -72,6 +72,7 @@ extern void read_rtc_time(void);
 extern void pmac_find_display(void);
 extern void giveup_fpu(struct task_struct *);
 extern void enable_kernel_fp(void);
+extern void giveup_altivec(struct task_struct *);
 extern void cvt_fd(float *from, double *to, unsigned long *fpscr);
 extern void cvt_df(double *from, float *to, unsigned long *fpscr);
 extern int call_rtas(const char *, int, int, unsigned long *, ...);
index 11b4c513a5dc4f2fc917f32603f6ebbb116dfeaf..9bba8286120de337b25bb0f893dd52ea1d82fff7 100644 (file)
@@ -57,12 +57,9 @@ struct termios {
 #define ICRNL  0000400
 #define IXON   0001000
 #define IXOFF  0002000
-#if defined(__KERNEL__) || defined(__USE_BSD)
-  /* POSIX.1 doesn't want these... */
-# define IXANY         0004000
-# define IUCLC         0010000
-# define IMAXBEL       0020000
-#endif
+#define IXANY  0004000
+#define IUCLC  0010000
+#define IMAXBEL        0020000
 
 /* c_oflag bits */
 #define OPOST  0000001
index 86fa349d375f53aa6241b26c6a74b4fb2cccab78..bd1a0c3ca505fb5ef4f54dfa4402ac32a7fc0dc4 100644 (file)
@@ -39,6 +39,10 @@ typedef unsigned int u32;
 typedef signed long long s64;
 typedef unsigned long long u64;
 
+typedef struct {
+       u32 u[4];
+} __attribute((aligned(16))) vector128;
+
 #define BITS_PER_LONG 32
 
 #endif /* __KERNEL__ */
index 4f0f51f30c3057ab5145f7c4181f75fe34649559..79031f79a2edcaf5c3ba9d998ba27e86767b79c1 100644 (file)
@@ -14,6 +14,8 @@
 
 struct linux_pbm_info;
 
+extern volatile u64 *pci_dma_wsync;
+
 /* This is what we use to determine what the PROM has assigned so
  * far, so that we can perform assignments for addresses which
  * were not taken care of by OBP.  See psycho.c for details.
index 922ad102c22dc75ad799d52c5b91069638113c1d..d644b365743efdc372ba5402adfc67c41e58e143 100644 (file)
@@ -698,13 +698,16 @@ static inline int tcp_memory_free(struct sock *sk)
 
 /*
  *     Wait for more memory for a socket
+ *
+ *     If we got here an allocation has failed on us. We cannot
+ *     spin here or we may block the very code freeing memory
+ *     for us.
  */
 static void wait_for_tcp_memory(struct sock * sk)
 {
        release_sock(sk);
        if (!tcp_memory_free(sk)) {
                struct wait_queue wait = { current, NULL };
-
                sk->socket->flags &= ~SO_NOSPACE;
                add_wait_queue(sk->sleep, &wait);
                for (;;) {
@@ -722,6 +725,12 @@ static void wait_for_tcp_memory(struct sock * sk)
                current->state = TASK_RUNNING;
                remove_wait_queue(sk->sleep, &wait);
        }
+       else
+       {
+               /* Yield time to the memory freeing paths */
+               current->state = TASK_INTERRUPTIBLE;
+               schedule_timeout(1);
+       }
        lock_sock(sk);
 }