]> git.neil.brown.name Git - history.git/commitdiff
Linux 2.2.14pre5 2.2.14pre5
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:20:13 +0000 (15:20 -0500)
committerAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:20:13 +0000 (15:20 -0500)
o Ext2fs race fixes (Andrea Arcangeli)
o Quota fixes (Jan Kara)
o IPC msg accounting fixes (Andi Kleen)
o Inode leak fixes (Andrea Arcangeli)
o Transparent proxy bug fix (Andi Kleen)
o PowerPC updates (Cort Dougan)
o NCR885E PPC driver (dan@synergymicro)
o SunRPC initialisation fix (Trond)
o SMBfs long directory fix (Pete Hilton)
o Blacklist update (Thorsten Kranzkowski)
o Bus mouse fixes (Alexis Wilke)
o Lance unload fixes (Mika Kuoppala)
o Dcache hash sizing changes (Andrea Arcangeli)

55 files changed:
CREDITS
arch/ppc/Makefile
arch/ppc/boot/Makefile
arch/ppc/boot/head.S
arch/ppc/chrpboot/main.c
arch/ppc/coffboot/main.c
arch/ppc/common_defconfig
arch/ppc/config.in
arch/ppc/defconfig
arch/ppc/gemini_defconfig [new file with mode: 0644]
arch/ppc/kernel/Makefile
arch/ppc/kernel/chrp_setup.c
arch/ppc/kernel/gemini_pci.c [new file with mode: 0644]
arch/ppc/kernel/gemini_prom.S [new file with mode: 0644]
arch/ppc/kernel/gemini_setup.c [new file with mode: 0644]
arch/ppc/kernel/head.S
arch/ppc/kernel/open_pic.c
arch/ppc/kernel/openpic.c
arch/ppc/kernel/prep_pci.c
arch/ppc/kernel/prep_setup.c
arch/ppc/kernel/prom.c
arch/ppc/kernel/setup.c
arch/ppc/kernel/smp.c
arch/ppc/mm/init.c
drivers/char/busmouse.c
drivers/char/console.c
drivers/char/msbusmouse.c
drivers/net/Config.in
drivers/net/Makefile
drivers/net/Space.c
drivers/net/lance.c
drivers/net/ncr885_debug.h [new file with mode: 0644]
drivers/net/ncr885e.c [new file with mode: 0644]
drivers/net/ncr885e.h [new file with mode: 0644]
drivers/scsi/scsi.c
fs/dcache.c
fs/dquot.c
fs/ext2/balloc.c
fs/ext2/fsync.c
fs/ext2/inode.c
fs/inode.c
fs/isofs/inode.c
fs/isofs/rock.c
fs/lockd/mon.c
fs/smbfs/proc.c
include/asm-ppc/gemini.h [new file with mode: 0644]
include/asm-ppc/gemini_serial.h [new file with mode: 0644]
include/asm-ppc/keyboard.h
include/asm-ppc/m48t35.h [new file with mode: 0644]
include/asm-ppc/processor.h
include/asm-ppc/serial.h
include/linux/dcache.h
include/linux/msg.h
ipc/msg.c
net/ipv4/tcp_ipv4.c

diff --git a/CREDITS b/CREDITS
index f3f8fdfd66f0a76574a85d15206a97ea946fce82..0bdd7c53b64dec570a4f8870703573f88ecfdc32 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -997,6 +997,7 @@ S: Austria
 
 N: Jan Kara
 E: jack@atrey.karlin.mff.cuni.cz
+E: jack@suse.cz
 D: Quota fixes for 2.2 kernel
 D: Few other fixes in filesystem area (isofs, loopback)
 W: http://atrey.karlin.mff.cuni.cz/~jack/
index 47dce28afc075c7252953ec3aaa4f7b6c3cd73f0..ee955161e48f3381df6cd726575cb6f3bd327be6 100644 (file)
@@ -112,6 +112,10 @@ apus_config:
        rm -f .config arch/ppc/defconfig
        ln -s apus_defconfig arch/ppc/defconfig
 
+gemini_config:
+       rm -f .config arch/ppc/defconfig
+       ln -s gemini_defconfig arch/ppc/defconfig
+
 tags:
        etags */*.c include/{asm,linux}/*.h arch/ppc/kernel/*.{c,h}
 
index 493b362d6e631265776a0d0ead1def146762f5e2..41a8a915f4780503c8a332d01217ca5588e2762d 100644 (file)
@@ -25,12 +25,22 @@ ZSZ = 0
 IOFF = 0
 ISZ = 0
 
+ifeq ($(CONFIG_ALL_PPC),y)
+CONFIG_PREP=y
+endif
+
 ifeq ($(CONFIG_SMP),y)
 TFTPIMAGE=/tftpboot/zImage.prep.smp$(MSIZE)
 else
 TFTPIMAGE=/tftpboot/zImage.prep$(MSIZE)
 endif
 
+ifeq ($(CONFIG_SMP),y)
+TFTPSIMAGE=/tftpboot/sImage.smp
+else
+TFTPSIMAGE=/tftpboot/sImage
+endif
+
 ifeq ($(CONFIG_PPC64),y)
 MSIZE=.64
 else
@@ -46,14 +56,10 @@ CFLAGS = -O2 -DSTDC_HEADERS -fno-builtin -I$(TOPDIR)/include
 OBJCOPY = $(CROSS_COMPILE)objcopy
 OBJCOPY_ARGS = -O elf32-powerpc
 
-ifeq ($(CONFIG_SMP),y)
-CFLAGS += -D__SMP__
-endif
-
 OBJECTS += vreset.o kbd.o of1275.o
- ifeq ($(CONFIG_SERIAL_CONSOLE),y)
-  OBJECTS += ns16550.o
- endif
+ifeq ($(CONFIG_SERIAL_CONSOLE),y)
+OBJECTS += ns16550.o
+endif
 
 all:   zImage
 
@@ -75,11 +81,20 @@ zvmlinux.initrd: zvmlinux
                zvmlinux.initrd.tmp $@
        rm zvmlinux.initrd.tmp
 
-zImage: zvmlinux mkprep
+zImage: zvmlinux mkprep sImage
+ifdef CONFIG_PREP
        ./mkprep -pbp zvmlinux zImage
+endif
+
+sImage: ../../../vmlinux
+ifdef CONFIG_GEMINI
+       $(OBJCOPY) -I elf32-powerpc -O binary ../../../vmlinux sImage
+endif
 
 zImage.initrd: zvmlinux.initrd mkprep
+ifdef CONFIG_PREP
        ./mkprep -pbp zvmlinux.initrd zImage.initrd
+endif
 
 zvmlinux: $(OBJECTS) ../coffboot/vmlinux.gz
 #
@@ -108,7 +123,12 @@ mkprep : mkprep.c
        $(HOSTCC) -o mkprep mkprep.c
 
 znetboot : zImage
+ifdef CONFIG_PREP
        cp zImage $(TFTPIMAGE)
+endif
+ifdef CONFIG_GEMINI
+       cp sImage $(TFTPSIMAGE)
+endif
 
 znetboot.initrd : zImage.initrd
        cp zImage.initrd $(TFTPIMAGE)
index 552e82fa1c7b7721c0baaebfda01221086a9f115..79377a2ac6676ed77b73e747d09901b53d3f81e4 100644 (file)
@@ -6,7 +6,7 @@
        .text
 
 /*
- * $Id: head.S,v 1.31 1999/04/22 06:32:00 davem Exp $
+ * $Id: head.S,v 1.33 1999/09/08 01:06:58 cort Exp $
  *     
  * Boot loader philosophy:
  *      ROM loads us to some arbitrary location
@@ -125,12 +125,11 @@ start_ldr:
         * get start address of kernel code which is stored as a coff
         * entry.  see boot/head.S -- Cort 
         */
-       li      r9,0x0
-       lwz     r9,0(r9)
+       li      r9,0x4
        mtlr    r9
-       li      r9,0
        lis     r10,0xdeadc0de@h
        ori     r10,r10,0xdeadc0de@l
