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/
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}
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
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
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
#
$(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)
.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
* 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
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);
flush_cache(dst, len);
- sa = *(unsigned *)dst + PROG_START;
+ sa = (unsigned long)dst;
printf("start address = 0x%x\n", sa);
#if 0
printf("gunzip: ran out of data in header\n");
exit();
}
-
s.zalloc = zalloc;
s.zfree = zfree;
r = inflateInit2(&s, -MAX_WBITS);
#
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
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
# 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_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
# 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
# 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_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
#
CONFIG_SOUND=y
CONFIG_DMASOUND=y
+# CONFIG_SOUND_CMPCI is not set
# CONFIG_SOUND_ES1370 is not set
# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_MAESTRO is not set
# CONFIG_SOUND_ESSSOLO1 is not set
# CONFIG_SOUND_SONICVIBES is not set
# CONFIG_SOUND_MSNDCLAS is not set
# CONFIG_SOUND_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
# 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
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' \
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
#
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
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
# 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_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
# 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
# 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_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
#
CONFIG_SOUND=y
CONFIG_DMASOUND=y
+# CONFIG_SOUND_CMPCI is not set
# CONFIG_SOUND_ES1370 is not set
# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_MAESTRO is not set
# CONFIG_SOUND_ESSSOLO1 is not set
# CONFIG_SOUND_SONICVIBES is not set
# CONFIG_SOUND_MSNDCLAS is not set
# CONFIG_SOUND_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
# 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
--- /dev/null
+#
+# 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
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
(*(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
--- /dev/null
+#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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
+}
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 */ \
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
.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
.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
* 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
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 */
#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
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
/* 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
.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
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)
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 */
/* 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 */
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:
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:
/*
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
*/
#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
#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 */
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 */
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 = {
/* 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();
}
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);
+}
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 */
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 */
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 */
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 */
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 |= 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
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
}
}
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;
+ }
}
}
void
prep_ide_fix_driveid(struct hd_driveid *id)
{
+ ppc_generic_ide_fix_driveid(id);
}
__initfunc(void
#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
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;
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];
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__ */
_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 */
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");
#include <asm/init.h>
#include <asm/io.h>
#include <asm/prom.h>
+#include <asm/gemini.h>
#include "time.h"
int first_cpu_booted = 0;
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);
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;
*MotSave_CpusState[1] = CPU_GOOD;
printk("CPU1 reset, waiting\n");
break;
+ case _MACH_gemini:
+ openpic_init_processor( 1<<i );
+ openpic_init_processor( 0 );
+ break;
}
/*
#include <asm/setup.h>
#include <asm/amigahw.h>
/* END APUS includes */
+#include <asm/gemini.h>
int prom_trashed;
atomic_t next_mmu_context;
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);
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 )
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;
(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 */
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))
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); */
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);
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;
}
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
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
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);
#endif
#ifdef CONFIG_BMAC
{bmac_probe, 0},
+#endif
+#ifdef CONFIG_NCR885E
+ {ncr885e_probe, 0},
#endif
{NULL, 0},
};
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>
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;
}
}
}
--- /dev/null
+#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
--- /dev/null
+/*
+ * 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 *) ®
+ 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:
+ */
--- /dev/null
+#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
{"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.*/
{"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 */
/*
{"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},
#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 {
* 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;
}
/*
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;
}
/*
* 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;
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;
}
/*
int found;
while ((found = select_parent(parent)) != 0)
- prune_dcache(found);
+ prune_dcache(found, -1);
}
/*
int count = 0;
if (priority)
count = dentry_stat.nr_unused / priority;
- prune_dcache(count);
+ prune_dcache(count, -1);
}
}
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;
* 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
*/
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;
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();
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++;
}
/*
* 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;
}
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++)
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;
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;
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);
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;
}
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;
}
"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);
(((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;
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,
*/
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.
*
* 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);
}
/*
* 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();
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));
}
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. */
#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;
#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",
(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 },
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);
--- /dev/null
+/*
+ * 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
--- /dev/null
+#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
#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)
--- /dev/null
+/*
+ * 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
#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 */
#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
/* 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 */
#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 */
struct ipc_perm *ipcp;
struct msg *msgh;
long mtype;
+ int err;
if (msgsz > MSGMAX || (long) msgsz < 0 || msqid < 0)
return -EINVAL;
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;
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)
#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)