From d2cefdfcd7db74ec64e1b40d02b31bc1e4be9fc9 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 23 Nov 2007 15:21:34 -0500 Subject: [PATCH] Linux 2.2.17pre3 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) --- Makefile | 2 +- arch/ppc/boot/Makefile | 3 + arch/ppc/coffboot/Makefile | 89 ++-- arch/ppc/coffboot/chrpmain.c | 209 ++++++++++ arch/ppc/coffboot/coffcrt0.S | 24 ++ arch/ppc/coffboot/coffmain.c | 157 +++++++ arch/ppc/coffboot/crt0.S | 4 - arch/ppc/coffboot/misc.S | 35 +- arch/ppc/coffboot/mknote.c | 43 ++ arch/ppc/coffboot/no_initrd.c | 2 + arch/ppc/coffboot/piggyback.c | 65 +++ arch/ppc/coffboot/start.c | 56 ++- arch/ppc/common_defconfig | 148 ++++--- arch/ppc/config.in | 12 +- arch/ppc/defconfig | 148 ++++--- arch/ppc/kernel/Makefile | 5 + arch/ppc/kernel/checks.c | 1 + arch/ppc/kernel/chrp_setup.c | 3 + arch/ppc/kernel/feature.c | 328 ++++++++++----- arch/ppc/kernel/head.S | 246 ++++++++++- arch/ppc/kernel/local_irq.h | 1 + arch/ppc/kernel/mbx_setup.c | 1 + arch/ppc/kernel/misc.S | 20 +- arch/ppc/kernel/mk_defs.c | 8 +- arch/ppc/kernel/openpic.c | 131 ++++-- arch/ppc/kernel/pci.c | 2 +- arch/ppc/kernel/pmac_pci.c | 263 +++++++++++- arch/ppc/kernel/pmac_pic.c | 78 ++++ arch/ppc/kernel/pmac_setup.c | 76 +++- arch/ppc/kernel/pmac_support.c | 302 +++++++++++++- arch/ppc/kernel/ppc-stub.c | 2 +- arch/ppc/kernel/ppc_asm.tmpl | 33 ++ arch/ppc/kernel/ppc_htab.c | 3 +- arch/ppc/kernel/ppc_ksyms.c | 20 +- arch/ppc/kernel/prep_pci.c | 275 ++++++++----- arch/ppc/kernel/prep_setup.c | 2 + arch/ppc/kernel/process.c | 97 ++++- arch/ppc/kernel/prom.c | 612 +++++++++++++++++++++++---- arch/ppc/kernel/setup.c | 37 +- arch/ppc/kernel/signal.c | 8 + arch/ppc/kernel/smp.c | 2 +- arch/ppc/kernel/syscalls.c | 13 +- arch/ppc/kernel/traps.c | 25 +- arch/ppc/lib/string.S | 368 ++++++++++++----- arch/ppc/mm/fault.c | 5 +- arch/ppc/mm/init.c | 7 +- arch/ppc/pmac_defconfig | 2 + arch/ppc/xmon/start.c | 143 +++++-- arch/sparc64/kernel/psycho.c | 8 + arch/sparc64/kernel/sparc64_ksyms.c | 2 + drivers/block/ide-cd.c | 4 +- drivers/char/vt.c | 2 + drivers/macintosh/adb.c | 49 ++- drivers/macintosh/mac_keyb.c | 55 ++- drivers/macintosh/macio-adb.c | 5 - drivers/macintosh/macserial.c | 423 ++++++++++--------- drivers/macintosh/macserial.h | 2 +- drivers/macintosh/mediabay.c | 562 ++++++++++++++++--------- drivers/macintosh/via-cuda.c | 3 +- drivers/macintosh/via-pmu.c | 185 ++++++--- drivers/net/Config.in | 1 + drivers/net/Makefile | 8 + drivers/net/Space.c | 4 + drivers/net/de4x5.c | 11 + drivers/net/gmac.c | 614 ++++++++++++++++++++++++++++ drivers/net/gmac.h | 113 +++++ drivers/net/sunhme.c | 5 + drivers/sound/dmasound.c | 89 +++- fs/ext2/namei.c | 6 + fs/read_write.c | 17 +- include/asm-ppc/bootx.h | 1 - include/asm-ppc/elf.h | 6 + include/asm-ppc/feature.h | 25 +- include/asm-ppc/heathrow.h | 47 +++ include/asm-ppc/ide.h | 10 - include/asm-ppc/io.h | 8 +- include/asm-ppc/keyboard.h | 3 +- include/asm-ppc/machdep.h | 1 + include/asm-ppc/mediabay.h | 11 +- include/asm-ppc/nvram.h | 38 +- include/asm-ppc/ohare.h | 17 +- include/asm-ppc/page.h | 2 +- include/asm-ppc/pmu.h | 3 + include/asm-ppc/processor.h | 26 +- include/asm-ppc/prom.h | 3 + include/asm-ppc/system.h | 1 + include/asm-ppc/termbits.h | 9 +- include/asm-ppc/types.h | 4 + include/asm-sparc64/pbm.h | 2 + net/ipv4/tcp.c | 11 +- 90 files changed, 5226 insertions(+), 1286 deletions(-) create mode 100644 arch/ppc/coffboot/chrpmain.c create mode 100644 arch/ppc/coffboot/coffcrt0.S create mode 100644 arch/ppc/coffboot/coffmain.c create mode 100644 arch/ppc/coffboot/mknote.c create mode 100644 arch/ppc/coffboot/no_initrd.c create mode 100644 arch/ppc/coffboot/piggyback.c create mode 100644 drivers/net/gmac.c create mode 100644 drivers/net/gmac.h create mode 100644 include/asm-ppc/heathrow.h diff --git a/Makefile b/Makefile index 815dba3f9051..fb8ee7d08e9b 100644 --- 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/) diff --git a/arch/ppc/boot/Makefile b/arch/ppc/boot/Makefile index 96b6ba306ecc..c595afaa77b3 100644 --- a/arch/ppc/boot/Makefile +++ b/arch/ppc/boot/Makefile @@ -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 diff --git a/arch/ppc/coffboot/Makefile b/arch/ppc/coffboot/Makefile index 915171746780..7468bf7a79ed 100644 --- a/arch/ppc/coffboot/Makefile +++ b/arch/ppc/coffboot/Makefile @@ -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 index 000000000000..254ced627768 --- /dev/null +++ b/arch/ppc/coffboot/chrpmain.c @@ -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 index 000000000000..43ae4e0ec4a7 --- /dev/null +++ b/arch/ppc/coffboot/coffcrt0.S @@ -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 index 000000000000..cc638067d81f --- /dev/null +++ b/arch/ppc/coffboot/coffmain.c @@ -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); +} diff --git a/arch/ppc/coffboot/crt0.S b/arch/ppc/coffboot/crt0.S index 43ae4e0ec4a7..c43340594032 100644 --- a/arch/ppc/coffboot/crt0.S +++ b/arch/ppc/coffboot/crt0.S @@ -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 diff --git a/arch/ppc/coffboot/misc.S b/arch/ppc/coffboot/misc.S index df542a5223ec..7defc69e870d 100644 --- a/arch/ppc/coffboot/misc.S +++ b/arch/ppc/coffboot/misc.S @@ -14,23 +14,26 @@ */ .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 index 000000000000..120cc1d89739 --- /dev/null +++ b/arch/ppc/coffboot/mknote.c @@ -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 + +#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 index 000000000000..ed5dcdb1f469 --- /dev/null +++ b/arch/ppc/coffboot/no_initrd.c @@ -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 index 000000000000..172025802026 --- /dev/null +++ b/arch/ppc/coffboot/piggyback.c @@ -0,0 +1,65 @@ +#include + +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 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); +} + diff --git a/arch/ppc/coffboot/start.c b/arch/ppc/coffboot/start.c index 1f11edbec836..6fc1fc1fbcdc 100644 --- a/arch/ppc/coffboot/start.c +++ b/arch/ppc/coffboot/start.c @@ -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; } diff --git a/arch/ppc/common_defconfig b/arch/ppc/common_defconfig index b42df37faea8..4e5fbb6a04aa 100644 --- a/arch/ppc/common_defconfig +++ b/arch/ppc/common_defconfig @@ -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 diff --git a/arch/ppc/config.in b/arch/ppc/config.in index 8f24011b0abf..1f1bcd5320db 100644 --- a/arch/ppc/config.in +++ b/arch/ppc/config.in @@ -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' diff --git a/arch/ppc/defconfig b/arch/ppc/defconfig index b42df37faea8..4e5fbb6a04aa 100644 --- a/arch/ppc/defconfig +++ b/arch/ppc/defconfig @@ -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 diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index b45ac90cb571..fc0a5156eeb5 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -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 diff --git a/arch/ppc/kernel/checks.c b/arch/ppc/kernel/checks.c index 9bb8e690ee4a..841295d8227f 100644 --- a/arch/ppc/kernel/checks.c +++ b/arch/ppc/kernel/checks.c @@ -1,3 +1,4 @@ +#include #include #include #include diff --git a/arch/ppc/kernel/chrp_setup.c b/arch/ppc/kernel/chrp_setup.c index f80ad32365fe..2159e8133d39 100644 --- a/arch/ppc/kernel/chrp_setup.c +++ b/arch/ppc/kernel/chrp_setup.c @@ -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 diff --git a/arch/ppc/kernel/feature.c b/arch/ppc/kernel/feature.c index a9a30396a0b2..1e561dd3bdcc 100644 --- a/arch/ppc/kernel/feature.c +++ b/arch/ppc/kernel/feature.c @@ -8,85 +8,182 @@ * 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 #include #include #include #include +#include #include #include +#include #include #include #include -#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; iparent; } @@ -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); } diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index adcbb82423d0..21ec8504443e 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -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 */ diff --git a/arch/ppc/kernel/local_irq.h b/arch/ppc/kernel/local_irq.h index 5149c291ac75..e9c23aef84f0 100644 --- a/arch/ppc/kernel/local_irq.h +++ b/arch/ppc/kernel/local_irq.h @@ -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]; diff --git a/arch/ppc/kernel/mbx_setup.c b/arch/ppc/kernel/mbx_setup.c index 0f1eb3eb5f9c..20a1356b9821 100644 --- a/arch/ppc/kernel/mbx_setup.c +++ b/arch/ppc/kernel/mbx_setup.c @@ -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) diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index 9425127147e5..223f5c98456c 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -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 diff --git a/arch/ppc/kernel/mk_defs.c b/arch/ppc/kernel/mk_defs.c index a3977193a3fe..9cf0eb8349de 100644 --- a/arch/ppc/kernel/mk_defs.c +++ b/arch/ppc/kernel/mk_defs.c @@ -8,7 +8,7 @@ * #defines from the assembly-language output. */ -#include +#include #include #include #include @@ -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); diff --git a/arch/ppc/kernel/openpic.c b/arch/ppc/kernel/openpic.c index 9fb8f274bda4..f93945dd657f 100644 --- a/arch/ppc/kernel/openpic.c +++ b/arch/ppc/kernel/openpic.c @@ -5,6 +5,12 @@ * * Fixed up IPI and restructured a bit * Cort Dougan + * + * 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 + * 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 @@ -21,10 +27,17 @@ #include #include #include "open_pic.h" +#ifdef __powerpc__ +#include +#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;jn_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)); } /* diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index 39b2337fa533..058dc1f511e7 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -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) diff --git a/arch/ppc/kernel/pmac_pci.c b/arch/ppc/kernel/pmac_pci.c index 089169e37a0e..462b92bc70c7 100644 --- a/arch/ppc/kernel/pmac_pci.c +++ b/arch/ppc/kernel/pmac_pci.c @@ -28,6 +28,18 @@ 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;iio_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;ichild, 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); } diff --git a/arch/ppc/kernel/pmac_pic.c b/arch/ppc/kernel/pmac_pic.c index a1610c445bd0..083e043e8b98 100644 --- a/arch/ppc/kernel/pmac_pic.c +++ b/arch/ppc/kernel/pmac_pic.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -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, diff --git a/arch/ppc/kernel/pmac_setup.c b/arch/ppc/kernel/pmac_setup.c index 31eb31e8c2d7..e8fc30eb87f9 100644 --- a/arch/ppc/kernel/pmac_setup.c +++ b/arch/ppc/kernel/pmac_setup.c @@ -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 diff --git a/arch/ppc/kernel/pmac_support.c b/arch/ppc/kernel/pmac_support.c index 0196c5eb64a6..698363261b88 100644 --- a/arch/ppc/kernel/pmac_support.c +++ b/arch/ppc/kernel/pmac_support.c @@ -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 #include #include #include +#include +#include #include #include #include @@ -13,6 +22,10 @@ #include #include #include +#include +#include + +#undef DEBUG /* * Read and write the non-volatile RAM on PowerMacs and CHRP machines. @@ -20,24 +33,236 @@ 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; iname, "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; iaddrs[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); +} + diff --git a/arch/ppc/kernel/ppc-stub.c b/arch/ppc/kernel/ppc-stub.c index ac18a8c14e1a..49292adc0f63 100644 --- a/arch/ppc/kernel/ppc-stub.c +++ b/arch/ppc/kernel/ppc-stub.c @@ -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 diff --git a/arch/ppc/kernel/ppc_asm.tmpl b/arch/ppc/kernel/ppc_asm.tmpl index e3004c8f64de..0d8f00b121da 100644 --- a/arch/ppc/kernel/ppc_asm.tmpl +++ b/arch/ppc/kernel/ppc_asm.tmpl @@ -64,3 +64,36 @@ #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 diff --git a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c index b8dd53eccf15..813179276e97 100644 --- a/arch/ppc/kernel/ppc_htab.c +++ b/arch/ppc/kernel/ppc_htab.c @@ -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; diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index 3410c32f877a..21302ad9bfb0 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -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); diff --git a/arch/ppc/kernel/prep_pci.c b/arch/ppc/kernel/prep_pci.c index 8627633381ed..2932aedd5a80 100644 --- a/arch/ppc/kernel/prep_pci.c +++ b/arch/ppc/kernel/prep_pci.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -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); diff --git a/arch/ppc/kernel/prep_setup.c b/arch/ppc/kernel/prep_setup.c index 80408f73ca67..10e1dc677bbb 100644 --- a/arch/ppc/kernel/prep_setup.c +++ b/arch/ppc/kernel/prep_setup.c @@ -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 } diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c index 9041fe3be276..0a6b08e66ec3 100644 --- a/arch/ppc/kernel/process.c +++ b/arch/ppc/kernel/process.c @@ -43,9 +43,11 @@ #include 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, ¤t->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, ¤t->tss.vr, sizeof(p->tss.vr)); + p->tss.vscr = current->tss.vscr; + childregs->msr &= ~MSR_VEC; +#endif /* CONFIG_ALTIVEC */ + memcpy(&p->tss.fpr, ¤t->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: diff --git a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c index fa1d8cd410e6..f4676c8d99c2 100644 --- a/arch/ppc/kernel/prom.c +++ b/arch/ppc/kernel/prom.c @@ -26,6 +26,7 @@ #include #include #include +#include /* * 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>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=regpsize) || ((mask & *map) != (mask & reg[i]))) + found = 0; + map++; + map_size--; + } + for (i=0; iparent; + } 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); } } diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 6310c7514695..f66c5b6de6e9 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -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 */ diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c index 05a48d1b44f8..1684fd31559e 100644 --- a/arch/ppc/kernel/signal.c +++ b/arch/ppc/kernel/signal.c @@ -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)) diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c index 27033e8bfd8d..684805f6758b 100644 --- a/arch/ppc/kernel/smp.c +++ b/arch/ppc/kernel/smp.c @@ -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 diff --git a/arch/ppc/kernel/syscalls.c b/arch/ppc/kernel/syscalls.c index 3aa0becef6fb..612b7667441a 100644 --- a/arch/ppc/kernel/syscalls.c +++ b/arch/ppc/kernel/syscalls.c @@ -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; } diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index c33bff3e0b49..8b119e24000b 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -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) diff --git a/arch/ppc/lib/string.S b/arch/ppc/lib/string.S index 8d7bf06c4d00..9d605979d25e 100644 --- a/arch/ppc/lib/string.S +++ b/arch/ppc/lib/string.S @@ -12,6 +12,11 @@ #include #include +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 diff --git a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c index 2e66dced65d5..103f039cabc1 100644 --- a/arch/ppc/mm/fault.c +++ b/arch/ppc/mm/fault.c @@ -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); diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index c672c86151e1..9a257c82c7b8 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -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) diff --git a/arch/ppc/pmac_defconfig b/arch/ppc/pmac_defconfig index c63ca94797f9..4e5fbb6a04aa 100644 --- a/arch/ppc/pmac_defconfig +++ b/arch/ppc/pmac_defconfig @@ -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 diff --git a/arch/ppc/xmon/start.c b/arch/ppc/xmon/start.c index 0590b6eeaae1..18d17bd394a3 100644 --- a/arch/ppc/xmon/start.c +++ b/arch/ppc/xmon/start.c @@ -11,16 +11,30 @@ #include #include #include +#include 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) { diff --git a/arch/sparc64/kernel/psycho.c b/arch/sparc64/kernel/psycho.c index 07bafd543c06..1f3ee859e953 100644 --- a/arch/sparc64/kernel/psycho.c +++ b/arch/sparc64/kernel/psycho.c @@ -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 diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index 9a5e5cec0b9c..3fd6b4c1e8ed 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -43,6 +43,7 @@ #endif #ifdef CONFIG_PCI #include +#include #endif #include #include @@ -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 */ diff --git a/drivers/block/ide-cd.c b/drivers/block/ide-cd.c index 28415078077c..802d311b4248 100644 --- a/drivers/block/ide-cd.c +++ b/drivers/block/ide-cd.c @@ -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; diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 0c0b80e1157e..9f4c7cbb69d6 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -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: diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index 0c98ace54b5d..7c2b45fd439c 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -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) diff --git a/drivers/macintosh/mac_keyb.c b/drivers/macintosh/mac_keyb.c index cf58421c2812..ab90dcef6492 100644 --- a/drivers/macintosh/mac_keyb.c +++ b/drivers/macintosh/mac_keyb.c @@ -24,6 +24,7 @@ * - Hunter digital (NoHandsMouse) * - Kensignton TurboMouse 5 (needs testing) * - Mouse Systems A3 mice and trackballs + * - MacAlly 2-buttons mouse (needs testing) * * 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)); diff --git a/drivers/macintosh/macio-adb.c b/drivers/macintosh/macio-adb.c index dcca410d94c9..a1cc769c0e4c 100644 --- a/drivers/macintosh/macio-adb.c +++ b/drivers/macintosh/macio-adb.c @@ -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) diff --git a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c index ea8a6f74df0a..238360be99d3 100644 --- a/drivers/macintosh/macserial.c +++ b/drivers/macintosh/macserial.c @@ -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; icontents) >> 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; in_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; istate != 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(¤t->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; idev_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; idev_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; } diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c index 0316b23400ea..25569d0b24d7 100644 --- a/drivers/macintosh/via-cuda.c +++ b/drivers/macintosh/via-cuda.c @@ -21,6 +21,7 @@ #include #include #include +#include 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 +} diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index ce8a2c3fd194..9559c8b18006 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -10,6 +10,12 @@ * 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 #include @@ -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; } diff --git a/drivers/net/Config.in b/drivers/net/Config.in index dbb376dd232b..8d66080f97d6 100644 --- a/drivers/net/Config.in +++ b/drivers/net/Config.in @@ -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 diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 3983a614f74f..7b9856483ea2 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -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 diff --git a/drivers/net/Space.c b/drivers/net/Space.c index 740428ede00d..2147b9b0649b 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -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 diff --git a/drivers/net/de4x5.c b/drivers/net/de4x5.c index 62a3f32e386d..0bd71464f6e5 100644 --- a/drivers/net/de4x5.c +++ b/drivers/net/de4x5.c @@ -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 index 000000000000..ebf70df335b5 --- /dev/null +++ b/drivers/net/gmac.c @@ -0,0 +1,614 @@ +/* + * Network device driver for the GMAC ethernet controller on + * Apple G4 Powermacs. + * + * Copyright (C) 2000 Paul Mackerras. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 index 000000000000..2e50f6072e8a --- /dev/null +++ b/drivers/net/gmac.h @@ -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 */ + diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 3150b2b32537..f719e33909fe 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -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)) { diff --git a/drivers/sound/dmasound.c b/drivers/sound/dmasound.c index 1a782f20ae51..084de211e520 100644 --- a/drivers/sound/dmasound.c +++ b/drivers/sound/dmasound.c @@ -115,6 +115,7 @@ History: #include #include #include +#include #include "awacs_defs.h" #include #include @@ -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 */ diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 24cb4557258c..14a7be2062ea 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -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)) diff --git a/fs/read_write.c b/fs/read_write.c index b6315ad24427..e2b5b789977b 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -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 */ diff --git a/include/asm-ppc/bootx.h b/include/asm-ppc/bootx.h index 5674bd0f9e51..90c79cdb795e 100644 --- a/include/asm-ppc/bootx.h +++ b/include/asm-ppc/bootx.h @@ -133,4 +133,3 @@ typedef struct boot_infos #endif #endif - \ No newline at end of file diff --git a/include/asm-ppc/elf.h b/include/asm-ppc/elf.h index 002736abf1ce..0e5567c30417 100644 --- a/include/asm-ppc/elf.h +++ b/include/asm-ppc/elf.h @@ -5,9 +5,11 @@ * ELF register definitions.. */ #include +#include #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)? \ diff --git a/include/asm-ppc/feature.h b/include/asm-ppc/feature.h index 07b10e8bc66c..78d73b5327bd 100644 --- a/include/asm-ppc/feature.h +++ b/include/asm-ppc/feature.h @@ -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 index 000000000000..647c63261592 --- /dev/null +++ b/include/asm-ppc/heathrow.h @@ -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 */ diff --git a/include/asm-ppc/ide.h b/include/asm-ppc/ide.h index 77c264c2366d..689cc93b24e9 100644 --- a/include/asm-ppc/ide.h +++ b/include/asm-ppc/ide.h @@ -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 diff --git a/include/asm-ppc/io.h b/include/asm-ppc/io.h index 0d4610ec66ca..6e735170d424 100644 --- a/include/asm-ppc/io.h +++ b/include/asm-ppc/io.h @@ -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)) diff --git a/include/asm-ppc/keyboard.h b/include/asm-ppc/keyboard.h index 2f4c21e48010..f5c5bc97b915 100644 --- a/include/asm-ppc/keyboard.h +++ b/include/asm-ppc/keyboard.h @@ -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() diff --git a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h index 78f35e285817..42b8ceeec079 100644 --- a/include/asm-ppc/machdep.h +++ b/include/asm-ppc/machdep.h @@ -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 */ diff --git a/include/asm-ppc/mediabay.h b/include/asm-ppc/mediabay.h index 04792d15ed50..d6b1d03bfde9 100644 --- a/include/asm-ppc/mediabay.h +++ b/include/asm-ppc/mediabay.h @@ -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); diff --git a/include/asm-ppc/nvram.h b/include/asm-ppc/nvram.h index ea7bf19146f6..2e61bb8f44cd 100644 --- a/include/asm-ppc/nvram.h +++ b/include/asm-ppc/nvram.h @@ -14,13 +14,13 @@ #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) @@ -30,4 +30,30 @@ #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 diff --git a/include/asm-ppc/ohare.h b/include/asm-ppc/ohare.h index ffc4ef10bf50..1303e5869be1 100644 --- a/include/asm-ppc/ohare.h +++ b/include/asm-ppc/ohare.h @@ -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 */ @@ -13,21 +16,21 @@ * 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. diff --git a/include/asm-ppc/page.h b/include/asm-ppc/page.h index 12e576e8555a..46ad64784afb 100644 --- a/include/asm-ppc/page.h +++ b/include/asm-ppc/page.h @@ -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 diff --git a/include/asm-ppc/pmu.h b/include/asm-ppc/pmu.h index 6991f2cd98a1..f6ee352e4088 100644 --- a/include/asm-ppc/pmu.h +++ b/include/asm-ppc/pmu.h @@ -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__ diff --git a/include/asm-ppc/processor.h b/include/asm-ppc/processor.h index afac1bc8483a..86d6f0951748 100644 --- a/include/asm-ppc/processor.h +++ b/include/asm-ppc/processor.h @@ -7,6 +7,7 @@ #include /* 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 + +#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 */ diff --git a/include/asm-ppc/prom.h b/include/asm-ppc/prom.h index 20a8519daaf5..40deb121b0fe 100644 --- a/include/asm-ppc/prom.h +++ b/include/asm-ppc/prom.h @@ -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, diff --git a/include/asm-ppc/system.h b/include/asm-ppc/system.h index 09790d0cdb33..68c2a0e537c1 100644 --- a/include/asm-ppc/system.h +++ b/include/asm-ppc/system.h @@ -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 *, ...); diff --git a/include/asm-ppc/termbits.h b/include/asm-ppc/termbits.h index 11b4c513a5dc..9bba8286120d 100644 --- a/include/asm-ppc/termbits.h +++ b/include/asm-ppc/termbits.h @@ -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 diff --git a/include/asm-ppc/types.h b/include/asm-ppc/types.h index 86fa349d375f..bd1a0c3ca505 100644 --- a/include/asm-ppc/types.h +++ b/include/asm-ppc/types.h @@ -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__ */ diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h index 4f0f51f30c30..79031f79a2ed 100644 --- a/include/asm-sparc64/pbm.h +++ b/include/asm-sparc64/pbm.h @@ -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. diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 922ad102c22d..d644b365743e 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -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); } -- 2.39.5