+       li      r9,0
        stw     r10,0(r9)
 /*
  * The Radstone firmware maps PCI memory at 0xc0000000 using BAT2
index 3b42ed1e7e379874dbddb5891e21dd11c2739608..80db69a7b10896bc00b90c622a9fc66602a57a76 100644 (file)
@@ -68,7 +68,7 @@ chrpboot(int a1, int a2, void *prom)
 
     flush_cache(dst, len);
     
-    sa = *(unsigned long *)PROG_START+PROG_START;
+    sa = (unsigned long)PROG_START;
     printf("start address = 0x%x\n\r", sa);
 
     (*(void (*)())sa)(0, 0, prom, a1, a2);
index 51e931f5e3fa708b1bd4036fd096b6b6efa04473..9692da0482a4f45cc1d8696b1c7ff71e0d2a2400 100644 (file)
@@ -100,7 +100,7 @@ coffboot(int a1, int a2, void *prom)
 
     flush_cache(dst, len);
 
-    sa = *(unsigned *)dst + PROG_START;
+    sa = (unsigned long)dst;
     printf("start address = 0x%x\n", sa);
 
 #if 0
@@ -165,7 +165,6 @@ void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
        printf("gunzip: ran out of data in header\n");
        exit();
     }
-
     s.zalloc = zalloc;
     s.zfree = zfree;
     r = inflateInit2(&s, -MAX_WBITS);
index 2fef5a644c5834a6e84e8cc9e8f10e6676c79350..b9bb6c56b4cecdc3434c2dcc16de457bb55348b2 100644 (file)
@@ -7,13 +7,13 @@
 #
 CONFIG_PPC=y
 CONFIG_6xx=y
-# CONFIG_PPC64 is not set
 # CONFIG_8xx is not set
 # CONFIG_PMAC is not set
 # CONFIG_PREP is not set
 # CONFIG_CHRP is not set
 CONFIG_ALL_PPC=y
 # CONFIG_APUS is not set
+# CONFIG_GEMINI is not set
 # CONFIG_MBX is not set
 # CONFIG_SMP is not set
 CONFIG_6xx=y
@@ -179,6 +179,7 @@ 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
@@ -197,6 +198,7 @@ CONFIG_AIC7XXX_RESET_DELAY=15
 # CONFIG_SCSI_INIA100 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_SYM53C8XX=y
@@ -244,6 +246,7 @@ CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
 CONFIG_MACE=y
 CONFIG_BMAC=y
+# CONFIG_NCR885E is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
@@ -258,6 +261,7 @@ CONFIG_PCNET32=y
 # 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
@@ -302,7 +306,9 @@ 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
@@ -337,6 +343,7 @@ CONFIG_FB_MATROX=y
 CONFIG_FB_MATROX_MYSTIQUE=y
 CONFIG_FB_MATROX_G100=y
 # CONFIG_FB_MATROX_MULTIHEAD is not set
+# CONFIG_FB_ATY is not set
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
 CONFIG_FBCON_CFB8=y
@@ -493,8 +500,10 @@ 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
@@ -503,13 +512,13 @@ CONFIG_SOUND_OSS=y
 # CONFIG_SOUND_DMAP is not set
 # CONFIG_SOUND_PAS is not set
 # CONFIG_SOUND_SB is not set
-# CONFIG_SOUND_ADLIB 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
@@ -522,6 +531,7 @@ CONFIG_SOUND_CS4232=m
 # 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
index 2865e34b5b157470d6530e7b78c9d84d4dcaaf0d..f653a4e7edb49859f85cdafd8f8a4cd1350e7d65 100644 (file)
@@ -9,7 +9,6 @@ comment 'Platform support'
 define_bool CONFIG_PPC y
 choice 'Processor type' \
        "6xx/7xx                CONFIG_6xx \
-        630/Power3(64-Bit)     CONFIG_PPC64 \
         860/821                CONFIG_8xx" 6xx/7xx
 
 choice 'Machine Type' \
@@ -18,6 +17,7 @@ choice 'Machine Type' \
         CHRP           CONFIG_CHRP \
         PowerMac/PReP/CHRP     CONFIG_ALL_PPC \
         APUS           CONFIG_APUS \
+        Gemini         CONFIG_GEMINI \
         MBX            CONFIG_MBX" PowerMac
 
 bool 'Symmetric multi-processing support' CONFIG_SMP
index 2fef5a644c5834a6e84e8cc9e8f10e6676c79350..b9bb6c56b4cecdc3434c2dcc16de457bb55348b2 100644 (file)
@@ -7,13 +7,13 @@
 #
 CONFIG_PPC=y
 CONFIG_6xx=y
-# CONFIG_PPC64 is not set
 # CONFIG_8xx is not set
 # CONFIG_PMAC is not set
 # CONFIG_PREP is not set
 # CONFIG_CHRP is not set
 CONFIG_ALL_PPC=y
 # CONFIG_APUS is not set
+# CONFIG_GEMINI is not set
 # CONFIG_MBX is not set
 # CONFIG_SMP is not set
 CONFIG_6xx=y
@@ -179,6 +179,7 @@ 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
@@ -197,6 +198,7 @@ CONFIG_AIC7XXX_RESET_DELAY=15
 # CONFIG_SCSI_INIA100 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_SYM53C8XX=y
@@ -244,6 +246,7 @@ CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
 CONFIG_MACE=y
 CONFIG_BMAC=y
+# CONFIG_NCR885E is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
@@ -258,6 +261,7 @@ CONFIG_PCNET32=y
 # 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
@@ -302,7 +306,9 @@ 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
@@ -337,6 +343,7 @@ CONFIG_FB_MATROX=y
 CONFIG_FB_MATROX_MYSTIQUE=y
 CONFIG_FB_MATROX_G100=y
 # CONFIG_FB_MATROX_MULTIHEAD is not set
+# CONFIG_FB_ATY is not set
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
 CONFIG_FBCON_CFB8=y
@@ -493,8 +500,10 @@ 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
@@ -503,13 +512,13 @@ CONFIG_SOUND_OSS=y
 # CONFIG_SOUND_DMAP is not set
 # CONFIG_SOUND_PAS is not set
 # CONFIG_SOUND_SB is not set
-# CONFIG_SOUND_ADLIB 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
@@ -522,6 +531,7 @@ CONFIG_SOUND_CS4232=m
 # 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
diff --git a/arch/ppc/gemini_defconfig b/arch/ppc/gemini_defconfig
new file mode 100644 (file)
index 0000000..349e955
--- /dev/null
@@ -0,0 +1,380 @@
+#
+# Automatically generated make config: don't edit
+#
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_6xx=y
+# CONFIG_8xx is not set
+# CONFIG_PMAC is not set
+# CONFIG_PREP is not set
+# CONFIG_CHRP is not set
+# CONFIG_ALL_PPC is not set
+# CONFIG_APUS is not set
+CONFIG_GEMINI=y
+# CONFIG_MBX is not set
+# CONFIG_SMP is not set
+CONFIG_MACH_SPECIFIC=y
+CONFIG_6xx=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KMOD=y
+CONFIG_PCI=y
+# CONFIG_PCI_QUIRKS is not set
+# CONFIG_PCI_OLD_PROC is not set
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+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_JAVA is not set
+# CONFIG_PARPORT is not set
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_FB is not set
+# CONFIG_PMAC_PBOOK is not set
+# CONFIG_MAC_KEYBOARD is not set
+# CONFIG_MAC_FLOPPY is not set
+# CONFIG_MAC_SERIAL is not set
+# CONFIG_ADBMOUSE is not set
+# CONFIG_PROC_DEVICETREE is not set
+# CONFIG_TOTALMP is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_MOTOROLA_HOTSWAP is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_IDE is not set
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_ONLY is not set
+
+#
+# Additional Block Devices
+#
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+CONFIG_PARIDE_PARPORT=y
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_NETLINK=y
+# CONFIG_RTNETLINK is not set
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_FIREWALL is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+CONFIG_IP_ALIAS=y
+CONFIG_SYN_COOKIES=y
+
+#
+# (it is safe to leave these untouched)
+#
+# CONFIG_INET_RARP is not set
+CONFIG_SKB_LARGE=y
+# CONFIG_IPV6 is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+# CONFIG_CPU_IS_SLOW is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=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
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_G_NCR5380_PORT is not set
+# CONFIG_SCSI_G_NCR5380_MEM is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 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_SYM53C8XX=y
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
+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_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_SEAGATE is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_MESH is not set
+# CONFIG_SCSI_MAC53C94 is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_ETHERTAP is not set
+# CONFIG_NET_SB1000 is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
+CONFIG_NCR885E=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 is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_RADIO is not set
+
+#
+# Token ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# 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
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Console drivers
+#
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+# CONFIG_MOUSE is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+
+#
+# Video For Linux
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Joystick support
+#
+# CONFIG_JOYSTICK is not set
+# CONFIG_DTLK is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_FT_NORMAL_DEBUG is not set
+# CONFIG_FT_FULL_DEBUG is not set
+# CONFIG_FT_NO_TRACE is not set
+# CONFIG_FT_NO_TRACE_AT_ALL is not set
+# CONFIG_FT_STD_FDC is not set
+# CONFIG_FT_MACH2 is not set
+# CONFIG_FT_PROBE_FC10 is not set
+# CONFIG_FT_ALT_FDC is not set
+
+#
+# USB drivers - not for the faint of heart
+#
+# CONFIG_USB is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_FAT_FS is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_EFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SUNRPC is not set
+# CONFIG_LOCKD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_BSD_DISKLABEL is not set
+CONFIG_MAC_PARTITION=y
+# CONFIG_SMD_DISKLABEL is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_NLS is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_KGDB is not set
+# CONFIG_XMON is not set
index 2c1e8233ddf7d05ea99e7ee747ff12c88511807c..b45ac90cb571cd0cbc9c23a1b99ebfe1ec0872fd 100644 (file)
@@ -40,7 +40,8 @@ O_OBJS += prep_time.o pmac_time.o chrp_time.o \
          pmac_setup.o pmac_support.o \
          prep_pci.o pmac_pci.o chrp_pci.o \
          residual.o prom.o openpic.o feature.o \
-         prep_nvram.o open_pic.o i8259.o pmac_pic.o indirect_pci.o
+         prep_nvram.o open_pic.o i8259.o pmac_pic.o indirect_pci.o \
+         gemini_pci.o gemini_prom.o gemini_setup.o
 OX_OBJS += chrp_setup.o prep_setup.o
 endif
 endif
index 9aed25d1c7a7479d772f280632050764d99e4b6b..8d2d4e9b8db10afbd55fa329ec6aa4fb6ee7ccef 100644 (file)
@@ -446,6 +446,7 @@ __initfunc(void
                        (*(unsigned long *)get_property(np,
                                                        "8259-interrupt-acknowledge", NULL));
        }
+       open_pic.irq_offset = 16;
        for ( i = 16 ; i < NR_IRQS ; i++ )
                irq_desc[i].ctl = &open_pic;
        /* openpic knows that it's at irq 16 offset
diff --git a/arch/ppc/kernel/gemini_pci.c b/arch/ppc/kernel/gemini_pci.c
new file mode 100644 (file)
index 0000000..2a9d56d
--- /dev/null
@@ -0,0 +1,273 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/malloc.h>
+
+#include <asm/machdep.h>
+#include <asm/gemini.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include "pci.h"
+
+#define pci_config_addr(bus,dev,offset) \
+        (0x80000000 | (bus<<16) | (dev<<8) | offset)
+
+
+int
+gemini_pcibios_read_config_byte(unsigned char bus, unsigned char dev,
+                                unsigned char offset, unsigned char *val)
+{
+       unsigned long reg;
+       reg = grackle_read( pci_config_addr( bus, dev, (offset & ~(0x3))));
+       *val = ((reg >> ((offset & 0x3) << 3)) & 0xff);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int
+gemini_pcibios_read_config_word(unsigned char bus, unsigned char dev,
+                                unsigned char offset, unsigned short *val)
+{
+       unsigned long reg;
+       reg = grackle_read( pci_config_addr( bus, dev, (offset & ~(0x3))));
+       *val = ((reg >> ((offset & 0x3) << 3)) & 0xffff);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int
+gemini_pcibios_read_config_dword(unsigned char bus, unsigned char dev,
+                                 unsigned char offset, unsigned int *val)
+{
+       *val = grackle_read( pci_config_addr( bus, dev, (offset & ~(0x3))));
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int
+gemini_pcibios_write_config_byte(unsigned char bus, unsigned char dev,
+                                 unsigned char offset, unsigned char val)
+{
+       unsigned long reg;
+       int shifts = offset & 0x3;
+
+       reg = grackle_read( pci_config_addr( bus, dev, (offset & ~(0x3))));
+       reg = (reg & ~(0xff << (shifts << 3))) | (val << (shifts << 3));
+       grackle_write( pci_config_addr( bus, dev, (offset & ~(0x3))), reg );
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int
+gemini_pcibios_write_config_word(unsigned char bus, unsigned char dev,
+                                 unsigned char offset, unsigned short val)
+{
+       unsigned long reg;
+       int shifts = offset & 0x3;
+
+       reg = grackle_read( pci_config_addr( bus, dev, (offset & ~(0x3))));
+       reg = (reg & ~(0xffff << (shifts << 3))) | (val << (shifts << 3));
+       grackle_write( pci_config_addr( bus, dev, (offset & ~(0x3))), reg );
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int
+gemini_pcibios_write_config_dword(unsigned char bus, unsigned char dev,
+                                  unsigned char offset, unsigned int val)
+{
+       grackle_write( pci_config_addr( bus, dev, (offset & ~(0x3))), val );
+       return PCIBIOS_SUCCESSFUL;
+}
+
+struct gemini_device {
+       unsigned short vendor, device;
+       unsigned char irq;
+       unsigned short cmd;
+       unsigned char cache_line, latency;
+       void (*init)(struct pci_dev *dev);
+};
+
+static struct gemini_device gemini_map[] = {
+       { PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C885, 11, 0x15, 32, 248, NULL },
+       { PCI_VENDOR_ID_NCR, 0x701, 10, 0, 0, 0, NULL },
+       { PCI_VENDOR_ID_TUNDRA, PCI_DEVICE_ID_TUNDRA_CA91C042, 3, 0, 0, 0, NULL },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_MPIC, 0xff, 0, 0, 0, NULL },
+       { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_670, 0xff, 0, 0, 0, NULL },
+       { PCI_VENDOR_ID_MOTOROLA, PCI_DEVICE_ID_MOTOROLA_MPC106, 0xff, 0, 0, 0, NULL },
+};
+
+static int gemini_map_count = (sizeof( gemini_map ) /
+                               sizeof( gemini_map[0] ));
+
+
+/*  This just sets up the known devices on the board. */
+__initfunc(static void mapin_device( struct pci_dev *dev ))
+{
+       struct gemini_device *p;
+       unsigned short cmd;
+       int i;
+  
+
+       for( i=0; i < gemini_map_count; i++ ) {
+               p = &(gemini_map[i]);
+    
+               if ( p->vendor == dev->vendor && 
+                    p->device == dev->device ) {
+     
+                       if (p->irq != 0xff) {
+                               pci_write_config_byte( dev, PCI_INTERRUPT_LINE, p->irq );
+                               dev->irq = p->irq;
+                       }
+
+                       if (p->cmd) {
+                               pci_read_config_word( dev, PCI_COMMAND, &cmd );
+                               pci_write_config_word( dev, PCI_COMMAND, (p->cmd|cmd));
+                       }
+
+                       if (p->cache_line)
+                               pci_write_config_byte( dev, PCI_CACHE_LINE_SIZE, p->cache_line );
+                       if (p->latency)
+                               pci_write_config_byte( dev, PCI_LATENCY_TIMER, p->latency );
+               }
+       }
+}
+
+#define KB 1024
+#define MB (KB*KB)
+
+#define ALIGN(val,align) (((val) + ((align) -1))&(~((align) -1)))
+#define MAX(a,b)   (((a) > (b)) ? (a) : (b))
+
+#define FIRST_IO_ADDR 0x10000
+#define FIRST_MEM_ADDR 0x02000000
+
+#define GEMINI_PCI_MEM_BASE (0xf0000000)
+#define GEMINI_PCI_IO_BASE  (0xfe800000)
+
+static unsigned long pci_mem_base = GEMINI_PCI_MEM_BASE;
+static unsigned long pci_io_base = GEMINI_PCI_IO_BASE;
+
+static unsigned int io_base = FIRST_IO_ADDR;
+static unsigned int mem_base = FIRST_MEM_ADDR;
+
+
+
+__initfunc(static void layout_dev( struct pci_dev *dev ))
+{
+       int i;
+       struct pci_bus *bus;
+       unsigned short cmd;
+       unsigned int reg, base, mask, size, alignto, type;
+
+       bus = dev->bus;
+
+       /* make any known settings happen */
+       mapin_device( dev );
+
+       gemini_pcibios_read_config_word( bus->number, dev->devfn, PCI_COMMAND, &cmd );
+
+       for( reg = PCI_BASE_ADDRESS_0, i=0; reg <= PCI_BASE_ADDRESS_5; reg += 4, i++ ) {
+    
+               /* MPIC already done */
+               if (dev->vendor == PCI_VENDOR_ID_IBM &&
+                   dev->device == PCI_DEVICE_ID_IBM_MPIC)
+                       return;
+
+               gemini_pcibios_write_config_dword( bus->number, dev->devfn, reg, 0xffffffff );
+               gemini_pcibios_read_config_dword( bus->number, dev->devfn, reg, &base );
+               if (!base) {
+                       dev->base_address[i] = 0;
+                       continue;
+               }
+
+               if (base & PCI_BASE_ADDRESS_SPACE_IO) {
+                       cmd |= PCI_COMMAND_IO;
+                       base &= PCI_BASE_ADDRESS_IO_MASK;
+                       mask = (~base << 1) | 0x1;
+                       size = (mask & base) & 0xffffffff;
+                       alignto = MAX(0x400, size);
+                       base = ALIGN(io_base, alignto);
+                       io_base = base + size;
+                       gemini_pcibios_write_config_dword( bus->number, dev->devfn, reg, 
+                                                          ((pci_io_base + base) & 0x00ffffff) | 0x1);
+                       dev->base_address[i] = (pci_io_base + base) | 0x1;
+               }
+
+               else {
+                       cmd |= PCI_COMMAND_MEMORY;
+                       type = base & PCI_BASE_ADDRESS_MEM_TYPE_MASK;
+                       mask = (~base << 1) | 0x1;
+                       size = (mask & base) & 0xffffffff;
+                       switch( type ) {
+
+                       case PCI_BASE_ADDRESS_MEM_TYPE_32:
+                               break;
+                       case PCI_BASE_ADDRESS_MEM_TYPE_64:
+                               printk("Warning: Ignoring 64-bit device; slot %d, function %d.\n",
+                                      PCI_SLOT( dev->devfn ), PCI_FUNC( dev->devfn ));
+                               reg += 4;
+                               continue;
+                       }
+
+                       alignto = MAX(0x1000, size);
+                       base = ALIGN(mem_base, alignto);
+                       mem_base = base + size;
+                       gemini_pcibios_write_config_dword( bus->number, dev->devfn,
+                                                          reg, (pci_mem_base + base));
+                       dev->base_address[i] = pci_mem_base + base;
+               }
+       }
+
+       if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
+               cmd |= PCI_COMMAND_IO;
+
+       gemini_pcibios_write_config_word( bus->number, dev->devfn, PCI_COMMAND,
+                                         (cmd|PCI_COMMAND_MASTER));
+
+}
+
+__initfunc(static void layout_bus( struct pci_bus *bus ))
+{
+       struct pci_dev *dev;
+
+       if (!bus->devices && !bus->children)
+               return;
+
+       io_base = ALIGN(io_base, 4*KB);
+       mem_base = ALIGN(mem_base, 4*KB);
+
+       for( dev = bus->devices; dev; dev = dev->sibling ) {
+               if (((dev->class >> 16) != PCI_BASE_CLASS_BRIDGE) ||
+                   ((dev->class >> 8) == PCI_CLASS_BRIDGE_OTHER))
+                       layout_dev( dev );
+       }
+}
+
+
+__initfunc(void gemini_pcibios_fixup(void))
+{
+       struct pci_bus *bus;
+       unsigned long orig_mem_base, orig_io_base;
+
+       orig_mem_base = pci_mem_base;
+       orig_io_base = pci_io_base;
+
+       for( bus = &pci_root; bus; bus = bus->children )
+               layout_bus( bus );
+
+       pci_mem_base = orig_mem_base;
+       pci_io_base = orig_io_base;
+
+
+}
+
+decl_config_access_method(gemini);
+
+/* The "bootloader" for Synergy boards does none of this for us, so we need to
+   lay it all out ourselves... --Dan */
+__initfunc(void gemini_setup_pci_ptrs(void))
+{
+
+       set_config_access_method(gemini);
+       ppc_md.pcibios_fixup = gemini_pcibios_fixup;
+}
diff --git a/arch/ppc/kernel/gemini_prom.S b/arch/ppc/kernel/gemini_prom.S
new file mode 100644 (file)
index 0000000..095f50e
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ *  arch/ppc/kernel/gemini_prom.S
+ *
+ *  Not really prom support code (yet), but sort of anti-prom code.  The current
+ *  bootloader does a number of things it shouldn't and doesn't do things that it
+ *  should.  The stuff in here is mainly a hodge-podge collection of setup code
+ *  to get the board up and running.
+ *    ---Dan
+ */
+
+#include "ppc_asm.tmpl"
+#include "ppc_defs.h"
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/gemini.h>
+
+#define HID0_ABE (1<<3)
+
+/*
+ *  On 750's the MMU is on when Linux is booted, so we need to clear out the
+ *  bootloader's BAT settings, make sure we're in supervisor state (gotcha!),
+ *  and turn off the MMU.
+ *
+ */
+
+_GLOBAL(gemini_prom_init)
+#ifdef __SMP__
+       /* Since the MMU's on, get stuff in rom space that we'll need */
+       lis     r4,GEMINI_CPUSTAT@h
+       ori     r4,r4,GEMINI_CPUSTAT@l
+       lbz     r5,0(r4)
+       andi.   r5,r5,3
+       mr      r24,r5          /* cpu # used later on */
+#endif
+       mfmsr   r4
+       li      r3,MSR_PR       /* ensure supervisor! */
+       ori     r3,r3,MSR_IR|MSR_DR
+       andc    r4,r4,r3
+       mtmsr   r4
+#if 0
+       /* zero out the bats now that the MMU is off */
+prom_no_mmu:   
+       li      r3,0
+        mtspr   IBAT0U,r3
+        mtspr   IBAT0L,r3
+        mtspr   IBAT1U,r3
+        mtspr   IBAT1L,r3
+        mtspr   IBAT2U,r3
+        mtspr   IBAT2L,r3
+        mtspr   IBAT3U,r3
+        mtspr   IBAT3L,r3
+
+        mtspr   DBAT0U,r3
+        mtspr   DBAT0L,r3
+        mtspr   DBAT1U,r3
+        mtspr   DBAT1L,r3
+        mtspr   DBAT2U,r3
+       mtspr   DBAT2L,r3
+        mtspr   DBAT3U,r3
+        mtspr   DBAT3L,r3
+#endif
+
+       /* the bootloader (as far as I'm currently aware) doesn't mess with page
+          tables, but since we're already here, might as well zap these, too */
+       li      r4,0
+       mtspr   SDR1,r4
+
+       li      r4,16
+       mtctr   r4
+       li      r3,0
+       li      r4,0
+3:     mtsrin  r3,r4
+       addi    r3,r3,1
+       bdnz    3b
+
+#ifdef __SMP__
+       /* The 750 book (and Mot/IBM support) says that this will "assist" snooping
+          when in SMP.  Not sure yet whether this should stay or leave... */
+       mfspr   r4,HID0
+       ori     r4,r4,HID0_ABE
+       mtspr   HID0,r4
+       sync
+#endif /* __SMP__ */
+       blr
+
+/*  apparently, SMon doesn't pay attention to HID0[SRST].  Disable the MMU and
+    branch to 0xfff00100 */
+_GLOBAL(_gemini_reboot)
+       lis     r5,GEMINI_BOOT_INIT@h
+       ori     r5,r5,GEMINI_BOOT_INIT@l
+       li      r6,MSR_IP
+       mtspr   SRR0,r5
+       mtspr   SRR1,r6
+       rfi
diff --git a/arch/ppc/kernel/gemini_setup.c b/arch/ppc/kernel/gemini_setup.c
new file mode 100644 (file)
index 0000000..d9abea7
--- /dev/null
@@ -0,0 +1,582 @@
+/*
+ *  linux/arch/ppc/kernel/setup.c
+ *
+ *  Copyright (C) 1995 Linus Torvalds
+ *  Adapted from 'alpha' version by Gary Thomas
+ *  Modified by Cort Dougan (cort@cs.nmt.edu)
+ *  Synergy Microsystems board support by Dan Cox (dan@synergymicro.com)
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h> 
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+#include <linux/console.h>
+#include <linux/openpic.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/m48t35.h>
+#include <asm/gemini.h>
+
+#include "time.h"
+#include "local_irq.h"
+#include "open_pic.h"
+
+void gemini_setup_pci_ptrs(void);
+
+static int l2_printed = 0;
+static unsigned char gemini_switch_map = 0;
+static char *gemini_board_families[] = {
+       "VGM", "VSS", "KGM", "VGR", "KSS"
+};
+
+static char *gemini_memtypes[] = {
+       "EDO DRAM, 60nS", "SDRAM, 15nS, CL=2", "SDRAM, 15nS, CL=2 with ECC"
+};
+
+static unsigned int cpu_7xx[16] = {
+       0, 15, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0
+};
+static unsigned int cpu_6xx[16] = {
+       0, 0, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 0, 12, 7, 0
+};
+
+void
+gemini_do_IRQ(struct pt_regs *regs, int cpu, int isfake)
+{
+       int irq, openpic_eoi_done = 0;
+       unsigned long bits = 0;
+       
+#ifdef __SMP__
+       if (cpu != 0) {
+               if (!isfake) {
+                       smp_message_recv();
+                       goto out;
+               }
+               goto out;
+       }
+       
+       {
+               unsigned int loops = 1000000;
+               while(test_bit(0, &global_irq_lock)) {
+                       if (smp_processor_id() == global_irq_holder) {
+                               printk("uh oh, it chokes!!! interrupt while we hold irq lock\n");
+                               break;
+                       }
+                       if (loops-- == 0) {
+                               printk("do_IRQ waiting for irq lock (holder=%d)\n", 
+                                      global_irq_holder);
+                       }
+               }
+       }
+#endif
+
+       irq = openpic_irq(cpu);
+       
+       if (irq == OPENPIC_VEC_SPURIOUS) {
+               ppc_spurious_interrupts++;
+               openpic_eoi_done = 1;
+               goto out;
+       }
+       
+       bits = 1UL<<irq;
+       irq -= OPENPIC_VEC_SOURCE;
+       
+       if (irq < 0) {
+               printk(KERN_DEBUG "Bogus interrupt %d from pc=%lx\n", irq,
+                      regs->nip);
+               ppc_spurious_interrupts++;
+       }
+       
+       else
+               ppc_irq_dispatch_handler(regs, irq);
+ out:
+       if (!openpic_eoi_done)
+               openpic_eoi(0);
+}
+
+static inline unsigned long _get_HID1(void)
+{
+       unsigned long val;
+
+       __asm__ __volatile__("mfspr %0,1009" : "=r" (val));
+       return val;
+}
+
+int
+gemini_get_cpuinfo(char *buffer)
+{
+       int i, len;
+       unsigned char reg, rev;
+       char *family;
+       unsigned int type;
+
+       reg = readb(GEMINI_FEAT);
+       family = gemini_board_families[((reg>>4) & 0xf)];
+       if (((reg>>4) & 0xf) > 2)
+               printk(KERN_ERR "cpuinfo(): unable to determine board family\n");
+
+       reg = readb(GEMINI_BREV);
+       type = (reg>>4) & 0xf;
+       rev = reg & 0xf;
+
+       reg = readb(GEMINI_BECO);
+
+       len = sprintf( buffer, "machine\t\t: Gemini %s%d, rev %c, eco %d\n", 
+                      family, type, (rev + 'A'), (reg & 0xf));
+
+       len += sprintf( buffer+len, "vendor\t\t: %s\n", 
+                       (_get_PVR() & (1<<15)) ? "IBM" : "Motorola");
+
+       reg = readb(GEMINI_MEMCFG);
+       len += sprintf( buffer+len, "memory type\t: %s\n", 
+                       gemini_memtypes[(reg & 0xc0)>>6]);
+       len += sprintf( buffer+len, "switches on\t: ");
+       for( i=0; i < 8; i++ ) {
+               if ( gemini_switch_map & (1<<i))
+                       len += sprintf(buffer+len, "%d ", i);
+       }
+       len += sprintf(buffer+len, "\n");
+
+       return len;
+}
+
+static u_char gemini_openpic_initsenses[] = {
+       1,
+       1,
+       1,
+       1,
+       0,
+       0,
+       1, /* remainder are level-triggered */
+};
+
+#define GEMINI_MPIC_ADDR (0xfcfc0000)
+#define GEMINI_MPIC_PCI_CFG (0x80005800)
+
+void __init gemini_openpic_init(void)
+{
+       grackle_write(GEMINI_MPIC_PCI_CFG + PCI_BASE_ADDRESS_0, 
+                     GEMINI_MPIC_ADDR);
+       grackle_write(GEMINI_MPIC_PCI_CFG + PCI_COMMAND, PCI_COMMAND_MEMORY);
+
+       OpenPIC = (volatile struct OpenPIC *) GEMINI_MPIC_ADDR;
+       OpenPIC_InitSenses = gemini_openpic_initsenses;
+       OpenPIC_NumInitSenses = sizeof( gemini_openpic_initsenses );
+
+       ioremap( GEMINI_MPIC_ADDR, sizeof( struct OpenPIC ));
+}
+
+
+extern unsigned long loops_per_sec;
+extern int root_mountflags;
+extern char cmd_line[];
+
+
+void __init
+gemini_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)
+{
+       unsigned int cpu;
+       extern char cmd_line[];
+
+
+       loops_per_sec = 50000000;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+       /* bootable off CDROM */
+       if (initrd_start)
+               ROOT_DEV = MKDEV(SCSI_CDROM_MAJOR, 0);
+       else
+#endif
+               ROOT_DEV = to_kdev_t(0x0801);
+
+       /* nothing but serial consoles... */  
+       sprintf(cmd_line, "%s console=ttyS0", cmd_line);
+
+
+       /* The user switches on the front panel can be used as follows:
+
+          Switch 0 - adds "debug" to the command line for verbose boot info,
+          Switch 7 - boots in single-user mode 
+
+       */
+
+       gemini_switch_map = readb( GEMINI_USWITCH );
+  
+       if ( gemini_switch_map & (1<<GEMINI_SWITCH_VERBOSE))
+               sprintf(cmd_line, "%s debug", cmd_line);
+
+       if ( gemini_switch_map & (1<<GEMINI_SWITCH_SINGLE_USER))
+               sprintf(cmd_line, "%s single", cmd_line);
+
+       printk("Boot arguments: %s\n", cmd_line);
+
+       /* mutter some kind words about who made the CPU */
+       cpu = _get_PVR();
+       printk("CPU manufacturer: %s [rev=%04x]\n", (cpu & (1<<15)) ? "IBM" :
+              "Motorola", (cpu & 0xffff));
+
+       /* take special pains to map the MPIC, since it isn't mapped yet */
+       gemini_openpic_init();
+
+       /* start the L2 */
+       gemini_init_l2();
+
+}
+
+
+int
+gemini_get_clock_speed(void)
+{
+       unsigned long hid1;
+       int clock;
+       unsigned char reg;
+  
+       hid1 = _get_HID1();
+       if ((_get_PVR()>>16) == 8)
+               hid1 = cpu_7xx[hid1];
+       else
+               hid1 = cpu_6xx[hid1];
+
+       reg = readb(GEMINI_BSTAT) & 0xc0;
+
+       switch( reg >> 2 ) {
+
+       case 0:
+       default:
+               clock = (hid1*100)/3;
+               break;
+  
+       case 1:
+               clock = (hid1*125)/3;
+               break;
+  
+       case 2:
+               clock = (hid1*50)/3;
+               break;
+       }
+
+       return clock;
+}
+
+
+#define L2CR_PIPE_LATEWR   (0x01800000)   /* late-write SRAM */
+#define L2CR_L2CTL         (0x00100000)   /* RAM control */
+#define L2CR_INST_DISABLE  (0x00400000)   /* disable for insn's */
+#define L2CR_L2I           (0x00200000)   /* global invalidate */
+#define L2CR_L2E           (0x80000000)   /* enable */
+#define L2CR_L2WT          (0x00080000)   /* write-through */
+
+void __init gemini_init_l2(void)
+{
+       unsigned char reg;
+       unsigned long cache;
+       int speed;
+
+       reg = readb(GEMINI_L2CFG);
+
+       /* 750's L2 initializes differently from a 604's.  Also note that a Grackle
+          bug will hang a dual-604 board, so make sure that doesn't happen by not
+          turning on the L2 */
+       if ( _get_PVR() >> 16 != 8 ) {
+     
+               /* check for dual cpus and cry sadly about the loss of an L2... */
+               if ((( readb(GEMINI_CPUSTAT) & 0x0c ) >> 2) != 1) 
+                       printk("Sorry. Your dual-604 does not allow the L2 to be enabled due "
+                              "to a Grackle bug.\n");
+               else if ( reg & GEMINI_L2_SIZE_MASK ) {
+                       printk("Enabling 604 L2 cache: %dKb\n", 
+                              (128<<((reg & GEMINI_L2_SIZE_MASK)>>6)));
+                       writeb( 1, GEMINI_L2CFG );
+               }
+       }
+
+       /* do a 750 */
+       else {
+               /* Synergy's first round of 750 boards had the L2 size stuff into the
+                  board register above.  If it's there, it's used; if not, the
+                  standard default is 1Mb.  The L2 type, I'm told, is "most likely
+                  probably always going to be late-write".  --Dan */
+
+               if (reg & 0xc0) {
+                       if (!l2_printed) {
+                               printk("Enabling 750 L2 cache: %dKb\n", 
+                                      (128 << ((reg & 0xc0)>>6)));
+                               l2_printed=1;
+                       }
+    
+                       /* take the size given */
+                       cache = (((reg>>6) & 0x3)<<28);
+               }
+               else
+                       /* default of 1Mb */
+                       cache = 0x3<<28;
+               reg &= 0x3;
+
+               /* a cache ratio of 1:1 and CPU clock speeds in excess of 300Mhz are bad
+                  things.  If found, tune it down to 1:1.5.  -- Dan */
+               if (!reg) {
+
+                       speed = gemini_get_clock_speed();
+   
+                       if (speed >= 300) {
+                               printk("Warning:  L2 ratio is 1:1 on a %dMhz processor.  Dropping to 1:1.5.\n",
+                                      speed );
+                               printk("Contact Synergy Microsystems for an ECO to fix this problem\n");
+                               reg = 0x1;
+                       }
+               }
+
+               /* standard stuff */
+               cache |= ((1<<reg)<<25);
+#ifdef __SMP__
+               /* A couple errata for the 750's (both IBM and Motorola silicon)
+                  note that you can get missed cache lines on MP implementations.
+                  The workaround - if you call it that - is to make the L2
+                  write-through.  This is fixed in IBM's 3.1 rev (I'm told), but
+                  for now, always make 2.x versions use L2 write-through. --Dan */
+               if (((_get_PVR()>>8) & 0xf) <= 2)
+                       cache |= L2CR_L2WT;
+#endif
+               cache |= L2CR_PIPE_LATEWR|L2CR_L2CTL|L2CR_INST_DISABLE;
+               _set_L2CR(0);
+               _set_L2CR(cache|L2CR_L2I|L2CR_L2E);
+       }
+}
+
+void
+gemini_restart(char *cmd)
+{
+       __cli();
+       /* make a clean restart, not via the MPIC */
+       _gemini_reboot();
+       for(;;);
+}
+
+void
+gemini_power_off(void)
+{
+       for(;;);
+}
+
+void
+gemini_halt(void)
+{
+       gemini_restart(NULL);
+}
+
+void __init gemini_init_IRQ(void)
+{
+       int i;
+
+       /* gemini has no 8259 */
+       open_pic.irq_offset = 0;
+       for( i=0; i < OPENPIC_VEC_SPURIOUS; i++ ) 
+               irq_desc[i].ctl = &open_pic;
+       openpic_init(1);
+#ifdef __SMP__
+       request_irq(OPENPIC_VEC_IPI, openpic_ipi_action, 0, "IPI0", 0);
+#endif /* __SMP__ */
+}
+
+#define gemini_rtc_read(x)       (readb(GEMINI_RTC+(x)))
+#define gemini_rtc_write(val,x)  (writeb((val),(GEMINI_RTC+(x))))
+
+/* ensure that the RTC is up and running */
+void __init gemini_time_init(void)
+{
+       unsigned char reg;
+
+       reg = gemini_rtc_read(M48T35_RTC_CONTROL);
+
+       if ( reg & M48T35_RTC_STOPPED ) {
+               printk(KERN_INFO "M48T35 real-time-clock was stopped. Now starting...\n");
+               gemini_rtc_write((reg & ~(M48T35_RTC_STOPPED)), M48T35_RTC_CONTROL);
+               gemini_rtc_write((reg | M48T35_RTC_SET), M48T35_RTC_CONTROL);
+       }
+}
+
+#undef DEBUG_RTC
+
+unsigned long
+gemini_get_rtc_time(void)
+{
+       unsigned int year, mon, day, hour, min, sec;
+       unsigned char reg;
+
+       reg = gemini_rtc_read(M48T35_RTC_CONTROL);
+       gemini_rtc_write((reg|M48T35_RTC_READ), M48T35_RTC_CONTROL);
+#ifdef DEBUG_RTC
+       printk("get rtc: reg = %x\n", reg);
+#endif
+  
+       do {
+               sec = gemini_rtc_read(M48T35_RTC_SECONDS);
+               min = gemini_rtc_read(M48T35_RTC_MINUTES);
+               hour = gemini_rtc_read(M48T35_RTC_HOURS);
+               day = gemini_rtc_read(M48T35_RTC_DOM);
+               mon = gemini_rtc_read(M48T35_RTC_MONTH);
+               year = gemini_rtc_read(M48T35_RTC_YEAR);
+       } while( sec != gemini_rtc_read(M48T35_RTC_SECONDS));
+#ifdef DEBUG_RTC
+       printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n", 
+              sec, min, hour, day, mon, year);
+#endif
+
+       gemini_rtc_write(reg, M48T35_RTC_CONTROL);
+
+       BCD_TO_BIN(sec);
+       BCD_TO_BIN(min);
+       BCD_TO_BIN(hour);
+       BCD_TO_BIN(day);
+       BCD_TO_BIN(mon);
+       BCD_TO_BIN(year);
+
+       if ((year += 1900) < 1970)
+               year += 100;
+#ifdef DEBUG_RTC
+       printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n", 
+              sec, min, hour, day, mon, year);
+#endif
+
+       return mktime( year, mon, day, hour, min, sec );
+}
+
+
+int
+gemini_set_rtc_time( unsigned long now )
+{
+       unsigned char reg;
+       struct rtc_time tm;
+
+       to_tm( now, &tm );
+
+       reg = gemini_rtc_read(M48T35_RTC_CONTROL);
+#if DEBUG_RTC
+       printk("set rtc: reg = %x\n", reg);
+#endif
+  
+       gemini_rtc_write((reg|M48T35_RTC_SET), M48T35_RTC_CONTROL);
+#if DEBUG_RTC
+       printk("set rtc: tm vals - sec=%x, min=%x, hour=%x, mon=%x, mday=%x, year=%x\n",
+              tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_mday, tm.tm_year);
+#endif
+  
+       tm.tm_year -= 1900;
+       BIN_TO_BCD(tm.tm_sec);
+       BIN_TO_BCD(tm.tm_min);
+       BIN_TO_BCD(tm.tm_hour);
+       BIN_TO_BCD(tm.tm_mon);
+       BIN_TO_BCD(tm.tm_mday);
+       BIN_TO_BCD(tm.tm_year);
+#ifdef DEBUG_RTC
+       printk("set rtc: tm vals - sec=%x, min=%x, hour=%x, mon=%x, mday=%x, year=%x\n",
+              tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_mday, tm.tm_year);
+#endif
+
+       gemini_rtc_write(tm.tm_sec, M48T35_RTC_SECONDS);
+       gemini_rtc_write(tm.tm_min, M48T35_RTC_MINUTES);
+       gemini_rtc_write(tm.tm_hour, M48T35_RTC_HOURS);
+       gemini_rtc_write(tm.tm_mday, M48T35_RTC_DOM);
+       gemini_rtc_write(tm.tm_mon, M48T35_RTC_MONTH);
+       gemini_rtc_write(tm.tm_year, M48T35_RTC_YEAR);
+
+       /* done writing */
+       gemini_rtc_write(reg, M48T35_RTC_CONTROL);
+
+       if ((time_state == TIME_ERROR) || (time_state == TIME_BAD))
+               time_state = TIME_OK;
+  
+       return 0;
+}
+
+/*  use the RTC to determine the decrementer count */
+void __init gemini_calibrate_decr(void)
+{
+       int freq, divisor;
+       unsigned char reg;
+
+       /* determine processor bus speed */
+       reg = readb(GEMINI_BSTAT);
+
+       switch(((reg & 0x0c)>>2)&0x3) {
+       case 0:
+       default:
+               freq = 66;
+               break;
+       case 1:
+               freq = 83;
+               break;
+       case 2:
+               freq = 100;
+               break;
+       }
+
+       freq *= 1000000;
+       divisor = 4;
+       decrementer_count = freq / HZ / divisor;
+       count_period_num = divisor;
+       count_period_den = freq / 1000000;
+}
+
+
+void __init gemini_init(unsigned long r3, unsigned long r4, unsigned long r5,
+                       unsigned long r6, unsigned long r7)
+{
+       void layout_bus( struct pci_bus * );
+
+       gemini_setup_pci_ptrs();
+
+       ISA_DMA_THRESHOLD = 0;
+       DMA_MODE_READ = 0;
+       DMA_MODE_WRITE = 0;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+       if ( r4 )
+       {
+               initrd_start = r4 + KERNELBASE;
+               initrd_end = r5 + KERNELBASE;
+       }
+#endif
+
+       ppc_md.setup_arch = gemini_setup_arch;
+       ppc_md.setup_residual = NULL;
+       ppc_md.get_cpuinfo = gemini_get_cpuinfo;
+       ppc_md.irq_cannonicalize = NULL;
+       ppc_md.init_IRQ = gemini_init_IRQ;
+       ppc_md.do_IRQ = gemini_do_IRQ;
+       ppc_md.init = NULL;
+
+       ppc_md.restart = gemini_restart;
+       ppc_md.power_off = gemini_power_off;
+       ppc_md.halt = gemini_halt;
+
+       ppc_md.time_init = gemini_time_init;
+       ppc_md.set_rtc_time = gemini_set_rtc_time;
+       ppc_md.get_rtc_time = gemini_get_rtc_time;
+       ppc_md.calibrate_decr = gemini_calibrate_decr;
+
+       /* no keyboard/mouse/video stuff yet.. */
+       ppc_md.kbd_setkeycode = NULL;
+       ppc_md.kbd_getkeycode = NULL;
+       ppc_md.kbd_translate = NULL;
+       ppc_md.kbd_unexpected_up = NULL;
+       ppc_md.kbd_leds = NULL;
+       ppc_md.kbd_init_hw = NULL;
+#ifdef CONFIG_MAGIC_SYSRQ
+       ppc_md.ppc_kbd_sysrq_xlate = NULL;
+#endif
+}
index 47a1777a5a671013b08f45d71c87e7dd265a515d..8e6b8aec158503ed5e20707138cd6d65d12279c6 100644 (file)
@@ -97,19 +97,6 @@ LG_CACHE_LINE_SIZE = 4
        bdnz    0b
 #endif
 
-#ifdef CONFIG_PPC64
-#define LOAD_BAT(n, offset, reg, RA, RB) \
-       ld      RA,offset+0(reg);       \
-       ld      RB,offset+8(reg);       \
-       mtspr   IBAT##n##U,RA;          \
-       mtspr   IBAT##n##L,RB;          \
-       ld      RA,offset+16(reg);      \
-       ld      RB,offset+24(reg);      \
-       mtspr   DBAT##n##U,RA;          \
-       mtspr   DBAT##n##L,RB;          \
-       
-#else /* CONFIG_PPC64 */
-       
 /* 601 only have IBAT cr0.eq is set on 601 when using this macro */ 
 #define LOAD_BAT(n, offset, reg, RA, RB) \
        /* see the comment for clear_bats() -- Cort */ \
@@ -126,7 +113,6 @@ LG_CACHE_LINE_SIZE = 4
        mtspr   DBAT##n##U,RA;          \
        mtspr   DBAT##n##L,RB;          \
 1:     
-#endif /* CONFIG_PPC64 */       
 
 #ifndef CONFIG_APUS
 #define tophys(rd,rs,rt)       addis   rd,rs,-KERNELBASE@h
@@ -153,7 +139,15 @@ _stext:
        .text
        .globl  _start
 _start:
-       .long   TOPHYS(__start),0,0
+       /* 
+        * These are here for legacy reasons, the kernel used to
+        * need to look like a coff function entry for the pmac
+        * but we're always started by some kind of bootloader now.
+        *  -- Cort
+        */
+       nop
+       nop
+       nop
 
 /* PMAC
  * Enter here with the kernel text, data and bss loaded starting at
@@ -224,16 +218,6 @@ _start:
        
        .globl  __start
 __start:
-#ifdef CONFIG_PPC64
-/* 
- * Go into 32-bit mode to boot.  OF should do this for
- * us already but just in case...
- * -- Cort 
- */
-       mfmsr   r10
-       clrldi  r10,r10,3
-       mtmsr   r10
-#endif 
 /*
  * We have to do any OF calls before we map ourselves to KERNELBASE,
  * because OF may have I/O devices mapped in in that area
@@ -255,7 +239,6 @@ __secondary_start:
  * call OF any more.
  */
        lis     r11,KERNELBASE@h
-#ifndef CONFIG_PPC64
        mfspr   r9,PVR
        rlwinm  r9,r9,16,16,31          /* r9 = 1 for 601, 4 for 604 */
        cmpi    0,r9,1
@@ -269,7 +252,6 @@ __secondary_start:
        mtspr   IBAT1U,r9
        mtspr   IBAT1L,r10
        b       5f
-#endif /* CONFIG_PPC64 */
 4:
 #ifdef CONFIG_APUS
        ori     r11,r11,BL_8M<<2|0x2    /* set up an 8MB mapping */
@@ -281,17 +263,10 @@ __secondary_start:
 #else  
        ori     r11,r11,BL_256M<<2|0x2  /* set up BAT registers for 604 */
        li      r8,2                    /* R/W access */
-#ifdef CONFIG_PPC64
-       /* clear out the high 32 bits in the BAT */
-       clrldi  r11,r11,32
-       clrldi  r8,r8,32
-       /* turn off the pagetable mappings just in case */
-       clrldi  r16,r16,63
-       mtsdr1  r16
-#else /* CONFIG_PPC64 */
        /*
         * If the MMU is off clear the bats.  See clear_bat() -- Cort
         */
+#ifndef CONFIG_GEMINI  
        mfmsr   r20
        andi.   r20,r20,MSR_DR
        bne     100f
@@ -314,14 +289,13 @@ __secondary_start:
        mtspr   DBAT2U,r21              /* bit in upper BAT register */
        mtspr   IBAT2L,r18
        mtspr   IBAT2U,r21
-#endif /* CONFIG_PPC64 */
+#endif /* ndef CONFIG_GEMINI */        
 #endif
        mtspr   DBAT0L,r8               /* N.B. 6xx (not 601) have valid */
        mtspr   DBAT0U,r11              /* bit in upper BAT register */
        mtspr   IBAT0L,r8
        mtspr   IBAT0U,r11
 5:     isync
-
 #ifdef CONFIG_APUS
        /* Unfortunately the APUS specific instructions bloat the
         * code so it cannot fit in the 0x100 bytes available. We have
@@ -511,7 +485,12 @@ label:                                             \
 
 /* System reset */
 #ifdef CONFIG_SMP /* MVME/MTX start the secondary here */
+#ifdef CONFIG_GEMINI
+       . = 0x100
+       b       __secondary_start_gemini
+#else /* CONFIG_GEMINI */
        STD_EXCEPTION(0x100, Reset, __secondary_start_psurge)
+#endif /* CONFIG_GEMINI */
 #else
        STD_EXCEPTION(0x100, Reset, UnknownException)
 #endif 
@@ -1281,6 +1260,7 @@ Hash_msk = (((1 << Hash_bits) - 1) * 64)
        .globl  hash_page
 hash_page:
 #ifdef __SMP__
+       SAVE_2GPRS(7,r21)
        eieio
        lis     r2,hash_table_lock@h
        ori     r2,r2,hash_table_lock@l
@@ -1294,10 +1274,18 @@ hash_page:
        bne-    12f
        stwcx.  r0,0,r2
        beq+    11f
-12:    cmpw    r6,r0
+       /* spin here a bit */
+12:    mfctr   r7
+       li      r8,1000
+       mtctr   r8
+13:
+       bdnz    13b
+       mtctr   r7
+       cmpw    r6,r0
        bdnzf   2,10b
        tw      31,31,31
 11:    eieio
+       REST_2GPRS(7, r21)
 #endif
        /* Get PTE (linux-style) and check access */
        lwz     r5,PG_TABLES(r5)                
@@ -1331,11 +1319,6 @@ hash_page:
        stw     r6,0(r2)                /* update PTE (accessed/dirty bits) */
 
        /* Convert linux-style PTE to low word of PPC-style PTE */
-#ifdef CONFIG_PPC64
-       /* clear the high 32 bits just in case */
-       clrldi  r6,r6,32
-       clrldi  r4,r4,32
-#endif /* CONFIG_PPC64 */
        rlwinm  r4,r6,32-9,31,31        /* _PAGE_HWWRITE -> PP lsb */
        rlwimi  r6,r6,32-1,31,31        /* _PAGE_USER -> PP (both bits now) */
        ori     r4,r4,0xe04             /* clear out reserved bits */
@@ -1343,34 +1326,17 @@ hash_page:
 
        /* Construct the high word of the PPC-style PTE */
        mfsrin  r5,r3                   /* get segment reg for segment */
-#ifdef CONFIG_PPC64
-       sldi    r5,r5,12
-#else /* CONFIG_PPC64 */
        rlwinm  r5,r5,7,1,24            /* put VSID in 0x7fffff80 bits */
-#endif /* CONFIG_PPC64 */
        
 #ifndef __SMP__                                /* do this later for SMP */
-#ifdef CONFIG_PPC64
-       ori     r5,r5,1                 /* set V (valid) bit */
-#else /* CONFIG_PPC64 */
        oris    r5,r5,0x8000            /* set V (valid) bit */
-#endif /* CONFIG_PPC64 */
 #endif
        
-#ifdef CONFIG_PPC64
-/* XXX:         does this insert the api correctly? -- Cort */
-       rlwimi  r5,r3,17,21,25          /* put in API (abbrev page index) */
-#else /* CONFIG_PPC64 */
        rlwimi  r5,r3,10,26,31          /* put in API (abbrev page index) */
-#endif /* CONFIG_PPC64 */
        /* Get the address of the primary PTE group in the hash table */
        .globl  hash_page_patch_A
 hash_page_patch_A:
        lis     r4,Hash_base@h          /* base address of hash table */
-#ifdef CONFIG_PPC64
-       /* just in case */
-       clrldi  r4,r4,32
-#endif 
        rlwimi  r4,r5,32-1,26-Hash_bits,25      /* (VSID & hash_mask) << 6 */
        rlwinm  r0,r3,32-6,26-Hash_bits,25      /* (PI & hash_mask) << 6 */
        xor     r4,r4,r0                /* make primary hash */
@@ -1735,33 +1701,26 @@ turn_on_mmu:
        mfmsr   r0
        ori     r1,r0,MSR_DR|MSR_IR
        mtspr   SRR1,r1
-#ifdef CONFIG_SMP
-       /* see the function start_here_ibm_hack for explanation -- Cort */
-       andi.   0,r1,MSR_DR     /* check if the MMU is already on */
-       bne     10f
-       lis     r5,smp_ibm_chrp_hack@h
-       ori     r5,r5,smp_ibm_chrp_hack@l
-       tophys(r5,r5,r6)
-       lwz     r5,0(r5)
-       cmpi    0,r5,0
-       beq     10f
-       lis     r5,first_cpu_booted@h
-       ori     r5,r5,first_cpu_booted@l
-       tophys(r5,r5,r6)
-       lwz     r5,0(r5)
-       cmpi    0,r5,0
-       beq     10f
-       lis     r0,start_here_ibm_hack@h
-       ori     r0,r0,start_here_ibm_hack@l
-       b       1010f
-10:    
-#endif /* CONFIG_SMP */
        lis     r0,start_here@h
        ori     r0,r0,start_here@l
-1010:  mtspr   SRR0,r0
+       mtspr   SRR0,r0
        SYNC
        rfi                             /* enables MMU */
 
+#ifdef CONFIG_GEMINI
+       .globl  __secondary_start_gemini
+__secondary_start_gemini:
+        mfspr   r4,HID0
+        ori     r4,r4,HID0_ICFI
+        li      r3,0
+        ori     r3,r3,HID0_ICE
+        andc    r4,r4,r3
+        mtspr   HID0,r4
+        sync
+        bl      prom_init
+        b       __secondary_start
+#endif /* CONFIG_GEMINI */
+
 #ifdef CONFIG_SMP
        .globl  __secondary_start_psurge
 __secondary_start_psurge:
@@ -1791,25 +1750,6 @@ __secondary_hold:
        blr
 #endif /* CONFIG_SMP */
        
-/* 
- * We get _strange_ behavior on the new IBM chrp firmware.
- * We end up here with the MMU disabled, even though we enable
- * it with the rfi that takes us here.  Somehow, a physical address
- * access fixes this by enabling the MMU.
- *
- * The IBM engineers can't explain this behavior and AIX doesn't 
- * seem to find it.  This hack gets around it for now.
- *          -- Cort
- */
-start_here_ibm_hack:
-       mfmsr   r1
-       lis     r5,smp_ibm_chrp_hack@h
-       ori     r5,r5,smp_ibm_chrp_hack@l
-       tophys(r5,r5,r6)
-       mfmsr   r1
-       stw     r1,_MSR-16(r5)
-       addi    r5,r5,_MSR-16
-       dcbf    0,r5
 #ifndef CONFIG_8xx
 start_here:
        /*
@@ -1896,6 +1836,8 @@ start_here:
        mr      r6,r28
        mr      r7,r27
        bl      identify_machine
+lis r20,0xc0000000@h
+stw    r20,0(r20)      
        bl      MMU_init
 /*
  * Go back to running unmapped so we can load up new values
@@ -1906,11 +1848,7 @@ start_here:
  */
 #ifndef CONFIG_8xx
        lis     r6,_SDR1@ha
-#ifdef CONFIG_PPC64    
-       ld      r6,_SDR1@l(r6)
-#else
        lwz     r6,_SDR1@l(r6)
-#endif         
 #else
        /* The right way to do this would be to track it down through
         * init's TSS like the context switch code does, but this is
@@ -1939,14 +1877,6 @@ start_here:
 #endif
 #ifndef CONFIG_8xx
        mtspr   SDR1,r6
-#ifdef CONFIG_PPC64
-       /* clear the v bit in the ASR so we can
-        * behave as if we have segment registers 
-        * -- Cort
-        */
-       clrldi  r6,r6,63
-       mtasr   r6
-#endif /* CONFIG_PPC64 */
        li      r0,16           /* load up segment register values */
        mtctr   r0              /* for context 0 */
        lis     r3,0x2000       /* Ku = 1, VSID = 0 */
@@ -1963,17 +1893,10 @@ start_here:
        lis     r3,BATS@ha
        addi    r3,r3,BATS@l
        tophys(r3,r3,r4)
-#ifdef CONFIG_PPC64
-       LOAD_BAT(0,0,r3,r4,r5)
-       LOAD_BAT(1,32,r3,r4,r5)
-       LOAD_BAT(2,64,r3,r4,r5)
-       LOAD_BAT(3,96,r3,r4,r5)
-#else /* CONFIG_PPC64 */
        LOAD_BAT(0,0,r3,r4,r5)
        LOAD_BAT(1,16,r3,r4,r5)
        LOAD_BAT(2,32,r3,r4,r5)
        LOAD_BAT(3,48,r3,r4,r5)
-#endif /* CONFIG_PPC64 */
 #endif /* CONFIG_8xx */
 /* Set up for using our exception vectors */
        /* ptr to phys current tss */
index 2ca879dd83e727482965e427e09fdbb688fd02b0..eddf6e4d47f44ab1ba64a015554e14231e3f8be2 100644 (file)
@@ -16,24 +16,24 @@ void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
 
 void chrp_mask_and_ack_irq(unsigned int irq_nr)
 {
-       if (is_8259_irq(irq_nr))
-           i8259_pic.mask_and_ack(irq_nr);
+       if ((_machine != _MACH_gemini) && is_8259_irq(irq_nr))
+               i8259_pic.mask_and_ack(irq_nr);
 }
 
 static void chrp_mask_irq(unsigned int irq_nr)
 {
-       if (is_8259_irq(irq_nr))
+       if ((_machine != _MACH_gemini) && is_8259_irq(irq_nr))
                i8259_pic.disable(irq_nr);
        else
-               openpic_disable_irq(irq_to_openpic(irq_nr));
+               openpic_disable_irq(irq_nr-open_pic.irq_offset);
 }
 
 static void chrp_unmask_irq(unsigned int irq_nr)
 {
-       if (is_8259_irq(irq_nr))
+       if ((_machine != _MACH_gemini) && is_8259_irq(irq_nr))
                i8259_pic.enable(irq_nr);
        else
-               openpic_enable_irq(irq_to_openpic(irq_nr));
+               openpic_enable_irq(irq_nr-open_pic.irq_offset);
 }
 
 struct hw_interrupt_type open_pic = {
index f7893dd794d0c91a870e4be9691661cb394169d6..cb2f6454b9c28bef3b82cb101f03c543a6d88ce5 100644 (file)
@@ -241,10 +241,13 @@ __initfunc(void openpic_init(int main_pic))
            
            /* Initialize the spurious interrupt */
            openpic_set_spurious(OPENPIC_VEC_SPURIOUS);
-           
-           if (request_irq(IRQ_8259_CASCADE, no_action, SA_INTERRUPT,
-                           "82c59 cascade", NULL))
-                   printk("Unable to get OpenPIC IRQ 0 for cascade\n");
+
+           if ( _machine != _MACH_gemini )
+           {
+                   if (request_irq(IRQ_8259_CASCADE, no_action, SA_INTERRUPT,
+                                   "82c59 cascade", NULL))
+                           printk("Unable to get OpenPIC IRQ 0 for cascade\n");
+           }
            openpic_set_priority(0, 0);
            openpic_disable_8259_pass_through();
     }
@@ -509,3 +512,10 @@ void openpic_set_sense(u_int irq, int sense)
                            OPENPIC_SENSE_LEVEL,
                            (sense ? OPENPIC_SENSE_LEVEL : 0));
 }
+
+void openpic_enable_IPI(u_int ipi)
+{
+       check_arg_ipi(ipi);
+       openpic_clearfield(&OpenPIC->Global.IPI_Vector_Priority(ipi),
+                          OPENPIC_MASK);
+}
index 6d248d2b64c00dbec890e84df2e4636bf11594b6..8627633381ed2b247a298aba2653628d9bab110b 100644 (file)
@@ -170,7 +170,7 @@ static char Mesquite_pci_IRQ_map[23] __prepdata =
        0,      /* Slot 8  - unused */
        0,      /* Slot 9  - unused */
        0,      /* Slot 10 - unxued */
-       0,      /* Slot 11 - unused */
+       0x1e,   /* Slot 11 - PCI-ISA/IDE/USB */
        0,      /* Slot 12 - unused */
        0,      /* Slot 13 - unused */
        2,      /* Slot 14 - Ethernet */
@@ -198,7 +198,7 @@ static char Sitka_pci_IRQ_map[21] __prepdata =
        0,      /* Slot 8  - unused */
        0,      /* Slot 9  - unused */
        0,      /* Slot 10 - unxued */
-       0,      /* Slot 11 - unused */
+       0x1e,   /* Slot 11 - PCI-ISA/IDE/USB */
        0,      /* Slot 12 - unused */
        0,      /* Slot 13 - unused */
        2,      /* Slot 14 - Ethernet */
@@ -224,7 +224,7 @@ static char MTX_pci_IRQ_map[23] __prepdata =
        0,      /* Slot 8  - unused */
        0,      /* Slot 9  - unused */
        0,      /* Slot 10 - unused */
-       0,      /* Slot 11 - unused */
+       0x1e,   /* Slot 11 - PCI-ISA/IDE/USB */
        3,      /* Slot 12 - SCSI */
        0,      /* Slot 13 - unused */
        2,      /* Slot 14 - Ethernet */
@@ -253,7 +253,7 @@ static char MTXplus_pci_IRQ_map[23] __prepdata =
         0,      /* Slot 8  - unused */
         0,      /* Slot 9  - unused */
         0,      /* Slot 10 - unused */
-        0,      /* Slot 11 - unused */
+        0x1e,   /* Slot 11 - PCI-ISA/IDE/USB */
         3,      /* Slot 12 - SCSI */
         0,      /* Slot 13 - unused */
         2,      /* Slot 14 - Ethernet 1 */
@@ -1076,40 +1076,91 @@ Mesquite_Map_Non0(struct pci_dev *pdev)
        return;
 }
 
+int motopenpic_to_irq(int n)
+{
+       if (n & 0xF0) {
+               return (n & 0x0F);
+       } else {
+               return(openpic_to_irq(n));
+       }
+}
+
+void prep_pib_init(void)
+{
+unsigned char   reg;
+unsigned short  short_reg;
+
+struct pci_dev *dev = NULL;
+
+       if (( _prep_type == _PREP_Motorola) && (OpenPIC)) {
+               /*
+                * Perform specific configuration for the Via Tech or
+                * or Winbond PCI-ISA-Bridge part.
+                */
+               if ((dev = pci_find_device(PCI_VENDOR_ID_VIA, 
+                                       PCI_DEVICE_ID_VIA_82C586_1, dev))) {
+                       /*
+                        * PPCBUG does not set the enable bits
+                        * for the IDE device. Force them on here.
+                        */
+                       pcibios_read_config_byte(dev->bus->number, 
+                                       dev->devfn, 0x40, &reg);
+
+                       reg |= 0x03; /* IDE: Chip Enable Bits */
+                       pcibios_write_config_byte(dev->bus->number, 
+                                       dev->devfn, 0x40, reg);
+
+               } else if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND, 
+                                       PCI_DEVICE_ID_WINBOND_83C553, dev))) {
+                       /*
+                        * Clear the PCI Interrupt Routing Control Register.
+                        */
+                       short_reg = 0x0000;
+                       pcibios_write_config_word(dev->bus->number, 
+                                       dev->devfn, 0x44, short_reg);
+               }
+       }
+}
 __initfunc(
 void
 prep_pcibios_fixup(void))
 {
-        struct pci_dev *dev;
-        extern unsigned char *Motherboard_map;
-        extern unsigned char *Motherboard_routes;
-        unsigned char i;
+extern unsigned char *Motherboard_map;
+extern unsigned char *Motherboard_routes;
+unsigned char  i;
+struct pci_dev  *dev;
 
-        if ( _prep_type == _PREP_Radstone )
-        {
-                printk("Radstone boards require no PCI fixups\n");
+       if (_prep_type == _PREP_Radstone) {
+               printk("Radstone boards require no PCI fixups\n");
                return;
-        }
+       }
 
        prep_route_pci_interrupts();
 
+       prep_pib_init();
+
        printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name);
+
        if (OpenPIC) {
-               /* PCI interrupts are controlled by the OpenPIC */
-               for(dev=pci_devices; dev; dev=dev->next) {
-                       if (dev->bus->number == 0) {
-                                       dev->irq = openpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]);
-                               pcibios_write_config_byte(dev->bus->number, dev->devfn, PCI_INTERRUPT_PIN, dev->irq);
-                       } else {
-                               if (Motherboard_non0 != NULL)
-                                       Motherboard_non0(dev);
-                       }
+
+           /* PCI interrupts are controlled by the OpenPIC */
+           for(dev=pci_devices; dev; dev=dev->next) {
+               if (dev->bus->number == 0) {
+                   dev->irq = 
+                      motopenpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]);
+
+                   pcibios_write_config_byte(dev->bus->number, dev->devfn, 
+                                             PCI_INTERRUPT_PIN, dev->irq);
+               } else {
+                       if (Motherboard_non0 != NULL)
+                               Motherboard_non0(dev);
                }
-               return;
+
+           }
+       return;
        }
 
-       for(dev=pci_devices; dev; dev=dev->next)
-       {
+       for(dev=pci_devices; dev; dev=dev->next) {
                /*
                 * Use our old hard-coded kludge to figure out what
                 * irq this device uses.  This is necessary on things
@@ -1118,29 +1169,26 @@ prep_pcibios_fixup(void))
                unsigned char d = PCI_SLOT(dev->devfn);
                dev->irq = Motherboard_routes[Motherboard_map[d]];
 
-               for ( i = 0 ; i <= 5 ; i++ )
-               {
-                       if ( dev->base_address[i] > 0x10000000 )
-                       {
-                               printk("Relocating PCI address %lx -> %lx\n",
-                                      dev->base_address[i],
-                                      (dev->base_address[i] & 0x00FFFFFF)
-                                      | 0x01000000);
-                               dev->base_address[i] =
-                                 (dev->base_address[i] & 0x00FFFFFF) | 0x01000000;
-                               pci_write_config_dword(dev,
-                                       PCI_BASE_ADDRESS_0+(i*0x4),
-                                      dev->base_address[i] );
-                       }
+               for ( i = 0 ; i <= 5 ; i++ ) {
+                       if ( dev->base_address[i] > 0x10000000 ) {
+                               printk("Relocating PCI address %lx -> %lx\n",
+                               dev->base_address[i],
+                               (dev->base_address[i] & 0x00FFFFFF)|0x01000000);
+
+                               dev->base_address[i] = (dev->base_address[i] & 
+                                                       0x00FFFFFF)|0x01000000;
+                               pci_write_config_dword(dev, 
+                                               PCI_BASE_ADDRESS_0+(i*0x4),
+                                               dev->base_address[i] );
+                       }
                }
 #if 0
-               /*
-                * If we have residual data and if it knows about this
-                * device ask it what the irq is.
-                *  -- Cort
-                */
-               ppcd = residual_find_device_id( ~0L, dev->device,
-                                               -1,-1,-1, 0);
+       /*
+        * If we have residual data and if it knows about this
+        * device ask it what the irq is.
+        *  -- Cort
+        */
+       ppcd = residual_find_device_id( ~0L, dev->device, -1,-1,-1, 0);
 #endif
        }
 }
index 5860716c0bb499d71b2972fe1dff9734353be62c..80408f73ca6717686088a709937763f65b48d956 100644 (file)
@@ -628,25 +628,36 @@ prep_init_IRQ(void))
 void
 prep_ide_insw(ide_ioreg_t port, void *buf, int ns)
 {
-       _insw((unsigned short *)((port)+_IO_BASE), buf, ns);
+       ide_insw(((port)+(_IO_BASE)), buf, ns);
 }
 
 void
 prep_ide_outsw(ide_ioreg_t port, void *buf, int ns)
 {
-       _outsw((unsigned short *)((port)+_IO_BASE), buf, ns);
+       ide_outsw(((port)+_IO_BASE), buf, ns);
 }
 
 int
 prep_ide_default_irq(ide_ioreg_t base)
 {
-       switch (base) {
-               case 0x1f0: return 13;
-               case 0x170: return 13;
-               case 0x1e8: return 11;
-               case 0x168: return 10;
-               default:
-                        return 0;
+       if ( _prep_type == _PREP_IBM ) {
+               switch (base) {
+                       case 0x1f0: return 13;
+                       case 0x170: return 13;
+                       case 0x1e8: return 11;
+                       case 0x168: return 10;
+                       default:
+                               return 0;
+               }
+       } else {
+               switch (base) {
+                       case 0x1f0: return 14;
+                       case 0x170: return 14;
+                       case 0x1e8: return 15;
+                       case 0x168: return 15;
+                       default:
+                               return 0;
+               }
        }
 }
 
@@ -687,6 +698,7 @@ prep_ide_release_region(ide_ioreg_t from,
 void
 prep_ide_fix_driveid(struct hd_driveid *id)
 {
+       ppc_generic_ide_fix_driveid(id);
 }
 
 __initfunc(void
index 0294220bee8d0cdfcd33d474394ad3782bf254ee..ed984a329cc4c4e05686bfdd1624cc18c53ef5b6 100644 (file)
@@ -25,6 +25,7 @@
 #include <asm/smp.h>
 #include <asm/bootx.h>
 #include <asm/system.h>
+#include <asm/gemini.h>
 
 /*
  * Properties whose value is longer than this get excluded from our
@@ -277,6 +278,11 @@ prom_init(int r3, int r4, prom_entry pp)
        int l;
        char *p, *d;
        
+#ifdef CONFIG_GEMINI
+       gemini_prom_init();
+       return;
+#endif /* CONFIG_GEMINI */
+       
        /* check if we're apus, return if we are */
        if ( r3 == 0x61707573 )
                return;
index 71aa08b8a2ffa68eaaed5e3cadeb3e37fbd7f360..6310c75146955b497aef212fe514cd921c3535bc 100644 (file)
@@ -62,6 +62,12 @@ extern void apus_init(unsigned long r3,
                       unsigned long r6,
                       unsigned long r7);
 
+extern void gemini_init(unsigned long r3,
+                      unsigned long r4,
+                      unsigned long r5,
+                      unsigned long r6,
+                      unsigned long r7);
+
 extern boot_infos_t *boot_infos;
 extern char cmd_line[512];
 char saved_command_line[256];
@@ -342,7 +348,6 @@ unsigned long __init
 identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
                 unsigned long r6, unsigned long r7)
 {
-       
 #ifdef __SMP__
        if ( first_cpu_booted ) return 0;
 #endif /* __SMP__ */
@@ -403,6 +408,8 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
        _machine = _MACH_fads;
 #elif defined(CONFIG_APUS)
        _machine = _MACH_apus;
+#elif defined(CONFIG_GEMINI)
+       _machine = _MACH_gemini;
 #else
 #error "Machine not defined correctly"
 #endif /* CONFIG_APUS */
@@ -487,6 +494,11 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
         case _MACH_mbx:
                 mbx_init(r3, r4, r5, r6, r7);
                 break;
+#endif
+#ifdef CONFIG_GEMINI
+       case _MACH_gemini:
+                gemini_init(r3, r4, r5, r6, r7);
+               break;
 #endif
        default:
                printk("Unknown machine type in identify_machine!\n");
index 504bff082923f6567552ab03e504bd52e9ca837f..ab7a2d74f65208a661e5b3e38b1f9794a8ab89d2 100644 (file)
@@ -34,6 +34,7 @@
 #include <asm/init.h>
 #include <asm/io.h>
 #include <asm/prom.h>
+#include <asm/gemini.h>
 
 #include "time.h"
 int first_cpu_booted = 0;
@@ -175,7 +176,7 @@ spinlock_t mesg_pass_lock = SPIN_LOCK_UNLOCKED;
 void smp_message_pass(int target, int msg, unsigned long data, int wait)
 {
        int i;
-       if ( !(_machine & (_MACH_Pmac|_MACH_chrp|_MACH_prep)) )
+       if ( !(_machine & (_MACH_Pmac|_MACH_chrp|_MACH_prep|_MACH_gemini)) )
                return;
 
        spin_lock(&mesg_pass_lock);
@@ -296,6 +297,12 @@ void __init smp_boot_cpus(void)
                        cpu_nr = 2;
                        break;
                }
+       case _MACH_gemini:
+               for ( i = 0; i < 4 ; i++ )
+                       openpic_enable_IPI(i);
+                cpu_nr = (readb(GEMINI_CPUSTAT) & GEMINI_CPU_COUNT_MASK)>>2;
+                cpu_nr = (cpu_nr == 0) ? 4 : cpu_nr;
+               break;
        default:
                printk("SMP not supported on this machine.\n");
                return;
@@ -357,6 +364,10 @@ void __init smp_boot_cpus(void)
                        *MotSave_CpusState[1] = CPU_GOOD;
                        printk("CPU1 reset, waiting\n");
                        break;
+               case _MACH_gemini:
+                       openpic_init_processor( 1<<i );
+                       openpic_init_processor( 0 );
+                       break;
                }
                
                /*
index bff308e2bfe2da6aae9acbacab750a111e26c0d7..9da48426effa593be99c75cb99c8eec7951b84e2 100644 (file)
@@ -54,6 +54,7 @@
 #include <asm/setup.h>
 #include <asm/amigahw.h>
 /* END APUS includes */
+#include <asm/gemini.h>
 
 int prom_trashed;
 atomic_t next_mmu_context;
@@ -83,6 +84,7 @@ static void *MMU_get_page(void);
 unsigned long *prep_find_end_of_memory(void);
 unsigned long *pmac_find_end_of_memory(void);
 unsigned long *apus_find_end_of_memory(void);
+unsigned long *gemini_find_end_of_memory(void);
 extern unsigned long *find_end_of_memory(void);
 #ifdef CONFIG_MBX
 unsigned long *mbx_find_end_of_memory(void);
@@ -987,6 +989,10 @@ __initfunc(void free_initmem(void))
                FREESEC(__pmac_begin,__pmac_end,num_pmac_pages);
                FREESEC(__prep_begin,__prep_end,num_prep_pages);
                break;
+       case _MACH_gemini:
+               FREESEC(__pmac_begin,__pmac_end,num_pmac_pages);
+               FREESEC(__prep_begin,__prep_end,num_prep_pages);
+               break;
        }
 
        if ( !have_of )
@@ -1024,9 +1030,13 @@ __initfunc(void MMU_init(void))
        else if (_machine == _MACH_apus )
                end_of_DRAM = apus_find_end_of_memory();
 #endif
+#ifdef CONFIG_GEMINI   
+       else if ( _machine == _MACH_gemini )
+               end_of_DRAM = gemini_find_end_of_memory();
+#endif /* CONFIG_GEMINI        */
        else /* prep */
                end_of_DRAM = prep_find_end_of_memory();
-
+*(unsigned long *)(KERNELBASE) = 0xdeadbeef;   
         hash_init();
         _SDR1 = __pa(Hash) | (Hash_mask >> 10);
        ioremap_base = 0xf8000000;
@@ -1069,6 +1079,10 @@ __initfunc(void MMU_init(void))
                   (kernel_map) remaps individual IO regions to
                   0x90000000. */
                break;
+       case _MACH_gemini:
+               setbat(0, 0xf0000000, 0xf0000000, 0x10000000, IO_PAGE);
+               setbat(1, 0x80000000, 0x80000000, 0x10000000, IO_PAGE);
+               break;
        }
        ioremap_bot = ioremap_base;
 #else /* CONFIG_8xx */
@@ -1409,6 +1423,32 @@ __initfunc(unsigned long *prep_find_end_of_memory(void))
        return (__va(total));
 }
 
+#if defined(CONFIG_GEMINI)
+unsigned long __init *gemini_find_end_of_memory(void)
+{
+       unsigned long total, kstart, ksize, *ret;
+       unsigned char reg;
+*(unsigned long *)(KERNELBASE) = 0x1;
+       reg = readb(GEMINI_MEMCFG);
+*(unsigned long *)(KERNELBASE) = 0x2;
+       total = ((1<<((reg & 0x7) - 1)) *
+                (8<<((reg >> 3) & 0x7)));
+       total *= (1024*1024);
+       phys_mem.regions[0].address = 0;
+       phys_mem.regions[0].size = total;
+       phys_mem.n_regions = 1;
+       
+       ret = __va(phys_mem.regions[0].size);
+       phys_avail = phys_mem;
+       kstart = __pa(_stext);
+       ksize = PAGE_ALIGN( _end - _stext );
+*(unsigned long *)(KERNELBASE) = 0x3;
+       remove_mem_piece( &phys_avail, kstart, ksize, 0 );
+*(unsigned long *)(KERNELBASE) = 0x4;
+       return ret;
+}
+#endif /* defined(CONFIG_GEMINI) */
+
 #ifdef CONFIG_APUS
 #define HARDWARE_MAPPED_SIZE (512*1024)
 __initfunc(unsigned long *apus_find_end_of_memory(void))
index d4fc2d7f9f45c2b1ee3f13b7cfdda311ed202c5d..3f575754ccf3a420281976cbbad6c686e58bc15b 100644 (file)
@@ -210,7 +210,8 @@ static ssize_t read_mouse(struct file * file,
        buttons = mouse.buttons;
        mouse.dx -= dx;
        mouse.dy -= dy;
-       mouse.ready = 0;
+       if(mouse.dx==0 && mouse.dy==0)
+               mouse.ready = 0;
        enable_irq(mouse_irq);
        /* restore_flags(flags); */
 
index 98c8e56daf9b92c2393d98ecb6f591460ef26aa8..57224683cdcba4b896ee27057c27f2a7bf717d14 100644 (file)
@@ -2820,6 +2820,7 @@ EXPORT_SYMBOL(default_blu);
 EXPORT_SYMBOL(video_font_height);
 EXPORT_SYMBOL(video_scan_lines);
 EXPORT_SYMBOL(vc_resize);
+EXPORT_SYMBOL(fg_console);
 
 #ifndef VT_SINGLE_DRIVER
 EXPORT_SYMBOL(take_over_console);
index 07c733b5b4482909134cffdf2f999f2715ad2cb0..5cabe7896b9f59c7cca7ce1f15b371be282e6e04 100644 (file)
@@ -157,7 +157,8 @@ static ssize_t read_mouse(struct file * file,
                put_user(0x00, buffer + i);
        mouse.dx -= dx;
        mouse.dy += dy;
-       mouse.ready = 0;
+       if(mouse.dx == 0 && mouse.dy == 0)
+               mouse.ready = 0;
        return i;       
 }
 
index 1196dc820a9286c9953133f2ce3bfc569108b2b7..49d24dd148d1a49961b9f72888414d062d0a2e14 100644 (file)
@@ -46,6 +46,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 'Symbios 53c885 (Synergy ethernet) support' CONFIG_NCR885E
   fi
   if [ "$CONFIG_ZORRO" = "y" ]; then
     tristate 'Ariadne support' CONFIG_ARIADNE
index 8d99b081bafc324ca86a4cf30854faaf35f12595..9551a3276fe89c633d3991abe5545006a23bbef0 100644 (file)
@@ -1154,6 +1154,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_NCR885E),y)
+L_OBJS += ncr885e.o
+else
+  ifeq ($(CONFIG_NCR885E),m)
+  M_OBJS += ncr885e.o
+  endif
+endif
+
 ifeq ($(CONFIG_VENDOR_SANGOMA),y)
   LX_OBJS += sdladrv.o
   L_OBJS += sdlamain.o
index 8c3ef645d62f485c9a89522a76ede7d86b209cdd..2da9b3872745fcd30147bc559db37d36c4c6acd4 100644 (file)
@@ -103,6 +103,7 @@ extern int pamsnet_probe(struct device *);
 extern int tlan_probe(struct device *);
 extern int mace_probe(struct device *);
 extern int bmac_probe(struct device *);
+extern int ncr885e_probe(struct device *);
 extern int cs89x0_probe(struct device *dev);
 extern int ethertap_probe(struct device *dev);
 extern int ether1_probe (struct device *dev);
@@ -453,6 +454,9 @@ struct devprobe ppc_probes[] __initdata = {
 #endif
 #ifdef CONFIG_BMAC
        {bmac_probe, 0},
+#endif
+#ifdef CONFIG_NCR885E
+       {ncr885e_probe, 0},
 #endif
        {NULL, 0},
 };
index e0c88c7fdeefe54faef779c6301f5558ddf94cf0..65d3b69be50faf42776216866c22764afa36bbc2 100644 (file)
     8/20/96 Fixed 7990 autoIRQ failure and reversed unneeded alignment -djb
     v1.12 10/27/97 Module support -djb
     v1.14  2/3/98 Module support modified, made PCI support optional -djb
+    v1.15 5/27/99 Fixed bug in the cleanup_module(). dev->priv was freed
+                  before unregister_netdev() which caused NULL pointer
+                  reference later in the chain (in rtnetlink_fill_ifinfo())
+                  -- Mika Kuoppala <miku@iki.fi>
     
     Forward ported v1.14 to 2.1.129, merged the PCI and misc changes from
     the 2.1 version of the old driver - Alan Cox
 */
 
-static const char *version = "lance.c:v1.14ac 1998/11/20 dplatt@3do.com, becker@cesdis.gsfc.nasa.gov\n";
+static const char *version = "lance.c:v1.15ac 1999/11/13 dplatt@3do.com, becker@cesdis.gsfc.nasa.gov\n";
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -349,11 +353,11 @@ void cleanup_module(void)
        for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) {
                struct device *dev = &dev_lance[this_dev];
                if (dev->priv != NULL) {
-                       kfree(dev->priv);
-                       dev->priv = NULL;
+                       unregister_netdev(dev); 
                        free_dma(dev->dma);
                        release_region(dev->base_addr, LANCE_TOTAL_SIZE);
-                       unregister_netdev(dev);
+                       kfree(dev->priv);
+                       dev->priv = NULL;
                }
        }
 }
diff --git a/drivers/net/ncr885_debug.h b/drivers/net/ncr885_debug.h
new file mode 100644 (file)
index 0000000..bd1fead
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef _H_NCR885_DEBUG
+#define _H_NCR885_DEBUG
+
+struct ncr885e_regs {
+  unsigned long tx_status;
+  unsigned long rx_status;
+  unsigned long mac_config;
+  unsigned long tx_control;
+  unsigned long rx_control;
+  unsigned long tx_cmd_ptr;
+  unsigned long rx_cmd_ptr;
+  unsigned long int_status;
+};
+
+#ifndef __KERNEL__
+
+struct ncr885e_private {
+
+  struct dbdma_cmd *head;
+  struct dbdma_cmd *tx_cmds;
+  struct dbdma_cmd *rx_cmds;
+  struct dbdma_cmd *stop_cmd;
+
+  struct sk_buff *tx_skbufs[NR_TX_RING];
+  struct sk_buff *rx_skbufs[NR_RX_RING];
+
+  int rx_current;
+  int rx_dirty;
+
+  int tx_dirty;
+  int tx_current;
+
+  unsigned short tx_status[NR_TX_RING];
+
+  unsigned char tx_fullup;
+  unsigned char tx_active;
+  
+  struct net_device_stats  stats;
+
+  struct device *dev;
+
+  struct timer_list tx_timeout;
+  int timeout_active;
+
+  spinlock_t lock;
+};
+
+#endif /* __KERNEL__ */
+
+
+#define NCR885E_GET_PRIV   _IOR('N',1,sizeof( struct ncr885e_private ))
+#define NCR885E_GET_REGS   _IOR('N',2,sizeof( struct ncr885e_regs ))
+
+#endif
diff --git a/drivers/net/ncr885e.c b/drivers/net/ncr885e.c
new file mode 100644 (file)
index 0000000..13f81b1
--- /dev/null
@@ -0,0 +1,1458 @@
+/*
+ *  An Ethernet driver for the dual-function NCR 53C885 SCSI/Ethernet
+ *  controller.
+ *
+ *
+ *  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.
+ *
+ */
+
+static const char *version =
+"ncr885e.c:v0.8 11/30/98 dan@synergymicro.com\n";
+
+#include <linux/config.h>
+
+#ifdef MODULE
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT 
+#define MOD_DEC_USE_COUNT
+#endif
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/dbdma.h>
+#include <asm/uaccess.h>
+
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include "ncr885e.h"
+#include "ncr885_debug.h"
+
+static const char *chipname = "ncr885e";
+
+/* debugging flags */
+#if 0
+#define DEBUG_FUNC    0x0001
+#define DEBUG_PACKET  0x0002
+#define DEBUG_CMD     0x0004
+#define DEBUG_CHANNEL 0x0008
+#define DEBUG_INT     0x0010
+#define DEBUG_RX      0x0020
+#define DEBUG_TX      0x0040
+#define DEBUG_DMA     0x0080
+#define DEBUG_MAC     0x0100
+#define DEBUG_DRIVER  0x0200
+#define DEBUG_ALL     0x1fff
+#endif
+
+#ifdef DEBUG_NCR885E
+#define NCR885E_DEBUG   0
+#else
+#define NCR885E_DEBUG   0
+#endif
+
+/* The 885's Ethernet PCI device id. */
+#ifndef PCI_DEVICE_ID_NCR_53C885_ETHERNET
+#define PCI_DEVICE_ID_NCR_53C885_ETHERNET  0x0701
+#endif
+
+#define NR_RX_RING    8
+#define NR_TX_RING    8
+#define MAX_TX_ACTIVE (NR_TX_RING-1)
+#define NCMDS_TX      NR_TX_RING
+
+#define RX_BUFLEN     (ETH_FRAME_LEN + 8)
+#define TX_TIMEOUT    5*HZ
+
+#define NCR885E_TOTAL_SIZE 0xe0
+
+#define TXSR          (1<<6)   /* tx: xfer status written */
+#define TXABORT       (1<<7)   /* tx: abort */
+#define EOP           (1<<7)   /* rx: end of packet written to buffer */
+
+int ncr885e_debug = NCR885E_DEBUG;
+static int print_version = 0;
+
+struct ncr885e_private {
+
+       /* preserve a 1-1 marking with buffs */
+       struct dbdma_cmd *head;
+       struct dbdma_cmd *tx_cmds;
+       struct dbdma_cmd *rx_cmds;
+       struct dbdma_cmd *stop_cmd;
+
+       struct sk_buff *tx_skbufs[NR_TX_RING];
+       struct sk_buff *rx_skbufs[NR_RX_RING];
+
+       int rx_current;
+       int rx_dirty;
+
+       int tx_dirty;
+       int tx_current;
+
+       unsigned short tx_status[NR_TX_RING];
+
+       unsigned char tx_fullup;
+       unsigned char tx_active;
+  
+       struct net_device_stats  stats;
+
+       struct device *dev;
+
+       struct timer_list tx_timeout;
+       int timeout_active;
+
+       spinlock_t lock;
+};
+
+#ifdef MODULE
+static struct device *root_dev = NULL;
+#endif
+
+
+static int ncr885e_open( struct device *dev );
+static int ncr885e_close( struct device *dev );
+static void ncr885e_rx( struct device *dev );
+static void ncr885e_tx( struct device *dev );
+static int ncr885e_probe1( struct device *dev, unsigned long ioaddr,
+                          unsigned char irq );
+static int ncr885e_xmit_start( struct sk_buff *skb, struct device *dev );
+static struct net_device_stats *ncr885e_stats( struct device *dev );
+static void ncr885e_set_multicast( struct device *dev );
+static void ncr885e_config( struct device *dev );
+static int ncr885e_set_address( struct device *dev, void *addr );
+static void ncr885e_interrupt( int irq, void *dev_id, struct pt_regs *regs );
+static void show_dbdma_cmd( volatile struct dbdma_cmd *cmd );
+#if 0
+static int read_eeprom( unsigned int ioadddr, int location );
+#endif
+
+#ifdef NCR885E_DEBUG_MII
+static void show_mii( unsigned long ioaddr );
+static int read_mii( unsigned long ioaddr, int reg );
+static void write_mii( unsigned long ioaddr, int reg, int data );
+#endif /* NCR885E_DEBUG_MII */
+
+#define TX_RESET_FLAGS    (TX_CHANNEL_RUN|TX_CHANNEL_PAUSE|TX_CHANNEL_WAKE)
+#define RX_RESET_FLAGS    (RX_CHANNEL_RUN|RX_CHANNEL_PAUSE|RX_CHANNEL_WAKE)
+
+
+#if 0
+static int
+debug_ioctl( struct device *dev, struct ifreq *req, int cmd )
+{
+       unsigned long ioaddr = dev->base_addr;
+       struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+       struct ncr885e_private *data;
+       struct ncr885e_regs *regs;
+       unsigned long flags;
+
+       union {
+               struct ncr885e_regs dump;
+               struct ncr885e_private priv;    
+       } temp;
+
+       switch( cmd ) {
+
+               /* dump the rx ring status */
+       case NCR885E_GET_PRIV:
+
+               data = (struct ncr885e_private *) &req->ifr_data;    
+
+               if ( verify_area(VERIFY_WRITE, &req->ifr_data,
+                                sizeof( struct ncr885e_private )))
+                       return -EFAULT;
+
+               memcpy((char *) &temp.priv, sp, sizeof( struct ncr885e_private ));
+               copy_to_user( data, (char *) &temp.priv, sizeof( struct ncr885e_private));
+               break;
+
+       case NCR885E_GET_REGS:
+
+               regs = (struct ncr885e_regs *) &req->ifr_data;
+  
+               if ( verify_area( VERIFY_WRITE, &req->ifr_data,
+                                 sizeof( struct ncr885e_regs )))
+                       return -EFAULT;
+
+               spin_lock_irqsave( &sp->lock, flags ); 
+
+               temp.dump.tx_status = inl( ioaddr + TX_CHANNEL_STATUS );
+               temp.dump.rx_status = inl( ioaddr + RX_CHANNEL_STATUS );
+               temp.dump.mac_config = inl( ioaddr + MAC_CONFIG );
+               temp.dump.tx_control = inl( ioaddr + TX_CHANNEL_CONTROL );
+               temp.dump.rx_control = inl( ioaddr + RX_CHANNEL_CONTROL );
+               temp.dump.tx_cmd_ptr = inl( ioaddr + TX_CMD_PTR_LO );
+               temp.dump.rx_cmd_ptr = inl( ioaddr + RX_CMD_PTR_LO );
+               temp.dump.int_status = inl( ioaddr + INTERRUPT_STATUS_REG );
+
+               spin_unlock_irqrestore( &sp->lock, flags );
+               copy_to_user( regs, (char *) &temp.dump, sizeof( struct ncr885e_regs ));
+
+               break;
+
+       default:
+               return -EOPNOTSUPP;
+       }
+       return 0;
+}
+#endif
+
+/*  Enable interrupts on the 53C885 */
+static inline void
+ncr885e_enable( struct device *dev )
+
+{
+       unsigned long ioaddr = dev->base_addr;
+       unsigned short reg;
+
+       reg = inw(ioaddr + INTERRUPT_ENABLE);
+       outw(reg | INTERRUPT_INTE, ioaddr + INTERRUPT_ENABLE);
+}
+
+/*  Disable interrupts on the 53c885 */
+static inline void
+ncr885e_disable( struct device *dev )
+
+{
+       unsigned long ioaddr = dev->base_addr;
+       unsigned short reg;
+
+       reg = inw( ioaddr + INTERRUPT_ENABLE );
+       outw( reg & ~INTERRUPT_INTE, ioaddr + INTERRUPT_ENABLE );
+}
+
+
+static inline void
+ncr885e_reset( struct device *dev )
+
+{
+       unsigned short reg;  
+       unsigned long cntl;
+       int i;
+       unsigned long ioaddr = dev->base_addr;
+
+       if (ncr885e_debug > 1)
+               printk( KERN_INFO "%s: Resetting 53C885...\n", dev->name );
+
+       /* disable interrupts on the 53C885 */
+       ncr885e_disable( dev );
+  
+       /* disable rx in the MAC */
+       reg = inw( ioaddr + MAC_CONFIG );
+       outw( reg & ~MAC_CONFIG_RXEN, ioaddr + MAC_CONFIG );
+  
+       for( i=0; i < 100; i++ ) {
+
+               if ( !(inw( ioaddr + MAC_CONFIG ) & MAC_CONFIG_RXEN ))
+                       break;
+               udelay( 10 );
+       }
+  
+       reg = inw( ioaddr + MAC_CONFIG );
+       outw( reg | MAC_CONFIG_SRST, ioaddr + MAC_CONFIG );
+       outw( reg, ioaddr + MAC_CONFIG );
+
+       /* disable both rx and tx DBDMA channels */
+       outl( TX_DBDMA_ENABLE << 16, ioaddr + TX_CHANNEL_CONTROL );
+       outl( RX_DBDMA_ENABLE << 16, ioaddr + RX_CHANNEL_CONTROL );
+
+       for( i=0; i < 100; i++ ) {
+    
+               if ( !(inw( ioaddr + TX_CHANNEL_STATUS ) & TX_DBDMA_ENABLE ) &&
+                    !(inw( ioaddr + RX_CHANNEL_STATUS ) & RX_DBDMA_ENABLE ))
+                       break;
+               udelay( 10 );
+       }
+
+       /* perform a "software reset" */
+       cntl = inl( ioaddr + DBDMA_CONTROL );
+       outl( cntl | DBDMA_SRST, ioaddr + DBDMA_CONTROL );
+
+       for( i=0; i < 100; i++ ) {
+  
+               if ( !(inl( ioaddr + DBDMA_CONTROL ) & DBDMA_SRST ))
+                       break;
+               udelay( 10 );
+       }
+
+       /* books says that a software reset should be done to the MAC, as
+          well.  This true??? */
+
+       if (ncr885e_debug > 3) 
+               printk( KERN_INFO "%s: reset complete\n", dev->name );
+
+}
+
+
+/*  configure the 53C885 chip.
+
+    The DBDMA command descriptors on the 53C885 can be programmed to
+    branch, interrupt or pause conditionally or always by using the
+    interrupt, branch and wait select registers.  */
+
+static void
+ncr885e_config( struct device *dev )
+
+{
+       unsigned long ioaddr = dev->base_addr;
+
+       if (ncr885e_debug > 3)
+               printk( KERN_INFO "%s: Configuring 53C885.\n", dev->name );
+
+       ncr885e_reset( dev );
+       /* The 53C885 can be programmed to perform conditional DBDMA
+          branches, interrupts or waits.
+  
+          Neither channel makes use of "wait", as it requires that the
+          DBDMA engine to be restarted.  Don't go there.  The rx channel
+          will branch upon the successful reception of a packet ('EOP' in
+          the xfer_status field).  The branch address is to the STOP
+          DBDMA command descriptor, which shuts down the rx channel until
+          the interrupt is serviced.   */
+     
+       /* cause tx channel to stop after "status received" */
+       outl( 0, ioaddr + TX_INT_SELECT );
+       outl( (TX_WAIT_STAT_RECV << 16) | TX_WAIT_STAT_RECV, 
+             ioaddr + TX_WAIT_SELECT );
+       outl( 0, ioaddr + TX_BRANCH_SELECT );
+
+       /* cause rx channel to branch to the STOP descriptor on "End-of-Packet" */
+#if 0
+       outl( (RX_INT_SELECT_EOP << 16) | RX_INT_SELECT_EOP,
+             ioaddr + RX_INT_SELECT );
+#else
+       outl( 0, ioaddr + RX_INT_SELECT );
+#endif
+#if 0
+       outl( 0, ioaddr + RX_WAIT_SELECT );
+#else
+       outl( (RX_WAIT_SELECT_EOP << 16) | RX_WAIT_SELECT_EOP, 
+             ioaddr + RX_WAIT_SELECT );
+#endif
+#if 1
+       outl( 0, ioaddr + RX_BRANCH_SELECT );
+#else
+       outl( (RX_BRANCH_SELECT_EOP << 16) | RX_BRANCH_SELECT_EOP,
+             ioaddr + RX_BRANCH_SELECT );
+#endif
+
+       /* configure DBDMA */
+       outl( (DBDMA_BE | DBDMA_DPMRLE | DBDMA_TDPCE |
+              DBDMA_DDPE | DBDMA_TDPE |
+              (DBDMA_BURST_4 << DBDMA_TX_BST_SHIFT) |
+              (DBDMA_BURST_4 << DBDMA_RX_BST_SHIFT) |
+              (DBDMA_TX_ARBITRATION_DEFAULT) |
+              (DBDMA_RX_ARBITRATION_DEFAULT)), ioaddr + DBDMA_CONTROL );
+
+       outl( 0, ioaddr + TX_THRESHOLD );
+
+       /* disable MAC loopback */
+       outl( (MAC_CONFIG_ITXA | MAC_CONFIG_RXEN | MAC_CONFIG_RETRYL |
+              MAC_CONFIG_PADEN | (0x18 << 16)),
+             ioaddr + MAC_CONFIG );
+
+       /* configure MAC */
+       outl( (MAC_CONFIG_ITXA | MAC_CONFIG_RXEN | MAC_CONFIG_RETRYL |
+              MAC_CONFIG_PADEN | ( 0x18 << 16)), ioaddr + MAC_CONFIG );
+
+       outw( (0x1018), ioaddr + NBTOB_INTP_GAP );
+
+       /* clear and enable interrupts */
+       inw( ioaddr + INTERRUPT_CLEAR );
+       ncr885e_enable( dev );
+
+       /* and enable them in the chip */
+       outl( (INTERRUPT_INTE|INTERRUPT_TX_MASK|INTERRUPT_RX_MASK)<<16,
+             ioaddr + INTERRUPT_ENABLE - 2);
+
+       if (ncr885e_debug > 3)
+               printk( KERN_INFO "%s: 53C885 config complete.\n", dev->name );
+
+       return;
+}
+
+
+
+/*
+   transmit interrupt  */
+
+static void
+ncr885e_tx( struct device *dev )
+
+{
+       struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+       volatile struct dbdma_cmd *cp, *dp;
+       unsigned short txbits, xfer;
+       int i;
+
+       del_timer( &sp->tx_timeout );
+
+       if (ncr885e_debug > 3)
+               printk( KERN_INFO "%s: ncr885e_tx: active=%d, dirty=%d, current=%d\n", 
+                       dev->name, sp->tx_active, sp->tx_dirty, sp->tx_current );
+
+       sp->timeout_active = 0;
+
+       i = sp->tx_dirty;
+       cp = sp->tx_cmds + (i*3);
+       dp = cp+1;
+       sp->tx_active--;
+
+       xfer = inw( &dp->xfer_status );
+       txbits = inw( &sp->tx_status[i] );
+
+       if (ncr885e_debug > 4) {
+               show_dbdma_cmd( cp );
+               show_dbdma_cmd( dp );
+       }
+
+       /* get xmit result */
+       txbits = inw( &sp->tx_status[i] );
+
+       if (ncr885e_debug > 3)
+               printk( KERN_INFO "%s: tx xfer=%04x, txbits=%04x\n", dev->name,
+                       xfer, txbits );
+
+       /* look for any channel status (?) */
+       if ( xfer ) {
+
+               dev_kfree_skb( sp->tx_skbufs[i] );
+               mark_bh( NET_BH );
+
+               if ( txbits & TX_STATUS_TXOK ) {
+                       sp->stats.tx_packets++;
+                       sp->stats.tx_bytes += inw( &cp->req_count );
+               }
+
+               /* dropped packets */
+               if ( txbits & (TX_STATUS_TDLC|TX_STATUS_TDEC) ) {
+                       sp->stats.tx_dropped++;
+               }
+
+               /* add the collisions */
+               sp->stats.collisions += ( txbits & 0x04 );
+
+       }
+
+       dev->tbusy = 0;
+  
+       return;
+}
+
+/*  rx interrupt handling */
+static void
+ncr885e_rx( struct device *dev )
+
+{
+       struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+       volatile struct dbdma_cmd *cp;
+       struct sk_buff *skb;
+       int i, nb;
+       unsigned short status;
+       unsigned char *data, *stats;
+       unsigned long rxbits, ioaddr = dev->base_addr;
+
+       i = sp->rx_current;
+       cp = sp->rx_cmds + (i*2);
+
+       if (ncr885e_debug > 3)
+               printk( KERN_INFO "%s: ncr885e_rx dirty=%d, current=%d (cp@%p)\n",
+                       dev->name, sp->rx_dirty, sp->rx_current, cp );
+
+       nb = inw( &cp->req_count ) - inw( &cp->res_count );
+       status = inw( &cp->xfer_status );
+
+       if (ncr885e_debug > 3)
+               printk( KERN_INFO "%s: (rx %d) bytes=%d, xfer_status=%04x\n", 
+                       dev->name, i, nb, status );
+
+       if ( status ) {
+
+               skb = sp->rx_skbufs[i];
+               data = skb->data;
+               stats = data + nb - 3;
+               rxbits = (stats[0]|stats[1]<<8|stats[2]<<16);
+  
+               if (ncr885e_debug > 3)
+                       printk( KERN_INFO "  rx_bits=%06lx\n", rxbits );
+
+               skb->dev = dev;
+               skb_put( skb, nb-3 );
+               skb->protocol = eth_type_trans( skb, dev );
+               netif_rx( skb );
+               sp->rx_skbufs[i] = 0;
+
+               if ( rxbits & RX_STATUS_RXOK ) {
+                       sp->stats.rx_packets++;
+                       sp->stats.rx_bytes += nb;
+               }
+
+               if ( rxbits & RX_STATUS_MCAST )
+                       sp->stats.multicast++;
+
+       }
+
+       sp->rx_dirty = sp->rx_current;
+
+       if ( ++sp->rx_current >= NR_RX_RING )
+               sp->rx_current = 0;
+
+       /* fix up the one we just trashed */
+       cp = sp->rx_cmds + (sp->rx_dirty * 2);
+
+       skb = dev_alloc_skb( RX_BUFLEN + 2 );
+       if ( skb != 0 ) {
+               skb_reserve( skb, 2 );
+               sp->rx_skbufs[sp->rx_dirty] = skb;
+       }
+
+       if (ncr885e_debug > 2)
+               printk( KERN_INFO "%s: ncr885e_rx: using ring index %d, filling cp @ %p\n", 
+                       dev->name, sp->rx_current, cp );
+  
+       outw( RX_BUFLEN, &cp->req_count );
+       outw( 0, &cp->res_count );
+       data = skb->data;
+       outl( virt_to_bus( data ), &cp->phy_addr );
+       outw( 0, &cp->xfer_status );
+
+       cp = sp->rx_cmds + (sp->rx_current * 2);
+
+       /* restart rx DMA */
+       outl( virt_to_bus( cp ), ioaddr + RX_CMD_PTR_LO );
+       outl( (RX_DBDMA_ENABLE << 16)|RX_CHANNEL_RUN,
+             ioaddr + RX_CHANNEL_CONTROL );
+
+       return;
+}
+
+static void
+ncr885e_misc_ints( struct device *dev, unsigned short status )
+
+{
+       struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+       struct dbdma_cmd *cp;
+       unsigned long ioaddr = dev->base_addr;
+
+       if (ncr885e_debug > 1)
+               printk( KERN_INFO "miscellaneous interrupt handled; status=%02x\n", 
+                       status );
+
+       /* various transmit errors */
+       if ( status & 
+            (INTERRUPT_PPET | INTERRUPT_PBFT | INTERRUPT_IIDT) ) {
+
+               /* illegal instruction in tx dma */
+               if ( status & INTERRUPT_IIDT ) {
+
+                       cp = (struct dbdma_cmd *) bus_to_virt( inl( ioaddr + TX_CMD_PTR_LO ));
+                       printk( KERN_INFO "%s: tx illegal insn:\n", dev->name );
+                       printk( KERN_INFO " tx DBDMA - cmd = %p, status = %04x\n", 
+                               cp, inw( ioaddr + TX_CHANNEL_STATUS ));
+                       printk( KERN_INFO " command = %04x, phy_addr=%08x, req_count=%04x\n",
+                               inw( &cp->command ), inw( &cp->phy_addr ), inw( &cp->req_count ));
+               }
+
+               if ( status & INTERRUPT_PPET )
+                       printk( KERN_INFO "%s: tx PCI parity error\n", dev->name );
+               if ( status & INTERRUPT_PBFT )
+                       printk( KERN_INFO "%s: tx PCI bus fault\n", dev->name );
+       }
+
+       /* look for rx errors */
+       if ( status &
+            (INTERRUPT_PPER | INTERRUPT_PBFR | INTERRUPT_IIDR)) {
+
+               /* illegal instruction in rx dma */
+               if ( status & INTERRUPT_IIDR ) {
+#if 0
+                       cmd = inl( ioaddr + RX_CMD_PTR_LO );      
+#endif
+                       printk( KERN_ERR "%s: rx illegal DMA instruction:\n", dev->name );
+                       printk( KERN_ERR "    channel status=%04x,\n",
+                               inl( ioaddr + RX_CHANNEL_STATUS ));
+#if 0
+                       show_dbdma_cmd( bus_to_virt( inl( ioaddr + RX_CMD_PTR_LO )));
+                       printk( KERN_ERR "    instr (%08x) %08x %08x %08x\n",
+                               (int) cmd, cmd[0], cmd[1], cmd[2] );
+#endif
+               }
+
+               /* PCI parity error */
+               if ( status & INTERRUPT_PPER )
+                       printk( KERN_INFO "%s: rx PCI parity error\n", dev->name );
+
+               if ( status & INTERRUPT_PBFR )
+                       printk( KERN_INFO "%s: rx PCI bus fault\n", dev->name );
+
+               sp->stats.rx_errors++;
+       }
+
+       if ( status & INTERRUPT_WI ) {
+               printk( KERN_INFO "%s: link pulse\n", dev->name );
+       }
+
+       /* bump any counters */
+  
+
+       return;
+}
+
+static void
+ncr885e_interrupt( int irq, void *dev_id, struct pt_regs *regs )
+
+{
+       struct device  *dev = (struct device *) dev_id;
+       struct ncr885e_private *sp;
+       unsigned short status;
+       int ioaddr;
+
+       if ( dev == NULL ) {
+               printk( KERN_ERR "symba: Interrupt IRQ %d for unknown device\n", irq );
+               return;
+       }
+
+       ioaddr = dev->base_addr;
+       sp = (struct ncr885e_private *) dev->priv;
+       spin_lock( &sp->lock );
+  
+       if ( dev->interrupt ) {
+               printk( KERN_ERR "%s: Re-entering interrupt handler...\n", 
+                       dev->name );
+       }
+
+       dev->interrupt = 1;
+       status = inw( ioaddr + INTERRUPT_CLEAR );
+
+       if (ncr885e_debug > 2)
+               printk( KERN_INFO "%s: 53C885 interrupt 0x%02x\n", dev->name, status );
+
+       /* handle non-tx and rx interrupts first */
+       if ( status & ~(INTERRUPT_DIT|INTERRUPT_DIR))
+               ncr885e_misc_ints( dev, status );
+
+       /* look for tx interrupt: more to transmit, DBDMA stopped, or tx done */
+       if ( ( status & INTERRUPT_DIT ) ) {
+
+               if (ncr885e_debug > 2)
+                       printk( KERN_INFO "%s: tx int; int=%02x, chan stat=%02x\n", 
+                               dev->name, status, inw( ioaddr + TX_CHANNEL_STATUS ));
+
+               /* turn off timer */
+               del_timer( &sp->tx_timeout );
+               sp->timeout_active = 0;
+
+               /* stop DMA */
+               outl( TX_DBDMA_ENABLE << 16, ioaddr + TX_CHANNEL_CONTROL );
+
+               ncr885e_tx( dev );
+       }
+
+       if ( status & INTERRUPT_DIR ) {
+
+               if ( ncr885e_debug > 2 )
+                       printk( KERN_INFO "%s: rx interrupt; int=%02x, rx channel stat=%02x\n", 
+                               dev->name, status, inw( ioaddr + RX_CHANNEL_STATUS ));
+
+               /* stop DMA */
+               outl( RX_DBDMA_ENABLE << 16, ioaddr + RX_CHANNEL_CONTROL );
+    
+               /* and handle the interrupt */
+               ncr885e_rx( dev );
+       }
+  
+       dev->interrupt = 0;
+       spin_unlock( &sp->lock );
+
+       return;
+}
+
+
+/*  doesn't set the address permanently, however... */
+static int 
+ncr885e_set_address( struct device *dev, void *addr )
+
+{
+       struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+       struct sockaddr *saddr = addr;
+       unsigned long  flags;
+       unsigned short reg[3];
+       unsigned char *ioaddr, *p;
+       int i;
+
+       memcpy( dev->dev_addr, saddr->sa_data, dev->addr_len );
+
+       p = (unsigned char *) dev->dev_addr;
+       printk( KERN_INFO "%s: setting new MAC address - ", dev->name );
+#if 0
+       for( p = (unsigned char *) dev->dev_addr, i=0; i < 6; i++, p++ ) 
+               printk("%c%2.2x", i ? ':' : ' ', *p );
+#endif
+
+
+       p = (unsigned char *) &reg;
+       for( i=0; i < 6; i++ )
+               p[i] = dev->dev_addr[i];
+
+#if 0
+       printk("%s: Setting new mac address - ", dev->name );
+       for( i=0; i < 6; i++ ) {
+               printk("%02x", i ? ':' : ' ', p[i] );
+       }
+
+       printk("\n");
+#endif
+
+       /* stop rx for the change */
+       outl( RX_DBDMA_ENABLE << 16, ioaddr + RX_CHANNEL_CONTROL );
+  
+       spin_lock_irqsave( &sp->lock, flags );
+
+       ioaddr = (unsigned char *) dev->base_addr;
+
+       for( i = 0; i < 3; i++ ) {
+               reg[i] = ((reg[i] & 0xff) << 8) | ((reg[i] >> 8) & 0xff);
+               printk("%04x ", reg[i] );
+               outw( reg[i], ioaddr + STATION_ADDRESS_0 + (i*2));
+       }
+       printk("\n");
+
+       spin_unlock_irqrestore( &sp->lock, flags );
+
+       /* restart rx */
+       outl((RX_DBDMA_ENABLE << 16)|RX_CHANNEL_RUN, 
+            ioaddr + RX_CHANNEL_CONTROL );
+
+       return 0;
+}
+
+static void 
+ncr885e_tx_timeout( unsigned long data )
+
+{
+       struct device *dev = (struct device *) data;
+       struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+       unsigned long flags, ioaddr;
+       int i;
+  
+       save_flags( flags );
+       cli();
+
+       ioaddr = dev->base_addr;
+       sp->timeout_active = 0;
+       i = sp->tx_dirty;
+
+       /* if we weren't active, bail... */
+       if ( sp->tx_active == 0 ) {
+               printk( KERN_INFO "%s: ncr885e_timeout...tx not active!\n", dev->name );
+               goto out;
+       }
+
+       printk( KERN_ERR "%s: 53C885 timed out.  Resetting...\n", dev->name );
+
+       /* disable rx and tx DMA */
+       outl( (TX_DBDMA_ENABLE << 16), ioaddr + TX_CHANNEL_CONTROL );
+       outl( (RX_DBDMA_ENABLE << 16), ioaddr + RX_CHANNEL_CONTROL );
+
+       /* reset the chip */
+       ncr885e_config( dev );
+       ncr885e_enable( dev );
+
+       /* clear the wedged skb in the tx ring */
+       sp->tx_active = 0;
+       ++sp->stats.tx_errors;
+  
+       if ( sp->tx_skbufs[i] ) {
+               dev_kfree_skb( sp->tx_skbufs[i] );
+               sp->tx_skbufs[i] = 0;
+       }
+
+       /* start anew from the beginning of the ring buffer (why not?) */
+       sp->tx_current = 0;
+       dev->tbusy = 0;
+       mark_bh( NET_BH );
+
+       /* restart rx dma */
+       outl( (RX_DBDMA_ENABLE << 16) | RX_CHANNEL_RUN,
+             ioaddr + RX_CHANNEL_CONTROL );  
+ out:
+
+       restore_flags( flags );
+}
+
+static inline void
+ncr885e_set_timeout( struct device *dev )
+
+{
+       struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+
+       if ( sp->timeout_active )
+               del_timer( &sp->tx_timeout );
+
+       sp->tx_timeout.expires = jiffies + TX_TIMEOUT;
+       sp->tx_timeout.function = ncr885e_tx_timeout;
+       sp->tx_timeout.data = (unsigned long) dev;
+       add_timer( &sp->tx_timeout );
+       sp->timeout_active = 1;
+       restore_flags( flags );
+}
+
+
+/*
+ *  The goal is to set up DBDMA such that the rx ring contains only
+ *  one DMA descriptor per ring element and the tx ring has two (using
+ *  the cool features of branch- and wait-select.  However, I'm not sure
+ *  if it's possible.  For now, we plod through it with 3 descriptors
+ *  for tx, and two for rx.
+ */
+
+static int
+ncr885e_open( struct device *dev )
+
+{
+       struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+       unsigned long ioaddr = dev->base_addr;
+       struct sk_buff *skb;
+       int i, size;
+       char *data;
+       struct dbdma_cmd *cp;
+       unsigned long flags;
+
+       /* allocate enough space for the tx and rx rings and a STOP descriptor */  
+       size = (sizeof( struct dbdma_cmd ) *
+               ((NR_TX_RING * 3) + (NR_RX_RING * 2) + 1));
+
+       cp = kmalloc( size, GFP_KERNEL );
+
+       if ( cp == 0 ) {
+               printk( KERN_ERR "Insufficient memory (%d bytes) for DBDMA\n", size );
+               return -ENOMEM;
+       }
+
+       spin_lock_init( &sp->lock );
+       spin_lock_irqsave( &sp->lock, flags );
+
+       memset((char *) cp, 0, size );
+       sp->head = cp;
+
+       sp->stop_cmd = cp;
+       outl( DBDMA_STOP, &cp->command );
+  
+       sp->rx_cmds = ++cp;
+
+       for( i = 0; i < NR_RX_RING; i++ ) {
+
+               cp = sp->rx_cmds + (i*2);
+               skb = dev_alloc_skb( RX_BUFLEN + 2 );
+
+               /* if there is insufficient memory, make this last ring use a 
+                  static buffer and leave the loop with that skb as final one */
+               if ( skb == 0 ) {
+                       printk( KERN_ERR "%s: insufficient memory for rx ring buffer\n",
+                               dev->name );
+                       break;
+               }
+
+               skb_reserve( skb, 2 );
+               sp->rx_skbufs[i] = skb;
+               data = skb->data;
+
+               /* The DMA commands here are done such that an EOP is the only
+                  way that we should get an interrupt.  This means that we could
+                  fill more than one skbuff before getting the interrupt at EOP. */
+
+               /* Handle rx DMA such that it always interrupts.... */
+               outw( (INPUT_MORE|INTR_ALWAYS), &cp->command );
+               outw( RX_BUFLEN, &cp->req_count );
+               outw( 0, &cp->res_count );
+               outl( virt_to_bus( data ), &cp->phy_addr );
+               outl( virt_to_bus( sp->stop_cmd ), &cp->cmd_dep );
+               outw( 0, &cp->xfer_status );
+#if 0
+               printk( KERN_INFO "rx at %p\n", cp );
+               show_dbdma_cmd( cp );
+#endif
+               ++cp;
+
+               outw( DBDMA_STOP, &cp->command );
+
+       }
+
+       /* initialize to all rx buffers are available, fill limit is the end */
+       sp->rx_dirty = 0;
+       sp->rx_current = 0;
+
+       /* fill the tx ring */
+       sp->tx_cmds = cp+1;
+
+       for( i = 0; i < NR_TX_RING; i++ ) {
+
+               /* minimal setup for tx command */
+               cp = sp->tx_cmds + (i*3);
+               outw( OUTPUT_LAST, &cp->command );
+               if (ncr885e_debug > 3) {
+                       printk( KERN_INFO "tx OUTPUT_LAST at %p\n", cp );
+                       show_dbdma_cmd( cp );
+               }
+
+               /* full setup for the status cmd */
+               cp++;
+               outw( INPUT_LAST|INTR_ALWAYS|WAIT_IFCLR, &cp->command );
+               outl( virt_to_bus( &sp->tx_status[i] ), &cp->phy_addr );
+               outw( 2, &cp->req_count );
+               if ( ncr885e_debug > 3) {
+                       printk( KERN_INFO "tx INPUT_LAST cmd at %p\n", cp );
+                       show_dbdma_cmd( cp );
+               }
+
+               ++cp;
+               outw( DBDMA_STOP, &cp->command );
+       }
+#if 0
+       /* chain the last tx DMA command to the STOP cmd */
+       outw((INPUT_LAST|INTR_ALWAYS|BR_ALWAYS), &cp->command );
+       outl( virt_to_bus( sp->stop_cmd ), &cp->cmd_dep );
+#endif
+       sp->tx_active = 0;
+       sp->tx_current = 0;
+       sp->tx_dirty = 0;
+
+       spin_unlock_irqrestore( &sp->lock, flags );
+
+       /* the order seems important here for some reason.  If the MPIC isn't
+          enabled before the ethernet chip is enabled, shrapnel from the
+          bootloader causes us to receive interrupts even though we've not 
+          yet enabled the tx channel.  Go figure.  It'd be better to configure
+          the chip in the probe1() routine, but then we don't see interrupts
+          at all.  Everything looks all right on the logic analyzer, but... */
+
+       ncr885e_config( dev );
+
+       /* enable ethernet interrupts */
+       if ( request_irq( dev->irq, &ncr885e_interrupt, SA_SHIRQ, chipname, dev )) {
+               printk( KERN_ERR "%s: can't get irq %d\n", dev->name, dev->irq );
+               return -EAGAIN;
+       }
+
+       (void) inw( ioaddr + INTERRUPT_CLEAR );
+
+       ncr885e_enable( dev );
+
+       /* start rx DBDMA */
+       outl( virt_to_bus( sp->rx_cmds ), ioaddr + RX_CMD_PTR_LO );
+       outl( (RX_DBDMA_ENABLE << 16)|RX_CHANNEL_RUN,
+             ioaddr + RX_CHANNEL_CONTROL );
+
+       dev->start = 1;
+       dev->tbusy = 0;
+       dev->interrupt = 0;
+
+       MOD_INC_USE_COUNT;
+
+       return 0;
+}
+
+static int
+ncr885e_xmit_start( struct sk_buff *skb, struct device *dev )
+
+{
+       struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+       volatile struct dbdma_cmd *cp, *dp;
+       unsigned long flags, ioaddr = dev->base_addr;
+       int len, next, fill, entry;
+
+       if ( ncr885e_debug > 3)
+               printk( KERN_INFO "%s: xmit_start len=%d, dirty=%d, current=%d, active=%d\n",
+                       dev->name, skb->len, sp->tx_dirty, sp->tx_current, sp->tx_active );
+
+       spin_lock_irqsave( &sp->lock, flags );
+
+       /* find the free slot in the ring buffer */
+       fill = sp->tx_current;
+       next = fill + 1;
+
+       if ( next >= NR_TX_RING )
+               next = 0;
+
+       /* mark ourselves as busy, even if we have too many packets waiting */
+       dev->tbusy = 1;
+
+       /* see if it's necessary to defer this packet */
+       if ( sp->tx_active >= MAX_TX_ACTIVE ) {
+               spin_unlock_irqrestore( &sp->lock, flags );
+               return -1;
+       }
+
+       sp->tx_active++;  /* bump "active tx" count */
+       sp->tx_current = next;  /* and show that we've used this buffer */
+       sp->tx_dirty = fill;     /* and mark this one to get picked up */
+
+       len = skb->len;
+
+       if ( len > ETH_FRAME_LEN ) {
+               printk( KERN_DEBUG "%s: xmit frame too long (%d)\n", dev->name, len );
+               len = ETH_FRAME_LEN;
+       }  
+
+       /* get index into the tx DBDMA chain */
+       entry = fill * 3;
+       sp->tx_skbufs[fill] = skb;
+       cp = sp->tx_cmds + entry;
+       dp = cp + 1;
+
+       /* update the rest of the OUTPUT_MORE descriptor */
+       outw( len, &cp->req_count );
+       outl( virt_to_bus( skb->data ), &cp->phy_addr );
+       outw( 0, &cp->xfer_status );
+       outw( 0, &cp->res_count );
+
+       /* and finish off the INPUT_MORE */
+       outw( 0, &dp->xfer_status );
+       outw( 0, &dp->res_count );
+       sp->tx_status[fill] = 0;
+       outl( virt_to_bus( &sp->tx_status[fill] ), &dp->phy_addr );
+
+       if ( ncr885e_debug > 2 )
+               printk(KERN_INFO "%s: xmit_start: active %d, tx_current %d, tx_dirty %d\n",
+                      dev->name, sp->tx_active, sp->tx_current, sp->tx_dirty );
+
+       if ( ncr885e_debug > 4 ) {
+               show_dbdma_cmd( cp );
+               show_dbdma_cmd( dp );
+       }
+
+
+       /* restart the tx DMA engine */
+       outl( virt_to_bus( cp ), ioaddr + TX_CMD_PTR_LO );
+       outl( (TX_DBDMA_ENABLE << 16)|TX_CHANNEL_RUN, 
+             ioaddr + TX_CHANNEL_CONTROL );
+
+       ncr885e_set_timeout( dev );
+
+       spin_unlock_irqrestore( &sp->lock, flags );
+       dev->trans_start = jiffies;
+
+       return 0;      
+}
+
+static int
+ncr885e_close(struct device *dev)
+
+{
+       int i;
+       struct ncr885e_private *np = (struct ncr885e_private *) dev->priv;
+       unsigned long ioaddr = dev->base_addr;
+
+       dev->start = 0;
+       dev->tbusy = 1;
+
+       spin_lock( &np->lock );
+
+       printk(KERN_INFO "%s: NCR885E Ethernet closing...\n", dev->name );
+
+       if (ncr885e_debug > 1)
+               printk(KERN_DEBUG "%s: Shutting down Ethernet chip\n", dev->name);
+
+       ncr885e_disable(dev);
+
+       del_timer(&np->tx_timeout);
+
+       /* flip off rx and tx */
+       outl( (RX_DBDMA_ENABLE << 16), ioaddr + RX_CHANNEL_CONTROL );
+       outl( (TX_DBDMA_ENABLE << 16), ioaddr + TX_CHANNEL_CONTROL );  
+
+       /* free up the IRQ */
+       free_irq( dev->irq, dev );
+
+       for( i = 0; i < NR_RX_RING; i++ ) {
+               if (np->rx_skbufs[i])
+                       dev_kfree_skb( np->rx_skbufs[i] );
+               np->rx_skbufs[i] = 0;
+       }
+#if 0
+       for (i = 0; i < NR_TX_RING; i++) {
+               if (np->tx_skbufs[i])
+                       dev_kfree_skb(np->tx_skbufs[i]);
+               np->tx_skbufs[i] = 0;
+       }
+#endif
+       spin_unlock( &np->lock );
+
+       kfree( np->head );
+
+       MOD_DEC_USE_COUNT;
+
+       return 0;
+}
+
+
+/*
+ *  multicast promiscuous mode isn't used here.  Allow code in the
+ *  IP stack to determine which multicast packets are good or bad....
+ *  (this avoids having to use the hash table registers)
+ */
+static void
+ncr885e_set_multicast( struct device *dev )
+
+{
+       int ioaddr = dev->base_addr;
+
+       if ( ncr885e_debug > 3 )
+               printk("%s: set_multicast: dev->flags = %x, AF=%04x\n", 
+                      dev->name, dev->flags, inw( ioaddr + ADDRESS_FILTER ));
+
+       if ( dev->flags & IFF_PROMISC ) {
+               printk( KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name );
+               outw( ADDRESS_RPPRO, ioaddr + ADDRESS_FILTER );
+       }
+
+       /* accept all multicast packets without checking the mc_list.  */
+       else if ( dev->flags & IFF_ALLMULTI ) {
+               printk( KERN_INFO "%s: Enabling all multicast packets.\n", 
+                       dev->name );
+               outw( ADDRESS_RPPRM, ioaddr + ADDRESS_FILTER );
+       }
+
+       /* enable broadcast rx */
+       else {
+               outw( ADDRESS_RPABC, ioaddr + ADDRESS_FILTER );
+       }  
+}
+
+static struct net_device_stats *
+ncr885e_stats( struct device *dev )
+
+{
+       struct ncr885e_private *np = (struct ncr885e_private *) dev->priv;
+
+       return &np->stats;
+}
+
+/*  By this function, we're certain that we have a 885 Ethernet controller
+ *  so we finish setting it up and wrap up all the required Linux ethernet
+ *  configuration.
+ */
+
+static int
+ncr885e_probe1( struct device *dev, unsigned long ioaddr, unsigned char irq )
+
+{
+       struct ncr885e_private *sp;
+       unsigned short station_addr[3], val;
+       unsigned char *p;
+       int  i;
+
+       dev = init_etherdev( dev, 0 );
+
+       /* construct private data for the 885 ethernet */
+       dev->priv = kmalloc( sizeof( struct ncr885e_private ), GFP_KERNEL );
+
+       if ( dev->priv == NULL )
+               return -ENOMEM;
+
+       sp = (struct ncr885e_private *) dev->priv;
+       memset( sp, 0, sizeof( struct ncr885e_private ));
+
+       /* snag the station address and display it */
+       for( i = 0; i < 3; i++ ) {
+               val = inw( ioaddr + STATION_ADDRESS_0 + (i*2));
+               station_addr[i] = ((val >> 8) & 0xff) | ((val << 8) & 0xff00);
+       }
+
+       printk( KERN_INFO "%s: %s at %08lx,", dev->name, chipname, ioaddr );
+
+       p = (unsigned char *) &station_addr;
+
+       for( i=0; i < 6; i++ ) {
+               dev->dev_addr[i] = *p;
+               printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i] );
+               p++;
+       }
+
+       printk(", IRQ %d.\n", irq );
+
+       request_region( ioaddr, NCR885E_TOTAL_SIZE, dev->name );
+
+       /* set up a timer */
+       init_timer( &sp->tx_timeout );
+       sp->timeout_active = 0;
+
+       dev->base_addr = ioaddr;
+       dev->irq = irq;
+
+       ether_setup( dev );
+
+       /* everything else */
+       dev->open = ncr885e_open;
+       dev->stop = ncr885e_close;
+       dev->get_stats = ncr885e_stats;
+       dev->hard_start_xmit = ncr885e_xmit_start;
+       dev->set_multicast_list = ncr885e_set_multicast;
+       dev->set_mac_address = ncr885e_set_address;
+
+       return 0;
+}
+
+/*  Since the NCR 53C885 is a multi-function chip, I'm not worrying about
+ *  trying to get the the device(s) in slot order.  For our (Synergy's)
+ *  purpose, there's just a single 53C885 on the board and we don't 
+ *  worry about the rest.
+ */
+
+int __init ncr885e_probe( struct device *dev )
+{
+       struct pci_dev *pdev = NULL;
+       unsigned int ioaddr, chips = 0;
+       unsigned short cmd;
+       unsigned char irq, latency;
+
+       while(( pdev = pci_find_device( PCI_VENDOR_ID_NCR, 
+                                       PCI_DEVICE_ID_NCR_53C885_ETHERNET,
+                                       pdev )) != NULL ) {
+
+               if ( !print_version ) {
+                       print_version++;
+                       printk( KERN_INFO "%s", version );
+               }
+
+               /* Use I/O space */
+               pci_read_config_dword( pdev, PCI_BASE_ADDRESS_0, &ioaddr );
+               pci_read_config_byte( pdev, PCI_INTERRUPT_LINE, &irq );
+
+               ioaddr &= ~3;
+               /* Adjust around the Grackle... */
+#ifdef CONFIG_GEMINI
+               ioaddr |= 0xfe000000;
+#endif
+
+               if ( check_region( ioaddr, NCR885E_TOTAL_SIZE ))
+                       continue;
+
+               /* finish off the probe */
+               if ( !(ncr885e_probe1( dev, ioaddr, irq ))) {
+
+                       chips++;
+
+                       /* Access is via I/O space, bus master enabled... */
+                       pci_read_config_word( pdev, PCI_COMMAND, &cmd );
+
+                       if ( !(cmd & PCI_COMMAND_MASTER) ) {
+                               printk( KERN_INFO "  PCI master bit not set! Now setting.\n");
+                               cmd |= PCI_COMMAND_MASTER;
+                               pci_write_config_word( pdev, PCI_COMMAND, cmd );
+                       }
+
+                       if ( !(cmd & PCI_COMMAND_IO) ) {
+                               printk( KERN_INFO "  Enabling I/O space.\n" );
+                               cmd |= PCI_COMMAND_IO;
+                               pci_write_config_word( pdev, PCI_COMMAND, cmd );
+                       }
+
+                       pci_read_config_byte( pdev, PCI_LATENCY_TIMER, &latency );
+
+                       if ( latency < 10 ) {
+                               printk( KERN_INFO "  PCI latency timer (CFLT) is unreasonably"
+                                       " low at %d.  Setting to 255.\n", latency );
+                               pci_write_config_byte( pdev, PCI_LATENCY_TIMER, 255 );
+                       }
+               }
+       }
+
+       if ( !chips )
+               return -ENODEV;
+       else
+               return 0;
+}
+
+/* debugging to peek at dma descriptors */
+static void
+show_dbdma_cmd( volatile struct dbdma_cmd *cmd )
+
+{
+       printk( KERN_INFO " cmd %04x, physaddr %08x, req_count %04x\n",
+               inw( &cmd->command ), inl( &cmd->phy_addr ), inw( &cmd->req_count ));
+       printk( KERN_INFO " res_count %04x, xfer_status %04x, branch %08x\n", 
+               inw( &cmd->res_count ), inw( &cmd->xfer_status ),inl( &cmd->cmd_dep ));
+}
+
+#if 0
+static int
+read_eeprom( unsigned int ioaddr, int location )
+
+{
+       int loop;
+       unsigned char val;
+
+       outb( (location & 0xff), ioaddr + EE_WORD_ADDR );
+
+       /* take spillover from location in control reg */
+       outb(EE_CONTROL_RND_READB | (location & (0x7<<8)), ioaddr + EE_CONTROL);
+
+       loop = 1000;
+       while( (inb( ioaddr + EE_STATUS) & EE_SEB) &&
+              (loop > 0) ) {
+               udelay( 10 );
+               loop--;
+       }
+
+       if ( inb( ioaddr + EE_STATUS ) & EE_SEE ) {
+               printk("%s: Serial EEPROM read error\n", chipname);
+               val = 0xff;
+       }
+
+       else 
+               val = inb( ioaddr + EE_READ_DATA );
+
+       return (int) val;
+}
+#endif
+
+#ifdef NCR885E_DEBUG_MII
+static void
+show_mii( unsigned long ioaddr )
+
+{
+       int   phyctrl, phystat, phyadvert, phypartner, phyexpan;
+
+       phyctrl = read_mii( ioaddr, MII_AUTO_NEGOTIATION_CONTROL );
+       phystat = read_mii( ioaddr, MII_AUTO_NEGOTIATION_STATUS );
+       phyadvert = read_mii( ioaddr, MII_AUTO_NEGOTIATION_ADVERTISEMENT );
+       phypartner = read_mii( ioaddr, MII_AUTO_NEGOTIATION_LINK_PARTNER );
+       phyexpan = read_mii( ioaddr, MII_AUTO_NEGOTIATION_EXPANSION );
+
+       printk( KERN_INFO "PHY: advert=%d %s, partner=%s %s, link=%d, %s%s\n",
+               (phyadvert & MANATECH_100BASETX_FULL_DUPLEX ? 100 : 10),
+               (phyctrl & MANC_AUTO_NEGOTIATION_ENABLE ? "auto" : "fixed"),
+               (phypartner & MANLP_ACKNOWLEDGE ?
+                (phypartner & MANATECH_100BASETX_FULL_DUPLEX ? "100" : "10") :
+                "?"),
+               (phyexpan & MANE_LINK_PARTNER_AUTO_ABLE ? "auto" : "fixed"),
+               (phyctrl & MANC_PHY_SPEED_100 ? 100 : 10),
+               (phystat & MANS_LINK_STATUS ? "up" : "down"),
+               (phyexpan & MANE_PARALLEL_DETECTION_FAULT ? " PD-fault" : "" ));
+       return;
+}
+
+
+static int
+read_mii( unsigned long ioaddr, int reg )
+
+{
+       int    timeout;
+
+
+       timeout = 100000;
+
+       while( inw( ioaddr + MII_INDICATOR ) & MII_BUSY ) {
+
+               if ( timeout-- < 0 ) {
+                       printk( KERN_INFO "Timed out waiting for MII\n" );
+                       return -1;
+               }
+       }
+
+       outw( (1<<8) + reg, ioaddr + MII_ADDRESS );
+       outw( MIIM_RSTAT, ioaddr + MIIM_COMMAND );
+
+       timeout = 100000;
+       while( inw( ioaddr + MII_INDICATOR ) & MII_BUSY ) {
+               if ( timeout-- < 0 ) {
+                       printk( KERN_INFO "Timed out waiting for MII\n" );
+                       return -1;
+               }
+       }
+
+       return( inw( ioaddr + MII_READ_DATA ));
+}
+
+static void
+write_mii( unsigned long ioaddr, int reg, int data )
+
+{
+       int timeout=100000;
+
+       printk( KERN_INFO "MII indicator: %02x\n", inw( ioaddr + MII_INDICATOR ));
+
+       while( inw( ioaddr + MII_INDICATOR ) & MII_BUSY ) {
+               if ( timeout-- <= 0 ) {
+                       printk( KERN_INFO "Timeout waiting to write to MII\n" );
+                       return;
+               }
+               udelay( 10 );
+       }
+
+       outw( (1<<8) + reg, ioaddr + MII_ADDRESS );
+       outw( data, ioaddr + MII_WRITE_DATA );
+
+       return;
+}
+
+#endif /* NCR885E_DEBUG_MII */
+
+#ifdef MODULE
+#if defined(LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20118
+MODULE_AUTHOR("dan@synergymicro.com");
+MODULE_DESCRIPTION("Symbios 53C885 Ethernet driver");
+MODULE_PARM(debug, "i");
+#endif 
+
+static int debug = 1;
+
+int
+init_module(void)
+{
+       if ( debug >= 0)
+               ncr885e_debug = debug;
+
+       return ncr885e_probe( NULL );
+}
+
+void
+cleanup_module(void)
+{
+       struct ncr885e_private *np;
+
+       if ( root_dev ) {
+
+               unregister_netdev( root_dev );
+               np = (struct ncr885e_private *) root_dev->priv;
+               release_region( root_dev->base_addr, NCR885E_TOTAL_SIZE );
+               kfree( root_dev->priv );
+               root_dev = NULL;
+       }  
+}
+#endif /* MODULE */
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -DMODULE -DMODVERSIONS -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O6 -c symba.c"
+ * End:
+ */
diff --git a/drivers/net/ncr885e.h b/drivers/net/ncr885e.h
new file mode 100644 (file)
index 0000000..bbcc82e
--- /dev/null
@@ -0,0 +1,367 @@
+#ifndef _NET_H_SYMBA
+#define _NET_H_SYMBA
+
+/* transmit status bit definitions */
+#define TX_STATUS_TXOK         (1<<13)     /* success */
+#define TX_STATUS_TDLC         (1<<12)     /* dropped for late colls */
+#define TX_STATUS_TCXSDFR      (1<<11)     /* excessive deferral */
+#define TX_STATUS_TDEC         (1<<10)     /* excessive collisions */
+#define TX_STATUS_TAUR         (1<<9)      /* abort on underrun/"jumbo" */
+#define TX_STATUS_PDFRD        (1<<8)      /* packet deferred */
+#define TX_STATUS_BCAST        (1<<7)      /* broadcast ok */
+#define TX_STATUS_MCAST        (1<<6)      /* multicast ok */
+#define TX_STATUS_CRCERR       (1<<5)      /* CRC error */
+#define TX_STATUS_LC           (1<<4)      /* late collision */
+#define TX_STATUS_CCNT_MASK    0xf         /* collision count */
+
+#define T_TXOK      (1<<13)
+#define T_TDLC      (1<<12)
+#define T_TCXSDFR   (1<<11)
+#define T_TDEC      (1<<10)
+#define T_TAUR      (1<<9)
+#define T_PDFRD     (1<<8)
+#define T_BCAST     (1<<7)
+#define T_MCAST     (1<<6)
+#define T_LC        (1<<4)
+#define T_CCNT_MASK 0xf
+
+/* receive status bit definitions */
+#define RX_STATUS_RXOVRN       (1<<23)     /* overrun */
+#define RX_STATUS_CEPS         (1<<22)     /* carrier event already seen */
+#define RX_STATUS_RXOK         (1<<21)     /* success */
+#define RX_STATUS_BCAST        (1<<20)     /* broadcast ok */
+#define RX_STATUS_MCAST        (1<<19)     /* multicast ok */
+#define RX_STATUS_CRCERR       (1<<18)     /* CRC error */
+#define RX_STATUS_DR           (1<<17)     /* dribble nibble */
+#define RX_STATUS_RCV          (1<<16)     /* rx code violation */
+#define RX_STATUS_PTL          (1<<15)     /* pkt > 1518 bytes */
+#define RX_STATUS_PTS          (1<<14)     /* pkt < 64 bytes */
+#define RX_STATUS_LEN_MASK     0x1fff      /* length mask */
+
+#define EEPROM_LENGTH          100
+
+
+/*  Serial EEPROM interface  */
+#define EE_STATUS              0xf0
+#define EE_CONTROL             0xf1
+#define EE_WORD_ADDR           0xf2
+#define EE_READ_DATA           0xf3
+#define EE_WRITE_DATA          0xf4
+#define EE_FEATURE_ENB         0xf5
+
+/*  Use on EE_STATUS  */
+#define EE_SEB                 (1<<8)
+#define EE_SEE                     1
+
+/*  Serial EEPROM commands */
+#define EE_CONTROL_SEQ_READB   (1<<4)
+#define EE_CONTROL_RND_WRITEB  (1<<5)
+#define EE_CONTROL_RND_READB   ((1<<4)|(1<<5))
+
+/*  Enable writing to serial EEPROM */
+#define EE_WRITE_ENB                1
+
+/*  The 885 configuration register */
+#define MAC_CONFIG             0xa0
+#define  MAC_CONFIG_SRST       1<<15
+#define  MAC_CONFIG_ITXA       1<<13
+#define  MAC_CONFIG_RXEN       1<<12
+#define  MAC_CONFIG_INTLB      1<<10
+#define  MAC_CONFIG_MODE_MASK  (1<<8|1<<9)
+#define  MAC_CONFIG_MODE_TP    1<<8
+#define  MAC_CONFIG_HUGEN      1<<5
+#define  MAC_CONFIG_RETRYL     1<<4
+#define  MAC_CONFIG_CRCEN      1<<3
+#define  MAC_CONFIG_PADEN      1<<2
+#define  MAC_CONFIG_FULLD      1<<1
+#define  MAC_CONFIG_NOCFR      1<<0
+
+
+
+
+
+#define TX_WAIT_SELECT         0x18
+#define RX_CHANNEL_CONTROL     0x40
+
+/* Tx channel status */
+#define TX_DBDMA_REG           0x00
+#define TX_CHANNEL_CONTROL     0x00
+#define TX_CHANNEL_STATUS      0x04
+#define  TX_STATUS_RUN         1<<15
+#define  TX_STATUS_PAUSE       1<<14
+#define  TX_STATUS_WAKE        1<<12
+#define  TX_STATUS_DEAD        1<<11
+#define  TX_STATUS_ACTIVE      1<<10
+#define  TX_STATUS_BT          1<<8
+#define  TX_STATUS_TXABORT     1<<7
+#define  TX_STATUS_TXSR        1<<6
+
+#define  TX_CHANNEL_RUN        TX_STATUS_RUN
+#define  TX_CHANNEL_PAUSE      TX_STATUS_PAUSE
+#define  TX_CHANNEL_WAKE       TX_STATUS_WAKE
+#define  TX_CHANNEL_DEAD       TX_STATUS_DEAD
+#define  TX_CHANNEL_ACTIVE     TX_STATUS_ACTIVE
+#define  TX_CHANNEL_BT         TX_STATUS_BT
+#define  TX_CHANNEL_TXABORT    TX_STATUS_TXABORT
+#define  TX_CHANNEL_TXSR       TX_STATUS_TXSR
+
+#define  TX_DBDMA_ENABLE       (TX_CHANNEL_WAKE | TX_CHANNEL_PAUSE | \
+                                TX_CHANNEL_RUN )
+
+/* Transmit command ptr lo register */
+#define TX_CMD_PTR_LO          0x0c
+
+/* Transmit interrupt select register */
+#define TX_INT_SELECT          0x10
+
+/* Transmit branch select register */
+#define TX_BRANCH_SELECT       0x14
+
+/* Transmit wait select register */
+#define TX_WAIT_SELECT         0x18
+#define  TX_WAIT_STAT_RECV     0x40
+
+/* Rx channel status */
+#define RX_DBDMA_REG           0x40
+#define RX_CHANNEL_CONTROL     0x40
+#define RX_CHANNEL_STATUS      0x44
+#define  RX_STATUS_RUN         1<<15
+#define  RX_STATUS_PAUSE       1<<14
+#define  RX_STATUS_WAKE        1<<12
+#define  RX_STATUS_DEAD        1<<11
+#define  RX_STATUS_ACTIVE      1<<10
+#define  RX_STATUS_BT          1<<8
+#define  RX_STATUS_EOP         1<<6
+
+#define  RX_CHANNEL_RUN        RX_STATUS_RUN
+#define  RX_CHANNEL_PAUSE      RX_STATUS_PAUSE
+#define  RX_CHANNEL_WAKE       RX_STATUS_WAKE
+#define  RX_CHANNEL_DEAD       RX_STATUS_DEAD
+#define  RX_CHANNEL_ACTIVE     RX_STATUS_ACTIVE
+#define  RX_CHANNEL_BT         RX_STATUS_BT
+#define  RX_CHANNEL_EOP        RX_STATUS_EOP
+
+#define  RX_DBDMA_ENABLE       (RX_CHANNEL_WAKE | RX_CHANNEL_PAUSE | \
+                                RX_CHANNEL_RUN)
+
+/*  Receive command ptr lo  */
+#define RX_CMD_PTR_LO          0x4c
+
+/*  Receive interrupt select register */
+#define RX_INT_SELECT          0x50
+#define  RX_INT_SELECT_EOP     0x40
+
+/*  Receive branch select  */
+#define RX_BRANCH_SELECT       0x54
+#define  RX_BRANCH_SELECT_EOP  0x40
+
+/*  Receive wait select  */
+#define RX_WAIT_SELECT         0x58
+#define  RX_WAIT_SELECT_EOP    0x40
+
+/*  Event status register  */
+#define EVENT_STATUS           0x80
+#define  EVENT_TXSR            1<<2
+#define  EVENT_EOP             1<<1
+#define  EVENT_TXABORT         1<<0
+
+/*  Interrupt enable register  */
+#define INTERRUPT_ENABLE       0x82
+
+/*  Interrupt clear register  */
+#define INTERRUPT_CLEAR        0x84
+
+/*  Interrupt status register  */
+#define INTERRUPT_STATUS_REG   0x86
+
+/*  bits for the above three interrupt registers */
+#define  INTERRUPT_INTE        1<<15   /* interrupt enable */
+#define  INTERRUPT_WI          1<<9    /* wakeup interrupt */
+#define  INTERRUPT_ERI         1<<8    /* early recieve interrupt */
+#define  INTERRUPT_PPET        1<<7    /* PCI Tx parity error */
+#define  INTERRUPT_PBFT        1<<6    /* PCI Tx bus fault */
+#define  INTERRUPT_IIDT        1<<5    /* illegal instruction Tx */
+#define  INTERRUPT_DIT         1<<4    /* DBDMA Tx interrupt */
+#define  INTERRUPT_PPER        1<<3    /* PCI Rx parity error */
+#define  INTERRUPT_PBFR        1<<2    /* PCI Rx bus fault */
+#define  INTERRUPT_IIDR        1<<1    /* illegal instruction Rx */
+#define  INTERRUPT_DIR         1<<0    /* DBDMA Rx interrupt */
+
+#define  INTERRUPT_TX_MASK     (INTERRUPT_PBFT|INTERRUPT_IIDT| \
+                                INTERRUPT_PPET|INTERRUPT_DIT)
+#define  INTERRUPT_RX_MASK     (INTERRUPT_PBFR|INTERRUPT_IIDR| \
+                                INTERRUPT_PPER|INTERRUPT_DIR)
+
+/*  chip revision register */
+#define CHIP_REVISION_REG      0x8c
+#define  CHIP_PCIREV_MASK      (0xf<<16)
+#define  CHIP_PCIDEV_MASK      0xff
+
+/*  Tx threshold register */
+#define TX_THRESHOLD           0x94
+
+/*  General purpose register */
+#define GEN_PURPOSE_REG        0x9e
+
+/*  General purpose pin control reg */
+#define GEN_PIN_CONTROL_REG    0x9f
+
+/*  DBDMA control register  */
+#define DBDMA_CONTROL          0x90
+#define  DBDMA_SRST            1<<31
+#define  DBDMA_TDPCE           1<<23
+#define  DBDMA_BE              1<<22
+#define  DBDMA_TAP_MASK        (1<<19|1<<20|1<<21)
+#define  DBDMA_RAP_MASK        (1<<16|1<<17|1<<18)
+#define  DBDMA_DPMRLE          1<<15
+#define  DBDMA_WIE             1<<14
+#define  DBDMA_MP              1<<13
+#define  DBDMA_SME             1<<12
+#define  DBDMA_CME             1<<11
+#define  DBDMA_DDPE            1<<10
+#define  DBDMA_TDPE            1<<9
+#define  DBDMA_EXTE            1<<8
+#define  DBDMA_BST_MASK        (1<<4|1<<5|1<<6)
+#define  DBDMA_BSR_MASK        (1<<0|1<<1|1<<2)
+
+#define  DBDMA_BURST_1         (0x00)
+#define  DBDMA_BURST_2         (0x01)
+#define  DBDMA_BURST_4         (0x02)
+#define  DBDMA_BURST_8         (0x03)
+#define  DBDMA_BURST_16        (0x04)
+#define  DBDMA_BURST_32        (0x05)
+#define  DBDMA_BURST_64        (0x06)
+#define  DBDMA_BURST_128       (0x07)
+
+#define  DBDMA_TX_BST_SHIFT    (4)
+#define  DBDMA_RX_BST_SHIFT    (0)
+
+#define  DBDMA_TX_ARBITRATION_DEFAULT ( 1 << 19 )
+#define  DBDMA_RX_ARBITRATION_DEFAULT ( 2 << 16 )
+
+
+/*  Back-to-back interpacket gap register */
+#define BTOB_INTP_GAP          0xa2
+#define  BTOB_INTP_DEFAULT     0x18
+
+/*  Non-back-to-back interpacket gap register */
+#define NBTOB_INTP_GAP         0xa4
+
+/*  MIIM command register */
+#define MIIM_COMMAND           0xa6
+#define  MIIM_SCAN             1<<1
+#define  MIIM_RSTAT            1<<0
+
+/*  MII address register */
+#define MII_ADDRESS            0xa8
+#define  MII_FIAD_MASK         (1<<8|1<<9|1<<10|1<<11|1<<12)
+#define  MII_RGAD_MASK         (1<<0|1<<1|1<<2|1<<3|1<<4)
+
+#define TPPMD_CONTROL_REG      0xa8
+#define  TPPMD_FO              1<<1
+#define  TPPMD_LB              1<<0
+
+/*  MII read and write registers */
+#define MII_WRITE_DATA         0xaa
+#define MII_READ_DATA          0xac
+
+/*  MII indicators */
+#define MII_INDICATOR          0xae
+#define  MII_NVALID            1<<2
+#define  MII_SCAN              1<<1
+#define  MII_BUSY              1<<0
+
+/*  Address filter  */
+#define ADDRESS_FILTER         0xd0
+#define  ADDRESS_RPPRM         1<<3       /* multicast promis. mode */
+#define  ADDRESS_RPPRO         1<<2       /* promiscuous mode */
+#define  ADDRESS_RPAMC         1<<1       /* accept multicasts */
+#define  ADDRESS_RPABC         1<<0       /* accept broadcasts */
+
+/*  Station addresses
+
+    Note that if the serial EEPROM is disabled, these values are all
+    zero.  If, like us, you get the chips when they're fresh, they're
+    also zero and you have to initialize the address */
+#define STATION_ADDRESS_0      0xd2
+#define STATION_ADDRESS_1      0xd4
+#define STATION_ADDRESS_2      0xd6
+
+/*  Hash tables  */
+#define HASH_TABLE_0           0xd8
+#define HASH_TABLE_1           0xda
+#define HASH_TABLE_2           0xdc
+#define HASH_TABLE_3           0xde
+
+/* PHY indentifiers */
+#define PHY_IDENTIFIER_0       0xe4
+#define PHY_IDENTIFIER_1       0xe6
+
+/*  MII Auto-negotiation register definitions  */
+
+#define MII_AUTO_NEGOTIATION_CONTROL        (0x0000)
+#define   MANC_PHY_RESET                      (0x8000)
+#define   MANC_PHY_LOOPBACK_ENABLE            (0x4000)
+#define   MANC_PHY_LOOPBACK_DISABLE           (0x0000)
+#define   MANC_PHY_SPEED_100                  (0x2000)
+#define   MANC_PHY_SPEED_10                   (0x0000)
+#define   MANC_AUTO_NEGOTIATION_ENABLE        (0x1000)
+#define   MANC_AUTO_NEGOTIATION_DISABLE       (0x0000)
+#define   MANC_PHY_POWER_DOWN                 (0x0800)
+#define   MANC_PHY_POWER_UP                   (0x0000)
+#define   MANC_ISOLATE_ENABLE                 (0x0400)
+#define   MANC_ISOLATE_DISABLE                (0x0000)
+#define   MANC_RESTART_AUTO_NEGOTIATION       (0x0200)
+#define   MANC_FULL_DUPLEX                    (0x0100)
+#define   MANC_HALF_DUPLEX                    (0x0000)
+
+#define MII_AUTO_NEGOTIATION_STATUS         (0x0001)
+#define   MANS_100BASE_T4_HALF_DUPLEX         (0x8000)
+#define   MANS_100BASE_X_FULL_DUPLEX          (0x4000)
+#define   MANS_100BASE_X_HALF_DUPLEX          (0x2000)
+#define   MANS_10MBS_FULL_DUPLEX              (0x1000)
+#define   MANS_10MBS_HALF_DUPLEX              (0x0800)
+#define   MANS_AUTO_NEGOTIATION_COMPLETE      (0x0020)
+#define   MANS_REMOTE_FAULT                   (0x0010)
+#define   MANS_AUTO_NEGOTIATION_ABILITY       (0x0008)
+#define   MANS_LINK_STATUS                    (0x0004)
+#define   MANS_JABBER_DETECT                  (0x0002)
+#define   MANS_EXTENDED_CAPABILITY            (0x0001)
+
+#define MII_PHY_IDENTIFIER_1                (0x0002)
+#define MII_PHY_IDENTIFIER_2                (0x0003)
+
+#define MII_AUTO_NEGOTIATION_ADVERTISEMENT  (0x0004)
+#define   MANA_NEXT_PAGE                      (0x8000)
+#define   MANA_REMOTE_FAULT                   (0x2000)
+#define   MANA_TECHNOLOGY_ABILITY_MASK        (0x1FE0)
+#define     MANATECH_10BASET_HALF_DUPLEX        (0x0020)
+#define     MANATECH_10BASET_FULL_DUPLEX        (0x0040)
+#define     MANATECH_100BASETX_HALF_DUPLEX      (0x0080)
+#define     MANATECH_100BASETX_FULL_DUPLEX      (0x0100)
+#define     MANATECH_100BASET4                  (0x0200)
+#define   MANA_SELECTOR_MASK                  (0x001F)
+#define     MANASELECTOR_802_3                  (0x0001)
+
+#define MII_AUTO_NEGOTIATION_LINK_PARTNER   (0x0005)
+#define   MANLP_NEXT_PAGE                     (0x8000)
+#define   MANLP_ACKNOWLEDGE                   (0x4000)
+#define   MANLP_REMOTE_FAULT                  (0x2000)
+#define   MANLP_TECHNOLOGY_ABILITY_MASK       (0x1FE0)
+#define   MANLP_SELECTOR_MASK                 (0x001F)
+
+#define MII_AUTO_NEGOTIATION_EXPANSION      (0x0006)
+#define   MANE_PARALLEL_DETECTION_FAULT       (0x0010)
+#define   MANE_LINK_PARTNER_NEXT_PAGE_ABLE    (0x0008)
+#define   MANE_NEXT_PAGE_ABLE                 (0x0004)
+#define   MANE_PAGE_RECEIVED                  (0x0002)
+#define   MANE_LINK_PARTNER_AUTO_ABLE         (0x0001)
+
+#define MII_AUTO_NEGOTIATION_NEXT_PAGE_TRANSMIT (0x0007)
+#define   MANNPT_NEXT_PAGE                    (0x8000)
+#define   MANNPT_MESSAGE_PAGE                 (0x2000)
+#define   MANNPT_ACKNOWLEDGE_2                (0x1000)
+#define   MANNPT_TOGGLE                       (0x0800)
+#define   MANNPT_MESSAGE_FIELD_MASK           (0x07FF)
+
+#endif
index 5ba16319d713c357f61ffb2a3db289e02751d875..2cb9b61639e177c4dc1d420bef059f3899055fa7 100644 (file)
@@ -258,6 +258,7 @@ static struct dev_info device_list[] =
 {"TEAC","CD-ROM","1.06", BLIST_NOLUN},          /* causes failed REQUEST SENSE on lun 1
                                                 * for seagate controller, which causes
                                                 * SCSI code to reset bus.*/
+       {"TEAC", "MT-2ST/45S2-27", "RV M", BLIST_NOLUN},        /* Responds to all lun */
 {"TEXEL","CD-ROM","1.06", BLIST_NOLUN},         /* causes failed REQUEST SENSE on lun 1
                                                 * for seagate controller, which causes
                                                 * SCSI code to reset bus.*/
@@ -268,7 +269,8 @@ static struct dev_info device_list[] =
 {"HP", "C1750A", "3226", BLIST_NOLUN},          /* scanjet iic */
 {"HP", "C1790A", "", BLIST_NOLUN},              /* scanjet iip */
 {"HP", "C2500A", "", BLIST_NOLUN},              /* scanjet iicx */
-{"YAMAHA", "CDR102", "1.00", BLIST_NOLUN},     /* extra reset */
+{"YAMAHA","CDR100","1.00", BLIST_NOLUN},       /* Locks up if polled for lun != 0 */
+{"YAMAHA","CDR102","1.00", BLIST_NOLUN},       /* Locks up if polled for lun != 0 */
 {"RELISYS", "Scorpio", "*", BLIST_NOLUN},      /* responds to all LUN */
 
 /*
@@ -292,8 +294,6 @@ static struct dev_info device_list[] =
 {"nCipher","Fastness Crypto","*", BLIST_FORCELUN},
 {"NEC","PD-1 ODX654P","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"MATSHITA","PD-1","*", BLIST_FORCELUN | BLIST_SINGLELUN},
-{"YAMAHA","CDR100","1.00", BLIST_NOLUN},       /* Locks up if polled for lun != 0 */
-{"YAMAHA","CDR102","1.00", BLIST_NOLUN},       /* Locks up if polled for lun != 0 */
 {"iomega","jaz 1GB","J.86", BLIST_NOTQ | BLIST_NOLUN},
 {"CREATIVE","DVD-RAM RAM","*", BLIST_GHOST},
 {"MATSHITA","PD-2 LF-D100","*", BLIST_GHOST},
index e1aace0a330c414b99728bee3d2c9bddbdfb62c1..d91ec96c803652a44ec57116895a608c47469c6d 100644 (file)
@@ -45,9 +45,9 @@ kmem_cache_t *dentry_cache;
 #define D_HASHBITS     d_hash_shift
 #define D_HASHMASK     d_hash_mask
 
-static unsigned int d_hash_mask = 0;
-static unsigned int d_hash_shift = 0;
-static struct list_head *dentry_hashtable = NULL;
+static unsigned int d_hash_mask;
+static unsigned int d_hash_shift;
+static struct list_head *dentry_hashtable;
 static LIST_HEAD(dentry_unused);
 
 struct {
@@ -71,18 +71,23 @@ static inline void d_free(struct dentry *dentry)
  * Release the dentry's inode, using the fileystem
  * d_iput() operation if defined.
  */
-static inline void dentry_iput(struct dentry * dentry)
+static inline int dentry_iput(struct dentry * dentry)
 {
        struct inode *inode = dentry->d_inode;
+       int ret = 0;
+
        if (inode) {
                dentry->d_inode = NULL;
                list_del(&dentry->d_alias);
                INIT_LIST_HEAD(&dentry->d_alias);
+               ret = inode->i_count == 1;
                if (dentry->d_op && dentry->d_op->d_iput)
                        dentry->d_op->d_iput(dentry, inode);
                else
                        iput(inode);
        }
+
+       return ret;
 }
 
 /*
@@ -196,87 +201,24 @@ int d_invalidate(struct dentry * dentry)
        return 0;
 }
 
-/*
- * Select less valuable dentries to be pruned when we need
- * inodes or memory. The selected dentries are moved to the
- * old end of the list where prune_dcache() can find them.
- * 
- * Negative dentries are included in the selection so that
- * they don't accumulate at the end of the list. The count
- * returned is the total number of dentries selected, which
- * may be much larger than the requested number of inodes.
- */
-int select_dcache(int inode_count, int page_count)
-{
-       struct list_head *next, *tail = &dentry_unused;
-       int found = 0;
-       int depth = dentry_stat.nr_unused >> 1;
-       unsigned long max_value = 4;
-
-       if (page_count)
-               max_value = -1;
-
-       next = tail->prev;
-       while (next != &dentry_unused && depth--) {
-               struct list_head *tmp = next;
-               struct dentry *dentry = list_entry(tmp, struct dentry, d_lru);
-               struct inode *inode = dentry->d_inode;
-               unsigned long value = 0;        
-
-               next = tmp->prev;
-               if (dentry->d_count) {
-                       dentry_stat.nr_unused--;
-                       list_del(tmp);
-                       INIT_LIST_HEAD(tmp);
-                       continue;
-               }
-
-               /*
-                * Select dentries based on the page cache count ...
-                * should factor in number of uses as well. We take
-                * all negative dentries so that they don't accumulate.
-                * (We skip inodes that aren't immediately available.)
-                */
-               if (inode) {
-                       value = inode->i_nrpages;       
-                       if (value >= max_value)
-                               continue;
-                       if (inode->i_state || inode->i_count > 1)
-                               continue;
-               }
-
-               /*
-                * Move the selected dentries behind the tail.
-                */
-               if (tmp != tail->prev) {
-                       list_del(tmp);
-                       list_add(tmp, tail->prev);
-               }
-               tail = tmp;
-               found++;
-               if (inode && --inode_count <= 0)
-                       break;
-               if (page_count && (page_count -= value) <= 0)
-                       break;
-       }
-       return found;
-}
-
 /*
  * Throw away a dentry - free the inode, dput the parent.
  * This requires that the LRU list has already been
  * removed.
  */
-static inline void prune_one_dentry(struct dentry * dentry)
+static inline int prune_one_dentry(struct dentry * dentry)
 {
        struct dentry * parent;
+       int ret;
 
        list_del(&dentry->d_hash);
        list_del(&dentry->d_child);
-       dentry_iput(dentry);
+       ret = dentry_iput(dentry);
        parent = dentry->d_parent;
        d_free(dentry);
        dput(parent);
+
+       return ret;
 }
 
 /*
@@ -284,9 +226,21 @@ static inline void prune_one_dentry(struct dentry * dentry)
  * more memory, or simply when we need to unmount
  * something (at which point we need to unuse
  * all dentries).
+ *
+ * If you don't want a limit on the number of
+ * inodes that will be released then call
+ * with i_nr = -1.
+ *
+ * If you don't want a limit on the number of
+ * dentries that will be released then call
+ * with d_nr = 0.
+ *
+ * Returns the number of inodes released.
  */
-void prune_dcache(int count)
+int prune_dcache(int d_nr, int i_nr)
 {
+       int __i_nr = i_nr;
+
        for (;;) {
                struct dentry *dentry;
                struct list_head *tmp = dentry_unused.prev;
@@ -298,11 +252,15 @@ void prune_dcache(int count)
                INIT_LIST_HEAD(tmp);
                dentry = list_entry(tmp, struct dentry, d_lru);
                if (!dentry->d_count) {
-                       prune_one_dentry(dentry);
-                       if (!--count)
+                       i_nr -= prune_one_dentry(dentry);
+                       if (!i_nr)
+                               break;
+                       if (!--d_nr)
                                break;
                }
        }
+
+       return __i_nr - i_nr;
 }
 
 /*
@@ -457,7 +415,7 @@ void shrink_dcache_parent(struct dentry * parent)
        int found;
 
        while ((found = select_parent(parent)) != 0)
-               prune_dcache(found);
+               prune_dcache(found, -1);
 }
 
 /*
@@ -477,7 +435,7 @@ void shrink_dcache_memory(int priority, unsigned int gfp_mask)
                int count = 0;
                if (priority)
                        count = dentry_stat.nr_unused / priority;
-               prune_dcache(count);
+               prune_dcache(count, -1);
        }
 }
 
@@ -926,8 +884,9 @@ void __init dcache_init(void)
                panic("Cannot create dentry cache");
 
        memory_size = num_physpages << PAGE_SHIFT;
-       for (order = 5; (1UL << order) < memory_size; order++)
-               ;
+       memory_size >>= 13;
+       memory_size *= 2 * sizeof(void *);
+       for (order = 0; ((1UL << order) << PAGE_SHIFT) < memory_size; order++);
 
        do {
                unsigned long tmp;
index 2630078f74a9e0ce79d5853a7387e7d589ccfd3c..a3121fec271e05c99b2d0a8301e6723076ca47d3 100644 (file)
@@ -31,6 +31,9 @@
  *             add_dquot_ref() restarts after blocking
  *             Added check for bogus uid and fixed check for group in quotactl.
  *             Jan Kara, <jack@atrey.karlin.mff.cuni.cz>, 4-6/99
+ *             Definitely (hopefully) fixed deadlock in write_dquot(). We no
+ *             longer account quota files.
+ *             Jan Kara, <jack@suse.cz>, 11/99, sposored by SuSE CR
  *
  * (C) Copyright 1994 - 1997 Marco van Wieringen 
  */
@@ -245,6 +248,9 @@ static inline void unlock_dquot(struct dquot *dquot)
        wake_up(&dquot->dq_wait);
 }
 
+/*
+ *     We don't have to be afraid of deadlocks as we never have quotas on quota files...
+ */
 static void write_dquot(struct dquot *dquot)
 {
        short type = dquot->dq_type;
@@ -252,20 +258,14 @@ static void write_dquot(struct dquot *dquot)
        mm_segment_t fs;
        loff_t offset;
        ssize_t ret;
-       struct dqblk data;
        struct semaphore *sem = &dquot->dq_mnt->mnt_dquot.dqio_sem;
 
-       /*
-        * We copy our data to preserve consistency when dquot is not locked.
-        * We can't lock it because it can cause deadlocks - think about
-        * growing the quota file...
-        */
-       memcpy(&data, &dquot->dq_dqb, sizeof(struct dqblk));
-       down(sem);
+       lock_dquot(dquot);
        if (!dquot->dq_mnt) {   /* Invalidated quota? */
-               up(sem);
+               unlock_dquot(dquot);
                return;
        }
+       down(sem);
        filp = dquot->dq_mnt->mnt_dquot.files[type];
        offset = dqoff(dquot->dq_id);
        fs = get_fs();
@@ -278,18 +278,15 @@ static void write_dquot(struct dquot *dquot)
        dquot->dq_flags &= ~DQ_MOD;
        ret = 0;
        if (filp)
-               ret = filp->f_op->write(filp, (char *)&data
+               ret = filp->f_op->write(filp, (char *)&dquot->dq_dqb
                                        sizeof(struct dqblk), &offset);
        if (ret != sizeof(struct dqblk))
                printk(KERN_WARNING "VFS: dquota write failed on dev %s\n",
                        kdevname(dquot->dq_dev));
 
-       /*
-        * Be sure that anybody didn't invalidated the dquot in the mean time...
-        * Nasty but I don't see other choice when we don't want to lock dquot.
-        */
-       up(sem);
        set_fs(fs);
+       up(sem);
+       unlock_dquot(dquot);
 
        dqstats.writes++;
 }
@@ -572,10 +569,9 @@ pressure:
        /*
         * Try pruning the dcache to free up some dquots ...
         */
-       count = select_dcache(128, 0);
-       if (count) {
-               printk(KERN_DEBUG "get_empty_dquot: pruning %d\n", count);
-               prune_dcache(count);
+       printk(KERN_DEBUG "get_empty_dquot: pruning %d\n", count);
+       if (prune_dcache(0, 128))
+       {
                free_inode_memory(count);
                goto repeat;
        }
@@ -652,12 +648,31 @@ static struct dquot *dqduplicate(struct dquot *dquot)
        return dquot;
 }
 
+/* Check whether this inode is quota file */
+static inline int is_quotafile(struct inode *inode)
+{
+       int cnt;
+       struct vfsmount *vfsmnt;
+       struct file **files;
+
+       vfsmnt = lookup_vfsmnt(inode->i_dev);
+       if (!vfsmnt)
+               return 0;
+       files = vfsmnt->mnt_dquot.files;
+       for (cnt = 0; cnt < MAXQUOTAS; cnt++)
+               if (files[cnt] && files[cnt]->f_dentry->d_inode == inode)
+                       return 1;
+       return 0;
+}
+
 static int dqinit_needed(struct inode *inode, short type)
 {
        int cnt;
 
         if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)))
                 return 0;
+       if (is_quotafile(inode))
+               return 0;
        if (type != -1)
                return inode->i_dquot[type] == NODQUOT;
        for (cnt = 0; cnt < MAXQUOTAS; cnt++)
@@ -1070,6 +1085,9 @@ void dquot_initialize(struct inode *inode, short type)
        if (S_ISREG(inode->i_mode) ||
             S_ISDIR(inode->i_mode) ||
             S_ISLNK(inode->i_mode)) {
+               /* We don't want to have quotas on quota files - nasty deadlocks possible */
+               if (is_quotafile(inode))
+                       return;
                for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                        if (type != -1 && cnt != type)
                                continue;
@@ -1512,6 +1530,7 @@ int quota_on(kdev_t dev, short type, char *path)
        error = -EINVAL;
        if (inode->i_size == 0 || (inode->i_size % sizeof(struct dqblk)) != 0)
                goto out_f;
+       dquot_drop(inode);      /* We don't want quota on quota files */
 
        set_enable_flags(vfsmnt, type);
        mnt_dquot->files[type] = f;
index bde5be314e46cbafba5c0c0e11ad226d78295676..dcdac2bd677c200b8beb56a6ee35bd368b178bac 100644 (file)
@@ -603,6 +603,8 @@ got_block:
                unlock_super (sb);
                return 0;
        }
+       if (!buffer_uptodate(bh))
+               wait_on_buffer(bh);
        memset(bh->b_data, 0, sb->s_blocksize);
        mark_buffer_uptodate(bh, 1);
        mark_buffer_dirty(bh, 1);
index 1a13c876b446ddf1f770f7a17293b792327351a4..0d6869b5c9c15a44741b0fa1a356f4a243bc7e37 100644 (file)
@@ -45,10 +45,21 @@ static int sync_block (struct inode * inode, u32 * block, int wait)
        if (!bh)
                return 0;
        if (wait && buffer_req(bh) && !buffer_uptodate(bh)) {
-               brelse (bh);
-               return -1;
+               /* There can be a parallell read(2) that started read-I/O
+                  on the buffer so we can't assume that there's been
+                  an I/O error without first waiting I/O completation. */
+               wait_on_buffer(bh);
+               if (!buffer_uptodate(bh))
+               {
+                       brelse (bh);
+                       return -1;
+               }
        }
        if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) {
+               if (wait)
+                       /* when we return from fsync all the blocks
+                          must be _just_ stored on disk */
+                       wait_on_buffer(bh);
                brelse (bh);
                return 0;
        }
@@ -68,10 +79,21 @@ static int sync_block_swab32 (struct inode * inode, u32 * block, int wait)
        if (!bh)
                return 0;
        if (wait && buffer_req(bh) && !buffer_uptodate(bh)) {
-               brelse (bh);
-               return -1;
+               /* There can be a parallell read(2) that started read-I/O
+                  on the buffer so we can't assume that there's been
+                  an I/O error without first waiting I/O completation. */
+               wait_on_buffer(bh);
+               if (!buffer_uptodate(bh))
+               {
+                       brelse (bh);
+                       return -1;
+               }
        }
        if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) {
+               if (wait)
+                       /* when we return from fsync all the blocks
+                          must be _just_ stored on disk */
+                       wait_on_buffer(bh);
                brelse (bh);
                return 0;
        }
index 5629f728a802115a105ee78861b53affa86e5603..c50737d675b8952cf2a109483f73676fa197d17e 100644 (file)
@@ -125,6 +125,8 @@ static int ext2_alloc_block (struct inode * inode, unsigned long goal, int * err
                                    "cannot get block %lu", result);
                        return 0;
                }
+               if (!buffer_uptodate(bh))
+                       wait_on_buffer(bh);
                memset(bh->b_data, 0, inode->i_sb->s_blocksize);
                mark_buffer_uptodate(bh, 1);
                mark_buffer_dirty(bh, 1);
index c5071f119341aea030635a12b90d08a2f81305ca..e21fab6404306216f7291fa245d78969ce94405d 100644 (file)
@@ -343,12 +343,11 @@ int invalidate_inodes(struct super_block * sb)
        (((inode)->i_count | (inode)->i_state) == 0)
 #define INODE(entry)   (list_entry(entry, struct inode, i_list))
 
-static int free_inodes(void)
+static int __free_inodes(struct list_head * freeable)
 {
-       struct list_head list, *entry, *freeable = &list;
+       struct list_head *entry;
        int found = 0;
 
-       INIT_LIST_HEAD(freeable);
        entry = inode_in_use.next;
        while (entry != &inode_in_use) {
                struct list_head *tmp = entry;
@@ -361,15 +360,19 @@ static int free_inodes(void)
                INIT_LIST_HEAD(&INODE(tmp)->i_hash);
                list_add(tmp, freeable);
                list_entry(tmp, struct inode, i_list)->i_state = I_FREEING;
-               found = 1;
+               found++;
        }
 
-       if (found)
-               dispose_list(freeable);
-
        return found;
 }
 
+static void free_inodes(void)
+{
+       LIST_HEAD(throw_away);
+       if (__free_inodes(&throw_away))
+               dispose_list(&throw_away);
+}
+
 /*
  * Searches the inodes list for freeable inodes,
  * shrinking the dcache before (and possible after,
@@ -377,6 +380,36 @@ static int free_inodes(void)
  */
 static void try_to_free_inodes(int goal)
 {
+       static int block;
+       static struct wait_queue * wait_inode_freeing;
+       LIST_HEAD(throw_away);
+       
+       /* We must make sure to not eat the inodes
+          while the blocker task sleeps otherwise
+          the blocker task may find none inode
+          available. */
+       if (block)
+       {
+               struct wait_queue __wait;
+
+               __wait.task = current;
+               add_wait_queue(&wait_inode_freeing, &__wait);
+               for (;;)
+               {
+                       /* NOTE: we rely only on the inode_lock to be sure
+                          to not miss the unblock event */
+                       current->state = TASK_UNINTERRUPTIBLE;
+                       spin_unlock(&inode_lock);
+                       schedule();
+                       spin_lock(&inode_lock);
+                       if (!block)
+                               break;
+               }
+               remove_wait_queue(&wait_inode_freeing, &__wait);
+               current->state = TASK_RUNNING;
+       }
+
+       block = 1;
        /*
         * First stry to just get rid of unused inodes.
         *
@@ -384,16 +417,18 @@ static void try_to_free_inodes(int goal)
         * to try to shrink the dcache and sync existing
         * inodes..
         */
-       free_inodes();
-       goal -= inodes_stat.nr_free_inodes;
+       goal -= __free_inodes(&throw_away);
        if (goal > 0) {
                spin_unlock(&inode_lock);
-               select_dcache(goal, 0);
-               prune_dcache(goal);
+               prune_dcache(0, goal);
                spin_lock(&inode_lock);
                sync_all_inodes();
-               free_inodes();
+               __free_inodes(&throw_away);
        }
+       if (!list_empty(&throw_away))
+               dispose_list(&throw_away);
+       block = 0;
+       wake_up(&wait_inode_freeing);
 }
 
 /*
@@ -472,7 +507,7 @@ static struct inode * grow_inodes(void)
         * If the allocation failed, do an extensive pruning of 
         * the dcache and then try again to free some inodes.
         */
-       prune_dcache(inodes_stat.nr_inodes >> 2);
+       prune_dcache(0, inodes_stat.nr_inodes >> 2);
 
        spin_lock(&inode_lock);
        free_inodes();
index d794a0846fa55af836c78cca103b2c8becf9d35d..a3926ed43c2b5108280c5c0e2dfc5e782de34936 100644 (file)
@@ -954,7 +954,7 @@ int isofs_bmap(struct inode * inode,int block)
        printk("isofs_bmap: mapped inode:block %x:%d to block %lu\n",
                inode->i_ino, block, (b_off - offset + firstext) >> ISOFS_BUFFER_BITS(inode));
 #endif
-       return (b_off - offset + firstext) >> ISOFS_BUFFER_BITS(inode);
+       return firstext + ((b_off - offset) >> ISOFS_BUFFER_BITS(inode));
 }
 
 
@@ -1162,8 +1162,7 @@ void isofs_read_inode(struct inode * inode)
          iso_date(raw_inode->date, high_sierra);
 
        inode->u.isofs_i.i_first_extent = (isonum_733 (raw_inode->extent) +
-                                          isonum_711 (raw_inode->ext_attr_length))
-         << inode -> i_sb -> u.isofs_sb.s_log_zone_size;
+                                          isonum_711 (raw_inode->ext_attr_length));
 
 /* Now test for possible Rock Ridge extensions which will override some of
    these numbers in the inode structure. */
index 8b5c8befd5b9b608da3c0c9fe875643c27b6a969..03235f22f7cdf52d96aaae8059345e4711229b4c 100644 (file)
@@ -358,9 +358,10 @@ int parse_rock_ridge_inode(struct iso_directory_record * de,
 #ifdef DEBUG
        printk("RR CL (%x)\n",inode->i_ino);
 #endif
-       inode->u.isofs_i.i_first_extent = isonum_733(rr->u.CL.location) <<
-               inode -> i_sb -> u.isofs_sb.s_log_zone_size;
-       reloc = iget(inode->i_sb, inode->u.isofs_i.i_first_extent);
+       inode->u.isofs_i.i_first_extent = isonum_733(rr->u.CL.location);
+       reloc = iget(inode->i_sb,
+                    (inode->u.isofs_i.i_first_extent <<
+                     inode -> i_sb -> u.isofs_sb.s_log_zone_size));
        if (!reloc)
                goto out;
        inode->i_mode = reloc->i_mode;
index 7439f2906a9695087a3f4e3b97ef1f99d933ccd3..a2f280bdc66ed0781d875128a34e3dfb17fe3a5f 100644 (file)
@@ -195,6 +195,12 @@ xdr_decode_stat(struct rpc_rqst *rqstp, u32 *p, struct nsm_res *resp)
 #define SM_my_id_sz    (3+1+SM_my_name_sz)
 #define SM_mon_id_sz   (1+XDR_QUADLEN(20)+SM_my_id_sz)
 #define SM_mon_sz      (SM_mon_id_sz+4)
+#define SM_monres_sz   2
+#define SM_unmonres_sz 1
+
+#ifndef MAX
+# define MAX(a, b)     (((a) > (b))? (a) : (b))
+#endif
 
 static struct rpc_procinfo     nsm_procedures[] = {
         { "sm_null",
@@ -205,10 +211,10 @@ static struct rpc_procinfo        nsm_procedures[] = {
                (kxdrproc_t) xdr_error, 0, 0 },
         { "sm_mon",
                (kxdrproc_t) xdr_encode_mon,
-               (kxdrproc_t) xdr_decode_stat_res, SM_mon_sz, 2 },
+               (kxdrproc_t) xdr_decode_stat_res, MAX(SM_mon_sz, SM_monres_sz) << 2, 0 },
         { "sm_unmon",
                (kxdrproc_t) xdr_encode_mon,
-               (kxdrproc_t) xdr_decode_stat, SM_mon_id_sz, 1 },
+               (kxdrproc_t) xdr_decode_stat, MAX(SM_mon_id_sz, SM_unmonres_sz) << 2, 0 },
         { "sm_unmon_all",
                (kxdrproc_t) xdr_error,
                (kxdrproc_t) xdr_error, 0, 0 },
index 06cd5dda9a774fa783eed33c0e76252bb4279d52..ea06839ea2dc73ff7eec22ac57290458d0f64b07 100644 (file)
@@ -1599,8 +1599,7 @@ printk("smb_proc_readdir_long: starting fpos=%d, mask=%s\n", fpos, mask);
                        command = TRANSACT2_FINDFIRST;
                        WSET(param, 0, aSYSTEM | aHIDDEN | aDIR);
                        WSET(param, 2, max_matches);    /* max count */
-                       WSET(param, 4, 8 + 4 + 2);      /* resume required +
-                                                          close on end +
+                       WSET(param, 4, 4 + 2);          /* close on end +
                                                           continue */
                        WSET(param, 6, info_level);
                        DSET(param, 8, 0);
diff --git a/include/asm-ppc/gemini.h b/include/asm-ppc/gemini.h
new file mode 100644 (file)
index 0000000..7e681e0
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ *  include/asm-ppc/gemini.h
+ *
+ *
+ *  Onboard registers and descriptions for Synergy Microsystems' 
+ *  "Gemini" boards.
+ *
+ */
+#ifndef __PPC_GEMINI_H
+#define __PPC_GEMINI_H
+
+/*  Registers  */
+
+#define GEMINI_SERIAL_B     (0xffeffb00)
+#define GEMINI_SERIAL_A     (0xffeffb08)
+#define GEMINI_USWITCH      (0xffeffd00)
+#define GEMINI_BREV         (0xffeffe00)
+#define GEMINI_BECO         (0xffeffe08)
+#define GEMINI_FEAT         (0xffeffe10)
+#define GEMINI_BSTAT        (0xffeffe18)
+#define GEMINI_CPUSTAT      (0xffeffe20)
+#define GEMINI_L2CFG        (0xffeffe30)
+#define GEMINI_MEMCFG       (0xffeffe38)
+#define GEMINI_FLROM        (0xffeffe40)
+#define GEMINI_P0PCI        (0xffeffe48)
+#define GEMINI_FLWIN        (0xffeffe50)
+#define GEMINI_P0INTMASK    (0xffeffe60)
+#define GEMINI_P0INTAP      (0xffeffe68)
+#define GEMINI_PCIERR       (0xffeffe70)
+#define GEMINI_LEDBASE      (0xffeffe80)
+#define GEMINI_RTC          (0xffe9fff8)
+#define GEMINI_LEDS         8
+#define GEMINI_SWITCHES     8
+
+
+/* Flash ROM bit definitions */
+#define GEMINI_FLS_WEN      (1<<0)
+#define GEMINI_FLS_JMP      (1<<6)
+#define GEMINI_FLS_BOOT     (1<<7)
+
+/* Memory bit definitions */
+#define GEMINI_MEM_TYPE_MASK 0xc0
+#define GEMINI_MEM_SIZE_MASK 0x38
+#define GEMINI_MEM_BANK_MASK 0x07
+
+/* L2 cache bit definitions */
+#define GEMINI_L2_SIZE_MASK  0xc0
+#define GEMINI_L2_RATIO_MASK 0x03
+
+/* Timebase register bit definitons */
+#define GEMINI_TIMEB0_EN     (1<<0)
+#define GEMINI_TIMEB1_EN     (1<<1)
+#define GEMINI_TIMEB2_EN     (1<<2)
+#define GEMINI_TIMEB3_EN     (1<<3)
+
+/* CPU status bit definitions */
+#define GEMINI_CPU_ID_MASK   0x03
+#define GEMINI_CPU_COUNT_MASK 0x0c
+#define GEMINI_CPU0_HALTED   (1<<4)
+#define GEMINI_CPU1_HALTED   (1<<5)
+#define GEMINI_CPU2_HALTED   (1<<6)
+#define GEMINI_CPU3_HALTED   (1<<7)
+
+/* Board status bit definitions */
+#define GEMINI_BRD_FAIL      (1<<0)   /* FAIL led is lit */
+#define GEMINI_BRD_BUS_MASK  0x0c     /* PowerPC bus speed */
+
+/* Board family/feature bit descriptions */
+#define GEMINI_FEAT_HAS_FLASH (1<<0)
+#define GEMINI_FEAT_HAS_ETH   (1<<1)
+#define GEMINI_FEAT_HAS_SCSI  (1<<2)
+#define GEMINI_FEAT_HAS_P0    (1<<3)
+#define GEMINI_FEAT_FAM_MASK  0xf0
+
+/* Mod/ECO bit definitions */
+#define GEMINI_ECO_LEVEL_MASK 0x0f
+#define GEMINI_MOD_MASK       0xf0
+
+/* Type/revision bit definitions */
+#define GEMINI_REV_MASK       0x0f
+#define GEMINI_TYPE_MASK      0xf0
+
+/* User switch definitions */
+#define GEMINI_SWITCH_VERBOSE    1     /* adds "debug" to boot cmd line */
+#define GEMINI_SWITCH_SINGLE_USER 7    /* boots into "single-user" mode */
+
+#define SGS_RTC_CONTROL  0
+#define SGS_RTC_SECONDS  1
+#define SGS_RTC_MINUTES  2
+#define SGS_RTC_HOURS    3
+#define SGS_RTC_DAY      4
+#define SGS_RTC_DAY_OF_MONTH 5
+#define SGS_RTC_MONTH    6
+#define SGS_RTC_YEAR     7
+
+#define SGS_RTC_SET  0x80
+#define SGS_RTC_IS_STOPPED 0x80
+
+#define GRACKLE_CONFIG_ADDR_ADDR  (0xfec00000)
+#define GRACKLE_CONFIG_DATA_ADDR  (0xfee00000)
+
+#define GEMINI_BOOT_INIT  (0xfff00100)
+
+#ifndef __ASSEMBLY__
+
+static inline void grackle_write( unsigned long addr, unsigned long data )
+{
+  __asm__ __volatile__(
+  " stwbrx %1, 0, %0\n \
+    sync\n \
+    stwbrx %3, 0, %2\n \
+    sync "
+  : /* no output */
+  : "r" (GRACKLE_CONFIG_ADDR_ADDR), "r" (addr),
+    "r" (GRACKLE_CONFIG_DATA_ADDR), "r" (data));
+}
+
+static inline unsigned long grackle_read( unsigned long addr )
+{
+  unsigned long val;
+
+  __asm__ __volatile__(
+  " stwbrx %1, 0, %2\n \
+    sync\n \
+    lwbrx %0, 0, %3\n \
+    sync "
+  : "=r" (val)
+  : "r" (addr), "r" (GRACKLE_CONFIG_ADDR_ADDR),
+    "r" (GRACKLE_CONFIG_DATA_ADDR));
+
+  return val;
+}
+
+static inline void gemini_led_on( int led )
+{
+  if (led >= 0 && led < GEMINI_LEDS)
+    *(unsigned char *)(GEMINI_LEDBASE + (led<<3)) = 1;
+}
+
+static inline void gemini_led_off(int led)
+{
+  if (led >= 0 && led < GEMINI_LEDS)
+    *(unsigned char *)(GEMINI_LEDBASE + (led<<3)) = 0;
+}
+
+static inline int gemini_led_val(int led)
+{
+  int val = 0;
+  if (led >= 0 && led < GEMINI_LEDS)
+    val = *(unsigned char *)(GEMINI_LEDBASE + (led<<3));
+  return (val & 0x1);
+}
+
+/* returns processor id from the board */
+static inline int gemini_processor(void)
+{
+  unsigned char cpu = *(unsigned char *)(GEMINI_CPUSTAT);
+  return (int) ((cpu == 0) ? 4 : (cpu & GEMINI_CPU_ID_MASK));
+}
+
+
+extern void _gemini_reboot(void);
+extern void gemini_prom_init(void);
+extern void gemini_init_l2(void);
+#endif /* __ASSEMBLY__ */
+#endif
diff --git a/include/asm-ppc/gemini_serial.h b/include/asm-ppc/gemini_serial.h
new file mode 100644 (file)
index 0000000..b030a5e
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef __ASMPPC_GEMINI_SERIAL_H
+#define __ASMPPC_GEMINI_SERIAL_H
+
+#include <asm/gemini.h>
+
+/* Rate for the 24.576 Mhz clock for the onboard serial chip */
+#define BASE_BAUD  (24576000 / 16)
+
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
+#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
+#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF)
+#endif
+
+#define STD_SERIAL_PORT_DEFNS \
+        { 0, BASE_BAUD, GEMINI_SERIAL_A, 15, STD_COM_FLAGS }, /* ttyS0 */ \
+        { 0, BASE_BAUD, GEMINI_SERIAL_B, 14, STD_COM_FLAGS }, /* ttyS1 */ \
+
+#ifdef CONFIG_GEMINI_PU32
+#define PU32_SERIAL_PORT_DEFNS \
+        { 0, BASE_BAUD, NULL, 0, STD_COM_FLAGS },
+#else
+#define PU32_SERIAL_PORT_DEFNS
+#endif
+
+#define SERIAL_PORT_DFNS \
+        STD_SERIAL_PORT_DEFNS \
+        PU32_SERIAL_PORT_DEFNS
+
+#endif
index 13ee32487a350782ecb00daa013ed3a38a9d82c6..385935507c39aecfeb44fd1a4121aa0ff8520a1f 100644 (file)
 
 #ifdef __KERNEL__
 
-#include <linux/ioport.h>
-#include <asm/io.h>
-
 #include <linux/config.h>
-#include <asm/adb.h>
 #include <asm/machdep.h>
-#ifdef CONFIG_APUS
-#include <asm-m68k/keyboard.h>
-#else
+
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
 
 #define KEYBOARD_IRQ                   1
 #define DISABLE_KBD_DURING_INTERRUPTS  0
 #define INIT_KBD
 
-#ifdef CONFIG_PREP
-extern int prep_kbd_present;
-#endif /* CONFIG_PREP */
-
 static inline int kbd_setkeycode(unsigned int scancode, unsigned int keycode)
 {
-       return ppc_md.kbd_setkeycode(scancode, keycode);
+       if ( ppc_md.kbd_setkeycode )
+               return ppc_md.kbd_setkeycode(scancode, keycode);
+       else
+               return 0;
 }
   
 static inline int kbd_getkeycode(unsigned int scancode)
 {
-       return ppc_md.kbd_getkeycode(scancode);
+       if ( ppc_md.kbd_getkeycode )
+               return ppc_md.kbd_getkeycode(scancode);
+       else
+               return 0;
 }
   
 static inline int kbd_translate(unsigned char keycode, unsigned char *keycodep,
                                char raw_mode)
 {
-       return ppc_md.kbd_translate(keycode, keycodep, raw_mode);
+       if ( ppc_md.kbd_translate )
+               return ppc_md.kbd_translate(keycode, keycodep, raw_mode);
+       else
+               return 0;
 }
   
 static inline int kbd_unexpected_up(unsigned char keycode)
 {
-       return ppc_md.kbd_unexpected_up(keycode);
+       if ( ppc_md.kbd_unexpected_up )
+               return ppc_md.kbd_unexpected_up(keycode);
+       else
+               return 0;
 }
   
 static inline void kbd_leds(unsigned char leds)
 {
-#ifdef CONFIG_PREP
-       if (prep_kbd_present)
-#endif /* CONFIG_PREP */
+       if ( ppc_md.kbd_leds )
                ppc_md.kbd_leds(leds);
 }
   
 static inline void kbd_init_hw(void)
 {
-#ifdef CONFIG_PREP
-       if (prep_kbd_present)
-#endif /* CONFIG_PREP */
+       if ( ppc_md.kbd_init_hw )
                ppc_md.kbd_init_hw();
 }
 
-#define kbd_sysrq_xlate        (ppc_md.kbd_sysrq_xlate)
-
-#ifdef CONFIG_MAC_KEYBOARD
-# define SYSRQ_KEY 0x69
-#else
-# define SYSRQ_KEY 0x54
-#endif
+#define kbd_sysrq_xlate        (ppc_md.ppc_kbd_sysrq_xlate)
 
-#endif /* CONFIG_APUS */
+extern unsigned long SYSRQ_KEY;
 
 /* resource allocation */
-#define kbd_request_region() request_region(0x60, 16, "keyboard")
+#define kbd_request_region()
 #define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \
                                              "keyboard", NULL)
 
diff --git a/include/asm-ppc/m48t35.h b/include/asm-ppc/m48t35.h
new file mode 100644 (file)
index 0000000..2e45f4f
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ *  Registers for the SGS-Thomson M48T35 Timekeeper RAM chip
+ */
+
+#ifndef __PPC_M48T35_H
+#define __PPC_M48T35_H
+
+/* RTC offsets */
+#define M48T35_RTC_CONTROL  0
+#define M48T35_RTC_SECONDS  1
+#define M48T35_RTC_MINUTES  2
+#define M48T35_RTC_HOURS    3
+#define M48T35_RTC_DAY      4
+#define M48T35_RTC_DOM      5
+#define M48T35_RTC_MONTH    6
+#define M48T35_RTC_YEAR     7
+
+#define M48T35_RTC_SET      0x80
+#define M48T35_RTC_STOPPED  0x80
+#define M48T35_RTC_READ     0x40
+
+#ifndef BCD_TO_BIN
+#define BCD_TO_BIN(x)   ((x)=((x)&15) + ((x)>>4)*10)
+#endif
+
+#ifndef BIN_TO_BCD
+#define BIN_TO_BCD(x)   ((x)=(((x)/10)<<4) + (x)%10)
+#endif
+
+#endif
index 7a17d9432bf305b97b4689d5a169375908c9e12e..afac1bc8483ac8a57321f2a43aff0a8fc1989abd 100644 (file)
@@ -69,6 +69,7 @@
 #define _MACH_rpxlite 64  /* RPCG RPX-Lite 8xx board */
 #define _MACH_bseip   128 /* Bright Star Engineering ip-Engine */
 #define _MACH_yk      256 /* Motorola Yellowknife */
+#define _MACH_gemini  512 /* Synergy Microsystems gemini board */
 
 /* see residual.h for these */
 #define _PREP_Motorola 0x01  /* motorola prep */
index ff42aa8176526079c201057ead706b861cecf97b..aa2486d69e7d8ce8d3d8d1dca9ae4e96d79a40ce 100644 (file)
@@ -4,7 +4,10 @@
 
 #include <linux/config.h>
 
-#ifdef CONFIG_APUS
+#if defined(CONFIG_GEMINI)
+#include <asm/gemini_serial.h>
+#else
+#if defined(CONFIG_APUS)
 #include <asm-m68k/serial.h>
 #else
 
        EXTRA_SERIAL_PORT_DEFNS         \
        HUB6_SERIAL_PORT_DFNS           \
        MCA_SERIAL_PORT_DFNS
-
-#endif /* CONFIG_APUS */
+#endif
+#endif
index 84e1376b31f094cbeffc853e7b248fa113432432..c44917b8023c406dcb37dcfc2f626aaa6e29340d 100644 (file)
@@ -133,15 +133,14 @@ extern void d_delete(struct dentry *);
 
 /* allocate/de-allocate */
 extern struct dentry * d_alloc(struct dentry * parent, const struct qstr *name);
-extern void prune_dcache(int);
+extern int prune_dcache(int, int);
 extern void shrink_dcache_sb(struct super_block *);
 extern void shrink_dcache_parent(struct dentry *);
 extern int d_invalidate(struct dentry *);
 
-#define shrink_dcache() prune_dcache(0)
+#define shrink_dcache() prune_dcache(0, -1)
 
 /* dcache memory management */
-extern int  select_dcache(int, int);
 extern void shrink_dcache_memory(int, unsigned int);
 extern void check_dcache_memory(void);
 extern void free_inode_memory(int);    /* defined in fs/inode.c */
index 2be62719829c9450f979d553db8ee8e76832be0f..0312b5de3c6f46b12b6c5a69153905985aca4c15 100644 (file)
@@ -49,6 +49,7 @@ struct msginfo {
 #define MSGMNI   128   /* <= 1K */     /* max # of msg queue identifiers */
 #define MSGMAX  4056   /* <= 4056 */   /* max size of message (bytes) */
 #define MSGMNB 16384   /* ? */        /* default max size of a message queue */
+#define MSGQNUM 1024   /* <=65535 */     /* Max messages in flight / queue */
 
 /* unused */
 #define MSGPOOL (MSGMNI*MSGMNB/1024)  /* size in kilobytes of message pool */
index 24828a706cf59560f4bc194c913e35457f1bdd00..6e477e590a6b2a472ab70a7c670cc38dd18ccce2 100644 (file)
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -50,6 +50,7 @@ static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg
        struct ipc_perm *ipcp;
        struct msg *msgh;
        long mtype;
+       int err;
        
        if (msgsz > MSGMAX || (long) msgsz < 0 || msqid < 0)
                return -EINVAL;
@@ -70,34 +71,38 @@ static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg
        if (ipcperms(ipcp, S_IWUGO)) 
                return -EACCES;
        
-       if (msgsz + msq->msg_cbytes > msq->msg_qbytes) { 
-               if (msgsz + msq->msg_cbytes > msq->msg_qbytes) { 
-                       /* still no space in queue */
-                       if (msgflg & IPC_NOWAIT)
-                               return -EAGAIN;
-                       if (signal_pending(current))
-                               return -EINTR;
-                       interruptible_sleep_on (&msq->wwait);
-                       goto slept;
-               }
+       if (msgsz + msq->msg_cbytes > msq->msg_qbytes || msq->msg_qnum>= MSGQNUM) { 
+               /* still no space in queue */
+               if (msgflg & IPC_NOWAIT)
+                       return -EAGAIN;
+               if (signal_pending(current))
+                       return -EINTR;
+               interruptible_sleep_on (&msq->wwait);
+               goto slept;
        }
-       
-       /* allocate message header and text space*/ 
+
+       /* Charge first to avoid races */
+       msgbytes  += msgsz;
+       msghdrs++;
+       msq->msg_qnum++;
+       msq->msg_cbytes += msgsz;
+
+       /* allocate message header and text space */ 
+       err = -ENOMEM;
        msgh = (struct msg *) kmalloc (sizeof(*msgh) + msgsz, GFP_KERNEL);
-       if (!msgh)
-               return -ENOMEM;
+       if (!msgh) 
+               goto uncharge;
        msgh->msg_spot = (char *) (msgh + 1);
 
-       if (copy_from_user(msgh->msg_spot, msgp->mtext, msgsz))
-       {
-               kfree(msgh);
-               return -EFAULT;
+       err = -EFAULT; 
+       if (copy_from_user(msgh->msg_spot, msgp->mtext, msgsz)) {
+               goto uncharge;
        }
        
+       err = -EIDRM; 
        if (msgque[id] == IPC_UNUSED || msgque[id] == IPC_NOID
                || msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) {
-               kfree(msgh);
-               return -EIDRM;
+               goto uncharge;
        }
 
        msgh->msg_next = NULL;
@@ -111,14 +116,19 @@ static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg
                msq->msg_last->msg_next = msgh;
                msq->msg_last = msgh;
        }
-       msq->msg_cbytes += msgsz;
-       msgbytes  += msgsz;
-       msghdrs++;
-       msq->msg_qnum++;
        msq->msg_lspid = current->pid;
        msq->msg_stime = CURRENT_TIME;
        wake_up (&msq->rwait);
        return 0;
+
+uncharge:
+       msgbytes  -= msgsz;
+       msghdrs--;
+       msq->msg_qnum--;
+       msq->msg_cbytes -= msgsz;
+       if (msgh)
+               kfree(msgh); 
+       return err;
 }
 
 static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg)
index f4fee5acd3f61e1a0dffd8f2b546532a2d79ecee..55efebb5cb89f3dd4022a87ae49734c425118502 100644 (file)
@@ -182,7 +182,7 @@ static __inline__ void __tcp_inherit_port(struct sock *sk, struct sock *child)
 
 #ifdef CONFIG_IP_TRANSPARENT_PROXY
        if (child->num != sk->num) {
-               unsigned short snum = ntohs(child->num);
+               unsigned short snum = child->num;
                for(tb = tcp_bhash[tcp_bhashfn(snum)];
                    tb && tb->port != snum;
                    tb = tb->next)